/* Copyright (c) 2026 openingpunisher.com. All rights reserved.
   Proprietary. See LICENSE. Readable in a browser is not a licence to reuse. */

  /* ============================================================
     NEWSSTAND — theme tokens
     Ink black stage, Ben-Day red, newsprint white. Red is the only
     chromatic accent in the chrome: it marks the punishment and
     nothing else. Everything structural is ink, paper, or rule.
     ============================================================ */
  :root {
    /* Archivo is the free grotesque nearest Benton Sans, the face Marvel's
       wordmark is cut from — so display and body come from one superfamily
       and only the weight changes. Archivo Black is held back for the four
       marquee moments (logo, headline, primary action) so it keeps its punch.
       Mono stays: FEN, PGN and centipawns need to line up. */
    --font-display: 'Archivo', system-ui, sans-serif;
    --font-black:   'Archivo Black', 'Archivo', Impact, sans-serif;
    --font-body:    'Archivo', system-ui, sans-serif;
    --font-mono:    'JetBrains Mono', ui-monospace, Menlo, monospace;

    /* Dark (default) — the newsstand at night */
    --bg:             #0b0b0d;
    --surface:        #121216;
    --surface-2:      #1a1a20;
    --border:         #2c2c36;
    --text:           #f5f3ee;
    --text-dim:       #9a9aa6;
    --accent:         #b21c22;
    --accent-dim:     #cc2a31;
    --accent-muted:   #241012;
    --accent-glow:    rgba(178,28,34,0.16);
    --on-accent:      #ffffff;
    --danger:         #a3161c;
    --warn:           #f5a623;
    /* The two poles of the results chart. Red is not a new meaning here — a
       line the opponent scores badly in IS the opportunity, which is what red
       marks everywhere else in this app. Blue is the only other hue on the
       page and does the opposite job.

       Both poles were run through the palette check against this surface, not
       eyeballed: chroma above the reads-as-grey floor, CVD separation ΔE 21
       (deutan/protan) and 29 for normal vision, and both clear 3:1 on
       #1a1a19. Do not nudge either by eye — re-run the check. */
    --chart-weak:     #cc2a31;
    --chart-strong:   #3a78b8;
    --gray:           #5c5c66;
    --ink:            #0b0b0d;   /* panel rules and hard edges */
    /* Printed stock for the eval plate. These do NOT flip with the theme:
       a white advantage is always paper, a black advantage is always ink,
       exactly like the pieces they stand for. */
    --stock-paper:    #f2f0ea;
    --stock-paper-fg: #14141a;
    --stock-ink:      #202028;
    --stock-ink-fg:   #f2f0ea;
    --shadow:         0 3px 14px rgba(0,0,0,0.55);
    --shadow-lg:      0 16px 44px rgba(0,0,0,0.72);
    --shadow-glow:    0 0 0 1px rgba(178,28,34,0.5), 0 10px 30px rgba(178,28,34,0.14);
    --radius:         2px;
    --transition:     150ms cubic-bezier(0.2, 0.8, 0.2, 1);
    /* Slower than --transition on purpose: a panel folding shut moves the
       board under it, and the eye needs to follow that, not be startled. */
    --op-fold-ms:     340ms;
    --op-fold-ease:   cubic-bezier(0.4, 0, 0.2, 1);
  }
  /* Light — newsprint. Cool grey stock, not cream: comics were printed
     on pulp, and pulp goes grey, never beige. */
  [data-theme="light"] {
    --bg:             #e6e5e1;
    --surface:        #f7f7f4;
    --surface-2:      #dbdad5;
    --border:         #b5b4ac;
    --text:           #131317;
    --text-dim:       #5c5c66;
    --accent:         #a3161c;
    --accent-dim:     #851014;
    --accent-muted:   #f0dcdc;
    --accent-glow:    rgba(163,22,28,0.12);
    --on-accent:      #ffffff;
    --danger:         #8f1218;
    /* Same pair, re-stepped for newsprint rather than flipped. Checked against
       the light surface: both poles pass chroma, contrast and separation
       (ΔE 19.8 deutan, 27.0 normal). */
    --chart-weak:     #a3161c;
    --chart-strong:   #2d6ba3;
    --gray:           #77767e;
    --ink:            #131317;
    --shadow:         0 1px 0 rgba(19,19,23,0.16), 0 2px 10px rgba(19,19,23,0.08);
    --shadow-lg:      0 16px 40px rgba(19,19,23,0.2);
    --shadow-glow:    0 0 0 1px rgba(163,22,28,0.45), 0 10px 26px rgba(163,22,28,0.12);
  }
  * { box-sizing: border-box; }
  html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
  }
  button { font-family: inherit; cursor: pointer; }
  a { color: var(--accent); text-decoration: none; }
  a:hover { text-decoration: underline; }

  /* Always show the vertical scrollbar so 100vw doesn't oscillate when page
     content height changes (chessboard rebuild, panels toggling). Without
     this, the scrollbar appearing/disappearing changes the visible viewport
     width by ~15px each time, causing the mobile board column to "jump". */
  html { overflow-y: scroll; overflow-x: hidden; }
  /* `clip`, not `hidden`. Both stop a stray wide element from producing a
     horizontal scrollbar, but `hidden` makes <body> a scroll container, and
     a sticky element measures against its nearest scrolling ancestor — one
     that is exactly as tall as its content and therefore never scrolls. That
     silently breaks every `position: sticky` on the page (the game viewer's
     frozen board, the plan and weights columns). `clip` clips without
     creating that scroll container, and leaves the vertical axis `visible`
     instead of forcing it to `auto`. */
  body { overflow-x: clip; }
  .app { max-width: 1100px; margin: 0 auto; padding: 20px; }

  /* Top bar */
  .topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 0 16px;
    border-bottom: 3px solid var(--text);
    margin-bottom: 28px;
    gap: 12px;
    flex-wrap: wrap;
    position: relative;
  }
  /* The masthead rule is drawn twice — a heavy ink line with a thin red
     one beneath it, the way a cover separates the logo bar from the art. */
  .topbar::after {
    content: '';
    position: absolute;
    left: 0; right: 0; bottom: -6px;
    height: 1px;
    background: var(--accent);
  }
  /* Logo — the newsstand lockup: the activated pawn beside a small tracked
     line set over a red badge, the way a comic stacks its series line above
     its logo. The badge is white-on-red in both themes; that is the whole
     point of it. */
  .logo {
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    line-height: 1;
    color: var(--text);
    cursor: pointer;
  }
  .logo-lockup {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    line-height: 1;
  }
  /* The mark: the rendered pawn badge, assets/pawn-logo.png. Its ground is
     baked-in black, so it reads as a small icon chip rather than a mark that
     blends into the topbar. */
  .logo-mark {
    width: 44px; height: 44px;
    flex-shrink: 0;
    display: block;
    border-radius: 4px;
    object-fit: cover;
    transition: transform var(--transition);
  }
  .logo:hover .logo-mark { transform: scale(1.06); }
  @media (prefers-reduced-motion: reduce) {
    .logo-mark { transition: none; }
  }
  .logo-eyebrow {
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 9px;
    letter-spacing: 0.4em;
    text-transform: uppercase;
    color: var(--text-dim);
    padding-left: 2px;
    transition: color var(--transition);
  }
  .logo:hover .logo-eyebrow { color: var(--text); }
  .logo-badge {
    font-family: var(--font-black);
    font-size: 19px;
    line-height: 1;
    letter-spacing: 0.015em;
    text-transform: uppercase;
    color: #fff;
    background: var(--accent);
    padding: 7px 10px 6px;
    border-radius: 1px;
  }
  /* Legacy square icon — kept for the side nav, restyled as a red chip. */
  .logo-icon {
    width: 32px; height: 32px;
    background: var(--accent);
    border-radius: 1px;
    display: grid; place-items: center;
    font-size: 18px;
    color: #fff;
    font-weight: 900;
  }
  .topbar-right { display: flex; align-items: center; gap: 8px; }
  .user-chip {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface);
    padding: 5px 10px 5px 5px;
    border-radius: 1px;
    border: 1px solid var(--border);
    font-size: 11px;
    font-family: var(--font-body);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
  }
  .user-chip:hover { border-color: var(--accent); }
  .user-chip .avatar {
    width: 22px; height: 22px;
    background: var(--accent);
    border-radius: 1px;
    color: #fff;
    display: grid; place-items: center;
    font-weight: 700;
    font-size: 11px;
    font-family: var(--font-display);
  }
  [data-theme="light"] .user-chip .avatar { color: var(--on-accent); }
  .theme-toggle, .signout-btn, .reset-btn, .topbar-signin-btn {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text-dim);
    padding: 5px 12px;
    border-radius: 2px;
    font-size: 12px;
    font-family: var(--font-display);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    transition: color var(--transition), border-color var(--transition), background var(--transition);
  }
  .topbar-settings-btn { padding: 5px 9px; font-size: 13px; line-height: 1; }
  .theme-toggle:hover, .signout-btn:hover, .reset-btn:hover, .topbar-signin-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
  }
  .coach-btn {
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--accent);
    padding: 5px 14px;
    border-radius: 2px;
    font-size: 12px;
    font-family: var(--font-display);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 6px;
    transition: background var(--transition), color var(--transition);
  }
  .coach-btn:hover {
    background: var(--accent);
    color: var(--on-accent);
  }
  [data-theme="light"] .coach-btn:hover { color: var(--on-accent); }
  .coach-btn-icon { font-size: 14px; }

  /* Coach picker modal */
  .coaches-page-header {
    padding: 32px 0 8px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
  }
  .coaches-page-title {
    font-family: var(--font-display);
    margin: 0 0 6px;
    font-size: 22px;
    letter-spacing: 0.04em;
    color: var(--text);
    font-weight: 700;
  }
  .coaches-page-sub {
    font-size: 13px;
    color: var(--text-dim);
    margin: 0;
    font-style: italic;
  }
  .coach-list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
  }
  @media (max-width: 900px) {
    .coach-list { grid-template-columns: repeat(2, 1fr); }
  }
  @media (max-width: 600px) {
    .coach-list { grid-template-columns: 1fr; }
  }
  .coach-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 16px 18px;
    cursor: pointer;
    transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
    position: relative;
    overflow: hidden;
  }
  .coach-card::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, var(--accent-glow) 0%, transparent 60%);
    opacity: 0;
    transition: opacity var(--transition);
    pointer-events: none;
  }
  .coach-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: var(--shadow-glow);
  }
  .coach-card:hover::before { opacity: 1; }
  .coach-card.selected {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent), var(--shadow-glow);
  }
  .coach-card-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.04em;
    margin-bottom: 8px;
  }
  .coach-card-gm {
    margin-top: 4px;
    font-family: var(--font-display);
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .coach-card-gm-label {
    font-size: 10px;
    color: var(--text-dim);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .coach-card-gm-name {
    font-size: 12px;
    color: var(--accent);
    font-weight: 700;
    letter-spacing: 0.04em;
  }
  .coach-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0 5px;
  }
  .coach-tag {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 3px 9px;
    border-radius: 2px;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text-dim);
    transition: border-color var(--transition), color var(--transition);
  }
  .coach-card:hover .coach-tag, .coach-card.selected .coach-tag {
    border-color: rgba(201,146,42,0.35);
    color: var(--accent);
  }
  .coach-card-bio {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.6;
  }
  .coach-card-portrait {
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: 2px;
    overflow: hidden;
    margin-bottom: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    position: relative;
    z-index: 1;
  }
  .coach-card-portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .coach-card-bio-btn {
    margin-top: 10px;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--accent);
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 6px 14px;
    border-radius: 2px;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
    position: relative;
    z-index: 2;
  }
  .coach-card-bio-btn:hover {
    border-color: var(--accent);
    background: rgba(201,146,42,0.12);
  }
  .coach-bio-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 20px;
  }
  .coach-bio-overlay.hidden { display: none; }
  .coach-bio-modal {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    max-width: 520px;
    width: 100%;
    max-height: 90vh;
    overflow-y: auto;
    padding: 28px;
    position: relative;
    box-shadow: var(--shadow-glow);
  }
  .coach-bio-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-dim);
    cursor: pointer;
    font-size: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .coach-bio-close:hover { color: var(--accent); border-color: var(--accent); }
  .coach-bio-portrait {
    width: 140px;
    height: 140px;
    border-radius: 50%;
    overflow: hidden;
    margin: 0 auto 16px;
    border: 2px solid var(--accent);
  }
  .coach-bio-portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .coach-bio-name {
    text-align: center;
    font-family: var(--font-display);
    font-size: 20px;
    margin: 0 0 6px;
  }
  .coach-bio-gm {
    text-align: center;
    font-family: var(--font-display);
    margin-bottom: 16px;
  }
  .coach-bio-gm-label {
    font-size: 10px;
    color: var(--text-dim);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .coach-bio-gm-name {
    font-size: 13px;
    color: var(--accent);
    font-weight: 700;
    letter-spacing: 0.04em;
    margin-top: 2px;
  }
  .coach-bio-text {
    font-size: 14px;
    color: var(--text);
    line-height: 1.7;
  }
  .coach-modal-save {
    background: var(--accent);
    color: var(--on-accent);
    border: none;
    padding: 9px 22px;
    border-radius: 2px;
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    flex-shrink: 0;
    transition: background var(--transition), transform var(--transition);
  }
  [data-theme="light"] .coach-modal-save { color: var(--on-accent); }
  .coach-modal-save:hover { background: var(--accent-dim); transform: translateY(-1px); }

  /* Coach category badge on card */
  .coach-category-badge {
    display: inline-block;
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    padding: 3px 10px;
    border-radius: 2px;
    border: 1px solid currentColor;
    margin-bottom: 8px;
  }
  .coach-category-badge.attacking { color: #e05c3a; background: rgba(224,92,58,0.12); border-color: rgba(224,92,58,0.45); }
  .coach-category-badge.balanced  { color: var(--accent); background: rgba(201,146,42,0.12); border-color: rgba(201,146,42,0.45); }
  .coach-category-badge.defensive { color: #5a9fd4; background: rgba(90,159,212,0.12); border-color: rgba(90,159,212,0.45); }

  /* Filter bar in coach modal */
  .coach-filter-bar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    padding: 0 36px 16px;
    flex-shrink: 0;
  }
  .coach-filter-btn {
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 5px 14px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
  }
  .coach-filter-btn:hover { border-color: var(--accent); color: var(--accent); }
  .coach-filter-btn.active { border-color: rgba(201,146,42,0.6); color: var(--accent); background: rgba(201,146,42,0.12); }
  .coach-filter-btn.active.attacking { border-color: rgba(224,92,58,0.6); color: #e05c3a; background: rgba(224,92,58,0.12); }
  .coach-filter-btn.active.balanced  { border-color: rgba(201,146,42,0.6); color: var(--accent); background: rgba(201,146,42,0.12); }
  .coach-filter-btn.active.defensive { border-color: rgba(90,159,212,0.6); color: #5a9fd4; background: rgba(90,159,212,0.12); }

  /* ============================================================
     COACH BUILDER
     ============================================================ */
  .cb-header {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 28px 0 20px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 28px;
    flex-wrap: wrap;
  }
  .cb-back-btn {
    flex-shrink: 0;
    align-self: center;
  }
  .cb-header-title { flex: 1; min-width: 200px; }
  .cb-title {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
    letter-spacing: 0.04em;
    margin: 0 0 4px;
    color: var(--text);
  }
  .cb-subtitle {
    font-size: 13px;
    color: var(--text-dim);
    font-style: italic;
    margin: 0;
  }
  .cb-save-btn { flex-shrink: 0; align-self: center; }

  .cb-layout {
    display: grid;
    grid-template-columns: 340px 1fr;
    gap: 28px;
    align-items: start;
  }
  @media (max-width: 860px) {
    .cb-layout { grid-template-columns: 1fr; }
  }

  .cb-section {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 20px;
    margin-bottom: 20px;
  }
  .cb-section:last-child { margin-bottom: 0; }
  .cb-section-title {
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 16px;
  }

  .cb-field { margin-bottom: 16px; }
  .cb-field:last-child { margin-bottom: 0; }
  .cb-label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 7px;
    font-family: var(--font-display);
  }
  .cb-label-sub {
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--gray);
    font-family: var(--font-body);
    font-size: 11px;
  }
  .cb-input, .cb-textarea {
    width: 100%;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 13px;
    padding: 9px 12px;
    transition: border-color var(--transition), box-shadow var(--transition);
    outline: none;
    resize: vertical;
  }
  .cb-input:focus, .cb-textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-glow);
  }
  .cb-textarea { resize: vertical; min-height: 70px; line-height: 1.55; }

  /* Category picker */
  .cb-category-group {
    display: flex;
    gap: 8px;
  }
  .cb-cat-btn {
    flex: 1;
    padding: 7px 8px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
  }
  .cb-cat-btn.attacking { }
  .cb-cat-btn.attacking.active { border-color: rgba(224,92,58,0.7); color: #e05c3a; background: rgba(224,92,58,0.12); }
  .cb-cat-btn.balanced.active  { border-color: rgba(201,146,42,0.7); color: var(--accent); background: rgba(201,146,42,0.12); }
  .cb-cat-btn.defensive.active { border-color: rgba(90,159,212,0.7); color: #5a9fd4; background: rgba(90,159,212,0.12); }
  .cb-cat-btn:not(.active):hover { border-color: var(--accent); color: var(--accent); }

  /* Tag picker */
  .cb-tag-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .cb-tag-opt {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    padding: 4px 10px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
    user-select: none;
  }
  .cb-tag-opt.selected {
    border-color: rgba(201,146,42,0.6);
    color: var(--accent);
    background: rgba(201,146,42,0.1);
  }
  .cb-tag-opt:not(.selected):hover { border-color: var(--accent); color: var(--accent); }

  /* Preview card */
  .cb-preview-section { }
  .cb-preview-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 14px 16px;
    pointer-events: none;
  }

  /* Weights column */
  .cb-weights-col {
    position: sticky;
    top: 0;
  }
  .cb-weights-header {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px 14px 0 0;
    padding: 16px 20px 14px;
    border-bottom: none;
  }
  .cb-weights-hint {
    font-size: 11px;
    color: var(--text-dim);
    font-style: italic;
    flex: 1;
    min-width: 120px;
  }
  .cb-reset-weights-btn {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 5px 12px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
    white-space: nowrap;
  }
  .cb-reset-weights-btn:hover { border-color: var(--accent); color: var(--accent); }

  .cb-weight-groups {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0 0 14px 14px;
    overflow: hidden;
  }
  .cb-weight-group {
    border-bottom: 1px solid var(--border);
  }
  .cb-weight-group:last-child { border-bottom: none; }
  .cb-group-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 20px;
    cursor: pointer;
    user-select: none;
    background: var(--surface-2);
    transition: background var(--transition);
  }
  .cb-group-header:hover { background: var(--surface); }
  .cb-group-icon {
    font-size: 14px;
    width: 20px;
    text-align: center;
  }
  .cb-group-label {
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text);
    flex: 1;
  }
  .cb-group-summary {
    font-size: 11px;
    color: var(--text-dim);
    font-style: italic;
  }
  .cb-group-caret {
    font-size: 11px;
    color: var(--text-dim);
    transition: transform var(--transition);
  }
  .cb-weight-group.open .cb-group-caret { transform: rotate(180deg); }

  .cb-group-body {
    display: none;
    padding: 4px 0 8px;
  }
  .cb-weight-group.open .cb-group-body { display: block; }

  /* Individual weight row */
  .cb-weight-row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: center;
    gap: 10px;
    padding: 8px 20px;
    transition: background var(--transition);
  }
  .cb-weight-row:hover { background: var(--surface-2); }
  .cb-weight-label {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.3;
  }
  .cb-weight-label strong {
    display: block;
    font-size: 12px;
    color: var(--text);
    font-weight: 600;
    margin-bottom: 1px;
  }
  .cb-weight-label span {
    font-size: 10px;
    color: var(--gray);
    font-style: italic;
  }
  .cb-slider-wrap {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 160px;
  }
  .cb-slider {
    -webkit-appearance: none;
    appearance: none;
    flex: 1;
    height: 4px;
    border-radius: 2px;
    background: var(--border);
    outline: none;
    cursor: pointer;
    transition: background var(--transition);
  }
  .cb-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px; height: 14px;
    border-radius: 50%;
    background: var(--accent);
    cursor: pointer;
    border: none;
    box-shadow: 0 0 6px var(--accent-glow);
    transition: transform 100ms;
  }
  .cb-slider::-webkit-slider-thumb:hover { transform: scale(1.2); }
  .cb-slider::-moz-range-thumb {
    width: 14px; height: 14px;
    border-radius: 50%;
    background: var(--accent);
    cursor: pointer;
    border: none;
  }
  .cb-weight-val {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    min-width: 30px;
    text-align: right;
    transition: color var(--transition);
  }
  .cb-weight-val.high { color: #e05c3a; }
  .cb-weight-val.mid  { color: var(--accent); }
  .cb-weight-val.low  { color: #5a9fd4; }
  .cb-weight-val.neutral { color: var(--text-dim); }

  .cb-error {
    margin-top: 16px;
    background: rgba(139,32,32,0.15);
    border: 1px solid rgba(139,32,32,0.5);
    border-radius: 2px;
    padding: 10px 14px;
    font-size: 13px;
    color: #e07070;
  }

  /* Coach builder delete button on custom cards */
  .coach-card-delete {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 22px; height: 22px;
    border-radius: 50%;
    background: rgba(139,32,32,0.2);
    border: 1px solid rgba(139,32,32,0.4);
    color: #e07070;
    font-size: 11px;
    display: grid; place-items: center;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--transition), background var(--transition);
    z-index: 2;
  }
  .coach-card:hover .coach-card-delete { opacity: 1; }
  .coach-card-delete:hover { background: rgba(139,32,32,0.5); }

  /* Edit pencil on custom cards */
  .coach-card-edit {
    position: absolute;
    top: 10px;
    right: 38px;
    width: 22px; height: 22px;
    border-radius: 50%;
    background: rgba(201,146,42,0.12);
    border: 1px solid rgba(201,146,42,0.35);
    color: var(--accent);
    font-size: 11px;
    display: grid; place-items: center;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--transition), background var(--transition);
    z-index: 2;
  }
  .coach-card:hover .coach-card-edit { opacity: 1; }
  .coach-card-edit:hover { background: rgba(201,146,42,0.25); }

  /* "Create Custom Coach" button on coaches page */
  .cb-create-btn {
    display: flex;
    align-items: center;
    gap: 7px;
    background: transparent;
    border: 1px dashed var(--accent);
    color: var(--accent);
    padding: 8px 18px;
    border-radius: 2px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background var(--transition), border-style var(--transition);
    flex-shrink: 0;
  }
  .cb-create-btn:hover { background: rgba(201,146,42,0.12); border-style: solid; }

  /* Coach attribution above plan headline */
  .coach-attribution {
    font-size: 12px;
    color: var(--accent);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 6px;
  }

  /* Tabs */
  .tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
  }
  .tab {
    background: none;
    border: none;
    color: var(--text-dim);
    padding: 10px 16px;
    font-size: 11px;
    font-family: var(--font-body);
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border-bottom: 3px solid transparent;
    transition: color var(--transition), background var(--transition);
  }
  .tab.active {
    color: var(--text);
    border-bottom-color: var(--accent);
  }
  .tab:hover { color: var(--text); background: var(--surface-2); }

  /* ============================================================
     AUTH MODAL — the sign-in prompt used everywhere (requireAccount() /
     openAuthModal() in auth-modal.js), not a page: there's no landing view
     anymore, the Explorer is the front door for guest and account alike.
     This repurposes the email/Google sign-in markup that used to live on the
     landing page — same inputs, same divider, same email button, just
     centered in a card instead of stacked down a full page. The Google
     button deliberately stays neutral surface/border rather than reusing the
     old page's red "stamp" button: that device is reserved for the logo
     badge and primary buttons, not a secondary sign-in option.
     ============================================================ */
  /* z-index above the settings drawer (3000) and its scrim (2900) — not just
     later in the DOM, which equal-z-index stacking would otherwise leave
     losing to source order: the drawer's own "sign in to save your
     usernames" button has to be able to open this modal ON TOP of itself.
     #authModalScrim overrides the shared .settings-scrim z-index by id. */
  .auth-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 3500;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }
  .auth-modal.open { display: flex; }
  #authModalScrim { z-index: 3400; }
  .auth-modal-card {
    position: relative;
    width: 100%;
    max-width: 360px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: 3px solid var(--accent);
    border-radius: 1px;
    padding: 30px 26px 26px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.35);
  }
  .auth-modal-close {
    position: absolute;
    top: 8px;
    right: 8px;
  }
  .auth-modal-title {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 8px;
  }
  .auth-modal-body {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.5;
    margin: 0 0 20px;
  }
  .auth-modal-body.hidden { display: none; }
  .auth-modal-card .email-auth {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
  }
  .auth-modal-card .email-auth input {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 1px;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 14px;
    padding: 12px 14px;
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
    width: 100%;
  }
  .auth-modal-card .email-auth input::placeholder { color: var(--text-dim); }
  .auth-modal-card .email-auth input:focus {
    border-color: var(--accent);
    box-shadow: inset 3px 0 0 var(--accent);
  }
  .auth-modal-card .email-auth .btn-email {
    background: transparent;
    color: var(--text);
    border: 2px solid var(--text);
    border-radius: 1px;
    padding: 12px 28px;
    font-size: 12px;
    font-family: var(--font-black);
    font-weight: 400;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition), color var(--transition);
    width: 100%;
  }
  .auth-modal-card .email-auth .btn-email:hover {
    border-color: var(--accent);
    background: var(--accent);
    color: #fff;
  }
  /* Switches the form between sign-in and create-account. Deliberately quiet —
     it is the second-most-likely thing anyone wants from this modal, and a
     button shouting as loud as .btn-email would make the pair read as a choice
     you have to make before you can start. */
  .auth-modal-card .email-auth .auth-switch {
    background: none;
    border: 0;
    color: var(--text-dim);
    cursor: pointer;
    font-family: var(--font-body);
    font-size: 12px;
    padding: 2px 0 0;
    text-align: center;
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color var(--transition);
    width: 100%;
  }
  .auth-modal-card .email-auth .auth-switch:hover { color: var(--text); }
  .auth-modal-card .auth-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    margin: 16px 0;
    color: var(--text-dim);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.24em;
    text-transform: uppercase;
  }
  .auth-modal-card .auth-divider::before,
  .auth-modal-card .auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
  }
  .auth-modal-card .cta-google {
    width: 100%;
    justify-content: center;
    align-items: center;
    gap: 10px;
    display: flex;
  }
  .auth-modal-card .gr-error { margin-top: 14px; }
  /* The credential-succeeded / waiting-on-onSignedIn() state (auth-modal.js
     setSigningIn()) — plain neutral text, not a progress bar; this is
     normally on screen for well under a second. */
  .auth-modal-signing {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 10px 0 2px;
    color: var(--text-dim);
    font-size: 13px;
  }
  /* Dev-only sign-in bypass (dev-auth.js), never visible off localhost.
     Styled as a utility rather than a third way to sign in: dashed border,
     dim label, no accent — it should read as scaffolding, not an offer. */
  .auth-modal-card .auth-dev { width: 100%; }
  .auth-modal-card .auth-dev .auth-divider { margin: 14px 0 12px; }
  .auth-modal-card .auth-dev-btn {
    width: 100%;
    justify-content: center;
    border-style: dashed;
    color: var(--text-dim);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  /* Home screen */
  .home-screen {
    max-width: 1180px;
    margin: 0 auto;
    padding: 40px 20px 60px;
  }
  .home-hero {
    text-align: center;
    margin-bottom: 36px;
  }
  .home-greeting {
    font-family: var(--font-display);
    font-size: clamp(1.8rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--text);
    line-height: 1.15;
    margin-bottom: 8px;
  }
  .home-name { color: var(--accent); }
  .home-sub {
    color: var(--text-dim);
    font-size: 1rem;
    margin: 0;
  }
  /* Hub layout — ANALYZE | board | TRAIN */
  .home-hub {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 32px;
    align-items: start;
    margin-bottom: 24px;
  }
  .home-hub-col {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
  }
  .home-section-header {
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--accent);
    padding: 7px 10px 7px 12px;
    border: 1px solid var(--border);
    border-radius: 2px;
    margin-bottom: 8px;
    background:
      repeating-linear-gradient(
        45deg,
        transparent,
        transparent 4px,
        rgba(255,255,255,0.012) 4px,
        rgba(255,255,255,0.012) 8px
      ),
      var(--surface-2);
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .home-section-header::before {
    content: '';
    display: inline-block;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent-glow);
    flex-shrink: 0;
  }
  .home-hub-board {
    align-self: center;
    flex-shrink: 0;
  }
  .home-hub-board-inner {
    width: 320px;
    height: 320px;
    border-radius: 2px;
    overflow: hidden;
    border: 1px solid var(--border);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35), 0 0 0 1px var(--accent-glow);
  }
  .home-hub-board-grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(8, 1fr);
    width: 100%;
    height: 100%;
  }
  .home-hub-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 26px;
    line-height: 1;
    user-select: none;
  }
  .home-hub-cell.is-light { background: var(--sq-light); color: #2a2a2a; }
  .home-hub-cell.is-dark  { background: var(--sq-dark); color: #1a1a1a; }

  @media (max-width: 1023px) {
    .home-hub { grid-template-columns: 1fr 1fr; gap: 20px; }
    .home-hub-board { display: none; }
  }
  @media (max-width: 700px) {
    .home-hub { grid-template-columns: 1fr; gap: 24px; }
  }

  .home-action-card {
    -webkit-appearance: none;
    appearance: none;
    display: flex;
    align-items: center;
    gap: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0;
    cursor: pointer;
    text-align: left;
    color: var(--text);
    transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
    width: 100%;
    overflow: hidden;
    position: relative;
  }
  /* Left accent bar */
  .home-action-card::before {
    content: '';
    display: block;
    width: 3px;
    align-self: stretch;
    background: var(--border);
    flex-shrink: 0;
    transition: background var(--transition);
  }
  .home-action-card:hover::before { background: var(--accent); }
  .home-action-card:hover {
    border-color: rgba(201,146,42,0.5);
    transform: translateY(-1px);
    box-shadow: 0 4px 18px var(--accent-glow);
  }
  /* Inner flex row (needed because ::before takes the left edge) */
  .home-action-card-inner {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px;
    flex: 1;
    min-width: 0;
  }
  .home-action-icon {
    font-size: 1.25rem;
    width: 38px; height: 38px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
  }
  .home-action-card:hover .home-action-icon {
    border-color: var(--accent);
    background: var(--accent-muted);
    box-shadow: 0 0 10px var(--accent-glow);
  }
  .home-action-body { flex: 1; min-width: 0; }
  .home-action-title {
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .home-action-desc {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.4;
  }
  .home-action-arrow {
    font-size: 1.1rem;
    color: var(--text-dim);
    flex-shrink: 0;
    transition: color var(--transition), transform var(--transition);
  }
  .home-action-card:hover .home-action-arrow {
    color: var(--accent);
    transform: translateX(2px);
  }
  /* Play vs Coach tile with nested coach sub-line */
  .home-action-card--with-sub {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  /* suppress the ::before bar for column-layout variant — the left border serves as the accent instead */
  .home-action-card--with-sub::before { display: none; }
  .home-action-card--with-sub .home-action-card-main {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px 16px 20px;
    flex: 1;
    min-width: 0;
    border-left: 3px solid var(--border);
    transition: border-color var(--transition);
  }
  .home-action-card--with-sub:hover .home-action-card-main {
    border-left-color: var(--accent);
  }
  .home-coach-sub {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border-top: 1px solid var(--border);
    background: var(--surface-2, var(--surface));
    font-size: 12px;
    color: var(--text-dim);
    border-radius: 0 0 var(--radius) var(--radius);
    flex-wrap: wrap;
  }
  .home-coach-sub--empty { font-style: italic; }
  .home-coach-sub-icon { font-size: 14px; }
  .home-coach-sub-name { font-weight: 600; color: var(--text); }
  .home-coach-sub-sep { color: var(--text-dim); opacity: 0.6; }
  .home-coach-sub-style { color: var(--text-dim); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .home-coach-sub-change {
    -webkit-appearance: none;
    appearance: none;
    background: none;
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--accent);
    font-size: 11px;
    padding: 4px 10px;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color var(--transition), background var(--transition);
    margin-left: auto;
  }
  .home-coach-sub-change:hover { border-color: var(--accent); background: var(--accent-muted); }

  /* Saved Plans tile — accent emphasis as a resume affordance */
  .home-action-card--resume {
    border-color: rgba(201,146,42,0.5);
    background: linear-gradient(90deg, var(--accent-muted) 0%, var(--surface) 60%);
  }
  .home-action-card--resume::before {
    background: var(--accent);
  }

  /* Home load panel */
  .home-action-card.home-action-card--open {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: transparent;
  }
  .home-load-panel {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius) var(--radius);
    padding: 16px 20px 20px;
    margin-top: -4px;
  }
  .home-load-label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin: 12px 0 6px;
  }
  .home-load-label:first-child { margin-top: 0; }
  .home-load-textarea {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 12px;
    padding: 10px 12px;
    resize: vertical;
    transition: border-color var(--transition);
  }
  .home-load-textarea:focus { outline: none; border-color: var(--accent); }
  .home-load-input {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 12px;
    padding: 8px 12px;
    transition: border-color var(--transition);
  }
  .home-load-input:focus { outline: none; border-color: var(--accent); }
  .home-load-color-row {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 12px 0 8px;
    font-size: 13px;
    color: var(--text-dim);
    flex-wrap: wrap;
  }
  .home-load-color-label { font-weight: 500; }
  .home-load-color-row label { display: flex; align-items: center; gap: 5px; color: var(--text); cursor: pointer; }
  .home-load-error {
    color: var(--danger);
    font-size: 13px;
    min-height: 18px;
    margin-bottom: 4px;
  }

  /* Play vs Coach */
  .pvc-setup {
    max-width: 480px;
    margin: 24px auto 0;
    padding: 0 4px;
  }
  .pvc-back {
    margin-bottom: 16px;
  }
  .pvc-setup-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 28px;
    box-shadow: var(--shadow);
  }
  .pvc-setup-coach {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 18px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
  }
  .pvc-setup-coach-icon { font-size: 1.8rem; }
  .pvc-setup-coach-name {
    font-weight: 700;
    font-size: 15px;
    color: var(--text);
  }
  .pvc-setup-coach-style {
    font-size: 12px;
    color: var(--text-dim);
    margin-top: 2px;
  }
  .pvc-setup-title {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 700;
    margin: 0 0 8px;
    color: var(--text);
  }
  .pvc-setup-desc {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.5;
    margin: 0 0 20px;
  }

  /* ---- Mode picker modal (Classic vs Evaluation Game) ---- */
  .pvc-mode-pick {
    max-width: 720px;
    margin: 8px auto 0;
    text-align: center;
  }
  .pvc-mode-title {
    font-family: var(--font-display);
    font-size: 1.6rem;
    font-weight: 800;
    margin: 0 0 6px;
    color: var(--text);
  }
  .pvc-mode-sub {
    font-size: 14px;
    color: var(--text-dim);
    margin: 0 0 24px;
  }
  .pvc-mode-cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 18px;
  }
  @media (max-width: 600px) {
    .pvc-mode-cards { grid-template-columns: 1fr; }
  }
  .pvc-mode-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 24px 22px;
    cursor: pointer;
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: 8px;
    position: relative;
    transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
  }
  .pvc-mode-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: var(--shadow);
  }
  .pvc-mode-card-icon { font-size: 30px; line-height: 1; }
  .pvc-mode-card-name {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text);
  }
  .pvc-mode-card-desc {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.5;
  }
  .pvc-mode-card-tag {
    position: absolute;
    top: 14px;
    right: 14px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 2px;
    padding: 2px 8px;
  }

  /* ---- Mode chip on the setup screen ---- */
  .pvc-setup-mode-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 16px;
  }
  .pvc-setup-mode-chip {
    font-size: 12px;
    font-weight: 700;
    padding: 4px 10px;
    border-radius: 2px;
    border: 1px solid var(--accent);
    background: rgba(76,175,80,0.10);
    color: var(--accent);
  }
  .pvc-setup-mode-change {
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 12px;
    text-decoration: underline;
    cursor: pointer;
    padding: 0;
  }
  .pvc-setup-mode-change:hover { color: var(--text); }
  .pvc-setup-note {
    font-size: 13px;
    color: var(--text-dim);
    line-height: 1.5;
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 12px 14px;
    margin-bottom: 16px;
  }

  .pvc-setup-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    flex-wrap: wrap;
  }
  .pvc-setup-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
    min-width: 72px;
    flex-shrink: 0;
  }
  .pvc-color-btns {
    display: flex;
    gap: 6px;
  }
  /* "Play from here" pending-position chip on the PvC setup screen */
  .pvc-fromfen-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 600;
    padding: 4px 6px 4px 10px;
    border-radius: 2px;
    border: 1px solid var(--accent);
    background: rgba(76,175,80,0.10);
    color: var(--accent);
  }
  .pvc-fromfen-clear {
    -webkit-appearance: none;
    appearance: none;
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 1;
    padding: 3px 5px;
    border-radius: 50%;
    cursor: pointer;
    transition: color var(--transition), background var(--transition);
  }
  .pvc-fromfen-clear:hover {
    color: var(--text);
    background: rgba(255,255,255,0.08);
  }
  .pvc-color-btn {
    -webkit-appearance: none;
    appearance: none;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text-dim);
    font-size: 12px;
    padding: 6px 14px;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
  }
  .pvc-color-btn.active {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-muted);
  }
  .pvc-color-btn:hover { border-color: var(--accent); }
  .pvc-diff-group {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
  }
  .pvc-diff-label {
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 5px;
  }
  .pvc-diff-label input { accent-color: var(--accent); }

  .pvc-level-group {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
  }
  .pvc-level-btn {
    -webkit-appearance: none;
    appearance: none;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text-dim);
    font-size: 12px;
    font-weight: 600;
    min-width: 44px;
    height: 32px;
    padding: 0 8px;
    cursor: pointer;
    transition: border-color 0.12s, color 0.12s, background 0.12s;
  }
  .pvc-level-btn:hover { border-color: var(--accent); }
  .pvc-level-btn.active {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-muted);
  }

  .pvc-coach-picker-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    background-color: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    font-size: 13px;
    font-family: inherit;
    padding: 7px 12px;
    flex: 1;
    min-width: 180px;
    cursor: pointer;
    transition: border-color 0.12s, background-color 0.12s;
    text-align: left;
  }
  .pvc-coach-picker-btn:hover {
    border-color: var(--accent);
    background-color: var(--accent-muted);
  }
  .pvc-coach-picker-arrow {
    color: var(--text-dim);
    font-size: 16px;
    line-height: 1;
  }

  /* Play vs Coach — game screen */
  .pvc-game {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 4px 40px;
  }
  .pvc-main {
    display: grid;
    grid-template-columns: minmax(0, 520px) minmax(280px, 360px);
    gap: 20px;
    align-items: start;
    justify-content: center;
  }
  /* Evaluation Game: no live imbalance panel — center the board alone. The
     panel still lives in the DOM (the quiz renders into it) but is .hidden
     until a pause, so a single column keeps the board centered during play. */
  .pvc-main--no-panel {
    grid-template-columns: minmax(0, 520px);
  }
  .pvc-board-col {
    min-width: 0;
  }
  .pvc-imb-panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 16px;
    position: sticky;
    top: 12px;
  }
  .pvc-imb-title {
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  .pvc-imb-empty {
    color: var(--text-dim);
    font-size: 12px;
    padding: 8px 0;
  }
  @media (max-width: 900px) {
    .pvc-main {
      grid-template-columns: minmax(0, 520px);
    }
    .pvc-imb-panel {
      position: static;
    }
  }
  .pvc-game-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 14px;
    flex-wrap: wrap;
  }
  .pvc-game-info {
    display: flex;
    gap: 8px;
    align-items: center;
    flex: 1;
    justify-content: center;
  }
  .pvc-coach-chip, .pvc-diff-chip {
    font-size: 12px;
    font-weight: 600;
    padding: 4px 10px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-dim);
  }
  .pvc-coach-chip { color: var(--accent); border-color: var(--accent); }
  .pvc-board-area {
    margin-bottom: 12px;
  }
  .pvc-board-and-eval {
    margin: 0;
  }
  .pvc-opponent-label, .pvc-player-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-dim);
    text-align: center;
    padding: 4px 0;
  }
  .pvc-captures {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    margin-left: 8px;
    min-height: 16px;
  }
  .pvc-captures img {
    width: 16px;
    height: 16px;
    margin-left: -4px;
  }
  .pvc-captures img:first-child {
    margin-left: 0;
  }
  /* Black pieces are solid #000 SVGs — give them a light halo so they read
     on the dark theme. Light theme doesn't need it. */
  .pvc-captures img.pvc-cap-b {
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.7))
            drop-shadow(0 0 1px rgba(255, 255, 255, 0.7));
  }
  [data-theme="light"] .pvc-captures img.pvc-cap-b {
    filter: none;
  }
  .pvc-cap-diff {
    font-size: 11px;
    font-weight: 700;
    color: var(--text);
    margin-left: 4px;
  }
  .pvc-thinking {
    font-style: italic;
    color: var(--accent);
    animation: pvcBlink 1s step-end infinite;
  }
  @keyframes pvcBlink { 0%,100%{opacity:1} 50%{opacity:0.3} }
  .pvc-book {
    font-size: 0.7em;
    font-style: normal;
    color: var(--text-muted);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 1px 5px;
    vertical-align: middle;
    margin-left: 4px;
  }
  .pvc-status-area {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px 16px;
    margin-bottom: 10px;
  }
  .pvc-status {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 8px;
    text-align: center;
  }
  .pvc-move-list {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.7;
    max-height: 100px;
    overflow-y: auto;
    font-family: var(--font-mono, monospace);
  }
  .pvml-num { color: var(--text-dim); }
  .pvml-w, .pvml-b { color: var(--text); margin: 0 2px; }

  /* ── Coach commentary speech bubble ─────────────────────────── */
  .pvc-game-actions {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .pvc-commentary-toggle-inline {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    user-select: none;
    font-size: 14px;
    padding: 4px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text-dim);
  }
  .pvc-commentary-toggle-inline input { margin-right: 4px; cursor: pointer; }
  .pvc-commentary-toggle-inline:has(input:checked) {
    color: var(--accent);
    border-color: var(--accent);
  }
  .pvc-commentary-toggle-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--text-dim);
    cursor: pointer;
  }
  .pvc-commentary-toggle-label input { cursor: pointer; }

  .pvc-commentary {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 10px 0;
  }
  .pvc-commentary.hidden { display: none; }
  .pvc-commentary-avatar {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    overflow: hidden;
    border: 2px solid var(--accent);
    background: var(--surface-2);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .pvc-commentary-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .pvc-commentary-icon {
    font-size: 24px;
    line-height: 1;
  }
  .pvc-commentary-bubble {
    position: relative;
    flex: 1;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 10px 14px;
    font-size: 13px;
    color: var(--text);
    line-height: 1.5;
  }
  .pvc-commentary-bubble::before {
    content: '';
    position: absolute;
    left: -8px;
    top: 14px;
    width: 0;
    height: 0;
    border-top: 8px solid transparent;
    border-bottom: 8px solid transparent;
    border-right: 8px solid var(--border);
  }
  .pvc-commentary-bubble::after {
    content: '';
    position: absolute;
    left: -7px;
    top: 14px;
    width: 0;
    height: 0;
    border-top: 8px solid transparent;
    border-bottom: 8px solid transparent;
    border-right: 8px solid var(--surface);
  }
  .pvc-commentary-imb-row {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
  }
  .pvc-commentary-imb-label {
    display: inline-block;
    font-weight: 600;
    font-size: 11px;
    color: #c9922a;
    background: rgba(201, 146, 42, 0.15);
    border: 1px solid rgba(201, 146, 42, 0.4);
    border-radius: 2px;
    padding: 1px 8px;
    margin-right: 4px;
  }
  .pvc-commentary-imb-label--bad {
    color: #c0392b;
    background: rgba(192, 57, 43, 0.15);
    border-color: rgba(192, 57, 43, 0.4);
  }
  .pvc-commentary-imb-label--neutral {
    color: #888;
    background: rgba(136, 136, 136, 0.12);
    border-color: rgba(136, 136, 136, 0.35);
  }
  .pvc-hint-panel {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 10px 0;
  }
  .pvc-hint-panel.hidden { display: none; }
  .pvc-hint-intro {
    margin: 0 0 6px;
    font-style: italic;
    color: var(--text-muted, #999);
    font-size: 13px;
  }
  .pvc-hint-loading {
    opacity: 0.6;
  }
  .pvc-hint-list {
    margin: 0;
    padding-left: 18px;
    font-size: 13px;
    color: var(--text);
    line-height: 1.7;
  }
  .pvc-hint-list li {
    margin-bottom: 2px;
  }
  .pvc-hint-list li.pvc-hint-aside {
    color: var(--text-muted, #888);
    font-style: italic;
  }
  .pvc-hint-imb-section {
    margin-top: 10px;
    border-top: 1px solid var(--border);
    padding-top: 8px;
    font-size: 12px;
    line-height: 1.7;
    color: var(--text-muted, #888);
  }
  .pvc-hint-imb-label {
    font-weight: 600;
    color: var(--text);
  }
  .pvc-hint-moves-section {
    margin-top: 10px;
    border-top: 1px solid var(--border);
    padding-top: 8px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .pvc-hint-move {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 3px 10px;
    font-size: 13px;
  }
  .pvc-hint-move-top {
    border-color: var(--accent);
  }
  .pvc-hint-move-san {
    font-weight: 700;
    font-family: monospace;
  }
  .pvc-hint-move-badge {
    font-size: 10px;
    color: var(--accent);
    font-style: italic;
  }
  .pvc-imb-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .pvc-imb-tag {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 11px;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 2px;
    border: 1px solid var(--border);
    white-space: nowrap;
    cursor: default;
  }
  .pvc-imb-tag.pvc-tag-strong {
    background: rgba(201,146,42,0.15);
    border-color: #c9922a;
    color: #c9922a;
  }
  .pvc-imb-tag.pvc-tag-weak {
    background: rgba(192,57,43,0.15);
    border-color: #c0392b;
    color: #c0392b;
  }
  .pvc-imb-tag.pvc-tag-neutral {
    background: var(--surface-2, var(--surface));
    border-color: var(--border);
    color: var(--text-dim);
  }

  #pvcTakeBack:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }
  .pvc-result-banner {
    background: var(--accent-muted);
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    color: var(--accent);
    font-weight: 700;
    font-size: 15px;
    text-align: center;
    padding: 14px;
    margin-top: 10px;
  }
  .home-action-card--play {
    border-color: var(--accent);
    background: linear-gradient(135deg, var(--surface) 80%, var(--accent-muted) 100%);
  }

  /* Onboarding — new two-panel shell layout (matches multigame analyzer) */
  .onboard-page {
    max-width: 760px;
    margin: 32px auto;
    display: flex;
    flex-direction: column;
    gap: 24px;
  }
  /* reuse .review-form-shell but override max-width constraint */
  .onboard-shell {
    width: 100%;
  }
  .onboard-heading {
    margin: 0 0 2px;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text);
  }
  .onboard-form-title {
    margin-bottom: -4px;
    padding-bottom: 0;
  }
  /* Textarea variant of review-input */
  .onboard-textarea {
    resize: vertical;
    min-height: 100px;
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.5;
  }
  /* Row that has a textarea needs to align the label to the top */
  .onboard-form-row--textarea {
    align-items: flex-start;
  }
  .onboard-form-row--textarea .review-label {
    padding-top: 10px;
  }
  /* Color picker cards (Auto / White / Black) */
  .onboard-color-cards {
    display: flex;
    gap: 8px;
  }
  .onboard-color-card {
    position: relative;
    cursor: pointer;
    flex: 1;
  }
  .onboard-color-card input[type="radio"] {
    position: absolute; opacity: 0; width: 0; height: 0;
  }
  .onboard-color-card-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 2px;
    background: transparent;
    font-size: 13px;
    color: var(--text-dim);
    transition: border-color var(--transition), background var(--transition), color var(--transition), box-shadow var(--transition);
    text-align: center;
  }
  .onboard-color-card input:checked + .onboard-color-card-inner {
    border-color: var(--accent);
    background: var(--accent-muted);
    color: var(--text);
    box-shadow: 0 0 0 1px var(--accent), 0 0 10px var(--accent-glow);
  }
  .onboard-color-card:hover .onboard-color-card-inner {
    border-color: rgba(201,146,42,0.45);
    color: var(--text);
  }
  /* Action row for the FEN card — wraps on small screens */
  .onboard-fen-actions {
    flex-wrap: wrap;
  }
  .onboard-scan-btn {
    font-size: 11px;
    padding: 8px 14px;
  }
  .onboard-scan-soon {
    opacity: 0.55;
    font-size: 10px;
  }
  @media (max-width: 680px) {
    .onboard-page { margin: 16px auto; gap: 16px; }
    .onboard-fen-actions { flex-direction: column; }
    .onboard-color-cards { gap: 6px; }
  }

  /* Legacy .onboard-card kept for any fallback references */
  .onboard-card {
    max-width: 480px;
    margin: 40px auto;
    background: var(--surface);
    padding: 36px;
    border-radius: 2px;
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
  }
  .onboard-card h2 {
    margin-top: 0;
    font-family: var(--font-display);
    font-size: 20px;
    letter-spacing: 0.04em;
  }
  .onboard-card p { color: var(--text-dim); line-height: 1.6; }
  .input-row {
    display: flex;
    gap: 8px;
    margin-top: 20px;
  }
  .input-row input {
    flex: 1;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 12px 14px;
    border-radius: 2px;
    font-size: 15px;
    font-family: inherit;
  }
  .input-row input:focus { outline: 2px solid var(--accent); }
  .upload-label {
    display: block;
    margin-top: 16px;
    margin-bottom: 6px;
    color: var(--text-dim);
    font-size: 13px;
    font-weight: 600;
  }
  .upload-textarea, .upload-input {
    width: 100%;
    box-sizing: border-box;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 10px 12px;
    border-radius: 2px;
    font-size: 13px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    resize: vertical;
  }
  .upload-textarea:focus, .upload-input:focus { outline: 2px solid var(--accent); }
  .upload-color-row {
    display: flex;
    gap: 14px;
    align-items: center;
    margin-top: 14px;
    color: var(--text-dim);
    font-size: 13px;
  }
  .upload-color-row label { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
  .upload-color-label { font-weight: 600; }
  .btn-primary {
    background: var(--accent);
    color: var(--on-accent);
    border: none;
    padding: 12px 22px;
    border-radius: 2px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    box-shadow: 0 4px 16px var(--accent-glow);
    transition: background var(--transition), transform var(--transition);
  }
  [data-theme="light"] .btn-primary { color: var(--on-accent); }
  .btn-primary:hover { background: var(--accent-dim); transform: translateY(-1px); }
  .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
  .btn-secondary {
    background: transparent;
    color: var(--text-dim);
    border: 1px solid var(--border);
    padding: 10px 18px;
    border-radius: 2px;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    transition: border-color var(--transition), color var(--transition);
  }
  .btn-secondary:hover { border-color: var(--accent); color: var(--accent); }
  .btn-secondary:disabled { opacity: 0.45; cursor: not-allowed; }
  .btn-disabled-turn { opacity: 0.45; cursor: not-allowed; }

  /* Dashboard */
  .dash-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 12px;
  }
  .username-display {
    font-size: 15px;
    color: var(--text-dim);
  }
  .username-display strong { color: var(--text); }
  .change-link {
    font-size: 13px;
    margin-left: 8px;
    background: none;
    border: none;
    color: var(--accent);
    cursor: pointer;
  }
  .change-link:hover { text-decoration: underline; }

  .search-bar-wrap {
    margin-bottom: 14px;
    display: flex;
    gap: 8px;
    align-items: stretch;
  }
  .search-input-wrap {
    position: relative;
    flex: 1;
    min-width: 0;
  }
  .search-bar-wrap input {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 10px 36px 10px 14px;
    border-radius: 2px;
    font-size: 14px;
    font-family: inherit;
  }
  .search-bar-wrap input:focus { outline: 2px solid var(--accent); }
  .search-bar-wrap input::placeholder { color: var(--text-dim); }
  .search-apply { padding: 0 16px; font-size: 13px; white-space: nowrap; }
  .color-filter-btns { display: flex; gap: 4px; align-items: stretch; }
  .color-filter-btn {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 2px;
    padding: 0 12px;
    font-size: 13px;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
  }
  .color-filter-btn:hover { border-color: var(--accent); color: var(--accent); }
  .color-filter-btn.active { border-color: var(--accent); color: var(--accent); background: rgba(201,146,42,0.12); }
  .search-clear {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 16px;
    cursor: pointer;
    padding: 0 4px;
    display: none;
  }
  .search-clear.visible { display: block; }
  .search-count {
    font-size: 12px;
    color: var(--text-dim);
  }
  .games-load-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
    min-height: 18px;
  }
  .games-load-control {
    font-size: 12px;
    color: var(--text-dim);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
  }
  .games-load-control select {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 4px 8px;
    border-radius: 2px;
    font-size: 12px;
    font-family: inherit;
    cursor: pointer;
  }
  .games-load-control select:focus { outline: 2px solid var(--accent); }
  .games-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
    gap: 12px;
  }
  .game-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 16px;
    cursor: pointer;
    transition: transform var(--transition), border-color var(--transition), box-shadow var(--transition);
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
  }
  .card-body {
    flex: 1;
    min-width: 0; /* lets .opening ellipsis work inside flex */
  }
  .card-thumb {
    flex-shrink: 0;
    width: 88px;
    height: 88px;
    position: relative;
    border-radius: 2px;
    overflow: hidden;
    border: 1px solid var(--border);
    /* 2x2 conic tile repeated 4x4 = 8x8 checkerboard; quadrant order is
       TR, BR, BL, TL, so the last color lands on a8 (light). The pattern
       is identical under 180° rotation, so flipped boards stay correct. */
    background-image: conic-gradient(
      var(--sq-dark) 0.25turn, var(--sq-light) 0.25turn 0.5turn,
      var(--sq-dark) 0.5turn 0.75turn, var(--sq-light) 0.75turn);
    background-size: 25% 25%;
  }
  .card-thumb.thumb-empty {
    background: var(--surface-2);
  }
  .thumb-piece {
    position: absolute;
    width: 12.5%;
    height: 12.5%;
    pointer-events: none;
    user-select: none;
  }
  .game-card:hover {
    border-color: var(--accent);
    transform: translateY(-3px);
    box-shadow: var(--shadow-glow);
  }
  .game-card.locked {
    opacity: 0.55;
    cursor: not-allowed;
  }
  .game-card.locked:hover {
    transform: none;
    border-color: var(--border);
  }
  .lock-overlay {
    position: absolute;
    top: 10px;
    right: 10px;
    background: var(--surface-2);
    padding: 4px 8px;
    border-radius: 2px;
    font-size: 11px;
    color: var(--warn);
    font-weight: 600;
  }
  .game-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
  }
  .color-icon { font-size: 16px; }
  .result-badge {
    padding: 2px 8px;
    border-radius: 2px;
    font-size: 11px;
    font-weight: 700;
    flex-shrink: 0;
  }
  .result-W { background: var(--accent); color: #0f1117; }
  .result-L { background: var(--danger); color: #fff; }
  .result-D { background: var(--gray); color: #fff; }
  .result-unknown { background: var(--surface-2); color: var(--text-dim); }
  .card-players {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-bottom: 8px;
  }
  .card-player-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 14px;
  }
  .card-player-row.you { font-weight: 700; color: var(--text); }
  .card-player-row.opp { color: var(--text-dim); }
  .rating { color: var(--text-dim); font-weight: 400; font-size: 12px; }
  .card-player-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 6px 0;
  }
  .card-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
  }
  .opening {
    color: var(--text-dim);
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
  }
  .game-date {
    font-size: 11px;
    color: var(--text-dim);
    flex-shrink: 0;
  }
  .card-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 6px;
    font-size: 11px;
    color: var(--text-dim);
  }
  /* Paywall */
  .paywall {
    background: linear-gradient(135deg, #1a1d27 0%, #232735 100%);
    border: 1px solid var(--warn);
    padding: 20px;
    border-radius: var(--radius);
    text-align: center;
    margin-bottom: 20px;
  }
  .paywall h3 { margin-top: 0; color: var(--warn); }
  .paywall p { color: var(--text-dim); margin-bottom: 16px; }

  /* Loading */
  .loading-screen {
    max-width: 600px;
    margin: 40px auto;
    text-align: center;
    padding: 40px 20px;
  }
  .spinner {
    width: 48px; height: 48px;
    border: 4px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto 24px;
  }
  @keyframes spin { to { transform: rotate(360deg); } }
  .loading-text {
    font-size: 17px;
    margin-bottom: 12px;
  }
  .loading-sub { color: var(--text-dim); font-size: 14px; }
  .progress-bar {
    height: 8px;
    background: var(--surface-2);
    border-radius: 2px;
    overflow: hidden;
    margin: 20px auto;
    max-width: 320px;
    display: none;
  }
  .progress-bar.show { display: block; }
  .progress-bar .fill {
    height: 100%;
    background: var(--accent);
    width: 0;
    animation: progress 40s linear forwards;
  }
  @keyframes progress {
    0% { width: 0; }
    100% { width: 100%; }
  }

  /* Plan output */
  .plan-output {
    display: grid;
    grid-template-columns: 420px 1fr;
    gap: 24px;
    align-items: start;
    animation: fadeIn 0.4s ease-out;
  }
  @keyframes fadeIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: none; }
  }
  @media (max-width: 820px) {
    .plan-output { grid-template-columns: 1fr; }
    .plan-left, .plan-right { position: static; max-height: none; overflow: visible; }
  }
  .plan-left {
    position: sticky;
    top: 16px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding-right: 4px;
  }
  .plan-right {
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding-right: 4px;
  }
  .plan-left::-webkit-scrollbar,
  .plan-right::-webkit-scrollbar { width: 8px; }
  .plan-left::-webkit-scrollbar-thumb,
  .plan-right::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 2px;
  }
  .plan-left::-webkit-scrollbar-thumb:hover,
  .plan-right::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
  .board-and-eval {
    display: flex;
    gap: 8px;
    align-items: stretch;
  }
  .eval-bar-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    width: 20px;
    flex-shrink: 0;
  }
  .eval-bar {
    flex: 1;
    width: 20px;
    min-height: 200px;
    border-radius: 2px;
    background: #111;
    overflow: hidden;
    border: 1px solid var(--border);
    position: relative;
  }
  .eval-bar-white {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: #f0ede8;
    transition: height 0.4s ease;
  }
  .eval-bar-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 700;
    color: var(--text);
    text-align: center;
    white-space: nowrap;
    min-height: 14px;
  }
  .eval-bar-thinking {
    animation: evalPulse 1s infinite alternate;
  }
  @keyframes evalPulse {
    from { opacity: 0.4; }
    to   { opacity: 1; }
  }
  .engine-panel {
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    line-height: 1.5;
    /* Reserve space for ~3 PV lines so adding/removing a line never reflows
       anything below this panel. Lichess pins the engine panel at a stable
       height for the same reason. */
    min-height: 110px;
    height: 110px;
    display: flex;
    flex-direction: column;
    contain: layout;
    overflow: hidden;
  }
  .engine-panel .engine-pv {
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }
  .engine-header {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-dim);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
    min-height: 16px;
  }
  .engine-header .engine-name { color: var(--accent); font-weight: 700; flex-shrink: 0; }
  .engine-header .engine-depth {
    color: var(--text-dim);
    /* Fixed width so "depth 8" → "depth 22" doesn't shift the toolbar */
    min-width: 56px;
    text-align: right;
    margin-left: auto;
    flex-shrink: 0;
  }
  .engine-toolbar {
    display: flex;
    gap: 4px;
    flex-shrink: 0;
  }
  .engine-tool-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 2px;
    padding: 2px 7px;
    font-size: 10px;
    font-family: inherit;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: pointer;
    line-height: 1.4;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .engine-tool-btn:hover { color: var(--text); border-color: var(--text-dim); }
  .engine-tool-btn.active {
    background: rgba(208,104,83,0.16);
    border-color: #d06853;
    color: #d06853;
  }
  .engine-pv {
    color: var(--text);
    padding-bottom: 2px;
    min-height: 18px;
  }
  .engine-pv .pv-eval {
    color: var(--accent);
    font-weight: 700;
    margin-right: 8px;
    flex-shrink: 0;
  }
  .engine-pv .pv-eval.minus { color: #d06853; }
  .engine-pv .pv-move { color: var(--text); }
  .engine-pv .pv-move.best { color: var(--accent); font-weight: 700; }
  .engine-pv.thinking { opacity: 0.6; }
  .engine-pv-line {
    /* Block layout (not flex) + nowrap + ellipsis is the simplest way to
       force long PVs to truncate to one row. Flex children resist shrinking
       below their content width even with min-width:0, which was causing
       long PV lines to push the engine panel — and with it the whole
       column — wider than the viewport. */
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-bottom: 1px;
    line-height: 1.5;
  }
  .engine-pv-line > * {
    /* Inline children inherit the line's nowrap/ellipsis behavior. */
    display: inline;
  }
  .engine-pv-line + .engine-pv-line {
    margin-top: 2px;
    opacity: 0.72;
  }
  .engine-pv-line + .engine-pv-line + .engine-pv-line {
    opacity: 0.5;
  }
  .engine-pv-line.threat .pv-eval { color: #d06853; }
  .engine-pv-line.threat::before {
    content: "⚠";
    color: #d06853;
    margin-right: 2px;
    flex-shrink: 0;
  }
  /* Settings modal */
  .sf-settings-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.55);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .sf-settings-overlay.hidden { display: none !important; }
  .sf-settings-modal {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 22px 24px 20px;
    width: 320px;
    max-width: calc(100vw - 32px);
    box-shadow: 0 8px 32px rgba(0,0,0,0.45);
  }
  .sf-settings-title {
    font-size: 14px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--accent);
    margin-bottom: 18px;
  }
  .sf-setting-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
  }
  .sf-setting-label {
    font-size: 12px;
    color: var(--text-dim);
    width: 90px;
    flex-shrink: 0;
  }
  .sf-setting-slider {
    flex: 1;
    accent-color: var(--accent);
    cursor: pointer;
  }
  .sf-setting-value {
    font-size: 12px;
    font-weight: 700;
    color: var(--text);
    width: 32px;
    text-align: right;
    flex-shrink: 0;
  }
  .sf-settings-actions {
    display: flex;
    gap: 8px;
    margin-top: 6px;
    justify-content: flex-end;
  }
  .settings-btn {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 6px 12px;
    border-radius: 2px;
    font-size: 13px;
    cursor: pointer;
  }
  .settings-btn:hover { background: var(--surface-2); }
  .sf-download-wrap {
    margin-top: 4px;
  }
  .sf-download-label {
    font-size: 10px;
    color: var(--text-dim);
    margin-bottom: 4px;
    display: flex;
    justify-content: space-between;
  }
  .sf-download-label span { color: var(--accent); }
  .sf-download-bar-track {
    height: 4px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
  }
  .sf-download-bar-fill {
    height: 100%;
    width: 0%;
    background: var(--accent);
    border-radius: 2px;
    transition: width 0.2s ease;
  }
  .sf-download-bar-fill.indeterminate {
    width: 40%;
    animation: sfSlide 1.4s ease-in-out infinite;
  }
  @keyframes sfSlide {
    0%   { margin-left: 0%;   width: 40%; }
    50%  { margin-left: 60%;  width: 40%; }
    100% { margin-left: 0%;   width: 40%; }
  }
  .board-wrap-inner {
    flex: 1;
    min-width: 0;
    position: relative;
  }
  #board { width: 100%; max-width: 380px; margin: 0 auto; }
  /* chessboard.js v1.0.0 was authored against content-box; our global
     `* { box-sizing: border-box }` breaks its size math. Restore content-box. */
  #board, #board *,
  #openings-board, #openings-board *,
  #pvcBoard, #pvcBoard *,
  #scanEditorBoard, #scanEditorBoard *,
  #evaltrainBoard, #evaltrainBoard *,
  #evaltrainPickBoard, #evaltrainPickBoard *,
  #evaltrainBoardReveal, #evaltrainBoardReveal *,
  #trnBoard, #trnBoard *,
  .piece-417db { box-sizing: content-box; }
  /* The dragged piece is a clone appended directly to <body> with
     position:absolute and no z-index, so other positioned elements can render
     over it, making the piece appear to vanish during drag. Force it above
     everything (incl. the scan modal overlay at 10000) and keep it from
     intercepting the pointer. Scope to body > img ONLY: a blanket
     pointer-events:none on .piece-417db kills spare-piece dragging, which
     binds mousedown on the piece img itself (board drags bind on squares). */
  body > img.piece-417db { z-index: 100000; pointer-events: none; }
  /* A touch drag must not scroll the page under the piece. chessboard.js does
     call preventDefault() in its touchmove handler, but jQuery binds it on
     window with no options, and browsers treat window/document touch listeners
     as passive by default — so the call is ignored and the page scrolls while
     you drag. touch-action is the only signal the browser honours here, and it
     is decided at touchstart, so the whole gesture stays locked.
     Scoped to pieces on drag-enabled boards (.cm-drag-board is added by
     click-to-move.js; view-only boards like #gvBoard never get it): a swipe
     that starts on an empty square still scrolls the page normally, and a drag
     can only ever start on a piece. */
  .cm-drag-board img.piece-417db {
    touch-action: none;
    -webkit-user-drag: none;
    -webkit-touch-callout: none;
    user-select: none;
    -webkit-user-select: none;
  }
  /* Click-to-move highlights (shared by every board via click-to-move.js) */
  .square-55d63.cm-selected {
    box-shadow: inset 0 0 0 3px rgba(255, 208, 0, 0.85);
  }
  .square-55d63.cm-move-dot {
    position: relative;
  }
  .square-55d63.cm-move-dot::after {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    width: 32%; height: 32%;
    border-radius: 50%;
    background: rgba(20, 20, 20, 0.35);
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 5;
  }
  .square-55d63.cm-move-capture::after {
    content: '';
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    border-radius: 50%;
    box-sizing: border-box;
    border: 4px solid rgba(20, 20, 20, 0.35);
    pointer-events: none;
    z-index: 5;
  }
  /* Promotion picker (shared by every board via promotion-picker.js) */
  .promo-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(10, 10, 14, 0.55);
    z-index: 200;
    cursor: pointer;
  }
  .promo-btn {
    position: absolute;
    z-index: 201;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: radial-gradient(circle, #f0f0f0 62%, rgba(240, 240, 240, 0) 68%);
    cursor: pointer;
  }
  .promo-btn img {
    width: 82%;
    height: 82%;
    pointer-events: none;
    transition: transform 0.08s ease;
  }
  .promo-btn:hover img {
    transform: scale(1.12);
  }
  .board-caption {
    text-align: center;
    margin-top: 10px;
    font-size: 13px;
    color: var(--text-dim);
    min-height: 20px;
  }
  #playerColors {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    font-size: 13px;
    font-weight: 600;
  }
  .player-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 2px;
    border: 1px solid var(--border);
    background: var(--surface-2);
  }
  .player-chip.you { border-color: var(--accent); color: var(--accent); }
  .player-chip .piece-icon { font-size: 16px; line-height: 1; }
  .vs-label { color: var(--text-dim); font-weight: 400; font-size: 12px; }
  .move-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-top: 10px;
  }
  .nav-btn {
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 2px;
    width: 32px;
    height: 32px;
    font-size: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s;
    touch-action: manipulation;
  }
  .nav-btn:hover:not(:disabled) { background: var(--accent); color: #fff; border-color: var(--accent); }
  .nav-btn:disabled { opacity: 0.3; cursor: default; }
  .nav-label {
    font-size: 13px;
    color: var(--text-dim);
    min-width: 80px;
    text-align: center;
    min-height: 18px;
  }
  .nav-jump {
    width: auto;
    padding: 0 10px;
    font-size: 11px;
    font-weight: 700;
    margin-left: 6px;
  }
  .nav-jump.active {
    background: var(--accent);
    color: #000;
    border-color: var(--accent);
  }
  .eval-graph-wrap {
    margin-top: 12px;
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 8px 10px 6px;
    background: var(--surface-2);
  }
  .eval-graph-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 11px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
  }
  .eval-graph-sub { font-size: 10px; text-transform: none; letter-spacing: 0; }
  .eval-graph-svg {
    width: 100%;
    height: 60px;
    display: block;
    cursor: crosshair;
    background: var(--bg);
    border-radius: 3px;
  }
  .tactic-card {
    margin-top: 10px;
    padding: 12px 14px;
    border: 1px solid var(--warn);
    border-radius: 2px;
    background: linear-gradient(135deg, #2a2010 0%, #3a2a15 100%);
    font-size: 13px;
    line-height: 1.5;
  }
  .tactic-card .tactic-title {
    font-weight: 700;
    color: var(--warn);
    margin-bottom: 6px;
    font-size: 13px;
  }
  .tactic-card .tactic-line {
    font-family: 'JetBrains Mono', monospace;
    font-size: 13px;
    color: var(--text);
  }
  .analyze-position-hint {
    font-size: 11px;
    color: var(--text-dim);
    text-align: center;
    margin-top: 4px;
    min-height: 14px;
  }
  .move-list {
    margin-top: 12px;
    max-height: 240px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 8px;
    background: var(--surface-2);
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    line-height: 1.7;
  }
  .move-list .move-num { color: var(--text-dim); margin-right: 4px; }
  .move-list .move-san {
    display: inline-block;
    padding: 1px 6px;
    margin: 0 2px 2px 0;
    border-radius: 3px;
    cursor: pointer;
    color: var(--text);
    transition: background 0.1s;
  }
  .move-list .move-san:hover { background: var(--surface); }
  .move-list .move-san.active {
    background: rgba(224, 164, 56, 0.35);
    font-weight: 700;
  }
  .move-list .move-san.middlegame-start {
    border: 1px solid var(--accent);
  }
  .move-list .eval {
    font-size: 10px;
    color: var(--text-dim);
    margin-left: 3px;
  }
  .move-list .eval.plus { color: #c9922a; }
  .move-list .eval.minus { color: #d06853; }
  .move-list .eval.mate { color: var(--warn); font-weight: 700; }
  .plan-section {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px;
    margin-bottom: 16px;
    animation: fadeIn 0.5s ease-out both;
  }
  .plan-section h3 {
    margin: 0 0 12px;
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-dim);
    font-weight: 600;
  }
  .position-summary {
    font-size: 16px;
    line-height: 1.6;
    margin: 0;
  }
  .hallucination-warning {
    background: linear-gradient(135deg, #2a1a1a 0%, #3a2020 100%);
    border: 1px solid #e05252;
    color: #e05252;
    padding: 12px 18px;
    border-radius: var(--radius);
    margin-bottom: 16px;
    font-size: 13px;
    animation: fadeIn 0.6s ease-out both;
  }
  .hallucination-warning ul {
    margin: 6px 0 0 0;
    padding-left: 18px;
    font-weight: 400;
  }
  .hal-confidence {
    display: inline-block;
    font-size: 11px;
    font-weight: 700;
    background: rgba(224, 82, 82, 0.2);
    border: 1px solid rgba(224, 82, 82, 0.4);
    border-radius: 2px;
    padding: 0 5px;
    margin-right: 4px;
    letter-spacing: 0.03em;
  }

  .imbalances-list {
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .imb-header {
    display: grid;
    grid-template-columns: 1fr 130px 1fr;
    gap: 0 8px;
    padding: 0 0 6px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
  }
  .imb-header-you {
    text-align: right;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--accent);
  }
  .imb-header-opp {
    text-align: left;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--danger);
  }
  .imb-row {
    display: grid;
    grid-template-columns: 1fr 130px 1fr;
    gap: 0 8px;
    align-items: center;
    padding: 5px 0;
    border-bottom: 1px solid var(--border);
    cursor: default;
  }
  .imb-row:last-child { border-bottom: none; }
  .imb-row:hover .imb-note { max-height: 80px; opacity: 1; padding-top: 4px; }
  .imb-label {
    font-size: 12px;
    font-weight: 600;
    text-transform: capitalize;
    text-align: center;
    color: var(--text-dim);
    letter-spacing: 0.02em;
    grid-column: 2;
    grid-row: 1;
  }
  .imb-cell {
    height: 28px;
    border-radius: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  /* You column (left) — strength = green, neutral = grey, weakness = red */
  .imb-cell-you { grid-column: 1; grid-row: 1; }
  .imb-cell-you.strength  { background: rgba(201,146,42,0.20); color: #c9922a; }
  .imb-cell-you.neutral   { background: rgba(85,85,85,0.15);   color: var(--text-dim); }
  .imb-cell-you.weakness  { background: rgba(192,57,43,0.15);  color: #c0392b; }
  /* Opponent column (right) */
  .imb-cell-opp { grid-column: 3; grid-row: 1; }
  .imb-cell-opp.strength  { background: rgba(192,57,43,0.20);  color: #c0392b; }
  .imb-cell-opp.neutral   { background: rgba(85,85,85,0.15);   color: var(--text-dim); }
  .imb-cell-opp.weakness  { background: rgba(201,146,42,0.15); color: #c9922a; }
  /* Note expands on hover spanning full width */
  .imb-note {
    grid-column: 1 / -1;
    grid-row: 2;
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.5;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-height 0.2s ease, opacity 0.2s ease, padding-top 0.2s ease;
    padding-top: 0;
  }
  @media (max-width: 640px) {
    .imb-header { grid-template-columns: 1fr 100px 1fr; }
    .imb-row    { grid-template-columns: 1fr 100px 1fr; }
  }

  .step-hint {
    font-size: 13px;
    color: var(--text-dim);
    font-style: italic;
    margin: -6px 0 12px;
  }
  .plan-headline {
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 8px;
    line-height: 1.4;
  }
  .plan-explanation {
    font-size: 14px;
    line-height: 1.6;
    color: var(--text);
  }
  .plan-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
  }
  .plan-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 2px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
  }
  .plan-chip.ok { background: var(--accent); color: #0f1117; border-color: transparent; }
  .plan-chip.warn { background: var(--warn); color: #0f1117; border-color: transparent; }

  /* Analyzed positions strip */
  .analyzed-strip {
    margin-top: 12px;
    border: 1px solid var(--border);
    border-radius: 2px;
    background: var(--surface-2);
    overflow: hidden;
  }
  .analyzed-strip-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 10px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-dim);
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    user-select: none;
  }
  .analyzed-strip-header:hover { color: var(--text); }
  .analyzed-strip-header .strip-toggle { font-size: 12px; }
  .analyzed-strip-body {
    display: flex;
    gap: 8px;
    padding: 8px;
    overflow-x: auto;
    flex-wrap: nowrap;
  }
  .analyzed-strip-body::-webkit-scrollbar { height: 4px; }
  .analyzed-strip-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
  .analyzed-thumb {
    flex-shrink: 0;
    width: 80px;
    cursor: pointer;
    border-radius: 2px;
    border: 2px solid var(--border);
    overflow: hidden;
    transition: border-color 0.15s, transform 0.15s;
    background: var(--surface);
  }
  .analyzed-thumb:hover { border-color: var(--accent); transform: translateY(-2px); }
  .analyzed-thumb.active { border-color: var(--accent); }
  .analyzed-thumb canvas,
  .analyzed-thumb .thumb-board {
    width: 80px;
    height: 80px;
    display: block;
    image-rendering: pixelated;
  }
  .analyzed-thumb-label {
    font-size: 9px;
    color: var(--text-dim);
    text-align: center;
    padding: 2px 4px 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
  }
  .analyzed-thumb.active .analyzed-thumb-label { color: var(--accent); }

  .plan-goal {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 14px;
    line-height: 1.6;
  }
  .plan-steps {
    margin: 0 0 18px 20px;
    padding: 0;
    font-size: 14px;
    line-height: 1.6;
  }
  .plan-steps li { margin-bottom: 6px; }
  .plan-steps .alt-tag {
    display: inline-block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.5px;
    padding: 1px 6px;
    border-radius: 3px;
    background: rgba(224, 164, 56, 0.15);
    color: var(--warn, #e0a438);
    border: 1px solid rgba(224, 164, 56, 0.4);
    vertical-align: middle;
    margin-left: 4px;
  }
  .move-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }
  .move-badge {
    font-family: 'JetBrains Mono', monospace;
    background: var(--surface-2);
    border: 1px solid var(--accent);
    color: var(--accent);
    padding: 6px 12px;
    border-radius: 2px;
    font-size: 14px;
    font-weight: 600;
  }
  .plan-alternatives {
    margin-top: 10px;
    font-size: 13px;
    color: var(--text-muted, #888);
    font-family: 'JetBrains Mono', monospace;
  }
  .plan-alternatives.hidden { display: none; }
  .plan-alternatives .alt-label {
    font-family: inherit;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 12px;
    margin-right: 4px;
  }
  .counter-plan-card {
    background: rgba(192, 57, 43, 0.1);
    border-left: 3px solid var(--danger);
    padding: 14px 18px;
    border-radius: 2px;
    line-height: 1.6;
    font-size: 14px;
  }
  .watch-out-card {
    background: rgba(224, 164, 56, 0.1);
    border-left: 3px solid var(--warn);
    padding: 14px 18px;
    border-radius: 2px;
    line-height: 1.6;
    font-size: 14px;
  }


  /* Pawn Breaks watchlist panel */
  .pawn-breaks-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
  }
  .pbreak-col {
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--border);
    border-radius: 2px;
    padding: 10px 12px;
  }
  .pbreak-col-title {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-dim);
    margin-bottom: 8px;
  }
  .pbreak-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .pbreak-item {
    font-weight: 600;
    font-size: 14px;
    color: var(--text);
    padding: 3px 8px;
    border: 1px solid var(--border);
    border-radius: 2px;
    background: rgba(255,255,255,0.02);
  }
  .pbreak-empty {
    color: var(--text-dim);
    font-size: 12px;
    font-style: italic;
  }
  @media (max-width: 600px) {
    .pawn-breaks-grid { grid-template-columns: 1fr; }
  }

  /* Dev scoring report */
  .dev-scoring-section { border-left: 3px solid #555; background: rgba(0,0,0,0.25); }
  .dev-section-title {
    display: flex; justify-content: space-between; align-items: center;
    cursor: pointer; user-select: none; margin: 0; padding: 4px 0;
    font-size: 13px; color: #aaa;
  }
  .dev-section-title:hover { color: #ddd; }
  .dev-section-caret { font-size: 11px; transition: transform 0.15s; }
  .dev-scoring-section.collapsed .dev-section-caret { transform: rotate(-90deg); }
  .dev-scoring-section.collapsed #devScoringBody { display: none; }
  .dev-scoring-table {
    width: 100%; border-collapse: collapse; font-size: 12px;
    font-family: monospace; margin-top: 8px;
  }
  .dev-scoring-table th {
    text-align: left; color: #888; font-weight: normal;
    border-bottom: 1px solid #444; padding: 3px 6px;
  }
  .dev-scoring-table td { padding: 3px 6px; color: #ccc; }
  .dev-scoring-table tr:first-child td { color: #ffe082; font-weight: bold; }
  .dev-scoring-table .dev-score { color: #c9922a; text-align: right; }
  .dev-reasons { color: #888; font-size: 11px; padding: 2px 6px 6px 6px; line-height: 1.5; }

  /* Endgame transition */
  /* ======================================================
     ENDGAME TRANSITION — redesigned card system
     ====================================================== */

  /* Hero block: readiness verdict + headline */
  .et-hero {
    position: relative;
    padding: 14px 16px 16px;
    border-radius: var(--radius);
    background: linear-gradient(135deg, rgba(201,146,42,0.08), rgba(201,146,42,0.02));
    border: 1px solid var(--border);
    margin-bottom: 14px;
    overflow: hidden;
  }
  .et-hero::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--accent);
  }
  .et-hero.not-ready { background: linear-gradient(135deg, rgba(231,76,60,0.08), rgba(231,76,60,0.02)); }
  .et-hero.not-ready::before { background: var(--danger); }
  .et-hero.neutral { background: linear-gradient(135deg, rgba(255,255,255,0.04), rgba(255,255,255,0.01)); }
  .et-hero.neutral::before { background: var(--text-dim); }

  .et-readiness-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 11px;
    border-radius: 2px;
    font-size: 11px;
    font-weight: 700;
    margin-bottom: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
  }
  .et-readiness-badge::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 8px currentColor;
  }
  .et-readiness-badge.ready {
    background: rgba(201,146,42,0.18);
    color: var(--accent);
  }
  .et-readiness-badge.not-ready {
    background: rgba(231,76,60,0.18);
    color: var(--danger);
  }
  .et-readiness-badge.neutral {
    background: rgba(255,255,255,0.08);
    color: var(--text-dim);
  }

  .et-headline {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.4;
    margin-top: 2px;
  }

  /* Weighed verdict: what pushes toward the endgame vs what holds back */
  .et-factor-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
  }
  .et-factor-head {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    margin-bottom: 7px;
  }
  .et-factor-col.pro .et-factor-head { color: var(--accent); }
  .et-factor-col.con .et-factor-head { color: var(--danger); }
  .et-factor-col ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
  .et-factor-col li {
    position: relative;
    padding-left: 15px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-dim);
  }
  .et-factor-col li::before {
    position: absolute;
    left: 1px;
    font-weight: 700;
  }
  .et-factor-col.pro li::before { content: '+'; color: var(--accent); }
  .et-factor-col.con li::before { content: '−'; color: var(--danger); }

  /* Section labels with icon affordance */
  .et-section-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    margin: 0 0 10px;
  }
  .et-section-label::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
  }
  .et-section-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px; height: 18px;
    border-radius: 2px;
    background: var(--surface-2);
    font-size: 11px;
    color: var(--accent);
  }

  /* Trades — card grid (rendered inside roadmap phase 2) */
  .et-trades-grid {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .et-trade-card {
    display: grid;
    grid-template-columns: 130px auto 1fr;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    border-left: 3px solid var(--border);
    font-size: 13px;
    transition: border-color 0.15s ease, background 0.15s ease;
  }
  .et-trade-card:hover { background: var(--surface); }
  .et-trade-card.good { border-left-color: var(--accent); }
  .et-trade-card.bad  { border-left-color: var(--danger); }
  .et-trade-card.neut { border-left-color: var(--text-dim); }

  .et-trade-piece {
    font-weight: 600;
    color: var(--text);
  }
  .et-trade-verdict {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 2px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
  }
  .et-trade-verdict.good { background: rgba(201,146,42,0.18); color: var(--accent); }
  .et-trade-verdict.bad  { background: rgba(231,76,60,0.18);  color: var(--danger); }
  .et-trade-verdict.neut { background: rgba(255,255,255,0.08); color: var(--text-dim); }
  .et-trade-verdict::before {
    content: '';
    width: 4px; height: 4px;
    border-radius: 50%;
    background: currentColor;
  }
  .et-trade-reason {
    color: var(--text-dim);
    font-size: 12.5px;
    line-height: 1.45;
  }

  .et-trade-reasons {
    color: var(--text-dim);
    font-size: 12.5px;
    line-height: 1.45;
    list-style: disc;
    margin: 0;
    padding-left: 18px;
  }

  /* Roadmap — three ordered phases, each tagged with its playing method */
  .et-roadmap { margin-bottom: 12px; }
  .et-phase {
    position: relative;
    padding: 12px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    margin-bottom: 8px;
  }
  .et-phase-header {
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .et-phase-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px; height: 22px;
    flex: 0 0 22px;
    border-radius: 50%;
    background: rgba(201,146,42,0.18);
    color: var(--accent);
    font-size: 12px;
    font-weight: 700;
  }
  .et-phase-title {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
  }
  .et-phase-principle {
    margin-left: auto;
    font-size: 11px;
    font-style: italic;
    color: var(--text-dim);
    white-space: nowrap;
  }
  .et-phase-intro {
    margin: 9px 0 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-dim);
  }
  .et-phase-items {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
  }
  .et-phase-items li {
    position: relative;
    padding-left: 16px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
  }
  .et-phase-items li::before {
    content: '›';
    position: absolute;
    left: 2px;
    font-weight: 700;
    color: var(--accent);
  }

  /* Target endgame — schematic-thinking feature card */
  .et-target-block { margin-bottom: 16px; }
  .et-target-hint {
    margin: 8px 0 0;
    font-size: 12px;
    font-style: italic;
    line-height: 1.5;
    color: var(--text-dim);
    border-top: 1px dashed var(--border);
    padding-top: 8px;
  }
  .et-target-others {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .et-target-other {
    display: grid;
    grid-template-columns: auto auto 1fr;
    align-items: baseline;
    gap: 8px 10px;
    padding: 8px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    font-size: 12px;
  }
  .et-target-other-type { font-weight: 600; color: var(--text); }
  .et-target-other-note { color: var(--text-dim); line-height: 1.45; }

  .et-endgame-card {
    padding: 12px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
  }
  .et-endgame-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
  }
  .et-endgame-type {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
  }
  .et-endgame-rating {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 2px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: rgba(201,146,42,0.18);
    color: var(--accent);
  }
  .et-endgame-rating.unfavorable { background: rgba(231,76,60,0.18); color: var(--danger); }
  .et-endgame-rating.neutral { background: rgba(255,255,255,0.08); color: var(--text-dim); }
  .et-endgame-howto {
    font-size: 12.5px;
    color: var(--text-dim);
    line-height: 1.5;
    margin: 0;
  }

  @media (max-width: 600px) {
    .et-trade-card {
      grid-template-columns: 1fr auto;
      gap: 6px 10px;
    }
    .et-trade-reason { grid-column: 1 / -1; }
    .et-trade-reasons { grid-column: 1 / -1; }
    .et-factor-cols { grid-template-columns: 1fr; }
    .et-phase-principle {
      white-space: normal;
      flex-basis: 100%;
      margin-left: 32px;
    }
    .et-phase-header { flex-wrap: wrap; row-gap: 2px; }
    .et-target-other { grid-template-columns: auto 1fr; }
    .et-target-other-note { grid-column: 1 / -1; }
  }

  /* Candidate lines */
  .candidate-lines-panel {
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
  }
  .candidate-lines-header {
    color: var(--text-dim);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 6px;
    font-weight: 600;
  }
  .candidate-line-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 3px 0;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
  }
  .candidate-line-row:last-child { border-bottom: none; }
  .candidate-line-row:hover .candidate-line-moves { color: var(--accent); }
  .candidate-line-san {
    color: var(--accent);
    font-weight: 700;
    min-width: 36px;
    flex-shrink: 0;
  }
  .candidate-line-eval {
    font-weight: 700;
    min-width: 52px;
    flex-shrink: 0;
  }
  .candidate-line-eval.plus { color: #c9922a; }
  .candidate-line-eval.minus { color: #d06853; }
  .candidate-line-moves {
    color: var(--text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
  }
  .candidate-line-depth {
    color: var(--text-dim);
    font-size: 10px;
    flex-shrink: 0;
  }
  .candidate-line-row.is-soft-flag .candidate-line-san,
  .candidate-line-row.is-soft-flag .candidate-line-eval.plus,
  .candidate-line-row.is-soft-flag .candidate-line-eval.minus { color: #d0a853; }
  .candidate-line-row.is-soft-flag { opacity: 0.9; }
  .candidate-line-row.is-engine-backfill .candidate-line-san { color: #7a9fd0; }
  .candidate-badge {
    font-size: 9px;
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 2px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    flex-shrink: 0;
  }
  .candidate-badge.engine { background: rgba(122,159,208,0.18); color: #7a9fd0; }
  .candidate-badge.warn   { background: rgba(208,168,83,0.18);  color: #d0a853; }

  /* Weakness dashboard */
  .empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--text-dim);
  }
  .empty-state h3 { color: var(--text); margin-bottom: 8px; }

  /* Saved plans list */
  .saved-list { display: flex; flex-direction: column; gap: 10px; }
  .saved-item {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 18px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    gap: 12px;
  }
  .saved-item:hover { border-color: var(--accent); }
  .saved-item-main { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; }
  /* Board thumbnail (the position the plan was generated from) — smaller than
     the games-grid thumb so rows stay compact. Scoped selector so the mobile
     .card-thumb width override doesn't re-inflate it. */
  .saved-item .card-thumb { width: 64px; height: 64px; flex-shrink: 0; }
  .saved-item-info { min-width: 0; flex: 1; }
  .saved-item-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .saved-item-meta { font-size: 12px; color: var(--text-dim); margin-top: 2px; }

  .error-card {
    background: rgba(192, 57, 43, 0.1);
    border: 1px solid var(--danger);
    color: var(--danger);
    padding: 14px;
    border-radius: var(--radius);
    margin: 20px 0;
  }

  .hidden { display: none !important; }

  /* ---------- Mobile ---------- */
  @media (max-width: 820px) {
    /* Kill nested scroll containers on phones — use natural page scroll */
    .plan-left, .plan-right {
      position: static;
      max-height: none;
      overflow: visible;
      padding-right: 0;
    }
  }
  @media (max-width: 700px) {
    .app { padding: 12px; }
    /* Room for the fixed bottom tab bar */
    body.sidenav-on .app { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }

    /* Topbar — logo and account on one row, the section bar wrapping to a
       second. `order` puts the nav last regardless of markup order. */
    .topbar {
      padding: 10px 0 12px;
      margin-bottom: 16px;
      gap: 8px 8px;
      flex-wrap: wrap;
    }
    .topbar .logo { order: 1; }
    .topbar-right { order: 2; }
    .topbar .site-nav { order: 3; }
    .logo { gap: 7px; min-width: 0; }
    .logo-lockup { gap: 3px; }
    .logo-mark { width: 34px; height: 34px; }
    .logo-eyebrow { font-size: 8px; letter-spacing: 0.32em; }
    .logo-badge { font-size: 15px; padding: 6px 8px 5px; }
    .logo-icon { width: 28px; height: 28px; font-size: 16px; }
    .topbar-right { gap: 6px; flex-shrink: 0; }
    .user-chip { padding: 5px 8px; font-size: 12px; }
    .user-chip #userName { display: none; }
    .theme-toggle, .signout-btn, .reset-btn, .settings-btn {
      padding: 6px 10px;
      font-size: 12px;
    }
    /* Collapse verbose button labels on phones */
    .signout-btn { font-size: 0; padding: 6px 10px; }
    .signout-btn::before { content: "⎋"; font-size: 14px; }
    .settings-btn { padding: 6px 10px; }
    /* Reset Dev Data is in the settings drawer — hide from topbar on mobile */
    .topbar .reset-btn { display: none !important; }
    /* Active-coach button is redundant on mobile (Coaches is in the hamburger menu) */
    .topbar .coach-btn { display: none !important; }

    /* Onboarding */
    .onboard-card { padding: 22px; margin: 20px auto; }
    .onboard-card h2 { font-size: 20px; }
    .input-row { flex-direction: column; }
    .input-row .btn-primary { width: 100%; }

    /* Dashboard */
    .dash-header { gap: 6px; margin-bottom: 14px; }
    .username-display { font-size: 14px; word-wrap: break-word; }
    .games-grid {
      grid-template-columns: 1fr;
      gap: 10px;
    }
    .game-card { padding: 14px; min-width: 0; gap: 12px; }
    .card-thumb { width: 72px; height: 72px; }

    /* Search bar wraps onto two rows: input on top, filter chips + Search below. */
    .search-bar-wrap {
      flex-wrap: wrap;
      gap: 8px;
    }
    .search-input-wrap {
      flex: 1 1 100%;
    }
    .color-filter-btns {
      flex: 1 1 auto;
      flex-wrap: wrap;
    }
    .color-filter-btn {
      flex: 1 1 0;
      min-width: 0;
      padding: 8px 6px;
      font-size: 12px;
    }
    .search-apply { flex: 0 0 auto; padding: 0 14px; }

    /* Tabs */
    .tabs { margin-bottom: 14px; }
    .tab { padding: 10px 12px; font-size: 13px; }

    /* Plan view */
    #view-plan > .btn-secondary { width: 100%; }
    .plan-output { gap: 16px; }
    .plan-section {
      padding: 16px;
      margin-bottom: 12px;
      /* Hard cap: on mobile, no descendant can push the section wider than
         the column. Prevents long PVs / candidate-line text from making the
         page horizontally scrollable, which was causing the entire app to
         shift left/right between moves. */
      overflow-x: hidden;
      max-width: 100%;
      min-width: 0;
    }
    .plan-section h3 { font-size: 13px; }
    .plan-left, .plan-right { min-width: 0; max-width: 100%; }

    /* Board takes full width on phones.
       We compute a stable size using 100vw minus app/section/eval padding,
       AND also subtract scrollbar width via `calc(100vw - var(--sbw))`
       (set in JS once on load). 100vw alone over-shoots the visible width
       by the scrollbar, which clips the right edge of the move-nav and
       engine panel. */
    .board-and-eval { align-items: flex-start; }
    .board-wrap-inner { flex: 0 0 auto; width: calc(100vw - 80px - var(--sbw, 0px)); }
    #board, #boardWrap {
      width: calc(100vw - 80px - var(--sbw, 0px));
      height: calc(100vw - 80px - var(--sbw, 0px));
      max-width: none;
    }
    .eval-bar-wrap { width: 16px; }
    .eval-bar { width: 16px; min-height: 0; height: calc(100vw - 80px - var(--sbw, 0px)); }

    /* Move nav — single row, no wrap (wrapping on resize was the main source
       of "jumpy" feel as the URL bar showed/hid). Buttons sized so all 6 +
       label fit inside `100vw - 80px` (the board-column width on mobile). */
    .move-nav {
      flex-wrap: nowrap;
      gap: 2px;
      justify-content: space-between;
      min-height: 32px;
      width: 100%;
      box-sizing: border-box;
    }
    .nav-btn {
      width: 28px;
      height: 28px;
      font-size: 13px;
      flex-shrink: 0;
      flex-grow: 0;
      padding: 0;
    }
    .nav-label {
      min-width: 0;
      flex: 1 1 0;
      font-size: 10px;
      text-align: center;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      padding: 0 2px;
    }
    .nav-jump {
      width: auto;
      min-width: 28px;
      padding: 0 5px;
      height: 28px;
      font-size: 9px;
      margin-left: 0;
      flex-shrink: 0;
      flex-grow: 0;
    }
    /* Engine panel: same fixed height on mobile so PV churn doesn't bump
       the candidate-lines / eval-graph below it. */
    .engine-panel { min-height: 110px; height: 110px; }
    .engine-tool-btn { padding: 2px 6px; font-size: 9px; }
    .engine-header .engine-depth { min-width: 48px; font-size: 9px; }
    /* Candidate lines: ellipsis-truncate instead of wrap */
    .candidate-line-row { flex-wrap: nowrap; }
    .candidate-line-moves { min-width: 0; }

    /* Imbalances — give values more room, label centred underneath */
    .imb-header { grid-template-columns: 1fr 72px 1fr; }
    .imb-row    { grid-template-columns: 1fr 72px 1fr; }
    .imb-label  { font-size: 11px; }
    .imb-cell   { font-size: 9px; height: 26px; }

    /* Analyzed thumbs slightly smaller */
    .analyzed-thumb { width: 64px; }
    .analyzed-thumb canvas,
    .analyzed-thumb .thumb-board { width: 64px; height: 64px; }

    /* Saved plan rows */
    .saved-item { padding: 12px 14px; }
  }

  @media (max-width: 420px) {
    /* Even tighter topbar */
    .topbar { padding: 8px 0 12px; margin-bottom: 12px; }
    .logo-badge { font-size: 13px; }
    .logo-mark { width: 30px; height: 30px; }
    .logo-icon { font-size: 16px; }

    /* Stack dash header */
    .dash-header { flex-direction: column; align-items: flex-start; }

    /* Engine settings modal */
    .sf-settings-modal { padding: 18px 18px 16px; width: calc(100vw - 24px); }
    .sf-setting-label { width: 70px; font-size: 11px; }

    /* Onboarding input */
    .input-row input { font-size: 14px; padding: 11px 12px; }

    /* Compact imbalances further */
    .imb-header { grid-template-columns: 1fr 60px 1fr; gap: 0 4px; }
    .imb-row    { grid-template-columns: 1fr 60px 1fr; gap: 0 4px; }
  }

  /* ============================================================
     SETTINGS DRAWER
     ============================================================ */
  .settings-scrim {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.45);
    z-index: 2900;
    cursor: pointer;
  }
  .settings-scrim.open { display: block; }

  .settings-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 420px;
    max-width: 100vw;
    background: var(--surface);
    border-left: 1px solid var(--border);
    z-index: 3000;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: hidden;
  }
  /* Shadow only when open: parked off-screen, it would still fall on the page. */
  .settings-drawer.open { transform: translateX(0); box-shadow: -6px 0 32px rgba(0,0,0,0.35); }

  .settings-drawer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
  }
  .settings-drawer-title {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0.05em;
  }
  .settings-drawer-close {
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 18px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 2px;
    cursor: pointer;
  }
  .settings-drawer-close:hover { background: var(--surface-2); color: var(--text); }

  .settings-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 0 0 32px;
  }

  .settings-section {
    padding: 20px 20px 20px;
    border-bottom: 1px solid var(--border);
  }
  .settings-section:last-of-type { border-bottom: none; }

  .settings-section-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--accent);
    margin-bottom: 14px;
  }
  .settings-section-label-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
  }
  .settings-section-label-row .settings-section-label { margin-bottom: 0; }
  .settings-section-sub {
    font-size: 12px;
    color: var(--text-dim);
    line-height: 1.5;
    margin: -6px 0 12px;
  }

  .settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 7px 0;
    gap: 10px;
  }
  .settings-row-label { font-size: 13px; color: var(--text-dim); flex-shrink: 0; }
  .settings-row-value { font-size: 13px; font-weight: 500; text-align: right; word-break: break-all; }
  .settings-row-dim { color: var(--text-dim); }

  .settings-theme-toggle {
    display: flex;
    border: 1px solid var(--border);
    border-radius: 2px;
    overflow: hidden;
  }
  .settings-theme-opt {
    background: none;
    border: none;
    color: var(--text-dim);
    padding: 5px 14px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
  }
  .settings-theme-opt.active { background: var(--accent); color: var(--on-accent); font-weight: 700; }
  .settings-theme-opt:not(.active):hover { background: var(--surface-2); }

  /* Board palette picker — each swatch is a 2x2 checker of the palette it
     selects, so the choice is made by eye rather than by name. */
  .settings-board-opts {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  .settings-board-opt {
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 2px;
    cursor: pointer;
    background-image: conic-gradient(
      var(--sw-dark) 0.25turn, var(--sw-light) 0.25turn 0.5turn,
      var(--sw-dark) 0.5turn 0.75turn, var(--sw-light) 0.75turn);
    background-size: 50% 50%;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
  }
  .settings-board-opt:hover { transform: translateY(-1px); }
  .settings-board-opt.active {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent);
  }

  .settings-model-toggle {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px;
  }
  .settings-model-opt {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    padding: 10px 14px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    text-align: left;
  }
  .settings-model-opt-title { font-size: 13px; font-weight: 600; }
  .settings-model-opt-sub { font-size: 11px; color: var(--text-dim); }
  .settings-model-opt:hover { background: var(--surface-3, var(--surface-2)); }
  .settings-model-opt.active {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
  }
  .settings-model-opt.active .settings-model-opt-sub { color: rgba(26, 24, 21, 0.75); }

  .settings-field-group { margin-top: 14px; }
  .settings-field-label {
    display: block;
    font-size: 12px;
    color: var(--text-dim);
    margin-bottom: 6px;
    font-weight: 500;
  }
  .settings-platform-row { display: flex; gap: 18px; }
  .settings-platform-opt {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    cursor: pointer;
  }

  .settings-input-row { display: flex; gap: 8px; margin-top: 4px; }
  .settings-text-input {
    flex: 1;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 7px 10px;
    border-radius: 2px;
    font-size: 13px;
    font-family: inherit;
  }
  .settings-text-input:focus { outline: 2px solid var(--accent); border-color: transparent; }
  .settings-save-btn { padding: 7px 14px; font-size: 13px; border-radius: 2px; }
  .settings-field-error { margin-top: 6px; font-size: 12px; color: var(--danger); }
  .settings-field-success { margin-top: 6px; font-size: 12px; color: var(--accent); }


  .settings-engine-hint {
    font-size: 11px;
    color: var(--text-dim);
    line-height: 1.6;
    margin-top: 8px;
  }

  /* A section within a section (Engine → Scan depth): a rule and a quieter
     label, so it reads as a subordinate group rather than a second Engine. */
  .settings-subsection {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
  }
  .settings-subsection-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-dim);
    margin-bottom: 12px;
  }

  /* ⓘ — a control's explanation, folded away until asked for. The button
     sits inline with the label it belongs to; the note unfolds full width
     underneath the whole row. */
  .settings-info-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    vertical-align: -2px;
    padding: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--text-dim);
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
  }
  .settings-info-btn:hover { color: var(--text); border-color: var(--text-dim); }
  .settings-info-btn.is-open {
    color: var(--on-accent);
    background: var(--accent);
    border-color: var(--accent);
  }
  .settings-info-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

  .settings-info-note {
    margin: 2px 0 12px;
    padding: 10px 12px;
    background: var(--surface-2);
    border-left: 2px solid var(--accent);
    border-radius: 0 2px 2px 0;
    font-size: 11.5px;
    line-height: 1.65;
    color: var(--text-dim);
  }
  .settings-info-note em { color: var(--text); font-style: normal; font-weight: 600; }
  .settings-info-note.hidden { display: none; }

  /* Segmented two-way choice (Automatic / Custom). Same shape as the theme
     toggle, without borrowing a name that means something else. */
  .settings-seg {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 2px;
    overflow: hidden;
  }
  .settings-seg-opt {
    background: none;
    border: none;
    color: var(--text-dim);
    padding: 5px 16px;
    font-family: inherit;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
  }
  .settings-seg-opt.active { background: var(--accent); color: var(--on-accent); font-weight: 700; }
  .settings-seg-opt:not(.active):hover { background: var(--surface-2); }

  .settings-scan-custom { margin-top: 16px; }
  .settings-scan-custom.hidden { display: none; }
  /* Each cost line belongs to the slider above it, not the one below — pull it
     up tight against its own row and leave the gap under it. */
  .settings-scan-custom .settings-engine-hint { margin: -4px 0 16px; }
  /* The label column is wider here than the lone Engine depth row: "Deep
     check" plus its ⓘ has to sit on one line. */
  .settings-scan-custom .sf-setting-label { width: 104px; }

  .settings-link-btn {
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 11px;
    cursor: pointer;
    padding: 0;
    text-decoration: underline;
    font-family: inherit;
  }
  .settings-link-btn:hover { color: var(--text); }

  .settings-history-btn {
    display: block;
    width: 100%;
    margin-top: 8px;
    padding: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    font-size: 14px;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
  }
  .settings-history-btn:hover { background: var(--border); }

  .settings-signout-btn { width: 100%; margin-top: 4px; }

  .settings-version {
    padding: 16px 20px 0;
    font-size: 11px;
    color: var(--text-dim);
    opacity: 0.5;
  }

  .user-chip:hover { background: var(--surface-2); border-color: var(--accent); }
  .user-chip-gear {
    font-size: 12px;
    opacity: 0.5;
    margin-left: 2px;
  }
  .user-chip:hover .user-chip-gear { opacity: 1; }

  @media (max-width: 480px) {
    .settings-drawer { width: 100vw; }
  }

  /* ============================================================
     BOARD PATTERN BACKGROUND
     ============================================================ */
  /* Ben-Day halftone. Two offset dot grids at 6px, dense enough to read as
     printed stock up close and as flat tone from a normal viewing distance.
     Red is doped into the field at a fraction of the ink dots, which is how
     four-colour process actually looked on pulp. */
  .board-pattern {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image:
      radial-gradient(var(--text) 0.6px, transparent 0.7px),
      radial-gradient(var(--accent) 0.6px, transparent 0.7px);
    background-size: 6px 6px, 24px 24px;
    background-position: 0 0, 4px 4px;
    opacity: 0.055;
  }
  [data-theme="light"] .board-pattern { opacity: 0.09; }

  /* ============================================================
     SITE NAV (inside topbar)
     ============================================================ */
  .site-nav {
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .site-nav a {
    font-family: var(--font-body);
    font-weight: 800;
    font-size: 12px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-dim);
    text-decoration: none;
    padding: 8px 14px 7px;
    position: relative;
    transition: color var(--transition);
  }
  /* Active section is underscored with a solid red bar, not tinted text —
     the bar reads at a glance from across the masthead. */
  .site-nav a::after {
    content: '';
    position: absolute;
    left: 14px; right: 14px; bottom: 0;
    height: 3px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--transition);
  }
  .site-nav a:hover { color: var(--text); text-decoration: none; }
  .site-nav a:hover::after { transform: scaleX(1); }
  .site-nav a.active { color: var(--text); }
  .site-nav a.active::after { transform: scaleX(1); }
  /* ---- Phone: the nav becomes a section bar under the masthead --------
     This used to be `display: none`, on the inherited assumption that a
     hamburger and a bottom tab bar would take over below 700px. Neither of
     those exists in this app — the markup and the JS for them were never
     brought across — so the nav simply vanished and there was no way off
     the page you landed on. A newspaper solves this the obvious way: the
     section heads run in a bar directly beneath the masthead, which is
     what the five destinations become here. Five short labels fit one row
     at phone widths, so nothing scrolls and nothing hides behind a menu. */
  @media (max-width: 700px) {
    .site-nav {
      display: flex;
      flex: 1 0 100%;
      gap: 0;
      margin-top: 2px;
      border-top: 1px solid var(--border);
      padding-top: 2px;
    }
    /* Equal columns: the bar reads as a ruled index, and the tap target of
       each section is the same size regardless of how long its name is. */
    .site-nav a {
      flex: 1 1 0;
      min-width: 0;
      text-align: center;
      font-size: 10px;
      letter-spacing: 0.1em;
      padding: 9px 2px 8px;
      /* A label that outgrows its column clips instead of widening the bar —
         a masthead that pushes the page sideways is the worse failure. */
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    /* The underscore runs the full column on a phone — inset ends read as a
       stray dash at this size. */
    .site-nav a::after { left: 0; right: 0; }
  }
  /* Narrow phones: COLLECTION is the long one, so give back the tracking
     before it comes anywhere near clipping. */
  @media (max-width: 380px) {
    .site-nav a { font-size: 9px; letter-spacing: 0.04em; padding: 9px 1px 8px; }
  }

  /* Hamburger button — mobile only */
  .hamburger-btn {
    display: none;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    width: 34px;
    height: 34px;
    border-radius: 2px;
    font-size: 18px;
    line-height: 1;
    align-items: center;
    justify-content: center;
    transition: background var(--transition), border-color var(--transition);
  }
  .hamburger-btn:hover { border-color: var(--accent); color: var(--accent); }
  .hamburger-btn.open { border-color: var(--accent); color: var(--accent); }
  @media (max-width: 700px) {
    .hamburger-btn { display: flex; }
  }

  /* Mobile nav dropdown */
  .mobile-nav {
    display: none;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 16px;
    overflow: hidden;
    box-shadow: var(--shadow);
  }
  .mobile-nav.open { display: flex; }
  .mobile-nav a {
    font-family: var(--font-display);
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-dim);
    text-decoration: none;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
    transition: background var(--transition), color var(--transition);
  }
  .mobile-nav a:last-child { border-bottom: none; }
  .mobile-nav a:hover { background: var(--surface-2); color: var(--accent); }
  .mobile-nav a.active { color: var(--accent); }
  /* Scrim behind the mobile tray — inert until the tray opens. Clicks land on
     the document, which the existing outside-click handler treats as "close". */
  .mobile-nav-scrim { display: none; }
  @media (max-width: 700px) {
    /* Full-height tray sliding in from the right (both triggers — the topbar
       hamburger and the "More" tab — are right-aligned). Kept in the layout
       and moved with transform so open/close animates; `visibility` keeps it
       untabbable while closed. */
    .mobile-nav {
      display: flex;
      position: fixed;
      top: 0; bottom: 0;
      right: 0; left: auto;
      width: min(320px, 84vw);
      max-height: none;
      overflow-y: auto;
      overscroll-behavior: contain;
      z-index: 45;
      margin-bottom: 0;
      border: none;
      border-left: 1px solid var(--border);
      border-radius: 0;
      box-shadow: -12px 0 32px rgba(0,0,0,0.32);
      padding: calc(12px + env(safe-area-inset-top, 0px)) 0
               calc(16px + env(safe-area-inset-bottom, 0px));
      visibility: hidden;
      transform: translateX(100%);
      transition: transform 260ms cubic-bezier(0.32, 0.72, 0, 1),
                  visibility 260ms;
    }
    .mobile-nav.open { visibility: visible; transform: translateX(0); }

    .mobile-nav-scrim {
      display: block;
      position: fixed;
      inset: 0;
      z-index: 44;
      background: rgba(0, 0, 0, 0.5);
      opacity: 0;
      visibility: hidden;
      transition: opacity 260ms ease, visibility 260ms;
    }
    #mobileNav.open + .mobile-nav-scrim { opacity: 1; visibility: visible; }
    #mobileNav.hidden + .mobile-nav-scrim { display: none; }
  }
  @media (max-width: 700px) and (prefers-reduced-motion: reduce) {
    .mobile-nav, .mobile-nav-scrim { transition: none; }
  }

  /* Mobile bottom tab bar — persistent core actions (Home/Review/Board/Play),
     plus a More tab that opens .mobile-nav for everything else. Hidden on
     tablet/desktop (the sidebar/site-nav cover those) and while signed out. */
  .bottom-tabs {
    display: none;
  }
  @media (max-width: 700px) {
    .bottom-tabs {
      position: fixed;
      left: 0; right: 0; bottom: 0;
      z-index: 30;
      justify-content: space-around;
      align-items: stretch;
      background: var(--surface);
      border-top: 1px solid var(--border);
      padding-bottom: env(safe-area-inset-bottom, 0px);
      box-shadow: 0 -4px 16px rgba(0,0,0,0.18);
    }
    body.sidenav-on .bottom-tabs:not(.hidden) { display: flex; }
  }
  .bottom-tabs a {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 8px 4px 6px;
    font-family: var(--font-body);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text-dim);
    text-decoration: none;
    transition: color var(--transition);
  }
  .bottom-tabs a.active, .bottom-tabs a:hover { color: var(--accent); text-decoration: none; }
  /* "More" tracks the drawer's open state via sibling selector — robust to
     whichever code path (hamburger, outside-click, a link inside) toggled it */
  #mobileNav.open ~ .bottom-tabs #bottomTabsMore { color: var(--accent); }
  .bt-ic { font-size: 18px; line-height: 1; }

  /* ============================================================
     APP WRAPPER (sits above board pattern)
     ============================================================ */
  .app { position: relative; z-index: 1; }

/* ============================================================
   MULTI-GAME REVIEW
   ============================================================ */
.review-page { max-width: 980px; margin: 0 auto; padding: 24px 20px; }
.review-header { margin-bottom: 20px; }
.review-title { margin: 0 0 4px; font-size: 26px; }
.review-sub { margin: 0; color: var(--text-dim); font-size: 14px; }

/* ---- Form shell: two-panel layout ---- */
.review-form-shell {
  display: grid;
  grid-template-columns: 220px 1fr;
  border: 1px solid var(--border);
  border-radius: 2px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
}
@media (max-width: 680px) {
  .review-form-shell { grid-template-columns: 1fr; }
  .review-form-aside { display: none; }
}

/* Left decorative aside */
.review-form-aside {
  background: linear-gradient(175deg, var(--accent-muted) 0%, var(--surface) 100%);
  border-right: 1px solid var(--border);
  padding: 28px 20px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  position: relative;
  overflow: hidden;
}
.review-form-aside::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--border) 1px, transparent 1px),
    linear-gradient(90deg, var(--border) 1px, transparent 1px);
  background-size: 28px 28px;
  opacity: 0.35;
  pointer-events: none;
}
.review-form-aside-icon {
  width: 44px; height: 44px;
  background: var(--accent-muted);
  border: 1px solid var(--accent);
  border-radius: 2px;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  position: relative; z-index: 1;
  box-shadow: 0 0 16px var(--accent-glow);
}
.review-form-aside-heading {
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--text);
  margin: 0 0 4px;
  position: relative; z-index: 1;
}
.review-form-aside-body {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.6;
  margin: 0;
  position: relative; z-index: 1;
}
.review-form-aside-pills {
  display: flex;
  flex-direction: column;
  gap: 7px;
  position: relative; z-index: 1;
}
.review-form-aside-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-dim);
}
.review-form-aside-pill-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
  box-shadow: 0 0 6px var(--accent-glow);
}

/* Right form body */
.review-form-body {
  padding: 28px 28px 22px;
  display: grid;
  gap: 18px;
}

/* Platform toggle cards */
.review-platform-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.review-platform-card {
  position: relative;
  cursor: pointer;
}
.review-platform-card input[type="radio"] {
  position: absolute; opacity: 0; width: 0; height: 0;
}
.review-platform-card-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: transparent;
  transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
  font-size: 13px;
  color: var(--text-dim);
}
.review-platform-card-inner .rv-platform-logo {
  width: 20px; height: 20px; object-fit: contain; opacity: 0.6;
  transition: opacity var(--transition);
  flex-shrink: 0;
}
.review-platform-card input:checked + .review-platform-card-inner {
  border-color: var(--accent);
  background: var(--accent-muted);
  color: var(--text);
  box-shadow: 0 0 0 1px var(--accent), 0 0 10px var(--accent-glow);
}
.review-platform-card input:checked + .review-platform-card-inner .rv-platform-logo {
  opacity: 1;
}
.review-platform-card:hover .review-platform-card-inner {
  border-color: rgba(201,146,42,0.45);
  color: var(--text);
}

/* Field rows */
.review-form-row {
  display: grid;
  grid-template-columns: 140px 1fr;
  align-items: center;
  gap: 12px;
}
@media (max-width: 680px) {
  .review-form-body { padding: 20px 16px 18px; }
  .review-form-row {
    grid-template-columns: 1fr;
    gap: 6px;
  }
}
.review-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.review-input, .review-select {
  width: 100%; max-width: 100%; padding: 9px 11px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 2px;
  font-size: 14px;
  font-family: var(--font-body);
  transition: border-color var(--transition), box-shadow var(--transition);
  appearance: none;
  -webkit-appearance: none;
}
.review-input:focus, .review-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
.review-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23a09890' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  padding-right: 30px;
}

/* Checkbox toggle */
.review-toggle-wrap {
  display: flex; align-items: center; gap: 10px;
}
.review-checkbox-toggle {
  position: relative; display: inline-block;
  width: 36px; height: 20px; flex-shrink: 0; cursor: pointer;
}
.review-checkbox-toggle input { opacity: 0; width: 0; height: 0; }
.review-checkbox-toggle-track {
  position: absolute; inset: 0;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  transition: background var(--transition), border-color var(--transition);
}
.review-checkbox-toggle-thumb {
  position: absolute; left: 3px; top: 3px;
  width: 12px; height: 12px;
  background: var(--text-dim);
  border-radius: 50%;
  transition: transform var(--transition), background var(--transition);
}
.review-checkbox-toggle input:checked ~ .review-checkbox-toggle-track {
  background: var(--accent-muted);
  border-color: var(--accent);
}
.review-checkbox-toggle input:checked ~ .review-checkbox-toggle-thumb {
  transform: translateX(16px);
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-glow);
}
.review-toggle-label {
  font-size: 13px;
  color: var(--text-dim);
}

/* Actions */
.review-form-actions { display: flex; gap: 10px; margin-top: 4px; }
.review-error { color: #ff7676; font-size: 13px; }
.review-foot-note {
  font-size: 11px;
  color: var(--text-dim);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}
.review-foot-note::before {
  content: '';
  display: inline-block;
  width: 14px; height: 1px;
  background: var(--border);
  flex-shrink: 0;
}

/* Legacy .review-form-card kept for graceful fallback */
.review-form-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px; padding: 20px;
  display: grid; gap: 14px;
}
.review-platform-row { display: flex; gap: 16px; align-items: center; color: var(--text-dim); font-size: 14px; }
.review-platform-row label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }

.review-progress { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 60px 20px; }
.review-progress-text { font-size: 16px; font-weight: 600; }
.review-progress-sub { font-size: 13px; color: var(--text-dim); }
.review-progress-bar { width: 100%; max-width: 420px; height: 6px; background: rgba(255,255,255,0.06); border-radius: 3px; overflow: hidden; }
.review-progress-bar .fill { height: 100%; background: var(--accent, #4caf50); transition: width 0.2s ease; }

.review-results-header {
  display: flex; gap: 16px; align-items: flex-start;
  margin-bottom: 24px;
}

.review-section { margin-bottom: 28px; }
.review-section-title { margin: 0 0 6px; font-size: 18px; }
.review-section-sub { margin: 0 0 12px; font-size: 13px; color: var(--text-dim); }
.review-empty-line { font-size: 13px; color: var(--text-dim); font-style: italic; }

.review-theme-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.review-theme-table th, .review-theme-table td {
  text-align: left; padding: 8px 10px; border-bottom: 1px solid rgba(255,255,255,0.06);
}
.review-theme-table th { font-weight: 600; color: var(--text-dim); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.review-theme-num { font-variant-numeric: tabular-nums; }
.review-theme-pct { color: var(--text-dim); font-size: 12px; }
.review-theme-bias { font-size: 13px; }
.review-bias-up   { color: #6fcf97; font-weight: 600; }
.review-bias-down { color: #f2994a; font-weight: 600; }

/* Results header stat strip (multi-game) */
.rv-stat-strip { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.rv-stat-pill {
  font-size: 12px; padding: 3px 10px; border-radius: 2px;
  background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1);
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}
.rv-stat-pill--win  { color: #6fcf97; }
.rv-stat-pill--draw { color: #a9c4d6; }
.rv-stat-pill--loss { color: #eb5757; }

/* Collapsible data sections (multi-game) */
.review-details summary {
  cursor: pointer; font-size: 13px; color: var(--text-dim);
  padding: 8px 0; user-select: none;
}
.review-details summary:hover { color: var(--text, #fff); }
.review-details[open] summary { margin-bottom: 8px; }

/* Conversion legend */
.rv-conv-legend {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  margin-top: 10px; font-size: 12px; color: var(--text-dim);
}
.rv-conv-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.rv-conv-legend-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }

/* Opening highlights + table */
.rv-open-highlights {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin: 14px 0;
}
.rv-open-hl-card {
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; padding: 10px 14px;
}
.rv-open-hl-kind {
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-dim); margin-bottom: 4px;
}
.rv-open-hl-kind--best  { color: #6fcf97; }
.rv-open-hl-kind--worst { color: #f2994a; }
.rv-open-hl-name { font-weight: 600; font-size: 13px; margin-bottom: 3px; }
.rv-open-hl-stats { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

.rv-open-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.rv-open-table th, .rv-open-table td {
  text-align: left; padding: 7px 10px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.rv-open-table th { font-weight: 600; color: var(--text-dim); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.rv-open-row { cursor: pointer; }
.rv-open-row:hover td { background: rgba(255,255,255,0.02); }
.rv-open-caret { display: inline-block; transition: transform 0.15s; font-size: 11px; color: var(--text-dim); }
.rv-open-row--open .rv-open-caret { transform: rotate(90deg); }
.rv-open-eco { color: var(--text-dim); font-size: 11px; margin-left: 8px; }
.rv-open-num { font-variant-numeric: tabular-nums; }
.rv-open-drill td { background: rgba(255,255,255,0.015); }
.rv-show-more { margin-top: 12px; }

/* Coach-lens chip (theme explorer) */
.rv-bias-chip { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.rv-bias-chip--up   { color: #6fcf97; }
.rv-bias-chip--down { color: #f2994a; }

/* Style profile (multi-game) */
.rv-profile-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.rv-profile-col { display: flex; flex-direction: column; gap: 8px; }
.rv-profile-col-title {
  font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  text-wrap: balance;
}
.rv-profile-col-title--strong { color: #6fcf97; }
.rv-profile-col-title--weak   { color: #f2994a; }
.rv-profile-card {
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; padding: 10px 14px;
}
.rv-profile-card-label { font-weight: 600; font-size: 13px; margin-bottom: 3px; }
.rv-profile-card-text { font-size: 13px; color: var(--text-dim); line-height: 1.45; }
.rv-profile-actions {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid rgba(255,255,255,0.07);
}
.rv-profile-reco { font-size: 13px; color: var(--text-dim); }
.rv-profile-actions-note { font-size: 12px; color: var(--text-dim); font-style: italic; }

/* "Since your training plan" check-in — re-measured focus areas */
.rv-checkin {
  margin-top: 14px; padding: 12px 14px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px;
}
.rv-checkin-title { font-weight: 700; font-size: 14px; margin-bottom: 2px; }
.rv-checkin-sub { font-size: 12px; color: var(--text-dim); margin-bottom: 10px; }
.rv-checkin-row {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 6px 0;
  border-top: 1px solid rgba(255,255,255,0.05);
}
.rv-checkin-label { font-weight: 600; font-size: 13px; min-width: 120px; }
.rv-checkin-vals { font-size: 13px; font-variant-numeric: tabular-nums; }
.rv-checkin-delta { font-size: 13px; font-weight: 700; white-space: nowrap; }
.rv-checkin-delta--up   { color: #6fcf97; }
.rv-checkin-delta--down { color: #eb5757; }
.rv-checkin-delta--flat { color: var(--text-dim); }
.rv-checkin-note { font-size: 12px; color: var(--text-dim); }

/* Training plan — deck list + drill view */
/* ---- Imbalances reference page ---- */
.imbr-page { max-width: 1040px; margin: 0 auto; padding: 24px 16px 48px; }
.imbr-header { margin-bottom: 22px; max-width: 680px; }
.imbr-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  margin-bottom: 24px;
}
.imbr-card {
  display: flex; flex-direction: column; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px; padding: 18px 18px 16px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.imbr-card:hover { border-color: var(--accent); box-shadow: var(--shadow-glow); }
.imbr-card-head { display: flex; align-items: flex-start; gap: 12px; }
.imbr-icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  font-size: 22px; line-height: 1;
  color: var(--accent);
  background: var(--accent-muted);
  border-radius: 2px;
}
.imbr-card-title { margin: 0; font-size: 18px; }
.imbr-tagline { margin: 2px 0 0; font-size: 13px; color: var(--text-dim); }
.imbr-body { margin: 0; font-size: 14px; line-height: 1.55; }
.imbr-meta {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.imbr-meta-row { display: flex; flex-direction: column; gap: 2px; }
.imbr-meta-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--accent); font-weight: 600;
}
.imbr-meta-val { font-size: 13px; line-height: 1.5; color: var(--text-dim); }
.imbr-actions { display: flex; }

.trn-page { max-width: 1040px; margin: 0 auto; padding: 24px 16px 48px; }
.trn-header { margin-bottom: 18px; }
.trn-deck-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  margin-bottom: 18px;
}
.trn-deck-card {
  display: flex; flex-direction: column; gap: 8px; text-align: left;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; padding: 14px 16px;
  cursor: pointer; color: inherit; font: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.trn-deck-card:hover { border-color: rgba(212,160,69,0.5); background: rgba(255,255,255,0.05); }
.trn-deck-title { font-weight: 700; font-size: 15px; }
.trn-deck-desc { font-size: 13px; color: var(--text-dim); line-height: 1.45; }
.trn-deck-progress { display: flex; align-items: center; gap: 10px; margin-top: auto; }
.trn-deck-bar {
  flex: 1; height: 6px; border-radius: 3px;
  background: rgba(255,255,255,0.08); overflow: hidden;
}
.trn-deck-fill { height: 100%; background: var(--accent, #b21c22); border-radius: 3px; }
.trn-deck-stats { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.trn-deck-cta { font-size: 13px; font-weight: 600; color: var(--accent, #b21c22); }
.trn-list-actions { display: flex; gap: 10px; }
.trn-danger { color: #eb5757; }

.trn-roundbar { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
.trn-roundbar-title { font-weight: 700; font-size: 15px; }
.trn-roundbar-game { font-size: 12px; color: var(--text-dim); }

.trn-quiz {
  display: grid; gap: 24px;
  grid-template-columns: minmax(280px, 480px) minmax(280px, 1fr);
  align-items: start;
}
@media (max-width: 760px) { .trn-quiz { grid-template-columns: 1fr; } }
.trn-board-caption { margin-top: 8px; font-size: 13px; color: var(--text-dim); text-align: center; }

.trn-reveal-actions { display: flex; gap: 10px; margin-top: 14px; align-items: center; }

/* Coach handoff after the drill reveal — "now let's play it out" */
.trn-handoff { display: flex; gap: 12px; align-items: flex-start; margin-top: 18px; }
.trn-handoff-avatar {
  flex-shrink: 0; width: 48px; height: 48px;
  border-radius: 50%; overflow: hidden;
  border: 2px solid var(--accent, #b21c22);
  background: rgba(255,255,255,0.05);
  display: flex; align-items: center; justify-content: center;
}
.trn-handoff-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.trn-handoff-icon { font-size: 24px; line-height: 1; }
.trn-handoff-bubble {
  position: relative; flex: 1;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 2px; padding: 12px 14px;
  font-size: 13px; line-height: 1.5;
}
.trn-handoff-name { font-weight: 700; font-size: 12px; color: var(--accent, #b21c22); margin-bottom: 4px; }
.trn-handoff-text { color: var(--text, inherit); }
.trn-handoff-actions { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; align-items: center; }

.review-patterns-grid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.review-pattern-card {
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; padding: 12px 14px;
}
.review-pattern-title { font-weight: 600; font-size: 14px; margin-bottom: 4px; }
.review-pattern-detail { font-size: 13px; color: var(--text-dim); }

.review-games-list { display: grid; gap: 6px; }
.review-game-row {
  display: grid; grid-template-columns: auto 1fr 2fr auto; gap: 12px;
  align-items: center; padding: 8px 10px;
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 2px; font-size: 13px;
}
.review-game-meta { display: flex; gap: 10px; align-items: center; }
.review-game-result {
  font-weight: 700; text-transform: uppercase; font-size: 11px;
  padding: 2px 6px; border-radius: 2px;
}
.review-game-result--win  { background: rgba(111, 207, 151, 0.15); color: #6fcf97; }
.review-game-result--loss { background: rgba(235, 87, 87, 0.15); color: #eb5757; }
.review-game-result--draw { background: rgba(255,255,255,0.06); color: var(--text-dim); }
.review-game-vs { color: var(--text-dim); }
.review-game-eco {
  color: var(--text-dim); font-size: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.review-game-plan {
  color: var(--text-dim); font-size: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.review-game-link { color: var(--accent, #4caf50); text-decoration: none; font-size: 16px; }
.review-game-open-review {
  background: rgba(212, 160, 69, 0.10);
  border: 1px solid rgba(212, 160, 69, 0.35);
  color: var(--accent, #b21c22);
  font-size: 11px; font-weight: 600;
  padding: 3px 8px; border-radius: 2px;
  cursor: pointer; white-space: nowrap;
  transition: background 0.1s, border-color 0.1s;
}
.review-game-open-review:hover {
  background: rgba(212, 160, 69, 0.18);
  border-color: rgba(212, 160, 69, 0.55);
}

/* ============================================================
   Game-Review Handoff Overlay
   Shown when the page is opened via ?gameReview=<id> from multi-game
   analysis. The pre-paint script in <head> adds .gr-handoff-pending to
   <html> before first paint so the landing view never flashes.
   ============================================================ */
.gr-handoff {
  display: none;
}
html.gr-handoff-pending {
  background: #0b0d10;
}
html.gr-handoff-pending body {
  background: #0b0d10;
  overflow: hidden;
}
/* Hide the entire app shell while handoff is in flight. Opacity (not
   visibility/display) so layout still computes — board libs measure their
   container during setup. */
html.gr-handoff-pending .app,
html.gr-handoff-pending .board-pattern {
  opacity: 0 !important;
  pointer-events: none !important;
  transition: opacity 320ms ease-out !important;
}
/* On the way out we let .app fade IN smoothly while the overlay fades OUT,
   cross-fading rather than snapping. */
html.gr-handoff-pending.gr-handoff-leaving .app,
html.gr-handoff-pending.gr-handoff-leaving .board-pattern {
  opacity: 1 !important;
}
/* Hard guard: while the handoff is in flight (including the leave fade), any
   non-plan view stays display:none even if JS hasn't toggled .hidden on it.
   Prevents a flash of view-home should some code path render into it. */
html.gr-handoff-pending #view-home,
html.gr-handoff-pending #view-onboard,
html.gr-handoff-pending #view-dashboard,
html.gr-handoff-pending #view-saved,
html.gr-handoff-pending #view-loading,
html.gr-handoff-pending #view-review,
html.gr-handoff-pending #view-coaches,
html.gr-handoff-pending #view-coach-builder,
html.gr-handoff-pending #view-play,
html.gr-handoff-pending #view-evaluation-trainer,
html.gr-handoff-pending #view-openings,
html.gr-handoff-pending #view-game-review {
  display: none !important;
}
html.gr-handoff-pending .gr-handoff {
  display: flex;
  position: fixed; inset: 0;
  z-index: 99999;
  align-items: center; justify-content: center;
  background:
    radial-gradient(ellipse at 50% 35%, rgba(212, 160, 69, 0.10), transparent 60%),
    radial-gradient(ellipse at 50% 85%, rgba(40, 60, 90, 0.18), transparent 70%),
    #0b0d10;
  color: #e8e2d2;
  animation: grHandoffFadeIn 220ms ease-out both;
}
html.gr-handoff-pending.gr-handoff-leaving .gr-handoff {
  animation: grHandoffFadeOut 260ms ease-in both;
  pointer-events: none;
}

.gr-handoff-inner {
  position: relative;
  display: flex; flex-direction: column;
  align-items: center; gap: 22px;
  text-align: center;
  padding: 32px 40px;
}

.gr-handoff-board {
  width: 88px; height: 88px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  gap: 2px;
  padding: 4px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(178, 28, 34, 0.28);
  border-radius: 2px;
  box-shadow:
    0 0 0 1px rgba(0,0,0,0.4),
    0 12px 40px -8px rgba(0,0,0,0.6),
    0 0 60px -10px rgba(178, 28, 34, 0.24);
}
.gr-handoff-board span {
  background: rgba(178, 28, 34, 0.08);
  border-radius: 1px;
  animation: grSquarePulse 1.8s ease-in-out infinite;
}
/* Wave pattern: stagger each square's pulse based on its diagonal position. */
.gr-handoff-board span:nth-child(1)  { animation-delay: 0.00s; }
.gr-handoff-board span:nth-child(2)  { animation-delay: 0.06s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(3)  { animation-delay: 0.12s; }
.gr-handoff-board span:nth-child(4)  { animation-delay: 0.18s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(5)  { animation-delay: 0.06s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(6)  { animation-delay: 0.12s; }
.gr-handoff-board span:nth-child(7)  { animation-delay: 0.18s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(8)  { animation-delay: 0.24s; }
.gr-handoff-board span:nth-child(9)  { animation-delay: 0.12s; }
.gr-handoff-board span:nth-child(10) { animation-delay: 0.18s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(11) { animation-delay: 0.24s; }
.gr-handoff-board span:nth-child(12) { animation-delay: 0.30s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(13) { animation-delay: 0.18s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(14) { animation-delay: 0.24s; }
.gr-handoff-board span:nth-child(15) { animation-delay: 0.30s; background: rgba(178, 28, 34, 0.16); }
.gr-handoff-board span:nth-child(16) { animation-delay: 0.36s; }

.gr-handoff-mark {
  font-family: var(--font-black);
  font-weight: 700;
  letter-spacing: 0.28em;
  font-size: 13px;
  color: var(--accent, #b21c22);
  text-transform: uppercase;
}

.gr-handoff-label {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.01em;
  color: #f5f3ee;
}

.gr-handoff-sub {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(245, 243, 238, 0.5);
  margin-top: -10px;
}
.gr-handoff-sub::after {
  content: "...";
  display: inline-block;
  width: 3ch;
  margin-left: 2px;
  overflow: hidden;
  vertical-align: bottom;
  animation: grHandoffDots 1.4s steps(4, end) infinite;
}

@keyframes grHandoffFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes grHandoffFadeOut {
  from { opacity: 1; }
  to   { opacity: 0; visibility: hidden; }
}
@keyframes grSquarePulse {
  0%, 100% { background-color: rgba(178, 28, 34, 0.06); }
  50%      { background-color: rgba(178, 28, 34, 0.4); }
}
@keyframes grHandoffDots {
  0%   { width: 0ch; }
  100% { width: 3ch; }
}

@media (prefers-reduced-motion: reduce) {
  .gr-handoff-board span { animation: none; }
  .gr-handoff-sub::after { animation: none; content: "…"; }
  .gr-handoff, .gr-handoff-leaving .gr-handoff { animation-duration: 1ms; }
}

/* ============================================================
   Auth splash — reuses the handoff overlay chrome (the pre-paint script
   adds .gr-handoff-pending + .auth-splash when a prior session is expected)
   but swaps the copy to "Signing you in".
   ============================================================ */
.gh-when-auth { display: none; }
html.auth-splash .gh-when-auth { display: inline; }
html.auth-splash .gh-when-review { display: none; }
/* Cinematic pawn backdrop, swapped in only for the auth splash (the
   game-review handoff above keeps its plain gold-glow background). A
   vignette sits between the photo and the text so the copy stays legible
   regardless of what's under it at that point in the image. */
html.auth-splash .gr-handoff {
  /* The source photo is a tall portrait crop. `cover` on a wide/landscape
     viewport would scale it up to fill the width, blowing the pawn's face up
     to the point it collides with the text. `contain` keeps it at its native
     framing on any aspect ratio — letterboxed in near-black on wide screens,
     near full-bleed on tall ones — with background-color filling the bars. */
  background-color: #0b0d10;
  background-image:
    radial-gradient(ellipse 60% 42% at 50% 50%, rgba(11, 13, 16, 0.86), rgba(11, 13, 16, 0.4) 65%, transparent 100%),
    linear-gradient(180deg, rgba(11, 13, 16, 0.45) 0%, rgba(11, 13, 16, 0.15) 40%, rgba(11, 13, 16, 0.6) 100%),
    url("assets/splash-pawn.jpg");
  background-position: center, center, center 15%;
  background-size: 100% 100%, 100% 100%, contain;
  background-repeat: no-repeat, no-repeat, no-repeat;
}
/* The photo already carries the pawn/eyes motif and the loading motion via
   its own glow — the small pulsing board mark would just double up on top
   of it (and lands right over the pawn's face), so drop it here. */
html.auth-splash .gr-handoff-board { display: none; }
/* Unlike the game-review handoff, the splash's destination view — the
   Explorer, guest-rendered underneath the splash the moment boot() calls
   launchOpenings(), before auth even resolves — must be allowed to render
   so the leave fade cross-fades onto it, not onto a blank app. */
html.auth-splash.gr-handoff-pending #view-home:not(.hidden),
html.auth-splash.gr-handoff-pending #view-openings:not(.hidden) {
  display: block !important;
}

.review-skipped summary { cursor: pointer; font-size: 13px; color: var(--text-dim); }
.review-skipped ul { font-size: 12px; color: var(--text-dim); margin: 6px 0 0 18px; padding: 0; }

/* Theme drill-down: clickable rows + W/D/L outcome chips */
.review-theme-row[data-key] { cursor: pointer; }
.review-theme-row[data-key]:hover { background: rgba(255,255,255,0.03); }
.review-theme-row--open { background: rgba(255,255,255,0.04); }
.review-theme-caret {
  display: inline-block; width: 14px; color: var(--text-dim);
  font-size: 10px; margin-right: 2px;
}
.review-theme-row--open .review-theme-caret { color: var(--accent, #b21c22); }

.review-wdl-cell { white-space: nowrap; }
.review-wdl-sep { color: var(--text-dim); margin: 0 1px; }
.review-wdl-chip {
  display: inline-block;
  min-width: 22px; padding: 1px 6px;
  border: 1px solid transparent;
  border-radius: 2px;
  text-align: center;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background 0.1s, border-color 0.1s;
}
.review-wdl-chip:hover { border-color: rgba(255,255,255,0.20); }
.review-wdl-chip--win    { color: #6fcf97; }
.review-wdl-chip--draw   { color: var(--text-dim); }
.review-wdl-chip--loss   { color: #f2994a; }
.review-wdl-chip--dim    { opacity: 0.35; cursor: default; }
.review-wdl-chip--dim:hover { border-color: transparent; }
.review-wdl-chip--active {
  background: rgba(255,255,255,0.10);
  border-color: rgba(255,255,255,0.25);
  font-weight: 700;
}

.review-theme-drill-row > td {
  background: rgba(255,255,255,0.02);
  padding: 10px 14px 14px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.review-drill-header {
  font-size: 12px; color: var(--text-dim);
  margin-bottom: 8px;
}
.review-drill-clear {
  background: transparent; border: 1px solid rgba(255,255,255,0.18);
  color: var(--text-dim); font-size: 11px;
  border-radius: 2px; padding: 1px 6px; margin-left: 6px;
  cursor: pointer;
}
.review-drill-clear:hover { color: var(--text, #fff); border-color: rgba(255,255,255,0.30); }
.review-games-list--nested { gap: 4px; }
.review-games-list--nested .review-game-row {
  background: rgba(255,255,255,0.02);
}

/* New players line — White vs Black with a 'you' highlight */
.review-game-row {
  display: grid;
  grid-template-columns: auto minmax(0, 2fr) auto minmax(0, 1.1fr) minmax(0, 1.4fr) auto auto auto;
  gap: 12px;
}
.review-game-mg {
  font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.review-game-players {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; min-width: 0;
}
.review-game-side {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.review-game-side--you { color: var(--text, #fff); font-weight: 600; }
.review-game-vs-sep { color: var(--text-dim); font-size: 11px; }
.review-game-color-dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.30);
}
.review-game-color-dot--w { background: #f4f4f4; }
.review-game-color-dot--b { background: #1d1d1d; }

/* Theme table view controls (Top-3 ↔ Convert-rate toggle + sort) */
.review-theme-controls {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  margin: 6px 0 12px;
}
.review-toggle {
  display: inline-flex;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 2px; padding: 2px;
}
.review-toggle-btn {
  background: transparent; color: var(--text-dim);
  border: none; cursor: pointer;
  padding: 6px 12px; font-size: 13px; border-radius: 2px;
}
.review-toggle-btn.active {
  background: rgba(255,255,255,0.10);
  color: var(--text, #fff);
  font-weight: 600;
}
.review-sort-label { font-size: 13px; color: var(--text-dim); display: inline-flex; align-items: center; gap: 6px; }
.review-sort-select {
  background: rgba(255,255,255,0.04);
  color: var(--text, #fff);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 2px;
  padding: 4px 8px; font-size: 13px;
}

/* Opening Repertoire section */
.review-family-grid { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.review-family-row {
  display: grid; grid-template-columns: 220px 1fr auto; gap: 12px;
  align-items: center; font-size: 13px;
}
.review-family-label { color: var(--text-dim); }
.review-family-bar {
  height: 8px; background: rgba(255,255,255,0.05); border-radius: 2px; overflow: hidden;
}
.review-family-fill { height: 100%; background: var(--accent, #b21c22); }
.review-family-stats { display: inline-flex; gap: 10px; font-variant-numeric: tabular-nums; }
.review-family-count { color: var(--text-dim); }
.review-family-wr { font-weight: 600; }

.review-opening-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.review-opening-card {
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; padding: 14px;
}
.review-opening-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 6px; }
.review-opening-title { font-size: 15px; font-weight: 600; }
.review-opening-color { color: var(--text-dim); font-weight: 400; font-size: 13px; }
.review-opening-eco { font-size: 11px; color: var(--text-dim); letter-spacing: 0.06em; }
.review-opening-stats { display: flex; flex-wrap: wrap; gap: 10px 14px; font-size: 13px; margin-bottom: 10px; font-variant-numeric: tabular-nums; }
.review-opening-stat { color: var(--text-dim); }
.review-opening-stat.review-bias-up,
.review-opening-stat.review-bias-down { color: inherit; }
.review-opening-delta { color: var(--text-dim); font-weight: 400; }
.review-opening-themes-label { font-size: 12px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 4px; }
.review-opening-themes { margin: 0; padding-left: 18px; font-size: 13px; }
.review-opening-themes li { margin: 2px 0; }
.review-opening-theme-meta { color: var(--text-dim); font-size: 12px; }
.review-opening-theme-empty { color: var(--text-dim); font-style: italic; list-style: none; margin-left: -18px; }

/* Imbalance Conversion section */
.review-conv-headline {
  display: inline-flex; align-items: center; gap: 10px;
  background: rgba(212, 160, 69, 0.08);
  border: 1px solid rgba(212, 160, 69, 0.25);
  border-radius: 2px; padding: 8px 12px;
  margin-bottom: 12px; font-size: 13px;
}
.review-conv-headline-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent, #b21c22);
}
.review-conv-grid { display: flex; flex-direction: column; gap: 8px; }
.review-conv-row {
  display: grid; grid-template-columns: 160px 1fr 180px;
  gap: 12px; align-items: center; font-size: 13px;
}
.review-conv-row-label { color: var(--text, #fff); font-weight: 500; }
.review-conv-row-stats {
  color: var(--text-dim); font-size: 12px;
  font-variant-numeric: tabular-nums; text-align: right;
}
.review-conv-bar {
  display: flex; height: 22px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 2px; overflow: hidden;
}
.review-conv-seg {
  border: none; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  color: rgba(0,0,0,0.75); font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: filter 0.1s, outline 0.1s;
  min-width: 0;
}
.review-conv-seg:hover { filter: brightness(1.15); }
.review-conv-seg--active { outline: 2px solid rgba(255,255,255,0.85); outline-offset: -2px; }
.review-conv-seg-count { padding: 0 2px; }
.review-conv-seg--converted          { background: #6fcf97; }
.review-conv-seg--drew               { background: #a9c4d6; }
.review-conv-seg--lost               { background: #eb5757; color: rgba(255,255,255,0.92); }
.review-conv-seg--won_despite_losing { background: #d6c44a; }
.review-conv-seg--traded             { background: #b78ad6; color: rgba(255,255,255,0.92); }
.review-conv-seg--dissipated         { background: #f2994a; }
.review-conv-seg--flickered          { background: rgba(255,255,255,0.22); color: rgba(255,255,255,0.85); }
.review-conv-seg--never_held         { background: rgba(255,255,255,0.08); color: var(--text-dim); }

.review-conv-drill {
  margin-top: 12px;
}
.review-conv-drill:empty { display: none; }
.review-conv-drill .review-drill-header { margin-bottom: 8px; }

/* Inline track strip on per-game rows */
.review-game-row { position: relative; }
.rv-track-strip {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed rgba(255,255,255,0.08);
}
/* Full strip stays hidden until the row's "tracks" toggle opens it. */
.rv-track-strip--collapsible { display: none; }
.review-game-row--open .rv-track-strip--collapsible { display: flex; }
/* Single-imbalance strip (conversion drill-down): no verdict column. */
.rv-track-strip--single .rv-track-row { grid-template-columns: 120px 1fr; }
.review-game-tracks-toggle {
  background: transparent;
  border: 1px solid rgba(255,255,255,0.14);
  color: var(--text-dim);
  font-size: 11px; padding: 3px 8px; border-radius: 2px;
  cursor: pointer; white-space: nowrap;
  transition: color 0.1s, border-color 0.1s;
}
.review-game-tracks-toggle:hover { color: var(--text, #fff); border-color: rgba(255,255,255,0.30); }
.review-game-row--open .review-game-tracks-toggle { color: var(--text, #fff); }
.rv-track-row {
  display: grid; grid-template-columns: 120px 1fr 160px;
  gap: 10px; align-items: center; font-size: 12px;
}
.rv-track-label { color: var(--text-dim); }
.rv-track-cells {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 1px; line-height: 1;
}
.rv-track-cell { display: inline-block; width: 10px; text-align: center; }
.rv-track-cell--strong  { color: #6fcf97; }
.rv-track-cell--neutral { color: var(--text-dim); }
.rv-track-cell--weak    { color: #eb5757; }
.rv-track-verdict {
  font-size: 11px; color: var(--text-dim);
  text-align: right;
}
.rv-track-verdict--converted          { color: #6fcf97; }
.rv-track-verdict--lost               { color: #eb5757; }
.rv-track-verdict--traded             { color: #b78ad6; }
.rv-track-verdict--dissipated         { color: #f2994a; }
.rv-track-verdict--won_despite_losing { color: #d6c44a; }

@media (max-width: 720px) {
  .review-conv-row { grid-template-columns: 1fr; gap: 4px; }
  .review-conv-row-stats { text-align: left; }
  .rv-track-row { grid-template-columns: 100px 1fr; }
  .rv-track-verdict { display: none; }
}

/* ==========================================================
   EVALUATION TRAINER
   ========================================================== */
.evaltrain-page {
  max-width: 1180px;
  margin: 24px auto;
  padding: 0 24px 60px;
}
.evaltrain-header { margin-bottom: 16px; }
.evaltrain-title  { font-size: 22px; font-weight: 700; margin: 0 0 4px; }
.evaltrain-sub    { color: var(--text-dim); font-size: 14px; margin: 0; }
.evaltrain-error  { color: var(--danger, #c0392b); font-size: 13px; margin-top: 8px; }

/* browse & pick */
.evaltrain-browse-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 60vh;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 8px;
  background: var(--surface);
}
.evaltrain-game-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface-2);
}
.evaltrain-game-item--picked { border-color: var(--accent); }
.evaltrain-game-meta { min-width: 0; flex: 1; }
.evaltrain-game-players { font-weight: 600; }
.evaltrain-game-sub { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
.evaltrain-game-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
.evaltrain-pick-tag {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 2px;
  padding: 3px 8px;
}

/* intro */
.evaltrain-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 20px;
  max-width: 480px;
  margin-top: 16px;
}
.evaltrain-card-label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  margin-bottom: 10px;
}
.evaltrain-platform-row { display: flex; gap: 10px; margin-bottom: 10px; }
.evaltrain-platform-btn {
  flex: 1;
  padding: 10px 14px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 2px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.evaltrain-platform-btn:hover { background: rgba(255,255,255,0.08); }
.evaltrain-platform-btn--active {
  background: rgba(76,175,80,0.15);
  border-color: var(--accent, #4caf50);
  color: var(--accent, #4caf50);
}
.evaltrain-username-input {
  width: 100%;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--text);
  font-size: 14px;
  box-sizing: border-box;
}
.evaltrain-username-input:focus {
  outline: none;
  border-color: var(--accent, #4caf50);
}

.evaltrain-size-row { display: flex; gap: 10px; margin-bottom: 18px; }
.evaltrain-size-btn {
  flex: 1;
  padding: 12px 16px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 2px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  transition: background 0.15s, border-color 0.15s;
}
.evaltrain-size-btn:hover { background: rgba(255,255,255,0.08); }
.evaltrain-size-btn--active {
  background: rgba(76,175,80,0.15);
  border-color: var(--accent, #4caf50);
  color: var(--accent, #4caf50);
}
.evaltrain-start-btn { width: 100%; margin-bottom: 8px; }
.evaltrain-back-btn  { width: 100%; }

/* round bar */
.evaltrain-roundbar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
  flex-wrap: wrap;
  gap: 8px;
}
.evaltrain-roundbar-title { font-size: 16px; font-weight: 700; }
.evaltrain-roundbar-game  { color: var(--text-dim); font-size: 13px; }
.evaltrain-roundbar-game a { color: var(--accent, #4caf50); }

/* quiz layout */
.evaltrain-quiz {
  display: grid;
  grid-template-columns: minmax(0, 480px) minmax(0, 1fr);
  gap: 28px;
  align-items: flex-start;
}
@media (max-width: 900px) {
  .evaltrain-quiz { grid-template-columns: 1fr; }
}
.evaltrain-board-col { display: flex; flex-direction: column; gap: 8px; }
.evaltrain-board-caption {
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.evaltrain-form-col { display: flex; flex-direction: column; gap: 20px; }

.evaltrain-form-section {
  background: var(--card-bg, #1f1f1f);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 16px;
}
.evaltrain-section-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  margin-bottom: 10px;
}

/* imbalance input cells (3-button group per side) */
/* 3-way verdict picker: [label] [you better] [equal] [opp better] */
.evaltrain-imb-row {
  grid-template-columns: 130px 1fr 1fr 1fr;
  gap: 0 8px;
  align-items: center;
}
.evaltrain-imb-row > .imb-label { grid-column: 1; text-align: left; padding-left: 4px; }
.evaltrain-imb-pick {
  height: 32px;
  border-radius: 2px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
  padding: 0 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
}
.evaltrain-imb-pick:hover { background: rgba(255,255,255,0.08); color: var(--text); }
.evaltrain-imb-pick-you   { grid-column: 2; }
.evaltrain-imb-pick-equal { grid-column: 3; }
.evaltrain-imb-pick-opp   { grid-column: 4; }
.evaltrain-imb-pick-you.evaltrain-imb-pick--active   { background: rgba(201,146,42,0.20); color: #c9922a; border-color: #c9922a; }
.evaltrain-imb-pick-opp.evaltrain-imb-pick--active   { background: rgba(192,57,43,0.20); color: #c0392b; border-color: #c0392b; }
.evaltrain-imb-pick-equal.evaltrain-imb-pick--active { background: rgba(85,85,85,0.25); color: var(--text); border-color: rgba(255,255,255,0.30); }
@media (max-width: 720px) {
  .evaltrain-imb-row { grid-template-columns: 1fr 1fr 1fr; }
  .evaltrain-imb-row > .imb-label { grid-column: 1 / -1; grid-row: 1; text-align: center; padding-left: 0; padding-bottom: 4px; }
  .evaltrain-imb-pick-you   { grid-column: 1; grid-row: 2; }
  .evaltrain-imb-pick-equal { grid-column: 2; grid-row: 2; }
  .evaltrain-imb-pick-opp   { grid-column: 3; grid-row: 2; }
}

/* eval picker */
.evaltrain-eval-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
  gap: 6px;
}
.evaltrain-eval-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10px 6px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: rgba(255,255,255,0.03);
  color: var(--text);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
  min-width: 0;
}
.evaltrain-eval-chip:hover { background: rgba(255,255,255,0.08); }
.evaltrain-eval-chip--active {
  background: rgba(76,175,80,0.15);
  border-color: var(--accent, #4caf50);
  color: var(--accent, #4caf50);
}
.evaltrain-eval-sym  { font-size: 18px; font-weight: 700; line-height: 1; }
.evaltrain-eval-desc { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; }
.evaltrain-eval-chip--active .evaltrain-eval-desc { color: var(--accent, #4caf50); }

.evaltrain-actions { display: flex; gap: 10px; }
.evaltrain-actions .btn-primary,
.evaltrain-actions .btn-secondary { flex: 1; }

/* reveal */
.evaltrain-imb-reveal-row {
  grid-template-columns: 1fr 130px 1fr;
  padding: 8px 0;
}
.evaltrain-reveal-pair {
  display: flex; flex-direction: column; gap: 3px;
  grid-row: 1;
}
.evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(1) { grid-column: 1; align-items: flex-end; }
.evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(2) { grid-column: 3; align-items: flex-start; }
.evaltrain-imb-reveal-row > .imb-label { grid-column: 2; }
.evaltrain-reveal-cap {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}
.evaltrain-reveal-pill {
  height: 26px;
  padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 2px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.evaltrain-verdict-you   { background: rgba(201,146,42,0.20); color: #c9922a; }
.evaltrain-verdict-opp   { background: rgba(192,57,43,0.20);  color: #c0392b; }
.evaltrain-verdict-equal { background: rgba(85,85,85,0.25);   color: var(--text-dim); }
@media (max-width: 720px) {
  .evaltrain-imb-reveal-row { grid-template-columns: 1fr 1fr; }
  .evaltrain-imb-reveal-row > .imb-label { grid-column: 1 / -1; grid-row: 1; text-align: center; }
  .evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(1) { grid-column: 1; grid-row: 2; align-items: center; }
  .evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(2) { grid-column: 2; grid-row: 2; align-items: center; }
  .evaltrain-imb-reveal-row > .imb-note { grid-row: 3; }
}
.evaltrain-cell-ok      { box-shadow: inset 0 0 0 2px #6fcf97; }
.evaltrain-cell-bad     { box-shadow: inset 0 0 0 2px #eb5757; opacity: 0.85; }
.evaltrain-cell-correct { outline: 1px dashed rgba(255,255,255,0.25); }
.evaltrain-note-static {
  max-height: none;
  opacity: 1;
  padding-top: 4px;
  font-size: 12px;
  color: var(--text-dim);
}

.evaltrain-eval-reveal {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 14px;
  background: rgba(255,255,255,0.02);
}
.evaltrain-eval-reveal--ok  { border-color: #6fcf97; background: rgba(111,207,151,0.06); }
.evaltrain-eval-reveal--bad { border-color: #eb5757; background: rgba(235,87,87,0.06); }
.evaltrain-eval-reveal-row {
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: 16px;
}
.evaltrain-eval-reveal-col {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  flex: 1; text-align: center;
}
.evaltrain-eval-reveal-cap  { font-size: 11px; text-transform: uppercase; color: var(--text-dim); letter-spacing: 0.06em; }
.evaltrain-eval-reveal-sym  { font-size: 32px; font-weight: 800; line-height: 1; }
.evaltrain-eval-reveal-desc { font-size: 12px; color: var(--text-dim); }
.evaltrain-eval-reveal-arrow { font-size: 22px; color: var(--text-dim); flex: 0 0 auto; }
.evaltrain-eval-reveal--ok .evaltrain-eval-reveal-arrow { color: #6fcf97; }
.evaltrain-topline {
  margin-top: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  color: var(--text);
  background: rgba(0,0,0,0.25);
  border-radius: 2px;
  padding: 8px 10px;
}
.evaltrain-topline-cap {
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  margin-right: 8px;
}

/* ============================================================
   PLAY VS COACH — "Evaluate as you play" quiz inside the side panel.
   Reuses the evaltrain-* rows but forces the narrow (stacked) layout
   regardless of viewport, since the panel is only ~280–360px wide.
   ============================================================ */
.pvc-quiz-score-chip {
  font-size: 12px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 2px;
  border: 1px solid var(--accent, #4caf50);
  background: rgba(76,175,80,0.12);
  color: var(--accent, #4caf50);
  white-space: nowrap;
}
.pvc-quiz-section-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-bottom: 8px;
}
.pvc-quiz-submit {
  width: 100%;
  margin-top: 14px;
}
/* Force the stacked imbalance picker layout (label on top, three buttons
   below) inside the panel — the 4-column layout would overflow. */
.pvc-quiz .evaltrain-imb-row {
  grid-template-columns: 1fr 1fr 1fr;
}
.pvc-quiz .evaltrain-imb-row > .imb-label {
  grid-column: 1 / -1; grid-row: 1; text-align: center; padding-left: 0; padding-bottom: 4px;
}
.pvc-quiz .evaltrain-imb-pick-you   { grid-column: 1; grid-row: 2; }
.pvc-quiz .evaltrain-imb-pick-equal { grid-column: 2; grid-row: 2; }
.pvc-quiz .evaltrain-imb-pick-opp   { grid-column: 3; grid-row: 2; }
.pvc-quiz .evaltrain-imb-pick { font-size: 11px; padding: 0 6px; }
/* Eval chips: 4 across to fit the narrow panel. */
.pvc-quiz .pvc-quiz-eval-row { grid-template-columns: repeat(4, 1fr); }
/* Reveal rows: stacked layout in the panel. */
.pvc-quiz-reveal .evaltrain-imb-reveal-row { grid-template-columns: 1fr 1fr; }
.pvc-quiz-reveal .evaltrain-imb-reveal-row > .imb-label { grid-column: 1 / -1; grid-row: 1; text-align: center; }
.pvc-quiz-reveal .evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(1) { grid-column: 1; grid-row: 2; align-items: center; }
.pvc-quiz-reveal .evaltrain-imb-reveal-row > .evaltrain-reveal-pair:nth-of-type(2) { grid-column: 2; grid-row: 2; align-items: center; }
.pvc-quiz-reveal .evaltrain-imb-reveal-row > .imb-note { grid-row: 3; }
.pvc-quiz-reveal .evaltrain-eval-reveal-sym { font-size: 26px; }
/* Mask the eval bar during a quiz so it doesn't reveal the "who's winning"
   answer. The fill is blurred (height becomes unreadable); label hidden. */
.eval-bar.pvc-eval-bar-masked { filter: blur(10px); }
.eval-bar-label.pvc-eval-bar-masked { color: transparent; }
.eval-bar-label.pvc-eval-bar-masked::after { content: '?'; color: var(--text-dim); }

/* summary */
.evaltrain-summary-grid {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: 20px;
}
@media (max-width: 720px) {
  .evaltrain-summary-grid { grid-template-columns: 1fr; }
}
.evaltrain-grade-card {
  background: var(--card-bg, #1f1f1f);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 28px 20px;
  text-align: center;
}
.evaltrain-grade-letter {
  font-size: 72px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent, #4caf50);
  margin-bottom: 12px;
}
.evaltrain-grade-caption { font-size: 14px; color: var(--text); margin-bottom: 6px; }
.evaltrain-grade-score   { font-size: 12px; color: var(--text-dim); }
.evaltrain-stats-card {
  background: var(--card-bg, #1f1f1f);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.evaltrain-stat-row {
  display: flex; justify-content: space-between; align-items: baseline;
  border-bottom: 1px solid var(--border); padding-bottom: 8px;
}
.evaltrain-stat-row:last-child { border-bottom: none; padding-bottom: 0; }
.evaltrain-stat-label { font-size: 13px; color: var(--text-dim); }
.evaltrain-stat-value { font-size: 18px; font-weight: 700; color: var(--text); }

.evaltrain-summary-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.evaltrain-summary-table th,
.evaltrain-summary-table td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
.evaltrain-summary-table th { color: var(--text-dim); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; }
.evaltrain-summary-table .evaltrain-cell-ok  { color: #6fcf97; box-shadow: none; }
.evaltrain-summary-table .evaltrain-cell-bad { color: #eb5757; box-shadow: none; opacity: 1; }

/* ============================================================
   SCAN-FROM-PHOTO MODALS (import.js)
   ============================================================ */
.scan-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.65);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overflow-y: auto;
}
.scan-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 20px 22px;
  max-width: 480px;
  width: 100%;
  max-height: 95vh;
  overflow-y: auto;
  color: var(--text);
}
.scan-modal.scan-modal-wide { max-width: 560px; }
.scan-modal h2 { margin: 0 0 6px; font-size: 18px; }
.scan-modal-hint { color: var(--text-dim); font-size: 13px; margin: 0 0 14px; }
.scan-preview-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 14px;
  background: #111;
  border-radius: 2px;
  padding: 8px;
}
.scan-preview-wrap img {
  max-width: 100%;
  max-height: 240px;
  border-radius: 2px;
}
.scan-field {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin: 10px 0;
  font-size: 14px;
}
.scan-field > label:first-child { font-weight: 600; }
.scan-editor-meta { font-size: 13px; color: var(--text-dim); margin-bottom: 4px; }
.scan-editor-notes { font-size: 12px; color: var(--text-dim); font-style: italic; margin-bottom: 10px; }
.scan-editor-board { margin: 10px auto 14px; max-width: 440px; }
.scan-modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 14px;
}
@media (max-width: 600px) {
  .scan-modal { padding: 16px; }
  .scan-modal-actions { justify-content: stretch; }
  .scan-modal-actions button { flex: 1 1 calc(50% - 4px); }
}

/* Corner-adjust step (scan-position.js) */
.scan-quad-wrap {
  position: relative;
  display: inline-block;
  margin: 0 auto 6px;
  max-width: 100%;
  background: #111;
  border-radius: 2px;
  line-height: 0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.scan-quad-wrap img {
  max-width: 100%;
  max-height: 55vh;
  border-radius: 2px;
  display: block;
  pointer-events: none;
}
.scan-quad-wrap svg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.scan-quad-handle {
  position: absolute;
  width: 40px;
  height: 40px;
  margin: -20px 0 0 -20px; /* center on the corner point */
  border-radius: 50%;
  cursor: grab;
  touch-action: none;
}
.scan-quad-handle::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  background: #2ecc71;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.scan-quad-handle:active { cursor: grabbing; }
.scan-warn {
  font-size: 13px;
  color: #e67e22;
  margin: 4px 0;
}

/* ============================================================
   Game Review (game-review.js)
   - Intro page (PGN paste + side + depth picker)
   - Post-review augmentation panel injected into the plan view
   ============================================================ */
/* ---- Game Review page shell ---- */
.gr-page { max-width: 820px; margin: 0 auto; padding: 28px 20px; }
/* Left-aligned, like the Explorer header (.openings-header). */
.gr-header { text-align: left; margin-bottom: 24px; }
.gr-title {
  font-size: 28px; margin: 0 0 6px;
  font-family: var(--font-display);
}
.gr-sub {
  color: var(--text-dim); margin: 0;
  font-size: 14px; max-width: 560px; line-height: 1.65;
}

/* Two-panel shell matching review-form-shell */
.gr-shell {
  display: grid;
  grid-template-columns: 190px 1fr;
  border: 1px solid var(--border);
  border-radius: 2px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
}
@media (max-width: 760px) {
  .gr-shell { grid-template-columns: 1fr; }
  .gr-aside  { display: none; }
  .gr-pull-row { flex-wrap: wrap; }
  .gr-pull-row .gr-input { flex: 1 1 100%; }
  .gr-pull-row .btn-secondary { flex: 1 1 100%; }
  .gr-actions { flex-wrap: wrap; }
  .gr-actions button { flex: 1 1 auto; }
}
@media (max-width: 420px) {
  .gr-page { padding: 20px 12px; }
  .gr-body { padding: 18px 14px 16px; }
  .gr-depth-btn, .gr-side-btn { font-size: 12px; padding: 8px 6px; }
}

/* Left aside */
/* The scan rail. Newsstand, not Middlegame Mentor: this panel arrived with
   the fork wearing a red wash, a graph-paper grid and two glowing objects,
   all of which spend the accent on decoration. The rule this file states
   further down — punished/solved earn the red and nothing else does — is
   what makes the red button beside this rail read as the action. So the
   rail carries NO accent at all. */
.gr-aside {
  background: var(--surface);
  border-right: 1px solid var(--border);
  padding: 24px 18px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: relative;
  overflow: hidden;
}
/* Ben-Day, but a screen you can actually see — the page field at 6px/0.055
   reads as flat tone, and this one is meant to read as printed stock. Dots
   are dense at the top and thin out down the rail: ink coverage falling off
   the way it does at the edge of a pulp panel. Monochrome; the page field
   dopes red into its dots, this one must not. */
.gr-aside::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(var(--text) 0.8px, transparent 0.9px);
  background-size: 7px 7px;
  opacity: 0.14;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,0.35) 55%, transparent 92%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,0.35) 55%, transparent 92%);
  pointer-events: none;
}
[data-theme="light"] .gr-aside::before { opacity: 0.2; }
/* A die-cut box, not a stamp. A filled block here was the brightest object
   on the screen and pulled the eye off the primary button, and the stamp
   device (white on red) is deliberately down to two places — the logo and
   the primary action. This keeps the corner-box shape and adds neither. */
.gr-aside-icon {
  width: 42px; height: 42px;
  background: var(--ink);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 1px;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  line-height: 1;
  position: relative; z-index: 1;
}
.gr-aside-heading {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 14px;
  line-height: 1.15;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text);
  margin: 0 0 4px;
  position: relative; z-index: 1;
}
.gr-aside-body {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.6;
  margin: 0;
  position: relative; z-index: 1;
}
.gr-aside-pills {
  display: flex;
  flex-direction: column;
  gap: 7px;
  position: relative; z-index: 1;
}
.gr-aside-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-dim);
}
/* Square, and no glow. Round dots and ambient light are the two things that
   made this rail look like it came off a different product. */
.gr-aside-pill-dot {
  width: 5px; height: 5px;
  border-radius: 0;
  background: var(--text-dim);
  flex-shrink: 0;
}

/* Right form body */
.gr-body {
  padding: 22px 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Source tabs — pill style */
.gr-source-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 18px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  width: fit-content;
}
.gr-source-tab {
  background: transparent;
  border: none;
  color: var(--text-dim);
  padding: 6px 14px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  border-radius: 2px;
  transition: color var(--transition), background var(--transition), box-shadow var(--transition);
  white-space: nowrap;
}
.gr-source-tab:hover { color: var(--text); }
.gr-source-tab--active {
  background: var(--accent-muted);
  color: var(--accent);
  border: 1px solid rgba(201,146,42,0.4);
  box-shadow: 0 0 8px var(--accent-glow);
}

.gr-source-panel { margin-bottom: 0; }
.gr-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 7px;
  display: block;
}
.gr-pull-row { display: flex; gap: 8px; align-items: center; margin-bottom: 2px; }
.gr-input {
  flex: 1;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--text);
  padding: 9px 12px;
  font: inherit;
  font-size: 14px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.gr-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
.gr-pull-status { margin-top: 8px; color: var(--text-dim); font-size: 13px; min-height: 1em; }
.gr-pull-list {
  margin-top: 10px;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface-2);
}
.gr-pull-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  padding: 10px 12px;
  font: inherit;
  cursor: pointer;
  transition: background var(--transition), padding-left var(--transition);
  position: relative;
}
.gr-pull-item::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: transparent;
  transition: background var(--transition);
}
.gr-pull-item:hover::before { background: var(--accent); }
.gr-pull-item:last-child { border-bottom: none; }
.gr-pull-item:hover { background: rgba(201,146,42,0.05); padding-left: 15px; }
.gr-pull-players { font-size: 13px; font-weight: 600; }
.gr-pull-result { color: var(--text-dim); font-weight: 500; margin-left: 6px; }
.gr-pull-meta { font-size: 11px; color: var(--text-dim); margin-top: 2px; }

.gr-textarea {
  width: 100%;
  min-height: 130px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: inherit;
  padding: 10px 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  resize: vertical;
  box-sizing: border-box;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.gr-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}

/* Side / depth row */
.gr-row {
  display: flex;
  gap: 20px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.gr-row > div { flex: 1 1 180px; }
.gr-side-row, .gr-depth-row { display: flex; gap: 6px; }
.gr-side-btn, .gr-depth-btn {
  flex: 1; padding: 9px 10px; border-radius: 2px; cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  transition: border-color var(--transition), background var(--transition),
              color var(--transition), box-shadow var(--transition);
}
.gr-side-btn:hover, .gr-depth-btn:hover {
  border-color: rgba(201,146,42,0.5);
  color: var(--text);
}
.gr-side-btn--active, .gr-depth-btn--active {
  background: var(--accent-muted);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 10px var(--accent-glow);
}
.gr-depth-num {
  font-size: 10px;
  font-weight: 500;
  opacity: 0.7;
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
}

.gr-error { margin-top: 10px; color: var(--warn, #d65a5a); font-size: 13px; }
.gr-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

/* Legacy .gr-card kept for any non-intro usage */
.gr-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 20px;
  margin-top: 12px;
}

/* Game-review scorecard injected into the eval-only placeholder on view-plan. */
.gr-sc {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 10px 12px;
  margin: 10px 0 14px;
}
.gr-sc-row {
  display: grid;
  grid-template-columns: 1fr 64px 64px;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
  font-size: 13px;
}
.gr-sc-row--head .gr-sc-val {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-dim); font-weight: 600;
}
.gr-sc-row--big { padding: 6px 0; }
.gr-sc-row--big .gr-sc-label { font-weight: 700; font-size: 14px; }
.gr-sc-row--big .gr-sc-val { font-weight: 700; font-size: 18px; }
.gr-sc-label { color: var(--text-dim); }
.gr-sc-val { text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.gr-sc-val--great { color: #6fbf4d; }
.gr-sc-val--good  { color: #9dc25b; }
.gr-sc-val--ok    { color: #e8b93c; }
.gr-sc-val--poor  { color: #f0704a; }
.gr-sc-val--elo   { color: var(--text); }
.gr-sc-divider { border-top: 1px solid var(--border); margin: 6px 0; }
.gr-sc-row--count { padding: 2px 0; font-size: 12.5px; }
.gr-sc-row--count .gr-sc-val { font-weight: 500; }
.gr-sc-sym {
  display: inline-block; width: 24px; margin-right: 6px;
  font-weight: 700; text-align: center;
}
.gr-sc-note {
  font-size: 11px; color: var(--text-dim);
  margin: 8px 0 0; line-height: 1.4;
}
/* Notable-class rows expand to show the actual moves. */
.gr-sc-row--click { cursor: pointer; }
.gr-sc-row--click:hover .gr-sc-label { color: var(--text); }
.gr-sc-chev {
  margin-left: 6px; font-size: 10px; color: var(--text-dim);
}
.gr-sc-detail {
  display: flex; flex-direction: column; gap: 4px;
  padding: 2px 0 6px 30px;
}
/* Filtered view: show only the clicked color's group. */
.gr-sc-detail--w .gr-sc-chipgroup[data-color="b"],
.gr-sc-detail--b .gr-sc-chipgroup[data-color="w"] { display: none; }
.gr-sc-chipgroup {
  display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
}
.gr-sc-chipgroup-label {
  font-size: 11px; color: var(--text-dim); margin-right: 4px; white-space: nowrap;
}
/* Nonzero counts render as buttons; keep them looking like the plain cells. */
button.gr-sc-val {
  background: none; border: none; padding: 0;
  font: inherit; color: inherit; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.gr-sc-val--click:hover { color: var(--text); text-decoration: underline dotted; }
.gr-sc-chip {
  background: var(--bg-light, rgba(255,255,255,0.05));
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 2px 7px;
  font: inherit; font-size: 12px;
  color: var(--text);
  cursor: pointer;
}
.gr-sc-chip:hover { border-color: var(--text-dim); }
/* Classification colors — shared by scorecard symbols and move-list badges. */
.gr-mvb--brilliant  { color: #26c2a3; }
.gr-mvb--great      { color: #5b8def; }
.gr-mvb--best       { color: #81b64c; }
.gr-mvb--excellent  { color: #9dc25b; }
.gr-mvb--good       { color: #8f9779; }
.gr-mvb--book       { color: #a88865; }
.gr-mvb--inaccuracy { color: #f7c631; }
.gr-mvb--mistake    { color: #ff9b41; }
.gr-mvb--miss       { color: #ff7769; }
.gr-mvb--blunder    { color: #fa412d; }
/* Badge appended to a move in the move list (e.g. "Qxf7 ??"). */
.gr-mvb {
  margin-left: 3px;
  font-weight: 800;
  font-size: 11px;
}
.gr-imb-wrap { margin-top: 6px; }
.gr-imb-title {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-dim); margin-bottom: 8px;
}
.gr-imb-pov { text-transform: none; letter-spacing: 0; opacity: 0.8; margin-left: 4px; }

/* ============================================================
   Scout Report (player-scoring.js) — reuses the .gr-* intro shell;
   .ps-* covers the progress screen and the report dashboard.
   ============================================================ */
.ps-select { width: 100%; }

/* Game-count slider */
.ps-count-block { margin: 14px 0 4px; }
.ps-count-head { display: flex; align-items: baseline; justify-content: space-between; }
.ps-count-val { font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ps-slider { width: 100%; margin: 6px 0 2px; accent-color: var(--accent); }
.ps-count-scale {
  display: flex; justify-content: space-between;
  font-size: 10.5px; color: var(--text-dim);
}
.ps-estimate { font-size: 12px; color: var(--text-dim); margin-top: 6px; min-height: 16px; }
.ps-estimate--warn { color: var(--text-dim); }

.ps-progress {
  max-width: 560px; margin: 40px auto; text-align: center;
}
.ps-progress-status { font-size: 15px; font-weight: 600; margin-bottom: 12px; }
.ps-progress-track {
  height: 8px; border-radius: 2px; background: var(--border);
  overflow: hidden; margin-bottom: 8px;
}
.ps-progress-fill {
  height: 100%; border-radius: 2px; background: var(--accent);
  transition: width 0.3s ease;
}
.ps-progress-sub { font-size: 12px; color: var(--text-dim); min-height: 16px; }
/* Scan-depth note under the bar. .ps-progress centres its children, which is
   right for a status line and wrong for two sentences — hence the left align
   and the narrower measure. The badge copies .settings-info-btn's circle so the
   same mark means the same thing in both places. */
.ps-progress-tip {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  max-width: 440px;
  margin: 20px auto 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--text-dim);
  text-align: left;
}
.ps-progress-tip-i {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-top: 1px;
  border: 1px solid var(--border);
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  font-style: italic;
  color: var(--text-dim);
}
.ps-progress .gr-actions { justify-content: center; margin-top: 18px; }

/* Overall banner */
.ps-overall {
  display: flex; align-items: center; gap: 20px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 18px 20px; margin: 16px 0 18px;
}
.ps-overall-ring {
  flex: 0 0 auto; width: 92px; height: 92px; border-radius: 50%;
  border: 4px solid currentColor;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.ps-overall-num { font-size: 30px; font-weight: 800; line-height: 1; color: var(--text); }
.ps-overall-cap { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); }
.ps-overall-text { font-size: 13.5px; line-height: 1.5; }
.ps-overall-text p { margin: 0 0 6px; }
.ps-overall-note { color: var(--text-dim); font-size: 12px; }

/* Category cards */
.ps-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}
.ps-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 14px 16px;
}
.ps-card--focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-glow); }
.ps-card-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.ps-card-icon { font-size: 15px; opacity: 0.85; }
.ps-card-name { font-weight: 700; font-size: 13.5px; flex: 1; }
.ps-card-score { font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ps-bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
.ps-bar-fill { height: 100%; border-radius: 3px; background: currentColor; }
/* The likely range. A score here is read off a sample of games, and the number
   alone hides how much of it is sampling noise — a 200-game Results score
   carries roughly ±23 points of it. Printing the range next to the number is
   what stops the page overclaiming. Deliberately quiet: it is a qualifier on
   the score above it, not a second score. */
.ps-band {
  display: flex; align-items: baseline; gap: 5px;
  margin-top: 6px; font-size: 11px; color: var(--text-dim);
}
.ps-band-range { font-variant-numeric: tabular-nums; font-weight: 600; }
.ps-band-cap { font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px; opacity: 0.7; }
/* A band too wide to support a verdict earns a dashed rule — the same "this is
   provisional" mark the empty-state rows use, rather than a colour. */
.ps-band--wide { border-bottom: 1px dashed var(--border); padding-bottom: 5px; }

.ps-card-word {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.5px;
  font-weight: 700; margin: 6px 0 8px;
}
.ps-card-subs { font-size: 12px; color: var(--text-dim); line-height: 1.5; }
.ps-actions { margin-top: 18px; }

/* Score tones — VALUE, not hue.
   The inherited traffic light (green/lime/amber/orange) belongs to another app.
   Here red is the only chromatic accent in the chrome and it marks the
   punishment, so a scorecard painted in four colours would spend that meaning
   on nothing. Instead the scale runs through weights of ink — full-strength
   down to dim — and red is kept for the bottom step alone, where "you are
   leaking points here" IS the punishment story and earns it.
   .ps-bar-fill inherits currentColor, so a card reads as how much ink. */
.ps-tone--great { color: var(--text); }
.ps-tone--good  { color: #c9c6bd; }
.ps-tone--ok    { color: var(--text-dim); }
.ps-tone--poor  { color: var(--accent); }
[data-theme="light"] .ps-tone--good { color: #4a4a55; }

/* ── Trend sparklines ──────────────────────────────────────────
   The line inherits the score's tone colour, so a leaking skill draws an
   orange history and a strength draws green — health and direction read as
   one mark. The delta chip stays neutral so it doesn't fight that colour. */
/* Grid, not flex: the SVG has an intrinsic aspect ratio, and as a flex item it
   would size to that instead of filling the card. */
.ps-card-trend, .ps-overall-trend {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 10px; margin-top: 8px;
}
.ps-overall-trend { margin: 8px 0 6px; max-width: 360px; }
.ps-spark {
  width: 100%; height: 26px; display: block; overflow: visible;
  animation: psDraw 520ms cubic-bezier(0.22, 0.8, 0.3, 1) both;
}
.ps-spark-line {
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linejoin: round; stroke-linecap: round;
}
.ps-spark-fill { fill: currentColor; opacity: 0.14; stroke: none; }
.ps-spark-dot, .ps-spark-cap { fill: currentColor; stroke: none; }
.ps-spark-empty {
  height: 26px; display: flex; align-items: center;
  font-size: 11px; color: var(--text-dim); opacity: 0.75;
}

@keyframes psDraw {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.ps-delta {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ps-delta-arrow { font-size: 9px; line-height: 1; }
.ps-delta-arrow--up   { color: var(--text); }
.ps-delta-arrow--down { color: var(--accent); }
.ps-delta-arrow--flat { color: var(--text-dim); }

/* ── What changed since the last comparable report ─────────────── */
.ps-change {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 14px 16px; margin-top: 14px;
}
.ps-change-head {
  font-size: 13.5px; font-weight: 700; margin-bottom: 8px;
}
.ps-change-list { list-style: none; margin: 0; padding: 0; }
.ps-change-item {
  position: relative; padding-left: 16px; font-size: 12.5px;
  color: var(--text-dim); line-height: 1.55; margin-bottom: 3px;
}
.ps-change-item::before {
  content: '–'; position: absolute; left: 0; color: var(--text-dim);
}
.ps-change-item--up::before   { content: '▲'; font-size: 8px; top: 4px; color: var(--text); }
.ps-change-item--down::before { content: '▼'; font-size: 8px; top: 4px; color: var(--accent); }
.ps-change-caveat {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-dim); opacity: 0.85;
}
.ps-change-empty { margin: 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.55; }

/* ── Historical-report banner ──────────────────────────────────── */
.ps-viewing {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 2px; padding: 9px 14px; margin-bottom: 14px;
  font-size: 12.5px; color: var(--text-dim);
}
.ps-viewing-back {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--accent);
}
.ps-viewing-back:hover { text-decoration: underline; }

/* ── Report history ────────────────────────────────────────────
   Each row carries the whole scorecard in miniature: seven bars in category
   order, in that report's own tone colours. Reading down the column shows the
   shape of your play changing. */
.ps-hist { margin-top: 18px; }
.ps-hist-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.ps-hist-title { font-size: 14px; font-weight: 700; margin: 0; }
.ps-hist-clear {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: 11.5px; color: var(--text-dim);
}
.ps-hist-clear:hover { color: var(--accent); }
.ps-hist-sub { font-size: 12px; color: var(--text-dim); margin: 4px 0 10px; line-height: 1.5; }
.ps-hist-list {
  list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--border); border-radius: 2px; overflow: hidden;
}
.ps-hist-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; background: var(--surface); cursor: pointer;
}
.ps-hist-row + .ps-hist-row { border-top: 1px solid var(--border); }
.ps-hist-row:hover { background: var(--surface-2, var(--border)); }
.ps-hist-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ps-hist-row--current { cursor: default; background: var(--surface); }
.ps-hist-row--current:hover { background: var(--surface); }
.ps-hist-row--current .ps-hist-date { font-weight: 700; }
.ps-hist-score {
  flex: 0 0 auto; width: 30px; font-size: 17px; font-weight: 800;
  font-variant-numeric: tabular-nums; text-align: right;
}
.ps-hist-mini {
  flex: 0 0 auto; display: inline-flex; align-items: flex-end; gap: 2px;
  height: 18px; opacity: 0.9;
}
.ps-hist-seg { width: 3px; border-radius: 1px; background: currentColor; }
.ps-hist-seg--none { background: var(--border); }
.ps-hist-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ps-hist-date { font-size: 12.5px; font-weight: 600; }
.ps-hist-meta { font-size: 11px; color: var(--text-dim); }
.ps-hist-del {
  flex: 0 0 auto; background: none; border: none; cursor: pointer;
  font-size: 12px; line-height: 1; padding: 4px 2px; color: var(--text-dim); opacity: 0.6;
}
.ps-hist-del:hover { opacity: 1; color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .ps-spark { animation: none; }
}

@media (max-width: 640px) {
  .ps-overall { flex-direction: column; text-align: center; }
  .ps-overall-trend { max-width: none; }
  /* Keep history rows on one line by dropping the date from the chip — the row
     already says when the report was built. */
  .ps-delta-since { display: none; }
  .ps-hist-row { gap: 9px; padding: 10px 11px; }
}

/* ============================================================
   Coach's Game Review (coach-review.js)
   - Reuses the Game Review intro shell (.gr-*) and the Play vs Coach
     commentary bubble (.pvc-commentary*). The .cr-* rules below cover
     only the plan card injected into the plan view.
   ============================================================ */
.cr-commentary { margin-top: 4px; }
/* Coach review can stack several imbalance changes from one move — space them. */
.cr-commentary .pvc-commentary-imb-row + .pvc-commentary-imb-row { margin-top: 6px; }
.cr-plan-btn {
  margin-top: 12px;
  width: 100%;
  font-size: 13px;
}
.cr-plan-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* Settings drawer — Coach Voice section */
.settings-voice-select {
  flex: 1; min-width: 0;
  background: var(--bg-input, rgba(255, 255, 255, 0.06));
  color: var(--text);
  border: 1px solid var(--border, rgba(255, 255, 255, 0.12));
  border-radius: 2px;
  padding: 6px 8px;
  font-size: 13px;
}
.settings-voice-preview { margin-top: 10px; font-size: 13px; }

/* Inline 🔊 toggle inside commentary bubbles / plan cards / hint panels. */
.bubble-speak-btn {
  background: none; border: none; cursor: pointer;
  font-size: 13px; padding: 2px 6px; margin-left: 6px;
  opacity: 0.65; vertical-align: middle; line-height: 1;
}
.bubble-speak-btn:hover { opacity: 1; }
/* Game Review's compact speak toggle sits at the right of the panel title. */
.gr-imb-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.gr-speak-btn { margin-left: auto; font-size: 12px; padding: 4px 10px; }
/* Plan + speak buttons share a row; the row owns the top margin. */
.cr-btn-row { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.cr-btn-row .cr-plan-btn { margin-top: 0; width: auto; flex: 1 1 140px; }
.cr-speak-btn { flex: 1 1 140px; font-size: 13px; }
/* Grid row currently being read aloud by the coach. */
.imb-row--speaking {
  background: rgba(224, 164, 88, 0.10);
  box-shadow: inset 2px 0 0 var(--accent, #b21c22);
}
/* Board squares the narration is referring to (outposts, files, diagonals).
   Inset shadows paint over the square color but under the piece image:
   a soft green fill plus a darker ring. Squares light one by one as the
   voice mentions them and fade back out — the transition sits on the base
   square so the fade-OUT (class removal) animates too. */
#board .square-55d63, #pvcBoard .square-55d63 { transition: box-shadow 0.3s ease; }
.square-55d63.sq-speak-hl {
  box-shadow: inset 0 0 0 3px rgba(56, 142, 60, 0.9),
              inset 0 0 0 999px rgba(76, 175, 80, 0.35);
}
.cr-plan-card {
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border, rgba(255,255,255,0.08));
  border-radius: 2px;
  background: rgba(255,255,255,0.02);
}
.cr-plan-loading, .cr-plan-empty {
  color: var(--text-dim); font-size: 13px; font-style: italic;
}
.cr-plan-header {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-dim); margin-bottom: 6px;
}
.cr-plan-label {
  font-size: 15px; font-weight: 600; color: var(--text);
  margin-bottom: 10px; line-height: 1.4;
}
.cr-plan-moves { display: flex; flex-direction: column; gap: 4px; }
.cr-plan-move {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px;
}
.cr-plan-move-arrow { width: 14px; text-align: center; color: var(--text-dim); }
.cr-plan-move-san {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-weight: 600; min-width: 56px;
}
.cr-plan-move--you .cr-plan-move-san { color: var(--accent, #b21c22); }
.cr-plan-move--reply .cr-plan-move-san { color: var(--text-dim); }
.cr-plan-move-tag {
  font-size: 11px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.4px;
}

/* Lecture mode checkbox (intro screen) + play/pause control (plan view). */
.cr-lecture-toggle {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 2px;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.cr-lecture-toggle:hover { border-color: rgba(201,146,42,0.5); }
.cr-lecture-toggle:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-muted);
}
.cr-lecture-toggle input { margin-top: 3px; cursor: pointer; flex-shrink: 0; }
.cr-lecture-toggle-title { font-weight: 700; font-size: 13.5px; color: var(--text); margin-bottom: 3px; }
.cr-lecture-toggle-desc { font-size: 12px; color: var(--text-dim); line-height: 1.45; }
.cr-lecture-btn { flex: 1 1 140px; font-size: 13px; }

/* ============================================================
   OPENINGS TAB — GM Explorer + Repertoire Builder
   ============================================================ */
.openings-page {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px 24px 40px;
}
.openings-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; margin-bottom: 20px;
}
.openings-title {
  font-family: 'Cinzel', serif;
  font-size: 28px; font-weight: 700;
  color: var(--text); margin: 0 0 6px;
}
.openings-sub {
  color: var(--text-dim); font-size: 14px; margin: 0; max-width: 560px;
}
.openings-coach-picker { display: flex; flex-direction: column; gap: 4px; min-width: 240px; }
.openings-coach-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px;
  color: var(--text-dim); font-weight: 600;
}
.openings-coach-select {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 8px 10px; font-size: 14px; font-family: inherit;
  cursor: pointer;
}
.openings-coach-select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.openings-body {
  display: grid;
  grid-template-columns: minmax(320px, 480px) 1fr;
  gap: 24px;
  align-items: start;
}
/* Grid items default to min-width:auto, so the board's fixed-pixel markup
   props the column open and it can never shrink back down (chessboard.js then
   re-measures the still-wide container and rebuilds at the same size). Same
   fix as .pvc-board-col. */
.openings-body > * { min-width: 0; }
@media (max-width: 880px) {
  .openings-body { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  .openings-page { padding: 12px 12px 40px; }
  .openings-title { font-size: 22px; }
  .openings-header { margin-bottom: 14px; gap: 12px; }
  .openings-body { gap: 16px; }
  .openings-own-form { padding: 10px 12px; gap: 8px; margin-bottom: 14px; }
  /* Text/month/select inputs share the row width instead of overflowing it. */
  .openings-own-form .op-own-input { flex: 1 1 130px; min-width: 0; }
  /* The flow keeps its own padding — the slug wraps to two lines and the
     stage stays a single question. */
  .op-flow { padding: 0; }
  .op-flow-chip { padding: 8px 10px; gap: 6px; }
  .op-flow-stage { padding: 10px 12px; }
  .op-flow .op-own-status { padding: 0 12px 10px; }
  .op-flow-name { min-width: 0; flex: 1 1 140px; }
  /* Two-option answers take the full row and split it, so a long label
     ("They play White") can't push the card wider than the screen. */
  .op-flow-seg { flex: 1 1 100%; }
  .op-flow-opt { flex: 1 1 0; text-align: center; padding: 9px 8px; white-space: normal; }
  /* On one line the hints are helpful; stacked under the controls on a
     phone they are just another row to scroll past. */
  .op-flow-hint { display: none; }
}

.openings-left { display: flex; flex-direction: column; gap: 12px; }
.openings-board { width: 100%; min-height: 320px; max-width: 100%; overflow: hidden; }

.openings-toolbar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  justify-content: space-between;
}
.op-nav { display: inline-flex; gap: 0; border: 1px solid var(--border); border-radius: 2px; overflow: hidden; }
.op-nav .op-nav-btn {
  border: none; border-right: 1px solid var(--border); border-radius: 0;
  padding: 7px 14px; font-size: 15px; line-height: 1;
}
.op-nav .op-nav-btn:last-child { border-right: none; }
.op-nav .op-nav-btn:disabled { opacity: 0.35; cursor: default; }
.op-nav .op-nav-btn:disabled:hover { border-color: var(--border); }
.op-nav-actions { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.op-btn {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 7px 12px; font-size: 13px; font-weight: 600;
  font-family: inherit; cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.op-btn:hover { border-color: var(--accent); }
.op-btn-primary {
  background: var(--accent); color: #1a1610;
  border-color: var(--accent);
}
.op-btn-primary:hover { filter: brightness(1.08); }

.openings-line {
  background: var(--surface); border: 1px solid var(--border); border-radius: 2px;
  padding: 10px 12px; font-family: 'JetBrains Mono', monospace; font-size: 13px;
  color: var(--text); line-height: 1.7; min-height: 38px;
  word-spacing: 2px;
  /* A loaded game runs to ~70 plies. Cap the box and scroll inside it so the
     board below doesn't get shoved down the page. */
  max-height: 122px; overflow-y: auto;
}
.op-line-num { color: var(--text-dim); margin-right: 2px; }
/* Each move is a button — click it to stand on that position. It has to keep
   reading as running text, so everything a button brings is stripped back out
   and only the padding needed for a hit target stays. */
.op-line-san {
  appearance: none;
  background: none;
  border: 0;
  border-radius: 2px;
  color: var(--text);
  font: inherit;
  padding: 1px 3px;
  margin: 0 -1px;
  cursor: pointer;
}
.op-line-san:hover { background: var(--border); }
.op-line-san:focus-visible { outline: 1px solid var(--accent); outline-offset: 0; }
/* Where the board is standing. */
.op-line-san.is-current { background: var(--text); color: var(--bg); font-weight: 700; }
.op-line-empty { color: var(--text-dim); font-style: italic; }
/* Loaded, not yet walked: the rest of a game or a queued punishing line. */
.op-line-ahead { color: var(--text-dim); opacity: 0.75; }
.op-line-ahead:hover { opacity: 1; }
.op-line-num--ahead { opacity: 0.5; }

.openings-right { display: flex; flex-direction: column; gap: 16px; }
.op-panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px;
  box-shadow: var(--shadow);
}
.op-panel-title {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.7px;
  color: var(--text-dim); font-weight: 700; margin-bottom: 10px;
}
.op-rep-count { color: var(--accent); margin-left: 4px; font-weight: 600; }

/* Running imbalance grader — collapsible panel wrapping the shared .imb-* grid. */
.op-imb-panel { margin-top: 12px; }
.op-imb-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 10px;
}
.op-imb-toggle {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.7px;
  color: var(--text-dim); font-weight: 700; display: inline-flex;
  align-items: center; gap: 6px;
}
.op-imb-toggle:hover { color: var(--text); }
.op-imb-caret { transition: transform 0.15s ease; font-size: 10px; }
.op-imb-collapsed .op-imb-caret { transform: rotate(-90deg); }
.op-imb-collapsed .op-imb-list { display: none; }
.op-imb-collapsed .op-imb-head { margin-bottom: 0; }
.op-imb-pov { display: inline-flex; gap: 2px; }
.op-imb-pov-btn {
  background: var(--surface-2, rgba(255,255,255,0.04));
  border: 1px solid var(--border); color: var(--text-dim);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 3px 8px; cursor: pointer; border-radius: 2px;
}
.op-imb-pov-btn:first-child { border-radius: 2px 0 0 4px; }
.op-imb-pov-btn:last-child { border-radius: 0 4px 4px 0; }
.op-imb-pov-btn.active { background: var(--accent); color: #1a1a1a; border-color: var(--accent); }

/* Tabbed panel: source tabs sit flush at the top edge (no panel padding), the
   move table fills the rest. Mirrors Lichess's database-source tab strip. */
.op-panel--tabbed { padding: 0; overflow: hidden; }
.op-panel--tabbed .op-moves { border: none; border-radius: 0; }
.op-panel--tabbed .op-moves .op-empty,
.op-panel--tabbed .op-moves .op-loading { padding: 14px 16px; }
.op-panel--tabbed .op-analyze { padding: 12px 16px 14px; margin-top: 0; }

.op-source-tabs {
  display: flex; align-items: stretch;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none;
}
.op-source-tabs::-webkit-scrollbar { display: none; }
.op-tab {
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  background: transparent; border: none; cursor: pointer;
  padding: 9px 10px; font-family: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--text-dim);
  border-right: 1px solid var(--border);
  border-bottom: 2px solid transparent;
  transition: color 0.12s, background 0.12s;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.op-tab:last-child { border-right: none; }
.op-tab:hover { color: var(--text); background: rgba(127,127,127,0.06); }
.op-tab.active {
  color: var(--text); background: var(--surface);
  border-bottom-color: var(--accent);
}
.op-tab-icon { font-size: 14px; line-height: 1; opacity: 0.85; flex-shrink: 0; }
.op-tab.active .op-tab-icon { color: var(--accent); opacity: 1; }
/* Three live tabs share the strip in the Explorer — tighten so they fit before
   scrolling kicks in. */
.op-source-tabs .op-tab { padding: 9px 7px; font-size: 12px; gap: 4px; }

/* The Punisher has one source, so its strip is a caption ("@user as white"),
   not a switch: same bar, nothing to click, reading left like a label. */
.op-tab--static { cursor: default; justify-content: flex-start; }
.op-source-tabs .op-tab--static { padding-left: 12px; }
.op-tab--static:hover { background: var(--surface); color: var(--text); }

/* Opening name caption above live-explorer rows (from the API's eco/name). */
.op-opening-name {
  padding: 6px 12px 2px;
  font-size: 11.5px; font-weight: 600; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Footer note while Lichess is still indexing a player's games (partial data). */
.op-live-partial { font-size: 11.5px; color: var(--text-dim); padding: 6px 12px; }

/* One-time Lichess API-token prompt (explorer requires OAuth since 2026). */
.op-live-auth { text-align: left; }
.op-live-auth p { margin: 0 0 8px; }
.op-live-auth a { color: var(--accent); }
.op-live-auth-row { display: flex; gap: 8px; align-items: center; }
.op-live-auth-row .op-own-input { flex: 1 1 auto; min-width: 0; }

/* ============================================================
   ENGINE READOUT — the paper's chess column, not an engine bar.
   A ruled slug line (ENGINE · DEPTH), the evaluation set on a plate
   of printed stock — paper when White is better, ink when Black is —
   and the principal variation printed underneath as a scoresheet,
   move numbers receding so the moves themselves carry the contrast.
   Structural only: ink, paper and rule. The red belongs to the
   punishment and is never spent here.

   Named areas rather than raw columns: the phone layout below
   re-stacks the same five parts without touching the markup.
   ============================================================ */
.op-engine {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  grid-template-areas: "pill eval pv depth gear";
  align-items: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: 1px; padding: 9px 12px;
  transition: border-top-color var(--transition);
}
/* The heavy rule goes to full contrast while the engine is running —
   the same "this panel is live" device the punished cards use. */
.op-engine--on { border-top-color: var(--text); }

/* ENGINE — the switch, set as a section slug (caps/tracking come from
   the shared chip rule further down). Active reads as an outlined block
   underscored in ink, matching the active source tab. */
.op-engine-pill {
  grid-area: pill;
  background: transparent;
  border: 1px solid var(--border); color: var(--text-dim);
  padding: 5px 10px; border-radius: 1px;
  white-space: nowrap; user-select: none;
  transition: color var(--transition), border-color var(--transition), box-shadow var(--transition);
}
.op-engine-pill:hover { color: var(--text); border-color: var(--text-dim); }
.op-engine--on .op-engine-pill {
  color: var(--text); border-color: var(--text);
  box-shadow: inset 0 -3px 0 var(--text);
}

/* The eval plate. Off/thinking it is an empty ruled box; once there is a
   reading it takes the stock of whoever stands better, so colour never has
   to do the work and both themes stay legible. */
.op-engine-eval {
  grid-area: eval;
  font-weight: 700; font-size: 17px; line-height: 1.1;
  color: var(--text-dim);
  min-width: 62px; text-align: center;
  padding: 4px 7px;
  border: 1px solid var(--border); border-radius: 1px;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.op-engine-eval.op-engine-thinking { color: var(--text-dim); opacity: 0.6; }
/* Scoped to the plate: the PV rows below reuse the same op-eval-* classes
   for their inline evals, and must not inherit a stock background. */
.op-engine--on .op-engine-eval.op-eval-white {
  background: var(--stock-paper); color: var(--stock-paper-fg); border-color: var(--stock-paper);
}
.op-engine--on .op-engine-eval.op-eval-black {
  background: var(--stock-ink); color: var(--stock-ink-fg); border-color: var(--gray);
}

/* DEPTH 22 — a dateline, not a readout. Fixed width so counting up from
   8 to 30 never shuffles the gear along the rule. */
.op-engine-depth {
  grid-area: depth;
  font-family: var(--font-display);
  font-weight: 800; font-size: 9.5px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap; text-align: right; min-width: 66px;
}

/* The score. A column rule separates it from the plate the way a
   newspaper separates two columns of type. */
.op-engine-pv {
  grid-area: pv;
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.55;
  color: var(--text);
  min-width: 0;
  border-left: 1px solid var(--border); padding-left: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.op-engine-pv:empty { border-left: none; padding-left: 0; }
/* Move numbers set back so the moves read first — a printed game score,
   where the numbering is apparatus and the SAN is the text. */
.op-pv-mv { white-space: nowrap; }
.op-pv-mv + .op-pv-mv { margin-left: 2px; }
.op-pv-no { color: var(--text-dim); }

.op-engine-gear {
  grid-area: gear;
  background: none; border: none; color: var(--text-dim);
  font-size: 15px; line-height: 1; cursor: pointer;
  padding: 3px 5px; border-radius: 1px;
}
.op-engine-gear:hover { color: var(--text); }
.op-engine-gear.active { color: var(--text); background: var(--surface-2); }

/* Extra PV rows when Multiple lines > 1 — one plate + score per row,
   ruled off from the headline reading above them. */
.op-engine-lines {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: 4px;
  border-top: 1px solid var(--border); margin-top: 3px; padding-top: 8px;
}
.op-engine-lines:empty { display: none; border-top: none; margin-top: 0; padding-top: 0; }
.op-engine-line {
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--font-mono); font-size: 11px;
}
.op-engine-line-eval {
  min-width: 46px; text-align: right; font-weight: 700; color: var(--text-dim);
}
.op-engine--on .op-engine-line-eval.op-eval-white { color: var(--text); }
.op-engine--on .op-engine-line-eval.op-eval-black { color: var(--text-dim); }
.op-engine-line-pv {
  color: var(--text);
  /* min-width:0 is load-bearing: a flex child sizes to min-content by
     default, so a nowrap PV would push the whole strip past the viewport
     instead of clipping inside it. */
  flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.op-engine-settings {
  grid-column: 1 / -1;
  display: grid; gap: 9px;
  border-top: 1px solid var(--border);
  margin-top: 6px; padding-top: 10px;
}
.op-engine-settings.hidden { display: none; }
.op-engine-set-row {
  display: grid; grid-template-columns: 110px minmax(0, 1fr) auto;
  align-items: center; gap: 12px;
  font-size: 12px; color: var(--text-dim);
}
.op-engine-set-label {
  font-family: var(--font-display);
  font-weight: 800; font-size: 9.5px;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.op-engine-set-row input[type="range"] { width: 100%; accent-color: var(--text); cursor: pointer; }
.op-engine-set-val {
  font-family: var(--font-mono); font-size: 11px; color: var(--text);
  min-width: 46px; text-align: right;
}
/* Dim the whole strip when the engine is off. */
.op-engine:not(.op-engine--on) .op-engine-eval,
.op-engine:not(.op-engine--on) .op-engine-depth,
.op-engine:not(.op-engine--on) .op-engine-pv { opacity: 0.5; }

/* ---- Phone: the strip becomes a stacked column head ----------------
   One row is not survivable at 360px — the score is the widest thing in
   it and a nowrap line was running straight off the screen. So the slug
   (ENGINE · DEPTH · gear) takes the top rule, and the plate and the score
   sit beneath it, where the score gets the full width and wraps. The
   score's height is pinned to two lines: deepening the search rewrites it
   constantly, and a box that grew and shrank underneath your thumb would
   shove the board around while you read. */
@media (max-width: 700px) {
  .op-engine {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "pill depth gear"
      "eval pv    pv";
    gap: 8px 10px;
    padding: 9px 10px;
  }
  .op-engine-eval {
    align-self: start;
    font-size: 19px; min-width: 66px;
    padding: 5px 7px;
  }
  .op-engine-depth { min-width: 0; }
  .op-engine-pv {
    align-self: start;
    white-space: normal; text-overflow: clip;
    word-break: break-word;
    height: calc(2 * 1.55em);
    padding-left: 10px;
  }
  /* Engine off: don't reserve two empty rows of nothing on a small screen. */
  .op-engine-pv:empty { height: 0; }
  /* Secondary lines stay one row each and clip — five wrapped variations
     would bury the board. */
  .op-engine-line { font-size: 10.5px; gap: 8px; }
  .op-engine-line-eval { min-width: 42px; }
  .op-engine-set-row { grid-template-columns: minmax(0, 1fr) auto; }
  .op-engine-set-label { grid-column: 1 / -1; }
}

/* ============================================================
   MOVE TABLE — Lichess opening-explorer layout (warm theme colors).
   A tight, full-width table: column header, then one row per move
   (Move · Games count+% · result bar), then a Σ totals footer.
   ============================================================ */
.op-moves {
  display: flex; flex-direction: column;
}

/* Column header — tiny caps flush above the rows, exactly like Lichess. */
.op-move-head {
  display: grid;
  grid-template-columns: 44px 52px 1fr;
  align-items: center; gap: 8px;
  padding: 3px 6px 4px;
  border-bottom: 1px solid var(--border);
  font-size: 9px; text-transform: uppercase; letter-spacing: 0.4px;
  font-weight: 700; color: var(--text-dim);
}
.op-move-head-games { text-align: right; }
.op-move-head-wdl { text-align: center; }
.op-move-head-freq { text-align: left; }

/* Each move is a full-bleed clickable row. Lichess rows are dense — minimal
   vertical padding, single text line, thin separators, accent hover. */
.op-move-row {
  display: grid;
  grid-template-columns: 44px 52px 1fr;
  align-items: center; gap: 8px;
  background: transparent; border: none;
  border-bottom: 1px solid var(--border);
  padding: 2px 6px; font-family: inherit; color: var(--text);
  cursor: pointer; text-align: left; width: 100%;
  transition: background 0.1s;
}
.op-move-row:last-child { border-bottom: none; }
.op-move-row[data-uci]:hover {
  background: var(--accent-muted);
}

.op-move-san {
  font-family: 'JetBrains Mono', monospace; font-weight: 600; font-size: 13px;
  white-space: nowrap;
}

/* Games cell: count + percentage on ONE line (Lichess shows e.g. "4.1K  86%"
   with the count prominent and the share muted). */
.op-move-games {
  display: flex; align-items: baseline; justify-content: flex-end; gap: 5px;
}
.op-move-count {
  font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text);
}
.op-move-pct {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-dim);
}

.op-move-perf {
  font-family: 'JetBrains Mono', monospace; font-size: 11px;
  color: var(--text-dim); text-align: right; min-width: 34px;
}
.op-move-row--wdl:has(.op-move-perf) {
  grid-template-columns: 44px 52px 36px 1fr;
}

/* Coach-book rows (no result data): the third column is a slim frequency bar. */
.op-move-bar {
  background: var(--bg); border-radius: 2px; height: 14px; overflow: hidden;
  border: 1px solid var(--border);
}
.op-move-bar-fill { display: block; height: 100%; background: var(--accent); }

/* The W/D/L bar fills the row's third column edge-to-edge, like Lichess —
   thin, hard segments, percentages inline. Higher-contrast than before. */
.op-move-wdl {
  display: flex; height: 16px; border-radius: 2px; overflow: hidden;
}
.op-move-wdl > span {
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600; overflow: hidden; white-space: nowrap;
  min-width: 0; line-height: 1;
}
/* White wins / draws / Black wins — crisp, like the Lichess result bar. */
.op-wdl-w { background: #f7f6f3; color: #2a2620; }
.op-wdl-d { background: #7d756a; color: #f0ede7; }
.op-wdl-l { background: #2e2a24; color: #e8e4dc; }

/* Σ totals footer — visually set apart from the move rows. */
.op-sigma {
  background: var(--surface-2) !important;
  border-top: 2px solid var(--border); cursor: default;
}
.op-sigma:hover { background: var(--surface-2); }
.op-sigma-label { color: var(--text-dim); font-weight: 700; }

/* Shared White/Black perspective selector. */
.openings-color { display: inline-flex; border: 1px solid var(--border); border-radius: 2px; overflow: hidden; }
/* The Punisher asks for the side inside the slug flow, and the community /
   masters databases aren't colour-scoped at all — so the header picker stands
   down everywhere except the live player tab. */
.openings-color.hidden { display: none; }
.op-color-btn {
  background: var(--surface); color: var(--text-dim); border: none;
  padding: 8px 14px; font-size: 13px; font-weight: 600; font-family: inherit;
  cursor: pointer; transition: background 0.12s, color 0.12s;
}
.op-color-btn:hover { color: var(--text); }
.op-color-btn.active { background: var(--accent); color: #1a1610; }

.op-analyze {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 6px;
}
.op-analyze.hidden { display: none; }
.op-analyze-btn { width: 100%; }
.op-analyze-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.op-analyze-hint { font-size: 12px; color: var(--text-dim); }

/* Games-from-here: collapsible list of the games reaching the current node.
   Toggled by its own header or the Σ row; each row loads the game on the
   board so the arrows can step through it. */
.op-node-games { border-top: 1px solid var(--border); }
.op-node-games.hidden { display: none; }
.op-node-games-toggle {
  width: 100%; background: transparent; border: none; cursor: pointer;
  padding: 10px 16px; text-align: left; font-family: inherit;
  font-size: 11px; font-weight: 700; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.4px;
  transition: color 0.12s;
}
.op-node-games-toggle:hover { color: var(--text); }
.op-node-games-caret { display: inline-block; width: 12px; }
.op-node-games-count { font-weight: 400; }
.op-node-games-list {
  display: flex; flex-direction: column;
  padding: 0 8px 10px; max-height: 420px; overflow-y: auto;
}
.op-node-games-list.hidden { display: none; }
.op-game-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: transparent; border: none; border-bottom: 1px solid var(--border);
  padding: 7px 8px; cursor: pointer; text-align: left; font-family: inherit;
  color: var(--text); width: 100%; transition: background 0.1s;
}
.op-game-row:last-of-type { border-bottom: none; }
.op-game-row:hover { background: var(--accent-muted); }
.op-game-row.active { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--accent); }
.op-game-players { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.op-game-p {
  font-size: 12px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.op-game-p.op-game-you { color: var(--text); font-weight: 600; }
.op-game-ico { margin-right: 4px; }
.op-game-rating { color: var(--text-dim); font-weight: 400; font-size: 11px; }
.op-game-side { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
.op-game-result {
  padding: 1px 7px; border-radius: 2px;
  font-size: 10px; font-weight: 700; text-transform: uppercase;
}
.op-game-result--win { background: var(--accent); color: #1a1610; }
.op-game-result--loss { background: var(--danger); color: #fff; }
.op-game-result--draw { background: var(--gray); color: #fff; }
.op-game-result--unknown { background: var(--surface-2); color: var(--text-dim); }
.op-game-meta { font-size: 10px; color: var(--text-dim); font-family: 'JetBrains Mono', monospace; }
.op-games-more { font-size: 11px; color: var(--text-dim); font-style: italic; padding: 6px 8px 0; }

/* Σ row doubles as the games-list toggle for your own games. */
.op-sigma--click { cursor: pointer; }
.op-sigma--click:hover { background: var(--accent-muted) !important; }

/* Header controls (color perspective + coach picker) + your-games form.
   The source picker moved into the move panel as Lichess-style tabs. */
.openings-controls { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }

.openings-own-form {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 18px; padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 2px;
}
.openings-own-form.hidden { display: none; }

/* ---- THE SLUG: the guided load form ------------------------------------
   A download is a request for one specific record — site, mode, name,
   color, period, controls. Asking for all six at once is the wall of
   controls this replaced. Asked one at a time, each answer stamps into
   the strip across the top and the next question takes the stage, so the
   strip is both the progress bar and the way back to any answer. */
.op-flow {
  display: block; padding: 0;
  background: var(--surface); border: 1px solid var(--border);
}
.op-flow-line {
  display: flex; flex-wrap: wrap; align-items: stretch;
  margin: 0; padding: 0; list-style: none;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}
.op-flow-cell { display: flex; }
.op-flow-cell + .op-flow-cell { border-left: 1px solid var(--border); }

/* One entry in the slug, built like a card in the reference grid: a small
   dim label over a bold name, with a red rule ruled under it. Unanswered
   it is a ghost — the word alone under a grey rule, so the shape of the
   whole record is visible from the first step, and the rules turning red
   left to right IS the progress bar. */
.op-flow-chip {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  background: none; border: none; border-radius: 0;
  padding: 8px 15px 8px; margin: 0; min-height: 46px;
  cursor: default; color: var(--text-dim); text-align: left;
  font-family: inherit;
  box-shadow: inset 0 -3px 0 var(--border);
  transition: background var(--transition), box-shadow var(--transition), color var(--transition);
}
.op-flow-w {
  font-family: var(--font-display);
  font-weight: 800; font-size: 9.5px; letter-spacing: 0.16em;
  text-transform: uppercase; white-space: nowrap;
}
.op-flow-answer {
  font-family: var(--font-mono); font-size: 12px;
  color: var(--text); white-space: nowrap;
}
.op-flow-answer:empty { display: none; }
.op-flow-chip:disabled { opacity: 0.45; }
.op-flow-chip.is-done { cursor: pointer; box-shadow: inset 0 -3px 0 var(--accent); }
/* The reference fills the whole label block red when a card is picked up,
   and that is exactly what this strip needs: the live step is a solid red
   cell, and answered cells go red under the pointer to say they can be
   picked up again. */
.op-flow-chip.is-done:hover,
.op-flow-chip.is-active {
  background: var(--accent);
  box-shadow: inset 0 -3px 0 var(--accent);
  color: rgba(255, 255, 255, 0.72);
}
.op-flow-chip.is-done:hover .op-flow-answer,
.op-flow-chip.is-active .op-flow-answer { color: var(--on-accent); }
.op-flow-chip.is-active { cursor: default; }

/* The answer hits the paper like a stamp: overprinted, then settling. */
@keyframes op-stamp {
  0%   { opacity: 0; transform: scale(1.5) rotate(-2deg); letter-spacing: 0.24em; }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: none; letter-spacing: normal; }
}
.op-flow-answer.is-stamped { animation: op-stamp 260ms cubic-bezier(0.2, 1.1, 0.3, 1) both; }

/* Collapse toggle: once a tree is loaded, the chip strip alone already says
   everything (site/mode/name/color/period/controls) — this hides the
   Load-games stage + status below it so the loaded tree gets the room. */
.op-flow-cell--toggle { margin-left: auto; }
.op-flow-toggle-btn {
  display: flex; align-items: center; justify-content: center;
  gap: 6px;
  padding: 0 12px; min-height: 46px;
  background: none; border: none; border-left: 1px solid var(--border);
  color: var(--text-dim); font-family: var(--font-display);
  font-size: 18px; line-height: 1; cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
/* The glyph alone read as decoration, so the button says what it does. The
   word is the hit target's whole point on a first visit; drop it on narrow
   screens where the chip strip already wraps. */
.op-flow-toggle-word {
  font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
}
.op-flow-toggle-btn:hover { background: var(--accent); color: var(--on-accent); }

/* Lean mode. Everything above the board that only restates what you already
   know — the page header (the masthead names the app two rows up), the
   Load-games stage, the status line, the report bar — folds away, leaving the
   one chip strip that summarises the load. This is the resting state; the
   travel between states is .op-foldable below. */
.openings-page.is-lean .openings-header,
.openings-page.is-lean .op-flow-stage,
.openings-page.is-lean .op-own-status,
.openings-page.is-lean .op-report-bar { display: none; }

/* The fold itself. setLean() supplies the two pixel heights (a height
   transition needs real numbers at both ends — `auto` is not one) and CSS
   owns the curve. Padding and margin have to travel too: a block at height:0
   still holds its own padding open, and the whole point is to reach zero.

   The page prefix is not decoration: `.op-flow .op-own-status` sets a
   padding-bottom at the same specificity and later in the file, and would
   otherwise hold 12px open under a panel that is meant to be gone. */
.openings-page .op-foldable {
  overflow: hidden;
  transition:
    height var(--op-fold-ms) var(--op-fold-ease),
    padding var(--op-fold-ms) var(--op-fold-ease),
    margin var(--op-fold-ms) var(--op-fold-ease),
    opacity calc(var(--op-fold-ms) * 0.6) ease;
}
.openings-page .op-foldable.is-shut {
  padding-top: 0; padding-bottom: 0;
  margin-top: 0; margin-bottom: 0;
  opacity: 0;
}

/* Reduced motion: setLean skips the animation entirely, but belt and braces
   in case a foldable is mid-flight when the preference flips. */
@media (prefers-reduced-motion: reduce) {
  .openings-page .op-foldable { transition: none; }
}

/* On a phone the chip strip is already wrapping; the sign carries it alone. */
@media (max-width: 560px) {
  .op-flow-toggle-word { display: none; }
  .op-flow-toggle-btn { padding: 0 13px; }
}

/* The stage. One question at a time; the panel wipes in from the side it
   came from, so stepping back through the slug reads as going back. */
.op-flow-stage { padding: 12px 14px; }
.op-flow-panel { display: none; align-items: center; gap: 10px; flex-wrap: wrap; }
.op-flow-panel.is-on { display: flex; }
@keyframes op-panel-fwd {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes op-panel-back {
  from { opacity: 0; transform: translateX(-14px); }
  to   { opacity: 1; transform: none; }
}
.op-flow-stage[data-dir="fwd"] .op-flow-panel.is-on  { animation: op-panel-fwd 300ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.op-flow-stage[data-dir="back"] .op-flow-panel.is-on { animation: op-panel-back 300ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
/* Refused: knock the panel back once so the error under it reads as
   being about the question still on the stage. */
@keyframes op-refuse {
  0%, 100% { transform: none; }
  20% { transform: translateX(-5px); }
  55% { transform: translateX(4px); }
  80% { transform: translateX(-2px); }
}
.op-flow-panel.is-refused { animation: op-refuse 260ms ease-in-out both; }

/* Two-option answers. Picking one answers the step, so there is no
   confirm here — the choice IS the click. */
.op-flow-seg { display: inline-flex; border: 1px solid var(--border); }
.op-flow-opt {
  background: var(--surface-2); color: var(--text-dim); border: none;
  padding: 8px 15px; font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: background var(--transition), color var(--transition);
}
.op-flow-opt + .op-flow-opt { border-left: 1px solid var(--border); }
.op-flow-opt:hover { color: var(--text); background: var(--border); }
.op-flow-opt.is-on { background: var(--accent); color: var(--on-accent); }
.op-flow-opt.is-on:hover { background: var(--accent-dim); }

.op-flow-name { min-width: 220px; }
/* Continue. Squared red block, cut corner — the same shape language as
   the primary button, sized down to a step rather than a finish. */
.op-flow-next {
  background: var(--accent); color: var(--on-accent);
  border: none; border-radius: 1px;
  padding: 0 13px; height: 35px; line-height: 1;
  font-size: 15px; font-family: var(--font-display); cursor: pointer;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%);
  transition: background var(--transition);
}
.op-flow-next:hover { background: var(--accent-dim); }
.op-flow-hint { font-size: 12px; color: var(--text-dim); }
/* The app's focus ring is red, which disappears on anything already filled
   red — those controls take an ink ring instead. */
.op-flow-opt.is-on:focus-visible,
.op-flow-chip.is-active:focus-visible,
.op-flow-next:focus-visible { outline-color: var(--text); }

.op-own-input {
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 8px 10px; font-size: 14px; font-family: inherit;
}
.op-own-count { cursor: pointer; }
.op-own-count-wrap { display: inline-flex; align-items: center; gap: 6px; }
.op-own-count-label { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
/* Date-range + filter controls (OpeningTree-style download form) */
.op-own-range-wrap { display: inline-flex; align-items: center; gap: 6px; }
.op-own-range-label { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.op-own-month { padding: 6px 8px; font-size: 13px; cursor: pointer; color-scheme: dark; }
.op-own-filter { padding: 6px 8px; font-size: 13px; cursor: pointer; }
.op-own-status { font-size: 13px; color: var(--text-dim); }
.op-own-status--error { color: #c75c4e; }
.op-own-status.is-busy { color: var(--text); }
/* Inside the flow the status is a footer under the stage, and it only
   takes room when it has something to say. */
.op-flow .op-own-status { padding: 0 14px 12px; }
.op-flow .op-own-status:empty { display: none; }

/* Small inline spinner for status text / the analyze button during long loads.
   Reuses the shared `spin` keyframes. */
.op-spinner-inline {
  display: inline-block;
  width: 13px; height: 13px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  vertical-align: -2px;
  margin-right: 6px;
}

.op-empty, .op-loading {
  color: var(--text-dim); font-size: 13px; font-style: italic;
  padding: 8px 4px;
}

/* A rate limit is a wait, not a failure. The countdown is what tells a
   first-time visitor the site isn't broken — quieter than the message it
   follows, and it removes itself when the wait is over. */
.op-retry-countdown, .pun-retry-countdown {
  margin-top: 6px;
  font-size: 12px;
  font-style: normal;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  letter-spacing: 0.02em;
}
.op-retry-countdown:empty, .pun-retry-countdown:empty { display: none; }

.op-rep-panel.hidden { display: none; }
.op-rep-list { display: flex; flex-direction: column; gap: 4px; }
.op-rep-item {
  display: flex; align-items: stretch; gap: 4px;
}
.op-rep-load {
  flex: 1; background: transparent; border: 1px solid transparent;
  border-radius: 2px; padding: 8px 10px; text-align: left; cursor: pointer;
  color: var(--text); font-family: inherit;
  display: flex; flex-direction: column; gap: 2px;
}
.op-rep-load:hover { background: var(--bg); border-color: var(--accent); }
.op-rep-name { font-size: 13px; font-weight: 600; }
.op-rep-meta { font-size: 11px; color: var(--text-dim); }
.op-rep-delete {
  background: transparent; border: 1px solid var(--border); border-radius: 2px;
  color: var(--text-dim); width: 28px; cursor: pointer; font-size: 16px;
  line-height: 1; font-family: inherit;
  transition: color 0.12s, border-color 0.12s;
}
.op-rep-delete:hover { color: #e25555; border-color: #e25555; }


/* ============================================================
   Inline-style extractions from index.html (review cleanup)
   ============================================================ */
.logo-accent { color: var(--accent); }

.coaches-sticky-head {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
  padding-bottom: 4px;
}

.coaches-header-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-shrink: 0;
}

.back-to-dash { margin-bottom: 16px; }

.btn-full { width: 100%; }

.btn-analyze-position {
  margin-top: 10px;
  font-size: 13px;
}

.btn-dev-mock {
  margin-top: 6px;
  font-size: 12px;
  border-color: #b8860b;
  color: #b8860b;
}

.btn-endgame-transition {
  margin-top: 6px;
  font-size: 13px;
}

.saved-plans-title { margin-top: 0; }

.cb-preview-name { margin-top: 6px; }

.cb-preview-bio {
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-dim);
}

.cb-weights-title { margin-bottom: 0; }

.settings-reset-dev {
  margin-top: 8px;
  width: 100%;
}

body.dragging-piece {
  overflow: hidden;
  touch-action: none;
  overscroll-behavior: none;
}

/* Post-game modal */
.pvc-modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  backdrop-filter: blur(2px);
  animation: fadeIn 200ms ease-out;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.pvc-modal-content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px;
  box-shadow: var(--shadow-lg);
  max-width: 420px;
  width: 90%;
  animation: slideUp 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.pvc-modal-header {
  padding: 20px 24px 0;
  border-bottom: 1px solid var(--border);
}

.pvc-modal-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
}

.pvc-modal-body {
  padding: 20px 24px;
}

.pvc-game-result-message {
  font-size: 16px;
  font-weight: 600;
  color: var(--accent);
  text-align: center;
  margin-bottom: 20px;
}

.pvc-game-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 24px;
  padding: 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
}

.pvc-game-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pvc-game-stat-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-dim);
}

.pvc-game-stat-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

.pvc-modal-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 16px;
}

.pvc-modal-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 14px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--text-dim);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: all var(--transition);
}

.pvc-modal-action:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--surface);
}

.pvc-modal-action.btn-primary {
  grid-column: 1 / -1;
  flex-direction: row;
  padding: 12px 18px;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
}

.pvc-modal-action.btn-primary:hover {
  background: var(--accent-dim);
  border-color: transparent;
}

.pvc-modal-action-icon {
  font-size: 18px;
}

.pvc-modal-close-link {
  display: block;
  margin-top: 8px;
  padding: 8px 0;
  background: none;
  border: none;
  color: var(--text-dim);
  font-family: var(--font-body);
  font-size: 12px;
  cursor: pointer;
  text-align: center;
  width: 100%;
  transition: color var(--transition);
}

.pvc-modal-close-link:hover {
  color: var(--accent);
}


/* ============================================================
   SIDEBAR NAVIGATION (Draft A layout)
   Desktop signed-in: fixed left rail; topbar hidden.
   Mobile: existing topbar + hamburger; mobileNav gains groups.
   ============================================================ */
:root {
  --sidenav-w: 232px;
}

.sidenav {
  display: none;
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: var(--sidenav-w);
  z-index: 30;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  padding: 18px 12px 14px;
  overflow-y: auto;
}
@media (min-width: 1001px) {
  body.sidenav-on .sidenav { display: flex; }
  body.sidenav-on { padding-left: var(--sidenav-w); }
  body.sidenav-on .topbar { display: none; }
}

.sidenav-logo {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-display);
  font-weight: 700; font-size: 15px; letter-spacing: 0.04em;
  color: var(--text);
  padding: 2px 8px 16px;
  cursor: pointer;
}
.sidenav-logo .logo-icon {
  width: 28px; height: 28px; font-size: 16px; border-radius: 2px;
}
.sidenav-body { display: flex; flex-direction: column; flex: 1; }
.sidenav-group { margin-top: 14px; }
.sidenav-group:first-child { margin-top: 0; }
.sidenav-label {
  font-family: var(--font-body);
  font-weight: 600; font-size: 10px; line-height: 1;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 10px 7px;
}
.sidenav a {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-body);
  font-weight: 500; font-size: 13.5px; line-height: 1;
  color: var(--text-dim);
  text-decoration: none;
  padding: 8px 10px;
  border-radius: 2px;
  border-left: 2px solid transparent;
  transition: background var(--transition), color var(--transition);
}
.sidenav a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.sidenav a.active {
  color: var(--text);
  background: var(--surface-2);
  border-left-color: var(--accent);
}
.sidenav a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.sn-ic { width: 18px; flex: none; text-align: center; opacity: 0.8; }
.sn-ic svg, .bt-ic svg, .guide-row-ic svg, .guide-icon svg { display: block; margin: 0 auto; }
.sidenav a.sn-special .sn-ic, .mobile-nav a.sn-special .sn-ic { color: var(--accent); opacity: 1; }
.sn-soon {
  margin-left: auto;
  font-size: 9px; font-weight: 600; letter-spacing: 0.12em;
  color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 3px 6px;
}
.sidenav-foot {
  margin-top: auto;
  display: flex; align-items: center; gap: 10px;
  padding: 14px 8px 0;
  border-top: 1px solid var(--border);
  cursor: pointer;
}
.sidenav-foot .avatar {
  width: 30px; height: 30px; flex: none;
  background: var(--accent); border-radius: 50%;
  color: var(--on-accent);
  display: grid; place-items: center;
  font-weight: 700; font-size: 12px;
}
[data-theme="light"] .sidenav-foot .avatar { color: var(--on-accent); }
.sidenav-foot-who { font-size: 12px; line-height: 1.35; min-width: 0; }
.sidenav-foot-who b { display: block; color: var(--text); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidenav-foot-who span { color: var(--text-dim); }
.sidenav-foot:hover .sidenav-foot-who span { color: var(--accent); }
.sidenav-foot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* Grouped mobile nav — reuse sidenav vocabulary inside the dropdown */
.mobile-nav .sidenav-label { padding: 10px 14px 4px; }
.mobile-nav-group { border-bottom: 1px solid var(--border); padding-bottom: 6px; }
.mobile-nav-group:last-child { border-bottom: none; }
.mobile-nav a {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-body);
  text-transform: none; letter-spacing: 0;
  font-size: 14px; font-weight: 500;
  border-bottom: none;
  padding: 9px 14px;
}
.mobile-nav .sn-ic { width: 18px; flex: none; text-align: center; opacity: 0.8; }
.mobile-nav .sn-soon {
  margin-left: auto;
  font-size: 9px; font-weight: 600; letter-spacing: 0.12em;
  color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 3px 6px;
}

/* ============================================================
   HOME (Draft A): two doors, resume strip, coach note, shelf
   ============================================================ */
.hm-doors { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.hm-door {
  position: relative; overflow: hidden;
  display: block; text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 28px 24px;
  min-height: 190px;
  width: 100%;
  color: var(--text);
  font-family: var(--font-body);
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}
.hm-door:hover, .hm-door:focus-visible {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: 0 0 24px var(--accent-glow);
}
.hm-door:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hm-door-eyebrow {
  font-weight: 600; font-size: 11px; line-height: 1;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 13px;
  display: flex; align-items: center; gap: 8px;
}
.hm-door-eyebrow::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.hm-door h2 {
  font-family: var(--font-display);
  font-weight: 600; font-size: 24px; letter-spacing: 0.02em;
  margin: 0 0 8px; max-width: 70%;
}
.hm-door p { color: var(--text-dim); max-width: 62%; font-size: 14px; margin: 0; }
.hm-door-cta {
  margin-top: 18px; display: inline-flex; align-items: center; gap: 8px;
  font-weight: 600; font-size: 13px; color: var(--accent-dim);
}
.hm-door-cta .hm-arr { transition: transform var(--transition); }
.hm-door:hover .hm-door-cta .hm-arr { transform: translateX(4px); }
.hm-door-board {
  position: absolute; top: -12%; right: -70px;
  width: 210px; height: 210px;
  background:
    conic-gradient(var(--sq-dark) 90deg, var(--sq-light) 90deg 180deg,
                   var(--sq-dark) 180deg 270deg, var(--sq-light) 270deg);
  background-size: 25% 25%;
  border-radius: 2px;
  transform: rotate(8deg);
  opacity: 0.45;
  -webkit-mask-image: linear-gradient(255deg, #000 30%, transparent 75%);
  mask-image: linear-gradient(255deg, #000 30%, transparent 75%);
  transition: opacity var(--transition);
  pointer-events: none;
}
.hm-door:hover .hm-door-board { opacity: 0.8; }
.hm-door-piece {
  position: absolute; top: 24px; right: 34px;
  font-size: 50px; line-height: 1;
  color: var(--bg);
  text-shadow: 0 1px 0 rgba(232,228,216,0.25);
  transform: rotate(8deg);
  pointer-events: none;
}
.hm-door--multi .hm-door-piece { color: #efe6d2; text-shadow: 0 2px 6px rgba(0,0,0,0.55); }

.hm-resume {
  margin-top: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px;
}
.hm-resume-head { display: flex; align-items: center; gap: 12px; }
.hm-resume-head .hm-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--accent); box-shadow: 0 0 8px var(--accent-glow);
}
.hm-resume-head h3 { font-size: 14.5px; font-weight: 600; margin: 0; font-family: var(--font-body); }
.hm-resume-head h3 span { color: var(--text-dim); font-weight: 400; }
.hm-resume-head button {
  margin-left: auto; flex: none;
  background: none; border: none;
  font-family: var(--font-body);
  font-weight: 600; font-size: 13px; color: var(--accent-dim);
  padding: 4px 2px;
}
.hm-resume-head button:hover { color: var(--accent); }
.hm-resume-chips {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 13px; padding-top: 13px;
  border-top: 1px solid var(--border);
}
.hm-resume-chips .hm-chip {
  font-size: 12px; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 5px 11px;
}
.hm-resume-chips .hm-chip b { color: var(--accent-dim); font-weight: 600; }

.hm-coach-note {
  margin-top: 20px;
  display: flex; align-items: flex-start; gap: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 17px 20px;
}
.hm-coach-note .hm-seal {
  width: 44px; height: 44px; border-radius: 50%; flex: none;
  border: 1px solid rgba(201,146,42,0.5); color: var(--accent);
  background: var(--surface-2);
  display: grid; place-items: center; font-size: 22px;
}
.hm-coach-note-who {
  font-weight: 600; font-size: 11px; line-height: 1;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.hm-coach-note-who span { color: var(--text-dim); }
.hm-coach-change {
  background: none; border: none; padding: 0;
  font-family: var(--font-body);
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  color: var(--text-dim); text-transform: none;
}
.hm-coach-change:hover { color: var(--accent); }
.hm-coach-note p {
  margin: 6px 0 0; font-size: 14.5px; font-style: italic;
  color: var(--text); max-width: 62ch;
}
.hm-coach-go {
  margin-left: auto; flex: none; align-self: center;
  font-family: var(--font-body);
  font-weight: 600; font-size: 13px; line-height: 1;
  color: #16120a;
  background: var(--accent); border: none; border-radius: 2px;
  padding: 11px 17px;
  transition: background var(--transition), box-shadow var(--transition);
}
[data-theme="light"] .hm-coach-go { color: var(--on-accent); }
.hm-coach-go:hover { background: var(--accent-dim); box-shadow: 0 0 16px var(--accent-glow); }
.hm-coach-go:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.hm-rack { margin-top: 40px; }
.hm-rack-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.hm-rack-head h3 {
  font-family: var(--font-body);
  font-weight: 600; font-size: 11px; line-height: 1;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-dim); margin: 0;
}
.hm-rack-head .hm-rule { flex: 1; height: 1px; background: var(--border); }
.hm-src-toggle {
  display: flex; gap: 2px; flex: none;
  border: 1px solid var(--border); border-radius: 2px; padding: 2px;
}
.hm-src-toggle button {
  font-family: var(--font-body);
  font-weight: 600; font-size: 10.5px; line-height: 1;
  letter-spacing: 0.08em;
  color: var(--text-dim); background: none; border: none; border-radius: 2px;
  padding: 5px 11px;
  transition: color var(--transition), background var(--transition);
}
.hm-src-toggle button:hover { color: var(--text); }
.hm-src-toggle button.is-on { color: var(--accent-dim); background: var(--surface-2); }
.hm-src-toggle button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.hm-shelf-hint { margin-top: 10px; font-size: 12px; color: var(--text-dim); }

.hm-shelf { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.hm-card {
  display: flex; flex-direction: column; align-items: center; gap: 11px;
  padding: 16px 12px 13px;
  background: none;
  border: 1px solid var(--border); border-radius: var(--radius);
  font-family: var(--font-body); color: var(--text);
  transition: border-color var(--transition), background var(--transition), transform var(--transition);
}
.hm-card:hover, .hm-card:focus-visible {
  border-color: var(--accent); background: var(--surface);
  transform: translateY(-2px);
}
.hm-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hm-thumb {
  width: 126px; height: 126px; border-radius: 2px; overflow: hidden;
  display: block; flex: none;
  border: 1px solid var(--border);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.hm-card:hover .hm-thumb { border-color: rgba(201,146,42,0.6); box-shadow: 0 0 18px var(--accent-glow); }
.hm-mini {
  width: 100%; height: 100%; display: grid;
  grid-template-columns: repeat(8, 1fr); grid-template-rows: repeat(8, 1fr);
}
.hm-mini .hm-sq { display: grid; place-items: center; font-size: 12px; line-height: 1; }
.hm-mini .hm-sq.l { background: var(--sq-light); }
.hm-mini .hm-sq.d { background: var(--sq-dark); }
.hm-mini .hm-sq.wpc { color: #f7f1e1; text-shadow: 0 1px 1px rgba(0,0,0,0.6); }
.hm-mini .hm-sq.bpc { color: #17130d; text-shadow: 0 1px 0 rgba(232,228,216,0.2); }
.hm-meta { text-align: center; }
.hm-meta b { display: block; font-size: 13px; font-weight: 600; max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hm-meta span { font-size: 12px; color: var(--text-dim); }
.hm-meta .hm-res { font-weight: 600; }
.hm-meta .hm-res.win { color: var(--accent-dim); }
.hm-shelf-status {
  grid-column: 1 / -1;
  color: var(--text-dim); font-size: 13px; font-style: italic;
  padding: 14px 4px;
}

/* ---- Getting-started checklist (onboarding.js) ---- */
.hm-onb {
  margin: 0 0 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px 10px;
}
.hm-onb-head { display: flex; align-items: center; gap: 12px; }
.hm-onb-head h3 {
  font-family: var(--font-body);
  font-size: 11px; font-weight: 600; line-height: 1;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}
.hm-onb-count { font-size: 12px; color: var(--text-dim); flex: none; }
.hm-onb-bar {
  flex: 1; height: 3px; border-radius: 2px;
  background: var(--surface-2); overflow: hidden;
}
.hm-onb-bar span {
  display: block; height: 100%;
  background: var(--accent);
  border-radius: 2px;
  transition: width var(--transition);
}
.hm-onb-hide {
  flex: none;
  background: none; border: none; padding: 2px 4px;
  font-size: 13px; line-height: 1;
  color: var(--text-dim);
}
.hm-onb-hide:hover { color: var(--text); }
.hm-onb-steps { margin-top: 6px; }
.hm-onb-step {
  display: flex; align-items: center; gap: 12px;
  width: 100%; text-align: left;
  background: none; border: none;
  border-top: 1px solid var(--border);
  padding: 10px 2px;
  font-family: var(--font-body);
  color: var(--text);
}
.hm-onb-step:first-child { border-top: none; }
.hm-onb-mark {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 50%;
  font-size: 11px; font-weight: 600;
  color: var(--text-dim);
}
.hm-onb-step.is-done .hm-onb-mark {
  border-color: rgba(201,146,42,0.5);
  color: var(--accent);
  background: var(--surface-2);
}
.hm-onb-step.is-done .hm-onb-text b { color: var(--text-dim); font-weight: 400; }
.hm-onb-step.is-next .hm-onb-mark {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}
.hm-onb-text { min-width: 0; }
.hm-onb-text b { display: block; font-size: 13.5px; font-weight: 600; }
.hm-onb-text span { display: block; font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.hm-onb-cta {
  margin-left: auto; flex: none;
  font-size: 13px; font-weight: 600;
  color: var(--accent-dim);
}
.hm-onb-step.is-next:hover .hm-onb-cta { color: var(--accent); }
.hm-onb-step:disabled { cursor: default; }

@media (max-width: 880px) {
  .hm-doors { grid-template-columns: 1fr; }
  .hm-door p, .hm-door h2 { max-width: 100%; }
  .hm-shelf { grid-template-columns: 1fr 1fr; }
  .hm-coach-note { flex-wrap: wrap; }
  .hm-coach-go { margin-left: 60px; align-self: flex-start; }
  .hm-onb-step.is-next { flex-wrap: wrap; }
  .hm-onb-cta { margin-left: 34px; }
}
@media (max-width: 560px) {
  .hm-shelf { grid-template-columns: 1fr 1fr; gap: 10px; }
  .hm-thumb { width: 104px; height: 104px; }
}

/* ============================================================
   CLONE AN OPPONENT
   Hero + forge pipeline (doubles as live build progress) +
   setup card + roster of existing clones.
   ============================================================ */
.clone-setup { max-width: 640px; margin: 8px auto 0; padding: 0 4px; }
.clone-back { margin-bottom: 24px; }

.clone-hero { text-align: center; margin-bottom: 30px; }
.clone-mask {
  width: 54px; height: 54px;
  margin: 6px auto 22px;
  display: grid; place-items: center;
  background: var(--surface-2);
  border: 1px solid rgba(201,146,42,0.5);
  border-radius: 2px;
  transform: rotate(45deg);
  box-shadow: 0 0 22px var(--accent-glow);
}
.clone-mask > span {
  transform: rotate(-45deg);
  font-size: 25px; line-height: 1;
}
.clone-title {
  font-family: var(--font-display);
  font-size: 1.7rem; font-weight: 700; letter-spacing: 0.02em;
  color: var(--text);
  margin: 0 0 10px;
}
.clone-sub {
  font-size: 14px; line-height: 1.6;
  color: var(--text-dim);
  max-width: 46ch;
  margin: 0 auto;
}

/* ---- Forge pipeline: the 4 real build phases as diamond stations ---- */
.clone-pipeline {
  list-style: none;
  display: flex; align-items: center;
  margin: 0 2px 18px; padding: 0;
}
.clone-step { display: flex; align-items: center; gap: 9px; }
.clone-step + .clone-step { flex: 1; justify-content: flex-end; }
.clone-step + .clone-step::before {
  content: "";
  flex: 1; height: 1px;
  background: var(--border);
  margin: 0 14px;
  transition: background var(--transition);
}
.clone-step-num {
  width: 21px; height: 21px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface);
  transform: rotate(45deg);
  transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}
.clone-step-num > span {
  transform: rotate(-45deg);
  font-family: var(--font-mono);
  font-size: 10px; line-height: 1;
  color: var(--text-dim);
  transition: color var(--transition);
}
.clone-step-name {
  font-size: 10.5px; font-weight: 600; line-height: 1;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-dim);
  transition: color var(--transition);
}
.clone-step.is-active .clone-step-num,
.clone-step.is-done .clone-step-num { border-color: var(--accent); }
.clone-step.is-done .clone-step-num { background: var(--accent-muted); }
.clone-step.is-active .clone-step-num > span,
.clone-step.is-done .clone-step-num > span { color: var(--accent-dim); }
.clone-step.is-active .clone-step-name,
.clone-step.is-done .clone-step-name { color: var(--accent-dim); }
.clone-step.is-done + .clone-step::before { background: var(--accent); opacity: 0.5; }
.clone-step.is-active .clone-step-num { animation: cloneForge 1.6s ease-in-out infinite; }
@keyframes cloneForge {
  0%, 100% { box-shadow: 0 0 4px var(--accent-glow); }
  50%      { box-shadow: 0 0 16px var(--accent-glow); }
}
@media (prefers-reduced-motion: reduce) {
  .clone-step.is-active .clone-step-num {
    animation: none;
    box-shadow: 0 0 10px var(--accent-glow);
  }
}

/* ---- Setup card ---- */
.clone-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px 28px;
  box-shadow: var(--shadow);
}
.clone-field { margin-bottom: 20px; }
.clone-label {
  display: block;
  font-size: 11px; font-weight: 600; line-height: 1;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 9px;
}

/* Platform: segmented control (real radios underneath) */
.clone-seg {
  display: inline-flex; gap: 2px;
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 3px;
}
.clone-seg-opt { position: relative; }
.clone-seg-opt input {
  position: absolute; inset: 0;
  width: 100%; height: 100%; margin: 0;
  opacity: 0; cursor: pointer;
}
.clone-seg-opt span {
  display: block;
  padding: 7px 18px;
  border-radius: 2px;
  font-size: 12.5px; font-weight: 600; line-height: 1;
  color: var(--text-dim);
  transition: color var(--transition), background var(--transition);
}
.clone-seg-opt:hover span { color: var(--text); }
.clone-seg-opt input:checked + span { color: var(--accent-dim); background: var(--surface-2); }
.clone-seg-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Username: the centerpiece — fixed gold @ prefix, mono handle */
.clone-handle {
  display: flex; align-items: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.clone-handle:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.clone-at {
  font-family: var(--font-display);
  font-size: 20px; font-weight: 700;
  color: var(--accent);
  padding: 0 5px 0 14px;
  user-select: none;
}
.clone-handle input {
  flex: 1; min-width: 0;
  background: none; border: none; outline: none;
  font-family: var(--font-mono);
  font-size: 16px;
  color: var(--text);
  padding: 13px 14px 13px 6px;
}
.clone-handle input::placeholder { color: var(--gray); }

/* Games to scan: chip row (real radios underneath) */
.clone-scan {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}
.clone-scan-opt { position: relative; }
.clone-scan-opt input {
  position: absolute; inset: 0;
  width: 100%; height: 100%; margin: 0;
  opacity: 0; cursor: pointer;
}
.clone-scan-box {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 10px 4px 8px;
  border: 1px solid var(--border);
  border-radius: 2px;
  transition: border-color var(--transition), background var(--transition);
}
.clone-scan-opt:hover .clone-scan-box { border-color: var(--text-dim); }
.clone-scan-box b {
  font-family: var(--font-mono);
  font-size: 13.5px; font-weight: 600; line-height: 1;
  color: var(--text-dim);
  transition: color var(--transition);
}
.clone-scan-box small {
  font-size: 9.5px; line-height: 1;
  letter-spacing: 0.05em;
  color: var(--gray);
  transition: color var(--transition);
}
.clone-scan-opt input:checked + .clone-scan-box {
  border-color: var(--accent);
  background: var(--accent-muted);
}
.clone-scan-opt input:checked + .clone-scan-box b { color: var(--accent-dim); }
.clone-scan-opt input:checked + .clone-scan-box small { color: var(--text-dim); }
.clone-scan-opt input:focus-visible + .clone-scan-box { outline: 2px solid var(--accent); outline-offset: 1px; }

.clone-build { width: 100%; margin-top: 4px; padding: 14px 22px; font-size: 13px; }
.clone-build:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Build progress + status line */
.clone-progress {
  height: 4px;
  margin-top: 18px;
  background: var(--surface-2);
  border-radius: 2px;
  overflow: hidden;
}
.clone-progress-bar {
  height: 100%; width: 0;
  background: var(--accent);
  border-radius: 2px;
  transition: width 300ms ease;
}
.clone-status {
  margin-top: 12px;
  font-size: 13px; text-align: center;
  color: var(--text-dim);
}
.clone-status--error { color: #d9705f; }
[data-theme="light"] .clone-status--error { color: #a33224; }

/* ---- Roster of existing clones ---- */
.clone-roster { margin-top: 36px; }
.clone-roster-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.clone-roster-head h3 {
  font-family: var(--font-body);
  font-weight: 600; font-size: 11px; line-height: 1;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-dim);
  margin: 0;
}
.clone-roster-head .clone-rule { flex: 1; height: 1px; background: var(--border); }
.clone-roster-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.clone-chip {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  transition: border-color var(--transition);
}
.clone-chip:hover { border-color: var(--accent); }
.clone-chip-mask {
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  font-size: 18px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.clone-chip-who { flex: 1; min-width: 0; }
.clone-chip-name {
  display: block;
  font-family: var(--font-mono);
  font-size: 13.5px; font-weight: 600;
  color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.clone-chip-elo {
  display: block;
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 3px;
}
.clone-chip-play {
  flex: none;
  background: var(--accent);
  color: var(--on-accent);
  border: none; border-radius: 2px;
  font-family: var(--font-display);
  font-weight: 700; font-size: 11px; line-height: 1;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 9px 16px;
  transition: background var(--transition);
}
[data-theme="light"] .clone-chip-play { color: var(--on-accent); }
.clone-chip-play:hover { background: var(--accent-dim); }
.clone-chip-play:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.clone-chip-del {
  flex: none;
  background: none; border: none;
  color: var(--text-dim);
  font-size: 13px; line-height: 1;
  padding: 7px 8px;
  border-radius: 2px;
  transition: color var(--transition), background var(--transition);
}
.clone-chip-del:hover { color: #d9705f; background: var(--surface-2); }
.clone-chip-del:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.clone-chip-info {
  flex: none;
  background: none; border: none;
  color: var(--text-dim);
  font-size: 14px; line-height: 1;
  padding: 7px 6px;
  border-radius: 2px;
  transition: color var(--transition), background var(--transition);
}
.clone-chip-info:hover { color: var(--accent-dim); background: var(--surface-2); }
.clone-chip-info.is-open { color: var(--accent-dim); background: var(--surface-2); }
.clone-chip-info:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---- "What this clone learned" panel (ⓘ) ---- */
.clone-info {
  grid-column: 1 / -1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin-top: -4px;
}
.clone-info.hidden { display: none; }
.clone-info-head {
  font-family: var(--font-body);
  font-weight: 600; font-size: 10.5px; line-height: 1;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 14px;
}
.clone-info-facts { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.clone-fact {
  display: flex; flex-direction: column; gap: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 7px 11px;
}
.clone-fact b { font-family: var(--font-mono); font-size: 12.5px; font-weight: 600; color: var(--text); }
.clone-fact small { font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); }
.clone-w-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.clone-w-row { display: grid; grid-template-columns: minmax(0, 1fr) 90px 38px; align-items: center; gap: 12px; }
.clone-w-name { min-width: 0; display: flex; align-items: baseline; gap: 7px; font-size: 12.5px; color: var(--text); }
.clone-w-icon { flex: none; color: var(--text-dim); }
.clone-w-name small { font-size: 11px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.clone-w-bar { height: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; }
.clone-w-bar i { display: block; height: 100%; background: var(--accent); opacity: 0.75; border-radius: 3px; }
.clone-w-val { font-family: var(--font-mono); font-size: 12px; color: var(--accent-dim); text-align: right; }
.clone-info-note { font-size: 11.5px; line-height: 1.5; color: var(--text-dim); margin: 13px 0 0; }

@media (max-width: 640px) {
  .clone-pipeline {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 10px 16px;
    margin-bottom: 16px;
  }
  .clone-step + .clone-step { flex: none; justify-content: flex-start; }
  .clone-step + .clone-step::before { display: none; }
  .clone-card { padding: 20px 18px; }
  .clone-scan { grid-template-columns: repeat(3, 1fr); }
  .clone-roster-grid { grid-template-columns: 1fr; }
  .clone-w-row { grid-template-columns: minmax(0, 1fr) 56px 38px; gap: 8px; }
  .clone-w-name small { display: none; }
}

/* ============================================================
   THE CLUB (players.js) — roster of fixed-Elo sparring players
   ============================================================ */
.club-screen { max-width: 860px; margin: 8px auto 0; padding: 0 4px 90px; }
.club-back { margin-bottom: 24px; }

.club-hero { text-align: center; margin-bottom: 30px; }
.club-crest {
  width: 54px; height: 54px;
  margin: 6px auto 22px;
  display: grid; place-items: center;
  font-size: 26px; line-height: 1;
  background: var(--surface-2);
  border: 1px solid rgba(201,146,42,0.5);
  border-radius: 50%;
  box-shadow: 0 0 22px var(--accent-glow);
}
.club-title {
  font-family: var(--font-display);
  font-size: 1.7rem; font-weight: 700; letter-spacing: 0.02em;
  color: var(--text);
  margin: 0 0 10px;
}
.club-sub {
  font-size: 14px; line-height: 1.6;
  color: var(--text-dim);
  max-width: 52ch;
  margin: 0 auto;
}

/* Spotlight — chess.com-style detail panel for the selected player */
.club-spotlight {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow);
  margin-bottom: 20px;
}
.club-spot-top { display: flex; align-items: flex-start; gap: 16px; }
.club-spot-avatar {
  width: 64px; height: 64px; flex: none;
  display: grid; place-items: center;
  font-size: 38px; line-height: 1;
  background: var(--surface-2);
  border: 1px solid rgba(201,146,42,0.45);
  border-radius: 2px;
}
.club-spot-main { flex: 1; min-width: 0; }
.club-spot-bubble {
  position: relative;
  font-size: 13.5px; font-style: italic; line-height: 1.45;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 10px 14px;
}
.club-spot-bubble::before {
  content: '';
  position: absolute; left: -6px; top: 20px;
  width: 10px; height: 10px;
  background: var(--surface-2);
  border-left: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  transform: rotate(45deg);
}
.club-spot-id {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 10px; margin-top: 10px;
}
.club-spot-name {
  font-family: var(--font-display);
  font-size: 1.15rem; font-weight: 700;
  color: var(--text);
}
.club-spot-bio {
  font-size: 13px; line-height: 1.55;
  color: var(--text-dim);
  margin: 12px 0 0;
}
.club-spotlight .club-tags { margin-top: 12px; }

/* Roster grid — compact selectable tiles, 3 wide on desktop */
.club-ladder {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.club-card {
  display: flex; flex-direction: column; align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 10px 14px;
  box-shadow: var(--shadow);
  cursor: pointer;
  font: inherit; color: inherit; text-align: center;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.club-card:hover { border-color: var(--accent); }
.club-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.club-card.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 18px var(--accent-glow);
}

.club-avatar {
  width: 52px; height: 52px; flex: none;
  display: grid; place-items: center;
  font-size: 30px; line-height: 1;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.club-card.selected .club-avatar { border-color: rgba(201,146,42,0.45); }
.club-name {
  font-family: var(--font-display);
  font-size: 1rem; font-weight: 700;
  color: var(--text);
}
.club-elo {
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 700; line-height: 1;
  color: var(--accent-dim);
  border: 1px solid rgba(201,146,42,0.45);
  border-radius: 2px;
  padding: 4px 9px;
}
.club-card-record {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
}

.club-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.club-tag {
  font-size: 10.5px; font-weight: 600; line-height: 1;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 5px 9px;
}
.club-record {
  flex: none;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-dim);
}
.club-record--none { font-style: italic; font-family: inherit; }
.club-rec-w { color: var(--accent-dim); }
.club-rec-l { color: #d9705f; }
.club-rec-d { color: var(--text-dim); }

/* Action bar — always visible, sticky above the bottom edge */
.club-actionbar {
  position: sticky; bottom: 12px; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-top: 20px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 -4px 24px rgba(0,0,0,0.45), var(--shadow);
}
.club-colors { display: flex; align-items: center; gap: 8px; }
.club-color-btn {
  font-size: 13px; font-weight: 600;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 9px 16px;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.club-color-btn:hover { border-color: var(--accent); background: var(--accent-muted); }
.club-color-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.club-color-btn.active {
  border-color: var(--accent);
  background: var(--accent-muted);
  color: var(--accent-dim);
}
.club-play {
  flex: none;
  font-size: 14px; font-weight: 700;
  padding: 11px 28px;
}

@media (max-width: 720px) {
  .club-ladder { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .club-spot-top { gap: 12px; }
  .club-spot-avatar { width: 52px; height: 52px; font-size: 30px; }
  .club-actionbar { flex-wrap: wrap; justify-content: center; }
  .club-color-btn { padding: 8px 12px; }
  .club-play { flex: 1 1 100%; }
}

/* Game Archive (played-games.js) — last 50 games played on-site */
.pg-page { max-width: 760px; margin: 0 auto; padding: 24px 20px 60px; }
.pg-header {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; margin-bottom: 20px;
}
.pg-header-actions { display: flex; gap: 8px; flex-shrink: 0; }
.pg-result { align-self: center; }
.pg-row-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.pg-del {
  background: none; border: none; color: var(--text-dim); cursor: pointer;
  font-size: 15px; line-height: 1; padding: 6px; border-radius: 2px;
}
.pg-del:hover { color: var(--danger); background: rgba(139,32,32,0.12); }

@media (max-width: 640px) {
  .pg-header { flex-direction: column; }
  .pg-row-actions .pg-review { display: none; } /* tap the row to open on mobile */
}

/* ============================================================
   OPENING PUNISHER (opening-punisher.js) — .pun-*
   ============================================================ */
.pun-stats {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 14px 18px; margin: 16px 0 18px;
}
.pun-stats-text { font-size: 13.5px; line-height: 1.5; }
.pun-stats-side { display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; }
.pun-solved-chip {
  font-size: 12px; font-weight: 700; color: var(--accent, #6fbf4d);
  background: var(--accent-muted); border-radius: 2px; padding: 4px 10px;
  white-space: nowrap;
}

/* The period this set has been scanned against. A saved line is a standing
   record, so what it covers is a fact about it, not a timestamp — set in the
   mono face the app uses for dates and stamped values elsewhere. */
.pun-period {
  font-family: var(--font-mono); font-size: 11.5px;
  color: var(--text-dim); white-space: nowrap;
  border: 1px solid var(--border); border-radius: 1px;
  padding: 3px 8px;
}
/* What an Update just did, dropped in under the stat line it changed. */
.pun-update-note {
  margin: -6px 0 14px; padding: 9px 12px;
  font-size: 13px; color: var(--text);
  background: var(--accent-muted);
  border-left: 3px solid var(--accent);
  border-radius: 0 2px 2px 0;
}
.pun-update-note--error { color: #c75c4e; }

/* The PGN export panel, in the same slot and the same voice as the Update note
   above it — this is another thing the set just did, not a dialog. Two states
   share the shell: a progress line with a Cancel, then the file with its two
   ways out. What is NOT in the file gets its own dim line rather than being
   folded into the headline count. */
.pun-export {
  margin: -6px 0 14px; padding: 11px 14px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: 0 2px 2px 0;
}
.pun-export-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px 16px; flex-wrap: wrap;
}
.pun-export-status { font-size: 13px; color: var(--text); }
.pun-export-status--error { color: #c75c4e; }
.pun-export-acts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pun-export-how {
  margin-top: 8px; font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
}
.pun-export-note {
  margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--text-dim);
}

.pun-group { margin-bottom: 18px; }
.pun-group-head {
  font-size: 13px; font-weight: 700; margin-bottom: 8px;
  display: flex; align-items: baseline; gap: 8px;
}
.pun-group-count {
  font-size: 11px; font-weight: 600; color: var(--text-dim);
  background: var(--border); border-radius: 2px; padding: 1px 8px;
}
.pun-cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 10px;
}
.pun-card {
  text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 12px 14px;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.pun-card:hover { border-color: var(--accent, #6fbf4d); transform: translateY(-1px); }
.pun-card--solved { opacity: 0.62; }
.pun-card-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 4px; }
.pun-card-move { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.pun-card-eval {
  font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--accent, #6fbf4d);
}
.pun-card-line { font-size: 13.5px; margin-bottom: 4px; }
.pun-card-sub { font-size: 11.5px; color: var(--text-dim); }
.pun-empty {
  text-align: center; color: var(--text-dim); font-size: 13.5px;
  padding: 36px 20px; border: 1px dashed var(--border); border-radius: 2px;
}

/* Drill: board + side panel */
.pun-drill {
  display: grid; grid-template-columns: minmax(280px, 480px) 1fr;
  gap: 22px; align-items: start; margin-top: 16px;
}
.pun-board { width: 100%; }
.pun-drill-panel { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.pun-banner {
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 2px; padding: 12px 16px;
}
.pun-banner-move { font-size: 14px; margin-bottom: 3px; }
.pun-banner-hint { font-size: 12.5px; color: var(--text-dim); }
.pun-feedback { font-size: 13.5px; min-height: 20px; }
.pun-wrong { color: var(--danger, #d06262); font-weight: 700; }
.pun-right { color: var(--accent, #6fbf4d); font-weight: 700; }
.pun-reveal {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 2px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 10px;
}
.pun-reveal-line { font-size: 14px; font-weight: 600; line-height: 1.6; }
.pun-reveal-eval {
  font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--accent, #6fbf4d); margin-right: 6px;
}
.pun-reveal-game { font-size: 12.5px; color: var(--text-dim); }
.pun-reveal-rarity { font-size: 12.5px; color: var(--text-dim); font-style: italic; min-height: 0; }
.pun-reveal-rarity:empty { display: none; }
.pun-reveal-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.pun-drill-actions { display: flex; gap: 8px; flex-wrap: wrap; }

@media (max-width: 760px) {
  .pun-drill { grid-template-columns: 1fr; }
  .pun-stats { flex-direction: column; align-items: flex-start; }
}

/* ============================================================
   GUIDE (guide.js), .guide-*
   Two views in one shell: an indexed table of contents (grouped to
   match the sidebar exactly) and a single-article detail page with
   prev/next paging. Swapped by re-rendering #view-guide's innerHTML.
   ============================================================ */
.guide-page { max-width: 780px; margin: 0 auto; padding: 24px 16px 48px; view-transition-name: guide-page; }
.guide-header { margin-bottom: 18px; }
.guide-header .review-title { font-family: var(--font-display); letter-spacing: 0.01em; }
.guide-actions { display: flex; }

/* Index <-> detail paging feels like turning to a page in a reference
   volume: content slides toward the direction of travel. Only runs when
   guide.js opts in (real navigation, not search-as-you-type) and the
   browser supports View Transitions; reduced-motion is checked in JS
   before this ever fires, so no separate CSS guard is needed. */
::view-transition-old(guide-page), ::view-transition-new(guide-page) {
  animation-duration: 240ms;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
[data-guide-nav="forward"]::view-transition-old(guide-page) { animation-name: guide-slide-out-l; }
[data-guide-nav="forward"]::view-transition-new(guide-page) { animation-name: guide-slide-in-r; }
[data-guide-nav="back"]::view-transition-old(guide-page) { animation-name: guide-slide-out-r; }
[data-guide-nav="back"]::view-transition-new(guide-page) { animation-name: guide-slide-in-l; }
@keyframes guide-slide-out-l { to { transform: translateX(-22px); opacity: 0; } }
@keyframes guide-slide-in-r { from { transform: translateX(22px); opacity: 0; } }
@keyframes guide-slide-out-r { to { transform: translateX(22px); opacity: 0; } }
@keyframes guide-slide-in-l { from { transform: translateX(-22px); opacity: 0; } }

/* --- search --- */
.guide-search-wrap { margin-bottom: 22px; }
.guide-search {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 11px 14px;
  border-radius: 2px;
  font-size: 14px;
  font-family: inherit;
}
.guide-search::placeholder { color: var(--text-dim); }
.guide-search:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
.guide-search::-webkit-search-cancel-button { cursor: pointer; }

/* --- index (table of contents) --- */
.guide-index { display: flex; flex-direction: column; gap: 22px; margin-bottom: 24px; }
.guide-group-label {
  font-family: var(--font-body);
  font-weight: 600; font-size: 11px; line-height: 1;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}
.guide-rows {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.guide-row {
  display: flex; align-items: center; gap: 13px;
  width: 100%;
  background: none; border: none;
  border-left: 2px solid transparent;
  padding: 12px 14px;
  text-align: left;
  color: var(--text);
  border-bottom: 1px solid var(--border);
  transition: background var(--transition), border-color var(--transition);
}
.guide-rows .guide-row:last-child { border-bottom: none; }
.guide-row:hover, .guide-row:focus-visible {
  background: var(--surface-2);
  border-left-color: var(--accent);
}
.guide-row:focus-visible { outline: none; }
.guide-row-ic {
  flex: 0 0 auto;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  font-size: 16px; line-height: 1;
  color: var(--accent);
  background: var(--accent-muted);
  border-radius: 2px;
}
.guide-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.guide-row-title { font-size: 14px; font-weight: 600; }
.guide-row-tag {
  font-size: 12.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.guide-row-chev { flex: 0 0 auto; color: var(--text-dim); font-size: 16px; }
.guide-row:hover .guide-row-chev, .guide-row:focus-visible .guide-row-chev { color: var(--accent); }
.guide-empty { color: var(--text-dim); font-size: 13.5px; text-align: center; padding: 28px 0; }

/* --- detail (single article) --- */
.guide-detail-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 16px; }
.guide-crumb-back {
  background: none; border: none; padding: 4px 0;
  color: var(--accent); font-size: 13.5px; font-weight: 600;
}
.guide-crumb-back:hover, .guide-crumb-back:focus-visible { color: var(--accent-dim); }
.guide-crumb-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.guide-crumb-group {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 2px;
  padding: 4px 10px;
}
.guide-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px; padding: 20px 22px;
}
.guide-card-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 14px; }
.guide-icon {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  font-size: 22px; line-height: 1;
  color: var(--accent);
  background: var(--accent-muted);
  border-radius: 2px;
}
.guide-card-title { margin: 0; font-size: 19px; font-family: var(--font-display); letter-spacing: 0.01em; }
.guide-tagline { margin: 2px 0 0; font-size: 13.5px; color: var(--text-dim); }
.guide-sections { display: flex; flex-direction: column; gap: 14px; }
.guide-section { padding-top: 12px; border-top: 1px solid var(--border); }
.guide-section:first-child { padding-top: 0; border-top: none; }
.guide-section-heading { font-size: 13px; font-weight: 700; margin-bottom: 4px; }
.guide-section-body { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--text-dim); }

/* --- prev / next pager --- */
.guide-pager { display: flex; gap: 12px; margin: 18px 0 24px; }
.guide-pager-btn {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 14px;
  text-align: left;
}
.guide-pager-next { text-align: right; align-items: flex-end; }
.guide-pager-btn:hover, .guide-pager-btn:focus-visible { border-color: var(--accent); }
.guide-pager-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.guide-pager-dir { font-size: 10.5px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.guide-pager-title {
  font-size: 13px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.guide-pager-empty { flex: 1; border: none; background: none; }

@media (max-width: 520px) {
  .guide-pager { flex-direction: column; }
  .guide-pager-empty { display: none; }
  .guide-pager-next { text-align: left; align-items: flex-start; }
}

/* ---- Opening Punisher: folder list ---- */
.pun-folders { display: flex; flex-direction: column; gap: 6px; margin: 14px 0 4px; }
.pun-folder {
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid var(--border); border-radius: 2px;
  background: var(--surface); overflow: hidden;
  transition: border-color 0.15s ease;
}
.pun-folder:hover { border-color: var(--accent, #6fbf4d); }
.pun-folder-open {
  flex: 1 1 auto; display: flex; align-items: center; gap: 11px;
  text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: none; border: none; padding: 8px 12px; min-width: 0;
  transition: background var(--transition, 0.15s ease);
}
.pun-folder-ic {
  flex: 0 0 auto; width: 28px; height: 28px; display: grid; place-items: center;
  font-size: 15px; border-radius: 2px;
  color: var(--accent, #6fbf4d); background: var(--accent-muted);
}
.pun-folder-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pun-folder-opening {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em;
  color: var(--accent, #6fbf4d); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pun-folder-label {
  font-size: 13.5px; font-weight: 700; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.pun-folder-sub { font-size: 11px; color: var(--text-dim); }
.pun-folder-count {
  margin-left: auto; flex: 0 0 auto; align-self: center;
  font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--text-dim); padding-right: 4px;
}
/* ---- red under the pointer, at every level of the tree --------------
   A branch row's label region and a set card's body both flood the
   accent on hover. It is deliberately the same gesture three levels
   deep — the thing you are about to open goes red — so a colour row,
   an opening row and a set read as one surface rather than three
   different kinds of control. Only the open-target floods: the buttons
   alongside it (Open/Hide, Review, the red drill) keep their own
   hovers, so nothing red ever lands on red. */
.pun-folder-caret,
.pun-folder-ic,
.pun-folder-opening,
.pun-folder-label,
.pun-folder-sub,
.pun-folder-count {
  transition: color var(--transition, 0.15s ease), background var(--transition, 0.15s ease);
}
.pun-folder-open:hover,
.pun-folder-open:focus-visible { background: var(--accent); }
.pun-folder-open:hover .pun-folder-caret,
.pun-folder-open:focus-visible .pun-folder-caret,
.pun-folder-open:hover .pun-folder-opening,
.pun-folder-open:focus-visible .pun-folder-opening,
.pun-folder-open:hover .pun-folder-label,
.pun-folder-open:focus-visible .pun-folder-label,
.pun-folder-open:hover .pun-folder-count,
.pun-folder-open:focus-visible .pun-folder-count { color: var(--on-accent); }
.pun-folder-open:hover .pun-folder-sub,
.pun-folder-open:focus-visible .pun-folder-sub { color: rgba(255, 255, 255, 0.78); }
/* The side chip carries its own tint (paper for White, ink for Black).
   On red it takes a neutral one so the two colours never fight. */
.pun-folder-open:hover .pun-folder-ic,
.pun-folder-open:focus-visible .pun-folder-ic {
  background: rgba(255, 255, 255, 0.16); color: var(--on-accent);
}

.pun-folder-del {
  flex: 0 0 auto; width: 32px; border: none; border-left: 1px solid var(--border);
  background: none; color: var(--text-dim); cursor: pointer; font-size: 13px;
}
.pun-folder-del:hover { color: var(--danger, #d06262); background: rgba(139,32,32,0.10); }
/* Row action — "drill everything under this row" when there is anything
   unsolved left, otherwise a plain "View". Sits before the ✕. */
.pun-folder-drill {
  flex: 0 0 auto; align-self: stretch; padding: 0 14px;
  border: none; border-left: 1px solid var(--border);
  background: none; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--accent, #6fbf4d); white-space: nowrap;
}
.pun-folder-drill:hover { background: var(--accent-muted); }
.pun-folder-view {
  flex: 0 0 auto; align-self: stretch; padding: 0 14px;
  border: none; border-left: 1px solid var(--border);
  background: none; cursor: pointer; white-space: nowrap;
  font-family: var(--font-display, inherit);
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-dim);
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}
.pun-folder-view:hover { background: var(--text); color: var(--bg); }
/* Review takes the same shape as Open/Hide — it is the other thing you can
   do to a branch, and neither of them is the red action. */
.pun-folder-review {
  flex: 0 0 auto; align-self: stretch; padding: 0 14px;
  border: none; border-left: 1px solid var(--border);
  background: none; cursor: pointer; white-space: nowrap;
  font-family: var(--font-display, inherit);
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-dim);
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}
.pun-folder-review:hover { background: var(--text); color: var(--bg); }
/* Dossier is the same shape again — a way of looking at the branch, not the
   red action. Scout branches only. */
.pun-folder-dossier {
  flex: 0 0 auto; align-self: stretch; padding: 0 14px;
  border: none; border-left: 1px solid var(--border);
  background: none; cursor: pointer; white-space: nowrap;
  font-family: var(--font-display, inherit);
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-dim);
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}
.pun-folder-dossier:hover { background: var(--text); color: var(--bg); }
/* Colour rows (As White / As Black) read as the level above the openings */
.pun-folder--color .pun-folder-ic { font-size: 18px; }
.pun-folder--white .pun-folder-ic { color: #f0ead8; background: rgba(240,234,216,0.12); }
.pun-folder--black .pun-folder-ic { color: #cfd3da; background: rgba(20,20,24,0.55); }
.pun-folder--color .pun-folder-label { font-size: 14px; }

/* ---- expanding rows -------------------------------------------------
   A branch row keeps its caret; its children are indented and step down
   in weight so the nesting is legible without extra chrome. */
.pun-folder-caret {
  flex: 0 0 auto; width: 10px; margin-right: -3px;
  font-size: 9px; line-height: 1; color: var(--text-dim);
}
.pun-folder.is-open .pun-folder-caret { color: var(--text); }

.pun-folder--d1 { margin-left: 22px; }
.pun-folder--d2 { margin-left: 44px; }
.pun-folder--d1 .pun-folder-open,
.pun-folder--d2 .pun-folder-open { padding: 6px 12px; }
.pun-folder--d1 .pun-folder-ic,
.pun-folder--d2 .pun-folder-ic { width: 22px; height: 22px; font-size: 12px; }
.pun-folder--d1 .pun-folder-label,
.pun-folder--d2 .pun-folder-label { font-size: 12.5px; }
.pun-folder--d1 .pun-folder-sub,
.pun-folder--d2 .pun-folder-sub { font-size: 10.5px; }

/* ---- Opening Punisher: set cards ------------------------------------
   A saved set gets a cover, a caption and a foot: the position the line
   arrives at, then the line in SAN with the count of what is punished
   under it, then a meter and the two actions.

   The cover used to be a five-by-four plate carrying a king — the same
   king on every set in the grid, so it said nothing about which set you
   were looking at while pushing the parts that did into a strip at the
   bottom. It is a real board now, drawn from the folder's own fenKey and
   turned to the side you will be playing. That is the one thing on the
   card that is different for every set before you have read a word of
   it. The board is why the card is tall; it is worth the height only
   because it is the actual position. */
.pun-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(212px, 1fr));
  gap: 8px;
  margin: 4px 0 10px;
}
.pun-cards--d1 { margin-left: 22px; }
.pun-cards--d2 { margin-left: 44px; }

.pun-cd-wrap {
  position: relative;
  display: flex; flex-direction: column;
  border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: 1px;
  background: var(--surface);
  transition: border-top-color var(--transition, 0.15s ease);
}
/* The top rule means finished — nothing left to punish in this set. It is
   a state, so it persists; the pointer's red is a flood on the caption
   (below) and the two never get confused for each other. */
.pun-cd-wrap.is-done { border-top-color: var(--accent); }

.pun-cd {
  position: relative;
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  padding: 0;
  border: 0; border-radius: 0; background: none;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.pun-cd:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }

/* The cover: the position this line arrives at. It reads its two colours
   from --sq-light / --sq-dark like every other board surface in the app,
   so a palette swap on <html> carries the whole collection with it. */
.pun-cd-bd {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  aspect-ratio: 1;
  border-bottom: 1px solid var(--border);
}
.pun-cd-bd i {
  background-size: contain; background-repeat: no-repeat; background-position: center;
}
.pun-cd-bd i.l { background-color: var(--sq-light); }
.pun-cd-bd i.d { background-color: var(--sq-dark); }

.pun-cd-txt {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 11px 13px;
  transition: background var(--transition, 0.15s ease);
}
/* The caption floods red under the pointer — the same gesture the branch
   rows make, so the whole tree answers the pointer one way. The board
   above it keeps its own colours: a chessboard is a chessboard. */
.pun-cd-wrap:hover .pun-cd-txt,
.pun-cd:focus-visible .pun-cd-txt { background: var(--accent); }

.pun-cd-kicker {
  min-height: 12px;   /* holds its line when a set carries no opening name */
  font-family: var(--font-display, inherit);
  font-size: 9px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The kicker holds SAN on a card that stands for a position — the two moves
   each side played to reach it. Case is meaning in SAN, so this one keeps its
   own: `Nf3` is a knight move and `NF3` is nothing. The letter-spacing comes
   back down too, because caps spacing on lowercase text reads as a gap. */
.pun-cd-kicker--san {
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 10px;
}
/* Deliberately NOT uppercased, unlike every other display string in the
   skin: the title is SAN, and case is meaning there — `Nf3` is a knight
   move and `NF3` is nothing. The kicker above carries the caps instead.
   Two lines before it truncates: a line is what the card IS, and half a
   line names a different position than the whole one. */
.pun-cd-title {
  font-family: var(--font-display, inherit);
  font-size: 17px; font-weight: 800; letter-spacing: 0.005em; line-height: 1.2;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Pushed to the foot so every card's count sits on one baseline across
   the grid, however long the line above it runs. */
.pun-cd-stat {
  margin-top: auto; padding-top: 9px;
  display: flex; align-items: baseline; gap: 5px; min-width: 0;
  font-family: var(--font-display, inherit);
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-dim);
  /* `14 / 23` must never break across the slash; the period is the only
     part allowed to give ground when the card is narrow. */
  white-space: nowrap;
}
.pun-cd-done {
  font-size: 12px; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: 0.01em;
}
.pun-cd-wrap.is-done .pun-cd-done { color: var(--accent); }
/* The period this set was scanned against, not the day the scan ran —
   it is what tells you whether the set is worth an update. */
.pun-cd-period {
  margin-left: auto; min-width: 0;
  font-weight: 600; letter-spacing: 0.02em; text-transform: none;
  font-variant-numeric: tabular-nums; opacity: 0.72;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* How much of this set is already punished. It rules off the card as
   well as measuring it — the action strip below needs no border. */
.pun-cd-bar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--border);
  transition: background var(--transition, 0.15s ease);
}
.pun-cd-bar i {
  display: block; height: 100%; background: var(--accent);
  transition: background var(--transition, 0.15s ease);
}

/* What the flood does to everything standing on it. The meter has to
   invert outright: an accent fill on an accent card is an empty meter,
   which would read as "nothing punished here" on exactly the card the
   user is pointing at. */
.pun-cd-kicker,
.pun-cd-title,
.pun-cd-stat,
.pun-cd-done { transition: color var(--transition, 0.15s ease); }
.pun-cd-wrap:hover .pun-cd-kicker,
.pun-cd:focus-visible .pun-cd-kicker,
.pun-cd-wrap:hover .pun-cd-title,
.pun-cd:focus-visible .pun-cd-title,
.pun-cd-wrap:hover .pun-cd-done,
.pun-cd:focus-visible .pun-cd-done { color: var(--on-accent); }
.pun-cd-wrap:hover .pun-cd-stat,
.pun-cd:focus-visible .pun-cd-stat { color: rgba(255, 255, 255, 0.78); }
.pun-cd-wrap:hover .pun-cd-bar,
.pun-cd:focus-visible .pun-cd-bar { background: rgba(0, 0, 0, 0.28); }
.pun-cd-wrap:hover .pun-cd-bar i,
.pun-cd:focus-visible .pun-cd-bar i { background: var(--on-accent); }

/* Review sits in ink at the left, drill in red at the right corner —
   the same order the branch rows put them in, so the eye learns one
   place to find each. A set with nothing outstanding drops the drill
   and still offers a way back through it. */
.pun-cd-acts {
  display: flex; align-items: stretch;
  background: var(--bg);
}
.pun-cd-drill,
.pun-cd-review {
  padding: 6px 11px; border: none; border-radius: 0;
  font-family: var(--font-display, inherit);
  font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  font-variant-numeric: tabular-nums; white-space: nowrap; cursor: pointer;
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}
.pun-cd-drill {
  margin-left: auto;
  background: var(--accent); color: var(--on-accent);
}
.pun-cd-drill:hover { background: var(--accent-dim); }
.pun-cd-review { background: none; color: var(--text-dim); }
.pun-cd-review:hover { background: var(--text); color: var(--bg); }
.pun-cd-del {
  position: absolute; z-index: 2; top: 3px; right: 3px;
  width: 20px; height: 20px; display: grid; place-items: center;
  border: none; border-radius: 1px;
  background: var(--bg); color: var(--text-dim);
  font-size: 11px; line-height: 1; cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition, 0.15s ease), background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
}
.pun-cd-wrap:hover .pun-cd-del,
.pun-cd-del:focus-visible { opacity: 1; }
.pun-cd-del:hover { background: var(--accent); color: var(--on-accent); }
/* No pointer, no hover — leave the delete showing rather than unreachable. */
@media (hover: none) {
  .pun-cd-del { opacity: 1; }
}
@media (max-width: 560px) {
  .pun-cards--d1 { margin-left: 10px; }
  .pun-cards--d2 { margin-left: 20px; }
  /* Two covers to a phone screen rather than one. A single 340px board
     per row is handsome and turns eight saved lines into a long scroll;
     at half that the position is still legible and the set above the
     fold is still the one you came for. */
  .pun-cards { grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 6px; }
  .pun-cd-txt { padding: 8px 9px 11px; }
  .pun-cd-title { font-size: 14px; }
  .pun-cd-drill,
  .pun-cd-review { padding: 6px 8px; }
  /* The period is the first thing to go when the caption gets this narrow —
     the count is what the card is for. */
  .pun-cd-period { display: none; }
}

/* Punish-from-here button in the openings analyze panel */
.op-punish-btn { margin-top: 8px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 6px; }
.op-punish-btn.hidden { display: none; }
.op-punish-ic { flex: none; }

/* ============================================================
   PUNISHMENTS ON THE TREE

   Punish scans in place and leaves its findings on the board:
   a badge on the moves that lead somewhere, a list of what's
   still ahead, and the reveal when you're standing on one.

   Colour follows the deck so the two screens agree: amber is
   "still owed" (.pun-tag--todo), the accent is a punishment
   already taken. Nothing new and nothing brighter — these sit
   next to a chessboard for long stretches.
   ============================================================ */

/* ---- scan progress, inside the analyze panel ---- */
.op-punish-progress { padding: 4px 0 2px; }
.op-punish-progress.hidden { display: none; }
.op-punish-progress .ps-progress-status { font-size: 12.5px; margin-bottom: 6px; }
.op-punish-progress .ps-progress-track { height: 6px; margin-bottom: 6px; }
.op-punish-cancel { width: 100%; margin-top: 8px; }
/* Same note as the full-scan screen, at this panel's scale: the standalone
   version is sized for a 560px page and would dwarf a sidebar bar 6px tall. */
.op-punish-progress .ps-progress-tip {
  max-width: none;
  margin: 10px 0 0;
  padding-top: 8px;
  font-size: 11px;
  line-height: 1.5;
}

/* ---- what the scan found ---- */
.op-punish-result {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  font-size: 12px; color: var(--text-dim); line-height: 1.5;
  padding-top: 8px; margin-top: 2px; border-top: 1px solid var(--border);
}
.op-punish-result.hidden { display: none; }
.op-punish-result-err { color: var(--danger); }
.op-punish-open {
  background: transparent; border: none; padding: 0; cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 700; color: var(--accent-dim);
  transition: color 0.12s;
}
.op-punish-open:hover { color: var(--accent); text-decoration: underline; }

/* ---- the badge on a move row ----
   Nested in the SAN cell (the row is a fixed-column grid). The panel widens
   that column for every row as soon as one of them carries a badge. */
.op-moves--punish .op-move-head,
.op-moves--punish .op-move-row { grid-template-columns: 68px 52px 1fr; }
.op-moves--punish .op-move-row--wdl:has(.op-move-perf) {
  grid-template-columns: 68px 52px 36px 1fr;
}
/* Both counts show side by side, gold first, so the grey one is never hidden
   behind it. The wider column below is what keeps the table lined up. */
.op-moves--punish2 .op-move-head,
.op-moves--punish2 .op-move-row { grid-template-columns: 94px 52px 1fr; }
.op-moves--punish2 .op-move-row--wdl:has(.op-move-perf) {
  grid-template-columns: 94px 52px 36px 1fr;
}
.op-move-san { display: inline-flex; align-items: center; gap: 5px; }
.op-move-punish {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 2px;
  font-family: var(--font-display); font-size: 9.5px; font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--text-dim); background: var(--border);
  padding: 1px 4px; border-radius: 1px;
}
.op-move-punish .op-punish-ic { width: 0.95em; height: 0.95em; }
.op-move-punish--missed { color: #e8b93c; background: rgba(232,185,60,0.14); }
/* Already punished: the muted default, stated outright so the pair reads as
   two deliberate states rather than "gold" and "unstyled". */
.op-move-punish--played { color: var(--text-dim); background: var(--border); }
.op-move-punish + .op-move-punish { margin-left: -1px; }

/* ---- findings list: what's still ahead of you here ---- */
.op-punish-found { border-top: 1px solid var(--border); }
.op-punish-found.hidden { display: none; }
.op-punish-found-toggle {
  width: 100%; display: flex; align-items: center; gap: 7px;
  background: transparent; border: none; cursor: pointer;
  padding: 10px 16px; text-align: left; font-family: var(--font-display);
  font-size: 10px; font-weight: 800; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.14em;
  transition: color 0.12s;
}
.op-punish-found-toggle:hover { color: var(--text); }
.op-punish-found-label { flex: 0 0 auto; }
.op-punish-found-missed { flex: 1 1 auto; color: #e8b93c; letter-spacing: 0.08em; }
.op-punish-found-caret { flex: 0 0 auto; }
.op-punish-found-list { display: flex; flex-direction: column; padding: 0 8px 10px; }
.op-punish-found-list.hidden { display: none; }
.op-punish-row {
  display: grid; grid-template-columns: 1fr auto auto 14px;
  align-items: center; gap: 10px;
  background: transparent; border: none; border-bottom: 1px solid var(--border);
  padding: 7px 8px; cursor: pointer; text-align: left; font-family: inherit;
  color: var(--text); width: 100%; transition: background 0.1s;
}
.op-punish-row:last-of-type { border-bottom: none; }
.op-punish-row:hover { background: var(--accent-muted); }
.op-punish-row-move { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; font-weight: 600; }
.op-punish-row-tag {
  font-family: var(--font-display); font-size: 9.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.14em;
  padding: 2px 6px; border-radius: 1px;
  color: var(--text-dim); background: var(--border);
}
.op-punish-row--missed .op-punish-row-tag { color: #e8b93c; background: rgba(232,185,60,0.14); }
.op-punish-row-eval {
  font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-dim);
}
.op-punish-row-go { color: var(--text-dim); font-size: 12px; }
.op-punish-row:hover .op-punish-row-go { color: var(--accent-dim); }

/* ---- the reveal: standing on a blunder ---- */
.op-punish-here {
  display: flex; flex-direction: column; gap: 5px;
  padding: 12px 16px 13px;
  border-bottom: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  background: var(--accent-muted);
}
.op-punish-here.hidden { display: none; }
/* Walked past it — still the subject, but no longer the position. */
.op-punish-here--behind { border-left-color: var(--border); background: var(--surface-2); }
.op-ph-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 3px; }
.op-ph-move { font-family: 'JetBrains Mono', monospace; font-size: 14px; font-weight: 700; }
.op-ph-verdict {
  font-family: var(--font-display); font-size: 9.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-dim);
}
.op-ph-verdict--missed { color: #e8b93c; }
.op-ph-behind { font-size: 10.5px; color: var(--text-dim); font-style: italic; }
.op-ph-row { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; }
.op-ph-key {
  flex: 0 0 74px; font-size: 10px; font-weight: 700; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.1em;
}
.op-ph-val { min-width: 0; color: var(--text); }
.op-ph-best { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 13.5px; }
.op-ph-eval { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; color: var(--accent-dim); font-weight: 700; }
.op-ph-line { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-dim); line-height: 1.5; }
.op-ph-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.op-ph-btn { font-size: 11.5px; padding: 5px 10px; }
.op-ph-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.op-ph-btn--drill { margin-left: auto; }

/* The blunder marked on the explorer board. chessboard.js rebuilds pieces but
   keeps the square divs, so the classes go on the squares (same as .gv-sq-*). */
.square-55d63.op-sq-from { box-shadow: inset 0 0 0 3px rgba(232, 185, 60, 0.30); }
.square-55d63.op-sq-to   { box-shadow: inset 0 0 0 3px rgba(232, 185, 60, 0.58); }

/* ---- Opening Punisher: outcome tags on cards ---- */
.pun-card-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pun-card--punished {
  opacity: 0.9;
  border-left: 3px solid var(--accent);
}
.pun-tag {
  flex: 0 0 auto; font-size: 10.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 2px 7px; border-radius: 2px; white-space: nowrap;
}
.pun-tag--won  { color: var(--accent, #6fbf4d); background: var(--accent-muted); }
.pun-tag--done { color: var(--text-dim); background: var(--border); }
.pun-tag--todo { color: #e8b93c; background: rgba(232,185,60,0.14); }

/* ---- Opening Punisher: PV line playback ---- */
.pun-pv-move {
  padding: 1px 4px; border-radius: 2px;
  transition: background 0.2s ease, color 0.2s ease;
}
.pun-pv-move.is-current {
  background: var(--accent-muted);
  color: var(--accent, #6fbf4d);
  font-weight: 800;
}
#punReplay[disabled] { opacity: 0.5; cursor: default; }

/* ==================================================================
   NEWSSTAND LAYER
   Geometry and ink for the app views. Everything above sets colour
   through the tokens; this section sets the *shape* of the theme —
   hard panels, heavy top rules, tracked uppercase labels, and red
   reserved for the punishment and the primary action.
   ================================================================== */

/* ---- Type discipline -------------------------------------------- */
/* Section labels and eyebrows are tracked uppercase, never sentence
   case: they are printed captions, not prose. */
.settings-section-label,
.gr-label,
.gr-aside-heading,
.op-move-head,
.pun-group-head {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: 10px;
}
/* Captions are ink, not red. Red is spent on the punishment and the
   primary action; a red label on every section buys nothing and, at this
   saturation against the black stage, it glares. */
.settings-section-label {
  color: var(--text-dim);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

/* Page titles were inheriting the dimmed body colour and reading washed. */
.gr-title, .openings-title { color: var(--text); }

.gr-title,
.openings-title,
.settings-drawer-title,
.coaches-page-title {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

/* Numbers stay in the mono face and line up in columns. */
.op-move-pct, .op-move-count, .op-move-games,
.op-eval-white, .op-eval-black, .op-engine-eval,
.pun-card-eval, .pun-reveal-eval, .op-game-rating {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ---- Buttons ----------------------------------------------------- */
/* Two shapes only. Primary is a red block with a cut corner; secondary
   is an outlined block that fills with ink on hover. Nothing is a pill.
   The doubled `.op-btn.op-btn-primary` selector is load-bearing: primary
   buttons carry both classes, and the secondary block below would
   otherwise win on source order and paint them transparent. */
.btn-primary,
.op-btn-primary,
.op-btn.op-btn-primary,
.pun-folder-drill {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 1px;
  padding: 11px 20px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  box-shadow: none;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%);
  transition: background var(--transition), transform var(--transition);
}
.btn-primary:hover,
.op-btn-primary:hover,
.op-btn.op-btn-primary:hover,
.pun-folder-drill:hover {
  background: var(--accent-dim);
  border-color: var(--accent-dim);
  color: var(--on-accent);
  transform: translate(-1px, -1px);
}
.btn-primary:active,
.op-btn-primary:active,
.pun-folder-drill:active { transform: none; }
/* The drill button rides inside a compact row, so it keeps the red block
   and the cut corner but not the standalone button's padding. */
.pun-folder-drill {
  padding: 0 13px;
  font-size: 10px;
  letter-spacing: 0.06em;
  clip-path: none;
}
.pun-folder-drill:hover { background: var(--accent-dim); transform: none; }
.btn-primary:disabled,
.op-btn-primary:disabled {
  opacity: 0.4;
  transform: none;
  clip-path: none;
}

.btn-secondary,
.op-btn {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 10px 18px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
}
.btn-secondary:hover,
.op-btn:hover {
  border-color: var(--text);
  background: var(--text);
  color: var(--bg);
}
.btn-secondary:disabled, .op-btn:disabled {
  opacity: 0.4;
  background: transparent;
  color: var(--text-dim);
  border-color: var(--border);
}

/* ---- Panels ------------------------------------------------------ */
/* A panel is a rectangle with a heavy rule across the top. The rule
   goes red only when the panel is the one that matters. */
.pun-card,
.pun-folder,
.pun-drill-panel,
.gr-shell,
.gr-aside,
.openings-left,
.openings-right {
  border-radius: 1px;
}

.pun-card,
.pun-folder {
  border-top: 3px solid var(--border);
  transition: border-top-color var(--transition), background var(--transition);
}
.pun-card:hover,
.pun-folder:hover { border-top-color: var(--text); }
/* Nested rows get a hairline instead of the heavy rule — the top-level
   rows stay the ones that carry weight in the list. */
.pun-folder.pun-folder--d1,
.pun-folder.pun-folder--d2 { border-top-width: 1px; }

/* Punished / solved states earn the red rule — this is the one thing
   the app is for, so it gets the accent and nothing else does. */
.pun-card--punished,
.pun-card--solved { border-top-color: var(--accent); }

/* ---- Tags and chips --------------------------------------------- */
.pun-tag,
.pun-solved-chip,
.gr-aside-pill,
.op-engine-pill {
  border-radius: 1px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Scouted opponents sit in the same list as your own record, so the row
   needs to read as a different KIND of set at a glance — the icon tile
   carries that, not another colour. */
.pun-folder--scout .pun-folder-ic {
  font-size: 15px;
  background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--border);
}
.pun-folder--scout .pun-folder-label { font-size: 14px; }
/* A gift nobody took is the whole point of scouting — let it say so. */
.pun-card-flag { color: var(--accent); font-weight: 700; }

/* ---- Phone: a folder row folds into two ----------------------------
   On one line the row is a label followed by its actions, and that only
   works while the label has room. It does not on a phone: Open, Review
   and the red drill count are all nowrap, so between them they took the
   width and left the label about 40px — enough to stack "2 openings ·
   2 lines · 58 of 70 solved" one word to a line and drive the count
   into it. So the row breaks in half. The label takes a full-width line
   with its count on the right, and the actions rule off beneath it and
   split that line evenly. Nothing is hidden and nothing is truncated —
   the row just gets taller, which is the one dimension a phone has. */
@media (max-width: 700px) {
  .pun-folder { flex-wrap: wrap; }
  .pun-folder-open { flex: 1 0 100%; padding: 9px 10px; }
  .pun-folder--d1 .pun-folder-open,
  .pun-folder--d2 .pun-folder-open { padding: 8px 10px; }
  /* The sub line has the whole width now, so let it use it. */
  .pun-folder-sub { white-space: normal; line-height: 1.4; }
  .pun-folder-count { padding-right: 0; }

  .pun-folder-view,
  .pun-folder-review,
  .pun-folder-dossier,
  .pun-folder-drill {
    flex: 1 1 0;
    min-width: 0;
    padding: 10px 6px;
    border-top: 1px solid var(--border);
    text-align: center;
    /* A stray vertical rule at the left edge of the action line reads as
       a broken cell — only the joins between actions get one. */
    border-left: 1px solid var(--border);
  }
  .pun-folder-open + * { border-left: none; }
  /* The row's ✕ stays a fixed square: it is not one of the four things
     you came here to do and should not get a quarter of the line. */
  .pun-folder-del { border-top: 1px solid var(--border); }

  /* Indented children give back their margin — three levels of 22px is
     a third of the screen. */
  .pun-folder--d1 { margin-left: 10px; }
  .pun-folder--d2 { margin-left: 20px; }
}

/* ---- Source tabs (Your games / Lichess / Masters) ---------------- */
.gr-source-tab,
.rep-mode-tab,
.op-flow-opt,
.op-color-btn {
  border-radius: 1px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.gr-source-tab--active,
.rep-mode-tab--active {
  box-shadow: inset 0 -3px 0 var(--accent);
}

/* ---- Move rows in the explorer ----------------------------------- */
/* The frequency bar is ink, not colour: colour in this table would
   compete with the eval readouts that actually carry meaning. */
.op-move-bar-fill { border-radius: 0; }
.op-move-row { border-radius: 0; }
.op-move-row:hover { background: var(--surface-2); }

/* ---- Inputs ------------------------------------------------------ */
.settings-text-input,
.gr-input,
.openings-own-form input,
.op-live-auth input {
  border-radius: 1px;
  font-family: var(--font-body);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.settings-text-input:focus,
.gr-input:focus,
.openings-own-form input:focus {
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
  outline: none;
}

/* ---- Settings drawer --------------------------------------------- */
.settings-drawer { border-left: 2px solid var(--accent); border-radius: 0; }
.settings-drawer-header {
  border-bottom: 3px solid var(--text);
}
.settings-drawer-close { border-radius: 1px; }
.settings-theme-opt {
  border-radius: 1px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.settings-board-opt { border-radius: 1px; }
.settings-version {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 9px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ---- Engine download bar ----------------------------------------- */
.sf-download-wrap { border-radius: 1px; }
.sf-download-bar-track { border-radius: 0; }
.sf-download-bar-fill { border-radius: 0; background: var(--accent); }
.sf-download-label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---- Board ------------------------------------------------------- */
/* Squares get a hard ink frame so the board reads as a printed panel
   like everything around it. */
.board-b72b1,
#board, #punBoard, #openingsBoard, #pvcBoard {
  border-radius: 0 !important;
}

/* ---- Selection and scrollbar ------------------------------------- */
::selection { background: var(--accent); color: #fff; }

* { scrollbar-color: var(--border) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 0; }
::-webkit-scrollbar-thumb:hover { background: var(--gray); }

/* ---- Quality floor ------------------------------------------------ */
/* One visible focus treatment, everywhere, that survives on both the
   dark stage and the newsprint. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 0;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .btn-primary:hover, .op-btn-primary:hover { transform: none; }
}

/* ---- Board squares ----------------------------------------------- */
/* Every board surface in the app — the real chessboard.js boards, the
   game-card thumbs, the home-hub board, the mini boards — reads its two
   colours from --sq-light / --sq-dark, so a palette swap is one attribute
   on <html> (set by applyBoardTheme in app-shell.js). Palettes are
   deliberately low-saturation: the red the app uses to mark a punishment
   has to stay the loudest thing on screen.

   Coordinate labels are painted by chessboard.js in the square's `color`,
   so each square takes the *other* colour of the pair and every palette
   gets legible notation for free. */
:root, [data-board="green"] {
  --sq-light: #eeeed2;
  --sq-dark:  #769656;
}
[data-board="walnut"] {
  --sq-light: #e8d0aa;
  --sq-dark:  #9c7549;
}
[data-board="slate"] {
  --sq-light: #dde3e8;
  --sq-dark:  #58748f;
}
[data-board="violet"] {
  --sq-light: #e5e0ee;
  --sq-dark:  #6f6191;
}
/* The original skin: newsprint against ink grey. */
[data-board="newsprint"] {
  --sq-light: #d9d6cd;
  --sq-dark:  #5f5d63;
}

#board .white-1e1d7, #punBoard .white-1e1d7,
#openingsBoard .white-1e1d7, .white-1e1d7 {
  background-color: var(--sq-light);
  color: var(--sq-dark);
}
#board .black-3c85d, #punBoard .black-3c85d,
#openingsBoard .black-3c85d, .black-3c85d {
  background-color: var(--sq-dark);
  color: var(--sq-light);
}

/* ---- Native controls --------------------------------------------- */
/* Radios, checkboxes and range thumbs default to the OS blue, which is
   the only colour on screen that belongs to no theme at all. */
input[type="radio"], input[type="checkbox"], input[type="range"], progress {
  accent-color: var(--accent);
}
select {
  border-radius: 1px;
  font-family: var(--font-body);
}

/* ============================================================
   GUEST SAVE BANNER — Punisher deck screen, signed-out only (renderDeck()
   in opening-punisher.js). A nudge, not a badge: neutral surface + a slim
   accent rule, not the red "stamp" reserved for the logo, and the button is
   the same .btn-secondary used everywhere else, so nothing here reads as a
   fourth instance of that device.
   ============================================================ */
.pun-guest-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 1px;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--text-dim);
}
.pun-guest-banner .btn-secondary { flex-shrink: 0; }

/* The saved sets a deck is made of, and the only place one can be deleted.
   Deliberately quiet and last on the page: it is housekeeping, not the work,
   and the delete inside it cannot be undone. */
.pun-deck-sets {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-top: 28px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-dim, var(--text));
}
.pun-deck-sets-lead {
  font-family: var(--font-display, inherit);
  font-size: 9px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim, var(--text));
  opacity: 0.75;
}
.pun-deck-set { display: inline-flex; align-items: baseline; gap: 8px; }
.pun-deck-set-name { color: var(--text); font-weight: 600; }
.pun-deck-set-n { opacity: 0.6; }
.pun-deck-set-del {
  background: none;
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 3px 8px;
  font: inherit;
  font-size: 11px;
  color: var(--text-dim, var(--text));
  cursor: pointer;
  transition: color var(--transition, 0.15s ease), border-color var(--transition, 0.15s ease);
}
.pun-deck-set-del:hover,
.pun-deck-set-del:focus-visible { color: var(--accent); border-color: var(--accent); }
/* Armed: the next click deletes, so it stops being quiet. */
.pun-deck-set-del.is-armed {
  color: var(--accent);
  border-color: var(--accent);
  font-weight: 700;
}

/* ============================================================
   GAME VIEWER (game-viewer.js), .gv-*
   The game a puzzle was cut out of, read in here instead of on Lichess.
   Borrows the drill's board/panel grid so stepping out of a puzzle and
   back doesn't move the board an inch; everything new is the movetext
   column beside it, set like a scoresheet — mono, tabular, ruled.

   Red is spent on exactly one thing on this screen, same as everywhere
   else: the move the puzzle is about. The move you're ON is an ink stamp
   (inverted text), which reads at a glance without adding a second colour.
   ============================================================ */
.gv-status {
  padding: 28px 20px;
  border: 1px dashed var(--border);
  border-radius: 2px;
  color: var(--text-dim);
  font-size: 13.5px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.gv-status--error { border-style: solid; border-left: 3px solid var(--accent); }

.gv-players {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
  font-size: 13.5px;
  font-weight: 600;
}
.gv-vs { color: var(--text-dim); font-weight: 400; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.06em; }
.gv-elo { color: var(--text-dim); font-weight: 400; font-family: var(--font-mono); font-size: 11.5px; }
.gv-meta { margin-top: 3px; font-size: 12px; color: var(--text-dim); }
.gv-meta:empty { display: none; }

.gv-note {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: 2px;
  padding: 10px 14px;
  font-size: 12.5px;
  color: var(--text-dim);
}

/* The scoresheet. Fixed columns so the move text lines up down the page
   however wide the SAN gets (O-O-O next to e4). */
.gv-movelist {
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--surface);
  padding: 6px;
  max-height: 340px;
  overflow-y: auto;
  font-family: var(--font-mono);
  font-size: 13px;
}
.gv-row {
  display: grid;
  grid-template-columns: 3.2em 1fr 1fr;
  align-items: stretch;
  gap: 2px;
}
.gv-row:nth-child(even) { background: var(--surface-2); }
.gv-no {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  padding: 4px 6px;
  text-align: right;
  font-size: 12px;
  align-self: center;
}
.gv-move {
  appearance: none;
  background: none;
  border: 0;
  border-radius: 1px;
  color: var(--text);
  font: inherit;
  text-align: left;
  padding: 4px 7px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.gv-move:hover { background: var(--border); }
.gv-move--empty { cursor: default; }
.gv-move--empty:hover { background: none; }
/* The blunder: underscored in red, not coloured — a move label has to stay
   readable, and the rule is louder than tinted text anyway. */
.gv-move--blunder { box-shadow: inset 0 -2px 0 var(--accent); }
.gv-move.is-current { background: var(--text); color: var(--bg); font-weight: 700; }
.gv-move--blunder.is-current { background: var(--accent); color: var(--on-accent); box-shadow: none; }

/* The board and the controls that step it are one unit — the controls used
   to live at the foot of the move list, a full screen away from the thing
   they move on a phone. */
.gv-stick { display: flex; flex-direction: column; gap: 10px; }

.gv-nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.gv-nav-btn {
  appearance: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--text);
  font-size: 13px;
  line-height: 1;
  padding: 8px 12px;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.gv-nav-btn:hover { border-color: var(--accent); background: var(--surface-2); }
.gv-ply {
  margin-left: auto;
  font-size: 11.5px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
}

/* Last move played, on the board. Same yellow the click-to-move selection
   uses, held back to a wash so it never competes with the pieces. */
.square-55d63.gv-sq-from { box-shadow: inset 0 0 0 3px rgba(255, 208, 0, 0.32); }
.square-55d63.gv-sq-to   { box-shadow: inset 0 0 0 3px rgba(255, 208, 0, 0.62); }

@media (max-width: 760px) {
  .gv-movelist { max-height: 220px; }

  /* One column on a phone, so everything below the board scrolls past it.
     Freeze the board and its controls at the top instead: reading the move
     list is the whole reason you scroll here, and the position you are
     reading it against was disappearing off the top as soon as you did.
     The topbar scrolls away rather than sticking, so top: 0 is the top. */
  .gv-stick {
    position: sticky;
    top: 0;
    z-index: 3;
    /* The list travels under this, so the frozen part needs a floor of its
       own and an edge to say where it stops. */
    background: var(--bg);
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
  }
  /* A frozen header taller than the screen freezes the whole screen. In
     portrait the column is far narrower than this and the cap never bites;
     it is here for a landscape phone still under the one-column breakpoint,
     where a full-width board would be twice the height of the viewport.
     `vh`, deliberately not `dvh`: chessboard.js measures the container once
     at mount and writes a fixed pixel height, so a unit that moved with the
     URL bar would leave the board a non-square with its pieces off-grid. */
  #gvBoard { width: min(100%, 62vh); margin: 0 auto; }
}

/* ============================================================
   REPORTS — the bits the .ps-* scorecard kit doesn't already cover:
   the Explorer entry bar, the opening-by-opening table, and the
   dossier's sections. Everything else on those pages is .ps-* and
   .gr-* reused as-is.
   ============================================================ */

/* --- Explorer entry bar (sits under the own-games status line) --- */
.op-report-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px;
}
.op-report-btn {
  font-size: 12px; font-weight: 700; letter-spacing: 0.01em;
  padding: 6px 12px;
}
.op-report-hint { font-size: 11.5px; color: var(--text-dim); }

/* --- section headers shared by the family table and the dossier --- */
.rep-section { margin-top: 22px; }

/* THE SECTION BARS on a dossier. The page runs five full-width sections deep,
   every one of them a big heading over prose, and scrolled at speed they read
   as one continuous document — the reader loses which section a number came
   from, which is the one thing this page cannot afford.

   A hairline with a short accent stub on it, not a full-strength rule: it marks
   a boundary and does not compete with the heading underneath it. Drawn by
   dossierSections in reports.js, which only puts one between sections that
   actually rendered. */
.rep-div {
  border: 0; height: 1px; background: var(--border);
  margin: 36px 0 28px; position: relative;
}
.rep-div::before {
  content: ''; position: absolute; left: 0; top: -1px;
  width: 56px; height: 3px; border-radius: 2px;
  background: var(--accent);
}
.rep-section-head {
  font-size: 14px; font-weight: 700; margin: 0 0 3px;
  text-transform: uppercase; letter-spacing: 0.07em;
}
.rep-section-sub {
  font-size: 12px; color: var(--text-dim); line-height: 1.5;
  margin: 0 0 10px; max-width: 62ch;
}

/* A history row that cannot honestly be differenced. Deliberately quieter than
   a delta chip: it is the absence of a measurement, not a measurement. */
.ps-hist-note {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-dim); opacity: 0.8; white-space: nowrap;
}

/* The single trend artefact kept above the fold — see trendLineHtml. Sized
   as a caption, not as a headline: it reports that the number moved, and the
   scorecards behind the fold are where it is explained. */
.rep-trendline {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  margin-top: 14px; padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.rep-trendline-cap {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.09em;
  font-weight: 700; color: var(--text-dim);
}
.rep-trendline-score {
  font-family: var(--font-black); font-size: 19px; line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* --- THE PUNISHER HERO ---
   The one place on this page that earns full-strength accent. The stylesheet's
   own standing rule is that punishment gets the red and nothing else does, and
   this block IS the punishment verdict — so the ring is accent-bordered and
   the persona is set in the display black, while every score behind the fold
   stays on the ink-weight scale. */
.pr-hero {
  display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 20px 22px; margin-top: 16px;
}
.pr-hero-ring {
  flex: 0 0 auto; width: 104px; height: 104px; border-radius: 50%;
  border: 4px solid var(--accent);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
}
/* Untested is not a bad score, so it must not wear the alarm colour. */
.pr-hero--untested { border-left-color: var(--border); }
.pr-hero-ring--empty { border-color: var(--border); border-style: dashed; }
.pr-hero-num {
  font-family: var(--font-black); font-size: 34px; line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.pr-hero--untested .pr-hero-num { color: var(--text-dim); }
.pr-hero-band {
  font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}
.pr-hero-text { flex: 1 1 300px; min-width: 0; }
.pr-hero-name {
  font-family: var(--font-black); font-size: 25px; line-height: 1.05;
  text-transform: uppercase; letter-spacing: 0.01em;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
/* A label the sample cannot settle says so next to itself, in the same dashed
   language the wide-band score rows already use. */
.pr-hero-tag {
  font-family: var(--font-body); font-size: 9.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-dim);
  border-bottom: 1px dashed var(--border); padding-bottom: 1px;
}
.pr-hero-line { margin: 6px 0 0; font-size: 14px; line-height: 1.45; }
.pr-hero-sub {
  margin: 7px 0 0; font-size: 12.5px; line-height: 1.55;
  color: var(--text-dim); max-width: 64ch;
}
.pr-hero-go { margin-top: 12px; font-size: 12px; padding: 8px 15px; }

/* Per-opening punishment verdict, in the table. */
.rep-fam-drill {
  display: block; font-size: 10.5px; color: var(--text-dim); margin-top: 2px;
}

@media (max-width: 700px) {
  .pr-hero { gap: 16px; padding: 16px 15px; }
  .pr-hero-ring { width: 78px; height: 78px; border-width: 3px; }
  .pr-hero-num { font-size: 26px; }
  .pr-hero-name { font-size: 20px; }
  .pr-hero-go { width: 100%; }
}

/* --- findings: the ranked instruction list a report now opens with ---
   Set as a numbered front-page list rather than another card grid. A grid of
   equal tiles was the original problem: it says "here are six things" and
   ranks none of them. The rank numeral is the only place the accent is spent,
   because the ranking IS the message. */
.rep-finds { margin-top: 18px; }
.rep-find-list {
  list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--surface);
}
.rep-find {
  display: grid; grid-template-columns: 48px 1fr;
  padding: 14px 16px 15px 0;
  border-top: 1px solid var(--border);
}
.rep-find:first-child { border-top: none; }
.rep-find-rank {
  font-family: var(--font-black); font-size: 22px; line-height: 1;
  text-align: center; padding-top: 2px; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* A strength is not a to-do. Same shape, no alarm. */
.rep-find--lean .rep-find-rank { color: var(--text-dim); }
.rep-find-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 4px;
}
.rep-find-title { font-weight: 700; font-size: 14.5px; line-height: 1.3; }
.rep-find-stat {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.rep-find-body {
  margin: 0; font-size: 13px; line-height: 1.55;
  color: var(--text-dim); max-width: 68ch;
}
.rep-find-go { margin-top: 11px; font-size: 12px; padding: 7px 14px; }
.rep-find-empty {
  font-size: 13px; line-height: 1.6; color: var(--text-dim);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px; margin: 0;
}

/* The opening the first finding names, marked in the table it was read off,
   so the sentence and its evidence are visibly the same row. */
.rep-fam-row--worst td { background: var(--accent-muted); }
.rep-fam-row--worst .rep-fam-name { box-shadow: inset 3px 0 0 var(--accent); }

/* --- the scorecards, one fold down ---
   Still every number, every band, every sparkline; just no longer the first
   thing on the page. Folded shut when there are findings to lead with, and
   open when there are not. */
.ps-scoring { margin-top: 24px; border-top: 1px solid var(--border); }
.ps-scoring-sum {
  cursor: pointer; list-style: none; padding: 13px 0;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em;
  font-weight: 700; color: var(--text-dim);
}
.ps-scoring-sum::-webkit-details-marker { display: none; }
.ps-scoring-sum::before { content: '\25B8'; margin-right: 8px; }
.ps-scoring[open] .ps-scoring-sum::before { content: '\25BE'; }
.ps-scoring-sum:hover { color: var(--text); }
.ps-scoring-sum:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ps-scoring[open] .ps-scoring-sum { border-bottom: 1px solid var(--border); }

@media (max-width: 700px) {
  .rep-find { grid-template-columns: 34px 1fr; padding-right: 13px; }
  .rep-find-rank { font-size: 17px; }
  .rep-find-title { font-size: 13.5px; }
  .rep-find-go { width: 100%; }
}

/* --- the opening-by-opening table ---
   Wide content scrolls inside its own box: the page body must never
   scroll sideways on a phone. */
.rep-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.rep-table { width: 100%; border-collapse: collapse; font-size: 12.5px; min-width: 520px; }
.rep-table th {
  text-align: left; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim);
  padding: 9px 12px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.rep-table td { padding: 9px 12px; border-top: 1px solid var(--border); vertical-align: middle; }
.rep-table tbody tr:first-child td { border-top: none; }
.rep-table tbody tr:hover { background: var(--surface-2); }
.rep-fam-name { font-weight: 600; }
.rep-fam-n, .rep-fam-score, .rep-fam-exit { font-variant-numeric: tabular-nums; white-space: nowrap; }
.rep-fam-score { font-weight: 700; }
.rep-fam-puz { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; }
.rep-fam-thin { color: var(--text-dim); font-style: italic; font-weight: 400; }
/* Sharpness (flames) and punisher score (pawns), each out of five. Unlit marks
   stay as faint placeholders so the row always reads "out of five". */
.rep-rate { display: inline-flex; gap: 1px; vertical-align: -3px; cursor: help; }
.rep-rate-mark { width: 15px; height: 15px; opacity: 0.18; }
.rep-rate-mark.is-lit { opacity: 1; }
.rep-fam-row--other td { color: var(--text-dim); font-style: italic; }
.rep-fam-bar { width: 110px; min-width: 90px; }

/* W/D/L strip. Ink for wins, rule-grey for draws, red for losses — the
   same value scale the score tones use, so a row reads without a legend. */
.rep-wdl {
  display: flex; height: 7px; width: 100%; overflow: hidden;
  border-radius: 1px; background: var(--border);
}
.rep-wdl-w { background: var(--text); }
.rep-wdl-d { background: var(--gray); }
.rep-wdl-l { background: var(--accent); }

/* --- intro extras --- */
.rep-offer {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: 12px 16px; margin-bottom: 16px;
}
.rep-offer-text { font-size: 13px; line-height: 1.5; }
.rep-link {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--accent); text-decoration: underline;
}
.rep-link:hover { color: var(--accent-dim); }

/* --- empty / can't-build --- */
.rep-empty {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 20px 22px; margin: 16px 0;
  font-size: 13.5px; line-height: 1.6;
}
.rep-empty p { margin: 0 0 8px; }
.rep-empty-note { color: var(--text-dim); font-size: 12.5px; margin: 0; }

/* --- dossier --- */
.rep-dossier-sub { font-size: 12px; color: var(--text-dim); margin: 2px 0 0; }
.rep-rep-table td.rep-rep-move { font-family: var(--font-mono); font-size: 12px; }
.rep-rep-share { width: 120px; }
.rep-share-bar {
  display: block; height: 7px; background: var(--border);
  border-radius: 1px; overflow: hidden;
}
.rep-share-fill { display: block; height: 100%; background: var(--text); }
.rep-stale {
  font-size: 11.5px; color: var(--text-dim);
  border-top: 1px solid var(--border); margin-top: 10px; padding-top: 8px;
}

@media (max-width: 700px) {
  .rep-offer { flex-direction: column; align-items: stretch; }
  .rep-section-head { font-size: 13px; }
}

/* Dossier index rows are navigation, not data. */
.rep-dossier-row { cursor: pointer; }
.rep-dossier-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ============================================================
   SITE FOOTER
   Legal links, present on every view. Markup is static in
   index.html, last inside .app; the modules' ensureViewShell()
   insert their views before it, so it stays at the bottom.
   ============================================================ */

.site-footer {
  margin-top: 56px;
  padding-top: 18px;
  /* Matches the topbar's heavy rule, halved — the footer closes the page but
     shouldn't compete with the masthead for weight. */
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 12px;
  color: var(--text-dim);
}

.site-footer-mark {
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.site-footer-links { display: flex; gap: 18px; }

.site-footer-links a {
  color: var(--text-dim);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: color var(--transition);
}
.site-footer-links a:hover { color: var(--accent-dim); text-decoration: none; }
[data-theme="light"] .site-footer-links a:hover { color: var(--accent); }
.site-footer-links a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* About leads to the author's courses, so it gets a little more weight than
   the legal links: full text colour and an accent underline. */
.site-footer-links a.site-footer-about {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
.site-footer-links a.site-footer-about:hover { color: var(--accent-dim); }
[data-theme="light"] .site-footer-links a.site-footer-about:hover { color: var(--accent); }

/* Pushed to its own end of the row on wide screens, wraps underneath on
   narrow ones rather than squeezing the links. */
.site-footer-note { margin-left: auto; }

@media (max-width: 620px) {
  .site-footer { margin-top: 36px; gap: 6px 16px; }
  .site-footer-note { margin-left: 0; flex-basis: 100%; }
}

/* The mobile tab bar is fixed to the bottom of the viewport, so the footer
   has to clear it or the last row sits underneath the tabs. .app already
   carries a matching padding-bottom when the sidenav is on; this is the
   footer's own share of it. */
body.sidenav-on .site-footer { padding-bottom: 8px; }

/* ============================================================
   THE GAME PLAN — "how to beat them"

   This block breaks the page's usual quiet on purpose. The stylesheet's
   standing rule is that punishment gets the red and nothing else does, and an
   instruction to go punish a named opening IS the punishment verdict, so it
   carries the accent rule down its left edge exactly like .pr-hero. Everything
   below it on the page is the working; this is the answer.

   Accents stay on the deep tokens (--accent, never a raw saturated red) and
   the hot number is weight and size before it is colour, so the block reads as
   emphatic rather than as a warning light.
   ============================================================ */
.gp-plan {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 18px 20px 16px;
  margin-top: 16px;
}
.gp-plan .rep-section-head { color: var(--text-dim); margin-bottom: 8px; }

/* The sentence the whole category is asked for out loud. Display black, sized
   to be read across the room, and it is a command rather than a statistic. */
.gp-verdict {
  font-family: var(--font-black);
  font-size: clamp(19px, 3.4vw, 25px);
  line-height: 1.12; letter-spacing: -0.01em;
  margin: 0 0 6px; text-wrap: balance;
}
.gp-verdict b { color: var(--accent); font-weight: inherit; }
/* Below the evidence floor the headline is an admission, so it drops out of
   the accent and back to body ink. Nothing on this page should look decisive
   while saying it cannot decide. */
.gp-verdict--thin { color: var(--text-dim); font-size: clamp(16px, 2.6vw, 19px); }

.gp-because {
  font-size: 13px; line-height: 1.5; color: var(--text-dim);
  margin: 0 0 12px; max-width: 62ch;
}
.gp-because b { color: var(--text); }
.gp-hot { font-variant-numeric: tabular-nums; }

.gp-steer {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 0 14px; padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.gp-steer-cap {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.09em; color: var(--text-dim); flex: 0 0 auto;
}
.gp-steer-line {
  font-family: var(--font-mono); font-size: 12.5px;
  background: var(--accent-muted); color: var(--text);
  padding: 3px 8px; border-radius: 3px;
  overflow-wrap: anywhere;
}

.gp-shots { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.gp-shot { margin: 0; }
.gp-shot-btn {
  display: flex; align-items: flex-start; gap: 12px; width: 100%;
  text-align: left; cursor: pointer;
  background: var(--bg); color: inherit; font: inherit;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 11px 13px;
  transition: border-color var(--transition), transform var(--transition);
}
.gp-shot-btn:hover { border-color: var(--accent); transform: translateY(-1px); }
.gp-shot-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Already drilled: still listed, because the plan is the firing order and you
   want to see that the first shot is loaded — just dimmed, the same way a
   prepared target card is. */
.gp-shot--ready .gp-shot-btn { opacity: 0.66; }

.gp-shot-rank {
  flex: 0 0 auto;
  font-family: var(--font-black); font-size: 17px; line-height: 1.15;
  color: var(--accent); font-variant-numeric: tabular-nums;
  min-width: 1.1em;
}
.gp-shot-body { display: grid; gap: 3px; min-width: 0; }
.gp-shot-line {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
  overflow-wrap: anywhere;
}
.gp-shot-move { font-size: 13.5px; line-height: 1.45; }
.gp-shot-best { color: var(--accent); }
.gp-shot-eval {
  font-family: var(--font-mono); font-size: 12px;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.gp-shot-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--text-dim); margin-top: 2px;
}
/* The one axis no competitor measures, so it is the one that gets the colour.
   A mistake somebody already refuted is ordinary, and reads as ordinary. */
.gp-shot-flag { color: var(--accent); font-weight: 700; }
.gp-shot-flag--taken { color: var(--text-dim); font-weight: 600; }

.gp-note {
  font-size: 11.5px; line-height: 1.55; color: var(--text-dim);
  margin: 12px 0 0; max-width: 68ch;
}

@media (max-width: 620px) {
  .gp-plan { padding: 15px 14px 14px; }
  .gp-steer { gap: 6px; }
  .gp-shot-btn { gap: 10px; padding: 10px 11px; }
}

/* The condition the instruction hangs on. Sits between the verdict and the
   line, quieter than either — it is a caveat, and a caveat that shouts is a
   second headline. */
.gp-depends {
  font-size: 12.5px; line-height: 1.5; color: var(--text-dim);
  margin: 0 0 12px; max-width: 62ch;
  padding-left: 10px; border-left: 2px solid var(--border);
}
.gp-depends b { color: var(--text); font-weight: 700; }
.gp-alt-line {
  font-family: var(--font-mono); font-size: 11.5px;
  background: var(--surface-2); padding: 1px 5px; border-radius: 3px;
  overflow-wrap: anywhere;
}

/* ============================================================
   THE MATCHUP — "if you played them today"

   Carries the same weight as the game plan above it, and deliberately so. It
   started quieter — the reasoning being that two blocks shouting in the same red
   leaves a page with two headlines and no lead — and that was the wrong call
   once the section had something to say. These are the two halves of one
   question. The plan says which of their mistakes to aim for; this says how to
   reach a position they have never had to solve. Neither is a footnote to the
   other, so they share a shape: same card, same eyebrow, same display headline.

   The one rule kept from the quiet version: inside the card, the accent still
   marks exactly one thing — the line where they are on their own.
   ============================================================ */
.mu-plan {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 18px 20px 16px;
  margin-top: 16px;
}
.mu-plan .rep-section-sub { margin: 0 0 4px; }
/* No background override for .mu-line here: it already sits on --bg, and a
   `.mu-plan .mu-line` rule would outrank .mu-line--opening on specificity and
   strip the accent fill off the one row that has earned it. */

/* The section showing its own working. Set as quiet metadata, not as a finding
   — it is here to answer "why is my move missing", which is a question about
   the tool rather than about the opponent.

   A real table: four columns of numbers read down, and the units belong in the
   header once rather than glued to every cell. */
.mu-roots {
  width: 100%; margin: 10px 0 0;
  border-collapse: collapse;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 11.5px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.mu-roots-cap {
  caption-side: top; text-align: left;
  font-weight: 700; color: var(--text);
  padding: 8px 11px 6px;
}
.mu-roots th, .mu-roots td { padding: 4px 11px; text-align: right; }
.mu-roots th:first-child, .mu-roots td:first-child { text-align: left; }
.mu-roots thead th {
  font-weight: 600; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border);
  padding-bottom: 5px;
}
.mu-roots tbody th {
  font-family: var(--font-mono); color: var(--text); font-weight: 700;
}
.mu-roots tbody tr + tr th, .mu-roots tbody tr + tr td {
  border-top: 1px solid var(--border);
}
/* Dropped by the floor. Struck through rather than hidden: the whole reason
   this row exists is that an invisible exclusion is indistinguishable from a
   bug. */
.mu-root.is-cut { opacity: 0.5; }
.mu-root.is-cut th { text-decoration: line-through; color: var(--text-dim); }
.mu-roots tfoot td {
  text-align: left; line-height: 1.5; opacity: 0.8;
  padding: 7px 11px 9px;
  border-top: 1px solid var(--border);
}

/* The section's own title and what it is for. It carries the display weight the
   deleted "Play 3.g3." headline used to — a name a reader can place beats an
   instruction they cannot — and it stays out of the accent, because the accent
   in this card marks the line where they are on their own and nothing else. */
/* Two clear steps, not one. At the first size this shipped at — 25px against
   the banners' uppercase 19px — the section title and the opening names read as
   the same rank, and a reader scrolling in could not tell which one owned the
   other. The title takes a size the banners cannot reach, and the banners give
   some back; uppercase at 17px still holds a banner's weight. */
.mu-title {
  font-family: var(--font-black);
  font-size: clamp(26px, 4.8vw, 34px);
  line-height: 1.08; letter-spacing: -0.015em;
  margin: 0 0 8px; text-wrap: balance;
}
.mu-what {
  font-size: 13.5px; line-height: 1.5; color: var(--text);
  margin: 0 0 10px; max-width: 62ch;
}

/* ---- THE OPENING BANNER ----------------------------------------------
   The way a paper marks a section: a heavy rule and a name. Ink and paper
   only — no coloured bar, no fill — because the one accent inside this card is
   already spoken for by the line where the opponent is out of preparation, and
   a second one would put the eye on the label instead of the finding. */
.mu-groups { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin: 16px 0 0; }
.mu-banner { border-top: 3px solid var(--text); padding-top: 9px; }
/* The Punisher List uses the same banner. Sharing the rule rather than
   copying it is what keeps one opening looking like one opening across two
   sections of the same page. */
.pl-plan .mu-groups { margin-top: 14px; }
.mu-banner-top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 6px 16px; flex-wrap: wrap; padding-bottom: 3px;
}
.mu-opening {
  font-family: var(--font-black);
  font-size: clamp(14px, 2.2vw, 17px);
  line-height: 1.1; letter-spacing: -0.005em;
  margin: 0; text-transform: uppercase;
}
.mu-opening-meta { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; }
.mu-eco { font-family: var(--font-mono); color: var(--text); font-weight: 700; }
.mu-stemrow {
  display: flex; align-items: baseline; gap: 6px 14px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
/* Scrolls rather than wraps. A move stem broken across two lines stops reading
   as one sequence, which is the only thing it is there to be. */
.mu-stem {
  font-family: var(--font-mono); font-size: 12.5px; color: var(--text);
  background: var(--surface-2); padding: 2px 7px; border-radius: var(--radius);
  white-space: nowrap; max-width: 100%; overflow-x: auto;
}
.mu-stem-note { font-size: 11.5px; color: var(--text-dim); line-height: 1.5; }
.mu-stem-note--thin { font-style: italic; }
/* A hairline bracket, so the banner visibly owns the cards under it. */
.mu-group-lines {
  margin: 12px 0 0 3px;
  border-left: 1px solid var(--border);
  padding-left: 15px;
}
/* The moves the banner already printed are gone from the card; this is what is
   left in their place, so the row still reads as a continuation. */
.mu-then { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-dim); }

.mu-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 10px; }
.mu-line {
  display: block; margin: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 13px 11px;
}
.mu-head { display: flex; align-items: baseline; gap: 10px; }
/* Board beside the reading matter. The board is the quick glance and the text
   is the finding, so the text gets the width that is left and the board is
   fixed — a thumbnail that grows with the column stops being a thumbnail. */
.mu-cols {
  display: flex; align-items: flex-start; gap: 14px; margin-top: 8px;
}
.mu-boardwrap { flex: 0 0 auto; display: grid; gap: 5px; justify-items: center; }
.mu-main { flex: 1 1 auto; min-width: 0; display: grid; gap: 3px; align-content: start; }
/* Whose preparation ran out is the whole finding, so it is the one thing here
   that carries colour — and only as an edge, not a fill. Running out yourself
   is the actionable one, so it takes the accent; them running out is good news
   and reads as calm rather than as an alarm. */
.mu-line--you { border-left-color: var(--accent); }
.mu-line--them { border-left-color: var(--text-dim); }
.mu-line--held { border-left-color: var(--border); }
/* "We did not look far enough" is not a finding, and must not be dressed as
   one. No edge colour at all, and the row is dimmed — it is on the page so the
   line can be read, not so it can be acted on. */
.mu-line--unknown { border-left-color: transparent; opacity: 0.72; }
.mu-line--unknown .mu-fact:first-child .mu-fact-v { font-style: italic; }
/* A position THEY have never had to solve. The same stop as above by mechanism
   and the opposite thing by meaning, so it gets the accent and the weight — it
   is the line you came here to find, not a hole in the data. */
.mu-line--opening { border-left-color: var(--accent); background: var(--accent-muted); }
.mu-line--opening .mu-fact-k { color: var(--text); }

.mu-rank {
  flex: 0 0 auto;
  font-family: var(--font-black); font-size: 15px; line-height: 1.25;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
  min-width: 1.1em;
}
/* THE BOARD. Eight rows of eight, straight from a FEN — no chessboard.js and no
   jQuery, because there are a dozen of these on one page and each library board
   wants an instance, a lifecycle and a resize listener. Redrawing this is one
   string, which is what makes stepping through a line affordable. */
.mu-board {
  display: grid;
  /* BOTH axes, explicitly. With only the columns declared the eight rows were
     implicit, and an implicit row sizes to its content — so a rank with no
     pieces on it collapsed to nothing and the board came out smooshed. Ranks 3
     and 5 are empty in most open Sicilians, which is why some boards looked
     right and others did not. */
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  width: 136px; height: 136px;
  border: 1px solid var(--border);
  border-radius: 3px; overflow: hidden;
}
/* Belt and braces: even if the grid template is ever lost, a square keeps its
   shape from its own aspect ratio rather than from whether a piece happens to
   be standing on it. */
.mu-sq { display: block; position: relative; aspect-ratio: 1 / 1; min-height: 0; }
/* Board colours come off the theme tokens, not from a chess palette, so the
   thumbnail belongs to this page rather than looking like a pasted widget. */
/* The palette the user picked in settings, same as every other board surface —
   see "Board squares". These read --surface-2/--border for a while, which meant
   the one board on the page that did NOT follow the setting was the one the
   report showed most often. */
.mu-sq.is-light { background: var(--sq-light); }
.mu-sq.is-dark { background: var(--sq-dark); }
.mu-sq img { display: block; width: 100%; height: 100%; }

.mu-nav {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 11px; color: var(--text-dim);
}
.mu-nav-btn {
  background: none; border: 1px solid var(--border); border-radius: 3px;
  color: var(--text-dim); font: inherit; line-height: 1;
  padding: 2px 7px; cursor: pointer;
  transition: border-color var(--transition), color var(--transition);
}
.mu-nav-btn:hover { border-color: var(--accent); color: var(--text); }
.mu-nav-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mu-ply {
  font-family: var(--font-mono); font-size: 11px;
  min-width: 5.5ch; text-align: center; font-variant-numeric: tabular-nums;
}

/* Each move is its own target. The arrows step; these jump, because pressing
   an arrow six times to reach the move you are already looking at is not
   navigation. */
.mu-mvlist { display: flex; flex-wrap: wrap; gap: 1px 4px; min-width: 0; }
.mu-mv {
  background: none; border: 0; border-radius: 3px; cursor: pointer;
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5;
  color: var(--text-dim); padding: 0 3px;
  transition: background var(--transition), color var(--transition);
}
.mu-mv:hover { color: var(--text); background: var(--surface-2); }
.mu-mv:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.mu-mv.is-on { color: var(--text); background: var(--accent-muted); font-weight: 700; }
.mu-mvno { opacity: 0.55; }

/* ---- THE FOUR FACTS ---------------------------------------------------
   The same labels in the same order on every card, so two lines are compared
   by reading down one column instead of re-reading two paragraphs. A label
   column wide enough for the longest of them ("Likelihood to reach") and no
   wider — a ragged left edge on the values would undo the point of labelling
   them at all. */
.mu-facts {
  margin: 0; display: grid; gap: 4px;
  font-size: 12.5px; line-height: 1.4;
}
.mu-fact {
  display: grid;
  grid-template-columns: minmax(0, 13.5em) minmax(0, 1fr);
  gap: 2px 12px; align-items: baseline;
}
.mu-fact-k {
  color: var(--text-dim); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.mu-fact-v {
  margin: 0; color: var(--text); font-weight: 600;
  font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap;
}
/* What makes the answer above it checkable. Never optional on a claim about
   what a player has or has not faced — the answer is not allowed on the page
   without the sample it came out of. */
.mu-fact-sub {
  font-weight: 400; font-size: 11.5px; color: var(--text-dim);
  font-variant-numeric: normal;
}
/* Evidence over a year old. It still gets printed — hiding it would be the same
   mistake in reverse — but it is marked, because a habit from two years ago
   read as current preparation is exactly how this section first went wrong. */
.mu-fact.is-stale .mu-fact-v { color: var(--accent); }
.mu-fact.is-stale .mu-fact-sub { color: var(--accent); font-weight: 600; }

.mu-note {
  font-size: 11.5px; line-height: 1.55; color: var(--text-dim);
  margin: 12px 0 0; max-width: 68ch;
}

@media (max-width: 620px) {
  .mu-line { padding: 9px 11px 10px; }
  /* The labels stack above their values rather than sharing a row: an 11.5em
     label column beside a value column leaves the values about eight characters
     wide on a phone. */
  .mu-fact { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .mu-fact-k { margin-top: 3px; }
  /* The count belongs under the name, not squeezed onto the same line with it:
     "Sicilian Defense: Lasker-Pelikan Variation" is already two lines wide on a
     phone, and a nowrap meta beside it pushes the name down to one word a row. */
  .mu-banner-top { flex-direction: column; gap: 2px; }
  .mu-group-lines { margin-left: 0; padding-left: 9px; }
  /* The board stacks above the text rather than shrinking. A 136px board is
     already at the limit of what a piece glyph survives; narrower and it stops
     being readable, which is the only thing it is there for. */
  .mu-cols { flex-direction: column; gap: 10px; }
  .mu-boardwrap { justify-items: start; }
}

/* ============================================================
   THE RADAR — two players on six axes

   IDENTITY IS NEVER COLOUR ALONE. Their ring is solid and filled, yours is
   dashed and hollow, both are named in the legend, and every vertex prints its
   own number. A reader who cannot separate the two hues still has three other
   ways to tell the rings apart — and the numbers beside the chart mean the
   shape is never the only reading.

   THE WEB IS RECESSIVE. Four rings and six spokes at low contrast; they are the
   ruler, not the finding. An unmeasured axis takes no ring at all — see the
   path builder, which breaks the line rather than pulling the vertex to the
   middle, because a dent reads as a weakness whatever the caption says.
   ============================================================ */
.rd-plan { margin-top: 16px; }
.rd-wrap {
  display: flex; gap: 8px 26px; flex-wrap: wrap; align-items: flex-start;
  margin-top: 14px;
}
.rd-svg { flex: 0 0 auto; width: 372px; max-width: 100%; height: auto; }
.rd-side { flex: 1 1 260px; min-width: 0; }

.rd-web { fill: none; stroke: var(--border); stroke-width: 1; }
.rd-spoke { stroke: var(--border); stroke-width: 1; }

.rd-ring { fill: none; stroke-linejoin: round; stroke-linecap: round; }
.rd-ring--them {
  stroke: var(--chart-strong); stroke-width: 2;
  fill: var(--chart-strong); fill-opacity: 0.16;
}
/* Dashed and hollow, so the two rings are told apart by shape before colour. */
.rd-ring--you {
  stroke: var(--text-dim); stroke-width: 2; stroke-dasharray: 5 4;
  fill: none;
}
/* A 2px surface ring, so a vertex that lands on top of the other ring still
   reads as one mark rather than a smudge. */
.rd-dot { stroke: var(--surface); stroke-width: 2; }
.rd-dot--them { fill: var(--chart-strong); }
.rd-dot--you { fill: var(--text-dim); }

.rd-axis {
  fill: var(--text); font-family: var(--font-body);
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.rd-num {
  fill: var(--text-dim); font-family: var(--font-mono); font-size: 11px;
}
/* An axis with nothing behind it is labelled and greyed, never drawn at zero. */
.rd-axis.is-unmeasured, .rd-num.is-unmeasured { fill: var(--text-dim); opacity: 0.6; }
.rd-num.is-unmeasured { font-size: 9.5px; font-family: var(--font-body); font-style: italic; }

.rd-key { display: grid; gap: 4px; font-size: 11.5px; color: var(--text-dim); }
.rd-key-item { display: inline-flex; align-items: center; gap: 7px; }
.rd-key-item--off { opacity: 0.75; font-style: italic; }
.rd-swatch { width: 14px; height: 0; flex: 0 0 auto; }
.rd-swatch--them { border-top: 3px solid var(--chart-strong); }
.rd-swatch--you { border-top: 3px dashed var(--text-dim); }

/* The working, in words. The chart is the glance; this is where a reader
   decides whether to believe it. */
.rd-rows { display: grid; gap: 9px; margin-top: 12px; }
.rd-row { display: grid; gap: 1px; }
.rd-row.is-unmeasured { opacity: 0.6; }
.rd-row-k {
  font-size: 10.5px; font-weight: 600; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.rd-row-v {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
.rd-row-v b { font-size: 15px; }
.rd-none { font-size: 12px; color: var(--text-dim); font-style: italic; }
.rd-you { font-size: 11.5px; color: var(--text-dim); }
.rd-row-why { font-size: 11.5px; line-height: 1.45; color: var(--text-dim); }
.rd-n { opacity: 0.75; font-variant-numeric: tabular-nums; }
.rd-foot {
  font-size: 11px; line-height: 1.5; color: var(--text-dim);
  margin: 12px 0 0; max-width: 46ch;
}
.rd-link {
  font: inherit; font-size: 11px; font-weight: 700;
  color: var(--text); background: none; border: 0; padding: 0;
  text-decoration: underline; cursor: pointer;
}
.rd-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 620px) {
  /* The chart shrinks; the labels do not, or they stop being readable. Its
     overflow stays visible so the outer axis names are not clipped. */
  .rd-svg { width: 100%; }
  .rd-wrap { gap: 14px; }
}

/* ============================================================
   HOW THEY DO — a bar chart of an opponent's own results

   THE FORM. One measure at a time, chosen by a control, rather than one chart
   carrying two. Score, frequency and the gap from their average sit on three
   different scales, and plotting two of them together needs a second y-axis —
   the one chart mistake that reliably makes a reader see a relationship the
   data does not contain. Same rows, same labels, one measure.

   THE COLOUR. Two poles and a neutral middle: red where they score below their
   own average, blue above, and plain paper for every row whose gap is inside
   its own error bar. That last part is the point — a chart that colours every
   row has said nothing with colour, and a row that is coloured here has passed
   a test rather than caught an eye.

   The hues are theme tokens (--chart-weak / --chart-strong) so light and dark
   are separately chosen steps rather than an automatic flip, and both were run
   through the palette validator against their own surface.
   ============================================================ */
.va-plan { margin-top: 16px; }

/* The number every bar is measured against. It leads because a chart of
   deviations is unreadable without the thing being deviated from. */
.va-base {
  display: flex; align-items: baseline; gap: 6px 12px; flex-wrap: wrap;
  margin: 12px 0 0; padding: 9px 12px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
}
.va-base-cap {
  font-size: 10.5px; font-weight: 600; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.va-base-num {
  font-family: var(--font-black); font-size: 20px; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.va-base-sub { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* Filters in one row above the chart. */
.va-controls { display: flex; gap: 6px; flex-wrap: wrap; margin: 12px 0 0; }
.va-view {
  font: inherit; font-size: 11.5px; font-weight: 600;
  color: var(--text-dim); background: transparent;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 5px 10px; cursor: pointer;
}
.va-view:hover { color: var(--text); border-color: var(--text-dim); }
.va-view:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.va-view.is-on { color: var(--text); background: var(--surface-2); border-color: var(--text-dim); }

/* Identity is never colour alone: the key names both poles in words, and every
   row also carries its signed number. */
.va-key {
  display: flex; gap: 6px 16px; flex-wrap: wrap;
  margin: 10px 0 0; font-size: 11px; color: var(--text-dim);
}
.va-key-item { display: inline-flex; align-items: center; gap: 6px; }
.va-swatch {
  width: 10px; height: 10px; border-radius: 2px;
  background: var(--border); flex: 0 0 auto;
}
.va-swatch--poor { background: var(--chart-weak); }
.va-swatch--good { background: var(--chart-strong); }

.va-rows { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
.va-row {
  display: grid;
  grid-template-columns: minmax(0, 15em) minmax(0, 1fr) minmax(0, 13em);
  gap: 4px 14px; align-items: center;
}
.va-label { min-width: 0; display: grid; gap: 1px; }
.va-name {
  font-size: 12.5px; font-weight: 600; line-height: 1.25;
  overflow-wrap: anywhere;
}
.va-sub { font-size: 10.5px; color: var(--text-dim); }
.va-sub code { font-family: var(--font-mono); font-size: 10.5px; }

/* Recessive track, thin marks. */
.va-track {
  position: relative; height: 14px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  min-width: 60px;
}
/* The baseline the diverging view measures from — a rule, not a gridline set. */
.va-zero {
  position: absolute; left: 50%; top: -2px; bottom: -2px;
  width: 1px; background: var(--text-dim); opacity: 0.7;
}
.va-bar {
  position: absolute; top: 2px; bottom: 2px;
  background: var(--border);
  /* 4px rounded at the data end, square where it meets the baseline, so the
     bar reads as growing away from zero rather than floating. */
  border-radius: 0;
}
.va-bar--from-left { border-radius: 0 4px 4px 0; }
.va-bar--from-right { border-radius: 4px 0 0 4px; }
.va-bar--poor { background: var(--chart-weak); }
.va-bar--good { background: var(--chart-strong); }

.va-val {
  display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.va-score { color: var(--text); font-size: 13px; }
/* The signed gap, which is what carries identity for a reader who cannot use
   the colour. Toned to match its bar, never instead of it. */
.va-delta { font-weight: 600; }
.va-delta--poor { color: var(--chart-weak); }
.va-delta--good { color: var(--chart-strong); }
.va-band { opacity: 0.8; }
.va-games { opacity: 0.75; }

@media (max-width: 620px) {
  /* The label above its own bar. A 15em label column beside a track leaves the
     track about forty pixels wide on a phone, which is not a chart. */
  .va-row { grid-template-columns: minmax(0, 1fr); gap: 3px; }
  .va-val { font-size: 11px; }
}

/* ============================================================
   THE PUNISHER LIST — every chance the scan found, as a list

   This was a grid of clickable cards. A move sequence is one line of type and
   wants to be read as one line of type; a card wraps it into three and puts a
   border round it. And twelve clickable cards is twelve competing targets out
   of an inventory nobody reads by clicking through it.

   So: rows, not cards, and the only thing you can press is one button per
   opening. The red is spent exactly once per row — on the move that answers
   the mistake, which is the one thing on the row you would want to remember.
   ============================================================ */
.pl-rows { list-style: none; margin: 12px 0 0 3px; padding: 0 0 0 15px; display: grid; }
.pl-row {
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 2px;
  border-top: 1px solid var(--border);
}
.pl-row:first-child { border-top: 0; }
/* Already answered by one of their opponents: still on the page, because a
   mistake they have been shown once is a different fact from one nobody has
   found — but not competing with the ones that are still open. */
.pl-row.is-answered { opacity: 0.62; }
.pl-rank {
  flex: 0 0 auto; min-width: 1.4em;
  font-family: var(--font-black); font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.pl-body { flex: 1 1 auto; min-width: 0; display: grid; gap: 3px; }
/* Wraps rather than scrolls. Unlike the banner stem, this is a whole game's
   worth of moves and a reader is looking for one move inside it, not reading
   the sequence as a single object. */
.pl-line {
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.5;
  color: var(--text-dim); overflow-wrap: anywhere;
}
.pl-line-seen { color: var(--text-dim); }
/* Moves the scan did not store. Marked rather than closed with invented ones:
   this row is read as though it were the game, so a gap has to look like a gap. */
.pl-gap { opacity: 0.55; padding: 0 2px; }
.pl-mvno { opacity: 0.5; padding-left: 4px; }
.pl-blunder { color: var(--text); font-weight: 700; }
/* The answer, and the only accent on the row. */
.pl-punish { color: var(--accent); font-weight: 700; }
.pl-meta {
  display: flex; align-items: baseline; gap: 4px 10px; flex-wrap: wrap;
  font-size: 11px; color: var(--text-dim);
}
.pl-eval {
  font-family: var(--font-mono); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.pl-flag--open { color: var(--accent); font-weight: 600; }
.pl-open-n { color: var(--accent); font-family: var(--font-mono); }
.pl-drill {
  font: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 4px 10px; cursor: pointer;
}
.pl-drill:hover { border-color: var(--accent); }
.pl-drill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 620px) {
  .pl-rows { margin-left: 0; padding-left: 9px; }
}

/* ============================================================
   THE OPPONENT DOSSIER INTAKE

   The scouting card leads the Reports page, so it carries the accent rule the
   Punisher hero uses and the report card below it does not. That contrast is
   the whole point of the block: the page now has a first thing and a second
   thing, and this is the first.
   ============================================================ */
.rep-scout-shell { border-left: 3px solid var(--accent); }
.rep-scout-shell .gr-aside-icon { color: var(--accent); }

/* Who is this card about — the switch that replaced the fold. Two intake
   forms sharing every field read as one form twice; the switch sits above
   the card, outside it, because it is the one thing on the page that does
   not flip. */
.rep-mode-tabs {
  display: flex;
  gap: 4px;
  margin: 0 0 20px;
  padding: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
  width: fit-content;
}
.rep-mode-tab {
  background: transparent;
  border: none;
  color: var(--text-dim);
  padding: 8px 20px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  border-radius: 2px;
  transition: color var(--transition), background var(--transition);
  white-space: nowrap;
}
.rep-mode-tab:hover { color: var(--text); }
.rep-mode-tab--active {
  background: var(--accent-muted);
  color: var(--accent);
}
@media (max-width: 480px) {
  .rep-mode-tabs { width: 100%; }
  /* Two uppercase labels do not fit one line under ~410px; wrap, don't clip. */
  .rep-mode-tab { flex: 1; min-width: 0; padding: 8px 10px; white-space: normal; line-height: 1.3; }
}

/* What the scan came back and said — a clean opponent, or a name that found
   nothing. Not a form error: nothing was typed wrong. */
.rep-scout-said {
  margin-bottom: 14px;
  border-left: 3px solid var(--accent);
}

/* The colour question a stranger may not be able to answer yet. */
.rep-scout-hint {
  font-size: 11.5px; line-height: 1.5; color: var(--text-dim);
  margin-top: 7px; max-width: 46ch;
}
/* The Clash intake puts a second name field straight under the side row; the
   hint above it needs air or the two labels read as one. */
.rep-scout-shell .gr-row + .gr-label { margin-top: 18px; }

/* The example dossier's own banner. It says what the page is before the page
   makes a claim, because an example that reads as a real report is a lie about
   a real player. */
.rep-demo-note {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: var(--radius);
  padding: 13px 15px; margin-top: 14px;
  font-size: 12.5px; line-height: 1.55; color: var(--text-dim);
  max-width: 100%;
}
.rep-demo-note b { color: var(--text); }
.rep-demo-note > div { flex: 1 1 320px; }
