        :root {
            --bg:#080b14; --surface:#0f1323; --surface-2:#161b30; --surface-3:#1e243d;
            --border:#252b47; --border-2:#323b63;
            --accent:#c9a84c; --accent-dim:rgba(201,168,76,.12); --accent-glow:rgba(201,168,76,.35);
            --purple:#7c6af5; --purple-dim:rgba(124,106,245,.12);
            --text:#dde1f5; --text-dim:#8890b8; --text-muted:#4d5580;
            --green:#3ecf82; --green-dim:rgba(62,207,130,.12);
            --red:#e05c6a; --red-dim:rgba(224,92,106,.12);
            --blue:#5b88e0; --blue-dim:rgba(91,136,224,.12);
            /* Step 13: hand zoom CSS variable; mutated by js/10-panzoom.js
               via document.documentElement.style.setProperty. board scale
               is NOT a variable — it composes into .pan-zoom-viewport's
               style.transform string written by JS. */
            --own-hand-scale:1;
        }
        *{margin:0;padding:0;box-sizing:border-box;}
        body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--text);height:100vh;overflow:hidden;display:flex;flex-direction:column;position:relative;}

        /* ── HEADER ──────────────────────────────────────── */
        .site-header{background:var(--surface);border-bottom:1px solid var(--border);padding:0 20px;display:flex;align-items:center;gap:14px;height:60px;position:sticky;top:0;z-index:200;box-shadow:0 4px 32px rgba(0,0,0,.5);}
        .logo{font-family:'Cinzel',serif;font-size:16px;font-weight:700;color:var(--accent);letter-spacing:.04em;white-space:nowrap;flex-shrink:0;cursor:pointer;}
        .logo:hover{filter:brightness(1.15);}
        .logo span{color:var(--text);font-weight:400;}
        .hdr-spacer{flex:1;}

        /* Status strip (header right side, visible only when seated) */
        .status{display:flex;align-items:center;gap:10px;font-size:12px;color:var(--text-dim);}
        .status[hidden]{display:none!important;}
        .status-room{font-family:'Cinzel',serif;letter-spacing:.04em;color:var(--text);background:var(--surface-3);border:1px solid var(--border);border-radius:20px;padding:4px 12px;}
        .status-sep{color:var(--text-muted);}
        .status-seat{display:inline-flex;align-items:center;gap:6px;}
        .status-seat::before{content:'';display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--text-muted);}
        .status-seat.red::before{background:var(--red);box-shadow:0 0 8px rgba(224,92,106,.6);}
        .status-seat.blue::before{background:var(--blue);box-shadow:0 0 8px rgba(91,136,224,.6);}
        .status-opp{font-size:11px;}
        .status-opp.connected{color:var(--green);}
        .status-opp.waiting{color:var(--text-muted);}
        .status-opp.disconnected{color:var(--red);}
        .status-conn{font-size:11px;color:var(--text-muted);}
        .status-conn.dead{color:var(--red);}

        /* ── PLAYMAT AREA ────────────────────────────────── */
        .playmat-area{
            flex:1;
            min-height:0;
            width:100%;
            display:flex;
            align-items:center;
            justify-content:center;
            overflow:hidden;
            background:var(--bg);
            padding:20px 20px 63px 20px;
            position:relative;
        }
        /* Board scene: square wrapper that scales to fit the playmat area.
           Contains the board image and the game-render layer; rotates
           180° as a unit on the Blue client so each player sees their
           own side at the bottom. */
        .board-scene{
            position:relative;
            aspect-ratio:1 / 1;
            max-width:100%;
            max-height:100%;
            /* width/height auto-derive from aspect-ratio + max constraints */
        }
        .board-scene.flip{transform:rotate(180deg);}
        .board-img{
            display:block;
            width:100%;
            height:100%;
            user-select:none;
            -webkit-user-drag:none;
            pointer-events:none;
        }
        /* Game render layer overlays the board exactly. Pile divs live
           inside it at percentage positions derived from board-absolute
           inches (so they stay aligned at any board size). */
        .game-render-layer{
            position:absolute;
            inset:0;
            pointer-events:none;
            z-index:50;
        }
        .game-render-layer[hidden]{display:none!important;}

        .pile{
            position:absolute;
            transform:translate(-50%, -50%);
            /* Card 2.5"×3.5" on a 48" board: 2.5/48 ≈ 5.208% wide,
               3.5/48 ≈ 7.292% tall. */
            width:5.208%;
            height:7.292%;
            background-image:url('/images/card_back.png');
            background-size:cover;
            background-position:center;
            background-repeat:no-repeat;
            border-radius:0.5%;
            pointer-events:auto;
            cursor:default;
            box-shadow:0 0.2% 0.6% rgba(0,0,0,.5);
        }
        .pile[hidden]{display:none!important;}
        .pile-count{
            position:absolute;
            inset:0;
            display:none;
            align-items:center;
            justify-content:center;
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:1.8vmin;
            color:var(--accent);
            background:rgba(8,11,20,.86);
            text-shadow:0 1px 4px rgba(0,0,0,.7);
            pointer-events:none;
        }
        /* Hover-only count badge. For Blue-owned piles, counter-rotate
           the text so it reads right-side-up to Blue (whose scene is
           already rotated 180° by .board-scene.flip). */
        .pile:hover .pile-count{display:flex;}
        .pile.owner-blue .pile-count{transform:rotate(180deg);}

        /* Clickable own-deck affordance. Applied dynamically in
           renderGame() to the local player's storybook + resource
           decks; opponent piles stay non-interactive. */
        .pile.own-pile{cursor:pointer;}
        .pile.own-pile:hover{box-shadow:0 0 0 2px var(--accent),0 0.2% 0.6% rgba(0,0,0,.5);}

        /* F8-b2: per-seat faction card. Board-absolute + card-sized like
           .pile, but shows the faction's FRONT art (not the card back);
           hover-only -- the screen-space #hoverPreview gives the readable
           view. owner-blue is counter-rotated 180deg (the
           .pile.owner-blue .pile-count precedent) so each owner sees their
           own faction upright and the opponent's facing away. No chrome. */
        .faction-card{
            position:absolute;
            transform:translate(-50%, -50%);
            width:5.208%;
            height:7.292%;
            background-size:cover;
            background-position:center;
            background-repeat:no-repeat;
            border-radius:0.5%;
            pointer-events:auto;
            cursor:default;
            box-shadow:0 0.2% 0.6% rgba(0,0,0,.5);
        }
        .faction-card.owner-blue{transform:translate(-50%, -50%) rotate(180deg);}
        .faction-card[hidden]{display:none!important;}

        /* ── HAND ROWS ───────────────────────────────────── */
        /* Live in screen-space outside .board-scene, so they do NOT
           rotate with the board. Always oriented for the local viewer:
           your hand at bottom (face-up), opponent's at top (card backs
           + count). Hidden whenever phase !== 'play'. */
        .hand-row, .opp-hand-row{
            width:100%;
            background:var(--surface);
            display:flex;
            align-items:center;
            justify-content:center;
            gap:8px;
            padding:8px 16px;
            overflow:hidden;
            flex-shrink:0;
            position:relative;
        }
        .hand-row{
            height:130px;
            border-top:1px solid var(--border);
        }
        .opp-hand-row{
            height:90px;
            border-bottom:1px solid var(--border);
        }
        .hand-row[hidden], .opp-hand-row[hidden]{display:none!important;}

        .hand-card{
            height:100%;
            border-radius:4px;
            box-shadow:0 2px 6px rgba(0,0,0,.5);
            flex-shrink:0;
            user-select:none;
            -webkit-user-drag:none;
            cursor:grab;                 /* P12 (F2): open-hand on hover; grabbing during drag via body.is-dragging-card */
        }
        img.hand-card{
            display:block;
            width:auto;
        }
        .hand-card-back{
            aspect-ratio:2.5 / 3.5;
            background-image:url('/images/card_back.png');
            background-size:cover;
            background-position:center;
            background-color:var(--surface-2);
        }

        /* Opponent hand count badge — top-right of .opp-hand-row. */
        .opp-hand-count{
            position:absolute;
            top:6px;
            right:12px;
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:13px;
            color:var(--accent);
            background:rgba(8,11,20,.85);
            border:1px solid var(--border-2);
            border-radius:12px;
            padding:2px 10px;
            pointer-events:none;
        }
        .opp-hand-count[hidden]{display:none!important;}

        /* ── BOARD CARDS ─────────────────────────────────── */
        /* Cards played from hand onto the shared table. Live INSIDE
           .game-render-layer (like the piles) so they rotate with the
           board; #boardCards sits after the piles in DOM so played
           cards paint above the deck piles. Per-card left/top/transform
           /zIndex are set inline by renderBoard(). */
        #boardCards{
            position:absolute;
            inset:0;
            pointer-events:none;
        }
        .board-card{
            position:absolute;
            /* Portrait card: 2.5"/48 ≈ 5.208% wide, 3.5"/48 ≈ 7.292%. */
            width:5.208%;
            height:7.292%;
            border-radius:0.5%;
            box-shadow:0 0.2% 0.6% rgba(0,0,0,.5);
            pointer-events:auto;
            cursor:default;
            user-select:none;
            -webkit-user-drag:none;
            object-fit:fill;
        }
        /* Support cards sit landscape on the board (design §6) — swap
           the box dimensions; the served /images/ art is already
           landscape for Support. */
        .board-card.board-card-landscape{
            width:7.292%;
            height:5.208%;
        }
        /* Only the card's controller can pick it up. */
        .board-card.controllable{cursor:grab;}
        .board-card.controllable:active{cursor:grabbing;}
        /* P12 (F2): closed grabbing-hand for the whole hand/board drag.
           Body class set at startHandDrag / startBoardDrag, cleared in
           onDragUp — same pattern as body.is-dragging-counter below, with
           a universal !important rule so the cursor stays "grabbing" even
           as the dragged element moves under the pointer and gains
           will-change (a per-element :active flickers in that case). */
        body.is-dragging-card,
        body.is-dragging-card *{
            cursor:grabbing !important;
        }
        /* Control indicator (step 7b): a thin ring tinted with the
           CURRENT CONTROLLER's seat colour, shown only when control has
           diverged from ownership (controller !== owner). Public — both
           clients render the identical ring from the unfiltered
           `controller` field. Composed WITH the base drop-shadow so it
           is preserved; box-shadow follows the card's border-radius, so
           the ring is a thin rounded outline that also rotates
           symmetrically with the card under the Blue scene-flip.
           Specificity (0,3,0) cleanly beats .board-card /
           .board-card-landscape. */
        .board-card.control-foreign.control-foreign-red{
            box-shadow:0 0 0 1px var(--red),0 0 8px 1px var(--red),0 1px 3px rgba(0,0,0,.5);
        }
        .board-card.control-foreign.control-foreign-blue{
            box-shadow:0 0 0 1px var(--blue),0 0 8px 1px var(--blue),0 1px 3px rgba(0,0,0,.5);
        }

        /* Source hand card dims while its drag ghost is in flight. */
        .hand-card.dragging{opacity:.4;}

        /* Cursor-following clone shown while dragging a hand card onto
           the board. Screen-space + fixed, so it never inherits the
           board's 180° flip. */
        .drag-ghost{
            position:fixed;
            height:130px;
            pointer-events:none;
            z-index:200;
            opacity:.85;
            transform:translate(-50%,-50%);
            border-radius:4px;
            box-shadow:0 4px 14px rgba(0,0,0,.6);
        }

        /* ── HOVER PREVIEW ───────────────────────────────── */
        /* Fixed to the vertical middle of the screen's left side,
           screen-space (never rotates with the board). One rule
           handles both shapes: a portrait card caps on height, a
           Support .landscape card caps on width. z-index sits above
           the board/hands but below the landing/pregame overlays
           (z 100) so it can't cover the pre-game UI. */
        .hover-preview{
            position:fixed;
            left:24px;
            top:50%;
            transform:translateY(-50%);
            max-height:min(70vh,600px);
            max-width:32vw;
            width:auto;
            height:auto;
            z-index:94;
            pointer-events:none;
            border-radius:6px;
            box-shadow:0 10px 36px rgba(0,0,0,.7),0 0 0 1px var(--border-2);
            background:var(--surface-2);
        }
        .hover-preview.landscape{
            max-height:min(46vh,420px);
            max-width:min(46vw,560px);
        }
        .hover-preview[hidden]{display:none!important;}

        /* ── CARD CONTEXT MENU ───────────────────────────── */
        /* Screen-space, fixed, pointer-anchored. Body-level sibling of
           the hover preview, OUTSIDE .board-scene so it never inherits
           the Blue 180° scene flip — it opens upright at the cursor for
           both seats. z 95: above the hover preview (94), below the
           landing/pregame overlays (100, hidden during play anyway).
           left/top are set inline by openCardMenu after a viewport
           clamp. */
        .ctx-menu{
            position:fixed;
            left:0;
            top:0;
            min-width:172px;
            padding:5px;
            z-index:95;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:8px;
            box-shadow:0 16px 44px rgba(0,0,0,.7),0 0 0 1px var(--border-2);
            font-size:13px;
            user-select:none;
        }
        .ctx-menu[hidden]{display:none!important;}
        .ctx-menu-item{
            padding:7px 14px;
            border-radius:5px;
            color:var(--text);
            cursor:pointer;
            white-space:nowrap;
            line-height:1.2;
        }
        .ctx-menu-item:hover{
            background:var(--accent-dim);
            color:var(--accent);
        }
        /* Divider between the gated verb rows and the single
           relationship-dependent control entry (step 7b). */
        .ctx-menu-sep{
            height:1px;
            margin:5px 6px;
            background:var(--border-2);
        }

        /* 9c: per-counter ctx-menu palette swatch row. Container is
           a flex strip inside #ctxMenu (which is already position:fixed
           body-level — see .ctx-menu above). 6 swatches × 24px + 5×4px
           gap + outer padding ≈ 168px row width, comfortably below
           .ctx-menu's min-width:172px so the row doesn't push the menu
           wider. Q3 α + α: direct visibility (no submenu) + single
           horizontal row. Built by openCounterMenu in 09-counters.js. */
        .ctx-menu-swatch-row{
            display:flex;
            gap:4px;
            padding:4px 6px;
        }
        .ctx-menu-swatch{
            width:24px;
            height:24px;
            border-radius:4px;
            cursor:pointer;
            border:1px solid var(--border-2);
            box-sizing:border-box;
        }
        .ctx-menu-swatch:hover{
            outline:2px solid var(--accent);
            outline-offset:1px;
        }
        /* is-current marks the swatch matching the counter's present
           color when the menu opens (set in openCounterMenu). Uses a
           --text outline (high-contrast against any palette hex)
           distinct from the --accent :hover outline above, so 'this
           is the current color' and 'this is the hover target' read
           differently. If the cursor hovers the current swatch, the
           :hover rule wins by source order — fine, both are valid
           affordances. */
        .ctx-menu-swatch.is-current{
            outline:2px solid var(--text);
            outline-offset:1px;
        }

        /* ── DISCARD VIEW PANEL (7c) ─────────────────────── */
        /* Screen-space, fixed, body-level sibling of #ctxMenu — OUTSIDE
           .board-scene so it never inherits the Blue 180° flip. z 93:
           above the hover preview (90), BELOW #ctxMenu (95) so the
           in-panel per-card pull menu (which reuses #ctxMenu) sits on
           top of the panel, and below the drag ghost (200) so a card
           dragged out of the panel floats above it. Public — either
           player can open either pile; the per-card pull
           menu/drag is wired only on your OWN pile (SD-1). */
        .discard-panel{
            position:fixed;
            left:50%;
            top:50%;
            transform:translate(-50%,-50%);
            z-index:93;
            max-width:min(86vw,720px);
            max-height:70vh;
            overflow-y:auto;
            padding:14px 16px 16px;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:10px;
            box-shadow:0 18px 50px rgba(0,0,0,.72),0 0 0 1px var(--border-2);
            user-select:none;
        }
        .discard-panel[hidden]{display:none!important;}
        .discard-panel-head{
            display:flex;
            align-items:baseline;
            justify-content:space-between;
            gap:18px;
            margin-bottom:12px;
            font-family:'Cinzel',serif;
            color:var(--text);
        }
        .discard-panel-title{font-size:15px;font-weight:700;letter-spacing:.04em;}
        .discard-panel-sub{font-size:12px;color:var(--text-dim);}
        .discard-panel-grid{
            display:flex;
            flex-wrap:wrap;
            gap:10px;
        }
        /* One card in the panel. Newest-on-top = first child. Own-pile
           cards get the pointer affordance (click → pull menu, drag →
           board/hand); opponent-pile cards are inert (view-only). */
        .discard-card{
            width:96px;
            height:auto;
            display:block;
            border-radius:5px;
            box-shadow:0 4px 12px rgba(0,0,0,.5);
            background:var(--surface-2);
        }
        .discard-card.pullable{cursor:pointer;}
        .discard-card.pullable:hover{
            box-shadow:0 0 0 2px var(--accent),0 4px 12px rgba(0,0,0,.5);
        }
        .discard-card.dragging{opacity:.4;}

        /* 7e: Search/Peek panel — a clone of the .discard-panel family
           on the same z-93 screen-space tier (the two are mutually
           exclusive so the shared tier is fine). PRIVATE: only ever
           shows YOUR OWN captured session (searchCards is own-side
           only). State-derived (Decision B): renderSearchPanel opens/
           re-renders/self-closes from the payload each state_update. */
        .search-panel{
            position:fixed;
            left:50%;
            top:50%;
            transform:translate(-50%,-50%);
            z-index:93;
            max-width:min(86vw,720px);
            max-height:70vh;
            overflow-y:auto;
            padding:14px 16px 16px;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:10px;
            box-shadow:0 18px 50px rgba(0,0,0,.72),0 0 0 1px var(--border-2);
            user-select:none;
        }
        .search-panel[hidden]{display:none!important;}
        .search-panel-head{
            display:flex;
            align-items:flex-start;
            justify-content:space-between;
            gap:18px;
            margin-bottom:12px;
            font-family:'Cinzel',serif;
            color:var(--text);
        }
        .search-panel-titles{display:flex;flex-direction:column;gap:3px;}
        .search-panel-title{font-size:15px;font-weight:700;letter-spacing:.04em;}
        .search-panel-sub{font-size:12px;color:var(--text-dim);}
        .search-panel-done{
            flex:0 0 auto;
            font:inherit;
            font-size:12px;
            letter-spacing:.04em;
            color:var(--text);
            background:var(--surface-2);
            border:1px solid var(--border-2);
            border-radius:6px;
            padding:5px 12px;
            cursor:pointer;
        }
        .search-panel-done:hover{box-shadow:0 0 0 2px var(--accent);}
        .search-panel-grid{
            display:flex;
            flex-wrap:wrap;
            gap:10px;
        }
        /* One card in the panel. Top-of-deck-first; always pullable
           (the panel is always your own — opponents never get one). */
        .search-card{
            width:96px;
            height:auto;
            display:block;
            border-radius:5px;
            box-shadow:0 4px 12px rgba(0,0,0,.5);
            background:var(--surface-2);
            cursor:pointer;
        }
        .search-card:hover{
            box-shadow:0 0 0 2px var(--accent),0 4px 12px rgba(0,0,0,.5);
        }
        .search-card.dragging{opacity:.4;}

        /* 7e: opponent Search/Peek status — a lightweight fixed line in
           the opponent-hand vicinity (top-center). PUBLIC, never
           cardIds; pointer-transparent so it never blocks the board. */
        .search-status{
            position:fixed;
            top:66px;
            left:50%;
            transform:translateX(-50%);
            z-index:80;
            font-family:'Cinzel',serif;
            font-size:12px;
            letter-spacing:.04em;
            color:var(--text);
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:6px;
            padding:5px 12px;
            box-shadow:0 6px 18px rgba(0,0,0,.5);
            pointer-events:none;
        }
        .search-status[hidden]{display:none!important;}

        /* 8a: click-to-pick attach mode. Banner mirrors .search-status
           (it is instruction text only → pointer-events:none) but sits
           just below it so an opponent's search status can co-exist, and
           carries an amber accent so the active pick mode reads clearly.
           The eligible-host highlight is an OUTLINE (not box-shadow) so
           it composes cleanly with the 7b control-foreign ring without
           fighting its box-shadow. */
        .attach-banner{
            position:fixed;
            top:96px;
            left:50%;
            transform:translateX(-50%);
            z-index:96;
            font-family:'Cinzel',serif;
            font-size:12px;
            letter-spacing:.04em;
            color:var(--text);
            background:var(--surface);
            border:1px solid #f5c542;
            border-radius:6px;
            padding:5px 12px;
            box-shadow:0 6px 18px rgba(0,0,0,.5);
            pointer-events:none;
        }
        .attach-banner[hidden]{display:none!important;}
        .board-card.attach-host-eligible{
            outline:3px solid #f5c542;
            outline-offset:1px;
            cursor:copy;
        }

        /* Either-seat clickable affordance on the discard piles (7c),
           distinct from .own-pile (deck-draw semantics + accent hover):
           a discard pile is a public View-Discard target for BOTH
           seats. */
        .pile.view-pile{cursor:pointer;}
        .pile.view-pile:hover{box-shadow:0 0 0 2px var(--accent),0 0.2% 0.6% rgba(0,0,0,.5);}

        /* ── LANDING OVERLAY ─────────────────────────────── */
        /* NOTE: overlay is opaque var(--bg) for now. Eventually the
           landing + pregame screens should sit on top of a dedicated
           background image (a logo / splash art) rather than the
           game board. See PLAYMAT_DESIGN.md §18. */
        .landing{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:var(--bg);
            z-index:100;
        }
        .landing[hidden]{display:none!important;}
        .landing-card{
            width:380px;
            max-width:calc(100vw - 40px);
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:12px;
            padding:32px 28px;
            box-shadow:0 20px 60px rgba(0,0,0,.6), 0 0 0 1px var(--accent-dim);
        }
        .landing-title{
            font-family:'Cinzel',serif;
            font-size:22px;
            font-weight:700;
            color:var(--accent);
            letter-spacing:.08em;
            text-align:center;
            margin-bottom:6px;
        }
        .landing-subtitle{
            font-size:11px;
            font-weight:500;
            color:var(--text-muted);
            letter-spacing:.18em;
            text-transform:uppercase;
            text-align:center;
            margin-bottom:24px;
        }

        .landing-btn{
            display:block;
            width:100%;
            padding:11px 16px;
            border-radius:8px;
            border:none;
            font-family:'DM Sans',sans-serif;
            font-size:13px;
            font-weight:600;
            cursor:pointer;
            transition:all .15s;
            letter-spacing:.02em;
        }
        .landing-btn.primary{
            background:var(--accent);
            color:#0c0800;
            margin-bottom:4px;
        }
        .landing-btn.primary:hover:not(:disabled){
            background:#d9bb60;
            box-shadow:0 0 14px var(--accent-glow);
        }
        .landing-btn.ghost{
            background:var(--surface-3);
            color:var(--text);
            border:1px solid var(--border-2);
        }
        .landing-btn.ghost:hover:not(:disabled){
            border-color:var(--accent);
            color:var(--accent);
        }
        .landing-btn:disabled{opacity:.45;cursor:not-allowed;}

        .landing-divider{
            display:flex;
            align-items:center;
            gap:12px;
            margin:18px 0;
        }
        .landing-divider::before,
        .landing-divider::after{
            content:'';
            flex:1;
            height:1px;
            background:var(--border);
        }
        .landing-divider span{
            font-size:10px;
            font-weight:600;
            letter-spacing:.18em;
            text-transform:uppercase;
            color:var(--text-muted);
        }

        .landing-join{
            display:flex;
            gap:8px;
        }
        .landing-input{
            flex:1;
            padding:11px 14px;
            background:var(--surface-3);
            border:1px solid var(--border-2);
            border-radius:8px;
            color:var(--text);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
            letter-spacing:.02em;
        }
        .landing-input::placeholder{color:var(--text-muted);}
        .landing-input:focus{outline:none;border-color:var(--accent);}
        .landing-join .landing-btn{width:auto;padding:11px 18px;margin:0;}

        .landing-error{
            margin-top:14px;
            padding:8px 12px;
            background:var(--red-dim);
            color:var(--red);
            border:1px solid rgba(224,92,106,.25);
            border-radius:6px;
            font-size:12px;
            text-align:center;
        }
        .landing-error[hidden]{display:none!important;}

        .landing-status{
            margin-top:18px;
            text-align:center;
            font-size:12px;
            color:var(--text-dim);
        }
        .landing-status[hidden]{display:none!important;}

        /* ── PREGAME OVERLAY ─────────────────────────────── */
        /* Same opaque treatment as .landing — see note above. */
        .pregame{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:var(--bg);
            z-index:90;
        }

        /* OD-S2b: opponent-disconnected “waiting…” veil. Play-only,
           look-only DIMMED scrim over the board area (fills .playmat-area
           like .landing / .pregame, OUTSIDE .board-scene → no 180° flip).
           pointer-events:none so pan, zoom, and the hover-preview pass
           straight through — this blocks nothing (presentation only).
           z-index 55: above the board, below the screen-space controls
           (recenter-btn 60, hover-preview 90, menus 93–96) so inspection
           UI stays crisp above the dim. */
        .disconnect-veil{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.62);
            pointer-events:none;
            z-index:55;
        }
        .disconnect-veil[hidden]{display:none!important;}
        .disconnect-veil-msg{
            font-family:'Cinzel',serif;
            font-size:1.6rem;
            font-weight:600;
            letter-spacing:0.04em;
            color:#f4f1ea;
            background:rgba(8,11,20,0.85);
            border:1px solid var(--border);
            border-radius:12px;
            padding:18px 32px;
            box-shadow:0 8px 40px rgba(0,0,0,0.6);
        }
        /* 10-C: SELF-disconnect veil -- BLOCKING scrim (pointer-events:auto),
           distinct from the look-only .disconnect-veil peer veil. */
        .self-disconnect-veil{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.78);
            pointer-events:auto;
            z-index:60;
        }
        .self-disconnect-veil[hidden]{display:none!important;}
        /* F8-d: BLOCKING "Loading decks..." cover during own-deck image
           preload at the play transition. Same scrim model as the
           self-disconnect veil; created in JS, appended to .playmat-area. */
        .deck-preload-veil{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.78);
            pointer-events:auto;
            z-index:60;
        }
        .deck-preload-veil[hidden]{display:none!important;}
        .deck-preload-msg{
            color:#e8ecf5;
            font-size:1.1rem;
            letter-spacing:0.02em;
        }
        .self-disconnect-card{
            display:flex;
            flex-direction:column;
            align-items:center;
            gap:18px;
            background:rgba(8,11,20,0.92);
            border:1px solid var(--border);
            border-radius:12px;
            padding:24px 36px;
            box-shadow:0 8px 40px rgba(0,0,0,0.6);
        }
        .self-disconnect-msg{
            font-family:'Cinzel',serif;
            font-size:1.5rem;
            font-weight:600;
            letter-spacing:0.04em;
            color:#f4f1ea;
            text-align:center;
        }
        .self-disconnect-actions{
            display:flex;
            gap:12px;
        }
        .self-disconnect-btn{
            font-family:'Cinzel',serif;
            font-size:0.95rem;
            font-weight:600;
            letter-spacing:0.03em;
            color:#f4f1ea;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:8px;
            padding:10px 20px;
            cursor:pointer;
        }
        .self-disconnect-btn:hover{
            border-color:var(--border);
        }
        /* F13-d d-1: Concede control (bottom-right screen-space button,
           sibling of .recenter-btn/.help-btn). z-60 like them -> BEHIND the
           z-71 game-over scrim. Greyed while disabled (veiled / decided). */
        .concede-btn{
            position:absolute;
            right:12px;
            bottom:12px;
            z-index:60;
            font-family:'Cinzel',serif;
            font-size:0.9rem;
            font-weight:600;
            letter-spacing:0.03em;
            color:#f4f1ea;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:8px;
            padding:8px 16px;
            cursor:pointer;
        }
        .concede-btn:hover{ border-color:var(--border); }
        .concede-btn:disabled{ opacity:0.4; cursor:default; }
        .concede-btn[hidden]{ display:none!important; }
        /* F13-d d-1: game-over end screen. Blocking scrim modeled on
           .self-disconnect-veil, but z-71: ABOVE .progress-widget (z-70) +
           .concede-btn (z-60), BELOW .chatlog-popup (z-72). */
        .gameover-veil{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.78);
            pointer-events:auto;
            z-index:71;
        }
        .gameover-veil[hidden]{display:none!important;}
        .gameover-card{
            display:flex;
            flex-direction:column;
            align-items:center;
            gap:18px;
            background:rgba(8,11,20,0.92);
            border:1px solid var(--border);
            border-radius:12px;
            padding:24px 36px;
            box-shadow:0 8px 40px rgba(0,0,0,0.6);
        }
        .gameover-msg{
            font-family:'Cinzel',serif;
            font-size:1.7rem;
            font-weight:600;
            letter-spacing:0.04em;
            color:#f4f1ea;
            text-align:center;
        }
        .gameover-actions{
            display:flex;
            gap:12px;
        }
        .gameover-btn{
            font-family:'Cinzel',serif;
            font-size:0.95rem;
            font-weight:600;
            letter-spacing:0.03em;
            color:#f4f1ea;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:8px;
            padding:10px 20px;
            cursor:pointer;
        }
        .gameover-btn:hover{ border-color:var(--border); }
        .gameover-btn:disabled{ opacity:0.4; cursor:default; }
        .gameover-note{
            font-family:'DM Sans',sans-serif;
            font-size:0.78rem;
            color:var(--text-dim);
            text-align:center;
            margin-top:-4px;
            max-width:280px;
        }
        /* CT-1: coin-toss modal. Cloned from .gameover-veil; z-71 so it sits
           ABOVE the disconnect veils (z-55/60) + progress widget (z-70) and
           BELOW the chat popup (z-72) -- "nothing else matters, but you can
           still chat". gameover + coin-toss never co-occur (Start vs end), so
           sharing z-71 is safe (the disconnect veils share z-60 likewise). */
        .cointoss-veil{
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.78);
            pointer-events:auto;
            z-index:71;
        }
        .cointoss-veil[hidden]{display:none!important;}
        .cointoss-card{
            display:flex;
            flex-direction:column;
            align-items:center;
            gap:18px;
            background:rgba(8,11,20,0.92);
            border:1px solid var(--border);
            border-radius:12px;
            padding:24px 36px;
            box-shadow:0 8px 40px rgba(0,0,0,0.6);
            max-width:440px;
        }
        .cointoss-msg{
            font-family:'Cinzel',serif;
            font-size:1.3rem;
            font-weight:600;
            letter-spacing:0.04em;
            color:#f4f1ea;
            text-align:center;
            line-height:1.4;
        }
        .cointoss-actions{
            display:flex;
            gap:12px;
        }
        .cointoss-actions[hidden]{display:none!important;}
        .cointoss-btn{
            font-family:'Cinzel',serif;
            font-size:0.95rem;
            font-weight:600;
            letter-spacing:0.03em;
            color:#f4f1ea;
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:8px;
            padding:10px 28px;
            cursor:pointer;
        }
        .cointoss-btn:hover{ border-color:var(--border); }
        .pregame[hidden]{display:none!important;}
        .pregame-card{
            position:relative;
            width:440px;
            max-width:calc(100vw - 40px);
            background:var(--surface);
            border:1px solid var(--border-2);
            border-radius:12px;
            padding:28px 28px 24px;
            box-shadow:0 20px 60px rgba(0,0,0,.6), 0 0 0 1px var(--accent-dim);
        }
        .pregame-lobby-btn{
            position:absolute;
            top:16px;
            left:16px;
            background:none;
            border:none;
            color:var(--text-dim);
            font-family:'DM Sans',sans-serif;
            font-size:12px;
            letter-spacing:.02em;
            cursor:pointer;
            padding:2px 4px;
        }
        .pregame-lobby-btn:hover{ color:var(--text); }
        .pregame-title{
            font-family:'Cinzel',serif;
            font-size:18px;
            font-weight:700;
            color:var(--accent);
            letter-spacing:.14em;
            text-align:center;
            margin-bottom:4px;
        }
        .pregame-subtitle{
            font-size:11px;
            font-weight:500;
            color:var(--text-muted);
            letter-spacing:.12em;
            text-transform:uppercase;
            text-align:center;
            margin-bottom:22px;
        }
        /* SS-1: pregame login control */
        .pregame-auth{
            display:flex;
            align-items:center;
            justify-content:center;
            gap:10px;
            font-size:12px;
            color:var(--text-muted);
            margin-bottom:18px;
        }
        .pregame-auth .pregame-auth-name{ color:var(--text); }
        .pregame-auth .pregame-auth-btn{
            display:inline-block;
            width:auto;
            padding:6px 14px;
            font-size:12px;
        }
        .pregame-section{margin-bottom:16px;}
        .pregame-label{
            font-size:10px;
            font-weight:600;
            letter-spacing:.14em;
            text-transform:uppercase;
            color:var(--text-muted);
            margin-bottom:8px;
        }
        .pregame-deck-input{display:flex;gap:8px;}
        .pregame-deck-input[hidden]{display:none!important;}
        .pregame-btn-inline{width:auto!important;padding:11px 18px!important;margin:0!important;}
        .pregame-deck-preview{
            display:flex;
            align-items:center;
            justify-content:space-between;
            gap:12px;
            padding:11px 14px;
            background:var(--surface-3);
            border:1px solid var(--accent-dim);
            border-left:3px solid var(--accent);
            border-radius:8px;
        }
        .pregame-deck-preview[hidden]{display:none!important;}
        .pregame-deck-info{flex:1;min-width:0;}
        .pregame-deck-name{
            font-family:'Cinzel',serif;
            font-size:14px;
            color:var(--text);
            overflow:hidden;
            text-overflow:ellipsis;
            white-space:nowrap;
        }
        .pregame-deck-counts{
            font-size:11px;
            color:var(--text-dim);
            margin-top:3px;
        }
        .pregame-deck-change{
            flex-shrink:0;
            font-size:11px;
            padding:5px 11px;
            background:transparent;
            border:1px solid var(--border-2);
            color:var(--text-dim);
            border-radius:5px;
            cursor:pointer;
            font-family:inherit;
            transition:all .15s;
        }
        .pregame-deck-change:hover:not(:disabled){
            color:var(--text);
            border-color:var(--text-dim);
        }
        .pregame-deck-change:disabled{opacity:.4;cursor:not-allowed;}
        .pregame-error{
            margin-top:8px;
            padding:7px 11px;
            background:var(--red-dim);
            color:var(--red);
            border:1px solid rgba(224,92,106,.25);
            border-radius:6px;
            font-size:12px;
        }
        .pregame-error[hidden]{display:none!important;}

        .pregame-opponent-wrap{
            margin:18px 0 14px;
            text-align:center;
        }
        .pregame-opponent{
            display:inline-flex;
            align-items:center;
            gap:8px;
            font-size:12px;
            color:var(--text-dim);
            padding:6px 14px;
            background:var(--surface-3);
            border:1px solid var(--border);
            border-radius:20px;
        }
        .pregame-opponent::before{
            content:'';
            display:inline-block;
            width:8px;
            height:8px;
            border-radius:50%;
            background:var(--text-muted);
        }
        .pregame-opponent.disconnected{
            color:var(--red);
            border-color:rgba(224,92,106,.25);
        }
        .pregame-opponent.disconnected::before{
            background:var(--red);
            box-shadow:0 0 6px rgba(224,92,106,.6);
        }
        .pregame-opponent.deck-loaded::before{
            background:var(--accent);
            box-shadow:0 0 6px var(--accent-glow);
        }
        .pregame-opponent.ready{
            color:var(--green);
            border-color:rgba(62,207,130,.25);
        }
        .pregame-opponent.ready::before{
            background:var(--green);
            box-shadow:0 0 6px rgba(62,207,130,.6);
        }
        .pregame-waiting{
            margin-top:12px;
            text-align:center;
            font-size:12px;
            color:var(--text-muted);
            font-style:italic;
        }
        .pregame-waiting[hidden]{display:none!important;}

        /* ── Step 9: ownerless counter discs ───────────────────────── */
        /* Counter layer overlays the game-render-layer (z:50). Counters
           paint at z:51, above cards. The layer itself doesn't trap
           pointer events (so card hit-tests below it still work); each
           disc opts back in with pointer-events:auto. */
        #boardCounters{
            position:absolute;
            inset:0;
            pointer-events:none;
            z-index:51;
        }
        .counter{
            position:absolute;
            /* Disc width is % of .board-scene (48"-wide). 1.5% ≈ 0.72"
               disc; revisit at zoom (Step 13). */
            width:1.5%;
            aspect-ratio:1 / 1;
            /* Stored x,y is the disc center; translate -50% centers it. */
            transform:translate(-50%, -50%);
            border-radius:50%;
            display:flex;
            align-items:center;
            justify-content:center;
            pointer-events:auto;
            /* 9b: grab affordance signals draggable; switch to grabbing
               handled inline in startCounterDrag (CSS :active is brittle
               under inline pointer-events:none used for hit-test
               transparency during drag). */
            cursor:grab;
            color:#000;
            font-weight:700;
            user-select:none;
            box-shadow:0 0.2% 0.6% rgba(0,0,0,.5);
            /* Tie inner font-size to the disc's own width via
               container-query units (.counter-value uses 60cqw). */
            container-type:inline-size;
        }
        /* Blue viewer: cancel the .board-scene.flip on the disc only,
           so position mirrors 180° but the number stays upright. */
        .counter.blue-view{
            transform:translate(-50%, -50%) rotate(180deg);
        }
        .counter-value{
            font-size:60cqw;
            line-height:1;
        }
        /* 9b: universal hit-test transparency during any counter drag.
           Toggled inline via boardCounters.classList in startCounterDrag /
           onDragUp counter branch (08-interaction.js). Overrides the
           per-disc pointer-events:auto in .counter so elementFromPoint
           at drop resolves to the card beneath, never to a non-dragged
           counter sitting on top of the card. Outside an in-flight
           counter drag, all .counter discs retain pointer-events:auto
           for 9c per-counter ctx-menu and +/− interactions. */
        #boardCounters.dragging-counters .counter{
            pointer-events:none;
        }
        /* 9b PC-1 (PLAN-CORRECTION at live-test step 2): Q4a's inline
           counterEl.style.cursor='grabbing' is bypassed because the
           disc carries pointer-events:none during drag — when an
           element is pointer-events:none, the browser does NOT use
           its cursor style; the cursor falls through to whatever layer
           is underneath (the .board-scene / .playmat-area / body, none
           of which have cursor rules; result: default arrow shown).
           Fix: a body class toggled at startCounterDrag / onDragUp
           counter branch, with a universal-selector !important rule so
           grabbing is forced regardless of which layer is currently
           hit-receiving. !important is required because per-element
           cursor rules (.board-card.controllable, etc.) would otherwise
           win for elements under the cursor during drag. Scoped to the
           drag duration only via the classList toggle. */
        body.is-dragging-counter,
        body.is-dragging-counter *{
            cursor:grabbing !important;
        }

        /* 9c: +/− buttons on disc (Q2 β-edge: minus at left edge,
           plus at right edge). Hover-revealed via .counter:hover
           selector (no JS hover-state tracking). Default opacity:0
           + pointer-events:none keeps them inert when not hovered.
           Sizing Q6a γ (PC-1 retuned at live-test step 2 — original
           clamp(14px, 30%, 32px) obscured the disc at base-zoom small
           viewport widths; user-confirmed via screenshot diagnosis):
           clamp(6px, 22%, 20px) — 6px floor preserves a clickable target
           at base zoom on small viewports (disc ≈ 12–20px → button
           30–50% only at tiny base, dropping fast as zoom rises);
           scales to 22% of disc at mid+ zoom; 20px ceiling at high
           zoom (≤14% of a max-zoom disc) so buttons stay subtle and
           Position:absolute against .counter; translate centers
           the button on the disc edge so half the button is inside
           the disc and half is outside. line-height:1 + flex centers
           the glyph regardless of clamp size. cursor:pointer
           overrides the parent .counter's cursor:grab while hover
           is over the button itself (not the disc body). The Q5/Q6
           is-dragging-counter universal cursor rule above wins
           during counter-drag — but during drag the parent .counter
           is pointer-events:none anyway so the buttons can't be
           interacted with then (inherits the disc's pointer-events
           neutralization). */
        .counter-btn{
            position:absolute;
            top:50%;
            width:clamp(6px, 22%, 20px);
            height:clamp(6px, 22%, 20px);
            border-radius:50%;
            background:var(--surface);
            border:1px solid var(--border-2);
            color:var(--text);
            display:flex;
            align-items:center;
            justify-content:center;
            font-weight:700;
            line-height:1;
            cursor:pointer;
            opacity:0;
            pointer-events:none;
            transition:opacity 0.08s ease-out;
            user-select:none;
            font-size:0.55em;
        }
        .counter-btn-minus{
            left:0;
            transform:translate(-50%, -50%);
        }
        .counter-btn-plus{
            right:0;
            transform:translate(50%, -50%);
        }
        /* Hover-reveal. .counter:hover gates BOTH buttons (and the
           wheel listener Q5 has its own gate). pointer-events:auto
           is the second axis — without it, opacity:1 buttons would
           still be click-through. */
        .counter:hover .counter-btn{
            opacity:1;
            pointer-events:auto;
        }
        /* Blue viewer: the .counter.blue-view rule rotates the disc
           180° so the value glyph stays upright (cancels the
           .board-scene's 180° flip applied to Blue's whole board
           view). The +/− buttons inherit BOTH rotations — the scene's
           180° (via .board-scene as a transformed ancestor) AND the
           disc's own 180° (via .counter directly). Two 180°s compose
           to identity for the buttons' screen-coord positions, so
           minus stays on screen-LEFT and plus on screen-RIGHT for
           both seats. The counter's BOARD-COORD POSITION mirrors
           (the desired Blue 180° perspective), but the INTERNAL DISC
           LAYOUT (which side the buttons sit on) does not. No
           additional Blue-specific rule needed — the symmetric
           β-edge layout reads correctly under flip because the two
           rotations cancel for the disc's children. Corrected at 9d
           PLAN (the prior text here described a single-rotation
           model and incorrectly predicted minus would swap to right
           for Blue). */

        /* ── Step 13: pan / zoom / hand peek ───────────────────────── */
        /* Wrapper inserted between .playmat-area and .board-scene. Fills
           the playmat-area's content-box; inherits the centering by being
           a flex container that centers .board-scene; the static transform
           is JS-mutated by js/10-panzoom.js. transform-origin at 0 0 so
           the cursor-anchored zoom math (which adjusts pan to keep the
           cursor's wrapper-local point stable) composes cleanly. */
        .pan-zoom-viewport{
            width:100%;
            height:100%;
            display:flex;
            align-items:center;
            justify-content:center;
            transform-origin:0 0;
            transform:translate(0px,0px) scale(1);
        }
        /* Step 13 own-hand peek (Q5=C, Arena-style overlay): take .hand-row
           out of body's flex flow so .playmat-area fills the remaining
           vertical space; .hand-row absolutely overlays the bottom 130px
           of .playmat-area when expanded. Default is translated 67% down
           so the top ~33% of cards peeks above the body's bottom edge
           (the bottom 67% clipped by body's overflow:hidden, anchored by
           body's position:relative from C13a-2). 150ms ease animates the
           slide in both directions. The existing .hand-row, .opp-hand-row
           shared rule (line 128) sets position:relative for both rows;
           this rule's later position:absolute wins for .hand-row only via
           same-specificity-later-wins cascade, leaving .opp-hand-row
           position:relative and in flex flow. The hand-card pointerdown
           handler (04-render.js renderHands) fires on the visible top
           strip of a collapsed card — existing hand→board drag runs
           unchanged, no auto-expand on pointerdown per Q5g. */
        .hand-row{
            position:absolute;
            left:0;
            right:0;
            bottom:0;
            transform:translateY(67%) scale(var(--own-hand-scale));
            transition:transform 150ms ease;
        }
        /* JS toggles .expanded on mouseenter; clears it after a 100ms-
           delayed mouseleave timer (flicker-guard for quick exits and
           re-entries). */
        .hand-row.expanded{
            transform:translateY(0) scale(var(--own-hand-scale));
        }
        /* ── Step 13b: recenter button ───────────────────────────────
           Screen-space button anchored top-right of .playmat-area, OUTSIDE
           .pan-zoom-viewport so it never inherits the wrapper transform.
           Click handler in js/10-panzoom.js resets boardScale/PanX/PanY to
           defaults; hand scale and hand-expanded state independent per
           §A2 Q5d. z:60 sits above .pan-zoom-viewport but below landing /
           pregame overlays (z:90+) so it's correctly occluded during non-
           play phases without needing JS-managed visibility. */
        .recenter-btn{
            position:absolute;
            top:12px;
            right:12px;
            width:36px;
            height:36px;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.75);
            color:#c9a84c;
            border:1px solid #c9a84c;
            border-radius:6px;
            font-size:20px;
            line-height:1;
            cursor:pointer;
            z-index:60;
            transition:background 120ms ease, transform 80ms ease;
        }
        .recenter-btn:hover{ background:rgba(8,11,20,0.95); }
        .recenter-btn:active{ transform:scale(0.96); }

        /* ── F8-c: help button + landing link + help overlay ─────────
           .help-btn is a screen-space sibling of .recenter-btn (same look),
           sat just left of it. The overlay is a fixed full-screen modal above
           every in-board menu (z:120). Visual language matches the deck-builder
           / landing: #080b14 ground, #c9a84c gold, Cinzel titles, DM Sans body. */
        .help-btn{
            position:absolute;
            top:12px;
            right:54px;
            width:36px;
            height:36px;
            display:flex;
            align-items:center;
            justify-content:center;
            background:rgba(8,11,20,0.75);
            color:#c9a84c;
            border:1px solid #c9a84c;
            border-radius:6px;
            font-size:20px;
            font-weight:600;
            line-height:1;
            cursor:pointer;
            z-index:60;
            transition:background 120ms ease, transform 80ms ease;
        }
        .help-btn:hover{ background:rgba(8,11,20,0.95); }
        .help-btn:active{ transform:scale(0.96); }

        .landing-help{
            margin-top:18px;
            background:none;
            border:none;
            color:#c9a84c;
            font-family:'DM Sans',sans-serif;
            font-size:13px;
            text-decoration:underline;
            text-underline-offset:3px;
            cursor:pointer;
            opacity:0.85;
        }
        .landing-help:hover{ opacity:1; }

        .help-overlay{
            position:fixed;
            inset:0;
            z-index:120;
            display:flex;
            align-items:center;
            justify-content:center;
        }
        .help-overlay[hidden]{ display:none; }
        .help-backdrop{
            position:absolute;
            inset:0;
            background:rgba(4,6,12,0.78);
        }
        .help-card{
            position:relative;
            width:min(560px,92vw);
            max-height:84vh;
            overflow-y:auto;
            background:#080b14;
            border:1px solid #c9a84c;
            border-radius:10px;
            padding:24px 26px 26px;
            box-shadow:0 18px 60px rgba(0,0,0,0.6);
        }
        .help-close{
            position:absolute;
            top:12px;
            right:12px;
            width:30px;
            height:30px;
            background:rgba(8,11,20,0.75);
            color:#c9a84c;
            border:1px solid #c9a84c;
            border-radius:6px;
            font-size:15px;
            line-height:1;
            cursor:pointer;
        }
        .help-close:hover{ background:rgba(8,11,20,0.95); }
        .help-title{
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:22px;
            color:#c9a84c;
            margin:0 0 14px;
            letter-spacing:0.04em;
        }
        .help-section-label{
            font-family:'Cinzel',serif;
            font-weight:600;
            font-size:13px;
            color:#c9a84c;
            text-transform:uppercase;
            letter-spacing:0.08em;
            margin:18px 0 8px;
            border-bottom:1px solid rgba(201,168,76,0.3);
            padding-bottom:4px;
        }
        .help-keywords{
            font-family:'DM Sans',sans-serif;
            font-size:14px;
            color:#e6e6e6;
        }
        .help-kw-row{
            padding:7px 0;
            border-bottom:1px solid rgba(255,255,255,0.06);
        }
        .help-kw-row:last-child{ border-bottom:none; }
        .help-kw-term{ color:#c9a84c; font-weight:600; }
        .help-kw-def{ color:#cfd3da; }
        .help-empty{
            color:#8a8f99;
            font-style:italic;
            padding:7px 0;
        }
        .help-more{
            font-family:'DM Sans',sans-serif;
            font-size:14px;
        }
        .help-more-row{ padding:7px 0; }
        .help-soon{ color:#8a8f99; }

        /* ── F4: drag-to-zone drop affordance (M2) ─────────────────
           While you drag one of YOUR cards, your own zones light up as drop
           targets: JS adds .drop-eligible to your discard, both decks, and
           (board drag only) the hand row, cleared at drag end. Empty piles are
           hidden by renderGame (.pile[hidden]); .drop-eligible overrides that
           so a first discard / emptied deck still shows a target on its painted
           slot. A CSS-glyph drop-symbol marks each: a "Forget" tray on the
           Forgotten pile (.view-pile), a "Top/Bottom" tag on the decks
           (.own-pile) flipped by body.drag-to-bottom (the M1 right-click
           toggle). The piles sit inside .board-scene, so undo Blue's 180° flip
           on the glyph exactly as .pile.owner-blue .pile-count does. ADD-ONLY. */
        .pile.drop-eligible{
            outline:0.3% dashed var(--accent);
            box-shadow:0 0 0 0.4% var(--accent), 0 0 2% 0.6% var(--accent);
            z-index:2;
            /* F4 polish: scope a query container onto the drag-active pile ONLY
               (a resting pile is unaffected — .drop-eligible is added/cleared by
               the drag) so the ::after label sizes in cqw = % of THIS pile's
               width and tracks the card at any zoom. inline-size containment
               only; no paint clip, so the glow box-shadow still shows. */
            container-type:inline-size;
        }
        .pile.drop-eligible[hidden]{
            display:block!important;   /* reveal an empty target on its slot */
            opacity:.7;
        }
        .pile.drop-eligible::after{
            content:'';
            position:absolute;
            inset:0;
            display:flex;
            align-items:center;
            justify-content:center;
            text-align:center;
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:16cqw;           /* F4 polish: % of pile WIDTH → reliably fits the card */
            line-height:1.05;          /* F4 polish: tight, the glyph + word now stack on 2 lines */
            color:var(--accent);
            background:rgba(8,11,20,.72);
            border-radius:inherit;
            pointer-events:none;
            white-space:pre;           /* preserves the \A line break between glyph and word */
            overflow:hidden;           /* F4 polish: hard backstop — a label can NEVER bleed onto a neighbour */
            box-sizing:border-box;
            padding:3% 2%;             /* F4 polish: margin to spare inside the card */
        }
        .pile.drop-eligible.view-pile::after{ content:'\21AC\A Forget'; }   /* ↬ above "Forget" */
        .pile.drop-eligible.own-pile::after{ content:'Top\A\2191'; }   /* "Top" above ↑ */
        body.drag-to-bottom .pile.drop-eligible.own-pile::after{ content:'\2193\A Bottom'; }   /* ↓ above "Bottom" */
        .pile.owner-blue.drop-eligible::after{ transform:rotate(180deg); }

        /* board->hand target: the hand row is screen-space (outside
           .board-scene, no flip). */
        .hand-row.drop-eligible{ box-shadow:inset 0 0 0 2px var(--accent); }

        /* ── F13-a: chat/log pop-up ───────────────────
           Screen-space, bottom-left, riding above the hand row inside
           .playmat-area (OUTSIDE .pan-zoom-viewport). z-index 70: ABOVE
           the z-60 self-disconnect veil (chat works while veiled) and
           BELOW the z-100 landing/pregame overlays (covered in pregame,
           revealed in play -- no reveal hook). Two tabs, separate
           scrolls; collapsed = a launcher + a fading peek. */
        .chatlog-popup{
            position:absolute; left:12px; bottom:12px; z-index:72;
            font-family:'DM Sans',system-ui,sans-serif;
            color:var(--text,#e8e3d4);
            display:flex; flex-direction:column; align-items:flex-start; gap:6px;
            pointer-events:none;
        }
        .chatlog-popup .cl-collapsed,
        .chatlog-popup .cl-panel{ pointer-events:auto; }
        .chatlog-popup.expanded .cl-collapsed{ display:none; }
        .cl-collapsed{ position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:6px; }
        .cl-collapsed[hidden]{ display:none; }
        .cl-launcher{
            display:inline-flex; align-items:center; gap:6px;
            background:rgba(8,11,20,0.75); color:#c9a84c;
            border:1px solid #c9a84c; border-radius:6px;
            padding:6px 12px; font-size:13px; line-height:1; cursor:pointer;
            transition:background 120ms ease;
        }
        .cl-launcher:hover{ background:rgba(8,11,20,0.95); }
        .cl-dot{ width:8px; height:8px; border-radius:50%; background:#c9a84c; }
        .cl-dot[hidden]{ display:none; }
        .cl-peek{
            max-width:300px; background:rgba(8,11,20,0.92);
            border:1px solid var(--border,#2a2f3a); border-radius:6px;
            padding:6px 10px; font-size:13px; line-height:1.35;
            white-space:pre-wrap; word-break:break-word;
            opacity:0; pointer-events:none;
        }
        .cl-peek.show{ opacity:1; }
        .cl-peek.fade{ opacity:0; transition:opacity 5s linear; }
        .cl-panel{
            width:320px; height:340px; display:flex; flex-direction:column;
            background:rgba(8,11,20,0.95);
            border:1px solid #c9a84c; border-radius:8px; overflow:hidden;
        }
        .cl-panel[hidden]{ display:none; }
        .cl-tabs{ display:flex; align-items:stretch; border-bottom:1px solid var(--border,#2a2f3a); }
        .cl-tab{
            flex:1; display:inline-flex; align-items:center; justify-content:center; gap:6px;
            background:transparent; color:var(--text-muted,#8a8f9a); border:0;
            padding:8px 10px; font-size:13px; cursor:pointer; border-bottom:2px solid transparent;
        }
        .cl-tab.active{ color:#c9a84c; border-bottom-color:#c9a84c; }
        .cl-tabdot{ width:7px; height:7px; border-radius:50%; background:#c9a84c; }
        .cl-tabdot[hidden]{ display:none; }
        .cl-min{ background:transparent; color:var(--text-muted,#8a8f9a); border:0; padding:0 12px; font-size:14px; cursor:pointer; }
        .cl-min:hover{ color:#c9a84c; }
        .cl-body{ flex:1; min-height:0; display:flex; }
        .cl-scroll{
            flex:1; min-height:0; overflow-y:auto; padding:8px 10px;
            font-size:13px; line-height:1.4; display:flex; flex-direction:column; gap:4px;
        }
        .cl-scroll[hidden]{ display:none; }
        .cl-line{ word-break:break-word; }
        .cl-who{ font-weight:600; margin-right:6px; }
        .cl-who-red{ color:#d9544f; }
        .cl-who-blue{ color:#4f8bd9; }
        .cl-text{ white-space:pre-wrap; }
        .cl-inputrow{ display:flex; gap:6px; padding:8px; border-top:1px solid var(--border,#2a2f3a); }
        .cl-inputrow[hidden]{ display:none; }
        .cl-input{
            flex:1; background:rgba(255,255,255,0.04);
            border:1px solid var(--border,#2a2f3a); border-radius:5px;
            color:var(--text,#e8e3d4); padding:6px 8px; font-size:13px; font-family:inherit;
        }
        .cl-input:focus{ outline:none; border-color:#c9a84c; }
        .cl-send{
            background:#c9a84c; color:#0b0e16; border:0; border-radius:5px;
            padding:6px 12px; font-size:13px; cursor:pointer; font-family:inherit;
        }
        .cl-send:hover{ background:#d8b95a; }
        /* F13-a-2: public log line -- visually distinct from chat (no
           who-chip; muted, slightly indented). */
        .cl-logline{ color:#9fb0c8; font-style:italic; padding-left:2px; }
        .cl-logline .cl-text{ font-style:italic; }
        .cl-logline-private{ color:#d8c98a; padding-left:6px; border-left:2px solid #6a5d2a; }
        .cl-logline-private .cl-text{ font-style:italic; }
        /* F13-b: progress widget. Screen-space, top-left of .playmat-area
           (mirrors .chatlog-popup bottom-left), z-70 above the z-60 veil
           (visible while veiled) + below z-100 overlays (hidden in
           pregame). Opponent's row above yours; border in the SEAT
           colour. Only your row shows +/- (opponent buttons [hidden]).
           ADD-ONLY. */
        .progress-widget{
            position:absolute; left:12px; top:12px; z-index:70;
            display:flex; flex-direction:column; gap:6px;
            pointer-events:none;
        }
        .progress-widget[hidden]{ display:none; }
        .pw-row{
            display:flex; align-items:center; justify-content:center; gap:8px;
            padding:4px 8px; border-radius:8px; pointer-events:auto;
            background:rgba(8,11,20,0.78); color:#e7ecf5;
            font:600 18px/1 system-ui,sans-serif;
        }
        .pw-row.owner-red{  border:2px solid var(--red); }
        .pw-row.owner-blue{ border:2px solid var(--blue); }
        .pw-val{ min-width:54px; text-align:center; }
        .pw-btn{
            width:26px; height:26px; line-height:24px; text-align:center;
            border-radius:6px; cursor:pointer; padding:0;
            border:1px solid #444b5c; background:#1a2030; color:#e7ecf5;
            font:600 16px/1 system-ui,sans-serif;
        }
        .pw-btn:hover{ background:#232b40; }
        .pw-btn[hidden]{ display:none; }
        /* F13-c: pass-turn control (below both rows) + active-seat glow. */
        .pw-turn-btn{
            pointer-events:auto; cursor:pointer; padding:5px 10px;
            border-radius:8px; border:1px solid #444b5c;
            background:#1a2030; color:#e7ecf5; text-align:center;
            font:600 15px/1 system-ui,sans-serif;
        }
        .pw-turn-btn:hover:not(:disabled){ background:#232b40; }
        .pw-turn-btn:disabled,
        .pw-turn-btn.inert{
            cursor:default; opacity:0.55; background:rgba(8,11,20,0.78);
        }
        .pw-row.owner-red.active{  box-shadow:0 0 0 1px var(--red),  0 0 10px 2px var(--red);  }
        .pw-row.owner-blue.active{ box-shadow:0 0 0 1px var(--blue), 0 0 10px 2px var(--blue); }

        /* ── SS-2: pregame deck browser ─────────────────────────────
           A pregame-only deck picker (Precons/Public/Mine tabs + search
           + rows), JS-created in 12-deckbrowser.js and modeled on
           .help-overlay; z-98 sits above the pregame card (z-90). */
        .db-overlay{
            position:fixed;
            inset:0;
            z-index:98;
            display:flex;
            align-items:center;
            justify-content:center;
        }
        .db-overlay[hidden]{ display:none; }
        .db-backdrop{
            position:absolute;
            inset:0;
            background:rgba(4,6,12,0.78);
        }
        .db-card{
            position:relative;
            width:min(560px,92vw);
            max-height:84vh;
            display:flex;
            flex-direction:column;
            background:var(--surface);
            border:1px solid var(--accent);
            border-radius:10px;
            padding:22px 22px 18px;
            box-shadow:0 18px 60px rgba(0,0,0,0.6);
        }
        .db-close{
            position:absolute;
            top:12px; right:12px;
            width:30px; height:30px;
            background:rgba(8,11,20,0.75);
            color:var(--accent);
            border:1px solid var(--accent);
            border-radius:6px;
            font-size:15px; line-height:1;
            cursor:pointer;
        }
        .db-close:hover{ background:rgba(8,11,20,0.95); }
        .db-title{
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:20px;
            color:var(--accent);
            margin:0 0 14px;
            letter-spacing:0.04em;
        }
        .db-tabs{ display:flex; gap:8px; margin-bottom:12px; }
        .db-tab{
            flex:1;
            padding:8px 10px;
            background:var(--surface-3);
            border:1px solid var(--border-2);
            border-radius:8px;
            color:var(--text-dim);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
            cursor:pointer;
        }
        .db-tab:hover{ color:var(--text); }
        .db-tab.active{ background:var(--accent-dim); border-color:var(--accent); color:var(--text); }
        .db-search{
            width:100%;
            box-sizing:border-box;
            padding:10px 14px;
            margin-bottom:12px;
            background:var(--surface-3);
            border:1px solid var(--border-2);
            border-radius:8px;
            color:var(--text);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
        }
        .db-search::placeholder{ color:var(--text-muted); }
        .db-search:focus{ outline:none; border-color:var(--accent); }
        .db-list{
            flex:1;
            overflow-y:auto;
            display:flex;
            flex-direction:column;
            gap:8px;
            min-height:120px;
        }
        .db-row{
            display:block;
            width:100%;
            text-align:left;
            padding:10px 12px;
            background:var(--surface-2);
            border:1px solid var(--border);
            border-radius:8px;
            color:var(--text);
            font-family:'DM Sans',sans-serif;
            cursor:pointer;
        }
        .db-row:hover{ border-color:var(--accent); background:var(--surface-3); }
        .db-row-head{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; }
        .db-row-name{ font-size:14px; font-weight:600; }
        .db-row-author{ font-size:12px; color:var(--text-dim); flex:none; }
        .db-row-counts{ font-size:12px; color:var(--text-dim); margin-top:3px; }
        .db-row-blurb{ font-size:12px; color:var(--text-muted); margin-top:6px; line-height:1.4; }
        .db-empty{
            padding:28px 8px;
            text-align:center;
            color:var(--text-dim);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
        }

        /* ── SS-3: DECK PREVIEW POPUP ───────────────────────────── */
        .dp-overlay{
            position:fixed;
            inset:0;
            z-index:99;                 /* above the SS-2 browser (z-98), below the hidden landing (z-100) */
            display:flex;
            align-items:center;
            justify-content:center;
        }
        .dp-overlay[hidden]{ display:none; }
        .dp-backdrop{
            position:absolute;
            inset:0;
            background:rgba(4,6,12,0.82);
        }
        .dp-card{
            position:relative;
            width:min(560px,92vw);
            max-height:84vh;
            display:flex;
            flex-direction:column;
            background:var(--surface);
            border:1px solid var(--accent);
            border-radius:10px;
            padding:22px 22px 18px;
            box-shadow:0 18px 60px rgba(0,0,0,0.6);
        }
        .dp-close{
            position:absolute;
            top:12px; right:12px;
            width:30px; height:30px;
            background:rgba(8,11,20,0.75);
            color:var(--accent);
            border:1px solid var(--accent);
            border-radius:6px;
            font-size:15px; line-height:1;
            cursor:pointer;
        }
        .dp-close:hover{ background:rgba(8,11,20,0.95); }
        .dp-title{
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:20px;
            color:var(--accent);
            margin:0 30px 14px 0;
            letter-spacing:0.04em;
        }
        .dp-list{
            flex:1 1 auto;
            min-height:0;
            overflow-y:auto;
            padding-right:4px;
        }
        .dp-grp{ margin-bottom:14px; }
        .dp-grp-ttl{
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:12px;
            letter-spacing:0.06em;
            text-transform:uppercase;
            color:var(--text-dim);
            border-bottom:1px solid var(--border-2);
            padding-bottom:3px;
            margin-bottom:5px;
        }
        .dp-row{
            display:flex;
            align-items:center;
            gap:8px;
            padding:3px 2px;
            font-family:'DM Sans',sans-serif;
            font-size:13px;
        }
        .dp-row:hover{ background:var(--accent-dim); border-radius:4px; }
        .dp-qty{ flex:none; min-width:24px; color:var(--text-muted); font-weight:600; }
        .dp-name{ flex:1; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .dp-dmd{ flex:none; display:inline-flex; align-items:center; gap:1px; }
        .dp-dmd-icon{ width:13px; height:13px; vertical-align:middle; }
        .dp-cost{
            flex:none;
            display:inline-block;
            background:var(--accent-dim);
            color:var(--accent);
            padding:1px 6px;
            border-radius:3px;
            font-size:10px; font-weight:700;
            min-width:16px; text-align:center;
        }
        .dp-empty{
            padding:28px 8px;
            text-align:center;
            color:var(--text-dim);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
        }
        .dp-actions{
            flex:none;
            display:flex;
            justify-content:flex-end;
            padding-top:14px;
            margin-top:4px;
            border-top:1px solid var(--border-2);
        }
        .dp-select-btn{
            font-family:'Cinzel',serif;
            font-weight:700;
            font-size:14px;
            letter-spacing:0.04em;
            color:var(--bg);
            background:var(--accent);
            border:1px solid var(--accent);
            border-radius:6px;
            padding:8px 24px;
            cursor:pointer;
        }
        .dp-select-btn:hover{ filter:brightness(1.08); }
        .dp-preview{
            position:fixed;
            left:24px;
            top:50%;
            transform:translateY(-50%);
            max-height:min(70vh,600px);
            max-width:30vw;
            width:auto; height:auto;
            z-index:5;                  /* above .dp-card within the overlay's stacking context */
            pointer-events:none;
            border-radius:6px;
            box-shadow:0 10px 36px rgba(0,0,0,.7),0 0 0 1px var(--border-2);
            background:var(--surface-2);
        }
        .dp-preview.dp-landscape{
            max-height:min(46vh,420px);
            max-width:min(44vw,540px);
        }
        .dp-preview[hidden]{ display:none!important; }

        /* F11-a-2-i: landing login control + New-Game room-config panel. */
        .landing-auth{
            display:flex;
            justify-content:center;
            align-items:center;
            gap:8px;
            margin:0 0 12px;
            font-size:13px;
            color:var(--text-muted);
        }
        .new-game-config{
            display:flex;
            flex-direction:column;
            gap:10px;
            margin:10px 0 4px;
            padding:12px;
            border:1px solid var(--border-2);
            border-radius:10px;
            background:var(--surface-2);
        }
        .new-game-config .ngc-visibility{
            display:flex;
            justify-content:center;
            gap:18px;
        }
        .new-game-config .ngc-opt{
            display:inline-flex;
            align-items:center;
            gap:6px;
            font-size:14px;
            color:var(--text);
            cursor:pointer;
        }
        .new-game-config .ngc-spectators{
            justify-content:center;
        }
        .new-game-config .ngc-gate{
            font-size:13px;
            color:var(--red);
            text-align:center;
        }
        .new-game-config[hidden],
        .landing-auth[hidden]{ display:none!important; }

        /* F11-a-2-ii: reactive join-password input, revealed only after the
           server returns bad_password on the join path. */
        .landing-join-pw{
            width:100%;
            margin:8px 0 0;
        }
        .landing-join-pw[hidden]{ display:none!important; }

        /* F11-b-2: public-games lobby — collapsed toggle + revealed list. */
        .public-games{ margin-top:14px; }
        .public-games-toggle{
            display:flex;
            align-items:center;
            justify-content:space-between;
            width:100%;
            padding:10px 14px;
            border-radius:8px;
            border:1px solid var(--border-2);
            background:var(--surface-2);
            color:var(--text);
            font-family:'DM Sans',sans-serif;
            font-size:13px;
            font-weight:600;
            letter-spacing:.02em;
            cursor:pointer;
            transition:all .15s;
        }
        .public-games-toggle::after{ content:'\25B8'; color:var(--text-muted); font-size:11px; }
        .public-games-toggle.open::after{ content:'\25BE'; }
        .public-games-toggle:hover{ border-color:var(--accent); color:var(--accent); }
        .public-games-panel{ margin-top:8px; max-height:240px; overflow-y:auto; }
        .public-games-panel[hidden]{ display:none!important; }
        .pg-list{ display:flex; flex-direction:column; gap:6px; }
        .pg-row{
            display:flex;
            align-items:center;
            gap:10px;
            padding:8px 12px;
            border:1px solid var(--border);
            border-radius:8px;
            background:var(--surface-2);
        }
        .pg-host{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); font-size:13px; }
        .pg-status{ color:var(--text-dim); font-size:12px; white-space:nowrap; }
        .pg-spectators{ color:var(--text-muted); font-size:12px; white-space:nowrap; }
        .pg-join,
        .pg-spectate{
            padding:6px 12px;
            border-radius:6px;
            font-family:'DM Sans',sans-serif;
            font-size:12px;
            font-weight:600;
            border:1px solid var(--border-2);
            white-space:nowrap;
            cursor:pointer;
        }
        .pg-join{ background:var(--accent); color:#0c0800; border-color:var(--accent); }
        .pg-join:hover{ box-shadow:0 0 12px var(--accent-glow); }
        .pg-spectate{ background:var(--surface-3); color:var(--text-muted); cursor:not-allowed; }
        .pg-spectate:disabled{ opacity:.55; }
        .pg-empty{ padding:10px 12px; text-align:center; color:var(--text-muted); font-size:12px; }

        /* ── F11-c-2: spectator view ─────────────────────── */
        .status-watching{ font-size:11px; color:var(--text-dim); margin-left:8px; white-space:nowrap; }
        .status-watching[hidden]{ display:none; }
        .status-seat.spectating::before{ background:var(--accent); box-shadow:0 0 8px var(--accent-glow); }
        .status.spectating .status-conn,
        .status.spectating .status-seat ~ .status-sep{ display:none; }
        /* ── EP-4: seat-name colouring ─────────── */
        .status-seat.red{ color:var(--red); }
        .status-seat.blue{ color:var(--blue); }
        .status-opp.connected.red{ color:var(--red); }
        .status-opp.connected.blue{ color:var(--blue); }
        .status-opp .opp-name.red{ color:var(--red); }
        .status-opp .opp-name.blue{ color:var(--blue); }
        .cl-login-prompt{ display:flex; gap:8px; align-items:center; justify-content:center; padding:8px; border-top:1px solid var(--border,#2a2f3a); font-size:12px; color:var(--text-dim); }
        .cl-login-prompt[hidden]{ display:none; }
        .cl-login-link{ color:var(--accent); text-decoration:none; font-weight:600; }
        .cl-login-link:hover{ text-decoration:underline; }
        .pg-spectate.active{ background:var(--accent); color:#0c0800; border-color:var(--accent); cursor:pointer; }
        .pg-spectate.active:hover{ box-shadow:0 0 12px var(--accent-glow); }
        /* ── F11-d-2: host watch popover + kicked modal ── */
        .status{ position:relative; }
        .status-watching.is-host{ cursor:pointer; }
        .status-watching.is-host::after{ content:' \25be'; color:var(--text-dim); }
        .watch-popover{ position:absolute; top:30px; left:0; min-width:200px; background:var(--surface-2,#161b26); border:1px solid var(--border,#2a2f3a); border-radius:8px; padding:8px; z-index:80; box-shadow:0 6px 24px rgba(0,0,0,0.5); }
        .watch-popover[hidden]{ display:none; }
        .wp-title{ font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:6px; }
        .wp-list{ display:flex; flex-direction:column; gap:4px; max-height:200px; overflow:auto; }
        .wp-row{ display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:13px; color:var(--text); }
        .wp-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .wp-empty{ font-size:12px; color:var(--text-dim); padding:2px 0; }
        .wp-kick{ font-size:11px; padding:2px 8px; border:1px solid var(--border,#2a2f3a); border-radius:5px; background:var(--surface-3,#1d2430); color:var(--text); cursor:pointer; }
        .wp-kick:hover{ border-color:var(--red,#e0556b); color:var(--red,#e0556b); }
        .wp-lock{ display:flex; align-items:center; gap:6px; margin-top:8px; padding-top:8px; border-top:1px solid var(--border,#2a2f3a); font-size:12px; color:var(--text-dim); cursor:pointer; }
        .kicked-veil{ position:fixed; inset:0; z-index:100; display:flex; align-items:center; justify-content:center; background:rgba(8,11,20,0.82); }
        .kicked-veil[hidden]{ display:none; }
        .kicked-card{ background:var(--surface,#0f1320); border:1px solid var(--border,#2a2f3a); border-radius:12px; padding:28px 32px; text-align:center; max-width:340px; }
        .kicked-msg{ font-size:15px; color:var(--text); margin-bottom:18px; }
        .kicked-btn{ padding:8px 24px; border:1px solid var(--accent); border-radius:7px; background:var(--accent); color:#0c0800; font-weight:600; cursor:pointer; }
        .kicked-btn:hover{ box-shadow:0 0 12px var(--accent-glow); }
        /* EP-5: attachment slide-behind/fan-out -- the ONLY transition on a
           board card, scoped to .att-anim toggled by attFollow/runAttFanOut
           (js/04-render.js). 140ms both ways (tuck-in + fan-out). The per-frame
           rigid follow writes transform WITHOUT this class, so the cluster
           travels with the host instantly (Q2); only the gather/spread ease. */
        .board-card.att-anim{ transition:transform 140ms ease; }
