@charset "UTF-8";
:root {
    --felt-deep: #0d3d28;
    --felt-mid: #164d33;
    --felt-edge: #06291b;
    --gold: #d4af37;
    --gold-soft: #f0d879;
    --ivory: #f4ede0;
    --ash: #9ca69c;
    --danger: #d03030;
    --danger-dim: #7a1a1a;
    --accent-cyan: #66ccff;
    --accent-green: #9cff57;
    --accent-ember: #ff7d57;
}
* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}

body {
    font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
    background: radial-gradient(ellipse at center, var(--felt-mid) 0%, var(--felt-deep) 55%, var(--felt-edge) 100%);
    color: var(--ivory);
    height: 100vh;
    overflow: hidden;
    display: flex;
}

/* ===== layout ===== */
#game-container {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 0;
}

#cards-section {
    padding: 14px 20px 80px 20px;
    overflow-y: auto;
    position: relative;
    height: 100%;
}
#cards-section::before {
    content: '';
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(45deg, rgba(0,0,0,0.04) 0 2px, transparent 2px 6px);
    pointer-events: none;
}

#counter-section {
    padding: 14px 12px;
    border-left: 1px solid rgba(212,175,55,0.15);
    background: linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0.55) 100%);
    overflow-y: auto;
    transition: opacity 0.2s;
}
body.counter-open #counter-section { }

/* ===== log modal ===== */
.modal {
    position: fixed;
    inset: 0;
    z-index: 800;
    display: flex;
    align-items: center;
    justify-content: center;
}
.modal.hidden { display: none; }
.modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,0.72);
    backdrop-filter: blur(3px);
}
.modal-panel {
    position: relative;
    width: min(640px, 92vw);
    max-height: 80vh;
    background: linear-gradient(180deg, rgba(20,30,24,0.96), rgba(8,14,10,0.98));
    border: 1px solid rgba(212,175,55,0.35);
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(0,0,0,0.4);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 18px;
    border-bottom: 1px solid rgba(212,175,55,0.2);
}
.modal-head h2 {
    margin: 0;
    color: var(--gold);
    font-family: 'Playfair Display', serif;
    font-size: 16px;
    letter-spacing: 3px;
    text-transform: uppercase;
}
.modal-close {
    background: transparent;
    border: 1px solid rgba(212,175,55,0.3);
    color: var(--gold);
    border-radius: 4px;
    width: 28px;
    height: 28px;
    font-size: 13px;
    cursor: pointer;
}
.modal-close:hover { background: rgba(212,175,55,0.18); }
#log-modal #log-container {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px;
}

/* ===== exposed cards modal ===== */
#exposed-body {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px;
}

/* ===== settings modal ===== */
#settings-body {
    flex: 1;
    overflow-y: auto;
    padding: 18px 22px;
}

#burn-body {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px;
}
.burn-target {
    margin-bottom: 14px;
    padding: 12px;
    border: 1px solid rgba(212,175,55,0.22);
    border-radius: 10px;
    background:
        linear-gradient(180deg, rgba(32,46,36,0.85) 0%, rgba(10,18,12,0.92) 100%);
    box-shadow: inset 0 0 24px rgba(0,0,0,0.45), 0 2px 6px rgba(0,0,0,0.5);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.burn-target:last-child { margin-bottom: 4px; }

/* Eights-Eternal rank-picker: each rank tile shows EVERY card of that
   rank that's currently in the graveyard, stacked in vertical fans of
   3 per row so the player sees what they'll resurrect. */
.picker-rank .picker-rank-stacks { flex-wrap: wrap; max-width: 220px; }
.picker-rank .picker-rank-card {
    position: relative;
    display: block;
    line-height: 0;
}
.picker-rank .picker-rank-card .card {
    transform: scale(0.85);
    transform-origin: top center;
    box-shadow: 0 2px 8px rgba(0,0,0,0.6);
}
.picker-rank.disabled { opacity: 0.45; cursor: not-allowed; }
.picker-rank.disabled .picker-rank-card .card { filter: grayscale(0.7) brightness(0.7); }
/* Saving-grace choice modal — appears on accusation misses when the
   user has a viable combo. Two-button choice: apply save (reveals combo)
   or decline (take the shot, keep cards hidden). */
#saving-grace-modal .modal-panel {
    max-width: 480px;
}
#saving-grace-body .sg-copy {
    font-size: 13px;
    color: var(--ivory);
    margin-bottom: 14px;
    line-height: 1.55;
}
#saving-grace-body .sg-combo {
    display: flex;
    gap: 10px;
    justify-content: center;
    padding: 18px 0;
    background: rgba(212,175,55,0.08);
    border: 1px solid rgba(212,175,55,0.3);
    border-radius: 6px;
    margin-bottom: 14px;
}
#saving-grace-body .sg-combo .card {
    transform: scale(1.15);
}
#saving-grace-body .sg-stakes {
    display: flex;
    justify-content: space-between;
    font-family: 'Oswald', sans-serif;
    font-size: 12px;
    letter-spacing: 2px;
    text-transform: uppercase;
    padding: 10px 14px;
    background: rgba(0,0,0,0.45);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 4px;
    margin-bottom: 16px;
}
#saving-grace-body .sg-chamber { color: var(--ash); }
#saving-grace-body .sg-risk { color: #ff9090; }
#saving-grace-body .sg-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.sg-btn {
    padding: 14px 16px;
    font-family: 'Oswald', sans-serif;
    font-size: 13px;
    letter-spacing: 2px;
    text-transform: uppercase;
    border-radius: 4px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: transform 0.12s, background 0.12s;
}
.sg-btn-save {
    background: linear-gradient(180deg, #c9a86b, #7a6030);
    color: #121008;
    border-color: rgba(212,175,55,0.7);
}
.sg-btn-save:hover { transform: translateY(-1px); background: linear-gradient(180deg, #e8c87a, #a07b3a); }
.sg-btn-risk {
    background: rgba(30,15,15,0.95);
    color: #ffb8b8;
    border-color: rgba(208,48,48,0.65);
}
.sg-btn-risk:hover { transform: translateY(-1px); background: rgba(60,25,25,1); color: #ffe0e0; }

.burn-target-head {
    display: flex;
    gap: 12px;
    align-items: center;
}
.burn-target-portrait {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    object-position: top center;
    border: 2px solid rgba(212,175,55,0.45);
    box-shadow: 0 0 14px rgba(212,175,55,0.35), 0 3px 10px rgba(0,0,0,0.5);
    flex-shrink: 0;
    background: radial-gradient(circle at 40% 30%, rgba(50,68,54,0.9), rgba(10,16,10,1));
}
.burn-target-meta {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.burn-target-name {
    font-family: 'Playfair Display', serif;
    font-size: 16px;
    color: var(--gold-soft);
    letter-spacing: 2px;
    text-transform: uppercase;
    font-weight: 700;
    line-height: 1;
}
.burn-target-bullets {
    display: flex;
    align-items: center;
    gap: 4px;
}
.burn-chip {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #333, #0a0a0a);
    border: 1px solid rgba(255,255,255,0.15);
    display: inline-block;
}
.burn-chip.loaded {
    background: radial-gradient(circle at 35% 30%, #ff6b6b 0%, #c41212 50%, #6a0404 100%);
    box-shadow: 0 0 6px rgba(208,48,48,0.7);
    border-color: rgba(208,48,48,0.6);
}
.burn-chip-count {
    font-size: 10px;
    color: var(--ash);
    letter-spacing: 1px;
    margin-left: 4px;
}
.burn-target-hint {
    font-size: 10px;
    color: rgba(156,166,156,0.75);
    letter-spacing: 1px;
    text-transform: uppercase;
}
.burn-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px;
    background: rgba(0,0,0,0.35);
    border-radius: 6px;
    border: 1px dashed rgba(255,255,255,0.06);
    justify-content: flex-start;
}
.burn-card-opt {
    cursor: pointer;
    border-radius: 5px;
    transition: transform 0.15s, box-shadow 0.15s;
}
.burn-card-opt:hover {
    transform: translateY(-4px) scale(1.06);
    box-shadow: 0 4px 12px rgba(208,48,48,0.6), 0 0 0 2px var(--danger);
}
.setting-row {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 0;
    border-bottom: 1px solid rgba(212,175,55,0.12);
}
.setting-row:last-child { border-bottom: none; }
.setting-title {
    font-family: 'Playfair Display', serif;
    font-size: 18px;
    color: var(--gold);
    letter-spacing: 2px;
    text-transform: uppercase;
    margin-bottom: 4px;
}
.setting-desc {
    font-size: 12px;
    color: var(--ash);
    line-height: 1.5;
    margin-bottom: 4px;
}
.setting-desc strong { color: var(--gold-soft); }
.setting-control {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.toggle-option {
    flex: 1 1 auto;
    min-width: 100px;
    padding: 10px 16px;
    background: linear-gradient(180deg, #1a1a1a, #0a0a0a);
    border: 1px solid rgba(212,175,55,0.35);
    color: var(--ivory);
    border-radius: 4px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    font-family: 'Inter', sans-serif;
    transition: all 0.15s;
}
.toggle-option:hover { border-color: var(--gold); color: var(--gold); }
.toggle-option.active {
    background: linear-gradient(180deg, var(--gold), #a88420);
    color: #0a0a0a;
    border-color: var(--gold);
    box-shadow: 0 0 14px rgba(212,175,55,0.45);
}
.exposed-summary {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding-bottom: 10px;
    margin-bottom: 6px;
    border-bottom: 1px solid rgba(212,175,55,0.18);
}
.exposed-stat {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.exposed-stat-num {
    font-family: 'Playfair Display', serif;
    font-size: 22px;
    color: var(--gold-soft);
    line-height: 1;
}
.exposed-stat-lbl {
    font-size: 9px;
    letter-spacing: 2px;
    color: var(--ash);
    text-transform: uppercase;
    margin-top: 4px;
    text-align: center;
    line-height: 1.3;
}
.exposed-stat-lbl small {
    display: block;
    font-size: 7px;
    letter-spacing: 1px;
    opacity: 0.7;
    text-transform: none;
    margin-top: 1px;
}
.exposed-source-breakdown {
    display: flex;
    justify-content: space-around;
    padding: 6px 0 14px 0;
    border-bottom: 1px solid rgba(212,175,55,0.12);
    margin-bottom: 12px;
    font-size: 10px;
    color: var(--ash);
    text-transform: uppercase;
    letter-spacing: 1px;
}
.exposed-source-breakdown span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.exposed-suit-row {
    margin-bottom: 10px;
}
.exposed-suit-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 4px;
    padding-left: 2px;
}
.exposed-suit-symbol {
    font-size: 20px;
    font-family: 'Playfair Display', serif;
    line-height: 1;
}
.exposed-suit-symbol.red { color: #ff6b6b; }
.exposed-suit-symbol.black { color: var(--ivory); }
.exposed-suit-count {
    font-size: 10px;
    color: var(--ash);
    letter-spacing: 1.5px;
    font-family: 'Playfair Display', serif;
}

.card-placeholder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 60px;
    margin: 1px;
    border: 1px dashed rgba(255,255,255,0.18);
    border-radius: 4px;
    background: rgba(255,255,255,0.02);
    color: rgba(255,255,255,0.22);
    font-family: 'Playfair Display', serif;
    font-size: 12px;
    font-weight: 700;
}
.card-placeholder.joker { color: rgba(212,175,55,0.25); }
.exposed-item-missing { opacity: 0.85; }

/* Source color-coding on exposed cards: thick top + bottom bars so the color
   stays visible even when cards overlap horizontally in the stack. */
.exposed-item { position: relative; }
.exposed-item .card {
    border-width: 0;
    /* no default source border — the .exposed-item-* variants set it */
}
.exposed-item-bar .card {
    box-shadow:
        0 -4px 0 var(--gold),
        0 4px 0 var(--gold),
        0 2px 4px rgba(0,0,0,0.5),
        0 0 0 1px rgba(0,0,0,0.35);
}
.exposed-item-you .card {
    box-shadow:
        0 -4px 0 var(--accent-green),
        0 4px 0 var(--accent-green),
        0 2px 4px rgba(0,0,0,0.5),
        0 0 0 1px rgba(0,0,0,0.35);
}
.exposed-item-revealed .card {
    box-shadow:
        0 -4px 0 var(--accent-cyan),
        0 4px 0 var(--accent-cyan),
        0 2px 4px rgba(0,0,0,0.5),
        0 0 0 1px rgba(0,0,0,0.35);
}
.exposed-item-dead .card {
    box-shadow:
        0 -4px 0 var(--danger),
        0 4px 0 var(--danger),
        0 2px 4px rgba(0,0,0,0.5),
        0 0 0 1px rgba(0,0,0,0.35);
}
/* Small corner chip so color is visible even at full-overlap in the stack */
.exposed-item::before {
    content: '';
    position: absolute;
    top: -5px;
    right: -3px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    z-index: 2;
    border: 1px solid rgba(0,0,0,0.7);
    display: none;
}
.exposed-item-bar::before     { background: var(--gold);          display: block; }
.exposed-item-you::before     { background: var(--accent-green);  display: block; }
.exposed-item-revealed::before { background: var(--accent-cyan);  display: block; }
.exposed-item-dead::before    { background: var(--danger);        display: block; }
.exposed-items {
    display: flex;
    flex-wrap: wrap;
    padding-left: 22px;
    row-gap: 20px;
}
.exposed-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-left: -22px;
    transition: transform 0.15s, margin 0.15s;
    position: relative;
}
.exposed-item:hover {
    z-index: 10;
    transform: translateY(-4px);
    margin-right: 18px;
}
.exposed-item .card,
.exposed-item .card-back {
    margin: 0;
}
.exposed-owner-group {
    margin: 6px 0 10px 0;
}
.exposed-owner-label {
    font-size: 10px;
    letter-spacing: 1.5px;
    color: var(--ivory);
    text-transform: uppercase;
    margin-bottom: 4px;
    opacity: 0.85;
}
.exposed-owner-count {
    color: var(--ash);
    font-size: 9px;
    margin-left: 4px;
}
.exposed-bar { border-left: 2px solid var(--gold); padding-left: 8px; }
.exposed-you { border-left: 2px solid var(--accent-green); padding-left: 8px; }
.exposed-revealed { border-left: 2px solid var(--accent-cyan); padding-left: 8px; }
.exposed-dead { border-left: 2px solid var(--danger-dim); padding-left: 8px; }
.exposed-empty {
    text-align: center;
    color: var(--ash);
    font-size: 12px;
    padding: 20px;
}

/* ===== sudden death banner ===== */
.sudden-death-banner {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    font-family: 'Playfair Display', serif;
    font-weight: 900;
    font-size: clamp(32px, 9vw, 72px);
    letter-spacing: clamp(3px, 1.6vw, 12px);
    color: var(--danger);
    text-shadow:
        0 0 18px rgba(208, 48, 48, 0.8),
        0 0 40px rgba(208, 48, 48, 0.5),
        0 2px 0 rgba(0,0,0,0.8);
    pointer-events: none;
    z-index: 900;
    text-align: center;
    white-space: nowrap;
    max-width: 95vw;
    line-height: 1;
}
@media (max-width: 480px) {
    .sudden-death-banner {
        white-space: normal;
        line-height: 1.05;
        letter-spacing: 4px;
    }
}
.death-screen-tint {
    position: fixed;
    inset: 0;
    background: radial-gradient(ellipse at center, rgba(208,30,30,0.55) 0%, rgba(120,10,10,0.35) 60%, rgba(80,0,0,0.15) 100%);
    pointer-events: none;
    z-index: 726;
}

/* ===== headers ===== */
h1 {
    font-family: 'Playfair Display', 'Georgia', serif;
    font-weight: 900;
    font-size: clamp(22px, 5vw, 38px);
    letter-spacing: clamp(2px, 0.7vw, 5px);
    color: var(--gold);
    text-align: center;
    margin: 4px auto 2px auto;
    padding: 0 160px;
    max-width: 100%;
    text-shadow: 0 2px 8px rgba(0,0,0,0.6), 0 0 24px rgba(212,175,55,0.18);
}
@media (max-width: 600px) {
    #top-toolbar h1 {
        font-size: 16px;
        letter-spacing: 2px;
    }
    #settings-btn, #log-toggle, #exposed-toggle, #rules-btn {
        width: 32px;
        height: 32px;
        font-size: 14px;
    }
}
h1::after {
    content: '';
    display: block;
    width: 120px;
    height: 2px;
    margin: 6px auto 0;
    background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
h2, h3 {
    text-align: center;
    color: var(--gold-soft);
    letter-spacing: 2px;
    font-weight: 600;
    text-transform: uppercase;
    font-size: 12px;
    margin: 8px 0;
}

/* ===== setup ===== */
#setup {
    text-align: center;
    margin: 16px 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    justify-content: center;
}
#setup.hidden { display: none; }
#setup h2 { width: 100%; margin: 4px 0; }
#setup > div { width: 100%; }
@media (max-width: 520px) {
    #setup { padding: 0 8px; flex-direction: column; gap: 4px; }
    #setup label, #setup select, #setup button, #actions button {
        padding: 9px 12px;
        font-size: 12px;
        letter-spacing: 1px;
        margin: 2px;
    }
    #setup select { width: 80%; max-width: 260px; }
    #setup button { width: 80%; max-width: 260px; min-width: 0; }
    #setup > div { display: flex; justify-content: center; width: 100%; }
    #actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; padding: 0 4px; }
    #actions button { flex: 1 1 auto; min-width: 58px; }
}

#lobby {
    margin: 16px auto;
    max-width: 540px;
    padding: 20px 22px;
    border: 1px solid rgba(212,175,55,0.35);
    border-radius: 10px;
    background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(0,0,0,0.35));
    text-align: center;
}
#lobby.hidden { display: none; }
#lobby h2 {
    margin: 0 0 14px 0;
    letter-spacing: 3px;
    color: var(--gold);
    font-size: 14px;
}
#lobby-code-row {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 12px;
    margin-bottom: 10px;
}
.lobby-label {
    font-size: 10px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ash);
}
#lobby-code {
    font-family: 'Playfair Display', serif;
    font-size: 28px;
    letter-spacing: 6px;
    color: var(--gold);
}
#lobby-invite-row {
    display: flex;
    gap: 6px;
    margin-bottom: 14px;
}
#lobby-invite {
    flex: 1;
    padding: 7px 10px;
    background: rgba(0,0,0,0.5);
    border: 1px solid rgba(212,175,55,0.3);
    color: var(--ivory);
    border-radius: 4px;
    font-family: 'Inter', monospace;
    font-size: 11px;
    letter-spacing: 0.5px;
}
#lobby-copy {
    padding: 7px 14px;
    background: linear-gradient(180deg, #1a1a1a, #0a0a0a);
    border: 1px solid var(--gold);
    color: var(--gold);
    border-radius: 4px;
    cursor: pointer;
    font-size: 11px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
}
#lobby-copy:hover { background: linear-gradient(180deg, var(--gold), #a88420); color: #0a0a0a; }
#lobby-players {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    margin: 14px 0;
}
.lobby-player {
    padding: 5px 10px;
    border-radius: 14px;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.08);
    font-size: 12px;
    color: var(--ivory);
}
.lobby-player.you { background: rgba(212,175,55,0.15); border-color: var(--gold); color: var(--gold); }
.lobby-player.host::before { content: '★ '; color: var(--gold); }
#lobby-host-controls {
    margin: 12px 0;
    padding: 10px 0;
    border-top: 1px solid rgba(212,175,55,0.12);
    border-bottom: 1px solid rgba(212,175,55,0.12);
}
#lobby-host-controls.hidden { display: none; }
#lobby-leave {
    margin-top: 10px;
    padding: 6px 14px;
    background: transparent;
    border: 1px solid rgba(208,48,48,0.4);
    color: var(--danger);
    border-radius: 4px;
    cursor: pointer;
    font-size: 10px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
}
#lobby-leave:hover { background: rgba(208,48,48,0.15); }
#setup select, #setup button, #actions button {
    padding: 10px 20px;
    margin: 4px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    border: 1px solid var(--gold);
    border-radius: 3px;
    cursor: pointer;
    background: linear-gradient(180deg, #1a1a1a 0%, #0a0a0a 100%);
    color: var(--gold);
    transition: all 0.2s;
    font-family: inherit;
}
#setup select { background: #0a0a0a; color: var(--ivory); }
#setup button:hover, #actions button:hover:not(:disabled) {
    background: linear-gradient(180deg, var(--gold) 0%, #a88420 100%);
    color: #0a0a0a;
    box-shadow: 0 0 12px rgba(212,175,55,0.4);
}
#actions button:disabled { opacity: 0.35; cursor: not-allowed; }
#actions { text-align: center; margin: 12px 0; display: none; }

/* Draw button when the deck is empty — flashes red to warn that pulling
   triggers sudden death instead of a normal draw. */
#actions button#draw-cards.death-warning {
    background: linear-gradient(180deg, var(--danger), #6a0a0a) !important;
    color: var(--ivory) !important;
    border-color: var(--danger) !important;
    animation: deathPulse 1.4s ease-in-out infinite;
    letter-spacing: 3px !important;
    font-weight: 800 !important;
}
@keyframes deathPulse {
    0%, 100% { box-shadow: 0 0 6px rgba(208,48,48,0.5); }
    50%      { box-shadow: 0 0 24px rgba(208,48,48,0.9); }
}

/* Top toolbar — plain static header at the top of the scroll container.
   Scrolls away with the rest of the content; only #bar is sticky. */
#top-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 4px 8px 4px;
}
#top-toolbar h1 {
    margin: 0;
    padding: 0;
    flex: 1;
    text-align: left;
    font-size: clamp(18px, 3.2vw, 28px);
    letter-spacing: clamp(2px, 0.5vw, 4px);
}
.toolbar-icons {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}
#settings-btn, #log-toggle, #exposed-toggle, #rules-btn {
    position: static;
    background: rgba(0,0,0,0.55);
    border: 1px solid rgba(212,175,55,0.35);
    color: var(--gold);
    border-radius: 6px;
    width: 36px;
    height: 36px;
    font-size: 15px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    flex-shrink: 0;
}
#mute-btn:hover, #log-toggle:hover, #exposed-toggle:hover, #rules-btn:hover {
    background: rgba(212,175,55,0.22);
    border-color: var(--gold);
}
#log-toggle.has-new { animation: log-pulse 1.2s ease-in-out infinite; border-color: var(--gold); }
@keyframes log-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(212,175,55,0); }
    50% { box-shadow: 0 0 12px rgba(212,175,55,0.6); }
}

/* ===== bar ===== */
/* The bar is in-game chrome — it should never be visible on the homepage
   before a match starts. body.game-active is added by rules.js::startGame
   for both classic and story modes. !important wins over the story-mode
   display:flex override that lives in campaign-board.css. */
body:not(.game-active) #bar { display: none !important; }
#bar {
    position: sticky;
    top: 0;
    z-index: 30;
    border: 1px solid rgba(212,175,55,0.4);
    padding: 12px;
    margin-bottom: 14px;
    min-height: 130px;
    background:
        radial-gradient(ellipse at center, rgba(26,77,51,0.96) 0%, rgba(10,41,27,0.98) 100%),
        rgba(8,24,15,1);
    border-radius: 10px;
    text-align: center;
    box-shadow: inset 0 0 30px rgba(0,0,0,0.5), 0 6px 14px rgba(0,0,0,0.55);
    backdrop-filter: blur(6px);
}
#bar-total {
    font-family: 'Playfair Display', serif;
    font-size: 28px;
    color: var(--gold);
    font-weight: 700;
    letter-spacing: 2px;
    text-shadow: 0 1px 3px rgba(0,0,0,0.6);
    margin-bottom: 8px;
}
.bar-total-prev {
    font-size: 11px;
    color: var(--ash);
    letter-spacing: 2px;
    text-transform: uppercase;
    margin-top: 2px;
    opacity: 0.85;
}
.bar-total-prev::before {
    content: '↩ ';
    color: var(--gold);
    opacity: 0.7;
}
#bar-cards {
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 0;
    min-height: 60px;
    align-items: center;
    padding-left: 44px; /* matches the overlap offset below so the first card isn't clipped */
    overflow-x: auto;
}
#bar-cards > .card,
#bar-cards > .card-back {
    margin-left: -44px;
    flex-shrink: 0;
}
/* Tea House Conditions reserved-card slot. Sits to the right of the
   bar's normal card row with a small label so it reads as a distinct
   "fortune" pile rather than just another bar card. The card inside
   uses the same dimensions as bar cards but is offset/highlighted. */
.bar-tea-house {
    margin-left: 18px;
    padding: 4px 6px;
    border: 1.5px dashed rgba(255,180,80,0.55);
    border-radius: 6px;
    background: linear-gradient(135deg, rgba(80,30,8,0.35), rgba(40,12,4,0.55));
    box-shadow: 0 0 12px rgba(255,180,80,0.2), inset 0 0 8px rgba(80,30,8,0.6);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    perspective: 800px;
}
.bar-tea-house-label {
    font: bold 9px 'Courier Prime', monospace;
    letter-spacing: 0.18em;
    color: rgba(255,200,100,0.85);
    text-shadow: 0 0 6px rgba(255,180,60,0.55);
}
.bar-tea-house > .card,
.bar-tea-house > .card-back {
    margin: 0;
    transform-style: preserve-3d;
    backface-visibility: hidden;
}
#deck-count {
    font-size: 10px;
    color: var(--ash);
    letter-spacing: 2px;
    margin-top: 8px;
    text-transform: uppercase;
}

/* ===== players ===== */
#players { display: flex; flex-direction: column; gap: 10px; }
.you-row { position: relative; }
.you-row::after {
    content: '— clockwise ↓↑ clockwise —';
    display: block;
    text-align: center;
    font-size: 9px;
    letter-spacing: 3px;
    color: var(--ash-dim);
    text-transform: uppercase;
    margin-top: 8px;
}
.table-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.table-col { display: flex; flex-direction: column; gap: 10px; }
.table-stack { display: flex; flex-direction: column; gap: 6px; }

.player {
    border: 1px solid rgba(255,255,255,0.08);
    padding: 8px 12px;
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(255,255,255,0.04) 0%, rgba(0,0,0,0.2) 100%);
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: all 0.2s;
    position: relative;
    overflow: hidden;
}

/* Character portrait — bottom-right anchored, sitting behind the cards so the
   upper-body of the illustration peeks up from the bottom-right corner. Cards
   and stats remain on top via z-index. */
.player-portrait {
    position: absolute;
    right: 0;
    bottom: 0;
    height: 160%;
    width: auto;
    max-width: 40%;
    object-fit: contain;
    object-position: bottom right;
    opacity: 0.55;
    pointer-events: none;
    z-index: 0;
    filter: drop-shadow(-4px -2px 8px rgba(0,0,0,0.6));
    /* Fade the portrait out toward the left so it blends into the row. */
    mask-image: linear-gradient(90deg, transparent 0%, black 45%, black 100%);
    -webkit-mask-image: linear-gradient(90deg, transparent 0%, black 45%, black 100%);
}
.player.dead .player-portrait {
    filter: grayscale(1);
    opacity: 0.25;
}

/* Name caption sits under the portrait in the bottom-right corner, inside the
   player box. Kept above the portrait image via z-index so the text stays
   readable against the illustration. */
.player-portrait-name {
    position: absolute;
    right: 8px;
    bottom: 4px;
    z-index: 2;
    font-family: 'Playfair Display', serif;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--gold-soft);
    text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.7);
    pointer-events: none;
    max-width: 38%;
    text-align: right;
    line-height: 1;
}
.player.dead .player-portrait-name {
    color: var(--ash);
    opacity: 0.5;
}

/* ===== character picker (settings modal) ===== */
/* The picker wraps everything: current-pick preview, search + gender
   filters, then the tile grid. Large pool (36+ characters) makes filtering
   important; tiles are smaller and lazy-loaded. */
#character-picker {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.charpicker-current {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(36,50,38,0.85), rgba(10,18,12,0.92));
    border: 1px solid rgba(212,175,55,0.3);
    box-shadow: inset 0 0 16px rgba(0,0,0,0.45);
}
.charpicker-current img,
.charpicker-current-random {
    width: 120px;
    height: 120px;
    border-radius: 8px;
    object-fit: contain;
    object-position: center;
    border: 2px solid var(--gold);
    box-shadow: 0 0 14px rgba(212,175,55,0.4);
    flex-shrink: 0;
    background: radial-gradient(circle at 40% 30%, rgba(50,68,54,0.9), rgba(10,16,10,1));
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
}
.charpicker-current-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}
.charpicker-current-label {
    font-size: 10px;
    letter-spacing: 2px;
    color: var(--ash);
    text-transform: uppercase;
}
.charpicker-current-name {
    font-family: 'Playfair Display', serif;
    font-size: 17px;
    color: var(--gold);
    letter-spacing: 1.5px;
    text-transform: uppercase;
    line-height: 1;
}
.charpicker-current-sub {
    font-size: 11px;
    color: var(--ash);
    letter-spacing: 1px;
}
.charpicker-clear,
.charpicker-change {
    background: transparent;
    border: 1px solid rgba(212,175,55,0.4);
    color: var(--gold-soft);
    font-family: inherit;
    font-size: 10px;
    letter-spacing: 2px;
    text-transform: uppercase;
    padding: 8px 12px;
    border-radius: 5px;
    cursor: pointer;
    white-space: nowrap;
    transition: all 0.15s;
}
.charpicker-clear:hover,
.charpicker-change:hover {
    background: rgba(212,175,55,0.12);
    color: var(--ivory);
}
.charpicker-change {
    background: linear-gradient(180deg, rgba(212,175,55,0.22), rgba(136,108,24,0.35));
    border-color: var(--gold);
    color: var(--gold-soft);
}
.charpicker-preview-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex-shrink: 0;
}
/* The character picker sub-modal uses a wider panel so the grid can breathe.
   Elevated z-index so it layers above the settings modal when opened from
   the preview's "Change" button. */
#character-modal { z-index: 850; }
.modal-panel-wide {
    width: min(880px, 96vw) !important;
    max-height: 92vh !important;
}
#character-picker-body {
    flex: 1;
    overflow-y: auto;
    padding: 14px 18px 20px 18px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
#character-picker-body .character-grid {
    max-height: none; /* unclamped inside its own modal */
    overflow-y: visible;
}
.charpicker-controls {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.charpicker-search-wrap { display: flex; }
.charpicker-search {
    flex: 1;
    background: rgba(0,0,0,0.45);
    border: 1px solid rgba(212,175,55,0.25);
    color: var(--ivory);
    font-family: inherit;
    font-size: 13px;
    padding: 8px 12px;
    border-radius: 6px;
    outline: none;
    transition: border-color 0.15s;
}
.charpicker-search:focus { border-color: var(--gold); }
.charpicker-search::placeholder { color: var(--ash); }
.charpicker-filters {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}
.charpicker-filter {
    background: rgba(0,0,0,0.35);
    border: 1px solid rgba(156,166,156,0.25);
    color: var(--ash);
    font-family: inherit;
    font-size: 10px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    padding: 6px 12px;
    border-radius: 5px;
    cursor: pointer;
    transition: all 0.15s;
}
.charpicker-filter:hover { color: var(--ivory); border-color: var(--ivory); }
.charpicker-filter.active {
    background: linear-gradient(180deg, rgba(212,175,55,0.22), rgba(136,108,24,0.3));
    border-color: var(--gold);
    color: var(--gold-soft);
}
.charpicker-empty {
    padding: 20px 8px;
    text-align: center;
    color: var(--ash);
    font-size: 12px;
    letter-spacing: 1px;
    font-style: italic;
}
.character-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 8px;
    max-height: 460px;
    overflow-y: auto;
    padding: 2px;
}
.char-tile {
    position: relative;
    background: rgba(0,0,0,0.35);
    border: 1px solid rgba(212,175,55,0.25);
    border-radius: 6px;
    padding: 6px;
    cursor: pointer;
    overflow: hidden;
    transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
    display: flex;
    flex-direction: column;
    gap: 4px;
    text-align: center;
    color: var(--ivory);
    font-family: inherit;
    /* Let content (wrapper div + name) determine the tile's height. */
}
.char-tile .char-tile-img {
    aspect-ratio: 1 / 1;
    width: 100%;
    border-radius: 4px;
    overflow: hidden;
    background: radial-gradient(circle at 40% 35%, rgba(140,160,130,0.35), rgba(60,86,72,0.55));
    display: block;
}
.char-tile .char-tile-img img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
    display: block;
}
.char-tile .char-random {
    width: 100%;
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    background: linear-gradient(135deg, rgba(212,175,55,0.15), rgba(0,0,0,0.35));
    border-radius: 4px;
}
.char-tile .char-name {
    font-size: 10px;
    letter-spacing: 1px;
    text-transform: uppercase;
    text-align: center;
    color: var(--ash);
    line-height: 1.1;
}
.char-tile:hover {
    transform: translateY(-2px);
    border-color: var(--gold);
    box-shadow: 0 4px 14px rgba(0,0,0,0.4);
}
.char-tile.selected {
    border-color: var(--gold);
    box-shadow: 0 0 0 2px var(--gold), 0 0 18px rgba(212,175,55,0.45);
}
.char-tile.selected .char-name {
    color: var(--gold);
}
/* Locked character tile — greyed silhouette, lock icon overlay,
   non-interactive. Click is blocked at the JS layer too. */
.char-tile.locked {
    cursor: not-allowed;
    opacity: 0.55;
}
.char-tile.locked .char-tile-img img {
    filter: grayscale(1) brightness(0.55) contrast(1.1);
}
.char-tile.locked .char-name,
.char-tile.locked .char-species {
    color: var(--ash);
    letter-spacing: 1px;
}
.char-tile.locked:hover {
    transform: none;
    box-shadow: none;
    border-color: rgba(160,160,160,0.25);
}
.char-tile-lock {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    color: rgba(255,255,255,0.85);
    text-shadow: 0 2px 6px rgba(0,0,0,0.8);
    pointer-events: none;
}
.charpicker-unlock-tally {
    margin-left: auto;
    font-size: 11px;
    letter-spacing: 2px;
    color: var(--ash);
    text-transform: uppercase;
}
.player > .player-stats,
.player > .player-hand,
.player > .player-settled {
    position: relative;
    z-index: 1;
}
.player.current-player {
    border-color: var(--gold);
    box-shadow: 0 0 20px rgba(212,175,55,0.35), inset 0 0 20px rgba(212,175,55,0.08);
}
.player.dead {
    opacity: 0.35;
    filter: grayscale(0.8);
}

.player-stats {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding-bottom: 4px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.stats-identity {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    min-width: 0;
}
.stats-meters {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.player-name {
    font-weight: 700;
    font-size: 14px;
    color: var(--ivory);
    letter-spacing: 0.5px;
}
.player-name.you { color: var(--gold); font-size: 16px; }
.star { color: var(--gold); }
.tag-dead {
    font-size: 10px;
    color: var(--danger);
    letter-spacing: 1.5px;
    padding: 1px 4px;
    border: 1px solid var(--danger-dim);
    border-radius: 2px;
    margin-left: 4px;
}
.player-persona {
    display: inline-block;
    font-size: 9px;
    color: var(--ash);
    letter-spacing: 1.8px;
    text-transform: uppercase;
    padding: 1px 6px;
    border: 1px solid rgba(156,166,156,0.3);
    border-radius: 10px;
}
.player-total {
    font-family: 'Playfair Display', serif;
    font-size: 18px;
    color: var(--gold-soft);
    font-weight: 600;
    line-height: 1;
}
.total-unknown {
    color: var(--ash);
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    letter-spacing: 1px;
    font-weight: 500;
}
.player-claim {
    font-size: 10px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    font-weight: 600;
    padding: 2px 7px;
    border-radius: 3px;
    background: rgba(0,0,0,0.3);
}
.claim-par { color: var(--accent-cyan); }
.claim-low { color: var(--accent-green); }

.player-settled, .player-hand {
    padding: 10px 14px;
    min-height: 128px;
    border-radius: 6px;
    background: rgba(0,0,0,0.25);
    border: 1px solid rgba(255,255,255,0.05);
    display: flex;
    align-items: center;
    gap: 14px;
}
.slot-label {
    font-size: 10px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ash);
    min-width: 82px;
    text-align: left;
    flex-shrink: 0;
}
.slot-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    flex: 1;
    min-height: 106px;
    align-items: center;
}
@media (max-width: 720px) {
    /* Mobile keeps desktop-sized cards (68×100). To save horizontal space we
       overlap them heavily inside the slot, but the slot itself grows tall
       enough to contain them comfortably. */
    .slot-cards {
        gap: 0;
        padding-left: 44px;
        flex-wrap: nowrap;
        overflow: visible;
    }
    .slot-cards > .card,
    .slot-cards > .card-back,
    .slot-cards > .card-exposed,
    .slot-cards > .card-secret,
    .slot-cards > .clickable-joker {
        margin-left: -44px;
        flex-shrink: 0;
    }
    .exposed-items { padding-left: 44px; }
    .exposed-items > .exposed-item { margin-left: -44px; }
    /* Slot dimensions: card is 100 tall + 3px margin = 106 visual. slot-cards
       gets 112 (6px buffer). player-settled/player-hand add 4px padding +
       small buffer → 124 for breathing room. (Historically the buffer also
       covered the 🔒 lock overlay when it hung outside the card; the lock
       is now positioned inside the card boundary so the buffer is purely
       layout breathing room.) */
    .player-settled, .player-hand {
        height: 124px;
        min-height: 124px;
        padding: 6px 8px;
        gap: 10px;
        box-sizing: border-box;
        overflow: visible;
    }
    .slot-cards {
        height: 112px;
        min-height: 112px;
        overflow: visible;
    }
    .slot-label { min-width: 60px; font-size: 9px; letter-spacing: 1px; }
    .player { padding: 6px 10px; gap: 4px; }
    .player-name { font-size: 12px; letter-spacing: 0.3px; }
    .player-name.you { font-size: 13px; }
    .player-total { font-size: 21px; }
    .total-unknown { font-size: 20px; letter-spacing: 2px; }
    .player-claim { font-size: 9px; }
    .revolver { padding: 2px 5px; gap: 1px; }
    .chamber { width: 7px; height: 7px; }
    .revolver-count { font-size: 8px; margin-left: 3px; }
    .stats-meters { gap: 6px; }
    .stats-identity { gap: 6px; }
    .you-row::after { content: '↓ accuse target ↓   (reverse turn order)'; font-size: 8px; letter-spacing: 1.5px; }
}

/* ===== revolver chamber ===== */
.revolver {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px 6px;
    background: linear-gradient(180deg, #2a2a2a, #111);
    border: 1px solid #333;
    border-radius: 10px;
    margin-top: 2px;
    width: fit-content;
}
.chamber {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #444, #0a0a0a);
    border: 1px solid #000;
    box-shadow: inset 0 0 2px #000;
    transition: background 0.3s;
}
.chamber.loaded {
    background: radial-gradient(circle at 35% 30%, #ff6b6b 0%, #c41212 50%, #6a0404 100%);
    box-shadow: 0 0 4px rgba(255,0,0,0.5), inset 0 0 2px #000;
}
.revolver-count {
    color: var(--danger);
    font-size: 9px;
    letter-spacing: 1px;
    margin-left: 4px;
    font-weight: 700;
    font-family: 'Inter', sans-serif;
}

/* ===== playing cards ===== */
.card {
    display: inline-flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 4px 5px;
    margin: 3px;
    width: 68px;
    height: 100px;
    border-radius: 6px;
    background: linear-gradient(180deg, #fefefe 0%, #e9e5d8 100%);
    color: #1a1a1a;
    font-family: 'Playfair Display', 'Georgia', serif;
    font-weight: 700;
    text-align: left;
    position: relative;
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), 0 0 0 1px rgba(0,0,0,0.35);
    user-select: none;
    transition: transform 0.18s;
    overflow: hidden;
}
.card:hover { transform: translateY(-2px); }
.card.red { color: #c41212; }
.card.black { color: #0a0a0a; }
.card-rank {
    line-height: 0.95;
    font-size: 17px;
    font-weight: 800;
}
.card-suit-big {
    font-size: 32px;
    text-align: center;
    line-height: 1;
    align-self: center;
    margin: 0;
}
.card-corner-bottom {
    transform: rotate(180deg);
    align-self: flex-end;
    font-size: 15px;
    line-height: 0.95;
    font-weight: 800;
}
.card.ghost { opacity: 0.3; }

/* Special-card ambient effects — gated by body.rule-* classes set by
   rules.js when the corresponding house rule is active. Cards carry
   data-rank and data-suit so we can target them precisely without
   touching render code. */

/* 4s burn — ghostly fire flicker around any 4 in play when the rule is
   on. Beefier than the old version: stacked box-shadows with a wider
   spread + faster flicker + hue-rotate pulse so it really reads as
   "these cards are on fire." ::after adds a subtle upward drift to
   mimic ember rise. */
body.rule-card-fours-burn .card[data-rank="4"] {
    position: relative;
    box-shadow:
        0 0 10px rgba(255,140,40,0.70),
        0 0 22px rgba(255,80,20,0.45),
        0 -4px 18px rgba(255,180,60,0.30),
        inset 0 0 8px rgba(255,180,60,0.30);
    animation: card-fx-flicker 1.2s ease-in-out infinite alternate;
}
body.rule-card-fours-burn .card[data-rank="4"]::after {
    content: '';
    position: absolute;
    inset: -2px;
    pointer-events: none;
    background: radial-gradient(ellipse at 50% 100%, rgba(255,180,60,0.35) 0%, transparent 55%);
    mix-blend-mode: screen;
    animation: card-fx-ember-rise 2.4s ease-in-out infinite;
    border-radius: inherit;
}
@keyframes card-fx-flicker {
    0%   { box-shadow: 0 0 8px rgba(255,140,40,0.50), 0 0 16px rgba(255,80,20,0.35), inset 0 0 6px rgba(255,180,60,0.25); filter: hue-rotate(0deg); }
    50%  { box-shadow: 0 0 14px rgba(255,170,60,0.85), 0 0 28px rgba(255,90,20,0.60), inset 0 0 10px rgba(255,200,80,0.45); filter: hue-rotate(-8deg); }
    100% { box-shadow: 0 0 11px rgba(255,155,50,0.65), 0 0 22px rgba(255,80,20,0.45), inset 0 0 8px rgba(255,190,70,0.35); filter: hue-rotate(4deg); }
}
@keyframes card-fx-ember-rise {
    0%   { opacity: 0.35; transform: translateY(0) scale(0.92); }
    50%  { opacity: 0.70; transform: translateY(-3px) scale(1.04); }
    100% { opacity: 0.35; transform: translateY(0) scale(0.92); }
}

/* 9s burn — same shape as 4s but cool blue-white so the two rules read
   distinct when both are active. "Cold flame" vibe. */
body.rule-player-user-nines-burn .card[data-rank="9"] {
    position: relative;
    box-shadow:
        0 0 10px rgba(120,200,255,0.70),
        0 0 22px rgba(60,140,220,0.45),
        0 -4px 18px rgba(180,220,255,0.30),
        inset 0 0 8px rgba(180,220,255,0.30);
    animation: card-fx-coldflicker 1.2s ease-in-out infinite alternate;
}
body.rule-player-user-nines-burn .card[data-rank="9"]::after {
    content: '';
    position: absolute;
    inset: -2px;
    pointer-events: none;
    background: radial-gradient(ellipse at 50% 100%, rgba(180,220,255,0.35) 0%, transparent 55%);
    mix-blend-mode: screen;
    animation: card-fx-ember-rise 2.4s ease-in-out infinite;
    border-radius: inherit;
}
@keyframes card-fx-coldflicker {
    0%   { box-shadow: 0 0 8px rgba(120,200,255,0.50), 0 0 16px rgba(60,140,220,0.35), inset 0 0 6px rgba(180,220,255,0.25); filter: hue-rotate(0deg); }
    50%  { box-shadow: 0 0 14px rgba(160,220,255,0.85), 0 0 28px rgba(80,160,230,0.60), inset 0 0 10px rgba(200,230,255,0.45); filter: hue-rotate(12deg); }
    100% { box-shadow: 0 0 11px rgba(140,210,255,0.65), 0 0 22px rgba(70,150,225,0.45), inset 0 0 8px rgba(190,225,255,0.35); filter: hue-rotate(-4deg); }
}

/* Aces High — every A gets a gold "doubled value" shimmer. Subtle but
   constant so the player knows the Aces they hold are worth 2x. */
body.rule-card-aces-high .card[data-rank="A"] {
    box-shadow:
        0 0 10px rgba(255,225,140,0.65),
        inset 0 0 6px rgba(212,175,55,0.35);
    animation: card-fx-gold-shimmer 2.2s ease-in-out infinite alternate;
}
@keyframes card-fx-gold-shimmer {
    from { box-shadow: 0 0 8px rgba(255,225,140,0.50), inset 0 0 5px rgba(212,175,55,0.25); }
    to   { box-shadow: 0 0 15px rgba(255,235,170,0.90), inset 0 0 9px rgba(230,190,70,0.55); }
}

/* 3♣ Doubles — just the single 3 of clubs gets a gold ×2 glow, distinct
   from other 3s styling. */
body.rule-card-three-of-clubs-double .card[data-rank="3"][data-suit="Clubs"] {
    box-shadow:
        0 0 10px rgba(255,225,140,0.70),
        0 0 22px rgba(212,175,55,0.40),
        inset 0 0 7px rgba(255,200,80,0.40);
    animation: card-fx-gold-shimmer 1.8s ease-in-out infinite alternate;
}

/* Tantrum Tens — 10 vents bullets onto a neighbor when revealed.
   Texture: pressure release. Long tense flat wait (the bottle shaking),
   then a sudden horizontal jolt + bright red burst (the VENT), then
   back to tension. Irregular cadence — steam pipes don't hiss on a
   metronome. */
body.rule-card-tantrum-tens .card[data-rank="10"] {
    box-shadow:
        0 0 10px rgba(255,80,80,0.65),
        inset 0 0 6px rgba(180,20,20,0.40);
    animation: card-fx-vent 2.2s steps(1, end) infinite;
}
@keyframes card-fx-vent {
    0%, 78% {
        box-shadow: 0 0 9px rgba(220,60,60,0.55), inset 0 0 5px rgba(160,20,20,0.35);
        transform: translateX(0);
    }
    80% {
        box-shadow: 0 0 26px rgba(255,140,80,1), inset 0 0 14px rgba(255,50,30,0.85);
        transform: translateX(-3px);
        filter: brightness(1.3) saturate(1.4);
    }
    82% {
        box-shadow: 0 0 20px rgba(255,120,70,0.9), inset 0 0 10px rgba(220,40,20,0.7);
        transform: translateX(3px);
        filter: brightness(1.2);
    }
    84% {
        box-shadow: 0 0 14px rgba(255,100,70,0.75), inset 0 0 8px rgba(200,30,20,0.55);
        transform: translateX(-1px);
        filter: brightness(1.1);
    }
    86%, 100% {
        box-shadow: 0 0 9px rgba(220,60,60,0.55), inset 0 0 5px rgba(160,20,20,0.35);
        transform: translateX(0);
        filter: brightness(1);
    }
}

/* Queens Spotlight — Q gets a violet search-light sweep. */
body.rule-card-queens-spotlight .card[data-rank="Q"] {
    position: relative;
    box-shadow:
        0 0 10px rgba(200,120,240,0.65),
        inset 0 0 6px rgba(140,60,200,0.35);
    animation: card-fx-violet-pulse 2.0s ease-in-out infinite alternate;
    overflow: hidden;
}
body.rule-card-queens-spotlight .card[data-rank="Q"]::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(110deg, transparent 30%, rgba(220,180,255,0.35) 50%, transparent 70%);
    animation: card-fx-sweep 2.6s linear infinite;
}
@keyframes card-fx-violet-pulse {
    from { box-shadow: 0 0 8px rgba(200,120,240,0.50), inset 0 0 5px rgba(140,60,200,0.25); }
    to   { box-shadow: 0 0 15px rgba(220,140,255,0.85), inset 0 0 9px rgba(160,80,220,0.50); }
}
@keyframes card-fx-sweep {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}

/* Bury The Tell — 5s let you hide a card. Texture: the card stutters
   out of visibility for a single frame every few seconds, like a bulb
   failing. NOT a rhythmic glow. A hard opacity dropout is what reads as
   "this card can disappear on demand." */
body.rule-card-fives-bury-tell .card[data-rank="5"] {
    box-shadow:
        0 0 8px rgba(80,80,100,0.55),
        inset 0 0 5px rgba(30,30,50,0.40);
    animation: card-fx-hide 3.6s steps(1, end) infinite;
}
@keyframes card-fx-hide {
    0%, 78% {
        box-shadow: 0 0 7px rgba(80,80,100,0.45), inset 0 0 4px rgba(30,30,50,0.3);
        filter: brightness(1);
    }
    80% {
        box-shadow: 0 0 4px rgba(40,40,60,0.25), inset 0 0 22px rgba(10,10,20,0.85);
        filter: brightness(0.4) blur(0.5px);
    }
    83%, 100% {
        box-shadow: 0 0 7px rgba(80,80,100,0.45), inset 0 0 4px rgba(30,30,50,0.3);
        filter: brightness(1);
    }
}

/* Triple Sixes — COMBINATION RULE. No passive styling on individual
   6s. The card-background cardiac pulse lives under `.combo-triple-
   sixes` (see COMBO BACKGROUNDS block below) and only renders when a
   player actually has three 6s revealed at once. */

/* 5♦ Bites — the 5 of diamonds smolders ember-red. */
body.rule-card-five-diamonds-chambers .card[data-rank="5"][data-suit="Diamonds"] {
    box-shadow:
        0 0 10px rgba(220,40,40,0.65),
        inset 0 0 8px rgba(140,20,20,0.40);
    animation: card-fx-ember 2.2s ease-in-out infinite alternate;
}
@keyframes card-fx-ember {
    from { box-shadow: 0 0 8px rgba(200,30,30,0.45), inset 0 0 6px rgba(120,15,15,0.30); }
    to   { box-shadow: 0 0 16px rgba(255,60,40,0.80), inset 0 0 10px rgba(160,30,20,0.55); }
}

/* Flytrap Bite — J♣ is a biting card. Jaws aesthetic: left+right green
   side-shadows (the open mouth) hold steady, then a single step clamps
   the frame tight (CHOMP) with a saturation spike. Reads as jaws
   cycling shut, not as a smooth glow. */
body.rule-card-flytrap-bite .card[data-rank="J"][data-suit="Clubs"] {
    box-shadow:
        -5px 0 14px rgba(60,200,90,0.55),
         5px 0 14px rgba(60,200,90,0.55),
         inset 0 0 6px rgba(20,140,40,0.40);
    animation: card-fx-bite 1.6s steps(1, end) infinite;
}
@keyframes card-fx-bite {
    0%, 62% {
        box-shadow:
            -5px 0 14px rgba(60,200,90,0.55),
             5px 0 14px rgba(60,200,90,0.55),
             inset 0 0 6px rgba(20,140,40,0.40);
        filter: saturate(1);
    }
    65% {
        box-shadow:
            0 0 26px rgba(100,255,130,1),
            inset 0 0 14px rgba(20,180,50,0.85);
        filter: saturate(2) brightness(1.25);
    }
    68%, 100% {
        box-shadow:
            -5px 0 14px rgba(60,200,90,0.55),
             5px 0 14px rgba(60,200,90,0.55),
             inset 0 0 6px rgba(20,140,40,0.40);
        filter: saturate(1);
    }
}

/* One-Eyed Jacks Wild — a CRT-glitch treatment. Wildcards break the
   rules of the deck, so the card breaks the rules of display: chromatic
   aberration (RGB split) on the outline, pixel-artifact flickers across
   the surface, and a hard jitter step on the rank/suit glyphs. Every
   layer uses steps() timing so nothing ever smoothly fades — everything
   SNAPS between frames, which is what reads as "glitch" rather than
   "pretty glow".
   isolation:isolate scopes the glyph z-index so it can't bleed through
   onto cards overlapping this one in a fanned settled pile. */
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Hearts"],
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Spades"] {
    position: relative;
    isolation: isolate;
    animation: card-fx-wildcard-aberration 0.18s steps(3, jump-none) infinite;
}
@keyframes card-fx-wildcard-aberration {
    0%   { box-shadow: -1px  0 0 rgba(255, 40, 40, 1), 1px  0 0 rgba(40, 240, 255, 1), 0 0 5px rgba(255,255,255,0.75); transform: translate(0, 0); }
    33%  { box-shadow:  1px -1px 0 rgba(255, 40, 40, 1), -1px 1px 0 rgba(40, 240, 255, 1), 0 0 5px rgba(255,255,255,0.75); transform: translate(0.5px, 0); }
    66%  { box-shadow: -1px  1px 0 rgba(255, 40, 40, 1), 1px -1px 0 rgba(40, 240, 255, 1), 0 0 5px rgba(255,255,255,0.75); transform: translate(-0.5px, 0.5px); }
    100% { box-shadow: -1px  0 0 rgba(255, 40, 40, 1), 1px  0 0 rgba(40, 240, 255, 1), 0 0 5px rgba(255,255,255,0.75); transform: translate(0, 0); }
}

/* Pixel-artifact layer — discrete 2×2 px squares of saturated color
   that snap to new positions every step. Single pseudo-element with a
   stack of box-shadows gives us ~8 crisp pixels at once; the keyframes
   shuffle their offsets so the artifacts appear to dance across the
   surface. No gradients, no mix-blend: each pixel is a defined color
   value against the card's own background.
   z-index:0 keeps it beneath the rank/suit glyphs (which render at the
   default content layer) within the card's isolated stacking context. */
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Hearts"]::before,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Spades"]::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 2px;
    height: 2px;
    pointer-events: none;
    z-index: 0;
    background: transparent;
    animation: card-fx-wildcard-pixels 0.14s steps(4, jump-none) infinite;
}
@keyframes card-fx-wildcard-pixels {
    0%   { box-shadow: -18px -14px 0 rgba(255, 40, 40, 1),  20px -10px 0 rgba(40, 240, 255, 1),  -12px  16px 0 rgba(255, 255, 60, 1),   14px  18px 0 rgba(255, 60, 255, 1),  -22px   4px 0 rgba(60, 255, 120, 1),    8px -22px 0 rgba(255, 255, 255, 1),   22px   8px 0 rgba(60, 180, 255, 1),   -6px   2px 0 rgba(255, 140, 60, 1); }
    25%  { box-shadow:  16px -18px 0 rgba(255, 40, 40, 1),  -8px  14px 0 rgba(40, 240, 255, 1),   22px   6px 0 rgba(255, 255, 60, 1),  -20px  -4px 0 rgba(255, 60, 255, 1),    4px  20px 0 rgba(60, 255, 120, 1),  -14px -16px 0 rgba(255, 255, 255, 1),    2px  22px 0 rgba(60, 180, 255, 1),   18px  -2px 0 rgba(255, 140, 60, 1); }
    50%  { box-shadow:  -4px  22px 0 rgba(255, 40, 40, 1),  18px  12px 0 rgba(40, 240, 255, 1),  -22px  -8px 0 rgba(255, 255, 60, 1),    6px -20px 0 rgba(255, 60, 255, 1),   20px  -4px 0 rgba(60, 255, 120, 1),  -18px   4px 0 rgba(255, 255, 255, 1),  -10px -22px 0 rgba(60, 180, 255, 1),   10px   6px 0 rgba(255, 140, 60, 1); }
    75%  { box-shadow:  22px   4px 0 rgba(255, 40, 40, 1),  -6px -18px 0 rgba(40, 240, 255, 1),   10px  22px 0 rgba(255, 255, 60, 1),  -14px   8px 0 rgba(255, 60, 255, 1),  -20px  18px 0 rgba(60, 255, 120, 1),   16px  -6px 0 rgba(255, 255, 255, 1),    4px -12px 0 rgba(60, 180, 255, 1),  -22px  -8px 0 rgba(255, 140, 60, 1); }
    100% { box-shadow: -18px -14px 0 rgba(255, 40, 40, 1),  20px -10px 0 rgba(40, 240, 255, 1),  -12px  16px 0 rgba(255, 255, 60, 1),   14px  18px 0 rgba(255, 60, 255, 1),  -22px   4px 0 rgba(60, 255, 120, 1),    8px -22px 0 rgba(255, 255, 255, 1),   22px   8px 0 rgba(60, 180, 255, 1),   -6px   2px 0 rgba(255, 140, 60, 1); }
}

/* Loaded Kings — every K chambers a bullet when revealed. Texture:
   heavy gun metal. Thin hard steel outline + drop shadow (no diffuse
   glow), and an occasional sharp recoil kick that flashes the outline
   bright and jolts the card down 1px. Reads as "this is chambered"
   rather than "this is pretty." */
body.rule-card-kings-loaded .card[data-rank="K"] {
    box-shadow:
        0 0 0 1px rgba(180,185,200,0.70),
        0 2px 3px rgba(0,0,0,0.55),
        inset 0 0 4px rgba(40,45,55,0.45);
    animation: card-fx-chamber-kick 2.6s steps(1, end) infinite;
}
@keyframes card-fx-chamber-kick {
    0%, 84% {
        box-shadow:
            0 0 0 1px rgba(180,185,200,0.70),
            0 2px 3px rgba(0,0,0,0.55),
            inset 0 0 4px rgba(40,45,55,0.45);
        transform: translateY(0);
    }
    86% {
        box-shadow:
            0 0 0 2px rgba(240,245,255,1),
            0 0 10px rgba(255,255,255,0.9),
            0 1px 2px rgba(0,0,0,0.85),
            inset 0 0 8px rgba(220,230,245,0.5);
        transform: translateY(1.5px);
    }
    89%, 100% {
        box-shadow:
            0 0 0 1px rgba(180,185,200,0.70),
            0 2px 3px rgba(0,0,0,0.55),
            inset 0 0 4px rgba(40,45,55,0.45);
        transform: translateY(0);
    }
}

/* Lucky Sevens / Lucky Threes — friendly mint-green halo on the rescuer cards. */
body.rule-card-seven-lucky .card[data-rank="7"],
body.rule-card-three-lucky .card[data-rank="3"] {
    box-shadow:
        0 0 8px rgba(120,220,160,0.55),
        inset 0 0 5px rgba(60,180,100,0.30);
}

/* Face Pull — 2s shimmer when a face is in the bar (always on when rule is
   active; engine-side check still gates the actual swap). */
body.rule-card-two-face-pull .card[data-rank="2"] {
    box-shadow:
        0 0 8px rgba(120,180,255,0.55),
        inset 0 0 5px rgba(60,100,200,0.30);
}

/* Soft Sixes — 6s drift gently under the rule, marking them as exempt
   from the thief count. Pale sky-blue glow + slow vertical bob so you
   always see which cards don't count in your hand. */
body.rule-card-soft-sixes .card[data-rank="6"] {
    box-shadow:
        0 0 9px rgba(140,200,240,0.55),
        inset 0 0 5px rgba(80,140,200,0.30);
    animation: card-fx-drift 3.2s ease-in-out infinite alternate;
}
@keyframes card-fx-drift {
    from { transform: translateY(0);    box-shadow: 0 0 7px rgba(140,200,240,0.45), inset 0 0 4px rgba(80,140,200,0.25); }
    to   { transform: translateY(-3px); box-shadow: 0 0 14px rgba(180,230,255,0.75), inset 0 0 7px rgba(100,160,220,0.45); }
}

/* Floating Fives — user's 5s are thief-exempt. Texture: a feather
   swaying SIDEWAYS in a draft. Horizontal sway + a tiny rotation so
   the card reads as "light enough to float" — differentiated from Soft
   Sixes' vertical drift even though both are thief-exemption rules. */
body.rule-player-user-floating-fives .card[data-rank="5"] {
    box-shadow:
        0 0 9px rgba(240,220,140,0.55),
        inset 0 0 5px rgba(160,130,40,0.30);
    animation: card-fx-feather-sway 4.8s ease-in-out infinite;
    transform-origin: top center;
}
@keyframes card-fx-feather-sway {
    0%   { transform: translateX(0) rotate(0);     box-shadow: 0 0 7px rgba(240,220,140,0.45), inset 0 0 4px rgba(160,130,40,0.25); }
    25%  { transform: translateX(-3px) rotate(-1.5deg); box-shadow: 0 0 12px rgba(255,230,160,0.70), inset 0 0 6px rgba(170,140,50,0.35); }
    50%  { transform: translateX(0) rotate(0);     box-shadow: 0 0 9px rgba(240,220,140,0.55), inset 0 0 5px rgba(160,130,40,0.30); }
    75%  { transform: translateX(3px) rotate(1.5deg);  box-shadow: 0 0 12px rgba(255,230,160,0.70), inset 0 0 6px rgba(170,140,50,0.35); }
    100% { transform: translateX(0) rotate(0);     box-shadow: 0 0 7px rgba(240,220,140,0.45), inset 0 0 4px rgba(160,130,40,0.25); }
}

/* =========================================================================
   GLYPH-LEVEL EFFECTS — the rank + suit text on special cards gets its
   own pulsing text-shadow so the glyphs themselves read as "this card
   is keyed." Layers on top of the card-level ambient glows above.
   Each rule applies a color-specific glyph-pulse to the three text
   spans that render the rank (top-left, center, bottom-right).
   ========================================================================= */

/* Shared selector shorthand isn't valid CSS, so each block spells out
   the three glyph elements. Kept compact by reusing keyframes across
   rules that share a color. */

/* Detonation — 4s Burn. Long smolder at low intensity, then a single
   DETONATION frame (scale + bright flare), then a quick aftershock,
   then back to smolder. The 4 is disposable ammo, so the texture
   should feel like an ignition event, not a steady fire. */
body.rule-card-fours-burn .card[data-rank="4"] .card-rank,
body.rule-card-fours-burn .card[data-rank="4"] .card-suit-big,
body.rule-card-fours-burn .card[data-rank="4"] .card-corner-bottom {
    animation: glyph-detonate 1.8s steps(1, end) infinite;
    display: inline-block;
}
@keyframes glyph-detonate {
    0%, 70% {
        text-shadow: 0 0 3px rgba(255,140,40,0.55), 0 0 6px rgba(255,90,20,0.3);
        transform: scale(1);
    }
    72% {
        text-shadow:
            0 0 10px rgba(255,235,120,1),
            0 0 20px rgba(255,140,40,0.95),
            0 0 36px rgba(255,80,20,0.75);
        transform: scale(1.18);
    }
    76% {
        text-shadow:
            0 0 6px rgba(255,180,60,0.85),
            0 0 14px rgba(255,100,30,0.6);
        transform: scale(1.05);
    }
    80%, 100% {
        text-shadow: 0 0 3px rgba(255,140,40,0.55), 0 0 6px rgba(255,90,20,0.3);
        transform: scale(1);
    }
}

/* Frost bloom — 9s Burn. Redesigned away from the stepped "ice shatter"
   (too close in cadence to the OE jacks glitch). Now: a slow breathing
   frost halo that blooms outward from the glyph, paired with a subtle
   hue drift so the cold reads as alive, not mechanical. Pure smooth
   cubic-bezier. Uses filter: blur + hue-rotate for a dimension no
   other rule is using. */
body.rule-player-user-nines-burn .card[data-rank="9"] .card-rank,
body.rule-player-user-nines-burn .card[data-rank="9"] .card-suit-big,
body.rule-player-user-nines-burn .card[data-rank="9"] .card-corner-bottom {
    animation: glyph-frost-bloom 3s cubic-bezier(0.4, 0.1, 0.4, 1) infinite;
}
@keyframes glyph-frost-bloom {
    0%   {
        text-shadow: 0 0 0 rgba(180,220,255,0);
        filter: hue-rotate(0deg);
    }
    40%  {
        text-shadow:
            0 0 4px rgba(200,235,255,0.95),
            0 0 12px rgba(140,200,240,0.70),
            0 0 24px rgba(80,160,220,0.30);
        filter: hue-rotate(-8deg) blur(0.2px);
    }
    55%  {
        text-shadow:
            0 0 6px rgba(220,240,255,1),
            0 0 18px rgba(160,210,245,0.80),
            0 0 36px rgba(100,180,230,0.40),
            0 0 54px rgba(60,140,220,0.20);
        filter: hue-rotate(0deg);
    }
    100% {
        text-shadow: 0 0 0 rgba(180,220,255,0);
        filter: hue-rotate(8deg);
    }
}

/* Fuse countdown — 5♦ Bites. A single spark travels from left of the
   glyph to right as the fuse burns down, then DETONATES in a bright
   red-orange flash at the right edge before resetting. Visually tells
   you: this card is on a timer, and when it goes off it BITES HARD
   (chambers 3 bullets). Longer 3s cycle so the travel reads. */
body.rule-card-five-diamonds-chambers .card[data-rank="5"][data-suit="Diamonds"] .card-rank,
body.rule-card-five-diamonds-chambers .card[data-rank="5"][data-suit="Diamonds"] .card-suit-big,
body.rule-card-five-diamonds-chambers .card[data-rank="5"][data-suit="Diamonds"] .card-corner-bottom {
    animation: glyph-fuse 3s ease-in infinite;
}
@keyframes glyph-fuse {
    0%   { text-shadow: -12px 0 2px rgba(255,100,40,0.45),  -14px 0 5px rgba(200,40,20,0.25); }
    25%  { text-shadow:  -6px 0 3px rgba(255,140,60,0.75),   -8px 0 6px rgba(220,60,30,0.5); }
    50%  { text-shadow:   0px 0 4px rgba(255,160,70,0.85),    0px 0 8px rgba(220,70,30,0.6); }
    75%  { text-shadow:   6px 0 3px rgba(255,140,60,0.75),    8px 0 6px rgba(220,60,30,0.5); }
    88%  { text-shadow:  12px 0 2px rgba(255,100,40,0.6),    14px 0 5px rgba(200,40,20,0.3); }
    90%, 94% {
        text-shadow:
            0 0 10px rgba(255,240,160,1),
            0 0 20px rgba(255,120,40,0.95),
            0 0 32px rgba(220,40,20,0.75);
    }
    96%, 100% { text-shadow: -12px 0 2px rgba(255,100,40,0.45), -14px 0 5px rgba(200,40,20,0.25); }
}

/* J♣ bite-and-swallow — redesigned from the step-snap jaws. Now an
   organic curve: jaws open WIDE (letter-spacing expands, shadows
   spread), then the glyph is PULLED INWARD to a compressed pinpoint
   (letter-spacing goes negative, scale pinches, shadows collapse to a
   single drip), then releases back to rest. No step timing — smooth
   breathing predator. Uses letter-spacing (no other rule touches it)
   and scale so the card's face literally appears to swallow. */
body.rule-card-flytrap-bite .card[data-rank="J"][data-suit="Clubs"] .card-rank,
body.rule-card-flytrap-bite .card[data-rank="J"][data-suit="Clubs"] .card-suit-big,
body.rule-card-flytrap-bite .card[data-rank="J"][data-suit="Clubs"] .card-corner-bottom {
    animation: glyph-swallow 2.2s cubic-bezier(0.6, 0, 0.35, 1) infinite;
    display: inline-block;
}
@keyframes glyph-swallow {
    0%   {
        text-shadow: -3px 0 2px rgba(60,200,90,0.75), 3px 0 2px rgba(60,200,90,0.75);
        letter-spacing: 0.5px;
        transform: scale(1);
    }
    30%  {
        text-shadow: -6px 0 4px rgba(90,240,130,0.95), 6px 0 4px rgba(90,240,130,0.95);
        letter-spacing: 1.8px;
        transform: scale(1.04);
    }
    45%  {
        text-shadow: 0 0 2px rgba(40,200,80,1), 0 3px 6px rgba(20,140,50,0.8);
        letter-spacing: -0.3px;
        transform: scale(0.96);
    }
    55%  {
        text-shadow: 0 0 1px rgba(20,140,50,0.85), 0 1px 3px rgba(10,80,30,0.65);
        letter-spacing: -0.5px;
        transform: scale(0.90);
    }
    75%  {
        text-shadow: -2px 0 2px rgba(70,220,100,0.7), 2px 0 2px rgba(70,220,100,0.7);
        letter-spacing: 0px;
        transform: scale(1);
    }
    100% {
        text-shadow: -3px 0 2px rgba(60,200,90,0.75), 3px 0 2px rgba(60,200,90,0.75);
        letter-spacing: 0.5px;
        transform: scale(1);
    }
}

/* Lucky Sevens — benevolent slow breath. Mercy rule applies to
   everyone, so the aesthetic is communal and patient: a long 4s cycle
   that gently exhales cool mint outward then inhales back. Longer
   duration than most other glyphs to convey "in no hurry to judge." */
body.rule-card-seven-lucky .card[data-rank="7"] .card-rank,
body.rule-card-seven-lucky .card[data-rank="7"] .card-suit-big,
body.rule-card-seven-lucky .card[data-rank="7"] .card-corner-bottom {
    animation: glyph-mercy-breath 4s ease-in-out infinite;
}
@keyframes glyph-mercy-breath {
    0%, 100% { text-shadow: 0 0 2px rgba(120,220,170,0.45); }
    50%      { text-shadow: 0 0 6px rgba(180,255,210,0.95), 0 0 14px rgba(80,220,150,0.65), 0 0 22px rgba(60,180,120,0.30); }
}

/* Solo Threes — user-only perk, warmer and quicker than Lucky Sevens.
   Three flickers in rapid succession (like a candle staying lit
   against the draft), then a pause. Warm amber-green tint instead of
   the communal cool mint so the player's personal mercy reads as
   intimate rather than table-wide. */
body.rule-player-user-three-lucky .card[data-rank="3"] .card-rank,
body.rule-player-user-three-lucky .card[data-rank="3"] .card-suit-big,
body.rule-player-user-three-lucky .card[data-rank="3"] .card-corner-bottom {
    animation: glyph-candle 2.2s steps(1, end) infinite;
}
@keyframes glyph-candle {
    0%, 9%    { text-shadow: 0 0 5px rgba(220,255,160,0.95), 0 0 12px rgba(180,230,120,0.65); }
    10%, 19%  { text-shadow: 0 0 2px rgba(180,200,140,0.4); }
    20%, 29%  { text-shadow: 0 0 6px rgba(240,255,180,1),    0 0 14px rgba(200,240,140,0.75); }
    30%, 39%  { text-shadow: 0 0 2px rgba(180,200,140,0.4); }
    40%, 49%  { text-shadow: 0 0 5px rgba(220,255,160,0.9),  0 0 12px rgba(180,230,120,0.6); }
    50%, 100% { text-shadow: 0 0 2px rgba(180,200,140,0.4); }
}

/* Weighted swing — Loaded Kings. Redesigned from the step-kick recoil;
   now a slow heavy pendulum. The K rotates gently back and forth as if
   hanging from its own weight, with a filter: drop-shadow that reads
   as actual metallic engraving (not a glowing text-shadow). The
   drop-shadow offsets move OPPOSITE the rotation — inertia. Sine-wave
   cubic-bezier so the swing feels physical, not glitchy. */
body.rule-card-kings-loaded .card[data-rank="K"] .card-rank,
body.rule-card-kings-loaded .card[data-rank="K"] .card-suit-big,
body.rule-card-kings-loaded .card[data-rank="K"] .card-corner-bottom {
    animation: glyph-weighted-swing 3.4s cubic-bezier(0.45, 0, 0.55, 1) infinite;
    display: inline-block;
    transform-origin: center top;
}
@keyframes glyph-weighted-swing {
    0%, 100% {
        transform: rotate(-1.5deg) translateY(0);
        filter:
            drop-shadow(2px 2px 0 rgba(30,35,45,0.95))
            drop-shadow(-1px -1px 0 rgba(220,225,240,0.75));
    }
    25%      {
        transform: rotate(0deg) translateY(0.5px);
        filter:
            drop-shadow(0 2px 0 rgba(30,35,45,0.95))
            drop-shadow(0 -1px 0 rgba(220,225,240,0.75))
            drop-shadow(0 0 3px rgba(180,185,200,0.4));
    }
    50%      {
        transform: rotate(1.5deg) translateY(0);
        filter:
            drop-shadow(-2px 2px 0 rgba(30,35,45,0.95))
            drop-shadow(1px -1px 0 rgba(220,225,240,0.75));
    }
    75%      {
        transform: rotate(0deg) translateY(0.5px);
        filter:
            drop-shadow(0 2px 0 rgba(30,35,45,0.95))
            drop-shadow(0 -1px 0 rgba(220,225,240,0.75))
            drop-shadow(0 0 3px rgba(180,185,200,0.4));
    }
}

/* Prestige gilt — Aces High. A diagonal highlight sweeps across the
   glyph like light catching polished metal. Highlight travels from
   upper-left → center → lower-right (matching a reading-eye diagonal).
   Slow and regal; aces are royalty, not fireworks. */
body.rule-card-aces-high .card[data-rank="A"] .card-rank,
body.rule-card-aces-high .card[data-rank="A"] .card-suit-big,
body.rule-card-aces-high .card[data-rank="A"] .card-corner-bottom {
    animation: glyph-gilt 3s linear infinite;
}
@keyframes glyph-gilt {
    0%   { text-shadow:  -3px -3px 1px rgba(255,255,220,0),   0 0 3px rgba(212,175,55,0.55); }
    25%  { text-shadow:  -3px -3px 2px rgba(255,255,220,0.95), 0 0 4px rgba(212,175,55,0.7), -2px -2px 8px rgba(255,230,150,0.6); }
    50%  { text-shadow:   0px  0px 3px rgba(255,245,200,0.95), 0 0 8px rgba(232,195,75,0.8); }
    75%  { text-shadow:   3px  3px 2px rgba(255,255,220,0.95), 0 0 4px rgba(212,175,55,0.7),  2px  2px 8px rgba(255,230,150,0.6); }
    100% { text-shadow:   3px  3px 1px rgba(255,255,220,0),   0 0 3px rgba(212,175,55,0.55); }
}

/* Hologram shimmer — 3♣ Doubles. Redesigned from the step-snap
   duplicate. Now a smooth holographic wobble: hue-rotates through a
   warm gold band, letter-spacing oscillates subtly, and a persistent
   offset ghost-shadow drifts in sync. Reads as a PROJECTION of a card
   rather than a glitchy double — the doubled-value mechanic shown as
   light that isn't quite real. Uses hue-rotate + letter-spacing so the
   dimensions don't overlap with any other rule. */
body.rule-card-three-of-clubs-double .card[data-rank="3"][data-suit="Clubs"] .card-rank,
body.rule-card-three-of-clubs-double .card[data-rank="3"][data-suit="Clubs"] .card-suit-big,
body.rule-card-three-of-clubs-double .card[data-rank="3"][data-suit="Clubs"] .card-corner-bottom {
    animation: glyph-hologram 2.8s ease-in-out infinite;
    display: inline-block;
}
@keyframes glyph-hologram {
    0%   {
        filter: hue-rotate(-8deg);
        text-shadow: -5px 0 1px rgba(180,140,40,0.40), 0 0 2px rgba(212,175,55,0.6);
        letter-spacing: 0;
    }
    25%  {
        filter: hue-rotate(0deg);
        text-shadow: -8px 0 2px rgba(210,170,70,0.65), 0 0 3px rgba(255,225,140,0.8);
        letter-spacing: 0.4px;
    }
    50%  {
        filter: hue-rotate(8deg);
        text-shadow:
            -10px 1px 3px rgba(255,225,140,0.80),
             0 0 5px rgba(255,245,200,0.95),
             5px 0 2px rgba(180,140,40,0.40);
        letter-spacing: 0;
    }
    75%  {
        filter: hue-rotate(2deg);
        text-shadow: -7px -1px 1px rgba(220,180,80,0.55), 0 0 3px rgba(232,195,75,0.75);
        letter-spacing: 0.4px;
    }
    100% {
        filter: hue-rotate(-8deg);
        text-shadow: -5px 0 1px rgba(180,140,40,0.40), 0 0 2px rgba(212,175,55,0.6);
        letter-spacing: 0;
    }
}

/* Wildcard glitch — One-Eyed Jacks glyphs. Chromatic-aberration text-
   shadow (red + cyan offset) with a hard jitter via steps() timing.
   Replaces the old vague gold gradient which looked identical to Aces
   High and 3♣ Doubles. Now OE jacks read as CRT-broken, not pretty. */
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Hearts"] .card-rank,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Hearts"] .card-suit-big,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Hearts"] .card-corner-bottom,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Spades"] .card-rank,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Spades"] .card-suit-big,
body.rule-card-one-eyed-jacks-wild .card[data-rank="J"][data-suit="Spades"] .card-corner-bottom {
    animation: glyph-wildcard-glitch 0.11s steps(3, jump-none) infinite;
    /* No z-index here — `isolation: isolate` on the parent card gives
       us a clean stacking context, and the ::before pixel layer sits at
       z-index:0, so glyphs render above it at the default layer without
       leaking z-index outside the card. */
}
@keyframes glyph-wildcard-glitch {
    0%   { text-shadow: -2px 0 0 rgba(255, 40, 40, 1),  2px 0 0 rgba(40, 240, 255, 1), 0 0 3px rgba(255,255,255,0.95); transform: translate(0, 0); }
    33%  { text-shadow:  2px -1px 0 rgba(255, 40, 40, 1), -2px 1px 0 rgba(40, 240, 255, 1), 0 0 3px rgba(255,255,255,0.95); transform: translate(0.5px, -0.3px); }
    66%  { text-shadow: -1px  2px 0 rgba(255, 40, 40, 1),  1px -2px 0 rgba(40, 240, 255, 1), 0 0 3px rgba(255,255,255,0.95); transform: translate(-0.3px, 0.5px); }
    100% { text-shadow: -2px 0 0 rgba(255, 40, 40, 1),  2px 0 0 rgba(40, 240, 255, 1), 0 0 3px rgba(255,255,255,0.95); transform: translate(0, 0); }
}

/* Sky-blue drift — Soft Sixes (6s) */
body.rule-card-soft-sixes .card[data-rank="6"] .card-rank,
body.rule-card-soft-sixes .card[data-rank="6"] .card-suit-big,
body.rule-card-soft-sixes .card[data-rank="6"] .card-corner-bottom {
    animation: glyph-sky 2.6s ease-in-out infinite alternate;
}
@keyframes glyph-sky {
    from { text-shadow: 0 0 3px rgba(140,200,240,0.50); }
    to   { text-shadow: 0 0 8px rgba(180,230,255,0.90), 0 0 14px rgba(100,160,220,0.50); }
}

/* Feather gold — Floating Fives (user-only) */
/* Feather sway — Floating Fives glyph. Matches the card's 4.8s
   horizontal sway cycle: text-shadow drifts left-right with a subtle
   tilt hint, like a feather swinging back and forth. Slower than a
   pulse — the glyph should feel weightless, not energetic. */
body.rule-player-user-floating-fives .card[data-rank="5"] .card-rank,
body.rule-player-user-floating-fives .card[data-rank="5"] .card-suit-big,
body.rule-player-user-floating-fives .card[data-rank="5"] .card-corner-bottom {
    animation: glyph-feather-sway 4.8s ease-in-out infinite;
}
@keyframes glyph-feather-sway {
    0%   { text-shadow: -1px 0 3px rgba(240,220,140,0.70); }
    25%  { text-shadow: -4px 0 5px rgba(255,235,170,0.85), -2px 0 10px rgba(180,150,60,0.45); }
    50%  { text-shadow:  0px 0 4px rgba(255,235,170,0.80); }
    75%  { text-shadow:  4px 0 5px rgba(255,235,170,0.85),  2px 0 10px rgba(180,150,60,0.45); }
    100% { text-shadow:  1px 0 3px rgba(240,220,140,0.70); }
}

/* Blue pulse — Face Pull (2s) */
/* Magnet tug — 2s Face Pull. Burn a 2 to pull faces from the bar; the
   glyph gets PULLED upward as if attracted to the bar above. Text-
   shadow leans down (anchoring) while the glyph itself translateY's
   upward, then snaps back. Reads as magnetic attraction, not a pulse. */
body.rule-card-two-face-pull .card[data-rank="2"] .card-rank,
body.rule-card-two-face-pull .card[data-rank="2"] .card-suit-big,
body.rule-card-two-face-pull .card[data-rank="2"] .card-corner-bottom {
    animation: glyph-magnet-tug 1.8s ease-in-out infinite;
    display: inline-block;
}
@keyframes glyph-magnet-tug {
    0%   { text-shadow: 0 2px 2px rgba(60,140,220,0.5);       transform: translateY(0); }
    40%  { text-shadow: 0 4px 6px rgba(80,160,230,0.75),      0 6px 12px rgba(40,100,200,0.4); transform: translateY(-3px); }
    55%  { text-shadow: 0 5px 8px rgba(120,200,255,0.95),     0 9px 16px rgba(60,140,220,0.6); transform: translateY(-4px); }
    70%  { text-shadow: 0 3px 5px rgba(100,180,245,0.8);      transform: translateY(-1px); }
    100% { text-shadow: 0 2px 2px rgba(60,140,220,0.5);       transform: translateY(0); }
}

/* Searchlight sweep — Queens Spotlight. A bright highlight travels from
   left to right across the glyph (text-shadow with animated X offset),
   matching the card-level ::after sweep. The glyph "catches the beam"
   as the stage light passes. Linear timing so the sweep feels like a
   mechanical fixture rotating, not a gentle pulse. */
body.rule-card-queens-spotlight .card[data-rank="Q"] .card-rank,
body.rule-card-queens-spotlight .card[data-rank="Q"] .card-suit-big,
body.rule-card-queens-spotlight .card[data-rank="Q"] .card-corner-bottom {
    animation: glyph-searchlight 2.6s linear infinite;
}
@keyframes glyph-searchlight {
    0%   { text-shadow:   -8px 0 4px rgba(220,140,255,0.35); }
    35%  { text-shadow:   -2px 0 3px rgba(240,180,255,0.9),   0 0 6px rgba(220,140,255,0.7); }
    50%  { text-shadow:    0px 0 6px rgba(255,220,255,1),     0 0 14px rgba(200,120,240,0.95); }
    65%  { text-shadow:    2px 0 3px rgba(240,180,255,0.9),   0 0 6px rgba(220,140,255,0.7); }
    100% { text-shadow:    8px 0 4px rgba(220,140,255,0.35); }
}

/* Eights Eternal has no glyph-level effect — its signature lives on
   the card background as a rising violet wisp (see the ::before rule
   further down). Per the "background texture over glyph glare"
   direction: revive-the-grave reads better as a slow undertow in the
   card surface than as text-shadow fireworks. */

/* Pressure build/release — Tantrum Tens. Redesigned from the stepped
   horizontal jitter. Now an asymmetric curve: filter: saturate ramps
   up SLOWLY for most of the cycle (pressure building inside the bottle),
   then the glyph pops and releases on a quick ease-out (the vent). No
   step timing — the compression is what sells the release. Uses
   saturate + brightness filter + scale so nothing else on the card
   reaches for these dimensions. */
body.rule-card-tantrum-tens .card[data-rank="10"] .card-rank,
body.rule-card-tantrum-tens .card[data-rank="10"] .card-suit-big,
body.rule-card-tantrum-tens .card[data-rank="10"] .card-corner-bottom {
    animation: glyph-pressure 2.4s cubic-bezier(0.75, 0, 0.25, 1) infinite;
    display: inline-block;
}
@keyframes glyph-pressure {
    0%   {
        filter: saturate(1) brightness(1);
        text-shadow: 0 0 2px rgba(200,60,60,0.4);
        transform: scale(1);
    }
    45%  {
        filter: saturate(1.5) brightness(1.12);
        text-shadow: 0 0 4px rgba(220,70,50,0.7);
        transform: scale(1.015);
    }
    62%  {
        filter: saturate(2.2) brightness(1.35);
        text-shadow:
            0 0 8px rgba(255,100,60,0.95),
            0 0 18px rgba(255,80,40,0.65);
        transform: scale(1.08);
    }
    68%  {
        filter: saturate(2.6) brightness(1.55);
        text-shadow:
            0 0 14px rgba(255,160,100,1),
            0 0 34px rgba(255,90,40,0.9),
            0 0 60px rgba(255,60,20,0.5);
        transform: scale(1.14);
    }
    76%  {
        filter: saturate(1.6) brightness(1.15);
        text-shadow: 0 0 8px rgba(255,100,60,0.6);
        transform: scale(1.02);
    }
    100% {
        filter: saturate(1) brightness(1);
        text-shadow: 0 0 2px rgba(200,60,60,0.4);
        transform: scale(1);
    }
}

/* Smoke dissolve — Bury The Tell (5s, when Floating Fives isn't also
   on). Redesigned from the hard opacity step. Now a smooth smoke
   spread: letter-spacing grows (the glyph's characters drift apart as
   if turning to vapor), filter: blur() softens to 3px at peak, opacity
   dips gently. All smooth. No step. The glyph appears to EXHALE into
   smoke, then recondenses. */
body.rule-card-fives-bury-tell:not(.rule-player-user-floating-fives) .card[data-rank="5"] .card-rank,
body.rule-card-fives-bury-tell:not(.rule-player-user-floating-fives) .card[data-rank="5"] .card-suit-big,
body.rule-card-fives-bury-tell:not(.rule-player-user-floating-fives) .card[data-rank="5"] .card-corner-bottom {
    animation: glyph-smoke-dissolve 3.8s ease-in-out infinite;
    display: inline-block;
}
@keyframes glyph-smoke-dissolve {
    0%   {
        opacity: 1;
        filter: blur(0);
        letter-spacing: 0;
        text-shadow: 0 0 1px rgba(160,160,180,0.7), 0 1px 0 rgba(30,30,50,0.85);
    }
    45%  {
        opacity: 0.78;
        filter: blur(0.6px);
        letter-spacing: 1px;
        text-shadow: 0 0 4px rgba(140,140,170,0.6);
    }
    55%  {
        opacity: 0.45;
        filter: blur(1.8px);
        letter-spacing: 2.5px;
        text-shadow: 0 0 8px rgba(130,130,160,0.5);
    }
    62%  {
        opacity: 0.22;
        filter: blur(3px);
        letter-spacing: 3.5px;
        text-shadow: none;
    }
    75%  {
        opacity: 0.7;
        filter: blur(1.2px);
        letter-spacing: 1.5px;
        text-shadow: 0 0 5px rgba(140,140,170,0.55);
    }
    100% {
        opacity: 1;
        filter: blur(0);
        letter-spacing: 0;
        text-shadow:
            0 0 1px rgba(160,160,180,0.70),
            0 1px 0 rgba(30,30,50,0.85);
    }
}

/* (Triple Sixes glyph effect removed — combo-only, see .combo-triple-
   sixes in the COMBO BACKGROUNDS section.) */

/* Eights Eternal — 8 revives the freshest grave card on reveal.
   Texture: a violet wisp RISES through the card's back surface like
   something being drawn up from below. Pure background-layer effect
   (::before with an animated gradient); rank/suit glyphs are left
   untouched so the card stays readable and the wisp is what tells you
   "this card belongs to the graveyard rule." */
body.rule-card-eights-eternal .card[data-rank="8"] {
    position: relative;
    isolation: isolate;
    box-shadow:
        0 0 6px rgba(120,80,200,0.35),
        inset 0 0 4px rgba(40,20,80,0.25);
}
body.rule-card-eights-eternal .card[data-rank="8"]::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
    /* Gradient sized 100% × 260% so there's 160% of height to scroll
       through — the wisp enters from below, climbs, fades out above. */
    background: linear-gradient(
        to top,
        rgba(60,  20, 110, 0.55) 0%,
        rgba(120, 70, 200, 0.40) 20%,
        rgba(170, 110, 230, 0.22) 40%,
        rgba(200, 160, 240, 0.08) 60%,
        transparent 85%);
    background-size: 100% 260%;
    background-position: 0% 100%;
    animation: card-fx-grave-rise 4s linear infinite;
    mix-blend-mode: screen;
}
@keyframes card-fx-grave-rise {
    0%   { background-position: 0% 100%; opacity: 0.30; }
    45%  { background-position: 0% 30%;  opacity: 0.85; }
    75%  { background-position: 0% -30%; opacity: 0.45; }
    100% { background-position: 0% -80%; opacity: 0; }
}

/* Threshold Reset — high-value cards (Aces, Ks) carry a thin gold tag
   under this rule, hinting that scores will trigger a chamber clear. */
body.rule-table-threshold-reset .card[data-rank="A"],
body.rule-table-threshold-reset .card[data-rank="K"] {
    box-shadow:
        0 0 7px rgba(212,175,55,0.45),
        inset 0 0 4px rgba(140,110,30,0.25);
}

/* ---------------------------------------------------------------------
   Whisper Pairs — 4s call their matching-suit twin on reveal. Texture:
   a sonar ping. Most of the cycle holds a calm soft green; then a
   single step snaps a wide expanding ring + a glyph flash, like a
   sonar pulse looking for its pair. Scoped to exclude 4s Burn so the
   loud orange detonation wins when both rules are active on the same
   card. */
body.rule-card-whisper-pairs:not(.rule-card-fours-burn) .card[data-rank="4"] {
    box-shadow:
        0 0 6px rgba(100,220,180,0.50),
        inset 0 0 4px rgba(40,160,120,0.30);
    animation: card-fx-sonar 3.2s steps(1, end) infinite;
}
@keyframes card-fx-sonar {
    0%, 74% {
        box-shadow: 0 0 6px rgba(100,220,180,0.45), inset 0 0 4px rgba(40,160,120,0.30);
    }
    76% {
        box-shadow:
            0 0 4px rgba(180,255,210,1),
            0 0 22px rgba(120,240,180,0.85),
            0 0 44px rgba(80,220,150,0.5),
            inset 0 0 6px rgba(60,200,140,0.45);
    }
    80% {
        box-shadow:
            0 0 14px rgba(140,240,190,0.65),
            0 0 28px rgba(100,220,160,0.35),
            inset 0 0 5px rgba(60,200,140,0.35);
    }
    84%, 100% {
        box-shadow: 0 0 6px rgba(100,220,180,0.45), inset 0 0 4px rgba(40,160,120,0.30);
    }
}

body.rule-card-whisper-pairs:not(.rule-card-fours-burn) .card[data-rank="4"] .card-rank,
body.rule-card-whisper-pairs:not(.rule-card-fours-burn) .card[data-rank="4"] .card-suit-big,
body.rule-card-whisper-pairs:not(.rule-card-fours-burn) .card[data-rank="4"] .card-corner-bottom {
    animation: glyph-sonar-ping 3.2s steps(1, end) infinite;
}
@keyframes glyph-sonar-ping {
    0%, 74% { text-shadow: 0 0 2px rgba(100,220,180,0.55); }
    76%     { text-shadow: 0 0 5px rgba(200,255,220,1), 0 0 12px rgba(120,240,180,0.9), 0 0 24px rgba(60,200,140,0.65); }
    80%     { text-shadow: 0 0 3px rgba(160,240,200,0.7); }
    84%, 100% { text-shadow: 0 0 2px rgba(100,220,180,0.55); }
}

/* Paint Pair — COMBINATION RULE. No passive styling on individual
   face cards. The matched pair gets a card-background paint-run under
   .combo-paint-pair-red / .combo-paint-pair-black (see COMBO
   BACKGROUNDS block below). Fires only when a player actually has two
   same-color faces revealed at once. */

/* ---------------------------------------------------------------------
   Scorched Joker — every Joker carries a permanent fire aura because a
   Joker burn now torches every revealed card on the target. Unlike the
   wildcard glitch (OE jacks), this is HOT: roiling orange flame + a
   fast rank-flicker on the star glyph. The Joker looks dangerous even
   at rest. */
body.rule-card-jokers-scorched-earth .card[data-rank="Joker"] {
    box-shadow:
        0 0 14px rgba(255, 110, 40, 0.85),
        0 0 28px rgba(255,  60, 20, 0.55),
        inset 0 0 8px rgba(255, 160, 60, 0.45);
    animation: card-fx-joker-fire 1.3s ease-in-out infinite alternate;
}
@keyframes card-fx-joker-fire {
    from {
        box-shadow:
            0 0 10px rgba(255,100,40,0.65),
            0 0 20px rgba(255,60,20,0.35),
            inset 0 0 6px rgba(255,150,60,0.35);
        filter: hue-rotate(0deg);
    }
    to {
        box-shadow:
            0 0 22px rgba(255,190,70,1),
            0 0 42px rgba(255,90,30,0.80),
            inset 0 0 12px rgba(255,210,90,0.6);
        filter: hue-rotate(-14deg);
    }
}

body.rule-card-jokers-scorched-earth .card[data-rank="Joker"] .card-rank,
body.rule-card-jokers-scorched-earth .card[data-rank="Joker"] .card-suit-big,
body.rule-card-jokers-scorched-earth .card[data-rank="Joker"] .card-corner-bottom {
    animation: glyph-joker-burn 0.7s steps(2, jump-none) infinite;
}
@keyframes glyph-joker-burn {
    0%   { text-shadow: 0 0 4px rgba(255,140,40,0.9),  0 0 10px rgba(255,80,20,0.7),   0 -2px 3px rgba(255,200,80,0.5); }
    50%  { text-shadow: 0 0 8px rgba(255,200,80,1),    0 0 18px rgba(255,100,30,0.95), 0 -4px 6px rgba(255,230,140,0.7), 0 0 28px rgba(255,60,20,0.6); }
    100% { text-shadow: 0 0 4px rgba(255,140,40,0.9),  0 0 10px rgba(255,80,20,0.7),   0 -2px 3px rgba(255,200,80,0.5); }
}

/* ---------------------------------------------------------------------
   Stealth Hand — your hand is shadow-hidden. Affects user cards that
   render with .card-secret (hand cards not yet in settled). Texture:
   a slow diagonal shadow veil sweeps across, reinforcing that the card
   is cloaked. ::after layer with a dark linear-gradient panning across,
   so the card reads as "under a shadow" without obscuring the rank. */
body.rule-card-stealth-hand .card-secret {
    position: relative;
    isolation: isolate;
}
body.rule-card-stealth-hand .card-secret::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    background: linear-gradient(
        135deg,
        rgba(10,10,20,0)    0%,
        rgba(20,20,35,0.45) 35%,
        rgba(30,30,50,0.55) 50%,
        rgba(20,20,35,0.45) 65%,
        rgba(10,10,20,0)    100%);
    background-size: 260% 260%;
    animation: card-fx-stealth-veil 4.6s ease-in-out infinite;
    z-index: 1;
}
@keyframes card-fx-stealth-veil {
    0%   { background-position:   0% 100%; opacity: 0.55; }
    50%  { background-position: 100%   0%; opacity: 0.85; }
    100% { background-position:   0% 100%; opacity: 0.55; }
}

/* =========================================================================
   COMBO BACKGROUNDS — card-level ::before animations that fire only
   when a combination of cards is present on a single player's revealed
   pile. state.js::detectCombos tags individual cards with _inCombo*
   flags; render.js emits the combo-* class names based on those flags.
   Classes render via ::before so they can layer cleanly on top of (or
   beneath) single-card glyph effects — e.g. a 6 under Soft Sixes still
   gets its sky-drift glyph pulse, AND, if two more 6s are revealed on
   the same player, picks up the cardiac background below.
   ========================================================================= */

/* Triple Sixes in effect — three 6s on one player. Cardiac lub-dub
   red veil sweeping through the card's back surface. Uses ::before
   so it layers under the rank/suit glyphs, and no fixed positioning
   is required on the card body (isolation: isolate creates the local
   stacking context). */
.card.combo-triple-sixes {
    position: relative;
    isolation: isolate;
}
.card.combo-triple-sixes::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
    background: radial-gradient(ellipse at 50% 60%,
        rgba(255, 30, 30, 0.65) 0%,
        rgba(200, 20, 20, 0.35) 35%,
        rgba(120, 10, 10, 0.10) 70%,
        transparent 100%);
    mix-blend-mode: screen;
    animation: combo-fx-cardiac 1.8s steps(1, end) infinite;
}
@keyframes combo-fx-cardiac {
    0%,   7% { opacity: 0.95; transform: scale(1.06); }
    8%,  16% { opacity: 0.20; transform: scale(0.96); }
    17%, 25% { opacity: 0.80; transform: scale(1.04); }
    26%,100% { opacity: 0.20; transform: scale(0.96); }
}

/* Paint Pair in effect — two same-color faces on one player. Paint
   "runs down" the card's back surface in the suit color. Red pair
   and black pair each render a different-colored drip. */
.card.combo-paint-pair-red,
.card.combo-paint-pair-black {
    position: relative;
    isolation: isolate;
}
.card.combo-paint-pair-red::before,
.card.combo-paint-pair-black::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
    background-size: 100% 240%;
    background-position: 0% -80%;
    animation: combo-fx-paint-drip 3.4s ease-in infinite;
    mix-blend-mode: multiply;
}
.card.combo-paint-pair-red::before {
    background: linear-gradient(
        to bottom,
        rgba(170, 20, 20, 0.85) 0%,
        rgba(210, 30, 30, 0.75) 20%,
        rgba(220, 40, 40, 0.55) 45%,
        rgba(200, 30, 30, 0.20) 75%,
        transparent 100%);
}
.card.combo-paint-pair-black::before {
    background: linear-gradient(
        to bottom,
        rgba(10, 10, 20, 0.85) 0%,
        rgba(20, 20, 35, 0.75) 20%,
        rgba(25, 25, 40, 0.55) 45%,
        rgba(20, 20, 35, 0.20) 75%,
        transparent 100%);
}
@keyframes combo-fx-paint-drip {
    0%   { background-position: 0% -80%; opacity: 0.4; }
    55%  { background-position: 0%   0%; opacity: 0.95; }
    100% { background-position: 0%  80%; opacity: 0.5; }
}

/* Four-of-a-Kind in effect — 4 cards of the same rank on one player.
   A shared gold halo orbits each of the 4 cards in sync; rotating
   angular gradient reads as "locked into a set" rather than a generic
   pulse. Gold matches the rank-completion / treasure-set vocabulary. */
.card.combo-four-kind {
    position: relative;
    isolation: isolate;
}
.card.combo-four-kind::before {
    content: '';
    position: absolute;
    inset: -2px;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
    background: conic-gradient(from 0deg,
        rgba(255, 220, 120, 0.0)  0deg,
        rgba(255, 225, 140, 0.55) 60deg,
        rgba(232, 195,  75, 0.85) 120deg,
        rgba(255, 225, 140, 0.55) 180deg,
        rgba(255, 220, 120, 0.0)  240deg,
        rgba(255, 220, 120, 0.0)  360deg);
    animation: combo-fx-quad-orbit 1.8s linear infinite;
    mix-blend-mode: screen;
    opacity: 0.85;
}
@keyframes combo-fx-quad-orbit {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* Straight Four in effect — 4 consecutive ranks on one player. A
   bright sweeping horizontal bar travels left-to-right across the card
   on a 1.2s cycle; same timing across all 4 cards in the run so the
   eye reads them as a connected sequence. */
.card.combo-straight-four {
    position: relative;
    isolation: isolate;
    overflow: hidden;
}
.card.combo-straight-four::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
    background: linear-gradient(110deg,
        transparent 20%,
        rgba(140, 240, 200, 0.55) 45%,
        rgba(200, 255, 230, 0.85) 52%,
        rgba(140, 240, 200, 0.55) 59%,
        transparent 80%);
    background-size: 260% 100%;
    animation: combo-fx-sequence-sweep 1.2s linear infinite;
    mix-blend-mode: screen;
}
@keyframes combo-fx-sequence-sweep {
    from { background-position: -130% 0; }
    to   { background-position:  130% 0; }
}

/* Tilted: rendered during the starter's turn on cards drawn at
   cycle-complete. Visual cue that this card does NOT count against the
   previous player if you call Bust on them — their claim was made before
   this card hit the bar. Matches the engine's previousBarTotal branch
   in handleBustCall. */
.card.card-tilted {
    transform: rotate(-10deg);
    box-shadow: 0 0 0 2px rgba(212,175,55,0.6), 0 3px 8px rgba(0,0,0,0.4);
    position: relative;
}
.card.card-tilted:hover {
    transform: rotate(-10deg) translateY(-2px);
}
.card.joker {
    background: linear-gradient(145deg, #f8d75c 0%, #d4af37 50%, #a88420 100%);
    color: #3a2100;
}
.card.joker .card-rank { font-size: 14px; }
.card.joker .card-suit-big { font-size: 30px; color: #3a2100; }

/* Visibility indicator on your own cards: 🔒 lock only on hidden cards.
   Revealed cards show no icon — they just look normal. */
.card-exposed, .card-secret {
    display: inline-block;
    position: relative;
}
.card-secret::after {
    content: '🔒';
    position: absolute;
    /* Pin INSIDE the card's bottom-left corner with a small inset
       padding so the lock sits cleanly within the card boundary
       instead of hanging off the edge. */
    bottom: 3px;
    left: 3px;
    font-size: 11px;
    line-height: 1;
    z-index: 3;
    pointer-events: none;
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.85));
}

/* Clickable joker affordance — the user can tap their Joker to burn it. */
.clickable-joker {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: joker-pulse 2s ease-in-out infinite;
}
/* Click-hint labels under manual-ability cards (Joker / 4 / 9 / 2 / 8)
   were removed 2026-04-27 — the pulse animation + hover glow + cursor:
   pointer carry the affordance, the labels added clutter without new
   information. The pseudo-element rules are kept empty (instead of
   deleted) so a future change can re-enable selectively. */
.clickable-joker:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-joker:hover:not(.disabled) .card.joker {
    box-shadow:
        0 8px 20px rgba(212,175,55,0.8),
        0 0 0 3px var(--danger),
        0 0 24px rgba(208,48,48,0.6);
}
.clickable-joker.disabled {
    animation: none;
    opacity: 0.75;
    cursor: not-allowed;
}
@keyframes joker-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(212,175,55,0); }
    50%      { box-shadow: 0 0 18px rgba(212,175,55,0.7); }
}

/* 4-burn: a dirtier, scrappier cousin of the Joker burn. Pulse in a
   cool cyan so the player instantly tells it apart from the gold Joker. */
.clickable-four {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: four-pulse 2.2s ease-in-out infinite;
}
/* 4-burn click hint suppressed — see clickable-joker note above. */
.clickable-four:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-four:hover:not(.disabled) .card {
    box-shadow:
        0 8px 20px rgba(80,180,255,0.6),
        0 0 0 3px #4fb8ff,
        0 0 20px rgba(80,180,255,0.55);
}
.clickable-four.disabled { animation: none; opacity: 0.75; cursor: not-allowed; }
@keyframes four-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(80,180,255,0); }
    50%      { box-shadow: 0 0 14px rgba(80,180,255,0.55); }
}

/* 9-burn — same shape as the 4-burn click affordance, but gold instead
   of cyan so the two rules read distinct side by side. */
.clickable-nine {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: nine-pulse 2.2s ease-in-out infinite;
}
/* 9-burn click hint suppressed — see clickable-joker note above. */
.clickable-nine:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-nine:hover:not(.disabled) .card {
    box-shadow:
        0 8px 20px rgba(240,200,80,0.55),
        0 0 0 3px #f0c850,
        0 0 20px rgba(240,200,80,0.50);
}
.clickable-nine.disabled { animation: none; opacity: 0.75; cursor: not-allowed; }
@keyframes nine-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(240,200,80,0); }
    50%      { box-shadow: 0 0 14px rgba(240,200,80,0.55); }
}

/* Freezing Nines (perk) — frost-blue affordance to differentiate from
   the gold 9-burn glow. Same hover/disabled patterns. */
.clickable-freeze {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: freeze-pulse 2.2s ease-in-out infinite;
}
.clickable-freeze:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-freeze:hover:not(.disabled) .card {
    box-shadow:
        0 8px 20px rgba(140,220,255,0.55),
        0 0 0 3px #8cdcff,
        0 0 20px rgba(140,220,255,0.50);
}
.clickable-freeze.disabled { animation: none; opacity: 0.75; cursor: not-allowed; }
@keyframes freeze-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(140,220,255,0); }
    50%      { box-shadow: 0 0 16px rgba(140,220,255,0.7); }
}

/* Face Pull click affordance — blue shimmer, "pull" arrow prompt. */
.clickable-two {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: two-pulse 2.2s ease-in-out infinite;
}
/* Face Pull click hint suppressed — see clickable-joker note above. */
.clickable-two:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-two:hover:not(.disabled) .card {
    box-shadow:
        0 8px 20px rgba(120,200,255,0.55),
        0 0 0 3px #78c8ff,
        0 0 20px rgba(120,200,255,0.50);
}
@keyframes two-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(120,200,255,0); }
    50%      { box-shadow: 0 0 14px rgba(120,200,255,0.55); }
}

/* Eights Eternal click affordance — violet death-revive. */
.clickable-eight {
    display: inline-block;
    position: relative;
    cursor: pointer;
    border-radius: 6px;
    transition: transform 0.15s;
    animation: eight-pulse 2.2s ease-in-out infinite;
}
/* Eights Eternal click hint suppressed — see clickable-joker note above. */
.clickable-eight:hover:not(.disabled) { transform: translateY(-6px) scale(1.05); }
.clickable-eight:hover:not(.disabled) .card {
    box-shadow:
        0 8px 20px rgba(180,130,220,0.55),
        0 0 0 3px #c8a8ff,
        0 0 20px rgba(200,168,255,0.50);
}
@keyframes eight-pulse {
    0%, 100% { box-shadow: 0 0 0 rgba(200,168,255,0); }
    50%      { box-shadow: 0 0 14px rgba(200,168,255,0.55); }
}

/* Peek button on the user's player card. */
.perk-peek-btn {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 5;
    padding: 4px 10px;
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    background: rgba(20,22,30,0.9);
    border: 1px solid rgba(120,200,255,0.6);
    color: #b5dcff;
    border-radius: 3px;
    cursor: pointer;
    box-shadow: 0 0 8px rgba(80,180,255,0.35);
}
.perk-peek-btn:hover { background: rgba(80,180,255,0.2); color: #fff; }

/* Manual-perk armed-button row — sits below the peek button on the
   user's seat. Each perk has its own accent color matching its
   animation glyph color so the player can recognize it without text. */
.perk-armed-row {
    position: absolute;
    top: 36px;
    right: 8px;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 4px;
    align-items: flex-end;
}
.perk-armed-btn {
    padding: 4px 10px;
    font-family: 'Courier Prime', monospace;
    font-size: 10px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    background: rgba(20,22,30,0.95);
    border: 1.5px solid;
    border-radius: 3px;
    cursor: pointer;
    white-space: nowrap;
    animation: perkArmedPulse 1.6s ease-in-out infinite;
}
.perk-armed-hammer { color: #ff9650; border-color: rgba(255,150,80,0.85);
                     box-shadow: 0 0 10px rgba(255,150,80,0.5); }
.perk-armed-hammer:hover { background: rgba(255,150,80,0.18); color: #ffd0b0; }
.perk-armed-loki   { color: #8cffba; border-color: rgba(140,255,180,0.85);
                     box-shadow: 0 0 10px rgba(140,255,180,0.5); }
.perk-armed-loki:hover   { background: rgba(140,255,180,0.18); color: #c8ffd6; }
.perk-armed-charon { color: #e0c850; border-color: rgba(220,200,80,0.85);
                     box-shadow: 0 0 10px rgba(220,200,80,0.5); }
.perk-armed-charon:hover { background: rgba(220,200,80,0.18); color: #fff0a0; }
@keyframes perkArmedPulse {
    0%, 100% { filter: brightness(1); }
    50%      { filter: brightness(1.4); }
}

/* Peek-result toast: centered card reveal, auto-dismisses in ~3s. */
#peek-top-toast {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%) scale(0.88);
    padding: 16px 22px 20px;
    background: rgba(14,18,28,0.95);
    border: 2px solid #4fb8ff;
    border-radius: 8px;
    box-shadow: 0 0 40px rgba(80,180,255,0.5), 0 10px 30px rgba(0,0,0,0.7);
    z-index: 320;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s, transform 0.25s;
    text-align: center;
    font-family: 'Courier Prime', monospace;
}
#peek-top-toast.show {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}
#peek-top-toast .peek-label {
    font-family: 'Oswald', sans-serif;
    font-size: 11px;
    letter-spacing: 3px;
    color: #4fb8ff;
    margin-bottom: 10px;
}
#peek-top-toast .peek-card .card { transform: scale(1.6); }

.card-back {
    display: inline-block;
    width: 68px;
    height: 100px;
    margin: 3px;
    border-radius: 6px;
    background:
        repeating-linear-gradient(45deg, rgba(212,175,55,0.2) 0 3px, transparent 3px 6px),
        repeating-linear-gradient(-45deg, rgba(212,175,55,0.2) 0 3px, transparent 3px 6px),
        linear-gradient(180deg, #6a1d2a 0%, #3a0510 100%);
    border: 1px solid rgba(212,175,55,0.4);
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), inset 0 0 8px rgba(0,0,0,0.5);
    position: relative;
}
.card-back::after {
    content: '♦';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: var(--gold);
    font-size: 34px;
    text-shadow: 0 0 4px rgba(0,0,0,0.8);
}

/* =====================================================================
 * Per-pantheon card-back styles (Book 2). Applied via body.card-back-{key}
 * which the campaign-app sets at battle-start based on the location's
 * cardBack tag (locations.js → CARD_BACK_BY_LOCATION). Each pantheon
 * gets a distinct base gradient + glyph + repeating pattern overlay so
 * the deck visually changes when you walk into a different House.
 * ===================================================================== */

/* === DUAT (Egyptian) — gold-amber, ankh, hieroglyph diamond grid === */
body.card-back-duat .card-back {
    background:
        repeating-linear-gradient(0deg,   rgba(80,30,8,0.18) 0 1px, transparent 1px 14px),
        repeating-linear-gradient(90deg,  rgba(80,30,8,0.18) 0 1px, transparent 1px 14px),
        repeating-linear-gradient(45deg,  rgba(255,180,60,0.12) 0 2px, transparent 2px 16px),
        linear-gradient(180deg, #c8881e 0%, #6a3d08 100%);
    border: 1px solid rgba(255,210,120,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), inset 0 0 10px rgba(80,30,8,0.65);
}
/* Duat ankh as inline SVG so it renders without depending on a
   symbol font being installed (☥ U+2625 falls back to a box on
   plenty of systems). Centered via the existing absolute layout +
   width/height. Color baked into the SVG fill to avoid the
   currentColor-in-data-URI inconsistency. */
body.card-back-duat .card-back::after {
    content: '';
    width: 28px;
    height: 38px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 32'><ellipse cx='12' cy='8' rx='6' ry='6' fill='none' stroke='%23ffe080' stroke-width='2.4'/><line x1='12' y1='13' x2='12' y2='28' stroke='%23ffe080' stroke-width='2.6' stroke-linecap='round'/><line x1='5' y1='19' x2='19' y2='19' stroke='%23ffe080' stroke-width='2.6' stroke-linecap='round'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 6px rgba(255,200,80,0.85)) drop-shadow(0 1px 2px #000);
}

/* === ASGARD (Norse) — cool steel, runic chevrons === */
body.card-back-asgard .card-back {
    background:
        repeating-linear-gradient(60deg,  rgba(160,200,240,0.22) 0 2px, transparent 2px 12px),
        repeating-linear-gradient(-60deg, rgba(160,200,240,0.22) 0 2px, transparent 2px 12px),
        linear-gradient(180deg, #2a4060 0%, #0e1828 100%);
    border: 1px solid rgba(160,200,240,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), inset 0 0 10px rgba(20,40,60,0.7);
}
/* Asgard Mjolnir (Thor's hammer) as inline SVG — symbolic forge weapon. */
body.card-back-asgard .card-back::after {
    content: '';
    width: 28px;
    height: 36px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 32'><rect x='4' y='4' width='16' height='9' rx='1' fill='%23c0e0ff' stroke='%2380a8d0' stroke-width='1'/><rect x='6' y='5' width='12' height='2' fill='%23ffffff' opacity='0.5'/><rect x='10.5' y='13' width='3' height='15' fill='%23c0e0ff' stroke='%2380a8d0' stroke-width='1'/><rect x='9' y='28' width='6' height='2' rx='0.5' fill='%2380a8d0'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 8px rgba(140,200,255,0.9)) drop-shadow(0 1px 2px #000);
}

/* === OLYMPUS (Greek) — marble white-gold, meander key pattern === */
body.card-back-olympus .card-back {
    background:
        /* Greek key fragments: short L-shapes via crossing strips */
        linear-gradient(90deg,  transparent 16%, rgba(212,175,55,0.45) 16% 18%, transparent 18%),
        linear-gradient(0deg,   transparent 16%, rgba(212,175,55,0.45) 16% 18%, transparent 18%),
        repeating-linear-gradient(0deg,  rgba(255,240,200,0.06) 0 1px, transparent 1px 8px),
        linear-gradient(180deg, #e8d8a0 0%, #8a6818 100%);
    background-size: 22px 22px, 22px 22px, auto, auto;
    border: 1px solid rgba(212,175,55,0.85);
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), inset 0 0 10px rgba(80,60,12,0.6);
}
body.card-back-olympus .card-back::after {
    content: '☼';   /* solar laurel */
    color: #fff8c0;
    text-shadow: 0 0 8px rgba(255,220,120,0.95), 0 1px 2px #000;
}

/* === YOMI (Japanese) — indigo violet, asanoha-like net === */
body.card-back-yomi .card-back {
    background:
        repeating-linear-gradient(60deg,  rgba(220,180,255,0.22) 0 1px, transparent 1px 12px),
        repeating-linear-gradient(-60deg, rgba(220,180,255,0.22) 0 1px, transparent 1px 12px),
        repeating-linear-gradient(0deg,   rgba(220,180,255,0.18) 0 1px, transparent 1px 12px),
        linear-gradient(180deg, #2a1850 0%, #0a0418 100%);
    border: 1px solid rgba(200,150,255,0.75);
    box-shadow: 0 2px 4px rgba(0,0,0,0.6), inset 0 0 10px rgba(40,20,60,0.7);
}
/* Yomi crescent moon as inline SVG — Yomi is the Japanese underworld
   ruled by Tsukuyomi (moon-god). Drawn as a half-moon arc. */
body.card-back-yomi .card-back::after {
    content: '';
    width: 30px;
    height: 30px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M16 2 A11 11 0 1 0 16 22 A8 8 0 1 1 16 2 Z' fill='%23e8d0ff' stroke='%23a880d8' stroke-width='0.6'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 8px rgba(200,150,255,0.9)) drop-shadow(0 1px 2px #000);
}

/* === MICTLAN (Aztec) — deep red-orange, sunstone radial + marigold === */
body.card-back-mictlan .card-back {
    background:
        radial-gradient(circle at 50% 50%, transparent 28%, rgba(255,200,80,0.22) 30%, transparent 32%),
        radial-gradient(circle at 50% 50%, transparent 44%, rgba(255,200,80,0.18) 46%, transparent 48%),
        repeating-conic-gradient(from 0deg at 50% 50%, rgba(255,160,40,0.15) 0deg 5deg, transparent 5deg 30deg),
        linear-gradient(180deg, #b04020 0%, #4a0810 100%);
    border: 1px solid rgba(255,180,60,0.8);
    box-shadow: 0 2px 4px rgba(0,0,0,0.6), inset 0 0 12px rgba(80,8,8,0.7);
}
body.card-back-mictlan .card-back::after {
    content: '✺';   /* sunburst / marigold */
    color: #ffd060;
    text-shadow: 0 0 8px rgba(255,180,60,0.95), 0 1px 3px #000;
}

/* === SVARGA (Hindu) — rose pink, mandala radial === */
body.card-back-svarga .card-back {
    background:
        repeating-conic-gradient(from 0deg at 50% 50%, rgba(255,200,220,0.22) 0deg 12deg, transparent 12deg 24deg),
        radial-gradient(circle at 50% 50%, rgba(255,200,220,0.3) 0%, transparent 50%),
        linear-gradient(180deg, #a8285a 0%, #38082a 100%);
    border: 1px solid rgba(255,180,200,0.8);
    box-shadow: 0 2px 4px rgba(0,0,0,0.6), inset 0 0 10px rgba(60,8,30,0.7);
}
body.card-back-svarga .card-back::after {
    content: '✿';   /* lotus / sacred-flower (reliable fallback for Om) */
    color: #ffe0ee;
    text-shadow: 0 0 8px rgba(255,180,220,0.95), 0 1px 3px #000;
    font-size: 28px;
}

/* === DIYU (Chinese) — jade green, dragon-scale fish-scale repeat === */
body.card-back-diyu .card-back {
    background:
        radial-gradient(circle at 50% 0%, rgba(180,255,200,0.28) 0 8px, transparent 9px),
        radial-gradient(circle at 0%  10px, rgba(180,255,200,0.28) 0 8px, transparent 9px),
        radial-gradient(circle at 100% 10px, rgba(180,255,200,0.28) 0 8px, transparent 9px),
        repeating-radial-gradient(circle at 50% 50%, rgba(255,255,255,0.06) 0 1px, transparent 1px 10px),
        linear-gradient(180deg, #1a6e3a 0%, #082010 100%);
    background-size: 18px 18px, 18px 18px, 18px 18px, auto, auto;
    border: 1px solid rgba(180,255,200,0.75);
    box-shadow: 0 2px 4px rgba(0,0,0,0.6), inset 0 0 10px rgba(8,30,12,0.7);
}
body.card-back-diyu .card-back::after {
    content: '⚌';   /* greater Yang trigram (reliable fallback for 龍 dragon) */
    color: #c0ffd0;
    text-shadow: 0 0 8px rgba(180,255,200,0.9), 0 1px 3px #000;
    font-size: 30px;
}

/* === BEYOND (Glitch) — corrupted scanlines + chromatic noise === */
body.card-back-beyond .card-back {
    background:
        repeating-linear-gradient(0deg,
            rgba(255,40,160,0.15) 0 1px,
            transparent          1px 3px,
            rgba(40,200,255,0.15) 3px 4px,
            transparent          4px 6px),
        repeating-linear-gradient(0deg, rgba(255,255,255,0.04) 0 1px, transparent 1px 2px),
        linear-gradient(180deg, #200428 0%, #050010 100%);
    border: 1px solid rgba(255,80,200,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.7),
                inset 0 0 14px rgba(80,8,80,0.7),
                0 0 4px rgba(255,40,160,0.45),
                0 0 4px rgba(40,200,255,0.45);
}
/* Beyond corruption glyph — fractured square grid as inline SVG with
   chromatic-aberration ghost layers stacked underneath. Each fragment
   has slight opacity variance so it reads as a shattered/broken icon. */
body.card-back-beyond .card-back::after {
    content: '';
    width: 28px;
    height: 28px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><rect x='4' y='4' width='6' height='6' fill='%23ff60c0'/><rect x='14' y='4' width='6' height='6' fill='%23ff60c0' opacity='0.7'/><rect x='4' y='14' width='6' height='6' fill='%23ff60c0' opacity='0.55'/><rect x='14' y='14' width='6' height='6' fill='%23ff60c0'/><rect x='10' y='10' width='4' height='4' fill='%23ffffff' opacity='0.85'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter:
        drop-shadow(2px 0 0 rgba(60,200,255,0.8))
        drop-shadow(-2px 0 0 rgba(255,60,80,0.8))
        drop-shadow(0 0 8px rgba(255,80,200,0.95));
}

/* === CONCORD (Ch.10 + Vestibule hub) — black-gold crown motif === */
body.card-back-concord .card-back {
    background:
        repeating-conic-gradient(from 0deg at 50% 50%,
            rgba(212,175,55,0.18) 0deg 8deg,
            transparent           8deg 32deg),
        radial-gradient(circle at 50% 50%, rgba(212,175,55,0.20) 0%, transparent 60%),
        linear-gradient(180deg, #1a1408 0%, #060300 100%);
    border: 1px solid rgba(212,175,55,0.85);
    box-shadow: 0 2px 4px rgba(0,0,0,0.7), inset 0 0 12px rgba(0,0,0,0.85);
}
body.card-back-concord .card-back::after {
    content: '✦';   /* 4-point star (reliable fallback for ♕ crown) */
    color: #ffd860;
    text-shadow: 0 0 10px rgba(255,210,80,0.95), 0 1px 2px #000;
    font-size: 32px;
}

/* =====================================================================
 * Book 1 card-back styles. Same pattern as book 2 — body.card-back-{key}
 * + ::after glyph. These cover the major book 1 chapter vibes (heist
 * warehouse, sea, fight pit, voodoo, corvid archives) so the deck
 * visually changes when you walk into a different story's locations.
 * ===================================================================== */

/* === BANDIT (Louie's heist) — crimson/black, crossed-pistols glyph === */
body.card-back-bandit .card-back {
    background:
        repeating-linear-gradient(0deg, rgba(0,0,0,0.35) 0 1px, transparent 1px 10px),
        repeating-linear-gradient(90deg, rgba(0,0,0,0.35) 0 1px, transparent 1px 10px),
        radial-gradient(circle at 50% 50%, #c0181a 0%, #5a0608 90%);
    border: 1px solid rgba(255,180,140,0.6);
    box-shadow: 0 2px 4px rgba(0,0,0,0.55), inset 0 0 10px rgba(60,0,0,0.7);
}
body.card-back-bandit .card-back::after {
    content: '';
    width: 32px;
    height: 32px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><g stroke='%23ffe0c0' stroke-width='2' stroke-linecap='round' fill='none'><line x1='6' y1='6' x2='26' y2='26'/><line x1='26' y1='6' x2='6' y2='26'/></g><circle cx='16' cy='16' r='3' fill='%23ffe0c0' stroke='%23000' stroke-width='1'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 6px rgba(255,200,160,0.9)) drop-shadow(0 1px 2px #000);
}

/* === AQUA (Marina/Audrey docks) — teal/navy, anchor glyph === */
body.card-back-aqua .card-back {
    background:
        repeating-linear-gradient(45deg, rgba(180,240,255,0.18) 0 2px, transparent 2px 14px),
        repeating-linear-gradient(-45deg, rgba(180,240,255,0.18) 0 2px, transparent 2px 14px),
        linear-gradient(180deg, #1a4870 0%, #082030 100%);
    border: 1px solid rgba(160,220,255,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.5), inset 0 0 12px rgba(8,28,48,0.7);
}
body.card-back-aqua .card-back::after {
    content: '';
    width: 26px;
    height: 34px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 34'><g stroke='%23a0e0ff' stroke-width='2.4' stroke-linecap='round' fill='none'><circle cx='13' cy='5' r='2.5'/><line x1='13' y1='8' x2='13' y2='28'/><line x1='8' y1='12' x2='18' y2='12'/><path d='M5 22 Q13 32 21 22'/></g></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 7px rgba(160,220,255,0.9)) drop-shadow(0 1px 2px #000);
}

/* === PIT (Magnus boxing/betting) — bronze/red, art-deco diamond === */
body.card-back-pit .card-back {
    background:
        repeating-linear-gradient(0deg, rgba(20,8,4,0.4) 0 1px, transparent 1px 8px),
        radial-gradient(ellipse at 50% 50%, #b04018 0%, #4a1408 90%);
    border: 1px solid rgba(220,160,80,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.55), inset 0 0 12px rgba(40,8,4,0.75);
}
body.card-back-pit .card-back::after {
    content: '';
    width: 30px;
    height: 30px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><g stroke='%23f4c060' stroke-width='2' fill='none'><path d='M15 3 L27 15 L15 27 L3 15 Z'/><path d='M15 8 L22 15 L15 22 L8 15 Z'/></g><circle cx='15' cy='15' r='1.8' fill='%23f4c060'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 6px rgba(220,160,80,0.9)) drop-shadow(0 1px 2px #000);
}

/* === MAMBO (voodoo) — purple/black, sigil glyph === */
body.card-back-mambo .card-back {
    background:
        repeating-linear-gradient(30deg, rgba(180,80,200,0.18) 0 2px, transparent 2px 14px),
        repeating-linear-gradient(-30deg, rgba(180,80,200,0.18) 0 2px, transparent 2px 14px),
        linear-gradient(180deg, #3a1052 0%, #100418 100%);
    border: 1px solid rgba(220,140,240,0.7);
    box-shadow: 0 2px 4px rgba(0,0,0,0.55), inset 0 0 12px rgba(20,4,28,0.8);
}
body.card-back-mambo .card-back::after {
    content: '';
    width: 30px;
    height: 30px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><g stroke='%23e0a0ff' stroke-width='2' fill='none'><circle cx='15' cy='15' r='10'/><path d='M15 5 L15 25'/><path d='M5 15 L25 15'/><path d='M8 8 L22 22'/><path d='M22 8 L8 22'/></g><circle cx='15' cy='15' r='2' fill='%23e0a0ff'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 8px rgba(200,120,240,0.95)) drop-shadow(0 1px 2px #000);
}

/* === CORVID (Cornelius archives) — slate gray, feather glyph === */
body.card-back-corvid .card-back {
    background:
        repeating-linear-gradient(75deg, rgba(80,90,100,0.32) 0 1px, transparent 1px 6px),
        linear-gradient(180deg, #404858 0%, #1a1e26 100%);
    border: 1px solid rgba(180,200,220,0.55);
    box-shadow: 0 2px 4px rgba(0,0,0,0.55), inset 0 0 12px rgba(10,12,16,0.7);
}
body.card-back-corvid .card-back::after {
    content: '';
    width: 24px;
    height: 36px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 36'><g stroke='%23c8d4e0' stroke-width='1.6' fill='none' stroke-linecap='round'><path d='M12 2 Q14 18 12 34'/><path d='M12 6 Q7 9 6 14'/><path d='M12 10 Q6 13 5 18'/><path d='M12 14 Q6 18 5 22'/><path d='M12 18 Q7 22 6 26'/><path d='M12 6 Q17 9 18 14'/><path d='M12 10 Q18 13 19 18'/><path d='M12 14 Q18 18 19 22'/><path d='M12 18 Q17 22 18 26'/></g></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    filter: drop-shadow(0 0 6px rgba(200,220,240,0.85)) drop-shadow(0 1px 2px #000);
}

/* ===== log ===== */
#log-container { overflow: auto; flex: 1; display: flex; flex-direction: column; }
#log {
    border: 1px solid rgba(212,175,55,0.2);
    padding: 10px 12px;
    flex: 1;
    overflow-y: auto;
    background: rgba(0,0,0,0.4);
    border-radius: 6px;
    color: var(--ivory);
    font-size: 11px;
    line-height: 1.5;
}
#log p {
    margin: 0 0 4px 0;
    padding: 3px 4px;
    border-bottom: 1px solid rgba(255,255,255,0.04);
    display: flex;
    gap: 6px;
    align-items: flex-start;
    line-height: 1.4;
}
#log p.log-latest { color: var(--gold-soft); font-weight: 600; background: rgba(212,175,55,0.06); border-radius: 3px; }
.log-icon {
    flex-shrink: 0;
    width: 20px;
    text-align: center;
    font-size: 13px;
}
.log-body { flex: 1; }
.log-you { color: var(--gold); font-weight: 700; }
.log-opp { color: var(--ivory); font-weight: 600; }
.log-bar { color: var(--gold-soft); }
.log-draw { color: #cfd8e3; }
.log-low { color: var(--accent-green); }
.log-par { color: var(--accent-cyan); }
.log-bust { color: #ff9966; }
.log-correct { color: var(--accent-green); }
.log-wrong { color: #ff8888; }
.log-die { color: var(--danger); font-weight: 700; }
.log-survive { color: #a9e0a9; }
.log-bullet { color: #ff6b6b; }
.log-suit { color: var(--gold); font-weight: 700; }
.log-facepull { color: var(--gold-soft); }
.log-cycle { color: var(--ash); font-style: italic; }
.log-round { color: var(--gold); font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
.log-death { color: var(--danger); font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; }
.log-win { color: var(--gold); font-weight: 700; letter-spacing: 1.5px; }
.log-turn { color: var(--ivory); }
.log-neutral { color: var(--ash); }
.log-skip { color: var(--ash-dim); font-style: italic; }

/* ===== game over ===== */
#game-over {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 700;
    min-width: 480px;
    max-width: min(820px, 96vw);
    max-height: 92vh;
    overflow-y: auto;
    text-align: center;
    padding: 28px 32px;
    background: linear-gradient(180deg, rgba(14,20,16,0.97), rgba(6,10,8,0.99));
    border: 1px solid rgba(212,175,55,0.4);
    border-radius: 12px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.7), 0 0 40px rgba(212,175,55,0.2);
    font-family: 'Playfair Display', serif;
    animation: go-pop 0.45s cubic-bezier(0.2, 0.9, 0.3, 1);
}
#game-over:empty { display: none; }
@keyframes go-pop {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
    60%  { opacity: 1; transform: translate(-50%, -50%) scale(1.06); }
    100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.go-verdict {
    font-size: clamp(28px, 6vw, 46px);
    font-weight: 900;
    letter-spacing: clamp(3px, 0.8vw, 6px);
    margin-bottom: 8px;
    line-height: 1;
}
.go-verdict.won  { color: var(--gold);   text-shadow: 0 0 24px rgba(212,175,55,0.6), 0 2px 0 rgba(0,0,0,0.8); }
.go-verdict.lost { color: var(--danger); text-shadow: 0 0 24px rgba(208,48,48,0.6), 0 2px 0 rgba(0,0,0,0.8); }
.go-verdict.draw { color: var(--ash);    text-shadow: 0 0 16px rgba(120,120,120,0.6), 0 2px 0 rgba(0,0,0,0.8); }
.go-sub {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ash);
    margin-bottom: 18px;
}
.go-sub strong { color: var(--gold-soft); letter-spacing: 1px; }

/* Winner spotlight inside the game-over modal: portrait, name, final total,
   plus their hand + settled piles so you see what they ended with. */
.go-winner {
    display: flex;
    align-items: center;
    gap: 14px;
    justify-content: center;
    padding: 14px 16px;
    margin: 10px auto 6px auto;
    max-width: 740px;
    border-radius: 10px;
    background:
        linear-gradient(180deg, rgba(36,50,38,0.85) 0%, rgba(12,20,14,0.92) 100%);
    border: 1px solid rgba(212,175,55,0.35);
    box-shadow: inset 0 0 22px rgba(0,0,0,0.5);
}
.go-winner-portrait {
    width: 92px;
    height: 92px;
    border-radius: 50%;
    object-fit: cover;
    object-position: top center;
    border: 3px solid var(--gold);
    box-shadow: 0 0 22px rgba(212,175,55,0.6), 0 4px 14px rgba(0,0,0,0.55);
    background: radial-gradient(circle at 40% 30%, rgba(50,68,54,0.9), rgba(10,16,10,1));
    flex-shrink: 0;
}
.go-winner-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-width: 0;
}
.go-winner-name {
    font-family: 'Playfair Display', serif;
    font-size: 22px;
    font-weight: 900;
    letter-spacing: 4px;
    text-transform: uppercase;
    color: var(--gold);
    line-height: 1;
}
.go-winner-total {
    font-family: 'Inter', sans-serif;
    font-size: 12px;
    letter-spacing: 2px;
    color: var(--ivory);
    text-transform: uppercase;
}
.go-cards {
    margin: 10px auto 0 auto;
    max-width: 760px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.go-cards-row {
    display: flex;
    align-items: center;
    gap: 10px;
    justify-content: center;
    padding: 8px 10px;
    background: rgba(0,0,0,0.35);
    border-radius: 8px;
    border: 1px dashed rgba(255,255,255,0.08);
}
.go-cards-label {
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    letter-spacing: 2px;
    color: var(--ash);
    text-transform: uppercase;
    min-width: 72px;
    text-align: left;
    flex-shrink: 0;
}
.go-cards-line {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    justify-content: center;
    flex: 1;
}
/* Overlapping-stacks layout: cards in a row collapse into a fan so a long
   hand reads compactly. Multiple rows when one row would overflow. */
.go-cards-stacks {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    min-width: 0;
}
.go-cards-stack {
    display: flex;
    justify-content: center;
    padding-left: 28px;        /* counter-balance the negative margin so the row stays centered */
}
.go-cards-stack > * {
    margin-left: -28px;
    transition: transform 0.18s ease, z-index 0s ease 0.18s;
    position: relative;
    z-index: 1;
}
.go-cards-stack > *:hover {
    transform: translateY(-6px) scale(1.04);
    z-index: 20;
    transition: transform 0.18s ease, z-index 0s;
}
@media (max-width: 720px) {
    #game-over { min-width: 0; padding: 20px 16px; }
    .go-cards-stack > * { margin-left: -34px; }
    .go-cards-stack { padding-left: 34px; }
}
.go-cards-empty {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    color: var(--ash);
    letter-spacing: 1px;
    padding: 8px;
}
#game-over button {
    display: inline-block;
    margin-top: 18px;
    padding: 10px 24px;
    background: linear-gradient(180deg, var(--gold) 0%, #a88420 100%);
    border: none;
    color: #0a0a0a;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    border-radius: 4px;
    cursor: pointer;
    font-size: 12px;
    font-family: 'Inter', sans-serif;
}

/* ===== discard pile ===== */
.discard-wrap { margin-top: 16px; }
.discard-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 10px;
    margin-bottom: 4px;
}
.discard-title {
    font-size: 11px;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--ash);
    font-weight: 600;
}
.discard-count {
    font-size: 10px;
    color: var(--ash-dim);
    letter-spacing: 1px;
}
.discarded {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    overflow: visible;
    padding: 10px 10px 10px 10px;
    gap: 4px;
    background: rgba(0,0,0,0.3);
    border-radius: 6px;
    margin-top: 8px;
    border: 1px dashed rgba(255,255,255,0.08);
}
.discard-column {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 68px;
}
.discard-column .card,
.discard-column .card-back {
    margin: 0 0 0 0;
    margin-top: -68px;
    transition: transform 0.15s, margin-top 0.15s, z-index 0s;
    position: relative;
}
.discard-column .card:hover {
    z-index: 20;
    transform: translate(-2px, -6px);
    box-shadow: 0 6px 14px rgba(0,0,0,0.7), 0 0 0 1px rgba(212,175,55,0.4);
}

/* ===== counter widget ===== */
.counter-head {
    margin-bottom: 10px;
    border-bottom: 1px solid rgba(212,175,55,0.2);
    padding-bottom: 6px;
}
.counter-title {
    color: var(--gold);
    font-size: 12px;
    letter-spacing: 3px;
    font-weight: 700;
    text-align: center;
    margin-bottom: 6px;
}
.counter-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    gap: 3px;
    font-size: 9px;
    color: var(--ash);
    letter-spacing: 0.5px;
}
.counter-legend span { display: inline-flex; align-items: center; gap: 3px; text-transform: uppercase; }
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; }
.dot-deck { background: #2a3a30; border: 1px solid #1a2a20; }
.dot-bar { background: var(--gold); }
.dot-you { background: var(--accent-green); }
.dot-known { background: var(--accent-cyan); }
.dot-hidden { background: var(--danger); }

.counter-grid {
    width: 100%;
    border-collapse: separate;
    border-spacing: 2px;
    font-size: 10px;
    table-layout: fixed;
}
.counter-grid th {
    width: 16px;
    padding: 2px;
    font-size: 13px;
}
.counter-grid th.red { color: #ff6060; }
.counter-grid th.black { color: var(--ivory); }
.cell, .joker-cell {
    padding: 2px 0;
    text-align: center;
    border-radius: 2px;
    font-family: 'Playfair Display', serif;
    font-weight: 700;
    font-size: 10px;
    color: transparent;
    cursor: default;
    transition: background 0.3s, color 0.3s;
    height: 18px;
}
.cell.cell-deck { background: #2a3a30; color: #4a5a50; border: 1px solid #1a2a20; }
.cell.cell-bar { background: var(--accent-cyan); color: #0a2035; }
.cell.cell-you { background: var(--gold); color: #0a0a0a; }
.cell.cell-known { background: var(--accent-green); color: #0a2010; }
.cell.cell-hidden { background: var(--danger-dim); color: #f8c5c5; }

.counter-jokers {
    margin-top: 8px;
    color: var(--ash);
    font-size: 10px;
    letter-spacing: 2px;
    display: flex;
    align-items: center;
    gap: 6px;
    justify-content: center;
}
.joker-cell {
    display: inline-block;
    width: 24px;
    height: 22px;
    line-height: 22px;
    font-weight: 700;
}

.counter-summary {
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid rgba(212,175,55,0.2);
    font-size: 11px;
    letter-spacing: 1px;
}
.sum-row { display: flex; justify-content: space-between; padding: 2px 0; color: var(--ash); }
.sum-row strong { color: var(--gold); }

/* ===== animation overlay ===== */
#anim-overlay {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 720;
    overflow: hidden;
}
#anim-canvas {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 721;
}
.flying-card {
    position: fixed;
    z-index: 725;
    pointer-events: none;
}
.flying-card .card, .flying-card .card-back {
    margin: 0;
    box-shadow: 0 8px 20px rgba(0,0,0,0.6);
}
.flash-overlay {
    position: fixed;
    pointer-events: none;
    z-index: 722;
    border-radius: 8px;
}
/* Self-call badge (Low / Par / Thief / Liar when no target) — big glyph +
   bold label rising above the caller so it's immediately clear WHY the
   chamber count is about to change. */
.call-badge {
    position: fixed;
    pointer-events: none;
    z-index: 724;
    transform: translate(-50%, -50%);
    text-align: center;
    font-family: 'Playfair Display', serif;
    filter: drop-shadow(0 4px 12px rgba(0,0,0,0.8));
}
.call-badge-glyph {
    font-size: 64px;
    line-height: 1;
    margin-bottom: 4px;
}
.call-badge-text {
    font-size: 28px;
    font-weight: 900;
    letter-spacing: 6px;
    text-transform: uppercase;
}
.call-bullet-preview {
    position: fixed;
    pointer-events: none;
    z-index: 724;
    font-size: 30px;
    line-height: 1;
    filter: drop-shadow(0 0 10px rgba(208,48,48,0.9));
    transform: translate(-50%, -50%);
}

/* ===== misc ===== */
#link {
    position: absolute;
    color: var(--ash);
    font-size: 10px;
    letter-spacing: 1px;
    text-transform: uppercase;
    right: 100px;
    top: 20px;
    text-decoration: none;
    opacity: 0.5;
    z-index: 20;
}
#link:hover { opacity: 1; color: var(--gold); }

#rules-link {
    display: inline-block;
    font-size: 11px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ash);
    text-decoration: none;
    padding: 6px 12px;
    border-bottom: 1px solid rgba(212,175,55,0.25);
    transition: color 0.2s;
}
#rules-link:hover { color: var(--gold); border-color: var(--gold); }

#home-link {
    position: fixed;
    left: 50%;
    bottom: 14px;
    transform: translateX(-50%);
    color: var(--ash);
    font-size: 11px;
    letter-spacing: 2px;
    text-transform: uppercase;
    padding: 6px 14px;
    border: 1px solid rgba(212,175,55,0.25);
    border-radius: 20px;
    background: rgba(0,0,0,0.55);
    text-decoration: none;
    opacity: 0.8;
    z-index: 20;
    transition: all 0.2s;
}
#home-link:hover { opacity: 1; color: var(--gold); border-color: var(--gold); }
/* Hide the off-site link during gameplay and campaign/story mode — it
   sits at bottom-center where it can collide with the action panel and
   pull players out mid-match. Only visible on the title/picker screens. */
body.game-active #home-link,
body.story-mode #home-link,
body.campaign-active #home-link { display: none; }

/* ===== responsive ===== */
@media (max-width: 1100px) {
    #game-container { grid-template-columns: 1fr; }
    #counter-section {
        position: fixed;
        right: 0;
        top: 0;
        bottom: 0;
        width: 260px;
        z-index: 30;
        transform: translateX(100%);
        transition: transform 0.25s ease;
    }
    body:not(.counter-closed) #counter-section { transform: translateX(0); }
    body.counter-closed #counter-section { transform: translateX(100%); }
}
@media (max-width: 800px) {
    .modal-panel { width: 94vw; max-height: 86vh; }
}

/* ===== stage overlay =====
   Full-screen takeover on mobile, centered sized modal on desktop.
   Slots stack top (actor) and bottom (target) so mobile can actually fit the
   portrait + hand + settled cards without side-by-side squeeze.
   Reuses the standard .player markup inside each slot — no bespoke layout.
   Shown while an AI is acting; hidden whenever it's your turn. */
#stage {
    position: fixed;
    inset: 0;
    z-index: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
#stage.hidden { display: none; }
/* While the stage modal is up, hide the classic game's board so it
   doesn't bleed through the stage backdrop. The stage takes over the
   focus — cards, players, bar, actions should all go silent visually
   until hideStage() flips #stage back to .hidden. */
#stage:not(.hidden) ~ #classic-view #cards-section { visibility: hidden; }
#stage-backdrop {
    position: absolute;
    inset: 0;
    /* Same green felt as the body — opaque (no bleed-through of the main
       table beneath) but visually consistent with the game's aesthetic. */
    background: radial-gradient(ellipse at center, var(--felt-mid) 0%, var(--felt-deep) 55%, var(--felt-edge) 100%);
    pointer-events: auto;
}
#stage-panel {
    position: relative;
    width: min(620px, 94vw);
    max-height: 92vh;
    display: flex;
    flex-direction: column;
    gap: 14px;
    /* Extra bottom padding reserves space for the absolute-positioned wheel. */
    padding: 16px 16px 196px 16px;
    overflow-y: auto;
    pointer-events: auto;
}
#stage .stage-slot {
    flex: 0 0 auto;
    overflow: hidden;
}
#stage .stage-slot.empty { display: none; }
/* Enter: slide in from the right. Exit: slide out to the left.
   Applied by stage.js via the .entering / .exiting classes on the slot. */
/* Actor slot enters from the right. Target slot enters from the LEFT —
   opposite direction so the two slide toward each other when an accusation
   or joker burn populates the target. */
#stage #stage-actor.entering .player {
    animation: stage-slide-in-right 0.32s cubic-bezier(0.2,0.65,0.3,1) both;
}
#stage #stage-actor.exiting .player {
    animation: stage-slide-out-left 0.24s cubic-bezier(0.4,0,0.8,0.4) both;
}
#stage #stage-target.entering .player {
    animation: stage-slide-in-left 0.32s cubic-bezier(0.2,0.65,0.3,1) both;
}
#stage #stage-target.exiting .player {
    animation: stage-slide-out-right 0.24s cubic-bezier(0.4,0,0.8,0.4) both;
}
@keyframes stage-slide-in-right {
    from { opacity: 0; transform: translateX(40%) scale(0.96); }
    to   { opacity: 1; transform: translateX(0) scale(1); }
}
@keyframes stage-slide-out-left {
    from { opacity: 1; transform: translateX(0) scale(1); }
    to   { opacity: 0; transform: translateX(-40%) scale(0.96); }
}
@keyframes stage-slide-in-left {
    from { opacity: 0; transform: translateX(-40%) scale(0.96); }
    to   { opacity: 1; transform: translateX(0) scale(1); }
}
@keyframes stage-slide-out-right {
    from { opacity: 1; transform: translateX(0) scale(1); }
    to   { opacity: 0; transform: translateX(40%) scale(0.96); }
}
/* Slight visual separation between actor and target when both present. */
#stage.has-target #stage-target .player {
    border-color: rgba(208,48,48,0.45);
    box-shadow: 0 0 0 1px rgba(208,48,48,0.2);
}
#stage.has-target #stage-actor .player {
    border-color: rgba(212,175,55,0.5);
    box-shadow: 0 0 0 1px rgba(212,175,55,0.2);
}
/* Compact bar inside the stage panel. Row layout: total + deck count stacked
   in the top-left, cards flowing to the right. */
#stage .stage-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    border: 1px solid rgba(212,175,55,0.4);
    padding: 8px 12px;
    min-height: 70px;
    background:
        radial-gradient(ellipse at center, rgba(26,77,51,0.96) 0%, rgba(10,41,27,0.98) 100%),
        rgba(8,24,15,1);
    border-radius: 8px;
    box-shadow: inset 0 0 20px rgba(0,0,0,0.5), 0 4px 10px rgba(0,0,0,0.5);
    flex: 0 0 auto;
}
#stage .bar-compact-left {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    flex-shrink: 0;
    min-width: 60px;
}
#stage .bar-total.compact {
    font-family: 'Playfair Display', serif;
    font-size: 22px;
    color: var(--gold);
    font-weight: 700;
    letter-spacing: 2px;
    line-height: 1;
    text-shadow: 0 1px 3px rgba(0,0,0,0.6);
}
#stage .deck-count.compact {
    font-size: 9px;
    color: var(--ash);
    letter-spacing: 2px;
    margin-top: 4px;
    text-transform: uppercase;
}
#stage .bar-cards.compact {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-start;
    flex: 1;
    min-height: 38px;
    padding-left: 30px;
    overflow-x: auto;
}
#stage .bar-cards.compact > .card,
#stage .bar-cards.compact > .card-back {
    margin-left: -30px;
    flex-shrink: 0;
}

/* 3D cover-flow wheel at the bottom of the stage. All alive players shown;
   current turn centered and scaled up, neighbors recede with rotateY +
   translateZ + opacity falloff. paintWheel() in js/stage.js writes the
   per-tile transform / opacity / z-index inline. */
.stage-wheel {
    position: absolute;
    left: 50%;
    bottom: 64px;
    transform: translateX(-50%);
    width: 420px;
    height: 92px;
    pointer-events: none;
}
.wheel-tile {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 56px;
    height: 56px;
    transform: translate(-50%, -50%);
    transition: transform 0.5s cubic-bezier(0.22, 0.85, 0.35, 1.05),
                opacity 0.45s ease;
    will-change: transform, opacity;
}
.wheel-tile img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    object-position: center 18%;
    border: 2px solid rgba(255,255,255,0.18);
    box-shadow: 0 4px 12px rgba(0,0,0,0.55);
    background: radial-gradient(circle at 40% 35%, rgba(36,50,38,0.9), rgba(6,14,10,0.96));
    display: block;
}
.wheel-tile.current img {
    border-color: var(--gold);
    box-shadow: 0 0 18px rgba(212,175,55,0.75), 0 4px 14px rgba(0,0,0,0.6);
}
/* The local user's tile always carries a soft blue ring so you can locate
   yourself at a glance — blends with the gold "current" ring when it's
   also your turn (gold dominates, blue becomes an outer halo). */
.wheel-tile.you img {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 12px rgba(102,204,255,0.65), 0 4px 12px rgba(0,0,0,0.55);
}
.wheel-tile.you.current img {
    border-color: var(--gold);
    box-shadow:
        0 0 0 2px rgba(102,204,255,0.8),
        0 0 18px rgba(212,175,55,0.85),
        0 4px 14px rgba(0,0,0,0.6);
}
.wheel-tile.dead {
    filter: grayscale(1) brightness(0.45);
}
.wheel-tile .wheel-star {
    position: absolute;
    top: -6px;
    right: -4px;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    background: radial-gradient(circle at 35% 30%, var(--gold-soft) 0%, var(--gold) 60%, #806412 100%);
    color: #2a1c04;
    border-radius: 50%;
    border: 1px solid rgba(0,0,0,0.6);
    box-shadow: 0 0 10px rgba(212,175,55,0.85);
    font-weight: 900;
    line-height: 1;
    z-index: 2;
}
.wheel-tile .wheel-name {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    color: var(--ivory);
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 13px;
    letter-spacing: 2px;
    text-transform: uppercase;
    white-space: nowrap;
    text-shadow: 0 2px 6px rgba(0,0,0,0.9), 0 0 8px rgba(0,0,0,0.6);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease 0.05s;
}
.wheel-tile.current .wheel-name { opacity: 1; }
.wheel-tile.current .wheel-name { top: calc(100% + 2px); font-size: 12px; }

/* Mobile: full-screen takeover, no side padding. */
@media (max-width: 720px) {
    #stage-panel {
        width: 100vw;
        height: 100vh;
        max-height: 100vh;
        /* Extra top padding + safe-area so the bar isn't clipped by the
           browser chrome / notch on phones. */
        padding: calc(env(safe-area-inset-top, 0px) + 48px) 8px calc(env(safe-area-inset-bottom, 0px) + 170px) 8px;
        justify-content: flex-start;
    }
    #stage .stage-bar { padding: 6px 8px; min-height: 60px; }
    #stage .bar-total.compact { font-size: 18px; }
    .stage-wheel { width: 320px; height: 78px; bottom: calc(env(safe-area-inset-bottom, 0px) + 84px); }
    .wheel-tile { width: 48px; height: 48px; }
    .wheel-tile .wheel-star { width: 16px; height: 16px; font-size: 10px; top: -4px; right: -4px; }
}

/* Joker-burn modal self-target tag + disabled card option. */
.burn-target.self { border-color: rgba(102,204,255,0.55); box-shadow: inset 0 0 14px rgba(102,204,255,0.12); }
.burn-self-tag {
    display: inline-block;
    margin-left: 6px;
    font-size: 9px;
    letter-spacing: 2px;
    font-family: 'Inter', sans-serif;
    background: var(--accent-cyan, #66ccff);
    color: #002030;
    padding: 2px 6px;
    border-radius: 3px;
    vertical-align: middle;
    font-weight: 700;
}
.burn-card-opt.disabled {
    opacity: 0.35;
    cursor: not-allowed;
    filter: grayscale(0.4);
}
.burn-card-opt.disabled::after {
    content: attr(data-disabled-reason);
    display: block;
    font-size: 9px;
    letter-spacing: 1px;
    color: var(--ash);
    text-align: center;
    margin-top: 2px;
    text-transform: uppercase;
}

/* Character picker tile: small species sub-label under the canonical name. */
.char-tile .char-species {
    font-family: 'Inter', sans-serif;
    font-size: 9px;
    letter-spacing: 1.5px;
    color: var(--ash);
    text-transform: uppercase;
    margin-top: 2px;
}

/* =====================================================================
   Challenge Mode overlay — single full-screen scrim that morphs through
   config / pick / prep / post / end phases. Uses the same dark-terminal
   aesthetic as the rest of the game.
   ===================================================================== */
#challenge-overlay {
    position: fixed;
    inset: 0;
    z-index: 600;
    background: radial-gradient(ellipse at center, rgba(20,20,20,0.92) 0%, rgba(0,0,0,0.96) 100%);
    display: flex;
    /* `safe center` falls back to flex-start when content overflows the
     * cross-axis — on mobile this keeps the top of a tall .ch-card
     * scrollable instead of clipping above the viewport. */
    align-items: safe center;
    justify-content: center;
    padding: 20px;
    overflow-y: auto;
    /* iOS momentum-scroll for the modal background. */
    -webkit-overflow-scrolling: touch;
    font-family: 'Courier Prime', monospace;
}
#challenge-overlay.hidden { display: none; }
.ch-card {
    background: linear-gradient(180deg, #16161a 0%, #0a0a0c 100%);
    border: 1px solid rgba(212,175,55,0.6);
    border-radius: 4px;
    padding: 28px 32px;
    max-width: 880px;
    width: 100%;
    /* Cap the card to viewport height so its internal scrollers (the perk
     * grid) never push the actions bar off-screen. The flex column lets the
     * grid take the leftover space and the actions bar pin at the bottom. */
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
    box-shadow: 0 0 40px rgba(0,0,0,0.85), 0 0 18px rgba(212,175,55,0.18);
    color: var(--ivory, #c8c8c8);
}
.ch-title {
    font-family: 'Oswald', sans-serif;
    font-weight: 600;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--gold, #d4af37);
    margin: 0 0 8px;
    font-size: 26px;
}
.ch-title.ch-win  { color: #9cff57; }
.ch-title.ch-loss { color: #ff6b6b; }
.ch-sub {
    color: var(--ash, #888);
    font-size: 13px;
    line-height: 1.5;
    margin: 0 0 18px;
}
.ch-config-row {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 12px 0;
}
.ch-config-row label {
    flex: 1;
    color: var(--ivory);
    font-size: 13px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
}
.ch-config-row input[type="number"] {
    width: 80px;
    padding: 6px 10px;
    background: #050505;
    border: 1px solid rgba(212,175,55,0.5);
    color: var(--ivory);
    font-family: inherit;
    font-size: 14px;
    border-radius: 3px;
    text-align: center;
}
.ch-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 24px;
    flex-wrap: wrap;
    /* In the scrollable .ch-card flex column, keep the actions row anchored
     * at the bottom and never let it shrink. Add a top divider so the
     * Confirm button is always visually separated from the grid above. */
    flex-shrink: 0;
    padding-top: 14px;
    border-top: 1px solid rgba(212,175,55,0.18);
    background: linear-gradient(180deg, transparent 0%, rgba(10,10,12,0.85) 60%);
}
.ch-btn {
    padding: 10px 22px;
    font-family: inherit;
    font-size: 12px;
    letter-spacing: 2px;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: 3px;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.ch-btn-ghost {
    background: transparent;
    color: var(--ash);
    border: 1px solid rgba(160,160,160,0.35);
}
.ch-btn-ghost:hover { color: var(--ivory); border-color: var(--ivory); }
.ch-btn-gold {
    background: linear-gradient(180deg, #2a2a2a, #0a0a0a);
    color: var(--gold);
    border: 1px solid var(--gold);
}
.ch-btn-gold:hover:not(:disabled) {
    background: linear-gradient(180deg, var(--gold), #b8923a);
    color: #0a0a0a;
}
.ch-btn-gold:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.ch-perk-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 10px;
    margin: 14px 0;
    /* Take the leftover space in the .ch-card flex column instead of a
     * fixed 480px, so on short viewports the grid shrinks and the actions
     * bar below it stays on-screen. min-height: 0 is the flex-child
     * sizing fix that lets overflow:auto actually take effect. */
    flex: 1 1 auto;
    min-height: 0;
    max-height: min(480px, 60vh);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.ch-perk {
    background: #0d0d10;
    border: 1px solid rgba(212,175,55,0.25);
    border-radius: 3px;
    padding: 10px 12px;
    text-align: left;
    cursor: pointer;
    color: var(--ivory);
    font-family: inherit;
    transition: border-color 0.15s, background 0.15s;
}
.ch-perk:hover { border-color: rgba(212,175,55,0.7); background: #161618; }
.ch-perk.selected {
    border-color: var(--gold);
    background: linear-gradient(180deg, rgba(212,175,55,0.15), rgba(212,175,55,0.05));
    box-shadow: inset 0 0 12px rgba(212,175,55,0.25);
}
.ch-perk-name {
    color: var(--gold);
    font-weight: 600;
    letter-spacing: 1px;
    font-size: 13px;
    margin-bottom: 4px;
}
.ch-perk-blurb {
    color: var(--ash);
    font-size: 11px;
    line-height: 1.45;
}
.ch-perk-small { padding: 8px 10px; }
.ch-prep-header {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 18px;
    border-bottom: 1px solid rgba(212,175,55,0.3);
    padding-bottom: 12px;
    flex-wrap: wrap;
}
.ch-prep-progress {
    color: var(--gold);
    font-family: 'Oswald', sans-serif;
    font-size: 18px;
    letter-spacing: 2px;
    text-transform: uppercase;
}
.ch-prep-loc {
    color: var(--ivory);
    font-size: 13px;
    letter-spacing: 1.5px;
}
.ch-prep-section {
    margin-bottom: 16px;
}
.ch-prep-section h3 {
    font-family: 'Oswald', sans-serif;
    color: var(--ivory);
    font-size: 13px;
    letter-spacing: 2px;
    text-transform: uppercase;
    margin: 0 0 8px;
}
.ch-rule-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.ch-rule-chip {
    background: rgba(212,175,55,0.12);
    border: 1px solid rgba(212,175,55,0.45);
    color: var(--gold);
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 11px;
    letter-spacing: 1px;
}
.ch-rule-chip.ch-empty {
    background: transparent;
    border-color: rgba(120,120,120,0.3);
    color: var(--ash);
}
.ch-perk-inventory {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 8px;
}
.ch-empty {
    color: var(--ash);
    font-style: italic;
    font-size: 12px;
}
.ch-summary-list {
    list-style: none;
    padding: 0;
    margin: 6px 0 0;
    color: var(--ivory);
    font-size: 13px;
}
.ch-summary-list li {
    padding: 4px 0;
    border-bottom: 1px solid rgba(212,175,55,0.15);
}
.ch-summary-list li strong {
    color: var(--gold);
    margin-right: 8px;
    letter-spacing: 1px;
}

/* Challenge mode opponent roster preview (in prep phase). */
.ch-opp-row {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 8px;
}
.ch-opp {
    display: flex;
    align-items: center;
    gap: 10px;
    background: #0d0d10;
    border: 1px solid rgba(120,120,120,0.25);
    border-radius: 3px;
    padding: 6px 8px;
}
.ch-opp.has-perk {
    border-color: rgba(255,140,40,0.55);
    background: linear-gradient(180deg, rgba(255,140,40,0.10), rgba(255,140,40,0.03));
}
.ch-opp-img {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 3px;
    overflow: hidden;
    background: #050505;
}
.ch-opp-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.ch-opp-info {
    min-width: 0;
    flex: 1;
}
.ch-opp-name {
    color: var(--ivory);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ch-opp-sub {
    color: var(--ash);
    font-size: 10px;
    letter-spacing: 1px;
    text-transform: uppercase;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ch-opp-perk {
    color: #ff9944;
    font-size: 10px;
    letter-spacing: 0.5px;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Challenge modal — mobile tightening so a long perk pool still fits a
 * short viewport without burying the action buttons below the fold. */
@media (max-width: 600px) {
    #challenge-overlay { padding: 8px; }
    .ch-card {
        padding: 16px 14px;
        max-height: calc(100vh - 16px);
        max-height: calc(100dvh - 16px);  /* dvh = dynamic viewport on iOS Safari */
    }
    .ch-perk-grid {
        grid-template-columns: 1fr;       /* single column for narrow screens */
        max-height: none;                 /* let the flex column do the math */
        gap: 8px;
        margin: 10px 0;
    }
    .ch-perk { padding: 8px 10px; }
    .ch-perk-name { font-size: 12px; margin-bottom: 2px; }
    .ch-perk-blurb { font-size: 11px; line-height: 1.35; }
    .ch-actions { margin-top: 14px; padding-top: 10px; }
    .ch-btn { padding: 10px 16px; font-size: 11px; letter-spacing: 1.4px; }
    .ch-title { font-size: 20px; }
}

/* =====================================================================
   Tutorial tip overlay — a floating card in the top-right while the
   tutorial is running. Each tip has a title, body, and a Next button.
   One tip on-screen at a time; subsequent tips queue via JS.
   ===================================================================== */
#tutorial-tip {
    position: fixed;
    top: 80px;
    right: 24px;
    max-width: 360px;
    /* Above the stage modal (z-index: 700) so AI turns don't cover
       the tip. Stage appears behind the tip while the player reads. */
    z-index: 800;
    opacity: 0;
    transform: translateX(20px);
    transition: opacity 0.25s ease-out, transform 0.25s ease-out;
    pointer-events: auto;
}
#tutorial-tip.show {
    opacity: 1;
    transform: translateX(0);
}
.tut-tip-card {
    background: linear-gradient(180deg, #16161c 0%, #0a0a10 100%);
    border: 1px solid rgba(255,153,68,0.7);
    border-radius: 6px;
    padding: 16px 18px;
    box-shadow:
        0 0 32px rgba(0,0,0,0.85),
        0 0 18px rgba(255,153,68,0.25);
    color: var(--ivory, #c8c8c8);
    font-family: 'Courier Prime', monospace;
}
.tut-tip-title {
    font-family: 'Oswald', sans-serif;
    font-size: 16px;
    font-weight: 600;
    letter-spacing: 2.5px;
    text-transform: uppercase;
    color: #ff9944;
    margin-bottom: 10px;
    border-bottom: 1px solid rgba(255,153,68,0.35);
    padding-bottom: 6px;
}
.tut-tip-body {
    font-size: 13px;
    line-height: 1.55;
    color: var(--ivory);
    margin-bottom: 14px;
}
.tut-tip-body b {
    color: #ff9944;
    font-weight: 600;
}
.tut-tip-next {
    padding: 6px 16px;
    font-family: inherit;
    font-size: 11px;
    letter-spacing: 2px;
    text-transform: uppercase;
    background: linear-gradient(180deg, #2a2a2a, #0a0a0a);
    color: #ff9944;
    border: 1px solid #ff9944;
    border-radius: 3px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.tut-tip-next:hover {
    background: linear-gradient(180deg, #ff9944, #cc7730);
    color: #0a0a0a;
}

/* Tutorial button gating. While tutorial mode is active, only the
   buttons whose ids are in the "allowed" set are clickable. Dimmed
   buttons are visually muted and pointer-events:none so the player
   can't click past the scripted path. The lead button (the one the
   current tip is steering toward) gets a pulsing glow to draw the
   eye. .tut-dimmed ALWAYS wins over .tut-highlight — we strip both
   together when gating is off, so they never race. */
#actions button.tut-dimmed {
    opacity: 0.28;
    pointer-events: none;
    filter: grayscale(0.6);
}
#actions button.tut-highlight {
    animation: tut-pulse 1.2s ease-in-out infinite;
    box-shadow:
        0 0 0 2px #ff9944,
        0 0 18px rgba(255,153,68,0.75),
        inset 0 0 8px rgba(255,153,68,0.35);
    position: relative;
    z-index: 1;
}
@keyframes tut-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 2px #ff9944,
            0 0 12px rgba(255,153,68,0.55),
            inset 0 0 6px rgba(255,153,68,0.25);
    }
    50% {
        box-shadow:
            0 0 0 2px #ffd280,
            0 0 28px rgba(255,210,128,0.95),
            inset 0 0 12px rgba(255,210,128,0.5);
    }
}
