/* ── Tokens ─────────────────────────────────────────────────────────────────── */
/* Table-specific tokens (felt, rail, --circ) now live in table-theme.css. */
:root {
  --bg:         #060c18;
  --surface:    rgba(8,16,32,0.92);
  --text:       #eef4ff;
  --muted:      #7a90b8;
  --accent:     #ffd700;
  --success:    #22c55e;
  --danger:     #ef4444;
  /* Suit colours on an ivory face — instantly tellable apart on small screens */
  --spade:      #23262d;
  --heart:      #d92038;
  --diamond:    #e8590c;
  --club:       #157347;
  --card-face:  linear-gradient(168deg, #fdfcf7 0%, #f3f0e6 100%);
  /* Card-back palette (2026-07-18): matches the Fable dealer-motion mockup
     exactly (--oxblood/--oxblood-lo/--bone there) — the "real deck" look
     the owner asked to replicate. Used by .pill-card-back and
     .mini-card.card-back; the in-flight ghost (aurora-motion.js) reuses
     these same values at a larger, mockup-scale size — see
     .aurora-deal-ghost-oversized in aurora-motion.css. */
  --card-back-hi: #6e1f2c;
  --card-back-lo: #4b131d;
  --card-back-border: #e9dfc6;
  /* Shared board-presentation spacing — one source of truth for the gap
     between board rows and between cards within a row, so multi-board
     variants (mb-board: DBBP/TBBP/HLHLH, f2-board: F2, cd-board: Countdown)
     read as one consistent, premium layout instead of each variant's
     renderer hand-picking its own numbers. */
  --board-row-gap:  8px;
  --board-card-gap: 7px;
}

/* ── Reset ──────────────────────────────────────────────────────────────────── */
*,*::before,*::after { box-sizing: border-box; margin: 0; padding: 0; }
html,body { height: 100%; overflow: hidden; }
body {
  font-family: Inter, system-ui, -apple-system, sans-serif;
  background: var(--bg);
  color: var(--text);
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* ── App Shell ──────────────────────────────────────────────────────────────── */
.app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh; /* iOS Safari fix — uses actual visible height */
  max-height: 100dvh;
  overflow: hidden;
}

/* ── Topbar ─────────────────────────────────────────────────────────────────── */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  height: 48px;
  flex-shrink: 0;
  background: rgba(0,0,0,0.45);
  border-bottom: 1px solid rgba(255,255,255,0.05);
  z-index: 20;
  gap: 8px;
}

.topbar-left  { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; overflow: hidden; }
.topbar-right  { display: flex; align-items: center; justify-content: flex-end; flex-shrink: 0; gap: 8px; }

.brand {
  font-weight: 800;
  font-size: 0.92rem;
  color: var(--accent);
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.street-badge {
  padding: 3px 11px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--muted);
  transition: background 0.3s, color 0.3s;
}
.street-badge.live {
  background: rgba(34,197,94,0.15);
  border-color: rgba(34,197,94,0.4);
  color: var(--success);
}
.street-badge.showdown {
  background: rgba(255,215,0,0.15);
  border-color: rgba(255,215,0,0.4);
  color: var(--accent);
}

/* End-game (practice mode only): quiet by default, reads as a warning on
   press — this ends the session, unlike every other topbar control. */
.btn-quit {
  padding: 4px 9px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.btn-quit:hover, .btn-quit:active {
  background: rgba(255,90,90,0.14);
  border-color: rgba(255,90,90,0.4);
  color: #ff8a8a;
}

/* Coach Mode toggle — quiet when off, softly lit when on */
.btn-coach {
  padding: 5px 12px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.btn-coach.on {
  background: rgba(192,132,252,0.12);
  border-color: rgba(192,132,252,0.45);
  color: #c084fc;
}

.btn-new {
  padding: 7px 18px;
  background: linear-gradient(135deg, #ffd700, #e5a800);
  color: #1a0800;
  font-weight: 800;
  font-size: 0.8rem;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  letter-spacing: 0.04em;
  transition: transform 0.12s, box-shadow 0.12s;
}
.btn-new:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(255,215,0,0.35); }

/* ── Table Wrap ─────────────────────────────────────────────────────────────── */
/* Portrait column (mobile-only app): rail → stage → pot → hero. Centered as a
   phone-width column everywhere — there is no desktop layout.
   position:relative so #oppStrip can be overlaid on #boardStage's box at
   desktop widths (Step 4) without moving either element in the DOM. */
.table-wrap {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  overflow: hidden;
  padding: 8px 12px 0;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
}

/* ── Board Stage ────────────────────────────────────────────────────────────────
   The board is the hero of the screen; the stage exists only to frame it —
   premium dark felt, one champagne hairline, soft depth. No oval, no rail
   furniture, no decoration competing with the cards. */
/* Mobile stadium is CSS-native — background/border/box-shadow directly on
   this element, elliptical percentage border-radius (self-adjusting to
   whatever box the flexible height produces, never a fixed aspect ratio).
   An object-fit:contain SVG-image approach was tried and reverted: it let
   the table shrink well below the stage's actual available height, leaving
   dead space above/below on real devices — confirmed on-device, not just
   in emulation. CSS always fills exactly what's available. */
.board-stage {
  position: relative;
  width: 100%;
  /* Shape comes from aspect-ratio (derived from width), NOT from letting
     flex-grow expand the box to fill leftover space — flex:1(grow) here
     produced a tall stretched oval/circle instead of a stadium, because
     #oppStrip is position:absolute (removed from .table-wrap's flex flow),
     so the stage inherited all the vertical space opponents used to occupy
     in-flow, on top of its own. flex-grow:0 keeps it at its natural,
     aspect-ratio-derived landscape height; flex-shrink:1 + min-height still
     let it compress on short viewports — the hero hand is a protected
     region and must never lose a pixel to it. */
  flex: 0 1 auto;
  aspect-ratio: 3 / 2;
  min-height: 110px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 15% 9%;
  border-radius: 46% / 42%;
  background: radial-gradient(ellipse at 50% 32%, var(--tt-felt-hi) 0%, var(--tt-felt) 55%, var(--tt-felt-lo) 100%);
  border: 6px solid var(--tt-rail);
  box-shadow:
    0 0 0 1px var(--tt-rail-hi),
    0 0 0 1px var(--tt-gold) inset,
    0 14px 30px rgba(0,0,0,0.5),
    inset 0 0 50px rgba(0,0,0,0.3);
}

.community-cards {
  display: flex;
  gap: 9px;
  align-items: center;
  justify-content: center;
  /* Must stay content-independent: BoardStage.fitCardBox() measures this
     element's clientWidth to decide card size, before any cards exist in
     it. Without an explicit width it shrinks-to-fit its own (still empty)
     content, making that measurement meaningless. */
  width: 100%;
}

/* At mobile widths the stadium is #boardStage's own background (see
   above), so this is just a plain in-flow flex column inset by the stage's
   own padding — no JS measurement needed. Desktop's shell is a separate
   image layer, so it repositions this via absolute percentages in the media
   query below instead. Pot info no longer lives in here (2026-07-26: moved
   to the fixed Aurora Pot Rail, aurora-experience-layer.css) — this now
   only ever holds #communityCards, but BoardStage.fitCardBox() still
   measures IT (not #boardStage) for available space, so it stays its own
   flex container rather than collapsing into #communityCards directly. */
.premium-table-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
}

/* ── Premium table shell — desktop (Table Redesign v1, Steps 1–4) ──────────────
   The shell's felt rect sits at (145,125)–(1055,575) of a 1200×700 viewBox —
   12.083% left/right, 17.857% top/bottom — used below as absolute inset
   percentages (which resolve per-axis against the matching container
   dimension), not padding (which always resolves against width). The stage
   is locked to the same aspect ratio, so the percentages are exact — safe
   only because desktop doesn't need the stage's height to flex. Desktop
   keeps its real SVG-image shell (approved, working) — only mobile moved
   to the CSS-native approach above.

   Four independently-replaceable layers, back to front: shadow → rail →
   gold trim → felt. Each is its own file (assets/premium-table/*.svg) so a
   future asset swap (e.g. a new felt texture) only touches one file. */
.table-shell-layer { display: none; }
@media (min-width: 601px) {
  .board-stage {
    position: relative;
    background: none;
    border: none;
    box-shadow: none;
    padding: 0;
    aspect-ratio: 1200 / 700;
    flex: 0 0 auto;
  }
  .table-shell-layer {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }
  .shell-shadow { z-index: 0; }
  /* The combined table_shell.svg (Step 1) wrapped its whole composite in one
     feDropShadow, which is what actually made the matte-black rail read
     against this app's near-black page background — splitting into separate
     files loses that (no individual layer casts its own edge shadow). A CSS
     drop-shadow on the rail — the layer that defines the table's outer
     silhouette — restores the same separation without touching the SVGs. */
  .shell-rail   { z-index: 1; filter: drop-shadow(0 14px 22px rgba(0,0,0,0.65)); }
  .shell-trim   { z-index: 2; }
  .shell-felt   { z-index: 3; }
  /* Step 3: existing game layer (board/pot) relocated here — pure
     positioning, renderBoard()/renderPot() still write
     to these same element IDs, no rendering-logic change. Sits at the
     shell's felt-rect inset (same 12.083%/17.857% math as Steps 1–2). */
  .premium-table-content {
    position: absolute;
    /* width:auto is required here: the base (mobile) rule sets an explicit
       width:100%, and on an absolutely-positioned element an explicit width
       overrides what left+right would otherwise compute — silently
       cancelling the right-inset and stretching this to the full stage
       width instead of the felt's actual inset box. */
    width: auto;
    left: 12.083%; right: 12.083%;
    top: 17.857%; bottom: 17.857%;
    z-index: 4;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
  }
}

/* Step 4/mobile-shell-fix: seat ring, now at every width. #oppStrip is
   positioned (top/left/width/height, in px) by AuroraTable.layoutSeats()
   in aurora-table.js to exactly overlay #boardStage — each .opp-pill inside
   is then just a plain percentage position within that box, per the
   LAYOUTS table keyed by seat count. Hero is never in this ring; it stays
   in its own protected zone below the stage. Unconditional (not gated to
   desktop) since the mobile stadium (CSS-native, above) has no
   letterboxing to account for — #boardStage's own box is always correct. */
.opp-strip.seat-ring-active {
  position: absolute;
  z-index: 5;
  padding: 0;
  pointer-events: none;
}
.opp-strip.seat-ring-active .opp-pill {
  position: absolute;
  transform: translate(-50%, -50%);
  pointer-events: auto;
}

/* Countdown's 10-card triangular board: 4 rows shrinking 4→1, left-aligned so
   each row's Nth card visually lines up into a column (Row k / Column k).
   width:max-content overrides the base .community-cards width:100% — without
   it, flex-start left-aligns each row against the FULL stage width (the
   reported bug: a left-pinned triangle with dead space on the right) instead
   of against the triangle's own natural (widest-row) footprint. The parent
   #premiumTableContent's align-items:center then centers that narrower,
   shrink-wrapped box as a whole — the row-to-row left alignment that keeps
   columns tracking is preserved untouched, only the outer box moves. */
.community-cards.cd-board {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--board-row-gap);
  width: max-content;
  max-width: 100%;
}
.cd-board-row { display: flex; gap: var(--board-card-gap); }
/* Card size computed from the stage's real box into --cd-card-w/--cd-card-h
   (board-stage.js fitCardBox), same responsive-fit mechanism as
   single-board/f2-board-v2/mb-board — the triangle no longer relies on
   fixed breakpoint sizes, and height is now its own real-space-derived
   ceiling rather than a flat ×1.43 of width (DYNAMIC-CARD-SIZING-SPEC.md). */
.cd-board .board-card {
  width: var(--cd-card-w, 50px);
  height: var(--cd-card-h, calc(var(--cd-card-w, 50px) * 1.43));
  border-radius: calc(var(--cd-card-w, 50px) * 0.14);
}
.cd-board .board-card .c-rank { font-size: calc(var(--cd-card-w, 50px) * 0.42); }
.cd-board .board-card .c-suit { font-size: calc(var(--cd-card-w, 50px) * 0.34); }

/* F2 twin battlefields (reference design): each board is one horizontal row
   of [R1][c][c][c][c][R2], with ruled TOP BOARD / BOTTOM BOARD labels between
   the rows. R1/R2 are the two SHARED rivers, drawn on both rows — either
   completes either board; the duplication teaches the fork. Card width is
   computed by the renderer (f2-ui.js) into --f2-card-w. */
.community-cards.f2-board {
  flex-direction: column;
  align-items: center;
  gap: var(--board-row-gap);
  width: 100%;
}
.f2-row {
  display: flex;
  gap: var(--board-card-gap);
  justify-content: center;
}
.f2-board .board-card {
  width: var(--f2-card-w, 46px);
  height: var(--f2-card-h, calc(var(--f2-card-w, 46px) * 1.43));
  border-radius: calc(var(--f2-card-w, 46px) * 0.14);
}
.f2-board .board-card .c-rank { font-size: calc(var(--f2-card-w, 46px) * 0.42); }
.f2-board .board-card .c-suit { font-size: calc(var(--f2-card-w, 46px) * 0.34); }

/* Empty shared-river slots carry their own name — R1/R2 read as river
   options, never a 5th/6th board card. */
.f2-slot-name {
  font-size: calc(var(--f2-card-w, 46px) * 0.3);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--tt-f2-label);
}
.board-card.f2-river-slot.placeholder { border-style: solid; border-color: rgba(201,160,74,0.35); }

.f2-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 92%;
}
.f2-rule { flex: 1; height: 1px; background: var(--tt-gold-dim); opacity: 0.55; }
.f2-row-label {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--tt-f2-label);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Double Board / Triple Board stacked boards (multiboard-ui.js): N flat,
   fully independent 5-card rows — no shared cards, no path alternatives,
   unlike F2's twin rows. Card width is computed by the renderer into
   --mb-card-w. */
.community-cards.mb-board {
  flex-direction: column;
  align-items: center;
  gap: var(--board-row-gap);
  width: 100%;
}
/* Triple Board's 3 rows are tight even at the mb3-mode card floor (28px,
   multiboard-ui.js) — measured deficit on real short-phone-landscape heights
   (844x390, 740x360) is only ~2-4px, so a small gap trim closes it without
   shrinking cards further. */
.app.mb3-mode .community-cards.mb-board { gap: 5px; }
.mb-row {
  display: flex;
  gap: var(--board-card-gap);
  justify-content: center;
}
.mb-board .board-card {
  width: var(--mb-card-w, 46px);
  height: var(--mb-card-h, calc(var(--mb-card-w, 46px) * 1.43));
  border-radius: calc(var(--mb-card-w, 46px) * 0.14);
}
.mb-board .board-card .c-rank { font-size: calc(var(--mb-card-w, 46px) * 0.42); }
.mb-board .board-card .c-suit { font-size: calc(var(--mb-card-w, 46px) * 0.34); }

.board-card.cd-highlight {
  outline: 2px solid var(--accent, #f2d67e);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(242, 214, 126, 0.22), 0 3px 10px rgba(0,0,0,0.38);
}

/* Newly-revealed emphasis on top of the baseline .board-card fade — a brief
   flip so the just-dealt street reads clearly without moving any card that
   was already on the felt (reduced-motion killed globally, see below). */
.board-card.cd-newly-revealed { animation: cdNewCard 420ms ease; }
/* R2 completes every F2 path (docs/F2.md §5) — a touch more emphasis than a
   routine newly-revealed card: same animation family, just a longer hold,
   never a different/flashier effect ("elegant, not arcade-like"). */
.board-card.cd-newly-revealed.f2-r2-reveal { animation-duration: 620ms; }
@keyframes cdNewCard {
  from { transform: scale(0.82) rotateY(90deg); opacity: 0; }
  60%  { transform: scale(1.04) rotateY(0deg); opacity: 1; }
  to   { transform: none; opacity: 1; }
}

/* Brief "Flop"/"Turn"/"River" flash and the point-guide trigger are anchored
   to the Board Stage itself (top: small positive inset), not the board
   contents — the board can be taller than the stage on very short viewports,
   and anchoring to the overflowing element pushed these off-screen there. */
.cd-street-flash {
  position: absolute;
  top: 4px; left: 50%;
  transform: translateX(-50%);
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #f2d67e;
  text-shadow: 0 2px 12px rgba(0,0,0,0.6);
  pointer-events: none;
  opacity: 0;
  white-space: nowrap;
  z-index: 5;
}
.cd-street-flash.show { animation: cdStreetFlash 1.1s ease; }
@keyframes cdStreetFlash {
  0%   { opacity: 0; transform: translateX(-50%) translateY(6px); }
  18%  { opacity: 1; transform: translateX(-50%) translateY(0); }
  70%  { opacity: 1; }
  100% { opacity: 0; }
}

.cd-guide-box { max-width: 420px; }
.cd-guide-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.cd-guide-row:last-of-type { border-bottom: none; }
.cd-guide-label { font-weight: 800; color: #f2d67e; font-size: 0.85rem; }
.cd-guide-detail { color: var(--muted); font-size: 0.78rem; }

.pill-bet { font-size: 0.62rem; color: #fde68a; margin-top: 1px; font-weight: 600; }

/* ── Countdown table layout priority (spec §12) ──────────────────────────────
   .app's direct children are topbar / table-wrap (opp strip → board → hand,
   already in priority order) / coach-bar / action-bar. Betting controls must
   outrank the coach/log strip, so swap their order — no DOM move needed,
   table-wrap's own internal order already matches board→hand→opponents. */
.app.cd-mode .action-bar { order: 1; }
.app.cd-mode .coach-bar  { order: 2; }

/* Secondary info (spec §15): coach chips are the one permanently-visible
   piece of "analysis" — keep it to a single scrollable line so a wide point
   count (Countdown has 5, HLH has 3) can never grow tall enough to shrink
   the board/hand above it. Hand Log and the Point Guide are already on-
   demand overlays, not part of the main table. */
.app.cd-mode .coach-chips {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.app.cd-mode .coach-chips::-webkit-scrollbar { display: none; }
.app.cd-mode .pt-chip { flex-shrink: 0; }

/* Multi-row boards (Countdown's 4-row triangle, F2's twin rows) need real
   vertical room — the stage grows to fit its content but stays capped so the
   hero hand and actions never leave the screen. F2's card size is computed
   by its renderer from the stage box; Countdown still uses fixed sizes. */
.app.f2-mode .board-stage,
.app.mb-mode .board-stage {
  max-height: min(48dvh, 420px);
}
/* Countdown's 4-row triangle is fixed-size (not dynamically fit like F2's),
   so unlike f2-mode/mb-mode it needs min-height, not just a max-height cap —
   otherwise aspect-ratio never grows the stage enough and the bottom rows
   render underneath the hero hand panel instead of inside the felt. Same
   fix already proven for Triple Board's 3 rows (.mb3-mode below). */
.app.cd-mode .board-stage {
  max-height: min(48dvh, 420px);
  min-height: min(48dvh, 420px);
}
/* Triple Board's 3 rows: the stage's aspect-ratio never grows to fit taller
   content (only shrinks it), so 2 rows' shared budget above left the top
   divider creeping up under the top-center seat avatar. min-height forces
   real growth here, not just a higher ceiling. */
.app.mb3-mode .board-stage {
  max-height: min(58dvh, 480px);
  min-height: min(58dvh, 480px);
}
/* Short screens: card size is already handled responsively by fitCardBox
   (factors available height in) — only gaps need to tighten further here.
   Applied to the shared tokens so every multi-board variant (mb-board,
   f2-board, cd-board) shrinks together instead of only Countdown tightening
   while HLH/DBBP/TBBP stay at full size — that mismatch was the visible
   "inconsistent spacing" reported when comparing variants on one screen. */
@media (max-height: 700px) {
  :root {
    --board-row-gap:  4px;
    --board-card-gap: 6px;
  }
}

/* ── Countdown Hero Hand Tray (spec §11) ────────────────────────────────────── */
.seat-card.cd-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  min-width: 0;
  max-width: none;
  padding: 10px 14px 12px;
}
.cd-hero-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cd-hero-head strong { font-size: 0.85rem; font-weight: 700; }
.cd-hero-stack { font-size: 0.74rem; color: var(--accent); font-weight: 700; margin-left: 2px; }

/* ── Board Cards ────────────────────────────────────────────────────────────── */
.board-card {
  width: 50px;
  height: 72px;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  line-height: 1.05;
  gap: 2px;
  background: var(--card-face);
  border: 1px solid rgba(0,0,0,0.1);
  box-shadow: 0 3px 10px rgba(0,0,0,0.38), inset 0 1px 0 rgba(255,255,255,0.85);
  transition: transform 0.18s ease;
}
.board-card:hover { transform: translateY(-3px); }

/* Single flat board (default renderer): card size computed from the stage's
   real box into --board-card-w/--board-card-h — simple games get the
   largest cards. */
.community-cards.single-board { gap: 6px; }
.single-board .board-card {
  width: var(--board-card-w, 50px);
  height: var(--board-card-h, calc(var(--board-card-w, 50px) * 1.43));
  border-radius: calc(var(--board-card-w, 50px) * 0.14);
}
.single-board .board-card .c-rank { font-size: calc(var(--board-card-w, 50px) * 0.42); }
.single-board .board-card .c-suit { font-size: calc(var(--board-card-w, 50px) * 0.34); }
/* Rank is the primary element; the suit sits smaller beneath it */
.board-card .c-rank { font-size: 1.18rem; letter-spacing: -0.02em; }
.board-card .c-suit { font-size: 0.92rem; }

.board-card.s-spades   { color: var(--spade); }
.board-card.s-hearts   { color: var(--heart); }
.board-card.s-diamonds { color: var(--diamond); }
.board-card.s-clubs    { color: var(--club); }
.board-card.placeholder {
  background: rgba(0,0,0,0.2);
  border: 1.5px dashed var(--tt-f2-slot-border);
  box-shadow: none;
}

/* ── Hero Zone (protected region: nothing may ever overlap the hero's cards) ── */
.seat--hero {
  position: relative;
  align-self: center;
  flex-shrink: 0;
  width: 100%;
}
.hero-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 2px 0 6px;
  transition: opacity 0.25s;
}
.hero-zone.is-folded { opacity: 0.4; filter: grayscale(0.8); }
.hero-zone.is-active .hero-id { color: var(--tt-gold); }
.hero-id {
  display: flex;
  align-items: center;
  /* 9px, not 6px: #auroraPuck (26px, the visible "D" marker) is centered on
     .d-badge's own invisible (visibility:hidden, aurora-components.css)
     reserved slot, which is only 20px wide — a fixed 3px overflow past that
     slot on each side no matter the gap. At 6px this measured (Puppeteer)
     to a 1px real gap between "You" and the puck — technically not
     overlapping, but tight enough to read as clipped and confirmed fragile
     across font-rendering differences. 9px gives real breathing room. */
  gap: 9px;
  font-size: 0.82rem;
}
.hero-id strong { font-weight: 700; }
/* Empty placeholder in the hero-id-timer's old avatar slot — reserves flex
   space only, #timerWrap visually overlays it (see aurora-table.js's
   updateHeroTimerPosition()). Invisible by design: the timer ring is the
   only thing that should paint here. */
.hero-id-timer-slot {
  width: 28px;
  height: 28px;
  flex: none;
}
.hero-chips {
  color: var(--tt-gold);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
  margin-left: 4px;
}

/* ── Player count selector ──────────────────────────────────────────────────── */
.player-count-select {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 10px;
  background: rgba(10,20,40,0.96);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  min-width: 90px;
  text-align: center;
}

/* ── Raise sizing: slider + preset snaps ────────────────────────────────────── */
.raise-sizing {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
  margin-bottom: 2px;
  width: 100%;
  max-width: 340px;
}
.raise-sizing.hidden { display: none; }

.raise-slider-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.raise-amt {
  font-size: 0.8rem;
  font-weight: 800;
  color: #fde68a;
  min-width: 46px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
#raiseSlider {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 28px; /* generous touch strip */
  background: transparent;
  cursor: pointer;
}
#raiseSlider::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(90deg, rgba(253,230,138,0.25), rgba(253,230,138,0.55));
}
#raiseSlider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin-top: -8px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff3c4, #e5a800);
  border: 2px solid #7c3205;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
}
#raiseSlider::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: rgba(253,230,138,0.35);
}
#raiseSlider::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff3c4, #e5a800);
  border: 2px solid #7c3205;
}

.raise-minmax-row {
  display: flex;
  justify-content: space-between;
  width: 100%;
  padding: 0 4px;
  font-size: 0.68rem;
  font-weight: 600;
  color: rgba(253,230,138,0.75);
}

/* All-in announce (first draft, 2026-07-18 — Arun expects to iterate on
   the exact visual treatment later; this captures the direction: recolor
   + glow rather than the confirm button's text-only "All In" swap that
   existed before). Toggled on #raiseSizing by updateRaiseLabel() in app.js
   whenever the selected slider amount would leave the hero's stack at 0 —
   not only at the slider's max, since dragging to the max is the common
   way to reach it but isn't the only one. Reuses --accent (the same gold
   the static ALL-IN pill-tag already uses, see .pill-tag.tag-allin) at
   full saturation + a pulse, deliberately brighter than the raise
   button/slider's own muted tan-gold so it still reads as a distinct
   state rather than blending into the always-gold sizing panel. (The
   static ALL-IN pill-tag this originally matched was superseded by the
   persistent .action-pill--allin treatment — see below.) */
@keyframes raiseSizingAllinPulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255,215,0,0.55), 0 0 10px rgba(255,215,0,0.35); }
  50%      { box-shadow: 0 0 0 1px rgba(255,215,0,0.85), 0 0 18px rgba(255,215,0,0.65); }
}
.raise-sizing--allin #raiseSlider::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, rgba(255,215,0,0.55), var(--accent));
}
.raise-sizing--allin #raiseSlider::-moz-range-track {
  background: linear-gradient(90deg, rgba(255,215,0,0.55), var(--accent));
}
.raise-sizing--allin #raiseSlider::-webkit-slider-thumb {
  background: radial-gradient(circle at 35% 35%, #fff9d6, var(--accent));
  border-color: #7c5e00;
  animation: raiseSizingAllinPulse 1.1s ease-in-out infinite;
}
.raise-sizing--allin #raiseSlider::-moz-range-thumb {
  background: radial-gradient(circle at 35% 35%, #fff9d6, var(--accent));
  border-color: #7c5e00;
}
.raise-sizing--allin .raise-amt { color: var(--accent); }
.raise-sizing--allin .raise-confirm {
  background: linear-gradient(160deg, #fff3c4, var(--accent)) !important;
  color: #241c04 !important;
  animation: raiseSizingAllinPulse 1.1s ease-in-out infinite;
}

/* Back sits in normal flow beside Confirm — small width vs. Confirm's
   flex:1 gives it clear secondary weight without any absolute positioning
   (which risked overlapping neighboring dock content at compact sizes). It
   is deliberately not a .btn-act: it must never read as a 4th primary
   action alongside Fold/Check/Call/Bet/Raise. */
.raise-confirm-row {
  display: flex;
  gap: 8px;
  width: 100%;
  margin-top: 2px;
}
.raise-back {
  flex: 0 0 44px;
  min-height: 44px;
  border-radius: 999px;
  border: 1px solid rgba(253,230,138,0.3);
  background: rgba(124,50,5,0.35);
  color: #fde68a;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.raise-back:active { transform: scale(0.92); }

/* The one confirmation button for the sizing state — reads "Bet X",
   "Raise to X" or "All In" (see updateRaiseLabel in app.js). */
.raise-confirm {
  flex: 1;
}

/* ── Opponent Rail ──────────────────────────────────────────────────────────────
   One compact horizontal rail — the only place opponents live. No card backs
   during play: avatar, name, chips and state badges carry everything. */
.opp-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  align-content: flex-start;
  width: 100%;
  padding: 2px 4px 0;
  flex-shrink: 0; /* protected: never crushed by the stage */
}

.opp-pill {
  position: relative;
  background: var(--tt-seat-surface);
  border: 1px solid var(--tt-seat-border);
  border-radius: 12px;
  padding: 5px 9px;
  min-width: 70px;
  /* Seats are absolutely positioned (aurora-table.js layoutSeats()) at fixed
     percentages assuming a compact pill — with no cap, a showdown reveal of
     a big ESG hand (7-10 cards, .pill-cards had no wrap/width limit either)
     let the pill balloon wide enough to visually merge into the neighboring
     seat's box, and clip off-screen entirely at the rail's outer seats
     (owner report 2026-07-20). */
  max-width: 108px;
  text-align: center;
  transition: border-color 0.25s, box-shadow 0.25s, opacity 0.25s;
}
.opp-pill [hidden] { display: none !important; }
.opp-pill.is-active {
  border-color: var(--tt-gold);
  box-shadow: 0 0 14px var(--tt-gold-glow);
}
.opp-pill.is-folded { opacity: 0.4; filter: grayscale(0.8); }
.opp-pill.is-allin  { border-color: rgba(239,68,68,0.55); }

/* ESG grant: the pill flashes and a transient +N badge appears — replaces the
   old card-back glow (there are no backs on the rail anymore) */
.opp-pill.pill-esg-flash { animation: esgCardGlow 1.2s ease; }
.pill-esg-plus {
  position: absolute;
  top: -7px;
  right: -4px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--tt-gold);
  color: #241c04;
  font-size: 0.62rem;
  font-weight: 800;
  animation: fadeIn 0.25s ease;
  pointer-events: none;
}

.pill-top {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}
.pill-top strong { font-size: 0.72rem; font-weight: 700; }
.pill-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1.5px solid var(--tt-avatar-ring);
  background: var(--tt-avatar-bg);
  object-fit: cover;
  object-position: 50% 40%;
  flex-shrink: 0;
}
.pill-stack { font-size: 0.66rem; color: var(--accent); margin-top: 1px; }
.pill-tag {
  font-size: 0.5rem;
  font-weight: 800;
  padding: 1px 4px;
  border-radius: 3px;
  letter-spacing: 0.06em;
}
/* Directive 1.4 (Aurora Table Geometry v2, 2026-07-23): opponent hand backs
   never wrap to a second row — hand size must never affect seat geometry.
   Was flex-wrap:wrap, which let 6+ cards spill onto a second line and grow
   the pod taller (the exact thing layoutSeats()'s flat-row geometry assumes
   pods don't do). engine.js caps every variant's holeCardCount at 5
   (checked all six), so the 6-7/8+ compression tiers below are defensive,
   not exercised by anything reachable today. */
.pill-cards { display: flex; flex-wrap: nowrap; gap: 2px; justify-content: center; margin-top: 3px; }
.pill-cards:has(.pill-card-back:nth-child(6)) { gap: 1px; }
.pill-cards:has(.pill-card-back:nth-child(6)) .pill-card-back { width: 11px; }
.pill-cards:has(.pill-card-back:nth-child(8)) .pill-card-back {
  width: 9px;
  margin-left: -4px;
}
.pill-cards:has(.pill-card-back:nth-child(8)) .pill-card-back:first-child { margin-left: 0; }

/* ── Action Pill — persistent per-seat action history (current street) ────
   Opponents: absolutely positioned below the pill, in the old ephemeral
   badge's footprint. Hero: a normal flex child — its own row in
   .hero-zone / .seat-card.cd-hero's column layout, never absolutely
   positioned over hole cards or betting controls. Visible only for the
   street it happened on, EXCEPT all-in (dimmed, carried forward — still a
   live seat eligible to win) — see HLHEngine.resetStreetPills() in
   engine.js and actionPillData()'s isPastStreet in app.js. */
.action-pill {
  display: inline-block;
  max-width: 108px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
  border: 1px solid transparent;
}
.opp-pill .action-pill {
  position: absolute;
  left: 50%;
  /* -9px put the pill's own top edge above .pill-stack's bottom edge (the
     pill's rendered height is taller than the offset that was supposed to
     hang it below the pod), so it visually overlapped the stack number
     instead of clearing it — bumped enough to leave real breathing room
     (owner report 2026-07-22). Verify empirically (Puppeteer rect
     comparison) before changing again — see the mobile override below for
     the shorter-pill/tighter-padding case. */
  bottom: -20px;
  translate: -50% 0;
  z-index: 60;
  pointer-events: none;
}
/* .action-pill's own `display: inline-block` above is an AUTHOR rule, so it
   always wins the cascade over the browser's default `[hidden] { display:
   none }` (UA-origin, lower priority regardless of specificity) — setting
   the DOM `hidden` attribute alone does nothing once ANY author rule
   targets that element's display. .opp-pill already carried the matching
   `!important` override below; .hero-id (the hero's own pill row) never
   got the equivalent, so app.js's `pillEl.hidden = true` silently failed to
   hide hero's pill — it kept showing whatever text was last painted onto
   it until the seat's next real action overwrote it (owner report,
   2026-08-05: a "CALL ALL-IN" pill sitting there with no live pill in
   eng.actionPills — confirmed via a live debug readout of the raw data). */
.hero-id [hidden] { display: none !important; }
/* Countdown variant's hero pill lives in its own separate markup
   (countdown-ui.js's cdHeroSkeleton()/updateCdHero(), predates
   heroZoneShell() — see that file's own comment) but calls the SAME
   updateActionPill()/actionPillData(), so it needs the identical override. */
.cd-hero-head [hidden] { display: none !important; }
.action-pill--hero {
  position: static;
  max-width: none;
}

@keyframes actionPillPop {
  0%   { opacity: 0; scale: .92; }
  60%  { opacity: 1; scale: 1.02; }
  100% { opacity: 1; scale: 1; }
}
.action-pill--pop { animation: actionPillPop 220ms cubic-bezier(.22,.82,.26,1) both; }
@media (prefers-reduced-motion: reduce) {
  .action-pill--pop { animation: none; }
}

/* Hero's own pill, shown while the action buttons are back up for a NEW
   decision this same street (owner bug report: a leftover "CALL 147" pill
   next to a fresh "Call 97" button read as two conflicting numbers for the
   same live requirement). Dimming — not new text — marks it as history:
   the live button is always the current truth. See updateActionPill()
   in app.js for the isStaleHeroTurn condition. */
.action-pill--past { opacity: 0.5; }

/* Colour reinforces the label text, it never stands alone — every state
   above also carries its own wording (CHECK/CALL/BET/RAISE/3-BET/FOLD). */
.action-pill--fold     { background: rgba(100,116,139,0.22); color: #cbd5e1; border-color: rgba(148,163,184,0.3); }
.action-pill--check    { background: rgba(71,85,105,0.26);   color: #e2e8f0; border-color: rgba(148,163,184,0.28); }
.action-pill--call     { background: rgba(76,143,232,0.24);  color: #dbe9fd; border-color: rgba(76,143,232,0.5); }
.action-pill--bet      { background: rgba(67,173,109,0.26);  color: #d3f5e0; border-color: rgba(67,173,109,0.55); }
.action-pill--raise    { background: rgba(240,146,44,0.28);  color: #ffe6c7; border-color: rgba(240,146,44,0.6); }
.action-pill--threebet { background: rgba(217,75,82,0.30);   color: #ffd8d8; border-color: rgba(217,75,82,0.62); }
.action-pill--allin {
  background: linear-gradient(180deg, #a8232c, #6e1218);
  color: #fff3f3;
  border-color: rgba(255,255,255,0.22);
  box-shadow: 0 2px 8px rgba(110,18,24,0.5);
}

/* Current aggressor — brighter, gold-outlined, slightly elevated. Only ever
   applied to a bet/raise/3-BET/BET ALL-IN/RAISE ALL-IN pill (see
   isAggressive in computeActionPill(), engine.js) — calling all-in never
   claims this highlight. Never the only signal: the label text itself
   always states the action underneath. */
.action-pill.action-pill--aggressor {
  border-color: var(--tt-gold);
  box-shadow: 0 0 10px var(--tt-gold-glow), 0 3px 8px rgba(0,0,0,0.35);
  filter: brightness(1.08);
}
.opp-pill .action-pill.action-pill--aggressor { translate: -50% -2px; }
.action-pill--hero.action-pill--aggressor { transform: translateY(-1px); }

/* Face-down backs: DOM exists whenever a player holds cards (so Aurora
   Motion's deal animation has [data-hole-index] targets to fly onto) but
   stays visually collapsed except during the dealing beat itself — the
   opponent rail's "no card backs during play" design (normalPillInner)
   is otherwise unchanged; see updateOppPill's comment. */
.pill-cards.pill-cards--backs { display: none; }
body.aurora-hand-dealing .pill-cards.pill-cards--backs { display: flex; }
.pill-card-back {
  width: 14px;
  height: 20px;
  border-radius: 3px;
  background:
    repeating-linear-gradient(45deg, rgba(233,223,198,0.14) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-45deg, rgba(233,223,198,0.14) 0 1px, transparent 1px 3px),
    linear-gradient(155deg, var(--card-back-hi) 0%, var(--card-back-lo) 100%);
  border: 1px solid var(--card-back-border);
  box-shadow: 0 2px 5px rgba(0,0,0,0.45);
}

/* ── Seat Open (multiplayer host removal + late-join spectating) ──────────── */
.opp-pill--open {
  border-style: dashed;
  border-color: var(--tt-gold-dim);
  background: rgba(0,0,0,0.2);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-height: 48px; justify-content: center;
}
.pill-open-badge {
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.05em;
  color: rgba(242,234,214,0.6); text-transform: uppercase;
}
.pill-claim-btn {
  background: linear-gradient(180deg, var(--tt-gold), #a9803a);
  color: #241c04; font-weight: 700; font-size: 0.66rem;
  border: none; border-radius: 999px; padding: 4px 12px; cursor: pointer;
}
.pill-remove-btn {
  position: absolute; top: -6px; right: -6px;
  width: 18px; height: 18px; line-height: 16px; padding: 0;
  border-radius: 50%; border: 1px solid rgba(239,68,68,0.45);
  background: rgba(30,10,10,0.9); color: #ef4444;
  font-size: 0.6rem; cursor: pointer;
}

/* ── Spectating (late-join backlog) ────────────────────────────────────────── */
.hero-zone--spectator {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: var(--tt-seat-surface);
  border: 1px dashed var(--tt-seat-border);
  border-radius: 12px;
}
.spectator-icon { font-size: 1.3rem; }
.spectator-copy strong { color: var(--tt-gold); font-size: 0.85rem; }
.spectator-copy p { margin: 2px 0 0; color: var(--muted); font-size: 0.72rem; }

/* ── Inline showdown cards (overlay + pills) ────────────────────────────────── */
.sd-card {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 1px 4px;
  border-radius: 4px;
  font-size: 0.66rem;
  font-weight: 800;
  line-height: 1.3;
  margin: 0 1px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.sd-card b { font-weight: 800; font-size: 1.12em; }
.sd-card { background: var(--card-face); border: 1px solid rgba(0,0,0,0.08); }
.sd-card.s-spades   { color: var(--spade); }
.sd-card.s-hearts   { color: var(--heart); }
.sd-card.s-diamonds { color: var(--diamond); }
.sd-card.s-clubs    { color: var(--club); }

.sd-board {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin: 4px 0 22px;
  padding: 8px 0;
}
.sd-board .sd-card { font-size: 1.05rem; padding: 9px 11px; border-radius: 8px; }

/* ── Seat Card ──────────────────────────────────────────────────────────────── */
.seat-card {
  background: var(--tt-seat-surface);
  border: 1px solid var(--tt-seat-border);
  border-radius: 14px;
  padding: 7px 10px 6px;
  min-width: 100px;
  max-width: 240px;
  box-shadow: var(--tt-seat-shadow);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transition: border-color 0.25s, box-shadow 0.25s, opacity 0.25s;
}

.seat-card.is-active {
  border-color: var(--tt-seat-border-active);
  box-shadow: 0 0 16px var(--tt-gold-glow), var(--tt-seat-shadow);
}
.seat-card.is-folded {
  opacity: 0.35;
  filter: grayscale(0.8);
}
.seat-card.is-hero {
  border-color: rgba(100,160,255,0.35);
  min-width: 170px;
}

.seat-name {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 2px;
}
.seat-name strong { font-size: 0.82rem; font-weight: 700; }

.d-badge {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff, #ccc);
  color: #111;
  font-size: 0.62rem;
  font-weight: 900;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid #999;
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}

/* Legibility pass (2026-07-29, owner report — "the font is so light, I
   can't see it on a small screen"): --muted (#7a90b8, a desaturated
   blue-grey) at 0.6rem/400-weight on a near-invisible 7%-alpha background
   read as a ghost, especially over a photo avatar. Switched to --text
   (near-white, same as every other high-priority label in this UI) at
   800-weight with an opaque-ish bordered chip background — same "solid
   pill" language .action-pill already uses for FOLD/CHECK/CALL (which was
   never the complaint), not a bespoke style. Deliberately NOT gold/
   --accent: that's the dealer puck's own color language one badge over —
   reusing it here would make SB/BB read as "another dealer signal"
   instead of a distinct one. */
.pos-label {
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text);
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(6,12,24,0.82);
  border: 1px solid rgba(238,244,255,0.32);
}

/* Opponent pills only: taken out of .pill-top's flex flow entirely, same
   "measure and overlay" corner-badge technique .pill-esg-plus already uses
   on this element (position:relative is already set on .opp-pill above).
   Found 2026-07-28: in-flow (like the hero's own .pos-label) wrapped
   .pill-top onto a second line at the narrowest viewports — .pill-top had
   zero spare width there — which grew the whole pill's measured height and
   pushed avatars off the top of the screen (caught by
   test/visual/run.js's countdown_full_triangle fixture, 7/10 viewports
   regressed before this was made absolute). Left corner since
   .pill-esg-plus already owns the top-right corner. */
.opp-pill .pos-label {
  position: absolute;
  top: -6px;
  left: -4px;
  pointer-events: none;
}

.seat-chips {
  font-size: 0.7rem;
  color: var(--accent);
  letter-spacing: 0.04em;
  margin-bottom: 5px;
}

/* ── Hand Fan ───────────────────────────────────────────────────────────────── */
.hand-fan {
  position: relative;
  height: 60px;
  min-width: 90px;
  max-width: 220px;
}

/* Directive 3.4 (Aurora Table Geometry v2): hero cards may overlap the left
   dock (#auroraGameDock, z-index:180, aurora-experience-layer.css) —
   intentional, not accidental. Nothing interactive lives under where the
   fan can reach (Game Info/End-Change sit lower in the dock's own column),
   so a higher z-index here is safe to let win. */
.hand-fan--hero { z-index: 190; }

.card-in-fan {
  position: absolute;
  bottom: 0;
  transform-origin: bottom center;
}

/* ── Mini Cards (in hands) ──────────────────────────────────────────────────── */
.mini-card {
  width: 28px;
  height: 44px;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  gap: 0;
  box-shadow: 0 3px 8px rgba(0,0,0,0.35);
  border: 1px solid rgba(0,0,0,0.12);
}
.mini-card { background: var(--card-face); }
.mini-card .m-rank { font-size: 0.8rem; line-height: 1.05; letter-spacing: -0.02em; }
.mini-card .m-suit { font-size: 0.7rem; line-height: 1; margin-top: 1px; }

.mini-card.s-spades   { color: var(--spade); }
.mini-card.s-hearts   { color: var(--heart); }
.mini-card.s-diamonds { color: var(--diamond); }
.mini-card.s-clubs    { color: var(--club); }
.mini-card.card-back {
  background:
    repeating-linear-gradient(45deg, rgba(233,223,198,0.14) 0 1.5px, transparent 1.5px 5px),
    repeating-linear-gradient(-45deg, rgba(233,223,198,0.14) 0 1.5px, transparent 1.5px 5px),
    linear-gradient(155deg, var(--card-back-hi) 0%, var(--card-back-lo) 100%);
  border: 1px solid var(--card-back-border);
  box-shadow: 0 3px 10px rgba(0,0,0,0.5);
}

/* ── Action Bar ─────────────────────────────────────────────────────────────── */
.action-bar {
  min-height: 60px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 14px;
  gap: 10px;
  background: rgba(0,0,0,0.68);
  border-top: 2px solid rgba(255,255,255,0.06);
  transition: border-color 0.3s, box-shadow 0.3s, background 0.3s;
}

/* Pulse the border gold when it's the hero's turn */
.action-bar.is-your-turn {
  border-top-color: rgba(255,215,0,0.7);
  background: rgba(0,0,0,0.82);
  box-shadow: 0 -4px 22px rgba(255,215,0,0.14);
  animation: border-pulse 1.6s ease-in-out infinite;
}

@keyframes border-pulse {
  0%, 100% { border-top-color: rgba(255,215,0,0.45); }
  50%       { border-top-color: rgba(255,215,0,0.9); }
}

/* "Your turn" is communicated by the gold action-bar border and the timer
   ring — a blinking label added noise, not information. Kept in the DOM for
   screen readers only. */
.your-turn-label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
@keyframes label-blink {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.35; }
}

.action-log-area {
  flex: 1;
  min-width: 0;
  font-size: 0.75rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: none; /* hidden on mobile; shown on desktop via media query */
}

.action-btns-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.action-btns { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.action-btns.hidden { visibility: hidden; pointer-events: none; }

.btn-act {
  padding: 11px 18px;
  border: none;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  letter-spacing: 0.03em;
  transition: transform 0.1s, box-shadow 0.1s;
  min-width: 72px;
  min-height: 44px; /* iOS minimum tap target */
}
.btn-act:active { transform: scale(0.94); }
/* Traffic-light action semantics: the eye finds decisions instantly */
.btn-act.fold  { background: linear-gradient(160deg, var(--tt-btn-fold-from), var(--tt-btn-fold-to)); color: var(--tt-btn-fold-text); }
.btn-act.check { background: linear-gradient(160deg, var(--tt-btn-check-from), var(--tt-btn-check-to)); color: var(--tt-btn-check-text); }
.btn-act.call  { background: linear-gradient(160deg, var(--tt-btn-call-from), var(--tt-btn-call-to)); color: var(--tt-btn-call-text); }
.btn-act.raise { background: linear-gradient(160deg, var(--tt-btn-raise-from), var(--tt-btn-raise-to)); color: var(--tt-btn-raise-text); }

.timer-area {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

/* ── Timer ──────────────────────────────────────────────────────────────────── */
.timer-wrap {
  position: relative;
  width: 42px;
  height: 42px;
}
.timer-wrap.hidden { visibility: hidden; }

.tsv {
  width: 42px;
  height: 42px;
  transform: rotate(-90deg);
  display: block;
}
.t-bg   { fill: none; stroke: var(--tt-timer-track); stroke-width: 3.5; }
.t-ring { fill: none; stroke: var(--tt-timer-normal); stroke-width: 3.5; stroke-linecap: round; }
.t-ring.urgent { stroke: var(--tt-timer-urgent); }

.t-num {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text);
}

/* ── Showdown Overlay ───────────────────────────────────────────────────────── */
.sd-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.82);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 140; /* above #dealerSeat's 130 (aurora-table.css) — the showdown
    modal must sit above the permanent dealer avatar, not behind it */
  animation: fadeIn 0.25s ease;
}
@keyframes fadeIn { from { opacity:0 } to { opacity:1 } }

.sd-box {
  background: #0b1526;
  border: 1px solid rgba(255,215,0,0.3);
  border-radius: 20px;
  padding: 28px 32px;
  min-width: 320px;
  max-width: 440px;
  width: 92vw;
  text-align: center;
  box-shadow: 0 0 60px rgba(255,215,0,0.12);
}
.sd-box h2 {
  font-size: 1.3rem;
  color: var(--accent);
  margin-bottom: 18px;
  letter-spacing: 0.02em;
}

.sd-note { font-size: 0.78rem; color: var(--muted); margin-top: 14px; }

/* ── Fold-win celebration (owner spec 2026-07-23, mockup round 2) ───────────
   A lighter scrim than the recap's blackout above — a fold-win has no card
   reveal to hide the table for, so the felt stays visible behind the card. */
.sd-overlay--fw { background: rgba(6,12,24,0.4); transition: opacity 0.3s ease; }
.sd-overlay--fw.fw-out { opacity: 0; }
.sd-box--fw { padding: 22px 30px; }
.sd-box--fw .fw-trophy { font-size: 1.4rem; margin-bottom: 2px; }
.sd-box--fw h2.fw-head { margin-bottom: 4px; }
.sd-box--fw .fw-sub { margin-top: 0; }
.sd-box--fw .fw-sub b { color: var(--success); }
/* beta-hygiene-v1.css's `@media (orientation: landscape)` block stretches
   .sd-overlay/.sd-box edge-to-edge for the full showdown recap (it needs the
   room for its carousel/tabs) — this app is landscape-only, so that rule is
   always live and would otherwise swallow the fold-win card whole, leaving
   no felt visible behind it (the entire point of the lighter scrim above).
   3-class selectors here (0,0,3,0) outrank that file's `.sd-overlay > .sd-box`
   (0,0,2,0) regardless of load order, so this wins without touching that file. */
@media (orientation: landscape) {
  .sd-overlay.sd-overlay--fw {
    align-items: center;
    justify-content: center;
    padding: 0;
  }
  .sd-overlay--fw .sd-box.sd-box--fw {
    width: auto;
    height: auto;
    max-width: 460px;
    max-height: 88dvh;
    border-radius: 20px;
  }
}
/* Online: no button, just a status line + a timed fill bar standing in for
   the auto-deal — see fwActionsHTML()/wireFwActions() in app.js. */
.fw-wait { font-size: 0.72rem; color: var(--muted); font-weight: 700; letter-spacing: 0.02em; margin-top: 16px; }
.fw-bar-track { width: 150px; height: 3px; border-radius: 2px; background: rgba(255,255,255,0.1); margin: 8px auto 0; overflow: hidden; }
.fw-bar-fill { width: 0%; height: 100%; background: var(--tt-gold-dim); transition: width 2.3s linear; }
/* Practice/AI: two one-tap actions, sharing showdown-shell.css's .sd2-quick-*
   look — #fwRepeat gets the same "first among equals" gold tint as
   ShowdownV2's own #sd2QuickRepeat. */
#fwRepeat { border-color: var(--tt-gold-dim); background: rgba(201,160,74,0.14); color: var(--tt-gold); }

.btn-sd-next {
  margin-top: 20px;
  padding: 11px 28px;
  background: linear-gradient(135deg, #ffd700, #e5a800);
  color: #1a0800;
  font-weight: 800;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.86rem;
  transition: transform 0.12s;
}
.btn-sd-next:hover { transform: translateY(-1px); }

.sd-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 18px;
}
/* .btn-sd-next's global margin-top must not leak into the flex row — it was
   staggering Deal Next Round 20px below AI Hand Analysis (owner-flagged). */
.sd-actions .btn-sd-next { margin-top: 0; }

.btn-ai-analysis {
  padding: 11px 20px;
  background: rgba(100,150,255,0.15);
  border: 1px solid rgba(100,150,255,0.4);
  color: #93c5fd;
  font-weight: 700;
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.84rem;
  transition: background 0.15s;
}
.btn-ai-analysis:hover { background: rgba(100,150,255,0.28); }

/* Online recap "Exit Table" (owner request 2026-07-27) — online mode had no
   exit affordance at all on either recap screen; same danger-red tone as
   the Assistant panel's "Quit Game Now" row (aurora-experience-layer.css)
   for a consistent "this leaves the table" visual language. */
.btn-sd-exit {
  padding: 11px 20px;
  background: rgba(239,68,68,0.14);
  border: 1px solid rgba(239,68,68,0.4);
  color: #f7a8a8;
  font-weight: 700;
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.84rem;
  transition: background 0.15s;
}
.btn-sd-exit:hover { background: rgba(239,68,68,0.24); }
/* Fold-win recap: no .sd-actions flex row to sit in (just the wait line +
   progress bar), so this needs its own spacing/centering. */
.btn-sd-exit--fw { display: block; margin: 14px auto 0; }

/* ── AI Analysis Overlay ──────────────────────────────────────────────── */
.ai-picker {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.ai-pick-btn {
  padding: 5px 14px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 999px;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 600;
  transition: background 0.15s;
}
.ai-pick-btn.active {
  background: rgba(255,215,0,0.18);
  border-color: rgba(255,215,0,0.5);
  color: var(--accent);
}
.ai-thoughts {
  max-height: 280px;
  overflow-y: auto;
  padding: 2px 4px;
  scrollbar-width: thin;
}
.think-entry {
  margin-bottom: 14px;
  border-left: 2px solid rgba(255,215,0,0.3);
  padding-left: 10px;
}
.think-street {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--accent);
  margin-bottom: 6px;
  font-weight: 700;
}
.think-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 6px;
}
.think-table tr td {
  padding: 2px 4px;
  font-size: 0.74rem;
  color: var(--muted);
  line-height: 1.4;
  vertical-align: top;
}
.think-table tr td:first-child {
  white-space: nowrap;
}
.th-label {
  font-size: 0.62rem !important;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(255,255,255,0.45) !important;
  padding-right: 8px !important;
  min-width: 60px;
}
.think-action {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--success);
  margin-top: 4px;
  line-height: 1.4;
}
/* Traffic-light decision colours, matching the action buttons */
.think-action.act-fold  { color: #f87171; }
.think-action.act-check { color: #4ade80; }
.think-action.act-call  { color: #facc15; }
.think-action.act-raise { color: #fb923c; }

/* ── Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */

/* Wider screens: the same phone column, centered — plus the action log */
@media (min-width: 601px) {
  .action-log-area { display: block; }
}

/* Phone widths — the primary composition */
@media (max-width: 600px) {
  /* Topbar: street badge stays — it is the only street indicator now that
     the felt carries no text. */
  .street-badge { padding: 2px 8px; font-size: 0.62rem; }
  .topbar { padding: 0 10px; height: 44px; }
  .brand { display: none; } /* reclaim space for street + coach controls */
  .btn-new { padding: 6px 14px; font-size: 0.75rem; }
  .btn-coach { padding: 4px 9px; font-size: 0.64rem; }

  .table-wrap {
    padding: 4px 8px 0;
    gap: 8px;
  }
  .board-stage { padding: 14px 8px; }

  /* Player count select */
  .player-count-select { min-width: 78px; font-size: 0.68rem; padding: 4px 8px; }

  /* Board cards — the centrepiece even on small screens */
  .board-card { width: 46px; height: 66px; border-radius: 7px; }
  .board-card .c-rank { font-size: 1.05rem; }
  .board-card .c-suit { font-size: 0.85rem; }
  .community-cards { gap: 6px; }

  /* Action bar: stacked, generous touch targets */
  .action-bar { padding: 8px 10px 10px; gap: 8px; }
  .action-btns-area { flex: 1; }
  .action-btns { gap: 8px; width: 100%; }
  .btn-act {
    padding: 12px 10px;
    font-size: 0.85rem;
    min-height: 48px;
    flex: 1;
    min-width: 0;
  }
  .raise-sizing { max-width: none; }
  .raise-back { flex-basis: 48px; min-height: 48px; font-size: 1.2rem; }
  .raise-minmax-row { font-size: 0.72rem; }

  /* Timer smaller */
  .timer-wrap { width: 36px; height: 36px; }
  .tsv { width: 36px; height: 36px; }
  .t-num { font-size: 0.62rem; }

  /* Showdown overlay: fits mobile */
  .sd-box { padding: 18px 12px; max-height: 88dvh; overflow-y: auto; }
  .sd-box h2 { font-size: 1.05rem; margin-bottom: 10px; }
  .sd-used .sd-card { font-size: 0.85rem; padding: 5px 6px; }
  .sd-cat { padding: 10px 8px 8px; }
}

/* Very small phones */
@media (max-width: 375px) {
  .btn-act { padding: 9px 10px; font-size: 0.75rem; min-width: 56px; }
  .board-card { width: 40px; height: 57px; }
  .board-card .c-rank { font-size: 0.9rem; }
  .board-card .c-suit { font-size: 0.74rem; }
  .mini-card { width: 22px; height: 34px; }
}

/* Short screens (must come after the width blocks — it wins the cascade):
   the stage gives up its floor before the hero loses a pixel; everything
   else tightens. A briefly cramped board beats hidden hero cards. */
@media (max-height: 700px) {
  .board-stage { min-height: 0; padding: 8px; }
  .table-wrap { gap: 5px; }
  .hero-zone { gap: 3px; padding-bottom: 2px; }
  .opp-pill { padding: 3px 7px; min-width: 62px; }
  .pill-avatar { width: 20px; height: 20px; }
  .pill-top strong { font-size: 0.66rem; }
  .pill-stack { font-size: 0.6rem; }
  /* Crowding fallback (three adjacent seats, four-digit amounts): tighter
     padding + smaller text before ever truncating the latest action. */
  .action-pill { max-width: 92px; padding: 2px 6px; font-size: 0.52rem; }
  .opp-pill .action-pill { bottom: -17px; }
}

/* ── AI Full-Screen Analysis Overlay ─────────────────────────────────────── */
.ai-full-overlay {
  position: fixed;
  inset: 0;
  background: #060c18;
  z-index: 200;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ai-full-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-width: 680px;
  margin: 0 auto;
  width: 100%;
}
.ai-full-header {
  flex-shrink: 0;
  padding: 16px 18px 10px;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.ai-full-header h2 {
  font-size: 1.1rem;
  color: var(--accent);
  margin-bottom: 10px;
}

/* ── AI Calibration Toolkit: Save for AI Review / Review Queue ────────────── */
.ai-review-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.ai-review-header-row h2 { margin-bottom: 0; }
.ai-review-header-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.btn-ai-review-save, .btn-ai-review-queue {
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(255,255,255,0.08);
  color: var(--muted);
}
.btn-ai-review-save {
  background: rgba(34,197,94,0.18);
  border-color: rgba(34,197,94,0.4);
  color: var(--success);
}
.ai-review-save-panel {
  margin: 0 18px 12px;
  padding: 12px 14px;
  border-radius: 10px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.12);
}
.ai-review-save-title { font-size: 0.82rem; font-weight: 700; margin-bottom: 8px; color: var(--accent); }
.ai-review-tag-grid { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.ai-review-tag-chip {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.68rem;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.06);
  color: var(--muted);
  cursor: pointer;
}
.ai-review-tag-chip.active {
  background: rgba(255,215,0,0.18);
  border-color: rgba(255,215,0,0.5);
  color: var(--accent);
}
.ai-review-tag-pill {
  display: inline-block;
  padding: 2px 8px;
  margin: 2px 4px 2px 0;
  border-radius: 999px;
  font-size: 0.62rem;
  background: rgba(255,215,0,0.12);
  border: 1px solid rgba(255,215,0,0.3);
  color: var(--accent);
}
.ai-review-note-input {
  width: 100%;
  background: rgba(0,0,0,0.3);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 8px;
  color: var(--text, #fff);
  padding: 8px 10px;
  font-size: 0.78rem;
  resize: vertical;
  margin-bottom: 8px;
}
.ai-review-voice-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.ai-review-voice-status { font-size: 0.7rem; color: var(--muted); }
.ai-review-voice-playback { display: flex; align-items: center; gap: 8px; margin: 8px 0; }
.ai-review-voice-playback audio { height: 32px; max-width: 260px; }
.ai-review-save-actions { display: flex; gap: 8px; }
.ai-review-save-status { margin-top: 8px; font-size: 0.72rem; color: var(--muted); }
.ai-review-save-status.ai-review-save-ok { color: var(--success); }

.ai-review-queue-row {
  padding: 10px 12px;
  margin-bottom: 8px;
  border-radius: 10px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.1);
}
.ai-review-queue-row-main { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 4px; }
.ai-review-select-cb { width: 15px; height: 15px; accent-color: var(--accent); }
.ai-review-queue-variant { font-weight: 800; color: var(--accent); font-size: 0.78rem; }
.ai-review-queue-date, .ai-review-queue-version { font-size: 0.68rem; color: var(--muted); }
.ai-review-queue-row-tags { margin-bottom: 6px; }
.ai-review-queue-row-flags { font-size: 0.8rem; margin-bottom: 6px; }
.ai-review-queue-row-actions { display: flex; gap: 8px; }

.ai-review-detail-meta { margin-bottom: 16px; }
.ai-review-detail-subhead { font-size: 0.85rem; color: var(--accent); margin: 10px 0; }
.ai-review-decision-entry { margin-bottom: 12px; padding-left: 10px; border-left: 2px solid rgba(255,215,0,0.2); }
.ai-thoughts-full {
  flex: 1;
  overflow-y: auto;
  padding: 14px 18px;
  -webkit-overflow-scrolling: touch;
}
.ai-full-footer {
  flex-shrink: 0;
  padding: 12px 18px;
  border-top: 1px solid rgba(255,255,255,0.07);
  background: rgba(0,0,0,0.4);
  display: flex;
  justify-content: center;
}

.think-street-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.ai-badge {
  font-size: 0.58rem;
  font-weight: 800;
  padding: 2px 7px;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.ai-badge-scoop { background: rgba(34,197,94,0.2); color: var(--success); border: 1px solid rgba(34,197,94,0.4); }
.ai-badge-nut   { background: rgba(255,215,0,0.15); color: var(--accent); border: 1px solid rgba(255,215,0,0.35); }

.ai-cards-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.ai-cards-group { display: flex; flex-direction: column; gap: 4px; }
.ai-cards-label {
  font-size: 0.58rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(255,255,255,0.35);
}

/* ── Tier-1 UI: coach bar, point chips, history, steppers, showdown v2 ─────── */

/* Hand history button (topbar) */
.btn-hist {
  padding: 4px 10px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 700;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.btn-hist:hover { background: rgba(255,255,255,0.14); }

/* Per-point status chips — HIGH gold · LOW purple · HAND blue */
.pt-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  border: 1px solid;
  white-space: nowrap;
}
.pt-chip b { font-weight: 700; font-size: 0.64rem; letter-spacing: 0; }
.pt-chip.pt-high { border-color: rgba(255,215,0,0.4);  color: #ffd700; background: rgba(255,215,0,0.08); }
.pt-chip.pt-low  { border-color: rgba(192,132,252,0.4); color: #c084fc; background: rgba(192,132,252,0.08); }
.pt-chip.pt-hand { border-color: rgba(96,165,250,0.4);  color: #60a5fa; background: rgba(96,165,250,0.08); }
.pt-chip.pt-dead { border-color: rgba(239,68,68,0.4);   color: #f87171; background: rgba(239,68,68,0.08); }
.pt-chip.cat-hand { border-color: rgba(96,165,250,0.4);  color: #60a5fa; background: rgba(96,165,250,0.08); }
.pt-chip.cat-p1   { border-color: rgba(52,211,153,0.4);  color: #34d399; background: rgba(52,211,153,0.08); }
.pt-chip.cat-p2   { border-color: rgba(251,146,60,0.4);  color: #fb923c; background: rgba(251,146,60,0.08); }
.pt-chip.cat-p3   { border-color: rgba(244,114,182,0.4); color: #f472b6; background: rgba(244,114,182,0.08); }
.pt-chip.cat-p4   { border-color: rgba(34,211,238,0.4);  color: #22d3ee; background: rgba(34,211,238,0.08); }
.pt-chip.cat-h1   { border-color: rgba(255,215,0,0.4);   color: #ffd700; background: rgba(255,215,0,0.08); }
.pt-chip.cat-l1   { border-color: rgba(192,132,252,0.4); color: #c084fc; background: rgba(192,132,252,0.08); }
.pt-chip.cat-h2   { border-color: rgba(52,211,153,0.4);  color: #34d399; background: rgba(52,211,153,0.08); }
.pt-chip.cat-l2   { border-color: rgba(34,211,238,0.4);  color: #22d3ee; background: rgba(34,211,238,0.08); }

/* Mix Master coach bar */
.coach-bar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 14px;
  background: rgba(10,16,32,0.9);
  border-top: 1px solid rgba(255,255,255,0.06);
}
.coach-left { display: flex; align-items: center; gap: 8px; min-width: 0; }
.coach-name {
  flex-shrink: 0;
  font-size: 0.58rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #c084fc;
  padding: 2px 8px;
  border: 1px solid rgba(192,132,252,0.35);
  border-radius: 999px;
  background: rgba(192,132,252,0.1);
}
.coach-text {
  font-size: 0.74rem;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.coach-chips { display: flex; gap: 5px; flex-shrink: 0; }

/* Slider fine-tune steppers */
.stepper {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid rgba(253,230,138,0.35);
  background: rgba(124,50,5,0.35);
  color: #fde68a;
  font-size: 1.05rem;
  font-weight: 800;
  cursor: pointer;
  line-height: 1;
}
.stepper:active { transform: scale(0.92); }

/* Timer badge pinned to hero seat card */
.seat-card { position: relative; }
.seat-timer {
  display: none;
  position: absolute;
  top: -10px;
  right: -10px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: #0b1526;
  border: 2px solid var(--success);
  color: var(--success);
  font-size: 0.72rem;
  font-weight: 800;
  align-items: center;
  justify-content: center;
  z-index: 5;
  box-shadow: 0 2px 10px rgba(0,0,0,0.6);
}
.seat-timer.show { display: inline-flex; }
.seat-timer.urgent { border-color: var(--danger); color: var(--danger); animation: label-blink 1s step-end infinite; }

/* Hand history overlay */
.hist-box { text-align: left; }
.hist-box h2 { text-align: center; }
.hist-list { max-height: 55dvh; overflow-y: auto; }
.hist-street {
  font-size: 0.6rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--accent);
  margin: 10px 0 4px;
  border-bottom: 1px solid rgba(255,215,0,0.15);
  padding-bottom: 2px;
}
.hist-line { font-size: 0.76rem; color: var(--muted); padding: 2px 0; }

/* ── Showdown v2 ────────────────────────────────────────────────────────────── */
.sd-banner {
  background: linear-gradient(135deg, rgba(255,215,0,0.14), rgba(229,168,0,0.05));
  border: 1px solid rgba(255,215,0,0.35);
  border-radius: 14px;
  padding: 12px 16px;
  margin-bottom: 14px;
}
.sd-banner-tag {
  display: block;
  font-size: 0.58rem;
  font-weight: 900;
  letter-spacing: 0.2em;
  color: var(--accent);
  margin-bottom: 2px;
}
.sd-banner h2 { margin-bottom: 2px !important; font-size: 1.25rem; }
.sd-banner-sub { font-size: 0.78rem; color: var(--muted); font-weight: 700; }

.sd-board-label {
  font-size: 0.8rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--accent);
  text-align: center;
  margin: 4px 0 6px;
}

/* Per-category proof panels — the showdown teaches by grouping: every card
   the category could draw from, in one row, scoring 5 gold-highlighted. */
.sd-cat {
  border: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.025);
  border-radius: 16px;
  padding: 16px 14px 14px;
  margin-top: 14px;
  text-align: center;
}
.sd-cat-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  margin-bottom: 12px;
}
.sd-cat-name { font-size: 0.62rem; font-weight: 900; letter-spacing: 0.18em; }
.sd-cat.cat-high .sd-cat-name { color: #ffd700; }
.sd-cat.cat-hand .sd-cat-name { color: #60a5fa; }
.sd-cat.cat-low  .sd-cat-name { color: #c084fc; }
/* Countdown Points 1-4 (Point 5 reuses cat-hand — same "hole cards only" rule) */
.sd-cat.cat-p1 .sd-cat-name { color: #34d399; }
.sd-cat.cat-p2 .sd-cat-name { color: #fb923c; }
.sd-cat.cat-p3 .sd-cat-name { color: #f472b6; }
.sd-cat.cat-p4 .sd-cat-name { color: #22d3ee; }
/* F2: h1/h2 reuse the gold/teal high palette, l1/l2 reuse the purple/cyan low palette */
.sd-cat.cat-h1 .sd-cat-name { color: #ffd700; }
.sd-cat.cat-l1 .sd-cat-name { color: #c084fc; }
.sd-cat.cat-h2 .sd-cat-name { color: #34d399; }
.sd-cat.cat-l2 .sd-cat-name { color: #22d3ee; }
.sd-cat--empty { padding: 9px 12px; opacity: 0.7; }
.sd-cat--empty .sd-cat-head { margin-bottom: 0; }
.sd-cat-none { font-size: 0.72rem; color: var(--muted); }

/* Winner "proof" card — gold, mirrors .sd-banner's treatment */
.sd-cat-win {
  background: linear-gradient(135deg, rgba(255,215,0,0.14), rgba(229,168,0,0.05));
  border: 1px solid rgba(255,215,0,0.35);
  border-radius: 14px;
  padding: 14px 16px 16px;
}
.sd-cat-win + .sd-cat-win { margin-top: 10px; }
.sd-win-head { display: flex; align-items: center; justify-content: center; gap: 5px; }
.sd-win-trophy { font-size: 0.85rem; }
.sd-win-tag { font-size: 0.58rem; font-weight: 900; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent); }
.sd-win-name { font-weight: 800; font-size: 1.08rem; color: var(--text); margin-top: 2px; }
.sd-win-pts { font-size: 0.72rem; font-weight: 800; color: var(--accent); margin-top: 1px; }
.sd-used {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.sd-group { display: inline-flex; gap: 3px; }
.sd-used .sd-card { font-size: 1rem; padding: 7px 8px; border-radius: 7px; margin: 0; opacity: 0.5; }
.sd-used .sd-card.sd-used-card { opacity: 1; }
.sd-cat-handname { margin-top: 10px; font-weight: 800; font-size: 0.98rem; color: var(--text); }
.sd-pathname { margin-top: 2px; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; color: var(--accent); }
.sd-used-caption { margin-top: 6px; display: flex; justify-content: center; gap: 2px; flex-wrap: wrap; opacity: 0.8; }
.sd-used-caption .sd-card { font-size: 0.66rem; padding: 1px 4px; }

.sd-legend {
  margin-top: 16px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 0.64rem;
  color: var(--muted);
}
.sd-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.sd-legend-swatch { font-size: 0.6rem; padding: 2px 5px; opacity: 0.5; }
.sd-legend-swatch.sd-used-card { opacity: 1; }

.sd-others {
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,0.07);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  justify-content: center;
}
.sd-other { font-size: 0.66rem; color: var(--muted); white-space: nowrap; }
.sd-other strong { margin-right: 4px; }

/* Coach bar + chips on small screens: one scrollable row, never a second
   line of chips stealing vertical space from the hero hand above. */
@media (max-width: 600px) {
  .coach-bar { flex-direction: column; align-items: stretch; gap: 4px; padding: 5px 10px; }
  .coach-text { white-space: normal; font-size: 0.7rem; line-height: 1.3; }
  .coach-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    justify-content: flex-start;
  }
  .coach-chips::-webkit-scrollbar { display: none; }
  .coach-chips .pt-chip { flex-shrink: 0; }
}

/* ── Mobile gameplay enhancement pass (owner spec 2026-07-12) ──────────────── */

/* Hero fan — large cards, the second-loudest element after the board.
   2026-07-23: width/height/container-height now come from inline styles
   app.js's cardInFan()/updateHeroZone() set per-render (continuous tiers
   derived from the felt's real available width + viewport height — see
   heroCardWidth()/heroFanAvailWidth() — replacing the old binary 50px/31px
   switch this rule and its @media sibling below used to hard-code). These
   rules are now only the fallback for the rare case JS hasn't run yet (or
   any non-hero .mini-card use, though cardInFan() is hero-only) — kept at
   the old baseline values, not deleted, since a flash-of-unstyled-size on
   first paint is worse than a redundant CSS rule. var() reads the inline
   custom properties cardInFan() sets; falls back to the original fixed rem
   values when they're absent. */
.hand-fan--hero { height: 84px; max-width: none; }
.hand-fan--hero .mini-card { width: 50px; height: 71px; border-radius: 7px; }
.hand-fan--hero .m-rank { font-size: var(--mc-fs-rank, 1.22rem); }
.hand-fan--hero .m-suit { font-size: var(--mc-fs-suit, 0.98rem); }

/* Short landscape heights (390px and below — the shortest supported devices):
   the fan's own natural height (84px) was nearly as tall as .hero-zone's
   entire allotted box at these heights, so it had nowhere to go but bleed
   past the bottom of the viewport — worse with more ESG cards, since a wider
   fan rotates its outer cards more, enlarging the bounding box further.
   Confirmed via direct getBoundingClientRect() measurement at 844x390 (owner
   report 2026-07-20): fan bottom edge landed at y=429 against a 390px-tall
   viewport. Superseded as the active sizing path by the inline styles above
   (2026-07-23) — kept as the fallback pairing for the same reason. */
@media (max-height: 420px) {
  .hand-fan--hero { height: 53px; }
  .hand-fan--hero .mini-card { width: 31px; height: 43px; border-radius: 5px; }
  .hand-fan--hero .m-rank { font-size: var(--mc-fs-rank, 0.78rem); }
  .hand-fan--hero .m-suit { font-size: var(--mc-fs-suit, 0.62rem); }
  /* The hero-id row (avatar/name/chips) above the fan also needs to give up
     space here — shrinking the fan alone wasn't enough, the row above it was
     still tall enough to push the fan's start position past what remained. */
  .hero-zone { gap: 2px; padding: 0 0 2px; }
  .hero-id-timer-slot { width: 20px; height: 20px; }
  /* 10px, not 6px: at this breakpoint .d-badge shrinks to 10px
     (aurora-components.css) but #auroraPuck (the visible "D" marker
     centered on it) stays a fixed 26px — an 8px overflow past the badge's
     own edge on each side that a 6px gap doesn't clear, measured via
     getBoundingClientRect() as real (if narrow) "You" clipping. */
  .hero-id { font-size: 0.7rem; gap: 10px; }
}

/* All-in seat: distinctive glow, cards stay visible */
.opp-pill.is-allin {
  border-color: var(--tt-gold-dim);
  box-shadow: 0 0 12px var(--tt-gold-glow);
}

/* Current actor: stronger contrast than neighbours
   (this rule wins over the earlier .opp-pill.is-active definition — same
   specificity, later in source order) */
.opp-pill.is-active {
  background: rgba(14,24,44,0.98);
  border-color: var(--tt-gold);
  box-shadow: 0 0 16px var(--tt-gold-glow);
}

/* Dealer button: chip-style, immediately recognisable
   (this rule wins over the earlier .d-badge definition — same specificity,
   later in source order — so this is the one that actually renders) */
.d-badge {
  width: 20px;
  height: 20px;
  font-size: 0.66rem;
  background: var(--tt-dealer-bg);
  border: 1.5px solid var(--tt-dealer-border);
  box-shadow: 0 1px 5px rgba(0,0,0,0.55), 0 0 6px var(--tt-gold-glow);
}

/* Coach action word: bold, traffic-light coloured */
.coach-act { font-weight: 900; letter-spacing: 0.04em; }
.coach-act.act-fold  { color: #f87171; }
.coach-act.act-check { color: #4ade80; }
.coach-act.act-call  { color: #facc15; }
.coach-act.act-raise { color: #fb923c; }

/* Strength dots inside coach chips */
.pt-chip .dots { font-size: 0.6rem; letter-spacing: 0.08em; }

/* Timer amber stage */
.t-ring.warn { stroke: var(--tt-timer-warn); }
.seat-timer.warn { border-color: #f59e0b; color: #f59e0b; }

/* Board card reveal: subtle 200ms fade/slide */
.board-card:not(.placeholder) { animation: cardIn 200ms ease; }
@keyframes cardIn {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Accessibility: honour reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

@media (max-width: 600px) {
  /* Dealer badge prominent at mobile sizes too */
  .d-badge { width: 18px; height: 18px; font-size: 0.6rem; }

  /* Coach text: max two lines, never pushes controls off-screen */
  .coach-text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
  }

  /* Respect iPhone browser chrome */
  .action-bar { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
}

/* ── ESG card-highlight animation ─────────────────────────────────────────── */
@keyframes esgCardGlow {
  0%, 100% { box-shadow: none; }
  30%      { box-shadow: 0 0 0 3px rgba(192,132,252,0.65); }
}

/* The whole fan glows briefly when it grows from an ESG grant (opponents get
   the pill flash + transient badge instead — see .pill-esg-flash). */
.hand-fan.hand-fan--esg-glow { animation: esgCardGlow 1s ease; }

/* ── Dev-only ESG timing trace (?esgDebug=1) — never shown otherwise ────────── */
.esg-debug-overlay {
  position: fixed;
  bottom: 8px; right: 8px;
  max-width: 280px;
  max-height: 40vh;
  overflow-y: auto;
  background: rgba(0,0,0,0.82);
  border: 1px solid rgba(192,132,252,0.4);
  border-radius: 8px;
  padding: 8px 10px;
  font: 11px/1.5 ui-monospace, monospace;
  color: #e5e7eb;
  white-space: pre-wrap;
  z-index: 999;
}
.esg-debug-overlay b { color: #c084fc; }
.deal-debug-overlay { bottom: auto; top: 8px; left: 8px; right: auto; border-color: rgba(74,222,128,0.4); }
.deal-debug-overlay b { color: #4ade80; }

/* ── Home / Lobby overlay (Phase 1 multiplayer join flow) ───────────────────── */
.home-overlay {
  position: fixed; inset: 0; z-index: 300;
  background: radial-gradient(ellipse at 50% 30%, rgba(22,101,52,0.35), transparent 60%), var(--bg);
  display: flex; align-items: safe center; justify-content: center;
  padding: 16px;
  overflow-y: auto;
}
.home-overlay.hidden { display: none; }
.home-box {
  /* Wider than a portrait-derived form needs — this app is landscape-only,
     so the pre-deal flow gets to use that width instead of staying narrow
     and stacking everything vertically. */
  width: min(560px, 92vw);
  /* Bounded + independently scrollable so its own scrollTop starts at 0
     (its own top) instead of relying on .home-overlay's centered-then-
     clipped scroll, which traps the topmost child (the lobby's room
     code + Invite button) off-screen with no way to scroll up to it on
     short landscape phones. Reuses --mix-visual-viewport-h, already
     published on every page load by p0-vertical-layout-budget-v1.js. */
  max-height: min(94dvh, calc(var(--mix-visual-viewport-h, 100dvh) - 24px));
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid rgba(255,215,0,0.18);
  border-radius: 16px;
  padding: 26px 22px;
  box-shadow: 0 18px 60px rgba(0,0,0,0.55);
  text-align: center;
}
@media (orientation: landscape) and (max-height: 450px) {
  #homeOverlay .home-box { padding: 14px 16px; }
  #homeOverlay .home-step { gap: 6px; }
}
@media (orientation: landscape) and (max-height: 380px) {
  #homeOverlay .home-box { padding: 10px 14px; }
}
.home-brand {
  font-size: 1.7rem; letter-spacing: 0.04em;
  color: var(--accent);
}
.home-sub { color: var(--muted); font-size: 0.8rem; margin: 6px 0 14px; }
.research-unlock-badge {
  background: rgba(90,200,120,0.14); color: #7fe3a0;
  border: 1px solid rgba(90,200,120,0.4);
  border-radius: 8px; padding: 6px 10px;
  font-size: 0.72rem; font-weight: 600; text-align: center;
  margin: 0 0 12px;
}
.home-step { display: flex; flex-direction: column; gap: 10px; }
.home-step.hidden { display: none; }
.home-step input, .home-step select {
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--text);
  border-radius: 9px;
  padding: 11px 12px;
  font-size: 0.95rem;
  width: 100%;
  text-align: center;
}
.home-step input:focus { outline: 2px solid rgba(255,215,0,0.45); }
.home-btn {
  background: linear-gradient(180deg, #ffd700, #d4a900);
  color: #201700; font-weight: 700;
  border: none; border-radius: 9px;
  padding: 12px; font-size: 0.95rem;
  cursor: pointer; min-height: 48px;
}
.home-btn:disabled { opacity: 0.45; cursor: default; }
.home-btn-ghost {
  background: rgba(255,255,255,0.07);
  color: var(--text);
  border: 1px solid rgba(255,255,255,0.16);
}
.home-divider {
  display: flex; align-items: center; gap: 10px;
  color: var(--muted); font-size: 0.66rem;
  text-transform: uppercase; letter-spacing: 0.14em;
}
.home-divider::before, .home-divider::after {
  content: ''; flex: 1; height: 1px; background: rgba(255,255,255,0.12);
}
/* Welcome / mode select — the actual front door, replacing the old buried
   "Practice vs AI" ghost button above a divider. */
.welcome-cards {
  display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px;
}
/* Insights (Aurora Private Insights Module v1.0): owner-only, so it wraps
   onto its own full-width row below Practice/Friends rather than
   squeezing them into a cramped three-up layout on the phones this app
   targets (mobile ONLY). */
.welcome-card.insights { flex-basis: 100%; border-color: rgba(143,196,255,0.22); }
.welcome-card.insights.hidden { display: none; }
.welcome-card {
  flex: 1;
  display: flex; flex-direction: column; align-items: flex-start;
  text-align: left;
  gap: 6px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 14px;
  padding: 16px 14px;
  cursor: pointer;
  transition: border-color 0.15s, transform 0.15s, background 0.15s;
}
.welcome-card:hover { border-color: rgba(255,215,0,0.4); transform: translateY(-2px); }
.welcome-card.friends { border-color: rgba(255,215,0,0.22); }
.wc-icon { font-size: 1.5rem; }
.wc-title { font-weight: 700; color: var(--text); font-size: 0.92rem; }
.wc-desc { color: var(--muted); font-size: 0.72rem; line-height: 1.4; }

.home-back {
  align-self: flex-start;
  background: none; border: none;
  color: var(--muted); font-size: 0.76rem; font-weight: 600;
  cursor: pointer; padding: 0; margin-bottom: -2px;
}
.home-back:hover { color: var(--text); }

.home-cfg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}
.home-cfg label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 0.66rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.home-cfg input, .home-cfg select { padding: 8px; font-size: 0.85rem; }
.home-cfg-full { grid-column: 1 / -1; }
.home-join-row { display: flex; gap: 8px; }
.home-join-row input { flex: 1; text-transform: uppercase; }
.home-join-row .home-btn { width: 92px; }
.home-err { color: var(--danger); font-size: 0.78rem; min-height: 1em; }

#joinHeading.hidden { display: none; }
/* Guest-shaped join form (invite-link entry): create-table controls hidden
   entirely rather than just demoted — a guest didn't ask to create a new
   table, and Join is the only action they should see. */
#homeStep-name.guest-join .home-cfg,
#homeStep-name.guest-join #btnCreate,
#homeStep-name.guest-join .home-divider { display: none; }
#homeStep-name.guest-join .home-join-row .home-btn { width: auto; flex: 1; }

.btn-copy {
  background: rgba(255,215,0,0.12); color: var(--accent);
  border: 1px solid rgba(255,215,0,0.35);
  border-radius: 7px; padding: 6px 10px; font-size: 0.72rem; cursor: pointer;
}

/* ── Lobby: Command Deck (redesign 2026-07-20) ──────────────────────────────
   Felt in its own scrollable column on the left, controls in a short,
   self-contained deck on the right — the room code and Invite action live
   in a column that's five rows tall and always fits, instead of a top
   banner that a short landscape screen could push off with no way to
   scroll up to it (Fable audit finding). The deck is styled in the Aurora
   App Shell's actual brass/felt/parchment tokens (aurora-shell.css) —
   duplicated here as literal values rather than var() because #homeOverlay
   sits outside #auroraShell's DOM subtree and can't inherit its custom
   properties; keep these in sync with aurora-shell.css by hand. */
#homeStep-lobby.home-step {
  flex-direction: row;
  align-items: stretch;
  gap: 0;
  margin: -26px -22px;
  height: min(calc(94dvh - 52px), calc(var(--mix-visual-viewport-h, 100dvh) - 24px - 52px));
  border-radius: 16px;
  overflow: hidden;
}
@media (orientation: landscape) and (max-height: 450px) {
  #homeStep-lobby.home-step { margin: -14px -16px; height: min(calc(94dvh - 28px), calc(var(--mix-visual-viewport-h, 100dvh) - 24px - 28px)); }
}
@media (orientation: landscape) and (max-height: 380px) {
  #homeStep-lobby.home-step { margin: -10px -14px; height: min(calc(94dvh - 20px), calc(var(--mix-visual-viewport-h, 100dvh) - 24px - 20px)); }
}

.lobby-table-scroll {
  flex: 1 1 auto; min-width: 0;
  overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  -webkit-overflow-scrolling: touch;
  background:
    radial-gradient(ellipse 900px 480px at 50% -60px, rgba(201,162,75,0.09), transparent 62%),
    radial-gradient(ellipse 1400px 900px at 50% 0%, #0a1712 0%, #050f0b 55%, #020604 100%);
}
.lobby-seats-note {
  font-family: 'SF Mono', ui-monospace, Menlo, monospace;
  font-size: 0.62rem; letter-spacing: 0.06em; color: #75897f;
  background: rgba(238,214,160,0.06); border: 1px solid rgba(238,214,160,0.10);
  border-radius: 999px; padding: 4px 12px;
}
.lobby-table {
  position: relative; flex: none;
  width: min(84%, 340px); aspect-ratio: 1 / 1; min-height: 190px;
  margin: 10px auto 0;
}
.lobby-felt {
  position: relative;
  width: 92%; height: 88%;
  border-radius: 50%;
  background: radial-gradient(ellipse 60% 55% at 50% 40%, var(--tt-felt-hi), var(--tt-felt) 65%, var(--tt-felt-lo) 100%);
  box-shadow:
    inset 0 0 0 6px var(--tt-rail),
    inset 0 0 0 7px var(--tt-gold-dim),
    inset 0 8px 26px rgba(0,0,0,0.5),
    var(--tt-shadow-table);
}

.lobby-seat {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center;
  gap: 3px;
  width: 68px;
}
.ls-badge {
  position: relative;
  width: 38px; height: 38px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--tt-avatar-bg);
  border: 2px solid var(--tt-gold-dim);
  color: var(--tt-gold);
  font-weight: 700; font-size: 0.72rem;
  box-shadow: var(--tt-seat-shadow);
}
.lobby-seat.you .ls-badge { border-color: var(--tt-avatar-ring); color: var(--text); }
.ls-name { font-size: 0.62rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
.lobby-seat.you .ls-name { color: var(--tt-gold); }
.ls-hosttag, .ls-away {
  font-size: 0.52rem; font-weight: 700; letter-spacing: 0.06em;
  border-radius: 4px; padding: 1px 5px;
}
.ls-hosttag { background: var(--tt-gold); color: #241c04; }
.ls-away { background: rgba(255,255,255,0.08); color: var(--muted); }

.lobby-seat.open .ls-badge {
  background: transparent; border-style: dashed; color: rgba(255,215,0,0.65);
  cursor: pointer; transition: transform 0.15s, border-color 0.15s, background 0.15s;
}
.lobby-seat.open .ls-name { color: rgba(255,215,0,0.6); }
.lobby-seat.open:hover .ls-badge, .lobby-seat.open:focus-visible .ls-badge {
  transform: scale(1.08); border-color: var(--tt-gold); background: rgba(255,215,0,0.08);
}

/* ── Lobby deck (right column) — Aurora App Shell brass/felt/parchment,
   see the shared-token note above .lobby-table-scroll. ─────────────────── */
.lobby-deck {
  position: relative; flex: 0 0 270px; display: flex; flex-direction: column; justify-content: center;
  gap: 12px; padding: 20px 20px;
  border-left: 1px solid rgba(238,214,160,0.10);
  background: linear-gradient(180deg, rgba(12,32,25,0.9), rgba(7,19,14,0.95));
  overflow-y: auto; overflow-x: hidden;
}
.lobby-deck::after {
  content: '♠'; position: absolute; right: -14px; bottom: -30px; font-family: Georgia, serif;
  font-size: 150px; color: rgba(238,214,160,0.05); pointer-events: none; line-height: 1;
}
.lobby-deck > * { position: relative; z-index: 1; }
@media (orientation: landscape) and (max-height: 450px) { .lobby-deck { flex-basis: 240px; padding: 14px 16px; gap: 8px; } }
@media (orientation: landscape) and (max-height: 380px) { .lobby-deck { flex-basis: 220px; padding: 10px 14px; gap: 6px; } }

.lobby-deck-title {
  font-family: 'Rockwell','Roboto Slab','Sitka Small', Georgia, 'Times New Roman', serif;
  font-size: 1.1rem; font-weight: 700; color: #f4ead7; margin: 0 0 3px;
}
.lobby-code-chip { display: flex; align-items: baseline; gap: 7px; }
.lobby-code-label {
  font-family: 'SF Mono', ui-monospace, Menlo, monospace;
  font-size: 0.58rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #75897f;
}
.lobby-code-value {
  font-family: 'Rockwell','Roboto Slab','Sitka Small', Georgia, 'Times New Roman', serif;
  font-size: 0.86rem; font-weight: 700; letter-spacing: 0.04em; color: #eed6a0;
}

.lobby-btn-brass {
  position: relative; font-family: inherit; font-weight: 700; font-size: 0.86rem;
  background: linear-gradient(160deg, #eed6a0, #c9a24b 60%, #8f7333);
  color: #201700; border: none; border-radius: 999px; padding: 12px; cursor: pointer; min-height: 44px;
  overflow: hidden;
}
.lobby-btn-brass::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.35) 48%, transparent 66%);
  background-size: 220% 100%; background-position: 120% 0; animation: lobbySheen 3.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .lobby-btn-brass::after { animation: none; display: none; } }
@keyframes lobbySheen { 0%, 60% { background-position: 120% 0; } 100% { background-position: -20% 0; } }
.lobby-btn-brass.hidden { display: none; }
.lobby-btn-brass:disabled { opacity: 0.45; cursor: default; }
.lobby-btn-brass:disabled::after { display: none; }

.lobby-start-help { font-size: 0.68rem; color: #75897f; margin: 4px 0 0; }
.lobby-waiting-row { display: flex; align-items: center; gap: 8px; }
.lobby-status-line { font-size: 0.82rem; color: #f4ead7; font-weight: 600; }
.lobby-status-sub { font-size: 0.72rem; color: #a8bab0; margin: 3px 0 0; line-height: 1.5; }
.lobby-dot {
  width: 7px; height: 7px; border-radius: 50%; background: #6fd6a0; flex: none;
  animation: lobbyPulse 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .lobby-dot { animation: none; } }
@keyframes lobbyPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

.lobby-rotation-label {
  font-family: 'SF Mono', ui-monospace, Menlo, monospace;
  font-size: 0.58rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #75897f;
  margin: 0 0 6px;
}
.lobby-rotation-strip { display: flex; gap: 6px; flex-wrap: wrap; }
.rot-tile {
  width: 46px; height: 46px; border-radius: 10px;
  background: linear-gradient(180deg, rgba(12,32,25,0.9), rgba(7,19,14,0.95));
  border: 1px solid rgba(238,214,160,0.10);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 4px; flex: none;
}
.rot-row { display: flex; gap: 2px; justify-content: center; }
.rot-row.spread { justify-content: space-between; width: 100%; }
.rot-slot { width: 5px; height: 7px; border-radius: 1px; background: rgba(238,214,160,0.5); flex: none; }

.lobby-leave-link {
  font-family: inherit; background: none; border: none; color: #75897f;
  font-size: 0.72rem; text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer; padding: 0; align-self: flex-start;
}

body.lobby-is-host #homeStep-lobby .guest-only { display: none !important; }
body:not(.lobby-is-host) #homeStep-lobby .host-only { display: none !important; }

.ls-remove {
  position: absolute; top: -3px; right: -3px;
  width: 16px; height: 16px;
  background: rgba(239,68,68,0.85); color: #fff;
  border: 1.5px solid rgba(20,4,4,0.7);
  border-radius: 50%;
  font-size: 0.55rem; cursor: pointer; line-height: 1;
  display: flex; align-items: center; justify-content: center; padding: 0;
}

/* ── Invite — a collapsible bottom sheet off the lobby, not a mandatory
   screen of its own. The in-app card stays minimal (who invited you, the
   code, who's here, share/copy); the richer sell lives only in the outbound
   share text/image (inviteText/buildInviteImageBlob in mp.js) — a host
   sitting in their own lobby doesn't need to be pitched the app they already
   opened. Reuses the live table's felt/gold tokens, same as the lobby seats. */
.invite-sheet { position: fixed; inset: 0; z-index: 320; }
.invite-sheet.hidden { display: none; }
.invite-sheet-backdrop {
  position: absolute; inset: 0; background: rgba(0,0,0,0.55);
}
.invite-sheet-panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  margin: 0 auto; width: min(560px, 92vw);
  border-radius: 18px 18px 0 0;
  padding: 18px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  background: radial-gradient(ellipse at 50% -10%, var(--tt-gold-glow), transparent 60%), var(--tt-felt);
  border: 1px solid var(--tt-gold-dim); border-bottom: none;
  box-shadow: 0 -18px 50px rgba(0,0,0,0.5);
}
.invite-sheet-close {
  position: absolute; top: 10px; right: 12px;
  background: none; border: none; color: rgba(242,234,214,0.6);
  font-size: 1rem; cursor: pointer;
}
.invite-card { text-align: left; padding-top: 6px; }
.invite-kicker {
  color: var(--tt-gold); font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; margin-bottom: 6px;
}
.invite-code-line { color: #f2ead6; font-size: 0.95rem; margin-bottom: 4px; }
.invite-code-line b { color: var(--tt-gold); letter-spacing: 0.08em; }
.invite-players { color: rgba(242,234,214,0.7); font-size: 0.76rem; margin-bottom: 14px; }
.invite-actions { display: flex; gap: 8px; }
.invite-actions .home-btn { flex: 1; background: linear-gradient(180deg, var(--tt-gold), #a9803a); color: #241c04; }
.invite-actions .btn-copy { flex: none; }

/* ── Install-as-PWA nudge (invite v2) ──────────────────────────────────────
   Same felt/gold family as .invite-card so it reads as part of the same
   premium invite moment, not a browser-chrome-style permission banner. */
.a2hs-banner {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 14px; padding: 12px 50px 12px 12px;
  border-radius: 12px;
  background: radial-gradient(ellipse at 0% 0%, var(--tt-gold-glow), transparent 65%), var(--tt-felt);
  border: 1px solid var(--tt-gold-dim);
  box-shadow: var(--tt-seat-shadow);
  text-align: left;
}
/* No generic `.hidden { display: none }` rule exists in this file — every
   other overlay/step scopes its own `.hidden` override (.home-step.hidden,
   .setup-overlay.hidden, etc.). This one was missing, so setupA2hsBanner()'s
   early-return case (no invite code / already standalone / dismissed) left
   the element's own `display: flex` above in force — the banner rendered
   unconditionally on every home-screen visit regardless of JS state. */
.a2hs-banner.hidden { display: none; }
.a2hs-icon { font-size: 1.6rem; flex: none; }
.a2hs-copy { flex: 1; min-width: 0; }
.a2hs-title { color: #f2ead6; font-size: 0.86rem; font-weight: 700; }
.a2hs-body { color: rgba(242,234,214,0.75); font-size: 0.72rem; line-height: 1.35; margin-top: 2px; }
.a2hs-body b { color: var(--tt-gold); }
.a2hs-action {
  flex: none; padding: 8px 12px; font-size: 0.78rem;
  min-height: 38px;
  background: linear-gradient(180deg, var(--tt-gold), #a9803a); color: #241c04;
}
/* Same missing-.hidden-rule gap as .a2hs-banner above: a <button>'s default
   display is inline-block, so the "hidden" class in the static markup did
   nothing — the Install App button rendered even on iOS and the generic
   fallback branch, neither of which ever calls classList.remove('hidden'). */
.a2hs-action.hidden { display: none; }
.a2hs-dismiss {
  /* 40x40 — the 38px tap-target floor (owner geometry spec, 2026-07-16)
     plus a hair of margin. Was 22x22: reported unresponsive on a real
     iPhone, and 22px is well under Apple's own 44pt HIG minimum too —
     the handler was never broken, the hit target was just too small to
     reliably land a real finger tap on. */
  position: absolute; top: 4px; right: 4px;
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.3); color: rgba(242,234,214,0.85);
  border: none; font-size: 0.85rem; line-height: 1; cursor: pointer;
}

/* Online extras */
.room-chip {
  background: rgba(255,215,0,0.12); color: var(--accent);
  border: 1px solid rgba(255,215,0,0.4);
  border-radius: 6px; padding: 2px 8px;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em;
}
.pill-tag.tag-away, .seat-name .tag-away {
  background: rgba(122,144,184,0.25); color: var(--muted);
  border-radius: 4px; padding: 1px 5px; font-size: 0.58rem; font-weight: 700;
}
.opp-pill.is-away, .seat-card.is-away { opacity: 0.65; }

/* ── Potential Analysis diagnostic section (AI Hand Analysis) ───────────────── */
.pa-block {
  margin-top: 8px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 8px;
  background: rgba(255,255,255,0.03);
}
.pa-block summary {
  cursor: pointer;
  padding: 8px 12px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.pa-block[open] summary { color: var(--accent); border-bottom: 1px solid rgba(255,255,255,0.1); }
.pa-body { padding: 10px 12px; font-size: 0.78rem; }
.pa-sec { margin-bottom: 10px; }
.pa-sec-title {
  font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 4px;
}
.pa-made, .pa-path, .pa-lowcore, .pa-expl { padding: 2px 0; line-height: 1.45; }
.pa-meta { color: var(--muted); font-size: 0.72rem; }
.pa-warn { color: #fbbf24; font-size: 0.72rem; padding: 2px 0; }
.pa-type {
  display: inline-block; font-size: 0.58rem; font-weight: 700;
  border-radius: 4px; padding: 1px 6px; margin-right: 4px;
  letter-spacing: 0.06em; vertical-align: 1px;
  background: rgba(255,255,255,0.1); color: var(--text);
}
.pa-t-made      { background: rgba(34,197,94,0.25);  color: #6ee7a0; }
.pa-t-draw      { background: rgba(59,130,246,0.25); color: #7cb8ff; }
.pa-t-backdoor  { background: rgba(59,130,246,0.15); color: #6b9fd8; }
.pa-t-redraw    { background: rgba(255,215,0,0.2);   color: var(--accent); }
.pa-t-backup    { background: rgba(148,163,184,0.2); color: #b6c2d4; }
.pa-t-scoop     { background: rgba(192,132,252,0.25); color: #d8b4fe; }
.pa-t-blocker   { background: rgba(251,146,60,0.2);  color: #fdba74; }
.pa-t-counterfeit_risk, .pa-t-domination_risk, .pa-t-rejected
                { background: rgba(239,68,68,0.22);  color: #fca5a5; }
.pa-score { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.pa-score span { width: 190px; color: var(--muted); font-size: 0.7rem; }
.pa-score b { width: 30px; text-align: right; font-size: 0.72rem; }
.pa-bar { flex: 1; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.08); overflow: hidden; }
.pa-bar i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg, #3b82f6, #ffd700); }
.pa-foot {
  margin-top: 8px; padding-top: 8px;
  border-top: 1px dashed rgba(255,255,255,0.14);
  color: var(--muted); font-size: 0.66rem; line-height: 1.5;
}
.pa-foot b { color: #fbbf24; }

/* ── Showdown Experience (docs/SHOWDOWN-EXPERIENCE.md) ──────────────────────
   Phase 1: celebration banner pops instantly (chips converge, amount pops).
   Phase 2: review area fades in ~1.4s later — banner pinned above, actions
   docked below, only the review scrolls. Panels are tabs: one Point at a time. */

.sd-box--exp {
  display: flex;
  flex-direction: column;
  max-height: 90dvh;
  overflow-y: hidden;
}
.sd-box--exp .sd-banner, .sd-box--exp .fs-banner { flex-shrink: 0; }
.sd-box--exp .sd-actions { flex-shrink: 0; }
.sd-review {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  animation: sdReviewIn 0.45s ease 1.4s backwards;
}
@keyframes sdReviewIn { from { opacity: 0; transform: translateY(8px); } }

/* Celebration banner */
.sd-celebrate {
  position: relative;
  overflow: hidden;
  animation: sdPop 0.5s cubic-bezier(0.2, 1.4, 0.4, 1);
}
.sd-celebrate h2 {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 4px !important;
}
.sd-banner-amt {
  font-size: 1.75rem;
  font-weight: 900;
  color: #ffd700;
  text-shadow: 0 0 18px rgba(255, 215, 0, 0.45);
  margin-bottom: 2px;
  animation: sdAmtIn 0.55s 0.3s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
@keyframes sdPop { from { transform: scale(0.92); opacity: 0; } }
@keyframes sdAmtIn { from { transform: translateY(10px) scale(0.7); opacity: 0; } }
/* Decorative chips converging on the winner */
.sd-chips i {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffe680, #d4a017);
  opacity: 0;
  animation: sdChipFly 0.8s ease-in 0.15s backwards;
}
.sd-chips i:nth-child(1) { --dx: -120px; --dy: 28px; }
.sd-chips i:nth-child(2) { --dx: 130px; --dy: -18px; animation-delay: 0.3s; }
.sd-chips i:nth-child(3) { --dx: -60px; --dy: -42px; animation-delay: 0.45s; }
@keyframes sdChipFly {
  0%   { transform: translate(var(--dx), var(--dy)); opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translate(0, 0); opacity: 0; }
}

/* Point stepper — numbered, chevron-linked, rendered after the panels so the
   board + current point's proof are the first things seen (variant order). */
.sd-points-lbl { margin-top: 18px; text-align: center; }
.sd-tabs { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 4px; margin: 8px 0 12px; }
.sd-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 6px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.sd-tab-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  font-size: 0.68rem;
  font-weight: 900;
}
.sd-tab-body { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.3; }
.sd-tab-label { font-weight: 800; font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; }
.sd-tab-pts { font-size: 0.58rem; font-weight: 700; opacity: 0.8; }
.sd-tab-chevron { color: var(--muted); font-size: 0.9rem; opacity: 0.45; }
.sd-tab--empty { opacity: 0.55; }
.sd-tab.active .sd-tab-num { background: var(--accent); color: #1a1300; border-color: var(--accent); }
.sd-tab.active .sd-tab-label::before { content: "🏆 "; }
.sd-tab.active.cat-high { color: #ffd700; border-color: rgba(255, 215, 0, 0.55);  background: rgba(255, 215, 0, 0.12); }
.sd-tab.active.cat-hand { color: #60a5fa; border-color: rgba(96, 165, 250, 0.55); background: rgba(96, 165, 250, 0.12); }
.sd-tab.active.cat-low  { color: #c084fc; border-color: rgba(192, 132, 252, 0.55); background: rgba(192, 132, 252, 0.12); }
.sd-tab.active.cat-p1   { color: #34d399; border-color: rgba(52, 211, 153, 0.55);  background: rgba(52, 211, 153, 0.12); }
.sd-tab.active.cat-p2   { color: #fb923c; border-color: rgba(251, 146, 60, 0.55);  background: rgba(251, 146, 60, 0.12); }
.sd-tab.active.cat-p3   { color: #f472b6; border-color: rgba(244, 114, 182, 0.55); background: rgba(244, 114, 182, 0.12); }
.sd-tab.active.cat-p4   { color: #22d3ee; border-color: rgba(34, 211, 238, 0.55);  background: rgba(34, 211, 238, 0.12); }
.sd-tab.active.cat-h1   { color: #ffd700; border-color: rgba(255, 215, 0, 0.55);   background: rgba(255, 215, 0, 0.12); }
.sd-tab.active.cat-l1   { color: #c084fc; border-color: rgba(192, 132, 252, 0.55); background: rgba(192, 132, 252, 0.12); }
.sd-tab.active.cat-h2   { color: #34d399; border-color: rgba(52, 211, 153, 0.55);  background: rgba(52, 211, 153, 0.12); }
.sd-tab.active.cat-l2   { color: #22d3ee; border-color: rgba(34, 211, 238, 0.55);  background: rgba(34, 211, 238, 0.12); }
.sd-tab.active { color: var(--text); border-color: rgba(255, 255, 255, 0.4); }

.sd-review-next {
  display: block;
  margin: 4px auto 0;
  padding: 10px 22px;
  border-radius: 999px;
  border: none;
  background: linear-gradient(135deg, #ffd700, #e5a800);
  color: #1a1300;
  font-weight: 900;
  font-size: 0.8rem;
  cursor: pointer;
}
.sd-review-next.hidden { display: none; }

/* One Point expanded at a time (hidden panels stay in the DOM) */
.sd-panel:not(.active) { display: none; }

/* Scoring-5 highlight: thick gold border + glow, wherever a card is part of
   the hand being shown (winner card or an "Everyone's Hands" comparison row).
   Broadcast-style sequential reveal (~1s) plays across these on tab activate. */
.sd-card.sd-used-card {
  border: 2.5px solid #ffd700;
  box-shadow: 0 0 10px rgba(255, 215, 0, 0.55), 0 0 3px rgba(255, 215, 0, 0.9) inset;
}
.sd-panel.reveal .sd-used-card {
  animation: sdDeal 0.3s calc(var(--i, 0) * 0.12s) cubic-bezier(0.2, 1.2, 0.4, 1) backwards;
}
@keyframes sdDeal { from { opacity: 0; transform: translateY(10px) scale(0.7); } }
.sd-panel.reveal .sd-cat-handname,
.sd-panel.reveal .sd-win-name { animation: fadeIn 0.35s 0.62s backwards; }

/* Point detail: every showdown hand for this point, ranked + coach insight */
.sd-sec-lbl {
  font-size: 0.56rem;
  font-weight: 900;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.sd-compare {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px dashed rgba(255, 255, 255, 0.1);
}
.sd-compare .sd-sec-lbl { margin-bottom: 8px; }
.sd-cmp-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 7px 8px;
  font-size: 0.74rem;
  color: var(--muted);
  border-radius: 8px;
}
.sd-cmp-row + .sd-cmp-row { border-top: 1px solid rgba(255, 255, 255, 0.05); }
.sd-cmp-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.18);
  font-size: 0.62rem;
  font-weight: 900;
}
.sd-cmp-info { display: flex; flex-direction: column; align-items: flex-start; min-width: 60px; }
.sd-cmp-name { font-weight: 700; color: var(--text); white-space: nowrap; }
.sd-cmp-pts { font-size: 0.6rem; opacity: 0.7; }
.sd-cmp-row.sd-cmp-hero .sd-cmp-name { color: #93c5fd; }
.sd-cmp-cards { display: flex; gap: 4px; flex-wrap: wrap; justify-content: center; }
.sd-cmp-cards .sd-card { font-size: 0.72rem; padding: 4px 5px; opacity: 0.5; }
.sd-cmp-cards .sd-card.sd-used-card { opacity: 1; }
.sd-cmp-hand { font-weight: 700; color: var(--text); white-space: nowrap; }
.sd-coach {
  margin-top: 9px;
  text-align: left;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--muted);
  background: rgba(96, 165, 250, 0.08);
  border: 1px solid rgba(96, 165, 250, 0.22);
  border-radius: 10px;
  padding: 7px 10px;
}
.sd-coach-lbl {
  font-weight: 900;
  color: #93c5fd;
  margin-right: 6px;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Reduced motion: the global rule shortens durations but not delays — kill
   the phased delays too so nothing sits invisible */
@media (prefers-reduced-motion: reduce) {
  .sd-review, .sd-celebrate, .sd-banner-amt, .sd-chips i,
  .sd-panel.reveal .sd-used-card,
  .sd-panel.reveal .sd-cat-handname,
  .sd-panel.reveal .sd-win-name { animation: none !important; }
}

/* ── Dealer Round-Setup Wizard ───────────────────────────────────────────────
   Full-screen takeover: no table, no avatars — one decision per screen. */
.setup-overlay {
  position: fixed; inset: 0; z-index: 320;
  background: radial-gradient(ellipse at 50% 20%, rgba(30,52,96,0.45), transparent 65%), var(--bg);
  display: flex; align-items: center; justify-content: center;
  padding: 14px;
  overflow-y: auto;
}
.setup-overlay.hidden { display: none; }

/* Felt game-picker mode (2026-07-20, solo only — feltGamePickerEnabled in
   env.js, toggled by app.js openRoundSetup() via body.mg-felt-picker).
   Reskins this SAME overlay/wizard — setup.js's step logic, card content
   and click handlers are completely unchanged — as a translucent scrim so
   the dimmed felt reads through behind it, matching the treatment
   .aurora-round-intro already uses for the round-announcement overlay,
   rather than the plain opaque takeover below. Scoped narrowly enough that
   mp.js's dealer's-choice wizard (never adds this class) is untouched. */
body.mg-felt-picker .setup-overlay {
  background:
    radial-gradient(circle at 50% 42%, rgba(15,76,54,.32), transparent 48%),
    rgba(2,6,9,.5);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
/* The .wiz card itself was still a solid, nearly full-width rectangle —
   making only #setupOverlay translucent left the felt with nothing real to
   show through. Stripping the card's own background/border/shadow (instead
   of just its wrapper) is what actually makes this read as "cards on the
   table" rather than "the same modal with a scrolling row." Text stays
   legible off the scrim above; individual .wg-card tiles carry their own
   background regardless. */
body.mg-felt-picker .wiz {
  width: min(720px, 94%);
  background: none;
  border: none;
  box-shadow: none;
  padding-top: 8px;
}
body.mg-felt-picker .wiz-head h2 {
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
}
body.mg-felt-picker .wiz-title,
body.mg-felt-picker .wiz-sub {
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
}
/* The "Choose Game" step no longer uses .wiz/.wiz-games at all (2026-07-23:
   replaced everywhere by the new .rw landscape shell below — see setup.js's
   rwGameStepHTML()), so this flag's own horizontal-scroll skin for that one
   step is superseded; its translucent-felt treatment for the REMAINING
   steps (preflop/ESG/points, still the old .wiz shell) is untouched below. */

/* Legibility fix (2026-07-20, found via full-playthrough audit): stripping
   .wiz's own background above only got a matching dark backing on the
   FIRST step's cards (.wiz-games .wg-card, right above). Preflop
   Structure/Choose ESG Mode/Points in Play never got the equivalent
   treatment — their card text (.wg-name/.wg-sub on .em-card, .pt-card's
   labels, .wiz-note, .wiz-stepno) was rendering near-white with a fully
   transparent background, floating directly on the blurred, brightness-
   varying felt. Confirmed by sampling computed styles: color rgb(238,244,
   255) on background rgba(0,0,0,0), zero text-shadow. A single backing on
   the whole body area (rather than chasing every individual card class)
   fixes every step uniformly, including any future step this wizard grows. */
body.mg-felt-picker .wiz-body {
  background: rgba(6, 10, 17, 0.58);
  border-radius: 16px;
  padding: 12px 10px;
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
body.mg-felt-picker .wiz-note {
  text-shadow: 0 1px 8px rgba(0,0,0,.75);
}

.wiz {
  position: relative;
  width: min(680px, 100%);
  max-height: 100%;
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid rgba(255,215,0,0.16);
  border-radius: 18px;
  box-shadow: 0 22px 70px rgba(0,0,0,0.6);
  padding: 20px 22px 16px;
}
.wiz-head { text-align: center; }
.wiz-head h2 {
  font-size: 0.92rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--text);
}
.wiz-x {
  position: absolute; top: 14px; right: 14px;
  width: 34px; height: 34px; border-radius: 9px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--muted); font-size: 0.9rem; cursor: pointer;
}
.wiz-prog {
  display: flex; align-items: center; justify-content: center;
  margin: 14px auto 4px; max-width: 320px;
}
.wp-dot {
  width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 700; flex-shrink: 0;
  background: rgba(255,255,255,0.06);
  border: 1.5px solid rgba(255,255,255,0.2);
  color: var(--muted);
}
.wp-dot.cur  { background: var(--accent); border-color: var(--accent); color: #201700; }
.wp-dot.done { border-color: var(--accent); color: var(--accent); background: rgba(255,215,0,0.08); }
.wp-line { flex: 1; height: 1.5px; background: rgba(255,215,0,0.3); min-width: 26px; }

.wiz-title { margin-top: 12px; font-size: 1.28rem; font-weight: 700; }
.wiz-sub   { color: var(--muted); font-size: 0.78rem; margin-top: 3px; }

/* min-width:0 overrides the flex item's implicit min-width:auto (2026-07-21
   fix): .wiz-body is a child of .wiz's column flex — without this, a flex
   item never shrinks below its content's min-content width, so a wide grid
   child (.wiz-games/.wiz-esgmodes) silently balloons .wiz-body past the
   card's own edge instead of being constrained to it. That's what was
   clipping "ESG by Street"'s description and the Choose Game carousel's
   trailing card with a hard, unsignaled edge. */
.wiz-body  { margin: 16px 0 6px; overflow-y: auto; min-width: 0; }
.wiz-note  {
  color: var(--muted); font-size: 0.72rem; text-align: center; margin-top: 12px;
}
.wiz-foot {
  display: flex; align-items: center; gap: 10px; margin-top: 12px;
}
.wiz-spacer { flex: 1; }
.wiz-btn {
  min-height: 46px; padding: 0 22px;
  border-radius: 10px; font-size: 0.9rem; font-weight: 700;
  letter-spacing: 0.04em; cursor: pointer;
}
.wiz-back {
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.16);
  color: var(--text);
}
.wiz-next {
  background: linear-gradient(180deg, #ffd700, #d4a900);
  border: none; color: #201700; min-width: 130px;
}
.wiz-next:disabled { opacity: 0.4; cursor: default; }
.wiz-confirm {
  background: linear-gradient(180deg, #34d374, #178a45);
  border: none; color: #04220f; min-width: 180px;
}
/* Selectable cards (ESG modes/preflop — the Choose Game step moved to its
   own .rw-cards rail below, 2026-07-23) */
.wiz-esgmodes {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  width: 100%; min-width: 0;
}
.wiz-esgmodes { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
.wg-card {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 16px 10px 12px;
  min-height: 138px;
  background: rgba(255,255,255,0.035);
  border: 1.5px solid rgba(255,255,255,0.12);
  border-radius: 13px;
  color: var(--text); cursor: pointer;
  text-align: center;
}
.wg-card:not(.soon):hover { border-color: rgba(255,215,0,0.5); }
.wg-card.sel {
  border-color: var(--accent);
  background: rgba(255,215,0,0.06);
}
.wg-card.soon { opacity: 0.55; cursor: default; }
.wg-check {
  /* Inset within the card's own padding box, not overhanging its corner:
     an overhanging badge gets clipped by .wiz-body's overflow-y:auto (which
     forces overflow-x:auto too, so BOTH axes clip) whenever a selected card
     sits in the grid's first row — the badge's negative top offset then
     pokes above the scrollport's own top edge with nothing to give it
     clearance. Confirmed via screenshot: the badge's top sliced flat. Kept
     inset rather than padding the scroll container, since this also fixes
     beta-hygiene-v1.css's landscape wizard (same .wiz-body overflow-y:auto,
     even tighter 4px top padding there) with zero changes to that file. */
  position: absolute; top: 6px; right: 6px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); color: #201700;
  font-size: 0.66rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
}
.wg-name { font-size: 0.82rem; font-weight: 700; line-height: 1.25; }
.wg-sub  { font-size: 0.68rem; color: var(--muted); line-height: 1.3; }
.wg-soon {
  margin-top: auto;
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.08em;
  color: #6fb2ff; text-transform: uppercase;
}

/* ══════════════════════════════════════════════════════════════════════
   "Choose Game" step — landscape-first redesign (2026-07-23), replacing
   the old .wiz-games grid for this one step everywhere (solo + multiplayer
   dealer wizard — owner call). One full-bleed strip (head / card rail /
   detail dock / foot) instead of stacked header/progress/title/sub rows
   competing with the cards for vertical room. Reuses .wg-check/.gi/.ic-*
   (board-geometry icons) unchanged — only the surrounding shell is new.
   Ported from mockups/choose-game-step-redesign-landscape.html, reviewed
   there first. ══════════════════════════════════════════════════════════ */
.rw {
  position: relative;
  width: min(1180px, 96vw); height: min(92vh, 580px); max-height: 100%;
  display: grid; grid-template-columns: minmax(0,1fr); grid-template-rows: auto 1fr auto;
  background:
    radial-gradient(ellipse at 50% -20%, rgba(199,155,79,.10), transparent 46%),
    linear-gradient(180deg, rgba(15,23,34,.97), rgba(6,10,16,.98));
  border: 1px solid rgba(255,215,0,0.16);
  border-radius: 22px;
  box-shadow: 0 22px 70px rgba(0,0,0,0.6);
  overflow: hidden;
}
.rw-head {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 18px; min-height: 60px;
  border-bottom: 1px solid rgba(255,215,0,0.14);
  background: rgba(255,255,255,.015);
}
.rw-headtitle { display: flex; flex-direction: column; gap: 1px; flex: 0 0 auto; }
.rw-eyebrow { font-size: 9.5px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase; color: rgba(255,215,0,.68); }
.rw-title { font-size: 1.05rem; font-weight: 800; color: var(--text); letter-spacing: -.01em; }
.rw-prog { display: flex; align-items: center; gap: 6px; margin: 0 auto; }
.rw-dot {
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 800; flex-shrink: 0;
  background: rgba(255,255,255,.06); border: 1.5px solid rgba(255,255,255,.18); color: var(--muted);
}
.rw-dot.cur  { background: var(--accent); border-color: var(--accent); color: #201700; }
.rw-dot.done { border-color: var(--accent); color: var(--accent); background: rgba(255,215,0,0.08); }
.rw-line { width: 20px; height: 1.5px; background: rgba(255,215,0,0.3); }

.rw-rail { position: relative; display: flex; align-items: stretch; min-height: 0; padding: 18px 6px; }
.rw-cards {
  display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch; padding: 2px 20px; margin: 0 auto; width: 100%;
  -webkit-mask-image: linear-gradient(to right, transparent 0, black 22px, black calc(100% - 22px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, black 22px, black calc(100% - 22px), transparent 100%);
}
.rg-card {
  position: relative; flex: 0 0 168px; scroll-snap-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 18px 12px 14px;
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.015));
  border: 1.5px solid rgba(255,255,255,.12); border-radius: 16px;
  cursor: pointer; text-align: center; color: var(--text);
  transition: border-color 160ms ease, background 160ms ease, transform 160ms ease, box-shadow 160ms ease;
}
.rg-card:hover:not(.rg-soon) { border-color: rgba(255,215,0,.5); transform: translateY(-2px); }
.rg-card.rg-sel {
  border-color: var(--accent); background: linear-gradient(180deg, rgba(255,215,0,.14), rgba(255,215,0,.03));
  box-shadow: 0 8px 26px rgba(255,215,0,.16), 0 0 0 1px rgba(255,215,0,.35) inset;
}
.rg-card.rg-soon { opacity: .5; cursor: default; }
.rg-check {
  position: absolute; top: 8px; right: 8px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); color: #201700; font-size: .62rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(0,0,0,.5);
}
.rg-icon { min-height: 52px; display: flex; align-items: center; justify-content: center; }
/* Name only — no separate "sub" line on the card itself. The board-geometry
   icon above already communicates shape (one board vs two vs a triangle vs
   rivers); restating it as a caption underneath duplicated information,
   worst on Countdown where the sub literally repeated the game's own name.
   Full sub/blurb text lives in .rw-detail below instead — one legible copy
   per game, never six competing for the same narrow card. */
.rg-name { font-size: .86rem; font-weight: 700; line-height: 1.2; }
.rg-pts { margin-top: auto; font-size: .72rem; font-weight: 800; color: var(--accent); }
.rg-badge { font-size: .6rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: #6fb2ff; }

.rw-detail {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 22px; min-height: 64px;
  border-top: 1px solid rgba(255,215,0,0.14);
  background: rgba(255,255,255,.015);
}
.rw-detail-icon { font-size: 1.3rem; flex: 0 0 auto; opacity: .85; }
.rw-detail-text { flex: 1; min-width: 0; }
.rw-detail-name { font-size: .86rem; font-weight: 800; color: var(--text); }
.rw-detail-name span { font-weight: 600; color: rgba(255,215,0,.8); margin-left: 6px; }
.rw-detail-blurb { font-size: .75rem; color: var(--muted); line-height: 1.4; margin-top: 2px; }

.rw-foot { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-top: 1px solid rgba(255,215,0,0.14); }
.rw-spacer { flex: 1; }
.rw-btn { min-height: 42px; padding: 0 20px; border-radius: 10px; font-size: .86rem; font-weight: 700; cursor: pointer; border: none; }
.rw-back { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.16); color: var(--text); }
.rw-next { background: linear-gradient(180deg, #ffd700, #d4a900); color: #201700; min-width: 120px; }

/* Board-geometry game icons — drawn, never generic */
.gi {
  min-height: 54px;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 3px;
}
.ic-row { display: flex; gap: 2.5px; }
.ic-slot {
  width: 11px; height: 15px; border-radius: 2.5px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.35);
}
.ic-fan { display: flex; gap: 3px; margin-bottom: 2px; }
.ic-card {
  width: 17px; height: 24px; border-radius: 3px;
  background: var(--card-face);
  display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center;
  font-size: 0.5rem; font-weight: 800; line-height: 1;
  box-shadow: 0 1px 3px rgba(0,0,0,0.45);
}
.ic-card b { color: #23262d; }
.ic-card i { font-style: normal; font-size: 0.48rem; }
.ic-card .ic-b { color: #23262d; }
.ic-card .ic-r { color: #d92038; }
.ic-fan .ic-card:nth-child(1) { transform: rotate(-8deg) translateY(1px); }
.ic-fan .ic-card:nth-child(3) { transform: rotate(8deg) translateY(1px); }
.gi-cd { align-items: flex-start; }
.gi-f2 { gap: 2px; }
.ic-riverrow { gap: 6px; margin: 1px 0; }
.ic-riv-slot {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 1px 4px; border-radius: 3px;
  background: rgba(255,215,0,0.12);
  border: 1px solid rgba(255,215,0,0.55);
}
.ic-riv-slot .ic-slot { width: 8px; height: 11px; }
.ic-riv-slot b {
  color: var(--accent); font-size: 0.42rem; font-weight: 800; letter-spacing: 0.02em;
}
.gi-dbbp, .gi-tbbp { position: relative; }
.ic-bomb { position: absolute; font-size: 0.85rem; right: -4px; bottom: -4px; }

/* ESG mode cards */
.em-svg { width: 44px; height: 44px; margin-bottom: 2px; }
.em-none   { color: #9aa9c4; }
.em-any    { color: #34d374; }
.em-street { color: #6fb2ff; }
.em-card .wg-name { color: var(--text); }

/* Preflop structure cards (reuses .em-card layout) */
.pf-icon { font-size: 1.8rem; line-height: 1; margin-bottom: 2px; }

/* Step 3 — configure ESG */
.wiz-modechip {
  display: block; margin: 0 auto 14px;
  background: rgba(111,178,255,0.08);
  border: 1px solid rgba(111,178,255,0.4);
  color: #6fb2ff; border-radius: 999px;
  font-size: 0.72rem; font-weight: 600;
  padding: 6px 14px; cursor: pointer;
}
.wiz-esgcfg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  align-items: stretch;
}
.esg-steppers {
  display: flex; flex-direction: column; justify-content: center;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px; padding: 6px 14px;
}
.esg-strow {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0;
}
.esg-strow + .esg-strow { border-top: 1px solid rgba(255,255,255,0.07); }
.esg-stname { flex: 1; font-size: 0.85rem; }
.esg-btn {
  width: 38px; height: 38px; border-radius: 9px;
  background: rgba(255,215,0,0.1);
  border: 1px solid rgba(255,215,0,0.5);
  color: var(--accent); font-size: 1.1rem; font-weight: 700;
  cursor: pointer;
}
.esg-btn:disabled { opacity: 0.3; cursor: default; }
.esg-n { width: 26px; text-align: center; font-size: 1rem; }
.esg-totalcard {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px; padding: 14px;
}
.ic-fan--esg .ic-card { background: linear-gradient(160deg, #24406e, #142642); border: 1px solid rgba(255,255,255,0.3); }
.esg-total-lbl { font-size: 0.8rem; font-weight: 600; margin-top: 4px; }
.esg-total-n { font-size: 1.7rem; color: var(--accent); line-height: 1.1; }
.esg-total-sum { font-size: 0.68rem; color: var(--muted); }

/* Step 4 — points in play */
.wiz-points {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.pt-card {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 16px 10px 14px;
  background: rgba(255,255,255,0.035);
  border: 1.5px solid rgba(255,255,255,0.12);
  border-radius: 13px; text-align: center;
}
.pt-ic {
  width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.35rem;
}
.t-gold   { background: rgba(255,215,0,0.12); }
.t-green  { background: rgba(52,211,116,0.12); }
.t-blue   { background: rgba(111,178,255,0.12); }
/* Countdown's Point 1-4 palette (matches .cat-p1..p4 in the showdown) */
.t-teal   { background: rgba(52,211,153,0.12); }
.t-orange { background: rgba(251,146,60,0.12); }
.t-pink   { background: rgba(244,114,182,0.12); }
.t-cyan   { background: rgba(34,211,238,0.12); }
.pt-check {
  position: absolute; top: 8px; right: 8px;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(52,211,116,0.9); color: #04220f;
  font-size: 0.58rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.wiz-ptotal {
  margin-top: 12px;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px; padding: 10px;
  font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted);
}
.wiz-ptotal b { font-size: 1.5rem; color: var(--accent); letter-spacing: 0; }

/* ── Waiting overlay (non-dealers, between hands) ───────────────────────────── */
.wait-overlay {
  position: fixed; inset: 0; z-index: 310;
  background: rgba(4,8,16,0.6);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.wait-overlay.hidden { display: none; }
.wait-box {
  width: min(430px, 100%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  background: linear-gradient(180deg, rgba(16,34,64,0.96), rgba(8,16,32,0.96));
  border: 1px solid rgba(255,215,0,0.2);
  border-radius: 16px;
  padding: 30px 26px;
  text-align: center;
  box-shadow: 0 18px 60px rgba(0,0,0,0.55);
}
.wait-crown { color: var(--accent); font-size: 1.7rem; line-height: 1; }
.wait-line1 { font-size: 1.05rem; }
.wait-line1 b { color: var(--accent); }
.wait-div { width: 130px; height: 1px; background: rgba(255,255,255,0.18); margin: 6px 0; }
.wait-line2 { color: var(--text); font-size: 0.86rem; }
.wait-line3 { color: var(--muted); font-size: 0.74rem; }

@media (max-width: 600px) {
  .wiz { padding: 16px 14px 12px; }
  .wiz-games, .wiz-esgmodes { grid-template-columns: 1fr 1fr; }
  .wiz-esgcfg { grid-template-columns: 1fr; }
  .wiz-points { grid-template-columns: 1fr; }
  .pt-card { flex-direction: row; text-align: left; padding: 12px 14px; }
  .pt-card .wg-name { flex: 1; }
  .pt-card .wg-sub { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Countdown Showdown — dedicated point-review carousel (Task 2)
   Fully isolated .cd-sd-* namespace; HLH's showdown (.sd-*) is untouched.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --cd-sd-row-accent: #38bdf8;
  --cd-sd-col-accent: #a78bfa;
}

.cd-sd-overlay { align-items: center; } /* inherits .sd-overlay's backdrop/centering */

.cd-sd-box {
  width: min(980px, calc(100vw - 24px));
  max-height: 92dvh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 18px;
  box-shadow: 0 24px 80px rgba(0,0,0,0.6);
  display: flex;
  flex-direction: column;
}

.cd-sd-header {
  padding: 16px 20px 10px;
  text-align: center;
  border-bottom: 1px solid rgba(255,255,255,0.07);
  flex-shrink: 0;
}
.cd-sd-header-trophy { font-size: 1.1rem; margin-right: 6px; }
.cd-sd-header-title { font-size: 1.05rem; font-weight: 800; color: var(--accent); letter-spacing: 0.02em; }
.cd-sd-header-sub { margin: 4px 0 0; font-size: 0.74rem; color: var(--muted); }

.cd-sd-body { display: flex; flex: 1; min-height: 0; }

/* ── Desktop sidebar: point summary list + running scoreboard ────────────── */
.cd-sd-sidebar {
  width: 280px;
  flex-shrink: 0;
  border-right: 1px solid rgba(255,255,255,0.07);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
}
.cd-sd-side-tabs { display: flex; flex-direction: column; gap: 8px; }
.cd-sd-side-row {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 9px 10px;
  border-radius: 10px;
  border: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.03);
  color: var(--text);
  cursor: pointer;
  font: inherit;
}
.cd-sd-side-row.cd-sd-side-active {
  border-color: rgba(255,215,0,0.6);
  background: rgba(255,215,0,0.08);
  box-shadow: 0 0 0 1px rgba(255,215,0,0.25);
}
.cd-sd-side-check { width: 16px; color: var(--success); font-weight: 800; flex-shrink: 0; }
.cd-sd-side-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cd-sd-side-title { font-size: 0.78rem; font-weight: 700; }
.cd-sd-side-detail { font-size: 0.64rem; color: var(--muted); }
.cd-sd-side-winner { font-size: 0.68rem; color: var(--accent); font-weight: 700; text-align: right; white-space: nowrap; }

.cd-sd-scoreboard {
  border-top: 1px solid rgba(255,255,255,0.07);
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.cd-sd-scoreboard-label { font-size: 0.62rem; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 2px; }
.cd-sd-score-row { display: flex; justify-content: space-between; font-size: 0.8rem; padding: 3px 2px; }
.cd-sd-score-leader { color: var(--accent); font-weight: 800; }
.cd-sd-score-val { font-variant-numeric: tabular-nums; }

.cd-sd-final-btn {
  margin-top: 4px;
  padding: 10px;
  border-radius: 10px;
  border: none;
  background: var(--accent);
  color: #201700;
  font-weight: 800;
  font-size: 0.78rem;
  cursor: pointer;
}

/* ── Mobile compact tabs (sidebar hidden below) ───────────────────────────── */
.cd-sd-tabs-compact { display: none; }
.cd-sd-dots { display: none; }

/* ── Main panel ────────────────────────────────────────────────────────────── */
.cd-sd-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.cd-sd-panel { flex: 1; overflow-y: auto; padding: 16px 20px; }
/* Point-transition entrance animation (spec §7) — a short slide-in from the
   direction the new point "arrives from"; the outgoing panel isn't kept
   around to slide out (consistent with this codebase's existing lightweight
   single-element entrance animations elsewhere). 200-300ms per spec;
   honors the existing global prefers-reduced-motion override automatically. */
.cd-sd-panel.cd-sd-anim-left { animation: cdSdSlideLeft 240ms ease; }
.cd-sd-panel.cd-sd-anim-right { animation: cdSdSlideRight 240ms ease; }
@keyframes cdSdSlideLeft {
  from { transform: translateX(28px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}
@keyframes cdSdSlideRight {
  from { transform: translateX(-28px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}
.cd-sd-panel-inner { display: flex; flex-direction: column; gap: 14px; }

.cd-sd-panel-head { text-align: center; position: relative; }
.cd-sd-point-title { font-size: 1.4rem; font-weight: 800; color: var(--accent); letter-spacing: 0.03em; }
.cd-sd-point-sub { font-size: 0.92rem; font-weight: 700; margin-top: 2px; }
.cd-sd-point-rule { font-size: 0.74rem; color: var(--muted); margin-top: 2px; }
.cd-sd-point-count { font-size: 0.66rem; color: var(--muted); margin-top: 6px; }

/* ── Row/Column path boxes — neutral by default, no "VS" treatment ───────── */
.cd-sd-paths { display: flex; align-items: stretch; gap: 12px; }
.cd-sd-path {
  flex: 1;
  border-radius: 12px;
  border: 1.5px solid rgba(255,255,255,0.1);
  background: rgba(255,255,255,0.02);
  padding: 12px;
  text-align: center;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.cd-sd-path-row .cd-sd-path-name { color: var(--cd-sd-row-accent); }
.cd-sd-path-col .cd-sd-path-name { color: var(--cd-sd-col-accent); }
.cd-sd-path-name { font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; margin-bottom: 8px; }
.cd-sd-path-cards { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; }
.cd-sd-path-letters { font-size: 0.64rem; color: var(--muted); margin-top: 6px; }
.cd-sd-path-row.cd-sd-path-focused { border-color: var(--cd-sd-row-accent); box-shadow: 0 0 0 3px rgba(56,189,248,0.18); }
.cd-sd-path-col.cd-sd-path-focused { border-color: var(--cd-sd-col-accent); box-shadow: 0 0 0 3px rgba(167,139,250,0.18); }
.cd-sd-path-divider { width: 1px; background: rgba(255,255,255,0.1); flex-shrink: 0; }
.cd-sd-rule-banner { text-align: center; font-size: 0.72rem; color: var(--muted); margin: 0; }

/* ── Winning combination — the clearest element on the screen ────────────── */
.cd-sd-combo {
  text-align: center;
  padding: 14px;
  border-radius: 12px;
  background: rgba(255,215,0,0.06);
  border: 1.5px solid rgba(255,215,0,0.35);
}
.cd-sd-combo-empty { color: var(--muted); font-size: 0.8rem; }
.cd-sd-combo-label { font-size: 0.68rem; font-weight: 800; letter-spacing: 0.1em; color: var(--accent); margin-bottom: 8px; }
.cd-sd-combo-cards { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; }
.cd-sd-combo-name { margin-top: 8px; font-size: 0.9rem; font-weight: 800; }

/* ── Card + used-highlight (accessible: border + text label, not color-only) */
.cd-sd-card-wrap { position: relative; display: inline-flex; }
.cd-sd-card-wrap.cd-sd-used .sd-card {
  outline: 3px solid var(--accent);
  outline-offset: 1px;
}
.cd-sd-used-tag {
  position: absolute;
  bottom: -8px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.5rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  background: var(--accent);
  color: #201700;
  padding: 1px 4px;
  border-radius: 3px;
  white-space: nowrap;
}

/* ── Player result rows ────────────────────────────────────────────────────── */
.cd-sd-players { display: flex; flex-direction: column; gap: 10px; }
.cd-sd-player-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  text-align: left;
  width: 100%;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1.5px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.02);
  color: var(--text);
  cursor: pointer;
  font: inherit;
}
.cd-sd-player-row.cd-sd-player-focused { border-color: rgba(255,215,0,0.5); background: rgba(255,215,0,0.05); }
.cd-sd-player-row.cd-sd-player-winner { border-color: rgba(34,197,94,0.5); }
.cd-sd-player-head { display: flex; align-items: center; gap: 8px; }
.cd-sd-player-avatar { font-weight: 800; }
.cd-sd-player-name { font-weight: 700; font-size: 0.88rem; }
.cd-sd-winner-text {
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #201700;
  background: var(--success);
  padding: 2px 7px;
  border-radius: 999px;
}
.cd-sd-player-hand { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.cd-sd-plus { color: var(--muted); font-weight: 800; margin: 0 2px; }
.cd-sd-path-used-cards { display: flex; gap: 4px; }
.cd-sd-path-used-label { font-size: 0.62rem; color: var(--muted); margin-left: 4px; }
.cd-sd-player-result { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 0.78rem; }
.cd-sd-hand-label { font-weight: 700; }
.cd-sd-path-pill {
  font-size: 0.62rem;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
}
.cd-sd-pill-row { color: var(--cd-sd-row-accent); }
.cd-sd-pill-col { color: var(--cd-sd-col-accent); }
.cd-sd-point-share { color: var(--accent); font-weight: 700; margin-left: auto; }
/* Tie-share reveal (spec §20/§21) — brief, optional, JS restarts it only on
   first entry into a tied point, never on every rerender. Honors the
   existing global prefers-reduced-motion override automatically. */
.cd-sd-share-reveal { animation: cdSdShareReveal 480ms ease; }
@keyframes cdSdShareReveal {
  0%   { transform: scale(0.7); opacity: 0.3; }
  60%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* ── Bottom announcement line + point-award badge ─────────────────────────── */
.cd-sd-announce {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 10px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.07);
}
.cd-sd-announce-text { font-size: 0.8rem; color: var(--text); }
.cd-sd-announce-badge {
  flex-shrink: 0;
  font-size: 0.72rem;
  font-weight: 800;
  color: #201700;
  background: var(--accent);
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

/* ── Footer nav ────────────────────────────────────────────────────────────── */
.cd-sd-footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 20px;
  border-top: 1px solid rgba(255,255,255,0.07);
}
.cd-sd-nav-btn {
  padding: 9px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.15);
  background: rgba(255,255,255,0.04);
  color: var(--text);
  font-weight: 700;
  font-size: 0.8rem;
  cursor: pointer;
}
.cd-sd-nav-btn:disabled { opacity: 0.35; cursor: default; }
.cd-sd-next-btn { background: var(--accent); color: #201700; border-color: transparent; }
.cd-sd-footer-count { font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ── Round totals strip — replaces the FINAL POINTS card (owner ruling
   2026-07-14): the carousel explains each point, so the recap keeps only a
   compact one-line tally. Scrolls sideways if names overflow 390px. */
.cd-sd-totals-strip {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 12px; padding: 8px 14px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03);
  font-size: 0.74rem; color: var(--muted);
  overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch;
}
.cd-sd-total-chip { flex-shrink: 0; }
.cd-sd-total-lead { color: var(--accent); font-weight: 800; }
.cd-sd-total-sep { color: rgba(255,255,255,0.25); flex-shrink: 0; }
.cd-sd-pot-amount { font-size: 1.3rem; font-weight: 800; color: var(--success); margin-top: 8px; }

.cd-sd-final-actions { display: flex; gap: 10px; justify-content: center; }

/* ── Mobile: hide sidebar, show compact tabs, stack paths vertically ─────── */
@media (max-width: 768px) {
  .cd-sd-sidebar { display: none; }
  .cd-sd-tabs-compact {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    padding: 10px 12px 0;
    flex-shrink: 0;
  }
  .cd-sd-tab-compact {
    flex-shrink: 0;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.12);
    background: rgba(255,255,255,0.03);
    color: var(--muted);
    font-weight: 700;
    font-size: 0.72rem;
    cursor: pointer;
  }
  .cd-sd-tab-compact.cd-sd-tab-active { color: #201700; background: var(--accent); border-color: transparent; }
  .cd-sd-tab-check { margin-right: 3px; }
  .cd-sd-dots { display: flex; gap: 5px; justify-content: center; padding: 8px 0 0; }
  .cd-sd-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,0.2); }
  .cd-sd-dot-active { background: var(--accent); }

  .cd-sd-box { width: 100vw; height: 100dvh; max-height: 100dvh; border-radius: 0; }
  .cd-sd-panel { padding: 12px 14px; }
  .cd-sd-paths { flex-direction: column; }
  .cd-sd-path-divider { width: auto; height: 1px; }
  .cd-sd-point-title { font-size: 1.15rem; }
  .cd-sd-player-result { font-size: 0.72rem; }
  .cd-sd-footer { padding: 10px 14px calc(10px + env(safe-area-inset-bottom)); }
  .cd-sd-nav-btn { padding: 10px 14px; font-size: 0.74rem; }

  .cd-sd-final-actions { flex-direction: column; }
}

/* ── Final Showdown — cinematic recap (final-showdown.js) ────────────────────
   Variant-agnostic: the ENTRY experience for Countdown's dedicated showdown
   and the generic showSd() (HLH/F2) alike. Reuses .sd-card/.sd-used-card for
   card faces; everything else lives here. Two acts:
     Act 1 — the winner banner ("title card") lands center-stage. Its layout
             slot is already its final docked position at the top; the hero
             moment is transform-only, so nothing below ever reflows/clips.
     Act 2 — wireHero() adds .fs-docked to the stage (.sd-box/.cd-sd-box):
             the banner glides home, the recap (.fs-after) rises in beneath.
   Reduced motion and re-entry from a deep-dive dock instantly. */

.fs-banner {
  position: relative;
  text-align: center;
  padding: 14px 12px 10px;
  transform-origin: top center;
  z-index: 2;
}
.fs-hero-stage .fs-banner {
  transform: translateY(min(30vh, 250px)) scale(1.3);
  transition: transform 0.7s cubic-bezier(0.35, 1, 0.3, 1);
}
.fs-hero-stage.fs-docked .fs-banner { transform: translateY(0) scale(1); }

.fs-trophy {
  display: block; font-size: 42px; line-height: 1; margin-bottom: 8px;
  animation: fsTrophyIn 0.7s cubic-bezier(0.2, 1.6, 0.4, 1) backwards;
}
@keyframes fsTrophyIn {
  0%   { transform: scale(0) rotate(-20deg); opacity: 0; }
  60%  { transform: scale(1.25) rotate(6deg); }
  100% { transform: scale(1) rotate(0); }
}
.fs-headline {
  /* Narrow enough that the hero-phase upscale never exceeds the viewport:
     it wraps to two balanced lines like a movie title card instead. */
  margin: 0 auto 4px; max-width: 270px;
  font-size: 1.25rem; line-height: 1.25; font-weight: 800;
  color: var(--text); text-wrap: balance;
  animation: fsHeadIn 0.5s 0.25s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
@keyframes fsHeadIn { from { transform: translateY(12px); opacity: 0; } }
.fs-amt {
  font-size: 1.9rem; font-weight: 900; color: var(--accent);
  text-shadow: 0 0 22px rgba(255, 215, 0, 0.45);
  animation: fsAmtIn 0.55s 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
.fs-amt small { font-size: 0.85rem; font-weight: 700; color: rgba(255, 215, 0, 0.6); }
@keyframes fsAmtIn { from { transform: translateY(10px) scale(0.7); opacity: 0; } }
/* One-line pot->split->payout math (Fable audit R6/B1, 2026-07-18) — lets
   a player verify the amount above against the pot they watched build,
   instead of only trusting it. Deliberately quieter than .fs-amt: it's a
   receipt, not the headline. */
.fs-ledger {
  margin-top: 2px; font-size: 0.68rem; font-weight: 600;
  color: var(--muted); letter-spacing: 0.01em;
  animation: fsAmtIn 0.55s 0.6s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
.fs-chips { position: absolute; top: 50%; left: 50%; width: 0; height: 0; }
.fs-chips i {
  position: absolute; width: 10px; height: 10px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffe680, #d4a017);
  opacity: 0; animation: fsChipFly 0.8s ease-in 0.4s backwards;
}
.fs-chips i:nth-child(1) { --dx: -110px; --dy: 26px; }
.fs-chips i:nth-child(2) { --dx: 120px; --dy: -16px; animation-delay: 0.55s; }
.fs-chips i:nth-child(3) { --dx: -58px; --dy: -40px; animation-delay: 0.7s; }
@keyframes fsChipFly {
  0%   { transform: translate(var(--dx), var(--dy)); opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translate(0, 0); opacity: 0; }
}
.fs-skip-hint {
  position: absolute; left: 0; right: 0; bottom: -110px;
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted); animation: fsHintIn 0.6s 1.4s backwards;
}
@keyframes fsHintIn { from { opacity: 0; } }
.fs-docked .fs-skip-hint { display: none; }

/* Recap content: hidden during the hero phase, rises in on dock. The hero
   phase also locks scroll and mutes anything competing with the title card
   (footer actions live outside .fs-after in the generic box). */
.fs-after {
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity 0.5s ease 0.15s, transform 0.5s ease 0.15s;
}
.fs-docked .fs-after { opacity: 1; transform: none; pointer-events: auto; }
.fs-hero-stage:not(.fs-docked) { overflow: hidden !important; }
.fs-hero-stage:not(.fs-docked) .sd-actions { opacity: 0; pointer-events: none; }
.fs-hero-stage.fs-docked .sd-actions { transition: opacity 0.5s ease 0.3s; opacity: 1; }
/* The generic showdown's old fixed-delay reveal is superseded by the dock */
.fs-hero-stage .sd-review { animation: none; }
/* Countdown recap: the cinematic banner IS the title — no header strip, and
   the body drops Stage A's sidebar row-flex for plain scrolling block flow */
.cd-sd-mode-recap .cd-sd-header { display: none; }
.cd-sd-mode-recap .cd-sd-body { display: block; }
.cd-sd-recap { padding: 6px 14px calc(14px + env(safe-area-inset-bottom)); }

.fs-section { padding: 4px 4px 14px; }
.fs-section-title {
  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent); font-weight: 900; margin-bottom: 4px;
}
.fs-hint { font-size: 0.7rem; color: var(--muted); font-style: italic; margin-bottom: 10px; }

/* Carousel: active card ~85% width, next card peeks ~10% as the "swipe for
   more" affordance — scroll-snap so a plain swipe/scroll always works, no tap
   required. */
.fs-carousel {
  display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 2px 2px 10px; margin: 0 -2px; -webkit-overflow-scrolling: touch;
}
.fs-point-card {
  flex: 0 0 85%; scroll-snap-align: start;
  background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.1);
  border-radius: 14px; padding: 14px 16px 10px;
  cursor: pointer;
}
.fs-point-card:active { border-color: rgba(255,215,0,0.4); }
.fs-point-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fs-point-card.fs-tie { border-color: rgba(255,215,0,0.35); background: rgba(255,215,0,0.05); }
@media (min-width: 700px) { .fs-point-card { flex-basis: 60%; } }
.fs-card-cta {
  margin-top: 9px; padding-top: 7px;
  border-top: 1px dashed rgba(255,255,255,0.08);
  text-align: center; font-size: 0.6rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}

/* Card head = point identity, never the winner (declared once, in their
   block): "Point #1 · Board High" (owner ruling 2026-07-14). */
.fs-card-head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 2px; }
.fs-card-num { font-weight: 900; font-size: 0.95rem; color: var(--accent); }
.fs-card-name { font-weight: 700; font-size: 0.82rem; }
/* Choppable variants only (Double Board) — this category's fixed pot share,
   e.g. "+150 chips" next to "Top Board" (owner spec: award each board's
   half independently, never folded into a single points total). */
.fs-card-share { margin-left: auto; font-weight: 800; font-size: 0.76rem; color: var(--accent); }
.fs-card-rule { font-size: 0.66rem; color: var(--muted); margin-bottom: 10px; }

/* The board zone leads the card, visually fenced off from the players */
.fs-board-zone { border-bottom: 1px dashed rgba(255,255,255,0.1); margin-bottom: 10px; }
.fs-board-lbl {
  text-align: center; font-size: 0.56rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 5px;
}

/* Mini board — a compact map, never half the card. Shape comes from variant
   data (boardMiniLayout/boardLayout rows padded to the widest with ghosts).
   Three cell states (owner ruling 2026-07-14): fs-hi participates in this
   point at full strength; fs-dim is a real dealt card excluded from the
   point — its face stays readable so "excluded" never looks like "empty";
   fs-ghost is a padding slot that doesn't exist in the row. */
.fs-board { margin-bottom: 11px; }
.fs-board .fs-board-row { display: flex; gap: 4px; margin-bottom: 4px; }
.fs-bcell {
  width: 27px; aspect-ratio: 5/7; border-radius: 5px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; opacity: 0.3;
}
.fs-bcell.fs-dim { opacity: 0.45; filter: saturate(0.3) brightness(0.9); }
.fs-bcell.fs-hi { opacity: 1; }
.fs-bcell.fs-hi .sd-card { box-shadow: 0 0 0 1.5px rgba(255,215,0,0.4); }
.fs-bcell .sd-card { font-size: 0.62rem; padding: 2px 3px; }
.fs-bcell.fs-ghost {
  background: repeating-linear-gradient(135deg, rgba(255,255,255,0.03), rgba(255,255,255,0.03) 5px, rgba(0,0,0,0.15) 5px, rgba(0,0,0,0.15) 10px);
  border: 1px solid rgba(255,255,255,0.06);
}
/* A labeled gap inside a row (e.g. F2's shared rivers between the boards).
   The rivers cluster tight to the CENTER (owner ruling 2026-07-14) — the
   label never stretches them out to the card edges. */
.fs-board-row-gapped { align-items: center; justify-content: center; gap: 10px; }
.fs-row-gap {
  flex: 0 1 auto; max-width: 130px; text-align: center; font-size: 0.56rem;
  letter-spacing: 0.06em; line-height: 1.3;
  text-transform: uppercase; color: var(--muted); padding: 0 4px;
}

/* Every contesting player, full hand, exactly-N cards pushed up as used —
   never a merged board+hand strip, never capped to the winner. */
.fs-players { display: flex; flex-direction: column; gap: 10px; }
.fs-player-block {
  border-radius: 10px; padding: 10px 12px 9px;
  background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.06);
}
.fs-player-block.fs-win { background: rgba(255,215,0,0.06); border-color: rgba(255,215,0,0.28); }
.fs-player-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.fs-player-name { font-weight: 800; font-size: 0.88rem; }
.fs-player-status { font-size: 0.66rem; color: var(--muted); }
.fs-player-block.fs-win .fs-player-status { color: var(--accent); font-weight: 700; }

/* ⓘ per player — toggles the inline Dealt/ESG breakdown (never an overlay) */
.fs-info-btn {
  margin-left: auto; width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
  border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.06);
  color: var(--muted); font-size: 0.7rem; font-weight: 800; font-style: italic;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  font-family: Georgia, serif;
}
.fs-info-btn.fs-info-open {
  background: rgba(255,215,0,0.18); border-color: rgba(255,215,0,0.5); color: var(--accent);
}
.fs-breakdown {
  margin-top: 9px; padding: 9px 10px 10px; border-radius: 9px;
  background: rgba(124,184,255,0.05); border: 1px dashed rgba(255,255,255,0.12);
}
.fs-breakdown .fs-hand-row .sd-card { opacity: 1; }
.fs-breakdown .fs-group-label:first-child { margin-top: 0; }

.fs-group-label {
  font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted); margin: 6px 0 4px;
}
.fs-esg-label { color: #7cb8ff; }
.fs-hand-row { display: flex; flex-wrap: wrap; gap: 5px; }
.fs-hand-row .sd-card { font-size: 0.78rem; padding: 5px 6px; opacity: 0.55; transition: transform 0.15s; }
.fs-hand-row .sd-card.fs-pushed { opacity: 1; transform: translateY(-4px); }

.fs-result { margin-top: 9px; padding-top: 8px; border-top: 1px dashed rgba(255,255,255,0.1); }
.fs-cat { font-weight: 800; font-size: 0.82rem; color: var(--accent); margin-bottom: 3px; }
.fs-player-block:not(.fs-win) .fs-cat { color: var(--text); }
.fs-caption { font-size: 0.68rem; color: var(--muted); line-height: 1.4; }
.fs-empty { font-size: 0.78rem; color: var(--muted); padding: 6px 0; }

.fs-dots { display: flex; justify-content: center; gap: 7px; margin-top: 2px; }
.fs-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,0.2); }
.fs-dot.fs-dot-on { background: var(--accent); box-shadow: 0 0 0 4px rgba(255,215,0,0.15); }

/* Generic showdown point-detail view (Countdown's Stage-A pattern): hidden
   on the recap — a card tap swaps the carousel for the full comparison at
   that point; "‹ Summary" swaps back. The banner stays docked on top. */
.sd-review .sd-detail { display: none; }
.sd-detail-open .sd-review .sd-detail { display: block; }
.sd-detail-open .sd-review .fs-section { display: none; }
.sd-detail-back {
  display: block; margin: 2px 0 12px; padding: 8px 16px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.16); background: rgba(255,255,255,0.05);
  color: var(--text); font-size: 0.78rem; font-weight: 700; cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .fs-hand-row .sd-card.fs-pushed { transition: none; }
  .fs-hero-stage .fs-banner, .fs-after,
  .fs-hero-stage.fs-docked .sd-actions { transition: none; }
  .fs-trophy, .fs-headline, .fs-amt, .fs-ledger, .fs-chips i, .fs-skip-hint { animation: none; }
}
@media (max-width: 600px) {
  .fs-point-card { flex-basis: 88%; padding: 12px 13px 9px; }
  .fs-bcell { width: 24px; }
  .fs-hero-stage .fs-banner { transform: translateY(min(30vh, 250px)) scale(1.18); }
  .fs-hero-stage.fs-docked .fs-banner { transform: translateY(0) scale(1); }
}
