/* Higher or Lower.

   Was three games' worth - Word Wrx and Trivia shared these shapes - and kept the name
   when they were retired, rather than renaming a file every page already links to. */

.hl {
    display: grid;
    /* Without an explicit track, the implicit one sizes to whatever its widest child
       asks for (here, .hl-stakes's two side-by-side figures) rather than to this
       element's own width:100% - a classic grid "blowout": the child renders at its
       full natural width even though its grid container is narrower, so it silently
       overflows the container's right edge instead of shrinking to fit. minmax(0, 1fr)
       gives the track a floor of 0 instead of auto (which floors at max-content), which
       is what actually lets a too-wide child shrink to the space available rather than
       spill past it. This is also why Higher or Lower read as sitting left of centre in
       its panel: justify-items:center was centring .hl-play in a grid, but a
       grid's own auto track had already let .hl-play overflow past the visible edge on
       the right before centring ever had anything correctly sized to work with. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    justify-items: center;
    color: var(--wx-ink, #fff);
    /* Explicit, not left to shrink-to-fit - the game column now centres this with
       flexbox (see gamestage.css), and a flex item with no width of its own sizes to
       its content's natural width instead of its container's. Higher or Lower's own
       content (.hl-actions/.hl-bank/.hl-peekrow max-width to 420px) wanted more room
       than the column had, so .hl came out a few pixels wider than its cell and
       spilled into the wins column next door. Slots and Scratch already set this;
       this brings the other three in line with them rather than leaving it to chance
       per game. */
    width: 100%;
    box-sizing: border-box;

    /* No padding of its own any more - .gstage-game (see gamestage.css) now draws the
       same bordered card .gi and .gwf always had, with its own inset built in, so a
       second inset here was spending width and height twice for one gap. Higher or
       Lower was the one game snug enough against that 420px ceiling for the loss to
       actually show: it overflowed .gstage-game's now-narrower box instead of merely
       sitting a little closer to the edge. */
}

/* The title bar (.gh, .gh h2, .gh-meta) is shared with every other game now - see
   gamestage.css. This used to be its own copy under three names; the markup moved,
   the rules didn't need to come along. */

.hl-note,
.hl-hint {
    color: var(--wx-muted, #9a9a9a);
    font-size: 0.86rem;
    text-align: center;
    margin: 0;
    max-width: 34ch;
}

/* A refused or failed peek - see PeekAsync's peekNote. Signal colour rather than a
   plain hint: this is the one message that exists specifically so a click that might
   have spent tokens never looks the same as one that did nothing. */
.hl-hint.is-bad { color: var(--wx-signal, #d4af37); }

.hl-btn {
    padding: 11px 24px;
    border: 1px solid var(--wx-line, #2c2c2c);
    border-radius: 999px;
    background: var(--wx-surface-2, #151515);
    color: var(--wx-ink, #fff);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.hl-btn.is-go {
    background: var(--wx-signal, #d4af37);
    color: var(--wx-signal-ink, #111);
    border-color: transparent;
    font-weight: 700;
}

.hl-btn.is-ghost { background: none; color: var(--wx-muted, #9a9a9a); }
.hl-btn:disabled { opacity: 0.5; cursor: default; }

.hl-start { display: grid; gap: 14px; justify-items: center; }

/* ── Higher or Lower ───────────────────────────────────────────────────────────

   Everything below the layout is feedback: the game has one decision in it and no time
   pressure, so what makes it a game rather than a form is that the screen answers back.
   Three answers, in order of how much they matter - a card lands, a run ends, a player
   walks away with something.

   All of it is driven by class and by element identity, never by a timer in CSS waiting
   on a timer in C#. The component re-keys the elements a card affects, which is what makes
   these animations run a second time; see the note there. */

/* The shake lives on the table rather than the card, so it can move the pair together
   without fighting the card's own deal transform - two animations on one transform is a
   fight the last one declared always wins. */
.hl-table { display: flex; gap: 12px; align-items: center; }

.hl-card {
    position: relative;
    width: 88px;
    height: 124px;
    border-radius: 10px;
    background: #fbfbf8;
    color: #16181d;
    display: grid;
    place-content: center;
    gap: 2px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
}

/* The card face is art, not surface: it is a playing card, and it stays white under every
   theme the same way the slot cabinet stays chrome. The chrome around it - rings, glows,
   the numbers - is what follows the tokens. */

/* Turned over rather than faded in. A card game should look like the card was dealt, and
   the half-turn is the cheapest honest way to say so. */
.hl-card.is-live { animation: hl-fromdeck 460ms cubic-bezier(0.2, 0.7, 0.3, 1) both; }

/* The card just turned over, shown smaller beside the live one so a player can see what
   they called against. It slides in from where the live card is, which reads as the old
   card having been pushed aside to make room. */
.hl-card.is-last {
    width: 58px;
    height: 82px;
    opacity: 0.55;
    animation: hl-aside 380ms cubic-bezier(0.2, 0.85, 0.3, 1);
}

/* The ring that reacts. One pseudo-element, two jobs, and they never co-occur: a right
   call pushes gold outwards, a wrong one flashes red and stays. Base state is invisible,
   so switching the animation off leaves nothing behind. */
.hl-card.is-live::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 13px;
    opacity: 0;
    pointer-events: none;
}

.hl-card.is-right::after {
    box-shadow: 0 0 0 2px var(--wx-signal, #d4af37);
    animation: hl-ring 620ms 90ms ease-out both;
}

.hl-card.is-bust {
    box-shadow: 0 0 0 2px var(--wx-bad, #c2453d), 0 6px 16px rgba(0, 0, 0, 0.35);
}

.hl-card.is-bust::after {
    inset: 0;
    background: var(--wx-bad, #c2453d);
    border-radius: 10px;
    animation: hl-bust 520ms ease-out both;
}

/* The rank, in the middle of the gear.

   Measured off the artwork rather than guessed. The mark is a cog with a figure inside
   it and two stars above, and the stars pull the shape's own middle upwards - so the
   card's centre, the mark's centre and the GEAR's centre are three different lines. The
   gear's rim runs from about 13% to 93% down the mark, putting its centre at 53% of the
   mark and, once the mark's vertical inset is added, 52% of the card.

   Both card sizes land on the same 52%, because every step of that is a proportion of
   the card rather than a number of pixels.

   Near-black over the white of the figure, which is what keeps it reading as printed on
   the artwork rather than laid across it. */
.hl-rank {
    position: absolute;
    top: 52%;
    left: 0;
    right: 0;
    transform: translateY(-50%);
    font-size: 3.2rem;
    font-weight: 900;
    line-height: 1;
    letter-spacing: -0.03em;
    text-align: center;

    /* 900 is the end of the scale, so the last of the weight comes from stroking the
       glyph in its own colour. Half a pixel, which thickens a 37px digit without closing
       up the counters in an 8 or a 9. */
    -webkit-text-stroke: 0.5px currentColor;
}

.hl-card.is-last .hl-rank {
    font-size: 2.05rem;
    -webkit-text-stroke: 0.3px currentColor;
}

/* The suit, in the two corners the mark used to hold - top right and bottom left, the
   diagonal the small corner pips leave free. Bigger than those pips and in the suit's own
   colour, so the card says what it is from either end without crowding the figure. */
.hl-suit {
    position: absolute;
    font-size: 1.65rem;
    line-height: 1;
    text-align: center;
}

.hl-suit.is-tr { top: 6px; right: 8px; }

/* Turned around, as the corner opposite it is - the same mark read from the other end. */
.hl-suit.is-bl { bottom: 6px; left: 8px; transform: rotate(180deg); }

.hl-card.is-last .hl-suit { font-size: 1.05rem; }
.hl-card.is-last .hl-suit.is-tr { top: 4px; right: 5px; }
.hl-card.is-last .hl-suit.is-bl { bottom: 4px; left: 5px; }
.hl-suit.is-red { color: #c2453d; }
.hl-suit.is-black { color: #16181d; }

.hl-streak { display: flex; align-items: baseline; gap: 6px; }

.hl-streak-count {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1;
    color: var(--wx-signal, #d4af37);
    font-variant-numeric: tabular-nums;
    display: inline-block;
}

/* The tick. Only on a right call - the number is unchanged on a bust and on the opening
   card, and a counter that jumps when it did not move is a lie. */
.hl-streak.is-up .hl-streak-count { animation: hl-tick 520ms cubic-bezier(0.2, 1.4, 0.4, 1) both; }
.hl-streak-label { color: var(--wx-muted, #9a9a9a); font-size: 0.82rem; }

/* The whole decision, side by side. */
.hl-stakes { display: flex; gap: 10px; width: 100%; max-width: 320px; }

.hl-stake {
    position: relative;
    overflow: hidden;
    flex: 1;
    display: grid;
    gap: 3px;
    padding: 9px;
    border: 1px solid transparent;
    border-radius: var(--wx-radius, 12px);
    background: var(--wx-surface-2, #151515);
    text-align: center;
}

/* Two panels, two temperatures. The safe number is left flat on the surface colour; the
   tempting one is lit. That contrast is the decision - the player is not comparing two
   figures, they are choosing between calm and gold. */
.hl-stake.is-next {
    border-color: var(--wx-signal, #d4af37);
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--wx-signal, #d4af37) 12%, transparent),
            transparent 70%),
        var(--wx-surface-2, #151515);
}

/* One pass of light across the tempting panel each time a new card makes the offer real,
   then nothing. A glow that breathed forever would stop meaning anything by the third
   card, and would keep a phone compositing for no reason. */
.hl-stake.is-next::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 45%;
    background: linear-gradient(100deg,
        transparent,
        color-mix(in srgb, var(--wx-signal, #d4af37) 26%, transparent),
        transparent);
    opacity: 0;
    pointer-events: none;
    animation: hl-sheen 900ms 160ms ease-out both;
}

.hl-stake-label { font-size: 0.7rem; color: var(--wx-muted, #9a9a9a); }

.hl-stake-value {
    font-size: 1.05rem;
    font-weight: 700;
    font-family: var(--wx-font-data, ui-monospace, monospace);
    font-variant-numeric: tabular-nums;
    animation: hl-roll 340ms 60ms cubic-bezier(0.2, 0.85, 0.3, 1) both;
}

.hl-stake.is-next .hl-stake-value { font-size: 1.2rem; color: var(--wx-signal, #d4af37); }

/* The three controls are one column: peek, the two calls, and bank. They share a width so
   the stack reads as one thing rather than three buttons that happen to be near each
   other. */
.hl-actions {
    display: flex;
    gap: 10px;
    width: min(320px, 92%);
}

.hl-actions .hl-btn {
    flex: 1 1 0;            /* the two calls split the row evenly */
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 13px 10px;
}

/* Direction, drawn rather than iconed - the available Font Awesome is a version behind and
   a triangle is two borders. It also survives a font failing to load, which an icon does
   not. */
.hl-btn.is-up::before, .hl-btn.is-down::before {
    content: '';
    width: 0;
    height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    transition: transform 140ms ease;
}

.hl-btn.is-up::before { border-bottom: 9px solid var(--wx-signal, #d4af37); }
.hl-btn.is-down::before { border-top: 9px solid var(--wx-signal, #d4af37); }

/* The call a peek has settled. Lit the way the peeked card is ringed, so the two read as
   one fact; the other button is disabled beside it. */
.hl-btn.is-lit {
    border-color: var(--wx-signal, #d4af37);
    box-shadow: 0 0 0 2px var(--wx-signal, #d4af37), 0 0 18px rgba(212, 175, 55, 0.35);
    color: var(--wx-ink, #fff);
}

/* Scoped to .hl-btn on purpose. Other games share the base button rule above but
   not this - their buttons are answers, not a physical action, and should not spring. */
.hl-btn {
    transition: transform 130ms ease, border-color 130ms ease, background 130ms ease;
}

/* Guarded, because a tap on Android leaves :hover latched on the last thing touched - the
   button would stay lifted after the card had already been dealt. Touch gets the press
   instead, which is the feedback that matters there anyway. */
@media (hover: hover) {
    .hl-btn:not(:disabled):hover {
        transform: translateY(-2px);
        border-color: var(--wx-signal, #d4af37);
        background: var(--wx-signal, #d4af37);
        color: var(--wx-signal-ink, #111);
    }

    /* The arrow is drawn out of borders, so it has to be re-coloured explicitly when the
       button fills in behind it - a gold triangle on a gold button is an invisible one. */
    .hl-btn.is-up:not(:disabled):hover::before {
        transform: translateY(-2px);
        border-bottom-color: var(--wx-signal-ink, #111);
    }

    .hl-btn.is-down:not(:disabled):hover::before {
        transform: translateY(2px);
        border-top-color: var(--wx-signal-ink, #111);
    }
}

.hl-btn:not(:disabled):active { transform: translateY(1px) scale(0.985); }

/* Only worth looking at once there is something in it. Left as an outline so it stays
   quieter than the two calls, which are the action - banking is the way out, not the
   thing to do next. */
.hl-btn.is-ghost:not(:disabled) {
    color: var(--wx-signal, #d4af37);
    border-color: var(--wx-signal, #d4af37);
}

/* Banking ends the game, so the game gets out of the way: the cards and the streak recede
   and the figure is the only lit thing left. A bust is the opposite - the losing card is
   the point, so it stays exactly as it is. */
.hl.is-bank .hl-table,
.hl.is-bank .hl-streak {
    opacity: 0.4;
    transition: opacity 500ms ease;
}

/* The game talking - the same fixed box under the status bar every game has now. The
   banked figure counts up in here at the end of a run; a wrong call says so in red. */
/* .hl-message: the box itself is .game-message in gamestage.css - one rule for every
   game. Only this game's own variants live here. */
/* .hl-message.is-lost is .game-message.is-lost - see gamestage.css. */
.hl-message.is-bad strong { color: var(--wx-bad, #e5484d); }

/* Ten sparks off the centre of the win. Each one carries its index inline and works out
   its own bearing from it, so the fan costs one rule rather than ten. Gold only: this is a
   rewards app and confetti in five colours would be a different product. */
.hl-burst {
    position: absolute;
    left: 50%;
    top: 42%;
    width: 0;
    height: 0;
    pointer-events: none;
}

.hl-burst i {
    position: absolute;
    left: -3px;
    top: -3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--wx-signal, #d4af37);
    opacity: 0;
    animation: hl-spark 760ms cubic-bezier(0.15, 0.7, 0.3, 1) both;
    animation-delay: calc(var(--i) * 18ms);
}

/* ── The beats ─────────────────────────────────────────────────────────────── */

/* Every keyframe here starts from somewhere and ends at the element's own resting style,
   or returns to it. That is what lets the reduced-motion block switch them all off with
   one declaration and leave the screen correct rather than half-drawn. */

}

.hl-table.is-shake { animation: hl-shake 420ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }

@keyframes hl-shake {
    0%, 100% { transform: translateX(0); }
    14% { transform: translateX(-9px); }
    30% { transform: translateX(8px); }
    46% { transform: translateX(-6px); }
    62% { transform: translateX(4px); }
    80% { transform: translateX(-2px); }
}

@keyframes hl-tick {
    0% { transform: scale(1); }
    38% { transform: scale(1.55); }
    100% { transform: scale(1); }
}

@keyframes hl-roll {
    from { transform: translateY(7px); opacity: 0; }
}

@keyframes hl-sheen {
    from { transform: translateX(-140%); opacity: 0; }
    35% { opacity: 1; }
    to { transform: translateX(300%); opacity: 0; }
}

@keyframes hl-settle {
    from { transform: scale(0.9); opacity: 0; }
    60% { transform: scale(1.035); }
}

@keyframes hl-spark {
    from { transform: rotate(calc(var(--i) * 36deg)) translateY(-6px) scale(1); opacity: 1; }
    to { transform: rotate(calc(var(--i) * 36deg)) translateY(-52px) scale(0.15); opacity: 0; }
}

/* Reduced motion. The screen still has to say the same three things, so what goes is the
   movement and not the information: the gold, the red and the numbers all stay, and the
   count-up is replaced by the total it was heading for. */
@media (prefers-reduced-motion: reduce) {
    .hl-card.is-live,
    .hl-card.is-right::after,
    .hl-card.is-last,
    .hl-table.is-shake,
    .hl-streak.is-up .hl-streak-count,
    .hl-stake.is-next::after,
    .hl-stake-value,
    .hl-message.is-good,
    .hl-message.is-bad,
    .hl-burst i {
        animation: none;
    }

    .hl-btn, .hl-btn.is-up::before, .hl-btn.is-down::before { transition: none; }
    .hl-btn:not(:disabled):hover, .hl-btn:not(:disabled):active { transform: none; }

    .hl-burst { display: none; }

    /* The bust ring is a permanent box-shadow, not the flash, so the card still shows it
       was the losing card. */
    .hl-card.is-bust::after { display: none; }
}

/* ── Higher or Lower: the redesigned table ──────────────────────────────────────

   Three colours named once, as tokens rather than literals, so a partner theme can move
   them without touching a rule - the courtesy every other colour here gets from --wx-*. */

.hl {
    --wx-hl-now: #8fd6a0;      /* Now Winning - light green */
    --wx-hl-next: #ff9a3c;     /* Next Win - orange */
    --wx-hl-bank: #2ecc5a;     /* Bank Now - bright green */
}

/* ── The two figures, above the cards ───────────────────────────────────────── */

.hl-stakes { position: relative; }

.hl-stake.is-now .hl-stake-label { color: var(--wx-hl-now); }
.hl-stake.is-now .hl-stake-value { color: var(--wx-hl-now); }

.hl-stake.is-next { border-color: var(--wx-hl-next); }
.hl-stake.is-next .hl-stake-label { color: var(--wx-hl-next); }
.hl-stake.is-next .hl-stake-value { color: var(--wx-hl-next); }

/* The multiplier a push leaves behind, riding beside the figure it applies to. */
.hl-mult {
    display: inline-block;
    margin-left: 5px;
    padding: 1px 6px;
    font-size: 0.56rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-radius: 999px;
    background: var(--wx-hl-next);
    color: #16181d;
    font-size: 0.66rem;
    font-weight: 800;
    vertical-align: middle;
}

/* Two copies of the Next Win figure: the rolling one ticks up after a push, the settled
   one is what reduced motion shows instead. */
.hl-next-final { display: none; }

/* Slightly lighter than the figure it introduces - it is a sign, not a digit. */
.hl-plus { opacity: 0.8; margin-right: 1px; }

.hl-stakes.is-push .hl-stake.is-next {
    animation: hl-pushflash 2600ms ease-out both;
}

/* Pulses three times over the badge's life rather than once, so the eye is drawn to the
   figure that is changing while the words are still on screen. */
@keyframes hl-pushflash {
    0%, 100% { box-shadow: none; }
    10%      { box-shadow: 0 0 16px 2px var(--wx-hl-next); }
    22%      { box-shadow: 0 0 0 2px var(--wx-hl-next); }
    38%      { box-shadow: 0 0 16px 2px var(--wx-hl-next); }
    52%      { box-shadow: 0 0 0 2px var(--wx-hl-next); }
    68%      { box-shadow: 0 0 16px 2px var(--wx-hl-next); }
    85%      { box-shadow: 0 0 0 2px var(--wx-hl-next); }
}

/* ── The deck ───────────────────────────────────────────────────────────────── */

/* The next card, face down, beside the one in play. Slightly smaller and set back, so it
   reads as waiting rather than as a third card on the table. */
.hl-card.is-deck {
    width: 58px;
    height: 82px;
    background: var(--wx-surface-2, #151515);
    border: 1px solid var(--wx-line, #2c2c2c);
    display: grid;
    place-items: center;
    padding: 6px;
    opacity: 0.9;
}

.hl-deck-logo {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* No partner logo set. A woven back rather than an empty rectangle. */
.hl-deck-back {
    width: 100%;
    height: 100%;
    border-radius: 5px;
    background:
        repeating-linear-gradient(45deg,
            var(--wx-signal, #d4af37) 0 3px,
            transparent 3px 7px);
    opacity: 0.45;
}

/* ── Bank Now ───────────────────────────────────────────────────────────────── */

/* Banking is the quiet option - the one that ends the run rather than pushing it - so it
   reads as an outline rather than a slab. Green trim, green text, nothing behind it.
   Padding drops by the 2px the border now takes on each side, so the button is the same
   height it was. */
/* The deal and bank buttons are .gplay (gamestage.css) - the same button every game
   buys a go with. Bank keeps its green as .gplay.is-bank. */

/* ── Reduced motion ─────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .hl-stakes.is-push .hl-stake.is-next { animation: none; }

    /* The rolling figure never runs, so show the settled one instead. */
    .hl-next-roll { display: none; }
    .hl-next-final { display: inline; }
}

/* ── The bank celebration ───────────────────────────────────────────────────────

   Over the whole game rather than inside the result box. Banking is the moment the game
   exists for, so it gets the screen and it takes its time - the old burst was ten sparks
   in a box, over before it registered.

   The cannons themselves are the shared ones now (Components/WinCelebration.razor and
   confetti.css), which is why there is so little here: all this side still owes them is
   somewhere to be positioned against. The CSS pair of cannons this replaced could throw
   paper in an arc but could not make it settle - every piece fell on the same curve at
   the same speed, because that is all a keyframe can say. */

.hl { position: relative; }

/* The result block settles in under the fall rather than competing with it. */


/* ── Holding the layout still ───────────────────────────────────────────────────

   Three places at the table, always. The empty ones are outlines: the row keeps its width
   and the live card keeps its position from the first deal to the last, so nothing slides
   sideways underneath a thumb that is already moving towards it. */

/* An empty place at the table.
   It was a barely-there dashed outline at half opacity, which on a dark panel read as
   nothing at all - the row looked like one card floating rather than three places with
   two of them waiting. Now it is a card-shaped hollow: a dashed edge in the theme's own
   line colour, so it is findable on a light ground as well as a dark one, and its label
   legible rather than hinted at. Still obviously not a card - no fill, no shadow, and
   nothing that reads as face up. The same rule for the spent place and the deal place:
   before a run, they are the same kind of empty. */
.hl-card.is-empty {
    background: none;
    border: 1px dashed var(--wx-line, #2c2c2c);
    box-shadow: none;
    opacity: 1;
}

/* The table reserves the height of the tallest card, so the row does not grow when the
   small "last" slot is replaced by a full one. Tops aligned rather than centres: the cards
   are different heights and a centred row makes the small ones look like they are floating
   between the big one. */
.hl-table { min-height: 124px; align-items: flex-start; }


/* And the two figures keep theirs, so a run ending does not close the gap up. */
.hl-stakes { min-height: 62px; }

/* ── Peek ───────────────────────────────────────────────────────────────────────

   A quieter button than Bank Now: it spends rather than collects, and it should not
   compete with the thing the player is here for. */

/* Fills its row rather than working out its own width. It was min(320px, 92%) inside a
   row that was already min(320px, 92%) - so the 92% resolved against 320px and the button
   came out 26px narrower than the bank button below it. */
/* A .gx-btn (gamestage.css) with a breath - what differs is only below. */
.hl-peek {
    align-self: center;
    border-color: var(--wx-line, #2c2c2c);
    color: var(--wx-muted, #9a9a9a);
}

.hl-peek:disabled { opacity: 0.45; cursor: default; animation: none; }

/* Says it is there and waiting. A peek is the one thing on this screen a player can do
   that is not the decision in front of them, so it has to ask for attention without
   taking it - a slow breath rather than a blink. */
.hl-peek:not(:disabled) {
    animation: hl-peekpulse 2600ms ease-in-out infinite;
}

/* The free one gets more of it. It costs nothing, and most players will never notice it is
   there - which is a shame the first time and expensive every time after. */
.hl-peek.is-free:not(:disabled) {
    border-style: solid;
    border-color: var(--wx-signal, #d4af37);
    color: var(--wx-signal, #d4af37);
    animation: hl-peekpulse-free 2200ms ease-in-out infinite;
}

@keyframes hl-peekpulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(212, 175, 55, 0); border-color: var(--wx-line, #2c2c2c); }
    50%      { box-shadow: 0 0 12px 0 rgba(212, 175, 55, 0.28); border-color: var(--wx-signal, #d4af37); }
}

@keyframes hl-peekpulse-free {
    0%, 100% { box-shadow: 0 0 6px 0 rgba(212, 175, 55, 0.25); transform: scale(1); }
    50%      { box-shadow: 0 0 20px 2px rgba(212, 175, 55, 0.55); transform: scale(1.015); }
}

/* Uppercase like the bank button, so the two priced buttons read as a pair. */
.hl-peek { text-transform: none; }

/* The lock. Past the free looks a free player is offered the same peek behind a
   short ad - the strongest membership pitch the game can make, and an honest one. The
   lock icon says what the button is; the dashed line says it is not the free one. */
.hl-peek.is-locked:not(:disabled) {
    border-style: dashed;
    border-color: var(--wx-signal, #d4af37);
    color: var(--wx-signal, #d4af37);
    animation: hl-peekpulse 2600ms ease-in-out infinite;
}
.hl-peek.is-locked .fa-lock { margin-right: 4px; font-size: 0.75em; }

@media (prefers-reduced-motion: reduce) {
    /* No breathing, but it keeps the gold - it is still the thing that is ready. */
    .hl-peek:not(:disabled),
    .hl-peek.is-free:not(:disabled) {
        animation: none;
        border-color: var(--wx-signal, #d4af37);
    }
}

@media (hover: hover) {
    .hl-peek:not(:disabled):hover {
        color: var(--wx-ink, #fff);
        border-color: var(--wx-signal, #d4af37);
    }
}

/* The card that has been paid for. Ringed so it reads as known rather than as a third
   card in play, and it turns over rather than simply appearing. */
.hl-card.is-deck.is-peeked {
    background: #fbfbf8;
    border: 0;
    box-shadow: 0 0 0 2px var(--wx-signal, #d4af37), 0 6px 16px rgba(0, 0, 0, 0.35);
    opacity: 1;
    animation: hl-peekturn 420ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}

@keyframes hl-peekturn {
    0%   { transform: rotateY(-84deg); }
    100% { transform: rotateY(0deg); }
}

@media (prefers-reduced-motion: reduce) {
    .hl-card.is-deck.is-peeked { animation: none; }
}

/* ── The deck column ────────────────────────────────────────────────────────────

   The face-down card and the button that buys a look at it, stacked. The button belongs
   here rather than under the actions: it acts on this card and on nothing else. */

/* The peek row: under the cards, above the calls. Always present, so the table does not
   rise when the looks run out. */
.hl-peekrow {
    display: flex;
    align-items: center;
    justify-content: center;
    width: min(320px, 92%);
    min-height: 40px;
}

.hl-peek-note {
    font-size: 0.72rem;
    color: var(--wx-muted, #9a9a9a);
    text-align: center;
}

.hl-peek-note.is-spent { opacity: 0.7; }

/* Cards come from the deck, so that is the deal: the card slides in from where the deck
   sits rather than turning over in place. It was only doing this for a card that had been
   peeked at, which made a paid card move and every other one simply appear. */
@keyframes hl-fromdeck {
    0%   { transform: translateX(72px) scale(0.72); opacity: 0.5; }
    100% { transform: translateX(0) scale(1); opacity: 1; }
}


/* ── Holding the three slots ────────────────────────────────────────────────────

   The spent card, the card in play and the deck. All three are always in the row and all
   three keep their width whether or not there is a card in them, so the card in play stays
   dead centre - which is what puts it between the two buttons underneath. */

.hl-card.is-last,
.hl-card.is-deck { width: 58px; flex: 0 0 58px; }

.hl-card.is-live { flex: 0 0 88px; }

/* ── The card face ──────────────────────────────────────────────────────────────

   The rank in the middle of the gear, and the suit at full size in two opposite corners.
   The tiny pips that used to sit in the other two are gone - a full-size suit already
   appears twice, and four of the same glyph was the card saying one thing four times. */

.hl-card { position: relative; }

/* The word in the empty slot, so it reads as somewhere a card goes rather than as a gap. */
.hl-slot-note {
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--wx-muted, #9a9a9a);
    opacity: 1;
}

/* ── The house mark on a card ────────────────────────────────────────────────
   A watermark across the middle of the face, with the rank and suit printed over it.

   It was two small marks in the corners, which at a size that stayed out of the way was
   a size nobody could see. Big and behind the print is the other answer, and the one a
   real card uses: it can be faint precisely because it is large, and the rank sitting on
   top of it is what keeps it from being read as content.

   Sized as a share of the card rather than in pixels, because the spent card beside the
   live one is a smaller card (.hl-card.is-last) and a fixed mark would swamp it.

   96% is as large as it goes. The card cannot clip - .hl-card.is-live::after is the ring
   that reacts to a call and it sits at inset -3px, OUTSIDE the card, so an overflow rule
   here would swallow the one bit of feedback the game has. That leaves the card width as
   a hard ceiling, and a square mark up against it. */
.hl-mark {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 96%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    background-image: url("../images/winwrx-mark.png");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;

    /* The mark is a mid teal and the card is very nearly white, so it takes more alpha
       than a watermark usually would to register at all - though far less now it is the
       width of the card than it did as a corner stamp. Under the print either way: the
       rank is near-black and the stacking below puts it on top. */
    opacity: 0.16;
    pointer-events: none;
    z-index: 0;
}

/* The face's own print, over the watermark. Everything on the face is positioned now, so
   this is only about which layer each sits in - and all of the print is above the mark. */
.hl-rank,
.hl-suit {
    z-index: 1;
}

/* The peek button while the card is up. Still a button, so the row keeps its size for the
   two seconds the card is showing - a bare label there was the last thing on this screen
   that still moved. */
.hl-peek.is-showing {
    opacity: 1;
    border-style: solid;
    border-color: var(--wx-signal, #d4af37);
    color: var(--wx-signal, #d4af37);
}

/* The card turned over after banking: what the next call would have been. Quieter than a
   card in play - it is an answer to a question, not part of the game any more. */
.hl-card.is-deck.is-revealed {
    box-shadow: 0 0 0 1px var(--wx-line, #2c2c2c), 0 6px 16px rgba(0, 0, 0, 0.35);
    opacity: 0.92;
}

/* ── A run that was lost ────────────────────────────────────────────────────────

   The figures stay on screen, holding what was riding on the call - but the colour goes
   out of them. Green and orange say "this is yours to take"; on a lost run that is exactly
   the wrong thing for them to say. */

.hl-stakes.is-lost .hl-stake {
    border-color: var(--wx-line, #2c2c2c);
    background: var(--wx-surface, #1b1b1b);
}

.hl-stakes.is-lost .hl-stake.is-next {
    background: var(--wx-surface, #1b1b1b);
    border-color: var(--wx-line, #2c2c2c);
}

.hl-stakes.is-lost .hl-stake-label,
.hl-stakes.is-lost .hl-stake-value,
.hl-stakes.is-lost .hl-plus {
    color: var(--wx-muted-dim, #666);
}

.hl-stakes.is-lost .hl-mult {
    background: var(--wx-muted-dim, #666);
    color: var(--wx-surface, #1b1b1b);
}

/* The card that ended it turns over on itself and the colour drains out. It arrives from
   the deck first, as every card does, and only then spins - so the beat reads as "dealt,
   and that was that" rather than as a card that came in already spinning. */
.hl-card.is-live.is-bust {
    animation:
        hl-fromdeck 460ms cubic-bezier(0.2, 0.7, 0.3, 1) both,
        hl-losespin 1100ms cubic-bezier(0.3, 0.1, 0.2, 1) 420ms both;
}

@keyframes hl-losespin {
    0%   { transform: rotateY(0deg) scale(1); filter: none; }
    50%  { transform: rotateY(360deg) scale(0.93); filter: grayscale(0.5); }
    100% { transform: rotateY(720deg) scale(1); filter: grayscale(1) brightness(0.72); }
}

/* The mark it left on the trail loses its colour with it. */

@media (prefers-reduced-motion: reduce) {
    /* No spin, but the lights still go out - that is information, not decoration. */
    .hl-card.is-live.is-bust {
        animation: none;
        filter: grayscale(1) brightness(0.72);
    }
}

/* ── Winning a call ─────────────────────────────────────────────────────────────

   The attention moves for a moment. A correct call adds to the total, so the green side
   lights up and the orange side steps back - then it hands over again, because the orange
   figure is the one the next decision is about.

   Timed in CSS rather than held in code: the block is keyed on the deal, so this plays
   once per card and finishes on its own. Holding it in C# would mean holding the buttons
   with it, and a right call should never make somebody wait. */

.hl-stakes.is-adding .hl-stake.is-now {
    animation: hl-nowflash 1900ms ease-out both;
}

.hl-stakes.is-adding .hl-stake.is-next {
    animation: hl-nextquiet 1900ms ease-out both;
}

@keyframes hl-nowflash {
    0%   { border-color: var(--wx-line, #2c2c2c); box-shadow: none; }
    7%   { border-color: var(--wx-hl-now); box-shadow: 0 0 20px 2px var(--wx-hl-now); }
    30%  { border-color: var(--wx-hl-now); box-shadow: 0 0 10px 1px var(--wx-hl-now); }
    72%  { border-color: var(--wx-hl-now); box-shadow: 0 0 6px 0 var(--wx-hl-now); }
    100% { border-color: var(--wx-line, #2c2c2c); box-shadow: none; }
}

/* The orange goes out and comes back. It is the standing highlight - the figure the next
   call is about - so it only ever steps aside, it does not leave. */
@keyframes hl-nextquiet {
    0%   { border-color: var(--wx-hl-next); opacity: 1; }
    7%   { border-color: var(--wx-line, #2c2c2c); opacity: 0.5; }
    72%  { border-color: var(--wx-line, #2c2c2c); opacity: 0.58; }
    100% { border-color: var(--wx-hl-next); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .hl-stakes.is-adding .hl-stake.is-now,
    .hl-stakes.is-adding .hl-stake.is-next { animation: none; }
}

/* The climbing total, and the settled copy reduced motion sees instead. */
.hl-now-final { display: none; }

@media (prefers-reduced-motion: reduce) {
    .hl-now-roll { display: none; }
    .hl-now-final { display: inline; }
}

/* ==========================================================================
   Higher or Lower: the game, and the panel that explains it.

   The panel used to be a page in front of the game - read once, pressed past, never
   seen again. It sits beside the table on a wide screen and under it on a phone,
   which is the same arrangement slots uses for its payouts, and for the same reason:
   a phone game centred in the middle of a desktop browser with empty space either
   side reads as something nobody finished.
   ========================================================================== */

.hl-play {
    display: grid;
    /* Same grid-blowout fix as .hl above, one level down - .hl-stakes (two side-by-side
       figures wanting more room together than this column has) is what was actually
       forcing the implicit track wider than width:100% allowed for. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    justify-items: center;
    width: 100%;
}

/* The panel is .gi - gamestage.css - like every other game's; its ladder is a GameKey. */

/* ---------- before the first deal ---------- */

/* The empty middle place: the outline it shares with the spent slot is in .hl-card.is-empty;
   this only switches off what a live card does when it lands. */
.hl-card.is-live.is-empty {
    animation: none;
}

.hl-card.is-live.is-empty::after { content: none; }

.hl-stake-idle {
    color: var(--wx-muted-dim, #6b6b6b);
}

/* ---------- with room ---------- */

/* Keyed on the stage being wide rather than on the window. The admin's preview is a
   phone-shaped panel inside a desktop page, so a media query here would hand it desktop
   cards inside a 390px frame - which is the whole reason GameStage takes Wide as a
   parameter instead of asking the browser. */

/* The game takes the room it has been given rather than sitting phone-width in the middle
   of it. Cards, figures and buttons all grow together; a table that widened while its
   buttons stayed put would look stretched rather than bigger.

   Each card is sized through flex-basis and not width. The row is a flex row and every
   slot already carries a flex-basis to hold its place, so a plain width here is simply
   ignored - which is what happened the first time: the heights grew, the widths did not,
   and all three cards came out stretched tall. Height and basis are set together, at the
   5:7 a playing card actually is. */
/* Wide, and the window wide enough for the stage to be three columns - see gamestage.css,
   which stacks a wide stage again on a narrow window. A phone browser gets the phone's
   cards: 120 + 84 + 84 across did not fit the column a 360px screen leaves. */
@media (min-width: 940px) {
    .gstage.is-wide .hl-table {
        gap: 18px;
        min-height: 168px;
    }

    .gstage.is-wide .hl-card.is-live {
        flex: 0 0 120px;
        width: 120px;
        height: 168px;
    }

    .gstage.is-wide .hl-card.is-last,
    .gstage.is-wide .hl-card.is-deck {
        flex: 0 0 84px;
        width: 84px;
        height: 118px;
    }

    .gstage.is-wide .hl-rank { font-size: 2.6rem; }
    .gstage.is-wide .hl-suit { font-size: 1.8rem; }
    .gstage.is-wide .hl-card.is-last .hl-rank { font-size: 1.7rem; }
    .gstage.is-wide .hl-card.is-last .hl-suit { font-size: 1.2rem; }

    .gstage.is-wide .hl-stakes { max-width: 420px; }
    .gstage.is-wide .hl-stake-value { font-size: 1.5rem; }
    .gstage.is-wide .hl-stake.is-next .hl-stake-value { font-size: 1.5rem; }

    .gstage.is-wide .hl-actions,
    .gstage.is-wide .hl-message,
    .gstage.is-wide .hl-play .gplay,
    .gstage.is-wide .hl-peekrow {
        width: 100%;
        max-width: 420px;
    }
}

/* A run in progress is worth more room than the panel is - but only once the window has
   it to give, which is the one thing the window is genuinely the authority on. */
@media (min-width: 1180px) {
    .gstage.is-wide .hl-table { min-height: 190px; }

    .gstage.is-wide .hl-card.is-live {
        flex: 0 0 136px;
        width: 136px;
        height: 190px;
    }

    .gstage.is-wide .hl-card.is-last,
    .gstage.is-wide .hl-card.is-deck {
        flex: 0 0 96px;
        width: 96px;
        height: 134px;
    }

    .gstage.is-wide .hl-rank { font-size: 3rem; }
}

@media (prefers-reduced-motion: reduce) {
    .hl-now-roll { display: none; }
    .hl-now-final { display: inline; }
}

/* ==========================================================================
   Higher or Lower: the game, and the panel that explains it.

   The panel used to be a page in front of the game - read once, pressed past, never
   seen again. It sits beside the table on a wide screen and under it on a phone,
   which is the same arrangement slots uses for its payouts, and for the same reason:
   a phone game centred in the middle of a desktop browser with empty space either
   side reads as something nobody finished.
   ========================================================================== */

.hl-play {
    display: grid;
    /* Same grid-blowout fix as .hl above, one level down - .hl-stakes (two side-by-side
       figures wanting more room together than this column has) is what was actually
       forcing the implicit track wider than width:100% allowed for. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    justify-items: center;
    width: 100%;
}

/* ---------- wider screens ---------- */

/* Same breakpoint as slots, so the two games do not disagree about where a desktop
   begins.

   This used to be a two-column grid of its own - header and rules on the left, the
   card table on the right - from when .hl laid itself out standalone. Both .hl-head
   (now .gh, in GameStage's own header zone) and .hl-info moved out to be siblings of
   .hl rather than children of it, so "header" and "info" have been empty areas for a
   while, reserving a 340px column for nothing and squeezing .hl-play - the one child
   .hl actually still has - into whatever was left. In three equal page-level columns
   there wasn't enough left, and the table overflowed into the wins column next door.
   .hl's own base rule (display:grid, justify-items:center) already centres .hl-play
   on its own; nothing here needs to lay it out again. */
@media (min-width: 820px) {
    /* The game takes the room it has been given rather than sitting phone-width in the
       middle of it. Cards, figures and buttons all grow together; a table that widened
       while its buttons stayed put would look stretched rather than bigger.

       Each card is sized on its own, through flex-basis and not width. The row is a flex
       row and every slot already carries a flex-basis to hold its place, so a plain width
       here is simply ignored - which is what happened the first time: the heights grew,
       the widths did not, and all three cards came out stretched tall. Height and basis
       are set together, at the 5:7 a playing card actually is. */
    .hl-table {
        gap: 18px;
        min-height: 168px;
    }

    .hl-card.is-live {
        flex: 0 0 120px;
        width: 120px;
        height: 168px;
    }

    .hl-card.is-last,
    .hl-card.is-deck {
        flex: 0 0 84px;
        width: 84px;
        height: 118px;
    }

    .hl-rank { font-size: 2.6rem; }
    .hl-suit { font-size: 1.8rem; }
    .hl-card.is-last .hl-rank { font-size: 1.7rem; }
    .hl-card.is-last .hl-suit { font-size: 1.2rem; }

    .hl-stakes { max-width: 420px; }
    .hl-stake-value { font-size: 1.5rem; }
    .hl-stake.is-next .hl-stake-value { font-size: 1.5rem; }

    .hl-actions,
    .hl-message,
    .hl-play .gplay,
    .hl-peekrow {
        width: 100%;
        max-width: 420px;
    }
}

/* This 1100px breakpoint used to exist alongside the near-identical
   @media (min-width: 1180px) .gstage.is-wide rule above - the same card sizes, the
   same properties, minus the now-dead 380px grid column and scoped to bare .hl-card
   instead of .gstage.is-wide .hl-card. Two breakpoints doing the same job a few dozen
   pixels apart is one more than this needs; the .gstage.is-wide version is the one
   that actually knows what page it's on. */

/* ==========================================================================
   Mystery Box - nine boxes, one of them yours. See MysteryBoxGame.razor.

   In this file rather than one of its own because it is the third session game
   and the other two live here; a fourth stylesheet to link on three hosts for
   sixty lines is a fourth place to forget.
   ========================================================================== */

.mb {
    position: relative;                    /* the win celebration is placed against this */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    box-sizing: border-box;
    color: var(--wx-ink, #fff);
}

.mb-note,
.mb-hint {
    color: var(--wx-muted, #9a9a9a);
    font-size: 0.86rem;
    text-align: center;
    margin: 0;
    max-width: 34ch;
}

.mb-note.is-bad { color: var(--wx-signal, #d4af37); }

/* The game talking - the same fixed box under the status bar every game has. */
/* .mb-message: the box itself is .game-message in gamestage.css - one rule for every
   game. Only this game's own variants live here. */
/* .mb-message.is-lost is .game-message.is-lost - see gamestage.css. */
/* An offer on the table. The message box IS the offer now - there used to be a second
   panel under the boxes saying the same figure bigger, and the game was talking from two
   places. Green, and the one time this box is allowed to be louder than one line. */
.mb-message.is-offer {
    border: 1px solid var(--wx-hl-bank, #2ecc5a);
    background: color-mix(in srgb, var(--wx-hl-bank, #2ecc5a) 8%, transparent);
}

.mb-message.is-offer strong {
    color: var(--wx-hl-bank, #2ecc5a);
    font-size: 1.08rem;
    font-weight: 700;
}

/* ── The board ────────────────────────────────────────────────────────────────
   Every amount in play, five across and three down to match the boxes under it,
   lowest first. A found amount is struck through and dimmed, not removed: the point of
   the board is seeing what has gone as much as what is left. No amount is singled out -
   the million used to be ringed in gold, which read as "this one is different" on a
   board where the whole game is that nothing is.

   A readout, not a row of controls: the figures sit on the table with no border and no
   fill, because with both they read as fifteen more buttons above the fifteen real
   ones. A hairline under the row is all that marks it as a board. */
.mb-board {
    list-style: none;
    margin: 0;
    padding: 0 0 6px;
    width: 100%;
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 2px 5px;
    border-bottom: 1px solid var(--wx-line, #2c2c2c);
}

.mb-val {
    padding: 4px 2px;
    font-family: var(--wx-font-data, ui-monospace, Consolas, monospace);
    font-size: 0.78rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: center;
    color: var(--wx-ink, #fff);
    transition: opacity 240ms ease;
}

.mb-val.is-gone {
    opacity: 0.32;
    text-decoration: line-through;
}

/* ── The boxes ────────────────────────────────────────────────────────────────
   Three across, five down - fifteen. Was five across; three makes each box a proper
   thing to tap on a phone, with room for a number you can read. A box is a button
   while it can be pressed - picked before a game, opened during one - and just a box
   the rest of the time. */
.mb-boxes {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}

.mb-box {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    /* Room for the lid, on the box rather than as a margin on the number - a margin
       moved with the content, so a box with two lines sat lower than one with one. */
    padding: 20% 2px 2px;
    box-sizing: border-box;
    aspect-ratio: 4 / 3;
    border-radius: 12px;
    border: 2px solid var(--wx-line, #2c2c2c);
    background: linear-gradient(to bottom, var(--wx-surface-2, #1f1f1f), var(--wx-surface, #151515));
    color: var(--wx-ink, #fff);
    font: inherit;
    cursor: pointer;
    transition: transform 120ms ease, border-color 120ms ease, filter 120ms ease;
    -webkit-tap-highlight-color: transparent;
}

/* The lid: a band across the top, which is what makes a rectangle read as a box. */
.mb-box::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 22%;
    border-radius: 10px 10px 0 0;
    background: color-mix(in srgb, var(--wx-signal, #d4af37) 22%, transparent);
    border-bottom: 1px solid var(--wx-line, #2c2c2c);
}

/* Sized for three across on a phone - a box is about 110px wide there. */
.mb-box-n {
    font-family: var(--wx-font-display, inherit);
    font-size: 1.4rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    line-height: 1;
}

/* The second line, amount or tag, is the same height whether or not it says anything,
   so every number on the board sits at the same height. */
.mb-box-amt,
.mb-box-tag {
    display: block;
    height: 1.05rem;
    line-height: 1.05rem;
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
}

.mb-box-amt {
    font-family: var(--wx-font-data, ui-monospace, Consolas, monospace);
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--wx-signal, #d4af37);
}

.mb-box-tag {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    /* Letter-spacing trails the last letter, which pulls a centred word left of centre;
       the same amount on the other side squares it. */
    padding-left: 0.14em;
    text-transform: uppercase;
    color: var(--wx-hl-bank, #2ecc5a);
}

.mb-box:disabled { cursor: default; }

@media (hover: hover) {
    .mb-box:not(:disabled):hover { border-color: var(--wx-signal, #d4af37); filter: brightness(1.08); }
}

.mb-box:not(:disabled):active { transform: translateY(1px) scale(0.99); }

/* Open: the lid comes off and the number gives way to what was inside. */
.mb-box.is-open {
    opacity: 0.55;
    border-style: dashed;
}

.mb-box.is-open::before { display: none; }
.mb-box.is-open .mb-box-n { font-size: 0.9rem; color: var(--wx-muted, #9a9a9a); }

/* The player's own: lit and ringed for the whole game, opened last. */
.mb-box.is-mine {
    border-color: var(--wx-hl-bank, #2ecc5a);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--wx-hl-bank, #2ecc5a) 28%, transparent);
    opacity: 1;
}

.mb-box.is-mine::before { background: color-mix(in srgb, var(--wx-hl-bank, #2ecc5a) 28%, transparent); }
.mb-box.is-mine.is-open { border-style: solid; }

/* ── The offer ────────────────────────────────────────────────────────────────
   Said in .mb-message at the top; down here are only the two answers. TAKE carries the
   figure in the outline green Higher or Lower banks with (.gplay.is-bank); PASS is the
   quiet one. */
.mb-decide {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

/* Two go-buttons sharing one row: tighter than one alone, so "TAKE · 152K" stays on a
   line in a phone-width column rather than folding in half. */
.mb-decide .gplay {
    padding: 12px 8px;
    font-size: 1.02rem;
    letter-spacing: 0.03em;
    white-space: nowrap;
}

.gplay.is-pass {
    background: var(--wx-surface-2, #151515);
    color: var(--wx-ink, #fff);
    border: 2px solid var(--wx-line, #2c2c2c);
}

/* ── Change My Box ────────────────────────────────────────────────────────────
   The quiet button under the game's controls - the wheel's bump buttons' shape
   (.pg-bump-btn), one across the row. While a box is being chosen it goes solid, so
   the way out reads as "you are in the middle of something". */
/* .mb-swap is a .gx-btn (gamestage.css) - nothing of its own but the wide cap below. */

/* A shut box while a change is being chosen: lit in the same gold, so the choice is
   the whole shut row and the player's own green one is plainly not in it. */
.mb-box.is-choice {
    border-color: var(--wx-signal, #d4af37);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--wx-signal, #d4af37) 28%, transparent);
}

/* Wide: the same cap the other session games take in the middle column. */
.gstage.is-wide .mb-board,
.gstage.is-wide .mb-boxes,
.gstage.is-wide .mb-decide,
.gstage.is-wide .mb-message,
.gstage.is-wide .mb-swap,
.gstage.is-wide .mb .gplay {
    max-width: 420px;
}
