/* =============================================================================
   bust.fun — LIMBO styles  (games/limbo/limbo.css)  — OWNER A (+B for fx CSS)
   -----------------------------------------------------------------------------
   Game-SPECIFIC styles for the limbo module. Loaded by limbo.js (it injects a
   same-origin <link> idempotently; the lead may instead add the <link> in
   index.html — see the module Report). Synthwave TOKENS ONLY (tokens.css) — no
   hard-coded palette. The shared chrome (target input row, .preview stats, Bet
   button, result card) is owned centrally in styles.css — this file only adds the
   limbo reveal surface + polishes the limbo-scoped controls.

   a11y bar: reduced-motion no-ops ALL motion (see the bottom block); 44px touch on
   the target input; 0 horizontal overflow at 360px (the big readout clamps + the
   long-number font-size steps down).
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Target input polish — neon, big, legible. Scoped by the unique #limboTarget id: the control now
   lives in the shared #gameControlsSlot rail (NOT inside the panel), so a .panel[data-panel="limbo"]
   ancestor never matched and this styling was dead. The id alone still beats the shared stepper chrome
   and stays limbo-only.
   -------------------------------------------------------------------------- */
#limboTarget {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  letter-spacing: .02em;
  min-height: var(--touch);                /* 44px touch target */
  text-align: center;
  color: var(--violet);
  border-color: var(--line-2);
  transition: border-color var(--dur-2), box-shadow var(--dur-2), color var(--dur-2);
}
#limboTarget:focus-visible {
  border-color: var(--violet);
  box-shadow: 0 0 0 3px var(--violet-glow);
  outline: none;
}
/* invalid target → rose border + a clear cue (paired with the live #limboHint text). */
#limboTarget[aria-invalid="true"] {
  /* --lose (#f43f5e rose-red), NOT --accent: in this theme --accent is a BLUE CTA color, so the invalid
     state was rendering blue — the opposite of an error signal. --lose is the canonical negative token. */
  border-color: var(--lose);
  color: var(--lose);
  box-shadow: 0 0 0 3px var(--lose-soft);
}

/* inline validation hint — replaces the old silent "—". role=status / aria-live=polite. */
/* CLS FIX (baccarat/roulette reserve pattern): #limboHint is IN FLOW in the left rail, ABOVE the
   preview stats (#limboChance / #limboPays). It toggled the global `.hidden { display:none !important }`
   (no hint) ↔ block (a validation message), so every time the target became invalid/valid the hint
   APPEARED and shoved the Win-chance / Win-pays preview DOWN (then pulled it back UP when valid). The
   message can wrap to 2 lines on a narrow rail, so reserve the 2-LINE worst case up front (2 × 1.4
   line-height + the top margin) and keep the box IN FLOW when hidden via the override below — the
   preview stats never move across valid → invalid → valid. */
.limbo-hint {
  box-sizing: border-box; min-height: calc(2 * 1.4em);
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--lose);   /* error/validation text → the rose negative token, not the blue --accent */
  font-weight: var(--fw-semi);
}
/* hidden = reserved-but-invisible: keep the box (and its reserved min-height) IN FLOW so the preview
   stats below never shift, but make it fully invisible + inert. The global `.hidden { display:none
   !important }` utility (styles/03-layout-forms.css) would otherwise pull the box out of flow — we
   override it with our own `!important` so the slot stays reserved; `visibility:hidden` hides the text
   and also removes it from the a11y tree (matching the old display:none aria semantics). */
.limbo-hint.hidden { display: block !important; visibility: hidden; pointer-events: none; }

/* -----------------------------------------------------------------------------
   The multiplier STAGE — the hero reveal. The climb (limbo.fx.js numberRamp) lands
   in .limbo-mult; .limbo-stage[data-state] drives the win/loss painting.
   -------------------------------------------------------------------------- */
.limbo-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  /* FILL the display column WIDTH. The shared rule that gives sibling stages (dice-meter,
     mines-grid, plinko-stage, …) `width:100%; align-self:center` in 12-gameview.css does NOT
     list .limbo-stage, and the .panel flex column inherits the base .gameview `align-items:start`,
     so without this the stage shrinks to its content width — on mobile (390px) it rendered as a
     narrow vertical strip with a large empty band beside it. width:100% + align-self:stretch make
     it span the column at every width. */
  width: 100%;
  align-self: stretch;
  /* FILL: the stage is the hero — it grows to consume the display column's spare height
     and centers the HUGE multiplier number inside it. min-height:0 lets it shrink on
     short screens; the clamp floor keeps it a generous band even then.
     C19 (frame-audit): the stage fills the column nicely on desktop (~662px), but on a TALL
     column (tablet ~1180px → ~890px stage) the hero NUMBER (which scales mainly on vh) stopped
     keeping pace with the stretching box, so it read as a small number marooned in a vast empty
     box (it filled only ~22% of the stage height). We keep the column-filling "screen" look but
     (a) bump the number scale below so it commands the stage, and (b) cap the runaway growth on
     the very tall column so the empty top/bottom bands can't balloon. `justify-content:center`
     keeps the (now bounded) stage centered in the column. */
  flex: 1 1 auto; min-height: clamp(160px, 38vh, 520px); max-height: min(72vh, 640px);
  margin: var(--sp-4) 0 var(--sp-2);
  padding: var(--sp-5) var(--sp-3);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 80% at 50% 0%, var(--violet-soft), transparent 70%),
    var(--surface-2);
  border: 1px solid var(--line-2);
  overflow: hidden;
  text-align: center;
}
/* faint synthwave grid wash behind the number (cheap, decorative). */
.limbo-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--grid-color) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
  background-size: var(--grid-size) var(--grid-size);
  opacity: .5;
  pointer-events: none;
}

.limbo-mult {
  position: relative;
  font-family: var(--font-display);
  /* HUGE hero number — the whole point of the game. Scales mainly with viewport HEIGHT
     (the display column is tall) plus a little width, floored so it stays bold on short
     screens and capped so a giant monitor doesn't get absurd. The long-number step-downs
     in the media queries below keep a runaway multiplier from overflowing at 360px.
     C19 (frame-audit): bumped the vh coefficient + ceiling (was 14vh+2vw, cap 200px) so the
     hero number COMMANDS the tall stage instead of floating small in it (it was ~22% of the
     stage height on tablet). `white-space:nowrap` + `max-width:100%` + the media step-downs
     keep a long multiplier (e.g. 1,000,000×) from overflowing the column. */
  font-size: clamp(56px, 18vh + 2vw, 260px);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
  color: var(--violet);
  text-shadow: 0 0 22px var(--violet-glow);
  /* clamp so a runaway multiplier (e.g. 1,000,000×) never overflows at 360px. */
  max-width: 100%;
  white-space: nowrap;
  transition: color var(--dur-2), text-shadow var(--dur-2), font-size var(--dur-2);
}

.limbo-target-line {
  position: relative;
  /* grow the caption a step with the bigger stage so it doesn't read as a tiny footnote */
  font-size: clamp(var(--fs-xs), 1vh + 0.4vw, var(--fs-md));
  text-transform: uppercase;
  letter-spacing: var(--tracking-cap);
  font-weight: var(--fw-semi);
  color: var(--muted);
  min-height: 1em;                              /* reserve space so the stage doesn't jump */
}

/* -----------------------------------------------------------------------------
   FIXED TARGET REFERENCE LINE (Finding 1): a labelled horizontal marker drawn across
   the stage at a FIXED height. The huge climbing number is vertically centred above it,
   so the player can SEE the climb cross the line (win) or stall beneath it (loss). It's
   absolutely positioned so it does NOT participate in the flex flow → it can't shift the
   centred number or the reserved caption (no CLS). Decorative (aria-hidden in the DOM).
   -------------------------------------------------------------------------- */
.limbo-target-ref {
  position: absolute;
  left: var(--sp-4);
  right: var(--sp-4);
  /* sit just below the vertical centre so the centred hero number reads as "above the line". */
  top: 68%;
  height: 0;
  border-top: 2px dashed var(--line-2);
  opacity: .85;
  pointer-events: none;
  transition: border-color var(--dur-2), opacity var(--dur-2);
}
.limbo-target-ref-label {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  padding: 2px var(--sp-2);
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-cap);
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  transition: color var(--dur-2), border-color var(--dur-2), background var(--dur-2);
}
/* on a WIN the landed number cleared the line → tint the line + label win-green. */
.limbo-stage[data-state="win"] .limbo-target-ref { border-top-color: var(--win); opacity: 1; }
.limbo-stage[data-state="win"] .limbo-target-ref-label { color: var(--win-2); border-color: var(--win); }
/* on a LOSS the climb stalled below the line → it stays a neutral, dim reference. */
.limbo-stage[data-state="loss"] .limbo-target-ref { border-top-color: var(--line-2); opacity: .7; }

/* ---- outcome states (set by the core via data-state) ---- */
.limbo-stage[data-state="win"] {
  border-color: var(--win);
  background:
    radial-gradient(120% 80% at 50% 0%, var(--win-soft), transparent 70%),
    var(--surface-2);
  box-shadow: var(--glow-win);
}
.limbo-stage[data-state="win"] .limbo-mult {
  color: var(--win);
  text-shadow: 0 0 18px var(--win-glow);
}
.limbo-stage[data-state="win"] .limbo-target-line { color: var(--win-2); }

.limbo-stage[data-state="loss"] {
  border-color: var(--line-2);
  background: var(--surface-2);
}
.limbo-stage[data-state="loss"] .limbo-mult {
  /* the climb stalled below target → dim, no glow. */
  color: var(--muted);
  text-shadow: none;
  opacity: .85;
}
.limbo-stage[data-state="loss"] .limbo-target-line { color: var(--muted); }

/* ---- CLIMBING state (set by limbo.fx.js via a .limbo-climbing class on the stage
   while the number RAMP is in flight; removed on settle). Presentation only — the
   server result is already known; this just dramatizes the display ramp. Reduced
   motion no-ops the drift (see the reduced-motion block). ---- */
.limbo-stage.limbo-climbing {
  border-color: var(--violet);
  box-shadow: var(--glow-brand, 0 0 24px var(--violet-glow));
}
.limbo-stage.limbo-climbing .limbo-mult {
  color: var(--violet);
  text-shadow: 0 0 22px var(--violet-glow);
}
/* the grid wash drifts upward while climbing → reads as "rising". */
.limbo-stage.limbo-climbing::before {
  opacity: .8;
  animation: limbo-grid-rise 1.1s linear infinite;
}
@keyframes limbo-grid-rise {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 0 calc(-1 * var(--grid-size)), 0 0; }
}

/* -----------------------------------------------------------------------------
   Win-chance stat emphasis (the real win-chance display) — keep it consistent with
   the shared .preview .stat chrome; just tint the chance value cyan (info).
   -------------------------------------------------------------------------- */
#limboChance { color: var(--cyan); }
/* the shared over-cap flag (.over-cap → --lose) still wins on #limboPays — don't override it. */

/* -----------------------------------------------------------------------------
   SESSION RETENTION CHROME (Finding 2) — rail, under the preview. A "best this session"
   readout (a chase target) + a recent-draws chip row (last ~12 landed multipliers as
   win/loss chips). PRESENTATION ONLY — labelled HISTORY, never a predictor, never money.
   Both reserve their own height so the empty idle state and a filled state occupy the SAME
   space (the first chip / first best never shifts the rail layout → no CLS).
   -------------------------------------------------------------------------- */
.limbo-best {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line-2);
}
.limbo-best-k {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-cap);
  font-weight: var(--fw-semi);
  color: var(--muted);
}
.limbo-best-v {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  color: var(--violet);
}

.limbo-history { margin-top: var(--sp-3); }
.limbo-history-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-1);
}
.limbo-history-k {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-cap);
  font-weight: var(--fw-semi);
  color: var(--muted);
}
/* the explicit "history · not a prediction" disclaimer so the chips are never read as a forecast. */
.limbo-history-note {
  font-size: var(--fs-xs);
  color: var(--muted);
  opacity: .8;
}
.limbo-history-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  /* RESERVE one chip row up front so the empty "No rounds yet" state and a filled row are the same height
     (no CLS when the first chip lands). One line of chips ≈ fs-xs text + 2×3px pad + 1px border + small slack. */
  min-height: calc(var(--fs-xs) + 12px);
  align-content: flex-start;
}
.limbo-chip {
  padding: 2px var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--line-2);
  white-space: nowrap;
}
.limbo-chip.is-win {
  color: var(--win-2);
  background: var(--win-soft);
  border-color: var(--win);
}
.limbo-chip.is-loss {
  color: var(--muted);
  background: var(--surface-2);
  border-color: var(--line-2);
}
.limbo-history-empty {
  font-size: var(--fs-xs);
  color: var(--muted);
  opacity: .75;
}

/* -----------------------------------------------------------------------------
   Narrow viewport: step the hero number down so a long multiplier never overflows
   at 360px (the HARD 0-overflow gate). The number is the only wide element here.
   -------------------------------------------------------------------------- */
@media (max-width: 420px) {
  /* still big on phones, but capped lower (vh only) so a long number doesn't overflow the
     narrower column and the stage shares the shorter viewport with the controls. */
  .limbo-mult { font-size: clamp(40px, 12vh, 92px); }
  .limbo-stage { min-height: clamp(140px, 30vh, 360px); padding: var(--sp-4) var(--sp-2); }
}
@media (max-width: 340px) {
  .limbo-mult { font-size: clamp(30px, 10vh, 64px); }  /* safety for very long numbers */
}

/* -----------------------------------------------------------------------------
   Reduced motion — no-op ALL limbo motion (the number still SNAPS to the truth via
   fx.numberRamp, the state colors still apply; only transitions/animation are off).
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  #limboTarget,
  .limbo-mult,
  .limbo-stage,
  .limbo-target-ref,
  .limbo-target-ref-label { transition: none; }
  /* kill the climbing grid drift entirely (the number still snaps to the truth). */
  .limbo-stage.limbo-climbing::before { animation: none; }
}
