/* ══════════════════════════════════════════════════════════════════════════════════════════
   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 a darker field, 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.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* Inter, served from our own origin so the app still looks right on a local file server with
   no internet. Two subsets: latin, and latin-ext for ş ğ İ, without which Turkish falls back
   to another face in the middle of a word. */
@font-face {
  font-family: 'Inter var';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('vendor/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter var';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('vendor/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

:root {
  /* ── the five the circle canvas parses, as hex ── */
  --bg: #08090b;
  --panel-2: #131417;
  --line: #1a1b1d;
  --text: #f3f3f5;
  --muted: #8d8d96;

  /* ── the rest of the surface, darkest first ── */
  --panel: #0d0e11;
  --panel-3: #1a1b1f;
  --sunk: #16171b;
  --line-2: #2b2b2d;
  /* What every border and separator in the page is actually drawn with: the sketch's own
     translucent hairline, which lightens whatever surface it lies on instead of being one
     fixed grey that is right on exactly one of them. --line above stays hex because the
     circle canvas parses it. */
  --hair: rgba(255, 255, 255, .075);
  --hair-2: rgba(255, 255, 255, .14);
  --dim: #5c5d65;
  --faint: #3e3f45;

  /* ── one accent, and the two other words colour is allowed to say ── */
  --accent: #f2b45c;
  /* YOUR OWN LINES. Deep blue with light text since 28 September; they were near white, and
     "my chat bubble colours are very bad, and on white the buttons cannot be read". Blue so
     they can never be mistaken for the monk, which is amber. */
  --mine-bg: #1d3150;
  --mine-line: #2c4770;
  --mine-text: #eaf1fb;
  --mine-dim: #a3b6d2;
  --mine-link: #a9cbff;
  --accent-ink: #17120a;
  --accent-soft: rgba(242, 180, 92, .12);
  --accent-line: rgba(242, 180, 92, .26);
  --ok: #63d3a4;
  --warn: #f2b45c;
  --hot: #ff6f61;
  --hot-soft: rgba(255, 111, 97, .1);
  --hot-line: rgba(255, 111, 97, .3);

  /* ── 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: 'Inter var', Inter, -apple-system, 'Segoe UI', system-ui, Roboto, sans-serif;
  --mono: ui-monospace, 'Cascadia Mono', Menlo, Consolas, monospace;
  --ease: cubic-bezier(.32, .72, 0, 1);
  --shadow: 0 24px 70px rgba(0, 0, 0, .6);
  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: -.005em;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  overscroll-behavior: none;
}

[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }
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: rgba(242, 180, 92, .3); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .1); 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: #121317;
  box-shadow: var(--shadow);
  font-size: 13.5px;
}
.tune h3, .tune .tune-title { margin-bottom: 8px; font-size: 15px; font-weight: 600; letter-spacing: -.015em; }
.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) {
  body { background: #050508; }
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(110% 70% at 50% -12%, rgba(242, 180, 92, .055), transparent 62%);
  }
  main {
    width: min(var(--col), 100%);
    border-left: 1px solid var(--hair);
    border-right: 1px solid var(--hair);
    box-shadow: 0 0 140px rgba(0, 0, 0, .7);
  }
}

/* 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: -24px 0 60px rgba(0, 0, 0, .55);
}
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: rgba(8, 9, 11, .74);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
}
.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: 600;
  letter-spacing: -.01em;
  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: 500; }
.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: 500;
  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(--panel-3);
  color: #b7b8c0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  user-select: none;
}
.face.sm { width: 44px; height: 44px; border-radius: var(--r2); background: none; }
.face.sm > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--panel-3);
  color: #b7b8c0;
  font-size: 13px;
  font-weight: 600;
}
.face.sm:hover > span { background: #24252b; }
.face.monk { background: var(--accent-soft); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent-line); }
.face.work { background: rgba(99, 211, 164, .1); color: var(--ok); box-shadow: inset 0 0 0 1px rgba(99, 211, 164, .22); }
.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); }
/* Six pairs, drawn from the name, so two people cannot collide into one colour by accident. */
.face[data-face="1"], .room-face[data-face="1"] { background: #17252b; color: #7fd3e8; }
.face[data-face="2"], .room-face[data-face="2"] { background: #26192b; color: #d79ae8; }
.face[data-face="3"], .room-face[data-face="3"] { background: #1c2430; color: #8fb6e8; }
.face[data-face="4"], .room-face[data-face="4"] { background: #2b1d1d; color: #e8a09a; }
.face[data-face="5"], .room-face[data-face="5"] { background: #1f2a1e; color: #a3d093; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   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-size: 34px;
  font-weight: 700;
  letter-spacing: -.03em;
  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: 500; }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   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-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}
.group-head .n { color: var(--dim); font-weight: 500; }

.group {
  --ins: 66px;                       /* where a hairline starts: past the face */
  margin: 0 var(--gut);
  background: var(--panel-2);
  border: 1px solid var(--hair);
  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);
}
.lrow:hover { background: var(--panel-3); }
.lrow:active { background: #202126; }
.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: 600;
  letter-spacing: -.012em;
  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: 500; }

/* ── 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: linear-gradient(180deg, #191a1f 0%, #131418 100%);
  text-align: left;
  color: var(--text);
}
.monk-card:hover { border-color: rgba(242, 180, 92, .42); }
.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: 600; letter-spacing: -.015em; }
.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: #c9c9d1; }
.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: 600; 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);
  border-radius: 11px;
  background: var(--panel-3);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
}
.org-go { background: var(--accent); border-color: transparent; color: var(--accent-ink); }
.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: rgba(0, 0, 0, .5); }
.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);
  border-bottom: 0;
  border-radius: 22px 22px 0 0;
  background: #121317;
  box-shadow: var(--shadow);
}
@media (min-width: 640px) {
  .sheet-host { align-items: center; }
  .sheet { border-radius: 22px; border-bottom: 1px solid var(--hair); max-height: 76vh; }
  .sheet-grip { display: none; }
}
.sheet-grip {
  width: 36px;
  height: 4px;
  margin: 4px auto 10px;
  border-radius: var(--pill);
  background: #32333a;
}
.sheet-t {
  padding: 4px 8px 10px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -.018em;
}
.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(--panel-3);
  color: #b7b8c0;
  font-size: 13px;
  font-weight: 600;
}
.sheet-item.on .sheet-mark { background: var(--accent-soft); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent-line); }
.sheet-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sheet-label { font-size: 15.5px; font-weight: 500; letter-spacing: -.01em; }
.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);
  border-radius: var(--r2);
  background: var(--panel-2);
  color: var(--text);
  font-size: 16px;
}
.sheet-field input:focus { border-color: var(--hair-2); }
.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-radius: var(--r2);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 15.5px;
  font-weight: 600;
}
.sheet-go:hover { filter: brightness(1.06); }
/* 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: 700; }
.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; }
.sheet-row > .sheet-go { flex: 1 1 auto; }
.sheet-alt { min-height: 50px; padding: 0 16px; border-radius: var(--r2); border: 1px solid var(--hair-2); background: var(--panel-2); color: var(--text); font-size: 15px; font-weight: 500; }
.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(--panel-3); color: var(--text); font-size: 14px; line-height: 1.4; box-shadow: 0 8px 24px rgba(0,0,0,.45); }
.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: 600; 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 */
.approvals-card { display: flex; align-items: center; gap: 12px; width: 100%; margin: 0 0 12px; padding: 12px 14px; border: 1px solid var(--accent-line); border-radius: var(--r3, 16px); background: var(--accent-soft); text-align: left; color: var(--text); }
.approvals-card[hidden] { display: none; }
.approvals-card .mc { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.approvals-card .mc-title { font-weight: 600; }
.approvals-card .mc-said { font-size: 13px; color: var(--muted); }
/* 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: 600; }
.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-size: 26px; letter-spacing: -.02em; }
.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 { background: var(--panel-3); color: var(--dim); }

.sheet-close {
  width: 100%;
  margin-top: 10px;
  padding: 12px;
  border-radius: 14px;
  background: var(--panel-2);
  font-size: 15.5px;
  font-weight: 500;
  color: var(--muted);
}
.sheet-close:hover { background: var(--panel-3); 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: rgba(8, 9, 11, .74);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
body[data-room="room"] .seg-wrap { display: none; }

.seg {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 3px;
  border: 1px solid var(--hair);
  border-radius: 13px;
  background: var(--sunk);
}
.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: 10px;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--muted);
  transition: background .2s, color .2s;
}
.segbtn:hover:not(:disabled) { color: var(--text); }
.segbtn.on {
  background: #26272d;
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
}
.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;
  gap: 8px;
  padding: 6px var(--gut) 16px;
}
/* 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. */
.msg {
  max-width: min(80%, 540px);
  align-self: flex-start;
  padding: 9px 14px 10px;
  border: 1px solid var(--hair);
  border-radius: var(--r4);
  border-bottom-left-radius: var(--r1);
  background: var(--sunk);
  font-size: 15.5px;
  line-height: 1.4;
  letter-spacing: -.008em;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* yours: the blue block on the right */
.msg.me {
  align-self: flex-end;
  border-color: var(--mine-line);
  border-bottom-left-radius: var(--r4);
  border-bottom-right-radius: var(--r1);
  background: var(--mine-bg);
  color: var(--mine-text);
  font-weight: 450;
}
/* the monk's: the accent block on the left */
.msg.bot {
  border-color: rgba(242, 180, 92, .2);
  background: rgba(242, 180, 92, .055);
  color: #ece4d9;
}
/* a note the engine made rather than something it said to you */
.msg.soft { background: var(--panel-2); border-color: var(--hair); color: var(--muted); font-size: 14px; }
/* an interjection: the engine cut in, and it says so */
.msg.hijack { border-color: var(--accent-line); }

/* who is speaking. A block, not an inline span: inline it ran straight into the first word
   of the message, which is exactly what he was looking at. */
.msg > .from {
  display: block;
  margin-bottom: 3px;
  font-size: 11.5px;
  font-weight: 500;
  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(--accent);
  opacity: .85;
  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(--accent-line);
  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 { text-decoration-color: rgba(169, 203, 255, .5); }
.msg.me a.thing:hover { text-decoration-color: var(--mine-link); background: rgba(169, 203, 255, .12); }

/* 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(--accent); opacity: .7; }

/* 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. The strip
   scrolls rather than pushing the conversation off the screen when a question has many answers. */
.quick {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 2px var(--gut) 8px;
  max-height: 158px;
  overflow-y: auto;
}
.quick .about { flex: 1 0 100%; font-size: 12.5px; color: var(--muted); }
.quick button,
.quick .ans {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--hair-2);
  border-radius: var(--pill);
  background: var(--panel-3);
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  cursor: pointer;
}
.quick button:hover,
.quick .ans:hover { background: #232429; }
.quick .ans.skip { border-style: dashed; background: transparent; color: var(--muted); }
.quick .ans.idle { background: transparent; border-color: var(--accent-line); }
.quick .ans.date { position: relative; 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 two buttons beside it. 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. */
.composer {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 8px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair);
  background: rgba(8, 9, 11, .86);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
/* THE WHOLE PILL IS THE FIELD. It was a 44px rounded box with 16px of padding either side
   holding a 24px input, so the top, the bottom and both ends were dead: clicking there put
   the caret nowhere, showed a blink, and swallowed everything typed after it. He reported
   exactly that. The padding moves onto the input and the input fills the box, so every
   pixel inside the pill is the field. */
.field {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-width: 0;
  min-height: 44px;
  border: 1px solid var(--hair);
  border-radius: 22px;
  background: var(--sunk);
  overflow: hidden;
}
.field:focus-within { border-color: var(--hair-2); }
.field input, .chat-input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  align-self: stretch;
  padding: 0 16px;
  font-size: 15.5px;
  color: var(--text);
}
.field input::placeholder, .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. */
.cbtn {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  line-height: 0;
}
.cbtn svg { display: block; }
.speech { color: var(--muted); }
.speech:hover { color: var(--text); background: var(--panel-2); }
.speech[aria-pressed="true"], .speech.on { background: var(--accent-soft); color: var(--accent); }
.send { background: var(--accent); color: var(--accent-ink); }
.send:hover { filter: brightness(1.06); }
.send:disabled { background: var(--panel-3); color: var(--dim); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   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(--panel-3);
  color: #b7b8c0;
  font-size: 14px;
  font-weight: 600;
  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: 600;
  letter-spacing: -.012em;
  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: 700;
  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: 600; }
.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); }

.chat-messages {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 var(--gut) 16px;
}
.chat-messages > :first-child { margin-top: auto; }
.chat-msg {
  max-width: min(80%, 540px);
  align-self: flex-start;
  padding: 9px 14px 10px;
  border: 1px solid var(--hair);
  border-radius: var(--r4);
  border-bottom-left-radius: var(--r1);
  background: var(--sunk);
}
.chat-msg.mine {
  align-self: flex-end;
  border-color: var(--mine-line);
  border-bottom-left-radius: var(--r4);
  border-bottom-right-radius: var(--r1);
  background: var(--mine-bg);
  color: var(--mine-text);
}
.msg-who { display: flex; align-items: baseline; gap: 8px; font-size: 11.5px; letter-spacing: 0; }
.msg-from { font-weight: 600; color: var(--muted); }
.chat-msg.mine .msg-from { color: var(--mine-dim); }
.msg-when { color: var(--dim); }
.chat-msg.mine .msg-when { color: var(--mine-dim); }
/* A monk's line, marked the way a monk in the member list is marked, and with the word
   printed rather than the colour left to carry it on its own (06_IOS_AND_UI). */
.chat-msg.is-monk { background: var(--accent-soft); border-color: var(--accent-line); }
.chat-msg.is-monk .msg-kind { color: var(--accent); }
.msg-kind { color: var(--dim); letter-spacing: .02em; }
.msg-body { font-size: 15.5px; line-height: 1.4; letter-spacing: -.008em; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg-body.gone { font-style: italic; opacity: .6; }
.msg-edited { font-size: 11px; letter-spacing: 0; opacity: .65; }

/* ── the delivery state ──────────────────────────────────────────────────────────────────
   Four states, and the word is always printed beside the mark. A mark on its own would be
   the lie he objected to: a tick that reached the server is not a tick that reached a phone,
   and neither one is a message somebody read. */
.msg-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  font-size: 11px;
  letter-spacing: 0;
  opacity: .8;
}
.chat-msg.mine .msg-state { color: var(--mine-dim); opacity: 1; }
.state-mark { line-height: 1; }
.state-word { letter-spacing: .01em; }
.msg-state[data-state="failed"] { color: var(--hot); opacity: 1; }
.msg-state[data-state="pending"] { opacity: .55; }
.msg-retry {
  margin-top: 5px;
  padding: 0 12px;
  border: 1px solid var(--hot-line);
  border-radius: 10px;
  background: var(--hot-soft);
  font-size: 12px;
  color: var(--hot);
}
.msg-why { display: block; margin-top: 2px; font-size: 11px; color: var(--hot); }

.chat-composer {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 8px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hair);
  background: rgba(8, 9, 11, .86);
}
.chat-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--hair);
  border-radius: 22px;
  background: var(--sunk);
}
.chat-attach { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; color: var(--muted); font-size: 20px; }
.chat-attach[hidden] { display: none; }            /* not shown until a file can be sent */
.chat-send {
  flex: 0 0 auto;
  padding: 0 18px;
  border-radius: 22px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 14px;
  font-weight: 600;
}
.chat-send:disabled { background: var(--panel-3); color: var(--dim); }

/* ══════════════════════════════════════════════════════════════════════════════════════════
   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; padding: 2px; border: 1px solid var(--hair); border-radius: 9px; }
.whose .tab { min-height: 44px; padding: 0 10px; border-radius: 7px; 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); }

.tab, .newbtn, .wtab, .ctxtab, .etab, .spacebtn {
  padding: 0 13px;
  border: 1px solid transparent;
  border-radius: 11px;
  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 {
  background: var(--panel-3);
  color: var(--text);
  font-weight: 500;
}
.newbtn, .etab { border-color: var(--hair); }

.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; }
/* a tick of the circle's own colour, not a dot */
#queue .item .swatch { flex: none; width: 3px; height: 14px; border-radius: 2px; background: hsl(var(--h, 38) 65% 55%); position: relative; z-index: 1; }
/* 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: 500; 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: #c3ccd8; 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: hsl(var(--h, 38) 65% 55%);
  opacity: .11;
  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: hsl(var(--h, 38) 65% 45%); background: hsl(var(--h, 38) 40% 12%); }
#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: hsl(var(--h, 38) 60% 55%); }
#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 hsl(var(--h, 38) 65% 55%); }
  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(--accent-soft); } }
@keyframes sink { 25% { background: rgba(140, 151, 166, .14); } }
@keyframes hijack { 15% { background: var(--hot-soft); border-color: var(--hot); } 60% { background: rgba(255, 111, 97, .12); } }

/* the line a circle has to cross to be allowed to speak, and the glow under it */
.threshold-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px dashed var(--accent-line);
  pointer-events: none;
}
.threshold-line::before {
  content: '';
  position: absolute;
  left: -12px;
  right: -12px;
  bottom: 0;
  height: 1200px;
  background: linear-gradient(to top, color-mix(in srgb, var(--accent) 9%, transparent), transparent 220px);
  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: 600;
}
.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: 600; 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: the
   accent was green and this interface is amber, so the glow and the lit edge follow the
   palette. 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 rgba(90, 103, 122, .35);
  border-radius: 6px;
  background: rgba(8, 10, 14, .72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  font-size: 10px;
  letter-spacing: 0;
  color: #cbd4e2;
  white-space: nowrap;
}
/* the one you asked about is readable whatever is in front of it */
.node-label.focus {
  font-size: 12px;
  color: #fff;
  border-color: rgba(242, 180, 92, .65);
  box-shadow: 0 0 18px rgba(242, 180, 92, .14);
}

/* the edge whose card is open, drawn over the canvas from one end to the other */
.edge-lit {
  position: absolute;
  height: 2px;
  transform-origin: 0 50%;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(242, 180, 92, .25), rgba(242, 180, 92, .95), rgba(242, 180, 92, .25));
  box-shadow: 0 0 12px rgba(242, 180, 92, .55);
  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: 600; }
.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: 600; }
.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: rgba(11, 13, 16, .8);
  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: rgba(11, 13, 16, .7);
  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: 600;
}
.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: 600; letter-spacing: -.012em; }
.work-where { font-size: 13px; letter-spacing: 0; color: var(--muted); }

.work-host { flex: 1 1 auto; min-height: 0; display: flex; }
.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: 600;
  letter-spacing: -.012em;
  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, to a screen reader, and to somebody who cannot tell the amber from
   the green. 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: #aeaeb6; }
.work-state[data-value="done"], .work-state[data-value="accepted"], .work-state[data-value="delivered"] {
  border-color: rgba(99, 211, 164, .26);
  background: rgba(99, 211, 164, .08);
}
.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);
  border-radius: 11px;
  background: var(--panel-3);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
}
.detail-title { padding: 6px var(--gut) 0; font-size: 26px; font-weight: 700; letter-spacing: -.028em; line-height: 1.15; }
.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: 600; letter-spacing: -.02em; }
.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: #c6c6cd; 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);
  border-radius: 11px;
  background: var(--panel-3);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--text);
}
.work-do:hover, .form-go:hover, .propose-date:hover, .tbtn:hover { background: #232429; }
.work-do.go, .form-go, .tbtn.key { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.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-size: 21px; font-weight: 600; letter-spacing: -.025em; }
.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-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  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: #202126; }
/* 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: -.01em; }
.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: -.005em;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-row .me-text { min-width: 0; flex: 1 1 auto; }
.me-row .me-control { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: 8px; }
.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); border-radius: 11px; 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);
  border-radius: 11px;
  background: var(--panel-3);
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--muted);
}
.switch.on, .me-switches .tog.on, .knob-host.on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent);
}
.knob {
  flex: 0 0 auto;
  position: relative;
  width: 30px;
  height: 18px;
  border-radius: var(--pill);
  background: #2a2b31;
  transition: background .22s;
}
.knob::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #8d8d96;
  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: #2a2b31;
  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-size: 26px; font-weight: 700; letter-spacing: -.03em; }
.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(--hair);
  border-radius: var(--r2);
  background: var(--panel-2);
  color: var(--text);
  font-size: 16px;
}
.gate-card input:focus { border-color: var(--hair-2); }
.gate-go {
  min-height: 50px;
  border-radius: var(--r2);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 15.5px;
  font-weight: 600;
}
.gate-go:hover { filter: brightness(1.06); }
.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: 650; line-height: 1.3; letter-spacing: -.01em; }
.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: #121317;
  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: 600; letter-spacing: -.018em; }
.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-radius: var(--r1);
  background: var(--panel-3);
  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, because this interface is amber now.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── 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: hsl(var(--h, 38) 65% 55%); }
.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: hsl(var(--h, 38) 65% 55%); }
/* the circle's own hue, so the form for a circle looks like that circle */
.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: hsl(var(--h, 38) 65% 55% / .18); border-color: hsl(var(--h, 38) 65% 55%); }
.spec .fld .sw:checked::after { left: 17px; background: hsl(var(--h, 38) 65% 55%); }
/* 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 rgba(255, 255, 255, .28);
  cursor: pointer;
  opacity: .9;
}
.msg a.circle-link:hover { border-bottom-style: solid; opacity: 1; }
.msg .from-circle a.circle-link { border-bottom-color: rgba(255, 255, 255, .18); }

/* ── 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: 500; }
.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: 600;
  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: 500; }
/* 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);
  border-radius: 11px;
  background: var(--panel-3);
  color: var(--muted);
  font-size: 13.5px;
}
.cancel:hover { background: #232429; color: var(--text); }
