/*
 * Speed Run — the game's own skin. Everything else (header, start screen, AI badge, tool
 * panels, dialog shell, fonts, the table felt) is inherited from ../core/deckades.css and is
 * deliberately NOT restated here.
 *
 * ── Where the colours come from ──────────────────────────────────────────────
 * The art is Michelle Campbell's pixel work: a magenta SPEED RUN wordmark over teal, navy and
 * lime diagonal stripes, and four 8-bit animal suits — a yellow earthworm, a grey raccoon, a
 * teal gecko, a navy gorilla. Three of the stripes' hues are suits (teal is the gecko's,
 * lime is the gorilla's lawn, the navy is every card's frame), so the ONE accent is the part
 * of the picture that is not a suit: the wordmark's magenta.
 *
 *   --dk-accent  #ea6a9c  the wordmark, sampled at rgb(207 78 133) off cover.webp and lifted
 *                         for a 12px label on a near-black panel (6.4:1 on #120a22). Nothing
 *                         else on the portal is this hue.
 *   --dk-tint    navy     the stripes' dark band — a cool slate wash over the shared felt.
 *   suit inks             the printed frames' own colours, used ONLY for suit labels (the
 *                         trump sign, the chips, the log). Never for chrome.
 *
 * ── The pixel face ───────────────────────────────────────────────────────────
 * The folder ships Press Start 2P (assets/fonts, OFL). It is NOT pointed at --dk-font-display:
 * an 8-px-grid face at the chrome's 17px status line and 22px logo is a wall, not a voice.
 * It is this game's own vocabulary instead — the two signs, the contract tiles, the scorecard
 * figures — where the printed cards use exactly that lettering. The house display face stays
 * on the shared chrome. A deliberate deviation from "the folder wins", recorded here.
 */

@font-face {
    font-family: 'Press Start 2P';
    src: url('assets/fonts/PressStart2P.woff2') format('woff2');
    font-weight: 400; font-style: normal; font-display: swap;
}

:root {
    --dk-accent:      #ea6a9c;
    --dk-accent-soft: rgba(234, 106, 156, 0.35);
    --dk-tint:        rgba(37, 53, 65, 0.40);

    /* Glass button 2 (../core/glassButton.css): the pane is tinted with the wordmark's
       magenta, its ink cool white, its shadow pool the stripes' navy. */
    --gb-tint:  208 78 133;
    --gb-ink:   #f4f0f2;
    --gb-shade: 8 14 20;

    /* ── This game's own vocabulary. Namespaced; never a new --dk-* token. ── */
    --sr-font-pixel: 'Press Start 2P', 'Cormorant Garamond', monospace;
    --sr-ink:        #e8edf1;                      /* body text: cool white */
    --sr-dim:        #9fb2c0;                      /* secondary text, tinted from the navy */
    --sr-navy:       #253541;                      /* the cards' frame; the tiles */
    --sr-navy-deep:  #16222b;
    --sr-slate:      rgba(22, 32, 42, 0.86);       /* the cabinet: sheet, signs, tags */
    --sr-slate-hi:   rgba(32, 46, 58, 0.94);
    --sr-line:       rgba(234, 106, 156, 0.22);
    --sr-teal:       #73c1bb;                      /* the printed cards' teal lettering */
    --sr-lime:       #b2c463;
    --sr-worm:       #f0bd4a;
    --sr-coon:       #c9d0cc;
    --sr-gecko:      #73c1bb;
    --sr-gorilla:    #b2c463;
    --sr-danger:     #f09a7e;                      /* the refusal, and a positive score */
    --sr-good:       #ea6a9c;                      /* a Perfect Bonus: the accent, the only "good" red */

    /* Card geometry is solved in JS and written back here, so one variable resizes every
       card on the table. The printed cards are 500×680 — a 5:6.8 box. */
    --card-w:  80px;
    --card-h:  109px;
    --card-scale: 1;
    --opp-scale: 0.62;                             /* face-down opponent backs: never read */
    --play-scale: 0.84;                            /* cards in the trick: read, so bigger */
    --tile-w: 64px;                                /* a contract tile (5:7) */
}

html { background: #0b1219; }
html, body { height: 100%; }
body {
    margin: 0;
    color: var(--sr-ink);
    font-family: var(--dk-font-ui);
    overflow: hidden;
    touch-action: none;
    -webkit-user-select: none; user-select: none;
}
::selection { background: var(--dk-accent-soft); color: var(--sr-ink); }

/* ── The play surface: the SHARED FELT, with the stripes baked onto it ──────────
   The cover is blended soft-light into the table photo, so the diagonal stripes come through
   the felt's grain as a pattern in the cloth rather than a picture behind the cards. The wash
   is a cool near-black — the stripes' navy — and heavy enough that a hand of printed cards is
   still the brightest thing on screen. */
#game {
    position: absolute; inset: 0;
    overflow: hidden;
    touch-action: none;
    background:
        linear-gradient(rgba(8, 13, 18, 0.72), rgba(6, 10, 14, 0.86)),
        url('assets/cover.webp') center 40% / cover no-repeat fixed,
        var(--dk-table);
    background-blend-mode: normal, soft-light, normal;
}

/* Behind the start screen the cover is shown whole and brighter — the one place a cover is
   a cover. */
#start-screen {
    background:
        linear-gradient(rgba(6, 10, 14, 0.62), rgba(6, 10, 14, 0.84)),
        url('assets/cover.webp') center 40% / cover no-repeat fixed,
        #0b1219;
}
/* The launch column's glass buttons: full width, the shared column's rhythm. */
.start-glass { width: 100%; }
.start-glass .gb { width: 100%; }

/* ── The track: the ellipse the seats sit around ────────────────────────────── */
#board {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.05);
    box-shadow: inset 0 0 70px rgba(0, 0, 0, 0.50), 0 18px 60px rgba(0, 0, 0, 0.35);
    background:
        radial-gradient(ellipse at 50% 46%, var(--felt-trump, transparent) 0%, rgba(0, 0, 0, 0) 60%),
        radial-gradient(ellipse at 50% 45%, rgba(37, 53, 65, 0.22), rgba(4, 8, 12, 0.30) 70%);
    transition: background 420ms ease;
    pointer-events: none;
}

/* THE TRUMP'S OWN EMBLEM, watermarked into the cloth under the trick it decides: the suit's
   8-bit animal cut from the card corners, used as a mask over the suit's ink. Over the felt's
   light and under every card. It fades slower than the sign that declares it. */
.felt-suit {
    position: absolute;
    transform: translate(-50%, -50%);
    background: var(--sr-ink);
    mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat;
    mask-position: center; -webkit-mask-position: center;
    mask-size: contain; -webkit-mask-size: contain;
    opacity: 0;
    pointer-events: none;
    z-index: 1;
    transition: opacity 560ms ease, background-color 300ms ease;
}
.felt-suit.on { opacity: 0.10; }
.felt-suit[data-suit="worm"]    { background: var(--sr-worm); }
.felt-suit[data-suit="coon"]    { background: var(--sr-coon); }
.felt-suit[data-suit="gecko"]   { background: var(--sr-gecko); }
.felt-suit[data-suit="gorilla"] { background: var(--sr-gorilla); }

#trick-zone, #seats, #piles, #hand, #bids { position: absolute; inset: 0; pointer-events: none; }
#trick-zone { z-index: 2; }
#bids { z-index: 3; }
#hand > *, #seats > *, #piles > *, #bids > * { pointer-events: auto; }
.play-zone { position: absolute; width: 0; height: 0; pointer-events: none; }

/* ── Cards ──────────────────────────────────────────────────────────────────
   The printed art IS the card: a 500×680 pixel face and a pixel back. The box carries a
   thin light edge so a card reads as a card against the dark track even where the art's
   frame is navy. */
.card {
    position: absolute;
    width: calc(var(--card-w) * var(--card-scale));
    height: calc(var(--card-h) * var(--card-scale));
    border-radius: calc(var(--card-w) * 0.06);
    background: #e9ece8;
    box-shadow: 0 3px 9px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(0, 0, 0, 0.35);
    overflow: hidden;
    transition: transform 180ms cubic-bezier(.22,.75,.3,1), box-shadow 140ms, filter 140ms;
    will-change: transform;
    touch-action: none;
}
.card img {
    display: block; width: 100%; height: 100%;
    object-fit: cover; pointer-events: none;
    -webkit-user-drag: none;
    image-rendering: auto;
}
.card .card-face, .card .card-back { position: absolute; inset: 0; }
.card.face-down .card-face { display: none; }
.card:not(.face-down) .card-back { display: none; }

/* Opponent backs and trick cards scale through their own tokens; every JS geometry helper
   reads the same numbers back, so layout and paint cannot disagree. */
.card.opp  { --card-scale: var(--opp-scale); }
.card.play { --card-scale: var(--play-scale); }

/* A card the human may legally play right now. Following is restrictive — often one suit —
   so showing it is most of the interface. */
.card.playable { cursor: pointer; }
.card.playable:hover { filter: brightness(1.12); box-shadow: 0 0 0 2px var(--dk-accent), 0 4px 14px rgba(0,0,0,.55); }
.card.illegal { filter: brightness(0.58) saturate(0.55); }
.card.illegal::after {
    content: ''; position: absolute; inset: 0;
    border-radius: inherit; background: rgba(6, 10, 14, 0.26);
}
.card.just-played { box-shadow: 0 0 0 2px var(--dk-accent), 0 4px 14px rgba(0,0,0,.55); }

/* The audible refusal: an illegal tap shakes the card and the status line says why. The
   shake runs on the FACE, not the card: the card's own transform is its position on the
   table, and a keyframe on it would throw the card to the origin for the duration. */
.card.shake .card-face, .card.shake .card-back { animation: sr-shake 360ms cubic-bezier(.36,.07,.19,.97) both; }
@keyframes sr-shake {
    10%, 90% { transform: translateX(-2px); }
    20%, 80% { transform: translateX(3px); }
    30%, 50%, 70% { transform: translateX(-5px); }
    40%, 60% { transform: translateX(5px); }
}

/* ── Trick piles ────────────────────────────────────────────────────────────
   Every seat's count scores, so every pile is laid out one trick at a time, the count in
   the pixel face beside it — readable from across the table. */
.pile {
    position: absolute;
    display: flex; align-items: center; gap: 4px;
    pointer-events: none;
}
.pile-card {
    width: calc(var(--card-w) * 0.30); height: calc(var(--card-h) * 0.30);
    border-radius: 3px;
    background: var(--sr-navy) url('assets/cards/back.webp') center / cover;
    box-shadow: 0 1px 3px rgba(0,0,0,.6);
    margin-left: calc(var(--card-w) * -0.14);
}
.pile-card:first-child { margin-left: 0; }
.pile-count {
    margin-left: 6px;
    font-family: var(--sr-font-pixel); font-size: 14px;
    color: var(--sr-ink); font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 4px rgba(0,0,0,.8);
}

/* ── Seats: the name tags ────────────────────────────────────────────────────── */
.seat {
    position: absolute;
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 5px 10px;
    border-radius: 10px;
    background: var(--sr-slate);
    border: 1px solid rgba(255, 255, 255, 0.07);
    font-size: 12.5px; line-height: 1.25;
    white-space: nowrap;
    transition: border-color 180ms, box-shadow 180ms, background 180ms;
}
.seat.turn {
    border-color: var(--dk-accent);
    box-shadow: 0 0 0 1px var(--dk-accent-soft), 0 6px 18px rgba(0, 0, 0, 0.35);
    background: var(--sr-slate-hi);
}
.seat-name { font-weight: 600; color: var(--sr-ink); }
.seat-name.ai { color: var(--sr-dim); }
.seat-row { display: flex; align-items: center; gap: 7px; color: var(--sr-dim); font-size: 11.5px; }
.seat-badge {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 1px 7px; border-radius: 999px;
    background: var(--dk-accent-soft);
    color: var(--sr-ink);
    font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
}
.seat-badge.quiet { background: rgba(255,255,255,.07); color: var(--sr-dim); }

/* ── The signs in the middle: live state ─────────────────────────────────────
   Two slabs of the cabinet's navy carrying the printed reminder cards' lettering in the
   pixel face: the ranking in force THIS trick (with the mode and its 12-trick track), and
   the trump (the suit's emblem on its ink, or NO TRUMP). */
#props { position: absolute; pointer-events: none; z-index: 1; }
.sign {
    position: absolute;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    padding: 8px 10px;
    border-radius: 10px;
    background: var(--sr-slate);
    border: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
    color: var(--sr-ink);
    font-family: var(--sr-font-pixel); font-size: 9px; line-height: 1.5; letter-spacing: 0;
    text-align: center;
    transition: box-shadow 300ms ease, border-color 300ms ease;
}
.sign.hidden { display: none; }
.sign .big { font-size: 15px; color: var(--sr-teal); white-space: nowrap; }
.sign .big.one { color: var(--sr-worm); }
.sign .sub { color: var(--sr-dim); font-size: 7px; }
.sign .sub b { color: var(--sr-ink); font-weight: 400; }
/* The direction arrows either side of the figure, drawn with the sign's own ink. */
.sign .arrow { display: inline-block; width: 12px; height: 12px; vertical-align: -2px; margin: 0 4px; }
.sign .arrow svg { display: block; width: 100%; height: 100%; }
/* The 12-trick track: a square per trick, filled where 10 is high, hollow where 1 is; the
   current trick is ringed in the accent. */
.track { display: flex; gap: 3px; margin-top: 2px; }
.track i {
    width: 7px; height: 7px; border-radius: 1px;
    background: var(--sr-teal);
    box-shadow: inset 0 0 0 1px var(--sr-teal);
}
.track i.one { background: transparent; box-shadow: inset 0 0 0 1px var(--sr-worm); }
.track i.done { opacity: .35; }
.track i.now { outline: 2px solid var(--dk-accent); outline-offset: 1px; }
/* The flip: the direction changed since the last trick. */
.sign.flip { animation: sr-flip 480ms ease-in-out; }
@keyframes sr-flip {
    0%   { transform: rotateX(0deg); }
    50%  { transform: rotateX(90deg); }
    100% { transform: rotateX(0deg); }
}
/* The trump sign: the emblem on a disc of its ink. */
.sign .emblem {
    width: 40px; height: 40px; border-radius: 50%;
    background: var(--sr-navy-deep);
    display: grid; place-items: center;
    box-shadow: inset 0 0 0 2px rgba(255,255,255,.08);
}
.sign .emblem i {
    display: block; width: 28px; height: 28px;
    background: var(--sr-ink);
    mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat;
    mask-position: center; -webkit-mask-position: center;
    mask-size: contain; -webkit-mask-size: contain;
}
.sign .emblem[data-suit="worm"] i    { background: var(--sr-worm); }
.sign .emblem[data-suit="coon"] i    { background: var(--sr-coon); }
.sign .emblem[data-suit="gecko"] i   { background: var(--sr-gecko); }
.sign .emblem[data-suit="gorilla"] i { background: var(--sr-gorilla); }
.sign .emblem.none { color: var(--dk-accent); }
.sign .emblem.none svg { width: 26px; height: 26px; display: block; }
.sign .label { color: var(--sr-dim); font-size: 7px; }
.sign .label.suit-worm    { color: var(--sr-worm); }
.sign .label.suit-coon    { color: var(--sr-coon); }
.sign .label.suit-gecko   { color: var(--sr-gecko); }
.sign .label.suit-gorilla { color: var(--sr-gorilla); }

/* The strip's one-line signs, inside the scorecard's title on a short table. */
.sheet-signs {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 10px;
    font-family: var(--sr-font-pixel); font-size: 8px; letter-spacing: 0; line-height: 1;
    color: var(--sr-ink); white-space: nowrap;
}
.sheet-signs.hidden { display: none; }
.sheet-signs .cs-rank { color: var(--sr-teal); display: inline-flex; align-items: center; }
.sheet-signs .cs-rank.one { color: var(--sr-worm); }
.sheet-signs .arrow { display: inline-block; width: 9px; height: 9px; margin: 0 3px; }
.sheet-signs .arrow svg { display: block; width: 100%; height: 100%; }
.sheet-signs .cs-mode { color: var(--sr-dim); font-size: 7px; }
.sheet-signs .cs-dot { color: var(--sr-dim); }
.sheet-signs .cs-trump { display: inline-flex; align-items: center; gap: 4px; font-size: 7px; }
.sheet-signs .cs-trump i {
    display: inline-block; width: 14px; height: 14px; background: currentColor;
    mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-size: contain;
    mask-position: center; -webkit-mask-position: center;
}
.sheet-signs .cs-trump svg { width: 12px; height: 12px; }
.sheet-signs .cs-trump.none { color: var(--dk-accent); }
.sheet-signs .cs-trump.suit-worm    { color: var(--sr-worm); }
.sheet-signs .cs-trump.suit-coon    { color: var(--sr-coon); }
.sheet-signs .cs-trump.suit-gecko   { color: var(--sr-gecko); }
.sheet-signs .cs-trump.suit-gorilla { color: var(--sr-gorilla); }
.sheet-signs.flip { animation: sr-flip 480ms ease-in-out; }
body.sheet-strip #sheet .sheet-title { justify-content: flex-start; white-space: nowrap; overflow: hidden; }
body.sheet-strip #sheet .sheet-title .sheet-title-text span { display: none; }   /* "lowest wins" waits for the grid */
body.sheet-strip #sheet .sheet-title .sheet-hand { margin-left: auto; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* The FIRST PLAYER card by that seat's tag: a small slab in the same lettering. */
.mini-sign {
    position: absolute; z-index: 5;
    padding: 6px 7px;
    border-radius: 6px;
    background: var(--sr-slate);
    border: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow: 0 3px 9px rgba(0, 0, 0, 0.45);
    font-family: var(--sr-font-pixel); font-size: 7px; line-height: 1.6; letter-spacing: 0;
    color: var(--dk-accent); text-align: center; white-space: nowrap;
    pointer-events: none;
}
.mini-sign.hidden { display: none; }

/* ── The contract tiles ─────────────────────────────────────────────────────
   The printed contract cards are white with teal lettering and a magenta figure. On the
   table they are tiles of the cabinet's navy carrying that lettering; face down they show
   the pixel back. 5:7, at least 44px wide as a tap. */
.tile {
    position: absolute;
    width: var(--tile-w); height: calc(var(--tile-w) * 1.4);
    border-radius: calc(var(--tile-w) * 0.08);
    background: linear-gradient(170deg, #2b3e4c, var(--sr-navy) 55%, var(--sr-navy-deep));
    border: 1px solid rgba(255, 255, 255, 0.10);
    box-shadow: 0 3px 9px rgba(0, 0, 0, 0.55);
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    font-family: var(--sr-font-pixel); font-size: 7px; line-height: 1.5; letter-spacing: 0;
    color: var(--sr-teal); text-align: center;
    overflow: hidden;
    transition: transform 180ms cubic-bezier(.22,.75,.3,1), box-shadow 140ms, filter 140ms;
    will-change: transform;
    touch-action: none;
}
.tile .num { font-size: 15px; color: var(--dk-accent); }
.tile .word { font-size: 7px; }
.tile .fine { font-size: 6px; color: var(--sr-dim); }
.tile.pass .word, .tile.redo .word { font-size: 8px; }
.tile.face-down { background: var(--sr-navy) url('assets/cards/back.webp') center / cover; }
.tile.face-down > * { display: none; }
.tile.playable { cursor: pointer; }
.tile.playable:hover { filter: brightness(1.15); box-shadow: 0 0 0 2px var(--dk-accent), 0 6px 16px rgba(0,0,0,.55); }
.tile.picked { box-shadow: 0 0 0 2px var(--dk-accent), 0 8px 18px rgba(0,0,0,.55); transform: translateY(-6px); }
.tile.dim { filter: brightness(0.6) saturate(0.6); }
/* The ×2 corner under the reveal variant. */
.tile .x2 {
    position: absolute; left: 0; right: 0; top: 0;
    font-size: 7px; line-height: 1; color: var(--sr-ink);
    background: var(--dk-accent); padding: 3px 0;
    text-align: center;
}
.tile.revealed { padding-top: 12px; }
/* A tile at the table (a bid placed) is small; the human's own is face up. */
.tile.placed { --tile-w: 44px; }
/* The reveal: a tile turning over, then the verdict printed beside it. */
.tile.turning { animation: sr-turn 520ms ease-in-out; }
@keyframes sr-turn {
    0%   { transform: rotateY(0deg); }
    50%  { transform: rotateY(90deg); }
    100% { transform: rotateY(0deg); }
}

/* ── The chooser: the human's selection and bid, in the middle of the table ─── */
#chooser {
    position: absolute; z-index: 60;
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    padding: 10px 12px;
    background: var(--sr-slate);
    border: 1px solid var(--sr-line);
    border-radius: 14px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5);
    max-width: calc(100vw - 24px);
}
#chooser.hidden { display: none; }
/* Bidding: no tray — the tiles lie on the felt. */
#chooser.bare { background: transparent; border-color: transparent; box-shadow: none; padding: 0; }
.chooser-title {
    font-family: var(--sr-font-pixel); font-size: 8px; color: var(--sr-dim); letter-spacing: 0;
    line-height: 1.5;
}
.chooser-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 10px; }
.chip .gb { min-width: 44px; min-height: 44px; padding: 0 12px 0 8px; }
.chip .gb-text { gap: 8px; font-family: var(--sr-font-pixel); font-size: 8px; letter-spacing: 0; }
.chip .gb-text i {
    display: block; width: 26px; height: 26px; flex: none;
    background: var(--sr-ink);
    mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat;
    mask-position: center; -webkit-mask-position: center;
    mask-size: contain; -webkit-mask-size: contain;
}
.chip[data-suit="worm"] .gb-text i,    .chip[data-suit="worm"] .gb-text span    { background-color: var(--sr-worm); color: var(--sr-worm); }
.chip[data-suit="coon"] .gb-text i,    .chip[data-suit="coon"] .gb-text span    { background-color: var(--sr-coon); color: var(--sr-coon); }
.chip[data-suit="gecko"] .gb-text i,   .chip[data-suit="gecko"] .gb-text span   { background-color: var(--sr-gecko); color: var(--sr-gecko); }
.chip[data-suit="gorilla"] .gb-text i, .chip[data-suit="gorilla"] .gb-text span { background-color: var(--sr-gorilla); color: var(--sr-gorilla); }
.chip .gb-text span { background: none !important; }
.chip .gb-text svg { width: 20px; height: 20px; display: block; flex: none; }
.chip .gb-text > span { display: inline-block; text-align: center; }
.chip .gb-text small { font-size: 7px; color: var(--sr-dim); display: block; margin-top: 3px; text-align: center; }
/* The tile row: the human's remaining contract cards, laid in the tray as static tiles. */
.tile-row { position: relative; display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; }
.tile-row .tile { position: relative; }
.tile-row .reveal-toggle { align-self: center; }
@media (max-height: 460px) { .tile .num { font-size: 12px; } }

/* ── The header's glass tools ───────────────────────────────────────────────────
   The material carries hover, press, focus and disabled; these add only the glyph size and
   the "its panel is open" state (header.js toggles .active on the button). */
.hdr-tool { touch-action: manipulation; }
.hdr-tool .gb-text svg { width: 18px; height: 18px; display: block; }
/* iOS: a tap landing on the SVG can miss the button — the icon is non-interactive. */
.hdr-tool svg, .hdr-tool svg * { pointer-events: none; }
.hdr-tool.active {
    background: linear-gradient(-75deg, rgba(255,255,255,.22), rgba(255,255,255,.04) 45%, rgba(255,255,255,.12)), rgba(var(--gb-tint) / 0.34);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.55), inset 0 -1px 1px rgba(var(--gb-shade) / .6), inset 0 0 0 1px rgba(var(--gb-tint) / .7), 0 0 22px -6px rgba(var(--gb-tint) / .6);
}
#header-right { gap: 8px; }

/* ── Status line ─────────────────────────────────────────────────────────────── */
#status-msg.alert { color: var(--sr-danger); }

/* ── Voice chat ────────────────────────────────────────────────────────────────
   The header's mic button (core/voice.js) is hidden outside a room; `.active` is the glass
   "on" state the other tools use. THE SEAT TAG IS THE SPEAKING INDICATOR: while its player
   talks the pill dissolves and the VOICE ORB (core/voiceOrb.js, the 21st.dev bubbling
   circle) is drawn in its place, centred on the tag and sized by game.js; the name and the
   badge stay on top. It wakes when that seat's level rises and fades 600 ms after it drops. */
#voice-wrap.hidden { display: none; }
.ico-spin { transform-origin: 50% 50%; animation: sr-spin 0.9s linear infinite; }
@keyframes sr-spin { to { transform: rotate(360deg); } }
#voice-orbs { position: absolute; inset: 0; pointer-events: none; }   /* under #seats in the DOM */
.seat-orb {
    position: absolute;
    opacity: 0; transform: scale(.7);
    transition: opacity 200ms ease, transform 200ms ease;
    will-change: opacity, transform;
}
.seat-orb.speaking { opacity: 1; transform: scale(1); }
canvas.voice-orb { display: block; width: 100%; height: 100%; }
/* The pill goes: the orb behind it is the tag now. Text keeps its place and gains a shadow. */
.seat.speaking {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}
.seat.speaking .seat-name, .seat.speaking .seat-name.ai { color: #fff; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 0 8px rgba(0, 0, 0, 0.6); }
.seat.speaking .seat-badge { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); }
@media (prefers-reduced-motion: reduce) { .ico-spin { animation: none; } .seat-orb { transition: none; } }

/* ── THE SCORECARD ─────────────────────────────────────────────────────────
   The printed scorecard (rulebook p.9) turned into the cabinet's own panel: one ROW per
   player, one COLUMN per main contract of this length, the totals down the right. Figures in
   the pixel face — the score large, the tricks small under it, a Perfect Bonus in the
   accent. Pass and Redo counts are chips by the name. JS builds the grid from the length and
   sets #sheet's outer box; the rules below are its material. */
#sheet {
    position: absolute;
    z-index: 40;
    display: flex; flex-direction: column;
    padding: 6px 10px 8px;
    background:
        linear-gradient(165deg, rgba(255,255,255,0.05), rgba(255,255,255,0) 40%, rgba(0,0,0,0.10)),
        var(--sr-slate);
    border: 1px solid rgba(255, 255, 255, 0.09);
    border-radius: 10px;
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255,255,255,0.08);
    color: var(--sr-ink);
    overflow: hidden;
}
.sheet-title {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    font-family: var(--sr-font-pixel); font-size: 9px; letter-spacing: 0; line-height: 1.5;
    color: var(--sr-teal);
    padding: 2px 2px 6px;
}
.sheet-title small { font-family: var(--dk-font-ui); font-size: 11.5px; font-weight: 600; letter-spacing: .03em; color: var(--sr-dim); }

/* The grid is one table: thin rules drawn as gaps over a line ground. */
.sheet-grid {
    display: grid;
    /* the columns are set inline by JS — they depend on how many contracts are in play */
    grid-template-rows: minmax(26px, auto) repeat(3, minmax(44px, 1fr));
    gap: 1px;
    flex: 1; min-height: 0;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 4px;
    overflow: hidden;
}
.sheet-grid[hidden] { display: none; }
.sheet-grid > * > * { background: var(--sr-navy-deep); }
.sheet-row { display: contents; }

.sheet-corner, .total-label {
    display: flex; align-items: flex-end; padding: 2px 8px 5px;
    font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--sr-dim);
}
.total-label { justify-content: center; }
.sheet-label {
    display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
    padding: 4px 4px; min-height: 30px;
    font-family: var(--sr-font-pixel); font-size: 7px; letter-spacing: 0; line-height: 1.5;
    color: var(--sr-teal); text-align: center; white-space: nowrap;
}
.sheet-label b { font-weight: 400; color: var(--dk-accent); }

/* Row heads: the players, with their Pass / Redo cards left as chips. */
.sheet-name {
    display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 3px;
    padding: 2px 8px; min-height: 40px; min-width: 0;
    font-size: 13px; font-weight: 600; color: var(--sr-dim);
    white-space: nowrap; overflow: hidden;
}
.sheet-name-text { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.sheet-name.mine { color: var(--sr-ink); }
.sheet-name.turn { color: var(--dk-accent); }
.sheet-name.turn .sheet-name-text::before { content: ''; display: inline-block; width: 6px; height: 6px; margin-right: 5px; border-radius: 50%; background: var(--dk-accent); vertical-align: middle; }
.sheet-chips { display: flex; gap: 4px; }
.sheet-chip {
    font-family: var(--sr-font-pixel); font-size: 7px; letter-spacing: 0;
    padding: 3px 4px; border-radius: 3px;
    background: rgba(255,255,255,.07); color: var(--sr-dim);
}
.sheet-chip.none { opacity: .35; }

/* The figures. */
.cell, .gp {
    position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 44px; min-width: 44px;
    font-family: var(--sr-font-pixel); font-size: 13px; letter-spacing: 0; line-height: 1;
    color: var(--sr-ink);
    transition: background 160ms, box-shadow 160ms, color 160ms;
}
.cell small { font-family: var(--dk-font-ui); font-size: 10px; font-weight: 600; color: var(--sr-dim); letter-spacing: .02em; }
.cell.blank::before { content: '·'; color: var(--sr-dim); opacity: .45; }
.cell.perfect { color: var(--sr-good); }
.cell.perfect::after {
    content: ''; position: absolute; left: 4px; right: 4px; bottom: 3px; height: 2px;
    background: var(--sr-good); opacity: .7;
}
.cell.positive { color: var(--sr-ink); }
.gp { font-size: 15px; background: var(--sr-navy) !important; }
.gp.leading { color: var(--sr-teal); }
.sheet-row-seat.mine .cell, .sheet-row-seat.mine .sheet-name { background: #1c2b36; }
/* The human's OWN bid this hand: the cell is ringed — nobody else's is, because nobody knows. */
.cell.mybid { box-shadow: inset 0 0 0 2px var(--dk-accent); }
.cell.mybid.blank::before { content: '?'; color: var(--dk-accent); opacity: 1; font-family: var(--sr-font-pixel); font-size: 11px; }
/* A redo target: the human's completed cells lift as taps. */
.cell.target { cursor: pointer; box-shadow: inset 0 0 0 1px var(--dk-accent); background: rgba(234, 106, 156, 0.14); }
.cell.target:hover { background: rgba(234, 106, 156, 0.28); }
/* A score landing: the cell pulses. */
.cell.pulse { animation: sr-pulse 900ms ease-out 2; z-index: 1; }
@keyframes sr-pulse {
    0%   { box-shadow: 0 0 0 0 var(--dk-accent); }
    100% { box-shadow: 0 0 0 10px rgba(234,106,156,0); }
}
.gp.rerank { animation: sr-rerank 720ms ease-out; }
@keyframes sr-rerank {
    0%   { transform: scale(1);   filter: brightness(1); }
    30%  { transform: scale(1.22); filter: brightness(1.25); }
    100% { transform: scale(1);   filter: brightness(1); }
}

/* The strip treatment: the same panel, one line (hand · totals) until tapped; opened, the
   grid unfolds downward over the board. */
body.sheet-strip #sheet { padding: 6px 10px; cursor: pointer; }
body.sheet-strip #sheet .sheet-title { padding-bottom: 2px; }
body.sheet-strip #sheet .sheet-title small { color: var(--sr-ink); }
body.sheet-strip #sheet.expanded .sheet-title { padding-bottom: 6px; }
body.sheet-strip #sheet.expanded { cursor: default; }
body.sheet-strip #sheet .sheet-grid { flex: none; }

/* ── The welcome (game.js welcome()) ──────────────────────────────────────────
   A glass plate in the middle of the table for three seconds, the page inert beneath it.
   The layer itself is the block — it takes every pointer and dims nothing, so the table it
   introduces stays in view. */
#sr-welcome {
    position: fixed; inset: 0; z-index: 1190;
    display: flex; align-items: center; justify-content: center;
    opacity: 0; transition: opacity 320ms ease;
}
#sr-welcome.show { opacity: 1; }
#sr-welcome .sr-welcome-plate { transform: translateY(10px); transition: transform 420ms cubic-bezier(.22,.75,.3,1); }
#sr-welcome.show .sr-welcome-plate { transform: none; }
#sr-welcome .gb-plate {
    flex-direction: column; gap: 8px; padding: 18px 34px 20px; border-radius: 16px;
    max-width: min(92vw, 520px); text-align: center;
    background:
        linear-gradient(-75deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.18) 50%, rgba(255, 255, 255, 0.06) 100%),
        rgba(var(--gb-tint) / 0.10),
        rgba(var(--gb-shade) / 0.62);
    backdrop-filter: blur(10px) saturate(1.15); -webkit-backdrop-filter: blur(10px) saturate(1.15);
}
.sr-welcome-title { font-family: var(--sr-font-pixel); font-size: 16px; line-height: 1.5; letter-spacing: 0; color: var(--sr-ink); text-shadow: 0 0 14px var(--dk-accent-soft), 0 1px 2px rgba(2, 6, 20, 0.7); }
.sr-welcome-line { font-family: var(--dk-font-ui); font-size: 15px; color: var(--sr-dim); }
@media (max-width: 620px) { .sr-welcome-title { font-size: 12px; } #sr-welcome .gb-plate { padding: 14px 22px 16px; } }
@media (prefers-reduced-motion: reduce) { #sr-welcome, #sr-welcome .sr-welcome-plate { transition: none; } }

/* ── The hand summary ─────────────────────────────────────────────────────────
   Four columns in the dialog shell: name · contract · result · points, the figures in the
   pixel face, a Perfect Bonus in the accent, a kept (worse) Redo dimmed. */
.summary-table {
    width: 100%; border-collapse: collapse;
    margin: 6px 0 4px;
    font-size: 14px; text-align: left;
}
.summary-table th {
    font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--sr-dim); padding: 4px 8px 6px;
    border-bottom: 1px solid rgba(255,255,255,.12);
}
.summary-table td { padding: 7px 8px; border-bottom: 1px solid rgba(255,255,255,.06); vertical-align: middle; }
.summary-table tr.mine td { background: rgba(255,255,255,.04); }
.summary-table .num { text-align: right; }
.summary-table .contract { color: var(--sr-teal); }
.summary-table .result { color: var(--sr-dim); white-space: nowrap; }
.summary-table .points { font-family: var(--sr-font-pixel); font-size: 13px; color: var(--sr-ink); white-space: nowrap; }
.summary-table .points.perfect { color: var(--sr-good); }
.summary-table .points.kept { color: var(--sr-dim); }
.summary-table .points small { display: block; font-family: var(--dk-font-ui); font-size: 10.5px; font-weight: 600; color: var(--sr-dim); margin-top: 3px; }
.summary-table tr.totals td { border-bottom: none; padding-top: 10px; font-size: 12.5px; color: var(--sr-dim); }
.summary-table tr.totals td.num { color: var(--sr-ink); font-weight: 600; }
#hand-summary-line { font-size: 13px; color: var(--sr-dim); }
@media (max-width: 620px) { .summary-table { font-size: 12.5px; } .summary-table td { padding: 5px 6px; } }

/* ── Round / game end ───────────────────────────────────────────────────────── */
#game-over-line { font-size: 14px; color: var(--sr-dim); margin: 2px 0 12px; }
.go-row {
    display: flex; align-items: center; gap: 10px;
    padding: 7px 12px; border-radius: 8px; margin-bottom: 4px;
    font-size: 14px; background: rgba(255,255,255,0.04);
}
.go-row.winner { background: var(--dk-accent-soft); box-shadow: inset 0 0 0 1px var(--dk-accent); }
.go-place { color: var(--sr-dim); font-size: 11px; width: 18px; }
.go-name  { flex: 1; text-align: left; }
.go-sub { font-size: 11px; color: var(--sr-dim); }
.go-score { font-family: var(--sr-font-pixel); font-size: 14px; color: var(--sr-ink); min-width: 40px; text-align: right; font-variant-numeric: tabular-nums; }
.go-score.negative { color: var(--sr-good); }
.modal-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }

/* Card names in the log, the status line and the AI panel carry their suit's ink. */
.suit-ink { font-weight: 600; white-space: nowrap; }
.suit-ink[data-suit="worm"]    { color: var(--sr-worm); }
.suit-ink[data-suit="coon"]    { color: var(--sr-coon); }
.suit-ink[data-suit="gecko"]   { color: var(--sr-gecko); }
.suit-ink[data-suit="gorilla"] { color: var(--sr-gorilla); }

/* ── Keyboard focus ─────────────────────────────────────────────────────────
   The UA ring is invisible on the felt; every tap target the game draws itself carries the
   accent ring under keyboard focus (the glass buttons bring their own). */
.card:focus-visible, .tile:focus-visible, .cell.target:focus-visible {
    outline: 2px solid var(--dk-accent); outline-offset: 2px;
}
.card:focus:not(:focus-visible), .tile:focus:not(:focus-visible), .cell:focus:not(:focus-visible) { outline: none; }

/* ── Animation ghosts ───────────────────────────────────────────────────────── */
#anim-layer { position: absolute; inset: 0; pointer-events: none; z-index: 900; }
.ghost { position: absolute; z-index: 900; pointer-events: none; will-change: transform; }
.ghost .card { position: absolute; left: 0; top: 0; transition: none; }
/* The score, flying from the tile to the cell. */
.ghost-score {
    position: absolute; z-index: 910; pointer-events: none;
    font-family: var(--sr-font-pixel); font-size: 18px;
    color: var(--sr-ink); text-shadow: 0 2px 8px rgba(0,0,0,.8);
}
.ghost-score.perfect { color: var(--sr-good); }
/* The verdict beside a turned tile: "4 tricks → −2". */
.verdict {
    position: absolute; z-index: 820;
    padding: 7px 10px; border-radius: 8px;
    background: var(--sr-slate-hi);
    border: 1px solid var(--dk-accent-soft);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5);
    color: var(--sr-ink);
    font-family: var(--sr-font-pixel); font-size: 8px; line-height: 1.6; letter-spacing: 0;
    white-space: nowrap; text-align: center;
    pointer-events: none;
    animation: sr-toast-in 260ms cubic-bezier(.22,.75,.3,1) both;
}
.verdict b { font-weight: 400; color: var(--dk-accent); font-size: 11px; }
.verdict .perfect { color: var(--sr-good); }
.verdict .dim { color: var(--sr-dim); }
@keyframes sr-toast-in  { from { opacity: 0; transform: translateY(8px) scale(.96); } to { opacity: 1; transform: none; } }
/* Call-outs floated beside the seat that made them. */
.callout {
    position: absolute; z-index: 800;
    padding: 5px 12px; border-radius: 999px;
    background: var(--sr-slate-hi);
    border: 1px solid var(--dk-accent-soft);
    color: var(--dk-accent);
    font-family: var(--dk-font-display); font-size: 14px; font-weight: 700;
    letter-spacing: .03em; white-space: normal; max-width: 240px; text-align: center; line-height: 1.25;
    pointer-events: none;
    animation: sr-callout 1900ms ease-out forwards;
}
@keyframes sr-callout {
    0%   { opacity: 0; transform: translateY(6px) scale(.92); }
    14%  { opacity: 1; transform: translateY(0) scale(1); }
    76%  { opacity: 1; }
    100% { opacity: 0; transform: translateY(-16px); }
}

/* The reveal checkbox's two-line label: the variant's name, the bracket under it. These are
   this game's own classes inside the shared .start-check; the shared rule is untouched. */
.check-label { display: flex; flex-direction: column; gap: 1px; line-height: 1.25; }
.check-sub { font-size: 12px; font-weight: 500; opacity: .75; }

/* The Rules link in the start screen's launch column — sized to its own text. */
.rules-link {
    align-self: center;
    display: inline-block;
    width: auto;
    margin-top: 4px;
    padding: 7px 16px;
    border: 1px solid var(--dk-accent-soft);
    border-radius: var(--dk-radius);
    background: transparent;
    color: var(--sr-ink);
    font-family: var(--dk-font-ui); font-size: 13px; font-weight: 600;
    text-align: center; text-decoration: none; white-space: nowrap;
    opacity: .85;
    transition: background .15s, opacity .15s;
}
.rules-link:hover { background: var(--dk-accent-soft); opacity: 1; }

/* ── The publisher's mark ───────────────────────────────────────────────────
   Moonshoot Games' logo, bottom left of the table at half strength — a credit, not a
   control: it takes no pointer and sits under everything the game draws. */
#publisher-mark {
    position: absolute; left: 14px; bottom: 12px;
    width: clamp(64px, 8vw, 110px); height: auto;
    opacity: 0.5;
    pointer-events: none; user-select: none; -webkit-user-drag: none;
    z-index: 0;
}
@media (max-height: 460px) { #publisher-mark { width: 56px; } }

/* ── The crawlable block ────────────────────────────────────────────────────── */
/* Crawlable copy (#intro in index.html): below the fold, never display:none. The table is
   JS-positioned from the viewport and body cannot scroll, so the block is never reached. */
#intro {
    margin: 100vh auto 0; max-width: 720px; padding: 4px 20px 8px; text-align: center;
    color: var(--dk-text-muted, #b8c4d0); font-family: var(--dk-font-ui); font-size: 14px;
    line-height: 1.55;
}
#intro h1 { color: var(--dk-text, #eef4ff); font-family: var(--dk-font-display); font-weight: 700;
            font-size: 24px; letter-spacing: 0.03em; margin: 0 0 8px; }
#intro p { margin: 0 0 9px; }
#intro a { color: var(--dk-accent); }

/* ── Mobile ─────────────────────────────────────────────────────────────────
   Layout is JS-positioned from the viewport; CSS only drops what it owns. */
@media (max-width: 700px), (max-height: 460px) {
    .pile-count { font-size: 11px; }
    #chooser { gap: 6px; padding: 6px 8px; }
    .chooser-row { gap: 6px; }
    .chip .gb { padding: 0 8px 0 6px; min-width: 44px; }
    .chip .gb-text { font-size: 7px; gap: 5px; }
    .tile-row { gap: 6px; }
    .seat { font-size: 11.5px; padding: 4px 8px; }
    .cell { font-size: 11px; }
    .gp { font-size: 12px; }
    .sign .big { font-size: 11px; }
    .sign .arrow { width: 10px; height: 10px; margin: 0 2px; }
    .chip .gb-text i { width: 22px; height: 22px; }
}

@media (prefers-reduced-motion: reduce) {
    .card, .tile, .sign, .cell, .seat, .gp, .felt-suit, #board { transition: none; animation: none; }
    .card.shake .card-face, .card.shake .card-back, .sign.flip, .tile.turning, .cell.pulse, .gp.rerank { animation: none; }
    .callout, .verdict { animation: none; opacity: 1; }
}
