/* Turret board: a dark turret panel of backlit keys. Generic turret practice
   only (no vendor names, marks or palettes). Plain CSS, no framework.

   Key states (DESIGN.md 2, highest precedence first):
   hot-live (pulsing red ring), transmitting (bright green), receiving (red,
   pulsing), ringing-in (flashing red), ringing-out (flashing green), dnd
   (amber), media-down (amber hatched), available (lit), neighbor (lit + N),
   pending (grey dashed), offline/unknown (dark, unlit). */

:root {
  color-scheme: dark;
  --panel-0: #0b0d10;
  --panel-1: #13161b;
  --panel-2: #1a1e24;
  --edge: #2a2f37;
  --edge-hi: #3a414c;
  --ink: #eef1f5;
  --ink-dim: #8a929d;
  --ink-faint: #59616c;

  --key-off: #16191e;
  --key-off-2: #121418;
  --key-lit: #344152;
  --key-lit-2: #283340;
  --key-lit-edge: #56677d;
  --lamp-off: #2a2f36;
  --lamp-lit: #a9c4e6;

  --tx: #2fd27a;
  --tx-2: #17a457;
  --tx-glow: rgba(47, 210, 122, 0.55);
  --rx: #e8463e;
  --rx-2: #b8231c;
  --rx-glow: rgba(232, 70, 62, 0.75);
  --amber: #e3a227;
  --amber-2: #b67b10;
  --pending: #2a2d33;

  --radius: 6px;
  --gutter: 16px;
  --key-h: 88px;
  --drawer-w: 400px;
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "Segoe UI", Roboto, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--panel-0);
  color: var(--ink);
  font: 14px/1.3 var(--font);
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}
#app { flex: 1; display: flex; flex-direction: column; min-height: 0; }
button { font: inherit; color: inherit; }
[hidden] { display: none !important; }

/* ---------- S0 Go live ---------- */
.screen { margin: auto; padding: 32px var(--gutter); text-align: center; max-width: 520px; }
.screen .brand { font-size: 26px; font-weight: 800; letter-spacing: 0.32em; margin-bottom: 10px; padding-left: 0.32em; }
.screen .identity { color: var(--ink-dim); margin-bottom: 28px; font-size: 15px; }
/* S0 pickers: one column of equal-width, labelled selects above Go live */
.screen .pick { display: grid; gap: 6px; width: min(320px, 100%); margin: 0 auto 16px; text-align: left; }
.screen .pick span { font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); }
.screen select {
  display: block; width: 100%; margin: 0 auto; padding: 9px 12px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.screen .golive-btn { margin-top: 10px; min-width: min(320px, 100%); }
.screen .warn { margin: 0 auto 14px; max-width: 320px; }
.golive-btn {
  font-size: 18px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 18px 44px; border: 1px solid #3fe08c; border-radius: var(--radius);
  background: linear-gradient(var(--tx), var(--tx-2)); color: #03140a; cursor: pointer;
  box-shadow: 0 0 24px var(--tx-glow);
}
.golive-btn:disabled { opacity: 0.55; cursor: default; box-shadow: none; }
.screen.station .golive-btn { font-size: 26px; padding: 30px 60px; }
.status { color: var(--ink-dim); margin-top: 16px; min-height: 1.4em; }
.fatal h1 { font-size: 22px; }

/* ---------- top bar ---------- */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 10px var(--gutter);
  background: linear-gradient(var(--panel-2), var(--panel-1));
  border-bottom: 1px solid #000;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03);
}
/* My own DND: an amber rule under the whole top bar, not just the small key */
body[data-dnd="1"] .topbar { box-shadow: inset 0 -3px 0 var(--amber); }
/* The identity block shrinks (the device name ellipsizes) before the keys wrap */
.ident { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex: 1 1 0; }
.ident .name { font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; font-size: 15px; }
.ident .where { color: var(--ink-faint); font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.conn { align-self: center; width: 10px; height: 10px; border-radius: 50%; background: var(--rx); box-shadow: 0 0 8px var(--rx-glow); flex: none; }
.conn[data-state="up"] { background: var(--tx); box-shadow: 0 0 8px var(--tx-glow); }
.conn[data-state="media-down"] { background: var(--amber); box-shadow: 0 0 8px rgba(227, 162, 39, 0.7); }

.tkeys { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; justify-content: flex-end; }
/* control groups: audio | DND | drawers | off duty | release */
.tkeys > .grp { margin-left: 12px; }
/* a key and its select read as one split control (profile + mic, DND + until) */
.tkey.split { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.tkey.split + .tsel { margin-left: -6px; border-top-left-radius: 0; border-bottom-left-radius: 0; border-left-color: #11141a; }
.tkey {
  position: relative;
  padding: 7px 12px; min-height: 32px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
  background: linear-gradient(#262b33, #1d2128); color: var(--ink);
  border: 1px solid var(--edge-hi); border-radius: 4px; cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 1px 0 #000;
}
.tkey:hover { border-color: #56606e; }
.tkey:active { transform: translateY(1px); }
.tkey:disabled { opacity: 0.55; cursor: default; }
.tkey:focus-visible, .key:focus-visible { outline: 2px solid var(--lamp-lit); outline-offset: 2px; }
.tkey.dnd[aria-pressed="true"] { background: linear-gradient(var(--amber), var(--amber-2)); color: #1c1203; border-color: #f0bb55; }
.tkey.release { color: #ff8a83; border-color: #6b2622; background: linear-gradient(#2c1b1c, #1f1415); }
.tkey.release:hover { color: #fff; background: linear-gradient(var(--rx), var(--rx-2)); border-color: var(--rx); }
.tkey.dnd[aria-pressed="true"] + .tsel { border-color: #f0bb55; color: var(--amber); }
/* a badge only shows when something waits: lit, so it is seen */
.tkey .badge {
  display: inline-block; margin-left: 7px; min-width: 17px; padding: 1px 5px;
  border-radius: 9px; background: var(--lamp-lit); color: #0b0d10; font-size: 10px; font-weight: 800;
  letter-spacing: 0; text-align: center; box-shadow: 0 0 6px rgba(169, 196, 230, 0.6);
}

/* ---------- board ---------- */
/* The middle band (board + drawers) sits between the top bar and the bottom
   strip, so a drawer never covers RELEASE, the ring bar or the gate indicator. */
.middle { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; }
.board { flex: 1; min-height: 0; padding: var(--gutter); overflow: auto; display: flex; flex-direction: column; }
.grid {
  flex: 1 0 auto;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-rows: minmax(var(--key-h), auto);
  gap: 8px;
  padding: 10px;
  background: #090a0c;
  border: 1px solid #000;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.03), inset 0 6px 18px rgba(0, 0, 0, 0.6);
}
/* Desktop: the 6x4 page fills the window height (no dead half-screen below
   the keys); rows never shrink under --key-h, the board scrolls instead. */
@media (min-width: 901px) {
  .grid:not(.station) { grid-template-rows: repeat(4, minmax(var(--key-h), 1fr)); }
}
.cell { position: relative; min-width: 0; display: flex; }

/* Text is top-aligned under the lamp row, so labels line up across a row
   whatever sits under them; the bottom band is left for the hover volume and MUTE. */
.key {
  position: relative; flex: 1;
  display: flex; flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 3px;
  min-height: var(--key-h); min-width: 0;
  padding: 30px 14px 20px;
  text-align: left; cursor: pointer; user-select: none; -webkit-user-select: none; touch-action: none;
  background: linear-gradient(var(--key-off), var(--key-off-2));
  color: var(--ink-faint);
  border: 1px solid #23272e; border-radius: var(--radius);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035), 0 2px 0 #000;
  transition: background-color 60ms linear, box-shadow 60ms linear;
}
.key:active { transform: translateY(1px); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 1px 0 #000; }
/* dark (offline / unknown) keys stay readable but clearly unlit */
.key .label {
  font-size: 17px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  color: #7f8792; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.key .far { font-size: 13px; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* the far name repeats the label (the usual case): say it once */
.key[data-same="1"] .far { display: none; }
.key .lamp { position: absolute; top: 10px; left: 14px; width: 28px; height: 5px; border-radius: 3px; background: var(--lamp-off); }
.key .mode {
  position: absolute; top: 8px; right: 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em; color: var(--ink-faint);
}
.key .latch {
  display: none; position: absolute; top: 6px; left: 50px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em;
  padding: 1px 5px; border-radius: 3px; background: rgba(0, 0, 0, 0.4); color: #fff;
}
.key[data-latched="1"] .latch { display: block; }
/* the Space-bar target: a quiet ring, so it never reads as a key state */
.key[data-selected="1"] { outline: 1px solid rgba(238, 241, 245, 0.45); outline-offset: 3px; }
/* desktop app only: the key push-to-talk from other apps talks on. A dark pill
   with a lamp-blue rim, so it reads on dark, lit, talking (green) and receiving (red) keys. */
.key .ptt-tag {
  position: absolute; top: 6px; right: 46px; pointer-events: none;
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.12em; line-height: 1.2;
  padding: 1px 5px; border-radius: 3px;
  background: rgba(0, 0, 0, 0.5); color: var(--ink); border: 1px solid var(--lamp-lit);
}
.grid.station .key .ptt-tag { top: 8px; right: 52px; }

/* State words under the label (line keys), so a state never rests on colour
   alone. Available says nothing: the lit key is the message. This is ::before
   with order 3 (it lays out after the label); ::after is the neighbour N badge. */
.key.line::before {
  order: 3; margin-top: 2px; max-width: 100%;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.key.line[data-state="offline"]::before { content: "Offline"; color: #5f6773; }
.key.line[data-state="dnd"]::before { content: "Do not disturb"; }
.key.line[data-state="media-down"]::before { content: "No audio"; }
.key.line[data-state="neighbor"]::before { content: "Co-located"; color: #a9b6c6; }
.key.line[data-state="ringing-in"]::before { content: "Ringing"; }
.key.line[data-state="ringing-out"]::before { content: "Calling…"; }
.key.line[data-state="transmitting"]::before { content: "Mic open"; }
.key.line[data-state="transmitting"][data-rx="1"]::before { content: "Mic open · speaking"; }
.key.line[data-state="receiving"]::before { content: "Speaking"; }
.key.line[data-state="hot-live"]::before { content: "Hot mic live"; }

/* lit: reachable */
.key[data-state="available"] {
  background: linear-gradient(#3a4a5e, #2a3646);
  border-color: #61748c; color: #c9d4e2;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 0 26px rgba(150, 190, 240, 0.16), 0 2px 0 #000;
}
.key[data-state="available"] .label { color: #fff; }
.key[data-state="available"] .lamp { background: #cfe2ff; box-shadow: 0 0 8px rgba(169, 196, 230, 0.95); }
.key[data-state="available"] .mode { color: #a9b6c6; }

/* transmitting: bright green */
.key[data-state="transmitting"] {
  background: linear-gradient(var(--tx), var(--tx-2));
  border-color: #6bf0a8; color: #04210f;
  box-shadow: 0 0 22px var(--tx-glow), inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 2px 0 #000;
}
.key[data-state="transmitting"] .label { color: #021208; }
.key[data-state="transmitting"] .lamp { background: #eafff2; box-shadow: 0 0 8px #fff; }
.key[data-state="transmitting"] .mode { color: #064a24; }
/* transmitting while the far side talks back: a pulsing inbound ring */
.key[data-state="transmitting"][data-rx="1"] { animation: rx-ring 0.9s ease-in-out infinite; }

/* receiving: red, pulsing */
.key[data-state="receiving"] {
  background: linear-gradient(var(--rx), var(--rx-2));
  border-color: #ff8a83; color: #ffe3e1;
  animation: rx-pulse 0.9s ease-in-out infinite;
}
.key[data-state="receiving"] .label { color: #fff; }
.key[data-state="receiving"] .lamp { background: #ffd9d6; box-shadow: 0 0 8px #fff; }
.key[data-state="receiving"] .mode { color: #ffc9c5; }

.key[data-state="ringing-in"] { animation: flash-red 0.5s steps(1, end) infinite; border-color: var(--rx); }
.key[data-state="ringing-out"] { animation: flash-green 0.5s steps(1, end) infinite; border-color: var(--tx); }
/* the flash keyframes set the key colour; label and far name follow it */
.key[data-state^="ringing"] .label, .key[data-state^="ringing"] .far, .key[data-state^="ringing"] .mode { color: inherit; }
.key[data-state^="ringing"] .lamp { background: currentColor; }
.key[data-state="hot-live"] { background: linear-gradient(var(--rx), var(--rx-2)); color: #fff; border-color: #fff; animation: hot-ring 0.8s ease-in-out infinite; }
.key[data-state="hot-live"] .label { color: #fff; }
.key[data-state="hot-live"] .far, .key[data-state="hot-live"] .mode { color: #ffe3e1; }
.key[data-state="hot-live"] .lamp { background: #fff; box-shadow: 0 0 8px #fff; }

/* DND: amber; media-down: amber hatched */
.key[data-state="dnd"] { background: linear-gradient(var(--amber), var(--amber-2)); border-color: #f3c46a; color: #2a1a02; }
.key[data-state="dnd"] .label { color: #1c1203; }
.key[data-state="dnd"] .lamp { background: #fff1cf; }
.key[data-state="dnd"] .mode { color: #4a3205; }
.key[data-state="media-down"] {
  background: repeating-linear-gradient(135deg, var(--amber-2) 0 8px, #3d2b0a 8px 16px);
  border-color: var(--amber); color: #ffe7b8;
}
.key[data-state="media-down"] .label, .key[data-state="media-down"] .far, .key[data-state="media-down"] .mode { color: #fff; text-shadow: 0 1px 2px #000, 0 0 4px #000; }
.key[data-state="media-down"] .lamp { background: var(--amber); }

/* neighbor: lit like available (the far end is reachable in the room), with an N badge, not pressable */
.key[data-state="neighbor"] {
  background: linear-gradient(var(--key-lit), var(--key-lit-2));
  border-color: var(--key-lit-edge); color: #c9d4e2; cursor: not-allowed;
}
.key[data-state="neighbor"] .label { color: #fff; }
.key[data-state="neighbor"] .lamp { background: var(--lamp-lit); }
.key[data-state="neighbor"] .mode { color: #a9b6c6; }
.key[data-state="neighbor"]::after {
  content: "N"; position: absolute; top: 6px; left: 50px;
  font-size: 11px; font-weight: 800; color: #0b0d10; background: #c9d4e2; border-radius: 3px; padding: 0 5px;
}
.key[data-state="pending"] {
  background: var(--pending); border: 1px dashed #5b616b; color: #8e959f; cursor: default;
}
.key[data-state="pending"] .label { color: #aab1ba; }

/* unassigned slot: a blank, unlit key position */
.key.blank { cursor: default; background: #0f1114; border-color: #191c21; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.02); }
.key.blank:active { transform: none; }

/* refused press */
.key[data-flash="denied"] { animation: deny 0.7s ease-out 1; }

/* rooms: one dot per occupant in the lamp row, lit while that person speaks */
.key.room .dots { position: absolute; top: 8px; left: 50px; display: flex; gap: 5px; }
.key.room .dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); }
.key.room .dot.on { background: var(--tx); box-shadow: 0 0 7px var(--tx-glow); }
.key.room .dot.muted { background: transparent; border: 1px solid #8a94a1; }
/* on a lit green or red key the dots must still read: dark when quiet, white when speaking */
.key.room[data-state="transmitting"] .dot, .key.room[data-state="receiving"] .dot { background: rgba(0, 0, 0, 0.3); }
.key.room[data-state="transmitting"] .dot.on, .key.room[data-state="receiving"] .dot.on { background: #fff; box-shadow: 0 0 7px #fff; }
.key.room[data-state="transmitting"] .dot.muted, .key.room[data-state="receiving"] .dot.muted { background: transparent; border-color: rgba(0, 0, 0, 0.55); }
/* I am in this room: a bright edge, and words under the occupants */
.key.room[data-joined="1"] { border-color: #cfe2ff; }
.key.room[data-joined="1"]::before {
  content: "You are in"; order: 3; margin-top: 2px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
}
.key.room[data-joined="1"][data-state="transmitting"]::before { content: "You are in · mic open"; }
.cell:has(.mute[aria-pressed="true"]) .key.room[data-joined="1"]::before { content: "You are in · muted"; }
.mute {
  position: absolute; right: 10px; bottom: 10px; z-index: 2;
  padding: 5px 10px; font-size: 10px; font-weight: 800; letter-spacing: 0.12em;
  background: #0f1114; color: var(--ink); border: 1px solid var(--edge-hi); border-radius: 4px; cursor: pointer;
}
.mute:hover { border-color: #8a94a1; }
.mute[aria-pressed="true"] { background: var(--amber); color: #1c1203; border-color: #f3c46a; }

/* per-line volume: on hover (or focus), in the band along the bottom of the key */
.vol {
  position: absolute; left: 14px; right: 14px; bottom: 5px; z-index: 2;
  height: 12px; margin: 0; opacity: 0; pointer-events: none;
  accent-color: #c9d4e2; transition: opacity 120ms;
}
.cell:hover .vol, .vol:focus-visible { opacity: 0.95; pointer-events: auto; }
/* not while the key itself is held down: the hand is on the key, not the slider */
.cell:hover .key:active ~ .vol, .cell:hover .key:active ~ .gear { opacity: 0; pointer-events: none; }

/* ---------- bottom strip ---------- */
.strip {
  display: flex; align-items: center; gap: 12px 16px; flex-wrap: wrap;
  min-height: 56px; padding: 9px var(--gutter);
  background: linear-gradient(var(--panel-1), var(--panel-2));
  border-top: 1px solid #000;
}
.meter { display: flex; gap: 2px; align-items: stretch; height: 16px; }
.meter .seg { width: 6px; border-radius: 1px; background: #20252c; }
.meter .seg.on { background: var(--tx); box-shadow: 0 0 4px var(--tx-glow); }
.meter .seg.warm.on { background: var(--amber); box-shadow: 0 0 4px rgba(227, 162, 39, 0.6); }
.meter .seg.hot.on { background: var(--rx); box-shadow: 0 0 4px var(--rx-glow); }
/* The meter always shows the mic, but green only while the gate is open: a
   closed mic reads neutral grey, so green on the strip always means "on air". */
.meter[data-open="0"] .seg.on { background: #6f7884; box-shadow: none; }
.meter[data-open="0"] .seg.warm.on { background: #8a7444; }
.meter[data-open="0"] .seg.hot.on { background: #8a4a45; }
.gate {
  display: inline-flex; align-items: center; gap: 9px; min-width: 168px;
  font-weight: 800; letter-spacing: 0.1em; font-size: 13px; text-transform: uppercase;
  padding: 8px 14px; border-radius: 4px; border: 1px solid var(--edge-hi);
  color: var(--ink-dim); background: #101317;
}
.gate::before { content: ""; flex: none; width: 9px; height: 9px; border-radius: 50%; background: #4a515b; }
.gate[data-open="1"] { color: #03140a; background: linear-gradient(var(--tx), var(--tx-2)); border-color: #6bf0a8; box-shadow: 0 0 14px var(--tx-glow); }
.gate[data-open="1"]::before { background: #eafff2; box-shadow: 0 0 6px #fff; }
/* who I am hearing right now (lines and rooms): red, like a receiving key */
.rxind {
  display: inline-flex; align-items: center; gap: 9px;
  font-weight: 800; letter-spacing: 0.1em; font-size: 13px; text-transform: uppercase;
  padding: 8px 14px; border-radius: 4px; border: 1px solid #ff8a83;
  color: #fff; background: linear-gradient(var(--rx), var(--rx-2));
  max-width: 40vw; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rxind::before { content: ""; flex: none; width: 9px; height: 9px; border-radius: 50%; background: #ffd9d6; box-shadow: 0 0 6px #fff; }
.warn { color: var(--amber); font-size: 12px; }

/* ---------- drawers ---------- */
/* Drawers open over the right of the board only (inside .middle): the top
   bar (RELEASE), the ring bar and the strip stay visible and usable. */
.drawer {
  position: absolute; top: 0; right: 0; bottom: 0; z-index: 10;
  width: min(var(--drawer-w), 100vw); overflow: auto;
  background: var(--panel-1); border-left: 1px solid var(--edge-hi);
  box-shadow: -12px 0 30px rgba(0, 0, 0, 0.5);
}
.drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 12px var(--gutter); border-bottom: 1px solid var(--edge); }
.drawer-head h2 { margin: 0; font-size: 13px; letter-spacing: 0.16em; text-transform: uppercase; }
.drawer-body { padding: 12px var(--gutter) 24px; color: var(--ink-dim); }
.drawer-body h3 { margin: 18px 0 8px; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-dim); }
.facts { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0; }
.facts dt { color: var(--ink-dim); font-size: 12px; }
.facts dd { margin: 0; color: var(--ink); font: 12px/1.3 var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
/* the ICE path strings are long: give them their own full-width line under the label */
.facts dd[data-testid^="stat-path"] { grid-column: 1 / -1; margin-top: -4px; padding-left: 12px; text-align: left; color: #c9d4e2; }
table.lines { width: 100%; border-collapse: collapse; font-size: 12px; }
table.lines th { text-align: right; font-weight: 600; color: var(--ink-faint); padding: 4px 6px; border-bottom: 1px solid var(--edge); }
table.lines td { text-align: right; padding: 5px 6px; color: var(--ink); font-family: var(--mono); font-variant-numeric: tabular-nums; border-bottom: 1px solid #1d2127; }
table.lines th:first-child, table.lines td:first-child { text-align: left; font-family: var(--font); }
table.lines td.empty { text-align: center; color: var(--ink-faint); font-family: var(--font); }

/* ---------- top-bar select (DND until) ---------- */
.tsel {
  min-height: 32px; padding: 0 8px; font-size: 11px; letter-spacing: 0.06em;
  background: #1d2128; color: var(--ink-dim); border: 1px solid var(--edge-hi); border-radius: 4px;
}

/* ---------- per-line settings key (S2 on touch; right-click on desktop) ---------- */
.gear {
  position: absolute; right: 10px; top: 28px; z-index: 2;
  width: 26px; height: 20px; padding: 0; line-height: 16px; font-size: 14px;
  background: rgba(0, 0, 0, 0.35); color: var(--ink); border: 1px solid transparent; border-radius: 3px;
  cursor: pointer; opacity: 0; transition: opacity 120ms;
}
.cell:hover .gear, .gear:focus-visible { opacity: 0.9; }
@media (hover: none) { .gear { opacity: 0.7; } }

/* call state on a key: a small tag under the mode icon */
.key[data-call^="ring:ringing"] .mode, .key[data-call^="hot:"] .mode { color: #fff; }

/* ---------- S3 incoming ring bar ---------- */
/* It sits just above the bottom strip (with the gate indicator), so a ring
   never pushes the keys down under the pointer. */
.ringbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px var(--gutter);
  background: linear-gradient(var(--rx), var(--rx-2)); color: #fff;
  border-top: 1px solid #000;
  animation: ringbar 1s ease-in-out infinite;
}
.ringbar .who { font-size: 15px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; flex: 1; min-width: 160px; }
.tkey.answer { background: linear-gradient(var(--tx), var(--tx-2)); color: #03140a; border-color: #6bf0a8; min-height: 40px; padding: 8px 24px; font-size: 13px; }
.tkey.decline { background: #1d2128; color: #fff; border-color: #ffb3ae; min-height: 40px; padding: 8px 20px; font-size: 13px; }
/* raise the bottom notices clear of a ringing bar */
body:has(.ringbar:not([hidden])) .notices { bottom: 128px; }
@keyframes ringbar { 0%, 100% { filter: none; } 50% { filter: brightness(1.18); } }
@media (max-width: 620px) { .ringbar .who { flex-basis: 100%; } }

/* ---------- S4 MIC LIVE: full-window banner ---------- */
.miclive {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  padding: 24px var(--gutter); text-align: center;
  background: radial-gradient(circle at 50% 40%, #d9322a, #7a0f0b 70%);
  color: #fff;
}
.miclive-title { font-size: clamp(44px, 12vw, 120px); font-weight: 900; letter-spacing: 0.14em; line-height: 1; padding-left: 0.14em; }
.miclive[data-phase="chime"] .miclive-title { opacity: 0.75; }
.miclive[data-phase="live"] .miclive-title::before { content: "● "; font-size: 0.5em; vertical-align: 0.34em; }
.miclive-who { font-size: clamp(18px, 4vw, 30px); font-weight: 700; }
.miclive-count { font: 16px/1.3 var(--mono); font-variant-numeric: tabular-nums; color: #ffd9d6; min-height: 1.3em; }
.miclive-warn { font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: #1c1203; background: var(--amber); padding: 6px 12px; border-radius: 4px; }
.miclive-close {
  margin-top: 10px; min-width: min(420px, 100%); min-height: 84px; padding: 18px 36px;
  font-size: 26px; font-weight: 900; letter-spacing: 0.1em; text-transform: uppercase;
  background: #fff; color: #7a0f0b; border: 0; border-radius: 10px; cursor: pointer;
  box-shadow: 0 6px 30px rgba(0, 0, 0, 0.45);
}
.miclive-close:active { transform: translateY(2px); }

/* ---------- S2 settings ---------- */
.settings .field { display: grid; gap: 6px; margin: 4px 0 14px; color: var(--ink-dim); font-size: 12px; }
.settings .field input[type="text"] {
  padding: 8px 10px; font: inherit; font-size: 14px; color: var(--ink); background: var(--panel-2);
  border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.settings .field input[type="range"] { accent-color: #c9d4e2; }
.modes { display: grid; gap: 8px; }
.mode-opt {
  display: grid; gap: 2px; text-align: left; padding: 10px 12px; cursor: pointer;
  background: #1a1e24; color: var(--ink-dim); border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.mode-opt strong { color: var(--ink); letter-spacing: 0.08em; text-transform: uppercase; font-size: 12px; }
.mode-opt span { font-size: 12px; }
.mode-opt[aria-pressed="true"] { border-color: var(--lamp-lit); background: #22303f; box-shadow: inset 0 0 0 1px var(--lamp-lit); }
.mode-opt[data-testid="mode-hot"][aria-pressed="true"] { border-color: var(--rx); background: #3a1716; box-shadow: inset 0 0 0 1px var(--rx); }
.mode-opt:disabled { opacity: 0.6; cursor: default; }
.disclosure { margin: 14px 0; padding: 12px; border: 1px solid var(--rx); border-radius: var(--radius); background: #23100f; color: #f3d6d4; }
.disclosure h3 { color: #fff; margin-top: 0; }
.disclosure p { font-size: 12.5px; line-height: 1.45; margin: 8px 0; }
.tkey.hot { background: linear-gradient(var(--rx), var(--rx-2)); border-color: #ff8a83; color: #fff; }
.row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.row.danger { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--edge); }
.hot-status { margin: 14px 0; padding: 10px 12px; border-radius: var(--radius); background: #2a1615; color: #ffd9d6; font-size: 12px; }
.hot-status .row { margin-top: 8px; }
.hot-status[data-mismatch="1"] { background: #2d2309; color: #ffe7b8; }
.error { color: #ff8a83; font-size: 12px; }

/* ---------- S7 activity ---------- */
.activity { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.activity li { padding: 8px 10px; border-radius: 4px; background: #1a1e24; color: var(--ink); font-size: 12.5px; line-height: 1.4; border-left: 3px solid var(--edge-hi); }
.activity li[data-kind="hot"] { border-left-color: var(--rx); }
.activity li[data-kind="hot_refused"] { border-left-color: var(--amber); }
.activity li[data-kind^="missed"] { border-left-color: var(--lamp-lit); }
.activity li.empty { color: var(--ink-faint); border-left-color: transparent; background: transparent; }
.hint { font-size: 12px; color: var(--ink-faint); margin: 0 0 12px; }

/* the one affirmative action in a form or request (Send, Accept) */
.tkey.primary { background: linear-gradient(#3a4a5e, #2a3646); border-color: #8fa6c2; color: #fff; }
.tkey.primary:hover { border-color: var(--lamp-lit); }

/* ---------- S2 remove / block ---------- */
.tkey.danger { border-color: #8f3a35; color: #ffb3ae; }
.tkey.danger:disabled { opacity: 0.55; }
.disclosure.confirm { border-color: #8f3a35; }

/* ---------- S5 directory and S6 requests ---------- */
.dir-search { display: flex; gap: 8px; margin: 4px 0 8px; }
/* every text field in the drawers at one size (the field captions are 12px) */
.dir-search input, .req-form input, .req-form textarea {
  flex: 1; min-width: 0; padding: 8px 10px; font: inherit; font-size: 14px; color: var(--ink); background: var(--panel-2);
  border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.req-form textarea { resize: vertical; min-height: 64px; }
.req-form .field { display: grid; gap: 6px; margin: 4px 0 12px; color: var(--ink-dim); font-size: 12px; }
.req-form { margin-top: 14px; padding-top: 4px; border-top: 1px solid var(--edge); }
.dir-results, .req-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.dir-result {
  width: 100%; text-align: left; padding: 10px 12px; cursor: pointer;
  background: #1a1e24; color: var(--ink); border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.dir-result[aria-pressed="true"] { border-color: var(--lamp-lit); box-shadow: inset 0 0 0 1px var(--lamp-lit); }
.req-item {
  display: grid; gap: 4px; padding: 10px 12px; border-radius: 4px; background: #1a1e24; color: var(--ink);
  font-size: 12.5px; line-height: 1.4; border-left: 3px solid var(--edge-hi);
}
.req-item[data-status="pending"] { border-left-color: var(--lamp-lit); }
.req-item .req-labels, .req-item .req-exp, .req-item .req-state { color: var(--ink-dim); }
.req-item .req-note { color: var(--ink); font-style: italic; }
.req-item .row { margin-top: 6px; }
.empty { color: var(--ink-faint); font-size: 12px; margin: 0 0 8px; }
.ok { color: #9df0c2; font-size: 12px; }
.key.pending-req .mode { color: #8e959f; }

/* ---------- station layout (?layout=station): 88 pt keys ---------- */
body.station { --key-h: 117px; } /* 88pt = 117 CSS px */
.grid.station { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.grid.station .key { padding: 30px 16px 16px; }
.grid.station .key .label { font-size: 24px; }
.grid.station .key .far { font-size: 16px; }
.grid.station .key .lamp { width: 34px; height: 6px; top: 12px; left: 16px; }
.grid.station .key .mode { font-size: 11px; top: 10px; right: 12px; }
body.station .tkey { min-height: 44px; padding: 10px 16px; font-size: 13px; }

/* narrow screens: fewer columns in slot order, no blanks, no horizontal scroll */
@media (max-width: 900px) {
  .grid:not(.station) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cell { grid-row: auto !important; grid-column: auto !important; }
  .cell.blank { display: none; }
}
@media (max-width: 620px) {
  .grid:not(.station), .grid.station { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .topbar { padding: 8px var(--gutter); }
}

/* ---------- animations ---------- */
@keyframes rx-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(232, 70, 62, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 2px 0 #000; }
  50% { box-shadow: 0 0 24px var(--rx-glow), inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 2px 0 #000; }
}
@keyframes rx-ring {
  0%, 100% { box-shadow: 0 0 18px var(--tx-glow), inset 0 0 0 3px rgba(232, 70, 62, 0.35); }
  50% { box-shadow: 0 0 18px var(--tx-glow), inset 0 0 0 3px rgba(232, 70, 62, 1); }
}
@keyframes flash-red { 0% { background: linear-gradient(var(--rx), var(--rx-2)); color: #fff; } 50% { background: linear-gradient(var(--key-off), var(--key-off-2)); color: #ffb3ae; } }
@keyframes flash-green { 0% { background: linear-gradient(var(--tx), var(--tx-2)); color: #03140a; } 50% { background: linear-gradient(var(--key-off), var(--key-off-2)); color: #9df0c2; } }
@keyframes hot-ring {
  0%, 100% { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2), 0 0 10px var(--rx-glow); }
  50% { box-shadow: 0 0 0 4px #fff, 0 0 26px var(--rx-glow); }
}
@keyframes deny {
  0% { box-shadow: 0 0 0 3px var(--rx); transform: translateX(0); }
  20% { transform: translateX(-3px); }
  40% { transform: translateX(3px); }
  60% { transform: translateX(-2px); }
  100% { box-shadow: 0 0 0 0 transparent; transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .key, .key[data-state], .ringbar { animation: none !important; }
  /* without the flash, ringing keys stay solidly lit in their colour */
  .key[data-state="ringing-in"] { background: linear-gradient(var(--rx), var(--rx-2)); color: #fff; }
  .key[data-state="ringing-out"] { background: linear-gradient(var(--tx), var(--tx-2)); color: #03140a; }
}

/* ---------- desktop pilot: notices, toasts, the dark board while away ---------- */
/* Notices (reconnecting, audio problem, update, off duty) sit above the strip
   and never take pointer events outside their own box; toasts never take any. */
.notices {
  position: fixed; left: var(--gutter); right: var(--gutter); bottom: 64px; z-index: 30;
  display: grid; gap: 8px; justify-items: center; pointer-events: none;
}
.notice {
  pointer-events: auto; max-width: 720px;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-radius: var(--radius);
  background: #1d2128; border: 1px solid var(--edge-hi); color: var(--ink);
  font-size: 13px; line-height: 1.35; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.notice.warn { border-color: var(--amber-2); }
.notice.error { border-color: #8f3a35; background: #2a1715; }
.notice .tkey { flex: none; }
.toasts {
  position: fixed; right: var(--gutter); top: 56px; z-index: 31;
  display: grid; gap: 6px; justify-items: end; pointer-events: none;
  max-width: min(420px, calc(100vw - 2 * var(--gutter)));
}
.toast {
  padding: 8px 12px; border-radius: 4px; font-size: 12.5px; line-height: 1.35;
  background: #20252c; color: var(--ink); border-left: 3px solid var(--lamp-lit);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
}
.toast.warn { border-left-color: var(--amber); }
.toast.error { border-left-color: var(--rx); }
/* with a drawer open, toasts sit left of it instead of over its header */
@media (min-width: 621px) {
  body:has(.middle .drawer:not([hidden])) .toasts { right: calc(var(--drawer-w) + var(--gutter)); }
}
.board-hint { margin: 0; flex: 1 1 260px; }
.warn.ab { color: #ffb3ae; font-weight: 700; }
/* While the socket is down or the media path is rebuilding, the keys are not
   pressable: say so visually as well as with the dark state. */
body[data-conn="down"] .board .key,
body[data-ready="0"] .board .key { cursor: not-allowed; }
.screen .hint { max-width: 520px; text-align: center; margin: 16px auto 0; }
.screen.golive .hint { max-width: 360px; line-height: 1.5; }
@media (max-width: 600px) {
  .notices { bottom: 96px; }
  .toasts { top: 96px; }
}

/* ---------- S9 audio: microphone and speaker (S0 setup, AUDIO drawer, strip line) ---------- */
.dsel {
  min-height: 34px; padding: 6px 10px; max-width: 100%; min-width: 0;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--edge-hi); border-radius: var(--radius);
}
.drawer .dsel { display: block; width: 100%; margin: 0 0 10px; }
.audio-setup {
  margin: 0 auto 22px; padding: 14px 16px; text-align: left;
  background: var(--panel-1); border: 1px solid var(--edge); border-radius: var(--radius);
}
.audio-setup h2 { margin: 0 0 10px; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-dim); }
.audio-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 10px; }
.audio-row .dsel { flex: 1 1 200px; }
.screen .audio-setup select { display: block; margin: 0; }
.audio-label { flex: 0 0 84px; font-size: 12px; color: var(--ink-dim); }
.audio-setup .meter { margin: -2px 0 12px 92px; }
.drawer .meter { margin: 0 0 6px; }
.audio-info { margin: 4px 0 0; font-size: 12px; color: var(--ink-dim); }
.drawer .audio-row .tkey { flex: 0 0 auto; }
.tkey.audio { color: var(--ink); border-color: var(--key-lit-edge); }
.audio-summary {
  min-width: 0; max-width: 42ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 4px 8px; font-size: 12px; color: var(--ink-dim); text-align: left;
  background: transparent; border: 1px solid var(--edge); border-radius: 4px; cursor: pointer;
}
.audio-summary:hover { color: var(--ink); border-color: var(--edge-hi); }
@media (max-width: 560px) {
  .audio-label { flex-basis: 100%; }
  .audio-setup .meter { margin-left: 0; }
}
.screen.golive { max-width: 600px; }

/* ---------- one live computer per person ---------- */
.conn[data-state="passive"] { background: var(--ink-faint); box-shadow: none; }
.screen .golive-elsewhere { max-width: 520px; margin: 0 auto 16px; }
.screen.fatal .golive-btn { margin-top: 18px; }
/* A dark board (reconnecting, or live on your other computer) knows nothing about the far ends: no state words. */
body[data-dark="1"] .key.line::before { content: none; }

/* Hosted sign-in (D-48): the link confirm, paste and signed-out screens. */
.screen.signin .paste-link { margin: 18px auto 0; display: grid; justify-items: center; gap: 6px; }
.screen.signin .paste-link input[type="text"] {
  width: min(360px, 100%); box-sizing: border-box; padding: 10px 12px; font: inherit; font-size: 14px;
  color: var(--ink); background: var(--panel-2); border: 1px solid var(--edge-hi); border-radius: 8px;
}
.screen.signin .tkey { margin-top: 12px; }
.screen.golive .signout { margin: -18px auto 22px; display: block; }

/* ---------- recording (D-49) ---------- */
/* Key tags: a small REC mark while armed, a red REC · TRANSCRIBING while a
   conversation is recorded, OFF THE RECORD and DISCARDED in amber. */
.key .rec-tag {
  position: absolute; left: 14px; right: 40px; bottom: 5px;
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none;
}
.key[data-rec="armed"] .rec-tag { color: #c9d4e2; opacity: 0.7; right: auto; }
.key[data-rec="armed"] .rec-tag::before,
.key[data-rec="on"] .rec-tag::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 5px; border-radius: 50%; background: #ff4d44; vertical-align: 0; }
.key[data-rec="on"] .rec-tag { color: #fff; }
.key[data-rec="on"] { box-shadow: inset 0 0 0 2px rgba(255, 77, 68, 0.85), 0 2px 0 #000; }
.key[data-rec="otr"] .rec-tag { color: #1c1203; background: var(--amber); padding: 1px 5px; border-radius: 3px; right: auto; max-width: calc(100% - 28px); }
.key[data-rec="discarded"] .rec-tag { color: var(--amber); }

.rec-strip {
  display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 6px 10px; border-radius: 4px; border: 1px solid #ff8a83; background: #2a0f0e;
}
.rec-strip-text { font-weight: 800; letter-spacing: 0.1em; font-size: 12px; text-transform: uppercase; color: #fff; }
.rec-strip[data-state="on"] .rec-strip-text::before { content: ""; display: inline-block; width: 9px; height: 9px; margin-right: 7px; border-radius: 50%; background: #ff4d44; box-shadow: 0 0 6px #ff4d44; animation: rx-pulse 1.4s ease-in-out infinite; }
.rec-strip[data-state="otr"] { border-color: #f3c46a; background: #2a1f08; }
.rec-strip[data-state="otr"] .rec-strip-text { color: var(--amber); }
.rec-strip[data-state="unavailable"] { border-color: var(--edge-hi); background: #15181d; }
.rec-strip[data-state="unavailable"] .rec-strip-text { color: var(--ink-dim); }
.rec-strip .tkey.rec-off { border-color: #f3c46a; color: var(--amber); }
.rec-drop { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-dim); }
.rec-discard { border-color: #ff8a83; }
.tkey.danger { border-color: #ff8a83; color: #ffd9d6; }

.rec-consent {
  position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center;
  padding: var(--gutter); background: rgba(5, 6, 8, 0.86);
}
.rec-consent-box {
  max-width: 640px; max-height: calc(100vh - 2 * var(--gutter)); overflow: auto;
  padding: 24px; background: var(--panel-1); border: 1px solid var(--edge-hi); border-radius: 8px; text-align: left;
}
.rec-consent-box h1 { margin: 0 0 12px; font-size: 20px; }
.rec-consent-text p { margin: 0 0 10px; color: var(--ink); line-height: 1.45; }
.rec-consent-q { font-weight: 700; margin: 16px 0; }
.rec-consent-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.rec-recent li { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
