/* Per-game layout: canvas stage + control dock, shared by all games.
   STAGE SIZING CONTRACT: anything rendered inside .stage must size from the STAGE box, never the
   viewport. Canvas games get this free (GameScreen.resize() measures the stage rect). DOM games
   use container-query units — .stage is a size container — e.g. min(92cqw, 92cqh, 420px).
   vw/vh are only legal for body-level overlays (toast, modals, celebrations). Viewport-unit
   sizing inside the stage is exactly what put the mines grid underneath the dock in landscape. */
.game{position:absolute; inset:0; display:flex; flex-direction:column;}
.stage{position:relative; flex:1 1 auto; min-height:0; container-type:size;}
.stage canvas{position:absolute; inset:0; width:100%; height:100%; display:block; touch-action:none;}

.dock{
  flex:0 0 auto; padding:10px 12px calc(10px + env(safe-area-inset-bottom));
  position:relative;
  background:linear-gradient(180deg, rgba(4,24,38,.72), rgba(2,14,24,.94));
  backdrop-filter:blur(8px);
  box-shadow:0 -12px 28px -16px rgba(0,0,0,.7);
  display:flex; flex-direction:column; gap:10px;
}
/* Divider that FADES at the edges — the old full-width border-top read as a stray line. */
.dock::before{content:''; position:absolute; top:0; left:8%; right:8%; height:1px;
  background:linear-gradient(90deg, transparent, var(--edge), transparent);}
.dock .line{display:flex; gap:8px; align-items:center; justify-content:center; flex-wrap:wrap;}

/* SHORT / LANDSCAPE viewport: the dock is flex:0 0 auto, so a tall control stack steals height from
   the play stage. Compact it — tighter padding/gaps/controls and a hidden "How to play" pill — so
   every canvas game keeps a usable stage. Shared by all games via .dock. */
@media (max-height: 500px){
  .dock{ padding:5px 10px calc(5px + env(safe-area-inset-bottom)); gap:5px; }
  .dock .line{ gap:6px; }
  .dock-info{ display:none; }                 /* the ⓘ INFO dock button still covers this */
  .readout{ font-size:11px; }
  .betctl .step-btn{ width:36px; height:36px; font-size:18px; }
  .betctl .minmax-btn{ height:36px; padding:0 8px; font-size:10px; }
  .betctl .bet-pill{ min-width:78px; padding:5px 12px; font-size:15px; }
  .action{ min-width:130px; font-size:15px; }
  .auto-btn{ min-width:78px; font-size:13px; }
}

/* bet controls — a compact − [bet] + stepper (reuses .step-btn / .bet-pill from the fish dock). */
.betctl{display:flex; align-items:center; gap:10px; justify-content:center;}
.betctl.disabled{opacity:.6;}
.chips{display:flex; gap:6px; flex-wrap:wrap; justify-content:center;}
.chips .btn{padding:8px 12px; font-size:13px; min-height:38px;}

.action{min-width:150px; font-size:17px;}
/* Slot AUTO-spin: a button left of SPIN with a pop-up batch-size menu. */
.auto-wrap{position:relative; display:flex;}
.auto-btn{min-width:98px; font-size:15px; white-space:nowrap;}
.auto-btn.active{background:linear-gradient(180deg,#ff8a5a,#ff5a6e); color:#2a0a0a; border-color:#ff6a7e;}
.auto-btn.pending{background:linear-gradient(180deg,#7fe6a8,#41c07a); color:#05231a; border-color:#41f0a0;}
.auto-menu{position:absolute; bottom:calc(100% + 8px); left:50%; transform:translateX(-50%);
  display:flex; flex-direction:column; gap:6px; padding:8px; border-radius:12px;
  background:rgba(6,20,30,.97); border:1px solid var(--stroke); box-shadow:0 10px 28px rgba(0,0,0,.55); z-index:6;}
.auto-menu.hidden{display:none;}
.auto-menu .btn{min-width:74px; font-size:14px; min-height:38px;}
/* Reef Spins PULL-LEVER — a slot-machine handle on the right of the cabinet. JS sets top/left/height
   from the reel-board geometry; the knob is dragged down (or clicked / Enter'd) to spin. */
.slot-lever{position:absolute; width:38px; z-index:4; display:flex; flex-direction:column-reverse;
  align-items:center; pointer-events:auto; user-select:none;}
.slot-lever .sl-mount{flex:none; width:28px; height:15px; border-radius:6px;
  background:linear-gradient(180deg,#d9b24a,#7a5f16); box-shadow:0 2px 7px rgba(0,0,0,.55), inset 0 1px 2px rgba(255,255,255,.4);}
.sl-rod{flex:1 1 auto; width:9px; margin-bottom:-2px; border-radius:6px 6px 3px 3px; position:relative;
  transform-origin:bottom center; transition:transform .38s cubic-bezier(.2,1.5,.4,1);
  background:linear-gradient(90deg,#6e520f,#ffe9a0 45%,#6e520f); box-shadow:0 1px 3px rgba(0,0,0,.4);}
.sl-knob{position:absolute; top:-13px; left:50%; transform:translateX(-50%); width:30px; height:30px;
  border-radius:50%; cursor:grab; pointer-events:auto; touch-action:none;
  background:radial-gradient(circle at 35% 30%, #ff9a9a, #d81f1f 58%, #7a0f0f);
  box-shadow:0 3px 9px rgba(0,0,0,.55), inset 0 2px 5px rgba(255,255,255,.45), inset 0 -3px 6px rgba(0,0,0,.4);}
.sl-knob:active{cursor:grabbing;}
.slot-lever:focus-visible{outline:none;}
.slot-lever:focus-visible .sl-knob{box-shadow:0 0 0 3px var(--cyan), 0 3px 9px rgba(0,0,0,.55);}
.slot-lever.is-disabled{opacity:.4;}
.slot-lever.is-disabled .sl-knob{cursor:default; pointer-events:none;}
@media (prefers-reduced-motion:reduce){ .sl-rod{transition:transform .12s linear;} }
/* Smaller pull-lever on phones so it fits the right gutter of the (thinner) mobile cabinet. */
@media (max-width:640px){
  .slot-lever{width:32px;}
  .slot-lever .sl-mount{width:24px; height:13px;}
  .sl-rod{width:8px;}
  .sl-knob{width:24px; height:24px; top:-11px;}
}
@media (max-width:520px){ .slot-lever{width:30px;} .sl-knob{width:24px; height:24px; top:-10px;} }
/* Reef Hi-Lo: HI/LO and CASH OUT are separate stacked rows — give them tall tap targets and a clear
   gap between them so a HI/LO tap can't spill onto CASH OUT (reported accidental touches). */
.hl-act .btn, .hl-cash .btn{min-height:50px;}
.hl-cash{margin-top:10px;}
.readout{text-align:center; color:var(--dim); font-size:13px;
  background:rgba(255,255,255,.035); border:1px solid rgba(255,255,255,.05);
  border-radius:10px; padding:5px 12px; align-self:center; max-width:100%;}
.readout b{color:var(--ink);}
/* Keno win line — high-contrast gold pill so the payout never gets lost against the felt/theme. */
.readout.keno-won{color:#fff; font-size:14px; font-weight:800;
  background:linear-gradient(180deg, rgba(255,211,77,.20), rgba(255,211,77,.06));
  border-color:rgba(255,211,77,.65); box-shadow:0 0 18px rgba(255,211,77,.4);
  animation:keno-won-pop .4s ease;}
.readout.keno-won b{color:#ffe9a8;}
@keyframes keno-won-pop{0%{transform:scale(.92); opacity:.4;} 60%{transform:scale(1.04);} 100%{transform:scale(1); opacity:1;}}
@media (prefers-reduced-motion: reduce){ .readout.keno-won{animation:none;} }
/* SHARED DOCK STANDARD (every game except Ocean Cannon): top-to-bottom the dock always reads
   STATUS/READOUT → BET STEPPER → ACTION button. The readout is pulled to the top of the dock column
   (order:-1); the bet line and action button follow in source order. This is the single consistent
   rhythm across all games, card games included. The fish hint (.dock-hint) keeps its own placement. */
.game:not(.fish-cannon-layout) .dock .readout:not(.dock-hint){ order:-1; }
/* Arcade status line reads a size up from the controls (card games keep their own felt readout look). */
.game:not(.fish-cannon-layout) .dock .readout:not(.card-readout):not(.dock-hint){
  font-size:15.5px; font-weight:600; padding:7px 14px; color:var(--ink);
}
.game:not(.fish-cannon-layout) .dock .readout:not(.card-readout):not(.dock-hint) b{font-weight:800;}

/* Shared "How to play" bar at the bottom of the dock + info modal content */
.dock-info{display:block; margin:8px auto 2px; padding:7px 16px; border-radius:999px;
  background:rgba(120,205,255,.06); border:1px solid var(--stroke); color:var(--cyan);
  font-size:12.5px; font-weight:700; letter-spacing:.02em; cursor:pointer; line-height:1;
  transition:background .12s, border-color .12s, transform .1s;}
.dock-info:hover{background:rgba(120,205,255,.12); border-color:var(--cyan);}
.dock-info:active{transform:translateY(1px);}
.gi-sec{margin-bottom:14px;}
.gi-sec h3{margin:0 0 8px; font-size:15px; color:var(--ink);}
.gi-list{margin:0; padding-left:20px; display:flex; flex-direction:column; gap:7px; color:var(--dim); font-size:13.5px; line-height:1.5;}
.gi-odds p{color:var(--dim); font-size:13px; line-height:1.6; margin:0;}
.gi-odds b{color:var(--gold);}
.gi-fair p{color:var(--dim); font-size:13px; line-height:1.6; margin:0;}
.gi-fair b{color:var(--cyan);}
.gi-tip{background:rgba(56,230,255,.08); border:1px solid var(--stroke); border-radius:12px; padding:11px 13px;
  font-size:13px; color:var(--ink); line-height:1.5; margin:0;}
.gi-sub{font-size:11.5px; font-weight:600; color:var(--dim);}
/* Slot paytable table inside the info card. */
.pt-wrap{overflow-x:auto;}
.pt-table{width:100%; border-collapse:collapse; font-size:13px;}
.pt-table th{text-align:right; font-size:10px; text-transform:uppercase; letter-spacing:.05em; color:var(--dim); padding:5px 8px; border-bottom:1px solid var(--stroke);}
.pt-table th:first-child{text-align:left;}
.pt-table td{padding:6px 8px; text-align:right; font-weight:800; color:var(--gold); border-bottom:1px solid rgba(255,255,255,.05); font-variant-numeric:tabular-nums;}
.pt-table td.pt-sym{text-align:left; color:var(--ink); font-weight:600;}
.pt-table td.pt-zero{color:var(--dim); font-weight:600; opacity:.5;}   /* a possible-but-no-win cell */
.pt-table td.pt-blank{color:transparent;}                              /* an impossible combo (e.g. more hits than picks) */
.pt-note{margin:8px 0 0; font-size:12px; line-height:1.5; color:var(--dim);}

/* Dice HIGH/LOW toggle (width from the dock, not the viewport — required by the side rail) */
.dice-mode{gap:0; width:min(100%,300px); margin:0 auto;}
.dice-modebtn{flex:1; border-radius:0; min-height:40px; font-size:13px; font-weight:800; letter-spacing:.02em;
  background:var(--panel); border:1px solid var(--stroke); color:var(--dim);}
.dice-modebtn:first-child{border-radius:12px 0 0 12px;}
.dice-modebtn:last-child{border-radius:0 12px 12px 0; border-left:none;}
.dice-modebtn.sel{color:#241800; background:linear-gradient(180deg,var(--gold),var(--gold2)); border-color:transparent;}
.dice-modebtn:disabled{opacity:.5;}

/* Dice target input — keyboard accessibility only. The CANVAS TRACK is the pointer control
   (drag the gold diamond knob on the felt); this hidden range mirrors it so tab + arrow keys
   still adjust the target. pointer-events:none keeps it from intercepting the stage drag. */
.dice-a11y{position:absolute; left:0; bottom:0; width:1px; height:1px; opacity:0;
  pointer-events:none; margin:0; padding:0; border:0;}
.dice-readout b{color:var(--gold);}
/* Last-roll result on its own line so the win% / multiplier / payout stays visible above it. */
.dice-result{min-height:18px; font-weight:700; font-size:13px;}
.dice-result:empty{display:none;}
.dice-result.win{color:var(--green);} .dice-result.win b{color:var(--green);}
.dice-result.lose{color:var(--red);} .dice-result.lose b{color:var(--red);}
/* Dice dock on a short/landscape stage: the shared dock compaction isn't enough — tighten the
   dice-specific rows too so the felt board keeps its height. */
@media (max-height: 500px){
  .dice-modebtn{ min-height:32px; font-size:12px; }
  .dice-result{ min-height:14px; font-size:12px; }
}

/* Shared card-game action bar (Casino Hold'em + Blackjack) — large, tactile, color-coded, with a
   recessed 3D press. FIXED height + no wrap (scrolls if the buttons overflow on a narrow phone) so
   the number of visible buttons can change per phase (deal → hit/stand/double/split → done) without
   ever changing the dock height — otherwise the stage would resize and the whole table would jump. */
.card-actions{gap:10px; min-height:58px; align-items:center; flex-wrap:nowrap; overflow-x:auto; justify-content:center; scrollbar-width:none;}
.card-actions::-webkit-scrollbar{display:none;}
.card-actions .btn{flex:0 0 auto; min-width:116px; height:54px; display:inline-flex; flex-direction:column; align-items:center; justify-content:center;
  font-size:16px; font-weight:800; padding:0 18px; border-radius:14px; letter-spacing:.03em;}
.card-actions .btn small{display:block; font-size:11px; font-weight:700; opacity:.85; letter-spacing:.02em; margin-top:2px; line-height:1;}
.card-actions .btn.good{background:linear-gradient(180deg,#2fd07e,#12864f); border-color:#43e087; color:#04240f; box-shadow:0 4px 0 #0a5a34, 0 7px 14px rgba(0,0,0,.35);}
.card-actions .btn.danger{background:linear-gradient(180deg,#ff7a8c,#d83b52); border-color:#ff8fa0; color:#2a0308; box-shadow:0 4px 0 #8f2233, 0 7px 14px rgba(0,0,0,.35);}
.card-actions .btn.primary{box-shadow:0 4px 0 #9a7a12, 0 7px 14px rgba(0,0,0,.35);}
.card-actions .btn:active{transform:translateY(3px); box-shadow:0 1px 0 rgba(0,0,0,.4);}
.card-actions .btn:disabled{filter:saturate(.5) brightness(.82); box-shadow:none; transform:none;}
/* Block + centered text, NOT flex: a flex readout turns each text run into a flex item and trims
   the whitespace between them, which ate the spaces around <b> ("0 won" → "0won", "3+ pays" →
   "3+pays"). Block preserves normal inline whitespace; the coin aligns via its vertical-align. */
.card-readout{font-size:15px; min-height:24px; line-height:1.5; display:block; text-align:center;}
.card-readout b{color:var(--gold); letter-spacing:.3px;} /* template controls spacing now, no margin hack */
.card-readout small{color:var(--dim); font-weight:600;}
/* Short / landscape: compact the card-game action row + readout so the felt table keeps its height. */
@media (max-height: 500px){
  .card-actions{ min-height:46px; gap:8px; }
  .card-actions .btn{ height:44px; min-width:100px; font-size:14px; }
  .card-readout{ font-size:13px; min-height:20px; }
}
/* Narrow portrait phones: HIT/STAND/DOUBLE/SPLIT must SHARE the width instead of overflowing
   behind an invisible scrollbar (4×116px ≈ 494px never fit a 360px screen). */
@media (max-width:420px){
  .card-actions{ gap:6px; }
  .card-actions .btn{ flex:1 1 0; min-width:0; padding:0 6px; font-size:13.5px; }
  .card-actions .btn small{ font-size:10px; }
}

/* reconnecting chip for WS games */
.netchip{
  position:absolute; top:10px; left:50%; transform:translateX(-50%);
  background:var(--panel); border:1px solid var(--red); color:var(--red);
  border-radius:20px; padding:6px 14px; font-size:12px; font-weight:700; z-index:20; display:none;
}
.netchip.show{display:block;}

/* mines grid */
.mines-wrap{position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; padding:16px;}
/* streak meter — renders the SERVER-returned multiplier (display only) + optional ghost next value */
.mines-meter{display:flex; align-items:baseline; gap:10px; min-height:30px; font-weight:800; letter-spacing:.5px;}
.mines-meter .mult{
  display:inline-block; font-size:24px; font-variant-numeric:tabular-nums; color:var(--gold);
  text-shadow:0 0 14px rgba(255,211,77,.45), 0 1px 0 rgba(0,0,0,.6);
}
/* cash-out payout (coin + digits) — sized close to the multiplier so it doesn't read as an afterthought */
.mines-meter .pay{display:inline-flex; align-items:center; gap:5px; font-size:22px; font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums;}
.mines-meter .next{font-size:12px; font-weight:600; color:var(--dim);}
.mines-meter.idle .mult{color:var(--dim); text-shadow:none;}
.mines-meter.bump .mult{animation:mine-bump .3s ease;}
@keyframes mine-bump{0%{transform:scale(1);} 40%{transform:scale(1.3);} 100%{transform:scale(1);}}
/* red vignette flash on a bomb (fast in, slow out) */
.mines-vignette{
  position:absolute; inset:0; pointer-events:none; z-index:5; opacity:0; transition:opacity .4s ease;
  background:radial-gradient(ellipse at center, transparent 45%, rgba(255,30,60,.4) 100%);
}
.mines-vignette.show{opacity:1; transition:opacity .06s ease;}
.mines-grid{
  display:grid; grid-template-columns:repeat(5,1fr); gap:8px;
  /* Sized from the STAGE box (container units), never the viewport — 60vh measured the whole
     screen and pushed the grid's bottom rows under the dock in landscape. The vw/vh line is a
     fallback for pre-container-query engines only. 44px reserves the streak-meter row. */
  width:min(92vw, 60vh - 44px, 420px);
  width:min(92cqw, 92cqh - 44px, 420px);
  aspect-ratio:1/1; border-radius:14px; transition:box-shadow .3s ease;
}
/* streak glow tiers on the whole board */
.mines-grid.streak-2{box-shadow:0 0 18px var(--glow1);}
.mines-grid.streak-5{box-shadow:0 0 26px var(--glow1), 0 0 44px var(--glow2);}
.mines-grid.streak-8{box-shadow:0 0 30px var(--glow2), 0 0 64px rgba(255,211,77,.3);}
/* bomb quake */
.mines-grid.quake{animation:mine-quake .4s linear;}
@keyframes mine-quake{
  0%,100%{transform:translate(0,0);} 15%{transform:translate(-6px,4px);} 30%{transform:translate(5px,-5px);}
  45%{transform:translate(-5px,-3px);} 60%{transform:translate(6px,3px);} 75%{transform:translate(-3px,5px);} 90%{transform:translate(3px,-2px);}
}
/* SINGLE-ELEMENT tiles: the tile's class sets colour/state, its textContent is the result glyph
   (💎/💣/💥). Deliberately NOT a two-face flip card — on the target mobile browser a child node
   (face span or inline-SVG) added on tap was left out of the tile's raster until an unrelated
   repaint (the "glyph shows one tap late / only after refresh" bug). A single element with its own
   text has no separately-rasterised child, so the glyph always paints on the same tap. */
.mines-grid .tile{
  border:1px solid var(--stroke); border-radius:12px; cursor:pointer; padding:0; color:var(--ink);
  font-size:min(11vw,40px); font-size:min(9cqw, 9cqh, 40px); line-height:1;
  display:flex; align-items:center; justify-content:center;
  background:
    linear-gradient(160deg, rgba(255,255,255,.12), rgba(255,255,255,0) 55%),
    radial-gradient(120% 130% at 30% 22%, var(--deep1), var(--deep2) 78%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.12), inset 0 -6px 12px rgba(0,0,0,.35), 0 2px 6px rgba(0,0,0,.4);
  transition:transform .1s ease, background .12s ease, border-color .12s ease;
}
.mines-grid .tile:not(.open):not(.bomb):not(.bomb-shown):active{transform:scale(.95);}
.mines-grid .tile:disabled{cursor:default;}
/* safe = green face + diamond */
.mines-grid .tile.open{background:linear-gradient(160deg,#0e5a3a,#083b2a); border-color:var(--green); box-shadow:inset 0 0 18px rgba(56,230,255,.12);}
/* hit mine = red face + blast */
.mines-grid .tile.bomb{background:linear-gradient(160deg,#6b1220,#3a0a12); border-color:var(--red);}
/* unhit mine revealed on loss = dim red face + mine */
.mines-grid .tile.bomb-shown{background:linear-gradient(160deg,#3a1016,#20080d); border-color:var(--red); filter:brightness(.82) saturate(.85);}
/* reveal pop — transform ONLY, so it can never hide the glyph */
.mines-grid .tile.pop{animation:mine-pop .28s cubic-bezier(.3,1.5,.5,1);}
@keyframes mine-pop{from{transform:scale(.55);} to{transform:scale(1);}}
/* cash-out gold sweep across the safe tiles */
.mines-grid .tile.win{border-color:var(--gold); box-shadow:0 0 0 1px var(--gold), 0 0 16px rgba(255,211,77,.5); animation:mine-win .5s ease;}
@keyframes mine-win{0%{transform:scale(1);} 40%{transform:scale(1.12);} 100%{transform:scale(1);}}
@media (prefers-reduced-motion: reduce){
  .mines-grid .tile{transition:none;}
  .mines-grid .tile.pop, .mines-grid .tile.win, .mines-grid.quake, .mines-meter.bump .mult{animation:none;}
}

/* fish cannon dock */
/* PORTRAIT / narrow default: a normal centred control row in the dock below the stage (the cannon is
   drawn at the stage bottom, directly above — traditional, no overlap). */
.cannon-dock{display:flex; gap:8px; justify-content:center; align-items:center; flex-wrap:wrap;}
.dock-left{display:flex; gap:8px; align-items:center; min-width:0; flex-wrap:wrap;}
.cannon-dock .btn small{display:block; font-size:10px; color:var(--dim); font-weight:600;}
.cannon-dock .btn.auto.on{border-color:var(--green); color:var(--green);}
.dock-hint{text-align:center;}

/* WIDE (landscape / desktop) "cannon at the bottom" layout: the dock overlays the bottom of the stage
   (transparent), so the canvas fills the FULL height and the cannon (drawn at the canvas bottom-centre)
   sits at the TRUE bottom of the screen. The two control groups become glass panels pinned to the
   bottom-left/right corners, leaving the centre open for the cannon between them. Only applied when
   there's enough WIDTH to flank the cannon — in portrait it would just crowd the "+" onto the cannon. */
@media (min-width: 600px){
  .fish-cannon-layout .dock{
    position:absolute; left:0; right:0; bottom:0; z-index:6;
    background:transparent; border-top:none; gap:0; box-shadow:none;
    /* The base .dock blurs its backdrop; on this transparent full-width overlay that painted a
       frosted STRIP across the bottom of the stage, over the cannon. Reset it — only the two glass
       corner panels (.dock-left / .dock-utils) keep their own blur. */
    -webkit-backdrop-filter:none; backdrop-filter:none;
    padding:0 10px calc(8px + env(safe-area-inset-bottom));
    pointer-events:none;                     /* taps fall through to the water; groups re-enable below */
  }
  .fish-cannon-layout .dock::before{display:none;} /* the transparent overlay dock has no divider */
  .fish-cannon-layout .cannon-dock{ align-items:flex-end; justify-content:space-between; flex-wrap:nowrap; }
  .fish-cannon-layout .dock-left,
  .fish-cannon-layout .dock-utils{
    pointer-events:auto;
    background:rgba(2,18,31,.6); border:1px solid rgba(56,230,255,.18);
    border-radius:14px; padding:6px 8px; backdrop-filter:blur(5px);
  }
  .fish-cannon-layout .dock-hint{ display:none; } /* keep the cannon's centre gap clear */
}

/* --- fish: side rail, bet stepper, paytable modal ------------------------------------- */
.dock-utils{display:flex; gap:6px; align-items:center;}
.dock-mini{display:flex; flex-direction:column; align-items:center; gap:1px; width:50px; padding:6px 0;
  background:rgba(2,18,31,.72); border:1px solid rgba(56,230,255,.4); border-radius:12px;
  color:#dff6ff; font-size:15px; cursor:pointer;}
.dock-mini small{font:700 8px system-ui; letter-spacing:.08em; color:#8fb6cc;}
.dock-mini:hover{border-color:#38e6ff; box-shadow:0 0 10px rgba(56,230,255,.35);}
.fish-rail{
  display:flex; flex-direction:column; gap:8px; z-index:5; align-items:center;}
.rail-badge{font:900 10px/1.15 system-ui; text-align:center; color:#12060f; letter-spacing:.05em;
  background:linear-gradient(180deg,#fff2b0,#ffd34d 55%,#e8a21f); border:2px solid #a3540d;
  border-radius:10px; padding:7px 8px; box-shadow:0 0 14px rgba(255,176,32,.5);}
.rail-btn{display:flex; flex-direction:column; align-items:center; gap:1px; width:52px; padding:7px 0;
  background:rgba(2,18,31,.72); border:1px solid rgba(56,230,255,.4); border-radius:12px;
  color:#dff6ff; font-size:17px; cursor:pointer;}
.rail-btn small{font:700 8.5px system-ui; letter-spacing:.08em; color:#8fb6cc;}
.rail-btn:hover{border-color:#38e6ff; box-shadow:0 0 10px rgba(56,230,255,.35);}
.bet-stepper{display:flex; align-items:center; gap:8px;}
.bet-col{display:flex; flex-direction:column; align-items:center; gap:4px;}
/* PWR meter: it's a METER, not a slider — bigger pips + a clearer cap label so the power level
   reads at a glance on a phone. Lit pips get their accent fill/glow inline from fish.js. */
.pow-pips{display:flex; align-items:center; gap:3px;}
.pow-pips b{font:900 10px/1 system-ui; letter-spacing:.12em; color:#cfeaff; margin-right:3px;
  text-shadow:0 0 6px rgba(56,230,255,.4);}
.pow-pips i{width:10px; height:7px; border-radius:2.5px; background:rgba(255,255,255,.14);
  box-shadow:inset 0 1px 1px rgba(0,0,0,.35);}
/* Chip-look stepper: recessed inset depth instead of the old translucent white border ring —
   that ring caught the light-topped gradient and read as a stray hairline across the button top.
   Theme-token driven (--red/--green glyphs, --gold pill, --stroke/--accent edges) so cosmetic
   themes recolor the stepper everywhere it appears. */
.step-btn{width:44px; height:44px; border-radius:50%; font-size:20px; font-weight:900; cursor:pointer;
  color:var(--ink); border:1px solid var(--stroke);
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.10), transparent 55%),
    linear-gradient(180deg, var(--bg2), var(--bg1));
  box-shadow:
    inset 0 0 0 3px rgba(255,255,255,.05),
    inset 0 2px 5px rgba(0,0,0,.45),
    0 2px 8px rgba(0,0,0,.4);
  transition:transform .06s, box-shadow .12s, border-color .12s;}
.step-btn.minus{color:var(--red); border-color:color-mix(in srgb, var(--red) 40%, transparent);}
.step-btn.plus{color:var(--green); border-color:color-mix(in srgb, var(--green) 40%, transparent);}
.step-btn:not(:disabled):hover{border-color:var(--accent);}
.step-btn:not(:disabled):active{transform:translateY(1px);
  box-shadow:inset 0 0 0 3px rgba(255,255,255,.04), inset 0 3px 8px rgba(0,0,0,.6);}
.step-btn:disabled{opacity:.4; cursor:not-allowed;}
.bet-pill{min-width:110px; display:flex; align-items:center; justify-content:center; gap:8px; padding:9px 18px; border-radius:999px;
  font:900 20px system-ui; color:var(--ink); letter-spacing:.03em;
  background:linear-gradient(180deg, color-mix(in srgb, var(--gold) 14%, var(--bg1)), var(--bg0));
  border:1px solid color-mix(in srgb, var(--gold) 45%, transparent);
  box-shadow:inset 0 2px 8px rgba(0,0,0,.4), 0 0 12px color-mix(in srgb, var(--gold) 22%, transparent);}
.bet-pill span{color:var(--gold);}
.bet-pill .coin{width:22px; height:22px; flex:none;}
/* MIN / MAX jump buttons — hop straight to the lowest / highest allowed bet instead of tapping − / +
   all the way. Reuses the stepper's material as a compact rounded-rect so the row stays tidy. */
.minmax-btn{height:44px; padding:0 12px; border-radius:12px; font:800 12px/1 system-ui; letter-spacing:.05em;
  cursor:pointer; color:var(--dim); border:1px solid var(--stroke);
  background:radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.08), transparent 55%), linear-gradient(180deg, var(--bg2), var(--bg1));
  box-shadow:inset 0 2px 5px rgba(0,0,0,.4), 0 2px 8px rgba(0,0,0,.35);
  transition:transform .06s, border-color .12s, color .12s;}
.minmax-btn:not(:disabled):hover{border-color:var(--accent); color:var(--ink);}
.minmax-btn:not(:disabled):active{transform:translateY(1px);}
.minmax-btn:disabled{opacity:.35; cursor:not-allowed;}

/* --- weapon shop -------------------------------------------------------------------------- */
/* SHOP dock button pulses gold once a weapon is unlocked / active, drawing the eye to the offer. */
.dock-mini.shop.ready{border-color:#ffd34d; color:#fff2c0; box-shadow:0 0 12px rgba(255,211,77,.5); animation:shopPulse 1.3s ease-in-out infinite;}
@keyframes shopPulse{0%,100%{box-shadow:0 0 10px rgba(255,211,77,.35);}50%{box-shadow:0 0 18px rgba(255,211,77,.7);}}
@media (prefers-reduced-motion: reduce){.dock-mini.shop.ready{animation:none;}}
.modal.wshop{max-width:440px;}
.wshop-intro{margin:0 0 12px; color:var(--dim); font-size:13px; line-height:1.5;}
.wshop-intro b{color:#9fe8c4;}
.wshop-obj{background:rgba(255,255,255,.04); border:1px solid rgba(255,255,255,.08); border-radius:12px; padding:10px 12px; margin-bottom:12px;}
.wshop-obj-top{display:flex; justify-content:space-between; align-items:center; font-size:13px; color:var(--ink);}
.wshop-obj-count{font-weight:800; font-variant-numeric:tabular-nums; color:var(--gold);}
.wshop-bar{height:7px; border-radius:5px; background:rgba(255,255,255,.1); overflow:hidden; margin:8px 0 6px;}
.wshop-bar i{display:block; height:100%; border-radius:5px; transition:width .25s ease;}
.wshop-obj-note{font-size:11.5px; color:var(--dim);}
.wshop-card{background:linear-gradient(160deg, rgba(56,230,255,.1), rgba(56,230,255,.02)); border:1px solid rgba(56,230,255,.35); border-radius:14px; padding:14px;}
.wshop-card.locked{background:rgba(255,255,255,.03); border-color:rgba(255,255,255,.1); opacity:.85;}
.wshop-card-head{display:flex; align-items:center; gap:8px;}
.wshop-name{font:800 17px system-ui; color:#eafcff;}
.wshop-live{margin-left:auto; font:800 10px system-ui; letter-spacing:.08em; color:#062; background:#43e0ff; border-radius:6px; padding:3px 7px;}
.wshop-blurb{margin:4px 0 10px; font-size:13px; color:var(--dim);}
.wshop-stats{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:12px;}
.wstat{display:flex; flex-direction:column; gap:1px; flex:1 1 auto; min-width:64px; text-align:center;
  background:rgba(0,0,0,.25); border:1px solid rgba(255,255,255,.07); border-radius:9px; padding:6px 4px;
  font:600 10px system-ui; letter-spacing:.06em; text-transform:uppercase; color:#8fb6cc;}
.wstat b{font:800 14px system-ui; letter-spacing:0; text-transform:none; color:#eafcff;}
.wshop-buy-row{display:flex; align-items:center; justify-content:space-between; gap:12px;}
.wshop-price{display:flex; align-items:center; gap:6px; font:800 18px system-ui; color:var(--gold);}
.wshop-price .coin{width:20px; height:20px;}
.wshop-buy-row .btn{min-width:110px;}
.modal.fish-info{max-width:520px; max-height:84vh; overflow-y:auto;}
.fish-info .info-sec{margin:14px 0; padding-top:12px; border-top:1px solid rgba(255,255,255,.07);}
.fish-info .info-sec:first-of-type{border-top:none; padding-top:0;}
.fish-info .info-sec h3{margin:0 0 8px; font:800 14px system-ui; letter-spacing:.02em; color:#bfe9ff;}
.fish-info .info-list{margin:0; padding-left:20px; display:flex; flex-direction:column; gap:7px;}
.fish-info .info-list li{font-size:13px; line-height:1.5; color:var(--ink);}
.fish-info .info-list b{color:#ffe9ad;}
.fish-info .info-note{margin:8px 0 0; font-size:11.5px; color:var(--dim); font-style:italic;}
/* friendly reassurance callout (you're always paid for damage dealt) */
.fish-info .info-tip{margin:11px 0 0; padding:10px 12px; font-size:12.5px; line-height:1.5; color:var(--ink);
  border-radius:10px; border:1px solid rgba(67,240,160,.4);
  background:linear-gradient(180deg, rgba(67,240,160,.12), rgba(67,240,160,.03));}
.fish-info .info-tip b{color:#8bffc0;}
/* the combo-laser section gets an electric highlight */
.fish-info .info-hot{border-radius:12px; padding:12px; margin-top:14px;
  background:linear-gradient(180deg, rgba(90,216,255,.1), rgba(90,216,255,.03));
  border:1px solid rgba(127,232,255,.4); box-shadow:inset 0 0 24px rgba(90,216,255,.08);}
.fish-info .info-hot h3{color:#8ff0ff; text-shadow:0 0 10px rgba(90,216,255,.5);}
.pay-grid{display:grid; grid-template-columns:1fr 1fr; gap:4px 14px; margin:10px 0;}
.pay-row{display:flex; align-items:center; gap:8px; padding:3px 0;}
.pay-row canvas{flex:none; background:rgba(3,40,60,.5); border-radius:8px;}
.pay-name{flex:1; font-size:12.5px; font-weight:700;}
.pay-val{font-weight:900; color:var(--gold, #ffd34d);}
@media (max-width:640px){ .pay-grid{grid-template-columns:1fr;} .fish-rail{right:4px;} }

/* sound settings popover */
.modal.snd-settings{max-width:380px;}
.snd-row{display:flex; align-items:center; justify-content:space-between; gap:14px; padding:12px 4px; border-bottom:1px solid rgba(255,255,255,.06); cursor:pointer;}
.snd-row:last-of-type{border-bottom:none;}
.snd-lbl{display:flex; flex-direction:column; font-size:14px; font-weight:800;}
.snd-lbl small{font-size:11px; font-weight:600; color:var(--dim,#8fb0c4); margin-top:2px;}
.snd-row input[type=checkbox]{flex:none; width:20px; height:20px; accent-color:var(--gold,#ffd34d);}

/* treasure chest-pick bonus overlay */
.modal.bonus-modal{max-width:440px; text-align:center; animation:bonusIn .32s cubic-bezier(.2,.9,.3,1.3) both;}
@keyframes bonusIn{from{opacity:0; transform:scale(.86) translateY(10px);} to{opacity:1; transform:none;}}
/* Arming beat: chests locked for ~1s so a stray mid-fire tap can't pick one. */
.modal.bonus-modal.arming .chest{opacity:.5; cursor:default; pointer-events:none;}
.modal.bonus-modal.arming #bonusHint{color:var(--gold,#ffd34d); animation:armPulse .7s ease-in-out infinite alternate;}
@keyframes armPulse{from{opacity:.55;} to{opacity:1;}}
@media (prefers-reduced-motion:reduce){ .modal.bonus-modal{animation:none;} .modal.bonus-modal.arming #bonusHint{animation:none;} }
.bonus-sub{color:var(--dim); font-size:13px; margin:2px 0 14px;}
.chest-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin:6px 0 14px;}
.chest{aspect-ratio:1/1; border-radius:14px; cursor:pointer; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:4px; font:800 13px system-ui; color:#ffe9ad;
  background:linear-gradient(180deg, rgba(255,211,77,.14), rgba(120,74,36,.22));
  border:2px solid rgba(255,211,77,.4); transition:transform .1s, box-shadow .15s, opacity .2s;}
.chest .lid{font-size:30px; line-height:1;}
.chest .prize{display:flex; align-items:center; gap:3px; min-height:15px;}
.chest:not([disabled]):hover{transform:translateY(-2px); box-shadow:0 6px 18px rgba(255,211,77,.25);}
.chest:not([disabled]):active{transform:scale(.96);}
.chest.open{background:linear-gradient(180deg, rgba(65,240,160,.18), rgba(6,40,28,.5)); border-color:rgba(65,240,160,.5); cursor:default;}
.chest.dim{opacity:.45;}
.chest[disabled]{cursor:default;}
.bonus-foot{display:flex; justify-content:space-between; align-items:center; font:800 14px system-ui; color:var(--ink); margin-bottom:10px;}
.bonus-foot #bonusTotal{color:var(--gold,#ffd34d); display:flex; align-items:center; gap:5px;}
#bonusCollect .btn{margin-top:4px;}

/* first-run coach overlay */
.modal.fish-coach{max-width:420px;}
.coach-list{list-style:none; margin:12px 0 6px; padding:0; display:flex; flex-direction:column; gap:11px;}
.coach-list li{position:relative; padding-left:22px; font-size:13.5px; line-height:1.5; color:var(--ink);}
.coach-list li::before{content:'▸'; position:absolute; left:4px; color:var(--cyan,#43e0ff);}
.coach-list b{color:#ffe9ad;}

/* --- compact dock on phones: smaller controls so they don't wrap into 3 tall rows and steal
   the play area (bigger canvas = fish use more of the screen) --- */
@media (max-width:640px){
  .dock{padding:6px 8px calc(6px + env(safe-area-inset-bottom)); gap:5px;}
  .cannon-dock{gap:6px;}
  .cannon-dock .btn.auto{padding:6px 12px; font-size:13px;}
  .bet-stepper{gap:6px;}
  .step-btn{width:40px; height:40px; font-size:20px;}
  .minmax-btn{height:40px; padding:0 9px; font-size:11px;}
  .bet-pill{min-width:72px; padding:7px 12px; font-size:18px;}
  .bet-col{gap:3px;}
  .pow-pips{gap:2px;}
  .pow-pips i{width:7px; height:5px;}
  .pow-pips b{font-size:8px; margin-right:2px;}
  .dock-mini{width:44px; font-size:13px; padding:4px 0;}
  .dock-mini small{font-size:7.5px;}
  .dock-utils{gap:5px;}
  .dock .readout{font-size:11px;}
}

/* ============ LANDSCAPE: LOCK NON-FISH GAMES TO A PORTRAIT COLUMN ============
   Only Ocean Cannon (.fish-cannon-layout) has a landscape layout. Every other game is LOCKED to a
   centered portrait-shaped column when the phone is turned sideways — the side gutters are dimmed
   (box-shadow letterbox) — so rotating never reflows the game into a broken wide layout. No rotation
   transform is used, so canvas pointer math stays exact; the column just keeps the normal portrait
   stack. The 62vh width is deliberately narrow enough that each stage stays PORTRAIT-shaped
   (width < height·1.45), so games' own wide/landscape draw branches never trigger. The old side rail
   was removed for good; this is the single, consistent landscape behavior. */
@media (orientation:landscape) and (max-height:500px){
  .game:not(.fish-cannon-layout){
    left:0; right:0; margin-inline:auto;
    width:min(100%, 62vh); max-width:100%;
    box-shadow:0 0 0 100vw rgba(2,8,14,.72);   /* dim the letterbox gutters on both sides */
  }
}

/* ============ WIDE-VIEWPORT DOCK STANDARD ============
   Desktop / tablet: the dock is a compact single band with the PRIMARY ACTION dead-centre. The bet
   stepper is pinned to the far left and "How to play" to the far right (both taken out of flow), so
   the action button sits at the true horizontal centre of the screen regardless of the other
   controls' widths. The readout drops onto its own line just above. Portrait phones keep the stack;
   short-landscape uses the side rail above. Fish excluded. */
@media (min-width:700px) and (min-height:501px){
  .game:not(.fish-cannon-layout) .dock{
    position:relative;
    flex-direction:row; flex-wrap:wrap; align-items:center; justify-content:center;
    column-gap:18px; row-gap:8px; min-height:64px;
    padding:8px 16px calc(8px + env(safe-area-inset-bottom));
  }
  /* readout on its own centred line, above the action row */
  .game:not(.fish-cannon-layout) .dock .readout,
  .game:not(.fish-cannon-layout) .dock .card-readout{flex-basis:100%; order:-1; max-width:none; text-align:center;}
  /* bet stepper pinned bottom-left, How-to bottom-right → level with the centred action button,
     out of flow so the action sits at the true horizontal centre. */
  .game:not(.fish-cannon-layout) .dock .line:has(.betctl){
    position:absolute; left:20px; bottom:calc(10px + env(safe-area-inset-bottom)); margin:0; width:auto;
  }
  .game:not(.fish-cannon-layout) .dock-info{
    position:absolute; right:20px; bottom:calc(12px + env(safe-area-inset-bottom)); margin:0;
  }
  .game:not(.fish-cannon-layout) .dock .line{width:auto; flex:0 0 auto;}
  .game:not(.fish-cannon-layout) .dice-mode{width:auto; min-width:230px;}
  /* Dice: force the ROLL onto its OWN full-width centred row so it can't drift to the right and sit
     under the bottom-right "How to play" pill (the mode toggle + ROLL sharing a row pushed it over).
     NOTE the `.dock` — without it this loses specificity to `.dock .line{width:auto}` above, so the
     roll line stayed auto-width, shared the row, and slid under the pill (the reported overlay). */
  .game:not(.fish-cannon-layout) .dock .dice-roll-line{flex-basis:100%; width:100%; justify-content:center;}
  /* Dice keeps its mode toggle + roll inline; pin the toggle left beside the stepper isn't needed —
     its single action (ROLL) already centres. */
}

/* --- Reef Craps: felt bet layout overlay (lower band of the green table; dice tumble above) ---- */
.craps-chip-k{font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:#cfe6d8; margin-right:2px;}
/* JS sets top (dice band above); the overlay fills to the bottom rim and CENTERS its rows so the
   felt never reads as empty below the bets. */
.craps-layout{position:absolute; left:0; right:0; bottom:2.6%; padding:0 4% 0; display:flex; flex-direction:column;
  justify-content:center; gap:12px; pointer-events:auto; overflow-y:auto;}
.craps-row{display:flex; gap:10px; justify-content:center;}
.craps-line .craps-spot, .craps-combo .craps-spot{flex:1 1 0;}
.craps-totals{flex-wrap:wrap;}
.craps-totals .craps-spot{flex:1 1 60px; min-width:50px; min-height:52px;}
.craps-totals-k{font-size:10px; text-transform:uppercase; letter-spacing:.12em; color:#ffe9a8; text-align:center; margin:2px 0 -3px;
  text-shadow:0 1px 3px rgba(0,0,0,.5);}
/* betting boxes painted on the felt: translucent dark-green well with a soft gold edge */
.craps-spot{position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
  padding:10px 8px; border-radius:12px; cursor:pointer; min-height:56px; color:#eafff5;
  border:1px solid rgba(255,231,154,.28);
  background:linear-gradient(180deg, rgba(6,58,42,.66), rgba(2,30,22,.72));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06), inset 0 -10px 20px -12px rgba(0,0,0,.6);
  transition:border-color .12s, box-shadow .15s, background .15s, opacity .2s, transform .08s;}
.craps-spot:active:not(:disabled){transform:translateY(1px);}
.craps-spot:hover:not(:disabled){border-color:#ffe79a; box-shadow:0 0 14px -3px rgba(255,211,77,.5), inset 0 1px 0 rgba(255,255,255,.08);}
.cs-label{font-size:13px; font-weight:800; line-height:1.1; text-align:center; letter-spacing:.01em;}
.cs-mult{font-size:10.5px; font-weight:800; color:#ffe9a8;}
/* the placed stake reads as a poker chip on the box — kept compact so it sits ABOVE the box label
   rather than covering it on the small "Total" tiles. */
.cs-chips{position:absolute; top:-8px; right:-6px; min-width:20px; height:19px; display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 38% 32%, #fff2c4, #ffd34d 55%, #d38a1a); color:#3a2600;
  font-size:9.5px; font-weight:900; padding:0 5px; border-radius:999px;
  border:1.5px dashed rgba(255,255,255,.75); box-shadow:0 2px 6px rgba(0,0,0,.5);}
/* Visibility is driven by the tapped button's own `.has-bet` class — NOT a child [hidden] toggle, which
   can paint one tap late on some mobile browsers. The chip amount is always textContent on this element. */
.craps-spot:not(.has-bet) .cs-chips{display:none;}
/* the red − (top-LEFT, mirroring the chip): tap to lower this spot's bet by one chip / clear it */
.cs-minus{position:absolute; top:-8px; left:-6px; width:20px; height:20px; display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 38% 32%, #ff9aa6, #e5484d 58%, #a51b20); color:#fff;
  font-size:16px; font-weight:900; line-height:1; border-radius:999px; cursor:pointer; z-index:2;
  border:1.5px solid rgba(255,255,255,.6); box-shadow:0 2px 6px rgba(0,0,0,.5);}
/* − shows only when the spot has a bet AND the layout isn't rolling (button disabled) — same as the old
   `minus.hidden = staked<=0 || rolling`, now class-driven so no child attribute toggles on tap. */
.craps-spot:not(.has-bet) .cs-minus, .craps-spot:disabled .cs-minus{display:none;}
.cs-minus:active{transform:translateY(1px); filter:brightness(1.1);}
.craps-spot.has-bet{border-color:var(--gold,#ffd34d); box-shadow:0 0 0 1px var(--gold,#ffd34d) inset, 0 0 16px -6px rgba(255,211,77,.7);}
.craps-spot.win{border-color:#54e08a; background:linear-gradient(180deg, rgba(84,224,138,.24), rgba(6,58,42,.6));
  box-shadow:0 0 20px -3px rgba(84,224,138,.8), 0 0 0 1px #54e08a inset;}
.craps-spot.lose{opacity:.4;}
.craps-spot.push{border-color:var(--cyan,#38e6ff); box-shadow:0 0 0 1px var(--cyan,#38e6ff) inset;}
.craps-spot:disabled{cursor:default;}
.craps-hint{font-size:11px; color:#bfe0cc; text-align:center; opacity:.75; margin-top:2px;}
@media (max-width:520px){
  .cs-label{font-size:11.5px;} .cs-mult{font-size:9.5px;}
  .craps-totals .craps-spot{min-width:42px; flex-basis:46px; min-height:46px;}
  /* Smaller chip + − on phones so they clear the box label on the narrow Total tiles. */
  .cs-chips{min-width:18px; height:17px; font-size:8.5px; padding:0 4px; top:-7px; right:-5px;}
  .cs-minus{width:18px; height:18px; font-size:15px; top:-7px; left:-5px;}
  .craps-hint{display:none;}
}
