/* Board, pieces, highlights and promotion picker. Page layout is added separately. */
.board {
  --bw: min(92vw, 560px);
  position: relative;
  width: var(--bw);
  height: var(--bw);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  border: 2px solid #333;
  box-sizing: content-box;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.board .sq {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  cursor: pointer;
}
.board .sq.light { background: #eeeed2; }
.board .sq.dark { background: #769656; }
.board .sq.last { box-shadow: inset 0 0 0 100px rgba(255, 210, 0, .5); }
.board .sq.selected { outline: 3px solid #1e88e5; outline-offset: -3px; }
/* SVG pieces (white with a dark outline, black solid), 88% of the square, centred by layout. */
.board .piece,
.board .ghost {
  position: absolute;
  left: 6%;
  top: 6%;
  width: 88%;
  height: 88%;
  display: block;
  pointer-events: none;
  -webkit-user-drag: none;
}
/* Piece motion (js/board.js): a sliding piece is drawn above pieces at rest and may leave its square. */
.board .sq.moving { overflow: visible; }
.board .sq.moving .piece { z-index: 1; }
.board .marker { position: absolute; pointer-events: none; }
.board .target.move .marker {
  width: 28%;
  height: 28%;
  border-radius: 50%;
  background: rgba(20, 60, 20, .45);
}
.board .target.capture .marker {
  inset: 6%;
  border-radius: 50%;
  border: 4px solid rgba(20, 60, 20, .55);
}
.board .coord {
  position: absolute;
  font-size: max(9px, calc(var(--bw) / 8 * 0.2));
  line-height: 1;
  font-weight: 700;
  opacity: .7;
  color: #333;
  pointer-events: none;
}
.board .coord.rank { left: 3px; top: 2px; }
.board .coord.file { right: 3px; bottom: 2px; }
.board .promo-picker {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2%;
  background: rgba(0, 0, 0, .55);
}
.board .promo-choice {
  position: relative;
  width: 20%;
  aspect-ratio: 1;
  padding: 0;
  border: 2px solid #333;
  border-radius: 8px;
  background: #eeeed2;
  cursor: pointer;
}
.board .promo-choice:focus-visible { outline: 3px solid #1e88e5; outline-offset: 2px; }

/* ---- Page layout and screens ---- */
:root {
  --bg: #0d1021;
  --card: #1a1f3a;
  --text: #f4f1e8;
  --muted: #a9b0cc;
  --accent: #8fd18f;
  --line: #2f3660;
  --btn: #262c50;
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
/* The "All games" bar, as on the other games: fixed, 40px, on every screen; .app starts below it.
   --bar is its height; every "below the bar" size uses it. Inside the Android app the bar is hidden and --bar is 0. */
:root { --bar: 40px; }
body.native { --bar: 0px; }
body.native #bar { display: none; }
#bar { position: fixed; top: 0; left: 0; right: 0; height: 40px; z-index: 10; display: flex; align-items: center; gap: 16px;
  padding: 0 12px; padding-left: max(12px, env(safe-area-inset-left)); background: #000; color: #ddd; font: 600 14px system-ui, sans-serif; border-bottom: 1px solid #333; }
#bar a { color: #ddd; text-decoration: none; padding: 4px 10px; border-radius: 6px; }
#bar a:hover { background: #333; color: #fff; }
#bar .title { opacity: 0.7; }
.app { max-width: 1000px; margin: 0 auto; padding: calc(var(--bar) + 24px) 16px 48px; }
.card { background: var(--card); border-radius: 16px; padding: 18px 20px; }
.muted { color: var(--muted); }
[hidden] { display: none !important; }

.btn {
  min-height: 44px;
  padding: 0 18px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--btn);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover:not(:disabled) { border-color: var(--accent); }
.btn:focus-visible { outline: 3px solid #ffd54f; outline-offset: 3px; }
.btn:disabled { opacity: .4; cursor: default; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #111; }

/* Home */
.home { max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.home h1 { text-align: center; color: var(--accent); font-size: clamp(2rem, 6vw, 2.8rem); margin: 8px 0 0; }
.home h2 { margin: 0 0 4px; font-size: 1.3rem; }
.home p { margin: 0; }
.level-card { display: flex; flex-direction: column; gap: 6px; }
/* The level and settling lines, redrawn per format, lay out as the card's own lines. */
.level-lines { display: contents; }
.your-level { font-size: 1.4rem; font-weight: 700; }
.settling { color: var(--accent); min-height: 1lh; } /* reserved even when empty (settled) */
.estimate { color: var(--muted); min-height: 1lh; } /* three forms; the range form wraps on a phone */
/* Narrow: "Your level (Blitz): about 1340" wraps while "Your level: about 1100" does not, and "Still settling:
   play 4 more rated games." wraps while a settled format's line is empty, so both keep two lines for every
   format and picking one never moves the format choices below. */
@media (max-width: 719.98px) {
  .your-level { line-height: 1.3; min-height: 2.6em; }
  .settling { min-height: 2lh; }
  .estimate { min-height: 2lh; }
}
.storage-warning { margin: 0; padding: 12px 16px; border-radius: 12px; background: #4a2a12; color: #ffd8a8; font-weight: 600; }
.continue-card { display: flex; flex-direction: column; gap: 12px; align-items: stretch; }
.new-game { display: flex; flex-direction: column; gap: 14px; }
.new-game fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.new-game legend { padding: 0; margin-bottom: 8px; color: var(--muted); font-size: .9rem; text-transform: uppercase; letter-spacing: .06em; }
.choices { display: flex; gap: 8px; }
.choice {
  flex: 1 1 0;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 2px solid var(--line);
  background: var(--btn);
  cursor: pointer;
}
.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice-label { font-weight: 700; text-align: center; }
.choice-note { font-size: .85rem; color: var(--muted); text-align: center; }
.choice:has(input:checked) { border-color: var(--accent); background: rgba(143, 209, 143, .12); }
.choice:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Five formats: they wrap onto a second row on a narrow screen rather than squeezing their labels. */
.formats .choices { flex-wrap: wrap; }
.formats .choice { flex: 1 0 auto; padding: 10px 8px; }
.level-box { display: flex; flex-direction: column; gap: 8px; }
.level-value, .rated-level { font-weight: 700; font-size: 1.1rem; }
#level-slider { width: 100%; height: 44px; accent-color: var(--accent); margin: 0; }

/* Game: panel under the board on narrow screens, beside it from 720px */
.game { display: flex; flex-direction: column; align-items: center; gap: 16px; }
.board-col { width: 100%; max-width: 564px; container-type: inline-size; }
.board-col .board { --bw: min(100cqi - 4px, 560px); margin: 0 auto; }
/* Practice: the eval bar beside the board, as tall as it. The bar takes 18px with its border, plus a 6px gap. */
.board-row { display: flex; align-items: stretch; gap: 6px; justify-content: center; }
.board-row .board { margin: 0; }
.board-row.with-bar .board { --bw: min(100cqi - 28px, 560px); }
.eval-bar { width: 14px; flex: 0 0 14px; display: flex; flex-direction: column; border: 2px solid #333; box-sizing: content-box; position: relative; background: #1b1b1b; }
.eval-bar[hidden] { display: none; }
.eval-bar[data-flipped="1"] { flex-direction: column-reverse; }
.eval-black { flex: 1 1 auto; }
.eval-white { background: #f0f0f0; height: 50%; transition: height .3s ease-out; }
.eval-bar.pending { opacity: .6; }
.eval-label { position: absolute; top: 2px; left: 0; right: 0; font-size: 9px; line-height: 1; text-align: center; color: #fff; mix-blend-mode: difference; font-variant-numeric: tabular-nums; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .eval-white { transition: none; }
}
.toggle { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; cursor: pointer; }
.toggle input { margin: 0; accent-color: var(--accent); }
.panel {
  width: 100%; max-width: 564px; display: flex; flex-direction: column; gap: 10px;
  /* The slot shared by the move list and the Ideas panel: the open panel's natural height, so the list matches it
     and nothing moves when the panel opens or closes. Tabs 52 + gap 8 + the line's moves (two 15px lines at 1.7,
     plus 12 padding and border) + gap 8 + the step controls (a 44px button) + gap 8 + the coach box 4.5em
     = 52 + 8 + 63 + 8 + 44 + 8 + 72 = 255px at the 16px page font. */
  --slot-h: calc(52px + 8px + (2 * 1.7 * 15px + 12px) + 8px + 44px + 8px + 4.5em);
}
/* Narrow: the buttons sit right under the status line and the move list (or the Ideas panel in its place) goes
   last, so Takeback, Resign, Flip and Home stay above the fold on a phone. */
@media (max-width: 719.98px) {
  .panel .buttons { order: 1; }
  .panel .level-change { order: 3; }
  .panel .list-slot { order: 4; }
}
@media (min-width: 720px) {
  .game { flex-direction: row; align-items: flex-start; justify-content: center; }
  .board-col { flex: 1 1 564px; }
  .board-col .board { --bw: min(100cqi - 4px, 560px, 100vh - 112px - var(--bar)); } /* room for the bar above and the step row under it */
  .board-row.with-bar .board { --bw: min(100cqi - 28px, 560px, 100vh - 112px - var(--bar)); }
  .toggle { min-height: 32px; }
  .panel { flex: 0 1 340px; min-width: 280px; }
}
.game-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.badge {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  border: 1px solid var(--accent);
  color: var(--accent);
}
.badge.rated { border-color: #ffb347; color: #ffb347; }
.bot-level { font-weight: 700; }
/* The player's clock: fixed-width digits and a minimum width, so the toggles after it never move as it counts. */
.clock { font-variant-numeric: tabular-nums; min-width: 5.5ch; text-align: right; font-weight: 700; }
/* A clock that starts at an hour or more (Classical) also shows "1:30:00": room for that, so crossing below an
   hour (and back, with the increment) never changes its width. */
.clock.long { min-width: 7ch; }
.clock.low { color: #e53935; }
.opening { min-height: 1.4em; color: var(--muted); }
/* Game and review screens: always two lines tall, so nothing under it moves when the name changes; longer
   names are clipped with an ellipsis (the full name is in the title). */
.game .opening {
  height: 2.8em;
  min-height: 0;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.opening .eco { font-family: ui-monospace, Menlo, Consolas, monospace; font-weight: 700; color: var(--text); }
.status { margin: 0; font-size: 1.25rem; font-weight: 700; min-height: 1.5em; }
/* Game screen: exactly one line at a fixed height whatever it says, so nothing under it moves. The size
   also follows the panel's width (100cqi / 16 leaves room for "Looking back. Tap ⏭ to return."), so every
   status fits where the panel is narrow: on a phone, and beside the board between 720px and about 900px. */
#game .panel { container-type: inline-size; }
#game .status { font-size: min(1.15rem, 100cqi / 16); height: 1.5em; min-height: 0; line-height: 1.5; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 719.98px) {
  #game .status { font-size: min(1.05rem, 100cqi / 16); }
}
#game .status.looking { color: var(--accent); }
.level-change { margin: 0; color: var(--accent); font-weight: 700; }
.moves {
  height: 200px;
  overflow-y: auto;
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--line);
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 15px;
  line-height: 1.7;
}
.move-row { display: grid; grid-template-columns: 3em 1fr 1fr; }
.move-num { color: var(--muted); }
/* Move list (js/screens/movelist.js), on the game and review screens. Each move is a button; on the game
   screen it looks like the plain text it replaced, on the review screen it has a little padding and a hover. */
.moves { --move-pad: 0; --move-radius: 4px; --move-glow: 4px; --move-hover: none; }
.review .moves { --move-pad: 6px; --move-radius: 6px; --move-glow: 0px; --move-hover: rgba(255, 255, 255, .08); }
.move-san {
  justify-self: start;
  white-space: nowrap;
  padding: 0 var(--move-pad);
  border: 0;
  border-radius: var(--move-radius);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.move-san:hover { background: var(--move-hover); }
.move-san:focus-visible { outline: 2px solid #ffd54f; outline-offset: 1px; }
.move-san.current { background: var(--accent); color: #111; box-shadow: calc(-1 * var(--move-glow)) 0 0 var(--accent), var(--move-glow) 0 0 var(--accent); }
@media (max-width: 719.98px) {
  .move-row { align-items: center; }
  .move-san { min-height: 36px; min-width: 44px; } /* a reasonable tap target on a phone */
}
.buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.buttons .btn { flex: 1 1 auto; }

/* The Ideas panel (practice): up to three candidate lines as tabs, the chosen line's moves, step controls, and the
   coach's note. Every part has a fixed height, so the controls above the coach box never move as the text changes. */
.ideas { display: none; }
.ideas.open { display: flex; flex-direction: column; gap: 8px; }
/* The move list and the Ideas panel in one slot of a fixed height (--slot-h on .panel): while the panel is open the
   list is hidden, and on Close it comes back in the same place. */
.list-slot { height: var(--slot-h); }
.list-slot .moves, .list-slot .ideas.open { height: 100%; }
.list-slot.ideas-open .moves { display: none; }
.idea-tabs { display: flex; gap: 6px; }
.idea-tab {
  flex: 1 1 0; min-width: 0; height: 52px; padding: 4px 8px;
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  border-radius: 10px; border: 1px solid var(--line); background: rgba(255, 255, 255, .04); color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
}
.idea-tab:disabled { opacity: .4; cursor: default; }
.idea-tab.on { border-color: var(--accent); background: rgba(143, 209, 143, .12); }
.idea-tab:focus-visible { outline: 3px solid #ffd54f; outline-offset: 2px; }
.idea-score, .idea-name { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; }
.idea-score { font-family: ui-monospace, Menlo, Consolas, monospace; font-weight: 700; min-height: 1.3em; }
.idea-name { font-size: .8rem; color: var(--muted); min-height: 1.3em; }
.idea-tab.on .idea-name { color: var(--text); }
.idea-moves {
  height: calc(2 * 1.7em + 12px); overflow: hidden; padding: 6px 10px;
  border-radius: 10px; background: rgba(255, 255, 255, .04); border: 1px solid var(--line);
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 15px; line-height: 1.7;
}
.idea-moves span { padding: 1px 3px; border-radius: 4px; margin-right: 2px; }
.idea-moves span.cur { background: var(--accent); color: #111; font-weight: 700; }
.idea-moves span.done { opacity: .55; }
.idea-ctrls { display: flex; align-items: center; gap: 6px; }
.idea-ctrls .btn { flex: 0 0 auto; padding: 0 14px; }
#idea-play { margin-left: auto; }
.idea-coach {
  height: 4.5em; overflow: hidden; padding: 3px 10px; line-height: 1.25;
  border-left: 4px solid var(--accent); border-radius: 0 10px 10px 0; background: rgba(143, 209, 143, .08);
}
.idea-label { font-size: .7rem; line-height: 1.2; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); height: 1.2em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.idea-sentence { font-size: .85rem; } /* three lines of a 120-character sentence fit under the label */
.step-row.disabled { pointer-events: none; opacity: .5; }

/* History: the page fits the viewport; a long list scrolls inside its own area. */
.history-btn { width: 100%; }
.history {
  max-width: 760px;
  margin: 0 auto;
  height: calc(100vh - 72px - var(--bar)); /* .app's top (24px and the bar) and bottom padding */
  height: calc(100dvh - 72px - var(--bar));
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.history-head { display: flex; align-items: center; gap: 16px; }
.history-head h1 { margin: 0; font-size: 1.8rem; color: var(--accent); }
.history p { margin: 0; }
.history-summary { font-weight: 600; }
.trend-card { flex: 0 0 auto; padding: 14px 16px; }
.trend-card h2 { margin: 0 0 8px; font-size: 1.05rem; }
/* The format picker: one row of a fixed height (the buttons never wrap), so picking a format never moves
   the title and chart under it. With more than one format to pick, the chart's room is kept even when a
   format has only the one-sentence message, so the list below does not move either. */
.format-picks { display: flex; gap: 6px; height: 44px; margin-bottom: 10px; }
.format-pick { flex: 0 1 auto; min-width: 0; padding: 0 12px; font-size: .9rem; white-space: nowrap; }
.format-pick[aria-pressed="true"] { border-color: var(--accent); background: rgba(143, 209, 143, .12); color: var(--accent); }
.trend-card.pickable .trend-body { min-height: 356px; } /* legend 18 + 4, chart 220, accuracy legend 6 + 18, accuracy 90 */
/* The legends have fixed heights, so the charts sit at the same place whatever the format. Text in text colours;
   the swatch beside it carries the series colour (dashed for practice). */
.trend-legend, .accuracy-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px 14px; height: 18px; overflow: hidden;
  font-size: 12px; color: var(--muted);
}
.trend-legend { margin-bottom: 4px; }
.accuracy-legend { margin-top: 6px; }
.accuracy-title { color: var(--text); font-weight: 600; }
.trend-key { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.trend-key .swatch { display: inline-block; width: 16px; height: 0; border-top: 2px solid; }
.trend-key .swatch.dashed { border-top-style: dashed; }
.trend-plot { position: relative; }
.trend-chart svg { display: block; font-family: inherit; }
.trend-chart svg:focus { outline: none; }
.trend-chart svg:focus-visible { outline: 3px solid #ffd54f; outline-offset: 2px; border-radius: 4px; }
.trend-hit { touch-action: pan-y; }
.trend-tip {
  position: absolute;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 10px;
  border-radius: 8px;
  background: #0d1021;
  border: 1px solid var(--line);
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
}
.trend-tip-value { color: var(--text); font-size: 14px; display: flex; flex-direction: column; }
.trend-tip-detail { color: var(--muted); }
.history-list {
  flex: 1 1 auto;
  min-height: 140px; /* room for the trend card's accuracy chart at 1100x800 */
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 2px 4px 2px 2px;
}
.history-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 0 0 auto;
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--text);
  font: inherit;
  text-align: left;
}
button.history-row { cursor: pointer; }
button.history-row:hover { border-color: var(--accent); }
button.history-row:focus-visible { outline: 3px solid #ffd54f; outline-offset: 2px; }
.history-row.broken { border-style: dashed; }
.row-head, .row-main, .row-more { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.row-date { color: var(--muted); min-width: 6.5em; }
.row-more { font-size: .9rem; }
.history-row .format { font-weight: 600; }
.history-notice { font-weight: 600; color: #ffd8a8; }
/* Narrow: the whole page scrolls, not a small box inside it. */
@media (max-width: 719.98px) {
  .history { height: auto; }
  .history-list { flex: 0 0 auto; min-height: 0; overflow-y: visible; }
  .format-pick { flex: 1 1 auto; padding: 0 6px; }
  .trend-card.pickable .trend-body { min-height: 334px; } /* legend 34 + 4, chart 180, accuracy legend 6 + 18, accuracy 90 */
  .trend-legend { height: 34px; } /* room for the three keys on two lines */
  /* "Level and rating, all games (Classical)" wraps at 360px while "(Free)" may not: two lines kept for every title. */
  .trend-card h2 { line-height: 1.3; min-height: 2.6em; }
}

/* Step controls (js/screens/stepper.js), directly under the board. The row has a fixed height and the
   readout a fixed width (room for "102… Qxe8=Q+"), so the buttons never move while stepping. */
.step-row { display: flex; align-items: center; gap: 4px; height: 52px; margin-top: 8px; }
.stepper { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 4px; }
.step-btn { flex: 1 1 0; min-width: 34px; max-width: 64px; padding: 0; font-size: 1.1rem; }
.step-readout {
  flex: 0 0 auto;
  width: calc(12ch + 8px);
  padding: 0 4px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 14px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
}
.step-row > .btn:not(.step-btn) { flex: 0 0 auto; padding: 0 10px; }
@media (max-width: 719.98px) {
  .step-readout { font-size: 13px; }
}

/* Review: the game screen's layout, with the step controls under the board (Flip beside Back on a phone). */
.review-top { display: flex; align-items: center; gap: 14px; }
.review-top #btn-flip { margin-left: auto; }
.review-result { margin: 0; font-size: 1.15rem; font-weight: 700; min-height: 1.4em; }
.your-time { margin: 0; height: 1.4em; line-height: 1.4; white-space: nowrap; overflow: hidden; color: var(--muted); }
/* The analysis line and the coach box keep fixed heights, so nothing under them moves as the numbers arrive. */
.review-analysis { margin: 0; height: 2.8em; line-height: 1.4; overflow: hidden; }
/* Four lines each: the panel can be under 300px wide beside the board as well as under it, and a lead plus a
   120-character sentence runs to four lines there. */
.review-coach { margin: 0; height: 5.4em; line-height: 1.35; overflow: hidden; font-size: .85rem; }
/* The list slot (--slot-h) is taller than the old 160px list: closer parts and a smaller coach box keep the panel
   within a 800px-tall window beside the board (gaps 6, padding 12 and the two coach boxes save 32 + 12 + 26 px). */
.review .panel { gap: 6px; padding-top: 12px; padding-bottom: 12px; }
/* The evaluation graph under the step row (js/screens/evalgraph.js): the board's width, a fixed 96px high.
   Horizontal drags pick positions; vertical ones still scroll the page on a phone. */
.eval-graph-box { margin-top: 8px; height: 96px; }
.eval-graph { display: block; width: 100%; height: 96px; cursor: pointer; touch-action: pan-y; }
.eval-graph:focus { outline: none; }
/* While the Ideas panel is open, the move list and the graph take no presses (the step row likewise). */
.review .moves.disabled, .eval-graph-box.disabled { pointer-events: none; opacity: .5; }
@media (min-width: 720px) {
  /* Wide: room above the board (the bar and the page padding), and under it the step row (60px), the graph (104px)
     and the page padding, so the Review fits the window without scrolling. */
  .review .board-col .board { --bw: min(100cqi - 4px, 560px, 100vh - 240px - var(--bar)); }
}
/* Quality labels in the Review's move list, in the badges' colours, and the mark of an assisted move. */
.move-tag { margin-left: .4em; font-size: .7em; font-weight: 600; white-space: nowrap; }
.move-tag.label-book { color: #b8946a; }
.move-tag.label-best { color: #1baaa0; }
.move-tag.label-excellent { color: #4caf50; }
.move-tag.label-good { color: #8bc34a; }
.move-tag.label-inaccuracy { color: #f4c20d; }
.move-tag.label-mistake { color: #f08c00; }
.move-tag.label-blunder { color: #d93025; }
.move-san.current .move-tag { color: #111; }
.move-assisted { font-size: .65em; vertical-align: super; margin-left: .2em; color: var(--muted); }
.move-san.current .move-assisted { color: #111; }
/* Move-quality badge (inside its square) and arrow overlay (js/board.js). Neither takes pointer events. */
.board .move-badge { position: absolute; top: 2%; right: 2%; width: 34%; height: 34%; z-index: 2; pointer-events: none; -webkit-user-drag: none; }
.board .arrows { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 3; }
.board .arrow { stroke-width: 0.18; stroke-linejoin: round; }
.board .arrow line { stroke-linecap: butt; }
.board .arrow polygon { stroke: none; }
.board .arrow { opacity: .85; }
.board .arrow.player { stroke: #3987e5; fill: #3987e5; }
.board .arrow.bot { stroke: #e5533a; fill: #e5533a; }

/* Blunder prompt (practice, opt-in): the held move's piece faded on its square, then "Are you sure?" over the page. */
.board.previewing .sq.last .piece { opacity: .6; }
.blunder-prompt {
  position: fixed; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  padding: 16px; background: rgba(0, 0, 0, .35);
}
.prompt-card { width: min(360px, 100%); display: flex; flex-direction: column; gap: 12px; border: 1px solid var(--line);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .5); }
.prompt-card h2 { margin: 0; font-size: 1.3rem; }
.prompt-card p { margin: 0; color: var(--muted); }
.prompt-card .buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.prompt-card .btn { flex: 1 1 auto; }
