/* =========================================================================
   1. VARIABLES
   ========================================================================= */
:root {
  /* Player colors */
  --yellow: #F7D44A;
  --yellow-dark: #EFC537;
  --blue: #69BDF5;
  --blue-dark: #3D93E8;
  --green: #61D73D;
  --green-dark: #3DAF2B;
  --red: #ED5B54;
  --red-dark: #C63E38;

  /* Brighter variants used only for the colored home-column paths */
  --path-red-1: #F2746D;
  --path-red-2: #D8483D;
  --path-green-1: #62D53F;
  --path-green-2: #3BAA2B;
  --path-yellow-1: #FADB6B;
  --path-yellow-2: #F0C93E;
  --path-blue-1: #73C5FF;
  --path-blue-2: #479DEE;

  /* Frame + neutrals */
  --gold-light: #F5E1A0;
  --gold: #D4A94A;
  --bronze: #A9752E;
  --white: #FFFFFF;
  --shadow: rgba(0, 0, 0, .35);
  --highlight: rgba(255, 255, 255, .4);

  /* Background radial gradient (deep purple) */
  --bg-1: #6664A9;
  --bg-2: #555196;
  --bg-3: #403D79;
  --bg-4: #31305F;

  /* Border radii */
  --radius-board: 24px;
  --radius-area: 18px;
  --radius-box: 14px;
  --radius-tile: 2px;
  --radius-btn: 12px;

  /* App chrome (outside the board spec — reused across the rest of the UI
     for a consistent premium-mobile-game feel) */
  --panel: #2f2761;
  --panel-raised: #3a3175;
  --ink: #eef0f3;
  --ink-muted: #b3a8dd;
  --rule: #4c3f92;
  --accent: #f2a71b;
  --board-track: #fbf8f0;
  --banner-h: 54px;
  --bottombar-h: 50px;
  --topbar-h: 58px;

  /* Fixed reference resolution for the whole app (see #stage-outer/#stage below) — every
     screen is built at this exact pixel size on desktop, Android, and iOS alike, then
     uniformly scaled to fit the real viewport, instead of reflowing per device. Matches an
     iPhone 14 Pro Max's own logical viewport (430x932) as the canonical "default" screen. */
  --stage-w: 430px;
  --stage-h: 932px;

  /* Display face for headings/big numbers only (see index.html's Google Fonts link) —
     body text/inputs/buttons stay on the system-font stack below for small-size legibility. */
  --font-display: "Baloo 2", "Fredoka", "Nunito", system-ui, sans-serif;
}

/* =========================================================================
   2. RESET
   ========================================================================= */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
button { font-family: inherit; }
.hidden { display: none !important; }

/* =========================================================================
   2b. ICONS (see index.html's shared UI icon sprite, right after #pawn-shape)
   ========================================================================= */
.icon { display: block; flex-shrink: 0; }

/* "Selected"/"active" ribbon — a small corner ribbon + checkmark, purely CSS, keyed off
   classes app.js already toggles (mode-card.selected, player-select-tile.selected,
   online-teams-btn.selected). Any element opting in just needs position:relative
   (each already has it via its own layout) and overflow visible at the corner. */
.ribbon-selectable { position: relative; overflow: hidden; }
.ribbon-selectable.selected::before,
.ribbon-selectable.active::before {
  content: ""; position: absolute; top: 0; left: 0; z-index: 2;
  border-style: solid; border-width: 22px 22px 0 0;
  border-color: var(--gold) transparent transparent transparent;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.35));
}
.ribbon-selectable.selected::after,
.ribbon-selectable.active::after {
  content: "✓"; position: absolute; top: 1px; left: 1px; z-index: 3;
  font-size: 10px; font-weight: 800; color: #3a2506; line-height: 1;
}

/* =========================================================================
   3. LAYOUT
   ========================================================================= */
body {
  /* Deep purple radial gradient, per spec, with a very subtle speckled
     noise texture layered on top (two faint repeating radial dot-fields). */
  background-image:
    radial-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
    radial-gradient(rgba(255,255,255,.018) 1px, transparent 1px),
    radial-gradient(ellipse 900px 650px at 50% 0%, var(--bg-1) 0%, transparent 68%),
    radial-gradient(ellipse 1000px 800px at 50% 100%, var(--bg-4) 0%, transparent 62%),
    linear-gradient(180deg, var(--bg-2) 0%, var(--bg-3) 100%);
  background-size: 70px 70px, 130px 130px, 100% 100%, 100% 100%, 100% 100%;
  background-position: 0 0, 35px 65px, 0 0, 0 0, 0 0;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Centers the fixed-size #stage in whatever real viewport it's running on (desktop browser
   window, phone, tablet) and lets index.html's inline script scale it uniformly to fit —
   letterboxed on whichever axis has slack, over the same purple background showing through.
   A transformed ancestor becomes the containing block for position:fixed descendants, so
   #ad-banner/#app-bottombar/.toast/.boot-loader (all position:fixed) dock to THIS box's
   edges rather than the real window's, scaling right along with everything else. */
#stage-outer {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
#stage {
  position: relative;
  width: var(--stage-w); height: var(--stage-h);
  flex-shrink: 0;
  transform-origin: center center;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

#app {
  min-height: 100%;
  padding-bottom: calc(var(--banner-h) + var(--bottombar-h) + 8px);
  display: flex;
  flex-direction: column;
}
/* Game screen hides the bottom bar (see app.js's showScreen) — reclaim its clearance so
   #screen-game's own centering isn't fighting a chunk of permanently-dead space below it. */
#app.no-bottombar { padding-bottom: calc(var(--banner-h) + 8px); }
.screen { flex: 1; display: flex; }
/* Centered rather than top-packed: on a real phone the fixed stage (see --stage-h) is
   usually taller than this screen's own content, and top-packing left a big empty gap
   above the ad banner. Centering distributes that slack evenly instead. */
/* 6px (not 12px) edge padding — sample-ui/compare/screen-size.jpeg's own reference board
   sits almost edge-to-edge on the real screen; tightening this (game-screen only, doesn't
   touch home/setup/lobby) is most of what makes the board noticeably wider. */
#screen-game { flex-direction: column; padding: 6px 6px 0; justify-content: center; }

/* =========================================================================
   4. BOARD (outer golden frame)
   ========================================================================= */
.board-wrap {
  position: relative;
  display: flex; justify-content: center; padding: 4px 14px 14px;
  background: radial-gradient(ellipse at 50% 40%, rgba(106,79,196,.28) 0%, transparent 72%);
  border-radius: 20px; margin: 0 0 10px;
}
/* A second, slowly-breathing gold glow layered behind the frame (same technique/keyframe as
   Home's glow orbs) — contained to the board via .board-wrap's own bounds, purely ambient. */
.board-wrap::before {
  content: ""; position: absolute; inset: -22px; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse at 50% 45%, rgba(244,209,110,.18) 0%, transparent 70%);
  animation: glow-breathe 6s ease-in-out infinite;
  border-radius: 30px;
}
/* The avatar+dice clusters no longer live on the board's own corners (see #top-players-row/
   #bottom-players-row in index.html and .players-row below) — they sit in their own rows
   above/below instead, spaced off the board by .players-row's own margin, not this padding.
   So this only needs enough room for the gold frame's drop shadow to breathe, letting the
   board stretch to ~95% of the screen width (5px padding on a ~418px available row width
   ((430 stage - 2*6px #screen-game edge padding)) leaves a 408px board frame, 94.9%). */
.board-wrap.corner-dice-mode { padding: 5px; margin: 0; }
.board-frame {
  position: relative; z-index: 1;
  width: 100%; max-width: 440px;
  padding: 9px;
  border-radius: var(--radius-board);
  /* Top light gold -> middle warm gold -> bottom bronze */
  background: linear-gradient(180deg, var(--gold-light) 0%, var(--gold) 48%, var(--bronze) 100%);
  box-shadow:
    0 18px 40px var(--shadow),                     /* outer shadow */
    0 0 0 1px rgba(255,255,255,.15),                /* thin outer rim, a jeweled edge */
    inset 0 2px 3px var(--highlight),               /* inner highlight */
    inset 0 -6px 10px rgba(0,0,0,.35);              /* inner shadow */
}
.board {
  position: relative;
  display: grid;
  grid-template-columns: repeat(15, 1fr);
  grid-template-rows: repeat(15, 1fr);
  width: 100%;
  aspect-ratio: 1 / 1;
  background: #d8cca3;
  gap: 1px;
  border-radius: calc(var(--radius-board) - 9px);
  overflow: hidden;
  box-shadow: inset 0 2px 6px rgba(0,0,0,.25);
}

/* =========================================================================
   5. PLAYER AREAS (the 4 colored corners)
   ========================================================================= */
.cell { position: relative; background: var(--board-track); border: 1px solid rgba(0,0,0,.06); border-radius: var(--radius-tile); }

/* Individual base-* cells stay transparent — .base-area below carries the
   actual color/gradient/shadow as one unified rounded panel, not 36 tiles. */
.cell.base-red, .cell.base-green, .cell.base-yellow, .cell.base-blue { background: transparent; border-color: transparent; box-shadow: none; }

.base-area {
  z-index: 1;
  border-radius: var(--radius-area);
  box-shadow:
    inset 0 2px 3px var(--highlight),   /* soft highlight */
    inset 0 -6px 10px rgba(0,0,0,.25),  /* depth */
    0 2px 4px rgba(0,0,0,.2);
}
/* Mostly flat, like the reference — just a subtle darkening toward one corner rather
   than a strong light-to-dark sweep across the whole panel. */
.base-area-yellow { background: linear-gradient(160deg, var(--yellow) 0%, var(--yellow) 72%, var(--yellow-dark) 100%); }
.base-area-blue   { background: linear-gradient(160deg, var(--blue) 0%, var(--blue) 72%, var(--blue-dark) 100%); }
.base-area-green  { background: linear-gradient(160deg, var(--green) 0%, var(--green) 72%, var(--green-dark) 100%); }
.base-area-red    { background: linear-gradient(160deg, var(--red) 0%, var(--red) 72%, var(--red-dark) 100%); }

/* =========================================================================
   6. PATHS (shared track tiles + colored home-column runways)
   ========================================================================= */
.cell {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),   /* light bevel */
    inset 0 -1px 0 rgba(0,0,0,.05),       /* tiny shadow */
    inset 0 0 0 1px rgba(255,255,255,.3); /* inset highlight */
}

.home-run { z-index: 1; }
.home-run-red    { background: linear-gradient(180deg, var(--path-red-1), var(--path-red-2)); }
.home-run-green  { background: linear-gradient(180deg, var(--path-green-1), var(--path-green-2)); }
.home-run-yellow { background: linear-gradient(180deg, var(--path-yellow-1), var(--path-yellow-2)); }
.home-run-blue   { background: linear-gradient(180deg, var(--path-blue-1), var(--path-blue-2)); }

/* A solid CSS triangle, not a text glyph — renders as a bold, consistent shape
   regardless of font/browser. Sits directly on the colored home-run entrance cell
   (white, so it reads clearly against any of the four colors), not off in a
   separate plain cell. */
.home-arrow-glyph { position: absolute; z-index: 3; pointer-events: none; }
.home-arrow-glyph-on-run {
  width: 42%; height: 42%; top: 29%; left: 29%;
  background: var(--white);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.4));
}
.home-arrow-glyph-right  { clip-path: polygon(0% 0%, 100% 50%, 0% 100%); }
.home-arrow-glyph-left   { clip-path: polygon(100% 0%, 0% 50%, 100% 100%); }
.home-arrow-glyph-down   { clip-path: polygon(0% 0%, 100% 0%, 50% 100%); }
.home-arrow-glyph-up     { clip-path: polygon(0% 100%, 100% 100%, 50% 0%); }

/* Start square: filled with its own owner's color (not the plain track color), with a star
   in a darker shade of that same color on top — matches sample-ui/ludo.png, where every
   arm's start tile is a solid color block, distinct from the plain-cream tiles with a plain
   blue star used elsewhere on the shared track. */
.cell.start-red    { background: var(--red); }
.cell.start-green  { background: var(--green); }
.cell.start-yellow { background: var(--yellow); }
.cell.start-blue   { background: var(--blue); }

/* Crisp SVG star (js/render.js's buildBoardStarIcon, #icon-board-star) in place of a plain
   "★" text glyph — scalable and consistent with every other icon this session, rather than
   depending on the platform's own font for that glyph's shape/weight. */
.board-star-icon {
  position: absolute; inset: 22%; z-index: 2; pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.3));
}
.cell.start-red .board-star-icon-start    { color: var(--red-dark); }
.cell.start-green .board-star-icon-start  { color: var(--green-dark); }
.cell.start-yellow .board-star-icon-start { color: color-mix(in srgb, var(--yellow-dark) 80%, black); }
.cell.start-blue .board-star-icon-start   { color: var(--blue-dark); }

/* Power tiles (this game's own bonus mechanic) reuse the reference's second, plain
   blue star style — the surprise is in what it does, not a special icon color. */
.board-star-icon-power {
  color: #AEDCFF;
  filter: drop-shadow(0 0 3px rgba(174,220,255,.9));
  animation: star-glow 1.6s ease-in-out infinite;
}
@keyframes star-glow { 0%,100% { opacity: .8; transform: scale(1); } 50% { opacity: 1; transform: scale(1.22); } }
.cell.flash { animation: cell-flash .5s ease; }
@keyframes cell-flash { 0%,100% { filter: none; } 30% { filter: brightness(2.1) saturate(1.4); } }

/* Power-Play dynamic tiles (Rush mode only — see engine.js's state.powerTiles/
   render.js's renderPowerPlayTiles). Unlike .power-tile above (baked into the board once,
   fixed for the whole game), these are re-rendered every turn at whatever cell they
   currently occupy — a real child element per marker, not a ::after, since each of the 3
   types needs its own icon/color rather than one shared star. */
.power-play-marker {
  /* Below every .token state (base z-index:2, .movable 3, .hopping 4) — a token sharing a
     cell with a marker (e.g. right before the marker gets picked up/removed) must never be
     visually hidden behind it. */
  position: absolute; inset: 4%; z-index: 1; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800; color: #fff;
  border: 1.5px solid rgba(255,255,255,.55);
  box-shadow: 0 1px 3px rgba(0,0,0,.5), inset 0 1px 1px rgba(255,255,255,.4);
  animation: power-play-pulse 1.4s ease-in-out infinite;
  pointer-events: none;
}
@keyframes power-play-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.16); } }
.power-play-marker-icon { width: 78%; height: 78%; display: block; overflow: visible; }
.power-play-bonusRoll .power-play-marker { background: radial-gradient(circle at 35% 30%, var(--gold-light), var(--bronze)); }
.power-play-shield .power-play-marker { background: radial-gradient(circle at 35% 30%, #7fd3ff, #2f7fb0); }
.power-play-doubleDistance .power-play-marker { background: radial-gradient(circle at 35% 30%, #d7a8ff, #7a3fb0); }
.power-play-diceControl .power-play-marker { background: radial-gradient(circle at 35% 30%, #ff9f8f, #b23a2a); }

/* =========================================================================
   7. HOME (die-face box + wells + name tag)
   ========================================================================= */
.base-yard {
  z-index: 1; border-radius: var(--radius-box);
  box-shadow:
    inset 0 4px 8px rgba(0,0,0,.45),      /* pressed-in shadow */
    inset 0 -1px 2px var(--highlight);    /* gloss edge */
}
.base-yard-red    { background: linear-gradient(160deg, rgba(0,0,0,.15), rgba(0,0,0,.4)), var(--red-dark); }
.base-yard-green  { background: linear-gradient(160deg, rgba(0,0,0,.15), rgba(0,0,0,.4)), var(--green-dark); }
.base-yard-yellow { background: linear-gradient(160deg, rgba(0,0,0,.15), rgba(0,0,0,.4)), var(--yellow-dark); }
.base-yard-blue   { background: linear-gradient(160deg, rgba(0,0,0,.15), rgba(0,0,0,.4)), var(--blue-dark); }

/* Home circles: soft transparent brown, inner shadow, small highlight. Sit on the grid-line
   crossing given by BASE_SLOTS (see board-data.js) — board-relative absolute placement, not
   a per-cell decoration, since a crossing point straddles 4 cells rather than centering in one. */
.base-slot-dot {
  position: absolute; z-index: 2; transform: translate(-50%, -50%);
  width: 3.07%; height: 3.07%; border-radius: 50%;
  background: rgba(76, 48, 30, .38);
  box-shadow: inset 0 2px 3px rgba(0,0,0,.45), inset 0 -1px 1px var(--highlight);
  pointer-events: none;
}

/* A .board-wrap child now, NOT a boardEl child — see render.js's renderBaseLabels for why
   (avoids a real rotation/flexbox bug the in-board version had). Fixed screen position per
   quadrant, sitting right at the actual playing panel's own inner edge — inset = board-wrap's
   own padding (.board-wrap.corner-dice-mode, 5px) + board-frame's own 9px padding = 14px —
   same convention sample-ui/ludo.png uses (a tag at the top of the top quadrants, bottom of
   the bottom ones). Independent of the avatar+dice clusters now (see .players-row/
   .player-pair below), which no longer sit on the board's corners at all. */
.base-label {
  position: absolute; z-index: 4; width: 130px;
  display: flex; justify-content: center; align-items: center;
  padding: 4px; pointer-events: none; overflow: hidden;
}
.base-label-pos-tl { top: 14px; left: 14px; }
.base-label-pos-tr { top: 14px; right: 14px; }
.base-label-pos-br { bottom: 14px; right: 14px; }
.base-label-pos-bl { bottom: 14px; left: 14px; }
.base-label-inner { display: flex; align-items: center; }
/* Level gets a solid pill (matches sample-ui/ludo.png's "Lv.16" tag); the name itself has
   no background at all — just bold text in a darker shade of the seat's own color, sitting
   directly on the base panel, exactly like the reference's plain "Gissellecb"/"JollyDiver". */
.base-label-level {
  background: rgba(20,14,40,.72); color: #fff; font-weight: 700;
  font-size: 10.5px; padding: 2px 5px; line-height: 1.5; white-space: nowrap;
  border-radius: 5px; flex-shrink: 0;
}
.base-label-name {
  font-weight: 800; font-size: 11px; line-height: 1.5; white-space: nowrap;
  margin-left: 4px; text-shadow: 0 1px 0 rgba(255,255,255,.25);
  overflow: hidden; text-overflow: ellipsis; max-width: 44px;
}
.base-label-red .base-label-level { background: var(--red-dark); }
.base-label-green .base-label-level { background: var(--green-dark); }
.base-label-yellow .base-label-level { background: color-mix(in srgb, var(--yellow-dark) 75%, black); }
.base-label-blue .base-label-level { background: var(--blue-dark); }
.base-label-red .base-label-name { color: color-mix(in srgb, var(--red-dark) 70%, black); }
.base-label-green .base-label-name { color: color-mix(in srgb, var(--green-dark) 70%, black); }
.base-label-yellow .base-label-name { color: color-mix(in srgb, var(--yellow-dark) 55%, black); }
.base-label-blue .base-label-name { color: color-mix(in srgb, var(--blue-dark) 70%, black); }

/* =========================================================================
   8. CENTER (four raised gradient triangles)
   ========================================================================= */
.cell.center { background: #2a2050; box-shadow: inset 0 0 0 1px rgba(0,0,0,.25); }
.center-triangle { z-index: 2; filter: drop-shadow(0 2px 2px rgba(0,0,0,.35)); }
.center-triangle-left  { clip-path: polygon(0% 0%, 0% 100%, 50% 50%); }
.center-triangle-right { clip-path: polygon(100% 0%, 100% 100%, 50% 50%); }
.center-triangle-top   { clip-path: polygon(0% 0%, 100% 0%, 50% 50%); }
.center-triangle-bottom{ clip-path: polygon(0% 100%, 100% 100%, 50% 50%); }
.center-triangle-red    { background: linear-gradient(135deg, var(--path-red-1), var(--red-dark)); }
.center-triangle-green  { background: linear-gradient(135deg, var(--path-green-1), var(--green-dark)); }
.center-triangle-yellow { background: linear-gradient(135deg, var(--path-yellow-1), var(--yellow-dark)); }
.center-triangle-blue   { background: linear-gradient(135deg, var(--path-blue-1), var(--blue-dark)); }

/* A small focal gold hub where the four triangles meet — previously just their bare
   corners touching, no centerpiece. */
.center-hub {
  z-index: 3; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--gold-light), var(--gold) 60%, var(--bronze) 100%);
  box-shadow: 0 0 0 2px rgba(255,255,255,.45), 0 2px 5px rgba(0,0,0,.5), inset 0 1px 1px rgba(255,255,255,.6);
  animation: hub-glow 2.4s ease-in-out infinite;
}
@keyframes hub-glow {
  0%, 100% { box-shadow: 0 0 0 2px rgba(255,255,255,.45), 0 2px 5px rgba(0,0,0,.5), inset 0 1px 1px rgba(255,255,255,.6); }
  50% { box-shadow: 0 0 0 2px rgba(255,255,255,.65), 0 0 10px 3px rgba(244,209,110,.65), inset 0 1px 1px rgba(255,255,255,.6); }
}

/* =========================================================================
   9. PAWNS
   ========================================================================= */
.token {
  position: absolute; cursor: pointer; z-index: 2;
  filter: drop-shadow(0 5px 10px rgba(0,0,0,.3));
}
/* Counter-rotation target for a rotated board (see render.js's createTokenEl) — kept separate
   from .token itself so it never fights the outer element's own transform (base-slot
   centering, hop-bounce, pulse). */
.token-inner { width: 100%; height: 100%; position: relative; }
/* fill/stroke are inherited SVG properties, so they must be set on the <svg>/<use>
   itself — classes on shapes *inside* a <symbol> aren't reachable by outside CSS
   selectors once cloned through a <use>. */
.pawn-svg {
  width: 100%; height: 100%; overflow: visible; display: block;
  stroke: rgba(0,0,0,.45); stroke-width: 1.5; stroke-linejoin: round;
}
.token.color-red .pawn-svg { fill: url(#grad-red); }
.token.color-green .pawn-svg { fill: url(#grad-green); }
.token.color-yellow .pawn-svg { fill: url(#grad-yellow); }
.token.color-blue .pawn-svg { fill: url(#grad-blue); }

.shield-badge {
  display: none; position: absolute; top: -8%; right: -8%; font-size: 46%;
  background: #fff; border-radius: 50%; padding: 2px; box-shadow: 0 1px 3px rgba(0,0,0,.5);
}
.token.shielded .shield-badge { display: block; }
.token.shielded .pawn-svg { filter: drop-shadow(0 0 3px #fff) drop-shadow(0 0 5px #fff); }

.token.movable { animation: pulse 1s infinite; cursor: pointer; z-index: 3; }
.token:not(.movable) { cursor: default; }
/* Shield-activation target picking (see app.js's shieldSelectMode) — same pulse as a normal
   movable token, but a distinct cyan glow so it doesn't read as "you can move this right
   now" during a mode that's specifically NOT the move-selection flow. */
.token.shield-selectable {
  animation: pulse 1s infinite; cursor: pointer; z-index: 3;
  filter: drop-shadow(0 0 4px #7fd3ff) drop-shadow(0 0 8px #7fd3ff);
}
.token.hopping { animation: hop-bounce .16s ease-out; z-index: 4; }
@keyframes pulse { 0%,100% { transform: scale(1) translateY(0); } 50% { transform: scale(1.1) translateY(-6%); } }
@keyframes hop-bounce {
  0% { transform: translateY(0) scale(1); }
  40% { transform: translateY(-42%) scale(0.96, 1.08); }
  100% { transform: translateY(0) scale(1); }
}

/* =========================================================================
   11. APP CHROME — everything outside the board itself (home screen, lobby,
   controls, modals, shop). Not covered by the board spec above, but built to
   match its variables/radii/shadow language for a consistent whole.
   ========================================================================= */
.home-inner { position: relative; max-width: 420px; margin: 0 auto; padding: 22px 20px 20px; width: 100%; }
/* Two soft "glow orb" layers behind the hero content — a contained echo of the reference's
   starfield atmosphere, without touching the global body background (keeps risk local to
   the home/gate screens only). Purely decorative, so they sit behind everything and ignore
   clicks. Slowly breathing rather than static — the "more alive" pass. */
#screen-home .home-inner::before, #screen-gate .gate-inner::before {
  content: ""; position: absolute; top: -40px; left: -60px; width: 260px; height: 260px;
  background: radial-gradient(circle, rgba(105,189,245,.18) 0%, transparent 70%);
  z-index: 0; pointer-events: none;
  animation: glow-breathe 6s ease-in-out infinite;
}
#screen-home .home-inner::after, #screen-gate .gate-inner::after {
  content: ""; position: absolute; top: 120px; right: -70px; width: 280px; height: 280px;
  background: radial-gradient(circle, rgba(212,169,74,.16) 0%, transparent 70%);
  z-index: 0; pointer-events: none;
  animation: glow-breathe 6s ease-in-out infinite 3s;
}
@keyframes glow-breathe { 0%, 100% { opacity: .7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.12); } }
#screen-home .home-inner > *, #screen-gate .gate-inner > * { position: relative; z-index: 1; }

/* Twinkling star particles — a handful of fixed points with a staggered fade/scale pulse,
   layered under the glow orbs above. Static markup (index.html's .star-field), not JS —
   there's nothing dynamic about where a star sits. */
.star-field { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.star-field .twinkle {
  position: absolute; width: 3px; height: 3px; border-radius: 50%;
  background: #fff; box-shadow: 0 0 4px 1px rgba(255,255,255,.8);
  animation: twinkle 3.2s ease-in-out infinite;
}
.star-field .twinkle:nth-child(1) { top: 8%; left: 12%; animation-delay: 0s; }
.star-field .twinkle:nth-child(2) { top: 15%; left: 78%; animation-delay: .5s; }
.star-field .twinkle:nth-child(3) { top: 30%; left: 45%; animation-delay: 1s; }
.star-field .twinkle:nth-child(4) { top: 55%; left: 88%; animation-delay: 1.6s; width: 2px; height: 2px; }
.star-field .twinkle:nth-child(5) { top: 68%; left: 20%; animation-delay: 2.1s; }
.star-field .twinkle:nth-child(6) { top: 82%; left: 60%; animation-delay: 2.6s; width: 2px; height: 2px; }
@keyframes twinkle { 0%, 100% { opacity: .15; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1.3); } }
/* Bold, layered "game logo" treatment — gold-gradient fill with a dark bevel and a soft
   glow behind it, in the spirit of the sample-ui reference's title art (we don't have
   custom illustrated wordmark art, so this is built entirely from CSS gradient/shadow
   layers rather than an image asset). */
.logo {
  font-family: var(--font-display);
  font-size: 42px; font-weight: 800; text-align: center; margin: 0 0 6px; letter-spacing: -0.01em;
  background: linear-gradient(180deg, var(--gold-light) 0%, var(--gold) 55%, var(--bronze) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0,0,0,.35)) drop-shadow(0 6px 14px rgba(0,0,0,.4));
  position: relative;
}
.logo::before {
  content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 220px; height: 90px; z-index: -1;
  background: radial-gradient(ellipse, rgba(244,209,110,.35) 0%, transparent 70%);
  pointer-events: none;
  animation: logo-glow-pulse 3s ease-in-out infinite;
}
@keyframes logo-glow-pulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: .75; }
  50% { transform: translate(-50%, -50%) scale(1.15); opacity: 1; }
}
.tagline { text-align: center; color: var(--ink-muted); margin: 0 0 28px; font-size: 14.5px; }

/* Onboarding gate (see index.html's #screen-gate) — the very first thing a brand-new
   player sees, so it gets its own vertically-centered, hero-style treatment rather than
   the top-packed layout every other Setup-style screen uses. */
#screen-gate .gate-inner {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 100%; text-align: center;
}
.gate-logo-wrap { margin-bottom: 10px; }
.gate-tagline { font-size: 16px; margin-bottom: 40px; padding: 0 8px; }
.gate-actions { display: flex; flex-direction: column; gap: 12px; }
.gate-actions .btn, .btn-icon-row { display: flex; align-items: center; justify-content: center; gap: 8px; }
.gate-hint { text-align: center; margin: 18px 0 0; }

.home-card { background: var(--panel); border: 1px solid var(--rule); border-radius: 18px; padding: 20px; box-shadow: 0 12px 30px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.05); }
.field { display: block; margin-bottom: 16px; }
.field span, .field-label { display: block; font-size: 12.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); margin-bottom: 6px; }
.field input {
  width: 100%; padding: 12px 14px; border-radius: 9px; border: 1px solid var(--rule);
  background: var(--panel-raised); color: var(--ink); font-size: 16px;
}
.field input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.name-row { display: flex; align-items: flex-end; gap: 10px; margin-bottom: 16px; }
.avatar-preview-btn {
  position: relative;
  flex-shrink: 0; width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  background: linear-gradient(155deg, var(--gold-light), var(--gold));
  border: 2px solid rgba(255,255,255,.5);
  box-shadow: 0 2px 0 var(--bronze), 0 4px 10px rgba(0,0,0,.35), inset 0 1px 1px rgba(255,255,255,.6);
  display: flex; align-items: center; justify-content: center; font-size: 22px;
}
/* Thin rotating ring accent — echoes the level/XP-bar motif already in the top bar. */
.avatar-preview-btn::after {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid transparent; border-top-color: var(--gold-light); border-right-color: var(--gold);
  animation: avatar-ring-spin 3s linear infinite; pointer-events: none;
}
@keyframes avatar-ring-spin { to { transform: rotate(360deg); } }
.avatar-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 16px 0; }
.avatar-grid-icon {
  aspect-ratio: 1; border-radius: 50%; cursor: pointer; font-size: 26px;
  background: var(--panel-raised); border: 2px solid var(--rule);
  display: flex; align-items: center; justify-content: center;
}
.avatar-grid-icon.selected { border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold) inset; }
.avatar-grid-icon:active { transform: scale(0.94); }

.btn { border: none; border-radius: var(--radius-btn); padding: 13px 18px; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 6px 14px rgba(0,0,0,.25); }
.btn-primary {
  background: linear-gradient(180deg, var(--gold-light) 0%, var(--gold) 60%, var(--bronze) 100%);
  color: #3a2506; font-weight: 800; text-shadow: 0 1px 0 rgba(255,255,255,.35);
  box-shadow: 0 3px 0 var(--bronze), 0 8px 16px rgba(0,0,0,.35), inset 0 1px 1px rgba(255,255,255,.5);
  border: 1px solid rgba(255,255,255,.3);
}
.btn-primary:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--bronze), 0 4px 8px rgba(0,0,0,.3), inset 0 1px 1px rgba(255,255,255,.5); }
.btn-secondary { background: var(--panel-raised); color: var(--ink); border: 1px solid var(--rule); box-shadow: none; }
/* A real, costly consequence (forfeit + coin penalty) — distinct from the gold "positive
   action" primary button and the neutral secondary one. */
.btn-danger {
  background: linear-gradient(180deg, #f2857c 0%, var(--red) 55%, var(--red-dark) 100%);
  color: #fff; font-weight: 800; text-shadow: 0 1px 2px rgba(0,0,0,.35);
  box-shadow: 0 3px 0 var(--red-dark), 0 8px 16px rgba(0,0,0,.35), inset 0 1px 1px rgba(255,255,255,.35);
  border: 1px solid rgba(255,255,255,.25);
}
.btn-danger:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--red-dark), 0 4px 8px rgba(0,0,0,.3), inset 0 1px 1px rgba(255,255,255,.35); }
.btn-text { background: transparent; color: var(--ink-muted); font-weight: 600; padding: 10px; box-shadow: none; }
.btn-block { width: 100%; display: block; }
.btn-facebook {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: #1877F2; color: #fff; box-shadow: 0 3px 0 #0d5bc4, 0 6px 12px rgba(0,0,0,.3);
}
.btn-facebook:active { transform: translateY(2px); box-shadow: 0 1px 0 #0d5bc4, 0 3px 6px rgba(0,0,0,.25); }
.btn-small { padding: 8px 12px; font-size: 13px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* Home hub: two big banner tiles ("Play Here" / "Play with Friends") in place of the old
   cramped tabs — each is its own tap target that opens a dedicated Setup screen, in the
   spirit of the sample-ui reference's separate hub-then-detail screens rather than one
   scrolling mega-card. */
/* Hero tiles ("Power" = Rush, "Classic" = Classic) — bigger, more prominent than the
   secondary nav tiles below, direct-launch shortcuts into a pre-selected mode. Reuses the
   same .mode-card-gold/.mode-card-blue gradients already defined for Setup's mode cards. */
.hero-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 18px 0; }
.hero-tile {
  position: relative; overflow: hidden;
  aspect-ratio: 1 / 0.95; border: none; border-radius: 20px; cursor: pointer; color: #fff;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  box-shadow: 0 10px 24px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.2);
  transition: transform .1s ease;
}
.hero-tile:active { transform: scale(0.97); }
/* "HOT" corner flag on the Power tile — Rush/Power-Play is the richer, newer mode, worth
   nudging players toward. Same corner-ribbon technique as .ribbon-selectable. */
/* Periodic diagonal shine sweep — a common "juicy" mobile-game tell that these two tiles
   are the primary tap targets, not static art. */
.hero-tile::after {
  content: ""; position: absolute; top: -20%; left: -60%; width: 40%; height: 140%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.4) 50%, transparent);
  transform: skewX(-20deg);
  animation: hero-shine 5s ease-in-out infinite;
  pointer-events: none; z-index: 1;
}
#btn-hero-classic::after { animation-delay: .4s; }
@keyframes hero-shine {
  0%, 20% { left: -60%; }
  55%, 100% { left: 140%; }
}
.hero-tile-badge {
  position: absolute; top: 12px; left: -30px; z-index: 2;
  transform: rotate(-45deg); transform-origin: center;
  background: linear-gradient(180deg, #ff8b7e, #ef3e36 55%, #a11f19 100%);
  color: #fff; font-family: var(--font-display); font-weight: 700; font-size: 11px; letter-spacing: .04em;
  padding: 2px 32px; box-shadow: 0 2px 4px rgba(0,0,0,.35);
}
.hero-tile-icon {
  font-size: 34px; width: 60px; height: 60px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.22);
  box-shadow: inset 0 2px 4px rgba(255,255,255,.4), inset 0 -3px 5px rgba(0,0,0,.2), 0 2px 4px rgba(0,0,0,.2);
}
.hero-tile-title { font-family: var(--font-display); font-weight: 700; font-size: 19px; text-shadow: 0 2px 2px rgba(0,0,0,.35); }

.nav-tiles { display: flex; flex-direction: column; gap: 14px; margin-top: 8px; }
.nav-tile {
  display: flex; align-items: center; gap: 14px; text-align: left;
  border: none; border-radius: 18px; padding: 18px 18px; cursor: pointer; color: #fff;
  box-shadow: 0 10px 24px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.2);
  transition: transform .1s ease;
}
.nav-tile:active { transform: scale(0.98); }
.nav-tile-gold { background: linear-gradient(155deg, #f6cf7c 0%, #dd9a34 55%, #a8641a 100%); }
.nav-tile-blue { background: linear-gradient(155deg, #83cdff 0%, #3d8bff 55%, #1c4fb0 100%); }
.nav-tile-icon {
  font-size: 32px; width: 58px; height: 58px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.22);
  box-shadow: inset 0 2px 4px rgba(255,255,255,.4), inset 0 -3px 5px rgba(0,0,0,.2), 0 2px 4px rgba(0,0,0,.2);
}
/* A light idle float on just the glyph (not the badge/shadow) so the screen reads as alive
   rather than static art, without the shadow jittering along with it. */
.nav-tile-icon .icon { animation: icon-float 2.6s ease-in-out infinite; }
#btn-nav-online .nav-tile-icon .icon { animation-delay: .4s; }
@keyframes icon-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
.nav-tile-text { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.nav-tile-title { font-family: var(--font-display); font-weight: 700; font-size: 17px; text-shadow: 0 2px 2px rgba(0,0,0,.35); }
.nav-tile-sub { font-size: 12.5px; line-height: 1.35; color: rgba(255,255,255,.9); text-shadow: 0 1px 2px rgba(0,0,0,.3); }
.nav-tile-arrow { font-size: 26px; font-weight: 800; opacity: .85; flex-shrink: 0; }

.setup-header { display: flex; align-items: center; gap: 6px; margin-bottom: 18px; }
.setup-header .icon-btn { font-size: 26px; color: var(--ink); padding: 4px 8px; }
.setup-title { font-size: 20px; font-weight: 800; margin: 0; }

.divider { text-align: center; color: var(--ink-muted); font-size: 12px; margin: 14px 0; position: relative; }
.divider span { background: var(--panel); padding: 0 10px; position: relative; z-index: 1; }
.divider::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--rule); }

.local-player-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.local-player-row { display: flex; align-items: center; gap: 10px; background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 9px; padding: 9px 12px; }
.local-player-row .swatch { width: 14px; height: 14px; border-radius: 4px; flex-shrink: 0; }
.local-player-row .label { flex: 1; font-size: 14px; font-weight: 600; }
.local-player-row select { background: var(--panel); color: var(--ink); border: 1px solid var(--rule); border-radius: 6px; padding: 6px 8px; font-size: 13px; }

.error-text { color: var(--red); font-size: 13px; margin-top: 10px; }

.room-code-display {
  font-family: ui-monospace, Consolas, monospace; letter-spacing: .16em; font-size: 26px; font-weight: 800;
  text-align: center; color: #3a2506;
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
  border: 1px solid rgba(255,255,255,.4); border-radius: 12px; padding: 12px 10px;
  box-shadow: 0 3px 0 var(--bronze), 0 6px 14px rgba(0,0,0,.3), inset 0 1px 1px rgba(255,255,255,.5);
}
.lobby-player-list { list-style: none; padding: 0; margin: 20px 0; display: flex; flex-direction: column; gap: 8px; }
.lobby-player-list li {
  display: flex; align-items: center; gap: 10px; font-size: 14.5px; font-weight: 700;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 100px; padding: 10px 16px;
}
.lobby-player-list .swatch { width: 14px; height: 14px; border-radius: 50%; box-shadow: 0 0 0 2px rgba(255,255,255,.25); }

/* justify-content:flex-end (not space-between) — the player-chip row that used to sit on
   the left is gone now that every seat's name/avatar already shows at its own board
   corner (see renderCornerDice/renderBaseLabels); this row is just the mute/exit controls. */
/* A real bar panel (not icons floating directly on the page background) — gives the HUD a
   designed, intentional footprint, matching the "tray" treatment on the bottom controls. */
.game-topbar {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  max-width: 480px; margin: 0 auto 20px; width: 100%;
  background: rgba(20,14,40,.35); border: 1px solid rgba(255,255,255,.07);
  border-radius: 16px; padding: 8px 10px;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
}
.topbar-right { display: flex; align-items: center; gap: 8px; }

/* Two rows of 2 avatar+dice "pairs" flanking the board (see index.html's #top-players-row/
   #bottom-players-row/#pair-slot-*) — a real flex row per side instead of 4 independently
   absolutely-positioned corners, so straight-line alignment is guaranteed by layout rather
   than by 4 separately hand-tuned offsets. 20px off the topbar and the board on both sides,
   matching .game-topbar's own margin-bottom and this row's own margin below. */
.players-row {
  display: flex; align-items: center; justify-content: space-between;
  max-width: 480px; margin: 0 auto 20px; width: 100%; min-height: 44px;
}
#bottom-players-row { margin: 20px auto 0; }
/* Avatar<->die gap is exactly the flex gap — no manual offset math. .mirror (the two
   right-hand slots) reverses draw order so the avatar still hugs the outer/screen edge and
   the die sits toward the board's center, mirroring the left-hand slots. */
.player-pair { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.player-pair.mirror { flex-direction: row-reverse; }
.icon-btn { background: transparent; border: none; color: var(--ink-muted); font-size: 17px; padding: 6px; cursor: pointer; line-height: 1; }
/* In-game top bar only: mute + Exit as matching rounded icon chips, closer to the
   reference's icon-button row than plain borderless icons/text. */
.game-topbar .icon-btn {
  width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 12px; padding: 0;
}
.game-topbar .icon-btn .icon { width: 21px; height: 21px; }
/* Subtle warning tint — this now carries a real, irreversible cost (forfeit + coin
   penalty, see the confirm-exit modal), worth visually distinguishing from Mute. */
.game-topbar #btn-leave-game {
  background: rgba(237,91,84,.14); border: 1px solid rgba(237,91,84,.5); color: #ffd3d0;
  border-radius: 12px; padding: 10px 16px; font-size: 14px;
}
.game-controls { max-width: 480px; margin: 0 auto; width: 100%; padding-bottom: 10px; }

/* Emoji + Chat buttons — anchored to the bottom-left pair slot specifically (see
   index.html), which is always where the local viewer's own seat ends up after
   per-viewer rotation, so these read as "your" controls next to "your" avatar, not a
   neutral shared-row control off to the side. Taken out of .player-pair's own flex flow
   (position:absolute) so it doesn't crowd into that row alongside the avatar/dice
   themselves — stacked vertically below the pair instead, matching the reference's own
   vertical Emoji/Chat arrangement. */
.social-row {
  position: absolute; top: 100%; left: 0; margin-top: 8px;
  display: flex; flex-direction: row; gap: 8px; z-index: 20;
}
.social-btn {
  width: 38px; height: 38px; flex-shrink: 0; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 50%;
  color: var(--ink-muted); cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,.25);
}
.social-btn:active { transform: scale(0.92); }

/* A small anchored panel right beside the Emoji/Chat buttons (matching the reference's
   power-play/premade-emo.jpeg and pre-messge.jpeg) instead of a centered, dimmed modal —
   no backdrop, just a lightweight "quick access" popover with a pointer tail. Opens to the
   right (left:100%) since the buttons themselves now sit at the screen's left edge — a
   popover expanding further left would run off-stage. */
.social-popover {
  position: absolute; left: 100%; bottom: 0; margin-left: 10px;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 14px;
  padding: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.5); width: 240px; z-index: 45;
}
.social-popover::after {
  content: ""; position: absolute; right: 100%; bottom: 14px;
  width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent;
  border-right: 9px solid var(--panel);
}

.emoji-picker-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.emoji-picker-btn {
  background: var(--panel-raised); border: 2px solid var(--rule); border-radius: 12px;
  padding: 8px 0; font-size: 24px; line-height: 1; cursor: pointer;
}
.emoji-picker-btn:active { transform: scale(0.9); }

.chat-presets { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 10px; }
.chat-preset-btn {
  background: #fff; color: var(--panel); border: none; border-radius: 100px;
  padding: 9px 6px; font-weight: 700; font-size: 12.5px; cursor: pointer; text-align: center;
}
.chat-preset-btn:active { transform: scale(0.96); }
.chat-input-row { display: flex; gap: 8px; }
.chat-input-row input {
  flex: 1; min-width: 0; padding: 9px 12px; border-radius: 9px; border: 1px solid var(--rule);
  background: var(--panel-raised); color: var(--ink); font-size: 13px;
}
.chat-input-row .btn { flex-shrink: 0; }

/* Emoji reactions and chat bubbles pop up above the sender's own avatar+dice pair, white
   background, matching power-play/message-popup.jpeg and emoji-popup.jpeg — a real z-index
   (not just DOM order) guarantees it renders above the board even for the bottom row's
   seats, where "above the pair" points back up toward the board's own bottom edge.
   Anchored to .player-pair itself (not the avatar alone) so it's centered over both the
   avatar and the die together, and stays correctly positioned regardless of which of the 4
   on-screen corners that pair currently occupies (see app.js's renderCornerDice). */
.player-pair { position: relative; }
.player-pair-social {
  position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  margin-bottom: 8px; display: flex; gap: 6px; z-index: 60; pointer-events: none;
}
/* One unified keyframe (not two overlapping animations) since both would otherwise fight
   over the same `transform` property once the shorter one finishes. No translateX needed
   here — these are normal flex items now, centered by their .player-pair-social parent, not
   individually. */
.reaction-bubble, .chat-bubble {
  position: relative; background: #fff; box-shadow: 0 6px 16px rgba(0,0,0,.5);
  animation: reaction-life 2.5s ease-out forwards;
}
/* Downward-pointing tail — both bubble types sit above the pair, pointing back down at it. */
.reaction-bubble::after, .chat-bubble::after {
  content: ""; position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
  width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent;
  border-top: 8px solid #fff;
}
@keyframes reaction-life {
  0% { transform: scale(0.3); opacity: 0; }
  15% { transform: scale(1.15); opacity: 1; }
  25% { transform: scale(1); opacity: 1; }
  80% { transform: scale(1); opacity: 1; }
  100% { transform: scale(1); opacity: 0; }
}

/* Big and expressive, like a sticker — legible at a glance, matching the reference's large
   emoji-popup treatment rather than a small icon-sized badge. */
.reaction-bubble { font-size: 40px; line-height: 1; border-radius: 16px; padding: 4px 8px; }

/* Same "shown once, removed by app.js after a fixed delay, never a log" model as
   .reaction-bubble, just longer-lived (there's text to actually read) — bold, dark-on-white
   text sized to actually be legible at a glance, matching power-play/message-popup.jpeg. */
.chat-bubble {
  max-width: 150px; min-width: 44px; width: max-content;
  border-radius: 14px; padding: 8px 14px;
  font-size: 15px; font-weight: 800; color: var(--panel); text-align: center;
  animation-duration: 5s;
}

/* Rush/Power-Play inventory (see app.js's renderPowerBar) — hidden entirely outside a
   Power-Play match, so Classic's game-controls footer is unchanged. A real grounded "tray"
   panel (not pills floating directly on the page background) with bigger, labeled buttons —
   easy to miss at the previous size. */
.power-bar {
  /* Extra clearance above the tray — the Emoji/Chat buttons now float (position:absolute,
     out of document flow) just below the bottom-left avatar+dice pair, right above where
     this tray would otherwise start; pushing it down keeps the two from visually colliding. */
  display: flex; gap: 10px; margin-top: 46px; padding: 10px;
  background: rgba(20,14,40,.32); border: 1px solid rgba(255,255,255,.07);
  border-radius: 16px; box-shadow: 0 4px 14px rgba(0,0,0,.2);
}
.power-bar-btn {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: var(--panel-raised); border: 2px solid var(--rule); border-radius: 14px;
  padding: 10px 6px; font-weight: 800; font-size: 13px; color: var(--ink); cursor: pointer;
}
.power-bar-btn:disabled { opacity: 0.45; cursor: default; }
/* "Armed" = tap again (or tap a token) to complete/cancel — an active mode, not just a
   count readout, so it gets its own visibly-different state from the resting button. */
.power-bar-btn.armed { border-color: #7fd3ff; box-shadow: 0 0 0 2px rgba(127,211,255,.35); }
.power-bar-icon { display: block; flex-shrink: 0; }
.power-bar-label { font-size: 11px; font-weight: 700; letter-spacing: .01em; white-space: nowrap; }

/* Dice Control's face picker (see app.js's openDiceControlPicker) — six real .dice faces
   (renderDiceFace reused as-is) in a grid, tap one to spend a charge and arm that face. */
.dice-control-card { max-width: 380px; }
.dice-control-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 18px; }
.dice-face-btn {
  background: none; border: none; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.dice-face-btn .dice { cursor: pointer; }
.dice-face-btn:active .dice { transform: translateY(2px); box-shadow: 0 1px 0 #c9bd97, 0 2px 6px rgba(0,0,0,.3); }

/* Idle-timer indicator: a radial "pie" countdown inscribed inside the dice face — a full
   green circle at the start of the turn, sweeping away clockwise (conic-gradient, driven
   by app.js's startTurnTimerIfNeeded) like a clock hand as the 10s runs out, rather than
   just fading in place. A round inset (not a full-square fill) so the dice's own corners
   stay visibly cream-colored even at full time — it reads as a clock face on the dice,
   not a flat color wash. Fixed, constant opacity: depletion is conveyed by the shrinking
   wedge shape itself, not by fading. */
.dice-wrap { position: relative; flex-shrink: 0; }

/* Turn HUD — matches sample-ui/6. actual-game.jpeg: the real dice (restyled as a green
   roll-box) connected by an arrow to whoever's turn it is, avatar-first. Only shown when
   there's a single clear viewer (solo-vs-bots, online — see app.js's isQuadDiceMode);
   local pass-and-play keeps the per-corner dice below instead. Shares the same container
   width as .game-topbar/.board-wrap so its right edge lines up with theirs. */
.turn-hud {
  position: relative;
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  max-width: 480px; margin: 0 auto 4px; width: 100%; padding: 6px 14px 0 0;
}
.turn-hud::before {
  content: ""; position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  width: 180px; height: 110px; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse, rgba(244,209,110,.22) 0%, transparent 72%);
}
/* Compound .dice.dice-rollbox (not just .dice-rollbox) so these deliberately outrank the
   base .dice rules below regardless of source order — equal-specificity single-class
   selectors would otherwise lose to whichever comes later in the file. */
.dice.dice-rollbox {
  width: 52px; height: 52px; border-radius: 12px;
  background: linear-gradient(155deg, var(--green-light, #6fd485) 0%, var(--green, #2fa84f) 55%, var(--green-dark, #166a2e) 100%);
  box-shadow: inset 0 2px 3px rgba(255,255,255,.5), inset 0 -4px 6px rgba(0,0,0,.25), 0 4px 10px rgba(0,0,0,.4);
  border: 1px solid rgba(255,255,255,.25);
}
.dice.dice-rollbox .pip.on { background: radial-gradient(circle at 35% 30%, #e8685a, #a3241a 75%); box-shadow: 0 1px 1px rgba(0,0,0,.4); }
.turn-hud-arrow-tail {
  position: relative; z-index: 1; flex-shrink: 0;
  width: 0; height: 0; border-top: 9px solid transparent; border-bottom: 9px solid transparent;
  border-left: 11px solid var(--green, #2fa84f); margin-left: -6px;
  filter: drop-shadow(1px 1px 1px rgba(0,0,0,.3));
}
.turn-hud-avatar-wrap {
  position: relative; z-index: 1; flex-shrink: 0; background: none; border: none; padding: 0; cursor: default;
}
.turn-hud-avatar-wrap:disabled, .turn-hud-avatar-wrap.no-gift { cursor: default; }
.turn-hud-avatar {
  width: 64px; height: 64px; border-radius: 50%;
  background: linear-gradient(155deg, var(--blue-light, #93d9ff) 0%, var(--blue, #3d8bff) 55%, var(--blue-dark, #123f97) 100%);
  display: flex; align-items: center; justify-content: center; font-size: 34px;
  border: 3px solid rgba(255,255,255,.9);
  box-shadow: 0 3px 0 rgba(0,0,0,.2), 0 6px 16px rgba(0,0,0,.45), inset 0 2px 3px rgba(255,255,255,.5);
}
.turn-hud-gift {
  position: absolute; top: -7px; left: -7px; width: 25px; height: 25px; border-radius: 50%;
  background: linear-gradient(155deg, #ff8b7e, #ef3e36 55%, #a11f19 100%);
  display: flex; align-items: center; justify-content: center; font-size: 13px;
  border: 2px solid var(--panel); box-shadow: 0 2px 6px rgba(0,0,0,.4), inset 0 1px 1px rgba(255,255,255,.4);
  cursor: pointer;
}
.turn-hud-avatar-wrap[data-clickable="true"] { cursor: pointer; }

/* The local viewer's own avatar, floating below the board (see index.html's comment on
   #viewer-avatar-float for when this shows). */
.viewer-avatar-float {
  width: 56px; height: 56px; border-radius: 50%;
  background: linear-gradient(155deg, var(--gold-light), var(--gold) 55%, var(--bronze) 100%);
  display: flex; align-items: center; justify-content: center; font-size: 30px;
  border: 3px solid rgba(255,255,255,.9);
  box-shadow: 0 3px 0 var(--bronze), 0 6px 16px rgba(0,0,0,.4), inset 0 2px 3px rgba(255,255,255,.6);
  margin: 4px 0 16px 12px;
}

.dice-timer-ring {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 52px; height: 52px; border-radius: 50%;
  opacity: 0.65;
  z-index: 0; pointer-events: none;
}
.dice {
  position: relative;
  width: 66px; height: 66px; border-radius: 16px; cursor: pointer;
  background: #fbf8f0; border: none; box-shadow: 0 4px 0 #c9bd97, 0 6px 14px rgba(0,0,0,.25);
  padding: 9px; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr);
  gap: 2px;
}
.dice:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 1px 0 #c9bd97, 0 2px 6px rgba(0,0,0,.3); }
.dice:disabled { opacity: .45; cursor: not-allowed; }
.dice .pip { position: relative; z-index: 1; border-radius: 50%; background: transparent; align-self: center; justify-self: center; width: 100%; height: 100%; }
.dice .pip.on { background: #241a04; }
.dice.rolling { animation: dice-shake .5s ease; }

/* One dice per seat, for every real game (local or online — see app.js's isQuadDiceMode).
   Only the currently-active seat's die is ever unhidden; app.js's renderCornerDice moves it
   (a plain appendChild, see .player-pair) into whichever slot matches its color's current
   on-screen quadrant. Sits in normal flex flow now (see .player-pair's own gap) rather than
   being absolutely positioned per corner, so it just inherits .dice's rolling/:active
   behavior below unchanged — no separate rotation-aware keyframes needed now that it's
   upright in a row instead of hugging a rotated board corner. */
.corner-dice { width: 50px; height: 50px; padding: 6px; flex-shrink: 0; }
.corner-dice .dice-timer-ring { width: 45px; height: 45px; }

/* Fixed seat avatar — one per color in the match, always in its own slot (see app.js's
   renderCornerDice); only .corner-dice above ever moves between slots. Sized closer to
   sample-ui/ludo.png's own avatar-vs-dice proportions (avatar a little larger than the die,
   not a tiny badge). */
.corner-avatar {
  position: relative;
  width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 24px;
  background: linear-gradient(155deg, var(--gold-light), var(--gold) 55%, var(--bronze) 100%);
  border: 3px solid rgba(255,255,255,.9);
  box-shadow: 0 3px 0 rgba(0,0,0,.2), 0 6px 14px rgba(0,0,0,.4), inset 0 2px 3px rgba(255,255,255,.5);
  transition: transform .2s ease, box-shadow .2s ease;
}
/* Idle-timer countdown ring — moved here from the die (see app.js's setDiceTimerWedge/
   startTurnTimerIfNeeded), matching the reference: a colored ring around the active
   player's own avatar, sweeping away clock-hand style as their turn's time runs out,
   instead of a ring inscribed in the dice face. --timer-deg is driven entirely from JS. */
.corner-avatar::before {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  background: conic-gradient(var(--green) var(--timer-deg, 360deg), transparent var(--timer-deg, 360deg) 360deg);
  opacity: 0; pointer-events: none; transition: opacity .15s ease;
}
.corner-avatar.timer-active::before { opacity: 1; }
/* Whose turn it is reads from the avatar itself now — no separate "Your turn (X)" text line
   (see app.js's renderCornerDice). transform doesn't affect flex layout, so the row's
   straight-line alignment/gap holds even while this one avatar grows. */
.corner-avatar.active-turn {
  transform: scale(1.16);
  box-shadow: 0 0 0 3px var(--accent), 0 3px 0 rgba(0,0,0,.2), 0 6px 14px rgba(0,0,0,.4), inset 0 2px 3px rgba(255,255,255,.5);
  animation: active-turn-pulse 1.6s ease-in-out infinite;
}
@keyframes active-turn-pulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--accent), 0 3px 0 rgba(0,0,0,.2), 0 6px 14px rgba(0,0,0,.4), inset 0 2px 3px rgba(255,255,255,.5); }
  50% { box-shadow: 0 0 0 5px var(--accent), 0 3px 0 rgba(0,0,0,.2), 0 6px 20px rgba(244,167,27,.6), inset 0 2px 3px rgba(255,255,255,.5); }
}

@keyframes dice-shake {
  0%, 100% { transform: rotate(0) scale(1); }
  20% { transform: rotate(-14deg) scale(1.05); }
  40% { transform: rotate(12deg) scale(1.05); }
  60% { transform: rotate(-10deg) scale(1.05); }
  80% { transform: rotate(8deg) scale(1.05); }
}
.modal { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px; }
.modal-card {
  position: relative; z-index: 1;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 18px; padding: 26px;
  max-width: 340px; width: 100%; text-align: center;
  box-shadow: 0 16px 40px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.06);
}

/* Win-screen confetti burst — small CSS particles falling/spinning past the result card,
   generated fresh (see app.js's spawnConfetti) each time a match is won. No library/assets,
   same "build it from CSS" approach used throughout this project. */
.confetti-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.confetti-piece {
  position: absolute; top: -14px; width: 8px; height: 14px; opacity: 0;
  animation: confetti-fall linear forwards;
}
@keyframes confetti-fall {
  0% { opacity: 1; transform: translateY(0) rotate(0deg); }
  100% { opacity: 0; transform: translateY(480px) rotate(600deg); }
}
.modal-card h2 { font-family: var(--font-display); font-weight: 700; margin: 0 0 8px; display: flex; align-items: center; justify-content: center; gap: 8px; }
.modal-card p { color: var(--ink-muted); margin: 0 0 20px; }

.daily-bonus-card { max-width: 360px; padding-top: 0; overflow: hidden; }
/* Lightweight CSS ribbon-banner strip (bleeds to the modal-card's own edges via negative
   margins matching its 26px padding) — a pennant shape via clip-path, in place of a real
   bow-ribbon illustration asset. */
.daily-bonus-banner {
  margin: 0 -26px 20px; padding: 18px 26px 14px;
  background: linear-gradient(180deg, #ef6a63 0%, #c63e38 100%);
  clip-path: polygon(0% 0%, 100% 0%, 100% 85%, 85% 100%, 50% 88%, 15% 100%, 0% 85%);
  box-shadow: 0 4px 10px rgba(0,0,0,.25);
}
.daily-bonus-banner h2 { color: #fff; margin: 0; text-shadow: 0 2px 2px rgba(0,0,0,.3); }
.daily-bonus-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.daily-day-card {
  background: var(--panel-raised); border: 2px solid var(--rule); border-radius: 12px;
  padding: 10px 4px; display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.daily-day-icon { width: 22px; height: 22px; }
.daily-day-card.daily-day-wide { grid-column: 1 / -1; flex-direction: row; justify-content: center; gap: 10px; }
.daily-day-label { font-size: 11px; font-weight: 700; color: var(--ink-muted); text-transform: uppercase; letter-spacing: .04em; }
.daily-day-amount { font-size: 14px; font-weight: 800; }
.daily-day-card.current {
  border-color: var(--gold); color: #241a04;
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
  box-shadow: 0 3px 8px rgba(0,0,0,.3);
}
.daily-day-card.current .daily-day-label { color: rgba(36,26,4,.7); }
.daily-day-card.claimed { opacity: .4; }
.daily-bonus-actions { display: flex; gap: 10px; }
.daily-bonus-actions .btn { flex: 1; }

.checklist-items { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.checklist-item {
  display: flex; align-items: center; gap: 12px; text-align: left;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 12px; padding: 12px 14px;
}
.checklist-item-text { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.checklist-item-title { font-weight: 700; font-size: 14.5px; }
.checklist-item-sub { font-size: 12.5px; color: var(--ink-muted); }

.toast {
  position: fixed; left: 50%; top: 16px; transform: translateX(-50%);
  background: var(--panel-raised); border: 1px solid var(--accent); color: var(--ink);
  padding: 10px 16px; border-radius: 10px; font-size: 13.5px; font-weight: 700; z-index: 60;
  box-shadow: 0 6px 20px rgba(0,0,0,.4);
  max-width: 300px; text-align: center; line-height: 1.4;
}

.ad-banner {
  position: fixed; left: 0; right: 0; bottom: 0; height: var(--banner-h);
  background: #0c0e11; border-top: 1px solid var(--rule);
  display: flex; align-items: center; justify-content: center; z-index: 40;
}
.ad-banner-placeholder { color: var(--ink-muted); font-size: 11px; padding: 0 12px; text-align: center; }

/* Slim bottom bar (Home/Setup/Lobby only), sitting directly above the ad banner. Only real,
   working features live here — Shop and Invite — no fake Ranking/Mission/Backpack icons. */
.app-bottombar {
  position: fixed; left: 0; right: 0; bottom: var(--banner-h); height: var(--bottombar-h);
  background: var(--panel); border-top: 1px solid var(--rule);
  display: flex; z-index: 41;
}
.bottombar-btn {
  flex: 1; display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 6px;
  background: transparent; border: none; color: var(--ink-muted); font-size: 12.5px; font-weight: 700; cursor: pointer;
  text-decoration: none;
}
.bottombar-btn:active { color: var(--ink); }
.bottombar-icon { font-size: 16px; }

.field-hint { font-size: 12px; color: var(--ink-muted); margin: -4px 0 14px; }

/* Persistent top bar (Home/Setup/Lobby — hidden during Game, which has its own).
   Sticky rather than fixed: pins to the viewport top while scrolling a tall Setup panel,
   without needing extra body padding math the way the fixed ad banner/bottom bar do. */
.app-topbar {
  position: sticky; top: 0; z-index: 30; min-height: var(--topbar-h);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 16px;
  background: rgba(28, 23, 59, .92); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
}
/* Real circular chip background (matching the in-game topbar's own .icon-btn treatment
   below) instead of a bare glyph floating on transparent — reads as a tappable button. */
.app-topbar .icon-btn {
  position: relative;
  width: 36px; height: 36px; flex-shrink: 0; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 50%;
  box-shadow: 0 2px 6px rgba(0,0,0,.25);
}
.app-topbar .icon-btn .icon { width: 18px; height: 18px; }
/* Small red dot badge — Checklist uses this when there's something unclaimed waiting
   (see app.js's renderChecklistBadge), matching the reference's clipboard-with-badge icon. */
.icon-btn-badge {
  position: absolute; top: 1px; right: 1px; width: 10px; height: 10px; border-radius: 50%;
  background: var(--red); border: 1.5px solid var(--panel);
}
.profile-level { display: flex; align-items: center; gap: 8px; flex: 1; }
.level-badge {
  font-family: var(--font-display);
  width: 34px; height: 34px; border-radius: 50%; color: #241a04;
  background: linear-gradient(155deg, var(--gold-light), var(--gold));
  box-shadow: 0 2px 0 var(--bronze), 0 4px 10px rgba(0,0,0,.35), inset 0 1px 1px rgba(255,255,255,.6);
  border: 2px solid rgba(255,255,255,.5);
  display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; flex-shrink: 0;
}
.xp-track { flex: 1; height: 8px; border-radius: 100px; background: var(--panel-raised); border: 1px solid var(--rule); overflow: hidden; max-width: 140px; box-shadow: inset 0 2px 3px rgba(0,0,0,.3); }
.xp-fill { height: 100%; background: linear-gradient(90deg, var(--accent), #ffd873); width: 0%; transition: width .4s ease; box-shadow: 0 0 6px rgba(244,209,110,.6); }
.coin-pill {
  display: flex; align-items: center; gap: 5px; color: #fff2cf; font-weight: 800; font-size: 13.5px; cursor: pointer;
  background: linear-gradient(180deg, var(--panel-raised), var(--panel));
  border: 1.5px solid var(--gold); border-radius: 100px; padding: 6px 10px 6px 6px;
  box-shadow: 0 3px 8px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.08);
}
.coin-pill.small { padding: 6px 12px 6px 7px; font-size: 13.5px; cursor: default; }
/* The icon-coin symbol is already a complete gold badge (circle + rim + star) — this
   wrapper is just a sizing/centering box now, not a second background underneath it. */
.coin-pill .coin-icon { width: 18px; height: 18px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.coin-pill .coin-icon .icon { width: 100%; height: 100%; }
.coin-pill.small .coin-icon { width: 18px; height: 18px; }
.coin-pill .plus { color: var(--accent); font-size: 15px; margin-left: 2px; }

.mode-cards { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
/* Big, colorful, icon-led cards in the spirit of the sample-ui reference's illustrated
   POWER/CLASSIC cards — built from gradients + an emoji "badge" rather than custom
   illustration art, since we don't have character/pawn artwork assets to draw from. */
.mode-card {
  display: flex; align-items: center; gap: 14px; text-align: left;
  border: none; border-radius: 14px; padding: 14px 16px; cursor: pointer; color: #fff;
  box-shadow: 0 6px 16px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.18);
  transition: transform .1s ease;
}
.mode-card:active { transform: scale(0.98); }
.mode-card-gold   { background: linear-gradient(155deg, #f6cf7c 0%, #dd9a34 55%, #a8641a 100%); }
.mode-card-blue   { background: linear-gradient(155deg, #83cdff 0%, #3d8bff 55%, #1c4fb0 100%); }
.mode-card-purple { background: linear-gradient(155deg, #cdb0ff 0%, #8f66f2 55%, #5a34ad 100%); }
.mode-card.selected {
  box-shadow: 0 0 0 3px var(--accent), 0 8px 20px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.25);
}
.mode-card-icon {
  font-size: 28px; width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.22);
  box-shadow: inset 0 2px 4px rgba(255,255,255,.4), inset 0 -3px 5px rgba(0,0,0,.2), 0 2px 4px rgba(0,0,0,.2);
}
.mode-card-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mode-card .mode-name { font-family: var(--font-display); font-weight: 700; font-size: 16px; text-shadow: 0 2px 2px rgba(0,0,0,.35); }
.mode-card .mode-blurb { font-size: 12px; line-height: 1.35; color: rgba(255,255,255,.9); text-shadow: 0 1px 2px rgba(0,0,0,.3); }

/* "Select Players" / "Choose Bet" — styled after the sample-ui player-selection
   reference: a titled card per section, tap tiles for player count, a stepper flanking a
   dark Win/Entry readout for the bet. */
.setup-section { background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 14px; padding: 14px; margin-bottom: 16px; }
.setup-section-title { text-align: center; font-weight: 800; font-size: 15px; margin: 0 0 12px; }
.setup-section-title-row { position: relative; margin: 0 0 12px; }
.setup-section-title-row .setup-section-title { margin: 0; }
.help-btn {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; border-radius: 50%; background: var(--panel); border: 1px solid var(--rule);
  display: flex; align-items: center; justify-content: center; color: var(--ink-muted); padding: 0;
}
.help-btn .icon { width: 13px; height: 13px; }
.bet-amount-value { display: inline-flex; align-items: center; gap: 4px; }
/* Tighter variant for the online panel's bet stepper — that screen already stacks mode
   cards, a teams toggle, this card, and the create/join controls in one scroll area, so it
   trims the padding/title-margin the full .setup-section card uses elsewhere (which has
   more breathing room to spare) rather than risk pushing "Join room" behind the fixed
   bottom bar on shorter viewports. */
.setup-section-compact { padding: 8px 14px; margin-bottom: 10px; }
.setup-section-compact .setup-section-title { margin-bottom: 6px; font-size: 14px; }

.player-select-tiles { display: flex; gap: 10px; }
.player-select-tile {
  flex: 1; background: var(--panel); border: 2px solid var(--rule); border-radius: 12px;
  padding: 14px 4px; text-align: center; font-weight: 800; font-size: 14px; color: var(--ink); cursor: pointer;
  transition: transform .1s ease;
}
.player-select-tile.selected {
  border-color: var(--blue); color: #fff;
  background: linear-gradient(155deg, var(--blue), var(--blue-dark));
  box-shadow: 0 3px 8px rgba(0,0,0,.3);
}
.player-select-tile:active { transform: scale(0.96); }

.bet-stepper-row { display: flex; align-items: center; justify-content: center; gap: 14px; }
.bet-readout {
  flex: 1; max-width: 220px; background: #1c1748; border: 1px solid var(--rule); border-radius: 10px;
  padding: 10px 14px; box-shadow: inset 0 2px 6px rgba(0,0,0,.4);
}
.bet-readout-row { display: flex; align-items: center; justify-content: space-between; font-weight: 800; font-size: 14px; padding: 3px 0; }
.bet-readout-row span:first-child { color: var(--ink-muted); font-weight: 700; font-size: 13px; }
.bet-readout-row span:last-child { color: var(--accent); }

.online-teams-toggle { display: flex; gap: 8px; margin-bottom: 10px; }
/* The online Setup panel already stacks mode cards, this toggle, the bet card, and the
   create/join controls in one scroll area — tighter than the shop's own use of .divider
   (which has more vertical room to spare), to keep "Join room" and its own shortfall
   prompt clear of the fixed bottom bar on shorter viewports. */
#mode-online .divider { margin: 8px 0; }
.online-teams-btn {
  flex: 1; background: var(--panel-raised); border: 2px solid var(--rule); border-radius: 100px;
  padding: 9px 4px; text-align: center; font-weight: 700; font-size: 13px; color: var(--ink); cursor: pointer;
}
.online-teams-btn.selected {
  border-color: var(--gold); color: #241a04;
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
}

.account-tabs { display: flex; gap: 8px; margin: 16px 0; }
.account-tab-btn {
  flex: 1; background: var(--panel-raised); border: 2px solid var(--rule); border-radius: 100px;
  padding: 9px 4px; text-align: center; font-weight: 700; font-size: 13px; color: var(--ink); cursor: pointer;
}
.account-tab-btn.active {
  border-color: var(--gold); color: #241a04;
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
}
.account-panel .field { text-align: left; }

.stepper-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.stepper {
  display: flex; align-items: center; gap: 12px; background: var(--panel-raised);
  border: 1px solid var(--rule); border-radius: 100px; padding: 4px; box-shadow: inset 0 2px 4px rgba(0,0,0,.25);
}
.stepper-btn {
  width: 30px; height: 30px; border-radius: 50%; border: none; color: #fff; font-size: 16px; font-weight: 800; cursor: pointer;
  background: linear-gradient(155deg, var(--blue), var(--blue-dark));
  box-shadow: 0 2px 0 rgba(0,0,0,.25), 0 3px 6px rgba(0,0,0,.3), inset 0 1px 1px rgba(255,255,255,.4);
}
.stepper-btn:active:not(:disabled) { transform: translateY(1px); box-shadow: 0 1px 0 rgba(0,0,0,.25), inset 0 1px 1px rgba(255,255,255,.4); }
.stepper-btn:disabled { opacity: .4; cursor: not-allowed; }
.stepper-btn-lg { width: 40px; height: 40px; font-size: 20px; flex-shrink: 0; }
#stepper-value { min-width: 18px; text-align: center; font-weight: 800; font-size: 15px; }

.result-badge { font-size: 44px; margin-bottom: 6px; display: flex; align-items: center; justify-content: center; }
.standings-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.standings-row {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 8px; padding: 7px 12px;
}
.standings-place { min-width: 26px; font-weight: 800; font-size: 13px; color: var(--ink-muted); }
.standings-row:first-child .standings-place { font-size: 16px; }
.standings-row .swatch { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; box-shadow: 0 0 0 2px rgba(255,255,255,.25); }
.standings-name { font-weight: 700; font-size: 14px; }
.result-rewards { background: var(--panel-raised); border: 1px solid var(--rule); border-radius: 10px; padding: 10px 14px; margin: 0 0 14px; }
.reward-row { display: flex; justify-content: space-between; font-size: 14px; font-weight: 700; padding: 4px 0; }
.reward-row span:last-child { color: var(--accent); }
.level-up-banner { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--accent); border-radius: 8px; padding: 8px; font-weight: 800; font-size: 13px; margin: -6px 0 14px; }

.shop-ad-btn { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; gap: 10px; }
.shop-ad-btn-label { display: inline-flex; align-items: center; gap: 8px; }
.play-chip {
  width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(155deg, var(--green-light, #7fe3a0), var(--green, #2fa84f) 65%, var(--green-dark, #166a2e) 100%);
  display: flex; align-items: center; justify-content: center; color: #fff;
  box-shadow: 0 2px 4px rgba(0,0,0,.3), inset 0 1px 1px rgba(255,255,255,.4);
}
.shop-reward { color: var(--accent); font-weight: 800; }
.shop-packages { display: flex; flex-direction: column; gap: 10px; margin: 14px 0; }
.shop-package {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 12px; background: var(--panel-raised);
  border: 1px solid var(--rule); border-radius: 12px; padding: 10px 14px; cursor: pointer; color: var(--ink);
}
.shop-package .pkg-icon { flex-shrink: 0; }
.shop-package .pkg-text { flex: 1; text-align: left; display: flex; flex-direction: column; gap: 1px; }
.shop-package .pkg-coins { font-family: var(--font-display); font-weight: 700; font-size: 15px; }
.shop-package .pkg-price { color: var(--ink-muted); font-size: 13px; font-weight: 700; }
.shop-package.best { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.shop-package.best::before {
  content: "BEST VALUE"; position: absolute; top: 8px; right: -28px;
  transform: rotate(40deg); transform-origin: center;
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
  color: #3a2506; font-size: 9.5px; font-weight: 800; letter-spacing: .03em;
  padding: 2px 30px; box-shadow: 0 2px 4px rgba(0,0,0,.3);
}

/* =========================================================================
   BOOT / LOADING SCREEN (Facebook Instant Games + web)
   ========================================================================= */
.boot-loader {
  position: fixed; inset: 0; z-index: 9999; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px;
  background: radial-gradient(120% 120% at 50% 30%, var(--bg-1), var(--bg-3) 60%, var(--bg-4));
  transition: opacity .35s ease, visibility .35s ease;
}
/* Cheap CSS-only "radiating light" behind the logo during the brief load — a conic-gradient
   wheel of alternating soft/transparent wedges, slowly rotating, no image asset needed. */
.boot-loader::before {
  content: ""; position: absolute; left: 50%; top: 30%; width: 900px; height: 900px;
  transform: translate(-50%, -50%);
  background: conic-gradient(from 0deg, rgba(255,255,255,.05) 0deg 10deg, transparent 10deg 30deg);
  animation: boot-rays-spin 40s linear infinite;
  z-index: 0; pointer-events: none;
}
@keyframes boot-rays-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
.boot-loader.hidden { opacity: 0; visibility: hidden; pointer-events: none; display: flex; }
.boot-logo {
  font-family: var(--font-display);
  font-weight: 700; font-size: 44px; letter-spacing: .5px; color: var(--white);
  position: relative; z-index: 1;
  text-shadow: 0 3px 0 var(--bronze), 0 6px 16px rgba(0, 0, 0, .4);
}
.boot-track {
  width: 220px; height: 8px; border-radius: 100px;
  background: rgba(0, 0, 0, .28); overflow: hidden; border: 1px solid rgba(255, 255, 255, .15);
}
.boot-fill {
  height: 100%; width: 8%;
  background: linear-gradient(90deg, var(--gold-light), var(--gold));
  border-radius: 100px; transition: width .2s ease;
}
.boot-hint { color: var(--ink-muted); font-size: 13px; font-weight: 600; }

/* Respect the OS-level motion preference for every purely-decorative animation added in
   this pass (twinkle stars, breathing glow orbs, logo pulse, hero-tile shine, avatar ring,
   nav-icon float, boot-loader rays) — none of these carry information, so freezing them is
   always safe. */
@media (prefers-reduced-motion: reduce) {
  .star-field .twinkle,
  #screen-home .home-inner::before, #screen-gate .gate-inner::before,
  #screen-home .home-inner::after, #screen-gate .gate-inner::after,
  .logo::before, .hero-tile::after, .avatar-preview-btn::after,
  .nav-tile-icon .icon, .boot-loader::before, .corner-avatar.active-turn,
  .board-wrap::before, .center-hub, .reaction-bubble, .chat-bubble {
    animation: none;
  }
}
