/* Palette sampled from the supplied smoke image: pixels sorted by brightness,
   averaged at each percentile. p05 #000000, p25 #040c08, p50 #091811,
   p75 #112a1d, p90 #1c402e, p97 #2f6349, p99.5 #569f7b. --glow is the same
   hue (~150deg) lifted for text and accents that must clear contrast. */

@font-face {
  font-family: 'Bricolage Grotesque';
  src: url('/fonts/bricolage.woff2') format('woff2');
  font-weight: 400 800;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/jetbrains-mono.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}

:root {
  --ink: #000000;
  --night: #040c08;
  --deep: #091811;
  --moss: #112a1d;
  --forest: #1c402e;
  --emerald: #2f6349;
  --mint: #569f7b;
  --glow: #7ee0ae;
  --glow-rgb: 126, 224, 174;

  --text: #e4f1ea;
  --dim: #a3bfb1;
  --faint: #7d998b;
  --danger: #ff8a80;
  --danger-bg: #3a1513;
  --warn: #f2c46b;

  --panel: rgba(4, 12, 8, 0.8);
  --panel-solid: #06110c;
  --line: rgba(86, 159, 123, 0.18);
  --line-strong: rgba(86, 159, 123, 0.36);
  --hover: rgba(86, 159, 123, 0.1);
  --active: rgba(86, 159, 123, 0.18);

  --r-lg: 22px;
  --r-md: 14px;
  --r-sm: 10px;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --font: 'Bricolage Grotesque', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, Consolas, monospace;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--ink);
  color: var(--text);
  font: 400 15px/1.5 var(--font);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
button, input { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; }
[hidden] { display: none !important; }
::selection { background: rgba(var(--glow-rgb), 0.3); }
:focus-visible { outline: 2px solid var(--glow); outline-offset: 2px; }
#root { position: relative; z-index: 1; height: 100dvh; }

/* ---------- Background ---------------------------------------------------- */

.bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--ink);
  contain: strict;
}
/* The still ground: soft green masses on black in the same palette as the
   animated shader. It paints instantly, sits under the canvas while the
   shader starts, and is all that shows in performance mode. */
.bg-base {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(42% 38% at 28% 30%, rgba(47, 99, 73, 0.5), transparent 70%),
    radial-gradient(38% 34% at 72% 68%, rgba(28, 64, 46, 0.6), transparent 70%),
    radial-gradient(30% 26% at 55% 45%, rgba(86, 159, 123, 0.16), transparent 70%),
    radial-gradient(60% 50% at 50% 50%, rgba(9, 24, 17, 0.9), transparent 80%),
    #000;
}
/* The moving smoke, dust and breathing glow are drawn by a worker onto this
   canvas (src/worker/bg.ts), so the page main thread does no work for them.
   History, all measured within one page load:
   - as CSS animations at 60fps: GPU process 767 ms/s (222-967)
   - stepped to 10-15 updates/s: 120 ms/s (87-144)
   - but during a call, every speaking-indicator frame also re-styled the
     looping layers: style work 129 ms/s (88-170) against 33 (17-45) without. */
.bg-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}
.bg-canvas--ready { opacity: 1; }
.bg-veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 50% 35%, transparent 0%, rgba(0, 0, 0, 0.35) 55%, rgba(0, 0, 0, 0.75) 100%),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.45));
}

/* Performance mode: the still image only. */
.perf .bg-canvas { display: none; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}

/* ---------- Shared pieces ---------------------------------------------------- */

.brand { display: flex; align-items: center; gap: 12px; }
.brand-name { font-size: 1.15rem; font-weight: 750; letter-spacing: -0.01em; }
.brand-mark {
  position: relative;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--glow);
  color: #03140c; /* the sound-wave glyph, dark on mint */
  flex: none;
}
/* The ripple and the credit glint play as one short PULSE every few seconds
   (ui.ts adds .pulse to <html>), never as infinite loops. Any infinite
   animation, however small, makes the browser composite a new frame of the
   whole screen 60 times a second. Measured, one page load, GPU-process ms/s:
   with these two looping 87 (80-91), without 28 (22-31). */
.brand-mark::before, .brand-mark::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(var(--glow-rgb), 0.55);
  opacity: 0;
}
.pulse .brand-mark::before { animation: ripple 1.5s var(--ease); }
.pulse .brand-mark::after { animation: ripple 1.5s var(--ease) 0.35s; }
@keyframes ripple {
  from { transform: scale(1); opacity: 0.8; }
  to { transform: scale(2.1); opacity: 0; }
}

.avatar {
  --s: 36px;
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  flex: none;
  display: inline-block;
  overflow: hidden;
  background: var(--moss);
}
.avatar img { width: 100%; height: 100%; display: block; object-fit: cover; }
.avatar--admin { box-shadow: 0 0 0 2px var(--glow); }
/* Blobatars have no disc behind them: the creature itself is the avatar. */
.avatar--blob { background: transparent; border-radius: 0; overflow: visible; }
.avatar--blob svg { display: block; width: 100%; height: 100%; overflow: visible; }
.orb .avatar.avatar--blob { box-shadow: none; } /* beats .orb .avatar: a blob has no disc, so no disc shadow */
/* The library's motion is infinite CSS animation. It only runs while someone can
   be looking: paused when the window is unfocused (in a game), the tab is
   hidden, or performance mode is on. */
.idle .mo-root, .idle .mo-root *, .perf .mo-root, .perf .mo-root * { animation-play-state: paused !important; }

.who { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.who-name { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge {
  font: 750 0.62rem/1 var(--font);
  letter-spacing: 0.06em;
  color: var(--ink);
  background: var(--glow);
  padding: 3px 5px 2px;
  border-radius: 5px;
  flex: none;
}

.icon { display: block; flex: none; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 42px;
  padding: 0 18px;
  border-radius: var(--r-sm);
  font-weight: 650;
  border: 1px solid var(--line-strong);
  transition: background-color 0.18s var(--ease), border-color 0.18s var(--ease), transform 0.12s var(--ease);
}
.btn:hover { background: var(--hover); border-color: var(--mint); }
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.6; cursor: progress; }
.btn--primary { background: var(--glow); border-color: var(--glow); color: #03140c; }
.btn--primary:hover { background: #9aeec3; border-color: #9aeec3; }
.btn--ghost { background: transparent; }
.btn--on { background: var(--active); border-color: var(--mint); }
.btn--danger { color: var(--danger); border-color: rgba(255, 138, 128, 0.35); }
.btn--danger:hover { background: var(--danger-bg); border-color: var(--danger); }
.btn--block { width: 100%; }
.btn--sm { min-height: 34px; padding: 0 12px; font-size: 0.875rem; }
.btn--lg { min-height: 52px; padding: 0 28px; font-size: 1.05rem; border-radius: var(--r-md); }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-sm);
  color: var(--dim);
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
  flex: none;
}
.icon-btn:hover { background: var(--hover); color: var(--text); }
.icon-btn--accent { color: var(--glow); }
.icon-btn--alert { color: var(--danger); }
.icon-btn--alert:hover { color: var(--danger); background: var(--danger-bg); }
.icon-btn--sm { width: 28px; height: 28px; }

.input, .field input, .composer-input {
  width: 100%;
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  background: rgba(0, 0, 0, 0.45);
  font-size: 16px; /* 16px stops iOS zooming into the field */
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.input:focus, .field input:focus, .composer-input:focus {
  outline: none;
  border-color: var(--glow);
  box-shadow: 0 0 0 3px rgba(var(--glow-rgb), 0.18);
}
.input::placeholder, .composer-input::placeholder { color: var(--faint); }

.link { color: var(--glow); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(var(--glow-rgb), 0.4); }
.link:hover { text-decoration-color: var(--glow); }
.hint { color: var(--faint); font-size: 0.875rem; }

/* ---------- Credit --------------------------------------------------------------- */

.credit {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 8px;
  text-decoration: none;
  font-size: 0.8rem;
  color: var(--faint);
}
.credit-name {
  position: relative;
  display: inline-flex;
  overflow: hidden;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.14em;
  color: var(--glow);
  padding: 0 2px;
}
/* A glint runs through the letters one at a time, on each pulse (see the
   note above .brand-mark::before). It fades a pre-drawn bright copy of each
   letter by OPACITY only: animating color + text-shadow instead forced a
   style recalc and a layout every frame (layouts 15.6/s -> 0.4/s when
   removed). A blended light band was tried before that and rendered as a
   grey box. */
.credit-letter { position: relative; display: inline-block; }
.credit-letter::after {
  content: attr(data-ch);
  position: absolute;
  inset: 0;
  color: #f0fff7;
  text-shadow: 0 0 10px rgba(var(--glow-rgb), 0.9);
  opacity: 0;
  pointer-events: none;
}
.pulse .credit-letter::after { animation: glint 0.7s var(--ease) calc(0.5s + var(--i) * 0.07s); }
@keyframes glint {
  0%, 100% { opacity: 0; }
  40% { opacity: 1; }
}
.credit-site {
  position: relative;
  color: var(--dim);
  font-weight: 600;
}
.credit-site::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: var(--glow);
  transform: scaleX(0.25);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}
.credit:hover .credit-site { color: var(--text); }
.credit:hover .credit-site::after { transform: scaleX(1); }
.credit-arrow { display: inline-block; margin-left: 3px; transition: transform 0.35s var(--ease); }
.credit:hover .credit-arrow { transform: translate(2px, -2px); }

/* ---------- Auth -------------------------------------------------------------------- */

.auth {
  height: 100%;
  overflow-y: auto;
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  align-items: center;
  padding: max(24px, env(safe-area-inset-top)) 16px max(20px, env(safe-area-inset-bottom));
  gap: 24px;
}
.auth-card {
  width: min(100%, 420px);
  padding: 30px 28px 24px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(9, 24, 17, 0.88), rgba(4, 12, 8, 0.9));
  border: 1px solid var(--line-strong);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(var(--glow-rgb), 0.08);
}
.auth-card .brand { margin-bottom: 26px; }
.tabs {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 4px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--line);
  margin-bottom: 22px;
}
.tab { position: relative; z-index: 1; min-height: 38px; border-radius: 9px; font-weight: 650; color: var(--dim); transition: color 0.2s var(--ease); }
.tab[aria-selected='true'] { color: #03140c; }
.tab-pill {
  position: absolute;
  top: 4px;
  left: 4px;
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  border-radius: 9px;
  background: var(--glow);
}
.auth-title { margin: 0; font-size: 1.75rem; font-weight: 750; letter-spacing: -0.02em; line-height: 1.15; }
.auth-lede { margin: 6px 0 20px; color: var(--dim); }
.auth-form { display: grid; gap: 14px; }
.auth-fields { display: grid; gap: 14px; }
.field { display: grid; gap: 6px; }
.field-label { font-size: 0.85rem; font-weight: 600; color: var(--dim); }
.field-error { font-size: 0.82rem; color: var(--danger); min-height: 0; }
.field-error:empty { display: none; }
.field--bad input { border-color: var(--danger); }
.form-error { margin: 0; padding: 10px 12px; border-radius: var(--r-sm); background: var(--danger-bg); color: var(--danger); font-size: 0.9rem; }
.auth-form .btn--primary { margin-top: 6px; min-height: 48px; }
.auth-below { margin-top: 16px; text-align: center; font-size: 0.9rem; }

/* ---------- App: the call is the screen ------------------------------------------- */
/* No server rail, no channel sidebar, no member column. A top bar, the room as
   one large stage, the chat as an island beside it, and one floating dock. */

.app {
  --dock-space: 112px; /* room left under the content for the floating dock */
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: 'top' 'stage';
  gap: 14px;
  padding: 14px 18px var(--dock-space);
}
.island {
  background: rgba(6, 17, 12, 0.82);
  border: 1px solid var(--line);
  border-radius: 28px;
  box-shadow: 0 30px 70px -24px rgba(0, 0, 0, 0.75);
}

/* Top bar. The credit sits here rather than at the bottom edge: the top bar is
   the one strip of persistent chrome, and the bottom belongs to the dock. */
.topbar { grid-area: top; display: flex; align-items: center; gap: 18px; min-height: 48px; padding: 0 4px; }
.topbar-credit { flex: 1; display: flex; padding-left: 18px; border-left: 1px solid var(--line); }
.online-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 16px 6px 8px;
  border-radius: 999px;
  background: rgba(6, 17, 12, 0.78);
  border: 1px solid var(--line);
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.online-btn:hover { border-color: var(--line-strong); background: rgba(9, 24, 17, 0.9); }
.stack { display: flex; }
.stack-face { display: block; line-height: 0; margin-left: -9px; border-radius: 50%; box-shadow: 0 0 0 2px var(--panel-solid); }
.stack-face:first-child { margin-left: 0; }
.stack-face.speaking { box-shadow: 0 0 0 2px var(--glow); }
.stack-label { font-size: 0.92rem; font-weight: 650; white-space: nowrap; }
.people { list-style: none; margin: 0; padding: 0; max-height: min(60dvh, 420px); overflow-y: auto; overscroll-behavior: contain; }
.person-btn { display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px; border-radius: var(--r-sm); text-align: left; }
.person-btn:hover { background: var(--hover); }
.person-text { display: grid; min-width: 0; line-height: 1.3; }
.person-where { font-size: 0.8rem; color: var(--faint); }
.person--voice .person-where { color: var(--glow); }

/* Stage: the room */
.stage { grid-area: stage; position: relative; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
.stage-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; padding: 26px 32px 0; }
.stage-title { margin: 0; font-size: clamp(1.75rem, 2.6vw, 2.6rem); font-weight: 800; line-height: 1.02; letter-spacing: -0.03em; text-wrap: balance; }
.stage-meta { margin: 8px 0 0; color: var(--dim); font-size: 0.98rem; }
.stage--joined .stage-meta { color: var(--glow); }
.stage-meta.stage-meta--warn { color: var(--warn); }
.banner { margin: 14px 32px 0; padding: 10px 14px; border-radius: var(--r-sm); background: rgba(242, 196, 107, 0.1); color: var(--warn); font-size: 0.9rem; }
.stage-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 30px;
  padding: 28px 32px 36px;
}
.stage--theater .stage-body { justify-content: flex-start; }
.stage-empty { margin: 0; max-width: 34ch; text-align: center; color: var(--dim); font-size: 1.02rem; }
.join { box-shadow: 0 14px 34px -14px rgba(126, 224, 174, 0.7); }

/* People as orbs */
.orbs { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 30px 36px; max-width: 960px; }
.orb-btn { display: grid; justify-items: center; gap: 10px; padding: 8px; border-radius: 22px; transition: transform 0.25s var(--ease); }
.orb-btn:hover { transform: translateY(-3px); }
.orb-ring { position: relative; display: block; line-height: 0; border-radius: 50%; isolation: isolate; } /* line-height 0: otherwise the ring wraps the line box, not the circle, and sits low */
/* Orb size follows headcount (render sets --orb): a few people own the room. */
.orb .avatar { --s: var(--orb, 112px) !important; box-shadow: 0 0 0 1px var(--line-strong), 0 20px 44px -14px rgba(0, 0, 0, 0.8); }
/* Speaking ring: a pseudo-element faded by opacity and scale, which the
   compositor handles. Toggled up to ten times a second, so it must stay cheap. */
.orb-ring::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 3px solid var(--glow);
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.12s var(--ease), transform 0.12s var(--ease);
}
.orb.speaking .orb-ring::after { opacity: 1; transform: scale(1); }
/* Speech lights the room: a soft mint bloom behind the speaker, opacity only. */
.orb-ring::before {
  content: '';
  position: absolute;
  inset: -45%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--glow-rgb), 0.26), rgba(var(--glow-rgb), 0.08) 55%, transparent);
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}
.orb.speaking .orb-ring::before { opacity: 1; }
.perf .orb-ring::before { display: none; }
.orb--muted .avatar img { filter: grayscale(0.55) brightness(0.78); }
.orb-badge {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--danger-bg);
  color: var(--danger);
  border: 3px solid var(--panel-solid);
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 0.15s var(--ease), transform 0.15s var(--ease);
}
.orb-badge--on { opacity: 1; transform: none; }
.orb-name { font-size: 1.04rem; max-width: 160px; }
.orb-status { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 6px; min-height: 20px; }
.stage--theater .orbs { gap: 10px 18px; }
.stage--theater .orb .avatar { --s: 64px !important; }
.stage--theater .orb-badge { width: 26px; height: 26px; }
.tag { font-size: 0.78rem; color: var(--faint); }
.ping { font: 600 0.76rem/1 var(--font); color: var(--glow); padding: 4px 7px; border-radius: 7px; background: rgba(var(--glow-rgb), 0.1); }
.ping--num { font: 500 0.75rem/1 var(--mono); font-variant-numeric: tabular-nums; }
.ping--mid { color: var(--warn); background: rgba(242, 196, 107, 0.1); }
.ping--bad { color: var(--danger); background: rgba(255, 138, 128, 0.1); }

/* Chat island */
.chat { grid-area: chat; display: none; flex-direction: column; min-height: 0; overflow: hidden; }
.chat-open .chat { display: flex; }
.chat-head { display: flex; align-items: center; gap: 8px; padding: 20px 14px 14px 22px; border-bottom: 1px solid var(--line); }
.chat-head > div:first-child { flex: 1; min-width: 0; }
.chat-title { margin: 0; font-size: 1.12rem; font-weight: 750; letter-spacing: -0.01em; }
.chat-note { margin: 2px 0 0; font-size: 0.76rem; color: var(--faint); }
.chat-actions { display: flex; gap: 6px; }
.chat-empty { margin: auto; padding: 40px 28px; max-width: 30ch; text-align: center; color: var(--faint); font-size: 0.92rem; }
.message-scroll { display: flex; flex-direction: column; }
.messages { margin-top: auto; }
.message-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 12px 0; }
.messages { list-style: none; margin: auto 0 0; padding: 0; } /* sits on the composer, like a conversation */
.msg { display: flex; gap: 11px; padding: 7px 18px; }
.msg:hover { background: rgba(86, 159, 123, 0.05); }
.msg-avatar { flex: none; align-self: flex-start; border-radius: 50%; }
.msg-body { flex: 1; min-width: 0; }
.msg-head { display: flex; align-items: center; gap: 9px; min-height: 24px; }
.msg-time { font: 500 0.7rem/1 var(--mono); color: var(--faint); font-variant-numeric: tabular-nums; }
.msg-del { margin-left: auto; opacity: 0; }
.msg:hover .msg-del, .msg-del:focus-visible { opacity: 1; }
@media (hover: none) { .msg-del { opacity: 1; } }
.msg-text { margin: 1px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; color: #d6e8de; font-size: 0.95rem; line-height: 1.45; }
.msg--mine .who-name { color: var(--glow); }
.msg-image { display: inline-block; margin-top: 6px; border-radius: var(--r-md); overflow: hidden; border: 1px solid var(--line); max-width: 100%; }
.msg-image img { display: block; max-width: 100%; max-height: 260px; object-fit: contain; background: rgba(0, 0, 0, 0.4); }
.msg-file {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 6px;
  max-width: 100%;
  padding: 11px 13px;
  border-radius: var(--r-md);
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid var(--line-strong);
  text-decoration: none;
  color: var(--mint);
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.msg-file:hover { border-color: var(--glow); background: var(--hover); }
.msg-file-text { display: grid; min-width: 0; }
.msg-file-name { color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-file-size { font: 500 0.75rem/1.4 var(--mono); color: var(--faint); }
.composer {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 12px 12px;
  padding: 6px;
  border-radius: 18px;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid var(--line-strong);
  transition: border-color 0.15s var(--ease);
}
.composer:focus-within { border-color: var(--mint); }
.composer-input { border: 0; background: transparent; min-height: 40px; padding: 0 6px; }
.composer-input:focus { box-shadow: none; }
.upload-chip { font: 500 0.75rem/1 var(--mono); color: var(--glow); padding: 6px 8px; border-radius: 6px; background: var(--active); }

/* Dock: channels, then controls, then you */
.dock {
  position: fixed;
  z-index: 40;
  left: 0;
  right: 0;
  bottom: max(18px, env(safe-area-inset-bottom));
  width: max-content;
  max-width: calc(100vw - 24px);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border-radius: 28px;
  background: rgba(6, 17, 12, 0.92);
  border: 1px solid var(--line-strong);
  box-shadow: 0 26px 60px -14px rgba(0, 0, 0, 0.85), inset 0 1px 0 rgba(var(--glow-rgb), 0.08);
}
.dock-channels { position: relative; display: flex; gap: 6px; }
.chan {
  position: relative;
  z-index: 1;
  width: 158px;
  height: 58px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 12px 0 16px;
  border-radius: 20px;
  text-align: left;
  color: var(--dim);
  transition: color 0.25s var(--ease), background-color 0.2s var(--ease);
}
.chan:hover { background: var(--hover); color: var(--text); }
.chan--joined, .chan--joined:hover { color: #03140c; background: transparent; }
.chan-text { display: grid; line-height: 1.15; min-width: 0; }
.chan-name { font-weight: 750; font-size: 1rem; }
.tile-count { font: 550 0.74rem/1.3 var(--font); opacity: 0.85; }
.tile-faces { display: flex; }
.face { display: block; line-height: 0; margin-left: -8px; border-radius: 50%; box-shadow: 0 0 0 2px var(--panel-solid); }
.face:first-child { margin-left: 0; }
.chan--joined .face { box-shadow: 0 0 0 2px var(--glow); }
.face.speaking { box-shadow: 0 0 0 2px #e8fff3; }
/* The lens: the mint plate under the room you are in. Only its transform animates. */
.lens {
  position: absolute;
  left: 0;
  top: 0;
  width: 158px;
  height: 58px;
  border-radius: 20px;
  background: var(--glow);
  box-shadow: 0 10px 26px -10px rgba(var(--glow-rgb), 0.75);
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}
.lens--on { opacity: 1; }
.dock-sep { width: 1px; height: 34px; background: var(--line-strong); flex: none; }
.dock-controls { display: flex; align-items: center; gap: 4px; }
.dock-btn {
  position: relative;
  width: 50px;
  height: 50px;
  display: grid;
  place-items: center;
  border-radius: 18px;
  color: var(--text);
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease), transform 0.12s var(--ease);
}
.dock-btn:hover { background: var(--hover); }
.dock-btn:active { transform: scale(0.94); }
.dock-btn--alert, .dock-btn--alert:hover { color: var(--danger); background: var(--danger-bg); }
.dock-btn--on { color: var(--glow); background: var(--active); }
.dock-btn--leave { color: #fff; background: #b8332b; }
.dock-btn--leave:hover { background: #cf3d33; }
.dot { position: absolute; top: 11px; right: 11px; width: 9px; height: 9px; border-radius: 50%; background: var(--glow); border: 2px solid var(--panel-solid); transform: scale(0); transition: transform 0.2s var(--ease); }
.has-dot .dot { transform: scale(1); }
.dock-me { margin-left: 4px; border-radius: 50%; }
.menu-credit { padding-top: 12px; border-top: 1px solid var(--line); display: flex; justify-content: center; }
.menu-group { display: grid; gap: 8px; }

/* Wide screens: the chat sits beside the room. */
@media (min-width: 1100px) {
  .app.chat-open { grid-template-columns: minmax(0, 1fr) clamp(330px, 27vw, 410px); grid-template-areas: 'top top' 'stage chat'; }
}

/* Narrower: the chat opens as a sheet over the room. */
@media (max-width: 1099px) {
  /* Solid here: over the room, a see-through sheet put the stage's text behind the messages. */
  .chat { position: fixed; z-index: 45; top: calc(var(--topbar-h, 62px) + 14px); right: 14px; bottom: var(--dock-space); width: min(420px, calc(100vw - 28px)); background: var(--panel-solid); }
}

/* Phones: the dock spans the width in two rows, channels above controls. */
@media (max-width: 760px) {
  .app { --dock-space: 156px; padding: 10px 10px var(--dock-space); gap: 10px; }
  /* The credit stays in persistent chrome on phones: a second line under the brand. */
  .topbar { flex-wrap: wrap; gap: 6px 12px; }
  .topbar-credit { order: 3; flex-basis: 100%; padding-left: 2px; border-left: 0; }
  .topbar-credit .credit { font-size: 0.74rem; }
  .topbar-credit .credit-name { font-size: 0.84rem; }
  .brand-name { font-size: 1.05rem; }
  .online-btn { padding: 5px 12px 5px 6px; }
  .stage-head { padding: 18px 18px 0; }
  .stage-body { padding: 18px 12px 26px; gap: 22px; }
  .orbs { gap: 18px 20px; }
  .orb-badge { width: 28px; height: 28px; }
  .orb .avatar { box-shadow: 0 0 0 1px var(--line-strong), 0 10px 22px -10px rgba(0, 0, 0, 0.8); }
  /* Two rows: channels on top, every control in one row beneath. */
  .dock { left: 8px; right: 8px; width: auto; max-width: none; flex-wrap: wrap; justify-content: space-around; gap: 6px 2px; border-radius: 24px; bottom: max(8px, env(safe-area-inset-bottom)); }
  .dock-channels { flex: 1 1 100%; }
  /* The buttons join one evenly spread row, so a hidden Share or Leave never leaves a hole. */
  .dock-controls { display: contents; }
  .chan { flex: 1; width: auto; height: 54px; }
  .dock-sep { display: none; }
  .dock-btn { width: 44px; height: 44px; border-radius: 15px; }
  /* --topbar-h is measured by app.ts: the phone top bar wraps to fit the credit line. */
  .chat { top: calc(var(--topbar-h, 58px) + 10px); left: 8px; right: 8px; width: auto; bottom: var(--dock-space); }
}

@media (max-width: 760px) {
  .toasts { top: 66px; left: 10px; right: 10px; justify-items: stretch; }
}

/* Voice channel cards in the room header: both channels always visible, with
   a people count and the faces inside, so occupancy reads at a glance. */
.stage-head { flex-wrap: wrap; align-items: flex-start; }
.stage-heading { flex: 1 1 260px; min-width: 0; }
.rooms { display: grid; grid-template-columns: repeat(2, minmax(0, 248px)); gap: 10px; }
.room {
  display: grid;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 20px;
  text-align: left;
  background: rgba(0, 0, 0, 0.38);
  border: 1px solid var(--line);
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.room:hover { border-color: var(--line-strong); background: rgba(9, 24, 17, 0.7); }
.room--viewing { border-color: var(--line-strong); }
.room--here, .room--here:hover { border-color: var(--glow); background: rgba(var(--glow-rgb), 0.08); }
.room-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.room-name { font-weight: 750; font-size: 1rem; }
.room-name-short { display: none; }
@media (max-width: 760px) { .room-name-short { display: inline; } }
.room--here .room-name { color: var(--glow); }
.room-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px 4px 7px;
  border-radius: 999px;
  color: var(--glow);
  background: rgba(var(--glow-rgb), 0.1);
}
.room-count { font: 500 0.88rem/1 var(--mono); font-variant-numeric: tabular-nums; }
.room-bottom { display: flex; align-items: center; gap: 8px; min-height: 30px; }
.room-faces { display: flex; }
.room-faces:empty { display: none; }
.room-more { font: 500 0.78rem/1 var(--mono); color: var(--dim); }
.room-more:empty { display: none; }
.room-state { margin-left: auto; font-size: 0.82rem; font-weight: 650; color: var(--dim); }
.room--here .room-state { color: var(--glow); }

/* Dock: the count as a number badge rather than "2 in" / "empty". */
.tile-pill { display: inline-flex; align-items: center; gap: 4px; opacity: 0.9; }
.tile-pill .tile-count { font: 500 0.78rem/1 var(--mono); font-variant-numeric: tabular-nums; opacity: 1; }

@media (max-width: 760px) {
  .rooms { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .room { padding: 10px 12px; gap: 8px; }
  .room-name-long { display: none; }
  .room-state { font-size: 0.78rem; }
}

/* Browser surfaces, themed: scrollbars and the text cursor belong to the palette too. */
* { scrollbar-width: thin; scrollbar-color: var(--forest) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--forest); border-radius: 10px; border: 3px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background-color: var(--emerald); }
input, textarea { caret-color: var(--glow); }

/* ---------- Popover, menus, controls ------------------------------------------------ */

.popover {
  position: fixed;
  z-index: 50;
  width: min(320px, calc(100vw - 16px));
  max-height: calc(100dvh - 16px);
  overflow-y: auto;
  padding: 16px;
  border-radius: var(--r-md);
  background: var(--panel-solid);
  border: 1px solid var(--line-strong);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
}
.menu { display: grid; gap: 10px; }
.menu-head { display: flex; align-items: center; gap: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); font-size: 1.05rem; }
.menu-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.menu-label { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: 0.9rem; }
.menu-note { margin: 0; font-size: 0.8rem; color: var(--faint); line-height: 1.45; }
.menu-section {
  margin: 10px 0 0;
  font: 750 0.98rem/1.2 var(--font);
  letter-spacing: -0.01em;
  color: var(--text);
}
.menu-section:first-child { margin-top: 0; }
.menu-admin { display: grid; gap: 8px; padding-top: 10px; border-top: 1px solid var(--line); }
.range-value { font: 500 0.8rem/1 var(--mono); font-variant-numeric: tabular-nums; color: var(--glow); }
.range-value--word { font: 650 0.84rem/1 var(--font); }
.poke { display: grid; grid-template-columns: 1fr auto; gap: 8px; }
.pw-form { display: grid; gap: 8px; }

input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 22px;
  background: transparent;
}
input[type='range']::-webkit-slider-runnable-track { height: 6px; border-radius: 6px; background: var(--forest); }
input[type='range']::-moz-range-track { height: 6px; border-radius: 6px; background: var(--forest); }
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  margin-top: -6px;
  border-radius: 50%;
  background: var(--glow);
  border: 3px solid var(--panel-solid);
  box-shadow: 0 0 0 1px var(--glow);
}
input[type='range']::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--glow); border: 3px solid var(--panel-solid); }

.switch-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px; cursor: pointer; }
.switch-text { display: grid; gap: 3px; }
.switch-input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.switch { position: relative; width: 42px; height: 24px; border-radius: 24px; background: var(--forest); transition: background-color 0.2s var(--ease); }
.switch::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--dim);
  transition: transform 0.2s var(--ease), background-color 0.2s var(--ease);
}
.switch-input:checked + .switch { background: var(--emerald); }
.switch-input:checked + .switch::after { transform: translateX(18px); background: var(--glow); }
.switch-input:focus-visible + .switch { outline: 2px solid var(--glow); outline-offset: 2px; }

.meter { position: relative; display: block; height: 8px; border-radius: 8px; background: var(--forest); overflow: hidden; }
.meter-fill { position: absolute; inset: 0; background: var(--faint); transform-origin: left; transform: scaleX(0); transition: transform 0.06s linear; }
.meter-fill--open { background: var(--glow); }
.meter-mark { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--warn); }

/* ---------- Toasts ------------------------------------------------------------------- */

.toasts {
  position: fixed;
  z-index: 60;
  right: 20px;
  top: 76px; /* under the top bar: the bottom belongs to the dock */
  display: grid;
  gap: 10px;
  justify-items: end;
  pointer-events: none;
}
.toast {
  max-width: min(360px, calc(100vw - 32px));
  padding: 12px 16px;
  border-radius: var(--r-md);
  background: var(--panel-solid);
  border: 1px solid var(--line-strong);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55);
  font-size: 0.92rem;
}
.toast--error { border-color: rgba(255, 138, 128, 0.5); color: var(--danger); }
.toast--poke { border-color: var(--glow); }
.poke-toast { display: flex; align-items: center; gap: 12px; }
.poke-toast > span:last-child { display: grid; }
.poke-text { color: var(--dim); overflow-wrap: anywhere; }

/* ---------- Screen sharing --------------------------------------------------------- */

.live {
  font: 800 0.62rem/1 var(--font);
  letter-spacing: 0.08em;
  color: #fff;
  background: #d8342b;
  padding: 3px 5px 2px;
  border-radius: 5px;
  flex: none;
}
.streams {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  max-width: 1200px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: 14px;
}
.streams:empty { display: none; }
.stream {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background: #000;
  aspect-ratio: 16 / 9;
}
/* My own share is a small preview: big enough to check, small enough to keep the room in view. */
.stream--own { max-width: 340px; justify-self: center; }
.stream-video { width: 100%; height: 100%; display: block; object-fit: contain; background: #000; }
.stream-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
}
.stream-name { flex: 1; min-width: 0; font-weight: 600; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.choice { display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: start; padding: 8px 10px; border-radius: var(--r-sm); border: 1px solid var(--line); cursor: pointer; }
.choice:hover { background: var(--hover); }
.choice:has(.choice-input:checked) { border-color: var(--glow); background: var(--active); }
.choice-input { margin: 3px 0 0; accent-color: var(--glow); }
.choice-body { display: grid; gap: 2px; }
.choice-label { font-weight: 650; font-size: 0.9rem; }

/* ---------- Modal and Voice setup ---------------------------------------------------- */

.modal-scrim {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  /* minmax(0, 1fr): without it the grid column sizes to the longest sentence
     inside, and on a phone the window grew to 644px and slid off screen. */
  grid-template-columns: minmax(0, 1fr);
  padding: 16px;
  background: rgba(0, 0, 0, 0.6);
}
.modal {
  width: min(100%, 460px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 26px 24px 20px;
  border-radius: var(--r-lg);
  background: var(--panel-solid);
  border: 1px solid var(--line-strong);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}
.setup { display: grid; gap: 14px; }
.setup-title { margin: 0; font-size: 1.4rem; font-weight: 750; letter-spacing: -0.01em; }
.setup-lede { margin: -6px 0 4px; color: var(--dim); font-size: 0.92rem; }
.setup-step { display: grid; gap: 10px; padding: 14px; border-radius: var(--r-md); border: 1px solid var(--line); background: rgba(0, 0, 0, 0.35); }
.setup-head { display: flex; align-items: center; gap: 10px; color: var(--mint); }
.setup-head h3 { flex: 1; margin: 0; font-size: 0.98rem; font-weight: 700; color: var(--text); }
.setup-body { display: grid; gap: 10px; justify-items: start; }
.setup-body .meter, .setup-body .select { width: 100%; }
.setup-actions { display: flex; justify-content: flex-end; gap: 10px; padding-top: 4px; }
.setup-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }
.pill { font: 650 0.74rem/1 var(--font); padding: 5px 8px; border-radius: 999px; color: var(--warn); background: rgba(242, 196, 107, 0.1); }
.pill--ok { color: var(--glow); background: rgba(var(--glow-rgb), 0.1); }
.pill--bad { color: var(--danger); background: rgba(255, 138, 128, 0.1); }
.select {
  appearance: none;
  cursor: pointer;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2716%27 height=%2716%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%237ee0ae%27 stroke-width=%272.2%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27m6 9 6 6 6-6%27/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  text-overflow: ellipsis;
}
.select option { background: var(--panel-solid); color: var(--text); }
@media (max-width: 760px) {
  .modal-scrim { place-items: end center; padding: 0; }
  .modal { width: 100%; border-radius: var(--r-lg) var(--r-lg) 0 0; padding-bottom: max(20px, env(safe-area-inset-bottom)); }
}
