/*
 * TV display. Everything here is sized for a screen being read from across a
 * room, so the floor for any text is ~20px and the things that matter (the
 * question, the clock's value, the standings) are far bigger than that.
 */

/* The TV page is drawn for a television, so it is always drawn at 16:9 and
 * centred, with black either side of it. On a monitor that is wider or shorter
 * than a TV -- a laptop with an address bar, an ultrawide -- the alternative is
 * every row reflowing into a shape nobody designed, which is what made the game
 * select look crushed. Sizes inside are container units against this frame
 * rather than viewport units, so the layout is the one the TV gets whatever
 * window it is in. */
html, body { height: 100%; }
body {
  overflow: hidden; background: #000;
  display: flex; align-items: center; justify-content: center;
}
/* The frame is always 1920x1080 CSS pixels and is scaled to the screen (app.js
 * sets --tv-scale), so a stick that reports a 960x540 viewport gets the same
 * picture as a laptop's 1080p window rather than every px floor blowing up. */
#tv-stage {
  container-type: size;
  position: relative; overflow: hidden; flex: 0 0 auto;
  width: 1920px; height: 1080px;
  transform: scale(var(--tv-scale, 1));
  transform-origin: center center;
}
body.tv-overscan #tv-stage { transform: scale(calc(var(--tv-scale, 1) * 0.95)); }

/* --------------------------------------------------------- live wallpaper --- */

/*
 * Two drifting pools of brand light and a slowly turning question mark, behind
 * everything. Only `transform` and `opacity` animate, so this is a compositor
 * job and never competes with the answer timers for the main thread -- a TV in a
 * bar is often a stick PC, and a repainting background would show up as a
 * stuttering countdown.
 */
.tv-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.tv-bg-glow {
  position: absolute; border-radius: 50%; filter: blur(70px);
  will-change: transform;
}
.tv-bg-glow-a {
  width: 46cqw; height: 46cqw; left: -10cqw; top: -14cqw;
  background: radial-gradient(circle, rgba(124, 58, 237, 0.5), transparent 68%);
  animation: tv-drift-a 34s ease-in-out infinite;
}
.tv-bg-glow-b {
  width: 40cqw; height: 40cqw; right: -12cqw; bottom: -16cqw;
  background: radial-gradient(circle, rgba(34, 211, 238, 0.22), transparent 68%);
  animation: tv-drift-b 46s ease-in-out infinite;
}
.tv-bg-mark {
  position: absolute; right: 4cqw; top: 50%;
  font-family: var(--font-display); font-weight: 900; font-size: 62cqh; line-height: 1;
  color: rgba(168, 85, 247, 0.07);
  transform-origin: 50% 50%;
  animation: tv-turn 24s linear infinite;
  will-change: transform;
}
.tv-bg-glow-c {
  width: 34cqw; height: 34cqw; left: 32cqw; bottom: -18cqw;
  background: radial-gradient(circle, rgba(244, 114, 182, 0.16), transparent 68%);
  animation: tv-drift-a 40s ease-in-out infinite reverse;
  opacity: 0; transition: opacity 900ms ease;
}
/* Between questions the two pools brighten and a third comes up, so a room
   glancing at the TV in a gap sees something alive rather than a still. */
body.in-here-we-go .tv-bg-glow-a { filter: blur(60px); opacity: 1.35; }
body.in-here-we-go .tv-bg-glow-b { filter: blur(60px); opacity: 1.5; }
body.in-here-we-go .tv-bg-glow-c { opacity: 1; }

/* Rings swelling out of the middle of "Here we go!", inside the overlay so they
   read over its light rather than under it. Three seconds, one ring every half
   second, and nothing animates once the question is up. */
.hwg-rings {
  position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center; pointer-events: none;
}
.hwg-ring {
  position: absolute; width: 40cqh; height: 40cqh; border-radius: 50%;
  border: 6px solid rgba(255, 255, 255, 0.75);
  box-shadow: 0 0 90px rgba(245, 179, 60, 0.55), inset 0 0 80px rgba(168, 85, 247, 0.45);
  opacity: 0; will-change: transform, opacity;
  animation: hwg-ring-swell 1.5s ease-out infinite;
}
.hwg-ring:nth-child(2) { animation-delay: 0.5s; border-color: rgba(245, 179, 60, 0.7); }
.hwg-ring:nth-child(3) { animation-delay: 1s; border-color: rgba(34, 211, 238, 0.6); }
@keyframes hwg-ring-swell {
  0% { transform: scale(0.2); opacity: 0; }
  20% { opacity: 1; }
  100% { transform: scale(3); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hwg-ring { animation: none; }
}

@keyframes tv-drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50% { transform: translate3d(6cqw, 5cqh, 0) scale(1.12); }
}
@keyframes tv-drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.05); }
  50% { transform: translate3d(-7cqw, -6cqh, 0) scale(0.92); }
}
/* Turned in 3D rather than spun flat: the perspective is what stops it reading
   as a rotating sticker. */
@keyframes tv-turn {
  from { transform: translateY(-50%) perspective(900px) rotateY(0deg); }
  to { transform: translateY(-50%) perspective(900px) rotateY(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .tv-bg-glow, .tv-bg-mark { animation: none; }
}

/* The shell sits over the wallpaper. */
.tv-shell {
  position: relative; z-index: 1;
  height: 100cqh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 26px 48px 20px;
  gap: 18px;
}

/* ------------------------------------------------------------- top bar --- */

.tv-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
}
.tv-bar .brand-name { font-size: 30px; }
.tv-bar-mid { display: flex; align-items: center; gap: 14px; justify-content: center; }
.tv-bar-mid .chip { font-size: 20px; padding: 8px 20px; }
/* Clear of the fixed connection pill in the corner. */
.tv-bar-right { text-align: right; padding-right: 130px; }
.tv-progress {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.tv-teams-count { font-size: 18px; color: var(--muted); font-weight: 600; }

/* While a question is up, the brand bar and the join footer come off the screen
   entirely: they cost about a fifth of the height, and neither is something the
   room can act on in the seconds a question lasts -- you can't join mid-question
   anyway. Both are back on every other screen. */
body.in-question .tv-bar,
body.in-question .tv-foot { display: none; }
body.in-question .tv-shell { padding: 0; gap: 0; }

/* Health, and nothing else: a green dot while the TV is talking to the server,
   amber the moment it isn't. The room reads nothing into a dot; the host walking
   past sees the colour change. */
#status.status-pill {
  width: 14px; height: 14px; padding: 0;
  border-radius: 50%; border: none; box-shadow: none;
  overflow: hidden; text-indent: 200%; white-space: nowrap;
  top: 22px; right: 24px;
}
#status.status-connected { background: var(--correct); box-shadow: 0 0 14px rgba(34, 197, 94, 0.7); }
#status.status-connecting { background: var(--gold); box-shadow: 0 0 14px rgba(245, 179, 60, 0.6); }
#status.status-lost, #status.status-offline { background: var(--incorrect); box-shadow: 0 0 14px rgba(244, 63, 94, 0.7); }

/* --------------------------------------------------------------- stage --- */

/* Pinned to the middle row rather than auto-placed: on a question the bar and
   the footer are display:none, and an auto-placed stage would land in the bar's
   auto row and collapse to nothing. */
.tv-stage { position: relative; min-height: 0; grid-row: 2; }
.screen { position: absolute; inset: 0; display: flex; flex-direction: column; }
/* With the chat panel up, every screen gives it the right-hand column. */
body.chat-open .screen { right: 26vw; }

/* ---------------------------------------------------------- room chat --- */
.tv-chat {
  position: absolute; right: 0; top: 0; bottom: 0; width: 24vw;
  display: flex; flex-direction: column;
  background: rgba(22, 16, 42, 0.92);
  border: 1px solid var(--line-strong);
  border-radius: 22px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}
.tv-chat-head {
  margin: 0; padding: 16px 20px 12px;
  font-size: 20px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
}
.tv-chat-head small { font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--gold); }
.tv-chat-log {
  flex: 1; min-height: 0; padding: 14px 20px;
  display: flex; flex-direction: column; gap: 12px; justify-content: flex-end;
  overflow: hidden;
}
.tv-chat-msg { font-size: 24px; line-height: 1.3; overflow-wrap: anywhere; }
.tv-chat-msg b { color: var(--gold); margin-right: 8px; }
.tv-chat-foot {
  padding: 12px 20px 16px; font-size: 16px; color: var(--muted);
  border-top: 1px solid var(--line);
}
.screen-center { align-items: center; justify-content: center; text-align: center; gap: 18px; }
/* Arriving screens rise in. Short enough that it never delays a question the
   room is timing itself against. */
.screen-in { animation: tv-screen-in 420ms var(--ease-out) both; }
@keyframes tv-screen-in {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------- lobby --- */

/* The join bar. Everything a tablet needs to get in, in one strip: a QR still
   big enough for a phone camera from the next table, and the address in the
   display face beside it rather than under it. The height it doesn't take goes
   to the explainer below, which is what a room of first-timers needs more. */
.join-bar {
  display: flex; align-items: center; gap: clamp(12px, 1.6cqw, 26px);
  padding: clamp(10px, 1.6cqh, 20px) clamp(14px, 1.6cqw, 26px);
  width: 100%; box-sizing: border-box; text-align: left;
}
.join-qr {
  width: 220px; height: 220px; display: block; flex: 0 0 auto;
  background: #ffffff; border-radius: var(--r-md); padding: 10px;
}
.join-card-text { text-align: left; min-width: 0; }
.join-step { font-size: 24px; color: var(--muted); font-weight: 700; }
.join-url {
  font-family: var(--font-display); font-weight: 900; font-size: 54px;
  letter-spacing: 0.02em; color: var(--brand-bright); margin: 6px 0 14px;
}
.join-code { font-size: 24px; color: var(--muted); font-weight: 700; margin-top: -8px; }
.join-code strong { color: var(--gold); letter-spacing: 0.18em; font-family: var(--font-display); font-size: 1.4em; }
.lobby-teams { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; margin-top: 10px; }
.lobby-team {
  display: flex; align-items: center; gap: 12px;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 12px 24px; font-size: 24px; font-weight: 700;
}
.lobby-team .dot { width: 12px; height: 12px; border-radius: 50%; background: var(--muted); }
.lobby-team.online .dot { background: var(--correct); box-shadow: 0 0 12px var(--correct); }
.lobby-hint { font-size: 22px; margin: 6px 0 0; }
/* The hidden host gesture's target: no size on screen, above everything, and
   the cursor stays a plain arrow so it never advertises itself. */
.tv-admin-corner {
  position: absolute; top: 0; right: 0; width: 90px; height: 90px; z-index: 200;
  background: transparent;
}
/* Small on purpose: the room doesn't need it, and the one person who does is
   standing at the TV wondering why it won't take a tap. */
.select-where {
  font-size: clamp(11px, 1.4cqh, 16px); font-weight: 700; color: var(--muted);
  margin: 2px 0 0; letter-spacing: 0.04em;
}

/* ----------------------------------------------------------- game select --- */

/* Joining on the left, choosing on the right. The right half is the one the
   room looks at, so it gets the space and the artwork. */
/* Everything on this screen is sized against the viewport height rather than in
   fixed pixels: it has to fit whole on whatever the venue plugs in -- a 4K set,
   a 1080p TV, a 720p projector -- and a game menu with its last row sliced off
   by the bottom edge is worse than a smaller one. */
.lobby-split { flex-direction: row; gap: clamp(18px, 2.6cqw, 40px); align-items: stretch; }
.lobby-left {
  flex: 0 0 34%; display: flex; flex-direction: column; align-items: stretch;
  gap: clamp(6px, 1.4cqh, 16px); text-align: center; min-height: 0;
}

/* The teaching slot: one card at a time, taking whatever height the join bar and
   the team list leave. Its own height never changes as cards swap, so the room
   isn't watching the layout jump every few seconds. */
.lobby-learn {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: clamp(6px, 1cqh, 12px);
}
.learn-head {
  font-size: clamp(11px, 1.5cqh, 16px); font-weight: 800; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--brand-bright);
}
.learn-eyebrow { font-size: clamp(10px, 1.4cqh, 15px); }
.learn-card {
  flex: 1 1 auto; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(6px, 1.4cqh, 16px); text-align: center;
  padding: clamp(10px, 2cqh, 26px) clamp(12px, 1.6cqw, 24px);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-radius: var(--r-lg);
}
.learn-card.is-swapping { animation: learn-in 520ms ease-out; }
@keyframes learn-in {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to { opacity: 1; transform: none; }
}
.learn-art { display: grid; place-items: center; }
.learn-art svg,
.learn-art .lc-art {
  width: clamp(34px, 7cqh, 84px); height: clamp(34px, 7cqh, 84px);
  color: var(--brand-bright);
  filter: drop-shadow(0 0 18px rgba(168, 85, 247, 0.5));
}
.learn-title {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.04em; font-size: clamp(18px, 3.2cqh, 40px); line-height: 1.05;
}
.learn-blurb {
  font-size: clamp(13px, 2cqh, 24px); font-weight: 600; color: var(--text);
  line-height: 1.3; margin-top: clamp(4px, 0.8cqh, 10px); max-width: 30ch;
  margin-inline: auto;
}
.learn-meta {
  font-size: clamp(11px, 1.5cqh, 17px); font-weight: 800; color: var(--muted);
  margin-top: clamp(4px, 0.8cqh, 10px); letter-spacing: 0.06em;
}
.learn-dots { display: flex; gap: 6px; justify-content: center; }
.learn-dot {
  width: clamp(4px, 0.7cqh, 8px); height: clamp(4px, 0.7cqh, 8px); border-radius: 50%;
  background: var(--line-strong);
}
.learn-dot.is-on { background: var(--brand-bright); box-shadow: 0 0 8px var(--brand-glow); }
.lobby-left .join-qr {
  width: clamp(88px, 13cqh, 150px); height: clamp(88px, 13cqh, 150px);
  padding: clamp(4px, 0.8cqh, 10px);
}
.lobby-left .join-step { font-size: clamp(12px, 1.7cqh, 20px); }
.lobby-left .join-url {
  font-size: clamp(20px, 2.8cqh, 32px); margin: 2px 0 clamp(3px, 0.8cqh, 8px);
}
.lobby-left .join-code { font-size: clamp(12px, 1.7cqh, 20px); margin-top: 0; }
.lobby-left .lobby-teams { gap: clamp(6px, 1cqh, 14px); margin-top: 0; }
.lobby-left .lobby-team {
  font-size: clamp(13px, 1.8cqh, 19px);
  padding: clamp(4px, 0.8cqh, 8px) clamp(10px, 1.2cqw, 16px);
}
.lobby-left .lobby-hint { font-size: clamp(13px, 1.8cqh, 22px); margin: 0; }

.lobby-right {
  flex: 1; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: clamp(4px, 1cqh, 10px);
  padding: 0 8px 0 0;
}

.select-head {
  border-left: 5px solid var(--brand-bright); padding-left: clamp(10px, 1.4cqw, 20px);
  margin-bottom: clamp(2px, 0.6cqh, 6px); flex: 0 0 auto;
}
.select-eyebrow {
  font-size: clamp(11px, 1.5cqh, 16px); font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.3em; color: var(--muted);
}
.select-title {
  font-family: var(--font-display); font-size: clamp(30px, 5.4cqh, 58px); font-weight: 900;
  text-transform: uppercase; letter-spacing: 0.02em; margin: 2px 0 4px;
  color: var(--text); line-height: 1.02;
  /* The chosen game's name reads as a title treatment, not a heading. */
  text-shadow: 0 0 34px rgba(168, 85, 247, 0.55);
}
.select-blurb {
  margin: 0; font-size: clamp(14px, 2cqh, 21px); color: var(--muted); font-weight: 600;
}
.select-meta {
  display: flex; flex-wrap: wrap; gap: clamp(6px, 0.9cqh, 10px);
  margin-top: clamp(5px, 1.1cqh, 12px);
}
.select-chip {
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: var(--r-pill); padding: clamp(4px, 0.7cqh, 7px) clamp(10px, 1.1cqw, 16px);
  font-size: clamp(12px, 1.6cqh, 17px); font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.08em;
}
.select-chip-brand {
  background: linear-gradient(135deg, var(--brand), var(--brand-bright));
  color: var(--on-brand); border-color: transparent;
}
.select-chip-warn {
  text-transform: none; letter-spacing: 0; font-weight: 700;
  color: var(--gold); border-color: rgba(245, 179, 60, 0.45);
}

.select-section-label {
  font-size: clamp(11px, 1.5cqh, 15px); font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.26em; color: var(--muted); margin-top: clamp(2px, 0.8cqh, 8px);
  flex: 0 0 auto;
}

.select-modes { display: flex; gap: clamp(8px, 1cqw, 14px); flex: 0 0 auto; }
.select-mode {
  flex: 1; display: flex; align-items: center; gap: clamp(8px, 1cqw, 14px); min-width: 0;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 2px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(8px, 1.3cqh, 14px) clamp(10px, 1.1cqw, 16px);
  transition: transform var(--t-med) var(--ease-out), border-color var(--t-med) ease,
    box-shadow var(--t-med) ease;
}
.select-mode-icon {
  width: clamp(22px, 3.2cqh, 34px); height: clamp(22px, 3.2cqh, 34px);
  color: var(--muted); flex: 0 0 auto;
}
/* The rendered art carries its own colour, so an unselected style card is dimmed
   rather than greyed. */
.select-mode img.select-mode-icon { opacity: 0.72; }
.select-mode.is-selected img.select-mode-icon { opacity: 1; }
.select-mode-name {
  font-size: clamp(16px, 2.3cqh, 24px); font-weight: 900; font-family: var(--font-display);
}
.select-mode-blurb {
  font-size: clamp(11px, 1.5cqh, 15px); color: var(--muted); font-weight: 600; line-height: 1.3;
}
.select-mode.is-selected {
  border-color: var(--brand-bright);
  box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.28), 0 18px 40px rgba(0, 0, 0, 0.5);
  transform: translateY(-3px);
}
.select-mode.is-selected .select-mode-icon { color: var(--brand-bright); }

/* Twenty cards, five across, the artwork beside the name rather than above it.
   `grid-auto-rows: 1fr` shares the leftover height between the rows instead of
   dropping the last one off the bottom, and the rows that come out of that are
   wide and short — which is a row of art plus two lines of text, not a stack. */
.select-packs {
  flex: 1 1 auto; min-height: 0; overflow: hidden;
  display: grid; grid-template-columns: repeat(5, 1fr); grid-auto-rows: 1fr;
  gap: clamp(6px, 1.1cqh, 12px); align-content: stretch;
  padding-bottom: clamp(2px, 0.8cqh, 8px);
}
.select-pack {
  /* Flat and thin-edged. Twenty-two gradients with 2px borders is twenty-two
     things asking to be looked at; the shelf reads as a list of games when only
     the chosen one is drawn loudly. */
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(5px, 0.9cqh, 10px); min-width: 0; min-height: 0;
  display: flex; align-items: center; gap: clamp(5px, 0.55cqw, 9px);
  transition: transform var(--t-med) var(--ease-out), border-color var(--t-med) ease,
    box-shadow var(--t-med) ease;
}
/* The art takes the card's full height and a fixed slice of its width, so a tall
   render (a trophy) and a wide one (a clapperboard) both sit inside the card
   instead of growing out through its top edge. */
.select-pack-art {
  position: relative; display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto; align-self: stretch;
  width: clamp(24px, 2.4cqw, 44px); min-height: 0;
  border-radius: var(--r-md);
}
/* The glyph carries the card on its own: a monogram watermark behind it read as
   noise from the couch rather than as a badge. */
.select-pack-icon {
  width: 100%; height: 100%; max-height: clamp(28px, 4.6cqh, 52px);
  color: var(--brand);
}
.select-pack-text { min-width: 0; flex: 1 1 auto; }
/* The name is the one line that must survive a short screen. */
.select-pack-name {
  font-size: clamp(12px, 1.7cqh, 17px); font-weight: 800; line-height: 1.15;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Only the handful of games that play in rounds carry one of these, and one line
   of it: a second line is what pushes a card past its own border at 720p. */
.select-pack-meta {
  font-size: clamp(10px, 1.3cqh, 13px); color: var(--muted); font-weight: 700; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.select-pack.is-elimination .select-pack-icon { color: var(--incorrect); }
.select-pack.is-empty { opacity: 0.35; }
.select-pack.is-selected {
  /* The ring is drawn inside the card, and the card doesn't move. The grid has
     to clip its overflow so a row can't spill off the bottom of the screen,
     which meant an outset ring on a card at the edge of the shelf -- the first
     one, which is the one that's usually chosen -- was cut off down one side. */
  border-color: var(--gold);
  background: rgba(245, 179, 60, 0.08);
  box-shadow: inset 0 0 0 2px var(--gold);
}
.select-pack.is-selected .select-pack-icon {
  color: var(--gold); filter: drop-shadow(0 0 12px rgba(245, 179, 60, 0.45));
}
/* The rendered art is fitted to whatever the card can spare rather than kept at
   its own size, which is what clipped it against the card's edge, and the
   unchosen ones are dimmed so the shelf doesn't read as twenty-two pictures. */
.select-pack-art img.select-pack-icon {
  width: auto; height: auto; max-width: 100%; max-height: 100%;
  object-fit: contain; opacity: 0.78;
}
.select-pack.is-selected img.select-pack-icon { opacity: 1; }
/* A rendered icon can't go gold, so the chosen card's art gets the gold light
   behind it instead. */
.select-pack.is-selected img.select-pack-icon {
  filter: drop-shadow(0 0 14px rgba(245, 179, 60, 0.75));
}

/* The franchise shelf. Chips, not cards: the whole point is that eighteen of
   them fit under the house games without the grid growing a scrollbar the room
   can't reach. `flex: 0 0 auto` so this shelf keeps its size and the cards above
   are what give up height on a short screen. */
.select-section-label-slim {
  flex: 0 0 auto; margin-top: clamp(4px, 0.9cqh, 10px);
  font-size: clamp(10px, 1.3cqh, 14px);
}
.select-franchise {
  flex: 0 0 auto;
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: clamp(4px, 0.7cqh, 8px);
}
.select-chip-pack {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  padding: clamp(3px, 0.6cqh, 7px) clamp(5px, 0.8cqh, 9px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: transform var(--t-med) var(--ease-out), border-color var(--t-med) ease,
    box-shadow var(--t-med) ease;
}
.select-chip-pack-icon {
  flex: 0 0 auto;
  width: clamp(14px, 2.1cqh, 22px); height: clamp(14px, 2.1cqh, 22px);
  color: var(--brand-bright);
}
.select-chip-pack-name {
  font-size: clamp(9px, 1.3cqh, 14px); font-weight: 800; line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.select-chip-pack.is-empty { opacity: 0.35; }
.select-chip-pack.is-selected {
  /* Inside the chip, for the same reason the chosen game card's ring is: a chip
     that grows into its neighbour's gap has its ring clipped there. */
  border-color: var(--gold);
  background: rgba(245, 179, 60, 0.08);
  box-shadow: inset 0 0 0 2px var(--gold);
}
.select-chip-pack.is-selected .select-chip-pack-icon { color: var(--gold); }

/* A pack with its own artwork (web_shared/pack_art) wears the artwork over its
   name. Side by side, the two split one chip's width and the name comes out as
   "Lord of th…", which is worse than no name at all; stacked, the wordmark is
   the thing you recognise and the name underneath is the thing you read out. */
.select-chip-pack.has-logo {
  flex-direction: column; justify-content: center; gap: 1px;
  padding: clamp(1px, 0.3cqh, 4px) clamp(4px, 0.7cqh, 8px);
}
.select-chip-pack.has-logo .select-chip-pack-name {
  white-space: normal; text-align: center; font-size: clamp(8px, 1.1cqh, 12px);
}
/* Twenty wordmarks on their own light plates are the brightest thing on the
   screen, brighter than the game the room is being asked to look at, so the
   ones nobody has chosen are held back. */
.select-chip-pack-logo {
  max-height: clamp(15px, 2.6cqh, 32px); max-width: 100%; width: auto; opacity: 0.82;
}
.select-chip-pack.is-selected .select-chip-pack-logo { opacity: 1; }
.select-pack.has-logo { flex-direction: column; justify-content: center; gap: clamp(2px, 0.5cqh, 6px); }
.select-pack-logo { max-height: clamp(26px, 5.4cqh, 62px); width: auto; max-width: 92%; }

/* 1080p, the television this is drawn for: five cards a row is 226px, and the
   name has to share it with the artwork, so it is set a shade smaller than the
   ratio would give it -- "Science & Nature" whole beats "Science & Na...". */
@container (max-height: 1200px) {
  .select-pack-name { font-size: clamp(12px, 1.45cqh, 15px); }
}

/* A shorter picture has the height for tall pack cards or for the theme shelf,
   not both: stacked artwork over two lines of text ends up taller than the row
   it's given and the cards overlap. Below this height the house games take the
   same chip shape as the shelf — the name alone, no meta line — and go a column
   wider, so four rows share the height instead of five. The query is against the
   16:9 frame rather than the window: what matters is how tall the picture is, and
   a browser window's picture is much shorter than its screen. */
@container (max-height: 1000px) {
  .select-packs { grid-template-columns: repeat(6, 1fr); }
  .select-pack {
    border-radius: var(--r-md); gap: clamp(5px, 0.9cqh, 9px);
    justify-content: center;
  }
  /* The artwork goes rather than shrinking: a sixth of this row is barely wide
     enough for "Books & Quotes", and an icon beside it turns every long name
     into "Books &...". The name is the thing the room reads out. */
  .select-pack-art { display: none; }
  .select-pack-text { flex: 0 1 auto; text-align: center; }
  .select-pack-meta { display: none; }
  .select-pack-logo { max-height: clamp(22px, 4.4cqh, 34px); }
}

/* Shorter still: 720p, or a browser window. A column off the theme shelf takes a
   row off it. */
@container (max-height: 720px) {
  .select-franchise { grid-template-columns: repeat(8, 1fr); }
  /* A shade smaller so "Current Events" and "Books & Quotes" read whole rather
     than ellipsised, which is the one thing a game name can't afford. */
  .select-pack-name { font-size: clamp(10px, 1.45cqh, 14px); }
  /* The theme shelf pays for it. A stacked wordmark over a name is the tallest
     thing on this screen, and at 720p it was taking more height for twenty
     brands than the twenty-two games above it. */
  .select-chip-pack { padding: 1px clamp(3px, 0.6cqh, 6px); }
  .select-chip-pack.has-logo { gap: 0; }
  .select-chip-pack-logo { max-height: clamp(11px, 1.9cqh, 18px); }
  .select-chip-pack.has-logo .select-chip-pack-name { font-size: clamp(7px, 0.95cqh, 10px); }
}

/* Not a television at all: a windowed browser, where the frame is 620 tall and
   the two shelves have about 150 of it between them. Wider rows rather than
   fewer games -- a game that isn't on the shelf can't be picked. */
@container (max-height: 660px) {
  .select-packs { grid-template-columns: repeat(8, 1fr); }
  .select-franchise { grid-template-columns: repeat(10, 1fr); }
  .select-pack { padding: 1px clamp(2px, 0.5cqh, 5px); }
  .select-pack-name { font-size: clamp(8px, 1.4cqh, 12px); }
  .select-chip-pack-logo { max-height: clamp(9px, 1.7cqh, 14px); }
}

/* ------------------------------------------------------------ question --- */

/* Three bands with air between them: the question owns the upper third, the
   answers the middle, the clock a quiet strip along the bottom. Nothing touches
   an edge -- the frame is what makes this read as a broadcast rather than a web
   page crammed onto a television -- and the padding doubles as a safe area on
   older sets that overscan the outer few percent. */
#quiz-screen {
  display: flex;
  flex-direction: column;
  gap: 3.4cqh;
  padding: 4cqh 2.4cqw 2.6cqh;
}
/* Fixed shares rather than grid rows, so a screen that hides its round pill or
   its clue band closes the gap instead of leaving a hole in the layout. */
/* The category line above is paid for out of the question's band rather than out
   of the answers, which are already at the size the back of the room needs. */
.q-marquee { flex: 0 0 27cqh; }
.answers-grid { flex: 1 1 auto; }
.q-foot, .wager-round, .clue-band, .question-category { flex: 0 0 auto; }
/* Buzztime pays for its clue band out of the question's height. */
#quiz-screen.has-clues { gap: 2.4cqh; }
#quiz-screen.has-clues .q-marquee { flex: 0 0 17cqh; }
/* Deep enough for two clues that each wrap to a second line, which is what a
   70-character joke does on a 720p set. At 20cqh the second clue was landing
   half outside the band. */
#quiz-screen.has-clues .clue-band { flex: 0 0 24cqh; }
/* Pub Quiz's round pill is a row of its own; the other styles don't reserve it. */
#quiz-screen:not(.has-round) .wager-round { display: none; }

/* ---------------------------------------------- the question and the fact */

/* The subject, in the gold small-caps the rest of the TV uses for labels: a
   question about a person or a year reads as a riddle until the room knows
   whether it is being asked about music or history. Quiet enough that the
   question is still the first thing anybody looks at. */
.question-category {
  font-family: var(--font-display);
  font-size: 2.6cqh;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--brand-bright);
  text-align: center;
  transition: opacity var(--t-base) var(--ease-out);
}

.q-marquee { position: relative; display: grid; align-items: center; justify-items: center; }
/* The stage: a violet aura behind the question box, and the box itself -- a
   faint glass panel whose height never changes with the question, so the
   cards below sit in the same place every round. */
#quiz-screen::before {
  content: "";
  position: absolute; z-index: 0; pointer-events: none;
  left: 50%; top: 0; width: 120cqw; height: 62cqh;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at 50% 30%, rgba(124, 58, 237, 0.34), rgba(124, 58, 237, 0.08) 42%, transparent 66%);
}
#quiz-screen > :not(.fact-stage) { position: relative; z-index: 1; }
.q-marquee::before {
  content: "";
  grid-area: 1 / 1;
  width: 76cqw; height: 100%;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(43, 32, 89, 0.42), rgba(22, 16, 42, 0.28));
  border: 1px solid rgba(168, 85, 247, 0.22);
  box-shadow: 0 2cqh 8cqh rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
/* Same cell, so the fact arrives exactly where the question was. */
.q-marquee > * { grid-area: 1 / 1; }

.question-text {
  margin: 0;
  font-size: 8.4cqh;
  line-height: 1.1;
  font-weight: 900;
  letter-spacing: -0.015em;
  text-align: center;
  text-wrap: balance;
  max-width: 68cqw;
  padding: 0 2cqw;
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
/* Four steps by length instead of one squeezed size: a typical question gets
   ~100px on a 1080p set and our longest still clears the 58px every question
   used to get. Bands come from the bank: median 81 characters, 90th 110,
   longest 148. */
.question-text[data-len="m"] { font-size: 7.4cqh; }
.question-text[data-len="l"] { font-size: 6.2cqh; }
.question-text[data-len="xl"] { font-size: 5.4cqh; }
#quiz-screen.has-clues .question-text { font-size: 6.6cqh; }
#quiz-screen.has-clues .question-text[data-len="m"] { font-size: 6cqh; }
#quiz-screen.has-clues .question-text[data-len="l"] { font-size: 5.2cqh; }
#quiz-screen.has-clues .question-text[data-len="xl"] { font-size: 4.6cqh; }

/* The fact's stage. Once the answer has had its beat this covers the question
   and the four cards -- opaque, so the fact is the only thing on the TV -- and
   the clock bar stays on top of it. */
#quiz-screen .q-foot { position: relative; z-index: 3; }
.fact-stage {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  padding: 4cqh 6cqw 14cqh;
  background: radial-gradient(ellipse at 50% 35%, rgb(70, 22, 110), rgb(12, 6, 24) 72%);
}
.fact-stage-in { animation: fact-stage-in 600ms var(--ease-out, ease-out) both; }
@keyframes fact-stage-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.fact-stage-in .fact-stage-card { animation: fact-in 600ms 150ms var(--ease-out, ease-out) both; }
@keyframes fact-in {
  from { opacity: 0; transform: translateY(3cqh); }
  to { opacity: 1; transform: none; }
}
.fact-stage-card {
  display: grid; justify-items: center; gap: 3.2cqh;
  max-width: 88cqw; text-align: center;
}
.fact-stage-tag {
  font-family: var(--font-display); font-size: 2.8cqh; font-weight: 900;
  text-transform: uppercase; letter-spacing: 0.28em; color: var(--gold);
}
.fact-stage-text {
  margin: 0;
  font-family: var(--font-display);
  font-size: 6.4cqh; line-height: 1.2; font-weight: 800;
  text-wrap: balance;
  color: #fff;
  text-shadow: 0 6px 40px rgba(0, 0, 0, 0.6);
}
.fact-stage[data-len="l"] .fact-stage-text { font-size: 5.4cqh; }
/* The answer, kept as a pill in the reveal green. */
.fact-stage-answer {
  display: inline-flex; align-items: center; gap: 1.2cqw;
  margin-top: 1cqh;
  padding: 1.4cqh 2.6cqw;
  border-radius: 999px;
  background: rgba(36, 140, 78, 0.28);
  border: 2px solid var(--correct, #2fbf6a);
  font-size: 3.6cqh; font-weight: 800;
  color: #fff;
}
.fact-stage-check { color: var(--correct, #2fbf6a); font-weight: 900; }
.fact-stage-count { font-weight: 600; opacity: 0.75; }
/* The cards fade under the stage so the transition reads as a hand-off. */
#quiz-screen.is-fact .answers-grid,
#quiz-screen.is-fact .q-marquee,
#quiz-screen.is-fact .question-category { opacity: 0; transition: opacity 400ms var(--ease-out); }

/* --------------------------------------------------------------- answers */

.answers-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 3cqh 2.6cqw;
  min-height: 0;
}
/* The reading beat. The four cards keep their space so the question doesn't
   move when they arrive, and they fade up together rather than appearing. */
#quiz-screen.is-reading .answers-grid { opacity: 0; }
.answers-grid { transition: opacity 420ms var(--ease-out); }

.list-panel { flex: 1 1 auto; }
/* Every card carries its own colour for the whole question and through the
   reveal: A violet, B cyan, C pink, D gold. Right, wrong and picked are layers
   on top of that identity, never a recolour. */
.answer-card[data-choice="A"] { --c: var(--choice-a); --c-rgb: 139, 92, 246; --on-c: #150a2b; }
.answer-card[data-choice="B"] { --c: var(--choice-b); --c-rgb: 34, 211, 238; --on-c: #04252b; }
.answer-card[data-choice="C"] { --c: var(--choice-c); --c-rgb: 244, 114, 182; --on-c: #2b0a1a; }
.answer-card[data-choice="D"] { --c: var(--choice-d); --c-rgb: 245, 179, 60; --on-c: var(--on-gold); }
.answer-card {
  --c: var(--brand); --c-rgb: 124, 58, 237; --on-c: var(--on-brand);
  position: relative;
  display: flex; align-items: center; gap: 2cqw;
  background: linear-gradient(158deg, rgba(var(--c-rgb), 0.14), var(--surface) 55%);
  border: 2px solid rgba(var(--c-rgb), 0.42);
  border-radius: var(--r-md);
  padding: 0 2.4cqw;
  overflow: hidden;
  min-height: 0;
  box-shadow: inset 0 0 0 0 rgba(var(--c-rgb), 0), 0 1.2cqh 3cqh rgba(0, 0, 0, 0.28);
  transition: opacity var(--t-slow) var(--ease-out), border-color var(--t-base) var(--ease-out),
    background var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out);
}
.answer-letter {
  background: var(--c);
  color: var(--on-c); font-weight: 900; border-radius: 50%;
  width: 7.6cqh; height: 7.6cqh;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-size: 4.2cqh;
  box-shadow: 0 0 0 0.35cqh rgba(var(--c-rgb), 0.28);
  transition: background var(--t-base) ease, color var(--t-base) ease, box-shadow var(--t-base) ease;
}

.answer-text {
  font-size: 5.4cqh; font-weight: 800; line-height: 1.1;
  max-width: 74%;
}
/* All four answers share one step, chosen by the longest of them, so B never
   ends up half the size of A. Longest answer in the bank is 40 characters. */
.answers-grid[data-len="m"] .answer-text { font-size: 4.6cqh; }
.answers-grid[data-len="l"] .answer-text { font-size: 3.9cqh; }
#quiz-screen.has-clues .answer-text { font-size: 4.6cqh; }
#quiz-screen.has-clues .answers-grid[data-len="m"] .answer-text { font-size: 4cqh; }
#quiz-screen.has-clues .answers-grid[data-len="l"] .answer-text { font-size: 3.4cqh; }

/* What the room picked, and only once the answer is out. Live percentages tell
   the slow tappers which way the room went -- and in a style that charges you
   for changing your mind, that is a trap rather than a feature. */
.answer-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums; font-size: 3cqh; font-weight: 800;
  color: var(--muted); opacity: 0; transition: opacity var(--t-base) ease;
}
.answer-card.show-count .answer-count { opacity: 1; }
.answer-share-bar {
  position: absolute; left: 0; bottom: 0; height: 0.7cqh; width: 0;
  background: linear-gradient(90deg, var(--c), rgba(var(--c-rgb), 0.55));
  transition: width var(--t-slow) var(--ease-out);
}

/* Progressive elimination mid-clock, and every remaining wrong answer at
   reveal -- one signal, used twice. A dead answer loses its colour and gets
   struck through, because dimming alone didn't carry across a bright room. */
.answer-card.eliminated {
  opacity: 0.34;
  transform: scale(0.985);
  border-color: rgba(148, 163, 184, 0.3);
  filter: grayscale(1);
}
.answer-card.eliminated .answer-text { text-decoration: line-through; text-decoration-thickness: 0.3cqh; color: var(--muted); }
.answer-card.eliminated .answer-letter {
  background: var(--surface-3); color: var(--muted);
  box-shadow: inset 0 0 0 2px rgba(148, 163, 184, 0.3);
}
/* The check that says "this one": drawn over the card's top-right corner in the
   card's own colour, so D's gold stays gold and A's violet stays violet. */
.answer-card::after {
  content: "";
  position: absolute; top: 1.2cqh; right: 1.2cqw;
  width: 5cqh; height: 5cqh; border-radius: 50%;
  background: var(--c) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M5 12.5l4.2 4.2L19 7' fill='none' stroke='%23101010' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / 62% no-repeat;
  box-shadow: 0 0 1.6cqh rgba(var(--c-rgb), 0.7);
  opacity: 0; transform: scale(0.6);
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
/* At reveal the room reads two things off these four cards: which one was
   right, and how the room split. Dropping the wrong ones to 13% took their text
   and their percentages with them -- unreadable from the back of a bar, which is
   the whole point of showing the split. So they stay legible in grey, and the
   winner is separated by colour, light and scale rather than by being the only
   thing still visible. */
#quiz-screen.is-reveal .answer-card {
  opacity: 0.62; transform: scale(0.98); filter: none;
  border-color: rgba(var(--c-rgb), 0.3);
  background: linear-gradient(158deg, rgba(var(--c-rgb), 0.08), rgba(17, 12, 32, 0.94) 55%);
  box-shadow: none;
}
#quiz-screen.is-reveal .answer-card .answer-text { text-decoration: none; color: #cec4e8; }
#quiz-screen.is-reveal .answer-card .answer-letter {
  background: rgba(var(--c-rgb), 0.2); color: var(--c);
  box-shadow: inset 0 0 0 2px rgba(var(--c-rgb), 0.55);
}
/* The number the room is actually asking about, so it is bigger than it was
   during play and in full-strength text. */
#quiz-screen.is-reveal .answer-count { color: var(--text); font-size: 3.8cqh; }
#quiz-screen.is-reveal .answer-share-bar {
  height: 1cqh;
  background: linear-gradient(90deg, rgba(var(--c-rgb), 0.55), rgba(var(--c-rgb), 0.25));
}
/* The right answer keeps its own colour and gets brighter: full-strength
   border, a glow in that colour, the check in the corner, the room's share bar
   lit. Nothing turns green. */
.answer-card.correct-final,
#quiz-screen.is-reveal .answer-card.correct-final {
  opacity: 1; transform: scale(1.015);
  border-color: var(--c);
  background: linear-gradient(158deg, rgba(var(--c-rgb), 0.3), rgba(22, 16, 42, 0.98) 60%);
  box-shadow: 0 0 0 0.4cqh rgba(var(--c-rgb), 0.28), 0 0 5cqh rgba(var(--c-rgb), 0.45), 0 2cqh 6cqh rgba(0, 0, 0, 0.35);
  filter: none;
}
.answer-card.correct-final::after { opacity: 1; transform: none; }
.answer-card.correct-final .answer-letter,
#quiz-screen.is-reveal .answer-card.correct-final .answer-letter {
  background: var(--c); color: var(--on-c);
  box-shadow: 0 0 0 0.35cqh rgba(var(--c-rgb), 0.35), 0 0 2.4cqh rgba(var(--c-rgb), 0.6);
}
.answer-card.correct-final .answer-count,
#quiz-screen.is-reveal .answer-card.correct-final .answer-count { color: #fff; }
.answer-card.correct-final .answer-text,
#quiz-screen.is-reveal .answer-card.correct-final .answer-text {
  text-decoration: none; color: #fff;
}
#quiz-screen.is-reveal .answer-card.correct-final .answer-share-bar {
  background: linear-gradient(90deg, var(--c), rgba(var(--c-rgb), 0.6));
}

/* ----------------------------------------------------------------- clues */

/* The band is on screen for the whole question, empty at first, so a clue that
   lands fades in instead of pushing the answers down the screen. Cyan, because
   in this product cyan is information and never a score. */
.clue-band {
  display: grid; align-items: center;
  padding: 2cqh 2.4cqw;
  border-radius: var(--r-md);
  background: linear-gradient(120deg, rgba(34, 211, 238, 0.09), rgba(22, 16, 42, 0.5));
  border: 1px solid rgba(34, 211, 238, 0.26);
  min-height: 0;
}
.clue-band > * { grid-area: 1 / 1; }
.clue-wait { font-size: 3cqh; font-weight: 800; color: rgba(167, 155, 200, 0.55); }
.clue-band.has-clue .clue-wait { display: none; }
.clue-rows { display: flex; flex-direction: column; gap: 1.4cqh; min-height: 0; }
.clue-card {
  display: flex; align-items: center; gap: 1.6cqw;
  font-size: 3.9cqh; font-weight: 700; line-height: 1.15;
  animation: clue-in 400ms var(--ease-out, ease-out) both;
}
/* A clue long enough to wrap gives up a little size so both clues fit the band
   whole -- still far bigger than the answers underneath it. */
.clue-rows[data-len="l"] .clue-card { font-size: 3.3cqh; }
.clue-rows[data-count="3"] .clue-card,
.clue-rows[data-count="4"] .clue-card { font-size: 3.2cqh; }
.clue-tag {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  padding: 0.7cqh 1.2cqw; border-radius: var(--r-pill);
  border: 1px solid rgba(34, 211, 238, 0.4);
  color: var(--accent); background: none;
  font-size: 2.1cqh; font-weight: 900; text-transform: uppercase; letter-spacing: 0.16em;
}
.clue-text { flex: 1; }
@keyframes clue-in {
  from { opacity: 0; transform: translateY(1.4cqh); }
  to { opacity: 1; transform: none; }
}
#quiz-screen.is-reveal .clue-band { opacity: 0.18; }
/* A question revealed before its first clue landed shouldn't leave the room
   reading a promise the question never kept. */
#quiz-screen.is-reveal .clue-wait { display: none; }

/* ----------------------------------------------------------------- clock */

.q-foot { display: grid; grid-template-rows: auto auto; gap: 1.4cqh; }
.clockbar { display: flex; align-items: center; gap: 1.8cqw; }
.timer-bar-track {
  flex: 1; height: 1.2cqh; background: rgba(255, 255, 255, 0.07);
  border-radius: var(--r-pill); overflow: hidden;
}
.timer-bar-fill {
  height: 100%; width: 100%;
  background: linear-gradient(90deg, var(--brand), var(--brand-bright));
  border-radius: var(--r-pill);
  box-shadow: 0 0 2.6cqh rgba(168, 85, 247, 0.5);
  transition: width 0.12s linear, background 0.3s ease;
}
/* Last three seconds: the bar goes hot so peripheral vision catches it. */
.timer-bar-fill.urgent { background: linear-gradient(90deg, #b91c5c, var(--incorrect)); box-shadow: 0 0 2.6cqh rgba(244, 63, 94, 0.5); }
#quiz-screen.is-reveal .timer-bar-fill { background: rgba(255, 255, 255, 0.16); box-shadow: none; }

.q-counter { font-size: 2.7cqh; font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; }
.timer-points {
  font-family: var(--font-display); font-weight: 900; font-size: 3.2cqh;
  font-variant-numeric: tabular-nums; color: var(--gold);
}
.timer-seconds {
  font-family: var(--font-display); font-weight: 900; font-size: 5.4cqh; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--text);
  min-width: 3.2ch; text-align: right;
}
/* Who got it, and how many of the room did -- the one line of standings the
   reveal needs, next to the clock rather than on top of the answers. */
.reveal-verdict { font-size: 2.7cqh; font-weight: 900; color: var(--correct); }
/* The hold before the answer lights: the line a host would say, breathing. */
.reveal-verdict.is-holding {
  color: var(--gold); font-style: italic; letter-spacing: 0.04em;
  animation: verdict-breathe 1.4s ease-in-out infinite;
}
@keyframes verdict-breathe {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}
.next-label { font-size: 2.7cqh; font-weight: 800; color: var(--muted); }

/* --------------------------------------------------------- leaderboard --- */

/* Everything on this screen is sized against the viewport's height, because a
   round break stacks the most furniture the TV ever shows at once: title, who
   went out, what's next, every team, and a clock. On a 720p set fixed sizes ran
   the board off the top and bottom of its own box. */
/* The board down the left, the clock and the way in down the right, the
   commentary across the whole bottom -- which is the only width the crawl ever
   made sense at. */
.lb-screen {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(280px, 27cqw, 520px);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "head rail"
    "main rail"
    "tick tick";
  gap: clamp(8px, 2cqh, 20px) clamp(16px, 2.6cqw, 44px);
}
.lb-head {
  grid-area: head;
  display: flex; align-items: baseline;
  gap: clamp(10px, 1.4cqw, 26px); min-width: 0;
}
.lb-main {
  grid-area: main; min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
}
.lb-title {
  font-family: var(--font-display); font-size: clamp(30px, 5cqh, 56px); font-weight: 900;
  letter-spacing: 0.02em; text-transform: uppercase; margin: 0;
}
.lb-title span { color: var(--brand-bright); }
.lb-subtitle { font-size: clamp(15px, 2.2cqh, 26px); color: var(--muted); font-weight: 700; }
/* The board takes whatever the head and the banners leave. It is one ranked
   column that moves a whole page at a time, and script spreads the leftover
   height between the rows so the bottom edge never cuts a team in half. */
.lb-board {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  position: relative; overflow: hidden;
  /* Room down the right for the page dots, so they never sit on a score. */
  padding-right: clamp(14px, 2cqw, 34px);
}
/* The list slides as one piece, by whole pages: that is what makes the paging
   honest -- a page is always a whole number of teams. */
.lb-rows {
  display: grid; gap: clamp(5px, 1.1cqh, 14px);
  transition: transform 900ms var(--ease-out);
}
/* Which page of the room is up, so a table that isn't on screen knows to wait
   rather than assume the board has forgotten it. */
.lb-dots {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: clamp(5px, 1cqh, 12px);
}
.lb-dots i {
  width: clamp(5px, 0.8cqh, 9px); height: clamp(5px, 0.8cqh, 9px); border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--line);
}
.lb-dots i.is-on { background: var(--brand-bright); border-color: var(--brand-bright); }

/* ------------------------------------------------------- standings rail --- */

.lb-rail {
  grid-area: rail; min-width: 0;
  display: grid; grid-template-rows: minmax(0, 1fr) auto auto auto;
  gap: clamp(8px, 1.8cqh, 20px);
}

/* The venue's all-time top ten on tonight's game, bottom of the rail: small
   type, one line a team, the room's own tables picked out and a team that
   just made it in gold. */
.lb-records {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(8px, 1.4cqh, 16px) clamp(10px, 1.2cqw, 20px);
  min-width: 0;
}
.lb-records-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  margin-bottom: clamp(4px, 0.8cqh, 10px);
}
.lb-records-title {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.14em; font-size: clamp(11px, 1.6cqh, 18px); color: var(--brand-bright);
}
.lb-records-sub {
  font-size: clamp(10px, 1.4cqh, 16px); font-weight: 700; color: var(--muted);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-records-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(1px, 0.3cqh, 4px); }
.lb-records-row {
  display: grid; grid-template-columns: 1.6em auto minmax(0, 1fr) auto; align-items: center;
  gap: clamp(6px, 0.6cqw, 12px);
  font-size: clamp(11px, 1.7cqh, 20px); font-weight: 800; color: var(--muted);
  padding: clamp(1px, 0.3cqh, 4px) 6px; border-radius: 8px;
}
.lb-records-rank { font-variant-numeric: tabular-nums; text-align: right; color: var(--muted); }
.lb-records-face { --av: clamp(14px, 2cqh, 24px); }
.lb-records-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.lb-records-score { font-variant-numeric: tabular-nums; color: var(--text); }
.lb-records-row.is-here { background: rgba(168, 85, 247, 0.16); }
.lb-records-row.is-here .lb-records-rank { color: var(--brand-bright); }
.lb-records-row.is-fresh { background: rgba(245, 179, 60, 0.16); }
.lb-records-row.is-fresh .lb-records-name, .lb-records-row.is-fresh .lb-records-score,
.lb-records-row.is-fresh .lb-records-rank { color: var(--gold); }
.break-records { margin-top: clamp(8px, 1.4cqh, 16px); }
/* The clock takes whatever height the rail has spare: it is the one thing on
   this screen the room looks up for. */
.lb-clock {
  display: flex; flex-direction: column; gap: clamp(6px, 1.2cqh, 14px);
  align-content: center; justify-content: center; text-align: center;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(10px, 2cqh, 24px);
}
.lb-clock .countdown-label { font-size: clamp(14px, 2.1cqh, 26px); }
.lb-join {
  display: flex; align-items: center; gap: clamp(10px, 1.2cqw, 22px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(10px, 1.8cqh, 20px) clamp(10px, 1.2cqw, 20px);
  min-width: 0; text-align: left;
}
.lb-qr {
  width: clamp(84px, 15cqh, 170px); height: clamp(84px, 15cqh, 170px); flex: 0 0 auto;
  background: #ffffff; border-radius: var(--r-md); padding: clamp(4px, 0.8cqh, 10px);
}
.lb-join-text { min-width: 0; }
.lb-join-label {
  font-size: clamp(11px, 1.6cqh, 18px); font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
}
/* One line, never wrapped: an address broken over two lines gets typed wrong. */
.lb-join-url {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(15px, 2.2cqh, 26px); line-height: 1.15; white-space: nowrap;
  color: var(--brand-bright);
}
.lb-join-hint { font-size: clamp(10px, 1.5cqh, 17px); font-weight: 700; color: var(--muted); }
.lb-teamcard {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(8px, 1cqw, 16px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(8px, 1.6cqh, 18px) clamp(10px, 1.2cqw, 20px);
  font-size: clamp(12px, 1.9cqh, 22px); font-weight: 800; color: var(--muted);
}
.lb-teamcard b { color: var(--text); font-size: clamp(15px, 2.5cqh, 30px); }
.lb-teamcard:has(b:empty) { display: none; }

.lb-board .lb-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  padding: clamp(6px, 1.5cqh, 18px) clamp(14px, 1.6cqw, 30px);
  gap: clamp(12px, 1.4cqw, 26px);
  min-width: 0; overflow: hidden;
}
/* The face column: sized to sit inside the row the name and hit rate already
   make, so the board fits the same number of tables it did without them. */
.lb-board .lb-row.has-av {
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: clamp(8px, 1cqw, 18px);
}
/* The face is as tall as the row's text block, so it nearly fills the bar. */
.lb-board .lb-av { --av: clamp(40px, 7cqh, 78px); margin-right: clamp(4px, 0.4cqw, 8px); }
.leaderboard-final .lb-row.has-av { grid-template-columns: auto auto minmax(0, 1fr) auto auto; }
.leaderboard-final .lb-av { --av: clamp(36px, 6cqh, 66px); }
.lb-board .lb-rank { font-size: clamp(22px, 3.6cqh, 40px); text-align: center; }
/* A team name is the one thing on this board that must be readable in full:
   "The Quizzard of Oz Crew" ellipsised to "The Quizzard of Oz Cr..." is a table
   that can't find itself. So it wraps onto a second line instead, which the
   row's min-content height already allows for. */
.lb-board .lb-name {
  font-size: clamp(18px, 2.9cqh, 32px);
  white-space: normal; overflow-wrap: anywhere; text-overflow: clip;
  line-height: 1.08;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
.lb-board .lb-meta { font-size: clamp(12px, 1.7cqh, 20px); overflow: hidden; }
.lb-board .lb-scorebox { display: flex; align-items: center; gap: clamp(8px, 1cqw, 18px); }
.lb-board .lb-score { font-size: clamp(22px, 3.6cqh, 40px); }
.lb-board .lb-delta {
  font-size: clamp(13px, 1.9cqh, 22px);
  padding: clamp(2px, 0.6cqh, 7px) clamp(8px, 1cqw, 16px);
}

/* First place gets gold and a slow sweep across it: from across a room a still
   board looks like a screenshot, and one moving highlight is the cheapest way
   to make the TV look live. The metal is drawn inside the border rather than as
   a thicker one, so the leader's row is exactly as tall as the rest and a page
   of rows measures the same wherever the leader sits in it. */
.lb-rows .lb-first {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg, rgba(245, 179, 60, 0.18), rgba(124, 58, 237, 0.16));
  border-color: var(--gold);
  box-shadow: inset 0 0 0 1px var(--gold), 0 0 clamp(20px, 4cqh, 48px) rgba(245, 179, 60, 0.2);
}
/* The sweep is a moving background rather than an oversized child, so it can't
   add to the row's own scroll height and squeeze the text. */
.lb-rows .lb-first::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 42%, rgba(255, 255, 255, 0.1) 50%, transparent 58%);
  background-size: 260% 100%;
  animation: lb-sweep 6s linear infinite;
}
@keyframes lb-sweep {
  0% { background-position: 160% 0; }
  35%, 100% { background-position: -60% 0; }
}
.lb-rows .lb-first .lb-rank,
.lb-rows .lb-first .lb-score { color: var(--gold); }
.lb-rows .lb-row.rank-2 { border-color: var(--silver); box-shadow: inset 0 0 0 1px var(--silver); }
.lb-rows .lb-row.rank-3 { border-color: var(--bronze); box-shadow: inset 0 0 0 1px var(--bronze); }
.lb-row.rank-2 .lb-rank, .lb-row.rank-2 .lb-score { color: var(--silver); }
.lb-row.rank-3 .lb-rank, .lb-row.rank-3 .lb-score { color: var(--bronze); }
.lb-rows .lb-score { color: var(--brand-bright); }

@media (prefers-reduced-motion: reduce) {
  .lb-rows { transition: none; }
  .lb-rows .lb-first::after { animation: none; }
}

/* The final board is a different job from the standings: every team at once,
   scrolling itself, so the table that came last still sees where it finished. */
.leaderboard-final { gap: clamp(5px, 1.1cqh, 12px); }
.leaderboard-final .lb-row { padding: clamp(4px, 1cqh, 10px) clamp(12px, 1.3cqw, 24px); }
.leaderboard-final .lb-rank { font-size: clamp(18px, 2.6cqh, 28px); }
.leaderboard-final .lb-name {
  font-size: clamp(16px, 2.3cqh, 24px);
  white-space: normal; overflow-wrap: anywhere; text-overflow: clip; line-height: 1.1;
}
.leaderboard-final .lb-meta { font-size: clamp(11px, 1.5cqh, 18px); }
.leaderboard-final .lb-score { font-size: clamp(18px, 2.6cqh, 28px); }
.leaderboard-final .lb-delta { font-size: clamp(13px, 1.9cqh, 22px); padding: clamp(3px, 0.8cqh, 8px) clamp(9px, 1cqw, 18px); }

/* The commentary, along the bottom next to the clock: streaks, climbs, a table
   that just got on the board. It scrolls rather than rotating in place so the
   board above it never moves, and it only carries lines the server actually
   found in the night's own state. */
.lb-ticker {
  grid-area: tick; min-width: 0; overflow: hidden;
  border-top: 3px solid var(--brand);
  background: rgba(22, 16, 42, 0.9);
  border-radius: var(--r-sm, 8px);
  padding: clamp(4px, 1cqh, 10px) 0;
}
.lb-ticker-move {
  display: inline-block; white-space: nowrap; padding-left: 100%;
  font-size: clamp(22px, 3.6cqh, 42px); font-weight: 900;
  letter-spacing: 0.02em; text-transform: uppercase;
  /* Negative delay so a break opens with a line already on screen instead of
     the room watching an empty strip fill up. */
  animation: lb-ticker 24s linear infinite -4s;
}
.lb-ticker-move .lb-ticker-line { padding: 0 2cqw; }
.lb-ticker-move .lb-ticker-sep { color: var(--brand-bright); }
@keyframes lb-ticker {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}
@media (prefers-reduced-motion: reduce) {
  .lb-ticker-move { animation: none; padding-left: 2cqw; }
}

/* A knockout is the loudest thing on the standings screen, so it reads as a
   verdict rather than another row: it is the moment the room reacts to. */
.knockout-banner {
  background: linear-gradient(90deg, rgba(244, 63, 94, 0.22), transparent);
  border-left: 6px solid var(--incorrect); border-radius: var(--r-md);
  font-size: clamp(18px, 3.2cqh, 34px); font-weight: 900; letter-spacing: 0.02em;
  padding: 1.4cqh clamp(14px, 1.6cqw, 26px); margin-bottom: clamp(6px, 1.5cqh, 16px);
}
.out-tag { color: var(--incorrect); font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; }

/* A round break used to be the standings and a clock. This says what the next
   round is about while that clock runs. */
.next-round-card {
  display: flex; align-items: center; gap: clamp(12px, 1.4cqw, 24px);
  background: linear-gradient(90deg, rgba(124, 58, 237, 0.26), transparent);
  border-left: 6px solid var(--brand-bright); border-radius: var(--r-md);
  padding: 1.2cqh clamp(14px, 1.6cqw, 26px); margin-bottom: clamp(6px, 1.5cqh, 16px);
}
.next-round-art { width: clamp(30px, 5cqh, 58px); height: clamp(30px, 5cqh, 58px); flex: 0 0 auto; }
.next-round-art svg,
.next-round-art .lc-art { width: 100%; height: 100%; }
.next-round-eyebrow {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.14em; color: var(--brand-bright); font-size: clamp(12px, 1.6cqh, 20px);
}
.next-round-title { font-size: clamp(20px, 3.4cqh, 40px); font-weight: 900; }


/* ---------------------------------------------------------- how it works --- */
/*
 * The title card. Big enough to be the room's cue that a game is starting: the
 * game's crest and name, its rules on the left, and a countdown big enough to
 * see from the bar on the right.
 */
/* Three bands with fixed shares of the screen, so a game whose crest is a
   wordmark or whose rules run to five cards can't push the countdown off the
   bottom of a 720p TV. */
#briefing-screen {
  display: flex; flex-direction: column; align-items: center;
  gap: 2cqh; padding: 2.4cqh 2.6cqw 2.2cqh; text-align: center;
}
.brief-head {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  gap: clamp(14px, 2cqw, 34px); max-width: 1600px;
}
.brief-crest { width: clamp(74px, 12cqh, 140px); height: clamp(74px, 12cqh, 140px); flex: 0 0 auto; }
.brief-crest .game-crest-icon { font-size: clamp(44px, 7cqh, 84px); }
/* The artwork is a wordmark, so the crest stops being a square and becomes a
   banner beside the name. */
.brief-crest.is-logo { width: auto; height: auto; max-width: min(34cqw, 520px); }
.brief-head-text {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 1cqh; text-align: left; min-width: 0;
}
.brief-title {
  margin: 0; font-family: var(--font-display); font-weight: 900;
  text-transform: uppercase; letter-spacing: -0.01em; line-height: 1;
  font-size: clamp(34px, 6.6cqh, 92px);
}
.brief-tagline {
  margin: 0; color: var(--muted); font-weight: 700;
  font-size: clamp(16px, 2.2cqh, 28px); max-width: 46ch;
}

/* The clock is the whole point of this screen: it is what tells a room mid-pint
   to pick a tablet up. The code beside it is for whoever just walked in. */
.brief-mid {
  flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  gap: clamp(24px, 5cqw, 90px);
}
.brief-join { display: flex; flex-direction: column; align-items: center; gap: 0.9cqh; }
/* The clock breathes light while it drains, so the biggest thing on the screen
   is also the most alive thing on it. */
.brief-mid .countdown-ring {
  border-radius: 50%;
  box-shadow: 0 0 40px rgba(168, 85, 247, 0.45);
}
.brief-qr {
  width: clamp(96px, 19cqh, 210px); height: clamp(96px, 19cqh, 210px);
  background: #ffffff; padding: clamp(5px, 0.8cqh, 10px);
  border-radius: var(--r-md); border: 3px solid var(--brand);
  box-shadow: 0 0 34px rgba(124, 58, 237, 0.35);
}
.brief-join-tag {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.14em; color: var(--brand-bright);
  font-size: clamp(12px, 1.8cqh, 22px);
}

/* Waiting on the room: who has tapped ready (gold) and who hasn't (dim), as
   a panel beside the clock so the host can see across the bar who to help. */
.brief-ready {
  flex: 0 1 auto; max-width: 46cqw; max-height: 44cqh; overflow: hidden;
  display: flex; flex-direction: column; gap: 1.2cqh;
  padding: clamp(12px, 2cqh, 26px) clamp(14px, 1.6cqw, 30px);
  background: rgba(255, 255, 255, 0.04); border: 2px solid var(--gold);
  border-radius: 22px; box-shadow: 0 0 40px rgba(245, 179, 60, 0.2);
}
.brief-ready-head { display: flex; align-items: baseline; gap: 1.2cqw; flex-wrap: wrap; }
.brief-ready-title {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--gold); font-size: clamp(16px, 2.6cqh, 34px);
}
.brief-ready-count {
  font-weight: 800; color: var(--muted); font-size: clamp(13px, 2cqh, 26px);
  font-variant-numeric: tabular-nums;
}
.brief-ready-list {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6cqh 1.2cqw; overflow: hidden;
}
.brief-ready.is-crowded .brief-ready-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.brief-ready-row {
  display: flex; align-items: center; gap: 0.7cqw; min-width: 0;
  font-size: clamp(14px, 2.4cqh, 30px); font-weight: 800;
}
.brief-ready.is-crowded .brief-ready-row { font-size: clamp(12px, 1.9cqh, 24px); }
.brief-ready-face { width: 1.6em; height: 1.6em; flex: 0 0 auto; }
.brief-ready-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brief-ready-row.is-waiting { color: var(--text); }
.brief-ready-row.is-waiting .brief-ready-face { opacity: 0.55; }
.brief-ready-row.is-ready { color: var(--gold); }
.brief-ready-row.is-out { color: var(--muted); }
.brief-ready-row.is-out .brief-ready-face { opacity: 0.35; filter: grayscale(1); }
.brief-ready-tag {
  font-size: 0.55em; text-transform: uppercase; letter-spacing: 0.12em;
  padding: 0.15em 0.6em; border-radius: 999px; border: 1px solid currentColor; flex: 0 0 auto;
}
.brief-ready-hint { color: var(--muted); font-size: clamp(12px, 1.8cqh, 22px); }
.brief-ready-hint b { color: var(--gold); }

.brief-rules { flex: 0 0 auto; width: 100%; max-width: 1700px; }
.briefing-heading {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.14em; color: var(--brand-bright);
  font-size: clamp(15px, 2cqh, 26px); margin-bottom: 1.2cqh;
}
/* One card per rule, always in a single row the room reads left to right: the
   headline is for the back of the bar, the sentence under it for whoever is on
   their first night. One row rather than two, so the band's height doesn't
   depend on how many rules a game has and can't push the clock off a 720p TV. */
.brief-cards {
  display: grid; gap: clamp(8px, 1cqw, 20px);
  grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
}
.brief-card {
  display: flex; flex-direction: column; align-items: center; gap: 0.7cqh;
  padding: clamp(10px, 1.6cqh, 22px) clamp(10px, 1cqw, 18px);
  border: 2px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); text-align: center;
}
.brief-card .lc-icon {
  width: clamp(24px, 3.6cqh, 44px); height: clamp(24px, 3.6cqh, 44px);
  color: var(--gold);
}
.brief-card-headline {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.06em; font-size: clamp(14px, 2.1cqh, 26px);
}
.brief-card-detail {
  color: var(--muted); font-weight: 700; line-height: 1.25;
  font-size: clamp(12px, 1.75cqh, 22px);
}

/* Who the room is chasing across every night played, on the way into this one.
   Sized in vh like the rest of the card so it can't push the countdown off a
   720p screen. */
.alltime-strip {
  width: 100%; max-width: 460px;
  border: 2px solid var(--line); border-radius: var(--r-md);
  background: rgba(124, 58, 237, 0.1);
  padding: clamp(6px, 1.1cqh, 14px) clamp(10px, 1.4cqw, 20px);
}
.alltime-label {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--gold);
  font-size: clamp(11px, 1.5cqh, 18px); margin-bottom: 0.6cqh;
}
.alltime-rows { display: flex; flex-direction: column; gap: 0.4cqh; }
.alltime-row {
  display: flex; align-items: baseline; gap: clamp(6px, 0.8cqw, 12px);
  font-size: clamp(13px, 1.9cqh, 24px); font-weight: 800;
}
.alltime-rank { color: var(--muted); min-width: 1.4em; }
.alltime-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alltime-points { color: var(--accent); font-variant-numeric: tabular-nums; }

/* The last beat of the countdown, over the rules card. Deliberately the loudest
   thing the TV ever shows: it is the cue for a room mid-conversation to look
   up and pick a tablet back up. */
.here-we-go {
  position: absolute; inset: 0; z-index: 20; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 50%, rgba(124, 58, 237, 0.94), rgba(11, 9, 20, 0.96));
  animation: here-we-go-in 260ms ease-out both;
}
.here-we-go > span {
  font-family: var(--font-display); font-weight: 900; font-style: italic;
  font-size: clamp(56px, 17cqh, 220px); line-height: 1;
  text-transform: uppercase; letter-spacing: -0.02em; text-align: center;
  transform: skewX(-6deg);
  color: #ffffff; text-shadow: 0 0 60px rgba(245, 179, 60, 0.8);
  /* Lands like a punch and then breathes, which is what makes a room look up. */
  animation: here-we-go-punch 620ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both,
             here-we-go-pulse 900ms ease-in-out 620ms infinite;
}
@keyframes here-we-go-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes here-we-go-punch {
  0% { transform: skewX(-6deg) scale(0.55); opacity: 0; }
  60% { transform: skewX(-6deg) scale(1.12); opacity: 1; }
  80% { transform: skewX(-6deg) scale(0.96); }
  100% { transform: skewX(-6deg) scale(1); opacity: 1; }
}
@keyframes here-we-go-pulse {
  0%, 100% { transform: skewX(-6deg) scale(1); }
  50% { transform: skewX(-6deg) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .here-we-go span { animation: none; }
}

/* ------------------------------------------------------------- next up --- */
/*
 * The two seconds before a question: the same rings the room already knows
 * mean look up, a category badge, the headline slamming in, and a line across
 * the top draining to the question. Covers whatever was showing -- the
 * break board and its join code included -- so it is opaque to the edges.
 */
.next-up {
  position: absolute; inset: 0; z-index: 30; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: #000 radial-gradient(circle at 50% 50%, rgba(124, 58, 237, 0.45), #16102a 50%, #000);
  animation: here-we-go-in 200ms ease-out both;
}
.next-up-sweep {
  position: absolute; top: 0; bottom: 0; left: 0; width: 12cqw;
  background: linear-gradient(90deg, transparent, rgba(168, 85, 247, 0.3), transparent);
  animation: next-up-sweep 1.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes next-up-sweep {
  0% { transform: translateX(-120%) skewX(-25deg); opacity: 0; }
  20%, 80% { opacity: 0.8; }
  100% { transform: translateX(950%) skewX(-25deg); opacity: 0; }
}
.next-up-drain {
  position: absolute; top: 0; left: 0; right: 0; height: 1.2cqh;
  background: rgba(59, 7, 100, 0.6);
}
.next-up-drain > span {
  display: block; height: 100%; width: 100%;
  background: linear-gradient(90deg, var(--gold), var(--brand-bright), var(--accent));
  box-shadow: 0 0 20px rgba(245, 179, 60, 0.9);
  animation: next-up-drain var(--next-up-seconds, 2s) linear forwards;
}
@keyframes next-up-drain { from { width: 100%; } to { width: 0%; } }
.next-up-text {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: 9cqh;
  text-align: center; padding: 0 6cqw;
}
.next-up-category {
  display: inline-flex; align-items: center; gap: 1.2cqw;
  padding: 1.4cqh 3cqw; border-radius: 999px;
  background: rgba(59, 7, 100, 0.7); border: 2px solid rgba(168, 85, 247, 0.6);
  box-shadow: 0 0 35px rgba(168, 85, 247, 0.5); backdrop-filter: blur(8px);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(20px, 4.2cqh, 54px); letter-spacing: 0.12em; text-transform: uppercase;
  color: #fcd68a;
  animation: next-up-pop 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.15s both;
}
.next-up-category:empty { display: none; }
.next-up-category::before {
  content: "★"; color: var(--gold); font-size: 0.9em;
  animation: next-up-bounce 1s ease-in-out infinite;
}
@keyframes next-up-pop {
  0% { transform: scale(0.8); opacity: 0; }
  40% { transform: scale(1.05); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes next-up-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-18%); }
}
.next-up-headline {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(64px, 19cqh, 250px); line-height: 0.95;
  letter-spacing: -0.03em; text-transform: uppercase;
  background: linear-gradient(180deg, #ffffff, #f1f5f9 55%, #d8b4fe);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 10px 35px rgba(0, 0, 0, 0.9));
  animation: next-up-slam 1.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.next-up-headline em {
  font-style: normal;
  background: linear-gradient(90deg, #fbbf24, #fcd34d, #fef08a);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 40px rgba(245, 179, 60, 0.8));
}
@keyframes next-up-slam {
  0% { transform: scale(0.6) translateY(20px); opacity: 0; filter: blur(8px); }
  25% { transform: scale(1.08) translateY(-4px); opacity: 1; filter: blur(0); }
  35% { transform: scale(0.98) translateY(0); }
  50% { transform: scale(1.02); }
  75% { transform: scale(0.99); }
  100% { transform: scale(1); }
}
/* The final question of a game: the headline flashes gold so the room knows
   this is the one that settles it. */
.next-up.is-last .next-up-headline {
  animation: next-up-slam 1.6s cubic-bezier(0.16, 1, 0.3, 1) both,
    next-up-flash 0.5s steps(2, jump-none) 0.6s infinite;
}
.next-up.is-last .next-up-headline em {
  background: linear-gradient(90deg, #fbbf24, #fef08a, #fbbf24);
  -webkit-background-clip: text; background-clip: text;
}
@keyframes next-up-flash {
  from { opacity: 1; filter: drop-shadow(0 0 60px rgba(245, 179, 60, 1)); }
  to { opacity: 0.55; filter: drop-shadow(0 10px 35px rgba(0, 0, 0, 0.9)); }
}
.next-up-counter {
  padding: 1.4cqh 3.4cqw; border-radius: 2cqh;
  background: rgba(22, 16, 42, 0.9); border: 2px solid rgba(168, 85, 247, 0.5);
  box-shadow: 0 0 30px rgba(124, 58, 237, 0.5);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(22px, 5cqh, 64px); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--gold); text-shadow: 0 0 20px rgba(245, 179, 60, 0.9);
  animation: next-up-slam 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.1s both;
}
.next-up-counter:empty { display: none; }
@media (prefers-reduced-motion: reduce) {
  .next-up-sweep, .next-up-category, .next-up-headline, .next-up-counter,
  .next-up.is-last .next-up-headline { animation: none; }
}

/* ------------------------------------------------------------- moments --- */
/*
 * The board changing hands, and the winner. Same rings and same punch as "Here
 * we go!", because by then the room has learned that those mean look up -- but
 * over whatever screen is up rather than only the rules card, and with a second
 * line for whose moment it is.
 */
.tv-moment {
  position: absolute; inset: 0; z-index: 40; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 50%, #7c3aed, #0b0914);
  animation: here-we-go-in 260ms ease-out both;
}
.tv-moment-text {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: 2cqh;
  text-align: center; padding: 0 6cqw;
}
#tv-moment-avatar:empty { display: none; }
.tv-moment-avatar { --av: clamp(118px, 22cqh, 250px); justify-content: center; }
.tv-moment-avatar .av-c { border-color: var(--gold); box-shadow: 0 0 42px rgba(245, 179, 60, 0.35); }
.tv-moment-headline {
  font-family: var(--font-display); font-weight: 900; font-style: italic;
  font-size: clamp(48px, 14cqh, 190px); line-height: 1;
  text-transform: uppercase; letter-spacing: -0.02em;
  transform: skewX(-6deg);
  color: #ffffff; text-shadow: 0 0 60px rgba(245, 179, 60, 0.8);
  animation: here-we-go-punch 620ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both,
             here-we-go-pulse 900ms ease-in-out 620ms infinite;
}
.tv-moment-sub {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(24px, 6cqh, 78px); line-height: 1.1;
  color: var(--gold); text-shadow: 0 0 40px rgba(245, 179, 60, 0.45);
  max-width: 80cqw; overflow-wrap: anywhere;
}
.tv-moment-sub:empty { display: none; }
@media (prefers-reduced-motion: reduce) {
  .tv-moment-headline { animation: none; }
}

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/*
 * The lead change gets a stage set: a purple game-show floor with a lit podium
 * and a gold-ringed aperture above it, painted as a plate behind the frame. The
 * leader's face is laid over the aperture live (never in the art), the banner
 * text is live too, so both change per event. The plate is 16:9 like the
 * stage, so its aperture sits at 50% / 53.3% and is 27.5% of the height across.
 * Gold here is the ring, the burst and the podium -- the winning moment only.
 */
.tv-moment.is-lead {
  background: #0b0914 url("/shared/brand/lead-change-stage.webp") center / cover no-repeat;
  animation: here-we-go-in 150ms ease-out both,
             lead-stage-out 300ms ease-in 1.2s forwards;
}
.tv-moment.is-lead .hwg-rings { display: none; }
.tv-moment.is-lead .tv-moment-text { position: absolute; inset: 0; padding: 0; display: block; }
/* The banner: the plate's outlined box runs 7% to 24.6% of the height. */
.tv-moment.is-lead .tv-moment-headline {
  position: absolute; left: 12%; right: 12%; top: 7%; height: 17.6%;
  display: flex; align-items: center; justify-content: center;
  font-style: normal; font-size: clamp(40px, 12.5cqh, 150px);
  letter-spacing: 0.01em; transform: none;
  color: #fff;
  -webkit-text-stroke: 0.06em #5b21b6; paint-order: stroke fill;
  text-shadow: 0 0 22px rgba(139, 92, 246, 0.9), 0 4px 0 #3b0d7a;
  animation: lead-banner-in 200ms cubic-bezier(0.2, 0.9, 0.3, 1.2) 150ms both;
}
/* Halo, then face, then the champion ring: one wrapper, centred on the aperture. */
.tv-moment.is-lead #tv-moment-avatar {
  position: absolute; left: 50%; top: 53.3%;
  width: clamp(140px, min(22cqw, 31cqh), 340px); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--gold), 0 0 0 5px rgba(59, 13, 122, 0.9),
              0 0 90px 30px rgba(139, 92, 246, 0.55), 0 0 60px rgba(245, 179, 60, 0.45);
  animation: lead-face-in 300ms cubic-bezier(0.2, 0.9, 0.3, 1.15) 250ms both;
}
.tv-moment.is-lead #tv-moment-avatar:empty { display: block; background: #1a0630; }
.tv-moment.is-lead .tv-lead-face {
  --av: 100%;
  display: block; width: 100%; height: 100%; border: 0;
  background: var(--av-bg, #1a0630); box-shadow: none;
}
.tv-moment.is-lead .tv-lead-face.av-default { background: #1a0630; }
/* A table's pair: two faces overlapped inside the one ring, on the plum fill. */
.tv-moment.is-lead #tv-moment-avatar:has(.tv-lead-pair) {
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; background: #1a0630; container-type: size;
}
.tv-moment.is-lead .tv-lead-pair { --av: 62cqw; display: flex; width: auto; }
.tv-moment.is-lead .tv-lead-pair .av-c { border-color: #1a0630; }
.tv-moment.is-lead .tv-lead-pair .av-c + .av-c { margin-left: -14cqw; }
/* Whose moment: on the podium's face, white -- gold is the podium's. */
.tv-moment.is-lead .tv-moment-sub {
  position: absolute; left: 20%; right: 20%; top: 73%;
  display: block; font-size: clamp(22px, 5.6cqh, 64px); line-height: 1.1;
  color: #fff; text-shadow: 0 0 18px rgba(26, 6, 48, 1), 0 2px 10px rgba(0, 0, 0, 0.9);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  animation: lead-banner-in 200ms ease-out 350ms both;
}
@keyframes lead-banner-in {
  from { opacity: 0; transform: translateY(-6%) scale(0.94); }
  to { opacity: 1; transform: none; }
}
@keyframes lead-face-in {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.82); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes lead-stage-out {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .tv-moment.is-lead, .tv-moment.is-lead .tv-moment-headline,
  .tv-moment.is-lead #tv-moment-avatar, .tv-moment.is-lead .tv-moment-sub { animation: none; }
}

/* ---------------------------------------------------------- paused --- */
/* A clock that has stopped moving reads as a crashed system, so the hold says
   it is a hold -- small, in a corner, out of the way of the game. */
.tv-paused {
  position: absolute; z-index: 45; left: 50%; transform: translateX(-50%);
  bottom: clamp(10px, 1.6cqh, 22px);
  display: flex; align-items: center; gap: 0.8cqw;
  padding: clamp(6px, 1cqh, 12px) clamp(12px, 1.6cqw, 24px);
  border-radius: var(--r-pill);
  background: rgba(11, 7, 20, 0.88);
  border: 2px solid var(--gold);
  color: var(--gold);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(14px, 2.4cqh, 30px); text-transform: uppercase;
  letter-spacing: 0.04em;
}
.tv-paused-dot {
  width: 1.4cqh; height: 1.4cqh; min-width: 10px; min-height: 10px;
  border-radius: 50%; background: var(--gold);
  animation: paused-blink 1.6s ease-in-out infinite;
}
@keyframes paused-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
  .tv-paused-dot { animation: none; }
}

/* Shown only when the browser refused the fullscreen the host asked for, so the
   room isn't left looking at an address bar with nobody knowing why. */
.tv-fs-cue {
  position: absolute; z-index: 50; top: clamp(8px, 1.4cqh, 20px); left: 50%;
  transform: translateX(-50%);
  padding: clamp(6px, 1cqh, 12px) clamp(12px, 1.6cqw, 24px);
  border-radius: var(--r-pill);
  background: rgba(11, 7, 20, 0.9); border: 2px solid var(--accent); color: var(--accent);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(13px, 2.2cqh, 26px);
}

/* The host turned TV sound on but the browser wants a touch first. Sits at
   the top like the fullscreen cue, in gold so it reads as a to-do. */
.tv-sound-nudge {
  position: absolute; z-index: 50; top: clamp(8px, 1.4cqh, 20px); left: 50%;
  transform: translateX(-50%);
  padding: clamp(6px, 1cqh, 12px) clamp(12px, 1.6cqw, 24px);
  border-radius: var(--r-pill);
  background: rgba(11, 7, 20, 0.9); border: 2px solid var(--gold); color: var(--gold);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(13px, 2.2cqh, 26px);
  max-width: 90%; text-align: center;
}

/* --------------------------------------------------------------- break --- */
/*
 * Between two games. The room is talking, getting a drink and looking up every
 * so often, so the screen answers one question at a glance -- how long until
 * the next game -- and fills the rest with something worth reading.
 */
#break-screen { gap: clamp(10px, 2cqh, 26px); }

.break-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(14px, 2cqw, 32px); width: 100%;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(10px, 1.8cqh, 22px) clamp(14px, 2cqw, 30px);
  box-sizing: border-box;
}
.break-next { display: flex; align-items: center; gap: clamp(10px, 1.4cqw, 22px); min-width: 0; }
.break-crest {
  width: clamp(56px, 9cqh, 108px); height: clamp(56px, 9cqh, 108px);
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md);
  background: linear-gradient(135deg, var(--brand-deep), var(--brand));
  color: var(--on-brand);
}
.break-crest.is-logo { width: auto; max-width: min(38cqw, 420px); background: none; }
.break-crest .game-crest-icon { font-size: clamp(30px, 5.4cqh, 62px); }
.break-crest .lc-art { width: 100%; height: 100%; }
.break-next-text { min-width: 0; text-align: left; }
.break-kicker {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.18em; color: var(--brand-bright);
  font-size: clamp(12px, 1.7cqh, 20px);
}
.break-next-title {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(26px, 5cqh, 60px); line-height: 1.05; margin: 0.2cqh 0 0.6cqh;
  text-shadow: 0 0 30px rgba(168, 85, 247, 0.5);
}

.break-clock { text-align: right; flex: 0 0 auto; }
.break-clock-label {
  font-size: clamp(12px, 1.7cqh, 20px); font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.2em; color: var(--muted);
}
.break-clock-num {
  font-family: var(--font-display); font-weight: 900; font-variant-numeric: tabular-nums;
  font-size: clamp(46px, 11cqh, 132px); line-height: 1; color: var(--gold);
  text-shadow: 0 0 40px rgba(245, 179, 60, 0.45);
}
/* The last half-minute, when the room should be sitting down. */
.break-clock-num.is-urgent { color: var(--danger, #f87171); animation: break-urgent 1s ease-in-out infinite; }
@keyframes break-urgent {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.break-stage {
  flex: 1 1 auto; width: 100%; min-height: 0;
  display: flex; align-items: stretch; gap: clamp(12px, 1.6cqw, 28px);
}
.break-filler { flex: 1 1 auto; min-width: 0; display: flex; }
/* The code and the all-time board, which are only worth screen time in a gap
   this long. Both hide themselves when there is nothing to show. */
.break-side {
  flex: 0 0 auto; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: clamp(10px, 2cqh, 26px);
}
.break-join {
  display: flex; flex-direction: column; align-items: center; gap: 0.9cqh;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(12px, 2.2cqh, 26px) clamp(14px, 1.6cqw, 30px);
}
.break-join-tag {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(14px, 2.2cqh, 28px); color: var(--text);
}
.break-qr {
  width: clamp(140px, 30cqh, 330px); height: clamp(140px, 30cqh, 330px);
  background: #ffffff; padding: clamp(6px, 1cqh, 14px);
  border-radius: var(--r-md); border: 3px solid var(--brand);
  box-shadow: 0 0 34px rgba(124, 58, 237, 0.35);
}
.break-join-or {
  font-size: clamp(11px, 1.5cqh, 18px); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.12em; margin-top: 0.4cqh;
}
.break-join-url {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(14px, 2.4cqh, 30px); color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.break-panel {
  flex: 1 1 auto; width: 100%; min-height: 0;
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(8px, 1.6cqh, 20px);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-left: 8px solid var(--brand-bright);
  border-radius: var(--r-lg);
  padding: clamp(14px, 3cqh, 40px) clamp(18px, 3cqw, 56px);
  box-sizing: border-box; text-align: left;
}
.break-board-panel { border-left-color: var(--gold); justify-content: flex-start; }
.break-fact-panel { justify-content: flex-start; }
.break-panel-in { animation: break-panel-in 320ms ease-out both; }
@keyframes break-panel-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .break-panel-in { animation: none; }
}
.break-tag {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.2em; color: var(--brand-bright);
  font-size: clamp(13px, 1.9cqh, 24px);
}
.break-board-panel .break-tag { color: var(--gold); }
/* The fact's own title, which is allowed to be silly: the facts are quirky and a
   thin tracked-out label over them read like a section header in a manual. Big,
   hand-drawn and knocked off square. The face ships with the repo, so it is the
   same on the stick, a Mac and a tablet with no internet. */
.break-fact-tag {
  font-family: var(--font-funky);
  font-size: clamp(30px, 6.4cqh, 78px);
  letter-spacing: 0.03em; line-height: 1;
  color: var(--gold); text-transform: uppercase;
  transform: rotate(-3.5deg); transform-origin: center;
  text-align: center;
  margin-top: clamp(20px, 5.2cqh, 68px);
  margin-bottom: clamp(10px, 2.4cqh, 32px);
  text-shadow: 0 4px 0 rgba(0, 0, 0, 0.45), 0 0 26px rgba(245, 179, 60, 0.35);
}
/* The title holds the top of the box; the fact takes the space that is left and
   sits in the middle of it, so the two never crowd each other. */
.break-fact-text {
  flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto; font-weight: 700; line-height: 1.25; color: var(--text);
  font-size: clamp(24px, 5.2cqh, 62px); max-width: 34ch;
  text-align: center;
}
.break-board-rows { display: flex; flex-direction: column; gap: clamp(4px, 0.9cqh, 10px); }
.break-board-row {
  display: flex; align-items: center; gap: clamp(10px, 1.4cqw, 22px);
  font-size: clamp(18px, 3.2cqh, 40px); font-weight: 800;
  border-bottom: 1px solid var(--line); padding-bottom: clamp(2px, 0.5cqh, 6px);
}
.break-board-row.is-winner { color: var(--gold); }
.break-board-rank { min-width: 1.6em; color: var(--muted); }
.break-board-av { --av: clamp(28px, 4.6cqh, 56px); }
.break-board-row.is-winner .break-board-rank { color: var(--gold); }
.break-board-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.break-board-score { font-variant-numeric: tabular-nums; }
/* The best-ofs: who did what, one line each, with the number on the right. */
.break-best-panel { border-left-color: var(--brand-bright); justify-content: flex-start; }
.break-best-rows { display: flex; flex-direction: column; gap: clamp(4px, 0.9cqh, 10px); }
.break-best-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
  align-items: center; gap: clamp(10px, 1.4cqw, 22px);
  font-size: clamp(16px, 2.9cqh, 36px); font-weight: 800;
  border-bottom: 1px solid var(--line); padding-bottom: clamp(2px, 0.5cqh, 6px);
}
.break-best-lead { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }
.break-best-who { color: var(--gold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.break-best-what {
  color: var(--muted); font-weight: 700; font-size: 0.62em; letter-spacing: 0.04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.break-best-num {
  text-align: right; font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The "only one to get it" line carries the question, not a number. */
.break-best-row.is-lone .break-best-num {
  font-size: 0.7em; font-weight: 700; white-space: normal; line-height: 1.15;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.break-foot {
  font-size: clamp(14px, 2.1cqh, 26px); font-weight: 700; color: var(--muted); text-align: center;
}
/* The vote: one bar per game with votes, the count on the right. */
.break-vote-panel { border-left-color: var(--gold); justify-content: flex-start; }
.break-vote-panel .break-tag { color: var(--gold); }
.break-vote-head { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; }
.break-vote-title {
  font-family: var(--font-display); font-weight: 900; line-height: 1;
  font-size: clamp(24px, 4.6cqh, 56px);
}
.break-vote-count {
  color: var(--muted); font-weight: 700; white-space: nowrap;
  font-size: clamp(14px, 2.2cqh, 26px);
}
.break-vote-rows { display: flex; flex-direction: column; gap: clamp(4px, 1cqh, 12px); }
.break-vote-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: clamp(10px, 1.4cqw, 22px);
  font-size: clamp(16px, 2.9cqh, 36px); font-weight: 800;
}
.break-vote-rows.is-small .break-vote-row { font-size: clamp(13px, 2cqh, 24px); }
.break-vote-icon {
  width: 1.6em; height: 1.6em; display: grid; place-items: center;
  border-radius: 10px; background: var(--surface-2); overflow: hidden;
}
.break-vote-icon img { width: 100%; height: 100%; object-fit: cover; }
.break-vote-icon svg, .break-vote-icon .lc-icon { width: 70%; height: 70%; }
.break-vote-lead { display: flex; flex-direction: column; min-width: 0; gap: 0.2em; }
.break-vote-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.1; }
.break-vote-bar { height: 0.42em; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.break-vote-bar i {
  display: block; height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--brand-bright), var(--gold));
  transition: width 420ms ease-out;
}
.break-vote-row.is-leading .break-vote-name { color: var(--gold); }
.break-vote-num { font-variant-numeric: tabular-nums; min-width: 1.4em; text-align: right; }
.break-vote-voters { color: var(--muted); font-weight: 700; font-size: 0.7em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.break-vote-empty { color: var(--muted); font-weight: 700; font-size: clamp(18px, 3cqh, 36px); padding: 1em 0; text-align: center; }
.break-vote-foot { color: var(--muted); font-weight: 700; font-size: clamp(14px, 2.1cqh, 26px); margin-top: auto; }
/* The result: the game's art, who called it, and the one sentence why. */
.break-vote-result-panel { border-left-color: var(--gold); justify-content: flex-start; }
.break-vote-result-panel .break-tag { color: var(--gold); }
.break-vote-winner { display: flex; align-items: center; gap: clamp(14px, 2cqw, 32px); }
.break-vote-art {
  width: clamp(80px, 14cqh, 170px); height: clamp(80px, 14cqh, 170px); flex: 0 0 auto;
  border-radius: var(--r-lg); background: var(--surface-2); overflow: hidden;
  display: grid; place-items: center;
}
.break-vote-art img { width: 100%; height: 100%; object-fit: cover; }
.break-vote-art .game-crest-icon { font-size: clamp(40px, 7cqh, 90px); }
.break-vote-winner-title {
  font-family: var(--font-display); font-weight: 900; line-height: 1;
  font-size: clamp(30px, 6.4cqh, 78px);
}
.break-vote-who {
  display: flex; align-items: center; gap: 0.5em; margin-top: 0.3em;
  color: var(--gold); font-weight: 800; font-size: clamp(16px, 2.8cqh, 34px);
}
.break-vote-who .lc-avgroup { --av: clamp(28px, 4.6cqh, 56px); }
.break-vote-reason {
  margin: 0; font-weight: 700; line-height: 1.3; color: var(--text);
  font-size: clamp(16px, 2.7cqh, 32px);
}

/* ---------------------------------------------------------- countdowns --- */

.countdown-big { flex-direction: column; gap: 10px; text-align: center; }
.countdown-big .countdown-label { font-size: clamp(16px, 2.2cqh, 28px); }
.countdown-inline { gap: 20px; }
.countdown-inline .countdown-label { font-size: clamp(18px, 2.4cqh, 30px); }

/* --------------------------------------------------------------- final --- */

/* Sized off the screen's height, not in pixels: the same ceremony has to leave
   room for the board's title on a 720p set as it does on a 1080p one. */
.final-head { text-align: center; margin-bottom: clamp(10px, 2.4cqh, 26px); }
.final-crown { font-size: clamp(34px, 5.2cqh, 56px); line-height: 1; }
.final-title {
  font-family: var(--font-display); font-size: clamp(38px, 5.8cqh, 62px); font-weight: 900;
  text-transform: uppercase; letter-spacing: 0.12em; margin: 6px 0 4px;
}
.final-winner { font-size: clamp(22px, 3cqh, 32px); color: var(--gold); font-weight: 800; margin: 0; }

/* The venue's record on the game, one line wherever the game is named: the
   score to beat on the rules card, the standing record under the break board
   and the final board -- and, when it has just fallen, said in gold. */
.brief-record, .break-record, .final-record {
  margin: 0; font-weight: 800; color: var(--muted);
  font-size: clamp(15px, 2.1cqh, 26px);
}
.break-record { margin-top: clamp(6px, 1.2cqh, 14px); }
.record-label {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.14em; font-size: 0.8em; color: var(--brand-bright);
}
.record-score { color: var(--text); font-variant-numeric: tabular-nums; }
.is-new .record-label, .is-new .record-score { color: var(--gold); }
.is-new .record-label { animation: record-pulse 1.2s ease-in-out infinite alternate; }
@keyframes record-pulse { from { opacity: 0.65; } to { opacity: 1; } }

/* Three plinths, tallest in the middle: the shape everyone already reads as
   1st / 2nd / 3rd without a legend. */
.podium { display: flex; align-items: flex-end; justify-content: center; gap: clamp(12px, 2.4cqh, 26px); margin-bottom: clamp(10px, 2.4cqh, 26px); }
/* Plinths are 300px wide but shrink rather than overflow the screen when a tie
   puts more than three teams on the podium. */
.podium-slot { flex: 0 1 300px; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: clamp(6px, 1.2cqh, 12px); }
/* Wraps within its plinth rather than growing the slot upward into the lockup:
   two 24-character names side by side is the widest this ever gets. */
.podium-name {
  font-size: clamp(20px, 2.8cqh, 30px); font-weight: 800; text-align: center;
  overflow-wrap: anywhere; max-width: 100%;
}
.podium-score { font-family: var(--font-display); font-size: clamp(26px, 3.8cqh, 40px); font-weight: 900; font-variant-numeric: tabular-nums; }
/* The winner's face is the biggest thing on the plinth; a pair sits centred
   with the same overlap as the board. */
.podium-av { --av: clamp(56px, 9cqh, 110px); justify-content: center; }
.podium-slot.p1 .podium-av { --av: clamp(72px, 12cqh, 140px); }
.podium-slot.p1 .av-c { border-color: var(--gold); }
.podium-block {
  width: 100%; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: linear-gradient(180deg, var(--surface-3), var(--surface));
  border: 1px solid var(--line); border-bottom: none;
  display: flex; align-items: flex-start; justify-content: center;
  font-family: var(--font-display); font-size: clamp(38px, 6cqh, 64px); font-weight: 900;
  padding-top: clamp(8px, 1.4cqh, 14px);
  animation: lc-rise-in var(--t-slow) var(--ease-out) both;
}
.podium-slot.p1 .podium-block { height: clamp(130px, 22cqh, 240px); background: linear-gradient(180deg, rgba(245, 179, 60, 0.4), var(--surface)); border-color: rgba(245, 179, 60, 0.6); color: var(--gold); }
.podium-slot.p2 .podium-block { height: clamp(98px, 16.5cqh, 180px); color: var(--silver); }
.podium-slot.p3 .podium-block { height: clamp(76px, 13cqh, 140px); color: var(--bronze); }
.podium-slot.p1 .podium-score { color: var(--gold); }
.podium-slot.knocked-out { opacity: 0.6; }
.podium-out {
  color: var(--incorrect); font-size: 22px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em; text-align: center;
}

/* The podium's few seconds of ceremony, then it shrinks out of the way of the
   board the room actually wants -- the podium is not why anybody stayed. */
.podium { transition: max-height var(--t-slow) var(--ease-out), opacity var(--t-slow) ease; overflow: hidden; }
/* Capped so the ceremony can never push the board's title off the bottom of a
   1080p set, however the tie shakes out. */
.podium.podium-hero { max-height: 52cqh; flex: 0 0 auto; }
.podium:not(.podium-hero) { max-height: 0; opacity: 0; overflow: hidden; margin-bottom: 0; }

.final-board-title {
  font-family: var(--font-display); font-size: clamp(22px, 3.2cqh, 34px); font-weight: 900;
  text-transform: uppercase; letter-spacing: 0.1em; text-align: center;
  color: var(--brand-bright); margin: 0 0 clamp(6px, 1.4cqh, 14px); flex: 0 0 auto;
}
/* Every team, scrolling itself: last place has to be able to see where it
   finished, and there is nobody at the laptop to page the board. */
.final-scroll { flex: 1; min-height: 0; overflow: hidden; }

/* The night's awards: one card each, in a row, faces big enough to be found
   from the back of the room. They land one after another like envelopes. */
.awards-grid {
  height: 100%; display: grid; gap: clamp(10px, 1.6cqw, 28px);
  grid-template-columns: repeat(var(--award-cols, 4), minmax(0, 1fr));
  align-content: center; padding: 0 clamp(8px, 2cqw, 40px);
}
.awards-1 { --award-cols: 1; max-width: 40cqw; margin: 0 auto; }
.awards-2 { --award-cols: 2; max-width: 70cqw; margin: 0 auto; }
.awards-3 { --award-cols: 3; }
.award-card {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: clamp(4px, 1cqh, 12px); padding: clamp(14px, 3cqh, 34px) clamp(10px, 1.4cqw, 26px);
  border-radius: var(--r-lg); border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--surface-3), var(--surface));
  animation: lc-rise-in var(--t-slow) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 260ms);
}
.award-fastest { border-color: rgba(250, 204, 21, 0.5); }
.award-comeback { border-color: rgba(52, 211, 153, 0.5); }
.award-sharpest { border-color: rgba(96, 165, 250, 0.5); }
.award-streak { border-color: rgba(251, 113, 133, 0.5); }
.award-icon { font-size: clamp(34px, 7cqh, 72px); line-height: 1; }
.award-title {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.1em; font-size: clamp(14px, 2.4cqh, 26px); color: var(--brand-bright);
}
.award-faces { --av: clamp(56px, 12cqh, 120px); margin-top: clamp(4px, 1cqh, 10px); justify-content: center; }
.award-team {
  font-family: var(--font-display); font-weight: 900; font-size: clamp(22px, 4.2cqh, 46px);
  line-height: 1.1; overflow-wrap: anywhere;
}
.award-detail { font-size: clamp(14px, 2.4cqh, 24px); font-weight: 700; color: var(--muted); }

/* ---------------------------------------------------------- wager mode --- */

/* Which slot of the night this is and what it costs, centred above the
   question. Gold, because the stake is the earned-value part of this style. */
.wager-round { justify-self: center; }
.wager-round-label {
  display: inline-block;
  padding: 1.2cqh 2.2cqw; border-radius: var(--r-pill);
  background: rgba(245, 179, 60, 0.1);
  border: 1px solid rgba(245, 179, 60, 0.42);
  font-size: 2.8cqh; font-weight: 800; color: var(--text);
}

/* The stakes, on one line above the clock. A team that hasn't staked yet is the
   only thing the host has to chase, so it's the only one that isn't dim -- and
   the row never wraps, so a busy room can't push the clock off the screen. */
.wager-team-row { display: flex; flex-wrap: nowrap; gap: 1cqw; overflow: hidden; }
.wager-team-row:empty { display: none; }
.wager-team-chip {
  white-space: nowrap;
  background: rgba(124, 58, 237, 0.14); border: 1px solid var(--line);
  padding: 0.8cqh 1.2cqw; border-radius: var(--r-pill);
  font-size: 2.4cqh; font-weight: 800; opacity: 0.72;
}
.wager-team-chip.staked { border-color: var(--line-strong); color: var(--brand-bright); }
.wager-team-chip.deciding {
  opacity: 1;
  background: rgba(245, 179, 60, 0.14); border-color: rgba(245, 179, 60, 0.5);
}

/* Halftime board: a grid of tiles replaces the answer grid entirely, and at the
   reveal each tile says whether it belonged or was a decoy. */
.list-panel {
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line); border-left: 6px solid var(--accent);
  border-radius: var(--r-md); padding: 20px 28px;
  flex: 1 1 auto; min-height: 0; overflow: hidden;
}
.list-instructions { font-size: 30px; margin: 0; color: var(--accent); font-weight: 800; }
.list-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 14px; margin: 18px 0 0;
}
.list-tile {
  background: var(--surface); border: 3px solid var(--line);
  border-radius: var(--r-sm); padding: 0.7em 0.9em;
  font-size: clamp(20px, 2.6cqh, 34px); font-weight: 800;
}
.list-tile.tile-belongs {
  border-color: var(--correct); background: rgba(34, 197, 94, 0.18);
  box-shadow: 0 0 30px rgba(34, 197, 94, 0.25);
}
.list-tile.tile-decoy {
  border-color: rgba(148, 163, 184, 0.3); color: var(--muted);
  text-decoration: line-through; filter: grayscale(1);
}

/* ------------------------------------------------------------- footer --- */

.tv-foot { display: flex; justify-content: space-between; align-items: center; font-size: 20px; font-weight: 600; }
.foot-join { color: var(--muted); }
.foot-join strong { color: var(--brand-bright); }

/* A style of play this machine has a logo for: the wordmark takes the icon's
   place and the name's, because it is the name. The blurb stays — the logo says
   which style, not how it scores. */
.select-mode.has-logo { align-items: center; }
.select-mode-logo {
  flex: 0 0 auto;
  max-height: clamp(26px, 4.6cqh, 52px);
  max-width: min(42%, 220px);
  width: auto;
}
.select-mode img.select-mode-logo { opacity: 0.8; }
.select-mode.is-selected img.select-mode-logo { opacity: 1; }
.chip-logo { max-height: clamp(34px, 6cqh, 78px); width: auto; }
.learn-logo { max-height: clamp(40px, 9cqh, 110px); width: auto; }

/* ------------------------------------------------------------ reactions --- */
/* The room's taps, on the big screen. A narrow lane up the right-hand edge so
   nothing ever crosses the question, and it holds no layout of its own. */
.tv-reactions {
  position: absolute; inset: 0 0 0 auto; width: 12cqw;
  pointer-events: none; overflow: hidden; z-index: 90;
}
.tv-reaction {
  position: absolute; bottom: 4cqh;
  font-size: clamp(28px, 3.4cqw, 64px); line-height: 1;
  filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.55));
  animation: tv-reaction-rise 3s var(--ease-out) forwards;
}
.tv-reaction.is-good-call { display: flex; flex-direction: column; align-items: center; gap: 0.2em; }
.tv-reaction.is-good-call small {
  font-family: var(--font-display); font-weight: 900; font-size: 0.34em;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--correct); white-space: nowrap;
}
@keyframes tv-reaction-rise {
  0% { opacity: 0; transform: translateY(0) scale(0.6); }
  14% { opacity: 1; transform: translateY(-6cqh) scale(1); }
  100% { opacity: 0; transform: translateY(-58cqh) scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .tv-reaction { animation-duration: 1.6s !important; }
}

/* The connection pill comes from the shared stylesheet fixed to the window; in
   the frame it belongs to the frame, or it floats in the black. */
#tv-stage .status-pill { position: absolute; }

/* ----------------------------------------------------------- room gate --- */

/* Which room this screen shows, asked once on a server that runs several. Sits
   over everything: a screen with no room has nothing else to draw. Wears the
   shared poster (shared/poster.css) at TV size, filling the stage. */
.tv-room-gate { position: absolute; inset: 0; z-index: 50; min-height: 0; }
