/* The pages' structure. Colours, type and surfaces are the look's (looks.css, loaded first): use its tokens
   (--bg, --panel, --text, --accent, --win, --card-*, --ctl-*, --primary-* ...), so a new page looks right in every
   look. A colour of your own only for what a thing is in every look: White and Black, a flame. */
:root {
  --strip: 30px;  /* height of the name bar above and below a board */
  --side: 0px;  /* room beside the board in its row: the game page's eval bar and its gap */
  --aside: 21.25rem;  /* the least room the panel beside the board keeps */
  --cg: 0px;  /* the gutter down the board's left and along its foot, for coordinates outside it */
  --head: 54px;  /* the header's and the footer's heights as drawn (they differ by look and wrap on a narrow window): */
  --foot: 53px;  /* app.js measures them; these until it has */
}
:root.coords-out { --cg: 1.5rem; }
/* The board is as big as the screen allows, with no fixed cap, so it grows on a big monitor: as tall as the height
   leaves room for (the header, main's 16px gutters, the two name bars, any coordinates outside it and the footer, so
   the page ends at the window's foot), but never so wide that the panel beside it falls under --aside. On a phone,
   where the panel drops below, it is the whole width, and the footer comes after the panel anyway. */
:root, #game, #drill { --bs: min(calc(100vh - var(--head) - var(--foot) - 32px - 2 * var(--strip) - var(--cg)), calc(100vw - 32px - 24px - var(--aside) - var(--side) - var(--cg))); }
#game { --side: 24px; }
@media (max-width: 900px) {
  :root, #game, #drill { --bs: min(calc(100vw - 32px - var(--side) - var(--cg)), calc(100vh - var(--head) - 32px - 2 * var(--strip) - var(--cg))); }  /* main's gutters are 16px */
}
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;  /* the footer (footer.css) rests at the bottom of a short page */
  background: var(--bg-art), var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font: var(--text-weight) var(--text-size)/1.45 var(--font-body);
}
/* a look's photograph, if it has one (--bg-photo: Quiet Hours'), fixed behind everything. A layer of its own, since a
   phone scrolls a body's fixed background with the page (and would stretch a photo set to cover it over the page). */
body::before { content: ""; position: fixed; inset: 0; z-index: -2; pointer-events: none; background: var(--bg-photo, none); }
h1, h2, h3, .verdict, .ring-text b, .level-text b, .streak b { font-family: var(--font-display); }
header {
  position: relative;
  z-index: 40;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 24px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--header-line);
  background: var(--header-bg);
  box-shadow: var(--header-shadow);
  backdrop-filter: var(--header-blur);
}
h1 { margin: 0; font-size: 1.375rem; font-weight: var(--display-weight); }
h1 .mark, .brand .mark { vertical-align: -4px; margin-right: 8px; border-radius: 5px; }
/* the name and mark take you home (the drill): drawn as the heading is, in every look (Night Arcade's gradient too) */
.home-link { color: inherit; text-decoration: none; border-radius: 6px; }
.home-link .mark { transition: transform 0.2s ease-out; }
.home-link:hover .mark { transform: rotate(-8deg) scale(1.08); }
.home-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.still .home-link .mark { transition: none; }
.tools { margin-left: auto; display: flex; gap: 6px; align-items: center; }
h2 { margin: 0 0 4px; font-size: 1.3125rem; font-weight: var(--display-weight); }
nav a {
  margin-right: 4px;
  padding: 5px 13px;
  border-radius: var(--nav-radius);
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-weight: 600;
  text-decoration: none;
}
nav a:hover { color: var(--text); }
/* on a phone the pages' names scroll sideways rather than fall off the edge, which fades to say there's more */
@media (max-width: 640px) {
  #nav { display: flex; max-width: 100%; overflow-x: auto; scrollbar-width: none; padding-right: 18px;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent); }
  #nav::-webkit-scrollbar { display: none; }
  #nav a { flex: none; padding: 5px 11px; margin-right: 2px; }
}
nav a.active { color: var(--nav-active-fg); background: var(--nav-active-bg); box-shadow: var(--nav-active-shadow); border-bottom-color: var(--nav-active-line); }
/* main has no width cap, so the board pages can use a big screen; the text-and-table pages keep a readable width */
main { padding: 16px; width: 100%; margin: 0 auto; }
#games, #stats, #start { max-width: 75rem; margin: 0 auto; }
a { color: var(--accent); }
.muted { color: var(--muted); }
.small { font-size: 0.875rem; }
[hidden] { display: none !important; }

.filters { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-bottom: 12px; }
.filters label { display: flex; gap: 6px; align-items: center; color: var(--muted); }
select, input, button {
  font: inherit;
  font-weight: var(--ctl-weight);
  color: var(--text);
  background: var(--ctl-bg);
  border: 1px solid var(--ctl-line);
  border-bottom-width: var(--ctl-depth);
  border-radius: var(--ctl-radius);
  padding: 4px 9px;
}
select option { background: var(--card-solid); color: var(--text); }
button { cursor: pointer; transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s; }
button:hover { border-color: var(--accent); box-shadow: var(--ctl-hover); }
button:active { transform: translateY(1px); }
/* the main thing to do on a page: Next, Start, Run */
.primary, .button-link {
  background: var(--primary-bg);
  color: var(--primary-fg);
  border: 1px solid var(--primary-line);
  border-bottom-width: var(--primary-depth);
  box-shadow: var(--primary-shadow);
  font-weight: 800;
}
.primary:hover, .button-link:hover { border-color: var(--primary-line); box-shadow: var(--primary-shadow); filter: brightness(1.08); }
/* a button with nothing to do right now: faded, and it doesn't light up or press */
button:disabled { opacity: 0.42; cursor: not-allowed; }
button:disabled:hover { border-color: var(--ctl-line); box-shadow: none; }
button:disabled:active { transform: none; }
.primary:disabled:hover { border-color: var(--primary-line); box-shadow: var(--primary-shadow); filter: none; }

table { width: 100%; border-collapse: collapse; background: transparent; }
th, td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--line); white-space: nowrap; }
th { color: var(--muted); font-weight: 600; font-size: 0.8125rem; text-transform: uppercase; letter-spacing: 0.05em; }
tbody tr { cursor: pointer; }
tbody tr:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
td.opening { max-width: 16.25rem; overflow: hidden; text-overflow: ellipsis; }

/* the panel beside the board stops growing at a readable width; the pair sits in the middle of a very wide screen */
.layout { display: grid; grid-template-columns: max-content minmax(17.5rem, 51.25rem); justify-content: center; gap: 24px; align-items: start; }
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } }
.layout > * { min-width: 0; }  /* long engine lines and move lists wrap or scroll inside, not widen the page */
.boardwrap { display: flex; gap: 8px; align-items: flex-start; }
.boardcol { display: flex; flex-direction: column; flex: none; width: var(--bs); }  /* never squeezed by the panel's text */
.pstrip {
  height: var(--strip);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.9375rem;
  white-space: nowrap;
  overflow: hidden;
}
.pstrip .chip { width: 11px; height: 11px; padding: 0; box-sizing: border-box; border-radius: 50%; border: 1px solid var(--muted); flex: none; }  /* not Stats' filter .chip */
/* the side to move (Board.renderStrips): its name bar lights from the left, edged in the look's accent, and its
   colour's disc glows */
.pstrip { border-radius: 8px; padding: 0 6px; }
.pstrip.to-move { background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 32%, transparent), transparent 80%);
  box-shadow: inset 3px 0 0 var(--accent); }
.pstrip.to-move .chip { width: 13px; height: 13px; border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent), 0 0 calc(10px * var(--glow, 1)) var(--accent); }
.pstrip.to-move .pname { color: var(--text); }
/* whose turn it is, as a chip in that colour with its king (board.js turnChip): the drill's prompt, Openings */
.turn-chip { display: inline-flex; align-items: center; gap: 7px; padding: 2px 12px 2px 2px; margin: 0 4px 2px 0; border-radius: 999px;
  font-weight: 800; font-size: 0.9375rem; vertical-align: middle; white-space: nowrap; animation: turn-in 0.35s ease-out both; }
.turn-chip .tc-disc { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; flex: none; }
.turn-chip .tc-disc img { width: 24px; height: 24px; }
.turn-chip.w { background: #f5f2ea; color: #1c1a16; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2), 0 2px 10px rgba(0, 0, 0, 0.25); }
.turn-chip.w .tc-disc { background: #fff; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14); }
.turn-chip.b { background: #24221e; color: #f5f2ea; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22), 0 2px 10px rgba(0, 0, 0, 0.35); }
.turn-chip.b .tc-disc { background: #44403a; }
@keyframes turn-in { from { opacity: 0; transform: scale(0.85); } }
.still .turn-chip { animation: none; }
@media (prefers-reduced-motion: reduce) { .turn-chip { animation: none; } }
.pstrip .chip.w { background: #f2f2f2; }
.pstrip .chip.b { background: #3a3a3a; }
.pstrip .pname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.pstrip .prate { color: var(--muted); }
.pstrip .caps { display: flex; flex: none; align-items: center; margin-left: 6px; padding: 0 4px; border-radius: 4px; background: #b9b7ae; }
.pstrip .caps:empty { display: none; }
.pstrip .grp { display: flex; flex: none; margin-right: 6px; }
.pstrip .grp img { width: 22px; height: 22px; flex: none; margin-left: -10px; }
.pstrip .grp img:first-child { margin-left: 0; }
.pstrip .adv { color: var(--muted); font-size: 0.875rem; font-weight: 600; }
.pstrip .clock {
  margin-left: auto;
  flex: none;
  padding: 0 8px;
  border-radius: 4px;
  font: 600 0.9375rem/1.375rem ui-monospace, Consolas, monospace;
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--line);
}
.pstrip .clock.active { color: var(--bg); background: var(--text); border-color: var(--text); }  /* whose turn it is */
.pstrip .clock.low { color: var(--loss); }
.pstrip .clock.active.low { color: #fff; background: var(--loss); border-color: var(--loss); }
.evalbar {
  margin-top: var(--strip);
  width: 16px;
  height: var(--bs);
  background: color-mix(in srgb, var(--bg) 55%, #000);
  border-radius: 999px;
  box-shadow: 0 0 0 1px var(--card-line);
  display: flex;
  flex-direction: column-reverse;
  overflow: hidden;
}
.evalbar.flip { flex-direction: column; }
.evalbar .white { background: var(--sq-light); height: 50%; transition: height 0.15s; }

.board {
  position: relative;
  touch-action: none;
  width: var(--bs);
  height: var(--bs);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  user-select: none;
  border: var(--board-frame);
  border-radius: var(--board-radius);
  box-shadow: var(--board-shadow);
  background: var(--board-art), var(--board-frame-art);  /* a look's board drawn as art (looks.css) */
  overflow: hidden;
  isolation: isolate; /* the layers below (sliding piece, arrows, badge) stay inside the board */
}
.sq { position: relative; display: flex; align-items: center; justify-content: center; }
.sq.light { background: var(--sq-light-fill, var(--sq-light)); }
.sq.dark { background: var(--sq-dark-fill, var(--sq-dark)); }
/* an open hand over the pieces you may move, a pointer where the picked-up one can go, a closed hand while dragging */
.sq.can { cursor: grab; }
.sq.dot { cursor: pointer; }
body.dragging, body.dragging * { cursor: grabbing !important; }
.sq.last::before, .sq.sel::before, .sq.best::before, .sq.played::before, .sq.answer::before {
  content: ""; position: absolute; inset: var(--sq-mark-inset, 0); border-radius: var(--sq-mark-radius, 0);  /* a look's tile's shape */
}
.sq.last::before { background: var(--last); }
.sq.sel::before { background: var(--sel); }
.sq.answer::before { background: rgba(60, 120, 220, 0.5); }
/* a lesson's area, tinted (learn.py show's zone: the square a king must reach to catch a pawn) */
.sq.zone { box-shadow: inset 0 0 0 100vmax color-mix(in srgb, var(--arrow-answer) 26%, transparent); }
.sq.best::before { background: var(--good); }
.sq.played::before { background: var(--bad); }
/* coordinates inside the board, in the corner of the edge squares in the other square's colour: they grow with the board */
.sq .coord { position: absolute; font: 700 max(11px, calc(var(--bs) / 8 * 0.18))/1 var(--font-body); opacity: 0.9; pointer-events: none; }
.sq .coord.file { right: 5%; bottom: 4%; }
.sq .coord.rank { left: 5%; top: 5%; }
.sq.light .coord { color: var(--sq-dark); }
.sq.dark .coord { color: var(--sq-light); }
.piece {
  position: relative;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* a piece sliding to its square passes over the others; a taken piece waits underneath it */
.piece.moving { z-index: 2; }
.piece.fading { position: absolute; inset: 0; z-index: 1; }
/* the piece an arrow starts from stands over the arrows (.arrows, z-index 2), so the arrow comes out from under it
   and its head lies over the piece it reaches (Board.liftTails) */
.piece.over { z-index: 3; }

.controls { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; align-items: center; }
.note {
  min-height: 3.2em;
  padding: 8px 10px;
  border-left: 3px solid var(--line);
  background: var(--panel);
  margin-bottom: 10px;
}
.note:empty { display: none; }
.lesson { background: var(--panel); border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: 6px; padding: 10px 14px; margin-bottom: 10px; }
.lesson h3 { margin: 0 0 6px; font-size: 1rem; color: var(--muted); font-weight: 600; }
/* a lesson's words: every step's stacked in one grid cell, all but the step on show invisible (lesson.js holdWords),
   so the box keeps the longest step's height at any width or text size and Back and Next never move under the mouse */
.l-words { display: grid; margin-bottom: 14px; }
.l-words > .l-step { grid-area: 1 / 1; min-width: 0; }
.l-step.l-held { visibility: hidden; }
.lesson .l-text { font-size: 1.0625rem; line-height: 1.5; margin: 0; }
/* a lesson question's answer, over the step's words (lesson.js showSaid) */
.lesson .l-ask { margin: 0 0 6px; font-weight: 700; color: var(--muted); }
.lesson .l-ask.found { color: var(--win); }
.lesson .l-ask.found::before { content: "\2605  "; }
/* the same idea in another of the player's games (lesson.js showCompare): a small board and its game beside the words */
.l-compare {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  margin: 12px 0 0;
  padding: 10px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.l-compare .bframe { --bs: min(230px, 62vw); flex: none; }
.l-compare-hold { height: 262px; margin: 12px 0 0; }  /* its room among the held words, until it's drawn (lesson.js) */
.l-compare-words { flex: 1 1 12em; min-width: 0; }
.l-compare-words p { margin: 0 0 6px; }
.l-compare-words #l-compare-why { font-weight: 600; }
.lesson .l-eval { margin: 1em 0 0; }
.lesson .l-eval:empty { display: none; }
/* who is speaking (showCoach in settings.js): a coach's face and name above a lesson's words, in Learn too. It's a
   button: pressing it opens the coach picker (#coach-pick) */
.coach-tag { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; padding: 0 12px 0 0; font-family: var(--font-display); font-weight: 700;
  font-size: 1rem; letter-spacing: 0.02em; color: var(--accent); background: none; border: 0; border-radius: 999px; text-align: left; }
.coach-tag:hover { box-shadow: none; border-color: transparent; background: color-mix(in srgb, var(--accent) 10%, transparent); }
.coach-tag .coach-swap { font-size: 0.875rem; opacity: 0; transition: opacity 0.15s; color: var(--muted); }
.coach-tag:hover .coach-swap, .coach-tag:focus-visible .coach-swap { opacity: 1; }
/* the face carries its own edge (a badge's cream and ink rings: scripts/build_coaches.py), so it needs none here; the
   still copy stands in while Animation is off (and in the picker and the wait card) */
.coach-tag img { width: 64px; height: 64px; flex: none; }
@media (max-width: 600px) { .coach-tag img { width: 52px; height: 52px; } }
.face-still, .still .face:has(+ .face-still) { display: none; }
.still .face-still { display: block; }
.coach-tag[hidden] { display: none; }

/* the coach picker (settings.js openCoachPicker): a card a coach, their face big */
dialog.coach-pick { width: min(40rem, calc(100vw - 32px)); padding: 20px 22px 22px; }
.coach-pick h2 { margin: 0 0 4px; }
.coach-pick > p { margin: 0 0 14px; }
.coach-pick-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 14px; }
.coach-card { display: grid; justify-items: center; gap: 6px; padding: 16px 14px 14px; text-align: center; border-radius: var(--card-radius, 14px);
  background: var(--card-bg); border: 2px solid var(--card-line); font-weight: 400; }
.coach-card:hover { border-color: var(--accent); }
.coach-card .cc-face img { width: 112px; height: 112px; }
.coach-card .cc-blank { display: grid; place-items: center; width: 112px; height: 112px; border-radius: 50%; font-size: 64px; background: var(--ctl-bg); }
.coach-card .cc-name { font: var(--display-weight) 1.25rem/1.2 var(--font-display); color: var(--text); }
.coach-card .cc-blurb { color: var(--muted); font-size: 0.875rem; line-height: 1.4; }
.coach-card .cc-state { margin-top: 4px; padding: 3px 12px; border-radius: 999px; font-weight: 800; font-size: 0.8125rem; border: 1px solid var(--ctl-line); }
.coach-card.on { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent), var(--card-shadow, none); }
.coach-card.on .cc-state { background: var(--accent); color: var(--on-accent, var(--panel)); border-color: var(--accent); }
.coach-card.locked .cc-state { color: var(--c1); border-color: var(--c1); }
.coach-card.soon { opacity: 0.6; }
.coach-card.soon:disabled { opacity: 0.6; }  /* readable: it says it's coming */

/* the Coach setting: the coach's face and name, a button to the picker */
.coach-open { display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px 2px 2px; border-radius: 999px; }
.coach-open img { width: 26px; height: 26px; flex: none; }
.coach-open .chev { color: var(--muted); }
#settings .srow { display: flex; justify-content: space-between; align-items: center; gap: 12px; color: var(--muted); }
#settings .srow[hidden] { display: none; }
/* Pieces and Board as pictures to press (buildSettings' swatches): two knights in each set, each board's colours */
#settings .swatch-row { display: grid; justify-content: stretch; gap: 6px; }
#settings .srow-now { color: var(--text); font-weight: 600; margin-left: 4px; }
.swatches { display: flex; flex-wrap: wrap; gap: 6px; }
.swatch { padding: 3px; border-radius: 8px; line-height: 0; border: 2px solid transparent; background: var(--ctl-bg); }
.swatch[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent); }
.swatch .pv-sq { display: inline-block; width: 26px; height: 26px; }
.swatch .pv-sq.light { background: var(--sq-light); border-radius: 4px 0 0 4px; }
.swatch .pv-sq.dark { background: var(--sq-dark); border-radius: 0 4px 4px 0; }
.swatch .pv-sq img { width: 100%; height: 100%; }
.swatch .pv-board { display: grid; grid-template-columns: 1fr 1fr; width: 26px; height: 26px; border-radius: 4px; overflow: hidden; }
.swatch .pv-board i:nth-child(1), .swatch .pv-board i:nth-child(4) { background: var(--pv-light); }
.swatch .pv-board i:nth-child(2), .swatch .pv-board i:nth-child(3) { background: var(--pv-dark); }

/* "Show me why" making its lesson (lesson.js lessonWait): the coach, what's under way, and a bar filling */
.lesson-wait { display: flex; align-items: center; gap: 14px; margin: 10px 0; padding: 12px 14px; border-radius: var(--card-radius, 12px);
  background: var(--card-bg); border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--card-line)); box-shadow: var(--card-shadow, none);
  animation: lw-in 0.3s ease-out both; }
@keyframes lw-in { from { opacity: 0; transform: translateY(6px); } }
.lw-face { flex: none; line-height: 0; }
.lw-face img { width: 56px; height: 56px; }
.lw-knight { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%; background: var(--ctl-bg); animation: lw-hop 1.2s ease-in-out infinite; }
.lw-knight img { width: 40px; height: 40px; }
@keyframes lw-hop { 0%, 100% { transform: none; } 30% { transform: translate(6px, -10px) rotate(8deg); } 55% { transform: translate(10px, 0); } }
.lw-text { display: grid; gap: 4px; flex: 1; min-width: 0; }
.lw-text b { font-family: var(--font-display); font-size: 1.0625rem; }
.lw-stage { color: var(--muted); font-size: 0.9375rem; min-height: 1.3em; }
.lw-bar { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin-top: 4px; }
/* the bar: quick at first, slowing as it nears the end, never quite full (lessons take 2 to 10 seconds); a sheen runs on it */
.lw-bar i { display: block; height: 100%; width: 0; border-radius: inherit; background: linear-gradient(90deg, var(--accent), var(--c1, var(--accent)));
  animation: lw-fill 11s cubic-bezier(0.1, 0.6, 0.25, 1) forwards, lw-sheen 1.4s linear infinite;
  background-size: 200% 100%; }
@keyframes lw-fill { to { width: 94%; } }
@keyframes lw-sheen { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.still .lesson-wait, .still .lw-knight { animation: none; }
.still .lw-bar i { animation: lw-fill 11s cubic-bezier(0.1, 0.6, 0.25, 1) forwards; }
@media (prefers-reduced-motion: reduce) { .lesson-wait, .lw-knight { animation: none; } .lw-bar i { animation: lw-fill 11s cubic-bezier(0.1, 0.6, 0.25, 1) forwards; } }
/* the "Show me why" button while its lesson is being made */
#d-explain.busy { display: inline-flex; align-items: center; gap: 8px; }
#d-explain.busy:disabled { opacity: 0.85; cursor: progress; }
/* the player's coach still writing a lesson's words (lesson.js coachLater): their tag holds its place, faded, with dots
   bobbing like someone typing, so when their words swap in nothing below moves */
.coach-tag.writing { opacity: 0.6; }
.coach-tag .typing { display: inline-flex; gap: 3px; }
.coach-tag .typing i { width: 4px; height: 4px; border-radius: 50%; background: currentColor; animation: typing 1.2s ease-in-out infinite; }
.coach-tag .typing i:nth-child(2) { animation-delay: 0.15s; }
.coach-tag .typing i:nth-child(3) { animation-delay: 0.3s; }
@keyframes typing { 0%, 60%, 100% { opacity: 0.35; transform: none; } 30% { opacity: 1; transform: translateY(-3px); } }
.still .coach-tag .typing i { animation: none; }
.lesson .controls { margin: 8px 0 0; }
.note.good { border-color: var(--win); }
.note.bad { border-color: var(--c3); }
.moves {
  display: grid;
  grid-template-columns: 2.25rem 1fr 1fr;
  max-height: 260px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.moves .num { color: var(--muted); padding: 2px 6px; text-align: right; }
.moves .mv { padding: 2px 8px; cursor: pointer; border-radius: 4px; white-space: nowrap; }
.moves .mv:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.moves .mv.cur { background: var(--accent); color: var(--on-accent); }
.moves .mv.c1 { color: var(--c1); }
.moves .mv.c2 { color: var(--c2); }
.moves .mv.c3 { color: var(--c3); font-weight: 700; }
.moves .mv.cur.c1, .moves .mv.cur.c2, .moves .mv.cur.c3 { color: var(--on-accent); }
.moves .mv.opp { opacity: 0.8; }
/* Stockfish's check of a game as it's opened (viewer.js renderCheck): a line saying how far along, with a bar that fills */
.check { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 10px 0 0; color: var(--muted); }
.check .spinner { width: 12px; height: 12px; }
.check .cbar { flex: 1 0 100%; height: 6px; border-radius: 3px; overflow: hidden; background: var(--line); }
.check .cbar .fill {
  display: block; height: 100%; width: 0; border-radius: inherit;
  background: linear-gradient(90deg, var(--info), var(--accent));
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 60%, transparent);
  transition: width 0.6s ease-out;
}
.check button.linkish { padding: 0; border: 0; background: none; box-shadow: none; color: var(--accent); text-decoration: underline; font-weight: 600; }
/* ... and when it's done, the marks it found pop into the move list */
.moves.fresh .mv.c1, .moves.fresh .mv.c2, .moves.fresh .mv.c3 { animation: mark-in 0.7s cubic-bezier(0.3, 1.6, 0.5, 1) both; }
@keyframes mark-in {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.25); opacity: 1; background: color-mix(in srgb, currentColor 22%, transparent); }
  100% { transform: scale(1); }
}
.still .moves.fresh .mv, .still .check .cbar .fill { animation: none; transition: none; }
/* the game's review (viewer.js renderReview): each side's accuracy, counting up, and its grades as chips that jump to them */
.review { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 16px; margin-top: 10px; padding: 8px 10px 10px; }  /* a surface (below) */
.review[hidden] { display: none; }
.review .rv-head { grid-column: 1 / -1; font-size: 0.75rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase; color: var(--accent); }
.rv-side { display: grid; gap: 6px; align-content: start; min-width: 0; }
.rv-who { display: flex; align-items: center; gap: 6px; font-weight: 700; min-width: 0; }
.rv-who span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rv-who .dot { width: 11px; height: 11px; flex: none; border-radius: 50%; border: 1px solid var(--muted); }
.rv-who .dot.w { background: #f2f2f2; }
.rv-who .dot.b { background: #3a3a3a; }
.rv-acc { display: flex; align-items: baseline; gap: 6px; }
.rv-acc b { font: 800 1.75rem/1 var(--font-display); font-variant-numeric: tabular-nums; color: var(--acc, var(--text));
  text-shadow: 0 0 calc(14px * var(--glow, 1)) color-mix(in srgb, var(--acc, var(--text)) 45%, transparent); }
.rv-acc.high { --acc: var(--win); }
.rv-acc.mid { --acc: var(--c1); }
.rv-acc.low { --acc: var(--c3); }
.rv-acc span { font-size: 0.8125rem; color: var(--muted); }
.rv-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.review .rv-chip { display: inline-flex; align-items: center; gap: 4px; height: auto; padding: 1px 8px 1px 2px; border: 0;
  border-radius: 999px; font-size: 0.8125rem; font-weight: 700; color: var(--text); cursor: pointer;
  background: color-mix(in srgb, var(--verdict) 14%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--verdict) 45%, transparent); }
.review .rv-chip:hover { background: color-mix(in srgb, var(--verdict) 26%, transparent); }
.rv-chip i { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 4px;
  border-radius: 10px; font-style: normal; font-size: 0.75rem; background: var(--verdict); color: var(--on-accent); }
.review .rv-chip.zero { opacity: 0.4; cursor: default; }
.review.fresh .rv-chip { animation: mark-in 0.6s cubic-bezier(0.3, 1.6, 0.5, 1) both; animation-delay: calc(var(--i) * 70ms + 250ms); }
.still .review.fresh .rv-chip { animation: none; }
.graphwrap { position: relative; margin-top: 10px; }
.graph { display: block; width: 100%; height: 90px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; cursor: pointer; }
/* the same light and dark as the eval bar beside the board */
.graph .g-black { fill: color-mix(in srgb, var(--bg) 55%, #000); }
.graph .g-white { fill: var(--sq-light); }
.graph .g-mid { stroke: var(--muted); stroke-dasharray: 3 3; }
.graph .g-line { fill: none; stroke: var(--muted); stroke-width: 1; }
.graph .g-cur { stroke: var(--accent); stroke-width: 2; }
.graph .g-hover { stroke: var(--info); stroke-width: 1; }
.graph .g-mist { stroke: #fff; stroke-width: 1.5; }
.graph .g-mist.c2 { fill: var(--c2); }
.graph .g-mist.c3 { fill: var(--c3); }
.graph .g-empty { fill: var(--muted); font-size: 0.875rem; text-anchor: middle; dominant-baseline: middle; }
/* the graph sweeping in (drawGraph(reveal)): the eval's area and line wiped in from the left, each mistake popping as
   the wipe reaches it */
.graph.reveal .g-white, .graph.reveal .g-line { animation: graph-sweep var(--sweep, 1.1s) cubic-bezier(0.45, 0, 0.2, 1) both; }
.graph.reveal .g-mist { transform-box: fill-box; transform-origin: center;
  animation: mark-in 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) both; animation-delay: calc(var(--sweep, 1.1s) * var(--at, 0)); }
@keyframes graph-sweep { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.still .graph.reveal .g-white, .still .graph.reveal .g-line, .still .graph.reveal .g-mist { animation: none; }
.graph-tip {
  position: absolute;
  bottom: calc(100% + 6px);
  transform: translateX(-50%);
  padding: 3px 8px;
  border-radius: 5px;
  background: var(--text);
  color: var(--bg);
  font-size: 0.875rem;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.report { background: var(--panel); border: 1px solid var(--line); padding: 14px; overflow-x: auto; font: 0.875rem/1.4 ui-monospace, Consolas, monospace; }
/* a piece in your hand (PieceDrag in drag.js): .ghost follows the pointer; .lift grows it and casts its shadow, tweened
   as it's picked up and set down; the board's own piece on the square it settles onto waits hidden (.landing) */
.ghost { position: fixed; left: 0; top: 0; z-index: 1000; pointer-events: none; }
.ghost .lift { width: 100%; height: 100%; will-change: transform, filter; }
.ghost img { display: block; width: 100%; height: 100%; }
.piece.landing { opacity: 0; }
/* ... and the square it would be set down on: a fine ring in the look's accent, its edges softly lit, that glides
   from square to square as you carry the piece (--glide, from the Animation setting) and fades as it lands. It sits
   over the square's own piece, so it's a ring and a vignette, never a fill. --ax/--ay: which square. */
.board .aim {
  --sqz: calc(var(--bs) / 8);
  position: absolute; left: 0; top: 0; z-index: 2; width: 12.5%; height: 12.5%; pointer-events: none;
  border-radius: calc(var(--sqz) * 0.07);
  background: radial-gradient(closest-side, transparent 62%, color-mix(in srgb, var(--accent) 20%, transparent) 100%);
  box-shadow:  /* the ring; a hairline inside it, so it stays crisp on a light square; a soft band; the look's glow */
    inset 0 0 0 calc(var(--sqz) * 0.04) color-mix(in srgb, var(--accent) 92%, #fff),
    inset 0 0 0 calc(var(--sqz) * 0.04 + 1px) rgba(0, 0, 0, 0.2),
    inset 0 0 0 calc(var(--sqz) * 0.085) color-mix(in srgb, var(--accent) 20%, transparent),
    0 0 calc(var(--sqz) * 0.3 * var(--glow)) color-mix(in srgb, var(--accent) 45%, transparent);
  opacity: 0;
  transform: translate(var(--ax, 0), var(--ay, 0)) scale(0.9);
  transition: transform var(--glide, 110ms) cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.14s ease-out;
}
.board .aim.on { opacity: 1; transform: translate(var(--ax, 0), var(--ay, 0)); }
.board .aim.jump { transition: none; }
.still .board .aim { transition: none; }
.arrows { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; }
/* arrows, circles and orbs (Board.arrowSvg, ringSvg, orbSvg), each in a tone whose colour is the look's (--arrow-* in
   looks.css): a halo of light (--arrow-halo), the crisp shape lifted off the squares by a soft shadow (the kd filter,
   --arrow-shade), and while the board is lively (Board.lively) a spark running down the shaft (--arrow-spark) at the
   look's pace (--arrow-pulse-ms, set by Board.liven), the head beating as it arrives, and a new arrow growing out of
   its square. The animations' lengths are in pathLength units (1 = the whole shaft), so one set fits every arrow. */
.arrows feDropShadow { flood-color: #000; flood-opacity: var(--arrow-shade); }
.arrows .arr { opacity: var(--arrow-alpha); }
.arrows .arr path, .arrows .circ circle, .arrows .orb path { fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.arrows .arr .core { stroke-width: 0.15; }
.arrows .arr.lane .core { stroke-width: 0.1; }
.arrows .arr polygon { fill: currentColor; stroke: currentColor; stroke-width: 0.02; stroke-linejoin: round; }
.arrows .arr .halo { stroke-width: 0.34; opacity: var(--arrow-halo); }
.arrows .arr.lane .halo { stroke-width: 0.24; }
.arrows .arr .zap path {  /* the spark's glow, a comet's tail behind its hot head (they lead together, the glow trails) */
  stroke: color-mix(in srgb, currentColor 30%, #fff); stroke-width: 0.17; stroke-dasharray: 0.2 1.3; stroke-dashoffset: 0.2;
  opacity: var(--arrow-spark); animation: arrow-tail 1700ms linear infinite;
}
.arrows .arr .zap .hot { stroke: #fff; stroke-width: 0.06; stroke-dasharray: 0.08 1.42; stroke-dashoffset: 0.08; animation-name: arrow-spark; }
.arrows .arr.lane .zap path { stroke-width: 0.12; }
.arrows .arr.lane .zap .hot { stroke-width: 0.045; }
.arrows .arr .beat { animation: arrow-beat 1700ms linear infinite; }
/* both run 1.5 a cycle with their leading edges together, which reach the arrowhead two thirds of the way through */
@keyframes arrow-tail { from { stroke-dashoffset: 0.2; } to { stroke-dashoffset: -1.3; } }
@keyframes arrow-spark { from { stroke-dashoffset: 0.08; } to { stroke-dashoffset: -1.42; } }
@keyframes arrow-beat { 0%, 62% { transform: none; } 69% { transform: scale(1.14); } 84%, 100% { transform: none; } }
.arrows .grow .core { animation: arrow-grow 380ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.arrows .grow .halo { animation: arrow-fade 800ms ease-out both; }
.arrows .grow .ahead { animation: arrow-head 340ms 220ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
@keyframes arrow-grow { from { stroke-dasharray: 0 1; } to { stroke-dasharray: 1 0; } }
@keyframes arrow-fade { from { opacity: 0; } }
@keyframes arrow-head { from { transform: scale(0); opacity: 0; } to { transform: none; opacity: 1; } }
.arrows .circ { opacity: calc(var(--arrow-alpha) + 0.05); }
.arrows .circ .core { stroke-width: 0.07; }
.arrows .circ .halo { stroke-width: 0.2; opacity: var(--arrow-halo); }
.arrows .circ.grow { animation: ring-in 420ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
@keyframes ring-in { from { transform: scale(0.5); opacity: 0; } }
/* an orb where arrows' heads meet: a ring of their tones turning, its glow, a fine dashed ring turning the other way
   and sparks circling; its middle is clear, so the piece shows */
.arrows .orb { opacity: var(--arrow-alpha); }
.arrows .orb-body { fill: rgba(255, 255, 255, 0.1); stroke: none; }
.arrows .orb-arcs path { stroke-width: 0.08; }
.arrows .orb-glow path { stroke-width: 0.24; opacity: min(1, calc(var(--arrow-halo) + 0.2)); }
.arrows .orb-dash { fill: none; stroke: rgba(255, 255, 255, 0.75); stroke-width: 0.014; stroke-dasharray: 0.05 0.085; }
.arrows .orb-sparks circle { fill: #fff; stroke: none; opacity: var(--arrow-spark); }
.arrows .orb.grow .orb-in { animation: orb-in 560ms 180ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
@keyframes orb-in { from { transform: scale(0.2); opacity: 0; } }
/* the arrows' tones, their ideas' medallions and the key to them: ideas.css */

/* ---------- captures that burst (Board.shatter): shards of the taken piece, a flash, a ring of shock and the look's
   sparks, drawn in a layer over the board that they may fly out of. Their colours are the look's (looks.css --cap-*). */
.bfx { position: absolute; z-index: 6; pointer-events: none; overflow: visible; }
.bfx > i { position: absolute; display: block; will-change: transform, opacity; }
.bfx .cap-shard { background-position: center; background-size: 100% 100%; background-repeat: no-repeat; }
.bfx .cap-ring { border: solid transparent; border-radius: 50%; box-sizing: border-box; }
.bfx .cap-spark, .bfx .cap-puff, .bfx .cap-flash { border-radius: 50%; }
.bfx .cap-confetti { border-radius: 2px; }

/* ---------- keyboard focus and motion ---------- */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
tbody tr:focus-visible, th:focus-visible { outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* ---------- header tools, settings panel, shortcut help ---------- */
button.icon { min-width: 30px; height: 30px; padding: 0; border-radius: 50%; font-size: 1rem; line-height: 1; }
.s-status { padding: 12px 14px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; }
.s-status p { margin: 4px 0; }
.s-status .spinner { margin-right: 8px; }
.s-status .bad { color: var(--loss); }
.button-link { display: inline-block; padding: 8px 16px; border-radius: var(--ctl-radius); text-decoration: none; }
details.danger { margin-top: 16px; padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px; }
details.danger summary { cursor: pointer; color: var(--loss); }
details.danger label { display: grid; gap: 6px; max-width: 21.25rem; margin: 10px 0; color: var(--muted); font-size: 0.875rem; }
details.danger button { border-color: var(--loss); color: var(--loss); }
.panel .account { margin: 4px 0 0; padding-top: 8px; border-top: 1px solid var(--line); }
.panel {
  position: absolute;
  right: 16px;
  top: calc(100% + 6px);
  z-index: 50;
  display: grid;
  gap: 8px;
  min-width: 13.75rem;
  padding: 12px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.panel label { display: flex; justify-content: space-between; align-items: center; gap: 12px; color: var(--muted); }
.panel label[hidden] { display: none; }  /* a setting that doesn't apply just now (showSettings) */
/* the settings in their groups: two columns where there's room, and it scrolls on a short screen. .panel: the app's
   panel only, as the staff Status page has a #settings of its own (status.css) */
#settings.panel {
  display: block; width: min(36rem, calc(100vw - 32px)); max-height: calc(100vh - 90px); overflow-y: auto; overscroll-behavior: contain;
  columns: 2 14.5rem; column-gap: 24px; padding: 14px 16px;
}
#settings.panel .sgroup { break-inside: avoid; display: grid; gap: 7px; margin-bottom: 14px; }
#settings.panel .sgroup h4 {
  display: flex; align-items: center; gap: 8px; margin: 0 0 1px;
  font: 800 0.75rem/1.2 var(--font-body); letter-spacing: 0.09em; text-transform: uppercase; color: var(--accent);
}
#settings.panel .sgroup h4::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, var(--card-line), transparent); }
#settings.panel .account { column-span: all; }
@media (max-width: 640px) { #settings.panel { max-height: calc(100vh - 150px); } }  /* the header takes three lines on a phone */
.update-btn { height: 30px; display: inline-flex; align-items: center; gap: 6px; position: relative; overflow: hidden; }
.update-btn.busy { border-color: var(--info); }
.update-btn .sync-ic { width: 16px; height: 16px; flex: none; }
.update-btn:hover .sync-ic { transform: rotate(-30deg); transition: transform 0.25s ease-out; }
.update-btn.busy .sync-ic { color: var(--info); animation: sync-turn 1.1s linear infinite; }
@keyframes sync-turn { to { transform: rotate(360deg); } }
.still .update-btn .sync-ic { animation: none; transition: none; }
@media (prefers-reduced-motion: reduce) { .update-btn .sync-ic { animation: none; transition: none; } }
/* the wait before the button may start another Update (jobs.wait): a bar along its foot that drains */
.update-btn .u-cool { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--info); opacity: 0;
  transform-origin: left; transform: scaleX(0); transition: transform 1s linear, opacity 0.3s; pointer-events: none; }
.update-btn.cooling .u-cool { opacity: 0.8; }
.update-btn.cooling { color: var(--muted); }
.panel.update { width: min(24rem, calc(100vw - 32px)); display: grid; gap: 8px; }
.panel.update p { margin: 0; }
.u-status { display: flex; align-items: center; gap: 10px; }
.u-status .bad { color: var(--loss); }
.u-body { display: grid; gap: 6px; }
.u-body:empty { display: none; }
.u-body .steps { margin: 2px 0 0; max-width: none; }
.u-body .plus-pitch { margin: 2px 0 0; }
#u-wait { font-variant-numeric: tabular-nums; }
.u-num { font-variant-numeric: tabular-nums; }
/* a step just done pops its check mark */
.u-steps li.just i { animation: u-tick 0.45s ease-out; }
@keyframes u-tick { 0% { transform: scale(0.2); } 60% { transform: scale(1.3); } 100% { transform: none; } }
/* the button may start another Update: a shine runs across it (as strong as the look's --news) */
.update-btn.ready::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 30%, color-mix(in srgb, var(--accent) calc(var(--news, 1) * 55%), transparent) 50%, transparent 70%);
  transform: translateX(-100%); animation: u-shine var(--shine-ms, 900ms) ease-out; }
@keyframes u-shine { to { transform: translateX(100%); } }
/* new drills from an Update, on the Blunderbuss tab until it's opened */
nav a .tab-new { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: 0.75rem;
  font-weight: 800; line-height: 1.5; vertical-align: 1px; color: var(--on-accent, #fff); background: var(--win);
  box-shadow: 0 0 calc(var(--news, 1) * 12px) color-mix(in srgb, var(--win) calc(var(--news, 1) * 70%), transparent); }
@media (prefers-reduced-motion: reduce) { .u-steps li.just i, .update-btn.ready::after { animation: none; } }
.u-log {
  max-height: 240px;
  overflow: auto;
  margin: 6px 0 0;
  padding: 6px 8px;
  font: 0.8125rem/1.4 ui-monospace, Consolas, monospace;
  white-space: pre-wrap;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
}
kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 0 6px;
  text-align: center;
  font: 0.8125rem/1.6 ui-monospace, Consolas, monospace;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
}
dialog { color: var(--text); background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 16px 22px; min-width: min(24rem, 92vw); }
dialog::backdrop { background: rgba(0, 0, 0, 0.45); }
dialog h3 { margin: 14px 0 6px; font-size: 0.875rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
dialog dl { display: grid; grid-template-columns: 4.375rem 1fr; gap: 6px 12px; margin: 0; align-items: center; }
dialog dt, dialog dd { margin: 0; }
dialog form { position: absolute; top: 10px; right: 12px; }

/* ---------- the welcome card (welcome.js): after a reload, the one click that lets the sound start ---------- */
dialog.welcome {
  width: min(34rem, calc(100vw - 32px));
  min-width: 0;
  padding: 30px clamp(20px, 5vw, 40px) 28px;
  text-align: center;
  overflow: hidden;
  box-shadow: var(--card-shadow), 0 0 calc(48px * var(--glow)) color-mix(in srgb, var(--accent) calc(35% * var(--glow)), transparent);
  animation: wl-in calc(380ms * var(--pace, 1)) cubic-bezier(0.2, 0.9, 0.3, 1.15) both;
}
dialog.welcome::before {  /* a strip of the look's colours along the top */
  content: ""; position: absolute; inset: 0 0 auto; height: 4px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2), var(--accent));
}
dialog.welcome::backdrop { background: rgba(5, 8, 22, 0.62); backdrop-filter: blur(6px); }  /* no look tokens: older browsers don't pass them to ::backdrop */
.welcome .wl-kicker { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font: var(--display-weight) 0.9375rem var(--font-display); letter-spacing: 0.03em; }
.welcome .wl-kicker img { border-radius: 5px; }
.welcome .wl-body { margin: 20px 0 26px; }
.welcome blockquote, .welcome .wl-line { margin: 0; font: var(--display-weight) 1.5rem/1.35 var(--font-display); color: var(--text); text-wrap: balance; }
.welcome blockquote.long { font-size: 1.1875rem; line-height: 1.45; }
.welcome blockquote.longer { font-size: 1.0625rem; }  /* over 160 characters: Franklin's longest, Kasparov's */
.welcome blockquote::before { content: "\201C"; display: block; height: 0.5em; margin-bottom: 6px; font: 700 4rem/1 Georgia, "Times New Roman", serif; color: var(--accent); opacity: 0.6; }
.welcome .wl-by { margin: 10px 0 0; color: var(--muted); font-size: 0.9375rem; }
.welcome .wl-by::before { content: "\2014\00a0"; }
.welcome .wl-go { min-width: 11rem; padding: 10px 24px; font-size: 1.0625rem; }
/* the picture (art.py): a pen-and-ink drawing whose ink is a mask, painted from the look's accent into its second one,
   with the look's glow, so one drawing suits every look. The words sit beside it, or under it on a phone. */
.welcome .wl-art { display: none; }
dialog.welcome.has-art { width: min(42rem, calc(100vw - 32px)); }
.welcome.has-art .wl-body { display: grid; grid-template-columns: 12rem 1fr; gap: clamp(16px, 4vw, 30px); align-items: center; text-align: start; }
.welcome.has-art .wl-art {
  display: block; aspect-ratio: 1;
  filter: drop-shadow(0 0 calc(10px * var(--glow)) color-mix(in srgb, var(--accent) calc(55% * var(--glow)), transparent));
}
.welcome .wl-art i { display: block; width: 100%; height: 100%; opacity: 0; background: linear-gradient(135deg, var(--accent) 15%, var(--accent-2) 85%); }
/* drawn: the ink sweeps in from the left behind a soft diagonal edge (a second mask layer, slid across) */
.welcome .wl-art.drawn i {
  opacity: 1;
  -webkit-mask: var(--art) center / contain no-repeat, linear-gradient(115deg, #000 40%, transparent 60%) 0 0 / 300% 100% no-repeat;
  -webkit-mask-composite: source-in;
  mask: var(--art) center / contain no-repeat, linear-gradient(115deg, #000 40%, transparent 60%) 0 0 / 300% 100% no-repeat;
  mask-composite: intersect;
  animation: wl-ink calc(var(--art-sweep, 1100ms) * var(--pace, 1)) cubic-bezier(0.3, 0.7, 0.25, 1) calc(120ms * var(--pace, 1)) both;
}
@keyframes wl-ink { from { -webkit-mask-position: center, 100% 0; mask-position: center, 100% 0; } }
@media (max-width: 560px) {
  .welcome.has-art .wl-body { grid-template-columns: 1fr; gap: 10px; margin-top: 12px; text-align: center; }
  .welcome.has-art .wl-art { width: min(8.5rem, 40vw); margin: 0 auto; }
}
@keyframes wl-in { from { opacity: 0; transform: translateY(16px) scale(0.96); } }
@keyframes wl-out { to { opacity: 0; transform: translateY(-10px) scale(0.98); } }
dialog.welcome.leaving { animation: wl-out calc(220ms * var(--pace, 1)) ease-in forwards; }
dialog.welcome.still, dialog.welcome.still.leaving, .welcome.still .wl-art.drawn i { animation: none; }  /* the Animation setting is off */
@media (prefers-reduced-motion: reduce) { dialog.welcome, dialog.welcome.leaving, .welcome .wl-art.drawn i { animation: none; } }

/* ---------- toasts ---------- */
/* "Tell us what you think" (tellus.js): a box to write in, and whether we may quote it */
dialog.tell { width: min(34rem, calc(100vw - 24px)); padding: 20px 22px 22px; }
dialog.tell h2 { margin: 0 34px 4px 0; }
dialog.tell textarea {
  display: block; width: 100%; margin: 12px 0; padding: 10px 12px; font: inherit; color: var(--text); resize: vertical;
  background: var(--ctl-bg); border: 1px solid var(--ctl-line); border-radius: var(--ctl-radius);
}
dialog.tell textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tell-quote { display: flex; gap: 8px; align-items: center; cursor: pointer; }
.tell-quote input { accent-color: var(--accent); }
.tell-as { display: grid; gap: 4px; margin-top: 10px; color: var(--muted); font-size: 0.9375rem; }
.tell-as input { padding: 8px 10px; }
.tell-go { margin: 14px 0 0; text-align: right; }
.tell-go button { padding: 9px 24px; font-weight: 700; }
/* "Add to your home screen" (install.js): a card at the foot of a phone's screen, once, which slides up */
.install-hint {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 1900; max-width: 30rem; margin: 0 auto;
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px 12px; align-items: center; padding: 14px 16px;
  color: var(--text); background: var(--card-solid); border: 1px solid color-mix(in srgb, var(--accent) 50%, var(--card-line));
  border-radius: calc(var(--card-radius) + 2px);
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.6), 0 0 calc(26px * var(--glow)) color-mix(in srgb, var(--accent) 30%, transparent);
  opacity: 0; transform: translateY(18px); transition: opacity 0.25s, transform 0.3s cubic-bezier(0.2, 1.2, 0.4, 1);
}
.install-hint.in { opacity: 1; transform: none; }
.install-hint .mark { border-radius: 11px; }
.install-words { display: grid; gap: 2px; }
.install-words b { font: var(--display-weight) 1.0625rem / 1.25 var(--font-display); }
.install-how { color: var(--muted); font-size: 0.9375rem; }
.install-hint .install-how.ios, .install-hint.ios .install-how.any, .install-hint.ios #install-add { display: none; }
.install-hint.ios .install-how.ios { display: inline; }
.install-go { grid-column: 1 / -1; display: flex; gap: 8px; justify-content: flex-end; }
.install-go button { padding: 8px 18px; font-weight: 700; }
.still .install-hint { transition: none; }
#toasts { position: fixed; right: 16px; bottom: 16px; z-index: 2000; display: grid; gap: 8px; width: min(22.5rem, calc(100vw - 32px)); }
/* --tk: the toast's colour, by kind; an icon in it, the message, a close button, and a line running down its time */
.toast {
  --tk: var(--info);
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 8px 12px 12px;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 4px solid var(--tk);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  animation: toast-in 0.38s cubic-bezier(0.2, 1.4, 0.4, 1);
}
.toast.good { --tk: var(--win); }
.toast.warn { --tk: var(--c2); }
.toast.bad { --tk: var(--c3); }
@keyframes toast-in { from { opacity: 0; transform: translateX(36px) scale(0.94); } }
.toast .t-icon {
  flex: none; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  background: var(--tk); color: var(--on-accent);
  box-shadow: 0 0 calc(14px * var(--glow)) color-mix(in srgb, var(--tk) 65%, transparent);
}
.toast .t-icon svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.toast .t-text { flex: 1; min-width: 0; padding-top: 1px; overflow-wrap: anywhere; }
.toast .t-close {
  flex: none; width: 24px; height: 24px; margin: -2px 0 0; padding: 0; border: 0; border-radius: 50%;
  background: none; box-shadow: none; color: var(--muted); font-size: 1.1875rem; font-weight: 400; line-height: 1;
}
.toast .t-close:hover { color: var(--text); background: color-mix(in srgb, var(--text) 10%, transparent); }
.toast .t-time {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--tk); opacity: 0.55;
  transform-origin: left; animation: toast-time var(--toast-ms, 4500ms) linear forwards;
}
.toast:hover .t-time { animation-play-state: paused; }  /* the toast waits while you read it (toast in common.js) */
@keyframes toast-time { to { transform: scaleX(0); } }

/* ---------- the connection pill (net.js): while the page's calls wait for the server to come back ----------
   It drops in at the top, over the header's middle; the dot pings while it waits and pops green when it's back. */
.netpill {
  --net: var(--c1);
  position: fixed; top: 10px; left: 50%; z-index: 2100;
  display: flex; align-items: center; gap: 10px;
  max-width: calc(100vw - 32px);
  padding: 6px 7px 6px 14px;
  border: 1px solid color-mix(in srgb, var(--net) 50%, var(--card-line));
  border-radius: 999px;
  background: var(--card-solid);
  box-shadow: var(--card-shadow), 0 0 calc(26px * var(--glow)) color-mix(in srgb, var(--net) 38%, transparent);
  font-size: 0.90625rem;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, calc(-100% - 24px));
  transition: transform 0.4s cubic-bezier(0.2, 1.4, 0.4, 1), opacity 0.25s, border-color 0.3s, box-shadow 0.3s;
}
.netpill.in { opacity: 1; transform: translate(-50%, 0); }
.netpill[data-state="offline"] { --net: var(--c2); }
.netpill[data-state="back"] { --net: var(--win); padding-right: 16px; }
.netpill b { font-family: var(--font-display); font-weight: var(--display-weight); }
.net-sub { color: var(--muted); font-variant-numeric: tabular-nums; }
.net-dot { position: relative; flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--net); }
.netpill:not([data-state="back"]) .net-dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--net);
  animation: net-ping 1.5s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@keyframes net-ping { 75%, 100% { opacity: 0; transform: scale(2.6); } }
.netpill[data-state="back"] .net-dot { animation: net-pop 0.5s cubic-bezier(0.2, 1.6, 0.4, 1); }
@keyframes net-pop { from { transform: scale(0.3); } 55% { transform: scale(1.6); } }
.net-now { padding: 3px 12px; border-radius: 999px; font-size: 0.84375rem; }
.netpill[data-state="newer"] { --net: var(--accent); }  /* an update went live: Reload, or dismiss it */
.netpill[data-state="newer"] .net-dot::after { animation-iteration-count: 3; }
.net-x { padding: 0 6px; border: 0; background: none; color: var(--muted); font-size: 1.125rem; line-height: 1; cursor: pointer; }
.net-x:hover { color: var(--text); }
/* ---------- games table ---------- */
.tablewrap { overflow-x: auto; }
@media (min-width: 1100px) {
  /* wide enough that nothing overflows, so the header row can stick to the top of the window */
  .tablewrap { overflow-x: clip; }
  #games-table thead th { position: sticky; top: 0; z-index: 2; background: var(--card-solid); box-shadow: inset 0 -1px 0 var(--line); }
}
tbody tr.recent { background: color-mix(in srgb, var(--accent) 14%, transparent); box-shadow: inset 3px 0 0 var(--accent); }
tbody tr.empty { cursor: default; }
tbody tr.empty:hover { background: none; }
tbody tr.empty td { padding: 24px 10px; text-align: center; color: var(--muted); white-space: normal; }
/* where the table scrolls sideways (a phone), the message keeps to the part of it on screen */
.empty-msg { max-width: 100%; margin: 0 auto; }
@media (max-width: 1099px) { .empty-msg { position: sticky; left: 0; width: calc(100vw - 72px); margin: 0; } }
/* the arrow keys move through the rows (moveRow in games.js): room for the header that sticks above them */
#games-table tbody tr { scroll-margin-top: 44px; scroll-margin-bottom: 8px; }
/* the date, and the result and blunders as badges */
td.date { font-variant-numeric: tabular-nums; }
th.blunders, td.blunders { text-align: center; }
.pill {
  display: inline-block; min-width: 2.4em; padding: 1px 9px; border-radius: 999px; text-align: center;
  font-size: 0.875rem; font-weight: 700; line-height: 1.5; font-variant-numeric: tabular-nums;
  color: var(--muted); background: color-mix(in srgb, var(--muted) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--muted) 28%, transparent);
}
.pill.W { color: var(--win); background: color-mix(in srgb, var(--win) 15%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--win) 42%, transparent); }
.pill.L { color: var(--loss); background: color-mix(in srgb, var(--loss) 13%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--loss) 40%, transparent); }
.pill.bl { min-width: 2em; color: var(--on-accent); background: var(--c3); box-shadow: 0 0 calc(12px * var(--glow)) color-mix(in srgb, var(--c3) 55%, transparent); }
.pill.zero, .pill.none { min-width: 2em; background: none; box-shadow: none; }
.pill.none { opacity: 0.5; }
/* Clear filters: beside the filters while any holds games back, and under "No games match" */
button.clear { padding: 3px 12px; border-radius: 999px; font-size: 0.875rem; color: var(--muted); }
button.clear:hover { color: var(--text); }
tbody tr.empty .clear { margin-top: 10px; }
/* on a phone the filters pair up, each name over its box, so the list starts higher up the screen */
@media (max-width: 640px) {
  .filters { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
  .filters label:not(.check) { flex-direction: column; align-items: stretch; gap: 2px; font-size: 0.8125rem; }
  .filters select, .filters input[type="search"] { width: 100%; min-width: 0; }
  .filters label.check { align-self: end; padding-bottom: 5px; }
  .filters #games-count { grid-column: 1 / -1; }
  .filters .clear { justify-self: start; align-self: end; }
}
/* the first list on its way: grey bars that shimmer where the rows will be */
tbody tr.skel { cursor: default; }
tbody tr.skel:hover { background: none; }
.sk {
  display: block; height: 11px; max-width: 100%; margin: 4px 0; border-radius: 6px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--text) 7%, transparent) 30%, color-mix(in srgb, var(--text) 17%, transparent) 50%,
    color-mix(in srgb, var(--text) 7%, transparent) 70%) 0 0 / 300% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
/* a new list on its way: the rows dim and a light runs along the top */
.tablewrap { position: relative; }
.tablewrap tbody { transition: opacity 0.2s; }
.tablewrap.loading tbody:not(:has(.skel)) { opacity: 0.5; }
.tablewrap.loading::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; z-index: 3; height: 3px; border-radius: 3px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--accent), var(--accent-2), transparent) -67% 0 / 40% 100% no-repeat;
  animation: sweep 1.1s ease-in-out infinite;
}
@keyframes sweep { to { background-position: 167% 0; } }
/* no games at all yet: a welcome on the list */
.nogames { display: grid; justify-items: center; gap: 6px; padding: 26px 12px 20px; color: var(--muted); }
.nogames .knight {
  width: 88px; height: 88px; border-radius: 50%; display: grid; place-items: center;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--accent) 38%, var(--card-solid)), color-mix(in srgb, var(--accent-2) 24%, var(--card-solid)) 72%);
  box-shadow: 0 0 0 1px var(--card-line), 0 0 calc(44px * var(--glow)) color-mix(in srgb, var(--accent-2) 45%, transparent);
  animation: bob 3.2s ease-in-out infinite;
}
.nogames .knight img { width: 62px; height: 62px; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.35)); }
.nogames h3 { margin: 8px 0 0; font-size: 1.375rem; color: var(--text); }
.nogames p { margin: 0 0 10px; max-width: 27rem; }
@keyframes bob { 50% { transform: translateY(-5px) rotate(-4deg); } }
.still .nogames .knight { animation: none; }
.more { text-align: center; margin: 14px 0 4px; }
.more button { padding: 6px 18px; }
th[data-col] { cursor: pointer; user-select: none; }
th[data-col]:hover { color: var(--text); }
.filters label.check { cursor: pointer; }
.filters input[type="checkbox"] { padding: 0; accent-color: var(--accent); }

/* ---------- board: move hints and coordinates ----------
   Move hints: a faint dot on each square the piece you picked up (or clicked) may go to, a ring round a piece it
   could take. They pop in as it's lifted; with Animation off (or reduced motion) they just appear. */
.sq.dot::after {
  content: "";
  position: absolute;
  width: 30%;
  height: 30%;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.2);
  pointer-events: none;
  animation: dot-in 0.2s cubic-bezier(0.2, 1.5, 0.4, 1) backwards;
}
.sq.dot.cap::after { width: 100%; height: 100%; background: none; box-shadow: inset 0 0 0 calc(var(--bs) / 8 * 0.07) rgba(0, 0, 0, 0.22); }
@keyframes dot-in { from { opacity: 0; transform: scale(0.2); } }
.still .sq.dot::after { animation: none; }
/* Coordinates (the setting) inside the board (above), outside it, or none. Outside, the frame Board puts round the
   board (.bframe) keeps a gutter (--cg) down its left for the ranks and along its foot for the files, in the look's
   quiet colour; the board gives up that much room (--bs, at the top). */
.no-coords .sq .coord, .coords-out .sq .coord { display: none; }
.bframe { position: relative; }
.bcoords { display: none; }
.coords-out .bframe { padding: 0 0 var(--cg) var(--cg); }
.coords-out .bcoords {
  position: absolute; display: grid; pointer-events: none; user-select: none;
  color: color-mix(in srgb, var(--text) 70%, transparent); font: 700 0.9375rem/1 var(--font-body);
}
.bcoords.ranks { left: 0; top: 0; width: var(--cg); height: var(--bs); grid-template-rows: repeat(8, 1fr); padding-right: 3px; }
.bcoords.files { left: var(--cg); bottom: 0; width: var(--bs); height: var(--cg); grid-template-columns: repeat(8, 1fr); padding-top: 3px; }
.bcoords span { display: grid; place-items: center; }
.coords-out .boardcol { width: calc(var(--bs) + var(--cg)); }
.coords-out .boardcol > .pstrip { margin-left: var(--cg); }  /* the name bars line up with the board, not the gutter */
.bframe:has(> .board.resting) .bcoords { visibility: hidden; }  /* a card on the board, not a position */

/* ---------- board pop-ups: the drill's moments in chips by the squares they're about (callouts.js) ----------
   Like a game's: a solid pill with a crisp edge and a deep shadow, that springs out of the square it's about, stays a few
   seconds and fades. Each goes as close to its square as it can without covering what matters there (Board.spot: the
   arrows, the moved piece, then the other pieces), the rest stacking beside the verdict; the panel says the same in
   full. The verdict takes its grade's colour (--verdict, .v-*). */
.callouts { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
.callout {
  position: absolute; left: 0; top: 0; display: inline-flex; align-items: center; gap: 8px; padding: 7px 14px; border-radius: 999px;
  background: var(--card-solid); border: 1px solid var(--card-line); color: var(--text);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.35); font-size: 0.9375rem; font-weight: 700; line-height: 1.25; white-space: nowrap;
  opacity: 0; transform: scale(0.5);  /* from its square: Callouts.place sets the transform-origin there */
  transition: opacity 0.3s, transform 0.5s cubic-bezier(0.2, 1.45, 0.4, 1);
}
.callout.on { opacity: 1; transform: none; }
.callout.measuring { visibility: hidden; transition: none; }  /* measured before it's placed */
.still .callout { transition: none; }
.callout.co-verdict {
  padding: 8px 16px 8px 8px; font-size: 1.0625rem;
  border-color: color-mix(in srgb, var(--verdict) 50%, var(--card-line)); background: color-mix(in srgb, var(--verdict) 13%, var(--card-solid));
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.35), 0 0 calc(26px * var(--glow)) color-mix(in srgb, var(--verdict) 45%, transparent);
}
.callout.co-verdict b { color: var(--verdict); }
.callout .cmark {
  display: inline-grid; place-items: center; min-width: 28px; height: 28px; padding: 0 6px; border-radius: 999px;
  background: var(--verdict); color: var(--on-accent); font: 800 0.875rem/1 var(--font-body); font-style: normal;
}
.callout .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--arrow-played); box-shadow: 0 0 calc(8px * var(--glow)) var(--arrow-played); }
.callout.co-game b { color: var(--loss); }  /* the arrow's red is for the board: on a dark chip the look's loss colour reads better */
.callout svg { width: 17px; height: 17px; flex: none; overflow: visible; }
.callout.co-streak .outer { fill: #f4a640; } .callout.co-streak .inner { fill: #ffe7a3; }
.callout.co-streak.t2 .outer { fill: #f2852a; } .callout.co-streak.t2 .inner { fill: #ffd36b; }
.callout.co-streak.t3 .outer, .callout.co-streak.t4 .outer { fill: #e8541e; } .callout.co-streak.t3 .inner, .callout.co-streak.t4 .inner { fill: #ffc14d; }
.callout.co-streak svg { filter: drop-shadow(0 0 calc(5px * var(--glow)) #ff8a2a); }
.callout.co-stage { font-weight: 600; }
.callout.co-stage .stg { font-weight: 700; }
/* a phone's squares are small: smaller chips, so more of them find a place (a chip with none isn't shown) */
@media (max-width: 600px) {
  .callout { font-size: 0.8125rem; padding: 5px 10px; gap: 6px; }
  .callout.co-verdict { font-size: 0.875rem; padding: 5px 12px 5px 5px; }
  .callout .cmark { min-width: 22px; height: 22px; font-size: 0.75rem; }
  .callout svg { width: 14px; height: 14px; }
}

/* ---------- drill progress bar ---------- */
/* the glow of a look (looks.css) reaches a little past the bar; the shine stays inside it */
.pbar { position: relative; display: flex; height: var(--bar-height); margin: 4px 0 6px; border-radius: 999px; overflow: clip; overflow-clip-margin: 6px;
  background: var(--bar-track); gap: 3px; }
.pbar span { min-width: 4px; border-radius: 999px; }
.pbar .mastered, .legend .mastered { background: var(--win); }
.pbar .junior, .legend .junior { background: var(--win); opacity: 0.5; }
.pbar .novice, .legend .novice { background: var(--c1); }
.pbar .blunder, .legend .blunder { background: var(--loss); }
.legend { display: flex; flex-wrap: wrap; gap: 2px 14px; margin-bottom: 12px; font-size: 0.875rem; color: var(--muted); }
.legend .key { position: relative; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
/* New isn't a stage, so it keeps to the far right: wrapped onto a line of its own at the left, it sat
   under Mastered, and a first try flying out of it looked like a drill leaving Mastered */
.legend .key[data-k="new"] { margin-left: auto; }
.plan-note { margin: -4px 0 12px; padding: 8px 12px; border-left: 3px solid var(--accent); border-radius: 6px; font-size: 0.875rem; color: var(--muted); background: color-mix(in srgb, var(--accent) 7%, var(--panel)); }
.plan-note b { color: var(--text); }
.legend i { width: 10px; height: 10px; border-radius: 2px; }
/* when the counts change (animateProgress in progress.js): a shine runs along the bar, a swatch flies across
   the key, and "+1" floats off a count. Each sits out of the way until its animation moves it. */
.pbar .shine {
  position: absolute; top: 0; bottom: 0; left: 0; width: 35%; transform: translateX(-100%); pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.75), transparent);
}
.legend .fly { position: fixed; left: 0; top: 0; z-index: 5; opacity: 0; pointer-events: none; }
/* confetti() draws here: over everything but toasts, and clicks go straight through */
.confetti { position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 1500; pointer-events: none; }
.legend .delta {
  position: absolute; left: 0; bottom: 70%; font-size: 0.9375rem; font-weight: 800; pointer-events: none;
  text-shadow: 0 0 3px var(--bg), 0 0 3px var(--bg), 0 0 3px var(--bg); /* a halo, to read over the bar */
}

/* ---------- drill: difficulty and your drill rating ---------- */
.level { margin: 0 0 14px; padding: 8px 12px 6px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; }
.level-text { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px 12px; font-size: 0.9375rem; }
.level-text b { font-size: 1.0625rem; }
.trend { width: 64px; height: 16px; margin-left: 4px; vertical-align: -2px; }
.trend polyline { fill: none; stroke: var(--accent); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
/* easier | the scale with both markers | harder */
.ruler { display: flex; align-items: center; gap: 8px; height: 62px; margin-top: 2px; }
.ruler .end { flex: none; font-size: 0.8125rem; color: var(--muted); }
.ruler .scale { position: relative; flex: 1; align-self: stretch; }
.ruler .track {
  position: absolute; left: 0; right: 0; top: 28px; height: 6px; border-radius: 3px;
  background: linear-gradient(90deg, var(--win), var(--c1) 50%, var(--c3));
  opacity: 0.75;
}
.ruler .mark {
  position: absolute; transform: translateX(-50%); transition: left 0.6s ease-out;
  display: flex; flex-direction: column; align-items: center;
  font-size: 0.75rem; font-weight: 700; line-height: 1; white-space: nowrap;
}
/* you: a dark label above the bar, pointing down at your rating */
.ruler .mark.you { top: 8px; }
.ruler .mark.you span { padding: 2px 5px; border-radius: 3px; background: var(--text); color: var(--bg); }
.ruler .mark.you::after { content: ""; border: 5px solid transparent; border-top-color: var(--text); }
/* this drill: a blue ring on the bar, named underneath in the same blue */
.ruler .mark.drill { top: 23px; color: var(--info); }
.ruler .mark.drill i {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--panel); border: 3px solid var(--info); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
.ruler .mark.drill span { margin-top: 3px; }
.level-text .drill-num { color: var(--info); }
.rchange { margin: 4px 0 0; font-weight: 600; }
.rchange.up { color: var(--win); }
.rchange.down { color: var(--loss); }

/* ---------- drill: its editions (Rapid, Blitz), each with how many drills wait in it ---------- */
.editions { display: flex; padding: 4px; gap: 4px; margin-bottom: 10px; border-radius: 999px; background: var(--card-bg); border: 1px solid var(--card-line); }
.edition {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border: 0; background: none;
  color: var(--muted); font-weight: 700; padding: 7px 14px; border-radius: 999px; transition: background 0.2s, color 0.2s, box-shadow 0.2s;
}
.edition:hover { color: var(--text); }
.edition[aria-selected="true"] { color: var(--nav-active-fg, var(--text)); background: var(--nav-active-bg, var(--panel)); box-shadow: var(--nav-active-shadow, none); }
.edition .waiting {
  min-width: 1.6em; padding: 1px 6px; border-radius: 999px; font-size: 0.75rem; font-variant-numeric: tabular-nums;
  color: var(--on-accent); background: var(--accent); box-shadow: 0 0 calc(10px * var(--glow)) color-mix(in srgb, var(--accent) 55%, transparent);
}
.edition[aria-selected="true"] .waiting { background: var(--accent-2, var(--accent)); }
.edition.bump .waiting { animation: edition-bump 0.5s ease-out; }
@keyframes edition-bump { 35% { transform: scale(1.35); } }
@media (prefers-reduced-motion: reduce) { .edition.bump .waiting { animation: none; } }

/* ---------- drill: streaks by the heading, and where an answer moved the drill ---------- */
.dhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 12px; margin-bottom: 4px; }
.dhead h2 { margin: 0; }
.streaks { display: flex; flex-wrap: wrap; gap: 6px; }
.streak {
  position: relative; display: inline-flex; align-items: center; gap: 4px; padding: 1px 9px 1px 6px;
  border: 1px solid var(--ctl-line); border-radius: 999px; background: var(--ctl-bg);
  font-size: 0.875rem; color: var(--muted); white-space: nowrap; cursor: default;
}
.streak b { color: var(--text); font-variant-numeric: tabular-nums; }
.streak svg { width: 16px; height: 16px; flex: none; overflow: visible; }
/* the flame grows and warms with the run: none yet, a flicker, orange, red, then ablaze. It's the chip's star: bigger
   than the calendar, lit from the first right answer, and it flares as the run grows (progress.js flameBurst) */
.streak.run { padding-left: 4px; }
.streak.run svg { width: 22px; height: 22px; margin: -3px 0 -2px; transform-origin: 50% 85%; }
.streak.run b { font-size: 1rem; }
.streak.run.t1 svg, .streak.run.t2 svg, .streak.run.t3 svg { filter: drop-shadow(0 0 calc(3px * var(--glow, 1)) rgba(255, 138, 42, 0.75)); }
.streak .ember, .streak .smoke { position: absolute; width: 5px; height: 5px; border-radius: 50%; pointer-events: none; z-index: 2; }
.streak .ember { background: #ffc14d; box-shadow: 0 0 6px 1px #ff8a2a; }
.streak .smoke { width: 7px; height: 7px; background: color-mix(in srgb, var(--muted) 70%, transparent); filter: blur(1px); }
.streak.run .outer { fill: var(--line); }
.streak.run .inner { fill: var(--panel); }
.streak.run.t1 .outer { fill: #f4a640; } .streak.run.t1 .inner { fill: #ffe7a3; }
.streak.run.t2 .outer { fill: #f2852a; } .streak.run.t2 .inner { fill: #ffd36b; }
.streak.run.t2 svg { transform: scale(1.1); }
.streak.run.t3 .outer, .streak.run.t4 .outer { fill: #e8541e; } .streak.run.t3 .inner, .streak.run.t4 .inner { fill: #ffc14d; }
.streak.run.t3 svg { transform: scale(1.2); }
.streak.run.t3, .streak.run.t4 { border-color: color-mix(in srgb, #e8541e 55%, var(--line)); }
.streak.run.t4 { background: color-mix(in srgb, #e8541e 12%, var(--panel)); }
.streak.run.t4 svg { transform: scale(1.3); filter: drop-shadow(0 0 3px #ff8a2a); animation: flicker 1.1s ease-in-out infinite; transform-origin: 50% 90%; }
@keyframes flicker { 0%, 100% { transform: scale(1.3) rotate(-3deg); } 50% { transform: scale(1.42) rotate(3deg); } }
.still .streak svg, .still .steps li.now i { animation: none; }
.streak.days svg { color: var(--muted); }
.streak.days .tick { display: none; }
.streak.days.done svg { color: var(--accent); }
.streak.days.done .tick { display: inline; }
/* a chip saying why it lit up (flare in progress.js): laid over it, reaching left, gone after a moment */
.streak .say {
  position: absolute; top: -1px; right: -1px; bottom: -1px; z-index: 3; opacity: 0; pointer-events: none;
  display: inline-flex; align-items: center; gap: 4px; padding: 0 9px 0 6px; border-radius: 999px;
  border: 1px solid transparent; font-weight: 700; white-space: nowrap; transform-origin: 85% 50%;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.streak .say.rightward { right: auto; left: -1px; transform-origin: 15% 50%; }
.streak .say.hot { background: #e8541e; color: #fff; }
.streak .say.hot b { color: #fff; }
.streak .say.hot .outer { fill: #fff1d6; }
.streak .say.hot .inner { fill: #ffb43c; }
.streak .say.day { background: var(--accent); color: var(--panel); }
.streak .say.day b, .streak .say.day svg { color: var(--panel); }
.streak .say.day .tick { display: inline; }
.streak .say.broke { background: var(--panel); border-color: var(--line); color: var(--muted); font-weight: 600; }
.stagechange { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 0.9375rem; }
.stg { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; }
.stg i { width: 10px; height: 10px; border-radius: 2px; background: var(--muted); }
.stg.mastered i { background: var(--win); }
.stg.junior i { background: var(--win); opacity: 0.5; }
.stg.novice i { background: var(--c1); }
.stg.blunder i { background: var(--loss); }
.stg.new i { background: none; border: 1px solid var(--muted); }

/* ---------- drill: nothing waiting (a card on the board), and the moments on the way there ---------- */
/* grows to fit the card on a small screen, its squares staying square */
.board.resting { display: flex; align-items: center; justify-content: center; height: auto; min-height: var(--bs); padding: 6%;
  background: var(--board-frame-art); }
.board.resting::before {  /* the board's squares, faded, behind the card */
  content: ""; position: absolute; inset: 0; z-index: -1; opacity: 0.3;
  background: repeating-conic-gradient(var(--sq-dark) 0 25%, var(--sq-light) 0 50%) 0 0 / calc(var(--bs) / 4) calc(var(--bs) / 4);
}
.donecard {
  max-width: 27.5rem; padding: 22px 24px; text-align: center; border-radius: 12px;
  background: var(--panel); border: 1px solid var(--line); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  animation: card-in 0.4s ease-out;
}
@keyframes card-in { from { opacity: 0; transform: translateY(10px) scale(0.97); } }
.donecard h3 { margin: 8px 0 6px; font-size: 1.3125rem; }
.donecard p { margin: 6px 0; color: var(--muted); }
.donecard .next-review { margin-top: 12px; color: var(--text); font-size: 1.0625rem; }
.donecard .next-review b { font-variant-numeric: tabular-nums; }
/* no drills yet: why, what to do, and the rest of the app to try meanwhile (progress.js noDrillsHtml) */
.nodrills { width: 100%; max-width: 28.75rem; box-sizing: border-box; margin: 0 auto; }
.nodrills > p:not(.small) { color: var(--text); }
.nodrills .nd-mark img { width: 38px; height: 38px; }
.nodrills .nd-sync { display: inline-flex; align-items: center; gap: 8px; }
.nodrills .nd-sync .sync-ic { width: 17px; height: 17px; }
.nodrills .nd-sync:hover .sync-ic { transform: rotate(-30deg); transition: transform 0.25s ease-out; }
.nd-meanwhile { margin: 18px 0 8px; font-size: 0.8125rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.nd-tiles { display: grid; gap: 8px; text-align: left; }
.nd-tile {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 10px; color: var(--text); text-decoration: none;
  border: 1px solid var(--line); background: color-mix(in srgb, var(--info) 7%, var(--panel));
  transition: transform 0.15s ease-out, border-color 0.15s, box-shadow 0.15s; animation: card-in 0.45s ease-out backwards;
}
.nd-tile:nth-child(1) { animation-delay: 0.12s; }
.nd-tile:nth-child(2) { animation-delay: 0.2s; }
.nd-tile:nth-child(3) { animation-delay: 0.28s; }
.nd-tile:hover, .nd-tile:focus-visible { transform: translateY(-2px); border-color: var(--info); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18); }
.nd-art { flex: none; width: 78px; height: 44px; display: flex; align-items: center; justify-content: center; }
.nd-art svg { width: 32px; height: 32px; fill: none; stroke: var(--info); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.nd-faces { display: flex; }
.nd-face { width: 40px; height: 40px; margin-left: -14px; border-radius: 50%; overflow: hidden; border: 2px solid var(--panel);
  background: color-mix(in srgb, var(--c1) 18%, var(--panel)); }
.nd-face:first-child { margin-left: 0; }
.nd-face img { display: block; width: 100%; height: 100%; }
.nd-tile:hover .nd-face { transform: translateY(-2px); transition: transform 0.2s ease-out; }
.nd-tile:hover .nd-face:nth-child(2) { transition-delay: 0.04s; }
.nd-tile:hover .nd-face:nth-child(3) { transition-delay: 0.08s; }
.nd-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nd-text small { color: var(--muted); font-size: 0.875rem; line-height: 1.35; }
.nd-go { flex: none; color: var(--muted); font-size: 1.5rem; line-height: 1; }
.nd-tile:hover .nd-go { color: var(--info); }
.still .nd-tile, .still .nd-tile:hover, .still .nd-face, .still .nodrills .sync-ic { animation: none; transition: none; transform: none; }
@media (prefers-reduced-motion: reduce) { .nd-tile, .nd-tile:hover, .nd-face, .nodrills .sync-ic { animation: none; transition: none; transform: none; } }
.badge-big { display: inline-flex; align-items: center; justify-content: center; width: 56px; height: 56px; border-radius: 50%; background: color-mix(in srgb, var(--c1) 18%, var(--panel)); }
.badge-big svg { width: 32px; height: 32px; }
.badge-big .cup { fill: var(--c1); }
.badge-big .shine { stroke: #fff; stroke-width: 1.4; stroke-linecap: round; opacity: 0.6; }
.all .badge-big { background: color-mix(in srgb, var(--win) 20%, var(--panel)); }
.all .badge-big .cup { fill: var(--win); }
.plus-pitch { margin-top: 14px; padding: 10px 12px; border-radius: 8px; font-size: 0.9375rem; text-align: left; color: var(--text); background: color-mix(in srgb, var(--accent) 9%, var(--panel)); border-left: 3px solid var(--accent); }
.plus-pitch .price { color: var(--muted); }
.plus-go { display: inline-block; margin-top: 10px; padding: 7px 16px; border-radius: var(--ctl-radius); text-decoration: none; }
.moment { display: flex; gap: 12px; align-items: flex-start; margin: 10px 0 4px; padding: 10px 12px; border-radius: 8px; background: color-mix(in srgb, var(--c1) 10%, var(--panel)); border: 1px solid color-mix(in srgb, var(--c1) 40%, var(--line)); }
.moment.all { background: color-mix(in srgb, var(--win) 10%, var(--panel)); border-color: color-mix(in srgb, var(--win) 40%, var(--line)); }
.moment .badge-big { flex: none; width: 44px; height: 44px; }
/* badges an answer earned (drill_badges.py), under the verdict */
.badge-moment { margin: 10px 0 4px; padding: 10px 12px; border-radius: 8px; background: color-mix(in srgb, var(--c1) 10%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--c1) 40%, var(--line)); }
.badge-moment .ln-kick { display: block; margin-bottom: 8px; font-weight: 800; font-size: 0.8125rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--c1); }
.badge-moment .badge-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; }
.moment .badge-big svg { width: 26px; height: 26px; }
.moment b { font-size: 1rem; }
.moment .plus-pitch { margin-top: 8px; }
/* Plus offered once under an answer (progress.js offerHtml): a card of its own, lit in the look's colours */
.offer {
  position: relative; overflow: hidden; isolation: isolate; margin: 14px 0 4px; padding: 14px 16px 12px;
  border-radius: var(--card-radius); border: 1px solid color-mix(in srgb, var(--accent) 50%, var(--line));
  background: color-mix(in srgb, var(--accent) 8%, var(--panel));
  box-shadow: 0 0 calc(22px * var(--glow)) color-mix(in srgb, var(--accent) 28%, transparent);
}
.offer-glow {  /* a soft light in the look's two colours, behind the words */
  position: absolute; inset: -60% -20%; z-index: -1; pointer-events: none;
  background: radial-gradient(closest-side at 18% 40%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
    radial-gradient(closest-side at 86% 60%, color-mix(in srgb, var(--accent-2) 20%, transparent), transparent 70%);
}
.offer p { margin: 0 0 6px; }
.offer .offer-head { font: var(--display-weight) 1.125rem / 1.3 var(--font-display); }
.offer .offer-head b { color: var(--accent); font-variant-numeric: tabular-nums; }
.offer .offer-price { color: var(--muted); font-size: 0.9375rem; }
.offer .offer-go { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin: 10px 0 0; }
.offer .offer-go .button-link { padding: 8px 18px; font-weight: 700; text-decoration: none; }
.offer .offer-no { padding: 7px 14px; color: var(--muted); background: none; border-color: transparent; box-shadow: none; }
.offer .offer-no:hover { color: var(--text); border-color: var(--ctl-line); }

/* ---------- a new player's wait for their first drills, and their first drill ---------- */
.s-status:has(.waitcard, .readycard, .nodrills) { padding: 0; border: 0; background: none; box-shadow: none; backdrop-filter: none; }
.waitcard, .readycard {
  max-width: 28.75rem; margin: 0 auto; padding: 22px 24px; text-align: center; border-radius: 12px;
  background: var(--panel); border: 1px solid var(--line); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.waitcard h3, .readycard h3 { margin: 10px 0 2px; font-size: 1.3125rem; }
.ring { position: relative; width: 120px; height: 120px; margin: 0 auto; }
.ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 9; }
.ring .track { stroke: var(--line); }
.ring .fill { stroke: var(--info); stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 97; transition: stroke-dashoffset 1.4s linear, stroke 0.4s; }
.waitcard.ready .ring .fill { stroke: var(--win); transition: stroke-dashoffset 0.6s ease-out, stroke 0.4s; }
.ring-text { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.1; }
.ring-text b { font-size: 1.875rem; font-variant-numeric: tabular-nums; }
.ring-text span { font-size: 0.8125rem; color: var(--muted); }
.waitcard.ready .ring-text b { color: var(--win); }
.waitcard .place { margin: 0 0 12px; font-weight: 600; color: var(--info); display: inline-block; }
.steps { list-style: none; margin: 0 auto 12px; padding: 0; display: grid; gap: 6px; text-align: left; max-width: 21.25rem; }
.steps li { display: flex; align-items: center; gap: 10px; color: var(--muted); }
.steps li i { flex: none; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--line); display: flex; align-items: center; justify-content: center; }
.steps li.now { color: var(--text); font-weight: 600; }
.steps li.now i { border-color: var(--info); border-top-color: transparent; animation: spin 0.9s linear infinite; }
.steps li.done i { border-color: var(--win); background: var(--win); }
.steps li.done i::after { content: ""; width: 5px; height: 9px; margin-top: -2px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.waitcard .tip { min-height: 2.9em; margin: 6px 0; padding: 8px 12px; border-radius: 8px; font-size: 0.9375rem; background: color-mix(in srgb, var(--info) 8%, var(--panel)); }
.readycard .bframe { --bs: min(260px, 70vw); width: fit-content; margin: 12px auto 8px; }
.readycard .mini-game { margin: 4px 0 12px; }
.readycard .foot { margin: 10px 0 0; }
.readycard .foot .spinner { margin-right: 6px; }
/* on the drill's board while it waits: the board grows to fit, like the done card */
.board.resting .waitcard { animation: card-in 0.4s ease-out; }

/* ---------- drill: the game it comes from, and the replay into it ---------- */
.dgame { margin: 0 0 10px; padding: 8px 12px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; transition: border-color 0.3s, box-shadow 0.3s; }
.dgame.replay { border-color: var(--info); box-shadow: 0 0 0 3px color-mix(in srgb, var(--info) 18%, transparent); }
.dgame-head { font-size: 1rem; }
.dgame-sub { font-size: 0.875rem; color: var(--muted); }
.dgame-sub .when { color: var(--text); }
.dgame-sub .id { margin-left: 4px; font-size: 0.8125rem; opacity: 0.75; white-space: nowrap; }
.dgame-moves { display: flex; flex-wrap: wrap; gap: 2px 4px; margin-top: 6px; font-size: 0.9375rem; font-variant-numeric: tabular-nums; }
.dgame-moves .lm { padding: 0 5px; border-radius: 4px; white-space: nowrap; }
.dgame-moves .lm i { font-style: normal; color: var(--muted); margin-right: 3px; }
.dgame-moves .lm.ahead { visibility: hidden; }  /* still to be played: keeps its place, so nothing jumps */
.dgame-moves .lm.now, .dgame-moves .lm.last { background: var(--last); }
.dgame-moves .lm.now i, .dgame-moves .lm.last i { color: inherit; opacity: 0.7; }
.dgame-moves .lm.now { animation: lead-in 0.25s ease-out; }
.dgame-moves .lm.you { font-weight: 700; color: var(--accent); }
.dgame-moves .lm.later { opacity: 0.45; }  /* looking back (drill.js lookAt): the moves after the one shown */
.dgame-moves.pick .lm { cursor: pointer; }
.dgame-moves.pick .lm:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
@keyframes lead-in { from { transform: translateY(-4px) scale(1.15); } }
.boardcol { position: relative; }
/* in the name bar under the board, at the right, clear of the pieces */
.replaying {
  position: absolute; right: 0; bottom: 3px; z-index: 4; height: calc(var(--strip) - 6px);
  display: flex; align-items: center; padding: 0 10px; border-radius: 999px;
  background: #2f6fd0; color: #fff; font-size: 0.8125rem; font-weight: 600;
  white-space: nowrap; pointer-events: none; animation: pill-in 0.3s ease-out;
}
@keyframes pill-in { from { opacity: 0; transform: translateY(4px); } }
@media (max-width: 500px) { .replaying .wide { display: none; } }

/* ---------- a lesson going back to an earlier position (lesson.js showRewind) ----------
   A badge drops in over the top of the board ("Back to 7.Re1"), its arrows tugging left, while the board takes the
   look's tint (--rewind-tint) and the moves run backwards. Each look dresses it its own way (looks.css). */
.rewind {  /* over the name bar above the board, so it hides no piece while they run back */
  position: absolute; left: 50%; top: calc(var(--strip) / 2); z-index: 6; transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 8px; padding: 7px 16px 7px 11px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); font-weight: 700; font-size: 0.9375rem; white-space: nowrap;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); pointer-events: none;
}
.rewind[hidden] { display: none; }
.rewind svg { width: 20px; height: 20px; fill: currentColor; flex: none; }
.rewind.go { animation: rewind-in 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.25); }
.rewind.go svg { animation: rewind-tug 0.34s ease-in-out infinite; }
@keyframes rewind-in { from { opacity: 0; transform: translate(-50%, -50%) translateY(-10px) scale(0.85); } }
@keyframes rewind-tug { 50% { transform: translateX(-4px); } }
/* a lesson: the drill's own cards above it (the editions, the heading and streaks, progress, Plus, the rating, the
   prompt) fold away until it closes (lesson.js openLesson), so its words and its Back and Next sit in view beside the
   board without scrolling (Troy, 2026-11-08). The game it came from stays, on a big screen: it's the spark. */
#drill.in-lesson #d-editions, #drill.in-lesson .dhead, #drill.in-lesson #d-progress, #drill.in-lesson #d-legend,
#drill.in-lesson #d-plan, #drill.in-lesson #d-level, #drill.in-lesson #d-prompt { display: none; }
#drill.in-lesson #d-lesson { animation: lesson-in 0.3s ease-out both; }
@keyframes lesson-in { from { opacity: 0; transform: translateY(8px); } }
.still #drill.in-lesson #d-lesson { animation: none; }
@media (prefers-reduced-motion: reduce) { #drill.in-lesson #d-lesson { animation: none; } }
/* ... and should a long lesson still run past the window's foot, the board stays in view while it scrolls */
@media (min-width: 901px) { #drill.in-lesson .boardwrap { position: sticky; top: 12px; } }
/* on a narrow screen its words sit under the board, so the moves can be watched while reading: the game folds too */
@media (max-width: 900px) { #drill.in-lesson #d-game { display: none; } }
#d-board { transition: filter 0.25s ease; }
#d-board.rewinding { filter: var(--rewind-tint, saturate(0.5) brightness(0.92)); }

/* ---------- drill: an answer being checked ---------- */
.note.checking { display: flex; align-items: center; gap: 10px; color: var(--muted); border-left-color: var(--info); }
.note.checking.waiting { border-left-color: var(--c1); }  /* the server is away: the move waits (net.js) */
.note.checking.waiting b { color: var(--text); }
.note.failed { border-left-color: var(--c2); }  /* the answer couldn't be checked: the board is back to try again */
.spinner {
  width: 16px;
  height: 16px;
  flex: none;
  border: 2px solid var(--line);
  border-top-color: var(--info);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- answer verdicts: banner, note edge and board marker share one colour per grade ---------- */
.v-best, .v-good { --verdict: var(--win); }
.v-slip, .v-inaccuracy { --verdict: var(--c1); }
.v-mistake { --verdict: var(--c2); }
.v-blunder { --verdict: var(--c3); }
.note[class*="v-"] { border-left-color: var(--verdict); }
.note p { margin: 6px 0 0; }
.verdict { display: flex; align-items: center; gap: 10px; color: var(--verdict); font-size: 1.4375rem; font-weight: 700; line-height: 1.2; }
.verdict .vmark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 38px;
  padding: 0 8px;
  border-radius: 19px;
  background: var(--verdict);
  color: var(--on-accent);
  font-size: 1.1875rem;
}
.veffect { margin-top: 2px; font-weight: 600; }
/* the why under the verdict (drill.js whyHtml): the idea's chip, then what the game move allowed or missed */
.why {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin-top: 10px;
  padding: 9px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--verdict, var(--accent)) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--verdict, var(--accent)) 30%, transparent);
}
.why p { margin: 0; flex: 1 1 14em; font-weight: 600; }
.why .idea-chip { flex: none; }
.why .why-more { flex-basis: 100%; margin: 0; font-weight: 400; font-size: 0.9375rem; }
/* two sentences: today's answer, when it was a different wrong move, over the game move's (whyHtml) */
.why .why-row { display: flex; align-items: center; gap: 6px 10px; flex: 1 1 100%; }
.why .why-row + .why-row {
  padding-top: 8px;
  border-top: 1px solid color-mix(in srgb, var(--verdict, var(--accent)) 22%, transparent);
}
.sq .badge {
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 4;  /* over a piece an arrow starts from (.piece.over) */
  min-width: calc(var(--bs) / 8 * 0.36);
  height: calc(var(--bs) / 8 * 0.36);
  padding: 0 3px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--verdict);
  color: #fff;
  font: 700 calc(var(--bs) / 8 * 0.2) / 1 system-ui, sans-serif;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  pointer-events: none;
}
.sq .badge { animation: badge-in 0.4s cubic-bezier(0.3, 1.6, 0.5, 1) both; }  /* a grade lands with a pop (setBadge: once) */
@keyframes badge-in { from { transform: scale(0.2); opacity: 0; } 70% { transform: scale(1.18); opacity: 1; } to { transform: scale(1); } }
.still .sq .badge { animation: none; }

/* ---------- game viewer: your own moves and the engine's lines ---------- */
.var, .engine { background: var(--panel); border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; margin-bottom: 10px; }
.var { border-left: 3px solid var(--info); }
.var-head, .engine-head { display: flex; align-items: center; gap: 8px; font-size: 0.875rem; color: var(--muted); margin-bottom: 4px; }
.var-head b, .engine-head b { color: var(--text); }
.var-head button { margin-left: auto; }
.engine-head .small { margin-left: auto; }
.var-moves { display: flex; flex-wrap: wrap; gap: 2px; }
.var-moves .vm { padding: 1px 6px; border-radius: 4px; cursor: pointer; white-space: nowrap; }
.var-moves .vm:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.var-moves .vm.cur { background: var(--accent); color: var(--on-accent); }
.var-moves .vm i { font-style: normal; font-weight: 700; color: var(--verdict); margin-left: 2px; }
.var-moves .vm.cur i { color: var(--on-accent); }
.lines { min-height: calc(3 * 1.7em); }
.lines .line { display: flex; gap: 8px; align-items: center; padding: 1px 4px; border-radius: 4px; line-height: 1.7em; cursor: pointer; }
.lines .line:hover, .lines .line:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.lines .line.over { cursor: default; font-weight: 600; }
.lines .ev {
  flex: none; min-width: 54px; padding: 0 4px; border-radius: 4px; text-align: center;
  font-weight: 700; font-variant-numeric: tabular-nums; background: var(--line);
}
.lines .ev.up { background: var(--win); color: var(--on-accent); }
.lines .ev.down { background: var(--loss); color: var(--on-accent); }
.lines .pv { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spinner.sm { width: 11px; height: 11px; display: inline-block; vertical-align: middle; }

/* ---------- the names in an uploaded PGN file (the "Bring in your games" page: start.css) ---------- */
.name-list { display: grid; gap: 4px; max-height: 260px; overflow-y: auto; }
.name-list .name { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 8px; font-size: 0.9375rem; color: var(--text); cursor: pointer; }
.name-list .name:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.name-list .name .muted { margin-left: auto; font-size: 0.8125rem; }
.name-list input { accent-color: var(--accent); width: 16px; height: 16px; padding: 0; }
.whose { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 2px 0 8px; }
.whose button { padding: 3px 10px; font-size: 0.875rem; }
.whose button.linkish { padding: 0; border: 0; background: none; box-shadow: none; color: var(--muted); text-decoration: underline; font-weight: 500; }

/* ---------- Stats (stats.js) ---------- */
.st-filters { display: flex; flex-wrap: wrap; gap: 10px 18px; margin: 4px 0 16px; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { padding: 5px 13px; border-radius: 999px; font-size: 0.9375rem; }
.chip .n { color: var(--muted); font-weight: 500; font-size: 0.8125rem; margin-left: 2px; }
.chip.on { color: var(--nav-active-fg); background: var(--nav-active-bg); box-shadow: var(--nav-active-shadow); border-color: transparent; }
.chip.on .n { color: inherit; opacity: 0.75; }
.st-body { display: grid; gap: 16px; transition: opacity 0.2s; }
.st-body.loading { opacity: 0.55; }  /* the old numbers stay while new ones load */
.st-grid { display: grid; gap: 16px; }
.st-grid.two { grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
.st-grid.tiles { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: 12px; }
.st-card, .tile { min-width: 0; padding: 14px 16px; }
.st-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 16px; margin-bottom: 10px; }
.st-head h2 { font-size: 1.1875rem; margin: 0; }
.st-chart { min-width: 0; }
.st-chart.scroll { overflow-x: auto; }
.st-none { margin: 12px 0; }
.st-empty { padding: 28px; text-align: center; }
.tile { display: grid; gap: 4px; align-content: start; }
.t-label { font-size: 0.8125rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.t-value { font: var(--display-weight) 2.125rem/1.1 var(--font-display); }
.t-value .delta { font: 700 0.9375rem var(--font-body); vertical-align: 6px; }
.delta.up { color: var(--win); } .delta.down { color: var(--loss); }
.t-sub { font-size: 0.875rem; color: var(--muted); }
.spark { width: 100%; height: 28px; }
.spark path { fill: none; stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
/* a win / draw / loss bar: thin in rows and tiles, tall with its shares in it */
.seg { display: flex; gap: 2px; width: 100%; overflow: hidden; }
.seg.thin { height: 8px; border-radius: 999px; }
.seg.tall { height: 28px; }
.seg span { min-width: 3px; display: flex; align-items: center; }
.seg.tall span { border-radius: 4px; }
.seg.tall i { font-style: normal; font-size: 0.8125rem; font-weight: 700; padding: 0 7px; color: var(--on-accent); white-space: nowrap; }
.wdl-w { background: var(--win); fill: var(--win); } .wdl-d { background: var(--muted); fill: var(--muted); } .wdl-l { background: var(--loss); fill: var(--loss); }
.cbar { display: grid; gap: 6px; margin-bottom: 12px; }
.cb-head { display: flex; align-items: center; gap: 8px; font-weight: 600; }
.cb-head .muted { font-weight: 400; font-size: 0.875rem; }
.cb-head b { margin-left: auto; font: var(--display-weight) 1.3125rem var(--font-display); }
.chip-piece { width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--muted); }
.chip-piece.w { background: #f2f2f2; } .chip-piece.b { background: #2a2a2a; }
.legend-row { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 0.875rem; color: var(--muted); }
.legend-row .key { display: inline-flex; align-items: center; gap: 6px; }
.legend-row button.key { padding: 2px 8px; border-radius: 999px; font-size: 0.875rem; font-weight: 500; color: var(--muted); background: none; border: 1px solid transparent; box-shadow: none; }
.legend-row button.key:hover { border-color: var(--card-line); }
.legend-row button.key.off { opacity: 0.4; }
.legend-row button.key.off .lk { border-top-style: dotted; }
.legend-row .sw { width: 10px; height: 10px; border-radius: 2px; }
.lk { display: inline-block; width: 14px; height: 0; border-top: 3px solid; border-radius: 2px; }
.lk.alt { opacity: 0.55; }
.s-rapid { --s: var(--s-rapid); } .s-blitz { --s: var(--s-blitz); } .s-classical { --s: var(--s-classical); }
.s-daily { --s: var(--s-daily); } .s-bullet { --s: var(--s-bullet); }
.lk[class*="s-"] { border-color: var(--s); }
.lk.wdl-w { border-color: var(--win); background: none; } .lk.wdl-d { border-color: var(--muted); background: none; } .lk.wdl-l { border-color: var(--loss); background: none; }
/* the charts */
.chart { display: block; max-width: none; overflow: visible; font-family: var(--font-body); }
.chart .grid { stroke: var(--line); stroke-width: 1; }
.chart .grid.mid { stroke: var(--muted); opacity: 0.6; }
.chart .axis { fill: var(--muted); font-size: 0.75rem; }
.chart .line { fill: none; stroke: var(--s); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart .line.thin { stroke-width: 1.5; opacity: 0.6; }
.chart .alt { opacity: 0.55; }
.chart .area { fill: var(--s); opacity: 0.1; stroke: none; }
.chart .end, .chart .dot, .chart .peak { fill: var(--s); stroke: var(--card-solid); stroke-width: 2; }
.chart .endlabel { fill: var(--text); font-size: 0.8125rem; font-weight: 700; }
.chart .peaklabel { fill: var(--muted); font-size: 0.75rem; font-weight: 600; }
.chart .cross { stroke: var(--muted); stroke-width: 1; }
.chart .col { transition: filter 0.15s; }
.chart .col.few { opacity: 0.35; }
.chart .col.on { filter: brightness(1.25); }
.chart .hit { fill: transparent; cursor: default; }
[data-look="arcade"] .chart .line { filter: drop-shadow(0 0 4px var(--s)); }
.st-tip { position: fixed; z-index: 1600; pointer-events: none; min-width: 120px; padding: 8px 10px; border-radius: 10px;
  background: var(--card-solid); border: 1px solid var(--card-line); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); font-size: 0.875rem; }
.st-tip .tt-title { color: var(--muted); font-size: 0.8125rem; margin-bottom: 4px; }
.st-tip .tt-row { display: flex; align-items: center; gap: 7px; white-space: nowrap; }
.st-tip .tt-row b { font-variant-numeric: tabular-nums; }
/* how games end: losses to the left, wins to the right */
.ends { display: grid; gap: 7px; }
.ends-head, .end-row { display: grid; grid-template-columns: 1fr 118px 1fr; align-items: center; gap: 10px; }
.ends-head { font-size: 0.8125rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.ends-head span:first-child { text-align: right; }
.end-row .what { text-align: center; font-size: 0.9375rem; font-weight: 600; }
.end-row .side { display: flex; align-items: center; gap: 6px; }
.end-row .side.lost { justify-content: flex-end; }
.end-row .bar { height: 14px; min-width: 2px; }
.end-row .lost .bar { border-radius: 4px 0 0 4px; transform-origin: right; }
.end-row .won .bar { border-radius: 0 4px 4px 0; transform-origin: left; }
.end-row .v { font-size: 0.875rem; font-variant-numeric: tabular-nums; color: var(--muted); }
.draws { margin: 10px 0 0; }
@media (max-width: 480px) { .ends-head, .end-row { grid-template-columns: 1fr 92px 1fr; } .end-row .what { font-size: 0.8125rem; } }
/* a year of days */
.heat .cell { fill: var(--line); }
.heat .cell.h0 { fill: color-mix(in srgb, var(--line) 60%, transparent); }
.cell.h1 { fill: color-mix(in srgb, var(--accent) 28%, var(--card-solid)); background: color-mix(in srgb, var(--accent) 28%, var(--card-solid)); }
.cell.h2 { fill: color-mix(in srgb, var(--accent) 52%, var(--card-solid)); background: color-mix(in srgb, var(--accent) 52%, var(--card-solid)); }
.cell.h3 { fill: color-mix(in srgb, var(--accent) 76%, var(--card-solid)); background: color-mix(in srgb, var(--accent) 76%, var(--card-solid)); }
.cell.h4 { fill: var(--accent); background: var(--accent); }
.heat .cell:hover { stroke: var(--text); stroke-width: 1.5; }
.heat-key { display: flex; align-items: center; gap: 4px; justify-content: flex-end; margin-top: 6px; }
.heat-key i { width: 11px; height: 11px; border-radius: 3px; }
/* openings and best wins */
.olist, .wlist { display: grid; gap: 2px; }
.orow, .wrow { display: grid; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 8px; text-align: left; color: var(--text); text-decoration: none;
  background: none; border: 0; box-shadow: none; font: inherit; }
.orow { grid-template-columns: minmax(0, 1fr) 44px minmax(60px, 120px) 40px; }
@media (max-width: 480px) { .orow { grid-template-columns: minmax(0, 1fr) 34px 54px 36px; gap: 8px; } .t-value { font-size: 1.75rem; } }
.orow:hover, .wrow:hover, .orow:focus-visible, .wrow:focus-visible { background: color-mix(in srgb, var(--accent) 10%, transparent); box-shadow: none; }
.oname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.ogames, .oscore { font-variant-numeric: tabular-nums; text-align: right; font-size: 0.9375rem; }
.ogames { color: var(--muted); }
.wrow { grid-template-columns: 24px minmax(0, 1fr) auto; }
.wrow .rank { font: var(--display-weight) 1.0625rem var(--font-display); color: var(--muted); text-align: center; }
.wrow .wname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wrow .welo { font: var(--display-weight) 1.1875rem var(--font-display); color: var(--accent); }

/* ---------- surfaces: every card-like box in the look's own (looks.css) ---------- */
.level, .dgame, .note, .lesson, .engine, .var, .moves, .review, .graph, .report, .plan-note, .s-status, .waitcard, .donecard,
.readycard, .panel, .toast, dialog, .tablewrap, details.danger, .st-card, .tile, .st-empty, .s-pgn, .s-pgn-done {
  background: var(--card-bg);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  backdrop-filter: var(--card-blur);
}
.panel, .toast, dialog { background: var(--card-solid); }  /* over other things: solid */
.note { border-left-width: 4px; }
.note[class*="v-"] { border-left-color: var(--verdict); }
.note.checking { border-left-color: var(--info); }
.lesson, .plan-note { border-left: 4px solid var(--accent); }
.plan-note { background: color-mix(in srgb, var(--accent) 9%, var(--card-solid)); }
.var { border-left: 4px solid var(--info); }
.toast { border-left: 4px solid var(--tk); }
.tablewrap { padding: 4px 6px; }

/* ---------- the game viewer's way back to the list ---------- */
.backlink {
  display: inline-flex; align-items: center; gap: 6px; margin: 0 0 8px; padding: 3px 13px 3px 9px; border-radius: 999px;
  font-size: 0.875rem; font-weight: 700; text-decoration: none; color: var(--muted);
  border: 1px solid var(--ctl-line); background: var(--ctl-bg); transition: color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.backlink span { font-size: 1.1875rem; line-height: 0.8; transition: transform 0.15s; }
.backlink:hover { color: var(--text); border-color: var(--accent); box-shadow: var(--ctl-hover); }
.backlink:hover span { transform: translateX(-3px); }

/* ---------- "How it works" and "Tips": the page's small print, folded away until asked for ---------- */
details.howto { margin-top: 14px; border: 1px dashed var(--card-line); border-radius: var(--card-radius); background: color-mix(in srgb, var(--panel) 35%, transparent); }
details.howto summary {
  display: flex; align-items: center; gap: 9px; padding: 8px 14px; border-radius: inherit; list-style: none; cursor: pointer;
  font-size: 0.875rem; font-weight: 700; color: var(--muted); user-select: none;
}
details.howto summary::-webkit-details-marker { display: none; }
details.howto summary::before {  /* a chevron that turns down when it opens */
  content: ""; flex: none; width: 6px; height: 6px; margin: 0 2px 0 1px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg); transition: transform 0.2s;
}
details.howto[open] summary::before { transform: rotate(45deg); }
details.howto summary:hover { color: var(--text); }
details.howto > p { margin: 0 14px 10px; }
details.howto[open] > p { animation: howto-in 0.25s ease-out; }
@keyframes howto-in { from { opacity: 0; transform: translateY(-4px); } }
.still .toast, .still details.howto[open] > p { animation: none; }  /* Animation off: they just appear (the toast's time line still runs) */

/* ---------- the key that presses a button, printed on it (KEY_HINTS in app.js): only with a keyboard and mouse ---------- */
kbd.hint { display: none; }
@media (hover: hover) and (pointer: fine) {
  kbd.hint {
    display: inline-block; min-width: 0; margin-left: 7px; padding: 0 5px; vertical-align: 1px;
    font: 600 0.71875rem/1.55 var(--font-mono); color: inherit; opacity: 0.6;
    background: color-mix(in srgb, currentColor 10%, transparent); border: 1px solid color-mix(in srgb, currentColor 35%, transparent); border-radius: 4px;
  }
}

/* ---------- the lesson's steps as dots (renderLessonDots in lesson.js) ---------- */
.ldots { display: inline-flex; align-items: center; gap: 6px; margin: 0 4px; }
.ldots.count { min-width: 7ch; justify-content: center; font-variant-numeric: tabular-nums; }  /* "9 / 14" as wide as "10 / 14": Next stays put */
.ldot {
  width: 11px; height: 11px; min-width: 0; padding: 0; border: 2px solid var(--muted); border-radius: 999px;
  background: transparent; box-shadow: none; transition: width 0.35s cubic-bezier(0.3, 1.5, 0.5, 1), background-color 0.2s, border-color 0.2s;
}
.ldot:hover { border-color: var(--accent); box-shadow: none; }
.ldot.done { background: color-mix(in srgb, var(--accent) 60%, transparent); border-color: transparent; }
.ldot.now { width: 28px; background: var(--accent); border-color: var(--accent); box-shadow: 0 0 calc(12px * var(--glow)) var(--accent); cursor: default; }

/* ---------- deleting an account: the button lights up red once the name typed matches ---------- */
details.danger button:not(:disabled) { background: color-mix(in srgb, var(--loss) 16%, transparent); box-shadow: 0 0 calc(16px * var(--glow)) color-mix(in srgb, var(--loss) 40%, transparent); }

/* ---------- on a phone: the drill's buttons stay at the foot of the screen, under the thumb ---------- */
@media (max-width: 900px) {
  #d-controls {
    position: sticky; bottom: 0; z-index: 30; margin: 10px -16px 0; padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
    background: var(--header-bg); backdrop-filter: var(--header-blur); -webkit-backdrop-filter: var(--header-blur);
    border-top: 1px solid var(--header-line); box-shadow: 0 -10px 26px rgba(0, 0, 0, 0.2);
  }
  #d-controls:not(:has(> :not([hidden]))) { display: none; }  /* nothing to press: no empty bar */
  #d-controls button { padding: 8px 14px; }
  #d-controls #d-next { flex: 1 1 auto; }
  body:has(#drill:not([hidden])) #toasts { bottom: 88px; }  /* toasts sit above the bar, not over Next */
  body:has(#drill:not([hidden])) .install-hint { bottom: 88px; }  /* ... and so does "Add to your home screen" */
}

/* Learn's refresh (learn.js finishRefresh, the map's button): passed lessons' questions back, mixed */
.ln-refresh { margin-left: 8px; }
@media (max-width: 600px) { .ln-refresh { margin: 8px 0 0; } }
.ln-refresh > span { display: inline-block; margin-right: 2px; }
.ln-refreshed { list-style: none; padding: 0; margin: 12px auto; max-width: 28em; text-align: left; }
.ln-refreshed li { display: flex; gap: 8px; align-items: baseline; padding: 4px 0; }
.ln-refreshed li.ok > span:first-child { color: var(--win); }
.ln-refreshed li.miss > span:first-child { color: var(--c1); }

/* a run of days being mended (progress.js renderStreaks, streaks.py) */
.streak.mend { color: var(--c1); font-weight: 600; }
.streak.mend b { color: var(--text); }

/* "What did it miss?" in a lesson (lesson.js showChoose): three reasons, one right */
.l-choose { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
.l-choose-hold { height: 44px; margin: 12px 0 0; }
.l-reason.right { border-color: var(--win); color: var(--win); font-weight: 700; }
.l-reason.wrong { border-color: var(--c3); color: var(--c3); }
.l-reason.faded { opacity: 0.55; }
.l-reason-said { flex-basis: 100%; margin: 2px 0 0; font-weight: 600; color: var(--muted); }
.l-reason-said.right { color: var(--win); }
