/* App-only lesson player and completion, from the owner's supplied screens.
   The existing board, hints, grading and review controls remain interactive. */
html.chessterApp.appTrainer { background: #fff8f0; color-scheme: light; }
.chessterApp.appTrainer body.puzzles-page {
  --font-display: 'Baloo 2', 'Nunito', system-ui, sans-serif;
  --font-body: 'Nunito', system-ui, sans-serif;
  --text: #272420;
  --text-dim: #625f5a;
  margin: 0; background: #fff8f0; color: #272420;
  font: 400 16px/1.5 'Nunito', system-ui, sans-serif;
  -webkit-tap-highlight-color: transparent;
}
.appTrainer *, .appTrainer *::before, .appTrainer *::after { box-sizing: border-box; }
.appTrainer [hidden] { display: none !important; }
.chessterApp.appTrainer .appHostBar,
.chessterApp.appTrainer #siteHeader,
.chessterApp.appTrainer #siteFooter,
.appTrainer .pageIntro, .appTrainer #sidebar,
.appTrainer #filterBanner, .appTrainer #recoBanner,
.appTrainer .puzzles-signoff, .appTrainer .board-heading,
.appTrainer .puzzle-coach, .appTrainer .puzzle-details,
.appTrainer #prevBtn { display: none !important; }
.chessterApp.appTrainer body.puzzles-page main {
  display: flex; flex-direction: column; align-items: stretch;
  width: 100%; max-width: 430px; min-height: 100vh; min-height: 100svh;
  margin: 0 auto; padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-left), env(safe-area-inset-right))
    max(24px, env(safe-area-inset-bottom)); background: none;
}
.appTrainer .appTrainerHeader { margin: 0 0 22px; }
.appTrainer .appTrainerTop { display: flex; align-items: center; gap: 8px; min-height: 44px; margin-bottom: 12px; }
.appTrainer .appTrainerClose {
  display: grid; place-items: center; flex: 0 0 36px; width: 36px; height: 44px;
  margin-left: -8px; color: #625f5a; text-decoration: none;
}
.appTrainer svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; vertical-align: middle; }
.appTrainer .appTrainerTitle { min-width: 0; flex: 1; font: 800 20px/1.2 'Baloo 2', 'Nunito', sans-serif;
  letter-spacing: -.015em; overflow-wrap: anywhere; }
.appTrainer .appTrainerCount { color: #625f5a; font-weight: 800; white-space: nowrap; font-variant-numeric: tabular-nums; }
.appTrainer .appTrainerProgress { height: 8px; overflow: hidden; border-radius: 99px; background: #e8e7df; }
.appTrainer .appTrainerProgress > span { display: block; height: 100%; width: 0; border-radius: inherit; background: #58cc02; }
.appTrainer .appTrainerPrompt { margin: 0 0 20px; font: 800 21px/1.25 'Baloo 2', 'Nunito', sans-serif; letter-spacing: -.015em; }
.chessterApp.appTrainer #layout { display: block; width: 100%; margin: 0; }
.chessterApp.appTrainer #puzzleCard,
.chessterApp.appTrainer .puzzles-page.dailyMode #puzzleCard {
  display: block; width: 100%; padding: 0; margin: 0; border: 0; border-radius: 0; background: none; box-shadow: none;
}
.chessterApp.appTrainer .board-panel,
.chessterApp.appTrainer .puzzles-page.dailyMode .board-panel { width: 100%; max-width: none; margin: 0; }
.appTrainer .board-frame { width: 100%; padding: 0; border: 0; border-radius: 11px; overflow: hidden; box-shadow: 0 8px 20px #412c171c; }
.chessterApp.appTrainer #board { width: 100%; max-width: none; margin: 0; border-radius: 0; }
.appTrainer #board .white-1e1d7 { background: #f0d9b5; }
.appTrainer #board .black-3c85d { background: #b68b64; }
.appTrainer #board .notation-322f9 { display: none; }
.appTrainer .board-instruction { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.appTrainer .appTrainerContext { margin-top: 16px; padding: 16px; border: 1px solid #f0dcc7; border-radius: 17px; background: #fff; }
.appTrainer .appTrainerContext h2 { margin-bottom: 6px; font: 800 18px/1.3 'Baloo 2', 'Nunito', sans-serif; }
.appTrainer .appTrainerContext p { color: #44413d; font-size: 16px; line-height: 1.5; }
.appTrainer .appTrainerActions { margin-top: auto; padding-top: 30px; }
.appTrainer #controls { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 0; padding: 0; border: 0; }
.appTrainer .navGroup { display: none; }
.appTrainer #controls .pressBtn,
.appTrainer .appTrainerShowAnswer,
.appTrainer .appTrainerExplore,
.appTrainer .appTrainerButton {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-width: 0; width: 100%; min-height: 54px; padding: 12px 10px;
  border: 2px solid #e4e2dc; border-radius: 16px; background: #fff; color: #44413d;
  box-shadow: 0 2px 0 #e4e2dc; font: 800 19px/1.2 'Baloo 2', 'Nunito', sans-serif;
  text-decoration: none; text-align: center; letter-spacing: 0; text-transform: none; cursor: pointer;
}
.appTrainer #controls .pressBtn:disabled { opacity: .55; cursor: default; }
.appTrainer #hintLine { margin: 0 0 16px; padding: 12px 14px; border-radius: 12px; font-size: 15px; }
.appTrainer .appTrainerChecking { padding: 12px; text-align: center; color: #625f5a; }
.appTrainer.appTrainerGrading #controls { display: none; }
.appTrainer.appTrainerAnswered #revealBtn { display: none; }
.appTrainer.appTrainerAnswered #controls { display: block; }
.appTrainer.appTrainerAnswered .navGroup { display: block; }
.appTrainer.appTrainerAnswered #nextBtn,
.appTrainer .appTrainerPrimary {
  background: #ef6c00; color: #fff; border-color: #ef6c00; box-shadow: 0 4px 0 #b64b00;
}
.appTrainer #controls button:active, .appTrainer .appTrainerButton:active { transform: translateY(2px); box-shadow: none; }
.appTrainer #puzzleReview { margin: 16px 0 0; padding: 16px; border: 1px solid #f0dcc7; border-radius: 17px; background: #fff; box-shadow: none; }
.appTrainer #reviewVerdict { display: none; }
.appTrainer #reviewBranches { margin: 0 0 16px; }
.appTrainer #reviewTitle { font: 800 20px/1.25 'Baloo 2', 'Nunito', sans-serif; letter-spacing: 0; }
.appTrainer #puzzleReview p { font-size: 15px; line-height: 1.5; }
.appTrainer #reviewContext { display: none; }
.appTrainer #reviewContinue { display: none; }
.appTrainer #puzzleReview button { font-size: 14px; min-height: 44px; }
.appTrainer .review-playback-controls { gap: 6px; flex-wrap: wrap; }
.appTrainer #reviewPosition { font-size: 12px; }
.appTrainer #reviewMoves { flex-wrap: wrap; }
.appTrainer #reviewMoves .lineChip { min-width: 38px; }
.appTrainer #reviewRetry { display: none !important; }   /* lives in the verdict row */
.appTrainer .review-takeaway { margin-top: 14px; }
.appTrainer .review-takeaway strong { font: 800 17px/1.3 'Baloo 2', 'Nunito', sans-serif; }
.appTrainer .review-branch { flex: 1 1 90px; font: 800 13px/1.3 'Nunito', sans-serif; }
.appTrainer #reviewExplore, .appTrainer #reviewReturn { display: inline-flex; align-items: center; margin-top: 10px; }
.appTrainer .puzzles-page #briefing { padding: 20px; margin: 0 0 24px; }
.appTrainer .puzzles-page #briefing.shown ~ #layout { display: none; }
.appTrainer .puzzles-page:has(#briefing.shown) .appTrainerActions { display: none; }
.appTrainer .puzzles-page.needsAccount .puzzle-details,
.appTrainer .puzzles-page.emptyPuzzle .puzzle-details { display: block !important; }
.appTrainer .puzzles-page.needsAccount #cardBottom,
.appTrainer .puzzles-page.emptyPuzzle #cardBottom,
.appTrainer .puzzles-page.needsAccount .appTrainerActions,
.appTrainer .puzzles-page.emptyPuzzle .appTrainerActions { display: none; }
.appTrainer .puzzles-page.needsAccount #metaHeader,
.appTrainer .puzzles-page.emptyPuzzle #metaHeader { font-size: 17px; }
.appTrainerDone .appTrainerHeader, .appTrainerDone .appTrainerActions,
.appTrainerDone #briefing, .appTrainerDone #demoBannerSlot { display: none !important; }
.chessterApp.appTrainer #endCard.shown {
  display: flex; flex-direction: column; flex: 1; width: 100%; max-width: none;
  margin: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; text-align: left;
}
.appTrainer .appCompletionHero { padding-top: clamp(22px, 5svh, 44px); text-align: center; }
.appTrainer .appCompletionCat { display: block; width: 84px; height: 84px; margin: 0 auto 18px; object-fit: contain; animation: none; }
.appTrainer .appCompletionHero h1 { font: 800 32px/1.2 'Baloo 2', 'Nunito', sans-serif; letter-spacing: -.015em; margin: 0; }
.appTrainer .appCompletionSub { color: #625f5a; font-size: 16px; margin-top: 8px; }
.appTrainer .appCompletionGrades { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 22px 0 0; }
.appTrainer .appGradeTile { display: flex; flex-direction: column; justify-content: center; min-width: 0; min-height: 82px;
  padding: 13px 14px; border: 1px solid; border-radius: 16px; }
.appTrainer .appGradeTile dt { font: 800 16px/1.3 'Baloo 2', 'Nunito', sans-serif; }
.appTrainer .appGradeTile dd { order: -1; margin: 0 0 5px; font: 800 28px/1 'Baloo 2', 'Nunito', sans-serif; }
.appTrainer .appGrade-top { background: #edfbdf; color: #326b00; border-color: #b3e880; }
.appTrainer .appGrade-good { background: #dff8f5; color: #08776a; border-color: #91ded6; }
.appTrainer .appGrade-better { background: #fff7db; color: #775700; border-color: #f8d16d; }
.appTrainer .appGrade-same, .appTrainer .appGrade-new { background: #fff0f2; color: #b5282c; border-color: #ffb8bb; }
.appTrainer .appGrade-hint, .appTrainer .appGrade-revealed { background: #fff3e5; color: #8e501b; border-color: #edc99f; }
.appTrainer .appCompletionNote { margin-top: 20px; padding: 13px 14px; border: 1px solid #f0dcc7; border-radius: 16px;
  background: #fff; color: #44413d; font-size: 15px; line-height: 1.45; }
.appTrainer .appCompletionStep { display: flex; align-items: center; gap: 12px; margin-top: 20px; padding: 15px 16px;
  border: 1px solid #f0dcc7; border-radius: 18px; background: #fff; text-decoration: none; color: #272420; }
.appTrainer .appCompletionCheck { display: grid; place-items: center; flex: 0 0 32px; width: 32px; height: 32px;
  border-radius: 50%; background: #58cc02; color: #fff; }
.appTrainer .appCompletionCheck svg { width: 20px; height: 20px; stroke-width: 3; }
.appTrainer .appCompletionStep > span:nth-child(2) { flex: 1; min-width: 0; }
.appTrainer .appCompletionStep strong { display: block; font: 800 17px/1.25 'Baloo 2', 'Nunito', sans-serif; }
.appTrainer .appCompletionStep strong + span { display: block; margin-top: 2px; font-size: 13px; color: #716d66; }
.appTrainer .appCompletionArrow { color: #817870; }
.appTrainer .appCompletionArrow svg { width: 17px; height: 17px; }
.appTrainer .appCompletionActions { display: grid; gap: 12px; margin-top: auto; padding-top: 48px; }
.appTrainer .appTrainerButton { min-height: 56px; }
.appTrainer .appTrainerButton span { display: inline-flex; }
.appTrainer .appTrainerButton svg { width: 18px; height: 18px; }
/* Answer replay (answer_replay.js): the game move, then the player's move. */
.appTrainer.appTrainerReplaying #puzzleReview { display: none; }
.appTrainer[data-replay-phase] .board-frame { box-shadow: 0 0 0 4px var(--phase-colour), 0 8px 20px #412c171c; transition: box-shadow .2s; }
.appTrainer[data-replay-phase="game"] .board-frame { --phase-colour: #e5383b; }
.appTrainer[data-replay-phase="user"] .board-frame { --phase-colour: #46a302; }
.appTrainer .appTrainerPhasePop { animation: replayPop .3s cubic-bezier(.3, 1.6, .5, 1) both; }
.appTrainer #board .square-55d63 { position: relative; }
.appTrainer #board .replay-from { box-shadow: inset 0 0 0 999px #f6c94a55; }
.appTrainer #board .replay-to { box-shadow: inset 0 0 0 999px #f6c94a99; }
.appTrainer .replayBadge {
  position: absolute; top: 2px; right: 2px; z-index: 3;
  display: grid; place-items: center; width: 42%; height: 42%; min-width: 18px; min-height: 18px;
  border: 2px solid #fff; border-radius: 50%; color: #fff; box-shadow: 0 2px 4px #0004;
  font: 900 clamp(11px, 2.6vw, 16px)/1 'Nunito', sans-serif; pointer-events: none;
  animation: replayPop .28s cubic-bezier(.3, 1.6, .5, 1) both;
}
.appTrainer .replayBadge-good { background: #58cc02; }
.appTrainer .replayBadge-okay { background: #e9a400; }
.appTrainer .replayBadge-bad { background: #e5383b; }
.appTrainer .replayBadge-unknown { background: #8d867d; }
@keyframes replayPop { from { transform: scale(0); } }
.appTrainer .appTrainerVerdict { display: flex; align-items: center; gap: 12px; height: 60px; margin: 0 0 16px; }
/* After an answer the slot above the board holds either the verdict or a
   heading (the replay banners, "Your turn", "Checking"). Same height for all,
   so the board never moves under a finger that is starting a drag. */
.appTrainer.appTrainerAnswered .appTrainerPrompt { display: flex; align-items: center; height: 60px; margin: 0 0 16px; }
.appTrainer.appTrainerAnswered[data-replay-phase] .appTrainerPrompt { height: auto; min-height: 44px; margin: 8px 0 24px; }
.appTrainer .appTrainerVerdictCat { flex: 0 0 56px; width: 56px; height: 56px; object-fit: contain;
  animation: replayPop .32s cubic-bezier(.3, 1.6, .5, 1) both; }
.appTrainer .appTrainerVerdict > span { display: flex; flex-direction: column; min-width: 0; }
.appTrainer .appTrainerVerdictScore { font: 800 28px/1.05 'Baloo 2', 'Nunito', sans-serif; letter-spacing: -.015em; }
.appTrainer .appTrainerRetry {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; margin-left: auto; min-height: 44px;
  padding: 8px 14px; border: 2px solid #e4e2dc; border-radius: 14px; background: #fff; color: #44413d;
  box-shadow: 0 2px 0 #e4e2dc; font: 800 16px/1 'Baloo 2', 'Nunito', sans-serif; cursor: pointer;
}
.appTrainer .appTrainerRetry svg { width: 18px; height: 18px; }
.appTrainer .appTrainerRetry:active { transform: translateY(2px); box-shadow: none; }
.appTrainer .appTrainerVerdictLabel { color: #625f5a; font-weight: 700; font-size: 15px; }
.appTrainer .appTrainerVerdict[data-mood="thrilled"] .appTrainerVerdictScore,
.appTrainer .appTrainerVerdict[data-mood="happy"] .appTrainerVerdictScore { color: #326b00; }
.appTrainer .appTrainerVerdict[data-mood="okay"] .appTrainerVerdictScore { color: #775700; }
.appTrainer .appTrainerVerdict[data-mood="sad"] .appTrainerVerdictScore,
.appTrainer .appTrainerVerdict[data-mood="mad"] .appTrainerVerdictScore { color: #b5282c; }
.appTrainer .appTrainerCompare { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.appTrainer .appTrainerCompare:has(> [hidden]) { grid-template-columns: 1fr; }
.appTrainer .appTrainerCompareMove {
  display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 52px; padding: 8px 12px;
  border: 2px solid #e4e2dc; border-radius: 14px; background: #fff; color: #272420; box-shadow: 0 2px 0 #e4e2dc;
  font: 800 17px/1.2 'Baloo 2', 'Nunito', sans-serif; cursor: pointer; text-align: left;
}
.appTrainer .appTrainerCompareMove:active { transform: translateY(2px); box-shadow: none; }
.appTrainer .appTrainerCompareMark { display: grid; place-items: center; flex: 0 0 24px; width: 24px; height: 24px;
  border-radius: 50%; color: #fff; font: 900 13px/1 'Nunito', sans-serif; }
.appTrainer .appTrainerMark-good { background: #58cc02; }
.appTrainer .appTrainerMark-okay { background: #e9a400; }
.appTrainer .appTrainerMark-bad { background: #e5383b; }
.appTrainer .appTrainerMark-unknown { background: #8d867d; }
.appTrainer .appTrainerCompareSan { overflow-wrap: anywhere; }
.appTrainer .appTrainerCompareWho { color: #817870; font: 700 13px/1.2 'Nunito', sans-serif; }
.appTrainer .appTrainerCompareIcon { margin-left: auto; color: #817870; }
.appTrainer .appTrainerCompareIcon svg { width: 18px; height: 18px; }
@media (prefers-reduced-motion: reduce) {
  .appTrainer .replayBadge, .appTrainer .appTrainerVerdictCat, .appTrainer .appTrainerPhasePop { animation: none; }
}
@media (max-width: 350px) {
  .appTrainer .appTrainerTitle { font-size: 18px; }
  .appTrainer .appTrainerPrompt { font-size: 19px; }
  .appTrainer .appGradeTile { padding: 12px; }
  .appTrainer .appCompletionStep { padding: 14px 12px; gap: 9px; }
}
/* Lesson migration: cream, orange, warm outlines and pressed card edges.
   Existing answer replay, retry, grading and navigation states stay intact. */
.chessterApp.appTrainer body.puzzles-page main { max-width:480px; padding-top:max(30px,env(safe-area-inset-top)); }
.appTrainer .appTrainerHeader { margin-bottom:20px; }
.appTrainer .appTrainerTitle { color:#a94b03; font:900 .8125rem/1.3 'Nunito',sans-serif; letter-spacing:.12em; text-transform:uppercase; }
.appTrainer .appTrainerCount { color:#5e5b57; font-size:1rem; }
.appTrainer .appTrainerProgress { height:10px; background:#f1e3d0; }
.appTrainer .appTrainerProgress > span { background:#f97b16; }
/* Each cell reopens its position. The strip keeps its 10px look but takes taps
   9px above and below it; the cell you are on stands taller than the rest, since
   a revisited one keeps its green or red. */
.appTrainer .appTrainerProgress.appTrainerProgressSteps { display:flex; align-items:center; gap:3px; background:none; overflow:visible; box-sizing:content-box; padding:9px 0; margin:-9px 0; -webkit-tap-highlight-color:transparent; }
.appTrainer .appTrainerProgressSteps > button { flex:1; min-width:0; height:10px; padding:0; border:0; border-radius:99px; background:#f1e3d0; font:inherit; cursor:pointer; transition:background-color .25s, height .15s; }
.appTrainer .appTrainerProgressSteps > button[aria-disabled="true"] { cursor:default; }
.appTrainer .appTrainerProgressSteps > button.appTrainerStepHere { height:16px; }
.appTrainer .appTrainerProgressSteps > button:focus-visible { outline:2px solid #a94b03; outline-offset:2px; }
.appTrainer .appTrainerProgressSteps > button[data-mark="current"] { background:#f97b16; }
.appTrainer .appTrainerProgressSteps > button[data-mark="pass"] { background:#2fb14c; }
.appTrainer .appTrainerProgressSteps > button[data-mark="fail"] { background:#e5383b; }
.appTrainer .appTrainerPrompt { position:relative; min-height:84px; padding-right:90px; font-size:1.75rem; line-height:1.12; margin-bottom:20px; }
.appTrainer .appTrainerTurn,.appTrainer .appTrainerInstruction { display:block; }
.appTrainer .appTrainerInstruction { color:#f97b16; margin-top:3px; }
.appTrainer:not(.appTrainerAnswered) .appTrainerPrompt::after {
  content:''; position:absolute; top:0; right:0; width:76px; height:84px;
  border:2px solid #2b1106; border-radius:20px; box-shadow:0 3px 0 #2b1106;
  background:#ffebd2 url('/chesster-v8-reading.png') center bottom/auto 72px no-repeat;
}
.appTrainer.appTrainerAnswered .appTrainerPrompt { padding-right:0; font-size:1.3125rem; }
.appTrainer .board-frame { border:2px solid #2b1106; border-radius:15px; box-shadow:0 5px 0 #2b1106; }
.appTrainer #board .black-3c85d { background:#b58863; }
.appTrainer .appTrainerContext { display:flow-root; padding:14px; border:2px solid #2b1106; border-radius:20px; box-shadow:0 4px 0 #2b1106; }
.appTrainer .appTrainerContext::before { content:'↶'; display:grid; place-items:center; float:left; width:42px; height:44px; margin-right:12px; background:#fff0e0; border:2px solid #ffc18a; border-radius:13px; color:#a94b03; font:800 1.625rem/1 'Nunito',sans-serif; }
.appTrainer .appTrainerContext h2 { font:900 .6875rem/1.3 'Nunito',sans-serif; color:#a94b03; letter-spacing:.1em; text-transform:uppercase; }
.appTrainer .appTrainerContext p { font-weight:800; line-height:1.4; }
.appTrainer #controls .pressBtn,.appTrainer .appTrainerShowAnswer,.appTrainer .appTrainerExplore,.appTrainer .appTrainerButton {
  border:2px solid #2b1106; border-radius:16px; box-shadow:0 4px 0 #2b1106; color:#3c3a37;
  font:800 1.0625rem/1.2 'Nunito',sans-serif; letter-spacing:.045em; text-transform:uppercase;
}
.appTrainer.appTrainerAnswered #nextBtn,.appTrainer .appTrainerPrimary { background:#f97b16; border-color:#f97b16; box-shadow:0 4px 0 #cb5d07; color:#fff; }
.appTrainer #puzzleReview { border:2px solid #2b1106; border-radius:20px; box-shadow:0 4px 0 #2b1106; }
.appTrainer .appTrainerRetry,.appTrainer .appTrainerCompareMove { border-color:#2b1106; box-shadow:0 3px 0 #2b1106; border-radius:15px; }
.appTrainer .appTrainerVerdict[data-mood="thrilled"] .appTrainerVerdictScore,
.appTrainer .appTrainerVerdict[data-mood="happy"] .appTrainerVerdictScore { color:#0a6b60; }
.appTrainer .appTrainerMark-good,.appTrainer .replayBadge-good { background:#14b8a6; }
.appTrainer[data-replay-phase="user"] .board-frame { --phase-colour:#14b8a6; }
/* Completion uses the actual result counts, including hints and reveals. */
.appTrainer .appCompletionHero { padding-top:8px; text-align:left; }
.appTrainer .appCompletionScene { position:relative; height:190px; border-radius:28px; overflow:hidden; background:#ffebd2; margin-bottom:18px; }
.appTrainer .appCompletionScene::before { content:''; position:absolute; width:145%; height:170px; border-radius:50%; background:#f6cf9f; bottom:-100px; left:-18%; }
.appTrainer .appCompletionCat { position:absolute; bottom:0; left:14px; width:auto; height:174px; max-width:55%; object-fit:contain; object-position:bottom; margin:0; animation:none; }
.appTrainer .appCompletionGreeting { position:absolute; right:18px; top:36px; color:#a94b03; font:700 1.875rem/1 'Caveat',cursive; transform:rotate(5deg); }
.appTrainer .appCompletionSpark { position:absolute; color:#f5b83d; font-size:1.75rem; line-height:1; }
.appTrainer .appCompletionSparkOne { top:26px; left:50%; }
.appTrainer .appCompletionSparkTwo { top:96px; right:24px; color:#f97b16; font-size:1.125rem; }
.appTrainer .appCompletionSub { margin:0 0 8px; color:#a94b03; font:900 .8125rem/1.4 'Nunito',sans-serif; text-transform:uppercase; letter-spacing:.12em; }
.appTrainer .appCompletionHero h1 { font-size:2.125rem; line-height:1.08; color:#22211f; }
.appTrainer .appCompletionAccent { display:block; color:#f97b16; margin-top:4px; }
.appTrainer .appCompletionGrades { gap:12px; margin-top:22px; }
.appTrainer .appGradeTile { min-height:88px; padding:14px; border:2px solid #2b1106; border-radius:20px; box-shadow:0 4px 0 #2b1106; background:#fff; }
.appTrainer .appGradeTile dt { font:800 1.0625rem/1.3 'Nunito',sans-serif; }
.appTrainer .appGradeTile dd { font-size:2rem; line-height:1; margin-bottom:6px; }
.appTrainer .appGrade-top { color:#0a6b60; border-color:#0a6b60; background:#e0f7f4; box-shadow:0 4px 0 #0a6b60; }
.appTrainer .appGrade-good { color:#0a6b60; }
.appTrainer .appGrade-better { color:#765700; border-color:#8f6d00; background:#fff7db; box-shadow:0 4px 0 #8f6d00; }
.appTrainer .appGrade-same,.appTrainer .appGrade-new { color:#a42424; border-color:#a42424; background:#fff0f2; box-shadow:0 4px 0 #a42424; }
.appTrainer .appGrade-hint,.appTrainer .appGrade-revealed { color:#8e501b; border-color:#cc9d68; background:#fff3e5; box-shadow:0 4px 0 #cc9d68; }
.appTrainer .appCompletionNote { order:3; margin:12px 0 0; padding:0 2px; border:0; box-shadow:none; background:none; color:#6f6257; font-size:.8125rem; line-height:1.4; }
.appTrainer .appCompletionStep { margin-top:20px; padding:16px; border:2px solid #2b1106; border-radius:20px; box-shadow:0 4px 0 #2b1106; }
.appTrainer .appCompletionCheck { flex:0 0 40px; width:40px; height:40px; background:#14b8a6; border:2px solid #0a6b60; }
.appTrainer .appCompletionStep strong { font:900 1.0625rem/1.25 'Nunito',sans-serif; }
.appTrainer .appCompletionStep strong + span { font-size:.9375rem; font-weight:800; color:#5e5b57; }
.appTrainer .appCompletionActions { order:4; padding-top:32px; }
@media (max-width:359px) {
  .appTrainer .appTrainerPrompt { font-size:1.5rem; padding-right:78px; }
  .appTrainer:not(.appTrainerAnswered) .appTrainerPrompt::after { width:66px; height:76px; background-size:auto 64px; }
  .appTrainer .appCompletionScene { height:166px; }
  .appTrainer .appCompletionCat { height:156px; left:6px; }
  .appTrainer .appCompletionGreeting { font-size:1.625rem; right:12px; }
  .appTrainer .appGradeTile { padding:12px; }
  .appTrainer .appCompletionStep { padding:14px 12px; }
}
/* Keep the board at the same vertical position through comparison and retry. */
.appTrainer .appTrainerVerdict { height:auto; min-height:84px; margin:0 0 20px; }
.appTrainer.appTrainerAnswered .appTrainerPrompt,
.appTrainer.appTrainerAnswered[data-replay-phase] .appTrainerPrompt { height:auto; min-height:84px; margin:0 0 20px; }
.appTrainer .appCompletionCat { z-index:1; }
.appTrainer .appCompletionGreeting,.appTrainer .appCompletionSpark { z-index:2; }
html.chessterApp.appTrainer { -webkit-text-size-adjust:100%; text-size-adjust:100%; }
.appTrainer .appCompletionScene { display:flex; align-items:flex-end; isolation:isolate; }
.appTrainer .appCompletionScene::before { z-index:0; }
.appTrainer .appCompletionCat { position:relative; left:auto; bottom:auto; flex:none; margin:0 0 0 14px; }
.appTrainer .appTrainerShowAnswer,.appTrainer .appTrainerExplore { font-size:clamp(.875rem,4vw,1.0625rem); letter-spacing:.03em; }
.appTrainer #appCompletionTitle:focus { outline:none; }
.appTrainer .appTrainerGoal { min-height:40px; margin:12px 0 0; color:#625f5a; font:800 .875rem/1.4 'Nunito',sans-serif; }
.appTrainer .appCompletionScore { margin:18px 0 6px; color:#22211f; font:900 1.75rem/1.2 'Nunito',sans-serif; }
.appTrainer .appCompletionRule { margin:0; color:#625f5a; font-size:1rem; line-height:1.45; }
/* Result colours follow correctness even when an improved move earns a high score. */
.appTrainer .appTrainerVerdict[data-outcome="correct"] .appTrainerVerdictScore { color:#0a6b60; }
.appTrainer .appTrainerVerdict[data-outcome="incorrect"] .appTrainerVerdictScore { color:#a42424; }
.appTrainer .appTrainerVerdict[data-outcome="unchecked"] .appTrainerVerdictScore { color:#625f5a; }
/* "Chesster says": the why behind the move, in a card with a paw-print header. */
.appTrainer .appTrainerVerdictDetail {
  margin:16px 0 0; padding:12px 16px 14px; border:2px solid #2b1106; border-radius:18px;
  box-shadow:0 4px 0 #2b1106; background:#fff7ee;
}
.appTrainer .appTrainerVerdictDetail[hidden] { display:none; }
.appTrainer .appTrainerSaysHead {
  display:flex; align-items:center; gap:6px; margin:0 0 6px; color:var(--cat-deep, #d2761f);
  font:900 .8125rem/1 'Nunito',sans-serif; letter-spacing:.08em; text-transform:uppercase;
}
.appTrainer .appTrainerSaysHead .pawIcon { width:14px; height:14px; }
.appTrainer .appTrainerSaysHead .pawIcon:first-child { transform:rotate(-18deg); }
.appTrainer .appTrainerSaysHead .pawIcon:last-child { transform:rotate(18deg); }
.appTrainer .appTrainerSaysBody { margin:0; color:#22211f; font:700 1rem/1.45 'Nunito',sans-serif; }
.appTrainer .appTrainerSaysNote { margin:8px 0 0; color:#625f5a; font:600 .8125rem/1.4 'Nunito',sans-serif; }
.appTrainer .appTrainerSaysNote[hidden] { display:none; }
/* What the bad move cost: a modal once the replay finishes, closed only by its X. */
.appTrainerCost {
  position:fixed; inset:0; z-index:1000; display:grid; place-items:center; padding:16px;
  background:rgba(34,33,31,.55);
}
.appTrainerCost[hidden] { display:none; }
.appTrainerCostCard {
  position:relative; width:min(420px,100%); max-height:calc(100vh - 32px); overflow:auto;
  padding:26px 24px 24px; border:2px solid #2b1106; border-radius:22px; box-shadow:0 5px 0 #2b1106;
  background:#fff; color:#22211f; font-family:'Nunito',sans-serif;
}
.appTrainerCostClose {
  position:absolute; top:20px; right:20px; display:grid; place-items:center; width:36px; height:36px;
  border:2px solid #2b1106; border-radius:50%; background:#fff; color:#2b1106;
  font:900 1rem/1 'Nunito',sans-serif; cursor:pointer;
}
/* Card-scoped so page resets like `.puzzles-page h2 { margin:0 }` don't eat the gap. */
.appTrainerCostCard .appTrainerCostTitle { min-height:36px; margin:0 52px 16px 0; font:900 1.5rem/1.15 'Nunito',sans-serif; color:#a42424; }
.appTrainerCostRows { display:grid; gap:12px; }
.appTrainerCostRow {
  display:flex; align-items:flex-start; gap:14px; padding:16px 18px;
  border:2px solid #2b1106; border-radius:16px; background:#fff4f2;
}
.appTrainerCostMark {
  flex:none; display:grid; place-items:center; width:28px; height:28px; border-radius:50%;
  background:#e5383b; color:#fff; font:900 .9375rem/1 'Nunito',sans-serif;
}
.appTrainerCostCopy { display:flex; flex-direction:column; gap:4px; min-width:0; }
.appTrainerCostWho { color:#625f5a; font:800 .75rem/1.2 'Nunito',sans-serif; text-transform:uppercase; letter-spacing:.04em; }
.appTrainerCostCopy strong { font:900 1.0625rem/1.25 'Nunito',sans-serif; }
/* Two full-width boards are taller than a phone: the title and X stay put and
   only the rows scroll. dvh, so the iOS toolbar never hides the bottom. */
.appTrainerCostCard { display:flex; flex-direction:column; overflow:hidden; max-height:calc(100vh - 32px);
  max-height:min(72dvh, calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom))); }
/* A popup, not a page: clear of the notch and the home bar, lesson visible around it. */
.appTrainerCost { padding:calc(16px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right))
  calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left)); }
.appTrainerCostRows { overflow-y:auto; min-height:0; overscroll-behavior:contain; }
/* "Still confused?" -- under the rows, outside the scroll, always reachable. */
.appTrainerCostMore { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;
  margin-top:14px; padding-top:14px; border-top:2px dashed #e0c48f; }
.appTrainerCostMore p { margin:0; color:#2b2925; font:800 .9375rem/1.35 'Nunito',sans-serif; flex:1 1 180px; }
.appTrainerCostMoreButton { flex:none; min-height:44px; padding:8px 16px; border:2px solid #2b1106; border-radius:12px;
  background:#fff; color:#2b1106; box-shadow:0 3px 0 #2b1106; font:900 .9375rem/1 'Nunito',sans-serif; cursor:pointer; }
.appTrainerCostMoreButton:active { transform:translateY(2px); box-shadow:none; }
/* Each row: its label, a board of the moment it describes, then the words.
   Stacked so the board can use the card's full width. */
.appTrainerCostRow { flex-direction:column; align-items:stretch; gap:10px; padding:14px; }
.appTrainerCostHead { display:flex; align-items:center; gap:8px; }
.appTrainerCostHead .appTrainerCostMark { width:22px; height:22px; font-size:.75rem; }
.appTrainerCostCopy strong { font-size:1rem; line-height:1.3; }
.appTrainerMini { position:relative; flex:none; width:100%; max-width:240px; margin:0 auto; aspect-ratio:1; border:2px solid #2b1106; border-radius:10px; overflow:hidden; }
.appTrainerMiniGrid { display:grid; grid-template-columns:repeat(8,1fr); width:100%; height:100%; }
.appTrainerMiniGrid .sq { position:relative; background:#f0d9b5; }
.appTrainerMiniGrid .sq.dark { background:#b58863; }
.appTrainerMiniGrid .sq.mark { box-shadow:inset 0 0 0 999px rgba(245,196,87,.75); }
.appTrainerMiniGrid img { position:absolute; inset:0; width:100%; height:100%; }
/* Outranks `.appTrainer svg`, which sizes every other svg here as a 22px icon. */
.appTrainer .appTrainerMiniArrows { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; stroke-width:0; }
/* Same arrow as the main board (drawArrow in puzzles.html): one solid shape, no outline. */
.appTrainer .appTrainerMiniArrows polygon { stroke:none; opacity:.8; }
.appTrainerMini[data-tone="bad"] polygon { fill:#d62828; }
.appTrainerMini[data-tone="good"] polygon { fill:#0a8f7d; }
.appTrainerMini[data-tone="okay"] polygon { fill:#b7791f; }
@media (max-width:360px) { .appTrainerCostCard { padding:20px 14px 16px; } .appTrainerCostRow { padding:10px; } }
/* Replay buttons show the piece that moved, not its notation. */
.appTrainer .appTrainerComparePiece { width:30px; height:30px; flex:none; }
.appTrainer .appTrainerComparePiece[hidden] { display:none; }
/* Tap-to-explain: a chess word is a quiet dotted underline, and opens a card. */
.appTrainerTerm { display:inline; padding:0; border:0; background:none; color:inherit; font:inherit; text-transform:inherit; letter-spacing:inherit; cursor:pointer;
  text-decoration:underline dotted 2px; text-underline-offset:3px; text-decoration-color:#b7791f; }
.appTrainerTerm[aria-expanded="true"] { text-decoration-style:solid; background:#fdf1d6; border-radius:4px; }
.appTrainerTerm:focus-visible { outline:2px solid #b7791f; outline-offset:2px; border-radius:4px; }
.appTrainerTermCard { display:grid; gap:10px; margin:10px 0 0; padding:12px 14px; border:2px dashed #e0c48f; border-radius:14px;
  background:#fffaf0; color:#2b2925; font:700 .9375rem/1.4 'Nunito',sans-serif; }
.appTrainerTermCard p { margin:0; }
.appTrainerTermCard .appTrainerMini { max-width:180px; }
.appTrainerMini[data-tone="learn"] polygon { fill:#2f6fde; }
.appTrainer .appTrainerCompareMove .appTrainerCompareWho { color:#272420; font:800 16px/1.2 'Baloo 2','Nunito',sans-serif; }
/* A move that worked reads calm and green; a sound-but-weaker one neutral. */
.appTrainerCost[data-kind="good"] .appTrainerCostTitle { color:#0a6b60; }
.appTrainerCost[data-kind="okay"] .appTrainerCostTitle,
.appTrainerCost[data-kind="missed"] .appTrainerCostTitle { color:#2b2925; }
.appTrainerCostRow[data-tone="good"] { background:#eef9f4; }
.appTrainerCostRow[data-tone="good"] .appTrainerCostMark { background:#0a8f7d; }
.appTrainerCostRow[data-tone="okay"] { background:#fbf6ec; }
.appTrainerCostRow[data-tone="okay"] .appTrainerCostMark { background:#b7791f; }
/* Replay banners ("What you played", "Your new move"): a lesson card with a
   round mark, same outline and pressed edge as the move chips below the board. */
.appTrainer[data-replay-phase] .appTrainerPrompt {
  display:flex; align-items:center; gap:12px; width:100%; min-height:84px; margin:0 0 20px;
  padding:12px 16px; border:2px solid #2b1106; border-radius:20px; box-shadow:0 4px 0 #2b1106;
  background:#fff; color:#22211f;
}
.appTrainer[data-replay-phase] .appTrainerPrompt::before,
.appTrainer[data-replay-phase] .appTrainerPrompt::after { content:none; }
.appTrainer .appTrainerPhaseMark {
  display:grid; place-items:center; flex:0 0 40px; width:40px; height:40px; border-radius:50%;
  border:2px solid; color:#fff; font:900 1.125rem/1 'Nunito',sans-serif;
}
.appTrainer[data-replay-phase="game"] .appTrainerPhaseMark { background:#e5383b; border-color:#a42424; }
.appTrainer[data-replay-phase="user"] .appTrainerPhaseMark { background:#14b8a6; border-color:#0a6b60; }
.appTrainer .appTrainerPhaseCopy { display:flex; flex-direction:column; min-width:0; }
.appTrainer .appTrainerPhaseEyebrow { font:900 .6875rem/1.3 'Nunito',sans-serif; letter-spacing:.1em; text-transform:uppercase; }
.appTrainer[data-replay-phase="game"] .appTrainerPhaseEyebrow { color:#a42424; }
.appTrainer[data-replay-phase="user"] .appTrainerPhaseEyebrow { color:#0a6b60; }
.appTrainer[data-replay-phase="best"] .board-frame { --phase-colour:#f59f00; }
.appTrainer[data-replay-phase="best"] .appTrainerPhaseMark { background:#f59f00; border-color:#b07200; }
.appTrainer[data-replay-phase="best"] .appTrainerPhaseEyebrow { color:#8e5a00; }
/* Lessons review on the board, not in text: the review panel stays hidden and
   Show answer + Explore sit under the replay chips. */
.appTrainer #puzzleReview { display:none !important; }
.appTrainer .appTrainerAnswerRow { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:12px; }
.appTrainer .appTrainerAnswerRow[hidden] { display:none; }
.appTrainer.appTrainerReplaying .appTrainerAnswerRow { visibility:hidden; }
.appTrainer.appTrainerExploring .appTrainerAnswerRow { grid-template-columns:1fr; }
.appTrainer.appTrainerExploring .appTrainerVerdictDetail,
.appTrainer.appTrainerExploring .appTrainerCompare,
.appTrainer.appTrainerExploring .appTrainerAnswerRow .appTrainerShowAnswer { display:none !important; }
.appTrainer .appTrainerEval { display:flex; align-items:center; gap:12px; margin-top:14px; }
.appTrainer .appTrainerEval[hidden] { display:none; }
.appTrainer .appTrainerEval #evalBarContainer { flex:1 1 auto; height:12px; border:2px solid #2b1106; border-radius:8px; }
.appTrainer .appTrainerEval #evalLabel { min-width:4ch; color:#2b1106; font:800 1.0625rem/1 'Nunito',sans-serif; text-align:right; }
.appTrainer .appTrainerEval #exploreSteps { order:-1; display:flex; gap:8px; margin:0; }
.appTrainer .appTrainerEval #exploreSteps[hidden] { display:none; }
.appTrainer .appTrainerEval #exploreSteps .toggleBtn { width:44px; height:40px; margin:0; padding:0; border:2px solid #2b1106; border-radius:12px; box-shadow:0 3px 0 #2b1106; background:#fff; color:#2b1106; font:800 1.25rem/1 'Nunito',sans-serif; cursor:pointer; }
.appTrainer .appTrainerEval #exploreSteps .toggleBtn:disabled { opacity:.4; cursor:default; }
.appTrainer .appTrainerPhaseTitle { margin-top:2px; font:800 1.375rem/1.15 'Baloo 2','Nunito',sans-serif; letter-spacing:-.015em; overflow-wrap:anywhere; }
@media (max-width:359px) {
  .appTrainer .appTrainerPhaseTitle { font-size:1.1875rem; }
  .appTrainer .appTrainerVerdictScore { font-size:24px; }
  .appTrainer .appTrainerRetry { padding:8px; font-size:14px; }
}

/* The position's pattern, shown once the first move is in. */
.appTrainer .appTrainerPattern { display:flex; align-items:baseline; flex-wrap:wrap; gap:4px 8px; margin:0 0 10px;
  color:#2b2925; font:800 .9375rem/1.3 'Nunito',sans-serif; }
.appTrainer .appTrainerPattern span { color:#8e5a00; font:900 .6875rem/1.3 'Nunito',sans-serif; letter-spacing:.1em; text-transform:uppercase; }

/* --- board effects (board_fx.js) ------------------------------------------
   The gliding copy lifts and casts a shadow; a knight hops. jQuery moves its
   top/left, so transforms here never fight the slide. */
.appTrainer body > img.fxGlide {
  animation: fxLift var(--fx-ms, 300ms) cubic-bezier(.3, .7, .4, 1) both;
  will-change: transform, filter;
}
.appTrainer body > img.fxGlide.fxKnight { animation-name: fxHop; }
.appTrainer body > img.fxGlide.fxHeavy { animation-name: fxLiftHeavy; }
@keyframes fxLift {
  0% { transform: scale(1); filter: drop-shadow(0 0 0 #3a241200); }
  45% { transform: scale(1.12); filter: drop-shadow(0 6px 5px #3a24124d); }
  100% { transform: scale(1); filter: drop-shadow(0 1px 1px #3a241226); }
}
@keyframes fxHop {
  0% { transform: translateY(0) scale(1); filter: drop-shadow(0 0 0 #3a241200); }
  50% { transform: translateY(-30%) scale(1.14); filter: drop-shadow(0 14px 7px #3a241238); }
  100% { transform: translateY(0) scale(1); filter: drop-shadow(0 1px 1px #3a241226); }
}
@keyframes fxLiftHeavy {
  0% { transform: scale(1); filter: drop-shadow(0 0 0 #3a241200); }
  55% { transform: scale(1.24); filter: drop-shadow(0 12px 9px #3a241259); }
  100% { transform: scale(1); filter: drop-shadow(0 1px 1px #3a241226); }
}

/* Landing: a small squash and settle on the real piece. */
.appTrainer #board img.fxLand { position: relative; z-index: 1; animation: fxSettle 190ms ease-out; }
.appTrainer #board img.fxLandHard { animation: fxSettleHard 280ms ease-out; }
@keyframes fxSettle { 0% { transform: scale(1.06); } 55% { transform: scale(.96); } 100% { transform: scale(1); } }
@keyframes fxSettleHard { 0% { transform: scale(1.2); } 45% { transform: scale(.9); } 75% { transform: scale(1.03); } 100% { transform: scale(1); } }

/* A capture: the taken piece pops off its square over a quick flash. */
.appTrainer #board .fxCaptured, .appTrainer #board .fxFlash, .appTrainer #board .fxCheck {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
}
.appTrainer #board .fxCaptured {
  background: center / contain no-repeat;
  animation: fxPop 360ms cubic-bezier(.2, .8, .3, 1) forwards;
}
.appTrainer #board .fxFlash {
  background: radial-gradient(circle, #fff6 0, #ffc95a80 32%, #ffc95a00 70%);
  animation: fxFade 420ms ease-out forwards;
}
@keyframes fxPop {
  0% { transform: scale(1) rotate(0); opacity: 1; }
  100% { transform: scale(1.45) rotate(-14deg); opacity: 0; }
}
@keyframes fxFade { 0% { opacity: 1; transform: scale(.6); } 100% { opacity: 0; transform: scale(1.25); } }

/* Check: one red pulse under the king. */
.appTrainer #board .fxCheck {
  background: radial-gradient(circle, #e5484d99 0, #e5484d55 40%, #e5484d00 72%);
  animation: fxCheck 900ms ease-out forwards;
}
@keyframes fxCheck { 0% { opacity: 0; transform: scale(.5); } 25% { opacity: 1; transform: scale(1.1); } 100% { opacity: 0; transform: scale(1); } }

/* The move that costs the material: the whole board takes the hit. */
.appTrainer .board-frame.fxShake { animation: fxShake 420ms cubic-bezier(.36, .07, .19, .97); }
@keyframes fxShake {
  0%, 100% { transform: translate(0, 0); }
  15% { transform: translate(-5px, 2px); }
  30% { transform: translate(5px, -2px); }
  45% { transform: translate(-4px, 1px); }
  60% { transform: translate(3px, -1px); }
  80% { transform: translate(-1px, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .appTrainer body > img.fxGlide, .appTrainer #board img.fxLand, .appTrainer .board-frame.fxShake { animation: none; }
}
