/* PLN green room, in the show's own Stamped Ledger language.
 *
 * Talent opens this on a laptop or a phone minutes before they are on live
 * television. They may be nervous and they are usually not technical, so the
 * page answers three questions and never makes anybody hunt for the answers:
 * am I on television right now, can they hear me, and where is the show.
 *
 * Every panel is the same lot ticket the overlay and /play use: solid plate,
 * 2px hairline border, a hard offset shadow with no blur, a perforated left
 * edge in the panel's own accent, and no rounded corners anywhere. Radius
 * zero is the language, not an oversight.
 *
 * The palette is semantic and never decorative (docs/design/stamped-ledger-
 * handoff.md). Cyan is platform truth, red is the Broker and the on-air
 * tally, gold is money, purple is the crowd. This page carries no crowd, so
 * purple does not appear on it at all. Cyan carries the page's own primary
 * actions, because everything this page offers is the platform letting talent
 * in and taking their word back.
 */

:root {
  --bg: #0a0d16;
  --plate: #0e1016;
  --strip: #12141b;
  --rule: #2a3347;
  --edge: #3d4a66;
  --ink: #e8ecf2;
  --dim: #7d8797;
  --truth: #3fd8ff;
  --truth-ink: #062733;
  --broker: #ff2e55;
  --broker-ink: #2b040d;
  --gold: #ffc63d;
  --gold-ink: #17130a;
  --ok: #43e39a;

  --display: "Anton", "Haettenschweiler", "Franklin Gothic Medium", "Archivo Narrow", sans-serif;
  --mono: "IBM Plex Mono", Consolas, "Courier New", monospace;
  --sans: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --hard: 6px 6px 0 rgba(0, 0, 0, 0.5);
  --hard-sm: 4px 4px 0 rgba(0, 0, 0, 0.5);
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.45;
  min-height: 100dvh;
}

.hidden { display: none !important; }

/* Every state here is legible without colour: the tally carries a word and a
   glyph and a sentence, each warning carries its own stamp. This is the class
   that lets the half a sighted person gets from layout reach a screen reader
   without reaching the layout. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── the lot ticket ── */

.plate {
  background: var(--plate);
  border: 2px solid var(--edge);
  box-shadow: var(--hard);
}
.ticket { border-left: 4px dotted var(--accent, var(--edge)); }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-bottom: 2px solid var(--rule);
  padding-bottom: 8px;
  margin-bottom: 13px;
}
.panel-title {
  font-family: var(--display);
  font-size: 17px;
  letter-spacing: 2px;
  color: var(--accent, var(--ink));
}
.head-note {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--dim);
  text-align: right;
}

/* ── rubber stamps ── */

.stamp {
  flex: none;
  font-family: var(--display);
  font-size: 12px;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  border: 2px solid currentColor;
  background: var(--plate);
  padding: 2px 7px;
  transform: rotate(-3deg);
}
.stamp.broker { color: var(--broker); }

/* ── the show bug ── */

.bug,
.bar {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
}
.pln {
  font-family: var(--display);
  font-size: 19px;
  letter-spacing: 1px;
  background: var(--gold);
  color: var(--gold-ink);
  border: 2px solid var(--gold-ink);
  padding: 3px 9px;
}
.showname {
  font-family: var(--display);
  font-size: 19px;
  letter-spacing: 3px;
  background: var(--plate);
  border: 2px solid var(--edge);
  border-left: 4px dotted var(--edge);
  padding: 4px 10px;
  color: var(--ink);
}

/* ══ the gate ══════════════════════════════════════════════════════════════ */

.gate {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 22px 16px 40px;
}
.gate-inner { width: 100%; max-width: 470px; }
.gate .bug { margin-bottom: 14px; }

.gate-card {
  --accent: var(--broker);
  padding: 20px 18px 22px;
  box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.5);
}

/* The headphones instruction is the headline, not a grey line under it. This
   is the one thing that ruins a taping and the one thing talent skips. */
.gate-head {
  font-family: var(--display);
  font-size: 34px;
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: 1.5px;
  color: var(--broker);
}
.gate-why {
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
}

/* The confirmation. A whole row rather than a 16px square, because it is
   pressed with a thumb, in a hurry, on a phone somebody is also holding a
   coffee next to. */
.confirm {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  margin-top: 18px;
  padding: 10px 13px;
  background: var(--strip);
  border: 2px solid var(--edge);
  border-left: 4px dotted var(--edge);
  cursor: pointer;
  user-select: none;
}
.confirm input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.confirm-box {
  flex: none;
  width: 26px;
  height: 26px;
  border: 2px solid var(--edge);
  background: var(--plate);
  display: grid;
  place-items: center;
}
.confirm-box svg {
  width: 15px;
  height: 13px;
  fill: none;
  stroke: var(--gold-ink);
  stroke-width: 2.6;
  stroke-linecap: square;
  opacity: 0;
}
.confirm-text {
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.4px;
}
.confirm input:checked + .confirm-box { background: var(--gold); border-color: var(--gold); }
.confirm input:checked + .confirm-box svg { opacity: 1; }
.confirm.on { border-color: var(--gold); border-left-color: var(--gold); }
/* :focus, not :focus-visible. The native box is hidden and this drawn one is
   the only focus a person can see, and the refused join button moves focus
   here programmatically after a mouse press, which :focus-visible does not
   match. A focus that arrives invisibly is the same dead end in slow motion. */
.confirm input:focus + .confirm-box { outline: 3px solid var(--truth); outline-offset: 3px; }

.field { display: block; margin-top: 16px; }
.field > span {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 6px;
}
.field input,
.field select {
  width: 100%;
  min-height: 48px;
  padding: 10px 12px;
  background: var(--strip);
  border: 2px solid var(--rule);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 15px;
}
.field input::placeholder { color: var(--dim); }

.primary {
  display: block;
  width: 100%;
  min-height: 58px;
  margin-top: 20px;
  padding: 12px 14px;
  background: var(--truth);
  color: var(--truth-ink);
  border: 2px solid var(--gold-ink);
  font-family: var(--display);
  font-size: 23px;
  letter-spacing: 3px;
  cursor: pointer;
  box-shadow: var(--hard);
}
/* Unready, not disabled. The button is a real button in every sense a browser,
   a screen reader or a keyboard can tell; it just looks like it is waiting for
   something, and pressing it says what. `:disabled` here is only the moment
   the join is actually in flight. */
.primary.not-ready,
.primary:disabled {
  background: var(--plate);
  color: var(--dim);
  border-color: var(--edge);
  box-shadow: var(--hard-sm);
}
.primary-sub {
  margin-top: 9px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.55;
  letter-spacing: 0.4px;
  color: var(--dim);
}
.gate-note {
  margin-top: 13px;
  min-height: 20px;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--gold);
}

/* ══ the room ══════════════════════════════════════════════════════════════ */

.room {
  max-width: 1180px;
  margin: 0 auto;
  padding: 14px 16px 34px;
}
.bar { margin-bottom: 12px; }
.who {
  margin-left: auto;
  text-align: right;
  line-height: 1.25;
}
.who b {
  display: block;
  font-family: var(--display);
  font-size: 18px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.who span {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--dim);
}

/* ══ the tally ═════════════════════════════════════════════════════════════
 *
 * The point of the page. On air and off air are told apart on five channels
 * at once, and colour is only one of them:
 *
 *   fill    solid red field with page-coloured ink | outline on the plate
 *   edge    hazard-striped gutter, solid border    | dotted gutter, dashed border
 *   glyph   filled pulsing beacon                  | hollow ring with a slash
 *   words   ON AIR / You are on television         | OFF AIR / not on television
 *           plus a sentence spelling out what that actually means
 *   weight  the state word is the largest thing on this page, either way
 *
 * It is sticky, because a warning that scrolls off the top of a phone is a
 * warning nobody reads. */

.tally {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 16px auto minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
  padding: 14px 18px 15px 0;
  background: var(--plate);
  border: 2px solid var(--edge);
  box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.5);
}
.tally-gutter { align-self: stretch; }
.beacon { width: 42px; height: 42px; flex: none; }
.b-ring,
.b-slash {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
}
.b-core { fill: currentColor; }
.tally-word {
  display: block;
  font-family: var(--display);
  font-size: 62px;
  font-weight: 400;
  line-height: 0.94;
  letter-spacing: 2px;
}
.tally-sub {
  display: block;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.tally-say {
  display: block;
  margin-top: 7px;
  font-size: 13.5px;
  line-height: 1.45;
  max-width: 60ch;
}

/* off air: an outline on the plate, dashed, with a dotted gutter */
.tally.off {
  border-style: dashed;
  color: var(--ink);
}
.tally.off .tally-gutter {
  background: repeating-linear-gradient(to bottom, var(--edge) 0 5px, transparent 5px 12px);
}
.tally.off .b-core { display: none; }
.tally.off .tally-sub { color: var(--dim); }
.tally.off .tally-say { color: var(--dim); }

/* on air: a solid red field with the page's own colour as ink */
.tally.on {
  background: var(--broker);
  border-color: var(--broker);
  color: var(--bg);
}
.tally.on .tally-gutter {
  background: repeating-linear-gradient(45deg, var(--bg) 0 7px, var(--broker) 7px 14px);
}
.tally.on .b-ring,
.tally.on .b-slash { display: none; }
.tally.on .b-core { animation: beat 1.4s ease-in-out infinite; }
.tally.on .tally-say { color: var(--broker-ink); }

/* The third state this page has always had, and keeps. When the link to the
   rig is down, this page is holding state of unknown age, and a confident OFF
   AIR built on nothing is the thing that gets somebody caught mid sentence.
   So it says so, and it leans hot: the only safe assumption in a studio is
   that the camera is live. Its own fill, gutter and glyph, distinct from both
   of the other two. */
.tally.unknown {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--gold-ink);
}
.tally.unknown .tally-gutter {
  background: repeating-linear-gradient(to bottom, var(--gold-ink) 0 14px, var(--gold) 14px 22px);
}
.tally.unknown .b-slash { display: none; }
/* Its own glyph: a ring with a solid centre, which is neither the off state's
   hollow ring nor the on state's full disc. */
.tally.unknown .b-core {
  transform: scale(0.6);
  transform-box: fill-box;
  transform-origin: center;
  animation: beat 1s ease-in-out infinite;
}
.tally.unknown .tally-say { color: var(--gold-ink); }

@keyframes beat { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* ── the warning lane ──
   Three failures that must never be read as each other. Each carries its own
   stamp word, its own edge and its own fill, so none of them is leaning on
   its colour. The lane sits under the tally and above the grid: it can push
   the room down, and it can never cover the tally or the self view. */

/* No :empty rule here. The lane's three warnings (#link-warning,
   #media-warning, #muted-warning) are always present in the DOM, each toggled
   by .hidden rather than removed, so .warn-lane never actually has zero
   children for :empty to match. Padding and gaps come from each .w instead. */
.w {
  position: relative;
  margin-bottom: 10px;
  padding: 11px 15px 13px 16px;
  border: 2px solid currentColor;
  background: var(--plate);
  font-size: 13.5px;
  line-height: 1.5;
  box-shadow: var(--hard-sm);
}
.w::before {
  display: block;
  width: fit-content;
  margin-bottom: 8px;
  font-family: var(--display);
  font-size: 12px;
  letter-spacing: 2.5px;
  border: 2px solid currentColor;
  background: var(--plate);
  padding: 2px 7px;
  transform: rotate(-3deg);
}

/* the rig link is down: gold, dashed all round, a dotted gutter */
.w.link {
  color: var(--gold);
  border-style: dashed;
  border-left: 6px dotted var(--gold);
}
.w.link::before { content: "LINK DOWN"; }

/* the camera or microphone is not working: red, solid, a hazard gutter */
.w.device {
  color: #ff8098;
  border-color: var(--broker);
  padding-left: 24px;
}
.w.device::before { content: "NO CAMERA OR MIC"; color: var(--broker); }
.w.device::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 11px;
  background: repeating-linear-gradient(45deg, var(--broker) 0 6px, var(--plate) 6px 12px);
}

/* the producer has muted you on air: solid red field, dark ink, solid gutter.
   The dark frame is not decoration. This warning sits directly under the tally,
   and on air the tally is itself a solid red band; without a hard edge of its
   own the two run together and read as one object. */
.w.muted {
  background: var(--broker);
  border: 3px solid var(--broker-ink);
  border-left: 10px solid var(--broker-ink);
  color: var(--broker-ink);
  font-weight: 600;
}
.w.muted::before {
  content: "MUTED ON AIR";
  background: var(--broker-ink);
  color: var(--broker);
  border-color: var(--broker-ink);
}

/* ── the grid ── */

.grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}
.panel { padding: 14px 16px 16px; }
.self { --accent: var(--edge); }
.decide { --accent: var(--truth); }
.cue { --accent: var(--gold); }
.broker { --accent: var(--broker); }
.feed { --accent: var(--edge); }
.devices-panel { --accent: var(--edge); }

/* ── the self view, and the on-air rails ──
   Narrow red bands flanking the picture, reading ON AIR down their length, so
   the tally is still in the corner of the eye while talent is looking at
   their own face rather than at the top of the page. Off air the rails do not
   exist: they are not dimmed, they are not drawn. */

.self-wrap { display: grid; grid-template-columns: minmax(0, 1fr); }
.rail { display: none; }
.rail b { font-weight: 400; }
.r-on,
.r-unk { display: none; }

#room[data-air="on"] .self-wrap,
#room[data-air="unknown"] .self-wrap {
  grid-template-columns: 26px minmax(0, 1fr) 26px;
  gap: 8px;
}
/* The rail's own text is absolutely positioned inside it, so a band of
   repeated ON AIR contributes nothing to the grid's intrinsic height and the
   picture is what decides how tall the row is. Set in flow it is taller than a
   16:9 frame and drags the whole panel down after it. */
#room[data-air="on"] .rail,
#room[data-air="unknown"] .rail {
  display: block;
  position: relative;
  overflow: hidden;
  border: 2px solid;
}
.rail b {
  position: absolute;
  inset: 0;
  writing-mode: vertical-rl;
  text-align: center;
  white-space: nowrap;
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 6px;
}
#room[data-air="on"] .rail {
  background: var(--broker);
  border-color: var(--broker);
  color: var(--bg);
}
#room[data-air="on"] .r-on { display: inline; }
#room[data-air="unknown"] .rail {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--gold-ink);
}
#room[data-air="unknown"] .r-unk { display: inline; }

.self-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #05070d;
  overflow: hidden;
  border: 2px solid var(--rule);
}
.self-frame.live { border-color: var(--broker); border-width: 4px; }
.self-frame.unknown { border-color: var(--gold); border-style: dashed; border-width: 4px; }
.self-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1);
}
.self-flag {
  position: absolute;
  left: 8px;
  bottom: 8px;
  padding: 3px 9px;
  background: var(--plate);
  border: 2px solid var(--edge);
  font-family: var(--display);
  font-size: 12px;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--dim);
}
.self-frame.live .self-flag {
  background: var(--broker);
  border-color: var(--broker);
  color: var(--bg);
}
.self-frame.unknown .self-flag {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--gold-ink);
}

.controls { display: flex; gap: 10px; margin-top: 12px; }
.ctrl {
  flex: 1;
  min-height: 48px;
  padding: 10px 12px;
  background: var(--strip);
  color: var(--ink);
  border: 2px solid var(--edge);
  border-left: 4px dotted var(--edge);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.4px;
  cursor: pointer;
  box-shadow: var(--hard-sm);
}
.ctrl.armed {
  background: var(--broker);
  border-color: var(--broker);
  border-left-color: var(--broker-ink);
  color: var(--broker-ink);
}

/* ── devices ── */

.devices { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.devices .field { margin-top: 0; }
.level {
  height: 10px;
  margin-top: 14px;
  background: var(--strip);
  border: 2px solid var(--rule);
}
.level-fill {
  height: 100%;
  width: 0%;
  background: var(--ok);
  transition: width 90ms linear;
}
.hint {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--dim);
}
.hint.warn { color: var(--gold); }

/* ── the cue card ── */

.cue-beat {
  font-family: var(--display);
  font-size: 28px;
  line-height: 1.05;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.cue-line {
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--dim);
  min-height: 21px;
}
/* Dotted leader rows, the overlay's own ledger. */
.cue-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.5px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  border-top: 2px dotted var(--rule);
  padding-top: 10px;
}
.cue-stats b { color: var(--ink); font-weight: 600; }
.cue-stats .money { color: var(--truth); }
.cue-you {
  margin-top: 13px;
  padding: 10px 12px;
  background: var(--strip);
  border-left: 4px dotted var(--gold);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--gold);
}

/* ══ the decision moment ═══════════════════════════════════════════════════
 *
 * This is the one point in the show where talent touches the rig, and they do
 * it on camera, holding a phone, with a host talking at them. So: the item,
 * then the two numbers that decide it side by side and never apart, then
 * three targets nobody could miss. */

.decide-item {
  font-family: var(--display);
  font-size: 24px;
  line-height: 1.1;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.decide-figures {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 12px;
}
.fig {
  padding: 9px 11px 11px;
  background: var(--strip);
  border: 2px solid var(--rule);
  border-left: 4px dotted var(--c);
}
.fig.truth { --c: var(--truth); --c-ink: var(--truth-ink); }
.fig.broker { --c: var(--broker); --c-ink: var(--broker-ink); }
.fig-k {
  display: block;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1.5px;
  color: var(--dim);
  margin-bottom: 7px;
}
.fig-v {
  display: block;
  width: fit-content;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--display);
  font-size: 34px;
  line-height: 1.12;
  font-weight: 400;
  letter-spacing: 1px;
  background: var(--c);
  color: var(--c-ink);
  border: 2px solid var(--gold-ink);
  padding: 2px 10px;
  font-variant-numeric: tabular-nums;
  box-shadow: var(--hard-sm);
}

.decide-note {
  margin: 14px 0 9px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--truth);
}

.decide-btns { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.declare {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 76px;
  padding: 14px 8px;
  background: var(--strip);
  color: var(--ink);
  border: 2px solid var(--edge);
  border-left: 4px dotted var(--d);
  font-family: inherit;
  cursor: pointer;
  box-shadow: var(--hard-sm);
}
.declare b {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 1.5px;
  color: var(--d);
}
.declare span {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.4px;
  color: var(--dim);
  text-align: center;
}
.declare.ship { --d: var(--truth); --d-ink: var(--truth-ink); }
.declare.flip { --d: var(--broker); --d-ink: var(--broker-ink); }
.declare.ride { --d: var(--gold); --d-ink: var(--gold-ink); }
.declare:disabled { opacity: 0.4; cursor: not-allowed; }

/* Declared is not decided, and the button must not pretend otherwise: it
   reports what was said, and the producer's confirmation is what spends. */
.declare.said {
  background: var(--d);
  border-color: var(--d);
  border-left-color: var(--d-ink);
  color: var(--d-ink);
}
.declare.said b,
.declare.said span { color: var(--d-ink); }

/* A said button goes disabled whenever the link is not trusted (ASSUME ON
   AIR): the declaration cannot be changed with no signal to the rig, same as
   the other two. Left with its bright accent fill it would be the one button
   on the row that still reads as pressable. It keeps the same muted look as
   its disabled siblings; the decide-state line below still reports what was
   said, in words. */
.declare.said:disabled {
  background: var(--strip);
  border-color: var(--edge);
  color: var(--dim);
}
.declare.said:disabled b,
.declare.said:disabled span { color: var(--dim); }

.decide-state {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dim);
  min-height: 20px;
}
.decide-state.said { color: var(--gold); }

/* ── the Broker's own number ── */

.broker-item { font-family: var(--mono); font-size: 13.5px; font-weight: 600; }
.broker-offer {
  margin-top: 8px;
  font-family: var(--display);
  font-size: 46px;
  line-height: 1.05;
  letter-spacing: 1px;
  color: var(--broker);
  font-variant-numeric: tabular-nums;
}
.broker-hint {
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--dim);
}

/* ── the return feed ── */

.feed-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.feed-tile {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #05070d;
  overflow: hidden;
  border: 2px solid var(--rule);
}
.feed-tile.live { border-color: var(--broker); border-width: 3px; }
.feed-tile video { width: 100%; height: 100%; object-fit: cover; }
.feed-name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  justify-content: space-between;
  gap: 6px;
  padding: 4px 7px;
  background: rgba(10, 13, 22, 0.88);
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.5px;
}
.feed-name .slot { color: var(--gold); text-transform: uppercase; letter-spacing: 1.5px; }
.feed-tile.audio-only::after {
  content: "AUDIO ONLY";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 3px;
  color: var(--dim);
}
.feed-empty { font-family: var(--mono); font-size: 12.5px; color: var(--dim); }

.foot {
  margin-top: 16px;
  padding: 9px 12px;
  border-left: 4px dotted var(--rule);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--dim);
}
.foot.warn { color: var(--gold); }

:focus-visible { outline: 2px solid var(--truth); outline-offset: 2px; }

/* ══ the room on a phone ═══════════════════════════════════════════════════
 *
 * 390x844 is the brief. Nothing that matters during a taping is dropped: the
 * tally still tops the page and still carries its full sentence, the self
 * view still has its rails, the decision still has three full width targets.
 * What goes is the two column desk layout, the wordmark beside the chip, and
 * the running order: the device pickers matter once, before anybody is live,
 * and then never again, so they go to the bottom rather than sitting between
 * talent and the beat they are trying to read. */

@media (max-width: 880px) {
  .grid { display: flex; flex-direction: column; gap: 12px; }
  #panel-decide { order: 0; }
  #panel-cue { order: 1; }
  #broker-panel { order: 2; }
  #panel-self { order: 3; }
  #panel-feed { order: 4; }
  #panel-devices { order: 5; }
  .self { grid-row: auto; }
  .decide-btns { grid-template-columns: 1fr; }
  .declare { flex-direction: row; justify-content: flex-start; gap: 12px; min-height: 64px; padding: 12px 14px; }
  .declare span { text-align: left; }
}

@media (max-width: 640px) {
  .room { padding: 10px 12px 28px; }
  .bar .showname { display: none; }
  .who b { font-size: 15px; }
  .tally {
    grid-template-columns: 12px auto minmax(0, 1fr);
    gap: 11px;
    padding: 12px 13px 13px 0;
    box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.5);
  }
  .beacon { width: 32px; height: 32px; }
  .tally-word { font-size: 44px; }
  .tally-sub { font-size: 13px; margin-top: 3px; }
  .tally-say { font-size: 12.5px; margin-top: 5px; }
  .devices { grid-template-columns: 1fr; }
  .cue-beat { font-size: 24px; }
  .fig-v { font-size: 28px; }
  .broker-offer { font-size: 38px; }
  .feed-grid { grid-template-columns: 1fr 1fr; }
  .gate-head { font-size: 30px; }
}

/* 360px and narrower: the two decision figures stop competing for a width
   neither of them has and stack, which keeps them one above the other rather
   than letting either wrap mid number. They still travel together. */
@media (max-width: 374px) {
  .decide-figures { grid-template-columns: 1fr; }
  .tally-word { font-size: 38px; }
  .decide-item { font-size: 21px; }
}

/* The resting state of everything on this page is fully visible outside this
   query, so a viewer who asks for less motion is never left holding a page
   whose content never arrived. All that is in here is the beacon's pulse and
   a level bar's width, and both simply stop: the beacon stays solid, which is
   the state that matters, and the tally still differs on four other channels
   with no motion at all. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
