/* ===== Self-hosted fonts =====
   Variable fonts (Inter: 100-900, Space Grotesk: 300-700), latin-subset only — no external font
   host in the loop at all. Each declares several static font-weight values pointing at the same
   file; browsers resolve the actual requested weight from the variable font's own wght axis
   regardless of which single weight number matched here, so this behaves exactly like distinct
   static weight files would. Glyphs the fonts don't cover (♠ ♥ ♦ ♣ and similar) fall through to
   the next entry in each font-family's fallback stack automatically. */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("fonts/inter-variable.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("fonts/inter-variable.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("fonts/inter-variable.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("fonts/space-grotesk-variable.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("fonts/space-grotesk-variable.woff2") format("woff2");
}

/* ===== BJStud design tokens =====
   Palette lifted straight from logo.svg / logo-icon.svg so the marketing site and the game
   brand are the same brand, not a reinterpretation of it. */
:root {
    --void: #05040a;
    --panel: #0b0a18;
    --panel-2: #150f30;
    --panel-glow: #1b1140;
    --border: #2a2350;
    --cyan: #00c2ff;
    --cyan-soft: #9bf2ff;
    --pink: #ff2e88;
    --pink-soft: #ffe2ef;
    --felt: #0e5c3b;
    --felt-dark: #063d29;
    --felt-line: rgba(255, 255, 255, 0.35);
    --text: #f5f3ff;
    --text-muted: #a79fd1;
    --text-faint: #6f6796;
    --win: #4ade80;
    --loss: #fb7185;
    --push: #facc15;
    --radius: 14px;
    --font-display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
    --font-body: "Inter", "Segoe UI", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--void);
    color: var(--text);
    font-family: var(--font-body);
    min-height: 100%;
}

body {
    background:
        radial-gradient(ellipse 80% 50% at 50% -10%, var(--panel-glow) 0%, transparent 60%),
        var(--void);
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    line-height: 1.15;
    margin: 0 0 0.5em;
}

/* App.razor's <FocusOnNavigate Selector="h1" /> moves focus to the page's h1 on navigation so
   screen readers announce it — a real accessibility feature, kept. But h1 isn't an interactive
   element anywhere else on the site, so the browser's default focus box it triggers here is just
   visual noise for sighted/mouse users; suppress it without touching focus styling on anything
   that's actually operable (links, buttons, inputs). */
h1:focus { outline: none; }

p { line-height: 1.65; color: var(--text-muted); }

a { color: var(--cyan); text-decoration: none; }
a:hover { color: var(--cyan-soft); }

.container {
    max-width: 1120px;
    margin: 0 auto;
    padding: 0 1.5rem;
}

/* ===== Buttons ===== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.95rem;
    padding: 0.75rem 1.5rem;
    border-radius: 999px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
    text-decoration: none;
}
.btn:disabled { cursor: not-allowed; opacity: 0.4; }
.btn:not(:disabled):hover { transform: translateY(-1px); }

.btn-primary {
    background: linear-gradient(135deg, var(--cyan), #0091c7);
    color: #04121a;
    box-shadow: 0 0 24px rgba(0, 194, 255, 0.35);
}
.btn-primary:not(:disabled):hover { box-shadow: 0 0 32px rgba(0, 194, 255, 0.55); }

.btn-accent {
    background: linear-gradient(135deg, var(--pink), #b3186a);
    color: #240012;
    box-shadow: 0 0 24px rgba(255, 46, 136, 0.35);
}

.btn-ghost {
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    border-color: var(--border);
}
.btn-ghost:not(:disabled):hover { border-color: var(--cyan); }

.btn-lg { padding: 1rem 2rem; font-size: 1.05rem; }
.btn-sm { padding: 0.5rem 1.1rem; font-size: 0.85rem; }

/* Undocumented ?help mode (see Play.razor's RecommendedAction): an amber pulse on whichever
   action button matches ordinary blackjack basic strategy for the hand in front of the player
   right now — never announced anywhere in the UI, so it stays a quiet aid rather than a feature. */
.strategy-glow { box-shadow: 0 0 0 2px var(--push), 0 0 18px rgba(250, 204, 21, 0.65); animation: strategy-pulse 1.4s ease-in-out infinite; }
@keyframes strategy-pulse {
    0%, 100% { box-shadow: 0 0 0 2px var(--push), 0 0 14px rgba(250, 204, 21, 0.5); }
    50% { box-shadow: 0 0 0 2px var(--push), 0 0 26px rgba(250, 204, 21, 0.9); }
}
.btn-block { width: 100%; }

/* ===== Header / nav ===== */
.site-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.5rem;
    background: rgba(5, 4, 10, 0.82);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
}

.brand {
    display: flex;
    align-items: center;
}

/* The rail lockup carries its own rule line under the wordmark, so it needs more height than a
   bare icon did before that line stops being a smudge — 44px puts the "BJ" itself at roughly the
   cap height the old icon-plus-text pairing had. Width is left to the artwork's own ratio. */
.brand img { height: 44px; width: auto; display: block; }

@media (max-width: 480px) {
    .brand img { height: 36px; }
}

.nav-links {
    display: flex;
    align-items: center;
    gap: 1.75rem;
    list-style: none;
    margin: 0;
    padding: 0;
}
.nav-links a:not(.btn) {
    color: var(--text-muted);
    font-weight: 500;
    font-size: 0.95rem;
}
.nav-links a:not(.btn).active, .nav-links a:not(.btn):hover { color: var(--text); }

.nav-toggle { display: none; }

@media (max-width: 780px) {
    .nav-links {
        position: absolute;
        top: 100%; left: 0; right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background: var(--panel);
        border-bottom: 1px solid var(--border);
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.2s ease;
    }
    .nav-links.open { max-height: 400px; }
    .nav-links li { border-top: 1px solid var(--border); }
    .nav-links a, .nav-links .btn { display: block; padding: 1rem 1.5rem; border-radius: 0; }
    .nav-toggle {
        display: inline-flex;
        background: none;
        border: 1px solid var(--border);
        border-radius: 8px;
        color: var(--text);
        padding: 0.5rem 0.7rem;
        font-size: 1.1rem;
        cursor: pointer;
    }
}

/* ===== Sections ===== */
.section { padding: 3rem 0; }
.section-tight { padding: 1.75rem 0; }
.section-alt { background: linear-gradient(180deg, transparent, rgba(27, 17, 64, 0.35), transparent); }

.eyebrow {
    display: inline-block;
    font-family: var(--font-display);
    font-size: 0.78rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--pink-soft);
    background: rgba(255, 46, 136, 0.12);
    border: 1px solid rgba(255, 46, 136, 0.35);
    padding: 0.3rem 0.9rem;
    border-radius: 999px;
    margin-bottom: 1.25rem;
}

.hero {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    gap: 3rem;
    align-items: center;
    padding: 2.5rem 0 3rem;
}
@media (max-width: 900px) {
    .hero { grid-template-columns: 1fr; text-align: center; }
    .hero .cta-row { justify-content: center; }
}

.hero h1 {
    font-size: clamp(2.2rem, 4.5vw, 3.4rem);
    background: linear-gradient(135deg, #fff 30%, var(--cyan-soft));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.hero .lede { font-size: 1.15rem; max-width: 46ch; }

.cta-row { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2rem; }

.lede-cta-row { display: flex; align-items: center; gap: 2rem; flex-wrap: wrap; margin-top: 1.5rem; }
.lede-cta-row .lede { margin: 0; flex: 1 1 360px; }
@media (max-width: 900px) { .lede-cta-row { justify-content: center; } }

.card-row.overlap .playing-card { --gap: -34px; }

.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.5rem;
    margin-top: 2.5rem;
}

.card-panel {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.01));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.75rem;
}
.card-panel h3 { color: var(--text); font-size: 1.1rem; }
.card-panel p { margin: 0; font-size: 0.95rem; }
.card-panel .icon {
    font-size: 1.6rem;
    margin-bottom: 0.75rem;
    filter: drop-shadow(0 0 8px rgba(0, 194, 255, 0.6));
}

.callout {
    border-left: 3px solid var(--cyan);
    background: rgba(0, 194, 255, 0.06);
    padding: 1.25rem 1.5rem;
    border-radius: 0 var(--radius) var(--radius) 0;
    margin: 2rem 0;
}
.callout.warn { border-left-color: var(--push); background: rgba(250, 204, 21, 0.07); }

table.pay-table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
table.pay-table th, table.pay-table td {
    padding: 0.6rem 0.9rem;
    text-align: left;
    border-bottom: 1px solid var(--border);
}
table.pay-table th { color: var(--text-faint); font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; }
table.pay-table td.odds { color: var(--cyan-soft); font-family: var(--font-display); text-align: right; }

.footer {
    border-top: 1px solid var(--border);
    padding: 2.5rem 0;
    color: var(--text-faint);
    font-size: 0.9rem;
}
.footer .container { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; }
.footer a { color: var(--text-muted); }

/* ===== Playing cards =====
   Cards are NOT flex children — flexbox re-centering a row when an item is added changes every
   sibling's box position, and box position (unlike transform) can't be transitioned, which is
   exactly the "jump" a flex-based row produces. Instead each card is absolutely positioned within
   its row and offset by its own index/count via --i/--n (set inline per card — see
   PlayingCard.razor), so the resting position is a plain `transform`, which *is* transitionable:
   when a new card changes the row's --n, every existing card's offset recalculates and eases
   smoothly to its new spot instead of snapping there. */
.playing-card {
    --w: 64px;
    --gap: 12px;
    --i: 0;
    --n: 1;
    width: var(--w);
    height: calc(var(--w) * 1.42);
    border-radius: calc(var(--w) * 0.12);
    position: absolute;
    top: 50%;
    left: 50%;
    perspective: 800px;
    font-family: var(--font-display);
    transform: translate(-50%, -50%) translateX(calc((var(--i) - (var(--n) - 1) / 2) * (var(--w) + var(--gap))));
    transition: transform 0.4s cubic-bezier(.4, 0, .2, 1);
    animation: deal-in 0.55s cubic-bezier(.2, .7, .3, 1) backwards;
}
@media (min-width: 640px) { .playing-card { --w: 84px; } }

.playing-card.black .card-front { color: #14121f; }
.playing-card.red .card-front { color: #d1204a; }

/* Every card is a two-sided flip container, back showing by default. The dealer's hole card is
   dealt with FaceDown=true (no "revealed" class) and later has its Card value filled in and
   FaceDown cleared on the very same element (see PlayingCard.razor's single shared markup path —
   no branch swap between hidden/shown), so this transition is what makes it visually turn over in
   place instead of vanishing and a face-up card flying in from off-screen. Cards dealt face-up
   from the start simply render already-revealed on their first paint, which plays no transition
   at all (only a class *change* animates), so this costs them nothing. */
/* A separate layer for the Raise card's sideways turn (see PlayingCard.razor's Sideways param) —
   kept apart from .card-flip-inner's own rotateY so the flip and the turn never have to share one
   transform's animated value. */
.card-sideways-wrap {
    position: relative;
    width: 100%;
    height: 100%;
    transition: transform 0.3s ease;
}
.playing-card.sideways .card-sideways-wrap { transform: rotate(90deg); }

.card-flip-inner {
    position: relative;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transition: transform 0.5s cubic-bezier(.4, 0, .2, 1);
}
.playing-card.revealed .card-flip-inner { transform: rotateY(180deg); }

.card-face {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: calc(var(--w) * 0.12);
    backface-visibility: hidden;
}

.card-back {
    background: repeating-linear-gradient(135deg, var(--panel-glow) 0 6px, var(--panel) 6px 12px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45), inset 0 0 0 2px rgba(0, 194, 255, 0.25);
}
.card-back::after {
    content: "♠";
    color: rgba(0, 194, 255, 0.4);
    font-size: calc(var(--w) * 0.5);
}

.card-front {
    background: #fdfcff;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(0, 0, 0, 0.06);
    transform: rotateY(180deg);
}
.card-front .pip { font-size: calc(var(--w) * 0.48); line-height: 1; }
.card-front .corner {
    position: absolute;
    font-size: calc(var(--w) * 0.19);
    line-height: 1.05;
    text-align: center;
    font-weight: 700;
}
.card-front .corner.top { top: calc(var(--w) * 0.08); left: calc(var(--w) * 0.09); }
.card-front .corner.bottom { bottom: calc(var(--w) * 0.08); right: calc(var(--w) * 0.09); transform: rotate(180deg); }

.playing-card.placeholder {
    background: rgba(255, 255, 255, 0.03);
    box-shadow: inset 0 0 0 2px dashed rgba(255,255,255,0.08);
    border: 2px dashed rgba(255, 255, 255, 0.12);
    animation: none;
}

/* Cards deal in from the upper right of the felt, and discard out to the upper left — see
   Play.razor's staggered reveal/discard sequencing, which is what makes these read as one card
   at a time instead of the whole hand popping in at once. Both keyframes re-derive the same
   resting-position formula as the base rule above (rather than "none") so a card's entrance and
   exit are relative to *where it actually sits in the row*, not the row's top-left corner.
   `deal-in` uses fill-mode "backwards" (not "both"): once it finishes, control has to fall back
   to the ordinary transform+transition above, or a later change to --n (a sibling arriving)
   couldn't smoothly retarget a held animation-forwards value. */
@keyframes deal-in {
    from {
        opacity: 0;
        transform: translate(-50%, -50%) translateX(calc((var(--i) - (var(--n) - 1) / 2) * (var(--w) + var(--gap)))) translate(170px, -190px) scale(0.8) rotate(12deg);
    }
    to {
        opacity: 1;
        transform: translate(-50%, -50%) translateX(calc((var(--i) - (var(--n) - 1) / 2) * (var(--w) + var(--gap))));
    }
}
@keyframes discard-out {
    from {
        opacity: 1;
        transform: translate(-50%, -50%) translateX(calc((var(--i) - (var(--n) - 1) / 2) * (var(--w) + var(--gap))));
    }
    to {
        opacity: 0;
        transform: translate(-50%, -50%) translateX(calc((var(--i) - (var(--n) - 1) / 2) * (var(--w) + var(--gap)))) translate(-190px, -190px) scale(0.7) rotate(-14deg);
    }
}
.card-row.discarding .playing-card { animation: discard-out 0.45s ease-in-out forwards; }

/* A quick shake on the whole row (not per-card) calls out a bust the moment it lands, before the
   pause-then-discard sequence in Play.razor's AnimateBustedCardsAsync takes over. Duration must
   match that method's own shake delay so the row settles right as the state flips back. */
@keyframes hand-shake {
    0%, 100% { transform: translateX(0); }
    10% { transform: translateX(-9px); }
    20% { transform: translateX(8px); }
    30% { transform: translateX(-8px); }
    40% { transform: translateX(7px); }
    50% { transform: translateX(-6px); }
    60% { transform: translateX(6px); }
    70% { transform: translateX(-4px); }
    80% { transform: translateX(4px); }
    90% { transform: translateX(-2px); }
}
.card-row.bust-shake { animation: hand-shake 0.45s ease-in-out; }

.card-row {
    position: relative;
    width: 100%;
    min-height: calc(84px * 1.42);
}

/* ===== Game table ===== */
.table-felt {
    position: relative;
    aspect-ratio: 1 / 1;
    max-width: 640px;
    margin: 0 auto;
    border-radius: 28px;
    background:
        radial-gradient(circle at 50% 38%, var(--felt) 0%, var(--felt-dark) 78%),
        var(--felt-dark);
    border: 10px solid #2b1a10;
    box-shadow:
        inset 0 0 60px rgba(0, 0, 0, 0.55),
        0 20px 50px rgba(0, 0, 0, 0.5);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 1.75rem 1rem;
    overflow: hidden;
}
.table-felt::before {
    content: "";
    position: absolute;
    inset: 14px;
    border: 2px solid var(--felt-line);
    border-radius: 20px;
    opacity: 0.5;
    pointer-events: none;
}
.table-felt::after {
    content: "♠ ♥ ♦ ♣";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3.2rem;
    letter-spacing: 1.5rem;
    color: rgba(255, 255, 255, 0.045);
    pointer-events: none;
}

/* The interactive game's felt: wider (more horizontal real estate, everything self-contained —
   bankroll, paytable and controls all live inside it) rather than square, with extra bottom
   padding reserved for the corner widgets pinned there. */
.table-felt-game {
    aspect-ratio: auto;
    max-width: 920px;
    min-height: 640px;
    padding: 1.5rem 1.25rem 9.5rem;
    /* A floor under space-between's own distribution — needed now that the center message moved
       out of the flow (it used to be the thing visually separating the two hands), so the dealer
       and player rows don't end up flush against each other. */
    gap: 1.5rem;
}

.hand-showcase-wrap .card-panel { margin-top: 1.25rem; }

.table-zone { position: relative; z-index: 1; text-align: center; }
.table-zone .zone-label {
    font-family: var(--font-display);
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
    margin-bottom: 0.6rem;
}

/* Both the dealer's and the player's rows pair a small total-chip pill with the cards instead of
   a text caption. The card fan itself is untouched — still full-width and self-centering exactly
   like before — so the chip has to track it instead: it repeats the fan's own --w/--gap centering
   math (see .playing-card below) to sit just left of the actual leftmost card, recalculating (and
   sliding, via the transition below) as --n changes with every card dealt. */
.hand-row {
    position: relative;
    --w: 64px;
    --gap: 12px;
}
@media (min-width: 640px) { .hand-row { --w: 84px; } }
/* Once a hand grows past 3 cards, tighten the gap (the chip inherits --gap from .hand-row same as
   always; .playing-card needs its own override since it declares --gap itself, same mechanism as
   .card-row.overlap above) so the fan keeps overlapping instead of pushing the total chip further
   and further left — far enough, with enough cards, to slide under the paytable in the corner. */
.hand-row.crowded { --gap: -24px; }
.hand-row.crowded .playing-card { --gap: -24px; }
.hand-total-chip {
    --n: 1;
    position: absolute;
    top: 50%;
    /* 50% - half the fan's width = the leftmost card's left edge; back off by the chip's own
       width plus a small gap so it sits clear of that card rather than tucked under it. */
    left: calc(50% - (var(--n) * var(--w) + (var(--n) - 1) * var(--gap)) / 2 - 60px);
    transform: translateY(-50%);
    transition: left 0.4s cubic-bezier(.4, 0, .2, 1), transform 0.4s cubic-bezier(.4, 0, .2, 1);
    min-width: 44px;
    height: 32px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.45);
    border: 2px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.72rem;
    color: var(--text);
    padding: 0 0.6rem;
}
.hand-total-chip.busted { color: var(--loss); border-color: rgba(251, 113, 133, 0.5); }
/* Applied once the busted hand's cards are actually gone (a beat after .busted itself, which
   flips the color right away) — stop tracking a fan that no longer exists and slide back to the
   middle of the zone instead of sitting wherever the (possibly wide) hand last left it. */
.hand-total-chip.empty {
    left: 50%;
    transform: translate(-50%, -50%);
}
/* Lives inside the player's own zone (which is position:relative) rather than in the gap between
   the two hands, so it reads as sitting in the open green space beside the player's cards, not
   in the middle of the table. Constrained to a narrow column so longer messages wrap onto a
   couple of lines instead of stretching across the felt. */
.table-center {
    position: absolute;
    z-index: 2;
    top: 50%;
    right: 1.5rem;
    transform: translateY(-50%);
    width: 190px;
    text-align: left;
    font-family: var(--font-display);
    color: var(--cyan-soft);
    font-size: 1.05rem;
    line-height: 1.3;
    transition: color 0.2s ease;
}
@media (max-width: 720px) {
    .table-center {
        position: static;
        transform: none;
        width: auto;
        text-align: center;
        margin-top: 0.75rem;
    }
}
.table-center.win { color: var(--win); }
.table-center.loss { color: var(--loss); }
.table-center.push { color: var(--push); }

.chip-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: rgba(0,0,0,0.35);
    border: 1px solid var(--border);
    padding: 0.35rem 0.8rem;
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: 0.85rem;
}

/* ===== Casino chips — used both for the clickable denomination picker and for the stacks
   rendered inside a bet circle. Colors follow standard casino convention: red 5, green 25,
   black 100. ===== */
.chip-disc {
    --size: 46px;
    width: var(--size);
    height: var(--size);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    color: #fff;
    font-size: calc(var(--size) * 0.32);
    background: radial-gradient(circle at 35% 30%, var(--chip-hi), var(--chip-lo));
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5), inset 0 0 0 3px rgba(255, 255, 255, 0.18), inset 0 0 0 6px rgba(0, 0, 0, 0.3);
    border: none;
    padding: 0;
}
.chip-5 { --chip-hi: #ea5f77; --chip-lo: #8f1626; }
.chip-25 { --chip-hi: #3fd28a; --chip-lo: #0e5c3b; }
.chip-100 { --chip-hi: #4a4a4a; --chip-lo: #0a0a0a; }
.chip-500 { --chip-hi: #c586ff; --chip-lo: #5b1a8f; }
.chip-1000 { --chip-hi: #ffe066; --chip-lo: #a6790a; color: #3a2c00; }
.chip-5000 { --chip-hi: #ffb066; --chip-lo: #b35900; }

.chip-picker { display: flex; align-items: center; gap: 0.9rem; }
.chip-picker button.chip-disc { cursor: pointer; transition: transform 0.15s ease, box-shadow 0.15s ease; }
.chip-picker button.chip-disc:hover:not(:disabled) { transform: translateY(-3px); }
.chip-picker button.chip-disc.selected { box-shadow: 0 0 0 3px var(--cyan), 0 3px 8px rgba(0, 0, 0, 0.5); }
.chip-picker button.chip-disc:disabled { opacity: 0.35; cursor: not-allowed; }

/* The denomination picker next to the bankroll figure reads better small and stacked than at
   full chip-stack size in a row. */
.chip-picker.vertical { flex-direction: column; gap: 0.4rem; }
.chip-picker.vertical .chip-disc { --size: 32px; }
.chip-picker.vertical button.chip-disc:hover:not(:disabled) { transform: translateX(-3px); }

.chip-stack { position: relative; width: 46px; height: 46px; }
.chip-stack .chip-disc { position: absolute; inset: 0; transform: translateY(calc(var(--i) * -6px)); }

/* A newly-created disc (a chip just placed) drops in from the bank cluster's own corner rather
   than simply appearing — since Decompose() can reshuffle which discs exist as the total crosses
   a denomination boundary, this targets "any disc that is a new DOM element", not literally "the
   last chip clicked", which is the right visual result even if not literally the same node. */
@keyframes chip-drop-in {
    from { opacity: 0; transform: translateY(calc(var(--i) * -6px)) translate(26px, 22px) scale(0.4); }
    to { opacity: 1; transform: translateY(calc(var(--i) * -6px)); }
}
.chip-stack .chip-disc { animation: chip-drop-in 0.3s ease-out backwards; }

/* Once a bet settles, its chip stack flies off toward the bank (wins and pushes — the money's
   coming back) or up toward the middle of the table (losses — the house keeps it) while a message
   describing the payout shows in the table-center slot; see Play.razor's AnimateSettlementAsync. */
.chip-stack.chip-fly-win { animation: chip-fly-win 0.6s ease-in-out forwards; }
.chip-stack.chip-fly-loss { animation: chip-fly-loss 0.6s ease-in-out forwards; }
@keyframes chip-fly-win { to { transform: translate(70px, 46px) scale(0.35); opacity: 0; } }
@keyframes chip-fly-loss { to { transform: translate(-120px, -230px) scale(0.4); opacity: 0; } }

/* A winning bet's payout lands beside its own circle — close, but never overlapping the bet
   itself (docs/dealing-procedure.md §9: BJ pays to the left, Stud and the Raise's poker bonus pay
   to the right). It drops in with the same chip-drop-in flourish every new chip gets, then holds
   there — paid, but not yet collected — until every bet on the layout has settled and
   Play.razor's SweepWinningsToBankAsync sends it toward the bank alongside the original stake. */
.payout-beside {
    position: absolute;
    top: 50%;
    z-index: 3;
    pointer-events: none;
}
.payout-beside-left { right: calc(100% + 10px); transform: translateY(-50%); }
.payout-beside-right { left: calc(100% + 10px); transform: translateY(-50%); }

/* ===== Betting circles — BJ and Stud must always be equal (hence the "="), Raise is the
   optional third spot that only ever fills once the player actually raises mid-hand, sized the
   same as BJ/Stud so it doesn't read as a lesser bet, and centered underneath the "=" on its own
   row below them. The whole stack sits in normal flow after the player's row (see
   .table-felt-game's flex column + space-between), which is what lands it near the bottom of the
   felt rather than dead center. ===== */
.betting-stack { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; margin-top: 1.5rem; }
.betting-row { display: flex; align-items: center; justify-content: center; gap: 1rem; }
.raise-row { display: flex; justify-content: center; }

.bet-equals { font-family: var(--font-display); font-size: 1.5rem; color: rgba(255, 255, 255, 0.4); }

.bet-circle {
    width: 88px;
    height: 88px;
    border-radius: 50%;
    border: 3px dashed rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.03);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    position: relative;
    transition: border-color 0.15s ease, background 0.15s ease;
}
button.bet-circle { cursor: pointer; font: inherit; color: inherit; }
button.bet-circle:hover { border-color: var(--cyan); background: rgba(0, 194, 255, 0.07); }
button.bet-circle:disabled { cursor: not-allowed; }
.bet-circle-label {
    font-family: var(--font-display);
    font-size: 0.86rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.72);
}

@media (max-width: 480px) {
    .bet-circle { width: 68px; height: 68px; }
}

/* ===== Corner widgets pinned inside the felt (see .table-felt-game's reserved padding) ===== */

/* The house mark, silkscreened rather than lit — the same one-colour white lockup treatment the
   paytable blocks use, and for the same reason: it belongs to the cloth, not to the interface.
   Unlike them it sits *below* the cards (z-index 0, under .table-zone) with no pointer events, so
   a card dealt into the upper right passes over it. Same 1.5rem inset as every other corner. */
.felt-logo-corner {
    position: absolute;
    top: 1.5rem;
    right: 1.5rem;
    z-index: 0;
    width: 200px;
    opacity: 0.55;
    pointer-events: none;
}
.felt-logo-corner img { display: block; width: 100%; height: auto; }

/* The paytable (and the smaller blackjack/insurance block below it) is permanent, not a
   disclosure — real felts silkscreen the payouts directly onto the surface, so both read as
   printed text baked into the felt itself, with no panel behind them, rather than a UI overlay.
   Each is a plain two-column grid so every line and its payout line up, the way a printed felt
   paytable does — and plain gray/white, like silkscreened text, not another spot of accent
   color. */
.felt-paytable-grid, .felt-info-corner {
    position: absolute;
    z-index: 3;
}
.felt-paytable-grid { top: 1.5rem; left: 1.5rem; }
.felt-info-corner { bottom: 1.5rem; left: 1.5rem; }

.felt-silkscreen-title {
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
    margin-bottom: 0.3rem;
}

.felt-paytable-grid table, .felt-info-corner table { border-collapse: collapse; }
.felt-paytable-grid td, .felt-info-corner td {
    font-family: var(--font-display);
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.75);
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
    padding: 0.12rem 0;
    white-space: nowrap;
}
.felt-paytable-grid td:first-child, .felt-info-corner td:first-child { padding-right: 1.1rem; }
.felt-paytable-grid td:last-child, .felt-info-corner td:last-child { text-align: right; color: #fff; font-weight: 700; }

/* Silkscreened rule copy, the way a real felt carries the Raise and qualifier rules in small type
   under the payout block. Wraps, unlike the payout rows, so it needs its own width. */
.felt-rule-note {
    max-width: 15rem;
    margin-top: 0.55rem;
    font-family: var(--font-display);
    font-size: 0.68rem;
    line-height: 1.35;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}
.felt-rule-note strong { color: rgba(255, 255, 255, 0.85); }

.felt-bank-cluster {
    position: absolute;
    bottom: 1rem;
    right: 1rem;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.6rem;
}
.felt-bank-cluster .bank-chip-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.85rem;
}
.felt-bank-cluster .bankroll-box {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    /* Roughly matches the vertical chip picker's height (3 discs + gaps) beside it, so the two
       line up as a matched pair instead of the balance box looking squat next to the chips. */
    min-height: 108px;
    text-align: center;
    background: rgba(0, 0, 0, 0.4);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0.5rem 1rem;
}
.felt-bank-cluster .figure { font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; color: var(--cyan-soft); line-height: 1.1; }
.felt-bank-cluster .bankroll-box button { margin-top: 0.4rem; }

/* Compact stand-in for the old full-size result panel — sits above the chips/balance cluster so
   the last hand's outcome stays visible without competing for space with the felt itself. Each
   wagered bet gets its own line so a mixed result (say Raise wins while Stud loses) doesn't have
   to be flattened into one net number. */
.last-result-breakdown {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    background: rgba(0, 0, 0, 0.4);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 0.45rem 0.9rem;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.8rem;
}
.last-result-title {
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
    font-weight: 600;
    margin-bottom: 0.15rem;
}
.result-line { display: flex; justify-content: space-between; gap: 1rem; white-space: nowrap; }
.result-line.win { color: var(--win); }
.result-line.loss { color: var(--loss); }
.result-line.push { color: var(--push); }

/* The action buttons sit centered at the bottom, lifted a bit off the felt's inner border so they
   don't read as glued to the edge. */
.felt-actions-corner {
    position: absolute;
    bottom: 1.75rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    max-width: calc(100% - 2rem);
}

@media (max-width: 720px) {
    .table-felt-game { padding: 1.25rem 1rem; min-height: auto; }
    .felt-bank-cluster, .felt-actions-corner, .felt-paytable-grid, .felt-info-corner {
        position: static;
        width: 100%;
        max-width: none;
        margin-top: 1rem;
        align-items: center;
        text-align: center;
    }
    .felt-paytable-grid table, .felt-info-corner table { margin: 0 auto; }
    .felt-actions-corner { transform: none; }
    /* Once the corners collapse into a single column there is no corner left to pin the mark to,
       and leaving it absolute drops it straight onto the paytable. It joins the column instead —
       it is the felt's first child, so it heads the stack. */
    .felt-logo-corner {
        position: static;
        width: 150px;
        margin: 0 auto 0.75rem;
    }
    .felt-bank-cluster .bank-chip-row { justify-content: center; flex-wrap: wrap; }
}

.action-bar {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 1.5rem;
}

/* ===== Blazor framework bits, restyled to match the theme ===== */
#blazor-error-ui {
    color-scheme: dark;
    background: var(--panel-2);
    color: var(--text);
    border-top: 1px solid var(--pink);
    bottom: 0; left: 0; width: 100%;
    box-sizing: border-box;
    display: none;
    padding: 0.9rem 1.25rem;
    position: fixed;
    z-index: 1000;
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 1rem; top: 0.6rem; color: var(--text-faint); }
#blazor-error-ui a.reload { color: var(--cyan); }

.blazor-error-boundary {
    background: rgba(255, 46, 136, 0.12);
    border: 1px solid var(--pink);
    border-radius: var(--radius);
    padding: 1rem 1rem 1rem 1rem;
    color: var(--text);
    margin: 1rem 0;
}
.blazor-error-boundary::after { content: "Something went wrong rendering this."; }

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 40vh 0 auto 0;
    margin: 0 auto 0 auto;
}
.loading-progress circle { fill: none; stroke: var(--border); stroke-width: 0.6rem; transform-origin: 50% 50%; transform: rotate(-90deg); }
.loading-progress circle:last-child {
    stroke: var(--cyan);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    color: var(--text-muted);
    font-family: var(--font-display);
    inset: calc(40vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after { content: var(--blazor-load-percentage-text, "Loading"); }

/* --- Felt details that mirror the printed table layout --- */

/* The Raise circle is solid white on the cloth, not an outline like the two mandatory bets — the
   filled disc is what tells a player at a glance that it is a different kind of bet. */
.raise-circle {
    border-style: solid;
    border-color: #fff;
    background: #fff;
}
.raise-circle .bet-circle-label { color: var(--felt-dark); }

/* The RAISE label and its chip stack are normally centred by .bet-circle's flex column, but that
   column only centres what's actually in it — adding the chip stack (only present once a Raise is
   made) shifts the whole centred block, and shoves the label down into the "+ STUD BONUS" caption
   curving below it. Pin both independently instead, so placing a chip never moves the label. */
.raise-circle .bet-circle-label {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
}
.raise-circle .chip-stack {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, calc(-50% - 26px));
}

/* "Double down" / "+ stud bonus" curved around the inside top and bottom of the Raise circle — the
   two halves of how the bet resolves. "5+ cards to qualify for bonus" wraps the *outside* of the
   circle along the bottom, the same qualifier every Stud bet needs — `overflow: visible` lets that
   outer arc extend past the circle's own box instead of being clipped at its edge. */
.raise-circle-caption {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
    pointer-events: none;
}
.raise-circle-caption text {
    font-family: var(--font-display);
    font-size: 7px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-anchor: middle;
    fill: var(--felt-dark);
}
.raise-circle-caption .raise-circle-caption-outer {
    font-size: 6.5px;
    letter-spacing: 0.3px;
    fill: #e8a93a;
}

/* Paytable odds are screened in gold on the felt; the categories stay white. */
.felt-paytable-grid td:last-child { color: #e8a93a; }
