:root{
  --surface: #18181c;
  --surface-2: #1c1c21;
  --input-bg: #0c0c0e;
  --border: #2a2a2e;
  --border-soft: rgba(255,255,255,.08);
  --text-soft: #9a9aa2;
  --text-faint: #6c6c74;
  --danger: #e05555;
  --radius-s: 8px;
  --radius-m: 12px;
}
*{ box-sizing: border-box; }
@media (prefers-reduced-motion: reduce){
  *{ transition: none !important; animation: none !important; scroll-behavior: auto !important; }
  /* Both only become visible through their entrance animation (off here); the script hides the announcement again. */
  .bingo-announce-card{ opacity:1; }
  .firework-spark, .confetti-piece{ display:none; }
}

.hidden{ display:none !important; }

body{
  overflow-x:hidden; min-height:100vh; display:flex; align-items:center; justify-content:center;
  background:var(--ink); transition:padding-left .25s ease;
}
body:not(.live-mode){ padding-left:360px; }
@media (max-width:900px){ body:not(.live-mode){ padding-left:0; } }
/* Live mode is meant to be captured full-frame (OBS source, screen-share,
   "2ª pantalla"), so the card fills the whole tab instead of staying the
   fixed 1040x420 size used while editing — any dead space around a small
   centered card gets captured/scaled right along with it. Unconditional
   (not just on narrow viewports) since a shared browser tab is usually
   desktop-sized. */
body.live-mode .stage{ margin:0; max-width:100%; width:100vw; height:100vh; height:100dvh; border-radius:0; }

/* --- Stage: same wide horizontal card as the other live games --- */
.stage{
  position:relative; width:100%; max-width:1040px; height:420px; margin:24px;
  display:flex; flex-direction:column; gap:8px;
  padding:56px 22px 6px;
  background:
    radial-gradient(ellipse 140% 90% at 50% -10%, rgba(255,255,255,.14), transparent 60%),
    linear-gradient(180deg,var(--brand-red),var(--brand-red-dark));
  border-radius:20px;
  box-shadow:0 20px 50px rgba(0,0,0,.45);
}
.watermark{
  position:absolute; top:8px; right:22px;
  height:48px; width:auto;
  opacity:1; pointer-events:none; z-index:5;
  filter:drop-shadow(0 2px 6px rgba(0,0,0,.5));
}

.stage-top{ display:flex; flex-direction:column; gap:6px; flex:1; min-height:0; }

/* Called-numbers board: 1 or 2 rows depending on the pool size (never a
   scrollbar — the newest call is always inserted first, so if it ever truly
   overflows, the oldest numbers are what quietly drop off, not the ones anyone's
   still watching). Chip size/gap/font are computed in JS (syncCalledStripSizing)
   from the configured pool size so a smaller pool gets comfortably bigger chips. */
.called-strip{
  flex:0 0 auto; display:flex; flex-wrap:wrap; align-content:flex-start; justify-content:center;
  gap:var(--chip-gap, 3px); overflow:hidden; padding:1px;
}
.called-chip{
  flex:0 0 auto; width:var(--chip-size, 20px); height:var(--chip-size, 20px); border-radius:50%;
  background:rgba(255,255,255,.08); color:rgba(255,255,255,.4);
  font-family:var(--font); font-weight:800; font-size:var(--chip-font, 9px);
  display:flex; align-items:center; justify-content:center;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12);
  transition:background .2s ease, color .2s ease, box-shadow .2s ease;
}
.called-chip.marked{
  background:#fff; color:#7a1420;
  box-shadow:inset 0 0 0 2px #f4c430, 0 0 6px rgba(244,196,48,.6);
}
/* Forces flex-wrap onto a new line right after a row's last chip, guaranteeing
   an exact split (e.g. 50/50) instead of leaving it to width-based wrapping. */
.called-strip-break{ flex-basis:100%; width:0; height:0; }
.called-chip.pop-in{ animation:tilePop .3s cubic-bezier(.2,1.4,.4,1); }
@keyframes tilePop{ from{ transform:scale(.55); opacity:0; } to{ transform:scale(1); opacity:1; } }

/* Player cards board — a fixed 5-column grid; past 5 cards (up to the 10-card
   cap) it wraps to a 2nd row instead of narrowing every card. JS
   (syncCardsSizing) picks the card size itself — width and height together,
   since a card's height tracks its width via the square 3x3 grid — from
   whichever of "5 across" or "rows stacked" is the tighter fit, so it's never
   wider or taller than the space actually has. justify-content centers the
   columns when that resulting width doesn't fill the full row. */
.cards-grid{
  flex:1; min-height:0; overflow-y:auto;
  background:rgba(0,0,0,.16); border-radius:18px; padding:12px;
  display:grid; grid-template-columns:repeat(var(--grid-cols, 5), var(--card-width, 1fr));
  justify-content:center; align-items:start; align-content:flex-start; gap:8px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
}
/* On a phone the stage is taller than the cards need: centre them in it instead of hugging the top. */
@media (max-width:600px){ .cards-grid{ align-content:center; } }
.cards-empty{
  grid-column:1 / -1; margin:auto; color:rgba(255,255,255,.55); font-size:14px; text-align:center;
  font-family:var(--font); text-transform:uppercase; letter-spacing:.5px; max-width:60ch;
}
/* Vertical stack: name on top (full width), grid below, then a prize-chip row
   below that. Centered (justify-content) so the numbers stay balanced in
   whatever height a row ends up with. */
.bingo-card{
  position:relative; min-width:0; background:rgba(0,0,0,.32); border-radius:14px; padding:6px;
  display:flex; flex-direction:column; justify-content:center; gap:4px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1), 0 4px 10px rgba(0,0,0,.25);
}
/* The card's Pokémon: big, centred behind the numbers and faint enough to read through (marked cells are
   solid white, so a marked number always stays clear). Official artwork, so it stays sharp at any size.
   Its own clipping layer keeps it inside the rounded card without clipping the prize chips. */
.card-mon-layer{ position:absolute; inset:0; z-index:0; border-radius:inherit; overflow:hidden; pointer-events:none; }
.card-mon{
  position:absolute; left:50%; top:50%; width:104%; height:104%; max-width:none;
  transform:translate(-50%, -48%); object-fit:contain; opacity:.36; user-select:none;
  filter:drop-shadow(0 6px 10px rgba(0,0,0,.28));
}
.bingo-card > .card-name, .bingo-card > .card-grid, .bingo-card > .card-badges, .bingo-card > .card-body{ position:relative; z-index:1; }
.card-name{
  font-family:var(--font); font-weight:800; font-size:var(--name-font, 11px); color:var(--text-color, #fff); text-transform:uppercase;
  text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.card-grid{ position:relative; display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:4px; }
.card-cell{
  aspect-ratio:1; display:flex; align-items:center; justify-content:center; overflow:hidden;
  background:rgba(255,255,255,.08); border-radius:8px;
  font-family:var(--font); font-weight:800; font-size:var(--cell-font, clamp(14px,2vw,21px)); color:var(--text-color, #fff);
  transition:background .2s ease, color .2s ease;
}
.card-cell.marked{ background:rgba(255,255,255,.92); color:#7a1420; }
.card-cell.winning{
  background:#f4c430; color:#3a2600;
  box-shadow:0 0 0 2px #fff, 0 0 14px rgba(244,196,48,.7);
}
/* One continuous stroke across a whole completed line (see buildCardElement)
   instead of decorating each number individually — positioned in percentages
   of the grid box so it scales with the card at any size. Thin and
   semi-transparent on purpose: several lines can share a card (up to all 8 on
   a full card), and solid, outlined strokes stacked on top of each other
   turned into a heavy, cluttered crosshatch — this stays legible instead of
   fighting for attention with the numbers underneath. */
.line-strike{
  position:absolute; z-index:1; background:rgba(58,38,0,.5); border-radius:2px; pointer-events:none;
}
.line-strike.line-row-0{ left:1%; right:1%; top:16.667%; height:var(--strike-thickness, 3px); transform:translateY(-50%); }
.line-strike.line-row-1{ left:1%; right:1%; top:50%; height:var(--strike-thickness, 3px); transform:translateY(-50%); }
.line-strike.line-row-2{ left:1%; right:1%; top:83.333%; height:var(--strike-thickness, 3px); transform:translateY(-50%); }
.line-strike.line-col-0{ top:1%; bottom:1%; left:16.667%; width:var(--strike-thickness, 3px); transform:translateX(-50%); }
.line-strike.line-col-1{ top:1%; bottom:1%; left:50%; width:var(--strike-thickness, 3px); transform:translateX(-50%); }
.line-strike.line-col-2{ top:1%; bottom:1%; left:83.333%; width:var(--strike-thickness, 3px); transform:translateX(-50%); }
.line-strike.line-diag-down{ left:50%; top:50%; width:141.5%; height:var(--strike-thickness, 3px); transform:translate(-50%, -50%) rotate(45deg); }
.line-strike.line-diag-up{ left:50%; top:50%; width:141.5%; height:var(--strike-thickness, 3px); transform:translate(-50%, -50%) rotate(-45deg); }
/* One chip per line actually won (see buildCardElement) instead of a single
   count, so an earlier win's chip stays put — never replaced or renumbered —
   as later ones are added alongside it. Full-width row below the grid (5
   cards or fewer, height to spare); no overflow:hidden on purpose — a chip
   should never silently disappear, so it wraps to extra rows (growing the
   card a little) rather than clipping. */
.card-badges{
  display:flex; flex-wrap:wrap; justify-content:center; gap:3px;
}
.card-badge{
  flex:0 0 auto; background:#f4c430; color:#3a2600;
  font-family:var(--font); font-weight:800; font-size:var(--badge-font, 9px); letter-spacing:.2px;
  padding:2px 6px; border-radius:999px; box-shadow:0 2px 5px rgba(0,0,0,.4);
  white-space:nowrap;
}
/* Lines completed but with nothing claimed (an earlier card already took every
   matching prize threshold) — muted instead of trophy-gold so it never reads
   as an actual win. */
.line-strike.fresh{ animation:strikeIn .35s ease; }
@keyframes strikeIn{ from{ opacity:0; } to{ opacity:1; } }
.card-badge.fresh{ animation:tilePop .3s cubic-bezier(.2,1.4,.4,1); }
.card-badge-plain{ background:rgba(255,255,255,.16); color:#fff; box-shadow:none; }
/* Past 5 cards (the tight 2-row layout) badges move beside the grid instead —
   a narrow reserved column (sized by syncCardsSizing) so a card's badges
   spend width, never height, keeping every card's size independent of how
   many prizes it's won. Wraps into extra sub-columns if it has more chips
   than fit in one — still no overflow:hidden, it can spill a little wider
   than its reserved width rather than ever hiding a chip. */
.bingo-card.badges-side .card-body{ display:flex; align-items:flex-start; gap:4px; }
/* Explicit width+height (not flex:1 + aspect-ratio) — see the --grid-size
   comment in syncCardsSizing for why: stretching the grid to match a tall
   badge column would otherwise distort its cells off-square. */
.bingo-card.badges-side .card-grid{ flex:0 0 auto; width:var(--grid-size); height:var(--grid-size); }
.bingo-card.badges-side .card-badges{
  flex:0 0 var(--badge-col-width, 18px); height:var(--grid-size); flex-direction:column;
  align-content:flex-start; justify-content:center;
}
.bingo-card.badges-side .card-badge{ font-size:var(--badge-font, 8px); padding:1px 4px; border-radius:6px; }
.bingo-card.game-winner{
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1), 0 0 0 3px #f4c430, 0 6px 20px rgba(244,196,48,.55);
}

/* Award toasts: brief pop-ups over the stage when a prize threshold is claimed */
.award-toasts{
  position:absolute; top:10px; left:16px; right:170px; z-index:20;
  display:flex; flex-direction:column; gap:6px; align-items:center; pointer-events:none;
}
.award-toast{
  background:#000; color:#fff; font-family:var(--font); font-weight:800; font-size:12.5px;
  padding:7px 16px; border-radius:999px; text-align:center; max-width:100%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  box-shadow:0 6px 16px rgba(0,0,0,.4), inset 0 0 0 2px #f4c430;
  animation:toastPop .3s cubic-bezier(.2,1.4,.4,1), toastFade .4s ease 3.4s forwards;
}
@keyframes toastPop{ from{ transform:translateY(-8px) scale(.9); opacity:0; } to{ transform:translateY(0) scale(1); opacity:1; } }
@keyframes toastFade{ to{ opacity:0; transform:translateY(-6px); } }

.stage-bottom{ display:flex; gap:14px; align-items:stretch; height:52px; }
.banner-wrap{ flex:1; min-width:0; position:relative; display:flex; }
.banner-pill{
  flex:1; min-width:0; background:#000; border-radius:999px;
  position:relative; overflow:hidden;
  transition:transform .15s ease, box-shadow .15s ease;
  box-shadow:0 8px 22px rgba(0,0,0,.35), inset 0 0 0 2px rgba(255,255,255,.08);
}
/* Faint on-stage indicator of the auto-call state — sits over the banner
   pill (not inside it, since renderBanner replaces that element's innerHTML
   wholesale) so it survives every banner slide/reset and stays visible to
   the audience, not just the host panel. Empty/hidden while the feature
   isn't armed at all. */
.banner-auto-icon{
  position:absolute; right:22px; top:50%; transform:translateY(-50%);
  font-size:22px; line-height:1; color:#fff; opacity:.22;
  pointer-events:none; z-index:2; transition:opacity .2s ease;
}
.banner-pill.call-step{ animation:callPulse 1.4s ease; }
@keyframes callPulse{
  0%{ transform:scale(1); }
  18%{ transform:scale(1.1); box-shadow:0 0 0 4px #f4c430, 0 0 30px #f4c430; }
  100%{ transform:scale(1); box-shadow:inset 0 0 0 2px rgba(255,255,255,.08); }
}
.banner-reel{
  --slide-ms:200ms;
  position:absolute; inset:0; padding:14px 26px;
  display:flex; align-items:center; justify-content:center;
  transform:translateY(0); opacity:1;
  transition:transform var(--slide-ms) cubic-bezier(.45,0,.8,.35), opacity var(--slide-ms) linear;
}
.banner-reel.banner-reel-incoming{ transform:translateY(105%); opacity:0; transition:none; }
.banner-reel.banner-reel-outgoing{ transform:translateY(-105%); opacity:0; }
.banner-text{
  min-width:0; max-width:100%;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  color:var(--text-color, #fff); font-family:var(--font); font-weight:900;
  font-size:clamp(18px,3.2vw,34px); letter-spacing:1px; text-align:center;
  text-transform:uppercase; text-shadow:0 2px 4px rgba(0,0,0,.5);
}
.banner-placeholder{ color:rgba(255,255,255,.5); letter-spacing:2px; }
.count-pill{
  background:linear-gradient(180deg,var(--green),var(--green-dark));
  border-radius:999px; padding:8px 22px; min-width:140px;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  box-shadow:var(--shadow-soft);
}
.count-pill span{ font-family:var(--font); font-weight:900; font-size:clamp(18px,2.6vw,28px); color:#0c2a10; line-height:1; }
.count-pill small{ font-weight:800; color:#0c2a10; letter-spacing:1px; font-size:10px; margin-top:2px; }

/* --- Corner gear + dock --- */
.corner-hover{ position:fixed; top:0; right:0; width:76px; height:76px; display:flex; align-items:flex-start; justify-content:flex-end; padding:12px; opacity:0; transition:opacity .2s ease; z-index:100; }
.corner-hover:hover{ opacity:1; }
.dock-toggle{ width:38px; height:38px; border-radius:50%; border:none; background:rgba(0,0,0,.65); color:#fff; font-size:18px; cursor:pointer; }

.dock{
  position:fixed; top:0; left:0; width:360px; height:100vh; overflow-y:auto;
  background:#141417; border-right:1px solid rgba(255,255,255,.08);
  padding:20px; display:flex; flex-direction:column; gap:16px; z-index:80;
}
body.live-mode .dock{ display:none; }
.dock .back-link{ font-size:12px; color:#888; text-decoration:none; }
.dock .back-link:hover{ color:#fff; }
.dock h2{ margin:0; font-size:16px; font-family:var(--font); color:#fff; }
.dock .hint{ margin:0; font-size:11px; color:#777; }
.live-toggle{ appearance:none; cursor:pointer; border:none; border-radius:12px; padding:12px; font-weight:800; font-size:13px; background:#232327; color:#fff; }

button.call-btn{
  appearance:none; border:none; cursor:pointer; width:100%; background:var(--brand-red); color:#fff;
  font-family:var(--font); font-weight:800; font-size:16px; border-radius:12px; padding:12px;
  transition:background .15s ease;
}
button.call-btn:hover{ background:var(--brand-red-dark); }
button.call-btn:disabled{ opacity:.5; cursor:not-allowed; }

.auto-call-row{ display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:4px; }
.auto-call-interval{ display:flex; align-items:center; gap:4px; font-size:11px; color:var(--text-soft); flex:0 0 auto; }
.auto-call-interval input[type="number"]{
  width:42px; font-size:12px; padding:7px 6px; border-radius:8px; text-align:center;
  border:1px solid var(--border); background:var(--input-bg); color:#fff;
}
.auto-call-interval.disabled{ opacity:.5; pointer-events:none; }
.auto-call-status{ margin:0 0 12px; min-height:14px; font-size:11px; font-weight:700; color:var(--text-faint); }
.auto-call-status.running{ color:var(--green); }

.seg-details{ border-top:1px solid rgba(255,255,255,.08); padding-top:12px; }
.seg-details summary{ cursor:pointer; font-size:13px; font-weight:800; font-family:var(--font); letter-spacing:.02em; text-transform:uppercase; color:#ddd; list-style:none; display:flex; align-items:center; gap:6px; }
.seg-details summary::-webkit-details-marker{ display:none; }
.seg-details summary::before{ content:'▸'; color:var(--brand-red); font-size:12px; transition:transform .15s ease; }
.seg-details[open] summary::before{ transform:rotate(90deg); }
.count-badge{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:18px; padding:0 6px; height:18px; border-radius:999px;
  background:var(--brand-red); color:#fff; font-size:10px; font-weight:800;
}
.section-body{ margin-top:12px; }
.hint-text{ font-size:11.5px; color:var(--text-faint); margin:0 0 12px; line-height:1.5; }

.pool-size-row{ display:flex; align-items:center; gap:8px; margin-bottom:12px; }
.pool-size-row label{ font-size:12.5px; color:var(--text-soft); white-space:nowrap; }
.pool-size-row input[type="number"]{
  width:64px; font-size:13px; padding:8px 10px; border-radius:var(--radius-m);
  border:1px solid var(--border); background:var(--input-bg); color:#fff;
}
.pool-size-row input[type="number"]:disabled{ opacity:.5; cursor:not-allowed; }

.add-card-row{ display:flex; gap:8px; margin-bottom:12px; }
.add-card-row input[type="text"]{
  flex:1; min-width:0; font-size:13.5px; padding:10px 12px; border-radius:var(--radius-m);
  border:1px solid var(--border); background:var(--input-bg); color:#fff;
}
.add-card-row button{
  flex:0 0 auto; appearance:none; cursor:pointer; background:var(--brand-red); color:#fff;
  border:none; font-weight:800; font-size:13px; padding:0 16px; border-radius:var(--radius-m);
}
.add-card-row button:hover{ background:var(--brand-red-dark); }
.add-card-row button:disabled{ opacity:.5; cursor:not-allowed; }
.add-card-row input[type="text"]:disabled{ opacity:.5; cursor:not-allowed; }

.cards-dock-list{ display:flex; flex-direction:column; gap:6px; max-height:280px; overflow-y:auto; padding-right:2px; }
.card-row{ display:flex; align-items:center; gap:8px; background:var(--surface-2); border-radius:var(--radius-s); padding:8px 9px; }
.card-row .card-row-name{ flex:1; min-width:0; font-size:12.5px; color:#eee; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.card-row .card-row-status{ flex:0 1 auto; font-size:10.5px; font-weight:700; color:#f4c430; max-width:46%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.card-row .card-row-remove{
  flex:0 0 auto; width:22px; height:22px; border-radius:6px; border:1px solid var(--border);
  background:var(--input-bg); color:#e05555; font-size:11px; cursor:pointer; padding:0;
}
.card-row .card-row-remove:disabled{ opacity:.35; cursor:not-allowed; }

.prize-list{ display:flex; flex-direction:column; gap:6px; }
.prize-row{ display:flex; align-items:center; gap:8px; background:var(--surface-2); border-radius:var(--radius-s); padding:7px 9px; transition:box-shadow .15s ease; }
.prize-row.claimed{ box-shadow:inset 0 0 0 1px #f4c430; }
.prize-row-label{ flex:0 0 96px; font-size:10.5px; font-weight:700; color:var(--text-soft); line-height:1.3; }
.prize-row input[type="text"]{
  flex:1; min-width:0; font-size:12.5px; padding:8px 10px; border-radius:var(--radius-s);
  border:1px solid var(--border); background:var(--input-bg); color:#fff;
}
.prize-row input[type="text"]:disabled{ opacity:.5; cursor:not-allowed; }
.prize-row-winner{ flex:0 0 auto; font-size:10px; font-weight:800; color:#f4c430; max-width:74px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

.chips{ display:flex; flex-wrap:wrap; gap:8px; }
.chip{
  appearance:none; cursor:pointer; font-size:13px; font-weight:700;
  padding:8px 13px; border-radius:999px; border:1px solid var(--border); background:var(--surface-2); color:#ddd;
  transition:background .15s ease, border-color .15s ease, color .15s ease;
}
.chip:hover{ border-color:var(--brand-red); }
.chip .check{ display:inline-block; width:13px; height:13px; border-radius:4px; border:1.5px solid var(--border); margin-right:7px; vertical-align:-2px; position:relative; }
.chip[aria-pressed="true"]{ background:rgba(223,32,48,.16); border-color:var(--brand-red); color:#fff; }
.chip[aria-pressed="true"] .check{ background:var(--brand-red); border-color:var(--brand-red); }
.chip[aria-pressed="true"] .check::after{
  content:""; position:absolute; left:2.5px; top:-0.5px; width:4px; height:7px;
  border-right:2px solid #fff; border-bottom:2px solid #fff; transform:rotate(40deg);
}

.color-field{ display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.color-field label{ flex:0 0 auto; font-size:12.5px; font-weight:600; color:var(--text-soft); min-width:88px; }
.color-field input[type="text"]{
  flex:1; min-width:0; font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:13px; padding:9px 10px;
  border-radius:var(--radius-s); border:1px solid var(--border); background:var(--input-bg); color:#fff;
}
.color-field input[type="color"]{
  width:34px; height:34px; padding:0; border-radius:8px; border:1px solid var(--border); background:none; cursor:pointer; flex:0 0 auto;
}

.preset-row{ display:flex; gap:6px; margin-bottom:8px; }
.preset-row:last-child{ margin-bottom:0; }
.preset-row input[type="text"]{ flex:1; background:var(--input-bg); border:1px solid var(--border); color:#fff; border-radius:8px; padding:8px; font-size:12px; }
.preset-row select{
  flex:1; min-width:0; appearance:none; -webkit-appearance:none;
  background:var(--input-bg); border:1px solid var(--border); color:#fff; border-radius:8px;
  padding:8px 30px 8px 10px; font-size:13px; cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' stroke='%239a9aa2' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center;
}
.preset-row select option{ color:#fff; background:var(--input-bg); }
.preset-row button{ appearance:none; cursor:pointer; background:var(--surface-2); color:#fff; border:1px solid var(--border); border-radius:8px; padding:8px 10px; font-size:12px; font-weight:700; }
.preset-row button:hover{ border-color:var(--brand-red); }

.round-reset-btn{ border:none; border-radius:12px; padding:12px; font-weight:800; font-size:13px; cursor:pointer; background:#232327; color:#e0b84c; border:1px solid #3a331a; }
.round-reset-btn:disabled{ opacity:.5; cursor:not-allowed; }

.modal-overlay{ position:fixed; inset:0; z-index:200; background:rgba(0,0,0,.65); display:flex; align-items:center; justify-content:center; padding:20px; }
.modal-box{ background:#18181c; border:1px solid #2e2e34; border-radius:16px; padding:22px; max-width:360px; width:100%; box-shadow:0 20px 50px rgba(0,0,0,.5); }
.modal-box p{ margin:0 0 18px; color:#fff; font-size:14px; line-height:1.4; }
.modal-actions{ display:flex; gap:10px; justify-content:flex-end; }
.modal-btn{ border:none; border-radius:10px; padding:10px 16px; font-weight:700; font-size:13px; cursor:pointer; }
.modal-btn-ghost{ background:#232327; color:#ccc; }
.modal-btn-ghost:hover{ background:#2e2e34; }
.modal-btn-primary{ background:var(--brand-red); color:#fff; }
.modal-btn-primary:hover{ background:var(--brand-red-dark); }

#confettiLayer{ position:fixed; inset:0; pointer-events:none; overflow:hidden; z-index:9999; }
.confetti-piece{ position:absolute; top:-12px; width:8px; height:14px; opacity:.95; animation:confettiFall linear forwards; }
@keyframes confettiFall{ to{ transform:translateY(105vh) translateX(var(--dx)) rotate(var(--rot)); opacity:.25; } }

.firework-spark{
  position:absolute; width:6px; height:6px; border-radius:50%;
  animation:fireworkBurst 1s cubic-bezier(.15,.6,.35,1) forwards;
}
@keyframes fireworkBurst{
  0%{ transform:translate(0,0) scale(1); opacity:1; }
  65%{ opacity:1; }
  100%{ transform:translate(var(--fx), var(--fy)) scale(.3); opacity:0; }
}

/* Game-over reveal: centered on the viewport, no click needed — pops in and
   fades itself out, so a live show never stalls waiting for someone to hit OK. */
.bingo-announce{
  position:fixed; inset:0; z-index:210; display:flex; align-items:center; justify-content:center;
  pointer-events:none;
}
.bingo-announce-card{
  background:rgba(10,10,12,.94); border-radius:24px; padding:28px 52px;
  text-align:center; box-shadow:0 24px 60px rgba(0,0,0,.6), 0 0 0 3px #f4c430;
  opacity:0;
}
.bingo-announce-card.play{
  animation:bingoPop .5s cubic-bezier(.2,1.4,.4,1) forwards, bingoFadeOut .5s ease 3.6s forwards;
}
.bingo-announce-title{
  font-family:var(--font); font-weight:800; font-size:clamp(36px,6vw,64px); color:#f4c430;
  letter-spacing:2px; text-shadow:0 4px 12px rgba(0,0,0,.5);
}
.bingo-announce-sub{
  margin-top:8px; font-family:var(--font); font-weight:800; font-size:clamp(14px,2vw,20px); color:#fff;
  text-shadow:0 2px 4px rgba(0,0,0,.5);
}
@keyframes bingoPop{
  0%{ transform:scale(.6); opacity:0; }
  60%{ transform:scale(1.06); opacity:1; }
  100%{ transform:scale(1); opacity:1; }
}
@keyframes bingoFadeOut{ to{ opacity:0; transform:scale(.94); } }

/* --- Espejo dentro del live de Chasers (shared/espejo.js): el tablero se queda con su fondo
   (diez tarjetas encima del video no se leerían). El letrero de «agrega tarjetas» es para el
   vendedor, no para la sala. --- */
html.modo-espejo .cards-empty{ display: none !important; }
