/* Chris's Questions -- shared styling for board, host, player and editor. */

/* Self-hosted, not linked from Google: the server this runs on is internal and
   may have no route out, and a webfont that silently fails to load would drop
   the board back to a system sans mid-meeting. Both faces are SIL Open Font
   License; the latin subset is all this app needs. */
@font-face {
  font-family: 'Anton';
  src: url('fonts/anton-latin.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Bebas Neue';
  src: url('fonts/bebasneue-latin.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}

:root {
  --bg-deep: #04122e;
  --bg-mid: #0b2a5e;
  --bg-panel: #0e1f42;
  --blue: #1657c0;
  --blue-light: #2f7ff0;
  --gold: #ffc528;
  --gold-deep: #e09b00;
  --red: #d92b2b;
  --green: #1faa5a;
  --text: #ffffff;
  --text-dim: #9db2d6;
  --border: rgba(255, 255, 255, 0.14);
  --slot-h: clamp(46px, 7.2vh, 78px);

  /* Anton for the big stuff you read from across a room, Bebas for the tighter
     caps of labels and scores. Controls stay on the system UI font -- a display
     face on a form field is unreadable at 15px. */
  --font-display: 'Anton', 'Arial Narrow', Impact, sans-serif;
  --font-caps: 'Bebas Neue', 'Anton', 'Arial Narrow', sans-serif;
  --font-ui: 'Segoe UI', system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: radial-gradient(ellipse at 50% 0%, var(--bg-mid) 0%, var(--bg-deep) 70%);
  color: var(--text);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}

/* The stage art is board-only. Phones get the flat gradient: it's a buzzer on a
   5-inch screen, and the beams would just eat contrast and battery. */
body.stage {
  background:
    url('img/stage.svg') center / cover no-repeat fixed,
    radial-gradient(ellipse at 50% 0%, var(--bg-mid) 0%, var(--bg-deep) 70%);
}

h1, h2, h3 { margin: 0; font-weight: 800; letter-spacing: 0.02em; }

/* ------------------------------------------------------------------ wordmark */

/* Deliberately its own design -- Anton in a gold-bevelled cap, not a copy of the
   television logo, which is trademarked and not ours to reproduce. */
.wordmark {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  line-height: 0.94;
  background: linear-gradient(180deg, #fff3c4 0%, #ffc528 46%, #e09b00 62%, #ffdd7a 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* Stacked shadows fake an extruded edge; the last one is the stage glow. */
  filter:
    drop-shadow(0 2px 0 rgba(90, 55, 0, 0.9))
    drop-shadow(0 5px 14px rgba(0, 0, 0, 0.6))
    drop-shadow(0 0 34px rgba(255, 197, 40, 0.35));
}

/* Corner brand mark on the board. Small on purpose -- the source art is 163px
   wide, so blowing it up would show. Top-left, because the scoreboard owns the
   whole bottom edge at every width and the sound button owns the top-right;
   anchored bottom-right it landed squarely on team 2's score. */
.brand-mark {
  position: fixed;
  left: clamp(12px, 2vw, 28px);
  top: clamp(10px, 1.6vh, 20px);
  width: clamp(92px, 9vw, 140px);
  opacity: 0.45;
  pointer-events: none;
  z-index: 2;
}

button {
  font-family: inherit;
  font-weight: 700;
  color: var(--text);
  background: var(--blue);
  border: 1px solid var(--blue-light);
  border-radius: 10px;
  padding: 12px 16px;
  font-size: 15px;
  cursor: pointer;
  transition: transform 0.08s ease, filter 0.12s ease;
}
button:hover:not(:disabled) { filter: brightness(1.15); }
button:active:not(:disabled) { transform: translateY(1px); }
button:disabled { opacity: 0.38; cursor: not-allowed; }
button.gold { background: linear-gradient(#ffd257, var(--gold-deep)); color: #2a1a00; border-color: var(--gold); }
button.red { background: #a81f1f; border-color: var(--red); }
button.green { background: #148a49; border-color: var(--green); }
button.ghost { background: transparent; border-color: var(--border); color: var(--text-dim); }

input, textarea, select {
  font-family: inherit;
  font-size: 15px;
  color: var(--text);
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  width: 100%;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--blue-light); }
select option { background: var(--bg-panel); }

.hidden { display: none !important; }

/* ---------------------------------------------------------------- scoreboard */

.scoreboard {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
}

.team {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(0, 0, 0, 0.25));
  border: 2px solid var(--border);
  border-radius: 14px;
  padding: 10px 16px;
  text-align: center;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.team.in-control {
  border-color: var(--gold);
  box-shadow: 0 0 24px rgba(255, 197, 40, 0.4);
}
.team .team-name {
  font-family: var(--font-caps);
  font-size: clamp(15px, 1.9vw, 24px);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.team.in-control .team-name { color: var(--gold); }
.team .team-score {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(34px, 5.4vw, 70px);
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 3px 10px rgba(0, 0, 0, 0.55);
}

/* -------------------------------------------------------------------- board */

.board-wrap {
  height: 100%;
  /* Dynamic viewport height, so mobile Safari's collapsing toolbars don't hide
     the scoreboard behind themselves. Ignored by browsers that predate it,
     which fall back to the 100% above. */
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: clamp(10px, 2vh, 24px) clamp(12px, 3vw, 40px);
  gap: clamp(8px, 1.6vh, 18px);
}

.question-bar {
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(20px, 3.1vw, 46px);
  line-height: 1.14;
  min-height: 1.2em;
  text-wrap: balance;
  text-transform: uppercase;
  text-shadow: 0 3px 12px rgba(0, 0, 0, 0.6);
}

.round-tag {
  text-align: center;
  color: var(--gold);
  font-family: var(--font-caps);
  font-size: clamp(14px, 1.6vw, 21px);
  letter-spacing: 0.26em;
  text-transform: uppercase;
}

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

/* Everything here sizes off min(vw, vh) rather than vw alone. The board is thrown
   on a TV about as often as it is shared into a Teams window two-thirds the height
   of a monitor, and on the second one width-only sizing kept the wordmark at its
   full 110px and pushed the scoreboard clean off the bottom edge. */
.lobby {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 1.9vh, 20px);
  text-align: center;
}
.lobby-title { font-size: clamp(34px, min(8.5vw, 12vh), 110px); }
.lobby-lead { font-size: clamp(14px, min(2vw, 2.7vh), 26px); color: var(--text-dim); }
.lobby-url {
  font-size: clamp(18px, min(3.6vw, 5vh), 48px);
  font-weight: 900;
  background: rgba(0, 0, 0, .35);
  border: 2px solid var(--gold);
  border-radius: 14px;
  padding: clamp(6px, 1.3vh, 14px) clamp(14px, 2vw, 28px);
}
.lobby-code {
  font-size: clamp(28px, min(6vw, 8.4vh), 84px);
  font-weight: 900;
  letter-spacing: 0.14em;
  color: var(--gold);
}
/* Two classes so it beats .hint's flat 13px, which the players line carries. */
.lobby .lobby-small { font-size: clamp(12px, min(1.6vw, 2.2vh), 20px); }
.lobby .lobby-dim { color: var(--text-dim); }

/* The crib sheet in the lobby. It is read off somebody else's shared screen, in a
   Teams window that may be a third of a monitor, so the steps wrap to two lines
   rather than shrinking -- below about 15px on a share nobody bothers squinting. */
.lobby-how {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  max-width: 780px;
}
.lobby-how .steps-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 20px;
}
.lobby-how .steps-row span {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: clamp(14px, min(1.7vw, 2.4vh), 22px);
  font-weight: 700;
}
.lobby-how .steps-row b {
  flex: 0 0 auto;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  background: var(--gold);
  color: #2a1c00;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.82em;
}
.lobby-how .more {
  font-size: clamp(12px, min(1.4vw, 2vh), 19px);
  color: var(--text-dim);
  text-align: center;
  line-height: 1.5;
}
.lobby-how .more b { color: var(--gold); font-weight: 900; }

.pot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-weight: 900;
}
.pot .pot-value {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(30px, 4.6vw, 62px);
  color: var(--gold);
  font-variant-numeric: tabular-nums;
  min-width: 2ch;
  text-align: center;
  text-shadow: 0 0 26px rgba(255, 197, 40, 0.4);
}
.pot .pot-label {
  font-family: var(--font-caps);
  font-size: clamp(13px, 1.4vw, 18px);
  color: var(--text-dim);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* The answer grid: two columns like the show, one column when narrow. */
.slots {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: minmax(var(--slot-h), 1fr);
  gap: clamp(6px, 1.1vh, 14px) clamp(10px, 1.6vw, 22px);
  align-content: center;
  max-width: 1500px;
  width: 100%;
  margin: 0 auto;
}
.slots.single-column { grid-template-columns: 1fr; }

.slot {
  position: relative;
  border-radius: 12px;
  /* Texture tile over a top-lit gradient. The tile is listed first so it sits
     above the fill; both are on the same element to keep the flip animation on
     a single compositor layer. */
  background:
    url('img/slot-texture.svg') repeat,
    linear-gradient(180deg, #1a4fa8 0%, #123f8f 38%, #071c46 100%);
  border: 2px solid rgba(255, 255, 255, 0.16);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.26),
    inset 0 -3px 6px rgba(0, 0, 0, 0.45),
    0 4px 12px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  overflow: hidden;
  transform-style: preserve-3d;
}
.slot.flip { animation: flip 0.45s ease; }
@keyframes flip {
  0% { transform: rotateX(0deg); }
  50% { transform: rotateX(90deg); background: var(--gold); }
  100% { transform: rotateX(0deg); }
}

.slot .slot-number {
  width: clamp(38px, 4vw, 66px);
  flex: none;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(22px, 2.8vw, 42px);
  color: rgba(255, 255, 255, 0.4);
}
.slot.revealed .slot-number { display: none; }

.slot .slot-text {
  flex: 1;
  padding: 0 clamp(8px, 1vw, 18px);
  font-family: var(--font-caps);
  font-size: clamp(17px, 2.4vw, 36px);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.slot .slot-points {
  flex: none;
  align-self: stretch;
  display: flex;
  align-items: center;
  padding: 0 clamp(10px, 1.4vw, 22px);
  background: linear-gradient(180deg, #2470e8 0%, #1a63d4 40%, #0a2f78 100%);
  border-left: 2px solid rgba(255, 255, 255, 0.2);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.22);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(20px, 2.6vw, 40px);
  font-variant-numeric: tabular-nums;
}
.slot:not(.revealed) .slot-text,
.slot:not(.revealed) .slot-points { display: none; }

/* Strike overlay -- big red X's, like the show. */
.strike-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4vw;
  pointer-events: none;
  z-index: 50;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.strike-overlay.show { opacity: 1; }
.strike-overlay .x {
  font-family: var(--font-display);
  /* Capped by width as well as height: three of these at 34vh each run off the
     side of a phone held upright. */
  font-size: min(34vh, 24vw);
  line-height: 1;
  font-weight: 400;
  color: var(--red);
  text-shadow: 0 0 40px rgba(217, 43, 43, 0.85);
  animation: pop 0.28s ease;
}
@keyframes pop {
  from { transform: scale(0.3); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.strike-pips { display: flex; gap: 8px; justify-content: center; min-height: 26px; }
.strike-pips .pip {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  border: 2px solid rgba(255, 255, 255, 0.22);
  display: grid;
  place-items: center;
  font-weight: 900;
  color: transparent;
}
.strike-pips .pip.on { color: var(--red); border-color: var(--red); background: rgba(217, 43, 43, 0.15); }

/* ------------------------------------------------------------------ buzzers */

.buzz-list { display: flex; flex-direction: column; gap: 6px; }
.buzz-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  font-weight: 700;
}
.buzz-row.first { border-color: var(--gold); background: rgba(255, 197, 40, 0.14); }
.buzz-row .rank { color: var(--gold); font-weight: 900; min-width: 1.4em; }
.buzz-row .delta { margin-left: auto; color: var(--text-dim); font-variant-numeric: tabular-nums; font-size: 13px; }

.banner {
  text-align: center;
  font-family: var(--font-caps);
  font-size: clamp(17px, 2.2vw, 32px);
  letter-spacing: 0.04em;
  color: var(--gold);
  min-height: 1.3em;
}

/* -------------------------------------------------------------- host panel */

.host-wrap {
  max-width: 900px;
  margin: 0 auto;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
}
.panel h2 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text-dim);
  margin-bottom: 10px;
}

/* Collapsible panels. Every one of these keeps its status pills in the header,
   so a collapsed panel still reports the phase, the pot and the strikes. */
.panel > summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  list-style: none;               /* the default triangle, replaced below */
}
.panel > summary::-webkit-details-marker { display: none; }
.panel > summary::after {
  content: '▾';
  margin-left: auto;
  color: var(--text-dim);
  font-size: 13px;
  transition: transform 0.15s ease;
}
.panel:not([open]) > summary::after { transform: rotate(-90deg); }
/* The h2 keeps its own bottom margin: that's the gap under an open header, and
   collapsed it reads as a few px of padding rather than as a missing rule. */

.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row > * { flex: 1 1 auto; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

/* Host answer buttons: tap to reveal. Masked when peek mode is off. */
.host-answers { display: flex; flex-direction: column; gap: 8px; }
.host-answer {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  width: 100%;
  padding: 14px 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
  font-size: 16px;
}
.host-answer .num { color: var(--gold); font-weight: 900; min-width: 1.3em; }
.host-answer .txt { flex: 1; }
.host-answer .pts { font-weight: 900; font-variant-numeric: tabular-nums; }
.host-answer.done { background: rgba(31, 170, 90, 0.22); border-color: var(--green); }
.masked .host-answer .txt {
  filter: blur(7px);
  user-select: none;
}
.masked .host-answer.done .txt { filter: none; }

.pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: rgba(255, 255, 255, 0.12);
  color: var(--text-dim);
}
.pill.live { background: rgba(31, 170, 90, 0.25); color: #7ee2a8; }
.pill.off { background: rgba(217, 43, 43, 0.22); color: #ff9d9d; }

.hint { color: var(--text-dim); font-size: 13px; line-height: 1.5; }

/* Bottom-of-screen toast on the host panel. Sits above the thumb on a phone but
   clear of the keyboard, and never intercepts a tap. */
.host-toast {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 14px);
  max-width: min(90vw, 460px);
  padding: 11px 18px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 700;
  text-align: center;
  background: #6b4a05;
  border: 1px solid var(--gold);
  color: #ffeab5;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.55);
  opacity: 0;
  pointer-events: none;
  z-index: 80;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.host-toast.show { opacity: 1; transform: translate(-50%, 0); }
.host-toast.good { background: #0e5c33; border-color: var(--green); color: #c6f5da; }

/* ----------------------------------------------------------------- player */

.play-wrap {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  padding: 14px;
  gap: 12px;
  max-width: 520px;
  margin: 0 auto;
}

.buzzer {
  /* Keep it an actual circle: no flex-grow, and the height follows the width.
     The vh term keeps it round on short screens instead of clipping it. */
  flex: 0 0 auto;
  align-self: center;
  border-radius: 50%;
  aspect-ratio: 1;
  margin: auto 0;
  width: min(78vw, 52vh, 340px);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(32px, 9.5vw, 58px);
  letter-spacing: 0.06em;
  background: radial-gradient(circle at 38% 32%, #ff6a6a, #a30f0f 70%);
  border: 6px solid rgba(255, 255, 255, 0.28);
  box-shadow: 0 14px 0 #5c0808, 0 20px 40px rgba(0, 0, 0, 0.55);
  color: #fff;
  text-shadow: 0 3px 8px rgba(0, 0, 0, 0.5);
  touch-action: manipulation;
  user-select: none;
}
.buzzer:active:not(:disabled) { transform: translateY(8px); box-shadow: 0 6px 0 #5c0808; }
.buzzer:disabled {
  background: radial-gradient(circle at 38% 32%, #56607a, #2a3145 70%);
  box-shadow: 0 14px 0 #171c29;
  opacity: 1;
}
.buzzer.armed { animation: pulse 1.4s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 14px 0 #5c0808, 0 20px 40px rgba(0, 0, 0, 0.55); }
  50% { box-shadow: 0 14px 0 #5c0808, 0 0 60px rgba(255, 90, 90, 0.75); }
}

.status-line { text-align: center; font-weight: 800; font-size: 17px; min-height: 1.4em; }
.status-line.good { color: #7ee2a8; }
.status-line.warn { color: var(--gold); }

/* -------------------------------------------------------------- fast money */

.fm-grid { display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 1100px; margin: 0 auto; }
.fm-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: stretch;
}
.fm-q {
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: clamp(12px, 1.5vw, 19px);
  display: flex;
  align-items: center;
}
.fm-a {
  background: linear-gradient(180deg, #123f8f, #071c46);
  border: 2px solid rgba(255, 255, 255, 0.16);
  border-radius: 8px;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-caps);
  font-size: clamp(14px, 1.8vw, 23px);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.fm-a .fm-answer-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fm-a .fm-answer-points { color: var(--gold); font-variant-numeric: tabular-nums; min-width: 2.5ch; text-align: right; }
.fm-a.dup { border-color: var(--red); }
.fm-a.pending .fm-answer-text::after { content: '— — —'; color: var(--text-dim); }

.fm-total {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 14px;
  font-weight: 900;
}
.fm-total .value {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(34px, 6.2vw, 76px);
  color: var(--gold);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 26px rgba(255, 197, 40, 0.4);
}
.fm-total .target {
  color: var(--text-dim);
  font-family: var(--font-caps);
  font-size: clamp(15px, 1.8vw, 22px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.fm-timer {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(36px, 7.2vw, 86px);
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.fm-timer.low { color: var(--red); animation: pulse-text 0.6s ease-in-out infinite; }
@keyframes pulse-text { 50% { opacity: 0.45; } }

/* --------------------------------------------------------------- editor */

.editor-wrap { max-width: 960px; margin: 0 auto; padding: 16px; display: flex; flex-direction: column; gap: 14px; }
.q-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; padding: 12px; }
.q-card .answers { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.answer-row { display: grid; grid-template-columns: 1fr 90px auto; gap: 6px; }
.toolbar { display: flex; gap: 8px; flex-wrap: wrap; position: sticky; top: 0; z-index: 5;
  background: var(--bg-deep); padding: 10px 0; border-bottom: 1px solid var(--border); }

.topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.28);
}
.topbar h1 { font-size: 17px; }
.topbar .spacer { flex: 1; }
.topbar a { color: var(--text-dim); text-decoration: none; font-size: 13px; font-weight: 700; }
.topbar a:hover { color: var(--gold); }

/* Links inherit the page's text colour. The browser default is a mid blue that
   turns purple once visited -- both are close to unreadable on a navy panel. */
a { color: inherit; }

/* The landing page: each card is one big link, so the card does the affording
   and the text stays plain white. Gold is reserved for the call to action. */
.card-link { display: block; text-decoration: none; color: inherit; }
.card-link .panel { transition: border-color 0.15s, background 0.15s; }
.card-link:hover .panel,
.card-link:focus-visible .panel {
  border-color: var(--gold);
  background: rgba(255, 197, 40, 0.06);
}
.card-link:focus-visible { outline: none; }
.card-link .go {
  color: var(--gold);
  font-weight: 800;
  font-size: 18px;
  margin: 0;
}

@media (max-width: 720px) {
  .slots { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
  .answer-row { grid-template-columns: 1fr 70px auto; }

  /* background-attachment:fixed repaints the whole stage on every scroll frame
     in mobile Safari, and the beams cost contrast on a 6-inch screen anyway. */
  body.stage { background: radial-gradient(ellipse at 50% 0%, var(--bg-mid) 0%, var(--bg-deep) 70%); }
}

/* --------------------------------------------------------------- bracket */

/* The tournament board. Shown between matches, so it is read from the same
   distance as the game board: big names, big scores, nothing to click. */

body.bracket-page {
  height: auto;
  min-height: 100%;
  padding: 18px 20px 40px;
  background:
    url('img/stage.svg') center / cover no-repeat fixed,
    radial-gradient(ellipse at 50% 0%, var(--bg-mid) 0%, var(--bg-deep) 70%);
}

.bracket-head { text-align: center; margin-bottom: 18px; }

/* Carries .wordmark in the markup, so the paint -- the gold bevel, the extrude,
   the stage glow -- comes from there and this rule only sets the measure. Don't
   put `color` or `text-shadow` back: the glyphs are a clipped gradient, so a
   colour would hide it and a text-shadow would print behind transparent text. */
.bracket-head h1 {
  font-size: clamp(28px, 4.4vw, 58px);
  margin: 0 auto;
  max-width: 22ch;
  text-wrap: balance;
}

/* A tournament name gets a whole line to itself and can run to 128 characters,
   which at full size would be four stacked lines of billboard. Step it down by
   length instead -- set on the element by bracket.js, which is the only place
   that knows how long the title actually is. */
.bracket-head h1[data-len="long"] { font-size: clamp(22px, 3.2vw, 42px); max-width: 30ch; }
.bracket-head h1[data-len="epic"] { font-size: clamp(18px, 2.4vw, 32px); max-width: 40ch; }

.bracket-sub {
  font-family: var(--font-caps);
  font-size: clamp(13px, 1.4vw, 20px);
  letter-spacing: 0.09em;
  color: var(--text-dim);
  margin: 4px 0 0;
}

.bracket-empty {
  text-align: center;
  color: var(--text-dim);
  font-size: 18px;
  padding: 60px 20px;
}

/* A wide bracket scrolls sideways rather than squeezing the cards. Sixteen teams
   is four columns, which fits a shared screen; the overflow is there so that a
   laptop in a small window still shows readable cards instead of slivers. */
.bracket-wrap { overflow-x: auto; padding-bottom: 8px; }

.bracket {
  display: flex;
  gap: clamp(18px, 3vw, 54px);
  min-width: min-content;
  margin: 0 auto;
  width: fit-content;
}

.bk-round { display: flex; flex-direction: column; flex: 0 0 auto; }

.bk-round-name {
  font-family: var(--font-caps);
  font-size: clamp(14px, 1.5vw, 22px);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  text-align: center;
  margin: 0 0 10px;
}

/* The date takes over the gap the heading was leaving, so a column that has one
   and a column that doesn't still start their cards at the same height. That is
   the only reason the two are siblings and this uses :has -- where :has isn't
   supported the date just sits a few pixels lower, which is cosmetic rather than
   a broken column. */
.bk-round-name:has(+ .bk-round-date) { margin-bottom: 2px; }

/* Deliberately quieter than the round name: on a shared screen the question is
   "which round is this", and the date is the answer to the follow-up. Gold would
   put it in competition with the winners. */
.bk-round-date {
  font-family: var(--font-ui);
  font-size: clamp(10px, 0.95vw, 13px);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  opacity: 0.72;
  text-align: center;
  margin: 0 0 10px;
  white-space: nowrap;
}

/* Each round is half as many cards as the one before it, spread over the same
   height -- so justify-content:space-around lines every card up in the gap
   between the two it feeds from, with no arithmetic and no absolute positioning.
   This is the whole layout trick; the connector lines just follow it. */
.bk-round-body {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  flex: 1;
  gap: 10px;
}

.bk-match {
  position: relative;
  width: clamp(180px, 15vw, 260px);
  background: linear-gradient(180deg, rgba(22, 87, 192, 0.5), rgba(14, 31, 66, 0.85));
  border: 2px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}

/* The match about to be played is the one the room is looking for. */
.bk-match.bk-ready {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(255, 197, 40, 0.25), 0 4px 18px rgba(0, 0, 0, 0.45);
}

.bk-match.bk-pending { opacity: 0.62; }
.bk-match.bk-bye { opacity: 0.78; }

.bk-side {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  min-height: 40px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.bk-side:last-child { border-bottom: 0; }

.bk-seed {
  flex: 0 0 22px;
  font-family: var(--font-caps);
  font-size: 14px;
  color: var(--text-dim);
  text-align: center;
}

.bk-name {
  flex: 1;
  font-family: var(--font-caps);
  font-size: clamp(15px, 1.5vw, 22px);
  letter-spacing: 0.04em;
  line-height: 1.1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bk-score {
  font-family: var(--font-display);
  font-size: clamp(16px, 1.7vw, 26px);
  color: var(--gold);
  min-width: 2ch;
  text-align: right;
}

/* Winner in gold, loser dimmed: the bracket has to be readable in one look from
   the back of the room, and colour does that faster than a tick would. */
.bk-side.won { background: rgba(255, 197, 40, 0.14); }
.bk-side.won .bk-name { color: var(--gold); }
.bk-side.lost { opacity: 0.45; }
.bk-side.lost .bk-score { color: var(--text-dim); }
.bk-side.empty .bk-name {
  font-family: var(--font-ui);
  font-size: 12px;
  letter-spacing: 0;
  color: var(--text-dim);
  font-style: italic;
}

.bk-tag {
  font-family: var(--font-caps);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  padding: 3px;
  background: var(--gold);
  color: #23180a;
}

/* Elbows: a stub out of every card, and a stub back into every card that has a
   round before it. Drawn with borders on pseudo-elements so there is no SVG to
   keep in step with the flex layout above. */
.bk-round:not(:last-child) .bk-match::after,
.bk-round:not(:first-child) .bk-match::before {
  content: '';
  position: absolute;
  top: 50%;
  width: clamp(9px, 1.5vw, 27px);
  border-top: 2px solid var(--border);
}
.bk-round:not(:last-child) .bk-match::after { left: 100%; }
.bk-round:not(:first-child) .bk-match::before { right: 100%; }

.bracket-champ {
  margin: 26px auto 0;
  max-width: 520px;
  text-align: center;
  padding: 14px 20px;
  border: 2px solid var(--gold);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 197, 40, 0.18), rgba(14, 31, 66, 0.8));
}

.champ-label {
  display: block;
  font-family: var(--font-caps);
  font-size: 15px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.champ-name {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(30px, 4vw, 56px);
  color: var(--gold);
  text-shadow: 0 3px 0 var(--gold-deep);
  margin-top: 4px;
}

@media (max-width: 720px) {
  body.bracket-page {
    padding: 12px 10px 30px;
    background: radial-gradient(ellipse at 50% 0%, var(--bg-mid) 0%, var(--bg-deep) 70%);
  }
  .bracket { gap: 14px; }
  .bk-match { width: 168px; }
  /* Connectors are noise once the columns are this tight together. */
  .bk-match::before, .bk-match::after { display: none; }
}

/* ------------------------------------------------------- board on a phone */

/* The board is built to be screen-shared on a laptop, but people do open it on
   their phone to follow along. On a phone the question, pot, eight slots, pips
   and scoreboard are taller than the screen -- and because .board-wrap is a
   fixed-height flex column that doesn't scroll, the excess used to paint
   straight over the scoreboard. So here the page scrolls and the scoreboard
   sticks to the bottom instead.

   Keyed on height as well as width: a phone turned sideways is 844x390, which
   is wide enough to miss a width-only rule and short enough to overflow just
   as badly. */
@media (max-width: 720px), (max-height: 560px) {
  :root {
    /* Slots have to give up the most height: they're the only thing there can
       be eight of. */
    --slot-h: clamp(38px, 5.6vh, 54px);
  }

  .board-wrap {
    height: auto;
    min-height: 100dvh;
    /* Reserved strip so the round tag clears the fixed sound button and the
       brand mark, which are both corner-anchored. */
    padding-top: 42px;
  }

  /* Rows may grow past the minimum -- with min-height on the wrap instead of a
     fixed height, that pushes the page taller and it scrolls, rather than
     spilling out over the scoreboard. The grid still takes the spare space so
     the answers stay centred when the round does fit. */
  .slots { grid-auto-rows: minmax(var(--slot-h), auto); }

  /* Scoped to the board. The player page has a scoreboard too, but it sits at
     the *top* of a short column -- sticking that to the bottom pins it over the
     strike pips, and the negative margins below are sized to cancel the board
     wrap's padding, not the player wrap's. Unscoped, this rule was landing the
     score on top of the pips on every phone. */
  .board-wrap .scoreboard {
    position: sticky;
    bottom: 0;
    z-index: 3;
    gap: 8px;
    /* Opaque, because the slots now scroll underneath it. */
    background: linear-gradient(180deg, rgba(4, 18, 46, 0.82), var(--bg-deep) 45%);
    /* auto top margin so it still sits at the bottom when the round is short
       enough to fit; sticky takes over once it isn't. */
    margin-top: auto;
    margin-inline: calc(-1 * clamp(12px, 3vw, 40px));
    margin-bottom: calc(-1 * clamp(10px, 2vh, 24px));
    padding: 8px clamp(12px, 3vw, 40px) calc(8px + env(safe-area-inset-bottom));
  }
  /* The player column is scoreboard, pips, question, buzzer -- top to bottom,
     in that order, with nothing overlapping anything. */
  .play-wrap .scoreboard { gap: 8px; }
  .team { padding: 6px 10px; }
  .team .team-score { font-size: clamp(28px, 9vw, 44px); }

  .strike-pips .pip { width: 22px; height: 22px; }

  .brand-mark { width: 88px; opacity: 0.4; }
  /* The label grows to "🔇 Enable sound" and shrinks to "🔊 Sound on", so cap it
     rather than let it push the Bracket link off the row. */
  #soundBtn {
    max-width: 46vw;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* A phone held sideways is only ~390px tall once the browser chrome is out.
   Everything has to give a little or the strike pips end up underneath the
   sticky scoreboard, which is the one thing on this row that has to be
   readable at a glance. */
@media (max-height: 560px) {
  :root { --slot-h: clamp(30px, 8.5vh, 44px); }

  .board-wrap { gap: 6px; padding-top: 32px; padding-bottom: 6px; }
  /* On a letterboxed share the code is the one thing that must not be pushed off,
     so the lobby's three steps go and the line naming the guide stays. */
  .lobby-how .steps-row { display: none; }
  .question-bar { font-size: clamp(16px, 2.5vw, 28px); }
  .pot { gap: 8px; }
  .pot .pot-value { font-size: clamp(22px, 3.2vw, 36px); }
  .strike-pips { min-height: 20px; }
  .strike-pips .pip { width: 20px; height: 20px; font-size: 12px; }
  .team { padding: 4px 10px; }
  .team .team-score { font-size: clamp(24px, 6.5vh, 40px); }
  .banner { font-size: clamp(15px, 2vw, 22px); }
}

/* ------------------------------------------------------------------ site nav
   The two shared screens, top right of every page. Built by nav.js, which
   decides which links to draw; this is only how they look.

   Fixed rather than in the flow because every page here has its own layout --
   the board is a full-bleed stage, the host panel is a scrolling column -- and
   there is no shared header to hang them off.

   It is a row, not a single link, because the corner is shared: the board keeps
   its sound toggle in here too. Anything a page puts in the group lines up
   beside the links instead of underneath them. */
.site-nav {
  position: fixed;
  top: 10px;
  right: 12px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 8px;
}
.site-nav a, .site-nav button {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  color: var(--text-dim);
  background: rgba(0, 0, 0, .45);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 12px;
  backdrop-filter: blur(4px);
  white-space: nowrap;
}
.site-nav button { cursor: pointer; line-height: inherit; }
.site-nav a:hover, .site-nav a:focus-visible,
.site-nav button:hover, .site-nav button:focus-visible { color: var(--gold); border-color: var(--gold); }

/* On the board it is furniture on a projector, so it recedes until somebody goes
   looking for it. Not further than this, though: the sound toggle lives in this
   group, and it is the first thing anyone has to find when the board comes up. */
.stage .site-nav { opacity: .7; transition: opacity .2s ease; }
.stage .site-nav:hover, .stage .site-nav:focus-within { opacity: 1; }

/* Phones: the host panel's own header is up there too, so shrink rather than
   overlap. Still tappable -- 5px padding on 13px text clears 30px of target.
   Wrapping matters on the board, where the row is a link plus the sound button
   and "🔇 Enable sound" is a wide thing to ask of a 375px screen. */
@media (max-width: 560px) {
  .site-nav {
    top: 6px;
    right: 6px;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
    max-width: calc(100vw - 12px);
  }
  .site-nav a, .site-nav button { font-size: 12px; padding: 4px 9px; }
}

/* --------------------------------------------------------------------- kbd
   host.html has always had <kbd>B</kbd> in its button labels and got the
   browser default, which is a serif monospace on a navy panel. */
kbd {
  font-family: var(--font-ui);
  font-size: 0.85em;
  font-weight: 800;
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  background: rgba(255, 255, 255, .1);
  color: var(--text);
  white-space: nowrap;
}

/* ------------------------------------------------------------------- guide
   /how-to-play and /how-to-host. Written to be read on a phone in a meeting
   that has already started, so: numbered steps, short lines, and the thing you
   do in bold at the front of each one.

   It borrows .panel and .hint from the rest of the app rather than inventing a
   second look -- the point is that the instructions and the thing they describe
   are visibly the same product. */
.guide { max-width: 780px; }
.guide h2 { font-size: 13px; }
.guide p { line-height: 1.55; margin: 0 0 10px; }
.guide p:last-child { margin-bottom: 0; }
.guide b, .guide strong { color: var(--text); }

/* Numbered steps. The numeral is a gold disc rather than a list marker so it
   holds its place when a step runs to three lines. */
.guide .steps {
  list-style: none;
  counter-reset: step;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.guide .steps > li {
  counter-increment: step;
  position: relative;
  padding-left: 40px;
  line-height: 1.55;
}
.guide .steps > li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: -1px;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: var(--gold);
  color: #2a1c00;
  font-weight: 900;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.guide .steps .hint { display: block; margin-top: 4px; }

/* An aside that matters: gold for "get this wrong and the meeting suffers",
   green for reassurance. */
.guide .callout {
  border-left: 3px solid var(--gold);
  background: rgba(255, 197, 40, .08);
  border-radius: 0 8px 8px 0;
  padding: 10px 12px;
  font-size: 14px;
  line-height: 1.5;
}
.guide .callout.good { border-left-color: var(--green); background: rgba(31, 170, 90, .1); }

/* Two-column reference: shortcuts, and symptom/fix. */
.guide table { width: 100%; border-collapse: collapse; font-size: 14px; }
.guide table th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-dim);
  padding: 0 10px 6px 0;
}
.guide table td { padding: 7px 10px 7px 0; border-top: 1px solid var(--border); vertical-align: top; }
.guide table td:first-child { white-space: nowrap; font-weight: 700; }
.guide table.wrap-first td:first-child { white-space: normal; }

/* The screen-name chips in the "which screen am I on" table. */
.guide .where { display: inline-block; font-weight: 800; color: var(--gold); }

/* Links inside body copy have to look like links. The global `a { color: inherit }`
   is right for the topbar and the card panels, where the whole block is the link,
   and wrong in a sentence -- there it just makes them disappear. */
.guide a, .hint a { color: var(--gold); }

/* Printing: this is a run sheet, and somebody will want it on the desk next to
   the laptop. The page is white-on-navy, so nearly all of it has to be undone. */
@media print {
  body.guide-page {
    background: #fff !important;
    color: #000;
  }
  body.guide-page .topbar { background: none; }
  body.guide-page .panel {
    background: #fff;
    border: 1px solid #bbb;
    break-inside: avoid;
  }
  body.guide-page .hint, body.guide-page .panel h2, body.guide-page .guide table th { color: #555; }
  body.guide-page .wordmark {
    background: none;
    -webkit-text-fill-color: #000;
    color: #000;
  }
  body.guide-page .callout { background: #f4f4f4; border-left-color: #666; }
  body.guide-page .guide .steps > li::before { background: #ddd; color: #000; }
  body.guide-page kbd { background: #eee; color: #000; border-color: #999; }
  body.guide-page .site-nav, body.guide-page .topbar a, body.guide-page .no-print { display: none !important; }
}
