  :root{
    --bg: #14161a;
    --panel: #1c1f26;
    --panel-2: #232732;
    --light-sq: #f0dfc2;
    --dark-sq: #3d5a73;
    --accent: #c9a24b;
    --accent-2: #4b8ac9;
    --danger: #d9534f;
    --text: #eef0f3;
    --text-dim: #9aa2b1;
    --sel: rgba(201,162,75,0.55);
    --move-dot: rgba(75,138,201,0.65);
    --check-glow: rgba(217,83,79,0.75);
    --move-arrow: rgba(255, 121, 198, 0.55); /* soft pink — the Turn Bar's "last move" line */
  }
  *{box-sizing:border-box;}
  html,body{
    margin:0; padding:0; height:100%;
    background: radial-gradient(circle at 30% 0%, #1e222b 0%, var(--bg) 60%);
    color: var(--text);
    font-family: 'Segoe UI', system-ui, -apple-system, Roboto, Arial, sans-serif;
  }
  .app{
    display:flex;
    flex-wrap:wrap;
    gap:20px;
    justify-content:center;
    align-items:flex-start;
    padding:20px;
    max-width:1100px;
    margin:0 auto;
  }
  /* The Stats Bar + the two main boxes live in one container that is exactly as wide as
     the two boxes together (it shrinks to fit its content, so the bar above can never be
     wider or narrower than the boxes below it) — and it is where the bar's future
     companions will go, too. */
  .app-body{
    display:flex;
    flex-direction:column;
    gap:10px;
    max-width:100%;
    min-width:0;
  }
  .app-main{
    display:flex;
    flex-wrap:wrap;
    gap:20px;
    justify-content:center;
    align-items:stretch; /* the side panel matches the board box's full height, watching bar included */
  }
  .ad-slot{
    display:flex;
    justify-content:center;
    align-items:center;
    width:100%;
    min-height:0;
    overflow:hidden; /* a slow-to-load ad unit should never push the board around or blow out the width */
  }
  h1{
    font-weight:600;
    color:var(--accent);
    margin:0;
  }
  .site-title{
    display:block;
    max-width:550px; /* matches the board's own max rendered width, see .board-wrap */
    margin:0 auto;
    font-family:'Cinzel', serif;
    font-size:2.5rem;
    font-weight:700;
    letter-spacing:5px;
    text-decoration:none;
    color:var(--accent);
  }
  .site-title:hover{ opacity:0.9; }
  .title-icon{
    height:0.8em;
    width:auto;
    vertical-align:-0.08em; /* optical nudge to sit nicely on the gold serif text's baseline */
    margin:0 0.15em;
  }
  .live-stats-bar{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:8px;
    background: var(--panel);
    border-radius:12px;
    padding:8px 14px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.35);
    font-size:0.78rem;
    color: var(--text-dim);
  }
  .live-dot{
    width:7px; height:7px; border-radius:50%;
    background:#3ecf6e;
    box-shadow:0 0 0 0 rgba(62,207,110,0.6);
    animation: live-pulse 2s infinite;
  }
  /* The green light is only on while somebody is actually playing; otherwise (nobody playing,
     or the stats unavailable) it is simply off. */
  .live-stats-bar.offline .live-dot,
  .live-stats-bar.idle .live-dot{ background:#666; animation:none; box-shadow:none; }
  @keyframes live-pulse{
    0%{ box-shadow:0 0 0 0 rgba(62,207,110,0.5); }
    70%{ box-shadow:0 0 0 5px rgba(62,207,110,0); }
    100%{ box-shadow:0 0 0 0 rgba(62,207,110,0); }
  }
  /* Status bar: top of the page, replacing the old turn-status line that used to sit in
     the side panel above the Support button. Left side is the live game status (what used
     to be #statusMsg down by the avatar); right side, past a thin divider, is a dimmed
     echo of the "N people playing" live stats -- the same numbers get their own full-size
     bar further down the page, just above the world map (see .live-stats-bar below). The
     message truncates with an ellipsis rather than wrapping, so one long status line (or a
     narrow phone) never grows the bar. */
  .status-bar{
    display:flex;
    align-items:center;
    gap:12px;
    background: var(--panel);
    border-radius:12px;
    padding:8px 14px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.35);
    font-size:0.78rem;
  }
  /* The bar is split into two halves so the live game status never visually blends into
     the "N people playing" echo on the right: each side gets equal, independent space and
     its own text-truncation, with the thin divider between them as the only shared seam. */
  .status-left{
    flex:1 1 0;
    min-width:0;
    display:flex;
    align-items:center;
    gap:12px;
  }
  .status-right{
    flex:1 1 0;
    min-width:0;
    display:flex;
    align-items:center;
    justify-content:flex-end;
  }
  .status-bar-label{
    color: var(--accent);
    font-weight:700;
    font-size:0.7rem;
    letter-spacing:0.5px;
    text-transform:uppercase;
    flex-shrink:0;
  }
  .status-bar .status-msg{
    flex:1;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    font-size:0.8rem;
  }
  .status-bar-divider{
    width:1px;
    height:16px;
    background:#333947;
    flex-shrink:0;
  }
  .status-bar-stats{
    color: var(--text-dim);
    flex-shrink:0;
    white-space:nowrap;
  }
  /* AI response-time badge (left half): a solid accent pill so it reads as a small piece of
     status, not as the game-status line itself, with room for the clock-icon prefix added
     in JS. Pulses 3 times (see .pulse-3x below) when it first appears or its text changes,
     then settles -- enough for the player to notice and read it, never a nagging loop. */
  #aiTimeEstimate{
    background: var(--accent);
    color:#1b1d22;
    font-weight:700;
    border-radius:6px;
    padding:2px 10px;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    /* Overrides .status-bar-stats' flex-shrink:0 -- without this the badge refused to
       shrink and spilled past .status-left into the "people playing" text on the right
       (min-width:0 is what actually lets a flex item shrink below its content size). */
    flex-shrink:1;
    min-width:0;
  }
  #aiTimeEstimate.pulse-3x{
    animation: start-pulse-anim 1.8s ease-in-out 3;
  }
  /* "ChessBoard" / "Options" jump buttons: only ever shown on mobile, right under the
     status bar — see the 720px media query below for their actual layout. */
  .mobile-jump-row{ display:none; }
  .credit-line{
    color:var(--text-dim);
    font-size:0.72rem;
    margin-top:6px;
  }
  .hero-headline{
    max-width:560px;
    margin:10px auto 0;
    color: var(--text);
    font-size:1.02rem;
    line-height:1.5;
  }
  .hero-headline strong{ color: var(--accent); font-weight:700; }
  .copyright-line{
    color:var(--text-dim);
    font-size:0.68rem;
    opacity:0.75;
  }
  .header{
    width:100%;
    text-align:center;
    margin-bottom:14px;
  }
  .board-wrap{
    position:relative; /* anchors .move-arrow-overlay, positioned in JS to exactly cover #board */
    --label: 24px; /* width of the rank-number column / height of the file-letter row (smaller on phones) */
    /* The move-history bars and the board share this SAME grid track template.
       Each square track is minmax(0, 62px): it can never grow past 62px, and never grows
       to fit a cell's content — a history bar with a very long move list simply scrolls
       inside its fixed-width cell instead of stretching the board area. It CAN shrink, all
       the way down, so the whole board always fits the screen; the squares stay square
       because each one takes its height from its own width (see .sq's aspect-ratio).
       This is a pure-CSS guarantee: it holds even without JavaScript. */
    display:grid;
    grid-template-columns: var(--label) repeat(8, minmax(0, 62px)) var(--label);
    row-gap:4px;
    align-content:space-between; /* any leftover height goes into the GAPS between rows, never into the rows themselves (that is what padded the binary bars) */
    background: var(--panel);
    padding:10px 14px;
    border-radius:16px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  }
  #board{
    grid-column: 1 / -1;
    display:grid;
    /* A "frame" (--label wide) on every side of the actual 8x9 squares: a spacer row/column
       at the top and right mirror the rank-number column (left) and file-letter row
       (bottom), so the border sits equidistant from the playable squares all around.
       The 9 square rows are `auto`: each row is exactly as tall as its squares are wide,
       so on any screen the squares are true squares — never stretched tall on a phone. */
    grid-template-columns: var(--label) repeat(8, minmax(0, 62px)) var(--label);
    grid-template-rows: var(--label) repeat(9, auto) var(--label) var(--label);
    background: var(--panel); /* shows through the new empty spacer row/column, matching .coord-label */
    border: 3px solid #0e0f12;
    border-radius:6px;
    overflow:hidden;
    touch-action:none;
    user-select:none;
  }
  .coord-label{
    display:flex;
    align-items:center;
    justify-content:center;
    font-size:0.7rem;
    font-weight:700;
    color: var(--text-dim);
    background: var(--panel);
    user-select:none;
  }
  .sq{
    position:relative;
    aspect-ratio:1 / 1; /* the height of every square follows its width — the fix for stretched squares on narrow screens */
    display:flex;
    align-items:center;
    justify-content:center;
    font-size: clamp(22px, 4.2vw, 42px); /* fallback for very old browsers */
    cursor:pointer;
    transition: background-color .12s ease;
  }
  .sq.light{ background: var(--light-sq); }
  .sq.dark{ background: var(--dark-sq); }
  /* Piece size = 68% of the square's own width (42px on a full 62px square, exactly as before),
     measured from the board itself rather than from the window. */
  @supports (width: 1cqw){
    #board{ container-type:inline-size; }
    .sq{ font-size: calc((100cqw - 2 * var(--label)) / 8 * 0.68); }
  }
  .sq.center-row{ box-shadow: inset 0 0 0 2px rgba(201,162,75,0.35); }
  .sq.selected{ background: var(--sel) !important; }
  .sq.last-move{ box-shadow: inset 0 0 0 3px rgba(201,162,75,0.55); }
  .sq.in-check{ box-shadow: inset 0 0 18px 6px var(--check-glow); }
  .sq .dot{
    position:absolute;
    width:26%;
    height:26%;
    border-radius:50%;
    background: var(--move-dot);
    pointer-events:none;
  }
  .sq .ring{
    position:absolute;
    width:82%;
    height:82%;
    border-radius:50%;
    box-shadow: inset 0 0 0 4px var(--move-dot);
    pointer-events:none;
  }
  .piece-slot{
    width:88%;
    height:88%;
    display:flex;
    align-items:center;
    justify-content:center;
    pointer-events:none;
  }
  .piece-glyph{
    line-height:1;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.5));
  }
  .piece-glyph.white{
    color:#c99b5f;
    text-shadow:
      -1.5px 0 #241a0e, 1.5px 0 #241a0e,
      0 -1.5px #241a0e, 0 1.5px #241a0e,
      -1.5px -1.5px #241a0e, 1.5px 1.5px #241a0e,
      -1.5px 1.5px #241a0e, 1.5px -1.5px #241a0e;
  }
  .piece-glyph.black{
    color:#14161a;
    text-shadow:
      -1.3px 0 #e8dcb8, 1.3px 0 #e8dcb8,
      0 -1.3px #e8dcb8, 0 1.3px #e8dcb8,
      -1.3px -1.3px #e8dcb8, 1.3px 1.3px #e8dcb8,
      -1.3px 1.3px #e8dcb8, 1.3px -1.3px #e8dcb8;
  }

  .side-panel{
    background: var(--panel);
    border-radius:16px;
    padding:12px;
    width:280px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.45);
    display:flex;
    flex-direction:column;
    gap:5px;
    /* No justify-content:space-between here on purpose — every section already keeps its
       own fixed slot via visibility (not display) toggling in updateControls(), so this
       just needs to stack them in a stable, predictable order. Any leftover height below
       Save/Load, once the panel is stretched to match the board, is left as plain empty
       space rather than redistributed — redistributing it is what used to make every box
       jump around whenever a mode-dependent section appeared or disappeared. */
  }
  /* ---- Avatar: the little reactive companion, replacing the old turn indicator +
     support button slot at the top of the side panel. See the JS avatar system
     (setAvatarState, checkAvatarReactions) for what drives these states. ---- */
  /* Two side-by-side rectangles: the Avatar's photo on one side, what it's saying on the
     other. Desktop puts the dialogue on the board-side (left) and the photo on the right,
     at an even 50/50 split, the photo filling its half edge to edge. Phones (see the
     720px media query below) instead show a shorter strip with a smaller, gold-framed
     photo, and the Avatar box itself is relocated — in JS, see positionAvatarForLayout()
     — to sit right after the board's own watching-bar rather than inside the side panel. */
  .avatar-box{
    width:100%;
    height:140px;
    border-radius:14px;
    overflow:hidden;
    display:flex;
    background: var(--panel-2);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.04);
    cursor:pointer; /* tappable once the game has started — see the tip system in the script */
  }
  .avatar-bubble{
    order:1;
    width:50%;
    box-sizing:border-box;
    display:flex;
    align-items:center;
    justify-content:center;
    padding:12px 14px;
    font-size:0.85rem;
    line-height:1.4;
    color: var(--text);
    text-align:center;
    opacity:0;
    transition: opacity .2s ease;
  }
  .avatar-bubble.visible{ opacity:1; }
  .avatar-bubble a{ color: var(--accent); font-weight:700; text-decoration:underline; }
  .avatar-bubble strong{ color: var(--accent); }
  .avatar-face{
    order:2;
    width:50%;
    height:100%;
    object-fit:cover;
    object-position:top;
    display:block;
  }
  /* The idle video is a square clip with its own padding around the cat, so it needs
     contain (not the cover/top crop used for the hand-painted state photos) to show the
     whole face instead of cropping into it. Scoped to the id so it only affects the
     video, never the <img> that still carries the other 7 states.
     Background is the same parchment/cream tone baked into the other 7 hand-painted
     photos (sampled from their corners) — the video itself is transparent, so this is
     what actually shows behind the cat. Matching it on purpose: without it, idle would
     flash to the dark site panel while every other state stays cream, which reads as a
     glitch every time the avatar switches between an animated and a static state. */
  #avatarFaceVideo{
    object-fit: contain;
    object-position: center;
    background: #f7ecd0;
  }
  .status-msg{
    font-size:0.85rem;
    color: var(--text-dim);
    min-height: 16px;
    line-height:1.2;
  }
  .status-msg.check{ color: var(--danger); font-weight:700; }
  .status-msg.mate{ color: var(--danger); font-weight:700; }

  .btn-row{ display:flex; gap:8px; flex-wrap:wrap; }
  button{
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid #333947;
    padding: 7px 12px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.82rem;
    flex:1;
    transition: background .15s ease, transform .05s ease;
  }
  button:hover{ background:#2b3040; }
  button:active{ transform: scale(0.97); }
  button.primary{ background: var(--accent); color:#1a1a1a; border-color:var(--accent); font-weight:700; }
  button.primary:hover{ filter:brightness(1.08); }

  .toggle-row{
    display:flex; align-items:center; justify-content:space-between;
    background: var(--panel-2);
    border-radius:10px;
    padding:6px 12px;
    font-size:0.85rem;
  }
  .switch{ position:relative; width:42px; height:22px; }
  .switch input{ opacity:0; width:0; height:0; }
  .slider{
    position:absolute; cursor:pointer; inset:0;
    background:#3a4050; border-radius:22px; transition:.2s;
  }
  .slider:before{
    content:""; position:absolute; height:16px; width:16px; left:3px; top:3px;
    background:#eee; border-radius:50%; transition:.2s;
  }
  input:checked + .slider{ background: var(--accent-2); }
  input:checked + .slider:before{ transform: translateX(20px); }

  #aiDifficultySelect{
    background: var(--panel);
    color: var(--text);
    border: 1px solid #333947;
    border-radius: 6px;
    padding: 4px 6px;
    font-size: 0.76rem;
    min-width:0;
    max-width:165px;   /* never wider than what is left of the row after the label */
  }

  /* Horizontal move-history bars above and below the board, each with browse
     arrows at both ends. The row has a fixed height so the bar can NEVER grow
     the page layout, however many moves pile up — it only scrolls sideways,
     via the arrow buttons or a drag/swipe.
     Whichever piece color sits on that side of the board (see boardFlipped)
     lends that bar its look: black pieces on top -> the top bar goes dark
     with soft gold letters, white pieces on top -> the top bar goes soft
     gold with dark letters, and the opposite bar always takes the other
     color. */
  .history-row{
    grid-column: 1 / -1;
    display:flex;
    align-items:stretch;
    gap:6px;
    height:32px;
    min-width:0;
  }
  /* Turn indicator bar, directly above the White (top) move-history row: same visual
     language as the history bars (light/cream for white, dark for black), but split
     into three — the currently-active side lights up, using the piece colors. */
  .turn-bar{
    grid-column: 1 / -1;
    display:flex;
    height:28px;
    border-radius:8px;
    overflow:hidden;
    font-size:0.74rem;
    font-weight:700;
    letter-spacing:0.5px;
  }
  /* .turn-bar-side is a real <button> now (so the last move it shows is reachable by
     keyboard/tap like any other control) — these overrides undo the generic button{}
     reset (border, padding, border-radius, font-size) so it still fills its third of the
     bar exactly as the plain <div> it used to be. */
  .turn-bar-side{
    flex:1;
    display:flex;
    align-items:center;
    justify-content:center;
    background: var(--panel-2);
    color: var(--text-dim);
    opacity:0.5;
    border:none;
    border-radius:0;
    padding:0;
    margin:0;
    font-size:0.74rem;
    font-weight:700;
    letter-spacing:0.5px;
    font-family:inherit;
    cursor:pointer;
    transition: background .2s ease, color .2s ease, opacity .2s ease;
  }
  .turn-bar-side:hover{ opacity:0.75; }
  .turn-bar-side.turn-bar-active.turn-bar-white{ background: var(--light-sq); color:#181a1f; opacity:1; }
  .turn-bar-side.turn-bar-active.turn-bar-black{ background:#0c0d10; color:#e7d6a6; opacity:1; }
  .turn-bar-side.turn-bar-active:hover{ opacity:0.9; }
  /* Lit up while this side's last move is the one currently drawn on the board. */
  .turn-bar-side.showing-move{ box-shadow: inset 0 0 0 2px var(--move-arrow); }
  .turn-bar-center{
    flex:1.5; /* the center gets more room than either side — it carries the real message */
    min-width:0;
    display:flex;
    align-items:center;
    justify-content:center;
    background: var(--panel);
    color: var(--text-dim);
    padding:0 10px;
    font-weight:400;
    transition: background .2s ease, color .2s ease;
  }
  /* Check / checkmate — Turn Bar Center only, same red as the in-check king glow. */
  .turn-bar-center.turn-bar-check{
    background:#d9534f;
    color:#fff;
    font-weight:800;
    letter-spacing:1px;
  }
  .turn-bar-center.turn-bar-mate{
    background:#d9534f;
    color:#fff;
    font-weight:800;
    letter-spacing:1px;
    animation: turn-bar-mate-pulse 1s ease-in-out infinite;
  }
  @keyframes turn-bar-mate-pulse{
    0%,100%{ opacity:1; }
    50%{ opacity:0.7; }
  }

  /* The pink line a Turn Bar button draws on the board: from the origin square of that
     color's last move to where it landed. Sized/positioned in JS (positionMoveArrowOverlay)
     to sit exactly over #board — see .board-wrap's position:relative above. */
  .move-arrow-overlay{
    position:absolute;
    top:0; left:0;
    pointer-events:none;
    overflow:visible;
    opacity:0;
    transition:opacity .15s ease;
    z-index:6;
  }
  .move-arrow-overlay.visible{ opacity:1; }

  /* A slow, paced pulse — waiting specifically for a click: on PLAY while a timed game
     sits ready to begin, and later in the game, on Resign once Reset has locked out (see
     updateControls() / resignUrgent in the JS) as the nudge toward the proper way to end
     a game that's gone on this long. Gentle and unhurried either way, never urgent. */
  @keyframes start-pulse-anim{
    0%,100%{ box-shadow:0 0 0 0 rgba(201,162,75,0.55); }
    50%{ box-shadow:0 0 0 8px rgba(201,162,75,0); }
  }
  #startBtn.start-pulse, #resignBtn.start-pulse{
    animation: start-pulse-anim 1.8s ease-in-out infinite;
    border-color: var(--accent);
  }

  /* Binary Timer Bars (Binary Timer White Bar / Binary Timer Black Bar) — one clock per
     color, always following that color's OWN element regardless of board orientation.
     Whichever bar belongs to the color currently shown on top of the board sits directly
     under the Turn Bar / above the top Move History bar; the other sits under the bottom
     Move History bar, above the Spectator Bar — see positionBinaryTimers() in the JS,
     which moves these two elements (never rebuilds them) whenever the board flips. */
  .binary-timer-bar{
    grid-column: 1 / -1;
    display:flex;
    align-items:stretch;
    justify-content:center;
    gap:10px;
    border-radius:8px;
    padding:4px 8px 3px;
  }
  .binary-timer-bar{ background:#0c0d10; }
  .binary-timer-section{
    display:flex;
    gap:3px;
    padding:0 6px;
    position:relative;
  }
  /* A thin divider between hours | minutes | seconds, on every section but the first. */
  .binary-timer-section + .binary-timer-section::before{
    content:'';
    position:absolute;
    left:-2px; top:2px; bottom:2px;
    width:1px;
    background:rgba(128,128,128,0.35);
  }
  .binary-dot-col{
    display:flex;
    flex-direction:column;
    align-items:center;
    gap:3px;
    min-width:13px;
  }
  .binary-dot-label{
    font-size:0.52rem;
    line-height:1;
    opacity:0.55;
    font-weight:600;
  }
  .binary-dot-label{ color:#e7d6a6; }
  .binary-dot{
    width:9px; height:9px;
    border-radius:50%;
    display:block;
    box-sizing:border-box;
  }
  .binary-dot{ border:1.5px solid rgba(231,214,166,0.35); background:transparent; }
  .binary-dot.on{ background: var(--accent); border-color: var(--accent); box-shadow:0 0 4px 1px rgba(201,162,75,0.7); }
  /* Running low (a third or less of the starting time left) — the lit dots turn red as
     a warning, on both players' bars alike. */
  .binary-timer-bar.low-time .binary-dot.on{ background:#e04b4b; border-color:#e04b4b; box-shadow:0 0 4px 1px rgba(224,75,75,0.75); }
  @media (max-width:520px){
    .binary-dot-col{ min-width:10px; }
    .binary-dot-label{ font-size:0.44rem; }
    .binary-dot{ width:7px; height:7px; }
    .binary-timer-section{ gap:2px; padding:0 4px; }
    .binary-timer-bar{ gap:6px; }
  }
  .hist-arrow{
    flex:0 0 28px;
    width:28px;
    padding:0;
    border:none;
    border-radius:8px;
    background: var(--panel-2);
    color: var(--text);
    font-size:1.15rem;
    line-height:1;
    cursor:pointer;
    display:flex;
    align-items:center;
    justify-content:center;
  }
  .hist-arrow:hover{ background:#2c3140; }
  .hist-arrow:active{ transform:scale(0.92); }

  .support-row{
    grid-column: 1 / -1;
    display:flex;
    justify-content:center;
    margin-top:2px;
  }
  .support-btn{
    display:block;
    width:100%;
    box-sizing:border-box;
    text-align:center;
    background: var(--accent);
    color:#1a1a1a;
    font-weight:700;
    font-size:0.85rem;
    text-decoration:none;
    padding:8px 14px;
    border-radius:10px;
    transition: filter .15s ease, transform .05s ease;
  }
  .support-btn:hover{ filter:brightness(1.08); }
  .support-btn:active{ transform:scale(0.97); }

  .world-map-wrap{
    width:100%;
    max-width:760px;
    margin:0 auto;
    background: var(--panel);
    border-radius:16px;
    padding:16px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  }
  .about-intro{
    width:100%;
    max-width:760px;
    margin:0 auto;
    background: var(--panel);
    border-radius:16px;
    padding:18px 20px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.45);
    color: var(--text-dim);
    font-size:0.92rem;
    line-height:1.6;
  }
  .about-intro h2{
    margin:0 0 10px;
    font-size:1.05rem;
    color: var(--accent);
  }
  .about-intro p{ margin:0 0 10px; }
  .about-intro p:last-child{ margin-bottom:0; }
  .about-intro a{ color: var(--accent); font-weight:600; }

  .world-map-title{
    text-align:center;
    font-size:1rem;
    font-weight:700;
    color:#1a1a1a;
    background: var(--accent);
    border-radius:10px;
    padding:10px 16px;
    margin-bottom:14px;
  }
  .world-map-zoom-controls{
    display:flex;
    justify-content:center;
    gap:6px;
    margin-bottom:8px;
  }
  .world-map-zoom-controls button{
    flex:0 0 auto;
    padding:4px 10px;
    font-size:0.78rem;
    border-radius:6px;
    border:none;
    background: var(--panel-2);
    color: var(--text);
    cursor:pointer;
  }
  .world-map-zoom-controls button:hover{ background:#2c3140; }
  .world-map-inner{
    position:relative;
    width:100%;
    padding-top:50%; /* 2:1 aspect ratio via the classic percentage-padding trick (works in every browser) */
    border-radius:10px;
    overflow:hidden;
    background:#0c1f1a; /* shown if the map image fails to load */
  }
  .world-map-zoomable{
    position:absolute;
    inset:0;
    transform-origin:center center;
    /* zoom/pan applied here via inline style (see setMapTransform); transition only
       covers the button-driven zoom steps, not live dragging (see mapPanning). */
    transition:transform .15s ease;
    cursor:grab;
  }
  .world-map-zoomable.panning{ cursor:grabbing; transition:none; }
  .world-map-img{
    position:absolute;
    top:0; left:0;
    width:100%;
    height:100%;
    pointer-events:none; /* dragging the map must not trigger the browser's native image-drag */
    /* A light Wikipedia map, tinted dark to fit the site's theme. */
    filter: invert(93%) hue-rotate(155deg) brightness(0.92) contrast(0.92) saturate(0.7);
  }
  .world-map-dots{
    position:absolute;
    top:0; left:0;
    width:100%;
    height:100%;
  }
  .map-dot{
    position:absolute;
    width:9px;
    height:9px;
    margin-left:-4.5px;
    margin-top:-4.5px;
    border-radius:50%;
    background:#3ecf6e;
    box-shadow:0 0 0 0 rgba(62,207,110,0.6);
    animation: live-pulse 2s infinite;
    cursor:default;
  }
  /* A dot with an active, joinable game — the only kind you can click to watch. */
  .map-dot-watchable{
    width:13px;
    height:13px;
    margin-left:-6.5px;
    margin-top:-6.5px;
    background: var(--accent);
    box-shadow:0 0 0 0 rgba(201,162,75,0.6);
    animation: live-pulse-gold 1.4s infinite;
    cursor:pointer;
  }
  @keyframes live-pulse-gold{
    0%{ box-shadow:0 0 0 0 rgba(201,162,75,0.55); }
    70%{ box-shadow:0 0 0 8px rgba(201,162,75,0); }
    100%{ box-shadow:0 0 0 0 rgba(201,162,75,0); }
  }
  .map-dot-tip{
    position:absolute;
    bottom:130%;
    left:50%;
    transform:translateX(-50%);
    background:#0b0c0f;
    color:#eef0f3;
    padding:4px 9px;
    border-radius:6px;
    font-size:0.74rem;
    white-space:nowrap;
    opacity:0;
    pointer-events:none;
    transition:opacity .12s ease;
    box-shadow:0 4px 10px rgba(0,0,0,0.45);
    z-index:2;
  }
  .map-dot:hover .map-dot-tip{ opacity:1; }
  .hist-arrow:disabled{ opacity:0.3; cursor:default; }
  .move-history-bar{
    flex:1 1 auto;
    min-width:0;              /* lets the bar scroll instead of stretching the row */
    height:100%;
    display:flex;
    flex-wrap:nowrap;         /* the moves never wrap to a second line */
    align-items:center;
    gap:10px;
    overflow-x:auto;
    overflow-y:hidden;
    white-space:nowrap;
    padding:0 12px;
    border-radius:10px;
    font-size:0.82rem;
    font-family:'Consolas', monospace;
    scrollbar-width:none;     /* the arrow buttons are the browsing control */
  }
  .move-history-bar::-webkit-scrollbar{ display:none; }
  .move-history-bar.side-white{ background: var(--light-sq); color:#181a1f; }
  .move-history-bar.side-black{ background:#0b0c0f; color:#e7d6a6; }
  .move-history-bar .hist-chip{ flex:0 0 auto; display:inline-flex; gap:4px; opacity:0.72; }
  .move-history-bar .hist-chip .hist-n{ opacity:0.6; font-weight:400; }
  .move-history-bar .hist-chip.latest{ opacity:1; font-weight:700; }
  .move-history-bar .hist-empty{ opacity:0.45; font-style:italic; }
  .move-history-bar .hist-result-chip{ margin-left:auto; font-weight:800; color: var(--accent); flex-shrink:0; }
  /* "Time machine": once the game is over, every move (and the result chip) becomes
     clickable, letting you step the board back to any past position without touching
     the real, final game state. */
  .move-history-bar .clickable{ cursor:pointer; border-radius:5px; padding:1px 4px; margin:-1px -4px; }
  .move-history-bar .clickable:hover{ opacity:1; background:rgba(128,128,128,0.22); }
  .move-history-bar .hist-chip.viewing{ opacity:1; text-decoration:underline; text-underline-offset:2px; }
  .move-history-bar .hist-result-chip.viewing{ text-decoration:underline; text-underline-offset:2px; }

  .online-box{
    background: var(--panel-2);
    border-radius:10px;
    padding:8px 12px;
    display:flex;
    flex-direction:column;
    gap:5px;
  }
  .online-box .btn-row button{ font-size:0.78rem; padding:8px 10px; }
  .timer-btn-row{ display:flex; gap:4px; }
  .timer-btn{ font-size:0.72rem; padding:8px 2px; white-space:nowrap; }
  .timer-btn.active{ background: var(--accent); color:#1a1a1a; font-weight:700; border-color: var(--accent); }
  .timer-status{ font-size:0.74rem; color: var(--text-dim); }
  .room-code-display{
    font-family:'Consolas', monospace;
    font-size:1.1rem;
    letter-spacing:3px;
    text-align:center;
    background:#14161a;
    border-radius:8px;
    padding:8px;
    color:var(--accent);
  }
  .label-small{
    font-size:0.7rem;
    text-transform:uppercase;
    letter-spacing:1px;
    color: var(--text-dim);
    margin-bottom:0;
  }

  /* Game mode / color selection / draw controls */
  .controls-disabled{ opacity:0.45; transition: opacity .15s ease; }
  .radio-box{
    background: var(--panel-2);
    border-radius:10px;
    padding:8px 12px;
    display:flex;
    flex-direction:column;
    gap:4px;
    font-size:0.85rem;
  }
  .radio-box label{ display:flex; align-items:center; gap:5px; cursor:pointer; }
  .radio-box input[type="radio"]{ margin:0; }
  .radio-line label{ font-size:0.8rem; }
  .radio-box input{ accent-color: var(--accent); }
  .radio-line{ display:flex; gap:4px 12px; flex-wrap:wrap; }

  /* Game Mode: pill buttons in one row, matching the Set Binary Timer buttons' look,
     rather than the plain radio dots every other group here still uses. The underlying
     <input type="radio"> elements are untouched (same ids, same 'change' listeners) —
     only visually replaced by their own <label>, so none of the existing JS needed to
     change. #modeRow's own specificity (an id) is what keeps this scoped to Game Mode
     only, without touching Play As or any other .radio-box group. */
  #modeRow{ display:flex; flex-direction:row; flex-wrap:wrap; gap:4px; }
  #modeRow .label-small{ flex-basis:100%; }
  #modeRow label{
    flex:1; justify-content:center; gap:0;
    font-size:0.72rem; padding:8px 4px; white-space:nowrap;
    background:#232732; color:var(--text); border:1px solid #333947; border-radius:8px;
  }
  #modeRow label:has(input:checked){
    background: var(--accent); color:#1a1a1a; font-weight:700; border-color:var(--accent);
  }
  #modeRow label input[type="radio"]{
    position:absolute; opacity:0; width:0; height:0; pointer-events:none;
  }
  .match-info{
    background: var(--panel-2);
    border-radius:10px;
    padding:5px 12px;
    font-weight:700;
    font-size:0.78rem;
    letter-spacing:0.5px;
    color: var(--accent);
    display:flex;
    justify-content:space-between;
    gap:10px;
  }
  button:disabled{ opacity:0.4; cursor:not-allowed; }
  button:disabled:hover{ background: var(--panel-2); }
  button:disabled:active{ transform:none; }
  .status-msg.draw{ color: var(--accent); font-weight:700; }
  .hist-result{
    margin-top:6px; padding-top:6px;
    border-top:1px solid #333947;
    color: var(--accent); font-weight:700;
  }

  /* Promotion modal */
  .modal-overlay{
    position:fixed; inset:0; background:rgba(0,0,0,0.6);
    display:none; align-items:center; justify-content:center; z-index:50;
  }
  .modal-overlay.open{ display:flex; }
  .modal{
    background: var(--panel); padding:20px; border-radius:14px;
    text-align:center; box-shadow:0 10px 40px rgba(0,0,0,0.6);
  }
  .modal h3{ margin-top:0; color:var(--accent); }
  .reset-request-text{ margin:6px 0 16px; font-size:0.9rem; max-width:280px; }
  .promo-options{ display:flex; gap:10px; margin-top:10px; }
  .promo-btn{
    font-size:34px; width:56px; height:56px;
    background: var(--panel-2); border-radius:10px; border:1px solid #333947;
    cursor:pointer; display:flex; align-items:center; justify-content:center;
  }
  .promo-btn:hover{ background:#2b3040; }

  footer{
    width:100%;
    text-align:center;
    color: var(--text-dim);
    font-size:0.72rem;
    margin-top:10px;
    opacity:0.7;
  }
  .footer-nav{
    display:flex;
    flex-wrap:wrap;
    justify-content:center;
    gap:6px 18px;
    margin-bottom:10px;
  }
  .footer-nav a, .footer-nav .cookie-prefs-link{
    color: var(--text-dim);
    text-decoration:none;
    font-size:0.74rem;
    opacity:0.9;
    margin:0 9px; /* explicit fallback spacing, in addition to the flex gap below */
  }
  .footer-nav a:hover, .footer-nav .cookie-prefs-link:hover{ color: var(--accent); opacity:1; text-decoration:underline; cursor:pointer; }
  .footer-nav a.footer-donate{ color: var(--accent); font-weight:700; opacity:1; }
  .footer-nav a.footer-donate:hover{ filter:brightness(1.15); }
  footer .copyright-line{ opacity:0.75; }
  footer .credits{
    margin-top:4px;
    font-size:0.66rem;
    opacity:0.8;
  }
  .cookie-prefs-link{ background:none; border:none; padding:0; font:inherit; }

  /* Cookie / ad-consent notice — shown until the visitor makes a choice; see the
     cookie-banner script near the end of the page for the logic. */
  .cookie-banner{
    display:none;
    position:fixed;
    left:0; right:0; bottom:0;
    z-index:1000;
    background: var(--panel);
    border-top:1px solid #333947;
    box-shadow: 0 -6px 24px rgba(0,0,0,0.5);
    padding:14px 18px;
    gap:12px;
    align-items:center;
    justify-content:center;
    flex-wrap:wrap;
  }
  .cookie-banner.visible{ display:flex; }
  .cookie-banner p{
    margin:0;
    font-size:0.8rem;
    color: var(--text-dim);
    max-width:520px;
    flex:1 1 320px;
  }
  .cookie-banner p a{ color: var(--accent); }
  .cookie-banner-actions{ display:flex; gap:8px; flex:0 0 auto; }
  .cookie-banner-actions button{
    padding:8px 14px;
    font-size:0.8rem;
    border-radius:8px;
    border:1px solid #333947;
    background: var(--panel-2);
    color: var(--text);
    cursor:pointer;
  }
  .cookie-banner-actions button.primary{ background: var(--accent); color:#1a1a1a; border-color:var(--accent); font-weight:700; }
  @media (max-width:520px){
    .cookie-banner{ justify-content:flex-start; }
    .cookie-banner-actions{ width:100%; }
    .cookie-banner-actions button{ flex:1; }
  }

  /* Static content pages (How to Play, Privacy, About, Contact) */
  .back-home{
    display:inline-block;
    margin-bottom:16px;
    color: var(--text-dim);
    text-decoration:none;
    font-size:0.8rem;
  }
  .back-home:hover{ color: var(--accent); }
  .page-content{
    width:100%;
    max-width:640px;
    background: var(--panel);
    border-radius:16px;
    padding:28px 32px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.45);
    color: var(--text);
    line-height:1.6;
  }
  .page-content h2{
    color: var(--accent);
    margin-top:0;
    font-size:1.3rem;
    letter-spacing:1px;
  }
  .page-content h3{
    color: var(--accent);
    font-size:1.05rem;
    margin:20px 0 8px 0;
  }
  .page-content p{ margin:0 0 14px 0; font-size:0.92rem; }
  .page-content ul, .page-content ol{ margin:0 0 14px 0; padding-left:22px; font-size:0.92rem; }
  .page-content li{ margin-bottom:6px; }
  .page-content a{ color: var(--accent); }
  .page-content strong{ color: var(--text); }
  .page-content .updated{ font-size:0.72rem; color: var(--text-dim); opacity:0.8; margin-top:24px; }

  @media (max-width: 520px){
    .app{ padding:8px; }
    .board-wrap{ --label:18px; padding:8px; } /* squares get the room the padding and label columns give back */
  }
  @media (max-width: 720px){
    .app{ flex-direction:column; align-items:center; }
    .app-main{ flex-direction:column; align-items:center; }
    .side-panel{ width: 100%; max-width: 420px; }
    .site-title{ font-size:1.7rem; letter-spacing:2px; }
    .hero-headline{ font-size:0.92rem; padding:0 12px; }
    .page-content{ padding:22px 20px; }

    /* Avatar box: a shorter strip (dialogue flexing to fill the space, a smaller
       gold-framed photo) instead of desktop's even 50/50 split. Relocated out of the
       side panel entirely by positionAvatarForLayout() in the script below, to sit right
       after the board's own watching bar — #avatarBox itself never moves in the markup,
       only in the live DOM via JS, so this sizing simply applies wherever it ends up. */
    #avatarBox{
      height:128px;
      align-items:center;
      gap:8px;
      padding:8px 8px 8px 14px;
      width:100%; max-width:420px; box-sizing:border-box;
      margin-top:8px;
    }
    .avatar-bubble{
      width:auto; flex:1; min-width:0;
      justify-content:flex-start; text-align:left;
      padding:0;
    }
    .avatar-face{
      width:112px; height:112px; flex-shrink:0;
      border:2px solid var(--accent); border-radius:9px;
      box-shadow:0 5px 12px rgba(0,0,0,0.4);
    }

    /* Game Mode and Support get a touch less padding here, to give the room back to the
       now-taller Avatar photo above without the page growing any taller overall. */
    #modeRow{ width:100%; max-width:420px; box-sizing:border-box; margin-top:6px; padding-top:6px; padding-bottom:6px; }
    #supportBtn{ width:100%; max-width:420px; box-sizing:border-box; margin-top:6px; padding-top:7px; padding-bottom:7px; }

    /* Right under the live-stats bar: "ChessBoard" centers the view on the board + Avatar
       (Turn Bar through the Avatar box); "Options" centers it on everything from Game Mode
       down to the world map's title — see scrollToCenterRange() in the script below. */
    .mobile-jump-row{
      display:flex;
      gap:8px;
      width:100%; max-width:420px;
      margin:0 auto;
    }
    .mobile-jump-row button{ flex:1; font-weight:700; }
  }
