  /* ============ Embedded trainer (scoped under .trainer-app) ============
     Retheme'd to use the site's actual design tokens (defined in site.css,
     which always loads before this file) instead of the old standalone
     app's own colors/fonts -- this is what makes the trainer feel like
     part of the same site instead of a bolted-on tool. */
  .trainer-app, .trainer-app * { box-sizing: border-box; }
  .trainer-app {
    font-family: var(--sans);
    color: var(--ivory);
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 48px;
  }

  #content-warnings {
    display: none;
    max-width: 1000px; margin: 0 auto 16px auto;
    background: rgba(180,70,70,0.12); border: 1px solid #7a3a3a; border-radius: 8px;
    padding: 12px 16px; color: #f0b8b8; font-size: 13px; line-height: 1.5;
  }
  #content-warnings strong { color: #ff9a9a; }
  #content-warnings ul { margin: 6px 0 0 0; padding-left: 20px; }

  .app-wrapper {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 24px;
    align-items: stretch;
  }

  .board-col {
    display: flex; flex-direction: column; align-items: center; gap: 12px;
    background: var(--ink-900); border: 1px solid var(--line); border-radius: 12px;
    padding: 18px; max-width: 700px;
  }
  .board-row { display: flex; gap: 8px; }

  /* Board + coordinate gutters. The gutters are a completely separate,
     never-rotated layer -- coordinate label position/order is computed
     directly in JS from BOARD_FLIPPED (simple, explicit, verifiable),
     rather than relying on CSS transforms to cancel out correctly. */
  #board-outer {
    display: grid;
    grid-template-columns: 22px 640px;
    grid-template-rows: 640px 22px;
    flex-shrink: 0;
  }
  #board-container {
    grid-column: 2; grid-row: 1;
    position: relative; width: 100%; height: 100%;
    border: 4px solid var(--line); border-radius: 4px;
  }
  #rank-gutter { grid-column: 1; grid-row: 1; position: relative; }
  #file-gutter { grid-column: 2; grid-row: 2; position: relative; }
  #rank-gutter .coord-label {
    position: absolute; left: 0; width: 22px; height: 12.5%;
    display: flex; align-items: center; justify-content: center;
  }
  #file-gutter .coord-label {
    position: absolute; top: 0; height: 22px; width: 12.5%;
    display: flex; align-items: center; justify-content: center;
  }
  .coord-label { font-size: 12px; font-weight: 600; pointer-events: none; font-family: var(--mono); color: var(--slate); }

  /* Board flip for Black repertoires: rotate the grid + piece layer
     180deg, then counter-rotate each square/piece so their own content
     still renders upright. DOM order and every row*8+col index lookup
     elsewhere in the code stay completely untouched -- only the visual
     presentation flips. Coordinates live outside this rotation entirely
     now, so there's nothing here to keep in sync for them. */
  #board-container.flipped #squares,
  #board-container.flipped #pieces-layer,
  #board-container.flipped #arrow-layer {
    transform: rotate(180deg);
  }
  #board-container.flipped .square,
  #board-container.flipped .piece {
    transform: rotate(180deg);
  }
  #squares {
    position: absolute; inset: 0;
    display: grid; grid-template-columns: repeat(8, 1fr); grid-template-rows: repeat(8, 1fr);
  }
  .square { position: relative; cursor: pointer; }
  .square.light { background: #f0d9b5; }
  .square.dark  { background: #b58863; }
  .square.legal-target::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 22%; height: 22%; background: rgba(0,0,0,0.28);
    border-radius: 50%; transform: translate(-50%, -50%); pointer-events: none;
  }
  .square.legal-capture::after {
    content: ""; position: absolute; inset: 6%;
    border: 5px solid rgba(0,0,0,0.28); border-radius: 50%; pointer-events: none;
  }
  .square.selected { outline: 4px solid var(--brass-bright); outline-offset: -4px; }
  .square.hint-highlight { outline: 4px solid var(--teal); outline-offset: -4px; background: rgba(75,145,135,0.28); }

  #pieces-layer { position: absolute; inset: 0; pointer-events: none; }
  /* Sits above pieces (z-index 2) and coordinates (z-index 3) so a
     hanging-piece arrow is never partly hidden behind either. No
     per-element counter-rotation needed here the way pieces/coords
     get, since an arrow's whole shape is defined by its two endpoints
     -- once those are correctly flipped by the parent's 180deg
     rotation, the arrow drawn between them is automatically correct
     too, unlike a piece glyph which has a fixed "this way up" image. */
  #arrow-layer { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
  .piece {
    position: absolute; width: 12.5%; height: 12.5%;
    display: flex; align-items: center; justify-content: center;
    font-size: 78px; cursor: pointer; pointer-events: auto; user-select: none;
    transition: left 0.28s ease, top 0.28s ease; z-index: 2;
  }
  .piece img {
    width: 82%; height: 82%; object-fit: contain; pointer-events: none;
    filter: drop-shadow(1px 3px 2px rgba(0,0,0,0.45));
  }
  /* Fallback styling only -- used if a piece image fails to load */
  .piece.white { color: #fefefe; -webkit-text-stroke: 2px #202225; text-shadow: 0 0 1px #202225, 0 0 1px #202225, 0 0 1px #202225; }
  .piece.black { color: #1a1a1a; text-shadow: 0 0 1px #f5f5f5; }


  #move-nav { display: flex; align-items: center; gap: 8px; width: 100%; }
  #move-nav button.nav-arrow {
    font-family: var(--sans); font-weight: 600;
    background: var(--ink-850); color: var(--ivory); border: 1px solid var(--line); border-radius: 6px;
    padding: 7px 12px; cursor: pointer; font-size: 13px; flex-shrink: 0;
  }
  #move-nav button.nav-arrow:disabled { opacity: 0.35; cursor: default; }
  #move-nav button.nav-arrow:not(:disabled):hover { background: var(--ink-800); border-color: var(--brass-dim); }
  #move-chips {
    display: flex; gap: 4px; overflow-x: auto; flex: 1; min-width: 0;
    padding: 5px; background: var(--ink-950); border: 1px solid var(--line); border-radius: 6px;
  }
  .move-chip {
    font-family: var(--mono);
    background: var(--ink-850); color: var(--slate); border: 1px solid var(--line); border-radius: 5px;
    padding: 5px 9px; font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0;
  }
  .move-chip.start-chip { color: var(--slate-dim); font-style: italic; }
  .move-chip.active { background: var(--teal-dim); border-color: var(--teal); color: var(--ivory); font-weight: 600; }
  .move-chip:disabled { opacity: 0.5; cursor: default; }
  #nav-hint { font-family: var(--mono); font-size: 12px; color: var(--brass); min-height: 14px; width: 100%; }

  #coach-panel {
    display: flex; flex-direction: column; gap: 12px;
    background: var(--ink-900); border: 1px solid var(--line); border-radius: 12px;
    padding: 18px; min-width: 360px;
  }

  /* "Line X of Y" badge at the very top of the right column */
  #line-counter {
    font-family: var(--mono);
    align-self: flex-start;
    background: var(--ink-850); border: 1px solid var(--line); border-radius: 20px;
    padding: 6px 14px; font-size: 12px; font-weight: 600; color: var(--slate);
    letter-spacing: 0.02em;
  }
  #line-counter.reviewing { background: rgba(201,162,75,0.12); border-color: var(--brass-dim); color: var(--brass-bright); }

  #line-progress-track {
    align-self: stretch;
    height: 5px;
    background: var(--ink-850);
    border: 1px solid var(--line);
    border-radius: 4px;
    overflow: hidden;
    margin-top: 8px;
  }
  #line-progress-fill {
    height: 100%;
    width: 0%;
    background: var(--brass);
    border-radius: 4px;
    transition: width 0.3s ease;
  }
  #line-counter.reviewing ~ #line-progress-track #line-progress-fill { background: var(--brass-bright); }

  #bubble-col { flex: 1; display: flex; flex-direction: column; gap: 10px; }
  .speech-bubble { background: var(--ink-850); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; font-size: 16px; line-height: 1.55; }

  .coach-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    width: 100%;
  }
  .coach-avatar {
    flex-shrink: 0;
    width: 17px; height: 17px;
    border-radius: 50%;
    overflow: hidden;
    box-shadow: 0 0 0 1px var(--brass-dim);
  }
  .coach-avatar svg { width: 100%; height: 100%; display: block; }

  /* #coach-text specifically becomes a white speech bubble with a tail
     pointing at its own avatar -- the shared .speech-bubble class above
     stays untouched, since puzzles.html also uses it for a plain box
     with no avatar. Sized from the real content, not a guess: across
     all 30 openings, move commentary runs up to ~146 characters in
     ordinary cases (~4 wrapped lines at the narrowest layout this
     renders at), with average length around 78 characters -- a rare
     off-book fallback message (~300 characters) is a genuine outlier
     tied to deviating from the taught line, not everyday play, and
     isn't worth reserving permanent space for. This applies at every
     width, not just mobile: on the wider desktop panel the same text
     wraps to fewer lines, so 138px comfortably covers both. */
  #coach-text {
    position: relative;
    background: var(--ivory);
    color: var(--ink-950);
    border: none;
    border-radius: 14px 14px 14px 14px;
    align-self: stretch;
    margin-top: 2px;
    min-height: 138px;
  }
  #coach-text::before {
    content: '';
    position: absolute;
    top: -7px; left: 8px;
    width: 0; height: 0;
    border-style: solid;
    border-width: 0 8px 8px 8px;
    border-color: transparent transparent var(--ivory) transparent;
  }

  /* Always reserves its own space and fades via opacity rather than
     display:none/block -- a prompt that pops in and out of the layout
     entirely pushes everything below it (the board, on mobile; the
     rest of the panel, on desktop) every time it toggles, which is
     most moves. Applies to both layouts, not just mobile, since the
     same jump risk exists either way, just less visible on the wider
     desktop column. */
  #coach-prompt-row {
    display: block;
    width: 100%;
    margin-bottom: 10px;
    min-height: 64px;
    opacity: 0;
    transition: opacity 0.15s ease;
  }
  #coach-prompt-row.visible { opacity: 1; }

  #coach-prompt {
    position: relative;
    background: var(--ivory);
    border-radius: 14px;
    padding: 12px 16px;
    font-size: 15px; font-weight: 600; color: var(--ink-950);
    text-align: center;
  }

  /* Theory now lives behind a collapsed-by-default accordion -- the
     "what to play" text above the board is what a player needs on
     every single move, but the "why" is opt-in depth for whenever
     they actually want it, not something forced into view every time. */
  #theory-accordion { width: 100%; }
  #theory-accordion summary {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    cursor: pointer; list-style: none;
    font-family: var(--sans); font-weight: 600; font-size: 13.5px; color: var(--brass);
    padding: 10px 2px;
  }
  #theory-accordion summary::-webkit-details-marker { display: none; }
  #theory-accordion .theory-plus {
    font-family: var(--mono); font-size: 15px; color: var(--brass); flex-shrink: 0;
  }
  #theory-accordion[open] .theory-plus::before { content: '\2212'; }
  #theory-accordion:not([open]) .theory-plus::before { content: '+'; }
  #theory-box {
    background: var(--ink-800); border: 1px solid var(--line); border-radius: 10px;
    font-size: 14px; line-height: 1.55; color: var(--ivory); opacity: 0.92;
    padding: 16px 18px; margin-top: 4px;
  }

  /* Line-level navigation: two buttons that together span full width */
  .line-nav-buttons { display: flex; gap: 10px; }
  .line-nav-buttons button {
    font-family: var(--sans); font-weight: 600;
    flex: 1; background: var(--teal-dim); color: var(--ivory); border: 1px solid var(--teal-dim);
    padding: 12px 10px; border-radius: 8px; cursor: pointer; font-size: 14px;
  }
  .line-nav-buttons button:hover:not(:disabled) { background: var(--teal); border-color: var(--teal); }
  .line-nav-buttons button:disabled { opacity: 0.35; cursor: default; }

  #reset-btn {
    font-family: var(--sans); font-weight: 600;
    background: transparent; color: var(--ivory); border: 1px solid var(--line);
    padding: 10px 16px; border-radius: 6px; cursor: pointer; font-size: 14px; margin-top: auto;
  }
  #reset-btn:hover { border-color: var(--brass); color: var(--brass-bright); }
  #line-counter-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  #practice-streak {
    font-family: var(--sans); font-size: 12.5px; color: var(--slate); white-space: nowrap;
  }
  #jump-to-first-btn {
    font-family: var(--sans); font-weight: 600; font-size: 12px;
    background: transparent; color: var(--slate); border: none; cursor: pointer;
    padding: 14px 6px; text-decoration: underline; text-underline-offset: 2px;
  }
  #jump-to-first-btn:hover:not(:disabled) { color: var(--brass-bright); }
  #jump-to-first-btn:disabled { opacity: 0.35; cursor: default; text-decoration: none; }
  #status-banner { text-align: left; font-weight: 600; color: var(--teal-bright); min-height: 22px; font-size: 15px; }

  @media (max-width: 860px) {
    .trainer-app { padding: 0 6px; }
  }

  @media (max-width: 1050px) {
    .app-wrapper { grid-template-columns: 1fr; max-width: 640px; }
    .board-col { min-width: 0; padding: 6px; }
    .board-row { width: 100%; align-items: stretch; gap: 0; }
    #board-outer {
      flex: 1 1 0%;
      min-width: 0;
      width: auto;
      display: block;
      position: relative;
    }
    #board-container { width: 100%; height: auto; aspect-ratio: 1 / 1; min-width: 0; }
    /* Coordinates move from their own reserved gutters (which were
       stealing width/height from the board on narrow screens) to a
       transparent overlay sitting exactly on top of the board itself.
       The JS's existing top%/left% inline styles need no changes --
       they're percentages of whichever container they're in, so they
       correctly remap onto the board the moment the container does. */
    #rank-gutter, #file-gutter {
      position: absolute; top: 0; left: 0; right: 0; bottom: 0;
      pointer-events: none; z-index: 3;
    }
    #rank-gutter .coord-label {
      width: auto; height: 12.5%; left: 3px;
      justify-content: flex-start;
    }
    #file-gutter .coord-label {
      height: auto; width: 12.5%; top: auto; bottom: 2px;
      align-items: flex-end; justify-content: flex-end; margin-right: 3px;
    }
    /* No background block behind the labels -- just bold, dark text
       with a light text-shadow doing double duty as a soft outline,
       so it reads on both the light and dark square colors without
       a visible white chip sitting on top of the board art. */
    .coord-label {
      font-size: 11px; font-weight: 700; color: #2a1c10;
      text-shadow: 0 0 2px rgba(240,235,225,0.9), 0 0 2px rgba(240,235,225,0.9);
      line-height: 1.3;
    }
    .piece { font-size: 62px; }
    #coach-panel { min-width: 0; }
  }

  /* ============ Free trial paywall ============ */
  #paywall-panel {
    display: none;
    grid-column: 1 / -1;
    align-items: center; justify-content: center;
    min-height: 420px;
    padding: 20px;
  }
  .paywall-card {
    max-width: 460px;
    text-align: center;
    background: var(--ink-900); border: 1px solid var(--line); border-radius: 14px;
    padding: 36px 32px;
  }
  .paywall-eyebrow {
    font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--teal-bright); margin-bottom: 14px;
  }
  .paywall-title {
    font-family: var(--serif); font-weight: 600; font-size: 24px; line-height: 1.25;
    color: var(--ivory); margin-bottom: 14px;
  }
  .paywall-body {
    font-family: var(--sans); font-size: 14.5px; line-height: 1.6; color: var(--slate);
    margin-bottom: 24px;
  }
  .paywall-cta {
    display: block; width: 100%;
    font-family: var(--sans); font-weight: 600; font-size: 15px; color: var(--ink-950);
    background: var(--brass-bright); padding: 14px; border-radius: 8px; text-decoration: none;
    margin-bottom: 12px;
  }
  .paywall-cta:hover { background: var(--ivory); }
  .paywall-back-btn {
    display: block; width: 100%;
    font-family: var(--sans); font-weight: 600; font-size: 13.5px; color: var(--slate);
    background: transparent; border: none; padding: 8px; cursor: pointer;
    margin-bottom: 18px;
  }
  .paywall-back-btn:hover { color: var(--ivory); }
  .paywall-beta { border-top: 1px solid var(--line-soft); padding-top: 16px; }
  .paywall-beta-toggle {
    font-family: var(--sans); font-size: 12.5px; font-weight: 600; color: var(--slate);
    background: transparent; border: none; cursor: pointer; text-decoration: underline;
    text-underline-offset: 2px;
  }
  .paywall-beta-toggle:hover { color: var(--brass-bright); }
  .paywall-beta-row {
    display: none; gap: 8px; margin-top: 12px;
  }
  .paywall-beta-row.visible { display: flex; }
  .paywall-beta-row input {
    flex: 1; min-width: 0;
    font-family: var(--mono); font-size: 13px; color: var(--ivory);
    background: var(--ink-850); border: 1px solid var(--line); border-radius: 6px;
    padding: 9px 10px;
  }
  .paywall-beta-submit {
    font-family: var(--sans); font-weight: 600; font-size: 12.5px; color: var(--ivory);
    background: transparent; border: 1px solid var(--line); border-radius: 6px;
    padding: 9px 14px; cursor: pointer; white-space: nowrap;
  }
  .paywall-beta-submit:hover { border-color: var(--brass); color: var(--brass-bright); }
  .paywall-beta-error {
    font-family: var(--sans); font-size: 12px; color: #d97a6c; margin-top: 8px; min-height: 16px;
  }

  @media (max-width: 1050px) {
    #paywall-panel { min-height: 320px; padding: 8px; }
    .paywall-card { padding: 26px 22px; }
    .paywall-title { font-size: 20px; }
  }

  /* ============ Puzzle categories (puzzles.html) ============ */
  #puzzle-paywall-panel {
    display: none;
    align-items: center; justify-content: center;
    min-height: 420px;
    padding: 20px;
  }
  .puzzle-cat-card { cursor: pointer; }
  .puzzle-cat-icon {
    width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center;
    color: var(--brass-bright);
    margin-bottom: 14px;
  }
  .puzzle-cat-icon svg { width: 26px; height: 26px; }
  .pz-cat-header {
    display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
    gap: 12px; margin-bottom: 20px;
  }
  .pz-cat-back-btn {
    font-family: var(--sans); font-weight: 600; font-size: 13px; color: var(--slate);
    background: transparent; border: none; cursor: pointer; padding: 6px 0;
  }
  .pz-cat-back-btn:hover { color: var(--brass-bright); }
  #pz-cat-progress {
    font-family: var(--mono); font-size: 12px; color: var(--slate-dim);
  }

  @media (max-width: 1050px) {
    #puzzle-paywall-panel { min-height: 320px; padding: 8px; }
  }

  /* ============ Puzzle scorecard ============ */
  .scorecard-card {
    border: 1px solid var(--line); border-radius: 14px; background: var(--ink-900);
    padding: 26px 28px;
  }
  .scorecard-head {
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
    flex-wrap: wrap;
    padding-bottom: 20px; margin-bottom: 18px; border-bottom: 1px solid var(--line-soft);
  }
  .scorecard-eyebrow {
    font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--slate-dim); margin-bottom: 6px;
  }
  .scorecard-total {
    font-family: var(--serif); font-weight: 600; font-size: 32px; color: var(--ivory);
  }
  .scorecard-total span {
    font-family: var(--sans); font-weight: 500; font-size: 14px; color: var(--slate);
  }
  .scorecard-streak {
    display: flex; align-items: baseline; gap: 6px; margin-top: 8px;
    font-family: var(--sans); font-size: 13px; color: var(--slate);
  }
  .scorecard-streak-flame { font-size: 14px; }
  .scorecard-streak-count { font-weight: 600; color: var(--brass-bright); font-size: 15px; }
  .scorecard-streak-best { color: var(--slate-dim); font-size: 12px; margin-left: 4px; }
  .scorecard-ring {
    --pct: 0;
    width: 68px; height: 68px; border-radius: 50%; flex-shrink: 0;
    background: conic-gradient(var(--brass-bright) calc(var(--pct) * 1%), var(--ink-800) 0);
    display: flex; align-items: center; justify-content: center;
  }
  .scorecard-ring::before {
    content: ''; position: absolute; width: 52px; height: 52px; border-radius: 50%; background: var(--ink-900);
  }
  .scorecard-ring { position: relative; }
  .scorecard-ring span {
    position: relative; z-index: 1;
    font-family: var(--mono); font-weight: 600; font-size: 13px; color: var(--ivory);
  }
  .scorecard-rows { display: flex; flex-direction: column; gap: 12px; }
  .scorecard-row { display: grid; grid-template-columns: 140px 1fr auto; align-items: center; gap: 14px; }
  .scorecard-row-label {
    font-family: var(--sans); font-weight: 500; font-size: 12.5px; color: var(--slate);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .scorecard-row-bar { height: 6px; border-radius: 4px; background: var(--ink-800); overflow: hidden; }
  .scorecard-row-fill { height: 100%; background: var(--teal-bright); border-radius: 4px; }
  .scorecard-row-count {
    font-family: var(--mono); font-size: 12px; color: var(--slate-dim); white-space: nowrap;
  }
  .scorecard-save-note {
    margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line-soft);
    font-family: var(--sans); font-size: 12.5px; color: var(--slate); line-height: 1.5;
  }
  .scorecard-save-note a { color: var(--brass-bright); text-decoration: none; font-weight: 600; }
  .scorecard-save-note a:hover { text-decoration: underline; }

  @media (max-width: 640px) {
    .scorecard-row { grid-template-columns: 100px 1fr auto; }
    .scorecard-total { font-size: 26px; }
  }
