/* Halo: a matte, softly lit room.
   Dark is near-black with one light source: a thin ring, warm to cool. The ring's colours appear in three places
   only: the room's mark, the loaders, and the rim of a message that is for you. Everything else is one accent
   family (a soft violet) or neutrals. Light mode is warm porcelain ("pearl").
   The mark holds still while the room is connected and idle; it runs only while (re)connecting and breathes
   while the room is closed or full.
   No inline styles anywhere (the page's policy forbids them): every state is a class or an attribute. */

/* ---------- tokens ---------- */
:root {
  color-scheme: dark light;

  /* The phone's or computer's own interface font: ui-sans-serif reaches it in one browser family, system-ui in the
     rest; the named fonts in between catch platforms whose system-ui would be a plainer fallback. */
  --font: ui-sans-serif, "SF Pro Text", "Segoe UI", Roboto, "Liberation Sans", system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-display: ui-sans-serif, "SF Pro Display", "SF Pro Text", "Segoe UI", Roboto, "Liberation Sans", system-ui, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, Menlo, Consolas, "DejaVu Sans Mono", "Roboto Mono", monospace;

  /* type scale */
  --t-caption2: 11px;
  --t-caption: 12px;
  --t-footnote: 13px;
  --t-subhead: 15px;
  --t-body: 16px;
  --t-headline: 17px;
  --t-title3: 20px;
  --t-title2: 22px;
  --t-title1: 28px;
  --t-large: 34px;

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px; --s9: 56px;
  --r-xs: 7px; --r-sm: 10px; --r-md: 14px; --r-lg: 18px; --r-xl: 24px; --r-pill: 999px;
  --ease: cubic-bezier(.22, .8, .26, 1);
  --ease-io: cubic-bezier(.45, 0, .25, 1);
  --d1: 150ms; --d2: 200ms; --d3: 250ms;
  --tap: 44px;
  --col: 720px;
  --bar-h: 58px;
  --pad-l: max(var(--s4), env(safe-area-inset-left));
  --pad-r: max(var(--s4), env(safe-area-inset-right));

  /* the ring: warm to cool */
  --ring-1: #f6c38a;
  --ring-2: #f2a0ad;
  --ring-3: #c6a6f7;
  --ring-4: #95b6fb;
  --ring-5: #8bd9d0;
  --ring: conic-gradient(from 200deg, var(--ring-1), var(--ring-2), var(--ring-3), var(--ring-4), var(--ring-5), var(--ring-1));
  --ring-line: linear-gradient(90deg, var(--ring-1), var(--ring-2) 30%, var(--ring-3) 55%, var(--ring-4) 78%, var(--ring-5));
  --comet: conic-gradient(from 0turn, transparent 0turn, transparent .1turn, var(--ring-5) .38turn, var(--ring-4) .58turn, var(--ring-3) .76turn, var(--ring-2) .9turn, var(--ring-1) 1turn);
  /* the ring while the room is closed or full: one amber tone */
  --shut-1: #f8d09a;
  --shut-2: #f5a65b;
  --shut-3: #dc8236;
  --ring-shut: conic-gradient(from 200deg, var(--shut-1), var(--shut-2), var(--shut-3), var(--shut-2), var(--shut-1));
  --shut-rim: rgba(245, 166, 91, .2);

  /* halo (dark) */
  --bg: #0b0b0c;
  --bg-grouped: #0e0e10;
  --surface-1: #161618;
  --surface-2: #1d1d20;
  --surface-3: #26262a;
  --group: #18181b;
  --menu: #1f1f23;
  --field: #18181b;
  --fill-1: rgba(255, 255, 255, .045);
  --fill-2: rgba(255, 255, 255, .075);
  --fill-3: rgba(255, 255, 255, .12);
  --line: rgba(255, 255, 255, .075);
  --line-2: rgba(255, 255, 255, .12);
  --line-3: rgba(255, 255, 255, .2);
  /* field-line: the edge of anything you type into or switch (3:1 or more against its background) */
  --field-line: #6a6a70;
  --field-line-hover: #85858c;
  --text: #e9e8e5;
  --text-2: #a9a8ad;
  --text-3: #8b8a91;
  --accent: #b5a8ff;
  --accent-fill: #8a7cf7;
  --on-accent: #15122b;
  --accent-soft: rgba(181, 168, 255, .13);
  --accent-line: rgba(181, 168, 255, .36);
  --accent-glow: rgba(160, 140, 255, .42);
  --primary: #ecebe8;
  --primary-hover: #ffffff;
  --on-primary: #0b0b0c;
  /* my own bubbles: a deep, low-saturation violet with soft light ink */
  --mine-1: #2b2840;
  --mine-2: #262338;
  --mine-edge: rgba(200, 190, 255, .07);
  --on-mine: #e6e3f3;
  --on-mine-2: #aca7c6;
  --mine-accent: #cbc2ff;
  --mine-quote: rgba(255, 255, 255, .055);
  --mine-quote-bar: #8f86c9;
  --bubble: #18181b;
  --bubble-for: #1b1a22;
  --bubble-line: rgba(255, 255, 255, .055);
  --quote: rgba(255, 255, 255, .055);
  --owner: #f2c27c;
  --owner-soft: rgba(242, 194, 124, .12);
  --owner-line: rgba(242, 194, 124, .36);
  --mod: #7fd8c3;
  --mod-soft: rgba(127, 216, 195, .11);
  --mod-line: rgba(127, 216, 195, .32);
  --bot: #86c8f0;
  --bot-soft: rgba(134, 200, 240, .09);
  --bot-line: rgba(134, 200, 240, .3);
  --warn: #ff9f8a;
  --warn-soft: rgba(255, 159, 138, .12);
  --warn-line: rgba(255, 159, 138, .36);
  --warn-glow: rgba(255, 130, 100, .34);
  /* amber: "for now" states (muted until …) */
  --amber: #f5a65b;
  --amber-soft: rgba(240, 182, 96, .12);
  /* hot: a count that needs someone (the queue) */
  --hot: #ff9f8a;
  --on-hot: #2a0b04;
  --danger: #ff8f9c;
  --danger-soft: rgba(255, 143, 156, .12);
  --danger-line: rgba(255, 143, 156, .36);
  --danger-fill: #d63b52;
  --on-danger: #ffffff;
  --ok: #7fd8c3;
  --bar: rgba(12, 12, 13, .97);
  --bar-solid: #0d0d0e;
  --seg-on: #34343a;
  --switch-off: #2c2c30;
  --knob: #ffffff;
  --scrim: rgba(0, 0, 0, .58);
  --toast: #2a2a2f;
  --toast-ink: #f2f1ee;
  --toast-warn: #ff9f8a;
  --toast-ok: #7fd8c3;
  --skel: rgba(255, 255, 255, .055);
  --skel-hi: rgba(255, 255, 255, .075);
  --mark-core: #0c0c0e;
  --mark-hi: #222127;
  --mark-rim: rgba(198, 166, 247, .2);
  /* the faint watermark over the chat: the viewer's own name and the date */
  --mark-ink: rgba(255, 255, 255, .17);
  --glow-cool: rgba(150, 132, 255, .11);
  --glow-warm: rgba(190, 170, 255, .05);
  --glow-type: rgba(160, 140, 255, .16);
  --av-bg-s: 22%; --av-bg-l: 21%; --av-ink-s: 62%; --av-ink-l: 80%;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 10px 30px -10px rgba(0, 0, 0, .75), 0 0 0 1px rgba(255, 255, 255, .06);
  --shadow-3: 0 30px 80px -20px rgba(0, 0, 0, .9), 0 0 0 1px rgba(255, 255, 255, .06);
}

@media (prefers-color-scheme: light) {
  :root {
    /* pearl */
    --ring-1: #e9a35c;
    --ring-2: #e5758a;
    --ring-3: #a67de9;
    --ring-4: #6f8ff0;
    --ring-5: #4cb9ae;
    --shut-1: #efb46c;
    --shut-2: #d98a2b;
    --shut-3: #b9661b;
    --shut-rim: rgba(217, 138, 43, .16);

    --bg: #f5f3ef;
    --bg-grouped: #efece7;
    --surface-1: #fdfcfa;
    --surface-2: #ffffff;
    --surface-3: #ebe8e2;
    --group: #fdfcfa;
    --menu: #fdfcfa;
    --field: #ffffff;
    --fill-1: rgba(60, 45, 25, .04);
    --fill-2: rgba(60, 45, 25, .065);
    --fill-3: rgba(60, 45, 25, .1);
    --line: rgba(60, 45, 25, .09);
    --line-2: rgba(60, 45, 25, .14);
    --line-3: rgba(60, 45, 25, .24);
    --field-line: #86828c;
    --field-line-hover: #6f6b76;
    --text: #1c1b1f;
    --text-2: #545259;
    --text-3: #69666e;
    --accent: #5a45d6;
    --accent-fill: #6350e0;
    --on-accent: #ffffff;
    --accent-soft: rgba(99, 80, 224, .085);
    --accent-line: rgba(90, 69, 214, .3);
    --accent-glow: rgba(110, 90, 230, .24);
    --primary: #1c1b1f;
    --primary-hover: #000000;
    --on-primary: #ffffff;
    --mine-1: #ece8fb;
    --mine-2: #e7e2f8;
    --mine-edge: rgba(90, 69, 214, .1);
    --on-mine: #1c1b1f;
    --on-mine-2: #5c5770;
    --mine-accent: #4a37bf;
    --mine-quote: rgba(90, 69, 214, .06);
    --mine-quote-bar: #7d6fd6;
    --bubble: #ffffff;
    --bubble-for: #fcfbff;
    --bubble-line: rgba(60, 45, 25, .07);
    --quote: rgba(60, 45, 25, .05);
    --owner: #835500;
    --owner-soft: rgba(214, 150, 40, .12);
    --owner-line: rgba(160, 105, 0, .36);
    --mod: #0a6b5a;
    --mod-soft: rgba(16, 150, 120, .1);
    --mod-line: rgba(10, 107, 90, .3);
    --bot: #0d638c;
    --bot-soft: rgba(30, 140, 200, .08);
    --bot-line: rgba(13, 99, 140, .28);
    --warn: #a93a1e;
    --warn-soft: rgba(225, 100, 70, .1);
    --warn-line: rgba(169, 58, 30, .32);
    --warn-glow: rgba(225, 100, 70, .22);
    --amber: #964a00;
    --amber-soft: rgba(214, 150, 40, .12);
    --hot: #a93a1e;
    --on-hot: #ffffff;
    --danger: #ad2139;
    --danger-soft: rgba(190, 40, 70, .08);
    --danger-line: rgba(173, 33, 57, .3);
    --danger-fill: #c42d45;
    --ok: #0a6b5a;
    --bar: rgba(245, 243, 239, .97);
    --bar-solid: #f5f3ef;
    --seg-on: #ffffff;
    --switch-off: #e6e2dc;
    --scrim: rgba(40, 30, 20, .26);
    --toast: #232227;
    --toast-ink: #f5f3ef;
    --skel: rgba(60, 45, 25, .055);
    --skel-hi: rgba(255, 255, 255, .75);
    --mark-core: #fbfaf7;
    --mark-hi: #ffffff;
    --mark-rim: rgba(120, 90, 230, .14);
    --mark-ink: rgba(60, 45, 25, .2);
    --glow-cool: rgba(130, 110, 240, .1);
    --glow-warm: rgba(130, 110, 240, .05);
    --glow-type: rgba(110, 90, 230, .12);
    --av-bg-s: 42%; --av-bg-l: 91%; --av-ink-s: 42%; --av-ink-l: 30%;
    --shadow-1: 0 1px 2px rgba(60, 45, 25, .08);
    --shadow-2: 0 10px 30px -12px rgba(60, 45, 25, .28), 0 0 0 1px rgba(60, 45, 25, .06);
    --shadow-3: 0 30px 70px -24px rgba(60, 45, 25, .38), 0 0 0 1px rgba(60, 45, 25, .06);
  }
}

/* Continuous (squircle) corners where the browser can draw them. The radii grow a little so the curve reads the same. */
@supports (corner-shape: squircle) {
  :root { --r-sm: 14px; --r-md: 19px; --r-lg: 25px; --r-xl: 32px; }
  .group, .q-item, .ban, .people-list, .log-list, .stack-empty, .dialog, .menu, .pin-welcome, .pin-msg, .notice-card,
  .input, .q-body, .dialog-quote, .banner, .reply-chip, .mention-list, .rules-card, .mod-nav, .seg, .ban details,
  .ban-reason, .q-ai, .form-note, .sheet-list, .code-value-box, .dialog-icon, .list-loader > span {
    corner-shape: squircle;
  }
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; background: var(--bg); }
html, body { margin: 0; min-height: 100%; }
/* body stays transparent so the fixed glow layer (z-index -1) shows; html carries the solid colour. */
body {
  background: transparent;
  color: var(--text);
  font: 400 var(--t-body)/1.47 var(--font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
  text-rendering: optimizeLegibility;
}
[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
button, input, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
button { cursor: pointer; }
button:disabled { cursor: default; }
code { font-family: var(--mono); }
blockquote { margin: 0; }
::selection { background: var(--accent-soft); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }
a:focus-visible { border-radius: 4px; }

.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.copy-buffer { position: fixed; left: -9999px; top: 0; width: 1px; height: 1px; opacity: 0; }
.icon {
  width: 20px; height: 20px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.icon-dots { stroke-width: 3.2; }

/* ---------- the light in the room ---------- */
/* One soft light source, as if the screen were a lit object on a dark table. Fixed, so it never scrolls. */
.glow { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.glow::before, .glow::after { content: ""; position: absolute; border-radius: 50%; }
.glow::before {
  width: 760px; height: 520px; left: 50%; top: -300px; margin-left: -380px;
  background: radial-gradient(closest-side, var(--glow-cool), transparent);
}
.glow::after {
  width: 520px; height: 360px; left: 50%; top: -220px; margin-left: -140px;
  background: radial-gradient(closest-side, var(--glow-warm), transparent);
}
/* In the room the light sits behind the mark in the top bar. */
body[data-view="chat"] .glow::before { left: 0; margin-left: -300px; top: -320px; }
body[data-view="chat"] .glow::after { left: 0; margin-left: -120px; top: -240px; }

/* ---------- the ring (the room's mark) ---------- */
.brand-mark, .overlay-mark {
  --size: 44px; --w: 2px; --spin: 24s;
  position: relative; display: inline-grid; place-items: center; flex: none; isolation: isolate;
  width: var(--size); height: var(--size); border-radius: 50%;
  background: radial-gradient(circle at 50% 28%, var(--mark-hi), var(--mark-core) 72%);
  box-shadow: inset 0 0 calc(var(--size) * .22) var(--mark-rim);
}
/* the ring itself: it holds still while the room is connected and idle */
.brand-mark::before, .overlay-mark::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: var(--ring);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--w) - .75px), #000 calc(100% - var(--w)));
  mask: radial-gradient(farthest-side, transparent calc(100% - var(--w) - .75px), #000 calc(100% - var(--w)));
}
/* its light, spilling softly inward and outward */
.brand-mark::after, .overlay-mark::after {
  content: ""; position: absolute; inset: calc(var(--size) * -.2); border-radius: 50%; z-index: -1;
  background: var(--ring);
  -webkit-mask: radial-gradient(farthest-side, transparent 50%, #000 68%, transparent 96%);
  mask: radial-gradient(farthest-side, transparent 50%, #000 68%, transparent 96%);
  filter: blur(calc(var(--size) * .1)); opacity: .5;
  transition: opacity var(--d3) var(--ease);
}
@keyframes halo-turn { to { transform: rotate(1turn); } }
.brand-mark-sm { --size: 28px; --w: 1.75px; }
.brand-mark-sm::after { opacity: .38; }
.brand-mark-md { --size: 40px; }
.brand-mark-xl { --size: 76px; --w: 2.5px; }
.brand-mark-xl::after { opacity: .62; }
/* While the room (re)connects, the mark in the top bar becomes the loader: a comet runs round it. */
body.is-connecting .topbar .brand-mark::before { background: var(--comet); animation: halo-turn 1.6s linear infinite; }
body.is-connecting .topbar .brand-mark::after { opacity: .22; }
/* While the room is closed or full the mark breathes, slowly. */
body:is(.room-closed, .room-full) .brand-mark { animation: breathe 4.8s var(--ease-io) infinite; }
body:is(.room-closed, .room-full) .brand-mark::after { animation: glow-breathe 4.8s var(--ease-io) infinite; }
@keyframes breathe { 50% { transform: scale(.955); } }
@keyframes glow-breathe { 50% { opacity: .2; } }
/* The mark shows the room's state: amber while it is closed or full for today; grey while the live connection
   is down (a grey comet while it reconnects); its own colours when connected and open. */
body:is(.room-closed, .room-full) .brand-mark { --mark-rim: var(--shut-rim); }
body:is(.room-closed, .room-full) .brand-mark::before,
body:is(.room-closed, .room-full) .brand-mark::after { background: var(--ring-shut); }
.brand-mark { transition: filter var(--d3) var(--ease), opacity var(--d3) var(--ease); }
body.is-offline .brand-mark { filter: grayscale(1); opacity: .72; }

/* ---------- loaders ---------- */
/* The signature loader: a comet running round a faint ring, in the ring's own colours. */
.halo-spin {
  --size: 18px; --w: 2px;
  position: relative; display: inline-block; flex: none; width: var(--size); height: var(--size); border-radius: 50%;
  filter: drop-shadow(0 0 3px var(--accent-glow));
}
.halo-spin::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  box-shadow: inset 0 0 0 var(--w) var(--line-2);
}
.halo-spin::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: var(--comet);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--w) - .75px), #000 calc(100% - var(--w)));
  mask: radial-gradient(farthest-side, transparent calc(100% - var(--w) - .75px), #000 calc(100% - var(--w)));
  animation: halo-turn 1.4s linear infinite;
}
.halo-spin-lg { --size: 64px; --w: 2.5px; display: grid; place-items: center; filter: drop-shadow(0 0 10px var(--accent-glow)); }
.halo-spin-lg::after { animation-duration: 1.8s; }
.halo-core {
  position: absolute; inset: 9px; border-radius: 50%;
  background: radial-gradient(circle at 50% 28%, var(--mark-hi), var(--mark-core) 72%);
  box-shadow: inset 0 0 12px var(--mark-rim);
  animation: core-breathe 1.8s var(--ease-io) infinite;
}
@keyframes core-breathe { 50% { transform: scale(.9); opacity: .75; } }

/* skeleton shimmer: a soft highlight sweeps over each placeholder (transform only) */
.skel-avatar, .skel-line, .skel-bubble, .list-loader > span { position: relative; overflow: hidden; background: var(--skel); }
.skel-avatar::after, .skel-line::after, .skel-bubble::after, .list-loader > span::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 25%, var(--skel-hi) 50%, transparent 75%);
  transform: translateX(-100%);
  animation: shimmer 1.9s var(--ease-io) infinite;
}
@keyframes shimmer { 0% { transform: translateX(-100%); } 65%, 100% { transform: translateX(100%); } }

/* ---------- buttons ---------- */
.btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: var(--tap); padding: 0 var(--s5);
  border: 0; border-radius: var(--r-pill);
  font-weight: 600; font-size: var(--t-subhead); line-height: 1.2; text-decoration: none; white-space: nowrap;
  --busy-ink: currentColor;
  transition: transform var(--d1) var(--ease), background-color var(--d2) var(--ease), color var(--d2), box-shadow var(--d2), opacity var(--d2);
}
.btn:hover { text-decoration: none; }
.btn .icon { width: 17px; height: 17px; }
.btn:active:not(:disabled) { transform: scale(.98); }
.btn:disabled { opacity: .5; }
.btn-block { width: 100%; }
.btn-lg { min-height: 52px; font-size: var(--t-headline); }
.btn-primary { color: var(--on-primary); background: var(--primary); --busy-ink: var(--on-primary); }
.btn-primary:hover:not(:disabled) { background: var(--primary-hover); }
a.btn-primary, a.btn-primary:hover { color: var(--on-primary); }
.btn-secondary { color: var(--text); background: var(--fill-3); }
.btn-secondary:hover:not(:disabled) { background: color-mix(in srgb, var(--fill-3), var(--text) 6%); }
.btn-ghost { color: var(--text); background: var(--fill-2); }
.btn-ghost:hover:not(:disabled) { background: var(--fill-3); }
.btn-tinted { color: var(--accent); background: var(--accent-soft); }
.btn-tinted:hover:not(:disabled) { background: color-mix(in srgb, var(--accent-soft), var(--accent) 4%); }
.btn-danger { color: var(--on-danger); background: var(--danger-fill); --busy-ink: var(--on-danger); }
.btn-danger:hover:not(:disabled) { filter: brightness(1.07); }
.btn-danger-ghost { color: var(--danger); background: var(--danger-soft); }
.btn-danger-ghost:hover:not(:disabled) { background: color-mix(in srgb, var(--danger-soft), var(--danger) 8%); }
.btn-ok { color: var(--on-accent); background: var(--accent); --busy-ink: var(--on-accent); }
.btn-ok:hover:not(:disabled) { background: color-mix(in srgb, var(--accent), var(--text) 8%); }
.btn-sm { min-height: 34px; padding: 0 14px; font-size: var(--t-footnote); gap: 6px; }
.btn-sm .icon { width: 15px; height: 15px; }
.btn-xs { min-height: 28px; padding: 0 11px; font-size: var(--t-caption); gap: 5px; }
.btn-xs .icon { width: 13px; height: 13px; }
/* busy: the label steps aside for a small ring */
.btn.is-busy { color: transparent !important; }
.btn.is-busy .icon { visibility: hidden; }
.btn.is-busy::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%;
  background: conic-gradient(from 0turn, transparent .1turn, var(--busy-ink));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.75px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.75px), #000 calc(100% - 2px));
  animation: halo-turn .9s linear infinite;
}
.btn-ghost.is-busy, .btn-secondary.is-busy { --busy-ink: var(--text); }
.btn-tinted.is-busy { --busy-ink: var(--accent); }

.icon-btn {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: var(--tap); height: var(--tap); padding: 0;
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--text-2);
  transition: background-color var(--d2), color var(--d2);
}
@media (hover: hover) { .icon-btn:hover { color: var(--text); background: var(--fill-2); } }
.icon-btn[aria-expanded="true"] { color: var(--accent); background: var(--accent-soft); }

.link-btn {
  display: inline-flex; align-items: center; gap: 5px; min-height: var(--tap); padding: 0 var(--s1);
  border: 0; background: none; color: var(--accent); font-weight: 600; font-size: var(--t-subhead);
  transition: opacity var(--d2);
}
.link-btn:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.link-btn:disabled { opacity: .45; }
.link-btn .icon { width: 17px; height: 17px; stroke-width: 2.1; }

/* chips: the quick choices in a dialog (5 min, 10 min …) */
.chip {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  min-height: 34px; padding: 0 14px; border-radius: var(--r-pill);
  border: 0; background: var(--fill-2); color: var(--text);
  font-size: var(--t-footnote); font-weight: 600;
  transition: background-color var(--d2), color var(--d2);
}
.chip:hover { background: var(--fill-3); }
.chip[aria-pressed="true"] { color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); }
.chip-count:empty { display: none; }
.chip-count {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-pill);
  background: var(--fill-3); color: var(--text-2);
  font-size: var(--t-caption2); font-weight: 700; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums;
}
.chip-count.is-hot { background: var(--hot); color: var(--on-hot); }

.badge {
  display: inline-flex; align-items: center; height: 17px; padding: 0 6px; border-radius: 5px; flex: none;
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; line-height: 1;
  color: var(--text-2); background: var(--fill-2);
  vertical-align: middle;
}
.badge-owner { color: var(--owner); background: var(--owner-soft); }
.badge-mod { color: var(--mod); background: var(--mod-soft); }
.badge-bot { color: var(--bot); background: var(--bot-soft); }
.badge-member { color: var(--text-2); }

/* status tags in the moderator tools: HELD, REPORTED, OPEN, ON WATCH … */
.tag {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: var(--r-pill); flex: none;
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; line-height: 1; white-space: nowrap;
  color: var(--text-2); background: var(--fill-2);
}
.tag-held { color: var(--accent); background: var(--accent-soft); }
.tag-reported { color: var(--owner); background: var(--owner-soft); }
.tag-ok { color: var(--ok); background: var(--mod-soft); }
.tag-danger { color: var(--danger); background: var(--danger-soft); }
.tag-bot { color: var(--bot); background: var(--bot-soft); }
.tag-muted { color: var(--text-2); background: transparent; box-shadow: inset 0 0 0 1px var(--line-3); }

.you-tag {
  display: inline-flex; align-items: center; height: 16px; margin-left: 5px; padding: 0 5px; border-radius: 4px; flex: none;
  font-size: 10px; font-weight: 600; letter-spacing: .03em; color: var(--text-2); background: var(--fill-2);
  vertical-align: 1px;
}

/* ---------- grouped lists (inset, like a phone's settings) ---------- */
.group { position: relative; background: var(--group); border-radius: var(--r-md); }
.group > * { position: relative; }
/* hairlines between rows, inset from the left edge */
.group > * + *::after, .people-list > li + li::after, .log-row + .log-row::after {
  content: ""; position: absolute; top: 0; left: var(--s4); right: 0; height: 1px; background: var(--line); pointer-events: none;
}

/* ---------- form fields ---------- */
.form { display: grid; gap: var(--s4); }
.field { display: grid; gap: var(--s2); }
.field-label { font-size: var(--t-footnote); font-weight: 600; color: var(--text-2); padding-left: 2px; }
.field-help { font-size: var(--t-footnote); color: var(--text-3); line-height: 1.45; padding-left: 2px; }
.field-help-lock { display: flex; gap: var(--s2); align-items: flex-start; }
.field-help-lock .icon { width: 15px; height: 15px; margin-top: 1px; color: var(--mod); }
.input {
  width: 100%; min-height: 50px; padding: 0 var(--s4);
  border: 1px solid var(--field-line); border-radius: var(--r-md);
  background: var(--field); color: var(--text);
  font-size: var(--t-headline); /* 16px or more: no zoom on phones */
  transition: border-color var(--d2), box-shadow var(--d2) var(--ease);
}
.input::placeholder { color: var(--text-3); opacity: 1; }
.input:hover { border-color: var(--field-line-hover); }
/* focus: one accent, with a soft halo of the same colour */
.input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft), 0 6px 24px -10px var(--accent-glow);
}
.input[aria-invalid="true"], .input[aria-invalid="true"]:focus { border-color: var(--warn); background: var(--field); box-shadow: 0 0 0 4px var(--warn-soft); }
.input.is-shaking { animation: shake .36s var(--ease); }
@keyframes shake { 20%, 60% { transform: translateX(-5px); } 40%, 80% { transform: translateX(5px); } }
.input-code { font-family: var(--mono); font-size: 18px; letter-spacing: .02em; text-transform: lowercase; }
.input-code::placeholder { text-transform: none; font-family: var(--mono); font-size: 17px; letter-spacing: .02em; }
.input-otp { font-family: var(--mono); font-size: 24px; letter-spacing: .3em; text-align: center; padding: 0 var(--s3) 0 calc(var(--s3) + .3em); }
.input-otp:placeholder-shown { font-family: var(--font); font-size: var(--t-headline); letter-spacing: normal; padding-left: var(--s3); }
.input-sm { min-height: 36px; width: 78px; padding: 0 26px 0 var(--s3); font-size: var(--t-body); font-variant-numeric: tabular-nums; border-radius: var(--r-sm); }
.input-suffix { position: relative; display: inline-flex; align-items: center; }
.input-suffix > span { position: absolute; right: 11px; color: var(--text-3); font-size: var(--t-footnote); pointer-events: none; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

/* an error sits right under its input, with an icon */
.field-error, .form-error { display: flex; align-items: flex-start; gap: 6px; font-size: var(--t-footnote); line-height: 1.4; color: var(--warn); font-weight: 500; padding-left: 2px; }
.field-error .icon, .form-error .icon { width: 15px; height: 15px; margin-top: 1px; }
.field-error:empty, .form-error:empty { display: none; }

/* a friendly next step (not an error) */
.form-note {
  display: flex; align-items: flex-start; gap: var(--s2); padding: 11px var(--s3);
  border-radius: var(--r-md); background: var(--mod-soft);
  color: var(--text); font-size: var(--t-footnote); font-weight: 500; line-height: 1.45;
}
.form-note .icon { width: 17px; height: 17px; color: var(--ok); }

.check-field { display: grid; gap: 4px; }
.check-row { display: flex; align-items: flex-start; gap: var(--s3); padding: 10px 0; margin: -8px 0; cursor: pointer; }
.check-error { padding-left: 36px; }
.check-box { position: relative; display: inline-grid; place-items: center; width: 24px; height: 24px; margin-top: 1px; flex: none; }
.check-input {
  appearance: none; -webkit-appearance: none; margin: 0; width: 24px; height: 24px; cursor: pointer;
  border: 1.5px solid var(--field-line); border-radius: 7px; background: var(--field);
  transition: background-color var(--d2), border-color var(--d2), box-shadow var(--d2);
}
.check-input:hover { border-color: var(--accent); }
.check-input:checked { background: var(--accent-fill); border-color: transparent; box-shadow: 0 4px 14px -6px var(--accent-glow); }
.check-input[aria-invalid="true"] { border-color: var(--warn); box-shadow: 0 0 0 4px var(--warn-soft); }
.check-mark { position: absolute; width: 16px; height: 16px; color: #fff; stroke-width: 2.8; pointer-events: none; opacity: 0; transform: scale(.6); transition: opacity var(--d1), transform var(--d2) var(--ease); }
.check-input:checked + .check-mark { opacity: 1; transform: none; }
.check-label { padding-top: 1px; font-size: var(--t-subhead); line-height: 1.45; color: var(--text); cursor: pointer; }

/* switches: the checkbox itself is the track; the knob is decoration */
.switch-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  min-height: 52px; padding: 10px var(--s4); cursor: pointer;
}
.switch-text, .slow-label { display: grid; gap: 1px; min-width: 0; }
.switch-title { font-weight: 500; font-size: var(--t-body); color: var(--text); line-height: 1.3; }
.switch-sub { font-size: var(--t-footnote); color: var(--text-3); line-height: 1.35; }
.switch { position: relative; display: inline-flex; flex: none; width: 51px; height: 31px; }
.switch-input {
  appearance: none; -webkit-appearance: none; margin: 0; width: 51px; height: 31px; cursor: pointer;
  border-radius: var(--r-pill); border: 0; background: var(--switch-off);
  box-shadow: inset 0 0 0 1px var(--field-line);
  transition: background-color var(--d3) var(--ease), box-shadow var(--d3);
}
.switch-knob {
  position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%;
  background: var(--knob); pointer-events: none;
  box-shadow: 0 3px 8px rgba(0, 0, 0, .22), 0 1px 1px rgba(0, 0, 0, .16), 0 0 0 .5px rgba(0, 0, 0, .04);
  transition: transform var(--d3) var(--ease);
}
.switch-input:checked { background: var(--accent-fill); box-shadow: inset 0 0 0 1px var(--accent-fill), 0 0 18px -6px var(--accent-glow); }
.switch-input:checked + .switch-knob { transform: translateX(20px); }
.switch-input:active + .switch-knob { width: 31px; }
.switch-input:checked:active + .switch-knob { transform: translateX(16px); }
.switch-warn .switch-input:checked { background: var(--danger-fill); box-shadow: inset 0 0 0 1px var(--danger-fill), 0 0 18px -6px var(--warn-glow); }

/* ---------- entry screens ---------- */
.entry {
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column; align-items: center;
  padding: max(var(--s7), calc(env(safe-area-inset-top) + var(--s5))) var(--pad-r) max(var(--s7), calc(env(safe-area-inset-bottom) + var(--s5))) var(--pad-l);
}
.entry-col { width: 100%; max-width: 380px; display: grid; flex: none; animation: rise .5s var(--ease) both; }
/* Free space splits 1 : 2, so short steps sit in the upper part of the screen instead of the middle. */
.entry::before, .entry::after { content: ""; flex: 1 1 0; }
.entry::after { flex-grow: 2; }
#view-loading::after { flex-grow: 1; }
@keyframes fade-in { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } }

.brand { display: grid; justify-items: center; text-align: center; gap: var(--s3); margin-bottom: var(--s7); }
.brand .brand-mark { margin-bottom: var(--s3); }
.brand .room-name { font: 700 var(--t-large)/1.12 var(--font-display); letter-spacing: -.022em; }
.brand-tag { color: var(--text-2); font-size: var(--t-headline); line-height: 1.4; max-width: 27ch; }
.brand-compact { grid-auto-flow: column; justify-content: center; align-items: center; gap: 10px; margin-bottom: var(--s7); }
.brand-compact .brand-mark { --size: 30px; --w: 1.75px; margin: 0; }
.brand-compact .room-name { font: 600 var(--t-headline)/1.2 var(--font-display); letter-spacing: -.01em; }

.room-status { display: grid; margin-bottom: var(--s7); }
.status-line { display: flex; align-items: flex-start; gap: 10px; padding: 12px var(--s4); font-size: var(--t-subhead); line-height: 1.4; color: var(--text-2); }
.status-line strong { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
.status-line > .icon { width: 17px; height: 17px; margin-top: 1px; color: var(--text-3); }
.status-stack { display: grid; gap: 2px; }
.status-when { font-size: var(--t-footnote); color: var(--text-3); }
.status-dot { width: 8px; height: 8px; margin: 6px 4px 0 5px; border-radius: 50%; background: var(--text-3); flex: none; }
.status-dot.is-open { background: var(--ok); box-shadow: 0 0 0 3px var(--mod-soft), 0 0 10px var(--ok); }
.status-dot.is-closed { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-soft); }
.status-dot.is-low { background: var(--owner); box-shadow: 0 0 0 3px var(--owner-soft); }
.status-wipe.is-soon .icon, .status-wipe.is-soon strong { color: var(--warn); }

.step-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s2); }
.steps { display: flex; gap: 4px; }
.steps span { width: 14px; height: 4px; border-radius: 2px; background: var(--fill-3); transition: width var(--d3) var(--ease), background-color var(--d3); }
.steps .is-done { background: var(--accent-line); }
.steps .is-on { width: 26px; background: var(--accent); box-shadow: 0 0 10px -2px var(--accent-glow); }
.kicker { font-size: var(--t-caption); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-3); }
.entry .kicker { margin: 0; }
.entry-title { font: 700 var(--t-title1)/1.15 var(--font-display); letter-spacing: -.02em; margin-bottom: var(--s5); overflow-wrap: anywhere; }
.entry-lede { color: var(--text-2); font-size: var(--t-subhead); margin: calc(var(--s2) * -1) 0 var(--s5); overflow-wrap: anywhere; }
.entry-lede strong { color: var(--text); font-weight: 600; }
.entry .form { margin-top: var(--s1); }
.entry .form > .btn { margin-top: var(--s2); }

.entry-foot { display: grid; justify-items: center; gap: 2px; margin-top: var(--s7); text-align: center; font-size: var(--t-footnote); color: var(--text-3); }
.entry-foot p { padding: 2px 0; }
.entry-facts { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px 0; margin-bottom: var(--s2); color: var(--text-3); font-size: var(--t-caption); font-weight: 500; letter-spacing: .02em; }
.entry-facts span + span::before { content: "·"; margin: 0 8px; color: var(--text-3); }
.code-foot { gap: 0; }
.resend-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; column-gap: 6px; line-height: 1.4; }
.resend-row .link-btn { min-height: 36px; font-size: var(--t-footnote); }
.resend-note { color: var(--text-3); }
/* "Use my phone number instead": under the box, left-aligned with it */
.contact-switch { justify-self: start; margin-left: calc(var(--s1) * -1); font-size: var(--t-footnote); }

.loading { display: grid; justify-items: center; gap: var(--s5); text-align: center; }
.loading-text { color: var(--text-2); font-size: var(--t-subhead); }

/* ---------- chat layout ---------- */
/* The chat scrolls in one column: the frosted top bar (with pins) sticks at the top and the frosted composer
   sticks at the bottom, so messages slide softly underneath both. Only the bars are blurred. */
body[data-view="chat"] { overflow: hidden; height: 100vh; height: 100dvh; }
.chat { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }
.chat-body { flex: 1; display: flex; min-height: 0; position: relative; }
.chat-main { flex: 1; min-width: 0; display: flex; flex-direction: column; position: relative; }
/* Positioned, so visually hidden labels inside stay inside it instead of stretching the page. */
.scroller {
  position: relative; flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--line-3) transparent;
}

.chat-head { position: sticky; top: 0; z-index: 10; flex: none; padding-top: env(safe-area-inset-top); }
.chat-head::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--bar);
  -webkit-backdrop-filter: blur(20px) saturate(170%); backdrop-filter: blur(20px) saturate(170%);
  box-shadow: 0 1px 0 var(--line);
  opacity: 0; transition: opacity var(--d3) var(--ease);
}
.chat-head.is-scrolled::before { opacity: 1; }

.topbar {
  display: flex; align-items: center; gap: var(--s2);
  height: var(--bar-h);
  padding: 0 max(var(--s2), env(safe-area-inset-right)) 0 var(--pad-l);
}
.room-id { display: flex; align-items: center; gap: 11px; min-width: 0; flex: 1; }
.room-id-text { min-width: 0; }
.room-id .room-name { font: 600 var(--t-headline)/1.2 var(--font-display); letter-spacing: -.012em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.room-sub { display: flex; align-items: center; gap: 6px; margin-top: 1px; font-size: var(--t-caption); line-height: 1.3; color: var(--text-2); white-space: nowrap; min-width: 0; }
.sub-item { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
/* "8 here": a button that opens the list of who is here. It looks like the quiet status text it replaced, with a faint
   dotted underline so it reads as something to tap. The hit area reaches past the line of text (about 34px tall). */
#online { flex: none; }
.sub-here {
  position: relative; padding: 0; border: 0; background: none; color: inherit; font: inherit; line-height: inherit; text-align: left;
}
.sub-here::after { content: ""; position: absolute; inset: -9px -8px; }
.here-count { text-decoration: underline dotted; text-decoration-color: var(--line-3); text-underline-offset: 3px; text-decoration-thickness: 1px; }
.sub-here:hover .here-count { color: var(--text); text-decoration-color: var(--text-3); }
.sub-here[aria-expanded="true"] .here-count { color: var(--accent); }
.sub-here:focus-visible { outline-offset: 4px; border-radius: 4px; }
.sub-item .icon { width: 13px; height: 13px; stroke-width: 2; }
.sub-watch { overflow: hidden; }
.sub-watch > span { overflow: hidden; text-overflow: ellipsis; }
.watch-short { display: none; }
.room-sub.is-short .watch-long { display: none; }
.room-sub.is-short .watch-short { display: inline; }
.room-sub.is-bare #watch-icon { display: none; }
.room-sub.is-min .sub-watch { display: none; }
.room-sub.is-min .sub-item + .sub-item::before { display: none; }
.sub-watch.is-staff { color: var(--mod); }
.sub-watch.is-bot { color: var(--bot); }
.sub-watch.is-none { color: var(--text-3); }
.sub-item + .sub-item::before { content: ""; width: 3px; height: 3px; border-radius: 50%; background: var(--text-3); margin-right: 1px; flex: none; }
.live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 6px var(--ok); flex: none; }
.is-offline .live-dot { background: var(--text-3); box-shadow: none; }

.topbar-actions { display: flex; align-items: center; gap: 4px; flex: none; }

/* the countdown always says what it counts: "5h 11m left" on phones, "Wipes in 5h 11m" when there's room */
.wipe-pill {
  display: inline-flex; align-items: center; gap: 5px; height: 32px; padding: 0 12px 0 10px;
  border-radius: var(--r-pill); background: var(--fill-2); color: var(--text-2);
  font-size: var(--t-footnote); font-weight: 500; white-space: nowrap;
  transition: background-color var(--d3), color var(--d3);
}
.wipe-pill .icon { width: 14px; height: 14px; color: var(--text-3); }
.wipe-pre { display: none; }
.wipe-time { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
.wipe-pill.is-soon { color: var(--warn); background: var(--warn-soft); }
.wipe-pill.is-soon .icon, .wipe-pill.is-soon .wipe-time { color: var(--warn); }
.wipe-pill.is-imminent { animation: imminent 2.4s var(--ease-io) infinite; }
@keyframes imminent { 50% { box-shadow: 0 0 22px -2px var(--warn-glow); } }

/* the moderator button is labelled: "Mod tools" and how many messages wait. The button itself is a full 44px
   target; the pill you see (32px, 34px on touch screens) is drawn inside it. */
.mod-btn {
  --pill-inset: 6px;
  position: relative; isolation: isolate; display: inline-flex; align-items: center; justify-content: center; gap: 6px; flex: none;
  height: var(--tap); min-width: var(--tap); padding: 0 10px 0 9px; border-radius: var(--r-pill);
  border: 0; background: none; color: var(--text);
  font-size: var(--t-footnote); font-weight: 600; white-space: nowrap;
  transition: color var(--d2);
}
.mod-btn::before {
  content: ""; position: absolute; inset: var(--pill-inset) 0; z-index: -1; border-radius: var(--r-pill);
  background: var(--fill-2); transition: background-color var(--d2);
}
.mod-btn:focus-visible { outline: none; }
.mod-btn:focus-visible::before { outline: 2px solid var(--accent); outline-offset: 2px; }
.mod-btn .icon { width: 15px; height: 15px; color: var(--mod); }
.mod-btn:hover::before { background: var(--fill-3); }
.mod-btn[aria-expanded="true"] { color: var(--accent); }
.mod-btn[aria-expanded="true"]::before { background: var(--accent-soft); }
.mod-btn[aria-expanded="true"] .icon { color: var(--accent); }
.count-badge {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-pill);
  background: var(--hot); color: var(--on-hot);
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums;
}

.menu-wrap { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 236px; padding: 6px;
  border-radius: var(--r-md); background: var(--menu);
  box-shadow: var(--shadow-3); transform-origin: top right; animation: pop var(--d2) var(--ease);
}
@keyframes pop { from { opacity: 0; transform: scale(.96); } }
.menu-who { padding: 9px 10px 11px; font-size: var(--t-footnote); color: var(--text-3); overflow-wrap: anywhere; }
.menu-who strong { color: var(--text); font-weight: 600; }
.menu-item {
  position: relative; display: flex; align-items: center; gap: var(--s3); width: 100%; min-height: var(--tap); padding: 0 10px;
  border: 0; border-radius: var(--r-sm); background: none; color: var(--text); text-decoration: none; font-size: var(--t-body); text-align: left;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--fill-2); color: var(--text); text-decoration: none; }
.menu-item .icon { color: var(--text-2); width: 18px; height: 18px; }
.menu-who + .menu-item::before { content: ""; position: absolute; top: -3px; left: 10px; right: 10px; height: 1px; background: var(--line); }

.banners { display: grid; gap: 6px; padding: 0 var(--pad-r) 0 var(--pad-l); }
.banners:has(> :not([hidden])) { padding-bottom: var(--s2); }
.banner {
  width: 100%; max-width: var(--col); margin: 0 auto;
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 9px var(--s4); border-radius: var(--r-md);
  font-size: var(--t-footnote); font-weight: 500; line-height: 1.4; text-align: center;
}
.banner .icon { width: 15px; height: 15px; flex: none; }
.banner-closed { color: var(--warn); background: var(--warn-soft); }
.banner-cap { color: var(--owner); background: var(--owner-soft); }

/* Connecting / reconnecting: a slim row of its own in the header stack, right under the top bar. It takes its
   own space, so it never covers the pinned notes or a message; it fades in a beat late, like the other loaders. */
.conn-row { display: flex; justify-content: center; padding: 0 var(--pad-r) var(--s2) var(--pad-l); animation: loader-in var(--d2) ease .12s both; }
.conn-pill {
  display: inline-flex; align-items: center; gap: 9px; min-width: 0; max-width: min(100%, var(--col)); min-height: 30px;
  padding: 5px 14px 5px 7px; border-radius: var(--r-pill);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-footnote); font-weight: 500; line-height: 1.3; color: var(--text-2); white-space: nowrap;
}
.conn-pill > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.conn-pill .halo-spin { --size: 16px; }

/* the pinned notes: the welcome note and one pinned message, inside the top bar */
.pins { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; padding: 0 var(--pad-r) 10px var(--pad-l); }
.pins > * { width: 100%; min-width: 0; max-width: var(--col); margin-inline: auto; }
.pin-welcome {
  position: relative; display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 4px 10px 12px; border-radius: var(--r-md);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line);
}
.pin-icon { display: grid; place-items: center; width: 28px; height: 28px; margin-top: 1px; border-radius: 50%; flex: none; color: var(--accent); background: var(--accent-soft); }
.pin-icon .icon { width: 15px; height: 15px; }
.pin-body { flex: 1; min-width: 0; display: grid; gap: 1px; padding-top: 1px; max-height: min(34vh, 240px); overflow-y: auto; scrollbar-width: thin; }
.pin-kicker { font-size: var(--t-caption2); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--accent); white-space: nowrap; }
.pin-text { font-size: var(--t-subhead); line-height: 1.45; color: var(--text); white-space: pre-line; overflow-wrap: anywhere; }
.pin-edit { flex: none; margin-top: 1px; }
.pin-toggle { width: 34px; height: 34px; margin: -3px 0; }
.pin-toggle .icon { width: 17px; height: 17px; transform: rotate(180deg); transition: transform var(--d3) var(--ease); }
.pin-toggle[aria-expanded="true"] { color: var(--text-2); background: transparent; }
@media (hover: hover) { .pin-toggle[aria-expanded="true"]:hover { color: var(--text); background: var(--fill-2); } }
.pin-welcome.is-folded { align-items: center; padding-block: 5px; cursor: pointer; }
.pin-welcome.is-folded .pin-icon { margin-top: 0; }
.pin-welcome.is-folded .pin-body { display: flex; align-items: baseline; gap: var(--s2); padding-top: 0; overflow: hidden; }
.pin-welcome.is-folded .pin-text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-2); font-size: var(--t-footnote); }
.pin-welcome.is-folded .pin-toggle .icon { transform: none; }
.pin-welcome.is-folded .pin-edit { display: none; }

.pin-msg {
  display: flex; align-items: center; gap: 4px; min-height: 48px; padding: 3px 6px 3px 3px;
  border-radius: var(--r-md); background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line);
}
.pin-jump {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  min-height: 42px; padding: 0 8px 0 9px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text); text-align: left; transition: background-color var(--d2);
}
.pin-msg { transition: background-color var(--d2); }
.pin-msg:has(.pin-jump:hover) { background: var(--surface-2); }
.pin-badge { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; flex: none; color: var(--accent); background: var(--accent-soft); }
.pin-mark { width: 15px; height: 15px; }
.pin-copy { flex: 1; min-width: 0; display: grid; gap: 0; line-height: 1.3; }
.pin-line { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--t-footnote); color: var(--text-2); }
.pin-name { font-weight: 600; color: var(--text); }
.pin-name::after { content: " · "; font-weight: 400; color: var(--text-3); }
.pin-unpin { flex: none; }

/* the welcome line above the first message */
.tonight {
  display: grid; justify-items: center; gap: 6px; text-align: center;
  width: 100%; max-width: calc(var(--col) + 64px); margin: 0 auto;
  padding: var(--s7) var(--pad-r) var(--s3) var(--pad-l);
}
.tonight-mark { margin-bottom: var(--s2); }
.tonight-title { font-weight: 600; font-size: var(--t-subhead); }
.tonight-text, .tonight-tip { font-size: var(--t-footnote); color: var(--text-3); max-width: 36ch; line-height: 1.45; }
.tonight-tip { display: none; }
.tonight-since { color: var(--text-2); }
@media (hover: none) { .tonight-tip { display: block; } }

.empty { display: none; justify-items: center; text-align: center; padding: var(--s6) var(--s4); }
/* "Quiet so far" only once the room has actually said hello, not while connecting. */
.messages.is-loaded:empty + .empty { display: grid; gap: 4px; }
.empty-mark { display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: var(--s2); border-radius: 50%; color: var(--accent); background: var(--accent-soft); }
.empty-mark .icon { width: 22px; height: 22px; }
.empty-title { font: 600 var(--t-headline)/1.3 var(--font-display); }
.empty-text { color: var(--text-3); font-size: var(--t-subhead); }

/* ---------- messages ---------- */
.messages {
  display: flex; flex-direction: column;
  width: 100%; max-width: calc(var(--col) + 64px); margin: 0 auto;
  padding: 0 var(--pad-r) var(--s3) var(--pad-l);
}
.msg { margin-top: 14px; animation: msg-in var(--d3) var(--ease) both; }
.msg.cont { margin-top: 2px; }
.messages.is-bulk .msg { animation: none; }
.msg.is-quiet { animation: none; }
@keyframes msg-in { from { opacity: 0; transform: translateY(8px) scale(.985); } }

.msg--other { display: grid; grid-template-columns: 30px minmax(0, 1fr); column-gap: 8px; padding-right: 40px; }
.msg-avatar {
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; flex: none;
  font-weight: 600; font-size: 13px; line-height: 1;
  color: hsl(var(--hue, 250) var(--av-ink-s) var(--av-ink-l));
  background: hsl(var(--hue, 250) var(--av-bg-s) var(--av-bg-l));
  text-transform: uppercase; user-select: none;
}
.msg--other > .msg-avatar { margin-top: 23px; }
.hue-0 { --hue: 250; } .hue-1 { --hue: 275; } .hue-2 { --hue: 200; } .hue-3 { --hue: 335; }
.hue-4 { --hue: 165; } .hue-5 { --hue: 22; } .hue-6 { --hue: 295; } .hue-7 { --hue: 42; }
.msg-avatar .icon { width: 17px; height: 17px; }
/* Roles are marked once: a badge and the name's colour. Avatars stay plain (the bot's shows its icon). */
.role-bot .msg-avatar { color: var(--bot); background: var(--bot-soft); }
.msg.cont .msg-avatar { visibility: hidden; height: 0; margin: 0; }

.msg-head { display: flex; align-items: center; gap: 6px; min-width: 0; height: 16px; margin: 0 0 3px 12px; font-size: var(--t-caption); line-height: 16px; }
.msg-name { font-weight: 600; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.role-owner .msg-name { color: var(--owner); }
.role-mod .msg-name { color: var(--mod); }
.role-bot .msg-name { color: var(--bot); }
.msg.cont .msg-head { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

.msg-main { min-width: 0; }
.msg-row { position: relative; display: flex; align-items: center; gap: 4px; min-width: 0; width: fit-content; max-width: 100%; }
.bubble {
  position: relative; min-width: 0; max-width: min(100%, 540px);
  padding: 8px 12px 8px 13px; border-radius: 19px;
  background: var(--bubble); box-shadow: inset 0 0 0 1px var(--bubble-line);
}
.msg--other.cont .bubble { border-top-left-radius: 6px; }
.msg--other.has-next .bubble { border-bottom-left-radius: 6px; }
.msg-body { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; font-size: var(--t-body); line-height: 1.4; }
.msg-time { float: right; margin: 5px 0 -3px 10px; font-size: var(--t-caption2); line-height: 1.4; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.role-bot .bubble { background: linear-gradient(var(--bot-soft), var(--bot-soft)), var(--bubble); }
.role-bot .msg-time { color: var(--text-2); }

.msg--mine { display: flex; flex-direction: column; align-items: flex-end; padding-left: 48px; }
.msg--mine .msg-head { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.msg--mine .msg-row { flex-direction: row-reverse; }
.msg--mine .bubble {
  color: var(--on-mine);
  background: linear-gradient(180deg, var(--mine-1), var(--mine-2));
  box-shadow: inset 0 0 0 1px var(--mine-edge);
}
.msg--mine.cont .bubble { border-top-right-radius: 6px; }
.msg--mine.has-next .bubble { border-bottom-right-radius: 6px; }
.msg--mine .msg-time { color: var(--on-mine-2); }

.msg--mine.is-held .bubble { color: var(--text); background: transparent; box-shadow: none; outline: 1.5px dashed var(--accent-line); outline-offset: -1.5px; }
.msg--mine.is-held .msg-time { color: var(--text-3); }
.msg-status { display: inline-flex; align-items: center; gap: 5px; margin: 5px 4px 0 0; font-size: var(--t-caption); color: var(--text-3); }
.msg-status .icon { width: 13px; height: 13px; color: var(--accent); }

/* Reported and pinned show quietly beside the time. */
.msg:has(.act-report.is-done) .msg-time::before { content: "Reported · "; color: var(--warn); }

/* Per-message actions. With a mouse: a small bar beside the bubble (on its open side, level with its top) on
   hover or focus, so it never covers the message above or its own text. On touch: tap the message to show
   labelled pills under it. The buttons are always in the message's DOM. */
.msg-acts { display: flex; flex: none; gap: 2px; }
.act {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: 32px; height: 30px; padding: 0 7px; border: 0;
  background: none; color: var(--text-2); border-radius: var(--r-pill); font-size: var(--t-footnote); font-weight: 600;
  transition: background-color var(--d1), color var(--d1);
}
.act .icon { width: 16px; height: 16px; }
.act:hover { color: var(--text); background: var(--fill-2); }
.act-report:hover { color: var(--warn); }
.act.is-done { color: var(--warn); }
.act.is-done .icon { fill: currentColor; }
.act-pin:hover, .act-reply:hover { color: var(--accent); }
.act.is-on { color: var(--accent); }
.act.is-on .icon { fill: currentColor; }
.act-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (hover: hover) {
  /* The bar keeps its place in the row (it is only invisible until wanted), so a long bubble makes room for it. */
  .msg-row { align-items: flex-start; }
  .msg-acts {
    position: relative; z-index: 3; align-self: flex-start; margin-top: 2px; padding: 2px;
    border-radius: var(--r-pill); background: var(--menu); box-shadow: var(--shadow-2);
    opacity: 0; transform: scale(.94);
    transition: opacity var(--d1) var(--ease), transform var(--d2) var(--ease);
  }
  .msg--other .msg-acts { transform-origin: left center; }
  .msg--mine .msg-acts { transform-origin: right center; }
  .msg:hover .msg-acts, .msg-acts:focus-within { opacity: 1; transform: none; }
  /* The bar sits in the space the side gutter used to hold. */
  .msg--other { padding-right: 0; }
  .msg--mine { padding-left: 0; }
}
/* A narrow window with a mouse has no room beside a wide bubble for the bar (and a reply's quote can't shrink
   enough to make room), so here the bar floats at the message's own outer edge, level with the top of its
   bubble: beside a short bubble, over the top corner of a long one, never over the message above. */
@media (hover: hover) and (max-width: 599px) {
  .msg--other { position: relative; padding-right: 40px; }
  .msg--mine { position: relative; padding-left: 48px; }
  .msg-row { position: static; }
  .msg-acts { position: absolute; right: 0; }
  .msg--mine .msg-acts { right: auto; left: 0; }
}
@media (hover: none) {
  .msg-row { flex-wrap: wrap; width: auto; }
  .msg--mine .msg-row { justify-content: flex-start; }
  .msg-acts {
    flex-basis: 100%; flex-wrap: wrap; gap: 6px; margin: 0;
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .msg--mine .msg-acts { justify-content: flex-end; }
  .msg.show-acts .msg-acts, .msg-acts:focus-within {
    position: static; width: auto; height: auto; overflow: visible; clip-path: none; margin: 6px 0 2px;
    animation: fade-in var(--d2) ease;
  }
  .msg.show-acts .bubble { box-shadow: inset 0 0 0 1px var(--accent-line), 0 0 0 3px var(--accent-soft); }
  .act { height: 44px; padding: 0 16px 0 14px; background: var(--fill-2); color: var(--text); }
  .act-report { color: var(--warn); }
  .act-label { position: static; width: auto; height: auto; overflow: visible; clip-path: none; }
}

/* system notices */
.msg--system { display: flex; justify-content: center; margin-top: var(--s5); margin-bottom: var(--s1); }
.notice {
  display: inline-flex; align-items: center; gap: var(--s2); max-width: min(100%, 500px);
  padding: 6px 14px; border-radius: var(--r-pill);
  font-size: var(--t-footnote); color: var(--text-2); text-align: center;
  background: var(--fill-1); box-shadow: inset 0 0 0 1px var(--line);
}
.notice .icon { width: 14px; height: 14px; color: var(--text-3); }
.notice-time { color: var(--text-3); font-size: var(--t-caption2); font-variant-numeric: tabular-nums; }

.notice-card {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 3px var(--s3); width: min(100%, 480px);
  padding: 14px var(--s4) var(--s3); border-radius: var(--r-lg); text-align: left;
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line);
}
.notice-card .notice-icon { grid-row: span 3; display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; }
.notice-card .notice-icon .icon { width: 19px; height: 19px; }
.notice-kicker { font-size: var(--t-caption2); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; }
.notice-body { font-size: var(--t-subhead); line-height: 1.45; color: var(--text); overflow-wrap: anywhere; }
.notice-card .notice-time { justify-self: start; }
.notice--warn { box-shadow: inset 0 0 0 1px var(--warn-line), 0 0 40px -18px var(--warn-glow); }
.notice--warn .notice-icon { color: var(--warn); background: var(--warn-soft); }
.notice--warn .notice-kicker { color: var(--warn); }
.notice--code { box-shadow: inset 0 0 0 1px var(--accent-line), 0 0 44px -18px var(--accent-glow); }
.notice--code .notice-icon { color: var(--accent); background: var(--accent-soft); }
.notice--code .notice-kicker { color: var(--accent); }
.notice-code-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin: 6px 0 4px; }
.notice-code {
  padding: 6px 13px; border-radius: var(--r-sm);
  font-family: var(--mono); font-size: 18px; font-weight: 600; letter-spacing: .01em; color: var(--text);
  background: var(--fill-2); overflow-wrap: anywhere; -webkit-user-select: all; user-select: all;
}
.notice-copy { min-width: 88px; }
/* Phone: the icon sits beside the kicker only, so the code and its Copy button get the full width on one line. */
@media (max-width: 479px) {
  .notice--code .notice-icon { grid-row: auto; width: 30px; height: 30px; }
  .notice--code .notice-icon .icon { width: 16px; height: 16px; }
  .notice--code .notice-kicker { align-self: center; }
  .notice--code .notice-code-row, .notice--code .notice-body { grid-column: 1 / -1; }
}
/* A 320px phone: a slightly smaller code keeps even dragonfly-buttercup-42 on one line. */
@media (max-width: 359px) { .notice-code { padding: 6px 10px; font-size: 16px; } }
.copy-btn.is-done, .notice-copy.is-done { color: var(--ok); background: var(--mod-soft); }

/* activity lines: small, centred and quiet */
.msg--event { display: flex; justify-content: center; margin-top: var(--s3); }
.msg--event + .msg--event { margin-top: 3px; }
.event-line {
  display: inline-flex; align-items: baseline; flex-wrap: wrap; justify-content: center; column-gap: 6px;
  max-width: min(100%, 500px); padding: 0 var(--s3);
  font-size: var(--t-caption); line-height: 1.5; color: var(--text-3); text-align: center; overflow-wrap: anywhere;
}
.event-time { font-size: var(--t-caption2); font-variant-numeric: tabular-nums; color: var(--text-3); }

/* @mentions, and messages that are for me */
.mention { color: var(--accent); font-weight: 600; }
.mention.is-me { padding: 0 3px; margin: 0 -1px; border-radius: 5px; background: var(--accent-soft); }
.msg--mine .mention { color: var(--mine-accent); }
.msg--mine.is-held .mention { color: var(--accent); text-decoration: none; }
/* For me: the bubble wears the ring. */
.msg.is-for-me .bubble {
  border: 1.5px solid transparent; padding: 6.5px 10.5px 6.5px 11.5px;
  background: linear-gradient(var(--bubble-for), var(--bubble-for)) padding-box, var(--ring) border-box;
  box-shadow: 0 0 26px -10px var(--accent-glow);
}

/* a reply's quote: who and one line, above the message */
.bubble.has-quote { min-width: min(100%, 210px); }
.msg-quote {
  display: grid; width: 0; min-width: 100%; margin: 1px 0 6px; padding: 5px 10px 6px 12px;
  border: 0; border-radius: 11px; box-shadow: inset 2.5px 0 0 var(--accent);
  background: var(--quote); color: var(--text-2); text-align: left; font-size: var(--t-footnote); line-height: 1.35;
}
button.msg-quote { transition: background-color var(--d2); }
button.msg-quote:hover { background: var(--fill-3); }
.msg-quote-name { font-weight: 600; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-quote-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-quote.is-removed { font-style: italic; color: var(--text-2); box-shadow: inset 2.5px 0 0 var(--line-3); }
.msg--mine .msg-quote { background: var(--mine-quote); box-shadow: inset 2.5px 0 0 var(--mine-quote-bar); color: var(--on-mine-2); }
.msg--mine .msg-quote-name { color: var(--mine-accent); }
.msg--mine .msg-quote.is-removed { color: var(--on-mine-2); }
.msg--mine button.msg-quote:hover { background: color-mix(in srgb, var(--mine-quote), var(--on-mine) 6%); }
.msg--mine.is-held .msg-quote { background: var(--quote); box-shadow: inset 2.5px 0 0 var(--accent); color: var(--text-2); }
.msg--mine.is-held .msg-quote-name { color: var(--accent); }

/* A message reached from a quote or the pinned bar: an accent outline lights round it for a moment. */
.msg.is-flash .bubble::after {
  content: ""; position: absolute; inset: -4px; border-radius: 23px; pointer-events: none;
  box-shadow: 0 0 0 2px var(--accent), 0 0 14px -2px var(--accent-glow);
  animation: flash-out 1.7s ease-in forwards;
}
@keyframes flash-out { 0%, 45% { opacity: 1; } 100% { opacity: 0; } }

/* skeleton messages before the room says hello */
.skeleton { display: grid; gap: 14px; padding-top: var(--s3); }
.skel-row { display: flex; align-items: flex-start; gap: 8px; }
.skel-mine { justify-content: flex-end; }
.skel-event { justify-content: center; }
.skel-stack { display: grid; gap: 3px; }
.skel-mine .skel-stack { justify-items: end; }
.skel-avatar { width: 30px; height: 30px; margin-top: 19px; border-radius: 50%; flex: none; }
.skel-name { width: 64px; height: 10px; margin: 3px 0 6px 12px; border-radius: 5px; }
.skel-bubble { height: 38px; border-radius: 19px; }
.skel-cont { border-top-left-radius: 6px; }
.skel-line.skel-w6 { width: 128px; height: 10px; border-radius: 5px; }
.skel-w1 { width: min(58vw, 250px); }
.skel-w2 { width: min(46vw, 190px); }
.skel-w3 { width: min(52vw, 220px); }
.skel-w4 { width: min(64vw, 290px); }
.skel-w5 { width: min(34vw, 140px); }
.skel-row:nth-child(2) ::after { animation-delay: .1s; }
.skel-row:nth-child(3) ::after { animation-delay: .2s; }
.skel-row:nth-child(4) ::after { animation-delay: .3s; }
.skel-row:nth-child(5) ::after { animation-delay: .4s; }

/* ---------- composer ---------- */
.composer-wrap {
  position: sticky; bottom: 0; z-index: 8; flex: none; margin-top: auto;
  padding: var(--s2) var(--pad-r) max(var(--s2), env(safe-area-inset-bottom)) var(--pad-l);
}
.composer-wrap::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background: var(--bar);
  -webkit-backdrop-filter: blur(20px) saturate(170%); backdrop-filter: blur(20px) saturate(170%);
  transition: box-shadow var(--d3);
}
.composer-wrap.is-over::before { box-shadow: 0 -1px 0 var(--line); }
/* While @mention suggestions are open they float over everything in the chat, the top bar and pins included,
   so on a short screen (a phone with its keyboard up) no name is hidden behind the header. */
.composer-wrap:has(#mention-list:not([hidden])) { z-index: 11; }
/* While typing, a faint light rises behind the message box. It fades out before the one-line note under the box,
   so that small grey line always sits on the plain bar and keeps its contrast. */
.composer-wrap::after {
  --meta-clear: calc(max(var(--s2), env(safe-area-inset-bottom)) + 26px);
  content: ""; position: absolute; z-index: -1; left: 50%; bottom: 0; width: min(760px, 100%); height: 100%;
  transform: translateX(-50%);
  background: radial-gradient(60% 90% at 50% 70%, var(--glow-type), transparent);
  -webkit-mask-image: linear-gradient(to top, transparent var(--meta-clear), #000 calc(var(--meta-clear) + 18px));
  mask-image: linear-gradient(to top, transparent var(--meta-clear), #000 calc(var(--meta-clear) + 18px));
  opacity: 0; transition: opacity var(--d3) var(--ease); pointer-events: none;
}
.composer-wrap:has(.composer:focus-within)::after { opacity: .55; }
.composer-wrap:has(#msg:not(:placeholder-shown))::after { opacity: 1; }

.new-pill {
  position: absolute; left: 50%; bottom: calc(100% + 10px); z-index: 5; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 var(--s4) 0 var(--s3);
  border-radius: var(--r-pill); border: 0;
  background: var(--menu); color: var(--accent); font-weight: 600; font-size: var(--t-footnote);
  /* one line always: as a centred absolute box it would otherwise only get half the width to wrap in */
  white-space: nowrap;
  box-shadow: var(--shadow-2), 0 0 24px -8px var(--accent-glow);
  animation: pill-in var(--d3) var(--ease);
}
.new-pill::after { content: ""; position: absolute; inset: -4px 0; }
.new-pill .icon { width: 15px; height: 15px; stroke-width: 2.2; }
/* Something new is for me: the pill says so, with the same tinted chip as an @mention of my name. */
.new-pill.is-for-me { box-shadow: var(--shadow-2), inset 0 0 0 1px var(--accent-line), 0 0 26px -6px var(--accent-glow); }
.new-pill-for { margin-left: 1px; padding: 1px 7px; border-radius: 6px; background: var(--accent-soft); }
@keyframes pill-in { from { opacity: 0; transform: translate(-50%, 8px); } }

/* The tip, the reply chip and the box, stacked; @mention suggestions open above the whole stack. */
.composer-stack { position: relative; max-width: var(--col); margin: 0 auto; }
.composer {
  position: relative; max-width: var(--col); margin: 0 auto;
  display: flex; align-items: flex-end; gap: var(--s2);
  min-height: 52px; padding: 3px 3px 3px var(--s4);
  border-radius: 26px; border: 1px solid var(--field-line);
  background: var(--field);
  transition: border-color var(--d2), box-shadow var(--d3) var(--ease);
}
.composer:hover { border-color: var(--field-line-hover); }
/* focus: one accent edge and a thin ring of the same colour; the soft light behind while you type is the wrap's
   own glow (above), which stays clear of the note line under the box */
.composer:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.composer.is-disabled { opacity: .65; }

/* "Replying to NAME: …" sits right above the message box. */
.reply-chip {
  max-width: var(--col); margin: 0 auto 8px; display: flex; align-items: center; gap: var(--s2);
  padding: 3px 3px 3px 12px; border-radius: var(--r-md);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line), inset 2.5px 0 0 var(--accent);
  font-size: var(--t-footnote); color: var(--text-2);
  animation: rise-in var(--d2) var(--ease);
}
.reply-chip > .icon { width: 15px; height: 15px; color: var(--accent); }
.reply-chip-text { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reply-chip-text strong { color: var(--text); font-weight: 600; }
.reply-close { display: grid; place-items: center; width: 36px; height: 36px; flex: none; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--text-2); }
.reply-close:hover { background: var(--fill-2); color: var(--text); }
.reply-close .icon { width: 15px; height: 15px; }
@keyframes rise-in { from { opacity: 0; transform: translateY(6px); } }

/* "Not sent: it mentions a price." The check flagged a message before it went out: change it, or send it anyway. */
.flag-card {
  max-width: var(--col); margin: 0 auto 8px; display: flex; align-items: center; gap: var(--s2);
  padding: 10px 10px 10px 12px; border-radius: var(--r-md);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line), inset 2.5px 0 0 var(--warn);
  font-size: var(--t-footnote); color: var(--text-2);
  animation: rise-in var(--d2) var(--ease);
}
.flag-card > .icon { width: 16px; height: 16px; flex: none; align-self: flex-start; margin-top: 2px; color: var(--warn); }
.flag-text { flex: 1; min-width: 0; }
.flag-title { color: var(--text); font-weight: 600; }
.flag-sub { margin-top: 2px; color: var(--text-3); font-size: var(--t-caption); line-height: 1.35; }
.flag-acts { display: flex; gap: 6px; flex: none; }
@media (max-width: 480px) {
  .flag-card { flex-wrap: wrap; }
  .flag-acts { width: 100%; justify-content: flex-end; }
}

/* "Tap a message to reply or report it.": once a day on touch screens, for people who missed the intro. */
.tap-tip {
  max-width: var(--col); margin: 0 auto 8px; display: flex; align-items: center; gap: var(--s2);
  padding: 0 0 0 12px; border-radius: var(--r-pill);
  background: var(--fill-1); box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-footnote); line-height: 1.35; color: var(--text-2);
  animation: rise-in var(--d2) var(--ease);
}
.tap-tip > .icon { width: 15px; height: 15px; color: var(--accent); }
.tap-tip-text { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tap-tip-close { display: grid; place-items: center; width: 34px; height: 34px; flex: none; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--text-2); }
.tap-tip-close:hover { background: var(--fill-2); color: var(--text); }
.tap-tip-close .icon { width: 14px; height: 14px; }

/* Notes from the room that are for me (a time-out, a new name), and any note too long for the one line under
   the box: shown whole, above the box, until closed (a time-out's note goes by itself when the time-out ends).
   A second note stacks under the first instead of replacing it. */
.note-stack { display: grid; gap: 6px; max-width: var(--col); margin: 0 auto 8px; }
.note-stack:empty { display: none; }
.note-card {
  --note-ink: var(--warn);
  display: flex; align-items: flex-start; gap: var(--s2);
  padding: 3px 3px 3px 12px; border-radius: var(--r-md);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--line), inset 2.5px 0 0 var(--note-ink);
  font-size: var(--t-footnote); line-height: 1.4; color: var(--text);
  animation: rise-in var(--d2) var(--ease);
}
.note-card[data-tone="held"] { --note-ink: var(--accent); }
.note-card[data-tone="ok"] { --note-ink: var(--ok); }
.note-card > .icon { width: 15px; height: 15px; margin-top: 10px; color: var(--note-ink); }
.note-card-text { flex: 1; min-width: 0; padding: 7px 0; overflow-wrap: anywhere; }
.note-card-close { display: grid; place-items: center; width: 36px; height: 36px; flex: none; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--text-2); }
.note-card-close:hover { background: var(--fill-2); color: var(--text); }
.note-card-close .icon { width: 15px; height: 15px; }

/* @mention suggestions open upward, above the reply chip when there is one, so "Replying to …" stays in view.
   Six rows at most; on a short screen (a phone with its keyboard up) the list is capped and scrolls. */
.mention-list {
  position: absolute; left: 4px; bottom: calc(100% + 8px); z-index: 6;
  width: min(290px, calc(100% - 8px)); max-height: min(288px, 40vh); max-height: min(288px, 40dvh); margin: 0; padding: 5px; list-style: none;
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
  border-radius: var(--r-md); background: var(--menu);
  box-shadow: var(--shadow-3); transform-origin: bottom left; animation: pop var(--d2) var(--ease);
}
.mention-opt { display: flex; align-items: center; gap: 10px; min-height: 42px; padding: 0 10px; border-radius: var(--r-sm); cursor: pointer; color: var(--text); }
.mention-opt:hover { background: var(--fill-2); }
.mention-opt[aria-selected="true"] { background: var(--accent-soft); }
.mention-opt[aria-selected="true"] .mention-name { color: var(--accent); }
.mention-opt .msg-avatar { width: 26px; height: 26px; font-size: 12px; }
.mention-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; font-size: var(--t-subhead); }

/* auto-growing textarea: the hidden ::after mirrors the text and sizes the grid cell */
.grow { flex: 1; min-width: 0; display: grid; max-height: 132px; overflow-y: auto; scrollbar-width: thin; }
.grow::after { content: attr(data-value) " "; visibility: hidden; white-space: pre-wrap; overflow-wrap: anywhere; }
.grow > textarea, .grow::after { grid-area: 1 / 1 / 2 / 2; padding: 11px 0 10px; font: 400 16px/1.45 var(--font); }
.grow > textarea {
  resize: none; overflow: hidden; border: 0; background: transparent; color: var(--text); min-height: 44px;
  overflow-wrap: anywhere;
}
.grow > textarea:focus { outline: none; }
.grow > textarea::placeholder { color: var(--text-3); }

.send-btn {
  position: relative; flex: none; display: grid; place-items: center;
  width: var(--tap); height: var(--tap); padding: 0; border: 0; border-radius: 50%;
  color: var(--on-accent); background: var(--accent);
  box-shadow: 0 6px 18px -8px var(--accent-glow);
  transition: transform var(--d1) var(--ease), background-color var(--d2) var(--ease), color var(--d2), box-shadow var(--d2), opacity var(--d2);
}
.send-btn:hover:not(:disabled) { box-shadow: 0 6px 22px -6px var(--accent-glow); }
.send-btn:active:not(:disabled) { transform: scale(.92); }
.send-btn .send-icon { width: 20px; height: 20px; stroke-width: 2.3; transition: opacity var(--d2), transform var(--d2) var(--ease); }
/* Nothing typed yet: the button rests, quiet. */
.composer:has(#msg:placeholder-shown) .send-btn:not(.is-waiting):not(.is-sending) { background: var(--fill-3); color: var(--text-2); box-shadow: none; }
.send-btn:disabled { cursor: default; opacity: .55; box-shadow: none; }
.send-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; opacity: 0; }
.send-count { position: absolute; font-family: var(--mono); font-size: 14px; font-weight: 600; opacity: 0; }
.send-btn.is-waiting { opacity: 1; background: var(--fill-2); color: var(--text); box-shadow: none; }
.send-btn.is-waiting .send-ring { opacity: 1; }
.send-btn.is-waiting .send-icon { opacity: 0; }
.send-btn.is-waiting .send-count { opacity: 1; }
/* Sending: the arrow steps aside and a small comet orbits inside the button until the server answers.
   It fades in a beat late, so a quick send doesn't flash. */
.send-btn.is-sending { opacity: 1; background: var(--surface-3); color: var(--text); box-shadow: none; }
.send-btn.is-sending .send-icon { opacity: 0; transform: translateY(-6px); }
.send-spin { position: absolute; inset: 0; border-radius: 50%; animation: loader-in var(--d2) ease .12s both; }
.send-spin::before {
  content: ""; position: absolute; inset: 7px; border-radius: 50%;
  background: var(--comet);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.75px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.75px), #000 calc(100% - 2px));
  animation: halo-turn 1.1s linear infinite;
}
.send-dot {
  position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 8px var(--accent-glow);
  animation: dot-breathe 1.1s var(--ease-io) infinite alternate;
}
@keyframes dot-breathe { from { transform: scale(.55); opacity: .6; } }
@keyframes loader-in { from { opacity: 0; } }

/* The line under the composer is always exactly one line, so the composer never changes height when a note
   comes or goes. While a note shows on a phone, the slow-mode chip shortens to its icon and seconds; a note
   longer than the line ends in an ellipsis (its full text is its title, and it is read out in full). */
.composer-meta {
  max-width: var(--col); margin: 6px auto 0; padding: 0 var(--s3) 0 var(--s4);
  display: flex; flex-wrap: nowrap; align-items: center; gap: var(--s3); height: 18px;
  font-size: var(--t-caption); line-height: 18px; color: var(--text-3);
}
.hint { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.hint > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.hint .icon { width: 14px; height: 14px; }
.slow-word { white-space: pre; }
@media (max-width: 599px) {
  .composer-meta:has(.hint:not([data-tone="rest"])) .slow-word {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
  }
}
.hint[data-tone="held"] { color: var(--accent); }
.hint[data-tone="warn"], .hint[data-tone="err"] { color: var(--warn); }
.hint[data-tone="ok"] { color: var(--ok); }
.meta-end { display: inline-flex; align-items: center; gap: var(--s3); margin-left: auto; flex: none; }
.counter { font-family: var(--mono); font-variant-numeric: tabular-nums; flex: none; }
.counter.is-low { color: var(--warn); }
.slow-chip { display: inline-flex; align-items: center; gap: 4px; flex: none; white-space: nowrap; }
.slow-chip .icon { width: 13px; height: 13px; }
.slow-chip.is-waiting { color: var(--accent); }

/* ---------- toasts ---------- */
.toasts {
  position: fixed; z-index: 70; left: 50%; bottom: calc(112px + env(safe-area-inset-bottom)); transform: translateX(-50%);
  width: min(400px, calc(100% - 32px)); display: grid; gap: 8px; justify-items: center; pointer-events: none;
}
.toast {
  display: inline-flex; align-items: center; gap: var(--s2); max-width: 100%; padding: 10px 16px 10px 13px; border-radius: var(--r-pill);
  background: var(--toast); color: var(--toast-ink); box-shadow: var(--shadow-3);
  font-size: var(--t-footnote); font-weight: 500; animation: toast-in var(--d3) var(--ease);
  transition: opacity .3s, transform .3s var(--ease);
}
.toast .icon { width: 16px; height: 16px; color: var(--toast-ok); stroke-width: 2.2; }
.toast.is-err .icon { color: var(--toast-warn); }
.toast.is-leaving { opacity: 0; transform: translateY(6px) scale(.98); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px) scale(.97); } }
/* The phone sheet covers the composer, so toasts can sit lower; a docked panel leaves the composer in view. */
body.mod-open:not(.mod-docked) .toasts { bottom: calc(var(--s6) + env(safe-area-inset-bottom)); }

/* ---------- moderator tools ---------- */
.scrim { position: fixed; inset: 0; z-index: 30; background: var(--scrim); animation: fade-in var(--d3) ease; }

.mod-panel {
  position: fixed; z-index: 40; left: 0; right: 0; bottom: 0; top: calc(env(safe-area-inset-top) + 10px);
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-grouped);
  border-radius: 22px 22px 0 0;
  box-shadow: var(--shadow-3);
  animation: sheet-up .32s var(--ease);
  container: modpanel / inline-size;
}
@keyframes sheet-up { from { transform: translateY(48px); opacity: 0; } }
.mod-head {
  position: relative; display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s3);
  padding: 26px max(var(--s3), env(safe-area-inset-right)) var(--s3) max(var(--s5), env(safe-area-inset-left));
}
.mod-head::before {
  content: ""; position: absolute; top: 7px; left: 50%; width: 36px; height: 5px; margin-left: -18px; border-radius: 3px; background: var(--fill-3);
}
.mod-kicker { font-size: var(--t-caption); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); margin-bottom: 2px; }
.mod-title { font: 700 var(--t-title1)/1.1 var(--font-display); letter-spacing: -.02em; }
.close-btn::before { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--fill-2); transition: background-color var(--d2); }
.close-btn:hover { background: transparent; }
.close-btn:hover::before { background: var(--fill-3); }
.close-btn .icon { position: relative; width: 16px; height: 16px; stroke-width: 2.4; }

/* The section index: a segmented control of equal segments; the section in view is the raised one, with a
   small accent bar under its label. Counts sit inline; only a waiting queue gets a badge. Even the widest panel
   has no room for seven equal segments with their counts in one row, so it is two rows of equal segments: three
   and three, and the owner's seven as four and three, the second row centred under the first (every segment the
   same width, so it still reads as one control). */
.mod-nav {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px;
  margin: 0 var(--s4) var(--s3); padding: 2px;
  border-radius: 10px; background: var(--fill-2);
}
.seg-item {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: 0;
  min-height: 34px; padding: 0 6px; border: 0; border-radius: 8px;
  background: transparent; color: var(--text); font-size: var(--t-footnote); font-weight: 500; white-space: nowrap;
  transition: background-color var(--d2) var(--ease), box-shadow var(--d2);
}
.seg-item:hover { background: var(--fill-2); }
.seg-item[aria-current="true"] { background: var(--seg-on); font-weight: 600; box-shadow: 0 1px 4px rgba(0, 0, 0, .18), 0 0 0 .5px var(--line); }
.seg-item[aria-current="true"]::after {
  content: ""; position: absolute; left: 50%; bottom: 3px; width: 14px; height: 2.5px; margin-left: -7px;
  border-radius: var(--r-pill); background: var(--accent);
}
.seg-item .chip-count {
  min-width: 0; height: auto; padding: 0; border-radius: 0; background: none;
  color: var(--text-2); font-size: var(--t-footnote); font-weight: 500; line-height: inherit;
}
.seg-item .chip-count.is-hot {
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--r-pill);
  background: var(--hot); color: var(--on-hot); font-size: 10.5px; font-weight: 700; line-height: 16px;
}
body.is-owner .mod-nav { grid-template-columns: repeat(8, minmax(0, 1fr)); }
body.is-owner .mod-nav > .seg-item { grid-column: span 2; }
body.is-owner .mod-nav > .seg-item:nth-child(5) { grid-column: 2 / span 2; }
@media (max-width: 374px) { .mod-nav { margin-inline: var(--s3); } }
.mod-scroll {
  position: relative;
  flex: 1; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--s2) max(var(--s4), env(safe-area-inset-right)) calc(var(--s8) + env(safe-area-inset-bottom)) max(var(--s4), env(safe-area-inset-left));
  display: grid; gap: 28px; align-content: start;
  scroll-padding-top: var(--s3);
  scrollbar-width: thin; scrollbar-color: var(--line-3) transparent;
}
.mod-card { min-width: 0; }
.mod-h-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); min-height: 28px; margin-bottom: 6px; padding: 0 2px 0 var(--s4); }
.mod-h {
  display: flex; align-items: center; gap: var(--s2); min-width: 0;
  font-size: var(--t-footnote); font-weight: 400; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3);
}
.mod-h:focus { outline: none; }
.mod-note { font-size: var(--t-footnote); color: var(--text-3); margin: 0 0 var(--s2); padding: 0 var(--s4); line-height: 1.45; }
.mod-note:empty { display: none; }
.mod-foot { margin: var(--s2) 0 0; }
.h-count:empty { display: none; }
/* counts beside a section's name are plain; only a waiting queue gets a badge */
.h-count { font-size: var(--t-footnote); font-weight: 400; letter-spacing: 0; color: var(--text-3); font-variant-numeric: tabular-nums; }
.h-count.is-hot {
  min-width: 20px; padding: 0 7px; border-radius: var(--r-pill); text-align: center;
  font-size: var(--t-caption); font-weight: 700; line-height: 20px; background: var(--hot); color: var(--on-hot);
}
.owner-only { display: none; }
body.is-owner .seg-item.owner-only { display: inline-flex; }
body.is-owner .mod-card.owner-only { display: block; }
body.is-owner .cap-step.owner-only { display: flex; }
body:not(.is-staff) .staff-only { display: none; }
.mod-card > .group + .group { margin-top: var(--s3); }

/* door codes */
.code-box {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label copy" "code copy";
  align-items: center; gap: 1px var(--s3); padding: 11px 12px 11px var(--s4); min-width: 0;
}
.code-label { grid-area: label; font-size: var(--t-caption2); font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--text-3); }
.code-value { grid-area: code; font-family: var(--mono); font-size: 18px; line-height: 1.35; font-weight: 600; color: var(--text); overflow-wrap: anywhere; user-select: all; }
.code-box-next .code-value { color: var(--text-2); }
.code-box .copy-btn { grid-area: copy; }
.copy-btn { min-width: 76px; }

.cap { display: grid; gap: 8px; padding: 12px var(--s4) 14px; }
.cap-line { font-size: var(--t-subhead); color: var(--text-2); }
.cap-line strong { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.cap-meter { display: block; width: 100%; height: 6px; overflow: visible; }
.cap-track { fill: var(--fill-3); }
.cap-fill { fill: var(--accent); }
.cap-fill.is-low { fill: var(--amber); }
.cap-left { color: var(--text-3); }
/* Daily cap (owner): minus / number / plus */
.cap-step { align-items: center; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; padding: 10px 12px 10px var(--s4); }
.stepper { display: inline-flex; align-items: center; flex: none; border-radius: 9px; background: var(--fill-2); padding: 2px; }
.step-btn { display: grid; place-items: center; width: 40px; min-height: 32px; padding: 0; border: 0; border-radius: 7px; background: transparent; color: var(--text); transition: background-color var(--d2), color var(--d2); }
.step-btn:hover:not(:disabled) { background: var(--fill-2); }
.step-btn:active:not(:disabled) { background: var(--fill-3); }
.step-btn:disabled { color: var(--text-3); opacity: .55; }
.step-btn .icon { width: 15px; height: 15px; stroke-width: 2.3; }
.input.step-input { width: 56px; min-height: 32px; padding: 0 4px; border: 0; border-radius: 7px; background: transparent; text-align: center; font-weight: 600; font-size: var(--t-body); }
.input.step-input:focus { background: var(--field); box-shadow: inset 0 0 0 1.5px var(--accent); }

.row-action {
  display: flex; align-items: center; gap: var(--s3); width: 100%; min-height: 50px; padding: 10px var(--s4);
  border: 0; background-color: transparent; color: var(--accent); font-size: var(--t-body); font-weight: 500; text-align: left;
  border-radius: var(--r-md) var(--r-md) 0 0; transition: background-color var(--d2);
}
.row-action:hover { background-color: var(--fill-1); }
.row-action .icon { width: 19px; height: 19px; }

/* room and the bot */
.slow-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; padding: 10px 12px 10px var(--s4); }
.slow-controls { display: flex; align-items: center; gap: var(--s2); }
.facts { list-style: none; margin: 0; padding: 12px var(--s4); display: grid; gap: 8px; }
.facts li { display: flex; align-items: flex-start; gap: 10px; font-size: var(--t-subhead); color: var(--text-2); line-height: 1.45; }
.facts .icon { width: 17px; height: 17px; margin-top: 1px; color: var(--bot); }
.facts li.is-off .icon { color: var(--text-3); }

.stack { display: grid; gap: 10px; }
.stack-empty { display: flex; align-items: center; gap: 10px; padding: 14px var(--s4); border-radius: var(--r-md); font-size: var(--t-subhead); color: var(--text-2); background: var(--group); list-style: none; }
.stack-empty .icon { width: 17px; height: 17px; color: var(--ok); }

/* queue cards */
.q-item, .ban {
  display: grid; gap: 10px; padding: 14px var(--s4); border-radius: var(--r-md);
  background: var(--group); min-width: 0;
}
.q-item { animation: rise var(--d3) var(--ease); }
.q-item.is-leaving { opacity: .4; pointer-events: none; transition: opacity var(--d2); }
.q-item.is-gone, .person.is-gone, .ban.is-gone { opacity: .7; }
.is-gone .btn { visibility: hidden; }
.has-gone { position: relative; }
.has-gone > :not(.gone-note), .has-gone > .q-decide, .has-gone > .q-person { visibility: hidden; }
.has-gone > .gone-note { position: absolute; inset: 0; }
.gone-note { display: flex; align-items: center; gap: 6px; font-size: var(--t-footnote); font-weight: 500; color: var(--text-2); }
.gone-note .icon { width: 15px; height: 15px; color: var(--ok); }
.q-staff-note { display: flex; align-items: flex-start; gap: 6px; font-size: var(--t-footnote); color: var(--text-3); line-height: 1.45; }
.q-staff-note .icon { width: 15px; height: 15px; margin-top: 1px; color: var(--mod); }
.q-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; min-width: 0; }
.q-head .tag { margin-left: auto; }
.q-name { font-weight: 600; color: var(--text); font-size: var(--t-body); overflow-wrap: anywhere; }
.q-name.role-owner, .who.role-owner { color: var(--owner); }
.q-name.role-mod, .who.role-mod { color: var(--mod); }
.who.role-bot { color: var(--bot); }
.q-time { font-size: var(--t-caption); color: var(--text-3); font-variant-numeric: tabular-nums; }
.q-body {
  font-size: var(--t-body); line-height: 1.42; padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--fill-1); box-shadow: inset 2.5px 0 0 var(--line-3);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.q-item.is-held .q-body { box-shadow: inset 2.5px 0 0 var(--accent); }
.q-item.is-live .q-body { box-shadow: inset 2.5px 0 0 var(--owner); }
.q-item.is-hidden .q-body { box-shadow: inset 2.5px 0 0 var(--warn); }
.q-why { font-size: var(--t-footnote); color: var(--text-2); line-height: 1.45; }
.q-ai, .log-ai { display: flex; gap: 8px; align-items: flex-start; font-size: var(--t-footnote); line-height: 1.45; color: var(--text-2); }
.q-ai { padding: 8px 10px; border-radius: var(--r-sm); background: var(--accent-soft); }
.q-ai .icon, .log-ai .icon { width: 15px; height: 15px; margin-top: 1px; color: var(--accent); }
.q-ai.ai-allow { background: var(--mod-soft); }
.q-ai.ai-remove { background: var(--danger-soft); }
.q-ai.ai-unsure { background: var(--owner-soft); }
.ai-allow strong, .ai-allow .icon { color: var(--ok); }
.ai-remove strong, .ai-remove .icon { color: var(--danger); }
.ai-unsure strong, .ai-unsure .icon { color: var(--owner); }
.q-actions { display: grid; gap: 8px; margin-top: 2px; }
.q-decide { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.q-decide .btn { width: 100%; }
.q-person { display: flex; justify-content: flex-end; gap: 6px; }
.q-actions .btn-sm { padding: 0 12px; }
.btn-ban:hover:not(:disabled) { color: var(--danger); background: var(--danger-soft); }

/* people: one inset list, a row per person */
.people-list { list-style: none; margin: 0; padding: 0; display: grid; background: var(--group); border-radius: var(--r-md); }
.people-list > .stack-empty { background: transparent; }
.person { position: relative; display: grid; gap: 10px; padding: 12px var(--s4); min-width: 0; container: person / inline-size; }
.person:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; }
.person:last-child { border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; }
/* Line one is the person: avatar, name and badge (never split apart), then "That's you" or "Muted until 10:45 PM".
   It has the whole width, because every button lives on the row below. */
.person-top { display: flex; align-items: center; gap: 10px; min-width: 0; }
.person-top .msg-avatar { width: 32px; height: 32px; flex: none; }
.person-id { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 3px 8px; }
.person-tag { display: inline-flex; align-items: flex-start; gap: 6px; min-width: 0; max-width: 100%; }
.person-tag .badge { flex: none; margin-top: 3px; }
/* Only a name wider than the whole line wraps, after an underscore where it can. */
.person-name { font-weight: 600; font-size: var(--t-body); min-width: 0; overflow-wrap: anywhere; }
.role-owner .person-name { color: var(--owner); }
.role-mod .person-name { color: var(--mod); }
.person-sub { display: inline-flex; align-items: center; gap: 4px; font-size: var(--t-caption); color: var(--text-3); white-space: nowrap; }
/* my own row: just a quiet "(you)" after the name */
.person-sub.is-you { font-size: var(--t-footnote); }
/* muted is a "for now" state: amber. Red is kept for bans. */
.person-sub.is-muted { color: var(--amber); font-weight: 600; }
.person-joined { font-variant-numeric: tabular-nums; }
.person-sub .icon { width: 13px; height: 13px; }
/* Mute / Kick / Ban are a row of buttons. The account itself (Reset name, and for the owner
   Make mod / Remove mod) gets a second row of two halves. */
.person-acts { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px; padding-left: 42px; }
.person-acts .btn { grid-column: span 2; min-height: 34px; min-width: 0; padding: 0 8px; }
/* The account row (Reset name, Make mod) is quieter than Mute / Kick / Ban: lighter fill, softer ink. */
.person-acts .person-rename, .person-acts .person-mod {
  grid-column: span 3; min-height: 32px; font-weight: 500; color: var(--text-2); background: var(--fill-1);
}
.person-acts .person-rename:hover:not(:disabled), .person-acts .person-mod:hover:not(:disabled) { color: var(--text); background: var(--fill-2); }
.person-mod .icon, .person-rename .icon { color: var(--text-3); }
/* The role button holds both labels in one cell (the other one invisible), so it is the same width on every card. */
.person-mod .btn-text { display: inline-grid; }
.person-mod .btn-text > * { grid-area: 1 / 1; justify-self: center; }
/* The grid already fixes the button's width, so the reserved second label is not needed here. */
.person-acts .label-ghost { display: none; }
.label-ghost { visibility: hidden; }
@container person (max-width: 330px) { .person-acts { padding-left: 0; } }
/* The narrowest cards (a 320px phone) drop the icons so every label fits. */
@container person (max-width: 249px) {
  .person-acts .btn { padding: 0 6px; }
  .person-acts .icon { display: none; }
}

/* the 24-hour log */
.seg { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); padding: 2px; gap: 2px; margin: 0 0 var(--s3); border-radius: 10px; background: var(--fill-2); max-width: 100%; }
.seg button { position: relative; min-width: 0; min-height: 32px; padding: 0 8px; border: 0; border-radius: 8px; background: transparent; color: var(--text); font-size: var(--t-footnote); font-weight: 500; transition: background-color var(--d2); }
.seg button:hover { background: var(--fill-2); }
.seg button[aria-pressed="true"] { background: var(--seg-on); font-weight: 600; box-shadow: 0 1px 4px rgba(0, 0, 0, .18), 0 0 0 .5px var(--line); }
.seg button[aria-pressed="true"]::after {
  content: ""; position: absolute; left: 50%; bottom: 3px; width: 14px; height: 2.5px; margin-left: -7px;
  border-radius: var(--r-pill); background: var(--accent);
}
.log-list { list-style: none; margin: 0; padding: 0; background: var(--group); border-radius: var(--r-md); }
.log-row { position: relative; display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: var(--s3); padding: 11px var(--s4); font-size: var(--t-footnote); min-width: 0; }
.log-time { color: var(--text-3); font-size: var(--t-caption); padding-top: 1px; font-variant-numeric: tabular-nums; }
.log-text { display: grid; gap: 4px; min-width: 0; overflow-wrap: anywhere; line-height: 1.45; }
.log-line .who { font-weight: 600; }
.log-line .tag { vertical-align: 1px; height: 18px; font-size: 10px; }
.log-act .log-line { color: var(--text-2); }
.log-act .who { color: var(--text); }
.log-kind { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; color: var(--accent); }
.log-quote { padding: 3px 10px; box-shadow: inset 2px 0 0 var(--line-3); color: var(--text-2); font-size: var(--t-footnote); }
.log-detail { font-size: var(--t-caption); color: var(--text-3); }
.log-detail strong { color: var(--text-2); font-weight: 600; }
.log-ai { font-size: var(--t-caption); }
/* activity lines and room notices in the log: no author, just what happened */
.log-quiet .log-line { color: var(--text-2); }
.log-quiet .log-kind { color: var(--text-3); }
.log-ai .icon { width: 13px; height: 13px; }
.log > .stack-empty, .log > .mod-note { margin-top: var(--s2); }

/* ban log */
.ban.is-active .ban-name::before { content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 8px 1px 0; border-radius: 50%; background: var(--danger); }
.ban-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
.ban-name { font-weight: 600; font-size: var(--t-body); overflow-wrap: anywhere; }
.ban-meta { font-size: var(--t-caption); color: var(--text-3); }
.ban-reason { font-size: var(--t-footnote); color: var(--text-2); padding: 8px 12px; border-radius: var(--r-sm); background: var(--fill-1); overflow-wrap: anywhere; }
.ban-reason strong { color: var(--text); }
.ban details { border-radius: var(--r-sm); background: var(--fill-1); }
.ban summary { display: flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 var(--s3); cursor: pointer; font-size: var(--t-footnote); font-weight: 500; color: var(--text-2); list-style: none; }
.ban summary::-webkit-details-marker { display: none; }
.ban summary .icon { width: 15px; height: 15px; transition: transform var(--d2) var(--ease); }
.ban details[open] summary .icon { transform: rotate(180deg); }
.ban-acts { display: flex; }

/* welcome note editor: the textarea is the group's first row; the group takes the accent edge while you type */
.group-editor { border: 1px solid var(--field-line); transition: border-color var(--d2), box-shadow var(--d2); }
.group-editor:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.group-editor .input-area {
  display: block; min-height: 108px; padding: 12px var(--s4); resize: vertical; line-height: 1.5; font-size: var(--t-body);
  border: 0; border-radius: var(--r-md) var(--r-md) 0 0; background: transparent; box-shadow: none;
}
.group-editor .input-area:focus { background: transparent; box-shadow: none; }
.welcome-foot { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2); padding: 8px 10px 8px var(--s4); }
.welcome-count { font-size: var(--t-caption); color: var(--text-3); }
.welcome-btns { display: flex; gap: 6px; margin-left: auto; }

/* activity lines */
.switch-hint { display: flex; align-items: flex-start; gap: 6px; padding: 2px var(--s4) 0; font-size: var(--t-footnote); color: var(--text-3); line-height: 1.45; }
.switch-hint .icon { width: 15px; height: 15px; margin-top: 1px; color: var(--mod); }

/* lists loading in the moderator tools */
.list-loader { display: grid; gap: 8px; }
.list-loader > span { height: 56px; border-radius: var(--r-md); }
.list-loader > span:nth-child(2)::after { animation-delay: .12s; }
.list-loader > span:nth-child(3)::after { animation-delay: .24s; }

/* ---------- overlay (wipe and endings) ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center;
  padding: max(var(--s6), env(safe-area-inset-top)) var(--s6) max(var(--s6), env(safe-area-inset-bottom));
  background: radial-gradient(600px 420px at 50% 32%, var(--glow-cool), transparent 70%), var(--bg);
  animation: fade-in .45s ease;
}
.overlay.is-danger { --ring: conic-gradient(from 200deg, #ffb48f, #ff8f9c, #f6c38a, #ff9f8a, #ffb48f); background: radial-gradient(600px 420px at 50% 32%, var(--warn-soft), transparent 70%), var(--bg); }
.overlay-card { width: 100%; max-width: 380px; display: grid; justify-items: center; text-align: center; gap: var(--s3); animation: rise .6s var(--ease) .1s both; }
.overlay-mark { --size: 92px; --w: 2.5px; margin-bottom: var(--s5); color: var(--text); }
.overlay-mark::after { opacity: .6; }
.overlay-mark .icon { width: 34px; height: 34px; stroke-width: 1.6; }
.overlay-mark.is-moon .icon { fill: currentColor; stroke: none; }
.overlay .kicker { color: var(--accent); }
.overlay.is-danger .kicker { color: var(--warn); }
.overlay-title { font: 700 var(--t-title1)/1.15 var(--font-display); letter-spacing: -.02em; }
.overlay-text { color: var(--text-2); font-size: var(--t-headline); line-height: 1.45; max-width: 32ch; margin-bottom: var(--s5); }
.overlay-link { display: inline-flex; align-items: center; min-height: var(--tap); font-weight: 600; font-size: var(--t-subhead); }
.overlay-foot { font-size: var(--t-footnote); color: var(--text-3); min-height: 1.4em; max-width: 34ch; }

/* ---------- dialogs ---------- */
.dialog {
  width: min(400px, calc(100% - 32px)); max-width: none; max-height: calc(100% - 32px); padding: 0;
  border: 0; border-radius: var(--r-xl);
  background: var(--menu); color: var(--text); box-shadow: var(--shadow-3);
}
.dialog[open] { animation: dialog-in var(--d3) var(--ease); }
@keyframes dialog-in { from { opacity: 0; transform: scale(.96); } }
.dialog::backdrop { background: var(--scrim); }
.dialog-card { display: grid; gap: var(--s3); padding: var(--s6) var(--s5) var(--s5); }
.dialog-icon { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; color: var(--accent); background: var(--accent-soft); }
.dialog-icon .icon { width: 21px; height: 21px; }
.dialog-icon.is-danger { color: var(--warn); background: var(--warn-soft); }
.dialog-title { font: 600 var(--t-title3)/1.25 var(--font-display); letter-spacing: -.012em; overflow-wrap: anywhere; }
.dialog-text { color: var(--text-2); font-size: var(--t-subhead); line-height: 1.45; }
.dialog-text:empty { display: none; }
.dialog-quote {
  margin: 0; padding: 9px 12px; border-radius: var(--r-sm); box-shadow: inset 2.5px 0 0 var(--accent-line);
  background: var(--fill-1); color: var(--text); font-size: var(--t-subhead); overflow-wrap: anywhere;
  max-height: 120px; overflow-y: auto;
}
.dialog-quote:empty { display: none; }
.dialog-quote.is-code { font-family: var(--mono); font-size: var(--t-title3); font-weight: 600; text-align: center; box-shadow: none; background: var(--fill-2); }
.dialog-actions { display: flex; gap: var(--s2); justify-content: flex-end; margin-top: var(--s2); }
.dialog-actions .btn { flex: 1; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chips:empty { display: none; }

.sheet-list { display: grid; background: var(--fill-1); border-radius: var(--r-md); overflow: hidden; }
.sheet-item {
  position: relative; display: flex; align-items: center; gap: var(--s3); min-height: 50px; padding: 0 var(--s4);
  border: 0; background: transparent; color: var(--text);
  font-size: var(--t-body); font-weight: 500; text-align: left; transition: background-color var(--d2);
}
.sheet-item + .sheet-item::after { content: ""; position: absolute; top: 0; left: 48px; right: 0; height: 1px; background: var(--line); }
.sheet-item:hover { background: var(--fill-2); }
.sheet-item .icon { width: 19px; height: 19px; color: var(--text-2); }
.sheet-item.is-danger, .sheet-item.is-danger .icon { color: var(--danger); }
.sheet-item small { margin-left: auto; font-weight: 400; font-size: var(--t-footnote); color: var(--text-2); }

/* Who is here: the grouped list of the mod tools, with the names stacked over "joined 6h ago" so that long names
   and narrow phones both fit. The list scrolls by itself when the room is busy. */
.here-count-line { color: var(--text-2); font-size: var(--t-subhead); font-variant-numeric: tabular-nums; margin-top: calc(var(--s2) * -1); }
.here-list { max-height: min(46vh, 380px); overflow-y: auto; overscroll-behavior: contain; background: var(--fill-1); scrollbar-width: thin; scrollbar-color: var(--line-3) transparent; }
.here-list:empty { display: none; }
.here-list:focus-visible { outline-offset: 2px; }
.here-row { position: relative; display: flex; align-items: center; gap: 10px; min-width: 0; padding: 10px var(--s4); }
.here-row .msg-avatar { width: 32px; height: 32px; flex: none; margin: 0; }
.here-id { display: grid; gap: 1px; min-width: 0; flex: 1; }
.here-who { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 6px; min-width: 0; }
.here-name { font-weight: 600; font-size: var(--t-body); min-width: 0; overflow-wrap: anywhere; }
.role-owner .here-name { color: var(--owner); }
.role-mod .here-name { color: var(--mod); }
.here-you { font-size: var(--t-footnote); color: var(--text-3); }
.ago { font-size: var(--t-footnote); color: var(--text-3); font-variant-numeric: tabular-nums; }
.here-note { color: var(--text-3); font-size: var(--t-footnote); line-height: 1.45; }

/* ---------- rules page ---------- */
.page { padding: 0 var(--pad-r) 0 var(--pad-l); }
.rules { max-width: 680px; margin: 0 auto; padding: max(var(--s8), calc(env(safe-area-inset-top) + var(--s6))) 0 var(--s9); }
.rules-head { display: grid; justify-items: start; gap: var(--s4); margin-bottom: var(--s7); }
.rules-head .brand-mark { --size: 52px; margin-bottom: var(--s2); }
.rules h1 { font: 700 var(--t-large)/1.1 var(--font-display); letter-spacing: -.022em; }
.rules .lede { font-size: var(--t-headline); color: var(--text-2); line-height: 1.5; max-width: 50ch; }
.rules-card { margin-top: var(--s7); }
.rules-card h2 {
  display: flex; align-items: center; gap: var(--s2); margin: 0 0 var(--s2); padding-left: var(--s4);
  font-size: var(--t-footnote); font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--text-2);
}
.rules-card h2 .icon { width: 16px; height: 16px; color: var(--accent); }
.rules ol, .rules ul { margin: 0; padding: 0; list-style: none; display: grid; background: var(--group); border-radius: var(--r-md); }
.rules li { position: relative; padding: 13px var(--s4) 13px 50px; line-height: 1.5; color: var(--text-2); font-size: var(--t-subhead); overflow-wrap: anywhere; }
.rules li + li::after { content: ""; position: absolute; top: 0; left: 50px; right: 0; height: 1px; background: var(--line); }
.rules li strong { color: var(--text); font-weight: 600; }
.rules ol { counter-reset: step; }
.rules ol li { counter-increment: step; }
.rules ol li::before {
  content: counter(step); position: absolute; left: var(--s4); top: 13px; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: var(--t-caption); font-weight: 700; color: var(--accent);
  background: var(--accent-soft);
}
.rules ul li::before { content: ""; position: absolute; left: 24px; top: 21px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 8px var(--accent-glow); }
.rules-card.is-warn h2 .icon { color: var(--warn); }
.rules-card.is-warn ul li::before { background: var(--warn); box-shadow: 0 0 8px var(--warn-glow); }
.rules-card.is-bot h2 .icon { color: var(--bot); }
.rules-card.is-bot ul li::before { background: var(--bot); box-shadow: 0 0 8px var(--bot-line); }
.rules-card.is-temp ul { box-shadow: inset 0 0 0 1px var(--accent-line); }
.rules-back { margin-top: var(--s8); }
/* The quiet link at the very bottom of the rules ("What we keep"). */
.rules-fine { margin-top: var(--s5); font-size: var(--t-footnote); }
.rules-fine a { color: var(--text-3); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* ---------- screenshot deterrence ---------- */
/* A website can't block screenshots or screen recording, and the rules page says so. These are the parts a page can
   do; app.js has the rest (the watermark rows, the blur when the window loses focus, and no copy or right-click
   menu on messages). */

/* No selecting messages, the pinned notes, or the lists of people and held messages. The message box is not in
   this list, so typing, selecting and pasting there work as always. */
.messages, .pins, .reply-chip, .here-list, .q-body, .log-row, .dialog-quote:not(.is-code) {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
/* The door code in a sign-off card sits in the messages but is the room's own, not a person's message: it stays
   selectable, so "copy it by hand" works when the Copy button can't. */
.messages .notice-code { -webkit-touch-callout: default; }

/* The watermark sits under the top bar (z 10) and the message box (z 8), over the messages. It takes no clicks. */
.watermark { position: absolute; inset: 0; z-index: 7; overflow: hidden; pointer-events: none; -webkit-user-select: none; user-select: none; }
.watermark-rows { position: absolute; left: -60%; top: -60%; width: 220%; height: 220%; transform: rotate(-24deg); }
.watermark-row {
  height: 76px; overflow: hidden; white-space: pre;
  font: 600 13px/76px var(--font); letter-spacing: .02em; color: var(--mark-ink);
}
.watermark-row::before { content: attr(data-mark); }
.watermark-row:nth-child(odd) { text-indent: 105px; }

/* The room blurs while the window isn't in front (or for 2 seconds after a screenshot key). It blurs at once and
   comes back with a short fade. */
.tonight, .messages, .empty, .pins, .reply-chip, .here-list, .mod-scroll, .dialog-quote { transition: filter var(--d2) var(--ease); }
body.is-shielded :is(.tonight, .messages, .empty, .pins, .reply-chip, .here-list, .mod-scroll, .dialog-quote) { filter: blur(16px); transition: none; }
/* Over everything on the page but a dialog: above the Mod tools sheet (z 40) and its scrim (z 30). */
.shield-note {
  position: fixed; z-index: 80; left: 50%; top: 42%; transform: translate(-50%, -50%);
  max-width: min(320px, calc(100% - 48px)); padding: 10px 16px; border-radius: var(--r-md);
  background: var(--menu); color: var(--text-2); box-shadow: var(--shadow-2);
  font-size: var(--t-footnote); font-weight: 600; line-height: 1.4; text-align: center; pointer-events: none;
}

/* Printing is turned off: the page prints one line instead of the room. (The rules page can still be printed.) */
.print-note { display: none; }
@media print {
  html, body[data-view] { background: #fff !important; }
  body[data-view] { height: auto !important; overflow: visible !important; }
  body[data-view] > :not(.print-note) { display: none !important; }
  body[data-view] > .print-note { display: block !important; margin: 3cm 0 0; text-align: center; font: 600 20pt/1.3 var(--font); color: #000; }
}

/* ---------- larger screens ---------- */
@media (min-width: 600px) {
  .topbar { padding-left: max(var(--s5), env(safe-area-inset-left)); padding-right: max(var(--s4), env(safe-area-inset-right)); gap: var(--s3); }
  .topbar-actions { gap: 6px; }
  .wipe-pre { display: inline; }
  .wipe-post { display: none; }
  .messages, .tonight { padding-left: var(--s6); padding-right: var(--s6); }
  .composer-wrap, .pins, .banners { padding-left: var(--s6); padding-right: var(--s6); }
  .msg--other { padding-right: 12%; }
  .msg--mine { padding-left: 14%; }
  .mod-panel { left: auto; top: 0; width: 440px; border-radius: 22px 0 0 22px; animation-name: drawer-in; }
  .mod-head::before { display: none; }
  .mod-head { padding-top: var(--s6); }
  .dialog-actions .btn { flex: 0 1 auto; min-width: 108px; }
  .entry-col { max-width: 400px; }
  .rules h1 { font-size: 40px; }
}
@keyframes drawer-in { from { transform: translateX(40px); opacity: 0; } }
@media (max-width: 599px) {
  .dialog { width: 100%; margin: auto 0 0; max-height: 92%; border-radius: 26px 26px 0 0; }
  .dialog[open] { animation: sheet-up .3s var(--ease); }
  .dialog-card { padding-bottom: calc(var(--s5) + env(safe-area-inset-bottom)); }
}
/* Staff on a phone carry two buttons in the top bar, so the extras go: "Moderator here" is them,
   and the labels say enough without icons. The room's mark stays: it shows the room's state to staff too.
   The countdown keeps its word ("2h 42m left") at every width. */
@media (max-width: 479px) {
  body.is-staff .sub-watch { display: none; }
  /* "Mod" is enough on a phone; the button is still named "Mod tools" for screen readers */
  body.is-staff .mod-btn-more { display: none; }
  body.is-staff .wipe-pill { padding: 0 10px; gap: 4px; }
  body.is-staff .wipe-pill .icon, body.is-staff .mod-btn .icon { display: none; }
  body.is-staff .mod-btn { padding: 0 8px 0 11px; gap: 6px; }
  .topbar-actions { gap: 2px; }
  /* the countdown and the Mod pill stay two clear shapes */
  body.is-staff .mod-btn { margin-left: 6px; }
}
@media (max-width: 380px) {
  .wipe-pill { padding: 0 10px 0 8px; }
  .topbar .brand-mark-sm { --size: 24px; }
  .room-id { gap: 9px; }
  body.is-staff .wipe-pill { padding: 0 9px; gap: 3px; }
  body.is-staff .mod-btn { padding: 0 6px 0 9px; gap: 5px; }
}
/* The smallest staff phones (320-374px): a little less air everywhere so the room's name is never cut short. */
@media (max-width: 374px) {
  /* the "…" button's dots sit in the middle of its 44px box, so the bar's right edge can give up a little */
  body.is-staff .topbar { gap: 6px; padding-left: max(var(--s3), env(safe-area-inset-left)); padding-right: max(4px, env(safe-area-inset-right)); }
  body.is-staff .topbar-actions { gap: 2px; }
  body.is-staff .mod-btn { margin-left: 4px; }
  body.is-staff .wipe-pill { padding: 0 7px; }
  body.is-staff .mod-btn { padding: 0 5px 0 8px; }
}
@media (max-width: 345px) {
  body.is-staff .topbar { gap: 4px; }
  body.is-staff .topbar .room-name { font-size: 14.5px; }
  body.is-staff .topbar .brand-mark-sm { --size: 22px; }
  body.is-staff .room-id { gap: 6px; }
  body.is-staff .wipe-pill { padding: 0 6px; }
  body.is-staff .mod-btn { padding: 0 4px 0 8px; gap: 4px; }
}
@media (min-width: 1024px) {
  :root { --panel-w: 420px; }
  .mod-panel {
    position: relative; inset: auto; z-index: 1; width: var(--panel-w); flex: none;
    border-radius: 0; box-shadow: none; border-left: 1px solid var(--line);
    animation: drawer-in var(--d3) var(--ease);
  }
  .mod-head { padding-top: var(--s5); }
  body.mod-docked .scrim { display: none !important; }
  /* With the panel docked, toasts centre over the chat column so they never cover the tools. */
  body.mod-open.mod-docked .toasts { left: calc((100% - var(--panel-w)) / 2); }
}
@media (min-width: 1280px) { :root { --panel-w: 440px; } }

/* Touch: every control is at least 44px tall (and wide where it is an icon). */
@media (pointer: coarse) {
  .btn-sm { min-height: 44px; }
  .btn-xs { min-height: 44px; padding: 0 14px; }
  .chip { min-height: 44px; }
  .seg-item, .seg button { min-height: 44px; }
  .reply-close { width: 44px; height: 44px; margin: -3px 0; }
  .tap-tip-close { width: 44px; height: 44px; margin: -5px 0; }
  .pin-toggle { width: 44px; height: 44px; margin: -5px 0; }
  .pin-msg { min-height: 50px; }
  .pin-jump { min-height: 44px; }
  .mention-opt { min-height: 46px; }
  .person-acts .btn, .person-acts .person-rename, .person-acts .person-mod { min-height: 44px; }
  .step-btn { width: 44px; min-height: 44px; }
  .input.step-input, .input-sm { min-height: 44px; }
  .resend-row .link-btn { min-height: 44px; }
  .ban summary { min-height: 44px; }
  .note-card-close { width: 44px; height: 44px; margin: -4px 0; }
  .wipe-pill { height: 34px; }
  .mod-btn { --pill-inset: 5px; }
}

/* A short screen (a phone with its keyboard up, or held sideways): the header gives the room back to the
   conversation. The welcome note steps aside (it is back as soon as there is room again), the pinned message
   keeps one slim line, and the tap tip waits. */
@media (max-height: 520px) {
  :root { --bar-h: 48px; }
  .pin-welcome, .tap-tip { display: none; }
  .pins:has(> .pin-msg[hidden]) { display: none; }
  .pins { padding-bottom: 6px; }
  .pin-msg { min-height: 0; padding-block: 1px; }
  .pin-copy > .pin-kicker { display: none; }
}

/* A browser that can't blur behind the bars gets solid ones. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .chat-head::before, .composer-wrap::before { background: var(--bar-solid); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
  .input.is-shaking { animation: none; }
  /* Loaders hold still, and settle into a calm, complete ring. */
  [data-loader], [data-loader] *, [data-loader]::before, [data-loader]::after, [data-loader] *::before, [data-loader] *::after { animation: none !important; }
  .halo-spin::after, .send-spin::before { background: var(--ring); }
  body.is-connecting .topbar .brand-mark::before { background: var(--ring); }
  .skel-avatar::after, .skel-line::after, .skel-bubble::after, .list-loader > span::after { display: none; }
  /* The mark is still the ring, just not running or breathing. */
  .brand-mark, .brand-mark::before, .brand-mark::after, .overlay-mark::before, .overlay-mark::after, .wipe-pill { animation: none !important; transform: none !important; }
  /* The outline on a message reached from a quote stays put until it is taken away. */
  .msg.is-flash .bubble::after { animation: none; }
}

@media (forced-colors: active) {
  /* Forced colours make the watermark's ink solid, so it is faded as a whole instead. */
  .watermark { opacity: .14; }
  .watermark-row { color: CanvasText; }
  .bubble, .notice, .notice-card, .group, .q-item, .people-list, .ban, .composer, .pin-msg, .pin-welcome, .dialog, .menu { border: 1px solid CanvasText; }
  .switch-input, .check-input { border: 1px solid CanvasText; }
  .switch-input:checked, .check-input:checked { background: Highlight; }
  .brand-mark::before, .overlay-mark::before { background: CanvasText; }
}

/* ---------- the scene behind the room ---------- */
/* A lava lamp or a few jellyfish (ambient.js), drawn behind everything, under the glow's layer. Each person picks
   it in the menu; "Off" leaves the plain room. It never takes a touch: ambient.js listens on the page instead. */
.ambient { position: fixed; inset: 0; z-index: -1; display: block; width: 100%; height: 100%; pointer-events: none; }
body[data-scene="off"] .ambient { display: none; }
/* Text that sits straight on the scene (no card behind it) gets a soft halo in the page colour, so a blob drifting
   behind it never washes it out. */
body:not([data-scene="off"]) :is(.tonight, .event-line) { text-shadow: 0 0 10px var(--bg), 0 0 3px var(--bg); }

.menu-scene { position: relative; display: grid; gap: 6px; padding: 10px 10px 8px; }
.menu-scene::before { content: ""; position: absolute; top: -3px; left: 10px; right: 10px; height: 1px; background: var(--line); }
.menu-label { font-size: var(--t-caption); font-weight: 600; color: var(--text-3); }
.scene-seg { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; padding: 3px; border-radius: var(--r-sm); background: var(--fill-1); }
.scene-btn {
  min-height: 34px; padding: 0 6px; border: 0; border-radius: var(--r-xs); background: none;
  color: var(--text-2); font-size: var(--t-footnote); font-weight: 600; white-space: nowrap;
  transition: background-color var(--d2), color var(--d2);
}
.scene-btn:hover { background: var(--fill-2); color: var(--text); }
.scene-btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--text); box-shadow: inset 0 0 0 1px var(--accent-line); }
.menu-scene + .menu-item::before { content: ""; position: absolute; top: -3px; left: 10px; right: 10px; height: 1px; background: var(--line); }

/* ---------- name styles ---------- */
/* Each person picks how their name looks; only the name changes, never what they write. The fonts are free to use
   (SIL Open Font License; the licence texts are in /fonts) and come from this site, so nothing loads from elsewhere. */
@font-face { font-family: "Caveat"; src: url("/fonts/caveat-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Lora"; src: url("/fonts/lora-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Nunito"; src: url("/fonts/nunito-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Righteous"; src: url("/fonts/righteous-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Playfair Display"; src: url("/fonts/playfair-display-latin-700-italic.woff2") format("woff2"); font-weight: 700; font-style: italic; font-display: swap; }

.ns-serif { font-family: "Lora", ui-serif, Georgia, serif; font-weight: 600; }
.ns-script { font-family: "Caveat", "Segoe Script", cursive; font-weight: 600; font-size: 1.22em; line-height: 1.05; }
.ns-rounded { font-family: "Nunito", ui-rounded, system-ui, sans-serif; font-weight: 700; }
.ns-retro { font-family: "Righteous", system-ui, sans-serif; font-weight: 400; letter-spacing: .03em; }

/* The owner's name: a slow gold-to-ember shimmer in an italic serif, a little larger, with a small flame. Nobody else
   can pick it; the server hands the owner this style and no one else. */
.ns-owner {
  font-family: "Playfair Display", ui-serif, Georgia, serif; font-style: italic; font-weight: 700; font-size: 1.16em; letter-spacing: .01em;
  background-image: linear-gradient(100deg, var(--shut-1) 0%, var(--ring-1) 24%, var(--shut-2) 48%, var(--ring-2) 72%, var(--shut-1) 100%);
  background-size: 240% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 7px var(--shut-rim));
  animation: owner-shimmer 16s linear infinite;
}
@keyframes owner-shimmer { to { background-position: 240% 0; } }
@media (prefers-color-scheme: light) {
  /* On the light page the gold runs darker, so the name keeps its contrast. */
  .ns-owner { background-image: linear-gradient(100deg, var(--owner) 0%, var(--shut-3) 30%, #9a3f12 55%, var(--shut-3) 78%, var(--owner) 100%); filter: none; }
}
.owner-flame { display: inline-block; width: 14px; height: 14px; margin-right: 3px; vertical-align: -1px; color: var(--shut-2); fill: var(--shut-rim); stroke-width: 1.7; }
.msg-name.ns-owner, .here-name.ns-owner, .person-name.ns-owner { overflow: visible; padding-right: .12em; }
/* Over the owner's messages the name is bigger than the text itself, and their avatar wears a gold ring. */
.msg-name.ns-owner { font-size: 1.33em; line-height: 1.15; }
.msg-name.ns-owner .owner-flame { width: 16px; height: 16px; vertical-align: -2px; }
.role-owner > .msg-avatar { box-shadow: 0 0 0 1.5px var(--shut-2), 0 0 14px var(--shut-rim); }

/* The picker: each choice shows your own name in that style. */
.style-field { margin: 0; padding: 0; border: 0; min-width: 0; }
.style-picks { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: var(--s2); }
.style-pick {
  position: relative; display: grid; gap: 2px; align-content: center; min-height: 60px; padding: 8px 12px;
  border-radius: var(--r-md); background: var(--fill-1); box-shadow: inset 0 0 0 1px var(--line-2); cursor: pointer;
  transition: background-color var(--d2), box-shadow var(--d2);
}
.style-pick:hover { background: var(--fill-2); }
.style-pick input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.style-pick.is-picked { background: var(--accent-soft); box-shadow: inset 0 0 0 1.5px var(--accent-line); }
.style-pick:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.style-sample { min-width: 0; overflow: hidden; color: var(--text); font-size: var(--t-headline); white-space: nowrap; text-overflow: ellipsis; }
/* Caveat runs small, so its sample gets the same lift it has in the chat. */
.style-sample.ns-script { font-size: calc(var(--t-headline) * 1.3); line-height: 1.05; }
.style-label { color: var(--text-3); font-size: var(--t-caption); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .ns-owner { animation: none; }
}
@media print { .ambient { display: none; } }
