:root {
  color-scheme: light dark;
  --bg: #f3f0ea;
  --panel: #ffffff;
  --panel-2: #f7f4ee;
  --text: #25221e;
  --muted: #7b756b;
  --line: #ddd7cc;
  --accent: #35679b;
  --accent-text: #ffffff;
  --good: #2c9a4c;
  --bad: #b13a30;
  --sq-light: #f0d9b5;
  --sq-dark: #b58863;
  --shadow: 0 10px 40px rgba(0, 0, 0, 0.22);
  --thumb: rgba(70, 60, 48, 0.28);
  --thumb-hover: rgba(70, 60, 48, 0.55);
  --hp-ok: #2f9e5f;
  --hp-warn: #d9a514;
  --hp-low: #d6453b;
  --g1: #2f9e5f;
  --g2: #e2b021;
  --g3: #d6453b;
  --list-w: 330px;
  /* The board's side (set by app.js on every resize, so that the board and what goes with it fit the window) and the window's height. */
  --bs: 560px;
  --app-h: 100vh;
  --credits-h: 72px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1c1b19;
    --panel: #262421;
    --panel-2: #2d2a27;
    --text: #e8e4dc;
    --muted: #9b958a;
    --line: #3b3834;
    --accent: #6aa2da;
    --accent-text: #0f1923;
    --good: #4fc673;
    --bad: #ec6e63;
    --sq-light: #dcc9a2;
    --sq-dark: #9a7351;
    --shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
    --thumb: rgba(232, 228, 220, 0.24);
    --thumb-hover: rgba(232, 228, 220, 0.5);
    --hp-ok: #4fc673;
    --hp-warn: #f0c243;
    --hp-low: #ec6e63;
    --g1: #4fc673;
    --g2: #f0c243;
    --g3: #ec6e63;
  }
}

* { box-sizing: border-box; }
/* Floating scroll bars: a thin rounded thumb, no visible track or gutter, stronger on hover. */
* { scrollbar-width: thin; scrollbar-color: var(--thumb) transparent; }
*:hover { scrollbar-color: var(--thumb-hover) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; background: transparent; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-track-piece, ::-webkit-scrollbar-corner { background: transparent; border: 0; box-shadow: none; }
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
::-webkit-scrollbar-thumb { background: var(--thumb); border-radius: 99px; border: 3px solid transparent; background-clip: padding-box; }
:hover::-webkit-scrollbar-thumb { background: var(--thumb-hover); background-clip: padding-box; }
/* the company's hand-lettered face, for the goal (WHITE TO WIN): kept invisible while it loads rather than shown in another face first */
@font-face { font-family: "Rin Casual"; src: url("fonts/rin-casual.otf") format("opentype"); font-display: block; }
html, body { margin: 0; height: 100%; overflow: hidden; }
body {
  background: var(--bg);
  color: var(--text);
  font: 15px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}
.defs { position: absolute; }
[hidden] { display: none !important; }
a { color: var(--accent); }
button { font: inherit; color: inherit; }

.btn {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 7px 14px;
  cursor: pointer;
  min-height: 36px;
}
.btn:hover:not(:disabled) { border-color: var(--accent); }
.btn:disabled { opacity: 0.4; cursor: default; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); font-weight: 600; }
.btn.small { padding: 4px 10px; min-height: 30px; font-size: 13px; }
.btn.nav { min-width: 46px; font-weight: 700; letter-spacing: 0.02em; }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The page never scrolls: the app is exactly the window, the drill list and the moves panel scroll inside it. */
.app {
  display: grid;
  grid-template-columns: var(--list-w) minmax(0, 1fr);
  grid-template-rows: var(--nav-h) minmax(0, 1fr);
  height: var(--app-h);
  overflow: hidden;
}
.topbar { display: none; }

/* ---- the Rin nav (rin-nav.js, placed by nav.js). Only the menu button shows, never the Rin logo (it is inside the open menu). One switch,
   the phone layout's: above 860 px the button sits in the top-left corner, over the drills column (which starts under it; the stage keeps
   the whole height); at 860 px and under it is the first thing in the top bar, before Drills. */
:root {
  --nav-h: 60px;
  --rin-nav-bg: var(--panel);
  --rin-nav-ink: var(--text);
  --rin-nav-muted: var(--muted);
  --rin-nav-accent: var(--accent);
  --rin-nav-line: var(--line);
}
.nav-head { grid-column: 1; grid-row: 1; display: flex; align-items: center; padding: 0 16px; background: var(--panel); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.list-panel { grid-column: 1; grid-row: 2; }
.stage { grid-column: 2; grid-row: 1 / 3; }
.nav-head .nav-slot, .topbar .nav-slot { flex: none; width: 44px; height: 44px; }   /* the button's room in the top bar, kept while the kit is still on its way (it loads from rin.games), so the bar does not move when the button arrives */
.topbar .rin-nav-button { flex: none; }

/* ---- list */
.list-panel {
  background: var(--panel);
  border-right: 1px solid var(--line);
  overflow-y: auto;
  min-height: 0;
  height: 100%;
}
.list-top { position: sticky; top: 0; z-index: 2; background: var(--panel); }
.list-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 12px 10px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.list-title { flex: 1; white-space: nowrap; }
.list-head .btn.small { padding: 4px 8px; }
.close-list { display: none; }
/* The account control (account.js): drawn only when the account service answers. In the list's head on a desktop; at 860 px and under the
   list is a drawer and the control sits in the top bar instead (a landscape phone) or the bottom bar (a portrait phone). It lives inside
   the bars' own rows, so it never changes the size of the board. */
.acct { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.acct a.btn, .modal a.btn { display: inline-flex; align-items: center; color: var(--text); text-decoration: none; }
.acct-name { max-width: 9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; color: var(--muted); }
button.acct-name { color: var(--text); }
.modal a.btn.primary { color: var(--accent-text); }
/* The crossed-out cloud (account.js): shown only while no account is signed in. A desktop: in the nav head, right beside the menu button (which keeps the
   head's left end). A portrait phone: top right, left of the credits button (the phone layout below). A landscape phone: the right end of the top bar. */
.btn.icon-cloud { display: inline-grid; place-items: center; width: 36px; height: 36px; min-height: 0; padding: 0; border-radius: 50%; color: var(--muted); }
.btn.icon-cloud svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.nav-head .acct { margin-left: 6px; }
.topbar .acct { order: 9; }
.topbar .btn.icon-cloud { min-height: 0; width: 44px; height: 44px; }
.list-head .acct { order: 9; flex: 1 0 100%; }
.topbar #open-list { flex: none; white-space: nowrap; }
.topbar .acct { flex: 0 1 auto; min-width: 0; }
.topbar .acct .btn { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 860px) { .list-head .acct { display: none; } }
.save-note { padding: 8px 14px; color: var(--bad); font-size: 13px; }
#list ul { list-style: none; margin: 0; padding: 8px 6px 4px; }
.item { display: flex; align-items: stretch; border-radius: 8px; }
.item.current { background: var(--panel-2); box-shadow: inset 3px 0 0 var(--accent); }
.item-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  background: none;
  border: 0;
  padding: 8px 8px;
  cursor: pointer;
  border-radius: 8px;
}
.item-main:hover { background: var(--panel-2); }
.item .nm { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.item .name { line-height: 1.3; }
/* difficulty: the bar's length is the score out of 100; the colour runs green to red along the whole 100 */
.group-head { list-style: none; }
.group-head h3 { margin: 12px 8px 2px; font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.group-head:first-child h3 { margin-top: 4px; }
.dbar { display: block; height: 4px; border-radius: 99px; background: var(--line); overflow: hidden; }
.dbar i { display: block; height: 100%; border-radius: 99px; background-image: linear-gradient(90deg, var(--g1), var(--g2), var(--g3)); background-repeat: no-repeat; }
.item.done .name { color: var(--muted); }
.goal {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 99px;
  padding: 1px 8px;
}
.tick { flex: none; width: 22px; height: 22px; }
.tick svg { display: block; width: 22px; height: 22px; }
.tick .ring { fill: none; stroke: var(--line); stroke-width: 2; }
.tick .disc { fill: var(--good); }
.tick .mark { fill: none; stroke: #fff; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.tick.grey .disc { fill: #8d9298; }
/* the trophy: the double tick of Vibe Chess's best-move stamp (white, outlined in the gem's dark ink) on a deep blue gem with an icy rim and a sparkle; it reads on both themes */
.tick .dm-disc { fill: url(#dm-fill); }
.tick .dm-ring { fill: none; stroke: url(#dm-edge); stroke-width: 1.4; }
.tick .dm-spark { fill: #fff; transform-origin: 17.6px 5.6px; animation: dm-twinkle 3.2s ease-in-out infinite; }
.tick.diamond svg { overflow: visible; filter: drop-shadow(0 0 2px rgba(120, 214, 255, 0.55)); }
@keyframes dm-twinkle { 0%, 70%, 100% { opacity: 0.35; transform: scale(0.7) rotate(0deg); } 82% { opacity: 1; transform: scale(1.15) rotate(20deg); } }
@media (prefers-reduced-motion: reduce) { .tick .dm-spark { animation: none; opacity: 0.9; } }
.defs { position: absolute; width: 0; height: 0; }
.best { display: flex; align-items: center; gap: 8px; margin: 2px 0 3px; font-size: 13px; color: var(--muted); }
.best .tick { width: 18px; height: 18px; }
.best .tick svg { width: 18px; height: 18px; }
.best[hidden] { display: none; }
.item .clear { align-self: center; margin-right: 4px; }
.item .clear:disabled { cursor: default; }

/* ---- stage
   Side by side (.side-by-side): the board at the left with its buttons row under it, the information column at the right. Stacked
   (.stacked): the board across the top, its buttons row, then the .side block under it, in two columns (the name and goal with the
   moves at the left, the bars with the training line at the right) or, on a phone or a narrow board (.one-col), in one. app.js picks
   the layout and the board's size (--bs) on every resize. */
.stage {
  display: grid;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  justify-content: center;
  align-content: start;
  padding: 14px 20px;
}
.stage > * { min-width: 0; }
.board-host { position: relative; width: var(--bs); height: var(--bs); }
.controls { display: flex; align-items: center; gap: 8px; margin-top: 8px; width: var(--bs); }
.controls .restart { min-width: 88px; }
.side { min-width: 0; min-height: 0; }
.info h1 { margin: 0; font-size: 19px; line-height: 1.2; font-weight: 650; overflow-wrap: anywhere; }
.info p { margin: 2px 0 3px; font-weight: 650; color: var(--accent); }
.bars { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.side-by-side .stage {
  grid-template-columns: var(--bs) minmax(340px, 400px);
  grid-template-rows: auto minmax(0, 1fr);
  column-gap: 28px;
}
.side-by-side .board-host { grid-column: 1; grid-row: 1; }
.side-by-side .controls { grid-column: 1; grid-row: 2; align-self: start; }
.side-by-side .side {
  grid-column: 2;
  grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: calc(var(--credits-h) + 12px);
}
.side-by-side .moves { flex: 1 1 0; }

.stacked .stage {
  grid-template-columns: var(--cw, var(--bs));
  grid-template-rows: auto auto minmax(0, 1fr);
  padding-bottom: calc(var(--credits-h) + 14px);
}
.stacked .side {
  grid-row: 3;
  margin-top: 10px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(250px, 46%);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "info bars" "moves bars";
  column-gap: 22px;
  row-gap: 10px;
}
.stacked .controls { width: var(--cw, var(--bs)); }
.stacked .info { grid-area: info; }
.stacked .bars { grid-area: bars; }
.stacked .moves { grid-area: moves; }
.stacked.one-col .side {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.stacked.one-col .moves { flex: 1 1 0; }

.board { display: block; width: 100%; height: 100%; touch-action: none; user-select: none; -webkit-user-select: none; border-radius: 4px; box-shadow: 0 2px 14px rgba(0, 0, 0, 0.18); }
.sq-light { fill: var(--sq-light); }
.sq-dark { fill: var(--sq-dark); }
.coord { font: 600 21px system-ui, sans-serif; opacity: 0.9; }
.coord.on-light { fill: var(--sq-dark); }
.coord.on-dark { fill: var(--sq-light); }
.hi-last { fill: rgba(155, 199, 0, 0.42); }
.hi-sel { fill: rgba(20, 110, 40, 0.5); }
/* the squares of a queued premove: translucent red */
.hi-pre { fill: rgba(214, 40, 40, 0.5); }
.dot-move { fill: rgba(20, 85, 30, 0.5); }
.dot-capture { fill: none; stroke: rgba(20, 85, 30, 0.5); stroke-width: 10; }
/* a Hint made the selection: blue instead of green */
.hi-sel.hint { fill: rgba(20, 84, 200, 0.5); }
.dot-move.hint { fill: rgba(20, 84, 200, 0.55); }
.dot-capture.hint { fill: none; stroke: rgba(20, 84, 200, 0.55); }
@media (prefers-color-scheme: dark) {
  .hi-pre { fill: rgba(235, 60, 52, 0.55); }
  .hi-sel.hint { fill: rgba(70, 140, 255, 0.55); }
  .dot-move.hint { fill: rgba(70, 140, 255, 0.6); }
  .dot-capture.hint { stroke: rgba(70, 140, 255, 0.6); }
}
.promo-dim { fill: rgba(0, 0, 0, 0.55); }
.promo-cell { fill: #f4eee2; stroke: #b9ae98; stroke-width: 2; cursor: pointer; }
.promo-cell:hover { fill: #ffe9b0; }

/* the goal said big over the middle of the board when a drill starts: white letters outlined dark, so they read on both square colours in both themes */
.goal-flash {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 3;
  font-family: "Rin Casual", system-ui, sans-serif;
  font-weight: 400;
  font-synthesis: none;
  font-size: calc(var(--bs) * 0.2);
  line-height: 1.05;
  letter-spacing: 0.03em;
  text-align: center;
  white-space: pre;
  color: #fff;
  -webkit-text-stroke: calc(var(--bs) * 0.012) rgba(18, 14, 8, 0.92);
  paint-order: stroke fill;
  text-shadow: 0 3px 16px rgba(0, 0, 0, 0.6);
  opacity: 0;
  user-select: none;
  -webkit-user-select: none;
}
.goal-flash.on { animation: goal-flash 1.5s ease-out both; }
@keyframes goal-flash {
  0% { opacity: 0; transform: scale(0.92); }
  12% { opacity: 1; transform: scale(1); }
  68% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.03); }
}
@media (prefers-reduced-motion: reduce) {
  .goal-flash.on { animation: goal-flash-still 1.5s linear both; }
  @keyframes goal-flash-still { 0% { opacity: 0; } 12%, 68% { opacity: 1; } 100% { opacity: 0; } }
}

.switch { position: relative; display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-size: 13px; user-select: none; -webkit-user-select: none; white-space: nowrap; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.switch .track { flex: none; position: relative; width: 30px; height: 17px; border-radius: 99px; background: var(--line); transition: background 0.15s; }
.switch .track::after { content: ''; position: absolute; top: 2px; left: 2px; width: 13px; height: 13px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); transition: transform 0.15s; }
.switch input:checked + .track { background: var(--accent); }
.switch input:checked + .track::after { transform: translateX(13px); }
.switch input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch.top { display: none; }

/* The three bars (Difficulty, Efficiency, Fifty-move rule) share one grid of columns: a label, the track and its value, so every track has
   the same left and right edges whatever the value beside it says. */
.meter { display: grid; grid-template-columns: 8em minmax(0, 1fr) 5.6em; align-items: center; column-gap: 8px; font-size: 13px; transition: opacity 0.2s; }
.meter.dim { opacity: 0.45; }
.m-label { color: var(--muted); white-space: nowrap; }
.m-bar { min-width: 0; height: 8px; border-radius: 99px; background: var(--line); overflow: hidden; }
.m-bar i { display: block; height: 100%; width: 100%; border-radius: 99px; background: var(--accent); transition: width 0.3s; }
.m-pct { text-align: left; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.meter .dbar { height: 8px; }
.meter .dbar i { background-color: transparent; background-image: linear-gradient(90deg, var(--g1), var(--g2), var(--g3)); background-repeat: no-repeat; transition: none; }
.meter.fifty .m-bar i { transition: width 0.3s, background-color 0.3s; }
.meter.fifty[data-level='ok'] .m-bar i { background: var(--hp-ok); }
.meter.fifty[data-level='warn'] .m-bar i { background: var(--hp-warn); }
.meter.fifty[data-level='low'] .m-bar i { background: var(--hp-low); }
/* a draw drill: the colour moves steadily from red through yellow to green as the bar fills (--p, 0 to 1, set by app.js) */
.meter.fifty[data-level='draw'] .m-bar i {
  background: color-mix(in srgb, var(--hp-ok) clamp(0%, calc((var(--p, 0) - 0.5) * 200%), 100%), color-mix(in srgb, var(--hp-warn) clamp(0%, calc(var(--p, 0) * 200%), 100%), var(--hp-low)));
}
.meter.fifty .m-bar { height: 10px; box-shadow: inset 0 0 0 1px rgba(127, 127, 127, 0.3); }
.holding { font-size: 13px; font-weight: 600; color: var(--good); }
.holding.lost { color: var(--bad); }
.coach { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; }
.coach #hint { order: -1; }
.msg { color: var(--bad); font-weight: 600; font-size: 13px; }
.notbest { display: flex; align-items: center; gap: 10px; min-height: 30px; color: var(--bad); font-weight: 600; visibility: hidden; }
.notbest.on { visibility: visible; }
.notbest .btn { color: var(--text); }

/* The moves panel: a box that takes the room that is left and scrolls inside itself. The marked slot (.next) is where the next move
   goes: an empty cell drawn before the move is played (it pulses softly while Stockfish thinks), or, when stepping back through
   the moves, the move that came next from the position shown. */
.moves {
  margin: 0;
  padding: 4px 6px;
  min-height: 64px;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: grid;
  grid-template-columns: 38px 1fr 1fr;
  align-content: start;
  gap: 2px 4px;
  font-variant-numeric: tabular-nums;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.moves .no { color: var(--muted); padding: 3px 4px; text-align: right; line-height: 1.4; }
.moves button {
  background: none;
  border: 0;
  text-align: left;
  padding: 3px 8px;
  border-radius: 6px;
  cursor: pointer;
  line-height: 1.4;
}
.moves button:hover { background: var(--panel-2); }
.moves .blank { visibility: hidden; }
.moves .next, .moves button.next {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  box-shadow: inset 0 0 0 2px var(--accent);
  border-radius: 6px;
  color: var(--text);
}
.moves .slot { display: block; min-height: calc(1.4em + 6px); }
.moves .slot.thinking { animation: slot-think 1.4s ease-in-out infinite; }
@keyframes slot-think { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) { .moves .slot.thinking { animation: none; } }

/* Pinned to the window's bottom-right corner: every line ends at the same right edge and none is wider than the window. */
.credits {
  position: fixed;
  right: 0;
  bottom: 0;
  z-index: 5;
  box-sizing: border-box;
  max-width: min(440px, 100vw);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  gap: 2px;
  padding: 8px 14px 8px 16px;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  border-top-left-radius: 8px;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.35;
}
.credits span { display: block; max-width: 100%; overflow-wrap: anywhere; text-align: right; }

/* The credits button, its dimming layer, the panel's heading and the last-move label are for the portrait phone layout only (below). */
.icon-btn, .credits-head, .lastmove { display: none; }

/* ---- confetti, dialogs, toast */
.confetti { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 60; }
.modal-back {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.modal {
  background: var(--panel);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 22px 24px;
  width: min(460px, 100%);
}
.modal h2 { margin: 0 0 6px; font-size: 20px; }
.modal p { margin: 0 0 16px; color: var(--muted); }
.modal p.note { margin: -8px 0 16px; }
.modal p.why { margin: -10px 0 16px; color: var(--text); }
.modal p.note strong { color: var(--text); font-weight: 600; }
.modal .row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
.modal .row.center { justify-content: center; margin-top: 12px; }
.modal .phone-break { display: none; }
@media (max-width: 860px) { .modal .phone-break { display: block; height: 1.4em; height: 1lh; } }
.modal .win-top { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 0; margin-bottom: 10px; }
.modal .win-actions { flex: 1 1 auto; display: flex; flex-wrap: nowrap; justify-content: center; gap: 8px; padding: 0 12px; }
.modal .win-actions .btn { white-space: nowrap; }
/* Four buttons (the thrown-away popup): they share the row with the badge, so they pack tighter; on a narrow screen they wrap. */
.modal .win-actions.tight { flex-wrap: wrap; gap: 6px; padding: 0 10px; }
.modal .win-actions.tight .btn { padding-left: 10px; padding-right: 10px; }
/* On a phone the four buttons go under the tick as two rows of two, each as wide as its half. */
@media (max-width: 470px) {
  .modal .win-actions.tight { flex: 1 1 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0; }
}
.modal .win-badge {
  flex: none; width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.modal .win-badge.fail { background: var(--bad); }
/* a success shows the mark the drill gets in the list for this game, at the popup's size */
.modal .win-badge.mark { border-radius: 0; }
.modal .win-badge .tick, .modal .win-badge .tick svg { width: 44px; height: 44px; }
.modal h2 .tm { font-size: 14px; font-weight: 500; color: var(--muted); white-space: nowrap; }
.modal p.ask { margin: 0 0 16px; color: var(--text); }
.modal .win-badge.fail svg { width: 26px; height: 26px; fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }

#toast-root { position: fixed; left: 16px; bottom: 16px; z-index: 70; }
.toast {
  background: #2b2926;
  color: #f3efe8;
  border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 12px 14px 14px;
  min-width: 260px;
  max-width: min(380px, calc(100vw - 32px));
  position: relative;
  overflow: hidden;
}
.toast .row { display: flex; align-items: center; gap: 14px; justify-content: space-between; }
.toast button { background: transparent; border: 1px solid #77716a; color: #fff; border-radius: 6px; padding: 4px 12px; cursor: pointer; font-weight: 600; }
.toast .bar { position: absolute; left: 0; bottom: 0; height: 4px; width: 100%; background: #6aa2da; transform-origin: left; animation: drain 10s linear forwards; }
@keyframes drain { to { transform: scaleX(0); } }

.scrim { display: none; }

/* ---- phone */
@media (max-width: 860px) {
  .app { display: flex; flex-direction: column; }
  :root { --nav-h: 0px; }
  .nav-head { display: none; }
  .topbar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 8px;
    height: 52px;
    flex: none;
    background: var(--bg);
  }
  .stage { flex: 1 1 0; padding-left: 8px; padding-right: 8px; padding-top: 0; }
  .topbar-name { display: none; }
  .switch.top { display: inline-flex; margin-left: auto; padding-right: 6px; }
  .chip { color: var(--muted); margin-left: 4px; }
  .list-panel {
    position: fixed;
    inset: 0 auto 0 0;
    width: min(92vw, 380px);
    height: 100%;
    z-index: 40;
    transform: translateX(-102%);
    transition: transform 0.2s ease;
    box-shadow: var(--shadow);
  }
  .list-panel.open { transform: none; }
  .close-list { display: inline-block; }
  .scrim.open { display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 30; }
  .controls { gap: 6px; margin-top: 8px; }
  .controls .nav { min-width: 38px; padding-left: 8px; padding-right: 8px; }
  .controls .restart { min-width: 0; padding-left: 10px; padding-right: 10px; }
  .info h1 { font-size: 17px; }
  #toast-root { left: 8px; right: 8px; bottom: 8px; }
  .toast { max-width: none; }
}
/* ---- portrait phone (Rin, 15 Oct 2026). From the top: the drill's name and goal and the three bars (text only), the board across the
   whole width, Restart and Next drill, the arrows with the latest move written between < and >, then the Drills button and the
   Training switch. There is no moves list (its stepping lives in the arrows) and the credits are a panel the corner button opens.
   A landscape phone keeps the layouts above. app.js sets --bs (the board's side) and --cw (the width of everything under and over it). */
@media (max-width: 860px) and (orientation: portrait) {
  .app { position: relative; }
  .topbar { order: 2; height: auto; gap: 8px; padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); }
  .topbar .btn { min-height: 44px; }
  .switch.top { padding-right: 4px; font-size: 14px; }
  .switch.top .track { width: 36px; height: 20px; }
  .switch.top .track::after { width: 16px; height: 16px; }
  .switch.top input:checked + .track::after { transform: translateX(16px); }
  .stage { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 8px 8px 0; }
  .stage > *, .info, .meter, .holding, .msg { flex: none; } /* .side and .bars are display: contents, so their children are the stage's own items and would otherwise shrink over each other */
  .side, .bars { display: contents; }
  .moves { display: none; }
  .info, .meter, .holding, .msg, .coach, .controls { width: var(--cw); }
  .info { order: 1; padding-right: 88px; min-height: 40px; } /* room for the credits button and, left of it, the cloud (account.js), kept whether or not the cloud shows so the board does not move when the account answers */
  .info h1 { font-size: 17px; line-height: 1.2; }
  .info p { margin: 1px 0 2px; }
  .best { margin: 0 0 2px; }
  .meter { order: 2; grid-template-columns: 6.9em minmax(0, 1fr) 4.6em; font-size: 12.5px; margin-bottom: 3px; }
  .meter .m-bar, .meter .dbar { height: 7px; }
  .meter.fifty .m-bar { height: 8px; }
  .holding, .msg { order: 2; font-size: 12.5px; }
  .board-host { order: 3; margin-top: 6px; }
  .coach { order: 4; flex-wrap: nowrap; justify-content: space-between; margin-top: 4px; }
  .coach #hint { order: 1; min-height: 40px; padding-left: 16px; padding-right: 16px; }
  .coach .notbest { flex: 1; min-width: 0; }
  .controls {
    order: 5;
    display: grid;
    grid-template-columns: 46px 46px minmax(0, 1fr) minmax(0, 1fr) 46px 46px;
    gap: 8px 6px;
    /* what the window leaves over goes above the buttons, so they sit low, where a thumb is */
    margin-top: auto;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  .controls .btn { min-height: 48px; min-width: 0; padding: 0 6px; }
  .controls .restart { grid-row: 1; font-weight: 600; }
  #b-again { grid-column: 1 / 4; }
  #b-nextdrill { grid-column: 4 / 7; }
  #b-first { grid-row: 2; grid-column: 1; }
  #b-prev { grid-row: 2; grid-column: 2; }
  .lastmove {
    display: block; grid-row: 2; grid-column: 3 / 5;
    align-self: center; text-align: center; min-width: 0;
    font-size: 17px; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #b-next { grid-row: 2; grid-column: 5; }
  #b-last { grid-row: 2; grid-column: 6; }

  .icon-btn { position: absolute; top: 8px; right: 8px; z-index: 6; display: grid; place-items: center; width: 36px; height: 36px; min-height: 0; padding: 0; border-radius: 50%; color: var(--muted); }
  .icon-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
  .icon-btn svg .dot { fill: currentColor; stroke: none; }
  .icon-btn[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
  .topbar .acct.acct-cloud { position: absolute; top: 8px; right: 52px; z-index: 6; }
  .topbar .btn.icon-cloud { width: 36px; height: 36px; }
  .credits { display: none; }
  .credits.open {
    display: flex; position: fixed; z-index: 45; top: 52px; bottom: auto; left: 8px; right: 8px; max-width: none; align-items: flex-start; text-align: left; gap: 8px;
    padding: 12px 14px 14px; background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); font-size: 13px; line-height: 1.45;
  }
  .credits.open span { text-align: left; }
  .credits-head { display: flex; align-items: center; justify-content: space-between; align-self: stretch; }
}
@media (max-width: 380px) {
  .topbar .chip { display: none; } /* the menu button took its room: the account control (account.js) keeps its width */
  .controls { gap: 4px; }
  .controls .nav { min-width: 34px; padding-left: 6px; padding-right: 6px; }
  .controls .restart { padding-left: 8px; padding-right: 8px; }
}
@media (min-width: 861px) and (max-width: 1180px) {
  :root { --list-w: 320px; }
}

/* ---- the list's piece filter: under "Drills", the counts (Complete, Perfect) at the left and the pieces at the right, your side's (white)
   over Stockfish's (black), then the mode switch */
.pf { padding: 10px 12px 8px; border-bottom: 1px solid var(--line); display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "stats rows" "mode mode"; column-gap: 8px; row-gap: 8px; align-items: center; }
.lf-stats { grid-area: stats; font-size: 12.5px; line-height: 1.5; color: var(--muted); white-space: nowrap; }
.lf-stats div { overflow: hidden; text-overflow: clip; }
.pf-rows { grid-area: rows; display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }
.pf-mode { grid-area: mode; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; }
.pf-mode .opt { display: inline-flex; align-items: center; gap: 7px; background: none; border: 0; border-radius: 6px; padding: 4px 6px; font: inherit; color: var(--muted); cursor: pointer; white-space: nowrap; transition: color 0.15s, background 0.15s; }
.pf-mode .opt .lamp { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--line); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18); transition: background 0.15s, box-shadow 0.15s; }
.pf-mode .opt.on { color: var(--text); cursor: default; }
.pf-mode .opt.on .lamp { background: var(--accent); box-shadow: 0 0 6px 1px var(--accent); }
.pf-mode .opt:hover:not(.on) { color: var(--text); background: var(--panel-2); }
.pf-mode .opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pf-row { display: flex; justify-content: flex-end; gap: 3px; }
.pf-piece {
  flex: none; width: 32px; height: 32px; padding: 0; border-radius: 7px; cursor: pointer;
  background: var(--sq-light); border: 2px solid var(--accent); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}
.pf-piece svg { display: block; width: 100%; height: 100%; }
.pf-piece:not(.lit) { background: var(--panel-2); border-color: var(--line); box-shadow: none; }
.pf-piece:not(.lit) svg { opacity: 0.28; filter: grayscale(1); }
.pf-piece:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- Rin's markup tools (markup.js): only in the page of a signed-in Vibe Chess developer; nothing here shows for anyone else */
.item .mk { flex: none; align-self: center; width: 30px; height: 30px; padding: 0; margin-right: 4px; display: grid; place-items: center; background: none; border: 1px solid transparent; border-radius: 8px; color: var(--muted); cursor: pointer; }
.item .mk svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.item .mk:hover { border-color: var(--line); color: var(--text); }
.item.marked .mk { color: var(--bad); }
.item.marked .mk svg { fill: color-mix(in srgb, var(--bad) 22%, transparent); }
.item.marked .name { text-decoration: line-through; text-decoration-thickness: 2px; text-decoration-color: var(--bad); color: var(--muted); }
.mk-modal textarea { display: block; width: 100%; margin: 0 0 14px; padding: 9px 10px; font: inherit; color: var(--text); background: var(--bg); border: 1px solid var(--line); border-radius: 8px; resize: vertical; min-height: 78px; }
.mk-modal textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.mk-modal .mk-unmark { margin-right: auto; color: var(--bad); }
.mk-err { margin: -6px 0 12px; font-size: 13px; color: var(--bad); }
.mk-handle { display: block; width: 100%; height: 20px; padding: 0; background: var(--panel); border: 0; border-bottom: 1px solid var(--line); cursor: pointer; }
.mk-handle:hover .mk-grip, .mk-handle[aria-expanded="true"] .mk-grip { background: var(--accent); }
.mk-grip { display: block; width: 38px; height: 4px; margin: 0 auto; border-radius: 99px; background: var(--line); transition: background 0.15s; }
.mk-panel {
  position: absolute; left: 0; right: 0; top: 20px; z-index: 3;
  display: flex; flex-direction: column;
  height: min(560px, calc(var(--app-h) - 52px - var(--nav-h)));
  background: var(--panel); border-bottom: 1px solid var(--line); box-shadow: var(--shadow);
  visibility: hidden; opacity: 0; transform: translateY(-10px); pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}
.mk-panel.open { visibility: visible; opacity: 1; transform: none; pointer-events: auto; transition-delay: 0s; }
.mk-body { flex: 1; min-height: 0; overflow-y: auto; padding: 8px 12px 4px; }
.mk-foot { padding: 8px 12px 12px; border-top: 1px solid var(--line); }
.mk-save-err { margin: 0; padding: 6px 12px 0; }
.mk-sec { padding: 8px 0 10px; border-bottom: 1px solid var(--line); }
.mk-sec:last-child { border-bottom: 0; }
.mk-sec-head { display: flex; align-items: center; gap: 4px; }
.mk-title { flex: 1; min-width: 0; padding: 5px 6px; font: inherit; font-weight: 650; color: var(--text); background: none; border: 1px solid transparent; border-bottom-color: var(--line); border-radius: 6px 6px 0 0; }
.mk-title:focus { outline: none; border-color: var(--accent); }
.mk-del { flex: none; width: 28px; height: 28px; padding: 0; display: grid; place-items: center; background: none; border: 0; border-radius: 6px; color: var(--muted); cursor: pointer; }
.mk-del:hover { color: var(--bad); background: var(--panel-2); }
.mk-del svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.mk-list { list-style: none; margin: 4px 0 0; padding: 0; }
.mk-li { position: relative; padding-left: 20px; }
.mk-li::before { content: ""; position: absolute; left: 8px; top: 12px; width: 5px; height: 5px; border-radius: 50%; background: var(--muted); }
.mk-b { display: block; width: 100%; padding: 3px 4px; font: inherit; line-height: 1.4; color: var(--text); background: none; border: 1px solid transparent; border-radius: 4px; resize: none; overflow: hidden; }
.mk-b:focus { outline: none; background: var(--panel-2); border-color: var(--line); }
