/* Bingo — one phone, one hand, one screen. Dark hall, warm lights.
   Layout law: the play screen never scrolls. The card is the hero, the called
   panel is the index beneath it, and all 75 tokens are on screen at once. */

:root {
  --bg: #0b1017;
  --bg2: #0e151e;
  --panel: #111a24;
  --cell: #16202b;
  --line: #24313f;
  --ink: #e9f0f8;
  --dim: #8ea0b4;
  --dimmer: #5d6d80;
  --gold: #ffbb2b;
  --gold-ink: #1a1405;
  --good: #4ade80;
  --bad: #f87171;
  --b: #4aa3ff;
  --i: #4ade80;
  --n: #f9a8d4;
  --g: #fbbf24;
  --o: #a78bfa;
  --radius: 12px;
}

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

/* A class with `display` beats the UA stylesheet's [hidden] rule; make `hidden`
   mean hidden, everywhere, so a banner or a host control never leaks through. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: radial-gradient(120% 80% at 50% 0%, #14202c 0%, var(--bg) 60%);
  color: var(--ink);
  font-family: ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, -apple-system, sans-serif;
  overscroll-behavior: none;
}

#app {
  position: relative;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}

/* ------------------------------------------------------------------ topbar */
#topbar {
  flex: 0 0 auto;
  height: 34px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--dim);
}
/* One span per letter, each carrying the colour of its card column — the same
   `--c` convention as .card-head span, so the two can never drift apart. */
#brand { font-weight: 800; letter-spacing: 0.3em; }
#brand span { color: var(--c); }
.roomtag {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2em;
  color: var(--ink);
  background: #17222e;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 10px;
}
.conn { margin-left: auto; }
.roomtag + .conn { margin-left: 0; }
.conn::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  margin-right: 5px;
  background: var(--dimmer);
  vertical-align: middle;
}
.conn.live::before { background: var(--good); }
.conn.down::before { background: var(--bad); }

/* ----------------------------------------------------------------- screens */
.screen { display: none; flex: 1 1 auto; min-height: 0; padding: 4px 12px 10px; }
.screen.active { display: flex; flex-direction: column; }
/* The layout law is that the play screen fits without scrolling; this is the
   safety valve for the one phone that does not, so nothing is ever clipped.
   On a screen that fits, it is inert. */
#screenPlay, #screenVote, #screenLobby { overflow-y: auto; }

h1 { font-size: 26px; line-height: 1.1; margin: 6px 0 6px; letter-spacing: -0.02em; }
h2 { font-size: 24px; margin: 4px 0 6px; letter-spacing: -0.01em; }
.lede { color: var(--dim); font-size: 13px; line-height: 1.4; margin: 0 0 14px; }
.hint { color: var(--dim); font-size: 12px; line-height: 1.45; }
.hint.tiny { font-size: 11px; }
.error { color: var(--bad); font-size: 12px; margin: 8px 0 0; }

/* -------------------------------------------------------------------- join */
.join-wrap { overflow-y: auto; padding-bottom: 16px; }
.field { display: block; margin: 0 0 12px; }
.field > span { display: block; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim); margin-bottom: 5px; }
.field input {
  width: 100%;
  font: inherit;
  font-size: 17px;
  padding: 12px 14px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  outline: none;
}
.field input:focus { border-color: var(--gold); }
#joinCode { letter-spacing: 0.28em; text-transform: uppercase; font-weight: 700; }
.field.inline { display: flex; align-items: center; gap: 10px; }
.field.inline > span { margin: 0; flex: 1; }
.field.inline input { width: auto; }

button { font: inherit; cursor: pointer; border-radius: var(--radius); border: 1px solid var(--line); background: #17222e; color: var(--ink); padding: 10px 14px; }
button:active { transform: translateY(1px); }
button.big { width: 100%; padding: 14px; font-size: 16px; font-weight: 700; margin-top: 4px; }
button.primary { background: var(--gold); color: var(--gold-ink); border-color: #d99a17; box-shadow: 0 6px 18px rgb(255 187 43 / 0.18); }
button.ghost { background: transparent; }
button.small { padding: 6px 10px; font-size: 12px; border-radius: 9px; }
button[disabled] { opacity: 0.45; }

.or { display: flex; align-items: center; gap: 10px; color: var(--dimmer); font-size: 11px; margin: 18px 0; }
.or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.create summary { font-size: 13px; color: var(--dim); padding: 6px 0; }
.advanced { border: 1px dashed var(--line); border-radius: var(--radius); padding: 10px 12px; margin: 8px 0 12px; }
.advanced-head { font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; margin-bottom: 8px; }
.advanced-head span { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--dimmer); }
.setrow { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center; padding: 7px 0; border-top: 1px solid #1b2632; }
.setrow:first-child { border-top: 0; }
.setrow label { font-size: 13px; }
.setrow .unit { font-size: 11px; color: var(--dimmer); }
.setrow input[type="range"] { grid-column: 1 / -1; width: 100%; accent-color: var(--gold); }
.setrow select {
  grid-column: 1 / -1;
  width: 100%;
  font: inherit;
  font-size: 14px;
  padding: 8px 10px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  outline: none;
}
.setrow select:focus { border-color: var(--gold); }
.setrow output { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--gold); font-size: 14px; }
.setrow .sethelp { grid-column: 1 / -1; font-size: 10.5px; color: var(--dimmer); line-height: 1.35; }

/* ------------------------------------------------------------------- lobby */
.code-card {
  display: flex; align-items: center; gap: 10px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 10px;
}
.code-label { font-size: 10px; letter-spacing: 0.18em; color: var(--dim); }
#lobbyCode { font-size: 26px; letter-spacing: 0.24em; font-variant-numeric: tabular-nums; margin-left: auto; }
.seats { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.seats li { display: flex; align-items: center; gap: 8px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 9px 12px; font-size: 14px; }
.seats li.you { border-color: #3a4d61; }
.seats .tag { font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; padding: 2px 6px; border-radius: 999px; background: #1d2a37; color: var(--dim); }
.seats .tag.host { background: #3a2f0a; color: var(--gold); }
.seats .tag.bot { background: #1b2330; color: #7f93a8; }
.seats .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dimmer); margin-left: auto; }
.seats .dot.on { background: var(--good); }
.host-controls { margin-top: 0; display: flex; flex-direction: column; gap: 8px; }
.lobby-foot { margin-top: auto; display: flex; flex-direction: column; gap: 8px; }
.bots-row { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--dim); }
.bots-row b { min-width: 18px; text-align: center; color: var(--ink); }

/* -------------------------------------------------------------------- vote */
.vote-head, .play-head {
  display: flex; align-items: baseline; justify-content: space-between;
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim);
  padding: 2px 0 6px;
}
.clock { font-variant-numeric: tabular-nums; color: var(--gold); font-weight: 700; letter-spacing: 0.04em; }
.pattern-grid {
  flex: 1 1 auto; min-height: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr);
  gap: 8px;
}
.tile {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 6px 4px 8px; min-height: 0;
}
.tile.voted { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold) inset; }
.tile .mini { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px; width: min(46px, 38%); aspect-ratio: 1; }
.tile .mini i { background: #1b2632; border-radius: 1.5px; }
.tile .mini i.on { background: #4b6079; }
.tile .tname { font-size: 10.5px; line-height: 1.15; text-align: center; color: var(--ink); font-weight: 600; }
.tile .pill {
  position: absolute; top: 4px; right: 4px;
  font-size: 9px; font-weight: 800; letter-spacing: 0.02em;
  background: var(--gold); color: var(--gold-ink);
  border-radius: 999px; padding: 2px 5px;
}
.tile .tally {
  position: absolute; top: 3px; left: 4px;
  font-size: 10px; font-weight: 800; color: var(--dim);
  background: #0e1620; border: 1px solid var(--line); border-radius: 999px; padding: 1px 6px;
}
.tile.voted .tally { color: var(--gold); border-color: #4a3a10; }
.vote-foot { flex: 0 0 auto; padding-top: 8px; }
.card-choice { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.toggle { font-size: 13px; padding: 10px; }
.toggle.on { border-color: var(--gold); color: var(--gold); background: #221b07; }

/* -------------------------------------------------------------------- play */
#screenPlay { gap: 5px; }
#lateNote { margin: 0; color: var(--gold); }
/* Name, the pattern's own shape, then the round counter: the dots sit beside the
   name and are centred on it, the counter keeps the right edge. */
.play-head { padding-bottom: 0; justify-content: flex-start; align-items: center; gap: 7px; }
#playMeta { font-variant-numeric: tabular-nums; margin-left: auto; }

/* The pattern drawn as the shape itself — 5×5, row-major, only the cells the
   pattern holds. A zero cell renders nothing at all: no cell, no border, no line,
   so a reader sees a line or an X rather than a lattice. Deliberately unlike the
   vote tiles' `mini` field. 5×3px dots + 4×3px gaps = 27px square. */
.pattern-dots {
  display: grid;
  grid-template-columns: repeat(5, 3px);
  grid-template-rows: repeat(5, 3px);
  gap: 3px;
  width: 27px;
  height: 27px;
  flex: 0 0 auto;
  align-self: center;
  /* Ordered first so the field's left edge is the screen's own 12px padding — the
     shape is the anchor and the name reads after it. The DOM keeps the name first
     for anything reading the head as text; the field is aria-hidden. */
  order: -1;
}
.pattern-dots i { width: 3px; height: 3px; border-radius: 50%; background: #93a8bd; }
.last-ball {
  flex: 0 0 auto; height: 54px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: linear-gradient(180deg, #16202c, #101821);
  border: 1px solid var(--line); border-radius: 14px;
  position: relative; overflow: hidden;
}
.last-ball::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(80% 120% at 50% 0%, var(--bc, #2b3a4c) 0%, transparent 70%);
  opacity: 0.22;
}
.ball-letter { font-size: 22px; font-weight: 800; color: var(--bc, var(--dim)); letter-spacing: 0.04em; }
.ball-num { font-size: 30px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.ball-caption { position: absolute; right: 10px; bottom: 4px; font-size: 9px; color: var(--dimmer); letter-spacing: 0.08em; text-transform: uppercase; }

.table {
  flex: 1 1 auto;
  /* Not 0: the table may not shrink below the height its own contents need (the
     card's square, the panel's floor). A screen too short for both scrolls the
     play screen instead of letting the panel slide under the CLAIM button. */
  min-height: min-content;
  width: min(100%, 40dvh, 340px); margin: 0 auto;
  display: flex; flex-direction: column; gap: 3px;
}
.card-head { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; flex: 0 0 auto; padding-bottom: 2px; }
/* One letter per card column. The left padding cancels the trailing letter-space so the glyph
   stays optically centred on its column however far the letters are spread. */
.card-head span { text-align: center; font-size: 13px; font-weight: 800; color: var(--c); letter-spacing: 0.26em; padding-left: 0.26em; }
.card {
  /* minmax(0, 1fr), not 1fr: a 1fr track refuses to shrink below its cell's min-content,
     which let the grid burst out of the table on short screens and left the BINGO letters
     sitting over the wrong columns. */
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-rows: repeat(5, minmax(0, 1fr));
  gap: 4px; width: 100%; aspect-ratio: 1 / 1; flex: 0 0 auto;
}
.cell {
  display: flex; align-items: center; justify-content: center;
  font-size: clamp(12px, 4.4vw, 19px); font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--cell); border: 1px solid #1f2b38; border-radius: 7px;
  color: var(--ink); user-select: none; min-height: 0; min-width: 0; padding: 0;
}
/* The free square is lit: deep red fill, pure white lettering (6.95:1), and an
   inset glow so it reads as a lamp rather than a flat swatch. Both shadows are
   inset or zero-spread, so the tile's box and its neighbours are untouched.
   `opacity: 1` overrides button[disabled]'s 0.45, which would otherwise dim both
   the red and the white to a muted maroon/grey. */
.cell.free {
  color: #fff; font-size: 9px; letter-spacing: 0.12em; opacity: 1;
  background: #b3121f; border-color: #d01726;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12),
              inset 0 0 12px rgb(255 96 96 / 0.35);
}
.cell.marked { background: var(--cc); border-color: var(--cc); color: #08111a; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15); }
.cell.marked::after { content: ""; }
.cell.pulse { animation: pop 420ms ease-out; }
@keyframes pop { 0% { transform: scale(0.86); } 60% { transform: scale(1.04); } 100% { transform: scale(1); } }

.panel-head { display: flex; justify-content: space-between; font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dimmer); }
.panel {
  flex: 1 1 auto;
  /* A floor, not a shrink-to-nothing: fifteen rows of 5 tokens are the index a
     player reads all game, and below ~8px a row the numbers collide. When the
     screen cannot give the panel this much, the play screen scrolls (the one
     thing it may do) rather than crushing the index or the card. */
  min-height: 150px;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-rows: repeat(15, minmax(0, 1fr));
  /* Fill DOWN each column, not across: tokens 1-15 stack under B, 16-30 under I, and so on,
     so every token sits in the column of the card it belongs to. */
  grid-auto-flow: column;
  gap: 2px;
}
.tok {
  display: flex; align-items: center; justify-content: center;
  font-size: clamp(7.5px, 2.1vw, 10.5px); font-weight: 600; font-variant-numeric: tabular-nums;
  color: #6f8095; background: #101821; border: 1px solid #1a2431; border-radius: 3px;
  min-height: 0; line-height: 1;
}
.tok.on { color: var(--cc); background: #182430; border-color: #2f4052; font-weight: 800; }
.tok.newest { animation: torch 900ms ease-out; background: var(--cc); color: #08111a; }
@keyframes torch { 0% { transform: scale(1.35); filter: brightness(1.6); } 100% { transform: scale(1); filter: none; } }
@media (prefers-reduced-motion: reduce) { .tok.newest, .cell.pulse { animation: none; } }

.claim {
  flex: 0 0 auto; margin-top: 2px; height: 46px;
  font-size: 17px; font-weight: 800; letter-spacing: 0.16em;
  background: #1b2836; border: 1px solid #33475c; color: var(--ink);
}
.claim:active { background: #24374a; }

/* Leave — quiet, small, a ghost. Never gold, never close enough to the control
   that decides the round to be hit by mistake: 12px of clear space above it. */
.leave {
  flex: 0 0 auto;
  display: block;
  margin: 12px auto 0;
  padding: 6px 16px;
  min-height: 30px;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--dimmer);
  background: transparent;
  border: 1px solid #1d2937;
  border-radius: 999px;
}
.leave:active { color: var(--dim); border-color: var(--line); }
.leave[disabled] { opacity: 0.4; }

.prize-banner {
  position: absolute; inset: 34px 12px auto; z-index: 5;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 14px 16px; border-radius: 14px;
  background: linear-gradient(180deg, #2a2005, #1a1405);
  border: 1px solid #6b520f; box-shadow: 0 18px 50px rgb(0 0 0 / 0.55);
  text-align: center;
}
.prize-tag { font-size: 9px; letter-spacing: 0.22em; color: var(--gold); }
.prize-banner strong { font-size: 17px; line-height: 1.25; }

/* ------------------------------------------------------------------ result */
.result-wrap { margin: auto 0; text-align: center; padding: 10px 4px 20px; }
.kicker { font-size: 10px; letter-spacing: 0.24em; color: var(--dim); margin: 0 0 6px; }
#resultTitle { font-size: 30px; }
.result-prize { margin: 14px 0 0; padding: 12px; border-radius: 12px; background: #221b07; border: 1px solid #6b520f; color: var(--gold); font-size: 14px; }
.mini-tallies { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 14px; }
.mini-tallies span { font-size: 10px; color: var(--dim); background: #131d27; border: 1px solid var(--line); border-radius: 999px; padding: 3px 8px; }

/* ------------------------------------------------------------------- toast */
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  max-width: calc(100% - 32px);
  background: #f3f6fa; color: #10161d;
  font-size: 14px; font-weight: 700;
  padding: 12px 18px; border-radius: 12px;
  box-shadow: 0 10px 30px rgb(0 0 0 / 0.5);
  z-index: 50; pointer-events: none;
  animation: toastin 180ms ease-out;
}
@keyframes toastin { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* Short phones: give the panel room by shrinking the card — but never below the width at
   which the five columns stop being comfortable. 32dvh made the card tiny on a 667-tall
   screen; 44dvh keeps the panel and the card both usable. */
@media (max-height: 720px) {
  .table { width: min(100%, 44dvh, 340px); }
  .last-ball { height: 46px; }
  .ball-num { font-size: 24px; }
}
