/* ══════════════════════════════════════════════════════════════════════════════════════════
   HyperMONK. One column, one screen at a time.

   THE SHAPE, in one paragraph. There is one home and one column. Everything else is a screen
   you push onto a stack or a sheet that rises from the bottom, so the app never shows you two
   lists of rooms at once and never needs a sidebar to say where you are. The large title IS
   the company switch. Your own monk is not a list row, it is the card under the title, so the
   app opens on something the monk wants from you. İşler and Ben are screens you go into and
   come back from. Daireler and Hafıza are not destinations at all: they are a segmented
   control INSIDE a conversation, because they are three perspectives on one dialogue.

   Written from scratch, not edited. Three previous attempts were a room list beside a message
   thread beside a panel, which is Slack's shape and Element's and Teams', and it was rejected
   each time. The bones are different here, not the paint.

   The phone is the original and the desktop is a tall screenshot of it: at 1024 and up the
   column is centred at 780 px on the same white, and it widens to 1160 only when a
   conversation is showing its circles or its memory, which are the two things that genuinely
   want room. The flanks stay empty on purpose.

   COUPLINGS a redesign must not break, checked by tools/ui-contract-tests.mjs and written up
   in docs/UI-CONTRACT.md:
     1. --bg --panel-2 --line --text --muted are read off :root by public/circles.js, whose
        parser takes #rgb and #rrggbb only. They are hex literals, in the first :root block.
     2. --row is the same number as ROW in public/app.js, which positions the queue rows this
        stylesheet sizes. The rows are placed by arithmetic, never measured.
     3. body carries a font-family, which the circle canvas borrows for its labels.
     4. the layout keys off data-tab, data-room and data-view on body, written by shell.js.
     5. menu.js, settings.js and voice/controls.js inject their own stylesheets written
        against --panel --panel-2 --line --text --muted --accent --warn --hot. All eight are
        defined below, or those three lose their colours with nothing said.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* THE WEBSITE'S LOOK (9 October 2026). The owner: "Change the style of the HyperMONK iPhone app,
   use the website style, super minimal, super super minimal. Light theme only. Choose fonts also
   based on that minimalism. Almost wireframe, nothing extra." So this is hypermonk.org's palette:
   white paper, ink #191919, greys, hairlines #ddd and #eee, and no colour anywhere else. There is
   one palette and no dark one; nothing in the app switches it.

   THE FACES are the website's too, and they are the phone's own, so nothing is downloaded: Arial
   (Helvetica on an iPhone) for everything you read, Georgia for a large title that earns it, and
   monospace for the small labels over a list. One weight: no bold anywhere. Inter is gone; its two
   files stay in public/vendor in case a later build wants it back. */

:root {
  /* ── the five the circle canvas parses, as hex ── */
  --bg: #ffffff;
  --panel-2: #ffffff;
  --line: #eeeeee;
  --text: #191919;
  --muted: #777777;

  /* ── the rest of the surface: white, with the barely different greys the website uses ── */
  --panel: #ffffff;
  --panel-3: #f4f4f4;       /* a row under the finger, a chosen tab */
  --sunk: #fafafa;
  --line-2: #dddddd;
  /* every border and separator in the page: the website's two hairlines */
  --hair: #eeeeee;
  --hair-2: #dddddd;
  --dim: #999999;
  --faint: #cccccc;
  --text-2: #555555;         /* the second ink: the last thing MONK said, a line of history */

  /* ── NO COLOUR. What used to be the amber accent is ink now, and the words that colour used
     to say (done, waiting, refused) are printed as words, which they always were. ── */
  --accent: #191919;
  --accent-ink: #ffffff;
  --accent-soft: transparent;   /* no fills: a chosen thing is drawn by its outline */
  --accent-line: #dddddd;
  /* YOUR OWN LINES: a very light grey on the right; MONK's are white with a hairline on the
     left, so the two can never be mistaken for each other */
  --mine-bg: #f4f4f4;
  --mine-line: #f4f4f4;
  --mine-text: #191919;
  --mine-dim: #888888;
  --mine-link: #191919;
  --theirs-bg: #ffffff;
  --theirs-line: #dddddd;
  /* THE DOCK under the conversation: the chips and the composer on a barely different white,
     apart from the conversation by one hairline (9 October: "it should have a different tone
     than the actual chat area"). The field and the chips are white pills on it. */
  --dock: #fafafa;
  --dock-field: #ffffff;
  --chip: #ffffff;
  --ok: #191919;
  --warn: #191919;
  --hot: #191919;
  --hot-soft: transparent;
  --hot-line: #dddddd;

  /* ── metrics ── */
  --nav: 56px;
  --col: 780px;
  --col-wide: 1160px;
  --gut: 16px;
  --row: 32px;              /* SAME NUMBER as ROW in public/app.js */

  --r1: 8px;
  --r2: 12px;
  --r3: 16px;
  --r4: 20px;
  --pill: 999px;

  --font: Arial, Helvetica, sans-serif;
  --serif: Georgia, 'Times New Roman', serif;
  --mono: ui-monospace, Menlo, Consolas, monospace;
  --ease: cubic-bezier(.32, .72, 0, 1);
  --shadow: none;
  /* the few colours that were written into rules, as tokens, so the dark theme can change them too */
  --sel: #e2e2e2;              /* text chosen with the finger */
  --veil: rgba(255, 255, 255, .82);   /* the page behind a sheet */
  --label-bg: rgba(255, 255, 255, .92);   /* a memory node's label over the graph */
  color-scheme: light;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE DARK THEME (17 October 2026, the owner: "Dark/Light theme. I want a button for that."). The same ink-on-paper
   look turned round: a near black page, the greys lifted, ink becomes a soft white, and still no colour anywhere.
   Every token of the light palette is given here, so no rule has to know which theme is on; <html data-theme> is set
   by the page head before anything is drawn (public/index.html) and by public/theme.js when the button is pressed.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
:root[data-theme="dark"] {
  --bg: #121212;
  --panel-2: #1a1a1a;
  --line: #262626;
  --text: #ececec;
  --muted: #9b9b9b;
  --panel: #1a1a1a;
  --panel-3: #262626;
  --sunk: #0c0c0c;
  --line-2: #333333;
  --hair: #262626;
  --hair-2: #343434;
  --dim: #7d7d7d;
  --faint: #4a4a4a;
  --text-2: #b8b8b8;
  --accent: #ececec;
  --accent-ink: #121212;
  --accent-soft: transparent;
  --accent-line: #343434;
  --mine-bg: #262626;
  --mine-line: #262626;
  --mine-text: #ececec;
  --mine-dim: #9b9b9b;
  --mine-link: #ececec;
  --theirs-bg: #1a1a1a;
  --theirs-line: #343434;
  --dock: #161616;
  --dock-field: #1f1f1f;
  --chip: #1f1f1f;
  --ok: #ececec;
  --warn: #ececec;
  --hot: #ececec;
  --hot-soft: transparent;
  --hot-line: #343434;
  --sel: #3a3a3a;
  --veil: rgba(10, 10, 10, .78);
  --label-bg: rgba(26, 26, 26, .92);
  color-scheme: dark;
}

/* ── reset ────────────────────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* the circle canvas borrows this off body: ui-contract-tests checks it is here */
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.45;
  letter-spacing: 0;
  overflow: hidden;
  overscroll-behavior: none;
}

[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }
/* ONE WEIGHT. Nothing in this app is bold: size and the serif carry a title, grey carries a note. */
b, strong, h1, h2, h3, h4, th { font-weight: 400; }
button, input, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
button:disabled { cursor: default; opacity: .45; }
input { border: 0; background: none; }
input:focus { outline: none; }
canvas { display: block; }
::selection { background: var(--sel); color: var(--text); }
:focus-visible { outline: 2px solid var(--muted); outline-offset: 2px; border-radius: 6px; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb { background: var(--hair-2); border-radius: 3px; }
::-webkit-scrollbar-track { background: transparent; }

/* ── A FINGER IS 44 PX ───────────────────────────────────────────────────────────────────
   Every control this app draws, in one place, so a new one inherits the floor instead of
   having to remember it. tools/e2e/browser.mjs measures every visible button in a real
   browser at 390 px; this block is what makes them pass. It comes before anything that could
   set a smaller height, and it never writes the size onto the visible ink: a 44 px box round
   a 34 px disc is a target, a 44 px disc is a shout. */
button, [role="button"], .segbtn, .tab, .etab, .spacebtn, .ctxtab, .wtab, .sheet-item,
.me-row, .chat-room, .lrow, .work-row, .work-do, .form-go, .detail-back, .receipt-retry,
.queue-retry, .deliver-path, .propose-date, .rail-face, .rail-plus, .icon-btn, .new-talk, .back,
.cbtn, .tbtn, .gate-alt, .gate-go, .sheet-close, .newbtn, .msg-retry, .chat-send {
  min-height: 44px;
}
/* A WIDTH AS WELL AS A HEIGHT: these are as wide as the word inside them, and the narrowest
   is the "+" that makes a new set of circles, which measured thirty-five pixels across. */
.spacebtn, .ctxtab, .tab, .wtab, .etab, .newbtn, .icon-btn, .cbtn, .ibtn, .gear, .del,
.vbtn, .power, .quick button, .x, .engine-note .x {
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── THE ENGINE'S KNOBS ───────────────────────────────────────────────────────────────────
   app.js builds div.tune, appends it to document.body and positions it with inline left and
   top computed from the gear's own rectangle. With no rule at all it computed
   position:static, so those inline coordinates meant nothing and the panel laid out in the
   body's flow UNDERNEATH main, which is fixed and paints the whole viewport. Every engine
   setting - threshold, ramp, decay, satisfied score, ask-every, and the switch for the timing
   line - was unreachable, and the gear looked like a button that did nothing. */
.tune {
  position: fixed;
  z-index: 60;
  width: min(340px, calc(100vw - 24px));
  max-height: calc(100vh - 24px);
  overflow-y: auto;
  padding: 12px 14px 14px;
  border: 1px solid var(--hair);
  border-radius: var(--r3);
  background: var(--bg);
  box-shadow: var(--shadow);
  font-size: 13.5px;
}
.tune h3, .tune .tune-title { margin-bottom: 8px; font-size: 15px; font-weight: 400; letter-spacing: 0; }
.tune label, .tune .knob-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.tune input[type="range"] { flex: 1 1 auto; min-width: 0; accent-color: var(--accent); }
.tune input[type="number"], .tune input[type="text"] {
  width: 74px;
  min-height: 36px;
  padding: 0 8px;
  border: 1px solid var(--hair);
  border-radius: var(--r1);
  background: var(--sunk);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.tune .val, .tune .unit { color: var(--dim); font-variant-numeric: tabular-nums; }

/* ── PRESS AND HOLD ───────────────────────────────────────────────────────────────────────
   menu.js turns a long press into the contextmenu event a mouse would have sent, because iOS
   Safari never sends one. iOS answers the same press with its own selection callout and a
   magnifier, which lands on top of the menu. Suppressed on exactly the elements that carry a
   menu, and nowhere else: a field is still selectable, and the menu itself offers Copy text.
   -webkit-touch-callout is the iOS-only property that does it; user-select stops the
   selection handles that come with it on both platforms. */
.msg, #queue .item, .ctxtab, .wtab, .spacebtn, .chat-msg, .chat-room, .work-row, .ar-row {
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

/* the parking: app.js fills these at boot and shell.js moves four of them into Ben. Off
   screen rather than display:none, because the browser rig must still be able to measure the
   voice buttons and the engine tabs. */
.parking { position: fixed; left: -9999px; top: 0; width: 1px; overflow: hidden; }

/* RETIRED. The element stays for the id contract; nothing draws it any more, because the
   company switch is the large title. */
.rail { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE COLUMN AND THE STACK
   ══════════════════════════════════════════════════════════════════════════════════════════ */

main {
  position: fixed;
  inset: 0;
  margin: 0 auto;
  width: 100%;
  background: var(--bg);
  /* clip, so a focus inside an off-screen screen can never scroll the stack sideways */
  overflow: clip;
  transition: width .5s var(--ease);
}

@media (min-width: 1024px) {
  main {
    width: min(var(--col), 100%);
    border-left: 1px solid var(--hair);
    border-right: 1px solid var(--hair);
  }
}

/* THE TWO THINGS THAT GENUINELY WANT ROOM, and the window in which wanting room means
   anything. This was inside the 1024 block, which meant it kept applying past 1500 as well,
   and there it BEAT the rule below that gives your own monk the full 1680: two attribute
   selectors outrank one, whatever the order of the blocks. So on a wide monitor, clicking a
   link in a message switched the view to the memory and the whole page jumped from 1680 to
   1160 - it contracted, which is exactly the word he used, twice. Capping it at 1499.98px
   leaves the three-column layout to the block below and there is nothing left to outrank. */
@media (min-width: 1024px) and (max-width: 1499.98px) {
  body[data-room="monk"][data-view="circles"] main,
  body[data-room="monk"][data-view="graph"] main { width: min(var(--col-wide), 100%); }
}

/* ── A BIG SCREEN SHOWS ALL THREE AT ONCE ─────────────────────────────────────────────────
   The stack is one thing at a time because a phone is one thing at a time. A 1500 pixel
   monitor is not, and the three views of a conversation are not three destinations: they are
   three readings of the same dialogue. The talk, what wants to speak, and what is known.
   Side by side they answer each other, which is the whole argument for them being one
   conversation rather than three tabs.

   The conversation is a SCREEN of the stack, so it is display:flex like every other screen
   and its children stack down the column. Turning it into a grid is the whole trick, and it
   has to be done on the screen itself rather than on some inner wrapper, because there is no
   inner wrapper: the nav, the switcher and the two panes are its direct children.

   Only for your own monk. A room has no circles and no memory of its own yet, so there is
   nothing to stand beside it and the column stays a column. */
@media (min-width: 1500px) {
  /* THE WHOLE WINDOW. It was capped at 1680, which on his 1920 monitor left a dark band on
     both sides: "in my personal monk conversation view, the UI is not full width." */
  body[data-room="monk"] main { width: 100%; border-left: 0; border-right: 0; }
  body[data-room="monk"] .convo {
    display: grid;
    grid-template-columns: minmax(420px, 1.1fr) minmax(300px, .85fr) minmax(360px, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }
  body[data-room="monk"] .convo > .nav { grid-row: 1; grid-column: 1 / -1; }
  /* The switcher has nothing left to switch: everything it offers is already on screen. It
     stays in the DOM, because a narrower window needs it back the moment it is resized. */
  body[data-room="monk"] .seg-wrap { display: none; }

  body[data-room="monk"] .convo > .chat-pane { display: flex; grid-row: 2; grid-column: 1; }
  body[data-room="monk"] .convo > .queue-pane {
    display: flex;
    grid-row: 2;
    grid-column: 2 / -1;
    border-left: 1px solid var(--hair);
  }
  /* the pane's two halves stop being one above the other and become the other two columns */
  body[data-room="monk"] .split { flex-direction: row; }
  body[data-room="monk"] .split > .top,
  body[data-room="monk"] .split > .bottom { display: flex; flex: 1 1 0; min-width: 0; }
  body[data-room="monk"] .split > .bottom { border-left: 1px solid var(--hair); }
  /* the circle controls belong with the circles, whatever the switcher last said */
  body[data-room="monk"] .queue-pane > .pane-head { display: flex; }
}

/* ── one screen at a time ────────────────────────────────────────────────────────────────
   shell.js writes data-state on each screen: active, behind, entering or off. Only two are
   ever mounted, the one you are looking at and the one you came from, so going back is
   instant and keeps its scroll, and so a rig can still find "the screen that is on" by
   looking for the visible one.

   .pane on a screen is a marker, not a style: tools/e2e/browser.mjs looks for main > .pane to
   check the first screen starts at the top of the phone. Nothing styles bare .pane. */
main > .screen {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg);
  transform: translate3d(100%, 0, 0);
  transition: transform .44s var(--ease), opacity .44s var(--ease);
  will-change: transform;
}
main > .screen[data-state="off"] { display: none; }
main > .screen[data-state="entering"] { transform: translate3d(100%, 0, 0); }
main > .screen[data-state="active"] {
  z-index: 2;
  transform: none;
  box-shadow: -1px 0 0 var(--hair);
}
main > .screen[data-state="behind"] {
  transform: translate3d(-19%, 0, 0);
  opacity: .4;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  main > .screen { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE NAV BAR
   Three columns: the way back or your own face, the title, one action. The title is invisible
   on a screen that has a large title until you scroll past it, which is what makes the large
   title feel like it collapsed into the bar rather than being replaced by it.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.nav {
  position: relative;
  z-index: 6;
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(44px, auto) 1fr minmax(44px, auto);
  align-items: center;
  gap: 8px;
  min-height: var(--nav);
  padding: 6px 10px;
  padding-top: calc(6px + env(safe-area-inset-top));
  background: var(--bg);
}
.nav::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--hair);
  opacity: 0;
  transition: opacity .25s;
}
.screen.scrolled .nav::after { opacity: 1; }
.nav-end { justify-self: end; }

.nav-title {
  justify-self: center;
  text-align: center;
  min-width: 0;
  opacity: 0;
  transform: translateY(7px);
  transition: opacity .24s, transform .24s;
}
.screen.scrolled .nav-title, .nav-title.always { opacity: 1; transform: none; }
/* Which build answered, beside the name on the home screen. Small and grey on purpose: it is
   there to be checked, not read, and it settles "did the phone update" without opening
   anything. */
.nav-ver {
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .03em;
  color: var(--dim);
}
.nav-title b {
  display: block;
  font-size: 15.5px;
  font-weight: 400;
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-title span {
  display: block;
  margin-top: -1px;
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.icon-btn { width: 44px; height: 44px; border-radius: var(--r2); color: var(--text); }
.icon-btn svg { width: 21px; height: 21px; }
.icon-btn:hover { background: var(--panel-2); }
/* in a room the corner belongs to the room: a new conversation is your own monk's */
body[data-room="room"] #newBtn { display: none; }
/* the new-conversation button in the conversation's own bar: a word as well as a mark */
.new-talk { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px 0 10px; border: 1px solid var(--hair-2); border-radius: var(--pill); color: var(--text); font-size: 14.5px; font-weight: 400; }
.new-talk svg { width: 17px; height: 17px; }
.new-talk[hidden] { display: none; }            /* its own display would otherwise beat [hidden] */
.new-talk:hover { background: var(--panel-2); }

.back {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: 44px;
  padding: 0 10px 0 6px;
  border-radius: var(--r2);
  font-size: 15px;
  font-weight: 400;
  color: var(--text);
}
.back svg { width: 17px; height: 17px; flex: 0 0 auto; }
.back span {
  max-width: 11ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.back:hover { background: var(--panel-2); }

/* ── a face ──────────────────────────────────────────────────────────────────────────────
   The disc is 34, because a 44 px circle at the top of a screen is a shout. The BOX is 44,
   because that is what a thumb hits. */
.face {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  color: var(--text);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0;
  user-select: none;
}
.face.sm { width: 44px; height: 44px; border-radius: var(--r2); background: none; box-shadow: none; }
.face.sm > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 400;
}
.face.sm:hover > span { background: var(--panel-3); }
.face.monk { background: var(--bg); color: var(--text); box-shadow: inset 0 0 0 1px var(--text); }
.face.work { background: var(--bg); color: var(--text); box-shadow: inset 0 0 0 1px var(--hair-2); }
.face.work svg { width: 20px; height: 20px; }
/* A conversation that has a monk in it says so on its face, and the room also prints the word
   in its member list: the dot is a reminder, never the only way to know. */
.face.has-monk::after {
  content: '';
  position: absolute;
  right: 1px; bottom: 1px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg);
}
.group .face.has-monk::after { box-shadow: 0 0 0 3px var(--panel-2); }
/* ONE FACE FOR EVERYBODY since 9 October: the six colour pairs drawn from the name went with the
   colour. The initial, and the name beside it, say who it is. */

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE SCROLL, AND THE LARGE TITLE THAT COLLAPSES INTO THE BAR
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: calc(36px + env(safe-area-inset-bottom));
}

.lt-wrap { padding: 2px var(--gut) 4px; }
.lt {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  max-width: 100%;
  font-family: var(--serif);
  font-size: 34px;
  font-weight: 400;
  letter-spacing: -.7px;
  line-height: 1.08;
  color: var(--text);
  text-align: left;
}
.lt > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lt .chev { width: 15px; height: 15px; flex: 0 0 auto; opacity: .42; transform: translateY(2px); }
.lt:hover .chev { opacity: .8; }
.lt-sub {
  margin: 1px 0 0;
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.lt-sub b { color: var(--text); font-weight: 400; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   GROUPED INSET LISTS  -  the home screen's body
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 26px 18px 8px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted);
}
.group-head .n { color: var(--dim); font-weight: 400; }

.group {
  --ins: 66px;                       /* where a hairline starts: past the face */
  margin: 0 var(--gut);
  background: var(--panel-2);
  border: 1px solid var(--hair-2);
  border-radius: var(--r3);
  overflow: hidden;
}
.group.flat { --ins: 16px; }
/* A group with nothing in it, and the heading that announces it, both go. "Sohbetler" over
   an empty rectangle is a heading for a list that does not exist, which reads as a failure
   rather than as an empty state. The screen's own status line says what is actually going
   on. */
.group:empty { display: none; }
.group-head:has(+ .group:empty) { display: none; }

/* A row in one of those lists. NOT called .row: public/app.js mints every rule-trace line as
   class "row", and a bare .row rule here would dress the developer read-out as a settings
   list. That exact collision put the trace lines and the queue rows on one rule for a whole
   release, each absolutely positioned on top of the next. */
.lrow {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 64px;
  padding: 10px 14px;
  text-align: left;
  color: var(--text);
}
.lrow + .lrow::before {
  content: '';
  position: absolute;
  top: 0;
  left: var(--ins);
  right: 0;
  height: 1px;
  background: var(--hair);
}
/* a person's row with a manager's "⋯" beside it (13 October 2026: removing a person from the company) */
.lrow-line { position: relative; display: flex; align-items: center; }
.lrow-line > .lrow { flex: 1 1 auto; min-width: 0; }
.lrow-line + .lrow-line::before { content: ''; position: absolute; top: 0; left: var(--ins); right: 0; height: 1px; background: var(--hair); }
.lrow-more { flex: 0 0 auto; width: 44px; height: 44px; margin-right: 6px; border: 0; border-radius: 50%; background: none; color: var(--muted); font-size: 22px; line-height: 1; cursor: pointer; }
.lrow-more:hover { background: var(--panel-3); color: var(--text); }
.lrow:hover { background: var(--panel-3); }
.lrow:active { background: var(--panel-3); }
.lrow-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lrow-top { display: flex; align-items: baseline; gap: 10px; }
.lrow-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15.5px;
  font-weight: 400;
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lrow-who { font-size: 13px; letter-spacing: 0; color: var(--muted); }
.disc { flex: 0 0 auto; display: inline-flex; color: var(--dim); }
.disc svg { width: 16px; height: 16px; }
.go .lrow-title { font-weight: 400; }

/* ── your own monk, which is a card and not a row ───────────────────────────────────────── */
.monk-card {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  /* A button sizes to its content even with display:flex, because a form control carries its
     own intrinsic width. width:auto left the card shrink-wrapped to the monk's last sentence
     while the İşler row beside it ran the full column: two cards, two different widths, on
     the same screen. The margins inset it, so the width has to take them back off. */
  width: calc(100% - var(--gut) * 2);
  margin: 6px var(--gut) 0;
  padding: 15px 16px 16px;
  border: 1px solid var(--accent-line);
  border-radius: 19px;
  background: var(--bg);
  text-align: left;
  color: var(--text);
}
.monk-card:hover { border-color: var(--dim); }
.mc { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.mc-top { display: flex; align-items: baseline; gap: 10px; }
.mc-title { flex: 1 1 auto; font-size: 16px; font-weight: 400; letter-spacing: 0; }
.mc-when { font-size: 12px; letter-spacing: 0; color: var(--dim); }
.mc-said { font-size: 14.5px; line-height: 1.4; letter-spacing: 0; color: var(--text-2); }
.mc-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
  font-size: 12.5px;
  letter-spacing: 0;
  color: var(--accent);
}

/* what the server asked while nobody was here */
.inbox-notice {
  margin: 12px var(--gut) 0;
  padding: 13px 15px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r3);
  background: var(--accent-soft);
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--text);
}
.inbox-head { font-weight: 400; margin-bottom: 3px; }
.inbox-row { display: flex; align-items: baseline; gap: 10px; padding: 3px 0; }
.inbox-text { flex: 1 1 auto; min-width: 0; }
.inbox-when, .inbox-note { font-size: 12px; color: var(--muted); }

/* the people, and the invite line */
.org-panel { margin: 20px var(--gut) 0; }
.org-line { padding: 4px 2px; font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.org-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border-radius: var(--r2);
  text-align: left;
  font-size: 14px;
  color: var(--text);
}
.org-row:hover { background: var(--panel-2); }
.org-pick { flex: 1 1 auto; min-width: 0; text-align: left; }
.org-go, .org-alt {
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
}
.org-go { border-color: var(--text); }
.org-link { color: var(--accent); font-size: 13px; word-break: break-all; }

/* KIMLER VAR. Bir satir bir kisi: adi solda, nasil ve ne zaman geldigi altinda. 26 Eylul'de
 * sordugu soru buydu ve cevabin bir yeri yoktu. Yeni gelen bir kisi isaretli, cunku "gonderdigim
 * davet calisti mi" bu haftaya dair bir soru. */
.org-person {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 2px;
  border-bottom: 1px solid var(--line);
}
.org-person:last-of-type { border-bottom: 0; }
.org-person-name { font-size: 14px; color: var(--text); }
.org-person-note { font-size: 12px; color: var(--muted); }
.org-person-new .org-person-name::after {
  content: 'yeni';
  margin-left: 8px;
  font-size: 10.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE SHEET  -  everything that starts something, and the company switch
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.sheet-host {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.scrim { position: absolute; inset: 0; background: var(--veil); }
.sheet {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: 84vh;
  overflow-y: auto;
  padding: 6px 12px calc(14px + env(safe-area-inset-bottom));
  border: 1px solid var(--hair-2);
  border-bottom: 0;
  border-radius: 22px 22px 0 0;
  background: var(--bg);
  box-shadow: var(--shadow);
}
@media (min-width: 640px) {
  .sheet-host { align-items: center; }
  .sheet { border-radius: 22px; border-bottom: 1px solid var(--hair-2); max-height: 76vh; }
  .sheet-grip { display: none; }
}
.sheet-grip {
  width: 36px;
  height: 4px;
  margin: 4px auto 10px;
  border-radius: var(--pill);
  background: var(--hair-2);
}
.sheet-t {
  padding: 4px 8px 10px;
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0;
}
.sheet-list { display: flex; flex-direction: column; }
.sheet-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 10px 12px;
  border-radius: 14px;
  text-align: left;
  color: var(--text);
}
.sheet-item:hover, .sheet-item.on { background: var(--panel-2); }
.sheet-mark {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 400;
}
.sheet-item.on .sheet-mark { box-shadow: inset 0 0 0 1px var(--text); }
.sheet-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sheet-label { font-size: 15.5px; font-weight: 400; letter-spacing: 0; }
.sheet-hint { font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.sheet-note { padding: 8px 10px 0; font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.sheet-sep { height: 1px; margin: 8px 12px; background: var(--hair); }
/* ONE FIELD, ONE ANSWER. The sheet's other shape: a short form, which is where renaming a
   company and founding one live now instead of at the foot of the home list. */
.sheet-form { display: flex; flex-direction: column; gap: 10px; padding: 4px 8px 0; }
.sheet-field { display: flex; flex-direction: column; gap: 6px; }
.sheet-cap { font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.sheet-field input {
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--hair-2);
  border-radius: var(--r2);
  background: var(--panel-2);
  color: var(--text);
  font-size: 16px;
}
.sheet-field input:focus { border-color: var(--text); }
.sheet-say { min-height: 18px; font-size: 13px; letter-spacing: 0; color: var(--muted); }
.sheet-say.bad { color: var(--hot); }
.sheet-go {
  min-height: 50px;
  border: 1px solid var(--text);
  border-radius: var(--pill);
  background: var(--bg);
  color: var(--text);
  font-size: 15.5px;
  font-weight: 400;
}
.sheet-go:hover { background: var(--panel-3); }
/* A SHEET THAT IS A SMALL PAGE (28 September): the group, the invitation and the people, which
   were drawn at the foot of the home list. One sentence at the top says what this is. */
.sheet-lead { padding: 0 2px 4px; font-size: 13.5px; line-height: 1.45; color: var(--muted); }
.sheet-body { display: flex; flex-direction: column; gap: 6px; }
.sheet-body > .sheet-cap { padding: 8px 2px 0; }
.sheet-toggle { border: 1px solid var(--hair); }
.sheet-toggle.on { border-color: var(--accent-line); background: var(--accent-soft); }
.sheet-check { flex: none; width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--hair-2); color: transparent; display: inline-flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 400; }
.sheet-toggle.on .sheet-check { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.sheet-linkbox { padding: 14px; border: 1px dashed var(--hair-2); border-radius: var(--r2); background: var(--panel-2); font-size: 13.5px; line-height: 1.4; overflow-wrap: anywhere; user-select: all; color: var(--text); }
.sheet-row { display: flex; gap: 8px; }
/* a few choices in a row, one of them on (the invitation's "how many people" and "how long", 12 October 2026) */
.sheet-choices { display: flex; flex-wrap: wrap; gap: 8px; }
.sheet-choice { min-height: 40px; padding: 0 14px; border-radius: var(--pill); border: 1px solid var(--hair-2); background: var(--bg); color: var(--text); font-size: 14px; cursor: pointer; }
.sheet-choice.on { background: var(--text); border-color: var(--text); color: var(--bg); }
.sheet-row > .sheet-go { flex: 1 1 auto; }
.sheet-alt { min-height: 50px; padding: 0 16px; border-radius: var(--pill); border: 1px solid var(--hair-2); background: var(--bg); color: var(--text); font-size: 15px; font-weight: 400; }
.sheet-alt:hover { background: var(--panel-3); }
/* what just happened, for a few seconds, above everything */
/* as wide as what it says, up to the screen: centred by its margins, because a box pinned at
   left: 50% can only ever grow into the right half, and on a phone it wrapped every word */
.notice-line { position: fixed; left: 0; right: 0; margin: 0 auto; width: fit-content; display: flex; align-items: center; gap: 12px; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); z-index: 9500; max-width: min(92vw, 520px); padding: 12px 16px; border: 1px solid var(--hair-2); border-radius: var(--r2); background: var(--bg); color: var(--text); font-size: 14px; line-height: 1.4; }
.notice-line[hidden] { display: none; }
/* the one thing to do about what just happened, "Geri al" after closing a group */
.notice-act { flex: 0 0 auto; padding: 6px 14px; min-height: 44px; border: 1px solid var(--accent-line); border-radius: var(--pill); color: var(--text); font-weight: 400; background: var(--accent-soft); }
/* the "..." in a conversation's corner, and the rows on its sheet that cannot be taken lightly */
.room-more[hidden] { display: none; }
.sheet-item.sheet-danger .sheet-label { color: var(--hot); }
/* WHO IS WAITING, on home for a manager or a team lead */
/* Somebody at the door, or a request of one's own waiting (12 October 2026, the owner: "very dominant, so that no one
   misses it"): the strongest thing on the home screen, dark with light words, first under the title. */
.approvals-card { display: flex; align-items: center; gap: 14px; width: calc(100% - var(--gut) * 2); margin: 6px var(--gut) 8px; padding: 16px 16px; border: 0; border-radius: var(--r3, 16px); background: var(--text); text-align: left; color: var(--panel-2, #fff); cursor: pointer; }
.approvals-card[hidden] { display: none; }
.approvals-card .face { flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--panel-2, #fff); color: var(--text); font-size: 18px; animation: doorPulse 1.6s ease-in-out infinite; }
.approvals-card .mc { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.approvals-card .mc-title { font-size: 16.5px; font-weight: 500; line-height: 1.3; }
.approvals-card .mc-said { font-size: 13.5px; color: inherit; opacity: .8; line-height: 1.35; }
.waiting-card { cursor: default; }
.waiting-card.rejected .face { animation: none; }
@keyframes doorPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }
@media (prefers-reduced-motion: reduce) { .approvals-card .face { animation: none; } }
/* an empty list says so in a plain line under its heading, not in a card of its own (12 October 2026, Atakan's phone:
   "Henüz sohbet yok" glued to the card above, and the people line with the card's border running through it) */
.group.is-empty-note { background: none; border: 0; border-radius: 0; overflow: visible; }
.group.is-empty-note .chat-note, .group.is-empty-note .group-empty { padding: 2px 4px 0; text-align: left; }
/* one request in the review sheet: who, what they wrote, and the two answers */
.req-card { display: flex; flex-direction: column; gap: 6px; padding: 12px; border: 1px solid var(--hair); border-radius: var(--r2); background: var(--panel-2); }
.req-name { font-size: 15.5px; font-weight: 400; }
.req-name.missing, .req-role.missing { color: var(--dim); font-weight: 400; font-style: italic; }
.req-role { font-size: 14px; }
.req-line { font-size: 12px; color: var(--dim); }
.req-card .sheet-row { margin-top: 4px; }
/* THE WAITING ROOM: the whole screen, until somebody lets them in */
.wait-room { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: center; justify-content: center; padding: 24px 16px; background: var(--bg); overflow-y: auto; }
.wait-card { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: 12px; }
.wait-card h1 { margin: 0; font-family: var(--serif); font-size: 28px; font-weight: 400; letter-spacing: -.01em; }
.wait-card .wait-note { margin: 0; font-size: 14.5px; line-height: 1.5; color: var(--muted); }
.wait-card .wait-out { align-self: flex-start; margin-top: 8px; font-size: 13.5px; color: var(--muted); text-decoration: underline; }
.sheet-go:disabled { border-color: var(--hair-2); background: var(--bg); color: var(--dim); }

.sheet-close {
  width: 100%;
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  font-size: 15.5px;
  font-weight: 400;
  color: var(--muted);
}
.sheet-close:hover { color: var(--text); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   A CONVERSATION, AND ITS THREE PERSPECTIVES
   The segmented control belongs to the conversation, not to the app: it switches the view of
   THIS dialogue. In a room there is only the talk, because a room's own circles and memory
   are not mounted per conversation yet.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.seg-wrap {
  position: relative;
  z-index: 5;
  flex: 0 0 auto;
  padding: 2px var(--gut) 10px;
  background: var(--bg);
}
body[data-room="room"] .seg-wrap { display: none; }

.seg {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 0;
}
.segbtn {
  /* 44 and not the 38 the sketch drew: this is the control that switches between the talk,
     the circles and the memory, it is pressed constantly, and it is the width of a third of
     the screen. The track grows with it. */
  min-height: 44px;
  border-radius: var(--pill);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--muted);
  transition: background .2s, color .2s;
}
.segbtn:hover:not(:disabled) { color: var(--text); }
.segbtn.on {
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--hair-2);
}
.segbtn:disabled { color: var(--faint); }

/* Which face of the conversation is on. One rule, one place. */
.convo > .pane { display: none; flex: 1 1 auto; min-height: 0; flex-direction: column; }
body[data-view="talk"] .convo > .chat-pane { display: flex; }
body[data-view="circles"] .convo > .queue-pane,
body[data-view="graph"] .convo > .queue-pane { display: flex; }
/* IN A ROOM, THE ROOM. #roomHost holds the thread shell.js carried onto this screen, and the
   personal engine's own pane goes away: drawing #transcript under a room's name shows you
   your own monk while the nav says you are talking to somebody else, and the composer under
   it sends to the local engine instead of to the room.

   A room's circles and memory are not per-conversation yet, so in a room there is only the
   talk. */
body[data-room="room"] .convo > .queue-pane,
body[data-room="room"] .convo > .chat-pane { display: none; }
body[data-room="room"] .convo > .room-pane { display: flex; }
.room-pane > .chat-thread { display: flex; flex: 1 1 auto; min-height: 0; }

/* and on home, where public/chat/ui.js parks the thread before any room is open, it is not
   drawn at all: it was a second message log and a second Send button under the room list,
   and anything typed into it went nowhere and was wiped without a word. */
.chat-screen > .chat-thread { display: none; }

/* ── the talk ──────────────────────────────────────────────────────────────────────────── */

.transcript {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  /* WhatsApp's rhythm: lines from one side sit 2 px apart, a change of speaker opens 8 */
  gap: 2px;
  padding: 6px 12px 10px;
}
/* an empty conversation sits at the bottom, against the composer, rather than at the top */
.transcript > :first-child { margin-top: auto; }

/* ── ONE TURN ─────────────────────────────────────────────────────────────────────────────
   public/app.js:1310 builds this and the shape is not negotiable:

     <div class="msg me|bot [soft|hijack]" data-turn="N">
       <span class="from">you | monk | interjection</span>
       a raw text node, which IS the message
       <span class="from-circle">from Morning check-in</span>   (circleLink, optional)
       <div class="marks"></div>
     </div>

   THE FIRST TEXT NODE IS THE MESSAGE. app.js:797 finds it with
   [...el.childNodes].find(n => n.nodeType === 3) and splices links into it at character
   offsets. Nothing here may wrap that text in an element or put a text node before it. */
/* A BUBBLE TO WHATSAPP'S MEASURE (9 October 2026): no outline, 16 px type, a 16 px corner, and
   the first line of a run from one side carries the small "tail" corner at the top on its own
   side; the lines after it are fully round. The border is there and transparent, so a voice
   line (data-call, dashed) and an interjection can still draw one. */
.msg {
  max-width: min(82%, 540px);
  align-self: flex-start;
  padding: 6px 10px 7px;
  border: 1px solid var(--theirs-line);
  border-radius: 16px;
  background: var(--theirs-bg);
  color: var(--text);
  font-size: 16px;
  line-height: 1.35;
  letter-spacing: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* yours: the light grey on the right */
.msg.me {
  align-self: flex-end;
  border-top-right-radius: 4px;
  border-color: var(--mine-line);
  background: var(--mine-bg);
  color: var(--mine-text);
}
/* the monk's: white, with its hairline, on the left */
.msg.bot { border-top-left-radius: 4px; }
.msg.me + .msg.me { border-top-right-radius: 16px; }
.msg.bot + .msg.bot { border-top-left-radius: 16px; }
/* a change of speaker opens the gap */
.msg.me + .msg.bot, .msg.bot + .msg.me { margin-top: 6px; }
/* a note the engine made rather than something it said to you: WhatsApp's small centred
   notice, with no time on it */
.msg.soft {
  align-self: center;
  max-width: 92%;
  margin: 6px 0;
  padding: 5px 12px;
  border-color: transparent;
  border-radius: 10px;
  background: none;
  color: var(--muted);
  font-size: 13.5px;
  text-align: center;
}
.msg.soft + .msg.bot { border-top-left-radius: 4px; }
/* an interjection: the engine cut in, and it says so */
.msg.hijack { border-color: var(--accent-line); }
/* a spoken line of a call (public/voicelive/apptools.mjs dashes it) */
.msg[data-call] { border-color: var(--hair-2); }

/* THE TIME INSIDE THE BUBBLE, bottom right, on the last line when there is room and under it
   when there is not, as WhatsApp prints it. Drawn from an attribute so the bubble's text stays
   its words alone: app.js writes data-time on its lines; a line of the kernel chat
   (public/personal/live.js) carries its time as its title. */
.msg[data-time]::after,
.msg[data-kn][title]::after {
  content: attr(data-time);
  float: right;
  margin: 8px -3px -5px 10px;
  font-size: 11px;
  line-height: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--dim);
  white-space: nowrap;
  pointer-events: none;
}
.msg[data-kn][title]::after { content: attr(title); }
.msg.me[data-time]::after, .msg.me[data-kn][title]::after { color: var(--mine-dim); }
.msg.soft[data-time]::after, .msg.soft[data-kn][title]::after { content: none; }

/* who is speaking. In a conversation of two, WhatsApp prints no names: the side says it. Only
   an interjection still names itself, because the side alone would not tell you the engine
   cut in. */
.msg > .from { display: none; }
.msg.hijack > .from {
  display: block;
  margin-bottom: 3px;
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--muted);
  white-space: normal;
}
.msg.bot > .from { color: var(--accent); }
.msg.me > .from { color: var(--mine-dim); }
.msg.hijack > .from { color: var(--hot); }

/* where a turn came from: a circle that reached the threshold and spoke */
.msg > .from-circle {
  display: block;
  margin-top: 5px;
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--muted);
  white-space: normal;
}
.msg.me > .from-circle { color: var(--mine-dim); }

/* THE COMMENTS ON A TURN. Marking an answer good or bad is how the engine is taught, and it
   is the feature he noticed was gone: with no rule at all the marks were three unstyled
   characters welded to the end of the message. */
.msg > .marks {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 6px;
  white-space: normal;
}
.msg > .marks:empty { display: none; }
.msg > .marks > * {
  cursor: pointer;
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--muted);
  opacity: .7;
}
.msg > .marks > *:hover { opacity: 1; color: var(--text); }
.msg.me > .marks > * { color: var(--mine-dim); opacity: .9; }
.msg .marked-good, .msg .mark.good { color: var(--ok); opacity: 1; }
.msg .marked-bad, .msg .mark.bad { color: var(--hot); opacity: 1; }
.msg .cmt { color: var(--accent); opacity: 1; }

/* ── A THING THE MEMORY KNOWS, NAMED INSIDE A TURN ────────────────────────────────────────
   app.js:794 splices <a class="thing" data-id="..."> into the message text wherever the
   engine recognised something it has a node for, and clicking one shows that node in the
   memory. The class had NO rule at all, so the links were the accent colour and nothing
   else: no underline, no cursor, no hint that they could be pressed. A link that does not
   look like a link is a feature nobody finds.

   The underline is the offset kind, under the word rather than through its descenders, so a
   sentence with four linked things in it is still a sentence. */
.msg a, .transcript a { color: var(--accent); }
.msg.me a { color: var(--mine-link); }
.msg a.thing, .transcript a.thing {
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--dim);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  border-radius: 3px;
  transition: text-decoration-color .15s, background .15s;
}
.msg a.thing:hover, .transcript a.thing:hover {
  text-decoration-color: var(--accent);
  background: var(--accent-soft);
}
/* Something the engine THINKS it recognised and will ask about. Dotted, because a guess that
   looks the same as a fact is the one thing a memory must never do. */
.msg a.thing.tentative, .transcript a.thing.tentative {
  text-decoration-style: dotted;
  opacity: .85;
}
/* A CIRCLE NAMED IN A LINE (28 September): a link to the circle rather than to the memory.
   A heavier underline, so the two kinds of link can be told apart before one is pressed. */
.msg a.thing.circle-ref, .transcript a.thing.circle-ref { text-decoration-thickness: 2px; text-decoration-color: var(--accent-line); }
.msg.me a.thing:hover { text-decoration-color: var(--mine-link); }

/* ── MONK'S CONVERSATION IN WHATSAPP'S OWN LOOK (17 October 2026) ─────────────────────────────────────────────────
   The owner, the evening the people's chats went WhatsApp: "why dont I see the whatsapp like UI havent you updated?".
   Those chats (public/chat/ui.js, .chat-msg) had the look; MONK's conversation (this .msg, drawn by public/app.js and
   public/personal/live.js) still had outlined 16 px bubbles on white. It now takes the same tokens as the people's
   chats: their ground under the lines, a white bubble for MONK and the light grey for you, 8 px corners with the small
   tail on the first line of a run, WhatsApp's shadow, the time in the chats' grey, and the day chip (.chat-day, the
   chats' own rule) above the first line of each day. Notes the app makes sit as small centred labels, as in WhatsApp. */
.transcript { background: var(--wa-ground); padding: 8px 10px 10px; }
.msg {
  position: relative;
  max-width: min(82%, 520px);
  padding: 6px 8px 7px 9px;
  border-color: transparent;
  border-radius: 8px;
  background: var(--wa-theirs);
  box-shadow: var(--wa-shadow);
}
.msg.me { border-color: transparent; background: var(--wa-mine); color: var(--text); border-top-right-radius: 0; }
.msg.bot { border-top-left-radius: 0; }
.msg.me + .msg.me { border-top-right-radius: 8px; }
.msg.bot + .msg.bot { border-top-left-radius: 8px; }
.msg.me::before, .msg.bot::before { content: ''; position: absolute; top: 0; width: 8px; height: 13px; background: inherit; }
.msg.bot::before { left: -8px; clip-path: polygon(0 0, 100% 0, 100% 100%); }
.msg.me::before { right: -8px; clip-path: polygon(0 0, 100% 0, 0 100%); }
.msg.me + .msg.me::before, .msg.bot + .msg.bot::before { content: none; }
/* a line after a note or a day chip starts a run again */
.msg.soft + .msg.bot { border-top-left-radius: 0; }
.msg.soft + .msg.bot::before { content: ''; }
.msg.soft {
  align-self: center;
  max-width: 92%;
  margin: 6px 0;
  padding: 5px 12px;
  border-radius: 8px;
  background: var(--wa-chip);
  box-shadow: var(--wa-shadow);
  color: var(--text-2);
  font-size: 12.5px;
}
.msg.soft::before { content: none; }
/* MONK typing, while typed words are checked on the server: on MONK's side, as WhatsApp shows it */
.msg.soft.k-typing { align-self: flex-start; margin: 6px 0 0; background: var(--wa-theirs); color: var(--wa-meta); font-size: 14px; font-style: italic; border-top-left-radius: 0; }
.msg.soft.k-typing::before { content: ''; }
.msg[data-time]::after, .msg[data-kn][title]::after, .msg.me[data-time]::after, .msg.me[data-kn][title]::after { color: var(--wa-meta); }
.msg[data-call] { border-color: var(--hair-2); }
.transcript > .chat-day:first-child { margin-top: auto; }

/* what speech has heard so far, before it commits to a turn */
.interim {
  align-self: flex-start;
  max-width: min(80%, 540px);
  padding: 9px 14px 10px;
  border: 1px dashed var(--hair-2);
  border-radius: var(--r4);
  color: var(--muted);
  font-size: 15.5px;
  font-style: italic;
  opacity: .75;
}

/* the engine's own note, and the picker it can carry */
/* .vnote is the voice module's own status line, drawn inside its controls; it is a sentence,
   not a card, and this rule was giving it a border, a background and 16 px of side margin. */
.engine-note {
  margin: 0 var(--gut) 8px;
  padding: 10px 13px;
  border: 1px solid var(--hair);
  border-radius: var(--r2);
  background: var(--panel-2);
  font-size: 13px;
  letter-spacing: 0;
  color: var(--muted);
}
.engine-note .x { float: right; color: var(--dim); cursor: pointer; }
.foreign { font-style: italic; color: var(--muted); }

/* the breakdown behind a turn, opened from its own context menu */
.trace {
  align-self: stretch;
  margin: 0 2px;
  padding: 10px 12px;
  border: 1px solid var(--hair);
  border-radius: var(--r2);
  background: var(--panel);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.tr-steps { display: flex; flex-direction: column; gap: 2px; }
.tr-head, .tr-step, .tr-out { display: flex; gap: 10px; }
.tr-total { display: flex; gap: 10px; color: var(--text); }
/* "processed in 11.30 ms - 18 steps": a real control, switched on behind the cog, that opens
   the breakdown of how an answer was formed. It is a button, so it carries the 44 px floor,
   and it was inheriting a button's centred text and the accent colour: a bright amber banner
   across the middle of the conversation between every turn. It belongs to the turn above it,
   so it sits under that turn's edge and says nothing louder than a timestamp. */
.trace-toggle {
  align-self: flex-start;
  margin-top: -4px;
  padding: 0 6px;
  text-align: left;
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--dim);
}
.trace-toggle:hover { color: var(--muted); }
.trace-toggle.tick { color: var(--muted); }

/* ── THE DOCK ────────────────────────────────────────────────────────────────────────────
   The ready buttons and the composer under the conversation, on a tone of their own (9 October:
   "it should have a different tone than the actual chat area"), the way WhatsApp's bar is. */
.dock {
  flex: 0 0 auto;
  background: var(--dock);
  border-top: 1px solid var(--hair);
}

/* THE ANSWERS UNDER THE QUESTION (29 September), the way the test bench shows them: an answer is a
   pill, a way out is a dashed one, a date is the phone's own date wheel under a pill.
   ONE ROW, ALWAYS (9 October: "a single line always, it should be able to scroll when
   needed"): it never wraps; with more buttons than fit it scrolls sideways under the thumb,
   with no scrollbar, and the edge that has more behind it fades (data-fade, set by app.js). */
.quick {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  padding: 2px 8px 0;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.quick::-webkit-scrollbar { display: none; }
.quick[data-fade="end"] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
}
.quick[data-fade="start"] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 36px);
  mask-image: linear-gradient(to right, transparent, #000 36px);
}
.quick[data-fade="start end"] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 36px, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 36px, #000 calc(100% - 36px), transparent);
}
.quick .about {
  flex: 0 0 auto;
  max-width: 70%;
  padding-left: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: var(--muted);
}
/* A CHIP the size of WhatsApp's quick replies: a 34 px pill, drawn as ::before inside a 44 px
   box, so the finger gets 44 and the eye gets a small pill. */
.quick button,
.quick .ans {
  position: relative;
  isolation: isolate;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  height: 44px;
  min-height: 44px;
  padding: 0 14px;
  border: 0;
  background: none;
  font-size: 14.5px;
  font-weight: 400;
  white-space: nowrap;
  color: var(--text);
  cursor: pointer;
}
.quick button::before,
.quick .ans::before {
  content: '';
  position: absolute;
  inset: 5px 0;
  z-index: -1;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--chip);
}
.quick button:hover::before,
.quick .ans:hover::before { background: var(--panel-3); }
.quick .ans.skip { color: var(--muted); }
.quick .ans.skip::before { border-style: dashed; background: transparent; }
.quick .ans.idle::before { background: transparent; }
/* one of several chosen, before "Tamam" (public/personal/live.js toggles .on) */
.quick .ans.on { color: var(--accent); }
.quick .ans.on::before { border-color: var(--text); }
/* "Beni şimdi ara", the owner's ring-me-now test (public/personal/live.js): first in the row, not one of MONK's answers */
.quick .ring-now { font-weight: 500; }
.quick .ans.date::before { background: transparent; }
.quick .ans.date::after { content: ""; width: 7px; height: 7px; margin-left: 9px; border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor; transform: translateY(-2px) rotate(45deg); opacity: .7; }
.quick .ans.date input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }

/* ── the composer ─────────────────────────────────────────────────────────────────────────
   One pill with the round buttons beside it, at WhatsApp's size (9 October: "The typing area is
   massive; it needs to be like WhatsApp size exactly"): a 36 px field in 16 px type (16 px also
   stops iOS zooming on focus) that grows with the words to five lines, in a 44 px row. The
   field never loses focus on send: app.js puts it back, because on a phone a blurred field
   closes the keyboard and you have to tap twice to say a second thing.

   THE HOME INDICATOR'S INSET is under the composer only while the keyboard is closed. With the
   keyboard open the keys cover that part of the screen, and the inset left a gap of 34 px
   between the keys and the field ("There is an unnecessary gap between the keyboard and the
   typing area"). app.js sets body[data-kb="open"] from the visual viewport. */
.composer {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 4px;
  padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
}
body[data-kb="open"] .composer,
body[data-kb="open"] .chat-composer { padding-bottom: 4px; }
/* while the keyboard is up the column is the part of the screen that is visible, exactly */
body[data-kb="open"] main {
  top: var(--app-top, 0px);
  bottom: auto;
  height: var(--app-h, 100%);
}
/* THE WHOLE PILL IS THE FIELD. The padding is on the textarea and the textarea fills the
   pill, so every pixel inside it puts the caret in the field (a dead border inside the pill
   once swallowed what was typed after a tap on it). 4 px above and below centre one line on
   the 44 px buttons; more lines grow it upwards, the buttons staying at the bottom. */
.field {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-width: 0;
  min-height: 36px;
  margin: 4px 0;
  border-radius: 18px;
  background: var(--dock-field);
  /* the website's hairline pill, drawn inside the box so the field stays 36 px */
  box-shadow: inset 0 0 0 1px var(--hair-2);
  overflow: hidden;
}
.field:focus-within { box-shadow: inset 0 0 0 1px var(--dim); }
.field textarea {
  flex: 1 1 auto;
  display: block;
  width: 100%;
  min-width: 0;
  height: 36px;
  min-height: 36px;
  margin: 0;
  padding: 8px 14px;
  border: 0;
  background: none;
  font-size: 16px;
  line-height: 20px;
  color: var(--text);
  resize: none;
  overflow-y: hidden;
  overflow-wrap: anywhere;
}
.field textarea:focus { outline: none; }
.field textarea::placeholder { color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-input::placeholder { color: var(--dim); }

/* Both of these are drawn by app.js as an inline SVG that inherits currentColor, so this
   gives them a box and a colour and never a glyph: a ::before here would be a second icon
   stacked on the real one. A 44 px box for the finger, a 36 px disc for the eye: the colour is
   clipped to the content box inside 4 px of padding. */
.cbtn {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 4px;
  border-radius: 50%;
  background-clip: content-box;
  line-height: 0;
}
.cbtn svg { display: block; }
.speech { color: var(--muted); }
.speech:hover { color: var(--text); }
.speech[aria-pressed="true"], .speech.on { color: var(--text); }
/* send is a line icon in ink, as every button here is ink and never a fill */
.send { color: var(--text); }
.send svg { width: 20px; height: 20px; margin: auto; }
.send:disabled { color: var(--faint); }

/* THE CALL BUTTON IN THE HEADER (9 October), where WhatsApp has its call icon: a line icon on
   the bar, a black disc while a call is on and a quiet pulse while MONK calls (set where the
   call lives, public/voicelive/apptools.mjs and public/app.js). The missed count
   sits on its corner. Your own MONK's call: a colleague's room shows none. */
.nav-acts { display: inline-flex; align-items: center; gap: 2px; }
.nav-acts #callBtn { position: relative; color: var(--text); }
.nav-acts #callBtn svg { width: 21px; height: 21px; }
body[data-room="room"] #callBtn { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   A REAL ROOM  -  public/chat/ui.js mounts its own list and thread into the page. The list
   goes into the home screen's Sohbetler group; the thread goes into the talk pane.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.chat-screen { display: flex; flex-direction: column; min-height: 0; }
.chat-rooms { display: block; }
/* The room list lives inside the home screen's grouped list, so a room row IS a list row. */
.chat-room {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 64px;
  padding: 10px 14px;
  text-align: left;
  color: var(--text);
}
.chat-room + .chat-room::before {
  content: '';
  position: absolute;
  top: 0;
  left: 66px;
  right: 0;
  height: 1px;
  background: var(--hair);
}
.chat-room:hover { background: var(--panel-3); }
.chat-room.on { background: var(--panel-3); }
.room-face {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  color: var(--text);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0;
}
.room-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.room-top { display: flex; align-items: baseline; gap: 10px; }
.room-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15.5px;
  font-weight: 400;
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.room-when { flex: 0 0 auto; font-size: 12px; letter-spacing: 0; color: var(--dim); }
.room-last {
  font-size: 14px;
  line-height: 1.35;
  letter-spacing: 0;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.room-unread {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 11px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0;
}
/* An empty status line is not a status line. It sits above the room list, so when it has
   nothing to say it was 36 pixels of padding inside the rounded rectangle, above the first
   room, which is the gap he was looking at. */
.chat-note:empty, .group-empty:empty, .work-note:empty { display: none; }
.chat-note, .group-empty {
  padding: 18px 16px;
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
  text-align: center;
}

/* the thread, which takes the talk pane's place when the conversation is a room */
.chat-thread { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.thread-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px var(--gut) 8px;
}
/* THE ROOM'S OWN HEADER IS THE NAV BAR'S HEADER. public/chat/ui.js draws its own head with
   the room's name and a members line, and the stack draws a nav bar above it with the same
   name: the room was announcing itself twice, and the second one sat over the first message
   for ever. The way back is the nav bar's too.
   What the head knew that the nav did not - whether there is a monk in this room - is
   written into the nav's own subtitle by shell.js instead, because it is a claim about
   privacy and it has to stay visible somewhere. */
.thread-head { display: none; }
.thread-back { display: none; }
.thread-title { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 400; }
.thread-who { font-size: 12.5px; letter-spacing: 0; color: var(--muted); }

/* Who is in here, and what each of them is. "This room has a monk in it" is the whole privacy
   claim, and a claim you have to infer from a colour is not one anybody can check. */
/* A chip per member, pinned above the first message and never changing. Four static lines
   over the conversation is four lines of the conversation you cannot see. The fact that
   matters, that a monk is in the room, is in the nav bar's subtitle now, which is one line
   and is read once. The chips stay in the DOM: a room screen that wants to show who is here
   can unhide them, and nothing has to be rebuilt to do it. */
.chat-members { display: none; }
.chat-members.show {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 var(--gut) 10px;
}
.chat-member {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border: 1px solid var(--hair);
  border-radius: var(--r1);
  background: var(--sunk);
  font-size: 11.5px;
  letter-spacing: 0;
}
.member-name { color: var(--text); }
.member-kind { color: var(--dim); }
.chat-member.is-monk { background: var(--accent-soft); border-color: var(--accent-line); }
.chat-member.is-monk .member-kind { color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   A CONVERSATION, WHATSAPP'S, IN WHITE (17 October 2026, the owner: "I really want a WhatsApp like UI, all the
   features ... the same exact user interface, however clean white style"). public/chat/ui.js draws the parts; this gives
   them WhatsApp's shapes and sizes in this app's ink-on-white: a quiet grey ground under the thread, white bubbles for
   the others and a light grey one for you, the tail on the first bubble of a run, the time and the ticks in the bubble's
   corner, a chip for each day, the composer with +, the field, the camera and the microphone.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

:root {
  --wa-ground: #f4f4f2;          /* under the bubbles, where WhatsApp has its wallpaper */
  --wa-theirs: #ffffff;
  --wa-mine: #e8e8e5;
  --wa-shadow: 0 1px .5px rgba(17, 17, 17, .13);
  --wa-meta: #8a8a86;            /* the time and the grey ticks */
  --wa-read: #191919;            /* the two ticks once read: dark, where WhatsApp has blue */
  --wa-chip: #ffffff;
  --wa-quote: rgba(0, 0, 0, .05);
  --wa-scrim: rgba(17, 17, 17, .28);
  --wa-rec: #d23c3c;             /* the red dot while the microphone is on, WhatsApp's own */
  --wa-pill: rgba(255, 255, 255, .9);   /* the time on a photo, how far a file has gone, the play disc on a video */
  --wa-line-bg: rgba(255, 255, 255, .7);   /* the band of the unread line */
  /* a group's sender names: six muted inks, never blue */
  --who0: #8a4b1f; --who1: #2f6b4f; --who2: #7a2f5e; --who3: #6b5a12; --who4: #8c2f2f; --who5: #4a4a4a;
}
:root[data-theme="dark"] {
  --wa-ground: #0b0b0b;
  --wa-theirs: #1f1f1f;
  --wa-mine: #2c2c2a;
  --wa-shadow: 0 1px .5px rgba(0, 0, 0, .6);
  --wa-meta: #8c8c88;
  --wa-read: #f2f2f2;
  --wa-chip: #1f1f1f;
  --wa-quote: rgba(255, 255, 255, .07);
  --wa-scrim: rgba(0, 0, 0, .55);
  --wa-rec: #e05a5a;
  --wa-pill: rgba(24, 24, 24, .88);
  --wa-line-bg: rgba(255, 255, 255, .06);
  --who0: #e0a77a; --who1: #86c9a5; --who2: #d99ac2; --who3: #d6c378; --who4: #e69a9a; --who5: #c2c2c2;
}

/* ── the icons, drawn by the stylesheet from a class (the screen never writes markup) ─────── */
.ic {
  display: inline-block;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask: var(--i) center / contain no-repeat;
  mask: var(--i) center / contain no-repeat;
  vertical-align: middle;
}
.ic-plus { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'><path d='M12 5v14M5 12h14'/></svg>"); }
.ic-camera { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><path d='M3.5 8.5A1.5 1.5 0 0 1 5 7h2.6l1.5-2.2h5.8L16.4 7H19a1.5 1.5 0 0 1 1.5 1.5v9.5a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 18z'/><circle cx='12' cy='12.8' r='3.6'/></svg>"); }
.ic-mic { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'><path d='M12 3.5a3 3 0 0 0-3 3v5a3 3 0 0 0 6 0v-5a3 3 0 0 0-3-3z'/><path d='M5.5 11.5v.5a6.5 6.5 0 0 0 13 0v-.5M12 18.5V21M8.5 21h7'/></svg>"); }
.ic-send { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round' stroke-linecap='round'><path d='M21 3L3 10.2l7.6 3.2L13.8 21z'/><path d='M21 3l-10.4 10.4'/></svg>"); }
.ic-close { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'><path d='M6 6l12 12M18 6L6 18'/></svg>"); }
.ic-trash { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6.5h16M9.5 6.5V5a1.5 1.5 0 0 1 1.5-1.5h2A1.5 1.5 0 0 1 14.5 5v1.5M6.5 6.5l.9 12.1a2 2 0 0 0 2 1.9h5.2a2 2 0 0 0 2-1.9l.9-12.1'/></svg>"); }
.ic-photo { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><rect x='3.5' y='5' width='17' height='14' rx='2'/><circle cx='9' cy='10' r='1.6'/><path d='M20.5 16l-5-5-8.5 8'/></svg>"); }
.ic-video { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><rect x='3' y='6.5' width='12.5' height='11' rx='2'/><path d='M15.5 10.5l5.5-3v9l-5.5-3z'/></svg>"); }
.ic-doc { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><path d='M7 3.5h7l4.5 4.5v12H5.5V3.5z'/><path d='M14 3.5V8h4.5M8.5 12.5h7M8.5 16h5'/></svg>"); }
.ic-play { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7.5 5v14l11-7z' fill='black'/></svg>"); }
.ic-pause { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6.5 5h4v14h-4zM13.5 5h4v14h-4z' fill='black'/></svg>"); }
.ic-play-big { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9.5 7.5v9l7-4.5z' fill='black'/></svg>"); }
.ic-down { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>"); }
.ic-chev { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M7 10l5 5 5-5'/></svg>"); }
.ic-reply { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M10 7l-5.5 5 5.5 5'/><path d='M4.5 12H14a5.5 5.5 0 0 1 5.5 5.5V19'/></svg>"); }
.ic-copy { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><rect x='8.5' y='8.5' width='11' height='11' rx='2'/><path d='M15.5 8.5V6A1.5 1.5 0 0 0 14 4.5H6A1.5 1.5 0 0 0 4.5 6v8A1.5 1.5 0 0 0 6 15.5h2.5'/></svg>"); }
.ic-note { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><path d='M6 4h12a2.5 2.5 0 0 1 2.5 2.5v7A2.5 2.5 0 0 1 18 16h-7l-4 4v-4H6a2.5 2.5 0 0 1-2.5-2.5v-7A2.5 2.5 0 0 1 6 4z'/></svg>"); }
.ic-edit { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><path d='M15.5 4.5l4 4L9 19l-4.5 1 1-4.5z'/></svg>"); }
.ic-info { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'><circle cx='12' cy='12' r='8.5'/><path d='M12 11v5M12 7.8v.4'/></svg>"); }
.ic-open, .ic-save { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4v11M7.5 10.5L12 15l4.5-4.5M5 19.5h14'/></svg>"); }
.ic-back { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M15 5l-7 7 7 7'/></svg>"); }
.ic-gone { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5'><circle cx='12' cy='12' r='8'/><path d='M6.4 6.4l11.2 11.2'/></svg>"); }
.ic-tasks { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6.5l1.5 1.5 3-3M4 13.5l1.5 1.5 3-3M11.5 7h8.5M11.5 14h8.5'/></svg>"); }
.ic-leave { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M13.5 4.5h-7a1 1 0 0 0-1 1v13a1 1 0 0 0 1 1h7M10.5 12h10M17 8.5l3.5 3.5-3.5 3.5'/></svg>"); }
.ic-add { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'><circle cx='10' cy='8.5' r='3.5'/><path d='M3.5 19.5a6.5 6.5 0 0 1 13 0M19 8v6M16 11h6'/></svg>"); }
.ic-star { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linejoin='round'><path d='M12 4l2.4 5 5.4.6-4 3.7 1.1 5.4L12 16l-4.9 2.7 1.1-5.4-4-3.7 5.4-.6z'/></svg>"); }
.ic-shut { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'><circle cx='12' cy='12' r='8.5'/><path d='M9 9l6 6M15 9l-6 6'/></svg>"); }
.ic-dot { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='3' fill='black'/></svg>"); }

/* ── the thread ──────────────────────────────────────────────────────────────────────────── */
.chat-thread { position: relative; background: var(--wa-ground); }
.chat-messages {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px 10px;
  background: var(--wa-ground);
  overflow-anchor: none;          /* a photo loading above must not move what you are reading */
}
.chat-messages > :first-child { margin-top: auto; }

/* a chip for each day, and the line over the first unread message */
.chat-day, .chat-unread-line {
  display: flex;
  justify-content: center;
  margin: 10px 0 6px;
  pointer-events: none;
}
.chat-day > span, .chat-unread-line > span {
  padding: 5px 12px;
  border-radius: 8px;
  background: var(--wa-chip);
  box-shadow: var(--wa-shadow);
  font-size: 12.5px;
  color: var(--text-2);
  letter-spacing: 0;
}
.chat-unread-line { margin: 8px -10px; background: var(--wa-line-bg); padding: 4px 0; }
.chat-unread-line > span { box-shadow: none; background: transparent; font-weight: 600; }

/* one message: the row, and the bubble in it */
.chat-msg {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: none;
  padding: 0;
  border: 0;
  background: none;
  transition: transform .18s var(--ease);
  touch-action: pan-y;
}
.chat-msg.mine { align-items: flex-end; }
.chat-msg.tail { margin-top: 6px; }
.msg-bubble {
  position: relative;
  max-width: min(82%, 520px);
  min-width: 72px;
  padding: 6px 8px 7px 9px;
  border-radius: 8px;
  background: var(--wa-theirs);
  box-shadow: var(--wa-shadow);
  color: var(--text);
  -webkit-touch-callout: none;
}
.chat-msg.mine .msg-bubble { background: var(--wa-mine); }
/* the tail, on the first of a run: a small corner pointing at whoever said it */
.chat-msg.tail .msg-bubble::before {
  content: '';
  position: absolute;
  top: 0;
  width: 8px;
  height: 13px;
  background: inherit;
}
.chat-msg.theirs.tail .msg-bubble { border-top-left-radius: 0; }
.chat-msg.theirs.tail .msg-bubble::before { left: -8px; clip-path: polygon(0 0, 100% 0, 100% 100%); }
.chat-msg.mine.tail .msg-bubble { border-top-right-radius: 0; }
.chat-msg.mine.tail .msg-bubble::before { right: -8px; clip-path: polygon(0 0, 100% 0, 0 100%); }
.chat-msg.flash .msg-bubble { animation: wa-flash 1.2s ease; }
@keyframes wa-flash { 0%, 60% { box-shadow: 0 0 0 3px rgba(17, 17, 17, .18); } 100% { box-shadow: var(--wa-shadow); } }

/* the sender's name on a group's bubble, and the monk's mark beside it */
.msg-who { display: flex; align-items: baseline; gap: 6px; margin-bottom: 2px; font-size: 13px; letter-spacing: 0; }
.msg-who[hidden] { display: none; }
.msg-from { font-weight: 600; color: var(--text-2); }
.msg-from[data-face="0"], .q-from[data-face="0"], .rb-from[data-face="0"] { color: var(--who0); }
.msg-from[data-face="1"], .q-from[data-face="1"], .rb-from[data-face="1"] { color: var(--who1); }
.msg-from[data-face="2"], .q-from[data-face="2"], .rb-from[data-face="2"] { color: var(--who2); }
.msg-from[data-face="3"], .q-from[data-face="3"], .rb-from[data-face="3"] { color: var(--who3); }
.msg-from[data-face="4"], .q-from[data-face="4"], .rb-from[data-face="4"] { color: var(--who4); }
.msg-from[data-face="5"], .q-from[data-face="5"], .rb-from[data-face="5"] { color: var(--who5); }
.msg-kind { font-size: 11px; color: var(--dim); letter-spacing: .02em; }
.chat-msg.is-monk .msg-bubble { box-shadow: inset 0 0 0 1px var(--hair-2), var(--wa-shadow); }

/* a reply, quoted inside the bubble; a press on it goes to the message it answers */
.msg-quote {
  display: flex;
  flex-direction: column;
  gap: 1px;
  width: 100%;
  margin: 1px 0 5px;
  padding: 5px 9px 6px;
  border: 0;
  border-left: 3.5px solid var(--text-2);
  border-radius: 6px;
  background: var(--wa-quote);
  text-align: left;
  color: var(--text);
  cursor: pointer;
}
.msg-quote[hidden] { display: none; }
.q-from { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.q-text { display: flex; align-items: center; gap: 4px; font-size: 13.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-text .ic { width: 15px; height: 15px; }

/* the words; a spacer at the end of the last line keeps them clear of the time in the corner */
.msg-body { font-size: 16px; line-height: 1.32; letter-spacing: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg-body[hidden] { display: none; }
.msg-body::after { content: ''; display: inline-block; width: 50px; }
.chat-msg.mine .msg-body::after { width: 70px; }
.chat-msg[data-edited="1"] .msg-body::after { width: 100px; }
.chat-msg.mine[data-edited="1"] .msg-body::after { width: 122px; }
.msg-body.gone { display: flex; align-items: center; gap: 5px; font-style: italic; color: var(--muted); opacity: 1; }
.msg-body.gone .ic { width: 16px; height: 16px; }
.msg-body.gone::after { width: 40px; }
.msg-link { color: inherit; text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; }

/* the time, an edit, and my ticks, in the bubble's bottom corner */
.msg-meta {
  position: absolute;
  right: 8px;
  bottom: 4px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  line-height: 1;
  color: var(--wa-meta);
  white-space: nowrap;
  pointer-events: none;
}
.msg-edited { font-size: 11px; opacity: 1; margin-right: 2px; }
.msg-when { color: var(--wa-meta); }

/* the ticks: a clock on its way, one tick on the server, two on their phone, two dark once read, a mark if it did not go */
.msg-state { display: inline-flex; align-items: center; margin: 0; opacity: 1; font-size: 0; color: var(--wa-meta); }
.msg-state .state-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.state-mark {
  display: inline-block;
  width: 16px;
  height: 15px;
  background: currentColor;
  -webkit-mask: var(--i) center / contain no-repeat;
  mask: var(--i) center / contain no-repeat;
}
.msg-state[data-state="pending"] .state-mark { width: 13px; --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='8'/><path d='M12 7.5v4.8l3 1.8'/></svg>"); }
.msg-state[data-state="sent"] .state-mark { --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12.5l4.2 4.2L19 7'/></svg>"); }
.msg-state[data-state="delivered"] .state-mark,
.msg-state[data-state="read"] .state-mark { width: 18px; --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2 12.5l4.2 4.2L16 7M10.5 15.8l.9.9L21.2 7'/></svg>"); }
.msg-state[data-state="read"] { color: var(--wa-read); }
.msg-state[data-state="failed"] { color: var(--hot); }
.msg-state[data-state="failed"] .state-mark { width: 14px; --i: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='8.5'/><path d='M12 7.5v5.5M12 16.2v.3'/></svg>"); }
.msg-state.sm .state-mark { width: 17px; height: 14px; }

/* a message that did not go: said under it, with the way to try again */
.msg-fail { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 3px 4px 2px; font-size: 12.5px; color: var(--hot); }
.msg-fail[hidden] { display: none; }
.msg-retry { min-height: 30px; padding: 0 12px; border: 1px solid var(--hot-line); border-radius: 15px; background: var(--bg); font-size: 12.5px; color: var(--hot); }
.msg-why { flex-basis: 100%; font-size: 11.5px; color: var(--muted); }
.msg-fail-say { font-weight: 600; }

/* the small chevron in a bubble's corner, for a mouse (a phone uses press and hold) */
.msg-more {
  position: absolute;
  top: 2px;
  right: 2px;
  display: none;
  width: 28px;
  min-width: 0;
  height: 22px;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0 6px 0 10px;
  background: linear-gradient(to left, var(--wa-theirs) 60%, transparent);
  color: var(--muted);
}
.chat-msg.mine .msg-more { background: linear-gradient(to left, var(--wa-mine) 60%, transparent); }
.msg-more .ic { width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) { .msg-bubble:hover .msg-more { display: inline-flex; align-items: center; justify-content: center; } }

/* ── photos, videos, voice messages and documents in a bubble ────────────────────────────── */
.msg-media[hidden] { display: none; }
.chat-msg.k-image .msg-bubble, .chat-msg.k-video .msg-bubble { padding: 3px 3px 4px; }
.chat-msg.k-image .msg-who, .chat-msg.k-video .msg-who, .chat-msg.k-image .msg-quote, .chat-msg.k-video .msg-quote { margin-left: 6px; margin-right: 6px; width: auto; }
.chat-msg.k-image .msg-body, .chat-msg.k-video .msg-body { padding: 5px 6px 2px; }
.media-img, .media-vid {
  position: relative;
  display: block;
  width: min(66vw, 280px);
  padding: 0;
  border: 0;
  border-radius: 6px;
  overflow: hidden;
  background: var(--panel-3);
  cursor: pointer;
}
.media-pic { display: block; width: 100%; max-height: 340px; min-height: 120px; object-fit: cover; }
.media-wait { display: block; width: 100%; height: 200px; background: var(--panel-3); }
.media-going {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  padding: 6px 12px;
  border-radius: 16px;
  background: var(--wa-pill);
  font-size: 13px;
  color: var(--text);
}
.media-vid .ic-play-big {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 52px;
  height: 52px;
  margin: -26px 0 0 -26px;
  border-radius: 50%;
  background: var(--wa-pill);
  -webkit-mask: none;
  mask: none;
}
.media-vid .ic-play-big::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--text);
  -webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9.5 7.5v9l7-4.5z' fill='black'/></svg>") center / 60% no-repeat;
  mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9.5 7.5v9l7-4.5z' fill='black'/></svg>") center / 60% no-repeat;
}
/* no caption under a photo: the time sits on it, on a white pill */
.chat-msg.k-image .msg-body[hidden] ~ .msg-meta,
.chat-msg.k-video .msg-body[hidden] ~ .msg-meta {
  right: 9px;
  bottom: 10px;
  padding: 3px 6px;
  border-radius: 10px;
  background: var(--wa-pill);
}

/* a voice message: play, how far it has got, its length, and the face of whoever spoke it */
.voice { display: flex; align-items: center; gap: 8px; width: min(64vw, 260px); padding: 4px 0 14px; }
.v-play { position: relative; flex: 0 0 auto; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text); }
.v-play .ic { width: 26px; height: 26px; }
.v-play .ic-pause, .voice.on .v-play .ic-play { display: none; }
.voice.on .v-play .ic-pause { display: inline-block; }
.v-play:disabled { color: var(--faint); }
.v-track { position: relative; flex: 1 1 auto; height: 18px; cursor: pointer; }
.v-track::before { content: ''; position: absolute; left: 0; right: 0; top: 8px; height: 3px; border-radius: 2px; background: var(--hair-2); }
.v-fill { position: absolute; left: 0; top: 8px; height: 3px; width: 0; border-radius: 2px; background: var(--text-2); }
.v-knob { position: absolute; top: 3px; left: 0; width: 13px; height: 13px; margin-left: -6px; border-radius: 50%; background: var(--text); }
.v-time { position: absolute; left: 52px; bottom: 3px; font-size: 11px; color: var(--wa-meta); }
.voice { position: relative; }
.v-face { position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: var(--bg); box-shadow: inset 0 0 0 1px var(--hair-2); font-size: 15px; color: var(--text); }
.v-face .ic { position: absolute; right: -3px; bottom: -2px; width: 16px; height: 16px; color: var(--text-2); }
.chat-msg.mine .voice { flex-direction: row; }
.chat-msg.theirs .v-face { order: -1; }
.chat-msg.theirs .v-time { left: 100px; }
.v-audio { display: none; }

/* a document: its kind, its name and its size */
.doc {
  display: flex;
  align-items: center;
  gap: 10px;
  width: min(66vw, 280px);
  margin: 1px 0 16px;
  padding: 10px;
  border-radius: 6px;
  background: var(--wa-quote);
  color: var(--text);
  text-decoration: none;
}
.doc-ico .ic { width: 18px; height: 18px; margin-bottom: 3px; }
.doc-ico {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: flex-end;
  justify-content: center;
  width: 32px;
  height: 40px;
  padding-bottom: 5px;
  border-radius: 3px 10px 3px 3px;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--text-2);
}
.doc-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.doc-name { font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-sub { font-size: 12px; color: var(--muted); }

/* the way back down when somebody writes while you read further up */
.chat-jump {
  position: absolute;
  right: 12px;
  bottom: 70px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
  color: var(--muted);
}
.chat-jump[hidden] { display: none; }
.jump-n:empty { display: none; }
.jump-n { position: absolute; top: -6px; right: -4px; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; background: var(--accent); color: var(--accent-ink); font-size: 11.5px; line-height: 20px; text-align: center; }

/* ── what you answer or change, over the field ───────────────────────────────────────────── */
.chat-replybar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 0 10px;
  background: var(--dock);
  border-top: 1px solid var(--hair);
}
.chat-replybar[hidden] { display: none; }
.chat-replybar + .chat-composer { border-top: 0; }
.rb-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px 10px;
  border-left: 3.5px solid var(--text-2);
  border-radius: 6px;
  background: var(--wa-quote);
}
.rb-from { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.chat-replybar[data-mode="edit"] .rb-from { color: var(--text); }
.rb-line { font-size: 13.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rb-close { flex: 0 0 auto; width: 40px; height: 40px; border: 0; background: none; color: var(--muted); }

/* ── the composer: +, the field, the camera, the microphone or send ──────────────────────── */
.chat-composer {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 2px;
  padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair);
  background: var(--dock);
}
.chat-composer > button {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text);
}
.chat-composer > button .ic { width: 24px; height: 24px; }
.chat-attach { color: var(--text); font-size: 0; }
.chat-attach[hidden] { display: none; }
.chat-field {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-width: 0;
  min-height: 36px;
  margin: 4px 2px;
  border-radius: 18px;
  background: var(--dock-field);
  box-shadow: inset 0 0 0 1px var(--hair-2);
  overflow: hidden;
}
.chat-field:focus-within { box-shadow: inset 0 0 0 1px var(--dim); }
.chat-input {
  flex: 1 1 auto;
  display: block;
  width: 100%;
  min-width: 0;
  height: 36px;
  min-height: 36px;
  max-height: 120px;
  margin: 0;
  padding: 8px 14px;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font: inherit;
  font-size: 16px;
  line-height: 20px;
  color: var(--text);
  resize: none;
  overflow-y: auto;
  overflow-wrap: anywhere;
}
.chat-input:focus { outline: none; }
/* empty: the camera and the microphone; with words: the send arrow */
.chat-send .ic-send { display: none; }
.chat-composer[data-mode="send"] .chat-send .ic-send { display: inline-block; }
.chat-composer[data-mode="send"] .chat-send .ic-mic { display: none; }
.chat-composer[data-mode="send"] .chat-cam { display: none; }
.chat-send { touch-action: none; }

/* while the microphone is on: the bin, the red dot, how long, and "slide to cancel" or send */
.chat-rec { flex: 1 1 auto; display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 4px; }
.chat-rec[hidden] { display: none; }
.chat-composer[data-rec="hold"] > .chat-attach,
.chat-composer[data-rec="hold"] > .chat-field,
.chat-composer[data-rec="hold"] > .chat-cam,
.chat-composer[data-rec="locked"] > .chat-attach,
.chat-composer[data-rec="locked"] > .chat-field,
.chat-composer[data-rec="locked"] > .chat-cam,
.chat-composer[data-rec="locked"] > .chat-send { display: none; }
.chat-composer[data-rec="hold"] > .chat-send { color: var(--wa-rec); transform: scale(1.25); }
.rec-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--wa-rec); animation: wa-blink 1s steps(2, start) infinite; }
@keyframes wa-blink { to { visibility: hidden; } }
.rec-time { min-width: 38px; font-size: 16px; font-variant-numeric: tabular-nums; color: var(--text); }
.rec-hint { flex: 1 1 auto; text-align: center; font-size: 14px; color: var(--muted); }
.rec-hint[hidden] { display: block; visibility: hidden; }
.rec-bin, .rec-send { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--text); }
.chat-composer[data-rec="hold"] .rec-bin, .chat-composer[data-rec="hold"] .rec-send { display: none; }
.rec-send { margin-left: auto; }

/* the + list, over the composer */
.chat-attach-menu {
  position: absolute;
  left: 8px;
  bottom: calc(56px + env(safe-area-inset-bottom));
  z-index: 5;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  padding: 6px 0;
  border-radius: 14px;
  background: var(--bg);
  box-shadow: 0 6px 24px rgba(0, 0, 0, .16), 0 0 0 1px var(--hair);
}
.chat-attach-menu[hidden] { display: none; }
.am-row { display: flex; align-items: center; gap: 14px; min-height: 48px; padding: 0 18px; border: 0; background: none; text-align: left; font-size: 16px; color: var(--text); }
.am-row:hover { background: var(--panel-3); }
.am-row .ic { color: var(--text-2); }
.am-label { flex: 1 1 auto; }
.chat-file { display: none; }

/* ── the layers: a message's menu, a picked file before it goes, a photo full size, a chat's info ── */
.msg-menu, .chat-preview, .chat-viewer, .chat-info {
  position: fixed;
  inset: 0;
  z-index: 60;
}
.msg-menu[hidden], .chat-preview[hidden], .chat-viewer[hidden], .chat-info[hidden] { display: none; }
.layer-scrim { position: absolute; inset: 0; background: var(--wa-scrim); }
.layer-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 80%;
  overflow-y: auto;
  padding: 8px 0 calc(10px + env(safe-area-inset-bottom));
  border-radius: 16px 16px 0 0;
  background: var(--bg);
  box-shadow: 0 -4px 24px rgba(0, 0, 0, .12);
}
@media (min-width: 700px) {
  .layer-panel { left: 50%; right: auto; bottom: auto; top: 50%; width: 360px; transform: translate(-50%, -50%); border-radius: 16px; }
}
.layer-title { padding: 12px 18px 8px; font-size: 15px; font-weight: 600; color: var(--text); }
.menu-quote { margin: 4px 14px 8px; padding: 10px 12px; border-radius: 10px; background: var(--wa-ground); font-size: 14.5px; color: var(--text-2); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.menu-row { display: flex; align-items: center; justify-content: space-between; width: 100%; min-height: 50px; padding: 0 18px; border: 0; border-top: 1px solid var(--hair); background: none; font-size: 16px; color: var(--text); text-align: left; }
.menu-row:hover { background: var(--panel-3); }
.menu-row.danger { color: var(--hot); }
.menu-row .ic { width: 20px; height: 20px; color: inherit; }
.menu-label { flex: 1 1 auto; }
.info-head { padding: 14px 18px 6px; font-size: 13px; color: var(--muted); letter-spacing: 0; }
.info-none { padding: 4px 18px 10px; font-size: 14px; color: var(--dim); }
.info-person { display: flex; align-items: center; gap: 12px; padding: 8px 18px; }
.ip-name { flex: 1 1 auto; font-size: 15.5px; }
.ip-when { font-size: 12.5px; color: var(--muted); }

/* a photo or a video, full size, on white */
.chat-viewer { display: flex; flex-direction: column; background: var(--bg); }
.viewer-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: env(safe-area-inset-top) 8px 0;
  border-bottom: 1px solid var(--hair);
}
.viewer-close, .viewer-save { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 0; background: none; color: var(--text); }
.viewer-who { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; }
.vw-name { font-size: 16px; font-weight: 600; }
.vw-when { font-size: 12.5px; color: var(--muted); }
.viewer-stage { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 8px; background: var(--wa-ground); }
.viewer-media { max-width: 100%; max-height: 100%; object-fit: contain; }
.viewer-cap { flex: 0 0 auto; padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); font-size: 15.5px; text-align: center; white-space: pre-wrap; }

/* what was picked, with a caption, before it goes */
.chat-preview { display: flex; flex-direction: column; background: var(--bg); }
.pv-to { flex: 1 1 auto; font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pv-stage { flex: 1 1 auto; min-height: 0; display: flex; flex-wrap: wrap; align-content: center; justify-content: center; gap: 10px; padding: 12px; overflow-y: auto; background: var(--wa-ground); }
.pv-item { display: flex; align-items: center; justify-content: center; gap: 10px; max-width: 100%; }
.pv-item.k-image, .pv-item.k-video { flex: 1 1 100%; }
.pv-stage:has(.pv-item:nth-child(2)) .pv-item.k-image, .pv-stage:has(.pv-item:nth-child(2)) .pv-item.k-video { flex: 0 0 calc(50% - 5px); }
.pv-media { max-width: 100%; max-height: 62vh; object-fit: contain; border-radius: 6px; }
.pv-item.k-doc, .pv-item.k-voice { flex: 1 1 100%; justify-content: flex-start; padding: 14px; border-radius: 10px; background: var(--bg); box-shadow: var(--wa-shadow); }
.pv-more { align-self: center; font-size: 18px; color: var(--muted); }
.pv-foot { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding: 8px 8px calc(8px + env(safe-area-inset-bottom)); border-top: 1px solid var(--hair); background: var(--dock); }
.pv-caption { flex: 1 1 auto; min-width: 0; height: 40px; padding: 0 16px; border: 0; border-radius: 20px; background: var(--dock-field); box-shadow: inset 0 0 0 1px var(--hair-2); font-size: 16px; color: var(--text); }
.pv-caption:focus { outline: none; box-shadow: inset 0 0 0 1px var(--dim); }
.pv-send { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border: 0; border-radius: 50%; background: var(--accent); color: var(--accent-ink); }
.pv-send .ic { width: 22px; height: 22px; }

/* a group's or a person's info, the way WhatsApp's info screen is laid out */
.chat-info { display: flex; flex-direction: column; background: var(--sunk); }
.info-bar { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; min-height: 56px; padding: env(safe-area-inset-top) 6px 0; background: var(--bg); border-bottom: 1px solid var(--hair); }
.info-back { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 0; background: none; color: var(--text); }
.info-title { font-size: 17px; font-weight: 600; }
.info-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
.info-top { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 24px 16px 18px; background: var(--bg); }
.room-face.big { width: 96px; height: 96px; font-size: 38px; }
.info-name { margin-top: 8px; font-size: 22px; font-weight: 600; text-align: center; overflow-wrap: anywhere; }
.info-sub { font-size: 14.5px; color: var(--muted); text-align: center; }
.info-quick { display: flex; justify-content: center; gap: 10px; padding: 0 16px 18px; background: var(--bg); }
.iq-btn { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 88px; padding: 10px 12px; border: 1px solid var(--hair-2); border-radius: 12px; background: var(--bg); font-size: 13.5px; color: var(--text); }
.info-sec { margin-top: 10px; padding-bottom: 6px; background: var(--bg); }
.info-media { display: flex; gap: 4px; padding: 0 16px 10px; overflow-x: auto; scrollbar-width: none; }
.info-media::-webkit-scrollbar { display: none; }
.im-item { flex: 0 0 auto; width: 84px; height: 84px; padding: 0; border: 0; border-radius: 8px; overflow: hidden; background: var(--panel-3); }
.im-item img, .im-item video { width: 100%; height: 100%; object-fit: cover; display: block; }
.info-doc { display: flex; align-items: center; gap: 12px; padding: 8px 16px; color: var(--text); text-decoration: none; }
.info-doc .doc-name { flex: 1 1 auto; min-width: 0; }
.info-row { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 58px; padding: 6px 16px; border: 0; background: none; text-align: left; color: var(--text); }
.info-row + .info-row { border-top: 1px solid var(--hair); }
.info-row.act:hover { background: var(--panel-3); }
.info-row.danger { color: var(--hot); }
.info-row > .ic { width: 22px; height: 22px; margin: 0 8px; }
.room-face.act { font-size: 22px; }
.ir-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ir-name { font-size: 16px; }
.ir-sub { font-size: 13px; color: var(--muted); }
.ir-tag { flex: 0 0 auto; padding: 3px 8px; border: 1px solid var(--hair-2); border-radius: 6px; font-size: 12px; color: var(--muted); }

/* ── the list: a chat's last line, its ticks, its time and its unread count ───────────────── */
.room-bottom { display: flex; align-items: center; gap: 8px; min-width: 0; }
.room-bottom .room-last { flex: 1 1 auto; min-width: 0; display: block; -webkit-line-clamp: unset; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.room-last .ic { width: 16px; height: 16px; margin: -2px 3px 0 0; color: var(--muted); }
.room-last .msg-state { margin: -2px 3px 0 0; vertical-align: middle; }
.room-when.has-unread { color: var(--text); font-weight: 600; }
.room-face.is-group { font-weight: 400; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   DAİRELER AND HAFIZA
   One pane with two faces, because app.js has always driven them as a pair. .split > .top is
   the circles, .split > .bottom is the memory; both are direct children, which the browser
   rig measures by that exact path.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.queue-pane { background: var(--bg); }

.pane-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 var(--gut) 8px;
}
.pane-head .tabs { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; }
.pane-tools { margin-left: auto; display: flex; align-items: center; gap: 8px; }
/* Liste, Daireler, the circle sets, "+ daire" and the archive are all about circles. In
   Hafıza they would be a row of controls for something that is not on the screen. */
body[data-view="graph"] .queue-pane > .pane-head { display: none; }
/* Liste and Daireler are both on screen now, so a pair of tabs that switch between them is
   a control with nothing left to do. The buttons stay in the page because app.js binds them
   unguarded at module level and a rig presses them; they are simply not drawn. */
#tabList, #tabCircles { display: none; }
/* The circle sets moved to the settings screen, where a list of named sets belongs. */
.csets { display: none; }
/* REMOVED, at his word. One switch per company over the circles: with one company it turned
   off the only thing on the screen, and the second company will get its own switch from the
   rule above it rather than from this one. */
.spacebar, .space-note { display: none; }
/* Which memory you are reading. He will be the only person who ever has more than one, so it
   is behind ?dev=1 with the memories themselves rather than over the picture. */
.ctxtabs { display: none; }
body.dev .ctxtabs { display: flex; align-items: center; gap: 4px; min-width: 0; flex-wrap: nowrap; }
/* YOURS, AND ASKED OF YOU. Two tabs over the one list, with how many are in each. */
.whose { display: inline-flex; align-items: center; gap: 2px; }
.whose .tab { min-height: 44px; padding: 0 10px; font-size: 12.5px; }   /* a finger, like every other switch here */
.whose .tab .n { margin-left: 3px; color: var(--dim); font-variant-numeric: tabular-nums; }
.whose .tab.on .n { color: var(--muted); }
.queue-empty { margin: 10px 2px; font-size: 12.5px; line-height: 1.45; color: var(--dim); }
/* ONE ENGINE PER PERSON (public/one-engine.js). Where the kernel chat runs this page (or has not answered yet) the old
   engine is not made, so its tray, its circle picture, its sets, its archive and its agenda switch have nothing to show
   and are not drawn; the note says why, once the kernel chat has said it takes the page. */
.old-engine-note { display: none; }
body[data-old-engine="off"] .old-engine-note { display: block; }
body:not([data-old-engine="on"]) #queue,
body:not([data-old-engine="on"]) #queueEmpty,
body:not([data-old-engine="on"]) #circleView,
body:not([data-old-engine="on"]) #archivePanel,
body:not([data-old-engine="on"]) #whoseTabs,
body:not([data-old-engine="on"]) #tabList,
body:not([data-old-engine="on"]) #tabCircles,
body:not([data-old-engine="on"]) #csets,
body:not([data-old-engine="on"]) #newCircleBtn,
body:not([data-old-engine="on"]) #archiveBtn,
body:not([data-old-engine="on"]) #agendaSwitch { display: none !important; }

.tab, .newbtn, .wtab, .ctxtab, .etab, .spacebtn {
  padding: 0 13px;
  border: 1px solid transparent;
  border-radius: var(--pill);
  font-size: 13px;
  letter-spacing: 0;
  color: var(--muted);
  white-space: nowrap;
}
.tab:hover, .newbtn:hover, .wtab:hover, .ctxtab:hover, .etab:hover, .spacebtn:hover {
  background: var(--panel-2);
  color: var(--text);
}
.tab.on, .wtab.on, .ctxtab.on, .etab.on, .spacebtn.on {
  border-color: var(--hair-2);
  color: var(--text);
}
.newbtn, .etab { border-color: var(--hair-2); }

.split { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.split > .top, .split > .bottom { display: none; flex: 1 1 auto; min-height: 0; position: relative; }
body[data-view="circles"] .split > .top { display: flex; flex-direction: column; }
body[data-view="graph"] .split > .bottom { display: flex; flex-direction: column; }

/* THE LIST ON TOP, THE PICTURE UNDER IT, both at once. They were two tabs over one pane
   showing the same seven circles two ways, and switching between them lost your place in
   both. The list gets the top because it is what you read; the picture gets the rest
   because it is what you watch. */
.split > .top { flex-direction: column; gap: 0; }
.queue-wrap {
  flex: 0 1 auto;
  min-height: 84px;
  max-height: 46%;
  width: 100%;
  position: relative;
  overflow-y: auto;
  padding: 0 var(--gut) 10px;
}
.circle-wrap {
  flex: 1 1 auto;
  min-height: 140px;
  width: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--hair);
}
.circle-wrap > canvas { flex: 1 1 auto; width: 100%; min-height: 0; touch-action: none; }
/* A DOUBLE TAP IS TWO TAPS, NOT A ZOOM (29 September). Safari does not honour user-scalable=no, so
   the double-tap zoom is also switched off here; scrolling is untouched. */
html, body { touch-action: manipulation; }

/* MAKING A CIRCLE TAKES THE PANE. The form used to append itself beside the list, so you
   were filling in a long form next to the seven circles it was about to join, with no
   obvious way out. While it is up the list and the picture stand aside, the way the archive
   already did. */
.split > .top.is-form > .queue-wrap,
.split > .top.is-form > .circle-wrap { display: none; }
.split > .top.is-form { overflow-y: auto; }

/* ── ONE CIRCLE, WAITING ITS TURN ─────────────────────────────────────────────────────────
   Ported back from the version before the rewrite, because what replaced it was wrong in a
   way that looked plausible and was not.

   THE METER IS NOT A GAUGE ON THE RIGHT. app.js:2492 mints it as an empty <span> and
   app.js:2516 sets that span's OWN width to the score as a percentage. So the meter IS the
   bar: a two pixel line along the bottom edge of the row, in the circle's own hue, as long
   as its score. The rewrite gave it a fixed 82 px width, a max-width that clamped the
   percentage, and the TRACK colour instead of the fill colour, which is why every row showed
   the same flat grey line and the scores beside them meant nothing.

   The row is placed by arithmetic: translateY(index * ROW), with #queue's height set to
   rows * ROW. So the height here must stay a function of --row and nothing may make a row
   grow. The name clamps to two lines and the note under it gives way, because a circle born
   in a conversation is named with the words that made it and a long one is normal. */
.queue { position: relative; min-height: 100%; }
#queue .item {
  position: absolute;
  left: 0;
  right: 0;
  height: calc(var(--row) - 4px);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px 0 2px;
  border: 1px solid var(--hair);
  border-radius: 7px;
  overflow: hidden;
  cursor: default;
  background: var(--panel-2);
  transition: transform .38s cubic-bezier(.2, .8, .2, 1), border-color .25s, background .25s, opacity .25s;
  will-change: transform;
}
#queue .item .rank { width: 16px; color: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums; }
/* the tick carried the circle's colour; with no colour it says nothing, so it is not drawn (9 October) */
#queue .item .swatch { display: none; }
/* ONE LINE, since 28 September: the name, then the note faintly after it, both cut with ...
   The name may take up to two thirds of the row; the note gets what is left. */
#queue .item .body { flex: 1; min-width: 0; display: flex; flex-direction: row; align-items: center; gap: 8px; overflow: hidden; position: relative; z-index: 1; }
#queue .item .name { display: flex; align-items: center; gap: 6px; min-width: 0; max-width: 66%; flex: 0 1 auto; font-size: 13px; font-weight: 400; line-height: 1.2; }
#queue .item .name .lbl {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
#queue .item .note, #queue .item .cmt {
  font-size: 11px;
  color: var(--dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}
#queue .item .cmt { flex: none; position: relative; z-index: 1; }
#queue .item .score { width: 24px; text-align: right; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; position: relative; z-index: 1; }
/* THE BAR, NOW THE CARD ITSELF. Its width is still written by app.js as a percentage and
   nothing here may fix or clamp it. Since 28 September it is a faint fill behind the whole
   card instead of a line along the bottom: "the loading can be just overlaid to the card
   itself, a little faint." */
#queue .item .meter {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--text);
  opacity: .05;
  transition: width .2s linear;
}
#queue .item .tag {
  flex: none;
  padding: 0 4px;
  border: 1px solid var(--hair);
  border-radius: 4px;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
}
/* the row is over the line and will speak */
#queue .item.floor { border-color: var(--text); }
#queue .item.above { border-color: var(--line-2); }
#queue .item.satisfied { opacity: .45; }
#queue .item.sel { box-shadow: inset 0 0 0 1px var(--line-2); }
/* switched off: still in the list, and said so in three ways rather than one */
#queue .item.off { opacity: .22; }
#queue .item.off .meter { opacity: .25; }
#queue .item.off .name { text-decoration: line-through; text-decoration-color: var(--faint); }
#queue .item.gone { opacity: .35; }
#queue .item .power, #queue .item .gear {
  flex: none;
  position: relative;
  z-index: 1;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--dim);
  font-size: 11px;
  line-height: 1;
  transition: .15s;
}
#queue .item:not(.off) .power { color: var(--text); }
#queue .item .power:hover, #queue .item .gear:hover { color: var(--text); background: var(--panel-3); }
#queue .item.flash-promote, #queue .item.flash-speak { animation: pop .7s ease; }
/* app.js:1606 restarts this by removing the class, forcing a reflow and adding it back. With
   no rule the reflow was work done for nothing and the row never moved: the one signal that
   says WHICH circle the engine just reached for. */
#queue .item.ping { animation: ping-row .5s ease; }
@keyframes ping-row {
  0% { box-shadow: inset 0 0 0 1px var(--text); }
  100% { box-shadow: inset 0 0 0 1px transparent; }
}
#queue .item.flash-demote { animation: sink .7s ease; }
#queue .item.flash-hijack { animation: hijack .9s ease; }
@keyframes pop { 25% { background: var(--panel-3); } }
@keyframes sink { 25% { background: var(--panel-3); } }
@keyframes hijack { 15% { background: var(--panel-3); border-color: var(--hot); } 60% { background: var(--panel-3); } }

/* the line a circle has to cross to be allowed to speak: a dashed hairline, no glow */
.threshold-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px dashed var(--dim);
  pointer-events: none;
}
.threshold-line::after {
  content: '';
  position: absolute;
  right: -6px;
  top: -4px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  opacity: .75;
}

/* ONE SWITCH PER COMPANY over the circles. With one company it is a switch that turns off
   the only thing on the screen, labelled with a name nobody needed to be told. It appears
   when there is a second company to compare against, and not before; shell.js writes
   data-spaces on the body with how many there are. The note under it says the one thing a
   switch cannot: a hidden company is still running and you have not left it. */
.spacebtn { border-color: var(--hair); gap: 7px; }
.spacebtn-name { font-size: 13px; }
.spacebtn-count, .spacebtn-state { font-size: 11px; letter-spacing: 0; color: var(--dim); font-variant-numeric: tabular-nums; }
.space-note { flex: 0 0 auto; padding: 0 var(--gut) 8px; font-size: 12px; letter-spacing: 0; color: var(--muted); }

/* the form that makes a circle from a pattern, and the archive */
.circle-form, .noteform { display: flex; flex-direction: column; gap: 10px; padding: 0 var(--gut) 16px; }
.circle-form .fld, .noteform .fld { display: flex; flex-direction: column; gap: 5px; }
.circle-form label, .noteform label { font-size: 12px; letter-spacing: 0; color: var(--muted); }
.circle-form input, .circle-form select, .circle-form textarea,
.noteform input, .noteform textarea {
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--hair);
  border-radius: var(--r2);
  background: var(--sunk);
  color: var(--text);
  font-size: 15px;
}
/* The button that commits a comment on a message. It is the whole way in on a phone: a form
   with one input and no submit button shows a return key that does nothing. */
.noteform-go {
  align-self: flex-start;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r2);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 13px;
  font-weight: 400;
}
.circle-link { color: var(--accent); font-size: 13.5px; }
.archive-panel {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow-y: auto;
  padding: 0 var(--gut) 16px;
  background: var(--bg);
}
/* THE FILES SIT UNDER THE CIRCLES, NOT OVER THEM. Until 28 September this panel was drawn
   over the whole column the moment Asvalin answered, so on his machine the circles were
   under a list of files and he wrote "I don't see the actual circles". It takes the room
   the circles leave, and scrolls inside it. */
.files-panel {
  flex: 1 1 0;
  min-height: 120px;
  overflow-y: auto;
  padding: 0 var(--gut) 12px;
  border-top: 1px solid var(--hair);
}
.files-head { display: flex; align-items: baseline; gap: 8px; padding: 8px 2px 6px; position: sticky; top: 0; background: var(--bg); z-index: 1; }
.files-title { font-size: 12px; font-weight: 400; color: var(--muted); }
.files-why, .files-hint, .files-note { font-size: 11.5px; color: var(--dim); }
.files-retry, .files-clear { margin-left: auto; font-size: 12px; color: var(--accent); }
.files-selected { display: flex; align-items: center; gap: 8px; padding: 4px 2px 8px; }
.files-pick { font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.files-list { display: flex; flex-direction: column; }
.files-row { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 28px; padding: 0 6px; border-radius: 6px; text-align: left; }
.files-row:hover { background: var(--panel-2); }
.files-row.on { background: var(--panel-3); }
.files-name { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.files-meta { flex: none; font-size: 11px; color: var(--dim); font-variant-numeric: tabular-nums; }
.ar-row { display: flex; align-items: center; gap: 10px; min-height: 56px; padding: 6px 8px; border-radius: var(--r2); }
.ar-row:hover { background: var(--panel-2); }
.ar-head { padding: 10px 2px 4px; font-size: 12px; letter-spacing: 0; color: var(--muted); }
.ar-name { flex: 1 1 auto; min-width: 0; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ar-meta, .ar-note { font-size: 11.5px; letter-spacing: 0; color: var(--dim); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE MEMORY
   Ported back, rule for rule, from the version before the interface was rewritten. Both
   rewrites dropped this block, and both times the class names I wrote were names I assumed
   rather than the ones the code mints: the labels are .node-label and the card is built from
   h4 / .kind / .said / .rel / .when / .close. With no rules the labels lost their
   position:absolute, so every one of them piled up in the top left corner as plain text
   while the graph drew underneath, and the card came out as three bare lines.

   The structure here is the old one exactly. The only thing changed is the colour: ink and
   greys on white since 9 October, with no glow. THE GRAPH IS NEVER MUTE: the count is drawn even when the graph is empty,
   because "nothing here" and "nothing loaded" are different things.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* THE PICTURE ON TOP, WHAT YOU PICKED UNDER IT. 25 September, written on a node: "In the graph
   UI you are providing a pop up whenever I click on something like a node. I think that is
   distracting. Dont do that. Instead use the bottom half of the page for listing all these
   notes. So its not a pop up but a legit ui section." The card was a box floating in the top
   left corner of the picture; it is the lower part of the pane now, always there, and the
   picture is the part above it. The renderer measures the canvas, so it simply draws smaller. */
#worldPane { position: relative; --details-h: 42%; }
#worldCanvas { position: absolute; left: 0; right: 0; top: 0; width: 100%; height: calc(100% - var(--details-h)); display: block; }
.label-layer { position: absolute; left: 0; right: 0; top: 0; bottom: var(--details-h); z-index: 6; overflow: hidden; pointer-events: none; }

/* One label per node, placed over it by vendor/graph-renderer.js, which writes left and top
   in pixels and expects this rule to make them mean something. */
.node-label {
  position: absolute;
  transform: translate(-50%, -50%);
  padding: 3px 6px;
  border: 1px solid var(--hair-2);
  border-radius: 6px;
  background: var(--label-bg);
  font-size: 10px;
  letter-spacing: 0;
  color: var(--muted);
  white-space: nowrap;
}
/* the one you asked about is readable whatever is in front of it */
.node-label.focus {
  font-size: 12px;
  color: var(--text);
  border-color: var(--text);
}

/* the edge whose card is open, drawn over the canvas from one end to the other */
.edge-lit {
  position: absolute;
  height: 1.5px;
  transform-origin: 0 50%;
  background: var(--text);
  pointer-events: none;
  animation: edge-lit-in .18s ease-out;
}
@keyframes edge-lit-in { from { opacity: 0; } to { opacity: 1; } }

/* ── where a node came from ────────────────────────────────────────────────────────────── */
.world-card {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--details-h);
  z-index: 6;
  overflow: auto;
  padding: 12px var(--gut) 16px;
  border-top: 1px solid var(--hair);
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: 0;
}
.world-card .empty { color: var(--dim); font-size: 13px; }
.world-card .notes-h { margin-top: 12px; color: var(--muted); font-size: 11.5px; font-weight: 400; }
.world-card .note-row { margin-top: 6px; padding: 8px 10px; border-left: 2px solid var(--accent-line); background: var(--panel-2); border-radius: 0 8px 8px 0; }
.world-card h4 { margin: 0 0 2px 0; font-size: 15px; font-weight: 400; }
.world-card .kind { color: var(--dim); font-size: 11px; }
.world-card .said { margin: 6px 0 0; color: var(--dim); font-style: italic; }
.world-card .rel { margin-top: 7px; padding-top: 6px; border-top: 1px solid var(--hair); }
.world-card .rel a { cursor: pointer; text-decoration: none; border-bottom: 1px dotted var(--line-2); color: var(--accent); }
.world-card .when { color: var(--dim); font-size: 11px; }
/* 44 px, like every other target. It was 19 once, which is about a third of what iOS expects
   a finger to be, so the tap landed on the card body and nothing happened, and the card is
   only reachable by tapping a node: a close button nobody can hit leaves it over the picture
   with no way back. Drawn small and hit large. */
.world-card .close, .world-card .x {
  position: absolute;
  right: 0;
  top: 0;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--dim);
  font-size: 15px;
  line-height: 44px;
  text-align: center;
  cursor: pointer;
}
.world-card .close:hover, .world-card .x:hover { color: var(--text); }

/* ── the bar over the picture ──────────────────────────────────────────────────────────
   At the TOP, and transparent: it is a set of controls floating over the graph, not a
   toolbar the graph sits under. pointer-events go off on the bar and back on for its
   children, so the empty space between them is still the graph and can be dragged. */
.world-bar {
  position: absolute;
  left: 8px;
  right: 8px;
  top: 8px;
  z-index: 7;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}
.world-bar > * { pointer-events: auto; }
/* Only the memories strip lays out here; which memory you are reading is retired above. */
.wtabs { display: flex; align-items: center; gap: 4px; min-width: 0; flex-wrap: nowrap; }
/* THE MEMORIES STRIP IS A DEVELOPER'S TOOL. "Main, seed, aa, New, aa, Duck2, +" are separate
   saved graphs over local log files; they need the node server on this laptop to do anything
   at all, and on anybody else's screen they are six unexplained words in a row. Behind
   ?dev=1, with the rest of the developer's furniture. */
.wtabs { display: none; }
body.dev .wtabs { display: flex; }
.wtabs { max-width: 45%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.wtabs::-webkit-scrollbar { display: none; }
.world-bar .search {
  flex: 1 1 auto;
  max-width: 220px;
  min-width: 0;
  min-height: 44px;
  padding: 5px 10px;
  border: 1px solid var(--hair);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 12px;
}
.world-bar .search:focus { border-color: var(--line-2); }
.world-stat, .world-bar .stat {
  margin-left: auto;
  padding: 3px 7px;
  border-radius: 6px;
  background: none;
  font-size: 10.5px;
  letter-spacing: 0;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.world-toggles { display: inline-flex; align-items: center; gap: 4px; }
.world-toggles .switch { min-height: 44px; font-size: 10.5px; padding: 2px 8px 2px 4px; }

/* a note you write onto a thing in the world */
.world-note {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 12px;
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 8;
  display: flex;
  gap: 6px;
}
/* The note is committed with this, because on a phone the return key of a form with no
   submit button does nothing at all. 44 px, like every other thing a thumb has to hit. */
.world-note-go {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--hair);
  border-radius: 8px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 12px;
  font-weight: 400;
}
.world-note input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 6px 10px;
  border: 1px solid var(--hair);
  border-radius: 8px;
  background: var(--panel);
  color: var(--text);
  font-size: 12px;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   İŞLER  -  one thing at a time: the two lists, then the item you opened
   public/work/ui.js writes data-open on the screen, so which of the two is on is a fact the
   screen already carries and not something a script has to hide by hand.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.work-note {
  flex: 0 0 auto;
  padding: 2px var(--gut) 10px;
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.work-note:empty { display: none; }
.work-cards { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; padding: 0 var(--gut) 10px; }
.work-card {
  padding: 13px 15px;
  border: 1px solid var(--hair);
  border-radius: var(--r3);
  background: var(--panel-2);
}
.work-what { font-size: 15px; font-weight: 400; letter-spacing: 0; }
.work-where { font-size: 13px; letter-spacing: 0; color: var(--muted); }

.work-host { flex: 1 1 auto; min-height: 0; display: flex; }
/* a sentence in place of the screen (no server, not signed in): on the column's gutter, in grey */
.work-host:not(:has(*)) { padding: 2px var(--gut) 10px; font-size: 14.5px; line-height: 1.5; color: var(--muted); }
.work-screen { display: flex; flex-direction: column; width: 100%; min-height: 0; }
.work-queue { flex: 0 0 auto; padding: 0 var(--gut) 6px; font-size: 11.5px; letter-spacing: 0; color: var(--dim); }
.work-lists, .work-detail { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.work-lists { padding: 0 var(--gut) calc(30px + env(safe-area-inset-bottom)); }
.work-screen[data-open="no"] > .work-detail { display: none; }
.work-screen[data-open="yes"] > .work-lists { display: none; }

/* AN EMPTY SCREEN IS ONE SENTENCE. work/ui.js writes data-empty when there is no work of
   any kind, and then the two headings and their two empty lines stand down and the note
   above them is the whole screen: centred, given room, and said once. */
.work-screen[data-empty="yes"] > .work-lists { display: none; }
.work-screen[data-empty="yes"] > .work-note {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 34ch;
  margin: 0 auto;
  padding: 0 var(--gut) 12vh;
  text-align: center;
  text-wrap: balance;
  font-size: 14.5px;
  line-height: 1.55;
}

.work-group { margin-top: 18px; }
.work-group:first-child { margin-top: 2px; }
.work-group > .group-head { margin: 0 2px 8px; }
/* ONE LIST EMPTY WHILE THE OTHER HAS WORK IN IT. The sentence takes the shape of the rows
   it stands in for - the same card, the same edge, the same left margin as a row's title -
   rather than floating centred under a left-aligned heading, which is the mismatch that
   made the screen look unfinished. */
.work-group > .group-empty {
  margin: 0;
  padding: 16px;
  text-align: left;
  background: var(--panel-2);
  border: 1px solid var(--hair);
  border-radius: var(--r3);
}
.work-rows {
  background: var(--panel-2);
  border: 1px solid var(--hair);
  border-radius: var(--r3);
  overflow: hidden;
}
.work-rows:empty { display: none; }
.work-row {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  padding: 12px 14px;
  text-align: left;
  color: var(--text);
}
.work-row + .work-row::before {
  content: '';
  position: absolute;
  top: 0; left: 14px; right: 0;
  height: 1px;
  background: var(--hair);
}
.work-row:hover { background: var(--panel-3); }
.work-row.on { background: var(--panel-3); }
.row-top { display: flex; align-items: baseline; gap: 10px; }
.row-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15.5px;
  font-weight: 400;
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.row-when { flex: 0 0 auto; font-size: 12px; letter-spacing: 0; color: var(--dim); }
.row-who { font-size: 13px; letter-spacing: 0; color: var(--muted); }
.row-proposed { font-size: 12px; letter-spacing: 0; color: var(--accent); }

/* ── a state chip ─────────────────────────────────────────────────────────────────────────
   Never a colour alone: the field and the word are both printed, so the chip still says what
   it means in greyscale, which is all there is since 9 October, and to a screen reader. work-ui-tests.mjs checks that state-word is styled here for exactly that. */
.work-states { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.work-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 7px;
  border: 1px solid var(--hair);
  border-radius: var(--r1);
  background: var(--sunk);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0;
  white-space: nowrap;
}
.state-field { color: var(--dim); }
.state-word { color: var(--text-2); }
.work-state[data-value="done"], .work-state[data-value="accepted"], .work-state[data-value="delivered"] {
  border-color: var(--hair-2);
}
.work-state[data-value="done"] .state-word,
.work-state[data-value="accepted"] .state-word,
.work-state[data-value="delivered"] .state-word { color: var(--ok); }
.work-state[data-value="waiting"], .work-state[data-value="pending"], .work-state[data-value="proposed"] {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
.work-state[data-value="waiting"] .state-word,
.work-state[data-value="pending"] .state-word,
.work-state[data-value="proposed"] .state-word { color: var(--accent); }
.work-state[data-value="blocked"], .work-state[data-value="refused"], .work-state[data-value="declined"] {
  border-color: var(--hot-line);
  background: var(--hot-soft);
}
.work-state[data-value="blocked"] .state-word,
.work-state[data-value="refused"] .state-word,
.work-state[data-value="declined"] .state-word { color: var(--hot); }

/* ── one item ─────────────────────────────────────────────────────────────────────────── */
.work-detail { padding: 0 0 calc(30px + env(safe-area-inset-bottom)); display: flex; flex-direction: column; }
.detail-head { display: flex; align-items: center; gap: 10px; padding: 0 var(--gut) 4px; }
.detail-back {
  padding: 0 13px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
}
.detail-title { padding: 6px var(--gut) 0; font-family: var(--serif); font-size: 26px; font-weight: 400; letter-spacing: -.01em; line-height: 1.2; }
.detail-who, .detail-note { padding: 5px var(--gut) 0; font-size: 13.5px; letter-spacing: 0; color: var(--muted); }

.detail-dates { display: flex; gap: 10px; padding: 16px var(--gut) 0; }
.date-asked, .date-proposed {
  flex: 1 1 0;
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid var(--hair);
  border-radius: 14px;
  background: var(--panel-2);
}
.date-proposed { border-color: var(--accent-line); background: var(--accent-soft); }
.date-value { font-size: 17px; font-weight: 400; letter-spacing: 0; }
.date-note { padding: 0; margin-top: 3px; font-size: 11.5px; line-height: 1.3; color: var(--muted); }

.detail-evidence, .detail-history { padding: 14px var(--gut) 0; display: flex; flex-direction: column; gap: 6px; }
.work-evidence { display: flex; align-items: center; gap: 10px; min-height: 56px; padding: 12px 14px; border: 1px solid var(--hair); border-radius: 14px; background: var(--panel-2); }
.ev-name { flex: 1 1 auto; min-width: 0; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ev-sha, .deliver-sha, .deliver-file, .hash, .mono {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0;
  color: var(--dim);
  overflow-wrap: anywhere;
}
.ev-sign { font-size: 11.5px; letter-spacing: 0; color: var(--ok); }
.work-evidence[data-signed="no"] .ev-sign { color: var(--dim); }
.work-event, .event-line { display: flex; gap: 12px; padding: 6px 0; font-size: 14px; letter-spacing: 0; color: var(--text-2); line-height: 1.4; }
.event-when { flex: 0 0 56px; font-size: 12px; letter-spacing: 0; color: var(--dim); }
.evidence-empty, .history-empty, .actions-none, .group-empty { font-size: 13px; letter-spacing: 0; color: var(--muted); }

.work-actions, .acts { display: flex; flex-wrap: wrap; gap: 8px; padding: 16px var(--gut) 0; }
.work-do, .form-go, .receipt-retry, .queue-retry, .propose-date, .deliver-path, .tbtn {
  padding: 0 15px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
}
.work-do:hover, .form-go:hover, .propose-date:hover, .tbtn:hover { background: var(--panel-3); }
.work-do.go, .form-go, .tbtn.key { border-color: var(--text); color: var(--text); }
.work-do.danger, .work-do.bad, .tbtn.bad { background: var(--hot-soft); border-color: var(--hot-line); color: var(--hot); }

.action-line, .receipt {
  margin: 14px var(--gut) 0;
  padding: 11px 13px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r2);
  background: var(--accent-soft);
  font-size: 13px;
  letter-spacing: 0;
  color: var(--accent);
}
.action-line:empty { display: none; }
.action-receipts { display: flex; flex-direction: column; gap: 4px; padding: 8px var(--gut) 0; }
/* emitted by public/work/ui.js and left without rules by the rewrite */
.queue-row { display: flex; align-items: center; gap: 10px; }
.queue-line, .receipt-line { flex: 1 1 auto; min-width: 0; }
.action-receipt { display: flex; gap: 10px; font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.action-receipt[data-state="refused"] { color: var(--hot); }
.work-forms { display: flex; flex-direction: column; gap: 10px; padding: 16px var(--gut) 0; }
.work-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 13px 15px;
  border: 1px solid var(--hair);
  border-radius: 14px;
  background: var(--panel-2);
}
.form-label, .form-why { font-size: 12px; letter-spacing: 0; color: var(--muted); }
.work-form input, .work-form textarea, .work-form select {
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--hair);
  border-radius: var(--r2);
  background: var(--sunk);
  color: var(--text);
  font-size: 15px;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   BEN  -  the same discipline as a settings table: label, value, hint, control
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.me-head { display: flex; align-items: center; gap: 14px; padding: 6px 18px 18px; }
.me-head .face { width: 62px; height: 62px; font-size: 23px; }
.me-id { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.me-n { font-family: var(--serif); font-size: 23px; font-weight: 400; letter-spacing: -.01em; }
.me-m { font-size: 13.5px; letter-spacing: 0; color: var(--muted); }

.me-list { padding: 0 var(--gut); }
.me-section {
  margin: 24px 4px 8px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted);
}
/* A row inside a grouped inset list: the GROUP carries the box, the row carries a hairline
   that starts where the text does. Standalone cards with their own border and six pixels
   between them is a list of buttons, not a settings screen. */
.me-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 11px 16px;
  text-align: left;
  color: var(--text);
}
.me-list .group { --ins: 16px; }
.me-row + .me-row::before {
  content: '';
  position: absolute;
  top: 0;
  left: var(--ins);
  right: 0;
  height: 1px;
  background: var(--hair);
}
button.me-row:hover { background: var(--panel-3); }
button.me-row:active { background: var(--panel-3); }
/* the two rows that are a decision rather than a setting */
.me-row.me-danger .me-label { color: var(--hot); }
.me-row.me-go .me-label { color: var(--accent); }
/* what a switch is set to, in a word, beside the switch */
.me-word { font-size: 13.5px; letter-spacing: 0; color: var(--muted); }
.me-control .disc { font-size: 17px; line-height: 1; color: var(--dim); }
.me-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.me-label { font-size: 15.5px; letter-spacing: 0; }
.me-hint { font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.me-control { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; }
/* The four holders Ben used to move the live control strips into. Ben builds rows now and
   drives those controls where they stand, so these only ever appear if something puts them
   back; kept so that doing so is not silently unstyled. */
.me-voice, .me-etabs, .me-switches, .me-session { display: flex; flex-wrap: wrap; gap: 8px; padding: 6px 0; }
.me-version { padding: 22px 0; text-align: center; font-size: 11.5px; letter-spacing: 0; color: var(--dim); }
/* The value a row is set to. It shrinks the LABEL when space is short, not itself: "Dil /
   En..." tells you nothing, and the label is the part you already know. */
.val {
  flex: 0 1 auto;
  min-width: 0;
  font-size: 14px;
  letter-spacing: 0;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-row .me-text { min-width: 0; flex: 1 1 auto; }
/* THE SWITCH IS NEVER CUT (18 October 2026, the owner, a screenshot of Me with "Dark theme" and "Developer mode"
   switches half off the card: "The user interfaces hides/crops the actual live menu behind ... no rookie mistakes"). A
   long line under the label wrapped less than the control could shrink, so the control, allowed to shrink, was pushed
   past the card's edge. The control keeps its own width now; only a value it shows may be cut short, at most half the
   row, and the label's lines wrap to make room. */
.me-row .me-control { flex: 0 0 auto; min-width: 0; max-width: 50%; display: flex; align-items: center; gap: 8px; }
.me-row .me-control .sw { flex: none; }
.me-row .me-control .me-word { flex: none; }
.whoami { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.whoami button { min-height: 44px; padding: 0 12px; border: 1px solid var(--hair-2); border-radius: var(--pill); color: var(--muted); font-size: 12.5px; }

/* ── a switch ─────────────────────────────────────────────────────────────────────────────
   .knob is the dot INSIDE a switch, not a button beside it. Giving it a button's box drew a
   pill on top of the word the switch is labelled with. The word is always printed: the
   position of the dot is a reminder, never the only way to know. */
/* Only the switches app.js mints for Ben. .power is the queue row's own button, .tog is a
   row in the cog panel and .vnote is the voice module's status line: a bare class name in a
   shared selector dressed all three as filled pills in places they do not belong. */
.switch, .me-switches .tog, .knob-host {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 0 13px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.switch.on, .me-switches .tog.on, .knob-host.on {
  border-color: var(--text);
  color: var(--text);
}
.knob {
  flex: 0 0 auto;
  position: relative;
  width: 30px;
  height: 18px;
  border-radius: var(--pill);
  background: var(--hair-2);
  transition: background .22s;
}
.knob::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--bg);
  transition: transform .22s var(--ease), background .22s;
}
.switch.on .knob { background: var(--accent); }
.switch.on .knob::after { transform: translateX(12px); background: var(--accent-ink); }
.sw {
  flex: 0 0 auto;
  position: relative;
  width: 48px;
  height: 29px;
  border-radius: 15px;
  background: var(--hair-2);
  transition: background .22s;
}
.sw::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 25px; height: 25px;
  border-radius: 50%;
  background: #fff;
  transition: transform .22s var(--ease);
}
.sw[aria-checked="true"] { background: var(--accent); }
.sw[aria-checked="true"]::after { transform: translateX(19px); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE GATE, THE DRAWER, THE STATUS LINE, AND THE DEVELOPER READ-OUT
   ══════════════════════════════════════════════════════════════════════════════════════════ */

.gate {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: calc(24px + env(safe-area-inset-top)) 20px calc(24px + env(safe-area-inset-bottom));
  background: var(--bg);
  overflow-y: auto;
}
.gate-card {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.gate-card h1 { font-family: var(--serif); font-size: 32px; font-weight: 400; letter-spacing: -.02em; }
.gate-why { font-size: 13.5px; line-height: 1.5; letter-spacing: 0; color: var(--muted); }
.gate-card label { display: flex; flex-direction: column; gap: 6px; font-size: 12.5px; letter-spacing: 0; color: var(--muted); }
.gate-card input {
  min-height: 48px;
  padding: 13px 15px;
  border: 1px solid var(--line-2);
  border-radius: var(--r1);
  background: var(--bg);
  color: var(--text);
  font-size: 16px;
}
.gate-card input:focus { border-color: var(--text); }
.gate-go {
  min-height: 50px;
  border: 1px solid var(--text);
  border-radius: var(--pill);
  background: var(--bg);
  color: var(--text);
  font-size: 15.5px;
  font-weight: 400;
}
.gate-go:hover { background: var(--panel-3); }
.gate-say { min-height: 20px; font-size: 13px; line-height: 1.5; letter-spacing: 0; color: var(--muted); }
.gate-say.bad { color: var(--hot); }
.gate-say.good { color: var(--ok); }
.gate-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px 18px; }
.gate-alt { padding: 0 4px; font-size: 13px; letter-spacing: 0; color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.gate-alt:hover { color: var(--text); }
/* THE INVITATION, over the sign-in card (29 September): who invited them, the iPhone app, and the
   address it should wait for. Inputs and buttons are the card's own, so it reads as one page. */
.gate-invite { display: flex; flex-direction: column; gap: 10px; padding: 16px; margin-bottom: 6px; border: 1px solid var(--accent-line); border-radius: 14px; background: var(--accent-soft); }
.gate-invite h2 { font-size: 18px; font-weight: 400; line-height: 1.3; letter-spacing: 0; }
.gate-invite-note { font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.gate-invite-note.small { font-size: 12.5px; }
.gate-invite .gate-alt { min-height: 44px; }
.gate-invite-field { color: var(--text); }            /* the card's own label, in the text colour: it is a question */

.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: 55;
  width: min(420px, 92vw);
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--hair);
  background: var(--bg);
  box-shadow: var(--shadow);
}
.drawer-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px var(--gut);
  padding-top: calc(14px + env(safe-area-inset-top));
  border-bottom: 1px solid var(--hair);
}
.drawer-head h2 { flex: 1 1 auto; font-size: 17px; font-weight: 400; letter-spacing: 0; }
.slist { flex: 0 0 auto; max-height: 40%; overflow-y: auto; padding: 8px; }
.sview { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px var(--gut); font-size: 13.5px; }
.srow { display: block; width: 100%; padding: 10px 12px; border-radius: var(--r2); text-align: left; font-size: 13.5px; color: var(--text); }
.srow:hover, .srow.on { background: var(--panel-2); }

/* A developer's crumb that sometimes carries a real warning ("the server is older than this
   page"). It is fixed to the viewport, so on a wide screen it landed on the dark field OUTSIDE
   the column, which reads as a stray label belonging to nothing. The media query below walks
   it back inside. */
/* A developer's crumb. It was hidden only under 820 px, so on every wider screen it printed
   across the composer, which is the one control that must never have anything over it. It is
   for a developer, so it is drawn for one: behind ?dev=1 and nowhere else. */
.statusbar { display: none; }
body.dev .statusbar {
  display: block;
  position: fixed;
  left: var(--gut);
  bottom: max(6px, env(safe-area-inset-bottom));
  z-index: 5;
  pointer-events: none;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
  opacity: .5;
}

@media (min-width: 1024px) {
  /* the same centring main does, so the crumb stays inside the column at either width */
  .statusbar { left: max(var(--gut), calc(50vw - min(var(--col), 100vw) / 2 + var(--gut))); }
}

/* The rule trace, behind ?dev=1. It used to take the whole column, so turning dev on buried
   the app under a wall of monospace with no way back to it. It is a drawer along the bottom
   now: the screen above it still works and the trace is still readable. */
.log-pane {
  position: absolute;
  inset: auto 0 0 0;
  height: 42vh;
  z-index: 3;
  border-top: 1px solid var(--hair);
  display: none;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  padding: var(--gut);
  background: var(--panel);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0;
}
body.dev .log-pane { display: flex; }
.log-pane h2 { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--dim); }
.memory, .log { display: flex; flex-direction: column; gap: 2px; color: var(--muted); }
/* app.js mints every trace line as class "row". It is a line of text in a developer read-out
   and must never pick up a list row's box, let alone the queue's absolute placement. */
.log .row, .memory .row {
  position: static;
  display: flex;
  gap: 8px;
  min-height: 0;
  height: auto;
  padding: 1px 0;
  background: none;
}

/* ── the small shared pieces ──────────────────────────────────────────────────────────── */
.empty, .memory .empty { color: var(--faint); }
.note, .hint, .foot, .lede, .meta, .ts, .when, .ms, .unit, .vnote { font-size: 11.5px; letter-spacing: 0; color: var(--muted); }
.lnk, .cmt, .go-link { color: var(--accent); }
.good { color: var(--ok); }
.bad, .warn { color: var(--hot); }
.stale { color: var(--hot); opacity: .8; }
.clock { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); }
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 50%; }
.card { padding: 13px 15px; border: 1px solid var(--hair); border-radius: var(--r3); background: var(--panel-2); }
.voice, .etabs { display: inline-flex; flex-wrap: wrap; gap: 8px; }
.tag {
  display: inline-flex;
  padding: 2px 7px;
  border: 1px solid var(--hair-2);
  border-radius: var(--r1);
  font-size: 11px;
  letter-spacing: 0;
  color: var(--muted);
}

/* An alert setting, shown on the circle row it belongs to. The mode is spelled out in the
   row's own text as well: the dot is a reminder, never the only way to know. */
.alert-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 6px;
  vertical-align: middle;
  border-radius: 50%;
  background: var(--dim);
}
.alert-dot[data-mode="off"] { display: none; }
.alert-dot[data-mode="ring"] { background: var(--accent); }
.alert-dot[data-mode="call"] { background: var(--hot); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THREE BLOCKS THE REWRITE DROPPED
   Found by tools/styled-tests.mjs, which exists because this kept happening: a class the code
   mints with no rule anywhere is not a missing element, it is an element wearing nothing, and
   nothing in the suite noticed three times running. Ported rule for rule from the version
   before the rewrite; only the palette changed, to the ink and greys of 9 October.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── PAST CONVERSATIONS, in the drawer ──────────────────────────────────────────────────
   app.js:3149 builds each turn as .tn > (.ts + div > (.bub + .note)). Without these the
   drawer was a wall of undifferentiated text with no sense of who said what. */
.sview { display: flex; flex-direction: column; gap: 9px; }
.sview .tn { display: flex; gap: 9px; }
.sview .tn.you { justify-content: flex-end; }
/* the cap sits on the WRAPPER: on the bubble it resolved against its own shrink-wrapped box
   and clipped short lines */
.sview .tn > div { max-width: 74%; min-width: 0; }
.sview .bub {
  padding: 7px 10px;
  border-radius: 9px;
  font-size: 13px;
  max-width: 100%;
  overflow-wrap: anywhere;
  box-sizing: border-box;
}
.sview .tn.you .bub { background: var(--mine-bg); color: var(--mine-text); border: 1px solid var(--mine-line); }
.sview .tn.agent .bub { background: var(--panel-2); border: 1px solid var(--hair); }
.sview .tn .ts {
  flex: none;
  width: 40px;
  padding-top: 4px;
  font-size: 10.5px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.sview .note { margin-top: 3px; font-size: 11.5px; color: var(--accent); }
.sview .empty { color: var(--faint); }

/* ── ONE CIRCLE'S SPEC, on two surfaces ─────────────────────────────────────────────────
   public/circlespec.js draws the same form twice: in the settings popover behind a circle's
   cog, and in the "+ daire" panel. Every one of these classes was minted with no rule, so
   both surfaces came out as an unstyled column of inputs. */
.spec { display: grid; gap: 2px; font-size: 12px; letter-spacing: 0; }
.spec details.grp { border-top: 1px solid var(--hair); padding: 2px 0; }
.spec details.grp:first-child { border-top: 0; }
.spec details.grp summary {
  padding: 6px 0;
  cursor: pointer;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted);
  list-style: none;
  user-select: none;
}
.spec details.grp summary::-webkit-details-marker { display: none; }
.spec details.grp summary::before { content: '\25B8  '; color: var(--muted); }
.spec details.grp[open] summary::before { content: '\25BE  '; }
.spec .fld { padding: 4px 0; }
.spec .fld .top { display: flex; align-items: center; gap: 6px; }
.spec .fld .top label { flex: 1; font-size: 12px; color: var(--text); }
.spec .fld .top output { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* a dot that lights when this field no longer matches the pattern it came from */
.spec .fld .chg { flex: none; width: 5px; height: 5px; border-radius: 50%; background: transparent; }
.spec .fld .chg.on { background: var(--warn); }
.spec .fld input[type="text"], .spec .fld input[type="number"],
.spec .fld textarea, .spec .fld select {
  width: 100%;
  box-sizing: border-box;
  margin-top: 3px;
  padding: 5px 8px;
  border: 1px solid var(--hair);
  border-radius: 7px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12px;
}
.spec .fld textarea { resize: vertical; min-height: 38px; }
.spec .fld .inline { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.spec .fld .inline input { width: 90px; margin-top: 0; }
.spec .fld .unit { color: var(--muted); font-size: 11px; }
.spec .fld input[type="range"] { width: 100%; margin: 4px 0 0; accent-color: var(--text); }
.spec .fld .inherit { display: flex; align-items: center; gap: 6px; margin-top: 4px; font-size: 11px; color: var(--muted); }
.spec .fld .hint { margin-top: 3px; font-size: 10.5px; line-height: 1.35; color: var(--muted); opacity: .85; }
.spec .fld .ck { margin: 0; accent-color: var(--text); }
/* a switch in ink, as every switch here is */
.spec .fld .sw {
  appearance: none;
  position: relative;
  flex: none;
  width: 34px;
  height: 19px;
  margin: 0;
  border: 1px solid var(--hair);
  border-radius: 19px;
  background: var(--panel-2);
  cursor: pointer;
}
.spec .fld .sw::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--muted);
  transition: .15s;
}
.spec .fld .sw:checked { background: var(--text); border-color: var(--text); }
.spec .fld .sw:checked::after { left: 17px; background: var(--bg); }
/* what this circle is bound to in the memory, and what it could be bound to */
.spec .bind .cur { margin-top: 2px; font-size: 11.5px; }
.spec .bind .cur.none { color: var(--muted); }
.spec .bind .also { margin: 3px 0 5px; font-size: 11px; line-height: 1.45; color: var(--muted); }
.spec .bind .also .lnk { font-size: 11px; }
.spec .bind .lnk { padding: 0 4px; border: 0; background: none; color: var(--muted); font: inherit; font-size: 10.5px; cursor: pointer; }
.spec .bind .sug { display: grid; gap: 3px; margin-top: 4px; }
.spec .bind .hit {
  padding: 4px 8px;
  border: 1px solid var(--hair);
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 11.5px;
  text-align: left;
  cursor: pointer;
}
.spec .bind .hit.add { color: var(--accent); }
.spec .bind .none { font-size: 11px; color: var(--muted); }
.circle-form { max-height: 78%; overflow-y: auto; gap: 2px; }
.circle-form .actions { position: sticky; bottom: 0; padding-top: 6px; background: var(--panel); }

/* ── A CIRCLE THAT SPOKE, named inside the turn it produced ─────────────────────────────
   Quieter than a memory link on purpose: which circle raised a subject is provenance, not
   something to chase. */
.msg a.circle-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--dim);
  cursor: pointer;
  opacity: .9;
}
.msg a.circle-link:hover { border-bottom-style: solid; opacity: 1; }
.msg .from-circle a.circle-link { border-bottom-color: var(--hair-2); }

/* ── THE ENGINE'S READ-OUT, behind ?dev=1 ──────────────────────────────────────────────── */
.memory { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; }
.memory .kv {
  padding: 4px 8px;
  border: 1px solid var(--hair);
  border-radius: 7px;
  background: var(--panel-2);
  font-size: 11.5px;
}
.memory .kv b { margin-right: 5px; color: var(--muted); font-weight: 400; }
.log .row { display: flex; gap: 8px; align-items: baseline; }
.log .ts { flex: none; width: 38px; color: var(--dim); font-variant-numeric: tabular-nums; }
.log .k { color: var(--muted); }
.log .row.trigger .k, .log .row.hijack .k, .log .row.muted .k, .log .row.layer .k { color: var(--hot); }
.log .row.nudge .k, .log .row.reask .k { color: var(--dim); }
.log .t { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

/* ── five more the rewrite left bare, found by tools/styled-tests.mjs ──────────────────── */
/* a section heading inside İşler, drawn as an h4 by work/ui.js:137 */
.section-head {
  margin: 8px 0 0;
  font-size: 11px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--muted);
}
/* the name of a step in the engine's breakdown, beside its milliseconds */
.trace .tr-step .nm { flex: 1 1 auto; min-width: 0; }
/* a past conversation's own name, in the drawer */
.srow .id { font-size: 12px; font-weight: 400; }
/* the picker that brings a thing from the memory into a circle, and the way out of it */
.bring-in {
  width: 100%;
  min-height: 44px;
  margin-top: 4px;
  padding: 5px 8px;
  border: 1px solid var(--hair);
  border-radius: 7px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12px;
}
.cancel {
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--bg);
  color: var(--muted);
  font-size: 13.5px;
}
.cancel:hover { background: var(--panel-3); color: var(--text); }

/* THE OLD CIRCLES AND THE MEMORY GRAPH, OFF THE SCREEN (13 October 2026). The owner: "remove the circle system in the
   phone app and also the graph database ... the UI looks weird because I see the chat on the left and emptiness in the
   middle and right side." His own chat runs on the simulation's functions since 11 October and the old circles are
   stopped for him, so the two columns beside the talk stood empty. The switcher (Sohbet / Daireler / Hafıza) and the
   pane that held both go; his conversation is one column, as wide as every other screen. The proper circle system and
   graph view come with phase 5; their code stays. */
body:not([data-circles-on]) .seg-wrap, body:not([data-circles-on]) .convo > .queue-pane { display: none !important; }
@media (min-width: 1500px) {
  body[data-room="monk"]:not([data-circles-on]) main { width: min(var(--col), 100%); border-left: 1px solid var(--hair); border-right: 1px solid var(--hair); }
  body[data-room="monk"]:not([data-circles-on]) .convo { display: flex; }
}
@media (min-width: 1024px) and (max-width: 1499.98px) {
  body[data-room="monk"][data-view="circles"]:not([data-circles-on]) main,
  body[data-room="monk"][data-view="graph"]:not([data-circles-on]) main { width: min(var(--col), 100%); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE CHAT LIST, WHATSAPP'S (15 October 2026)
   The owner: "the initial UI should be like WhatsApp, all the conversations, that's it, either group or individuals.
   And on top HyperMONK." The large title is the app's name, the company is the line under it, and below that one flat
   list runs across the screen: MONK, the groups and one-to-ones, the colleagues not talked to yet. A hairline between
   rows starts past the face, as in every chat list.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.lt-wrap .lt-brand { display: flex; margin: 0; }
.space-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  min-width: 44px;                 /* "Chats" in English is shorter than a finger is wide */
  max-width: 100%;
  margin-top: -6px;
  padding: 0;
  border: 0;
  background: none;
  font-size: 15px;
  letter-spacing: 0;
  color: var(--muted);
  text-align: left;
  cursor: pointer;
}
.space-pick > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.space-pick .chev { width: 13px; height: 13px; flex: 0 0 auto; opacity: .75; }
.space-pick:hover { color: var(--text); }
.lt-wrap .lt-sub:empty { display: none; }

.chats { margin-top: 6px; border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair); background: var(--bg); }
.chats .chat-room { padding: 10px 16px; }
.chats .chat-room:not(#monkRow)::before { content: ''; position: absolute; top: 0; left: 66px; right: 0; height: 1px; background: var(--hair); }
.chats .chat-room.on, .chats .chat-room:hover, .chats .chat-room:active { background: var(--panel-3); }
.room-face.monk { box-shadow: inset 0 0 0 1px var(--text); }
.chats .chat-note { margin: 0; padding: 10px 16px; font-size: 13.5px; line-height: 1.4; color: var(--muted); }
.chats .chat-note:empty { display: none; }
/* a colleague not talked to yet: a chat row whose second line is who they are and how many open tasks they have */
.chats .person-row .room-last { -webkit-line-clamp: 1; }
.people-host .lrow-line > .chat-room { flex: 1 1 auto; min-width: 0; }
.people-host .lrow-line { position: relative; display: flex; align-items: center; }
.people-host .lrow-line .lrow-more { margin-right: 8px; }

/* the bar under a chat's header that opens the tasks of whoever the chat is with */
.task-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 8px 16px;
  border: 0;
  border-bottom: 1px solid var(--hair);
  background: var(--panel-2);
  color: var(--text);
  font-size: 14px;
  letter-spacing: 0;
  text-align: left;
  cursor: pointer;
}
.task-bar[hidden] { display: none; }
.task-bar:hover, .task-bar:active { background: var(--panel-3); }
.task-bar .tb-icon { width: 18px; height: 18px; flex: 0 0 auto; color: var(--muted); }
.task-bar .tb-text { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.task-bar .tb-n { flex: 0 0 auto; font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.task-bar .tb-go { width: 14px; height: 14px; flex: 0 0 auto; color: var(--dim); }

/* a person's tasks, in the sheet the bar opens */
.task-list { display: flex; flex-direction: column; border: 1px solid var(--hair-2); border-radius: 12px; overflow: hidden; background: var(--bg); }
.task-row { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px; }
.task-row + .task-row { border-top: 1px solid var(--hair); }
.task-title { font-size: 15px; line-height: 1.35; overflow-wrap: anywhere; }
.task-meta { font-size: 12.5px; line-height: 1.4; color: var(--muted); }
.task-row.is-late .task-flag, .task-row.is-blocked .task-flag { color: var(--text); }
.task-who { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 10px 2px 2px; font-size: 13px; color: var(--muted); }
.task-who:first-child { margin-top: 0; }
.task-who button { min-height: 36px; padding: 0 12px; border: 1px solid var(--hair-2); border-radius: 18px; background: var(--bg); font-size: 13px; color: var(--text); cursor: pointer; }
.task-empty { margin: 0; padding: 4px 2px; font-size: 14px; line-height: 1.45; color: var(--muted); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   SIGNING IN WITH YOUR PHONE (16 October 2026): the QR on the sign-in card, and the phone's scanner
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.gate-qr { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 16px; border: 1px solid var(--line-2); border-radius: 16px; background: var(--bg); text-align: center; }
.gate-qr[hidden] { display: none; }
.qr-lead { margin: 0; font-size: 16px; color: var(--text); }
.qr-box { width: 196px; height: 196px; display: grid; place-items: center; }
.qr-box svg { width: 196px; height: 196px; display: block; }
.qr-code { margin: 0; min-height: 1.2em; font-family: var(--mono); font-size: 24px; letter-spacing: .14em; color: var(--text); font-variant-numeric: tabular-nums; }
.qr-how { margin: 0; font-size: 13px; line-height: 1.5; color: var(--muted); max-width: 32ch; }
.qr-said { margin: 0; min-height: 2.9em; font-size: 13px; line-height: 1.45; color: var(--muted); }
.qr-box .qr-said { min-height: 0; padding: 0 12px; }
.qr-again { min-height: 44px; padding: 0 18px; border: 1px solid var(--text); border-radius: var(--pill); background: var(--bg); color: var(--text); font-size: 14px; cursor: pointer; }
/* hidden but keeping its room, so the card never moves when it comes and goes */
.qr-again[hidden] { display: inline-flex; visibility: hidden; }
.gate-or { margin: 2px 0 0; text-align: center; font-size: 12.5px; color: var(--muted); }
.gate-or[hidden] { display: none; }
.qr-scan { align-self: stretch; }
.qr-video { width: 100%; max-height: 52vh; border-radius: 12px; background: #000; object-fit: cover; }
.qr-video[hidden] { display: none; }
@media (max-width: 520px) {
  .qr-box, .qr-box svg { width: 156px; height: 156px; }
  .qr-code { font-size: 21px; }
}

/* THE OPEN QUESTION ABOVE ITS BUTTONS (16 October 2026, public/personal/live.js drawAsk): when newer lines pushed the
   question up the chat, its words stand again here, so the buttons never wait without saying what they answer */
.k-ask {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  width: 100%;
  padding: 8px 16px 2px;
  border: 0;
  background: none;
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
}
.k-ask[hidden] { display: none; }

/* MONK typing while the typed words are checked on the server (public/personal/live.js pending), and the owner's
   developer view under a MONK line: closed until opened, small, in the page's own greys (17 October 2026) */
.msg.k-typing { color: var(--muted); font-style: italic; }
.k-behind { margin-top: 6px; border-top: 1px solid var(--hair); padding-top: 4px; font-size: 12px; line-height: 1.45; color: var(--muted); }
.k-behind summary { cursor: pointer; list-style: none; min-height: 28px; display: flex; align-items: center; color: var(--muted); }
.k-behind summary::-webkit-details-marker { display: none; }
.k-behind summary::before { content: '›'; display: inline-block; width: 14px; transition: transform .15s; }
.k-behind[open] summary::before { transform: rotate(90deg); }
.k-behind .kb-row { padding: 2px 0 2px 14px; color: var(--text); overflow-wrap: anywhere; }
.k-behind .kb-row b { font-weight: 600; color: var(--muted); }

/* WHATSAPP'S CONVERSATION HEADER: the arrow back, the face, the name and the line under it, left-aligned; a press on
   them opens the info. The word "Chats" beside the arrow stays for a screen reader only. */
.convo > .nav { grid-template-columns: auto minmax(0, 1fr) auto; gap: 2px; }
.convo .back { min-width: 44px; justify-content: center; padding: 0 4px 0 2px; }   /* 44 to a finger, the arrow alone */
.convo .back span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.convo .back svg { width: 22px; height: 22px; }
.convo-head { justify-self: stretch; display: flex; align-items: center; gap: 10px; min-width: 0; text-align: left; cursor: pointer; border-radius: var(--r2); }
.convo-head > .room-face { display: inline-flex; width: 38px; height: 38px; margin: 0; font-size: 15px; color: var(--text); }
.convo-head > .ch-text { display: flex; flex-direction: column; min-width: 0; margin: 0; font-size: inherit; color: var(--text); }
.convo-head > .ch-text > b { font-size: 16.5px; font-weight: 600; text-align: left; }
.convo-head > .ch-text > span { text-align: left; font-size: 12.5px; color: var(--muted); }

/* LIGHT OR DARK, one press on home (17 October 2026, public/theme.js): the moon while the page is light, the sun while
   it is dark, beside the + */
.theme-btn .tb-sun { display: none; }
:root[data-theme="dark"] .theme-btn .tb-moon { display: none; }
:root[data-theme="dark"] .theme-btn .tb-sun { display: block; }

/* THE WORKFLOW STUDIO's button (18 October 2026, public/studio/app-glue.mjs): in your own MONK chat only, beside the call */
body:not([data-room="monk"]) #studioBtn { display: none; }
#studioLayer[hidden] { display: none !important; }
