/* styles.css */
:root {
    --light-square-bg: #f0d9b5;
    --dark-square-bg: #b58863;
    --selected-bg: #fff176;
    --last-move-bg: #ffa;
    --threatened-bg: #ff6b6b;
    --protected-bg: #6b8eff;
    --low-threat-bg: #90EE90;
    --medium-threat-bg: #FFA500;
    --high-threat-bg: #FF4500;
    --potential-threat-bg: #FFD700;
    --primary-color: #2b70c5;
    --secondary-color: #f1911b;
    --success-color: #4CAF50;
    --danger-color: #f44336;
    --warning-color: #ffc107;
    --light-color: #f8f9fa;
    --dark-color: #343a40;
    --transition: all 0.3s ease;
    --hint-from-bg: #ffff00; /* Yellow for from square */
    --hint-to-bg: #00ff00; /* Green for to square */
    /* Metallic gold palette used across the welcome/theme/pieceset/bot/
       difficulty onboarding pages, to match the dark-wood + gold-text
       look used on the game page itself (board-bg.jpg). */
    --gold-bright: #f4dfa8;
    --gold: #d9b06a;
    --gold-deep: #9c7027;
    --wood-page-overlay: radial-gradient(circle at 50% 30%, rgba(90, 60, 30, 0.15), rgba(15, 8, 4, 0.55) 75%);
    /* CSS-only wood look (no image file): a warm top-center glow, thin
       repeating vertical stripes for grain, and a base left-to-right
       brown gradient. Used only on the 5 onboarding pages below
       (welcome/theme/pieceset/bot/difficulty); .game-page keeps the real
       board-bg.jpg photo as its background. */
    --wood-css-bg:
        radial-gradient(ellipse 60% 40% at 50% 22%, rgba(220, 170, 110, 0.45), rgba(220, 170, 110, 0) 55%),
        repeating-linear-gradient(89deg,
            rgba(0, 0, 0, 0.10) 0px, rgba(0, 0, 0, 0.10) 1px,
            rgba(255, 255, 255, 0.025) 2px, rgba(255, 255, 255, 0.025) 3px,
            rgba(0, 0, 0, 0.06) 5px, transparent 8px,
            transparent 11px, rgba(0, 0, 0, 0.08) 13px),
        linear-gradient(90deg,
            #140b06 0%, #2a1a0f 12%, #3d2717 28%,
            #4a3018 48%, #3d2717 68%, #2a1a0f 85%, #140b06 100%);
    --wood-css-bg-size: cover, 6px 100%, cover;
    /* Extra fiber/noise texture layered with mix-blend-mode: overlay. */
    --wood-grain-noise: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='300'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.012 0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.35 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    /* Dark Wooden / Luxe theme — dark-wood bars + warm gold text/icons,
       used by the game page's top bar (.game-info-container), bottom bar
       (.controls-bottom) and the page-nav arrows (.nav-arrow). */
    --wood-bar-bg: linear-gradient(160deg, #3a2415 0%, #241407 55%, #170d05 100%);
    --wood-bar-border: rgba(217, 176, 106, 0.28);
    --gold-text: #e8cf9e;
    --gold-icon-dark: #3a2312;
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    /* Kills the default mobile-browser blue flash on tap (most visible on
       round buttons like .nav-arrow, where its square shape peeks out
       past the rounded corners) — leftover from the old blue theme, now
       replaced everywhere by each element's own :active/:hover state. */
    -webkit-tap-highlight-color: transparent;
}
html {
    height: 100%;
    width: 100%;
}
body {
    /* Base/default typeface for the whole app. Poppins is intentionally
       NOT set here — it's scoped further down to only the welcome page
       and the 4 selection pages (theme/pieceset/bot/difficulty), where
       it's inherited by everything inside them. The game page and every
       modal (premium, unlock, stats, leaderboard, etc.) stay on this
       original stack, since Poppins' bold/extra-bold weights rendered
       noticeably thicker than intended there (e.g. the premium plan
       prices and the game page's own text). */
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    /* Was a light-blue sky gradient (leftover from the old blue theme) —
       showed through during page fade transitions (.page animates
       opacity, so the body behind it is briefly visible) and clashed
       with the dark-wood/gold theme everywhere else. Matches the same
       dark-brown fallback .game-page uses under board-bg.jpg, so any
       peek-through is consistent with the rest of the app. */
    background-color: #3a2317;
    color: #333;
    height: 100%;
    width: 100%;
    overflow: hidden;
    margin: 0;
    padding: 0;
}
/* Poppins scoped to just these 5 pages — everything inside them inherits
   it normally. Deliberately excludes .game-page and every modal (several
   modals, like #premium-modal and #unlock-modal, live outside .game-page
   in the DOM too), which all fall back to the body's stack above. */
.welcome-page,
.theme-page,
.pieceset-page,
.bot-page,
.difficulty-page {
    font-family: 'Poppins', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-image: var(--wood-page-overlay), var(--wood-css-bg);
    background-size: cover, var(--wood-css-bg-size);
    background-position: center, center;
    background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
    border-radius: 0;
    box-shadow: none;
    position: relative;
    isolation: isolate;
}
.welcome-page::before,
.theme-page::before,
.pieceset-page::before,
.bot-page::before,
.difficulty-page::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--wood-grain-noise);
    mix-blend-mode: overlay;
    opacity: 0.5;
    pointer-events: none;
    z-index: -1;
}
.app-container {
    width: 100%;
    height: 100%;
    position: relative;
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    box-sizing: border-box;
}
.page {
    width: 100%;
    height: 100%;
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.5s ease, visibility 0.5s;
    /* Extra bottom padding biases the centered title+cards block upward,
       reserving the room the fixed .nav-arrows / .navigation-dots occupy
       at the very bottom (they're position:fixed/absolute so they don't
       otherwise take up any flex space here). */
    padding: 20px 20px 100px;
    text-align: center;
}
.page.active {
    opacity: 1;
    visibility: visible;
}

/* ---- Very small / very old screens (e.g. old feature phones, BlackBerry
   8300 in landscape, early Android/iPhone devices with short viewports).
   Rather than clipping content that simply can't all fit on one screen,
   make each page scrollable internally so every element stays reachable,
   and shrink the board further to reduce how much scrolling is needed. ---- */
@media (max-height: 550px) {
    .page {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        justify-content: flex-start;
        padding: 8px;
    }
    .welcome-page {
        justify-content: center;
    }
    .chessboard {
        width: 70vmin;
        height: 70vmin;
        max-width: 320px;
        max-height: 320px;
        font-size: calc(70vmin / 8 * 0.9);
    }
    .side-indicator-row {
        width: 70vmin;
        max-width: 320px;
    }
    .board-container {
        margin-top: 4px;
        margin-bottom: 4px;
    }
    .game-info-container {
        padding: 3px 12px;
        margin-bottom: 4px;
    }
    .controls-bottom {
        padding: 4px 10px;
        gap: 1px;
    }
    .control-icon {
        padding: 4px 2px;
    }
    .control-icon i {
        width: 24px;
        height: 24px;
        font-size: 13px;
        margin-bottom: 2px;
    }
    .control-icon span {
        font-size: 9px;
    }
}
.welcome-content {
    text-align: center;
    animation: fadeIn 1s ease;
}
.welcome-logo {
    width: 200px;
    height: auto;
    margin-bottom: 20px;
    /* Golden 3D look: dark contact shadow for depth + a soft warm gold
       glow, on top of the shading already baked into the artwork. */
    filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 18px rgba(244, 223, 168, 0.35));
}
.welcome-title {
    font-size: 3.5rem;
    margin-bottom: 20px;
    text-shadow: 0 2px 3px rgba(0, 0, 0, 0.6), 0 0 18px rgba(217, 176, 106, 0.35);
    color: var(--gold-bright);
    background: linear-gradient(180deg, var(--gold-bright), var(--gold) 60%, var(--gold-deep));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.welcome-subtitle {
    font-size: 1.8rem;
    margin-bottom: 40px;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
    color: var(--gold-bright);
    line-height: 1.6;
}
/* Detached from .welcome-content and pinned near the bottom of the page
   (above the fixed nav arrows) instead of sitting inline right under the
   subtitle, so the centered logo/title block and the loading indicator
   read as two separate zones like a typical splash screen. */
.welcome-loading-container {
    position: absolute;
    left: 50%;
    bottom: 100px;
    transform: translateX(-50%);
    width: 300px;
    max-width: 90vw;
    z-index: 5;
}
.welcome-loading-label {
    text-align: center;
    font-size: 0.85rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(232, 207, 158, 0.75);
    margin: 0 0 8px;
}
.progress-bar {
    width: 300px;
    max-width: 100%;
    height: 6px;
    background: rgba(0, 0, 0, 0.4);
    border: 1px solid rgba(217, 176, 106, 0.3);
    border-radius: 3px;
    margin: 0 auto;
    overflow: hidden;
}
.progress {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, var(--gold-deep), var(--gold-bright));
    border-radius: 3px;
    transition: width 5s linear;
}
.language-page {
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(10px);
    border-radius: 15px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
.page-title {
    font-size: 2.5rem;
    font-weight: 700;
    margin-bottom: 30px;
    text-shadow: 0 2px 3px rgba(0, 0, 0, 0.6), 0 0 18px rgba(217, 176, 106, 0.35);
    color: var(--gold-bright);
    background: linear-gradient(180deg, var(--gold-bright), var(--gold) 60%, var(--gold-deep));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.options-container {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 20px;
    max-width: 800px;
    margin: 0 auto;
}
.option-card {
    width: 150px;
    height: 215px;
    background: rgba(20, 12, 6, 0.55);
    border-radius: 10px;
    padding: 15px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: var(--transition);
    backdrop-filter: blur(3px);
    border: 2px solid rgba(217, 176, 106, 0.35);
    position: relative;
    /* Clips the diagonal free/premium ribbon to the card's rounded
       corner instead of letting it float past the card's edges. */
    overflow: hidden;
}
.option-card:hover {
    transform: translateY(-5px);
    border-color: var(--gold);
    background: rgba(30, 18, 8, 0.65);
}
.option-card.selected {
    border-color: var(--gold-bright);
    background: rgba(30, 18, 8, 0.65);
    box-shadow: 0 0 18px rgba(244, 223, 168, 0.55), inset 0 0 12px rgba(244, 223, 168, 0.15);
}
.option-card.locked {
    /* Eased back from grayscale(0.7)/opacity 0.8 so the icon's own color
       still reads clearly — the lock badge is what signals "locked",
       not a washed-out icon. */
    filter: grayscale(0.35);
    opacity: 0.92;
}
.option-card.locked:hover {
    transform: none;
    border-color: transparent;
}
.lock-overlay {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    z-index: 2;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
    transition: var(--transition);
}
/* Once a previously-locked item is purchased/unlocked, renderLockState()
   in script.js swaps this badge's icon from a closed padlock (fa-lock) to
   an open one (fa-lock-open) and adds .unlocked-badge, instead of just
   removing the .locked class from the card and leaving the closed-lock
   icon showing. Green ties it visually to "purchased" the same way the
   rest of the UI uses green for success/confirmation. */
.lock-overlay.unlocked-badge {
    background: rgba(39, 174, 96, 0.85);
}
/* "Free"/"Premium" corner label — kept in sync with real unlock state by
   setCardLockState() in script.js, not just set once from static HTML.
   A small ribbon angled into the top-left corner (kept compact and
   pulled fully into the corner) so it never reaches the icon, which
   sits centered in the card. */
.option-price-badge {
    position: absolute;
    top: 11px;
    left: -26px;
    width: 92px;
    padding: 2px 0;
    border-radius: 0;
    font-size: 8px;
    font-weight: 700;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: #fff;
    z-index: 2;
    line-height: 1.5;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
    transform: rotate(-45deg);
    transform-origin: center;
}
.option-price-badge.free {
    background: linear-gradient(135deg, var(--gold-bright), var(--gold));
    color: #3a2317;
}
.option-price-badge.premium {
    background: linear-gradient(135deg, var(--gold), var(--gold-deep));
    color: #fff;
}
.option-icon {
    font-size: 3rem;
    margin-bottom: 15px;
    color: #2c3e50;
}
/* Colored icons for the selection pages (theme / bot personality /
   difficulty). Deliberately scoped to these 3 pages only — the game page
   reuses the same .option-icon class for its promotion-modal piece
   choices (queen/rook/bishop/knight), which must stay untouched, so
   nothing here targets .option-icon on its own, only within these
   specific page containers. Colors bumped to more saturated shades so
   they read clearly instead of looking washed out. */
.theme-page .fa-mug-hot.option-icon { color: #a0522d; }
.theme-page .fa-leaf.option-icon { color: #2ecc71; }
.theme-page .fa-heart.option-icon { color: #e91e63; }
.theme-page .fa-water.option-icon { color: #2196f3; }

.bot-page .fa-fire.option-icon { color: #f57c00; }
.bot-page .fa-shield-halved.option-icon { color: #1e88e5; }
.bot-page .fa-chess-king.option-icon { color: #e8b923; }
.bot-page .fa-hat-wizard.option-icon { color: #8e24aa; }

.difficulty-page .fa-seedling.option-icon { color: #2ecc71; }
.difficulty-page .fa-user.option-icon { color: #2196f3; }
.difficulty-page .fa-robot.option-icon { color: #f57c00; }
.difficulty-page .fa-brain.option-icon { color: #d32f2f; }
.option-piece-preview {
    width: 3.2rem;
    height: 3.2rem;
    object-fit: contain;
    margin-bottom: 15px;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
}
.option-name {
    font-size: 1.2rem;
    font-weight: bold;
    color: var(--gold-bright);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
.option-desc {
    font-size: 0.9rem;
    opacity: 0.85;
    margin-top: 5px;
    color: var(--gold);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.2;
    min-height: 2.4em;
}
.navigation-dots {
    display: flex;
    gap: 10px;
    position: absolute;
    bottom: 20px;
}
.dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: rgba(217, 176, 106, 0.35);
    cursor: pointer;
    transition: var(--transition);
}
.dot.active {
    background: var(--gold-bright);
    box-shadow: 0 0 6px rgba(244, 223, 168, 0.8);
    transform: scale(1.2);
}
.game-page {
    background-color: #3a2317;
    /* Plain url() only — deliberately NOT using image-set()/-webkit-
       image-set() for the WebP version here. Pi Browser's embedded webview
       parses that syntax as valid (so it wins the cascade over this url()
       fallback) but then fails to actually decode the WebP resource, which
       left the background blank there while every other browser rendered
       it fine. A plain url() with a broadly-supported format has no such
       silent-decode-failure path, so this stays this way even though it
       costs the WebP file-size saving. */
    background-image: url('board-bg.c0a72b4ecf.jpg');
    background-size: cover;
    background-position: center 20%;
    background-repeat: no-repeat;
    color: #333;
    display: flex;
    flex-direction: column;
    padding: 0;
    justify-content: flex-start;
    user-select: none;
}
.container {
    max-width: 100%;
    height: 100%;
    margin: 0 auto;
    padding: 10px;
    display: flex;
    flex-direction: column;
}

.game-container {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    overflow: visible;
    padding-bottom: calc(env(safe-area-inset-bottom) + 4px);
}

.board-container {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-grow: 1;
    overflow: visible;
    position: relative;
    min-height: 0;
    margin-top: 20px;
    margin-bottom: 20px;
}
.chessboard {
    width: 96vmin;
    height: 96vmin;
    max-width: 650px;
    max-height: 550px;
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(8, 1fr);
    border: 5px solid #333;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
    background-color: white;
    aspect-ratio: 1 / 1;
    flex-shrink: 0;
    font-size: calc(96vmin / 8 * 0.9);
    overflow: visible;
    position: relative;
}
.square {
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    transition: background-color 0.2s;
    position: relative;
    overflow: hidden;
}
.square.white {
    background-color: var(--light-square-bg);
}
.square.black {
    background-color: var(--dark-square-bg);
}
/* Chess.com-style board coordinates: rank numbers (top-left of the left
   edge squares) and file letters (bottom-right of the bottom edge squares).
   Colors automatically use each square's OPPOSITE color for contrast, and
   follow whichever theme is active since they read the same CSS variables
   used for the squares themselves. */
.square[data-rank]::before {
    content: attr(data-rank);
    position: absolute;
    top: 2px;
    left: 3px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
    z-index: 2;
}
.square[data-file]::after {
    content: attr(data-file);
    position: absolute;
    bottom: 2px;
    right: 3px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
    z-index: 2;
}
.square.white[data-rank]::before,
.square.white[data-file]::after {
    color: var(--dark-square-bg);
}
.square.black[data-rank]::before,
.square.black[data-file]::after {
    color: var(--light-square-bg);
}
.square.selected {
    background-color: var(--selected-bg);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.35);
    z-index: 2;
}
.move-marker {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    pointer-events: none;
    z-index: 1;
}
.move-marker.valid-marker {
    width: 24%;
    height: 24%;
    background-color: rgba(20, 20, 20, 0.5);
}
.move-marker.capture-marker {
    width: 86%;
    height: 86%;
    background-color: transparent;
    border: 4px solid rgba(20, 20, 20, 0.5);
    box-sizing: border-box;
}
.square.last-move {
    background-color: var(--last-move-bg) !important;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.2);
}
.square.check {
    background-color: #ff6b6b !important;
}
.theme-blue .square.check {
    background-color: #ff0000 !important;
}
.square.threatened {
    background-color: var(--threatened-bg);
}
.square.protected {
    background-color: var(--protected-bg);
}
.square.hint-from {
    background-color: var(--hint-from-bg) !important;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.25);
}
.square.hint-to {
    background-color: var(--hint-to-bg) !important;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.25);
}
.piece {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: inherit;
    transition: transform 0.2s;
}
.piece-img {
    width: 85%;
    height: 85%;
    object-fit: contain;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
    -webkit-user-select: none;
}
/* Piece-level threat/defense frames, applied to every one of the player's
   own pieces (not just the ones the square-tint classes already mark), so
   the whole board's status is visible at a glance: a red frame means the
   piece is currently attacked, a blue frame means another of the player's
   own pieces defends it, and a piece under attack that's also defended
   gets both rings at once. */
.piece-img.piece-threatened {
    box-shadow: 0 0 0 3px #e53935, 0 0 7px 2px rgba(229, 57, 53, 0.65);
    border-radius: 6px;
}
.piece-img.piece-defended {
    box-shadow: 0 0 0 3px var(--protected-bg), 0 0 7px 2px rgba(107, 142, 255, 0.6);
    border-radius: 6px;
}
.piece-img.piece-threatened.piece-defended {
    box-shadow: 0 0 0 3px #e53935, 0 0 0 6px var(--protected-bg), 0 0 7px 3px rgba(0, 0, 0, 0.35);
    border-radius: 6px;
}
.piece-img.piece-threatened.piece-hanging {
    animation: pulse-danger 0.8s infinite;
}

.controls-bottom {
    display: flex;
    justify-content: space-around; 
    align-items: center;
    padding: 10px 16px; 
    /* Dark Wooden / Luxe theme: capsule/pill container with the same
       dark-wood / brushed-metal gradient as the top bar, plus a soft
       inner highlight for a 3D feel. */
    background: var(--wood-bar-bg);
    border: 1px solid var(--wood-bar-border);
    border-radius: 999px;
    margin-top: 5px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(244, 223, 168, 0.08), inset 0 -3px 6px rgba(0, 0, 0, 0.45);
    flex-shrink: 0;
    position: relative;
    z-index: 20;
    gap: 4px;
    flex-wrap: nowrap;
}
.control-icon {
    display: flex;
    flex-direction: column;
    align-items: center;
    cursor: pointer;
    padding: 8px 6px;
    /* Rounded pill-shaped button "well" around each icon+label. Left
       transparent so the dark-wood bar shows through; only the round
       icon badge itself (below) carries the golden fill. */
    border-radius: 999px;
    background-color: transparent;
    transition: background-color 0.2s, transform 0.15s ease;
    position: relative;
    flex: 1; 
    max-width: 80px; 
}

.control-icon:hover {
    background-color: rgba(217, 176, 106, 0.14);
}
.control-icon:active {
    transform: scale(0.95);
}
.control-icon i {
    font-size: 16px;
    line-height: 1;
    margin-bottom: 5px;
    /* Dark brown glyph so it reads clearly against the golden/bronze
       circular badge behind it. */
    color: var(--gold-icon-dark);
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(145deg, var(--gold-bright), var(--gold) 55%, var(--gold-deep));
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35), inset 0 1px 1px rgba(255, 255, 255, 0.35);
    transition: transform 0.2s ease, background 0.2s ease;
}
.control-icon:hover i {
    transform: translateY(-2px);
    background: linear-gradient(145deg, #fff3d6, var(--gold-bright) 55%, var(--gold));
}
.control-icon span {
    font-size: 11px;
    text-align: center;
    font-weight: 500;
    color: var(--gold-text);
}
.feature-count {
    /* Red circle with a white number, pulled in a bit closer to the icon
       (top/right eased from -5px to -2px) so the badge sits more within
       the icon's circle instead of hanging off its edge. */
    background-color: #e63946;
    color: #fff;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 600;
    position: absolute;
    top: -2px;
    right: -2px;
    border: 1.5px solid #1a0f08;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.control-icon.disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.control-icon.disabled:hover {
    background-color: transparent;
}
/* Pi coin icon for the Refill button — golden/bronze circular badge with
   a dark-brown π glyph, matching the other Dark Wooden / Luxe theme
   control icons. */
.pi-coin-icon {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: linear-gradient(145deg, var(--gold-bright), var(--gold) 55%, var(--gold-deep));
    color: var(--gold-icon-dark);
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: bold;
    font-size: 17px;
    margin-bottom: 5px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35), inset 0 1px 1px rgba(255, 255, 255, 0.35);
}
#refill-btn span {
    color: var(--gold-text);
    font-weight: 600;
}
/* Grabs attention once every feature is fully depleted, nudging the player
   toward using the Pi payment refill: the whole button glows/blinks, the
   coin gently pulses, and the "Refill" label blinks on and off. */
@keyframes refillButtonBlink {
    0%, 100% {
        background-color: transparent;
        box-shadow: none;
    }
    50% {
        background-color: rgba(217, 176, 106, 0.2);
        box-shadow: 0 0 14px 4px rgba(244, 223, 168, 0.6);
    }
}
@keyframes refillCoinPulse {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(244, 223, 168, 0.55);
        transform: scale(1);
    }
    50% {
        box-shadow: 0 0 0 10px rgba(244, 223, 168, 0);
        transform: scale(1.1);
    }
}
@keyframes refillTextBlink {
    0%, 45% {
        opacity: 1;
    }
    55%, 100% {
        opacity: 0;
    }
}
#refill-btn.attention {
    animation: refillButtonBlink 1.2s ease-in-out infinite;
    border-radius: 8px;
}
#refill-btn.attention .pi-coin-icon {
    animation: refillCoinPulse 1.2s ease-in-out infinite;
}
#refill-btn.attention span {
    animation: refillTextBlink 1.2s steps(1) infinite;
}
.modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    animation: fadeIn 0.3s;
}
.modal-content {
    background-color: white;
    margin: 8vh auto;
    padding: 20px;
    border-radius: 10px;
    width: 80%;
    max-width: 500px;
    max-height: 84vh;
    overflow-y: auto;
    position: relative;
    text-align: center;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
    animation: scaleIn 0.3s;
}
/* Root-level fix: this .close (×) button sits inside every plain
   .modal-content dialog (Statistics, Leaderboard, Import PGN, Surrender,
   Board/Pieces/Bot settings, Unlock, Premium, Pi Payment). It used to be
   float: right, which pulls it out of normal text flow but still reserves
   its own height/width on that line — so the very next element (a
   centered <h2> title, or a centered icon like the lock/crown) had its
   line box narrowed on the right side and rendered visually off-center,
   shifted left. Absolute positioning removes it from flow entirely
   (.modal-content is already position: relative, so it anchors to the
   dialog itself), leaving every centered title/icon after it to center
   on the modal's full width with nothing nudging it. This one change
   covers every modal that relies on the shared .close — the three that
   previously had their own scoped position:absolute workaround
   (#unlock-modal, #premium-modal, #pi-payment-modal) keep working
   identically since their overrides just repeat the same values. */
.close {
    color: #aaa;
    position: absolute;
    top: 14px;
    right: 18px;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
}
.close:hover {
    color: black;
}
/* ===== Live in-game board/piece settings modal ===== */
/* Dark Luxury theme: matches the wood+gold visual language used on the
   game page's top/bottom bars (--wood-bar-bg, --gold-text, --gold) instead
   of the plain white/blue modal look used elsewhere. Scoped entirely to
   .game-settings-modal-content so no other modal in the app is affected. */
.game-settings-modal-content {
    text-align: left;
    padding: 16px 18px;
    margin: 5vh auto;
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.game-settings-modal-content h2 {
    text-align: center;
    margin: 0 0 4px;
    font-size: 19px;
    color: var(--gold-bright);
}
.game-settings-modal-content .close {
    color: var(--gold);
}
.game-settings-modal-content .close:hover {
    color: var(--gold-bright);
}
.game-settings-modal-desc {
    text-align: center;
    color: rgba(232, 207, 158, 0.65);
    font-size: 11px;
    margin: 0 0 12px;
    line-height: 1.3;
}
.settings-section + .settings-section {
    margin-top: 10px;
}
.settings-section-title {
    font-size: 11px;
    color: var(--gold-text);
    margin: 0 0 6px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
/* Fixed 4-column grid (never auto-fill/wrap) — every category here has
   exactly 4 items, so this guarantees a single row per section no matter
   how narrow the screen is; items just shrink to fit instead of a 4th
   item wrapping onto a second row. That wrapping was exactly what forced
   the whole modal to scroll before: 3 sections x 2 rows each didn't fit
   on one screen, but 3 sections x 1 row each does. */
.settings-swatch-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.settings-swatch {
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 8px;
    border: 2px solid transparent;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    transition: var(--transition);
    background-size: cover;
    background-position: center;
}
.settings-swatch:hover {
    transform: translateY(-2px);
}
.settings-swatch.selected {
    border-color: var(--gold);
    box-shadow: 0 0 0 2px rgba(217, 176, 106, 0.35);
}
.settings-swatch.locked {
    /* Keep the swatch's own theme/piece-set color fully visible even while
       locked — the lock badge (see .swatch-lock-badge below) is what
       communicates "locked", not a grayed-out card. A full desaturating
       filter here was hiding the theme color on every locked card (i.e.
       most of them for a non-Premium player), which is what made the
       Themes grid look uncolored. */
    opacity: 0.92;
}
.settings-swatch .swatch-piece-preview {
    width: 60%;
    height: 60%;
    object-fit: contain;
    pointer-events: none;
}
/* Theme swatch icons: same glyphs/colors as the theme-selection page cards
   (see .theme-page rules above), with a subtle shadow so each icon still
   reads clearly against its own swatch's matching background color. */
.settings-swatch[class*="theme-swatch-"] > i {
    font-size: 20px;
    pointer-events: none;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}
.settings-swatch.theme-swatch-brown > i { color: #a0522d; }
.settings-swatch.theme-swatch-green > i { color: #2ecc71; }
.settings-swatch.theme-swatch-pink > i { color: #e91e63; }
.settings-swatch.theme-swatch-blue > i { color: #2196f3; }
.settings-swatch .swatch-lock-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    color: var(--gold-bright);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 8px;
}
/* Once purchased/unlocked, buildSwatchLockBadge() in script.js swaps this
   badge's icon to an open padlock and adds this class — same green used
   for .lock-overlay.unlocked-badge on the theme/pieceset/bot selection
   pages, so "you own this" reads identically everywhere in the app. */
.settings-swatch .swatch-lock-badge.unlocked-badge {
    background: rgba(39, 174, 96, 0.85);
}
.settings-swatch .swatch-label {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 8px;
    font-weight: 600;
    text-align: center;
    padding: 1px 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Theme swatches: each card is a solid, unmistakable block of its theme's
   color (not a subtle split) so the Brown/Green/Pink/Blue cards are
   instantly recognizable as brown/green/pink/blue at a glance. */
.settings-swatch.theme-swatch-brown { background: linear-gradient(145deg, #d9b78e, #a97a4a); }
.settings-swatch.theme-swatch-green { background: linear-gradient(145deg, #9fcf7a, #5c8a41); }
.settings-swatch.theme-swatch-pink { background: linear-gradient(145deg, #f2b4c1, #d16f89); }
.settings-swatch.theme-swatch-blue { background: linear-gradient(145deg, #9dc6ea, #4f83b3); }
.settings-swatch.pieceset-swatch {
    /* Explicit light background (not the modal's dark wood tone) so the
       piece preview stays readable at any screen brightness; the inset
       ring keeps the card visually distinct from the dark modal behind it. */
    background-color: #f4f1ec;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.settings-swatch.bot-swatch {
    background-color: #f4f1ec;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
    flex-direction: column;
    gap: 2px;
}
/* Direct child only — this must NOT also match the lock badge's own <i>
   (nested one level deeper inside .swatch-lock-badge), otherwise the lock
   icon inherits this 16px/dark styling instead of the small white/green
   badge look shared with the theme and piece-set swatches. */
.settings-swatch.bot-swatch > i {
    font-size: 17px;
    color: #1a1a1a;
    text-shadow: 0 1px 1px rgba(255, 255, 255, 0.4);
    pointer-events: none;
}
/* Match each bot personality's icon color to its card on the bot-selection
   page (see .bot-page rules above) instead of the flat dark default, so the
   settings modal reads consistently with the rest of the UI. */
.settings-swatch.bot-swatch > i.fa-fire { color: #f57c00; }
.settings-swatch.bot-swatch > i.fa-shield-halved { color: #1e88e5; }
.settings-swatch.bot-swatch > i.fa-chess-king { color: #e8b923; }
.settings-swatch.bot-swatch > i.fa-hat-wizard { color: #8e24aa; }
.settings-swatch .swatch-piece-preview {
    /* Guarantees the piece glyph reads clearly against the light card
       background regardless of device screen brightness. */
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
/* Apply row: selections in the modal above are staged (just the "selected"
   outline moves) until this button is pressed, which is what actually
   commits them to the board/game. */
.game-settings-apply-row {
    display: flex;
    justify-content: center;
    margin-top: 14px;
}
.game-settings-apply-btn {
    /* Was width: 100% — stretched "Apply" across the full modal width,
       which reads as an oversized bar for a five-letter label. Sized to
       its own text + padding instead; .game-settings-apply-row's
       justify-content: center still keeps it centered. */
    margin: 0;
    padding: 11px 32px;
}
/* Gold gradient Apply button — overrides the shared blue .nav-button look
   (via #id specificity, since .nav-button is declared later in this file)
   so this button matches the modal's dark-wood/gold theme instead of the
   app-wide default blue. */
#apply-game-settings-btn {
    background: linear-gradient(160deg, var(--gold-bright) 0%, var(--gold) 55%, var(--gold-deep) 100%);
    color: var(--gold-icon-dark);
    border: 1px solid rgba(0, 0, 0, 0.15);
    text-shadow: none;
}
#apply-game-settings-btn:hover {
    background: linear-gradient(160deg, #f8e8bc 0%, var(--gold-bright) 55%, var(--gold) 100%);
}

.nav-button {
    background-color: var(--primary-color);
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 5px;
    cursor: pointer;
    font-weight: bold;
    margin: 10px;
    transition: background-color 0.3s;
    font-size: 16px;
}
.nav-button:hover {
    background-color: #1a5a9e;
}
/* Statistics / Analyze Game / Analyze PGN when Premium isn't active —
   dimmed and non-interactive-looking, with a small padlock so it reads
   as "locked" rather than just "disabled". The click handler still
   fires (it needs to, to show the Premium explainer), it just refuses
   to open the feature. */
.nav-button.premium-locked {
    opacity: 0.55;
    filter: grayscale(35%);
    cursor: not-allowed;
}
.nav-button.premium-locked:hover {
    background-color: var(--primary-color);
}
.nav-button.premium-locked::after {
    content: "\f023";
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    margin-left: 6px;
    font-size: 0.85em;
}
.settings-buttons {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}
.features-modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    animation: fadeIn 0.3s;
}
.features-content {
    background-color: #fefefe;
    color: #333;
    position: relative;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
    animation: scaleIn 0.3s;
}
/* Help ("?") — full-page takeover, same treatment as Statistics /
   Leaderboard / Game Analysis (see .stats-content / .game-analysis-content)
   instead of a floating centered card. Header (title + close) stays
   pinned; only .features-scrollable-content below it scrolls. */
.help-page-content {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: 0;
    padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
    box-shadow: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.help-page-content > .features-header {
    flex-shrink: 0;
}
.features-scrollable-content {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 5px;
}
.features-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    border-bottom: 2px solid #eee;
    padding-bottom: 10px;
}
.features-header h2 {
    color: var(--primary-color);
    margin: 0;
}
.features-close {
    color: #aaa;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
}
.features-close:hover {
    color: black;
}
.features-section {
    margin-bottom: 25px;
}
.features-section h3 {
    color: var(--primary-color);
    margin-bottom: 15px;
    border-bottom: 1px solid #eee;
    padding-bottom: 5px;
    display: flex;
    align-items: center;
}
.features-section h3 i {
    margin-right: 10px;
    font-size: 1.2rem;
}
.features-section p {
    margin-bottom: 10px;
    line-height: 1.6;
}
.features-list {
            list-style-type: none; 
            padding: 0;
            margin: 10px 0;
        }
        
        .features-list li {
            margin-bottom: 10px;
            padding: 8px 10px;
            background-color: white;
            border-radius: 5px;
            border-right: 3px solid var(--primary-color);
            transition: all 0.3s ease;
        }
/* "Blue" theme: Chess.com-style "Pillow" board — puffy, cushioned-looking
   squares, achieved with a soft gradient + inset shadow for a 3D effect. */
.theme-blue .square.white {
    background: linear-gradient(145deg, #eaf3fb, #c9dfef);
    box-shadow: inset 2px 2px 5px rgba(255, 255, 255, 0.8),
                inset -2px -2px 5px rgba(0, 0, 0, 0.12);
}
.theme-blue .square.black {
    background: linear-gradient(145deg, #7fb0d6, #5a8ebb);
    box-shadow: inset 2px 2px 5px rgba(255, 255, 255, 0.25),
                inset -2px -2px 5px rgba(0, 0, 0, 0.25);
}
.nav-arrows {
    position: fixed;
    bottom: 30px;
    width: 100%;
    display: flex;
    justify-content: space-between;
    padding: 0 30px;
    z-index: 100;
    pointer-events: none;
}
.nav-arrow {
    width: 50px;
    height: 50px;
    /* Dark Wooden / Luxe theme: golden/bronze circular button. */
    background: linear-gradient(145deg, var(--gold-bright), var(--gold) 55%, var(--gold-deep));
    border: 1px solid rgba(255, 246, 224, 0.4);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    color: var(--gold-icon-dark);
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.35);
    pointer-events: auto;
}
.nav-arrow:hover {
    background: linear-gradient(145deg, #fff3d6, var(--gold-bright) 55%, var(--gold));
    color: #241407;
    transform: scale(1.1);
}
.nav-arrow:active {
    /* Visible tap feedback now that the default browser tap-highlight is
       suppressed globally (see the `*` rule above) — same brighten as
       :hover, without the enlarge, so it still reads instantly on touch. */
    background: linear-gradient(145deg, #fff3d6, var(--gold-bright) 55%, var(--gold));
    color: #241407;
}
.nav-arrow.hidden {
    opacity: 0;
    pointer-events: none;
}
#pi-payment-modal .modal-content {
    background-color: #fefefe;
    padding: 20px;
    border-radius: 10px;
    width: 90%;
    max-width: 400px;
    text-align: center;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
    backdrop-filter: blur(5px);
}
#pi-payment-modal h2 {
    color: var(--primary-color);
    margin-bottom: 20px;
}
/* No scoped override needed here anymore — the base .close rule already
   positions it absolutely (top: 14px; right: 18px), matching every other
   modal in the app instead of its own slightly different 10px/20px. */
#pi-payment-modal .nav-button {
    margin-top: 20px;
    padding: 12px 24px;
    font-size: 16px;
}

.game-info-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    max-width: 650px;
    margin: 0 auto 10px auto;
    padding: 5px 14px;
    /* Dark Wooden / Luxe theme: dark-wood / brushed-metal rectangle with
       rounded corners (not a full pill), soft depth shadows for a
       3D glassmorphic / dark-wood feel. */
    background: var(--wood-bar-bg);
    border: 1px solid var(--wood-bar-border);
    border-radius: 18px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(244, 223, 168, 0.08), inset 0 -3px 6px rgba(0, 0, 0, 0.45);
    z-index: 20;
    position: relative;
}
/* Invisible row that spans the exact same width/position as the board,
   purely so its content can be left-aligned with the board's left edge. */
.side-indicator-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    width: 96vmin;
    max-width: 650px;
    margin: 0 auto;
    box-sizing: border-box;
    overflow: visible;
    position: relative;
}
/* The actual visible "pill" - sized to fit its own content only. Never
   shrinks below its natural width (flex-shrink: 0) — previously the
   default flex-shrink:1 let the promo-message next to it (see below)
   squeeze this pill down, which had nowhere to give except wrapping the
   bot's name onto two lines. */
.side-indicator-pill {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: bold;
    font-size: 14px;
    color: #2c3e50;
    background-color: white;
    border-radius: 10px;
    padding: 6px 14px;
    width: fit-content;
    flex-shrink: 0;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    opacity: 0.55;
    transition: opacity 0.25s ease, box-shadow 0.25s ease;
}
.side-indicator-row.active .side-indicator-pill {
    opacity: 1;
    box-shadow: 0 3px 12px rgba(43, 112, 197, 0.35);
}
/* Bot (Black) & White-player (Guest) name pills: Dark Wooden / Luxe
   styling — same dark-wood / brushed-metal background as the top &
   bottom bars, with the name text in warm gold instead of the default
   dark slate text. */
#bot-indicator .side-indicator-pill,
#white-player-indicator .side-indicator-pill {
    background: var(--wood-bar-bg);
    border: 1px solid var(--wood-bar-border);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(244, 223, 168, 0.08);
}
#bot-indicator.side-indicator-row.active .side-indicator-pill,
#white-player-indicator.side-indicator-row.active .side-indicator-pill {
    box-shadow: 0 3px 14px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(244, 223, 168, 0.12);
}
#bot-text,
#player-text {
    color: var(--gold-bright);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
#player-text {
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Same one-line guarantee as #player-text above, for the bot's name — this
   is what actually keeps "Aggressive Attacker" (or any bot personality
   name) from wrapping in the first place; flex-shrink: 0 on the pill above
   only stops the *pill* from shrinking, not the text inside it from
   wrapping if there were ever still not enough room. */
#bot-text {
    white-space: nowrap;
}
/* Motivational promo message that briefly appears next to the Bot AI
   indicator (e.g. when features run out, or time is almost up). */
/* Motivational promo message that briefly appears next to the Bot AI
   indicator (e.g. when features run out, or time is almost up).
   Positioned absolutely (anchored to the row's right edge, vertically
   centered on the pill) so it floats OVER the layout instead of
   participating in it — its own height (it can wrap onto 2 lines on
   narrow screens) used to add to .side-indicator-row's flex height and
   push the whole board down for as long as it was visible; as an overlay
   it can never do that, no matter how much text it wraps to. */
.promo-message {
    position: absolute;
    top: 50%;
    right: 0;
    margin-left: 0;
    padding: 6px 12px;
    /* Matches the app's dark-wood/gold theme (same gradient used by the
       Apply button and page-nav arrows) instead of the old purple that
       didn't match anything else in the app. */
    background: linear-gradient(135deg, var(--gold-bright) 0%, var(--gold) 100%);
    color: var(--gold-icon-dark);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.3;
    border-radius: 14px;
    box-shadow: 0 2px 8px rgba(156, 112, 39, 0.4);
    opacity: 0;
    transform: translateY(-50%) translateY(-4px);
    pointer-events: none;
    transition: opacity 0.4s ease, transform 0.4s ease;
    max-width: 60%;
    overflow-wrap: break-word;
    text-align: right;
    z-index: 30;
}
.promo-message.visible {
    opacity: 1;
    transform: translateY(-50%) translateY(0);
}
.top-controls {
    display: flex;
    gap: 5px;
    margin-left: auto; 
}
.left-controls {
    display: flex;
    gap: 5px;
    align-items: center;
    margin-right: auto;
}
.player-color-indicator {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    margin-right: 0;
}
.player-white {
    background-color: #ffffff;
    border: 2px solid #d9b06a;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.player-black {
    background-color: #0d0d0d;
    border: 2px solid #d9b06a;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.game-timer {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}
.game-timer-label {
    font-size: 11px;
    color: var(--gold-text);
    opacity: 0.85;
    margin-bottom: 2px;
}

/* ---- START OF MODIFICATION ---- */
.game-timer-display {
    font-size: 18px;
    font-weight: bold;
    color: var(--gold-bright);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
    font-family: monospace;
    background-color: transparent; /* Changed to transparent */
}
/* ---- END OF MODIFICATION ---- */

@media (max-width: 768px) {
    .welcome-title {
        font-size: 2.5rem;
    }
   .welcome-subtitle {
        font-size: 1.4rem;
    }
    .welcome-logo {
        width: 150px;
    }
    .page-title {
        font-size: 2rem;
    }
    .option-card {
        width: 130px;
        height: 194px;
    }
    .option-icon {
        font-size: 2.5rem;
    }
    .option-piece-preview {
        width: 2.6rem;
        height: 2.6rem;
    }
    .option-desc {
        font-size: 0.8rem;
        min-height: 2.2em;
        line-height: 1.1;
    }
    .chessboard {
        width: 96vmin;
        height: 96vmin;
        font-size: calc(96vmin / 8 * 0.9);
    }
    .side-indicator-row {
        width: 96vmin;
    }
/* ---- START OF MODIFICATION ---- */
    .controls-bottom {
        padding: 6px 10px;
        gap: 1px; 
    }
/* ---- END OF MODIFICATION ---- */
    .control-icon {
        padding: 6px 2px; 
        min-width: auto; 
    }
    .control-icon i {
        font-size: 14px;
        width: 26px;
        height: 26px;
        margin-bottom: 3px;
    }
    .control-icon span {
        font-size: 10px; 
    }
    
    .nav-arrows {
        padding: 0 15px;
    }
    .nav-arrow {
        width: 40px;
        height: 40px;
        font-size: 18px;
    }
    .feature-count {
        width: 18px;
        height: 18px;
        font-size: 11px;
    }

    .game-timer-label {
        font-size: 10px;
    }
    .game-timer-display {
        font-size: 16px;
    }
}

@media (max-width: 380px) {
    .square[data-rank]::before,
    .square[data-file]::after {
        font-size: 8px;
    }
    .control-icon i {
        font-size: 12px;
        width: 22px;
        height: 22px;
    }
    .control-icon span {
        font-size: 9px; 
    }
    .option-card {
        width: 110px;
        height: 172px;
    }
    .option-price-badge {
        top: 9px;
        left: -28px;
        width: 84px;
        font-size: 7px;
        padding: 2px 0;
    }
    .option-desc {
        font-size: 0.75rem;
        min-height: 2em;
    }
}

html.device-tablet .game-container {
    justify-content: center;
}
html.device-tablet .chessboard {
    width: 60vmin;
    height: 60vmin;
}
html.device-tablet .side-indicator-row {
    width: 60vmin;
}
html.device-tablet .game-status {
    height: 30px;
    line-height: 15px;
    margin: 5px auto;
}
html.device-tablet .board-container {
    margin-top: 20px;
    margin-bottom: 20px;
}
html.device-tablet .control-icon i {
    width: 40px;
    height: 40px;
    font-size: 18px;
}
html.device-tablet .control-icon span {
    font-size: 13px;
}
html.device-tablet .feature-count {
    width: 22px;
    height: 22px;
    font-size: 13px;
}
@keyframes moveAnimation {
    from { opacity: 0.7; transform: scale(1.1); }
    to { opacity: 1; transform: scale(1); }
}
.piece.moved {
    animation: moveAnimation 0.3s ease-in-out;
}
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes scaleIn {
    from { opacity: 0; transform: scale(0.9); }
    to { opacity: 1; transform: scale(1); }
}
@keyframes optionClick {
    0% { transform: scale(1); }
    50% { transform: scale(0.95); }
    100% { transform: scale(1); }
}
.option-card.clicked {
    animation: optionClick 0.3s ease;
}
.timer-container {
    position: absolute;
    top: 10px;
    right: 10px;
    background: rgba(255, 255, 255, 0.9);
    padding: 8px 12px;
    border-radius: 20px;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
    font-weight: bold;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    display: none;
}
.timer-label {
    font-size: 12px;
    margin-bottom: 4px;
    color: #666;
    display: none;
}
.timer-display {
    font-size: 16px;
    color: #2c3e50;
    display: none;
}
.timer-low {
    color: #f44336;
    animation: pulse 1s infinite;
}
@keyframes pulse {
    0% { opacity: 1; }
    50% { opacity: 0.5; }
    100% { opacity: 1; }
}
.difficulty-time-info {
    font-size: 12px;
    margin-top: 5px;
    color: #666;
}

.top-controls .control-icon,
.left-controls .control-icon {
    min-width: 45px;
    padding: 4px 3px;
}
.game-status {
    background-color: transparent;
    box-shadow: none;
    border-radius: 10px;
    padding: 5px;
    margin-top: 5px;
    text-align: center;
    font-weight: bold;
    max-width: 650px;
    margin: 5px auto;
    height: 30px;
    line-height: 30px;
    overflow: hidden;
    display: block;
}
.game-status.in-check {
    color: #e53935;
    animation: checkBlink 1s ease-in-out infinite;
}
@keyframes checkBlink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}
.game-over-modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
}
.game-over-content {
    background-color: #fefefe;
    margin: 15% auto;
    padding: 20px;
    border-radius: 10px;
    width: 80%;
    max-width: 400px;
    text-align: center;
}
.game-over-buttons {
    display: flex;
    justify-content: center;
    gap: 5px;
    margin-top: 20px;
    flex-wrap: wrap;
}
.analyze-lichess-btn i {
    margin-right: 6px;
}
.import-pgn-buttons {
    display: flex;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 10px;
}
/* PGN file picker — was left with the browser's tiny default "Choose
   File" button. Sized to match the app's other buttons and themed to
   fit the dark wood/gold modal instead of looking like a stray native
   control. */
#pgn-file {
    display: block;
    width: 100%;
    margin-top: 12px;
    padding: 10px 8px;
    font-size: 15px;
    color: rgba(232, 207, 158, 0.85);
    border: 1px solid var(--wood-bar-border);
    border-radius: 6px;
    background-color: rgba(255, 255, 255, 0.05);
}
#pgn-file::file-selector-button,
#pgn-file::-webkit-file-upload-button {
    padding: 10px 18px;
    margin-right: 12px;
    font-size: 15px;
    font-weight: bold;
    color: #2a1806;
    background: linear-gradient(160deg, var(--gold-bright) 0%, var(--gold) 100%);
    border: none;
    border-radius: 5px;
    cursor: pointer;
}
#pgn-file::file-selector-button:hover,
#pgn-file::-webkit-file-upload-button:hover {
    background: linear-gradient(160deg, #fff0cf 0%, var(--gold-bright) 100%);
}
/* New styles for enhanced threats */
.square.low-threat {
    background-color: var(--low-threat-bg) !important;
    box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.45);
}
.square.medium-threat {
    background-color: var(--medium-threat-bg) !important;
    box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.45);
}
.square.high-threat {
    background-color: var(--high-threat-bg) !important;
    box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.45);
    animation: pulse-danger 1s infinite;
}
.square.hanging-threat {
    box-shadow: inset 0 0 0 4px #ff0000, 0 0 14px 3px rgba(255, 0, 0, 0.7);
    animation: pulse-danger 0.6s infinite;
}
.square.potential-threat {
    background: repeating-linear-gradient(
        45deg,
        transparent,
        transparent 5px,
        var(--potential-threat-bg) 5px,
        var(--potential-threat-bg) 10px
    );
}
.square.defended {
    box-shadow: inset 0 0 0 4px var(--protected-bg), 0 0 8px 2px rgba(107, 142, 255, 0.7);
}
.threat-source {
    box-shadow: 0 0 0 4px #ff0000, 0 0 10px 3px rgba(255, 0, 0, 0.6);
    animation: pulse-threat 2s infinite;
}
.board-arrow-shaft.threat-arrow {
    background-color: rgba(220, 20, 20, 0.82);
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.35);
}
.board-arrow-head.threat-arrow-head {
    color: rgba(220, 20, 20, 0.82);
    filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.35));
}
/* Engine-verified tactical threat (real Stockfish best reply) — a
   distinct violet so it reads as "the engine's #1 threat" rather than
   blending into the rule-based red threats above. */
.engine-threat-target {
    box-shadow: inset 0 0 0 4px #ab47bc, 0 0 14px 4px rgba(171, 71, 188, 0.75);
    animation: pulse-engine-threat 0.9s infinite;
}
.engine-threat-source {
    box-shadow: 0 0 0 4px #ab47bc, 0 0 10px 3px rgba(171, 71, 188, 0.6);
    animation: pulse-engine-threat 0.9s infinite;
}
.board-arrow-shaft.engine-threat-arrow {
    background-color: rgba(171, 71, 188, 0.9);
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.35);
}
.board-arrow-head.engine-threat-arrow-head {
    color: rgba(171, 71, 188, 0.9);
    filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.35));
}
@keyframes pulse-engine-threat {
    0% { opacity: 0.75; }
    50% { opacity: 1; }
    100% { opacity: 0.75; }
}
.threat-info-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
    border-bottom: 1px solid #eee;
    padding-bottom: 8px;
}
.threat-info-title {
    font-weight: bold;
    color: var(--primary-color);
    font-size: 18px;
}
.threat-info-content {
    margin-bottom: 10px;
}
.threat-info-list {
    list-style-type: none;
    padding: 0;
    margin: 0;
}
.threat-info-list li {
    padding: 5px 0;
    border-bottom: 1px solid #f0f0f0;
}
.threat-info-list li:last-child {
    border-bottom: none;
}
.threat-tip {
    background-color: #f8f9fa;
    padding: 10px;
    border-radius: 5px;
    margin-top: 10px;
    font-style: italic;
    border-left: 3px solid var(--primary-color);
}
.threat-level-indicator {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    margin-right: 5px;
}
.threat-level-low {
    background-color: var(--low-threat-bg);
}
.threat-level-medium {
    background-color: var(--medium-threat-bg);
}
.threat-level-high {
    background-color: var(--high-threat-bg);
}
.threat-level-potential {
    background: repeating-linear-gradient(
        45deg,
        var(--potential-threat-bg),
        var(--potential-threat-bg) 5px,
        #ffffff 5px,
        #ffffff 10px
    );
}
@keyframes pulse-danger {
    0% { opacity: 0.7; }
    50% { opacity: 1; }
    100% { opacity: 0.7; }
}
@keyframes pulse-threat {
    0% { box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.7); }
    50% { box-shadow: 0 0 0 6px rgba(255, 0, 0, 0.4); }
    100% { box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.7); }
}
/* Advice modal styles */
.advice-modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    animation: fadeIn 0.3s;
}
.advice-content {
    background-color: #fefefe;
    margin: 5% auto;
    padding: 20px;
    border-radius: 10px;
    width: 90%;
    max-width: 600px;
    color: #333;
    position: relative;
    max-height: 80vh;
    overflow-y: auto;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
    animation: scaleIn 0.3s;
}
.advice-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    border-bottom: 2px solid #eee;
    padding-bottom: 10px;
}
.advice-header h2 {
    color: var(--primary-color);
    margin: 0;
}
.advice-close {
    color: #aaa;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
}
.advice-close:hover {
    color: black;
}
.advice-section {
    margin-bottom: 25px;
}
.advice-section h3 {
    color: var(--primary-color);
    margin-bottom: 15px;
    border-bottom: 1px solid #eee;
    padding-bottom: 5px;
    display: flex;
    align-items: center;
}
.advice-section h3 i {
    margin-right: 10px;
    font-size: 1.2rem;
}
.advice-section p {
    margin-bottom: 10px;
    line-height: 1.6;
}
.advice-list {
    list-style-type: none;
    padding-left: 20px;
    margin-top: 10px;
}
.advice-list li {
    margin-bottom: 8px;
    position: relative;
    padding-left: 25px;
}
.advice-list li:before {
    content: "•";
    color: var(--primary-color);
    font-weight: bold;
    position: absolute;
    left: 0;
    font-size: 20px;
}
.advice-tip {
    background-color: #f8f9fa;
    padding: 10px;
    border-radius: 5px;
    margin-top: 10px;
    font-style: italic;
    border-left: 3px solid var(--primary-color);
}
@media (max-width: 768px) {
    .advice-content {
        width: 95%;
        margin: 10% auto;
        padding: 15px;
    }
}
/* Custom alert modal — used app-wide for Pi payment success/failure/
   cancellation messages and "you've used up X" notices (hints, undos,
   extra time, threat visualizations, refill). Previously fully inline-
   styled as a plain white box with a generic green button, clashing with
   the dark wood/gold theme used by every other modal in the app. */
.custom-alert-modal {
    display: none;
    position: fixed;
    z-index: 10000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.6);
    animation: fadeIn 0.3s;
}
.custom-alert-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    margin: 15% auto;
    padding: 24px 20px 20px;
    width: 80%;
    max-width: 500px;
    border-radius: 10px;
    text-align: center;
    animation: scaleIn 0.3s;
}
.custom-alert-content p {
    margin: 0 0 20px;
    font-size: 16px;
    line-height: 1.5;
    color: rgba(232, 207, 158, 0.9);
}
.custom-alert-content .nav-button {
    margin: 0;
}

/* Promotion Modal Styles */
.promotion-options {
    display: flex;
    justify-content: space-around;
    margin: 20px 0;
}
.promotion-options button {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 10px;
    font-size: 1.2rem;
    background: var(--light-color);
    border: 1px solid var(--primary-color);
    border-radius: 5px;
    cursor: pointer;
    transition: background 0.3s;
}
.promotion-options button:hover {
    background: var(--primary-color);
    color: white;
}
.promotion-options span {
    font-size: 3rem;
    margin-bottom: 5px;
}
#promotion-modal .options-container {
    flex-wrap: wrap;
    justify-content: center;
}
#promotion-modal .option-card {
    width: 100px;
    height: 150px;
}
#promotion-modal .option-icon {
    font-size: 2.5rem;
}
#promotion-modal .option-name {
    font-size: 1rem;
}
@media (max-width: 480px) {
    #promotion-modal .option-card {
        width: 80px;
        height: 120px;
    }
    #promotion-modal .option-icon {
        font-size: 2rem;
    }
    #promotion-modal .option-name {
        font-size: 0.9rem;
    }
}

/* Statistics Modal Styles — full-page takeover (not a floating box) so
   the tab content, difficulty breakdown, and (for the Leaderboard reuse
   below) each ranked row all get the full screen instead of being
   squeezed into an 80vh/400px-wide card. Structured as a flex column:
   h2 + tabs stay pinned, only .stats-scrollable-content scrolls — same
   pattern as the Game Analysis modal. Back/close still return to
   game-over-modal exactly as before; this only changes presentation. */
.stats-content {
    background-color: #fefefe;
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: 0;
    padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
    color: #333;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: none;
    animation: scaleIn 0.3s;
    text-align: center;
}

.stats-content h2 {
    flex-shrink: 0;
}

.stats-scrollable-content {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 5px;
    margin-bottom: 12px;
}

/* Custom scrollbar for stats modal */
.stats-scrollable-content::-webkit-scrollbar {
    width: 6px;
}

.stats-scrollable-content::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
}

.stats-scrollable-content::-webkit-scrollbar-thumb {
    background: var(--primary-color);
    border-radius: 3px;
}

.stats-scrollable-content::-webkit-scrollbar-thumb:hover {
    background: #1a5a9e;
}

.stats-container {
    display: flex;
    flex-direction: column;
    gap: 15px;
    margin: 20px 0;
    padding: 10px;
}

#stats-back-btn {
    flex-shrink: 0;
    margin-top: 8px;
    width: 100%;
}

/* Covers #leaderboard-back-btn too (same .nav-button, direct child of
   .stats-content) — belt-and-suspenders alongside #stats-back-btn above
   so neither back button can ever be squeezed by the flex column. */
.stats-content > .nav-button {
    flex-shrink: 0;
}

@media (max-width: 768px) {
    .stat-item {
        padding: 8px 12px;
    }
    
    .stat-label {
        font-size: 13px;
    }
    
    .stat-value {
        font-size: 14px;
    }
}

@media (max-width: 480px) {
    .stats-content {
        padding-left: 12px;
        padding-right: 12px;
    }
    
    .stat-item {
        padding: 6px 10px;
    }
    
    .stat-label {
        font-size: 12px;
    }
    
    .stat-value {
        font-size: 13px;
    }
}

/* Enhanced Statistics Styles */
.stats-tabs {
    display: flex;
    justify-content: space-around;
    margin-bottom: 20px;
    border-bottom: 1px solid #ddd;
}

.tab-button {
    background: none;
    border: none;
    padding: 10px 15px;
    cursor: pointer;
    font-size: 14px;
    color: #666;
    border-bottom: 2px solid transparent;
    transition: all 0.3s ease;
}

.tab-button.active {
    color: var(--primary-color);
    border-bottom-color: var(--primary-color);
    font-weight: bold;
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

.stats-section {
    margin-bottom: 25px;
    padding: 15px;
    background-color: #f8f9fa;
    border-radius: 8px;
    border-left: 4px solid var(--primary-color);
}

.stats-section h3 {
    color: var(--primary-color);
    margin-bottom: 15px;
    font-size: 18px;
    border-bottom: 1px solid #e0e0e0;
    padding-bottom: 8px;
}

.difficulty-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

.leaderboard-title-icon {
    color: var(--secondary-color);
    margin-right: 6px;
}

/* The leaderboard modal reuses .stats-content (now a full-page layout,
   see above) — no extra width override needed anymore since it already
   gets the full screen like Statistics does. */

.leaderboard-note {
    color: #888;
    font-size: 14px;
    text-align: center;
    margin: 16px 0;
}

.leaderboard-list {
    list-style: none;
    margin: 0;
    padding: 4px 2px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.leaderboard-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 12px;
    background: #ffffff;
    border: 1px solid #eceff3;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.leaderboard-item:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 10px rgba(15, 23, 42, 0.1);
}

/* Top 3 get a subtle tinted, elevated look */
.leaderboard-top {
    border-width: 1px;
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
}

.leaderboard-top.rank-1 {
    background: linear-gradient(135deg, #fff8e6, #fffdf7);
    border-color: #f0d68a;
}

.leaderboard-top.rank-2 {
    background: linear-gradient(135deg, #f3f5f7, #fdfdfe);
    border-color: #d7dce2;
}

.leaderboard-top.rank-3 {
    background: linear-gradient(135deg, #fdf1e8, #fffaf6);
    border-color: #eab98c;
}

.leaderboard-item.leaderboard-me {
    border: 1.5px solid var(--primary-color);
    background: rgba(43, 112, 197, 0.07);
    box-shadow: 0 2px 8px rgba(43, 112, 197, 0.18);
}

.leaderboard-rank {
    flex-shrink: 0;
    width: 32px;
    text-align: center;
    font-weight: 700;
    font-size: 14px;
    color: var(--primary-color);
}

.leaderboard-medal {
    font-size: 22px;
    line-height: 1;
}

.leaderboard-info {
    flex-grow: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
}

.leaderboard-name {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 15px;
    font-weight: 600;
    color: #22262b;
    min-width: 0;
}

.leaderboard-username-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* VIP badge: active Pi Premium subscriber, or has paid Pi for at least
   one theme/piece-set/level unlock (see isVipMember() in script.js). */
.leaderboard-vip-badge {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: linear-gradient(145deg, #f5c451, #d1971e);
    color: #4a2a00;
    font-size: 10px;
    box-shadow: 0 1px 4px rgba(209, 151, 30, 0.5);
    cursor: help;
}

.leaderboard-stats {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    row-gap: 2px;
    gap: 6px;
    font-size: 12px;
    color: #6b7280;
}

.leaderboard-wins {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--secondary-color);
    font-weight: 600;
}

.leaderboard-wins i {
    font-size: 11px;
}

.leaderboard-dot {
    color: #c7ccd3;
}

.leaderboard-winrate {
    flex-shrink: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--primary-color);
    background: rgba(43, 112, 197, 0.1);
    padding: 4px 10px;
    border-radius: 999px;
    min-width: 42px;
    text-align: center;
}

.leaderboard-points-label {
    font-size: 10px;
    font-weight: 600;
    margin-left: 2px;
    opacity: 0.75;
}

.leaderboard-top.rank-1 .leaderboard-winrate {
    color: #a67c00;
    background: rgba(230, 180, 0, 0.16);
}

.leaderboard-top.rank-3 .leaderboard-winrate {
    color: #a05a1f;
    background: rgba(201, 123, 61, 0.16);
}

.diff-stat-item {
    display: flex;
    justify-content: space-between;
    padding: 8px 12px;
    background-color: white;
    border-radius: 5px;
    margin-bottom: 5px;
}

.diff-label {
    font-weight: bold;
    color: #2c3e50;
}

.diff-value {
    color: var(--primary-color);
    font-weight: bold;
}

/* Enhanced stat items for better readability */
.stat-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 15px;
    background-color: white;
    border-radius: 8px;
    margin-bottom: 8px;
    transition: all 0.3s ease;
}

.stat-item:hover {
    background-color: #f0f0f0;
    transform: translateX(5px);
}

.stat-label {
    font-weight: bold;
    color: #2c3e50;
    font-size: 14px;
}

.stat-value {
    font-weight: bold;
    color: var(--primary-color);
    font-size: 16px;
}

/* Responsive design for statistics */
@media (max-width: 768px) {
    .stats-tabs {
        flex-direction: column;
        gap: 5px;
    }
    
    .tab-button {
        text-align: center;
        padding: 8px;
    }
    
    .difficulty-stats {
        grid-template-columns: 1fr;
    }
    
    .stats-section {
        padding: 10px;
    }
    
    .stat-item {
        padding: 8px 10px;
    }
    
    .stat-label {
        font-size: 13px;
    }
    
    .stat-value {
        font-size: 14px;
    }
}

@media (max-width: 480px) {
    .stats-tabs {
        margin-bottom: 15px;
    }
    
    .tab-button {
        font-size: 12px;
        padding: 6px 8px;
    }
}

/* ===== Unlock modal (paying to unlock a locked level/theme/piece set) ===== */
.unlock-modal-content {
    text-align: center;
}
.unlock-lock-icon {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: linear-gradient(145deg, var(--gold-bright), var(--gold) 60%, var(--gold-deep));
    color: var(--gold-icon-dark);
    font-size: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 10px auto 15px;
    box-shadow: 0 4px 10px rgba(156, 112, 39, 0.4);
}
/* No scoped override needed here anymore — the base .close rule is now
   position: absolute globally, so the lock icon below already centers
   purely on the modal's own width without any extra help. */
/* Small category pill above the title (Difficulty Level / Board Theme /
   Piece Set / Bundle) — kept from the previous layout since it's the only
   thing telling the player at a glance which kind of item this modal is
   for; script.js (showUnlockModal) sets its text directly. */
.unlock-type-badge {
    display: inline-block;
    background: rgba(244, 223, 168, 0.15);
    color: var(--gold-bright);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    padding: 4px 12px;
    border-radius: 20px;
    margin-bottom: 8px;
}
/* "You already used your free trial for this" pill — hidden by default,
   shown by script.js only for a locked item the player has already
   sampled once. */
.unlock-tried-note {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    text-align: left;
    background: #fff6e6;
    color: #8a5c00;
    font-size: 12.5px;
    line-height: 1.4;
    border-radius: 8px;
    padding: 8px 10px;
    margin: 10px auto 0;
    max-width: 320px;
}
.unlock-tried-note i {
    margin-top: 1px;
    flex-shrink: 0;
}
.unlock-tried-note.hidden {
    display: none;
}
.pi-coin-icon-small {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: bold;
    font-size: 13px;
    flex-shrink: 0;
}
.unlock-pay-btn,
.unlock-all-btn {
    /* Unified pair: identical padding/height/font. Sized to fit their
       short price-only content (not stretched full-width) so the buttons
       read as compact pills rather than long bars — .unlock-buttons-group
       below centers them and caps the width so a long 8-decimal Pi
       amount still can't overflow the modal. Gold (not purple) to match
       the rest of the app's dark-wood/gold theme — purple is reserved
       for the Premium subscription modal only. */
    background: linear-gradient(145deg, var(--gold-bright), var(--gold) 60%, var(--gold-deep));
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--gold-icon-dark);
    border: none;
    width: fit-content;
    min-width: 120px;
    max-width: 100%;
    margin: 0 auto;
    padding: 9px 18px;
    /* <button> elements don't inherit the page's font-family from body by
       default (the browser's own UA stylesheet gives them a system font
       instead), so without this the price text here was rendering in a
       different typeface than the .unlock-all-label span above it even
       at the same declared font-size — hence looking mismatched/smaller. */
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.3;
    min-height: 42px;
    white-space: nowrap;
}
.unlock-pay-btn span,
.unlock-all-btn span {
    /* A long 8-decimal Pi amount stays on one line and shrinks gracefully
       instead of forcing the button wider than the modal. */
    overflow: hidden;
    text-overflow: ellipsis;
}
.unlock-buttons-group {
    /* max-width caps how wide either button (or the label above the
       bundle button) can grow — generous enough to comfortably fit Pi's
       full 8-decimal precision (e.g. "20.24118273 π") without clipping,
       while keeping the pair compact and centered rather than spanning
       the full modal width. */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: 100%;
    max-width: 220px;
    margin: 8px auto;
}
/* Caption naming what the bundle button unlocks (e.g. "Unlock Remaining
   3 Themes") — sits above the price-only button now that the button
   itself only shows the price, so the purchase still reads clearly. */
.unlock-all-label {
    /* Matches .unlock-pay-btn/.unlock-all-btn's own font-size (14px) and
       weight (700) so the bundle caption reads at the exact same size and
       boldness as the individual-item price text, not a smaller footnote. */
    font-size: 14px;
    font-weight: 700;
    color: var(--gold-bright);
    text-align: center;
    margin-top: 4px;
}
.unlock-all-label.hidden {
    display: none;
}
.unlock-pay-btn .pi-coin-icon-small {
    /* Base .pi-coin-icon-small is white-on-translucent-white, tuned for
       the purple premium-plan-price context; the unlock button is now
       gold, so give the coin a dark fill here to stay legible against it. */
    background: rgba(58, 35, 18, 0.18);
    color: var(--gold-icon-dark);
}
.unlock-pay-btn:hover,
.unlock-all-btn:hover {
    background: linear-gradient(145deg, #fff3d6, var(--gold-bright) 55%, var(--gold));
}
.unlock-all-btn.hidden {
    display: none;
}
.unlock-cancel-btn {
    /* Deliberately NOT full-width like the Unlock/Pay buttons above it —
       it's a short two-word dismissal action, so sizing it to 100% /
       max-width: 260px (matching those longer-text primary buttons) left
       it looking like an oversized empty bar. Shrinks to fit its own
       text + padding instead; still centered via .modal-content's
       text-align: center. */
    background: transparent;
    color: #777;
    border: 1px solid #ccc;
    padding: 10px 24px;
    margin: 10px auto;
}
.unlock-cancel-btn:hover {
    background: #f2f2f2;
}

/* ===== Pi Premium crown button (top-controls) ===== */
/* Dark-brown glyph by default so it stays legible on the new golden
   circular badge (.control-icon i); the active/flash states below switch
   to a bright cream so the "premium" glow still reads against the gold. */
.premium-crown-btn i {
    color: var(--gold-icon-dark);
    transition: color 0.2s, text-shadow 0.2s;
}
.premium-crown-btn:hover i {
    color: #241407;
}
#premium-btn.premium-active i {
    color: #fff6e0;
    text-shadow: 0 0 6px rgba(255, 246, 224, 0.85);
}
/* Gentle glow so a subscriber can always tell Premium is active at a glance */
@keyframes premiumCrownGlow {
    0%, 100% { text-shadow: 0 0 4px rgba(255, 246, 224, 0.55); }
    50% { text-shadow: 0 0 10px rgba(255, 246, 224, 0.95); }
}
#premium-btn.premium-active i {
    animation: premiumCrownGlow 2.4s ease-in-out infinite;
}
/* Eye-catching gold flash shown briefly after a new game starts, to draw
   a non-subscriber's attention to the Premium button so they notice it's
   there to try. Distinct from premiumCrownGlow above (which is the calm,
   permanent glow for players who already subscribed) — this one is
   faster and stronger, and JS removes the class after ~10s so it never
   runs indefinitely. */
@keyframes premiumAttentionFlash {
    0%, 100% {
        color: var(--gold-icon-dark);
        text-shadow: none;
        transform: scale(1);
    }
    50% {
        color: #fff6e0;
        text-shadow: 0 0 12px rgba(255, 246, 224, 0.95), 0 0 22px rgba(255, 215, 0, 0.6);
        transform: scale(1.18);
    }
}
#premium-btn.premium-attention-flash i {
    animation: premiumAttentionFlash 0.9s ease-in-out infinite;
}
@keyframes premiumAttentionPulseBg {
    0%, 100% { box-shadow: none; }
    50% { box-shadow: 0 0 14px 4px rgba(255, 215, 0, 0.55); border-radius: 50%; }
}
#premium-btn.premium-attention-flash {
    animation: premiumAttentionPulseBg 0.9s ease-in-out infinite;
}
/* Days-left badge on the crown button — reuses the .feature-count circle
   but in the gold Premium color instead of the default blue, so it reads
   as "part of Premium" rather than a regular feature counter. */
.premium-days-badge {
    background: linear-gradient(145deg, #f5c451, #d1971e) !important;
    color: #4a2a00 !important;
    font-weight: 700;
    cursor: help;
}
.premium-days-badge-warning {
    background: linear-gradient(145deg, #ff8a5c, #e0522b) !important;
    color: #fff !important;
}

/* ===== Pi Premium subscription page ===== */
/* Full-page takeover, same treatment as Statistics / Leaderboard / Game
   Analysis / Help / Threat Report — was a floating centered card. */
.premium-modal-content {
    text-align: center;
}
.premium-page-content {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: 0;
    padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
    box-shadow: none;
    overflow-y: auto;
}
.premium-crown-icon {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: linear-gradient(145deg, #f5c451, #d1971e);
    color: #fff;
    font-size: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 6px auto 12px;
    box-shadow: 0 4px 10px rgba(209, 151, 30, 0.45);
}
/* No scoped override needed here anymore — the base .close rule is now
   position: absolute globally, so the crown icon below already centers
   purely on the modal's own width without any extra help. */
.premium-modal-desc {
    color: #555;
    font-size: 14px;
    margin: 0 auto 6px;
    max-width: 360px;
}
.premium-plans {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: 14px;
    margin: 18px 0 10px;
    flex-wrap: wrap;
}
.premium-plan-card {
    position: relative;
    flex: 1 1 140px;
    max-width: 175px;
    background: #faf8ff;
    border: 2px solid #e4dbf7;
    border-radius: 14px;
    padding: 20px 12px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    cursor: pointer;
    font-family: inherit;
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.premium-plan-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 18px rgba(91, 44, 153, 0.18);
    border-color: #c9b6f0;
}
.premium-plan-card:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none;
}
.premium-plan-name {
    font-weight: 700;
    color: #4a2a7a;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 0.6px;
}
.premium-plan-price {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 19px;
    font-weight: 800;
    color: #5b2c99;
    margin-top: 6px;
}
.premium-plan-price .pi-coin-icon-small {
    background: linear-gradient(145deg, #8247e5, #5b2c99);
    color: #fff;
}
.premium-plan-sub {
    font-size: 12px;
    color: #9086a3;
    margin-top: 2px;
}
.premium-plan-best {
    border-color: #f5c451;
    background: linear-gradient(180deg, #fffaf0 0%, #fdf3dc 100%);
    box-shadow: 0 4px 16px rgba(245, 196, 81, 0.35);
}
.premium-plan-best:hover {
    box-shadow: 0 10px 24px rgba(245, 196, 81, 0.5);
    border-color: #f5c451;
}
.premium-best-badge {
    position: absolute;
    top: -12px;
    left: 50%;
    transform: translateX(-50%);
    background: linear-gradient(145deg, #f5c451, #d1971e);
    color: #4a2a00;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    padding: 4px 12px;
    border-radius: 20px;
    box-shadow: 0 2px 6px rgba(209, 151, 30, 0.45);
    white-space: nowrap;
}
.premium-plan-savings {
    margin-top: 8px;
    font-size: 11px;
    line-height: 1.3;
    font-weight: 800;
    color: #96650a;
    background: rgba(245, 196, 81, 0.25);
    padding: 4px 9px;
    border-radius: 10px;
    text-align: center;
}
.premium-status {
    font-size: 13px;
    color: #5b2c99;
    font-weight: 700;
    min-height: 18px;
    line-height: 1.35;
    margin: 4px 0 0;
}
.premium-status.premium-status-expired {
    color: #d1491e;
}
.premium-fineprint {
    font-size: 12px;
    color: #6b5a8c;
    margin: 8px auto 0;
    max-width: 320px;
}

/* ===== Store modal (levels/themes/piece sets/bots + Starter Offer) =====
   Uses the same gold/dark-wood palette as the rest of the app's icons and
   buttons (--gold-bright/--gold/--gold-deep/--gold-icon-dark) instead of
   a separate purple accent, so the Store reads as part of the same set of
   controls as the crown/mute/settings icons rather than a different
   sub-brand. */
.store-modal-content {
    text-align: center;
}
.store-section {
    text-align: left;
    max-width: 420px;
    margin: 0 auto 14px;
}
.store-section-title {
    font-size: 13px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--gold-bright);
    margin: 0 0 6px;
}
.store-item-grid {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.store-item-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: linear-gradient(160deg, rgba(244, 223, 168, 0.16) 0%, rgba(217, 176, 106, 0.1) 100%);
    border: 1px solid var(--wood-bar-border);
    border-radius: 10px;
    padding: 8px 12px;
}
.store-bundle-row {
    background: linear-gradient(160deg, rgba(245, 196, 81, 0.28) 0%, rgba(209, 151, 30, 0.18) 100%);
    border-color: var(--gold);
}
.store-item-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--gold-text);
}
.store-item-owned {
    font-size: 12px;
    font-weight: 700;
    color: #7fe0a8;
}
.store-item-buy-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    padding: 6px 12px;
    width: auto;
    min-width: 0;
    /* Same light-gold fill + dark-brown text as .unlock-cancel-btn, so
       this button reads clearly against its own row instead of relying
       on the base .nav-button styling meant for the dark shell. */
    background: linear-gradient(160deg, rgba(244, 223, 168, 0.9) 0%, rgba(217, 176, 106, 0.85) 100%);
    color: var(--gold-icon-dark);
    border: 1px solid rgba(217, 176, 106, 0.6);
}
.store-item-buy-btn:hover {
    background: linear-gradient(160deg, rgba(248, 232, 188, 0.95) 0%, rgba(244, 223, 168, 0.9) 100%);
}
.store-item-buy-btn .pi-coin-icon-small {
    background: linear-gradient(145deg, var(--gold-bright), var(--gold-deep));
    color: var(--gold-icon-dark);
}

/* Starter Offer banner: small-Pi-holder intro price for Chess Pi Premium.
   Kept in its own green accent (distinct from the gold controls above) on
   purpose — it's a promotional callout, not a regular store row, so it
   should still stand out — but every text color inside it is scoped by
   ID/high-specificity selectors so it can't lose to the dark shell's
   `.modal-content p`/`.modal-content` rules (see the fix note below).
   Only shown while the player is server-confirmed eligible — see
   renderStarterOfferBanner() in script.js. */
.starter-offer-banner {
    max-width: 420px;
    margin: 4px auto 18px;
    background: linear-gradient(180deg, #eafff2 0%, #dcf9e6 100%);
    border: 2px solid #6fcf97;
    border-radius: 14px;
    padding: 14px 16px;
}
/* BUG FIX: no rule anywhere translated the "hidden" class (toggled by
   renderStarterOfferBanner() in script.js) into an actual display: none
   for this specific element — unlike .nav-arrow.hidden/.unlock-tried-note.hidden/
   etc. above, which each have their own such rule. That let the banner
   (badge, description, and buy button) stay fully visible inside the Store
   modal even when script.js had correctly determined the player is
   ineligible (e.g. an existing regular subscriber) and added the class —
   only the price text was blank in that case, since renderStarterOfferBanner()
   returns before setting it once ineligible. Clicking the still-visible
   button then hung in Pi's "Preparing" state until timeout, since
   approve.js correctly rejects the payment server-side either way. */
.starter-offer-banner.hidden {
    display: none;
}
.starter-offer-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #1e7a45;
    background: rgba(111, 207, 151, 0.25);
    padding: 4px 10px;
    border-radius: 20px;
    margin-bottom: 8px;
}
.starter-offer-desc {
    font-size: 13px;
    color: #2f5b41;
    margin: 0 0 10px;
}
/* SPECIFICITY FIX: the app's dark modal shell has a later, more specific
   `.modal-content p` rule (class+element) that overrides any single-class
   selector on a <p> — including .starter-offer-desc above — to a light
   cream color meant for the dark wood background. That washed this
   paragraph out to near-invisible against the banner's light mint
   background. Scoping by ID (highest specificity short of !important)
   guarantees the intended dark, readable green always wins here. */
#starter-offer-desc {
    color: #204631;
}
.starter-offer-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    /* FIX: .nav-button (the button's other class) sets margin: 10px on
       all sides. Combined with width: 100% here, that pushed the button
       20px wider than the banner's inner content box (10px past each
       edge), so it overflowed off-center inside the frame instead of
       sitting centered within it. Reset the inherited margin and use
       box-sizing so width: 100% is measured including padding. */
    margin: 0;
    box-sizing: border-box;
    background: linear-gradient(145deg, #6fcf97, #2e9e5b);
    color: #fff;
    font-weight: 800;
}
.starter-offer-btn .pi-coin-icon-small {
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
}
.starter-offer-price-sub {
    display: block;
    font-size: 10px;
    font-weight: 600;
    opacity: 0.9;
    margin-top: 2px;
}

/* Filled-out mobile layout for the whole Premium page — icon, title,
   copy, cards, status/fineprint text, and button are all sized up
   together (not just the plan cards) to make good use of the screen,
   while staying tight enough that the full page still fits in one
   screen on a phone with no scrolling. */
@media (max-width: 480px) {
    .premium-page-content {
        padding-top: max(16px, env(safe-area-inset-top, 0px));
        padding-bottom: max(16px, env(safe-area-inset-bottom, 0px));
    }
    .premium-crown-icon {
        width: 50px;
        height: 50px;
        font-size: 20px;
        margin: 4px auto 10px;
    }
    #premium-modal-title {
        font-size: 23px;
        margin: 0 0 6px;
    }
    .premium-modal-desc {
        font-size: 13.5px;
        line-height: 1.35;
        margin: 0 auto 4px;
        max-width: 320px;
    }
    .premium-plans {
        flex-direction: column;
        align-items: center;
        gap: 12px;
        margin: 14px 0 10px;
    }
    .premium-plan-card {
        /* Square, stacked cards — sized to fill noticeably more of the
           screen than the previous compact pass, while the width (and
           matching min-height) still drives the square shape. Content
           scales up via the larger name/price/sub/savings font sizes
           below so it doesn't look sparse inside the bigger box. */
        flex: 0 0 auto;
        width: min(40vw, 148px);
        max-width: none;
        min-height: min(40vw, 148px);
        justify-content: center;
        padding: 14px 12px;
        gap: 4px;
    }
    .premium-plan-name {
        font-size: 13px;
    }
    .premium-plan-price {
        font-size: 18px;
        gap: 6px;
        margin-top: 4px;
    }
    .premium-plan-price .pi-coin-icon-small {
        width: 19px;
        height: 19px;
        font-size: 13px;
    }
    .premium-plan-sub {
        font-size: 11px;
        margin-top: 2px;
    }
    /* The floating "BEST VALUE" ribbon sits above its own card via
       absolute positioning — once cards stack, give the first card
       (Monthly) a little extra top margin so it isn't crowded against
       the Yearly card's ribbon above it. */
    .premium-plan-best {
        margin-top: 6px;
    }
    .premium-best-badge {
        top: -11px;
        font-size: 9.5px;
        padding: 4px 11px;
    }
    .premium-plan-savings {
        margin-top: 6px;
        font-size: 10px;
        padding: 4px 9px;
        border-radius: 9px;
    }
    .premium-status {
        font-size: 13px;
        min-height: 17px;
        margin: 4px 0 0;
    }
    .premium-fineprint {
        font-size: 11.5px;
        margin: 6px auto 0;
        max-width: 310px;
    }
    .premium-page-content .unlock-cancel-btn {
        padding: 10px 26px;
        margin: 10px auto 0;
        font-size: 15px;

    }
}


/* ============================================================
   LARGE SCREEN / DESKTOP LAYOUT (computers, laptops, wide tablets)
   ------------------------------------------------------------
   Everything above this block is the original phone layout and is
   left completely untouched.

   This block is now driven by an actual "adaptive layout" approach:
   JavaScript (script.js) detects the device/viewport on load and on
   resize, and toggles a class on <html> — device-mobile / device-tablet
   / device-desktop. CSS below reacts to that class instead of (only)
   a width media query, which is what makes this a genuine layout
   re-arrangement rather than a simple shrink: elements are moved to
   different grid cells (not just resized), and the same mechanism can
   be extended per device class (e.g. a distinct html.device-tablet
   ruleset) without touching the phone rules above.

   A @media fallback further below still applies the very first frame
   (before JS finishes running) so there's no flash of the wrong layout.

   Colors, gradients and visual style are all inherited unchanged from
   the rules above — only sizing/position/order change here.
   ============================================================ */
html.device-desktop .game-page .container,
html.device-tablet.orientation-landscape .game-page .container {
    justify-content: center;
    align-items: center;
}

html.device-desktop .game-container,
html.device-tablet.orientation-landscape .game-container {
    /* Single source of truth for the whole desktop layout scale.
       Grows with viewport height/width, bounded so it never gets
       absurdly small or large. */
    --board-size: clamp(240px, min(68vh, 46vw), 780px);
    flex-grow: 0;
    display: grid;
    grid-template-columns: var(--board-size) calc(var(--board-size) * 0.22);
    grid-template-rows: auto auto auto minmax(var(--board-size), auto) auto;
    column-gap: clamp(16px, 2vw, 32px);
    row-gap: 10px;
    justify-content: center;
    align-items: start;
    padding-bottom: 0;
}

/* ---- Left column: everything the phone layout already stacks
   vertically (top bar, status, indicators, board) stays stacked,
   just pinned to board-width and to grid rows 1-3 & 5. ---- */
html.device-desktop .game-info-container,
html.device-tablet.orientation-landscape .game-info-container {
    grid-column: 1;
    grid-row: 1;
    width: var(--board-size);
    max-width: var(--board-size);
    margin: 0;
    padding: calc(var(--board-size) * 0.018) calc(var(--board-size) * 0.025);
}
html.device-desktop .game-status,
html.device-tablet.orientation-landscape .game-status {
    grid-column: 1;
    grid-row: 2;
    width: var(--board-size);
    max-width: var(--board-size);
    margin: 0 auto;
}
html.device-desktop #bot-indicator,
html.device-tablet.orientation-landscape #bot-indicator {
    grid-column: 1;
    grid-row: 3;
}
html.device-desktop .board-container,
html.device-tablet.orientation-landscape .board-container {
    grid-column: 1;
    grid-row: 4;
    margin: 0;
    align-self: center;
}
html.device-desktop #white-player-indicator,
html.device-tablet.orientation-landscape #white-player-indicator {
    grid-column: 1;
    grid-row: 5;
}
html.device-desktop .side-indicator-row,
html.device-tablet.orientation-landscape .side-indicator-row {
    width: var(--board-size);
    max-width: var(--board-size);
}
html.device-desktop .chessboard,
html.device-tablet.orientation-landscape .chessboard {
    width: var(--board-size);
    height: var(--board-size);
    max-width: none;
    max-height: none;
    font-size: calc(var(--board-size) / 8 * 0.9);
}

/* ---- Right column: vertical properties bar, same height as
   the board, taking the place of the old bottom icon strip. ---- */
html.device-desktop .controls-bottom,
html.device-tablet.orientation-landscape .controls-bottom {
    grid-column: 2;
    grid-row: 4;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: space-evenly;
    align-items: center;
    align-self: center;
    width: 100%;
    height: auto;
    min-height: var(--board-size);
    margin: 0;
    padding: calc(var(--board-size) * 0.015) calc(var(--board-size) * 0.008);
    gap: calc(var(--board-size) * 0.006);
}
html.device-desktop .controls-bottom .control-icon,
html.device-tablet.orientation-landscape .controls-bottom .control-icon {
    max-width: none;
    width: 100%;
    padding: calc(var(--board-size) * 0.007) 4px;
}
html.device-desktop .controls-bottom .control-icon i,
html.device-tablet.orientation-landscape .controls-bottom .control-icon i {
    width: calc(var(--board-size) * 0.065);
    height: calc(var(--board-size) * 0.065);
    font-size: calc(var(--board-size) * 0.032);
    margin-bottom: calc(var(--board-size) * 0.006);
}
html.device-desktop .controls-bottom .control-icon span,
html.device-tablet.orientation-landscape .controls-bottom .control-icon span {
    font-size: calc(var(--board-size) * 0.021);
}
html.device-desktop .controls-bottom .feature-count,
html.device-tablet.orientation-landscape .controls-bottom .feature-count {
    width: calc(var(--board-size) * 0.04);
    height: calc(var(--board-size) * 0.04);
    font-size: calc(var(--board-size) * 0.022);
    top: calc(var(--board-size) * -0.01);
    right: calc(var(--board-size) * -0.01);
}
html.device-desktop .controls-bottom .pi-coin-icon,
html.device-tablet.orientation-landscape .controls-bottom .pi-coin-icon {
    width: calc(var(--board-size) * 0.065);
    height: calc(var(--board-size) * 0.065);
    font-size: calc(var(--board-size) * 0.032);
    margin-bottom: calc(var(--board-size) * 0.006);
}

/* ---- Top bar keeps its own icons in sync with board-size too ---- */
html.device-desktop .game-info-container .control-icon i,
html.device-tablet.orientation-landscape .game-info-container .control-icon i {
    width: calc(var(--board-size) * 0.07);
    height: calc(var(--board-size) * 0.07);
    font-size: calc(var(--board-size) * 0.035);
}
html.device-desktop .game-timer-display,
html.device-tablet.orientation-landscape .game-timer-display {
    font-size: calc(var(--board-size) * 0.045);
}
html.device-desktop .game-timer-label,
html.device-tablet.orientation-landscape .game-timer-label {
    font-size: calc(var(--board-size) * 0.024);
}
html.device-desktop .side-indicator-pill,
html.device-tablet.orientation-landscape .side-indicator-pill {
    font-size: calc(var(--board-size) * 0.028);
    padding: calc(var(--board-size) * 0.012) calc(var(--board-size) * 0.025);
    gap: calc(var(--board-size) * 0.014);
}
html.device-desktop #player-text,
html.device-tablet.orientation-landscape #player-text {
    max-width: calc(var(--board-size) * 0.22);
}
html.device-desktop .player-color-indicator,
html.device-tablet.orientation-landscape .player-color-indicator {
    width: calc(var(--board-size) * 0.032);
    height: calc(var(--board-size) * 0.032);
}

/* ---- One-frame fallback: applies the same desktop rules purely by
   viewport width, in case this paints before script.js has attached
   the device-desktop class (e.g. very first paint). JS then takes
   over immediately and keeps the class in sync on every resize. ---- */
@media (min-width: 1024px) {
    html:not(.device-mobile):not(.device-tablet) .game-container {
        --board-size: clamp(240px, min(68vh, 46vw), 780px);
    }
}

/* =====================================================================
   GLOBAL DARK LUXURY MODAL THEME
   Unifies every popup (Statistics, Leaderboard, Help/Advice, Features,
   Game Over, Import PGN, Surrender, Promotion, Pi Payment, Unlock,
   Premium) with the same dark-wood + gold look already used on the game
   page bars and the Board/Pieces/Bot settings modal above. Placed at the
   end of the file so these same-specificity selectors win over the
   original light-mode rules earlier in the file, without touching them
   (keeps the diff readable and reversible).

   Left untouched on purpose: the purple "buy" CTAs/badges in the Premium
   subscription modal, and the green "unlocked" badges — those are
   deliberate semantic colors (purple = Premium subscription, green =
   owned) used consistently elsewhere in the app, not decorative
   blue/white leftovers. The Unlock modal's own pay CTAs were switched
   from purple to gold (see the Unlock modal section above) so purple
   reads as "Premium" specifically, not "any payment".
   ===================================================================== */

/* ---- Base shell shared by Statistics, Leaderboard, Import PGN,
   Promotion, Surrender, Unlock and Premium modals (all use
   .modal-content) ---- */
.modal-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    color: var(--gold-text);
}
.modal-content h2 {
    color: var(--gold-bright);
}
.modal-content p {
    color: rgba(232, 207, 158, 0.75);
}
.close {
    color: var(--gold);
}
.close:hover {
    color: var(--gold-bright);
}

/* ---- Shared Apply/nav buttons across every modal (New Game, Settings,
   Statistics, Leaderboard, Back, Import, Surrender/Cancel...) ---- */
.nav-button {
    background: linear-gradient(160deg, var(--gold-bright) 0%, var(--gold) 55%, var(--gold-deep) 100%);
    color: var(--gold-icon-dark);
}
.nav-button:hover {
    background: linear-gradient(160deg, #f8e8bc 0%, var(--gold-bright) 55%, var(--gold) 100%);
}

/* ---- Features modal (Help "?" — feature tour) ---- */
.features-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    color: rgba(232, 207, 158, 0.85);
}
.features-header {
    border-bottom-color: var(--wood-bar-border);
}
.features-header h2 {
    color: var(--gold-bright);
}
.features-close {
    color: var(--gold);
}
.features-close:hover {
    color: var(--gold-bright);
}
.features-section h3 {
    color: var(--gold-text);
    border-bottom-color: rgba(217, 176, 106, 0.2);
}
.features-list li {
    background-color: rgba(255, 255, 255, 0.06);
    color: rgba(232, 207, 158, 0.85);
    border-right-color: var(--gold);
}

/* ---- Advice / Help modal ---- */
.advice-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    color: rgba(232, 207, 158, 0.85);
}
.advice-header {
    border-bottom-color: var(--wood-bar-border);
}
.advice-header h2 {
    color: var(--gold-bright);
}
.advice-close {
    color: var(--gold);
}
.advice-close:hover {
    color: var(--gold-bright);
}
.advice-section h3 {
    color: var(--gold-text);
    border-bottom-color: rgba(217, 176, 106, 0.2);
}
.advice-list li:before {
    color: var(--gold);
}
.advice-tip {
    background-color: rgba(255, 255, 255, 0.06);
    color: rgba(232, 207, 158, 0.85);
    border-left-color: var(--gold);
}

/* ---- Threat Report panel inside the Advice modal (was still using its
   original light-mode colors — #eee dividers and the blue --primary-color
   heading — while sitting on the modal's dark wood background above, so
   the divider was nearly invisible and, worse, .threat-tip's #f8f9fa
   near-white background combined with the modal's light-gold inherited
   text color made the "Recommended actions" list unreadable.) ---- */
.threat-info-header {
    border-bottom-color: rgba(217, 176, 106, 0.2);
}
.threat-info-title {
    color: var(--gold-text);
}
.threat-info-list li {
    border-bottom-color: rgba(217, 176, 106, 0.15);
}
.threat-tip {
    background-color: rgba(255, 255, 255, 0.06);
    color: rgba(232, 207, 158, 0.85);
    border-left-color: var(--gold);
}
.threat-tip strong {
    color: var(--gold-text);
}

/* ---- Threat Report page ---- */
/* Full-page takeover, same treatment as Statistics/Leaderboard/Game
   Analysis — was cramped inside an 80vh/600px-wide card. Placed after the
   .advice-content mobile media query above (source order) so it wins on
   small screens too, exactly like .game-analysis-content below. Header
   stays pinned; only .advice-scrollable-content scrolls. */
.threat-report-content {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: 0;
    padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
    box-shadow: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.threat-report-content > .advice-header {
    flex-shrink: 0;
}
.advice-scrollable-content {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 5px;
}

/* ---- Game Analysis modal (local, in-app Stockfish analysis) ---- */
/* Full-page takeover, same treatment as Statistics/Leaderboard above —
   the board and move-detail list were cramped inside an 85vh/440px-wide
   card. Back/close still return to whichever origin modal opened it
   (game-over-modal in the normal post-game case, import-pgn-modal when
   reached via PGN import) exactly as before; this only changes how much
   screen it's drawn on. */
.game-analysis-content {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    border-radius: 0;
    padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
    box-shadow: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.game-analysis-content > .advice-header {
    flex-shrink: 0;
}
.analysis-progress-view {
    text-align: center;
    padding: 10px 0 4px;
}
.analysis-progress-view p {
    color: rgba(232, 207, 158, 0.85);
    margin-bottom: 14px;
}
.analysis-progress-bar {
    width: 100%;
    margin: 0 0 18px;
}
/* Results view: the board+eval-bar stay pinned at the top (see
   .analysis-board-pinned below) while the stats/moves panels underneath
   scroll independently within this column. */
.analysis-results-view {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}
.analysis-summary {
    display: flex;
    gap: 8px;
}
.analysis-summary-col {
    /* Shrunk from the original layout (was ~4 loosely-spaced lines with
       10px/12px padding) so the summary takes noticeably less vertical
       room — that space goes to the board/move-detail area below, which
       was cramped. Value + its "Avg. centipawn loss" label are merged
       onto one line instead of two separate ones. */
    flex: 1;
    background-color: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(217, 176, 106, 0.2);
    border-radius: 8px;
    padding: 6px 10px;
    text-align: center;
}
.analysis-summary-col h4 {
    margin: 0 0 2px;
    color: var(--gold-text);
    font-size: 0.8rem;
}
.analysis-summary-col p {
    margin: 1px 0;
    font-size: 0.68rem;
    line-height: 1.25;
    color: rgba(232, 207, 158, 0.75);
}
.analysis-summary-col .acpl-value {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--gold-bright);
}
.analysis-summary-col .acpl-label {
    /* Sits inline right after the number instead of on its own line
       (previously a separate <p>) — same info, one less line of height. */
    font-size: 0.68rem;
    font-weight: 400;
    color: rgba(232, 207, 158, 0.6);
    margin-left: 3px;
}
/* ---- Mini preview board shown in the results view — clicking any move
   row below re-renders this board at that move's position and slides the
   moved piece into place, so the game's outcome can be seen visually
   without leaving the Game Analysis modal. ---- */
.analysis-board-wrap {
    display: flex;
    justify-content: center;
    align-items: stretch;
    gap: 10px;
    flex-shrink: 0;
}
/* Pins the board+eval-bar to the top of the scrolling .analysis-results-view
   column instead of letting them scroll away with the rest of the content —
   the stats/moves panels below (.analysis-panels) scroll underneath it.
   The opaque wood-gradient background stops the panels' content from
   showing through as they scroll past underneath. */
.analysis-board-pinned {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--wood-bar-bg);
    margin: 0 -20px;
    padding: 10px 20px 14px;
    border-bottom: 1px solid var(--wood-bar-border);
}
/* Vertical evaluation bar, lichess/chess.com style: white fills from the
   bottom up in proportion to White's advantage, black fills the rest at
   the top. Updates the instant a move row is clicked, ahead of the piece
   slide animation on the board itself. */
.analysis-eval-bar-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex-shrink: 0;
    /* Fixed width, not just the bar's own 18px: without this, the wrap's
       width followed whichever child was widest — usually the eval label
       below the bar ("+0.3" vs "-12.4" vs "#5" are all different widths).
       Since the sibling board is centered against this wrap via
       .analysis-board-wrap's justify-content:center, any change in the
       wrap's width shifted the whole row's center point — visibly
       nudging the board left/right every time a move row was clicked.
       Wide enough for the longest realistic label (e.g. "-99.9" or a
       3-digit mate score) plus a little breathing room. */
    width: 46px;
}
.analysis-eval-bar {
    width: 18px;
    height: min(72vw, 300px);
    background-color: #2b2b2b;
    border: 2px solid #333;
    border-radius: 3px;
    position: relative;
    overflow: hidden;
}
.analysis-eval-fill {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 50%;
    background-color: #f4f4f4;
    transition: height 0.35s ease;
}
.analysis-eval-label {
    margin-top: 6px;
    font-size: 0.72rem;
    font-weight: 600;
    color: rgba(232, 207, 158, 0.75);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.analysis-board {
    width: min(72vw, 300px);
    aspect-ratio: 1 / 1;
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(8, 1fr);
    border: 3px solid #333;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
    position: relative;
    font-size: calc(min(72vw, 300px) / 8 * 0.85);
}
.analysis-board .square {
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    overflow: hidden;
}
/* ---- The two frames below the pinned board: Stats (.analysis-summary,
   avg. centipawn loss / blunders-mistakes-inaccuracies) and Moves
   (.analysis-movelist). Both share the same bordered "card" look so they
   read as a matched pair. ---- */
.analysis-panels {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 14px;
}
.analysis-panel {
    background-color: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(217, 176, 106, 0.2);
    border-radius: 10px;
    padding: 12px;
}
.analysis-panel-title {
    margin: 0 0 10px;
    font-size: 0.82rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--gold-text);
    display: flex;
    align-items: center;
    gap: 6px;
}
.analysis-panel-title i {
    color: var(--gold);
    font-size: 0.85rem;
}
.analysis-movelist {
    /* No longer its own scroll container — .analysis-results-view (the
       ancestor two levels up) is what scrolls; this panel just grows to
       its natural content height. */
    max-height: none;
}
.analysis-move-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 2px 10px;
    padding: 7px 4px;
    border-bottom: 1px solid rgba(217, 176, 106, 0.12);
    font-size: 0.88rem;
    cursor: pointer;
    border-radius: 6px;
}
.analysis-move-row:hover {
    background-color: rgba(255, 255, 255, 0.05);
}
.analysis-move-row.active {
    background-color: rgba(217, 176, 106, 0.16);
}
.analysis-move-row:last-child {
    border-bottom: none;
}
.analysis-move-label {
    color: rgba(232, 207, 158, 0.9);
    min-width: 90px;
}
.analysis-move-eval {
    color: rgba(232, 207, 158, 0.6);
    font-variant-numeric: tabular-nums;
    margin-left: auto;
}
.analysis-move-badge {
    font-size: 0.72rem;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.analysis-best-suggestion {
    flex-basis: 100%;
    font-size: 0.78rem;
    color: rgba(232, 207, 158, 0.55);
}
/* Move-quality colors */
.analysis-move-row.eval-blunder .analysis-move-badge { background: rgba(229, 115, 115, 0.2); color: #ff6b6b; }
.analysis-move-row.eval-mistake .analysis-move-badge { background: rgba(255, 146, 72, 0.2); color: #ff9248; }
.analysis-move-row.eval-inaccuracy .analysis-move-badge { background: rgba(244, 223, 168, 0.2); color: #f4dfa8; }
.analysis-move-row.eval-best .analysis-move-eval { color: #7ed957; }

/* ---- Game Over modal ---- */
.game-over-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.game-over-content h2 {
    color: var(--gold-bright);
}
.game-over-content p {
    color: rgba(232, 207, 158, 0.8);
}

/* ---- Statistics & Leaderboard modals (both share .stats-content) ---- */
.stats-content h2 {
    color: var(--gold-bright);
}
/* Leaderboard title split into a main title + smaller subtitle line
   ("Leaderboard" / "Top Players") instead of one em-dash-joined line. */
.leaderboard-title {
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.25;
}
.leaderboard-title .leaderboard-subtitle {
    font-size: 0.5em;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgba(232, 207, 158, 0.7);
}
.stats-tabs {
    border-bottom-color: rgba(217, 176, 106, 0.2);
}
.tab-button {
    color: rgba(232, 207, 158, 0.55);
}
.tab-button.active {
    color: var(--gold-bright);
    border-bottom-color: var(--gold);
}
.stats-section {
    background-color: rgba(255, 255, 255, 0.05);
    border-left-color: var(--gold);
}
.stats-section h3 {
    color: var(--gold-text);
    border-bottom-color: rgba(217, 176, 106, 0.2);
}
.stat-item, .diff-stat-item {
    background-color: rgba(255, 255, 255, 0.06);
}
.stat-item:hover {
    background-color: rgba(255, 255, 255, 0.1);
}
.stat-label, .diff-label {
    color: rgba(232, 207, 158, 0.75);
}
.stat-value, .diff-value {
    color: var(--gold-bright);
}
.stats-scrollable-content::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.06);
}
.stats-scrollable-content::-webkit-scrollbar-thumb {
    background: var(--gold);
}
.stats-scrollable-content::-webkit-scrollbar-thumb:hover {
    background: var(--gold-bright);
}
.leaderboard-note {
    color: rgba(232, 207, 158, 0.6);
}
.leaderboard-item {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(217, 176, 106, 0.18);
}
.leaderboard-item:hover {
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.leaderboard-top.rank-1 {
    background: linear-gradient(135deg, rgba(245, 196, 81, 0.22), rgba(245, 196, 81, 0.08));
    border-color: rgba(245, 196, 81, 0.45);
}
.leaderboard-top.rank-2 {
    background: linear-gradient(135deg, rgba(200, 205, 212, 0.2), rgba(200, 205, 212, 0.06));
    border-color: rgba(200, 205, 212, 0.4);
}
.leaderboard-top.rank-3 {
    background: linear-gradient(135deg, rgba(210, 140, 80, 0.22), rgba(210, 140, 80, 0.08));
    border-color: rgba(210, 140, 80, 0.4);
}
.leaderboard-item.leaderboard-me {
    border: 1.5px solid var(--gold);
    background: rgba(217, 176, 106, 0.1);
    box-shadow: 0 2px 8px rgba(217, 176, 106, 0.2);
}
.leaderboard-rank {
    color: var(--gold-bright);
}
.leaderboard-name {
    color: var(--gold-text);
}
.leaderboard-stats {
    color: rgba(232, 207, 158, 0.55);
}
.leaderboard-dot {
    color: rgba(232, 207, 158, 0.3);
}
.leaderboard-winrate {
    color: var(--gold-bright);
    background: rgba(217, 176, 106, 0.15);
}
.leaderboard-top.rank-1 .leaderboard-winrate {
    color: #f5c451;
    background: rgba(245, 196, 81, 0.2);
}
.leaderboard-top.rank-3 .leaderboard-winrate {
    color: #e0985a;
    background: rgba(210, 140, 80, 0.2);
}

/* ---- Pi Payment modal ---- */
#pi-payment-modal .modal-content {
    background: linear-gradient(160deg, rgba(58, 36, 21, 0.97) 0%, rgba(36, 20, 7, 0.97) 55%, rgba(23, 13, 5, 0.97) 100%);
    border: 1px solid var(--wood-bar-border);
    backdrop-filter: blur(5px);
}
#pi-payment-modal h2 {
    color: var(--gold-bright);
}
#pi-payment-modal .close {
    color: var(--gold);
}

/* ---- Promotion modal (pawn promotion choice) ---- */
.promotion-options button {
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--gold);
    color: var(--gold-text);
}
.promotion-options button:hover {
    background: var(--gold);
    color: var(--gold-icon-dark);
}

/* ---- Unlock & Premium modals: the Premium subscription CTAs/badges keep
   their purple + gold "best value" treatment (semantic, not decorative);
   the Unlock modal's pay CTAs were switched to gold above to match the
   rest of the app, so just lift the plain body copy so it reads clearly
   on the new dark shell. ---- */
#unlock-modal-desc, #premium-modal-desc {
    color: rgba(232, 207, 158, 0.75);
}
.premium-status {
    color: var(--gold-bright);
}
.premium-fineprint {
    color: rgba(232, 207, 158, 0.55);
}
.unlock-cancel-btn {
    /* Plain rgba text on the transparent/dark-wood button never had a
       fill of its own to sit against, so a plain lighter or darker text
       color alone can't fix legibility either way. Give it the same
       light-gold fill the Apply/nav-button uses, so the requested dark
       brown text (--gold-icon-dark, matching Apply's text) actually has
       something light to read against. */
    background: linear-gradient(160deg, rgba(244, 223, 168, 0.9) 0%, rgba(217, 176, 106, 0.85) 100%);
    color: var(--gold-icon-dark);
    border-color: rgba(217, 176, 106, 0.6);
}
.unlock-cancel-btn:hover {
    background: linear-gradient(160deg, rgba(248, 232, 188, 0.95) 0%, rgba(244, 223, 168, 0.9) 100%);
}
