/* =============================================================================
   gv-controls — shared game left-rail control library styling.
   Wraps the EXISTING design tokens + base classes (.seg/.preview/.field/.gv-select/.bet-btn/.gv-readout);
   only the NEW composite bits (full-width rail segmented, slider head, stepper ±, status tones, collapsible,
   toolbar, action row) get rules here. No new tokens, no new colors — see styles.css for the palette.
   Design doc: .plan/scan-reports/07-game-controls-layout.md
   ========================================================================== */

/* ---- segmented: the shared .seg, made full-width in the narrow rail, buttons share the row ---- */
.gv-seg { display: flex; width: 100%; margin: 0; gap: 4px; }
.gv-seg .gv-seg-btn { flex: 1 1 0; min-width: 0; justify-content: center; display: inline-flex; align-items: center; gap: 6px; text-align: center; }
.gv-seg.seg--two .gv-seg-btn { flex-direction: column; gap: 1px; padding-block: 6px; }
.gv-seg .gv-seg-main { font-weight: var(--fw-semi); }
.gv-seg .gv-seg-sub { font-size: var(--fs-xs); opacity: .7; text-transform: none; letter-spacing: 0; }
/* SAFETY NET (site-wide): a selected segment's background flips to --brand, so force the sub-label to the
   on-accent ink — a game that tints its sub-label (e.g. a green multiplier) can never collide with the green
   active background and become invisible. Per-game rules with higher specificity may still restate this. */
.gv-seg .gv-seg-btn.active .gv-seg-sub { color: var(--brand-ink); }
.gv-seg.seg--tray .gv-seg-btn { padding: 6px 8px; font-variant-numeric: tabular-nums; }

/* ---- slider: label.seg.grow column + a head row (label left / value right) over the range ---- */
.gv-slider { gap: var(--sp-1); }
.gv-slider-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }
.gv-slider-val { color: var(--fg); font-size: var(--fs-md); font-weight: var(--fw-bold); text-transform: none; letter-spacing: 0; font-variant-numeric: tabular-nums; }
.gv-slider-input { width: 100%; }
.gv-slider.gv-locked { opacity: .7; }

/* ---- select: reuses .field + .gv-select; no extra chrome needed (margin zeroed inside the slot) ---- */
.gv-field { margin: 0; }

/* ---- stepper / numberField: bordered box, borderless input, optional ± and $/× affixes ---- */
.gv-stepper { gap: var(--sp-1); }
.gv-stepper-box {
  display: flex; align-items: stretch; min-height: var(--touch);
  /* fill the column wrapper and never overflow the rail at wider widths (the box is a flex column child;
     without an explicit width + border-box it can size to its content and spill past the slot edge). */
  width: 100%; box-sizing: border-box;
  border: 1px solid var(--line-2); border-radius: var(--r-md); background: var(--bg-1); overflow: hidden;
}
.gv-stepper-box:focus-within { border-color: var(--brand); box-shadow: var(--ring); }
.gv-stepper-input {
  flex: 1 1 0; min-width: 0; width: auto; border: 0; background: transparent; box-shadow: none;
  text-align: center; padding: 10px 8px; min-height: 0;
}
.gv-stepper-input:focus-visible { outline: none; box-shadow: none; }
.gv-affix { display: flex; align-items: center; padding: 0 10px; color: var(--muted); font-weight: var(--fw-semi); }
.gv-prefix { border-right: 1px solid var(--line-2); }
.gv-suffix { border-left: 1px solid var(--line-2); }
.gv-step {
  appearance: none; border: 0; cursor: pointer; width: 42px; flex: 0 0 auto;
  background: var(--surface-3); color: var(--fg); font-size: 20px; line-height: 1; font-family: var(--font-display);
  transition: background var(--dur-1);
}
.gv-step:hover { background: var(--surface-2); color: var(--brand); }
.gv-step-dn { border-right: 1px solid var(--line-2); }
.gv-step-up { border-left: 1px solid var(--line-2); }
.gv-hint { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); color: var(--muted); text-transform: none; letter-spacing: 0; }
.gv-hint.invalid { color: var(--danger, #ff6b6b); }

/* ---- status line: aria-live text with optional outcome tone ---- */
.gv-status { margin: 0; font-size: var(--fs-sm); line-height: 1.4; }
.gv-status.is-safe { color: var(--win, #46d39a); }
.gv-status.is-bust { color: var(--danger, #ff6b6b); }
.gv-status.is-cashout { color: var(--violet); }
.gv-status.invalid { color: var(--danger, #ff6b6b); }

/* ---- preview PAYOUT figure: its OWN money accent (gold), NOT the link-blue used for usernames/links ----
   The shared `.preview .stat.accent b` (04-lobby-game.css) tints the accent figure --violet — the same blue
   used for links/usernames, so a "$X" payout wrongly reads as navigable. gv-controls.css loads AFTER
   styles.css, so this equal-or-higher-specificity rule re-tints ONLY the pay figure (`.gv-pay`, set by
   preview() on the pay:true stat) to --gold — the reserved big-win money color. This is display-only text
   (money via textContent); it does not change any id/data-* hook or the cap gate. Applies uniformly to every
   game that renders a win-pays preview (dice/limbo/coinflip/wheel/roulette/plinko/keno/sicbo/crash/slots/…);
   games with no accent preview (mines/hilo/dragontower next-pays readouts) are unaffected. */
.preview .stat.accent b.gv-pay { color: var(--gold); text-shadow: 0 0 10px var(--gold-glow); }
/* The over-cap gate (cap.js toggles `.over-cap` on the SAME <b> when the previewed win breaches the house
   max) MUST still out-rank the gold accent so an unpayable win reads red, not gold. `.over-cap` alone
   (specificity 0,1,0) loses to the gold rule above; re-assert red at matching specificity + drop the glow. */
.preview .stat.accent b.gv-pay.over-cap { color: var(--lose); text-shadow: none; }

/* ---- "Max bet" is NOT a duplicate of "Win pays": show it for EVERY game.
   HISTORY: `.bet-max-win` used to read "Max win $X" — the SAME worst-case payout the shared preview()
   already showed as `.gv-pay`, so it was hidden for the 10 preview games (`:has(.gv-game-controls .gv-pay)`)
   to avoid TWO identical payout readouts. Owner relabel (2026-07): the readout now leads with "Max bet $Y"
   (the cap-safe max STAKE the player can place) — a DISTINCT, useful figure that is NOT the win-pays number.
   So the de-dup hide rule is gone: every game shows "Max bet", and the house WIN cap is context-only (a small
   "wins capped at $X" note under it, shown by cap.js/renderMaxBet ONLY when the current stake's win is capped).
   Display-only; the cap gate + stake clamp are unchanged. */

/* ---- inline readout: value right-aligned (label left) for the rail ---- */
.gv-readout-v { margin-left: auto; font-variant-numeric: tabular-nums; }

/* ---- primary action button: reuses .bet-btn; ensure the label/spinner swap works ---- */
.gv-action .label { display: inline; }

/* ---- PRE-ROUND action hierarchy: a disabled Cash-Out / Pick-random reads "available after Bet", not broken.
   Pre-round, the climb games (mines/hilo/dragontower/coinflip-streak) mount Cash-Out (actionButton → .gv-action)
   and Pick-random (ghostButton → .gv-ghost) PRESENT-BUT-DISABLED (kept in-flow to avoid a CLS shift when a round
   starts/ends). The site-wide `button:disabled` (opacity:.45, flat fill) makes those full-size buttons look like
   dead grey slabs. Here a disabled shared action/ghost button instead gets an explicit "inactive-until-Bet"
   affordance: a dashed outline + transparent fill + a legible muted label — so it reads as intentionally gated,
   not broken. Scoped to the SHARED classes and to `:disabled` only, so every game's ENABLED (in-round) Cash-Out /
   Pick-random and the resolved/loading states are untouched. `.loading` (spinner up) keeps the solid look — a
   loading button is mid-action, not pre-round — so we exclude it. The site-wide `button:disabled:not(.tile)…`
   fade is a 4-`:not()` chain (specificity 0,5,1); these selectors match/exceed it (element + `.gv-*` + the
   same 4-`:not()` tile guards) so this skin wins deterministically, not by source order alone. The tile guards
   are also correct on their own merits — a shared action/ghost button is never a board tile. */
button.gv-action:disabled:not(.loading):not(.tile):not([class*="-tile"]):not([class*="-cell"]),
button.gv-ghost:disabled:not(.tile):not([class*="-tile"]):not([class*="-cell"]) {
  opacity: 1;                                   /* override the .45 "broken" fade — legibility over a flat dim */
  background: transparent;
  border: 1px dashed var(--line-3);
  color: var(--muted);
  box-shadow: none;
  text-shadow: none;
  cursor: not-allowed;
}
/* the primary-action (Cash-Out) placeholder keeps its full height/type so the rail doesn't reflow when it
   becomes enabled — only its skin changes (dashed vs solid). */
button.gv-action:disabled:not(.loading):not(.tile):not([class*="-tile"]):not([class*="-cell"]) { font-weight: var(--fw-bold); letter-spacing: .02em; }

/* ---- secondary action row (blackjack hit/stand/…; insurance) ---- */
.gv-action-row { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
/* min-width:max-content + nowrap: at the docked/narrow rail these secondary actions (Hit/Stand/Rebet/Cash Out)
   WRAP to the next line instead of shrinking to 0 and ellipsizing their labels. */
.gv-action-row .gv-row-btn { flex: 1 1 auto; min-width: max-content; padding: 12px; min-height: 46px; font-size: var(--fs-md); box-shadow: none; white-space: nowrap; }
.gv-action-row.loading { opacity: .7; pointer-events: none; }
/* same "gated, not broken" treatment for a disabled row button (blackjack shows Hit/Stand/Double/Split
   pre-deal): dashed placeholder instead of the flat .45 slab. Loading row is mid-deal, so leave it solid.
   Specificity padded (element + `.gv-*` + the 4-`:not()` tile guards) to out-rank the site-wide 0,5,1 fade. */
.gv-action-row:not(.loading) button.gv-row-btn:disabled:not(.tile):not([class*="-tile"]):not([class*="-cell"]) {
  opacity: 1; background: transparent; border: 1px dashed var(--line-3); color: var(--muted); box-shadow: none;
}

/* ---- ghost secondary button ---- */
.gv-ghost { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }

/* ---- collapsible (native details) with a caret ---- */
.gv-collapsible { border: 1px solid var(--line-2); border-radius: var(--r-md); background: var(--surface-2); overflow: hidden; }
.gv-collapsible-sum {
  cursor: pointer; list-style: none; padding: 10px 12px; display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--fg);
}
.gv-collapsible-sum::-webkit-details-marker { display: none; }
.gv-collapsible-sum::after { content: ""; margin-left: auto; width: 8px; height: 8px; border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); transform: rotate(45deg); transition: transform var(--dur-2); }
.gv-collapsible[open] > .gv-collapsible-sum::after { transform: rotate(-135deg); }
.gv-collapsible-body { padding: 0 12px 12px; }

/* ---- toolbar: a cluster of tiny ghost buttons + an optional counter ---- */
.gv-toolbar { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.gv-toolbar-count { font-size: var(--fs-sm); color: var(--muted); font-weight: var(--fw-semi); margin-right: auto; }
.gv-tool-btn { display: inline-flex; align-items: center; gap: 5px; }
