/**
 * The look.
 *
 * Palette, typography and glass treatment follow the reference design: a deep
 * teal-to-black field, neon green as the primary, and three typefaces doing
 * three jobs — Bebas Neue for numbers you read at a glance, Share Tech Mono for
 * labels and identifiers, Rajdhani for everything else.
 *
 * Two rules the whole file obeys:
 *
 *   1. Animate transform and opacity only. Anything animating width, height,
 *      top or left forces layout every frame, and this page already has a
 *      canvas asking for the frame budget.
 *
 *   2. The game page does not scroll. It is a fixed viewport with a flexible
 *      middle, so the bet controls stay under the player's thumb whatever the
 *      screen. Every other page scrolls normally — see .app-scroll.
 */

:root {
    --green:  #00ff88;
    --red:    #ff3355;
    --yellow: #ffcc00;
    --blue:   #00ccff;

    --text:   #d8f5ec;
    --muted:  rgba(170, 230, 210, 0.55);

    --glass:  rgba(3, 18, 28, 0.55);
    --line:   rgba(0, 200, 140, 0.22);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body { height: 100%; }

body {
    font-family: 'Rajdhani', system-ui, -apple-system, sans-serif;
    color: var(--text);
    overflow-x: hidden;
    /* A game screen, not a document: an accidental pull-to-refresh mid-flight
       is a lost cashout. */
    overscroll-behavior: none;
}

button, input, select { font-family: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* ------------------------------------------------------------- background */

.field-bg {
    position: fixed; inset: 0; z-index: 0;
    background: radial-gradient(ellipse at 50% 0%, #06263a 0%, #041722 45%, #010a10 100%);
}

.field-bg::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(180deg,
        rgba(0, 10, 18, 0.42) 0%,
        rgba(0, 10, 18, 0.22) 45%,
        rgba(0, 10, 18, 0.50) 100%);
}

/* ------------------------------------------------------------- app shells */

.app {
    position: relative; z-index: 2;
    max-width: 1180px; margin: 0 auto;
    display: flex; flex-direction: column;
}

/*
 * The game shell. dvh, not vh: on a phone `100vh` is the viewport with the
 * browser's address bar HIDDEN, so a vh-sized layout is taller than the screen
 * until the user scrolls — which is exactly what a non-scrolling page cannot
 * do. dvh tracks the visible height as the chrome slides away.
 */
.app-fixed {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    gap: 8px;
    padding: calc(8px + env(safe-area-inset-top)) 10px calc(8px + env(safe-area-inset-bottom));
}

/* Every other page is a normal document. */
.app-scroll {
    min-height: 100vh;
    min-height: 100dvh;
    gap: 12px;
    padding: calc(14px + env(safe-area-inset-top)) 14px calc(20px + env(safe-area-inset-bottom));
}

@media (min-width: 640px) {
    .app-fixed  { gap: 12px; padding-left: 16px; padding-right: 16px; }
    .app-scroll { padding-left: 18px; padding-right: 18px; }
}

/* ------------------------------------------------------------------ header */

.topbar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex: none;
}

.brand { display: flex; align-items: center; gap: 9px; min-width: 0; }

.brand-icon {
    width: 38px; height: 38px; flex: none;
    border-radius: 11px;
    background: linear-gradient(135deg, #00e87a, #005533);
    display: grid; place-items: center;
    box-shadow: 0 0 22px rgba(0, 255, 136, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.brand-icon::after {
    content: ''; width: 13px; height: 13px; border-radius: 50%;
    background: radial-gradient(circle at 34% 30%, #eafff5, #00ff88 55%, #007a44);
    box-shadow: 0 0 12px rgba(255, 255, 255, 0.7);
}

.brand-name {
    font-family: 'Bebas Neue', sans-serif;
    font-size: 25px; letter-spacing: 2.5px; line-height: 1;
    background: linear-gradient(90deg, #00ff88, #80ffe0);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    filter: drop-shadow(0 0 10px rgba(0, 255, 136, 0.5));
}

.brand-sub {
    display: flex; align-items: center; gap: 6px; margin-top: 2px;
    font-family: 'Share Tech Mono', monospace; font-size: 10px;
    color: var(--muted); letter-spacing: 1px;
}

.conn-dot {
    width: 7px; height: 7px; border-radius: 50%; flex: none;
    background: var(--green); box-shadow: 0 0 8px var(--green);
    animation: blink 1.6s ease-in-out infinite;
}
.conn-dot.is-down { background: var(--red); box-shadow: 0 0 8px var(--red); }

@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

.topbar-right { display: flex; align-items: center; gap: 8px; flex: none; }

.balance-chip {
    display: flex; flex-direction: column; align-items: flex-end;
    padding: 5px 12px; border-radius: 11px;
    background: rgba(2, 12, 20, 0.72);
    border: 1px solid var(--line);
    line-height: 1.15;
}
.balance-chip:hover { border-color: rgba(0, 255, 136, 0.45); }

.balance-chip .lbl {
    font-family: 'Share Tech Mono', monospace; font-size: 8.5px;
    letter-spacing: 1.5px; color: var(--muted);
}

.balance-chip .val {
    font-family: 'Bebas Neue', sans-serif; font-size: 19px; letter-spacing: 1px;
    color: #fff;
}

.balance-chip.bump { animation: bump 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); }
.balance-chip.bump .val { color: var(--green); }

@keyframes bump {
    0% { transform: scale(1); } 40% { transform: scale(1.09); } 100% { transform: scale(1); }
}

/* --------------------------------------------------------- history rail */

.rail {
    display: flex; gap: 5px; align-items: center; flex: none;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    min-height: 24px;
}
.rail::-webkit-scrollbar { display: none; }

.hist {
    flex: 0 0 auto;
    padding: 3px 9px; border-radius: 7px;
    font-family: 'Share Tech Mono', monospace; font-size: 11px; font-weight: 700;
    border: 1px solid transparent; white-space: nowrap;
    background: rgba(2, 12, 20, 0.72);
}

.hist-low  { color: var(--red);    border-color: rgba(255, 51, 85, 0.28); }
.hist-mid  { color: var(--yellow); border-color: rgba(255, 204, 0, 0.28); }
.hist-high { color: var(--green);  border-color: rgba(0, 255, 136, 0.30); }
.hist-huge {
    color: #fff; border-color: rgba(0, 255, 136, 0.65);
    box-shadow: 0 0 14px rgba(0, 255, 136, 0.28);
}

.hist-mine-won  { outline: 1px solid var(--green); outline-offset: 1px; }
.hist-mine-lost { opacity: 0.45; }

.hist-new { animation: hist-in 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes hist-in { from { transform: scale(0.6); opacity: 0; } }

/* ------------------------------------------------------------------ stage */

.stage-wrap {
    position: relative; flex: 1; min-height: 0;
    border-radius: 18px; overflow: hidden;
    border: 1px solid rgba(0, 210, 150, 0.18);
    background: #060e14;
    box-shadow: 0 8px 40px rgba(0, 0, 0, 0.55);
    isolation: isolate;
}

.stage { position: absolute; inset: 0; z-index: 1; }

/* A slow breathing halo behind the number. Atmosphere, and the only purely
   decorative element on the stage. */
.glow-ring {
    position: absolute; top: 46%; left: 50%;
    transform: translate(-50%, -50%);
    width: min(78vw, 380px); aspect-ratio: 1; border-radius: 50%;
    background: radial-gradient(circle, rgba(0, 255, 136, 0.09) 0%, transparent 68%);
    animation: ring 3s ease-in-out infinite;
    pointer-events: none; z-index: 2;
}

@keyframes ring {
    0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: 0.6; }
    50%      { transform: translate(-50%, -50%) scale(1.16); opacity: 1; }
}

/* ---- overlay chrome ---- */

.stage-top {
    position: absolute; z-index: 4; top: 0; left: 0; right: 0;
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 8px; padding: 9px 11px; pointer-events: none;
}

.session-badge {
    font-family: 'Share Tech Mono', monospace; font-size: 10.5px;
    color: var(--muted);
    background: rgba(0, 255, 136, 0.07);
    border: 1px solid rgba(0, 255, 136, 0.15);
    padding: 4px 10px; border-radius: 7px; white-space: nowrap;
}
.session-badge b { color: var(--green); font-weight: 400; }

.status-badge {
    font-family: 'Bebas Neue', sans-serif; letter-spacing: 2px; font-size: 13px;
    padding: 4px 14px; border-radius: 7px; border: 1px solid;
    white-space: nowrap; transition: color 0.3s, border-color 0.3s, background-color 0.3s;
}

.st-wait  { color: var(--yellow); border-color: rgba(255, 204, 0, 0.35); background: rgba(255, 204, 0, 0.08); }
.st-soon  { color: var(--blue);   border-color: rgba(0, 200, 255, 0.35); background: rgba(0, 200, 255, 0.08); }
.st-fly   { color: var(--green);  border-color: rgba(0, 255, 136, 0.35); background: rgba(0, 255, 136, 0.08); }
.st-crash { color: var(--red);    border-color: rgba(255, 51, 85, 0.35); background: rgba(255, 51, 85, 0.08); }

/* ---- the number ---- */

.centre {
    position: absolute; z-index: 3; inset: 0;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 10px; pointer-events: none; padding: 0 12px;
}

/*
 * No panel behind the number. The text carries its own glow and the shadow
 * stack below gives it enough separation from the chart to stay readable —
 * a filled box floating over the curve was hiding the thing it sits on.
 */
.mult-box { text-align: center; }

#mult {
    font-family: 'Bebas Neue', sans-serif;
    font-size: clamp(56px, 15vw, 118px);
    line-height: 1; letter-spacing: 2px;
    color: #fff;
    text-shadow: 0 0 35px rgba(0, 255, 136, 0.5),
                 0 0 80px rgba(0, 255, 136, 0.2),
                 0 3px 0 rgba(0, 0, 0, 0.7);
    transition: color 0.15s, text-shadow 0.15s;
    font-variant-numeric: tabular-nums;
}

/* Banded by size, so the colour alone says roughly where the round is. */
#mult.m-mid {
    color: var(--yellow);
    text-shadow: 0 0 40px rgba(255, 204, 0, 0.9), 0 0 90px rgba(255, 204, 0, 0.4);
}

#mult.m-high {
    color: var(--green);
    text-shadow: 0 0 40px rgba(0, 255, 136, 0.95),
                 0 0 90px rgba(0, 255, 136, 0.5),
                 0 0 160px rgba(0, 255, 136, 0.2);
}

#mult.m-crash {
    color: var(--red);
    text-shadow: 0 0 40px rgba(255, 51, 85, 0.95), 0 0 90px rgba(255, 51, 85, 0.45);
    animation: shake 0.5s ease-in-out;
}

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-13px); } 40% { transform: translateX(13px); }
    60% { transform: translateX(-8px); }  80% { transform: translateX(8px); }
}

.flew {
    font-family: 'Bebas Neue', sans-serif; font-size: clamp(20px, 5vw, 30px);
    letter-spacing: 4px; color: var(--red);
    text-shadow: 0 0 30px rgba(255, 51, 85, 0.8);
}

/* ---- countdown ---- */

.cd-label {
    font-size: 12px; color: var(--muted); letter-spacing: 3px;
    text-transform: uppercase; text-align: center;
}

#cd-timer {
    font-family: 'Bebas Neue', sans-serif;
    font-size: clamp(72px, 20vw, 130px); line-height: 1; text-align: center;
    color: var(--blue);
    text-shadow: 0 0 50px rgba(0, 200, 255, 0.9), 0 0 100px rgba(0, 200, 255, 0.4);
    animation: cdp 1s ease-in-out infinite;
    font-variant-numeric: tabular-nums;
}

@keyframes cdp { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.07); } }

/* ---- climb-rate gauge ---- */
/*
 * Real, not decorative. The curve is e^(kt), so its slope is exactly k*m(t):
 * the needle shows how fast the multiplier is climbing at this instant, which
 * is a fact about the round rather than a mood.
 */
/*
 * Sits in the centre column under the number, the way the reference lays it
 * out. It was pinned to the bottom-left corner first, which is exactly where
 * the curve's origin sits during the betting phase.
 */
/*
 * Sized off the viewport, not fixed: the reference lays these out at about
 * 280px and 220px on a desktop panel, which is unreadable if it is carried
 * verbatim onto a 390px phone and pointlessly small if it is not carried at
 * all. clamp() keeps the desktop proportions and scales down to something
 * still legible on a handset.
 */
.telemetry {
    display: flex; align-items: flex-end; justify-content: center;
    gap: clamp(14px, 3vw, 36px);
    padding: 12px clamp(16px, 4vw, 34px) 6px;
    pointer-events: none;

    /* A soft radial vignette rather than a panel. The readouts sit over the
       history columns and the live curve, and with their boxes removed the
       thin strokes were competing with everything behind them. This darkens
       what is underneath without drawing an edge — no border, no corners,
       nothing that reads as a card. */
    background: radial-gradient(ellipse at 50% 58%,
        rgba(2, 10, 18, 0.78) 0%,
        rgba(2, 10, 18, 0.5) 46%,
        transparent 74%);
}

.gauge { width: clamp(152px, 30vw, 270px); }

.gauge svg { width: 100%; height: auto; display: block; overflow: visible; }

.gauge-track { fill: none; stroke: rgba(255, 255, 255, 0.09); stroke-width: 14; stroke-linecap: round; }

.gauge-fill {
    fill: none; stroke: var(--green); stroke-width: 14; stroke-linecap: round;
    stroke-dasharray: 264; stroke-dashoffset: 264;
    transition: stroke-dashoffset 90ms linear, stroke 200ms ease;
}

.gauge-fill.mid { stroke: var(--yellow); }
.gauge-fill.hot { stroke: var(--red); }

.gauge-needle {
    stroke: #fff; stroke-width: 3; stroke-linecap: round;
    transform-origin: 100px 104px;
    transition: transform 90ms linear;
}

.gauge-needle circle { fill: #fff; stroke: none; }

.gauge-cap {
    display: flex; align-items: baseline; justify-content: center; gap: 6px;
    margin-top: -14px;
}

.gauge-val {
    font-family: var(--mono); font-size: clamp(19px, 4.4vw, 30px);
    font-weight: 700; color: #fff; letter-spacing: -0.02em;
}

.gauge-unit {
    font-family: var(--mono); font-size: clamp(9px, 1.8vw, 12px);
    letter-spacing: 0.18em; color: rgba(255, 255, 255, 0.42);
}

/* ---- rarity meter ---- */
/*
 * How unusual it is to still be flying. P(crash >= m) = (32/33) * 99/(m-1)
 * comes straight from the published fairness formula, so the bar fills with
 * 1 - P: at 2.00x roughly half of rounds have already ended, at 10x about
 * nine in ten have. Unlike the climb-rate needle this is NOT a restatement of
 * the number above it — it is the one thing on the stage telling a player
 * something the multiplier alone does not.
 */
.rarity {
    width: clamp(122px, 23vw, 215px);
    display: flex; flex-direction: column; gap: 7px;
}

.rarity-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    font-family: 'Share Tech Mono', monospace;
    font-size: clamp(9px, 1.5vw, 13px);
    letter-spacing: 2px; color: var(--muted);
    text-shadow: 0 0 10px rgba(0, 0, 0, 0.9);
}

.rarity-pct {
    font-family: 'Bebas Neue', sans-serif;
    font-size: clamp(18px, 3.4vw, 27px); letter-spacing: 1px;
    color: var(--green);
    text-shadow: 0 0 12px rgba(0, 0, 0, 0.95);
}

/* The track is the meter, not a card behind one — a bar chart needs something
   to be a fraction OF. Kept translucent so the columns still show through. */
.rarity-track {
    position: relative; width: 100%;
    height: clamp(66px, 15vh, 150px);
    border-radius: 14px; overflow: hidden;
    /* Barely there. A meter needs something to be a fraction of, but at 40%
       black this read as exactly the dark panel that was removed from the
       rest of the stage — the columns have to show through it. */
    background: rgba(0, 0, 0, 0.16);
    box-shadow: inset 0 0 0 1px rgba(0, 210, 150, 0.18);
}

.rarity-fill {
    position: absolute; left: 0; right: 0; bottom: 0; height: 2%;
    background: linear-gradient(180deg, var(--red) 0%, var(--yellow) 55%, var(--green) 100%);
    box-shadow: 0 0 18px rgba(0, 255, 136, 0.3);
    transition: height 0.25s ease-out;
}

.rarity-ticks {
    position: absolute; inset: 0; padding: 7px 0;
    display: flex; flex-direction: column; justify-content: space-between;
    pointer-events: none;
}

.rarity-ticks span { display: block; height: 1px; background: rgba(255, 255, 255, 0.07); }

/* In landscape the stage is a sliver and the readouts would take most of it. */
@media (max-height: 560px) { .telemetry { display: none; } }

/* ---- celebration ---- */
/*
 * Balloons, released only when a real bet of this player's actually resolves
 * as won. Nothing here fires on a guess, on somebody else's round, or on a
 * round this player sat out.
 *
 * Each balloon is one element animating transform and opacity, removed by
 * script when its animation ends — so a long session cannot accumulate a
 * thousand invisible divs behind the canvas.
 */
.balloons {
    position: absolute; inset: 0; z-index: 2;
    overflow: hidden; pointer-events: none;
}

.balloon {
    position: absolute; bottom: -70px;
    width: 26px; height: 33px; border-radius: 50% 50% 48% 48%;
    will-change: transform, opacity;
    animation: rise var(--dur, 3s) cubic-bezier(0.25, 0.5, 0.4, 1) forwards;

    /* Translucent so the round stays readable through them. A celebration
       that hides the multiplier and the cash-out button is a celebration that
       costs the player the next round. */
    opacity: 0.72;
    mix-blend-mode: screen;
}

/* The highlight, and the knot underneath. */
.balloon::before {
    content: ''; position: absolute; top: 18%; left: 22%;
    width: 26%; height: 20%; border-radius: 50%;
    background: rgba(255, 255, 255, 0.55);
}

.balloon::after {
    content: ''; position: absolute; top: 100%; left: 50%;
    width: 1px; height: 26px; margin-left: -0.5px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.28), transparent);
}

@keyframes rise {
    0%   { transform: translate3d(0, 0, 0) scale(0.5) rotate(-6deg); opacity: 0; }
    14%  { opacity: 0.72; }
    50%  { transform: translate3d(var(--sway, 14px), -46vh, 0) scale(1) rotate(6deg); }
    75%  { opacity: 0.72; }
    100% { transform: translate3d(0, -104vh, 0) scale(1) rotate(-4deg); opacity: 0; }
}

/* ---- toasts ---- */

.toasts {
    position: absolute; z-index: 5; left: 0; right: 0; top: 46px;
    display: flex; flex-direction: column; align-items: center; gap: 5px;
    pointer-events: none;
}

.toast {
    padding: 5px 14px; border-radius: 999px;
    font-family: 'Share Tech Mono', monospace; font-size: 13px; font-weight: 700;
    color: #04120b; background: var(--green);
    box-shadow: 0 6px 22px rgba(0, 255, 136, 0.35);
    animation: toast-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
               toast-out 0.4s ease-in 2.1s forwards;
}

.toast-lost { color: #fff; background: var(--red); box-shadow: 0 6px 22px rgba(255, 51, 85, 0.35); }

@keyframes toast-in  { from { transform: translateY(-10px) scale(0.9); opacity: 0; } }
@keyframes toast-out { to   { transform: translateY(-8px); opacity: 0; } }

.banner {
    flex: none; border-radius: 10px; padding: 6px 12px; text-align: center;
    font-size: 12px; font-weight: 600;
    color: var(--yellow); background: rgba(255, 204, 0, 0.12);
    border: 1px solid rgba(255, 204, 0, 0.28);
}

.notice {
    flex: none; border-radius: 10px; padding: 7px 12px; text-align: center;
    font-size: 12.5px; color: var(--text);
    background: rgba(2, 12, 20, 0.7); border: 1px solid var(--line);
}

/* ------------------------------------------------------------- bet decks */

.decks {
    flex: none;
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}

/* Stack below 400px: two full sets of controls side by side stop being
   tappable long before they stop fitting. Both decks stay — hiding one would
   quietly remove the second bet slot rather than adapt to the screen. */
@media (max-width: 400px) { .decks { grid-template-columns: 1fr; } }

.deck {
    border-radius: 15px; padding: 9px;
    background: rgba(3, 16, 26, 0.72);
    border: 1px solid var(--line);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
    display: flex; flex-direction: column; gap: 7px;
    transition: border-color 0.2s, box-shadow 0.2s;

    /* Grid items are min-width:auto by default, so a column cannot shrink
       below its content's minimum — the fixed-width auto-cashout box made the
       pair wider than a phone and pushed the whole page into horizontal
       scroll. This is what lets the columns actually be 1fr. */
    min-width: 0;
}

.deck.is-live {
    border-color: rgba(255, 204, 0, 0.5);
    box-shadow: 0 0 22px -6px rgba(255, 204, 0, 0.45);
}

.deck-head {
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
    font-family: 'Share Tech Mono', monospace; font-size: 9px;
    letter-spacing: 1.5px; color: var(--muted); text-transform: uppercase;
}

.deck-msg { color: var(--green); text-transform: none; letter-spacing: 0; font-size: 10px; }

.deck-inputs { display: flex; gap: 6px; }

.stepper {
    display: flex; align-items: center; flex: 1; min-width: 0;
    border-radius: 10px; border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.4); overflow: hidden;
}

.deck-inputs > * { min-width: 0; }

.step-btn {
    width: 30px; height: 38px; flex: none;
    color: var(--muted); font-size: 18px; font-weight: 700;
    transition: background-color 0.15s, color 0.15s;
}
.step-btn:active { background: rgba(0, 255, 136, 0.15); color: var(--green); }

.step-input {
    flex: 1; min-width: 0; height: 38px; background: transparent;
    text-align: center; outline: none; border: 0;
    font-family: 'Share Tech Mono', monospace;
    /* 16px exactly: iOS Safari zooms the whole page in on focus for anything
       smaller, and a zoomed viewport mid-round is unrecoverable one-handed. */
    font-size: 16px; font-weight: 700; color: #fff;
}

.auto-box {
    display: flex; align-items: center; gap: 3px; flex: none; width: 88px;
    height: 38px; padding: 0 8px;
    border-radius: 10px; border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.4);
}

.auto-lbl {
    font-family: 'Share Tech Mono', monospace; font-size: 8px;
    letter-spacing: 1px; color: var(--muted); flex: none;
}

.auto-input {
    width: 100%; min-width: 0; background: transparent; border: 0; outline: none;
    text-align: right; font-family: 'Share Tech Mono', monospace;
    font-size: 16px; font-weight: 700; color: #fff;
}
.auto-input::placeholder { color: rgba(170, 230, 210, 0.3); font-weight: 400; }

.auto-x { font-size: 10px; color: var(--muted); flex: none; }
/* The trailing x belongs to a multiplier, so it appears only once there is one. */
.auto-input:placeholder-shown + .auto-x { display: none; }

.chips { display: flex; gap: 5px; }

.chip {
    flex: 1; padding: 5px 0; border-radius: 7px;
    font-family: 'Share Tech Mono', monospace; font-size: 10.5px; font-weight: 700;
    color: var(--muted); background: rgba(0, 255, 136, 0.06);
    border: 1px solid rgba(0, 255, 136, 0.12);
    transition: color 0.15s, border-color 0.15s;
}
.chip:active { color: var(--green); border-color: rgba(0, 255, 136, 0.45); }

/* ---- the one button that matters ---- */

.action {
    width: 100%; border-radius: 12px; min-height: 52px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
    font-family: 'Rajdhani', sans-serif; font-weight: 700;
    transition: transform 0.12s, filter 0.15s;
}

.action:active:not(:disabled) { transform: scale(0.975); }
.action:disabled { cursor: not-allowed; }

.action-title { font-size: 16px; line-height: 1.1; letter-spacing: 0.5px; }
.action-sub   { font-family: 'Share Tech Mono', monospace; font-size: 10px; opacity: 0.8; line-height: 1; }
.action-sub:empty { display: none; }

.action-bet {
    color: #02231a;
    background: linear-gradient(180deg, #00ff88, #00b45f);
    box-shadow: 0 5px 20px -6px rgba(0, 255, 136, 0.7);
}

.action-wait {
    color: var(--muted);
    background: rgba(0, 255, 136, 0.06);
    border: 1px solid var(--line);
}

/* Deliberately the loudest thing on the page: the only control with a
   deadline. */
.action-cash {
    color: #2b1400;
    background: linear-gradient(180deg, #ffd84d, #ffab00);
    box-shadow: 0 6px 24px -6px rgba(255, 171, 0, 0.85);
    animation: cash-pulse 1.05s ease-in-out infinite;
}

@keyframes cash-pulse {
    0%, 100% { box-shadow: 0 6px 24px -6px rgba(255, 171, 0, 0.85); }
    50%      { box-shadow: 0 6px 32px -3px rgba(255, 171, 0, 1); }
}

.action-won  { color: #02231a; background: linear-gradient(180deg, #6bffb8, #00c46a); }

.action-lost {
    color: rgba(255, 140, 160, 0.9);
    background: rgba(255, 51, 85, 0.1);
    border: 1px solid rgba(255, 51, 85, 0.3);
}

.action:disabled.action-bet {
    color: var(--muted);
    background: rgba(0, 255, 136, 0.05);
    border: 1px solid var(--line);
    box-shadow: none;
}

/* ------------------------------------------------------------------ footer */

.footbar {
    flex: none; display: flex; align-items: center; justify-content: space-between; gap: 10px;
    font-family: 'Share Tech Mono', monospace; font-size: 9.5px;
    color: rgba(170, 230, 210, 0.28); letter-spacing: 0.5px;
}
.footbar a:hover { color: var(--green); }

@media (max-height: 640px) { .footbar { display: none; } }

/*
 * Short viewport — a small phone, or any phone in landscape. Shed the
 * optional chrome rather than letting the stage collapse to a sliver: the
 * quick-stake chips duplicate the stepper, and the rail and footer are
 * reference material, but the curve and the cash-out button are the game.
 */
@media (max-height: 560px) {
    .rail, .footbar { display: none; }
    .chips { display: none; }
    .deck { padding: 7px; gap: 5px; }
    .action { min-height: 44px; }
    .stage-top { padding: 6px 8px; }
    .topbar { gap: 6px; }
    .brand-name { font-size: 20px; }
}

/* ------------------------------------------------------- account controls */

.nav-btn {
    display: inline-flex; align-items: center; height: 32px; padding: 0 12px;
    border-radius: 9px; border: 1px solid var(--line);
    background: rgba(2, 12, 20, 0.7);
    font-size: 12px; font-weight: 700; color: var(--text);
    transition: border-color 0.15s, color 0.15s;
}
.nav-btn:hover { border-color: rgba(0, 255, 136, 0.45); color: var(--green); }

.nav-btn-primary {
    color: #02231a; border-color: transparent;
    background: linear-gradient(180deg, #00ff88, #00b45f);
}

.account-menu { position: relative; flex: none; }
.account-menu > summary { list-style: none; cursor: pointer; }
.account-menu > summary::-webkit-details-marker { display: none; }

.account-trigger {
    width: 36px; height: 36px; border-radius: 11px;
    display: grid; place-items: center;
    border: 1px solid var(--line);
    background: rgba(2, 12, 20, 0.72);
    font-family: 'Bebas Neue', sans-serif; font-size: 17px; letter-spacing: 1px;
    color: var(--green);
}
.account-trigger:hover { border-color: rgba(0, 255, 136, 0.45); }

.account-pop {
    position: absolute; right: 0; top: calc(100% + 7px); z-index: 40;
    min-width: 195px; padding: 9px;
    border-radius: 13px; border: 1px solid var(--line);
    background: #041420;
    box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.9);
}

.account-name  { font-size: 13px; font-weight: 700; color: var(--text); padding: 2px 6px; }
.account-email {
    font-family: 'Share Tech Mono', monospace; font-size: 10px; color: var(--muted);
    padding: 0 6px 8px; border-bottom: 1px solid var(--line); margin-bottom: 6px;
    overflow: hidden; text-overflow: ellipsis;
}

.account-item {
    display: block; width: 100%; text-align: left;
    padding: 8px 6px; border-radius: 8px; font-size: 13px; color: var(--text);
    transition: background-color 0.15s, color 0.15s;
}
.account-item:hover { background: rgba(0, 255, 136, 0.08); color: var(--green); }
.account-item-danger:hover { background: rgba(255, 51, 85, 0.12); color: #ff9db0; }

/* ============================================================ auth pages */

/* position + z-index are load-bearing, not decoration. .field-bg is a fixed,
   opaque, full-viewport gradient at z-index 0, and a POSITIONED element paints
   above a non-positioned one whatever the source order — so without these two
   properties the background covers this shell and the page renders blank while
   the HTML is perfectly intact. .app carries the same pair for the same reason. */
.auth-shell {
    position: relative; z-index: 2;
    min-height: 100%; display: grid; place-items: center; padding: 24px 16px;
}

.auth-card {
    width: 100%; max-width: 390px;
    display: flex; flex-direction: column; gap: 14px;
    padding: 24px; border-radius: 20px;
    border: 1px solid var(--line);
    background: radial-gradient(120% 80% at 50% 0%, rgba(0, 255, 136, 0.08), transparent 60%),
                rgba(3, 16, 26, 0.8);
    box-shadow: 0 8px 40px rgba(0, 0, 0, 0.6);
}

.auth-brand { display: flex; align-items: center; gap: 11px; }
.auth-title { font-family: 'Bebas Neue', sans-serif; font-size: 24px; letter-spacing: 2px; }
.auth-sub   { font-size: 12px; color: var(--muted); margin-top: 1px; }

.auth-alert { border-radius: 10px; padding: 9px 12px; font-size: 13px; line-height: 1.45; }
.auth-alert-error { color: #ff9db0; background: rgba(255, 51, 85, 0.12); border: 1px solid rgba(255, 51, 85, 0.28); }
.auth-alert-ok    { color: #6bffb8; background: rgba(0, 255, 136, 0.1);  border: 1px solid rgba(0, 255, 136, 0.28); }

.field { display: block; }

.field-label {
    display: block; margin-bottom: 5px;
    font-family: 'Share Tech Mono', monospace; font-size: 9.5px;
    text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted);
}

.field-input {
    width: 100%; height: 44px; padding: 0 12px;
    border-radius: 11px; border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.4); color: #fff;
    font-size: 16px;                     /* see .step-input — iOS zoom */
    outline: none; transition: border-color 0.15s, box-shadow 0.15s;
}
.field-input::placeholder { color: rgba(170, 230, 210, 0.3); }
.field-input:focus { border-color: rgba(0, 255, 136, 0.6); box-shadow: 0 0 0 3px rgba(0, 255, 136, 0.1); }

select.field-input { appearance: none; cursor: pointer; }
select.field-input option { background: #041420; }

.auth-submit {
    height: 48px; border-radius: 12px;
    font-size: 15px; font-weight: 800; letter-spacing: 0.5px;
    color: #02231a;
    background: linear-gradient(180deg, #00ff88, #00b45f);
    box-shadow: 0 5px 20px -6px rgba(0, 255, 136, 0.7);
    transition: filter 0.15s, transform 0.12s;
}
.auth-submit:hover:not(:disabled)  { filter: brightness(1.08); }
.auth-submit:active:not(:disabled) { transform: scale(0.985); }
.auth-submit:disabled { filter: grayscale(0.6); cursor: not-allowed; }

.auth-foot { text-align: center; font-size: 13px; color: var(--muted); }
.auth-link { color: var(--green); text-decoration: underline; text-underline-offset: 2px; }

.auth-dev {
    margin-top: 2px; padding-top: 12px; border-top: 1px dashed var(--line);
    font-size: 11px; line-height: 1.5; color: var(--muted); text-align: center;
}

/* ====================================================== wallet & profile */

.page-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
}

.balance-hero {
    border-radius: 18px; padding: 18px;
    border: 1px solid var(--line);
    background: radial-gradient(120% 90% at 50% 0%, rgba(0, 255, 136, 0.12), transparent 62%),
                rgba(2, 12, 20, 0.75);
}

.hero-label {
    font-family: 'Share Tech Mono', monospace; font-size: 10px;
    letter-spacing: 2.5px; text-transform: uppercase; color: var(--muted);
}

.hero-value {
    font-family: 'Bebas Neue', sans-serif; font-size: 44px; line-height: 1;
    letter-spacing: 1px; color: #fff; margin-top: 4px;
    text-shadow: 0 0 30px rgba(0, 255, 136, 0.35);
}

.hero-value.flash { animation: bump 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); color: var(--green); }

.panel {
    border-radius: 16px; padding: 14px;
    border: 1px solid var(--line);
    background: rgba(3, 16, 26, 0.72);
}

.panel-head { display: flex; align-items: center; gap: 8px; margin-bottom: 11px; }

.panel-title {
    font-family: 'Bebas Neue', sans-serif; font-size: 16px; letter-spacing: 2px;
    color: var(--green);
}

.panel-badge {
    min-width: 20px; height: 20px; padding: 0 6px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px; background: rgba(0, 255, 136, 0.14);
    font-family: 'Share Tech Mono', monospace; font-size: 11px; font-weight: 700;
    color: var(--green);
}

.empty { font-size: 13px; color: var(--muted); padding: 8px 2px; }

.deposit {
    display: flex; flex-direction: column; gap: 9px;
    border-radius: 13px; padding: 12px;
    border: 1px solid var(--line); background: rgba(0, 0, 0, 0.35);
}
.deposit-pending { border-color: rgba(255, 204, 0, 0.32); }

.reference-box {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    border-radius: 10px; padding: 9px 11px;
    background: rgba(0, 255, 136, 0.06);
    border: 1px dashed rgba(0, 255, 136, 0.32);
}

.copy-btn {
    height: 32px; padding: 0 12px; border-radius: 8px; flex: none;
    border: 1px solid rgba(0, 255, 136, 0.35);
    font-family: 'Share Tech Mono', monospace; font-size: 11px; font-weight: 700;
    color: var(--green); background: rgba(0, 255, 136, 0.08);
}
.copy-btn:hover { background: rgba(0, 255, 136, 0.18); }

.pill {
    padding: 3px 9px; border-radius: 999px; white-space: nowrap;
    font-family: 'Share Tech Mono', monospace; font-size: 9.5px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.5px;
}
.pill-pending   { color: var(--yellow); background: rgba(255, 204, 0, 0.14); }
.pill-confirmed { color: var(--green);  background: rgba(0, 255, 136, 0.14); }
.pill-rejected  { color: #ff9db0;       background: rgba(255, 51, 85, 0.14); }
.pill-expired   { color: var(--muted);  background: rgba(150, 200, 190, 0.1); }

.row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 9px 10px; border-radius: 10px; background: rgba(0, 0, 0, 0.35);
}

.mono { font-family: 'Share Tech Mono', monospace; }

.avatar-lg {
    width: 40px; height: 40px; border-radius: 12px; flex: none;
    display: grid; place-items: center;
    background: linear-gradient(135deg, #00e87a, #005533);
    color: #02231a; font-family: 'Bebas Neue', sans-serif; font-size: 20px; letter-spacing: 1px;
    box-shadow: 0 0 18px -2px rgba(0, 255, 136, 0.5);
}

.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
@media (min-width: 560px) { .stat-grid { grid-template-columns: repeat(4, 1fr); } }

.stat {
    border-radius: 14px; padding: 11px 12px;
    border: 1px solid var(--line);
    background: rgba(2, 12, 20, 0.75);
}

.stat-label {
    font-family: 'Share Tech Mono', monospace; font-size: 9px;
    text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted); margin-bottom: 5px;
}

.stat-value {
    font-family: 'Bebas Neue', sans-serif; font-size: 24px; line-height: 1;
    letter-spacing: 1px; color: #fff;
}

.detail-list { display: flex; flex-direction: column; }

.detail {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 9px 2px; border-bottom: 1px solid rgba(0, 200, 140, 0.12);
}
.detail:last-child { border-bottom: 0; }
.detail dt { font-size: 13px; color: var(--muted); }
.detail dd { font-family: 'Share Tech Mono', monospace; font-size: 12.5px; color: var(--text); }

.bet-table { display: flex; flex-direction: column; }

.bet-row {
    display: grid; grid-template-columns: 3.4rem 1fr 1fr 1.6fr;
    align-items: center; gap: 8px;
    padding: 8px 2px; border-bottom: 1px solid rgba(0, 200, 140, 0.1);
    font-family: 'Share Tech Mono', monospace; font-size: 12px;
}
.bet-row:last-child { border-bottom: 0; }
.bet-row > *:nth-child(n+2) { text-align: right; }

.bet-row-head { border-bottom: 1px solid var(--line); padding-bottom: 6px; }
.bet-row-head span {
    font-size: 9px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted);
}

.win  { color: var(--green); }
.lose { color: var(--red); }

.hidden { display: none !important; }

/* ============================================================ live sidebar */
/*
 * Who else is at the table right now. Every row that reaches this panel is a
 * real bet or a real cashout from the database — see /api/activity — so the
 * one liberty taken with the truth is the name: each player gets a stable,
 * anonymous handle (pseudonym_for()) instead of their real display_name,
 * because this is the one surface that shows a player to people who are not
 * them.
 */

.live-toggle {
    display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 11px;
    border-radius: 9px; border: 1px solid var(--line);
    background: rgba(2, 12, 20, 0.72);
    font-family: 'Share Tech Mono', monospace; font-size: 11px; color: var(--text);
    transition: border-color 0.15s;
}
.live-toggle:hover { border-color: rgba(0, 255, 136, 0.45); }

.live-dot {
    width: 7px; height: 7px; border-radius: 50%; flex: none;
    background: var(--green); box-shadow: 0 0 8px var(--green);
    animation: blink 1.6s ease-in-out infinite;
}

.live-count { font-weight: 700; color: #fff; }
.live-toggle-lbl { color: var(--muted); }

.live-backdrop {
    position: fixed; inset: 0; z-index: 45;
    background: rgba(0, 6, 10, 0.55);
    opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease;
}
.live-backdrop.is-open { opacity: 1; pointer-events: auto; }

.live-panel {
    position: fixed; top: 0; right: 0; z-index: 50;
    height: 100vh; height: 100dvh; width: min(88vw, 300px);
    display: flex; flex-direction: column; gap: 14px;
    padding: calc(16px + env(safe-area-inset-top)) 15px calc(16px + env(safe-area-inset-bottom));
    background: #041420; border-left: 1px solid var(--line);
    box-shadow: -20px 0 50px -14px rgba(0, 0, 0, 0.9);
    transform: translateX(100%);
    transition: transform 0.28s cubic-bezier(0.19, 1, 0.22, 1);
    overflow-y: auto; overscroll-behavior: contain;
}
.live-panel.is-open { transform: translateX(0); }

.live-panel-head {
    flex: none; display: flex; align-items: center; justify-content: space-between;
}

.live-panel-title {
    font-family: 'Bebas Neue', sans-serif; font-size: 18px; letter-spacing: 2px;
    color: var(--green);
}

.live-close {
    width: 28px; height: 28px; border-radius: 8px; flex: none;
    display: grid; place-items: center;
    border: 1px solid var(--line); color: var(--muted); font-size: 13px;
    transition: color 0.15s, border-color 0.15s;
}
.live-close:hover { color: var(--green); border-color: rgba(0, 255, 136, 0.45); }

.live-section { flex: none; }

.live-section-title {
    font-family: 'Share Tech Mono', monospace; font-size: 9.5px;
    text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted);
    margin-bottom: 8px;
}

.live-list { display: flex; flex-direction: column; gap: 6px; min-height: 34px; }

.live-empty {
    font-size: 12px; color: var(--muted); padding: 9px 2px;
    border-radius: 10px; background: rgba(0, 0, 0, 0.2);
}

.live-row {
    display: flex; align-items: center; gap: 9px;
    padding: 7px 9px; border-radius: 11px;
    background: rgba(0, 0, 0, 0.32); border: 1px solid transparent;
}

.live-row.is-win { border-color: rgba(0, 255, 136, 0.26); background: rgba(0, 255, 136, 0.06); }
.live-row.is-big { border-color: rgba(255, 204, 0, 0.4); background: rgba(255, 204, 0, 0.08); }

.live-avatar {
    width: 27px; height: 27px; border-radius: 8px; flex: none;
    display: grid; place-items: center;
    background: linear-gradient(135deg, #00e87a, #005533);
    color: #02231a; font-family: 'Bebas Neue', sans-serif; font-size: 13px;
}

.live-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }

.live-name {
    font-size: 12px; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.live-sub {
    font-family: 'Share Tech Mono', monospace; font-size: 10px; color: var(--muted);
}

.live-amt {
    flex: none; font-family: 'Share Tech Mono', monospace; font-size: 12.5px; font-weight: 700;
    color: var(--muted);
}
.live-row.is-win .live-amt { color: var(--green); }
.live-row.is-big .live-amt { color: var(--yellow); }

.live-row-in { animation: live-in 0.32s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes live-in { from { transform: translateY(-6px) scale(0.96); opacity: 0; } }

/*
 * Docked permanently once the screen is wide enough to hold the game and the
 * panel side by side without either one shrinking.
 *
 * .app is independently centered with `max-width: 1180px; margin: 0 auto`.
 * Bolting the panel on with `right: <viewport-relative offset>` computed from
 * a guessed half-width of that column drifts out of sync with it — it did,
 * in fact, and clipped the bet decks under the panel the first time this
 * shipped. Instead the (game column + gap + panel) width is treated as one
 * 1472px block and THAT is what gets centered, so .app's own centering is
 * overridden here rather than fought with two separate calculations that
 * have to agree by coincidence.
 *
 *   1180 (game column) + 24 (gap) + 268 (panel) = 1472
 *
 * The breakpoint is that block width plus a small margin on each side, so
 * the pair never touches the viewport edge at the narrowest width this rule
 * applies.
 */
@media (min-width: 1500px) {
    body.game-page .app-fixed {
        margin-left: calc((100vw - 1472px) / 2);
        margin-right: 0;
    }

    .live-toggle { display: none; }

    .live-backdrop { display: none; }

    .live-panel {
        top: 50%; right: auto;
        left: calc((100vw - 1472px) / 2 + 1204px);
        transform: translateY(-50%);
        height: min(680px, 92dvh); width: 268px;
        border-radius: 18px; border: 1px solid var(--line);
        box-shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.85);
    }
    .live-panel.is-open { transform: translateY(-50%); }
}

/* Anyone who has asked their device to calm down gets a calm page. */
@media (prefers-reduced-motion: reduce) {
    .conn-dot, .glow-ring, .action-cash, #cd-timer, .brand-icon, .live-dot { animation: none; }
    .hist-new, .toast, .balance-chip.bump, #mult.m-crash, .live-row-in { animation-duration: 0.01ms; }
}
