/* Learning Curve — Learn / lesson player / match step / code exercise / checkpoint /
   Practice / Drill / Quiz / exam, in the Chunky Play design. Loaded after ui.css (which is
   loaded after styles.css), so a selector here wins the cascade over both without needing
   extra specificity. Every colour is a ui.css --c-* token; nothing is hard-coded here, so
   every palette falls out of the same rules. Nothing under 12px. */

/* ---- two alignment helpers the shared primitives don't have yet ---- */
.ui-title.center { text-align: center; }
.ui-sub.center { text-align: center; margin-left: auto; margin-right: auto; }

/* ================= Learn (renderCourse): folder tabs, phase hero, continue card ================= */
.lrn-page { max-width: 1100px; }
/* folder-tab phase switcher: every tab in its phase colour; the current one is taller and
   joins the hero below (the row overlaps the hero's top edge by one border width) */
.ftabs {
  display: flex; align-items: flex-end; padding: 8px 6px 0 9px; margin: 0 -6px calc(-1 * var(--c-bw));
  position: relative; z-index: 2; overflow-x: auto; overflow-y: hidden;
}
.ft {
  flex: 1 0 auto; height: 44px; display: grid; place-items: center; padding: 0 7px 2px; margin: 0 0 var(--c-bw) -2.5px;
  border: var(--c-bw) solid var(--c-line); border-bottom: 0; border-radius: 10px 10px 0 0;
  background: var(--pc); color: var(--c-on-color); font: 800 12.5px/1 var(--sans); letter-spacing: -.01em;
  white-space: nowrap; text-decoration: none; position: relative;
}
.ft.on { height: calc(52px + var(--c-bw)); margin-bottom: 0; font-size: 13.5px; padding-bottom: 6px; z-index: 3; }
.ft:hover { text-decoration: none; }
/* a focused tab rises above its neighbours; the ring is inset (so .ftabs' overflow cannot
   clip it) and ink (so it reads on every phase colour, >= 5.97:1 in every palette) */
.ft:focus-visible { z-index: 4; outline: 3px solid var(--c-on-color); outline-offset: -6px; }
.ft-full { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* narrow phones: the tightest tabs (up to 409px). Seven short tabs used to fit a 390px window; with
   Quantum and the Cert Exams tab (nine tabs, 12px text being the floor) the row is about 60px too wide
   below ~460px, so it scrolls sideways with its slim themed scrollbar (never hidden), and app.js
   centerCurrentTab() brings the current tab into view on every render */
@media (max-width: 409px) {
  .ft { padding: 0 4px 2px; font-size: 12px; }
  .ft.on { font-size: 12.5px; }
}
@media (max-width: 339px) {
  .ftabs { padding-left: 7px; }
  .ft { padding: 0 2px 2px; }
}
@media (min-width: 900px) {
  .ft { padding: 0 8px 2px; font-size: 13px; }
  .ft.on { font-size: 14px; }
}
/* short names at every width: the full names of nine tabs need about 1160px of row, more than the
   1100px Learn page ever gives (they switched on from 1360px while there were seven, and already
   overflowed with eight). The full name stays each tab's accessible name (.ft-full, visually hidden),
   and from ~460px up the row fits without scrolling (tools/smoke.js measures it at 1280px). */
/* the phase hero, filled with the phase colour. Both top corners sit under a folder tab
   (the tabs always fill the row), so both are square-ish; only the bottom ones round. */
.ui-card.phero {
  background: var(--pc); color: var(--c-on-color); border-radius: 6px 6px 20px 20px;
  padding: 12px 14px 13px; position: relative; z-index: 1;
}
/* on a phase fill the blue ring can sit at 1.1:1 (LLMs): ink reads on every phase */
.phero :focus-visible { outline-color: var(--c-on-color); }
/* wide desktops: the continue card sits beside the title instead of under it */
@media (min-width: 1100px) {
  .ui-card.phero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, 440px); column-gap: 28px; align-items: start; }
  .phero > :not(.lrn-cont) { grid-column: 1; }
  .phero .lrn-cont { grid-column: 2; grid-row: 1 / span 2; align-self: end; margin-top: 0; max-width: none; }
}
/* the title block, and beside it (an unstarted phase only: .phero.has-mascot) the mascot reading */
.phero-top { display: flex; align-items: flex-start; gap: 10px; }
.phero-text { flex: 1; min-width: 0; }
.phero-top .mascot { width: 104px; height: 104px; margin: -2px -6px -8px 0; }
/* phones: only the label and the title sit beside a smaller mascot; the tagline runs the full
   width under both (beside an 84px mascot all three lost ~88px, so "Data Science & ML" left
   "ML" alone on a line and the hero grew ~75px) */
@media (max-width: 899px) {
  .phero.has-mascot .phero-top { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; align-items: center; }
  .phero.has-mascot .phero-text { display: contents; }
  .phero.has-mascot .phero-top .ui-label, .phero.has-mascot .phero-title { grid-column: 1; }
  .phero.has-mascot .phero-tag { grid-column: 1 / -1; }
  .phero.has-mascot .phero-top .mascot { grid-column: 2; grid-row: 1 / span 2; width: 64px; height: 64px; margin: -4px -6px -2px 0; }
}
/* wide desktops: the mascot perches above the Start card in the right column, grouped with it,
   and the title keeps the whole left column */
@media (min-width: 1100px) {
  .phero.has-mascot { grid-template-areas: "text mascot" "prog card"; }
  .phero.has-mascot .phero-top { display: contents; }
  .phero.has-mascot .phero-text { grid-area: text; }
  .phero.has-mascot .phero-top .mascot { grid-area: mascot; justify-self: end; align-self: end; margin: -6px 10px 4px 0; }
  .phero.has-mascot .phero-prog { grid-area: prog; align-self: end; }
  .phero.has-mascot .lrn-cont { grid-area: card; align-self: end; }
}
.phero .ui-label { color: var(--c-on-color); }
.phero-title { font: 800 var(--fs-display)/1.05 var(--sans); letter-spacing: -.02em; margin: 3px 0 5px; color: var(--c-on-color); text-wrap: balance; }
.phero-tag { font: 400 15px/1.35 var(--sans); margin: 0; max-width: 60ch; }
.phero-prog { display: flex; align-items: center; gap: 10px; margin-top: 10px; font: 400 14px/1.3 var(--sans); white-space: nowrap; max-width: 560px; }
.phero-prog b { font: 700 13px var(--mono); }
.phero .segbar { --seg-line: var(--c-on-color); --seg-bg: var(--c-on-color-bg); border-color: var(--c-on-color); }
.phero .segbar i { background: var(--c-on-color); }
/* continue / start-here card inside the hero, with a round go-blue play key */
.lrn-cont {
  display: flex; align-items: center; gap: 12px; margin-top: 12px; padding: 8px 12px 8px 10px; max-width: 560px;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-on-color); border-radius: 14px;
  box-shadow: 0 4px 0 var(--c-on-color); text-decoration: none; transition: transform .08s ease, box-shadow .08s ease;
}
.lrn-cont:hover { text-decoration: none; }
.lrn-cont:active { transform: translateY(2px); box-shadow: 0 2px 0 var(--c-on-color); }
/* the ring comes from its own token pair (ui.css): a palette can set its own, where one shared
   ring on the raised card would vanish (themes.css) */
.lrn-cont .playkey { background: var(--c-go); color: var(--c-on-go); border-color: var(--c-go-ring); box-shadow: 0 3px 0 var(--c-go-ring-sh); }
.lrn-cont-main { flex: 1; min-width: 0; }
.lrn-cont .ui-label { color: var(--c-muted); display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrn-cont-title { display: block; font: 800 16px/1.15 var(--sans); margin: 1px 0 6px; letter-spacing: -.01em; }
.pbar { display: flex; align-items: center; gap: 8px; }
.pbar .ui-bar { flex: 1; }
.pbar b { font: 700 13px var(--mono); }

/* ================= Lesson player (renderPlayer) =================
   Mock: a square back key, the phase dot and module name, a steps key with the module's %;
   step blocks for the current section with "SECTION · STEP n / N"; the step title with a
   rotated tag sticker; a docked footer Back · note · Next. */
.player, .lrn-player { max-width: 760px; margin: 0 auto; }
.lrn-topbar { display: flex; align-items: center; gap: 12px; min-height: 48px; margin-bottom: 16px; }
/* the square back key (the class name predates the square) */
.lrn-back-circle {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center; border-radius: 13px;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-line);
  box-shadow: var(--c-sh-key); text-decoration: none; transition: transform .08s ease, box-shadow .08s ease;
  -webkit-tap-highlight-color: transparent;
}
.lrn-back-circle:hover { text-decoration: none; }
.lrn-back-circle svg { width: 20px; height: 20px; stroke-width: 2.8; }
.lrn-topbar-title {
  flex: 1; min-width: 0; margin: 0; display: flex; align-items: center; justify-content: center; gap: 7px;
  font: 700 13px/1.25 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--c-ink);
}
.lrn-topbar-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the exam review's position ("Review · 3 of 18 missed") wraps to a second line on a narrow phone
   rather than losing its count and filter to an ellipsis */
.lrn-topbar-text.cx-revpos { white-space: normal; text-overflow: clip; text-align: center; overflow-wrap: anywhere; }
.lrn-steps-btn {
  flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 11px 0 10px;
  border-radius: 13px; cursor: pointer; background: var(--c-raised); color: var(--c-ink);
  border: var(--c-bw) solid var(--c-line); box-shadow: var(--c-sh-key);
  font: 700 13px/1 var(--mono); transition: transform .08s ease, box-shadow .08s ease;
  -webkit-tap-highlight-color: transparent;
}
.lrn-steps-btn span { font: 700 13px/1 var(--mono); }
@media (hover: hover) {
  .lrn-back-circle:hover, .lrn-steps-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); }
}
.lrn-back-circle:active, .lrn-steps-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--c-slab); }

/* step blocks (.lrn-secbar > .lrn-seg, a ui.css primitive) and the label row under them */
.lrn-secwrap { margin-bottom: 18px; }
/* a one-step section: a single half-filled block read as "50% done", so it stays empty and
   "STEP 1 / 1" carries the position */
.lrn-secbar.solo > .lrn-seg.current { background: var(--c-raised); }
.lrn-seclabel { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin: 10px 0 0; }
.lrn-secname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrn-secpos { flex: none; white-space: nowrap; }

/* the title row: step title, then the tag sticker ("MATCH · ~3 MIN") */
.lrn-stephead { margin-bottom: 16px; }
.lrn-titlerow { display: flex; align-items: center; justify-content: space-between; gap: 10px 12px; flex-wrap: wrap; }
.lrn-stephead .step-title { font: 800 var(--fs-title)/1.1 var(--sans); letter-spacing: -.02em; color: var(--c-ink); margin: 0; min-width: 0; text-wrap: balance; }
.lrn-steptag { flex: none; margin-right: 3px; }

.lrn-body { display: block; }
.stage, .lrn-stage { min-width: 0; }
/* room for the docked footer and the tab bar under it */
.lrn-stage { padding-bottom: calc(var(--ui-tabbar-h, 0px) + var(--ui-safe-b) + 120px); }
.step-content { min-height: 200px; }
.step-content > .widget-sub { margin-top: 4px; }
.lrn-stage pre { max-width: 100%; overflow-x: auto; }

/* ---- the step list: behind the steps key at EVERY width, never a permanent column (the
   lesson keeps the whole player width). A bottom SHEET on a phone; from 700px a right-side
   DRAWER over a dimmed backdrop (see the 700px block below). Hidden (visibility, not just
   moved) while closed, so its links are out of the tab order off screen. It slides in only
   when motion is allowed; under reduced motion it simply appears. ---- */
.lrn-stepsheet-backdrop {
  position: fixed; inset: 0; z-index: 70; background: var(--c-scrim); opacity: 0; pointer-events: none;
}
.lrn-stepsheet-panel {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 71; max-height: 82vh; max-height: 82dvh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--c-card); border-top: var(--c-bw) solid var(--c-line); border-radius: 20px 20px 0 0;
  padding: 20px 0 var(--ui-safe-b);
  transform: translateY(105%); visibility: hidden;
}
.lrn-stepsheet-panel::before {   /* grab handle */
  content: ""; position: absolute; top: 8px; left: 50%; width: 40px; height: 5px; margin-left: -20px;
  border-radius: 3px; background: var(--c-line);
}
.lrn-stepsheet.open .lrn-stepsheet-backdrop { opacity: 1; pointer-events: auto; }
.lrn-stepsheet.open .lrn-stepsheet-panel { transform: none; visibility: visible; }
/* while the list is open the page behind it is locked (app.js stepsLock): no wheel-scrolling
   the lesson through the backdrop, and no page scrollbar left undimmed beside the drawer's.
   The body is padded by the scrollbar's width (--lc-sbw, measured on open) so the page does
   not shift under the scrim; the phone's docked footer is fixed, so it gets the same pad. */
html.lc-steps-open { overflow: hidden; }
html.lc-steps-open body { padding-right: var(--lc-sbw, 0px); }
@media (max-width: 899px) { html.lc-steps-open .lrn-stepfoot { padding-right: calc(16px + var(--lc-sbw, 0px)); } }
@media (prefers-reduced-motion: no-preference) {
  .lrn-stepsheet-backdrop { transition: opacity .18s ease; }
  .lrn-stepsheet-panel { transition: transform .22s cubic-bezier(.2, .8, .3, 1), visibility 0s linear .22s; }
  .lrn-stepsheet.open .lrn-stepsheet-panel { transition: transform .22s cubic-bezier(.2, .8, .3, 1), visibility 0s; }
}
/* head: "ALL STEPS" · the module name · a bar and "n / N done" · the close key */
.lrn-stepsheet-head {
  flex: none; display: flex; align-items: flex-start; gap: 12px;
  padding: 2px 16px 14px 20px; border-bottom: var(--c-bw-sm) solid var(--c-line-soft);
}
.lrn-stepsheet-titles { flex: 1; min-width: 0; }
.lrn-stepsheet-kicker { display: flex; align-items: center; gap: 7px; color: var(--c-muted); }
.lrn-stepsheet-title { margin: 5px 0 9px; font: 800 20px/1.15 var(--sans); letter-spacing: -.015em; color: var(--c-ink); text-wrap: balance; }
.lrn-stepsheet-prog { display: flex; align-items: center; gap: 10px; margin: 0; }
.lrn-stepsheet-prog .ui-bar { flex: 1; max-width: 180px; }
.lrn-stepsheet-count { font: 700 12.5px/1.2 var(--mono); color: var(--c-ink-2); white-space: nowrap; }
.lrn-stepsheet-close {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center; border-radius: 13px; cursor: pointer;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-line); box-shadow: var(--c-sh-key);
}
.lrn-stepsheet-close svg { stroke-width: 2.8; }
@media (hover: hover) { .lrn-stepsheet-close:hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); } }
.lrn-stepsheet-close:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--c-slab); }
/* the list scrolls (positioned: app.js scrolls it by offsetTop); the gutter is kept so opening
   a section never shifts the rows sideways */
.stepper {
  position: relative; list-style: none; margin: 0; padding: 8px 8px 20px 12px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable;
}
/* one collapsible group per section: a header key (chevron · name · done/total) over its steps */
.stepper-group { margin: 0; padding: 0; }
.stepper-group + .stepper-group { border-top: var(--c-bw-sm) solid var(--c-line-soft); }
.stepper-group-head {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; margin: 3px 0;
  padding: 8px 10px 8px 8px; border: 0; border-radius: 10px; background: none; cursor: pointer; text-align: left;
  font: 700 12.5px/1.3 var(--mono); letter-spacing: .05em; text-transform: uppercase; color: var(--c-ink);
  -webkit-tap-highlight-color: transparent;
}
/* hover only where there is a real pointer: on a touch screen the row last tapped kept its
   raised background and read as the current row */
@media (hover: hover) { .stepper-group-head:hover { background: var(--c-raised); } }
/* the section you are in, folded: the current step's raised box on its header (line and hard
   shadow drawn inset/outside so the row keeps its size), so folding it never hides where you
   are. Open, the highlighted step inside it already says so. */
.stepper-group.current > .stepper-group-head[aria-expanded="false"] {
  background: var(--c-raised); box-shadow: inset 0 0 0 var(--c-bw-sm) var(--c-line), var(--c-sh-sm);
}
/* the list scrolls, so an outside ring would be clipped at its edges: draw it inside */
.stepper-group-head:focus-visible { outline-offset: -3px; }
.stepper-group-head > svg { flex: none; width: 18px; height: 18px; stroke-width: 2.8; }
.stepper-group-head[aria-expanded="true"] > svg { transform: rotate(90deg); }
@media (prefers-reduced-motion: no-preference) { .stepper-group-head > svg { transition: transform .15s ease; } }
.stepper-group-name { flex: 1; min-width: 0; }
.stepper-group-count {
  position: relative; flex: none; display: inline-flex; align-items: center; gap: 7px;
  font: 400 12.5px/1.3 var(--mono); letter-spacing: 0; text-transform: none; color: var(--c-muted);
}
/* a finished section: the green done box before its count (green = done, nothing else);
   ::before is the box, ::after the CSS check drawn on it (the step boxes' treatment) */
.stepper-group.done .stepper-group-count::before {
  content: ""; width: 16px; height: 16px; flex: none; box-sizing: border-box;
  border: var(--c-bw-sm) solid var(--c-line); border-radius: 5px; background: var(--c-ok);
}
.stepper-group.done .stepper-group-count::after {
  content: ""; position: absolute; left: 6px; top: calc(50% - 6px); width: 4px; height: 8px;
  border: solid var(--c-on-color); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.stepper-group-list { list-style: none; margin: 0 0 10px; padding: 0 0 0 28px; }
.stepper-group-list[hidden] { display: none; }
/* each row is an <li class="stepper-row"> holding a real link, a.stepper-item (app.js): the
   title on its own line (two at most), the type and minutes under it */
.stepper-row { margin: 0; padding: 0; }
.stepper-item {
  display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; grid-template-areas: "dot title title" "dot type min";
  column-gap: 10px; row-gap: 2px; align-items: center;
  min-height: 48px; margin: 2px 2px 2px 0; padding: 6px 10px 6px 6px; border: var(--c-bw-sm) solid transparent; border-radius: 10px;
  cursor: pointer; font: 500 14.5px/1.3 var(--sans); color: var(--c-ink-2); text-decoration: none;
}
.stepper-item:hover { text-decoration: none; }
@media (hover: hover) { .stepper-item:hover { background: var(--c-raised); } }
.stepper-item:focus-visible { outline-offset: -3px; }
.stepper-item.current {
  background: var(--c-raised); border-color: var(--c-line); box-shadow: var(--c-sh-sm); color: var(--c-ink); font-weight: 700;
}
.stepper-item.optional { color: var(--c-muted); }
/* done boxes, the rail's treatment: a square with a CSS check, never a glyph */
.stepper-dot {
  grid-area: dot; align-self: start; margin-top: 1px;
  position: relative; width: 16px; height: 16px; border-radius: 5px; font-size: 0;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-raised);
}
.stepper-item.done .stepper-dot { background: var(--c-ok); }
.stepper-item.done .stepper-dot::after {
  content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
  border: solid var(--c-on-color); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.stepper-title {
  grid-area: title; min-width: 0; overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
}
.stepper-type {
  grid-area: type; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 700 12px/1.2 var(--mono); letter-spacing: .04em; text-transform: uppercase; color: var(--c-muted);
}
.stepper-min { grid-area: min; font: 400 12px/1.2 var(--mono); color: var(--c-muted); white-space: nowrap; }

/* ---- footer: "‹ Back · note · Next ›". Docked above the tab bar on a phone; the ground
   colour fills the strip under and around the bar, so lesson text never shows between. ---- */
.lrn-stepfoot {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  background: var(--c-ground); border-top: var(--c-bw) solid var(--c-line);
  padding: 10px 16px calc(10px + var(--ui-tabbar-h, 0px) + var(--ui-safe-b));
}
.lrn-stepfoot-row { display: flex; align-items: center; gap: 10px; max-width: 760px; margin: 0 auto; }
.lrn-stepfoot-center { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; }
.lrn-stepfoot-note { font: 400 14px/1.25 var(--sans); color: var(--c-muted); max-width: 22ch; }
.lrn-stepfoot-note:empty { display: none; }
.lrn-stepfoot .lrn-stepfoot-back, .lrn-stepfoot .lrn-stepfoot-next { flex: none; min-height: 48px; padding: 0 16px; }
/* Back is a SECONDARY key even though it carries the ghost classes */
.lrn-stepfoot .lrn-stepfoot-back {
  background: var(--c-raised); color: var(--c-ink); border-color: var(--c-line);
  box-shadow: var(--c-sh-key); text-decoration: none;
}
@media (hover: hover) {
  .lrn-stepfoot .lrn-stepfoot-back:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); text-decoration: none; }
}
.lrn-stepfoot .lrn-stepfoot-back:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--c-slab); }
.lrn-stepfoot .lrn-stepfoot-back:disabled {
  background: var(--c-dis-bg); border-color: var(--c-dis-line); color: var(--c-dis-ink); box-shadow: none; transform: none;
}
.lrn-stepfoot .lrn-stepfoot-skip { min-height: 36px; padding: 0 6px; font: 700 14px/1.2 var(--sans); position: relative; }
.lrn-stepfoot .lrn-stepfoot-skip::after { content: ""; position: absolute; inset: -4px 0; }   /* a 44px hit area */
.lrn-stepfoot-skip[hidden] { display: none; }

/* from 700px the step list is a right-side DRAWER: full height, a card with the 2.5px line
   and a hard shadow on its open (left) edge, sliding in from the right */
@media (min-width: 700px) {
  .lrn-stepsheet-panel {
    top: 0; right: 0; bottom: 0; left: auto; width: min(420px, calc(100vw - 64px)); max-height: none;
    border-top: 0; border-left: var(--c-bw) solid var(--c-line); border-radius: 0;
    box-shadow: -4px 0 0 var(--c-slab); padding: 16px 0 0;
    transform: translateX(calc(100% + 12px));
  }
  .lrn-stepsheet-panel::before { display: none; }
  .lrn-stepsheet-head { padding: 2px 16px 16px 22px; }
  .stepper { padding: 10px 10px 24px 14px; }
}
/* desktop: no step column any more, so the lesson takes the whole player, centred. 720px keeps
   the ~595px prose measure (styles.css, about 70-75 characters a line) filling most of the
   column so it still reads as centred; widgets, code and tables use the full 720 */
@media (min-width: 900px) {
  .player, .lrn-player { max-width: 720px; }
  .lrn-stage { padding-bottom: 0; }
  .lrn-stepfoot { position: static; margin-top: 28px; padding: 16px 0 0; background: transparent; }
  .lrn-stepfoot-row { max-width: none; }
  .lrn-stepfoot-note { max-width: 30ch; }
}

/* ================= Worked examples (app.js "worked examples": .wx steppers, .why-steps) =================
   A lesson's worked example and "Your turn" are plain HTML (<div class="wx" data-wx>); app.js enhances them
   into steppers. Colors come only from ui.css tokens, in pairs the app already proves AA in all three looks:
   ink on card / raised / recess, on-fill on fill (the sticker label), ok-ink on ok-wash, bad on bad-wash.
   Nothing under 12 px. Without .is-live (no script, or the enhancer rolled back) NOTHING is hidden: the
   stepper reads as a complete worked example, and only the tap checks stay out of sight. Every rule is
   scoped by .wx, so the same block works in a lesson, a read step and an exercise's walkthrough. */
.wx {
  background: var(--c-card); color: var(--c-ink);
  border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-md); box-shadow: var(--c-sh-sm);
  padding: 14px 16px 16px; margin: 0 0 1.3em; max-width: min(68ch, calc(var(--fs-prose) * 35)); min-width: 0;
}
.wx > :last-child { margin-bottom: 0; }
/* the enhancer hides with the hidden attribute; no display rule below may win over it */
.wx [hidden] { display: none !important; }
.wx p { margin: 0 0 .6em; max-width: none; }
.wx .wx-head { font: 800 17px/1.3 var(--sans); color: var(--c-ink); }
.wx .wx-label {
  display: block; width: -moz-fit-content; width: fit-content; margin: 0 0 8px;
  font: 700 12px/1.3 var(--mono); letter-spacing: .06em; text-transform: uppercase;
  background: var(--c-fill); color: var(--c-on-fill); border-radius: 6px; padding: 2px 8px 3px;
  transform: rotate(-2deg);
}
.wx .wx-given { color: var(--c-ink); }
/* the steps: a counted list; each step is one line of work and a "why" under it */
.wx .wx-steps { list-style: none; counter-reset: wx; margin: 10px 0 12px; padding: 0; max-width: none; }
.wx .wx-step {
  counter-increment: wx; position: relative; margin: 0 0 10px; padding: 0 0 0 40px; min-height: 30px; min-width: 0;
  scroll-margin-block: 12px 76px;                          /* keeps the controls under a revealed step in view */
}
.wx .wx-step::before {
  content: counter(wx); position: absolute; left: 0; top: 0; width: 28px; height: 28px;
  display: grid; place-items: center; border-radius: 8px;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-raised); color: var(--c-ink);
  font: 700 13px/1 var(--mono);
}
.wx .wx-step:focus, .wx .wx-result:focus { outline: none; }
.wx .wx-step:focus-visible, .wx .wx-result:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; border-radius: 8px; }
.wx .wx-work { font: 600 16px/1.5 var(--sans); color: var(--c-ink); margin: 0 0 4px; overflow-wrap: anywhere; }
.wx .wx-why {
  font: 400 15px/1.5 var(--sans); color: var(--c-ink); margin: 0;
  background: var(--c-recess); border: 1.5px solid var(--c-line-soft); border-radius: 10px; padding: 6px 10px;
}
/* a walkthrough's work line is code: the code slate, one short line that scrolls rather than wraps */
.wx pre.wx-work {
  background: var(--c-code-bg); color: var(--c-code-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 10px;
  box-shadow: none; padding: 7px 12px; font: 400 13.5px/1.55 var(--code); white-space: pre; overflow-x: auto;
  overflow-wrap: normal; max-width: 100%; tab-size: 4;
}
.wx .wx-why-label { font-weight: 700; }
.wx pre.wx-work code { background: none; border: 0; padding: 0; font: inherit; color: inherit; }
.wx .wx-result { font-weight: 700; color: var(--c-ink); }
/* the tap check inside a step: out of sight until the enhancer runs */
.wx .wx-check { display: none; }
.wx.is-live .wx-check { display: block; margin: 0 0 6px; }
.wx .wx-ask { font-weight: 700; margin: 0 0 6px; }
/* the question takes focus when its step comes out (app.js); "Just show me this step" sits after the options */
.wx .wx-ask:focus { outline: none; }
.wx .wx-ask:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; border-radius: 6px; }
.wx .wx-check .wx-skip { min-height: 44px; padding: 0 6px; margin: 0 0 4px -6px; }
.wx .wx-check .wx-hintbtn { min-height: 44px; padding: 0 6px; margin: 0 8px 4px -6px; }
.wx .wx-check .wx-hintbtn[aria-disabled="true"] { opacity: .75; cursor: default; }
/* graduated hints: plain paragraphs (labelled "Hint:" when the enhancer has not run), then a gentle callout */
.wx .wx-hints { margin: 0 0 6px; display: grid; gap: 6px; }
.wx .wx-hint {
  margin: 0; font: 400 14.5px/1.45 var(--sans); padding: 6px 10px; border-radius: 10px;
  border: var(--c-bw-sm) solid var(--c-line-soft); background: var(--c-recess); color: var(--c-ink);
}
.wx .wx-hint[hidden] { display: none; }
.wx:not(.is-live) .wx-hint::before { content: "Hint: "; font-weight: 700; }
.wx .wx-hintlab { font: 700 12px var(--mono); letter-spacing: .06em; }
.wx .wx-opts { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 8px; max-width: none; }
.wx .wx-opts > li { margin: 0; min-width: 0; }
.wx .wx-opt-btn {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 8px 12px; text-align: left;
  border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-key); background: var(--c-raised); color: var(--c-ink);
  font: 600 15.5px/1.35 var(--sans); box-shadow: var(--c-sh-key); cursor: pointer; overflow-wrap: anywhere;
}
.wx .wx-opt-btn > .wx-otext-b { min-width: 0; }
.wx .wx-opt-btn[disabled] { cursor: default; box-shadow: none; background: var(--c-card); color: var(--c-ink); }
.wx .wx-opt-btn.correct { background: var(--c-ok-wash); border-color: var(--c-line); }
.wx .wx-opt-btn.wrong { background: var(--c-bad-wash); border-color: var(--c-bad); }
.wx .wx-mark {
  flex: none; width: 24px; height: 22px; display: grid; place-items: center; border-radius: 6px;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-panel); color: var(--c-ink); font: 800 13px/1 var(--mono);
}
.wx .wx-opt-btn.correct .wx-mark { color: var(--c-ok-ink); }
.wx .wx-opt-btn.wrong .wx-mark { color: var(--c-bad); border-color: var(--c-bad); }
.wx.is-live .wx-fb { display: none; }
.wx.is-live .wx-fb.is-shown { display: block; }
.wx .wx-fb {
  font: 400 14.5px/1.45 var(--sans); margin: 6px 0 0; padding: 6px 10px; border-radius: 10px;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-recess); color: var(--c-ink);
}
.wx .wx-fb.ok { background: var(--c-ok-wash); }
.wx .wx-fb.no { background: var(--c-bad-wash); }
.wx .wx-fb b { font: 700 12px var(--mono); letter-spacing: .06em; }
.wx .wx-fb.ok b { color: var(--c-ok-ink); }
.wx .wx-fb.no b { color: var(--c-bad); }
/* the controls the enhancer adds */
.wx .wx-ctrl { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 4px 0 0; }
.wx .wx-ctrl .ui-btn { min-height: 44px; }
.wx .wx-ctrl .ui-btn.ghost { padding: 0 6px; }
.wx .wx-count { font: 700 12px/1.3 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--c-ink); }
/* on a phone the lesson footer is docked over the page: a revealed step scrolls in above it */
@media (max-width: 899px) {
  .lrn-player .wx .wx-step { scroll-margin-bottom: calc(150px + var(--ui-tabbar-h, 0px) + var(--ui-safe-b, 0px)); }
}
/* a newly revealed step settles in; reduced motion (the device's or Settings') gets none of it: this rule
   only exists under no-preference, and styles.css stops every animation under both reduced settings */
@media (prefers-reduced-motion: no-preference) {
  :root:not([data-motion="reduced"]) .wx .wx-step.wx-in { animation: wx-in .18s ease-out both; }
}
@keyframes wx-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* "Show the steps" inside a quiz or checkpoint explanation (.qq-why: the plain box, Yuzu's bubble, Today's) */
.why-steps { margin: 8px 0 0; }
.why-steps > summary {
  display: block; width: -moz-fit-content; width: fit-content; padding: 7px 0; cursor: pointer; list-style: none;
  font: 700 14px/1.3 var(--sans); color: var(--c-ink);
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.why-steps > summary::-webkit-details-marker { display: none; }
/* an inline-block marker: the summary's underline does not reach into it */
.why-steps > summary::before { content: "+"; display: inline-block; width: 1em; margin-right: 4px; font: 800 15px/1 var(--mono); text-decoration: none; }
.why-steps[open] > summary::before { content: "\2212"; }
.why-steps ol { margin: 6px 0 0; padding-left: 1.5em; }
.why-steps li { margin: 0 0 6px; }
.why-steps .ws-work { display: block; font-weight: 700; overflow-wrap: anywhere; }
.why-steps .ws-why { display: block; font-size: 14px; overflow-wrap: anywhere; }

/* ================= Checkpoint ("N-question check-in") ================= */
.lrn-checkpoint .ui-title { margin: 0 0 4px; }
.lrn-cp-sub { font: 400 14px/1.45 var(--sans); color: var(--c-ink-2); margin: 0 0 8px; }

/* ================= Code exercise (renderExercise: player code steps, Practice, the exam) =================
   No card around it: the slate editor, the output slate and the check rows are chunky on
   their own. Run (secondary) and Submit (primary) stay the first two buttons in .ex-bar. */
/* one explicit minmax(0, 1fr) column: the implicit auto track grew to the solution's
   min-content width (white-space:pre) and pushed a 390px phone page to 492px */
.ex { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; min-width: 0; }
.ex > * { min-width: 0; }
/* 70ch alone runs 85-90 characters a line in Bricolage (its '0' is wide); 36em keeps it near 65-75, like the lesson prose */
.ex .ex-instructions { font-size: 15.5px; line-height: 1.6; max-width: min(70ch, 36em); }
.ex .ex-instructions > :last-child { margin-bottom: 0; }
.ex-editor {
  display: block; width: 100%; min-height: 180px; resize: vertical;
  white-space: pre; overflow-wrap: normal; overflow-x: auto;
}
.ex-bar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 4px; }
.ex-bar .ui-btn { min-height: 48px; padding: 0 20px; }
/* help actions: ghost keys, a row below the two real actions */
.ex-tools { display: flex; flex-wrap: wrap; gap: 0 6px; margin-top: -6px; margin-left: -8px; }
.ex-tool {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 8px; background: none; border: 0; cursor: pointer;
  font: 700 14px/1.2 var(--sans); color: var(--c-ink);
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.ex-tool:hover { text-decoration-thickness: 3px; }
.ex-status { font: 400 14px/1.45 var(--sans); color: var(--c-ink-2); min-height: 1.45em; }
.ex-status .r3 { color: var(--c-ok-ink); font-weight: 700; }
.ex-status .r2 { color: var(--c-bad); font-weight: 700; }
.ex-status:empty, .ex-extra:empty { display: none; }
.ex-loading { display: flex; align-items: center; gap: 10px; }   /* Pyodide downloading: thinking */
/* the thinking sticker is empty on its left (x 36-200 of 200): -11px puts the figure on the
   column edge the Run and Submit keys start at */
.ex-loading .mascot { width: 64px; height: 64px; margin: -4px 0 -4px -11px; }
.ex-out {
  margin: 0; background: var(--c-code-bg); color: var(--c-code-ink);
  border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-md); box-shadow: var(--c-sh);
  padding: 10px 14px 12px; font: 400 13px/1.55 var(--code); white-space: pre-wrap; overflow-wrap: anywhere;
  max-height: 280px; overflow: auto;
}
.ex-out::before {
  content: "Output"; display: block; margin-bottom: 4px;
  font: 700 12px/1.3 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--c-code-cm);
}
.ex-out.has-error { border-color: var(--c-bad); }
.ex-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.ex-checks[hidden], .ex-fallback[hidden] { display: none; }
.ex-checks li {
  position: relative; min-height: 44px; padding: 10px 12px 10px 44px;
  font: 400 14.5px/1.45 var(--sans); color: var(--c-ink);
  background: var(--c-raised); border: var(--c-bw-sm) solid var(--c-line); border-radius: 10px;
}
.ex-checks li b {
  position: absolute; left: 10px; top: 10px; width: 22px; height: 22px; display: grid; place-items: center;
  border: var(--c-bw-sm) solid var(--c-line); border-radius: 6px; font: 800 13px/1 var(--sans);
}
.ex-checks li.ok b { background: var(--c-ok); color: var(--c-on-color); }
.ex-checks li.no { background: var(--c-bad-wash); border-color: var(--c-bad); }
.ex-checks li.no b { background: var(--c-raised); color: var(--c-bad); border-color: var(--c-bad); }
.ex-err { font: 400 12.5px/1.4 var(--code); color: var(--c-muted); overflow-wrap: anywhere; }
.ex-extra .callout { max-width: none; margin: 0; min-width: 0; }
.ex-extra pre.starter { margin-bottom: 0; max-width: 100%; overflow-x: auto; }
/* progressive help (app.js renderExercise): the hints stack above the solution, and every one stays */
.ex-extra, .ex-hints { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; min-width: 0; }
.ex-extra .wx { margin: 0; max-width: none; }
.ex-extra .callout:focus { outline: none; }
.ex-extra .callout:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; }
.ex-tool:disabled { cursor: default; text-decoration: none; color: var(--c-muted); }
/* the spent hint key stays in the Tab order (aria-disabled), plain text and AA */
.ex-tool[aria-disabled="true"] { cursor: default; text-decoration: none; color: var(--c-ink-2); }
.ex-hints:focus { outline: none; }
.ex-hints:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; }
.ex-fallback {
  background: var(--c-recess); border: var(--c-bw-sm) solid var(--c-line); border-radius: 16px;
  padding: 14px 18px; font: 400 14.5px/1.55 var(--sans); color: var(--c-ink-2);
}
.ex-fallback p { margin: 0 0 6px; }
.ex-fallback code { font-family: var(--code); }
.ex-fallback .ui-btn { justify-content: flex-start; text-align: left; padding: 0; font-size: 14.5px; line-height: 1.3; }

/* ================= Drag-and-drop match (matchBlock) =================
   Mock: a recess tray with an "N OF M PLACED" count; white chip keys with a grip; slot cards
   whose empty holes are DASHED (dashed = empty slot, nothing else); placed ideas turn green
   with "✓ CORRECT"; the picked-up idea lifts and tilts. */
.match { background: none; border: 0; padding: 0; }
.match-sub { font: 400 14.5px/1.35 var(--sans); color: var(--c-ink-2); margin: 0; max-width: 60ch; }
.match-tray {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0; min-height: 60px;
  padding: 8px 12px 9px 8px; background: var(--c-recess); border: var(--c-bw) solid var(--c-line);
  border-radius: 16px; box-shadow: inset 3px 3px 0 var(--c-inset);
}
.match-count { order: 99; margin-left: auto; text-align: right; }
/* everything placed: the tray steps back to just its count (a bare recess bar read as an
   empty text field) */
.match-tray.empty { min-height: 0; padding: 0 2px; background: none; box-shadow: none; border-color: transparent; }
.match-chip {
  display: inline-flex; align-items: center; gap: 7px; min-height: 44px; max-width: 100%; padding: 6px 13px 6px 9px;
  text-align: left; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-line); border-radius: 11px;
  box-shadow: var(--c-sh-key); font: 800 14.5px/1.2 var(--sans);
  transition: transform .08s ease, box-shadow .08s ease; -webkit-tap-highlight-color: transparent;
}
.match-chip::before {   /* the grip */
  content: ""; width: 10px; height: 16px; flex: none;
  background: radial-gradient(circle, currentColor 1.5px, transparent 1.7px) 0 0 / 5px 5.3px;
}
@media (hover: hover) {
  .match-chip:not(.locked):not(.selected):hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); }
}
/* the picked idea lifts and tilts with a heavier ink edge (as in the mock). Not blue: blue
   is the main action and the focus ring, and a picked chip looked like a focused one. */
.match-chip.selected, .match-chip[aria-pressed="true"] {
  border-color: var(--c-line); box-shadow: 0 0 0 2.5px var(--c-fill), var(--c-sh-lift);
  transform: translateY(-2px) rotate(var(--match-tilt));
}
.match-chip.dragging { opacity: .35; }   /* the origin, while its ghost is carried */
.match-chip.locked { cursor: default; }
.match-chip.locked::before { display: none; }
/* the carried copy: lifted and tilted by the inline transform; pointer-events:none is
   REQUIRED (the drop is found with elementFromPoint, and tools/verify_match.js drags) */
.match-ghost { position: fixed; left: 0; top: 0; z-index: 100; margin: 0; pointer-events: none; box-shadow: var(--c-sh-lift); }
.match-slots { display: grid; gap: 10px; }
/* a slot is a one-column grid: the drop key fills the hole (row 1) and a placed chip, its SIBLING (never
   a button inside the button), sits over the hole's left end in the same cell; the definition is row 2 */
.match-slot {
  display: grid; grid-template-columns: minmax(0, 1fr);
  background: var(--c-card); border: var(--c-bw) solid var(--c-line); border-radius: 15px;
  box-shadow: 3px 3px 0 var(--c-slab); padding: 6px 7px 8px; margin-right: 3px;
}
.match-slot > .match-drop { grid-area: 1 / 1; align-self: stretch; }
.match-slot > .match-chip { grid-area: 1 / 1; justify-self: start; align-self: center; position: relative; z-index: 1; margin: 7px 4px; max-width: calc(100% - 8px); }
.match-drop {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; min-height: 46px;
  padding: 0 4px; cursor: pointer; text-align: left; font: inherit; color: var(--c-ink);
  background: var(--c-recess); border: var(--c-bw-sm) dashed var(--c-line); border-radius: 11px;
  box-shadow: inset 3px 3px 0 var(--c-inset);
}
.match-drop-hint {
  display: inline-flex; align-items: center; gap: 7px; padding-left: 8px;
  font: 700 13px/1.2 var(--mono); letter-spacing: .04em; text-transform: uppercase; color: var(--c-muted);
}
.match-drop-hint svg { flex: none; width: 16px; height: 16px; stroke-width: 2.6; }
/* hot target: under a carried idea, or every empty hole while an idea is picked */
.match-slot.over .match-drop, .match.picking .match-slot:not(:has(> .match-chip)) > .match-drop {
  background: var(--c-raised); border-width: var(--c-bw); box-shadow: none;
}
.match-slot:has(> .match-chip) > .match-drop { border-style: solid; }
.match-slot > .match-chip {
  width: auto; min-height: 32px; padding: 3px 10px 3px 8px; border-width: 2px; border-radius: 9px;
  box-shadow: none; font-size: 14px;
}
.match-slot.right .match-chip { background: var(--c-ok); color: var(--c-on-color); border-color: var(--c-line); }
.match-slot.right .match-drop::after, .match-slot.wrong .match-drop::after {
  flex: none; margin-left: auto; padding-right: 6px; font: 700 12px/1 var(--mono); letter-spacing: .05em; text-transform: uppercase;
}
/* checked: the verdict word at the hole's right end keeps its room beside the chip */
.match-slot.right > .match-chip, .match-slot.wrong > .match-chip { max-width: calc(100% - 118px); }
.match-slot.right .match-drop::after { content: "✓ Correct"; color: var(--c-ink); }
.match-slot.wrong .match-drop { border-color: var(--c-bad); }
.match-slot.wrong .match-chip { background: var(--c-bad-wash); color: var(--c-ink); border-color: var(--c-bad); }
.match-slot.wrong .match-drop::after { content: "✗ Try again"; color: var(--c-bad); }
.match-def { margin: 6px 2px 0 4px; font: 400 14px/1.3 var(--sans); color: var(--c-ink); }
.match-actions { display: flex; align-items: center; gap: 12px 16px; margin-top: 16px; flex-wrap: wrap; }
.match-actions .match-check { min-height: 48px; padding: 0 22px; }
.match-check[hidden] { display: none; }   /* finished: the dead Check key steps aside */
.match-reset { padding: 0 6px; font-size: 14.5px; font-weight: 700; }
.match-reset[hidden] { display: none; }
.match-result { margin: 10px 0 0; font: 400 14px/1.45 var(--sans); color: var(--c-ink-2); min-height: 1.45em; }
.match.done .match-result b { color: var(--c-ok-ink); }
.match-result.has-mascot { display: flex; align-items: center; gap: 12px; }   /* all matched: correct */
.match-result .mascot { width: 72px; height: 72px; margin: -4px 0 -4px -4px; }
/* the checkpoint's result strip: correct at 80%+, oops below it */
.quiz-result.has-mascot { padding-top: 6px; padding-bottom: 6px; }
.quiz-result .mascot { width: 64px; height: 64px; margin: -2px 0 -2px -4px; }

/* ================= Practice list (practiceList) ================= */
.lrn-page.pr-page { max-width: 900px; }
.lrn-page .pf.lrn-pf { display: block; background: none; border: 0; box-shadow: none; padding: 0; margin: 0 0 2px; }
.pf-searchwrap { position: relative; display: block; max-width: 560px; }
.pf-searchwrap > svg {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; color: var(--c-muted); pointer-events: none;
}
.pf-searchwrap .pf-search { width: 100%; max-width: none; min-height: 48px; padding-left: 42px; margin: 0; }
/* chip rows scroll sideways; the padding keeps focus rings and hit areas from being clipped.
   The scrollbar is slim and themed (ui.css "Scrollbars"), never hidden: a hidden one left
   chips past the edge out of mouse reach. */
.pf-chips {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; overflow-x: auto;
  padding: 8px 6px 10px; margin: 0 -6px; scroll-padding-inline: 12px;
}
.pf-chips .ui-chip { flex: none; scroll-margin-inline: 12px; }
/* app.js brings a keyboard-focused item fully into its scroller, this far from the edge */
.ft { scroll-margin-inline: 8px; }
.stepper-item { scroll-margin-block: 8px; }
/* desktop: the rows wrap, so every chip is in reach without scrolling */
@media (min-width: 900px) {
  .pf-chips { flex-wrap: wrap; overflow: visible; row-gap: 12px; }
  .pf-group { flex-wrap: wrap; flex: 0 1 auto; }
}
.pf-group { display: flex; gap: 8px; flex: none; }
.pf-sep { flex: none; width: 2px; height: 24px; margin: 0 4px; border-radius: 1px; background: var(--c-line); }
/* difficulty pips: three small squares, filled for the level (1 beginner, 2, 3 advanced) */
.pr-diff, .ui-chip.pips { --pip-bg: var(--c-raised); }
button.ui-chip.pips[aria-pressed="true"] { --pip-bg: var(--c-fill); }
.pr-diff::before, .ui-chip.pips::before {
  content: ""; flex: none; width: 5px; height: 5px; margin-right: 14px; border-radius: 1px; background: currentColor;
  box-shadow: 7px 0 0 -1.5px var(--pip-bg), 7px 0 0 0 currentColor, 14px 0 0 -1.5px var(--pip-bg), 14px 0 0 0 currentColor;
}
.pr-diff.d-intermediate::before, .ui-chip.pips.d-intermediate::before {
  box-shadow: 7px 0 0 0 currentColor, 14px 0 0 -1.5px var(--pip-bg), 14px 0 0 0 currentColor;
}
.pr-diff.d-advanced::before, .ui-chip.pips.d-advanced::before { box-shadow: 7px 0 0 0 currentColor, 14px 0 0 0 currentColor; }
.lrn-page .pf-actions { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: auto; margin: 2px 2px 4px; }
.pf-count { font: 400 12.5px/1.3 var(--mono); color: var(--c-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pf-clear { padding: 0 4px; font-size: 14.5px; font-weight: 700; }
.pr-list { display: grid; gap: 10px; margin-top: 8px; }
.pr-group { display: flex; align-items: center; gap: 10px; margin: 20px 2px 2px; }
.pr-group:first-child { margin-top: 4px; }
.pr-group-num {
  flex: none; min-width: 28px; height: 22px; padding: 0 4px; display: grid; place-items: center;
  background: var(--pc, var(--c-raised)); color: var(--c-on-color); border: var(--c-bw-sm) solid var(--c-line);
  border-radius: 7px; font: 700 12px/1 var(--mono);
}
.pr-group-name { flex: 1; min-width: 0; font: 700 12px/1.3 var(--mono); letter-spacing: .05em; text-transform: uppercase; color: var(--c-ink); }
.pr-group-count { flex: none; margin-left: auto; font: 400 12px/1.3 var(--mono); color: var(--c-muted); }
.pr-row {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 4px 12px; align-items: center;
  padding: 12px 14px; margin-right: 3px; color: var(--c-ink); text-decoration: none;
  background: var(--c-card); border: var(--c-bw) solid var(--c-line); border-radius: 16px;
  box-shadow: 3px 3px 0 var(--c-slab); transition: transform .08s ease, box-shadow .08s ease;
}
.pr-row:hover { text-decoration: none; }
@media (hover: hover) { .pr-row:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 var(--c-slab); } }
.pr-row:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--c-slab); }
.pr-dot {
  position: relative; width: 22px; height: 22px; flex: none; border-radius: 6px; font-size: 0;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-raised);
}
.pr-row.done .pr-dot { background: var(--c-ok); }
.pr-row.done .pr-dot::after {
  content: ""; position: absolute; left: 6px; top: 2px; width: 5px; height: 10px;
  border: solid var(--c-on-color); border-width: 0 2.5px 2.5px 0; transform: rotate(45deg);
}
.pr-main { display: grid; gap: 2px; min-width: 0; }
.pr-title { font: 700 15px/1.3 var(--sans); color: var(--c-ink); }
.pr-where { font: 400 13px/1.4 var(--sans); color: var(--c-muted); }
.pr-tags { display: flex; align-items: center; gap: 8px; }
/* phones: the difficulty chip rides on the meta line, right-aligned (it used to take a line
   of its own, making every row ~97px) */
@media (max-width: 620px) {
  .pr-row { grid-template-areas: "dot title title" "dot where tags"; gap: 3px 10px; padding: 10px 12px; }
  .pr-main { display: contents; }
  .pr-dot { grid-area: dot; }
  .pr-title { grid-area: title; }
  .pr-where { grid-area: where; min-width: 0; align-self: center; }
  .pr-tags { grid-area: tags; align-self: center; }
}

/* ================= a single practice problem (practiceOne): the player's frame ================= */
.pr-one { max-width: 820px; margin: 0 auto; }
.pr-pos { flex: none; min-width: 44px; text-align: right; font: 400 12.5px/1.3 var(--mono); color: var(--c-muted); }
.pr-head { margin-bottom: 16px; }
.pr-head .lrn-steptags { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-bottom: 10px; }
.lrn-stepmin { font: 400 12.5px/1.3 var(--mono); color: var(--c-muted); }
.pr-head .pr-name { font: 800 var(--fs-title)/1.15 var(--sans); letter-spacing: -.015em; color: var(--c-ink); margin: 0; }
.pr-from { margin: 6px 0 0; font: 400 14px/1.4 var(--sans); color: var(--c-muted); }
.pr-from a { position: relative; color: var(--c-go-ink); font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
/* the page's one-tap way back to the lesson: a 17px line of text, so an invisible ::after takes
   the hit area to ~45px tall (it stays inside the title's and the head's own spacing) */
.pr-from a::after { content: ""; position: absolute; inset: -14px -4px; }
.pr-head .ui-pill.done[hidden] { display: none; }
.pr-stage { margin-top: 4px; }
.pr-stage .ex { background: none; border: 0; padding: 0; }
.pr-foot { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 24px 0 8px; }
.pr-foot .ui-btn { min-height: 48px; }

/* ================= empty states (Practice, Drill, Quiz, exam, "No such problem") ================= */
.pf-empty, .empty-state {
  margin: 0; max-width: none; padding: 16px 18px; background: var(--c-recess); color: var(--c-ink-2);
  border: var(--c-bw-sm) solid var(--c-line); border-radius: 16px; font: 400 15px/1.55 var(--sans);
}
/* ink, not go-ink: blue on the recess was 4.05:1 in Chunky Play light (under AA); the underline marks the link */
.empty-state a, .pf-empty a { color: var(--c-ink); font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
/* app.js emptyState(): the resting mascot beside the words (the pose is wide and low, so the
   negative margins trim its empty top and keep the card compact) */
.pf-empty.has-mascot, .empty-state.has-mascot { display: flex; align-items: center; gap: 14px; }
.pf-empty > .mascot, .empty-state > .mascot { width: 80px; height: 80px; margin: -12px 0 -4px -4px; }
/* the resting sticker's weight is low (the sleeping body fills its lower half; the z's rise
   above it), so centring its box put the body 10-14px below the words: the words step down a
   little and the sticker up a little, which lines the body up with them */
.pf-empty.has-mascot > .empty-text, .empty-state.has-mascot > .empty-text { padding-top: 16px; }
@media (min-width: 900px) {
  .pf-empty > .mascot, .empty-state > .mascot { width: 96px; height: 96px; }
  .pf-empty.has-mascot > .empty-text, .empty-state.has-mascot > .empty-text { padding-top: 22px; }
}

/* ================= question sessions (Quiz session, Drill) and the exam box ================= */
.sess-page { max-width: 760px; margin: 0 auto; }
.sess-card { margin-top: 4px; }
.sess-bar { margin-bottom: 14px; }
.sess-card .quiz-head { margin: 0 0 12px; }
.sess-next { margin-top: 14px; min-height: 48px; }
.sess-result { display: grid; justify-items: center; gap: 8px; text-align: center; padding: 4px 0; }
.sess-seal .seal { display: block; width: 112px; height: 112px; }
/* the seal, and beside it on a good round, an exam pass or an exam "Not yet" the mascot */
.sess-hero { display: flex; align-items: center; justify-content: center; gap: 4px; }
.sess-hero .mascot { width: 96px; height: 96px; }
.sess-result .ui-title { margin: 2px 0 0; }
.sess-result .ui-sub, .sess-result .quiz-sub { margin: 2px auto 0; text-align: center; font-size: 15px; }
.sess-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
.sess-actions .ui-btn { min-height: 48px; }

/* ================= Drill ================= */
.lrn-drill-status { text-align: center; margin: 0 0 12px; font: 400 12.5px/1.4 var(--mono); color: var(--c-ink-2); }
/* nothing due: the resting mascot beside the line */
.lrn-drill-status.has-mascot { display: flex; align-items: center; justify-content: center; gap: 10px; text-align: left; }
.lrn-drill-status .mascot, .lrn-drill-status .yz-gap { width: 72px; height: 72px; margin: -8px 0 -4px; }   /* .yz-gap: his slot while Yuzu explains an answer */
.lrn-drill-status.has-mascot > span { padding-top: 26px; }   /* level with the sleeping body (see empty states) */
@media (min-width: 900px) {
  /* the text centered in the line itself and Yuzu (or his empty slot while he explains an answer) just
     left of it, so the slot never pushes the text off-center; a tight line gives the right column up first */
  .lrn-drill-status.has-mascot { display: grid; grid-template-columns: 1fr auto 1fr; column-gap: 10px; }
  .lrn-drill-status.has-mascot > .mascot, .lrn-drill-status.has-mascot > .yz-gap { grid-column: 1; justify-self: end; }
  .lrn-drill-status.has-mascot > span:not(.mascot):not(.yz-gap) { grid-column: 2; }
}
.lrn-howreview {
  margin: 0 0 14px; padding: 0 14px; background: var(--c-raised);
  border: var(--c-bw) solid var(--c-line); border-radius: 14px; box-shadow: var(--c-sh-sm);
}
.lrn-howreview summary {
  display: flex; align-items: center; gap: 8px; min-height: 48px; cursor: pointer; list-style: none;
  font: 700 14px/1.2 var(--sans); color: var(--c-ink);
}
.lrn-howreview summary::-webkit-details-marker { display: none; }
.lrn-howreview summary svg { flex: none; width: 18px; height: 18px; stroke-width: 2.6; transition: transform .15s ease; }
.lrn-howreview[open] summary svg { transform: rotate(90deg); }
.lrn-howreview .mod-goal { margin: 0 0 14px; font-size: 14.5px; }

/* ================= phase exam ================= */
.exam-tiles { margin-bottom: 14px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.exam-rules { margin-bottom: 14px; }
.exam-rules-tag { margin: 0 0 4px; }
.exam-list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 10px; font: 400 15px/1.5 var(--sans); color: var(--c-ink-2); }
.exam-list li { position: relative; padding-left: 20px; }
.exam-list li::before { content: ""; position: absolute; left: 2px; top: .55em; width: 8px; height: 8px; border-radius: 2px; background: var(--c-fill); }
.exam-status { margin: 14px 0 0; font: 400 14px/1.45 var(--sans); color: var(--c-ink-2); }
.exam-status .ui-pill { margin-right: 6px; vertical-align: 1px; }
/* once the exam starts its intro steps aside, so the question sits at the top */
.sess-page > .pg-head[hidden], .exam-tiles[hidden], .exam-rules[hidden] { display: none; }
.exam-box > .ui-btn.block { min-height: 50px; }
.exam-box:has(> .ui-btn.block:only-child) { padding: 0; border: 0; background: none; box-shadow: none; }
.exam-ptitle { font: 800 var(--fs-h3)/1.25 var(--sans); letter-spacing: -.01em; color: var(--c-ink); margin: 0 0 4px; }
.exam-box .ex { margin-bottom: 4px; }
.exam-giveup { justify-self: start; margin-top: 8px; }


/* ---- one header for every page: left-aligned eyebrow, display title, one line ---- */
.pg-head { text-align: left; margin: 0 0 16px; max-width: none; }
.pg-head .ui-title { margin-top: 4px; }
.pg-head .center { text-align: left; }
.pg-head .ui-sub, .pg-head .ui-sub.center { font-size: 15px; color: var(--c-ink-2); margin: 6px 0 0; }
.pg-count { margin: 8px 0 0; font: 400 12.5px/1.3 var(--mono); color: var(--c-muted); }

/* ---- Learn: module cards ---- */
.lrn-modlist { display: grid; gap: 10px; grid-template-columns: minmax(0, 1fr); margin: 14px 0 24px; }
@media (min-width: 700px) { .lrn-modlist { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } }
@media (min-width: 1500px) { .lrn-modlist { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ui-card.lrn-mod { display: flex; gap: 10px; align-items: flex-start; padding: 8px 12px 9px 10px; border-radius: 16px; text-decoration: none; color: inherit; }
/* in the 2-3 column grid cards share a row height: the meta line sits at the bottom of each,
   so the chips line up across the row */
.lrn-mod-main { align-self: stretch; display: flex; flex-direction: column; }
.lrn-mod-main .lrn-mod-meta { margin-top: auto; padding-top: 6px; }
.num {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center; margin-top: 1px;
  border: var(--c-bw) solid var(--c-line); border-radius: 11px; background: var(--c-key); color: var(--c-ink);
  font: 700 13px/1 var(--mono);
}
.num.go { background: var(--c-raised); box-shadow: inset 0 -12px 0 var(--c-recess); }
.num.done { background: var(--c-ok); color: var(--c-on-color); }
.num.done svg { stroke-width: 3; }
.lrn-mod-main { flex: 1; min-width: 0; }
.lrn-mod-title { font: 800 16px/1.2 var(--sans); letter-spacing: -.01em; margin: 0; color: var(--c-ink); }
.lrn-opt { display: inline-block; vertical-align: middle; font: 700 12px/1.2 var(--mono); color: var(--c-muted); border: 1.5px solid var(--c-line-soft); border-radius: 999px; padding: 2px 8px; margin-left: 6px; letter-spacing: 0; }
.lrn-mod-hook {
  font: 400 14px/1.3 var(--sans); color: var(--c-muted); margin: 2px 0 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.lrn-mod-meta {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 6px 0 0;
  font: 400 12.5px/1.3 var(--mono); color: var(--c-muted);
}
.lrn-mod-meta > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* a reopened module (app.js renderCourse): the "New lessons" chip and the progress bar travel
   together at the end of the line, drop below the lesson count when a phone runs out of room,
   and stack (chip over bar) when even their own line is too narrow (320px with a scrollbar) */
.lrn-mod-meta.has-new { flex-wrap: wrap; row-gap: 4px; }
.lrn-mod-st {
  display: inline-flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 4px 8px;
  flex: 0 1 auto; min-width: 0; margin-left: auto;
}
.minibar { display: inline-flex; align-items: center; gap: 7px; flex: none; }
.minibar .ui-bar { width: 66px; }
.minibar b { font: 700 12.5px var(--mono); color: var(--c-ink); }
.lrn-section-label { margin: 6px 2px 10px; }
/* the exam card is one grid column wide, like the module cards above it */
@media (min-width: 700px) { .lrn-page .ui-card.act { max-width: calc(50% - 7px); } }
@media (min-width: 1500px) { .lrn-page .ui-card.act { max-width: calc((100% - 28px) / 3); } }
@media (min-width: 900px) {
  .ui-card.lrn-mod { padding: 12px 14px 12px 12px; }
  .lrn-mod-title { font-size: var(--fs-h3); }
}

/* ================= Lesson diagrams (diagrams.js draws them; the data is in dg*.js) =================
   One card per lesson, right under the title row and before the prose: <figure class="dg"
   role="img" aria-label="alt + caption">, a zero-height .dg-probe (its width is what the layout
   may use), an aria-hidden .dg-svg and a visible .dg-cap. Every colour is a token set through a
   class on an SVG element, so a palette or mode switch recolours the drawing with no re-render.
   Variants (.dg-v-*):
     neutral   raised face, ink line, ink text
     a b c     a wash of --c-dg-1/2/3 on the raised face, ink line and text
     *-solid   the TEXT shade --c-dg-N-text as the fill (>= 4.5:1 against --c-on-fill in all six
               looks), drawn flat: no slab shadow, so it never reads as a key
     muted     card face, muted line and text (quiet; never a hole in the page)
     dashed    card face, dashed muted line
   The accents are the diagram tokens --c-dg-1/2/3 (ui.css, themes.css): in every palette they
   differ from --c-go (the one main action) and --c-ok (done), which never appear in a diagram.
   Nothing here is under 12px (diagrams.js never scales text down). */
.dg { margin: 0 0 22px; padding: 14px 10px 12px; background: var(--c-card); border: var(--c-bw) solid var(--c-line);
  border-radius: var(--c-r-md); box-shadow: var(--c-sh-sm); min-width: 0; }
@media (min-width: 400px) { .dg { padding: 16px 14px 12px; } }
@media (min-width: 900px) { .dg { padding: 20px 22px 14px; } }
.dg-probe { height: 0; }
.dg-svg { display: block; margin: 0 auto; max-width: 100%; height: auto; overflow: hidden; }
/* not drawn yet (diagrams.js mount() draws it before the first paint): take no room meanwhile */
.dg-svg:not([viewBox]) { height: 0; }
/* a wrapped caption breaks into even lines, never a one-word orphan */
.dg-cap { margin: 10px auto 0; max-width: 60ch; text-align: center; font: 400 12px/1.45 var(--mono); color: var(--c-muted); text-wrap: balance; }
/* on a desktop column the drawing is scaled up to 1.15x (its labels reach about 16px) */
@media (min-width: 900px) { .dg-cap { font-size: 13px; } }
.dg-svg text { font-family: var(--mono); font-weight: 400; fill: var(--c-ink); font-variant-ligatures: none; }

/* boxes */
.dg-face { fill: var(--c-raised); stroke: var(--c-line); stroke-width: 2; }
.dg-slab { fill: var(--c-slab); stroke: var(--c-slab); stroke-width: 2; }
.dg-svg .dg-lbl { fill: var(--c-ink); }
.dg-svg .dg-node > .dg-lbl.dg-note { font-weight: 400; }
.dg-v-a-solid > .dg-face { fill: var(--c-dg-1-text); }
.dg-v-b-solid > .dg-face { fill: var(--c-dg-2-text); }
.dg-v-c-solid > .dg-face { fill: var(--c-dg-3-text); }
.dg-svg :is(.dg-v-a-solid, .dg-v-b-solid, .dg-v-c-solid) > .dg-lbl { fill: var(--c-on-fill); font-weight: 700; }
.dg-v-muted > .dg-face { fill: var(--c-card); stroke: var(--c-muted); }
.dg-svg :is(.dg-v-muted, .dg-v-dashed) > .dg-lbl { fill: var(--c-muted); }
.dg-v-dashed > .dg-face { fill: var(--c-card); stroke: var(--c-muted); stroke-dasharray: 5 4; }
/* the washes: a mix of the accent into the raised face (plain raised where color-mix is
   missing, so the ink line and text still read) */
@supports (fill: color-mix(in srgb, red 50%, blue)) {
  .dg-v-a > .dg-face { fill: color-mix(in srgb, var(--c-dg-1) 22%, var(--c-raised)); }
  .dg-v-b > .dg-face { fill: color-mix(in srgb, var(--c-dg-2) 22%, var(--c-raised)); }
  .dg-v-c > .dg-face { fill: color-mix(in srgb, var(--c-dg-3) 22%, var(--c-raised)); }
  .dg-shade-a-1 > .dg-face { fill: color-mix(in srgb, var(--c-dg-1) 12%, var(--c-raised)); }
  .dg-shade-a-2 > .dg-face { fill: color-mix(in srgb, var(--c-dg-1) 24%, var(--c-raised)); }
  .dg-shade-a-3 > .dg-face { fill: color-mix(in srgb, var(--c-dg-1) 36%, var(--c-raised)); }
  .dg-shade-b-1 > .dg-face { fill: color-mix(in srgb, var(--c-dg-2) 12%, var(--c-raised)); }
  .dg-shade-b-2 > .dg-face { fill: color-mix(in srgb, var(--c-dg-2) 24%, var(--c-raised)); }
  .dg-shade-b-3 > .dg-face { fill: color-mix(in srgb, var(--c-dg-2) 36%, var(--c-raised)); }
  .dg-shade-c-1 > .dg-face { fill: color-mix(in srgb, var(--c-dg-3) 12%, var(--c-raised)); }
  .dg-shade-c-2 > .dg-face { fill: color-mix(in srgb, var(--c-dg-3) 24%, var(--c-raised)); }
  .dg-shade-c-3 > .dg-face { fill: color-mix(in srgb, var(--c-dg-3) 36%, var(--c-raised)); }
}
/* the top shade is the solid fill (a wash stronger than 36% would drop ink text under 4.5:1
   in some palettes), so the largest values stand out the way a heatmap's darkest cell should */
.dg-shade-a-4 > .dg-face { fill: var(--c-dg-1-text); }
.dg-shade-b-4 > .dg-face { fill: var(--c-dg-2-text); }
.dg-shade-c-4 > .dg-face { fill: var(--c-dg-3-text); }
.dg-svg :is(.dg-shade-a-4, .dg-shade-b-4, .dg-shade-c-4) > .dg-lbl { fill: var(--c-on-fill); font-weight: 700; }
/* matrix cells: a thinner line than a box, so a 6 x 6 grid does not turn into a cage */
.dg-k-grid .dg-face { stroke-width: 1.5; }
.dg-seg { stroke: none; }
.dg-outline { fill: none; stroke: var(--c-line); stroke-width: 2; }
.dg-segdiv { stroke: var(--c-line); stroke-width: 2; }
/* a flow's group box (a Deployment round its pods): a quiet rounded frame; its small-caps
   label (.dg-rlbl) names it */
.dg-group { fill: none; stroke: var(--c-muted); stroke-width: 1.5; }

/* arrows and connectors */
.dg-ln { fill: none; stroke: var(--c-line); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dg-hd { fill: var(--c-line); stroke: var(--c-line); stroke-width: 1; stroke-linejoin: round; }
.dg-e-a .dg-ln { stroke: var(--c-dg-1); }  .dg-e-a .dg-hd { fill: var(--c-dg-1); stroke: var(--c-dg-1); }
.dg-e-b .dg-ln { stroke: var(--c-dg-2); }  .dg-e-b .dg-hd { fill: var(--c-dg-2); stroke: var(--c-dg-2); }
.dg-e-c .dg-ln { stroke: var(--c-dg-3); }  .dg-e-c .dg-hd { fill: var(--c-dg-3); stroke: var(--c-dg-3); }
.dg-e-muted .dg-ln, .dg-e-dashed .dg-ln { stroke: var(--c-muted); }
.dg-e-muted .dg-hd, .dg-e-dashed .dg-hd { fill: var(--c-muted); stroke: var(--c-muted); }
.dg-e-dashed .dg-ln, .dg-ln.dg-dash { stroke-dasharray: 6 5; }
.dg-ln.dg-thin { stroke-width: 1.25; }

/* words drawn on the card */
.dg-svg .dg-small { fill: var(--c-muted); }
.dg-svg .dg-rlbl { fill: var(--c-ink-2); font-weight: 700; letter-spacing: .06em; }
.dg-svg .dg-title { fill: var(--c-ink); font-weight: 700; }
.dg-svg .dg-hdr { fill: var(--c-ink-2); font-weight: 700; }
.dg-halo { fill: var(--c-card); }
.dg-div { stroke: var(--c-line-soft); stroke-width: 2; stroke-linecap: round; }
.dg-brk, .dg-tick { fill: none; stroke: var(--c-muted); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* plots */
.dg-axis { fill: none; stroke: var(--c-muted); stroke-width: 1.5; stroke-linecap: round; }
.dg-axhd { fill: var(--c-muted); stroke: var(--c-muted); stroke-width: 1; stroke-linejoin: round; }
.dg-grid { stroke: var(--c-chart-grid); stroke-width: 1; }
.dg-svg text.dg-tick { fill: var(--c-muted); stroke: none; }
.dg-ln.dg-sln { stroke-width: 2.5; }
.dg-e-neutral .dg-ln.dg-sln { stroke: var(--c-ink-2); }
.dg-mark { stroke: var(--c-muted); stroke-width: 1.5; stroke-dasharray: 4 4; }
.dg-bound { fill: none; stroke: var(--c-ink-2); stroke-width: 2; stroke-dasharray: 7 5; }
.dg-bar, .dg-pt { stroke: var(--c-line); stroke-width: 1.5; }
.dg-p-a { fill: var(--c-dg-1); } .dg-p-b { fill: var(--c-dg-2); } .dg-p-c { fill: var(--c-dg-3); }
.dg-p-neutral, .dg-p-dashed { fill: var(--c-raised); } .dg-p-muted { fill: var(--c-card); }
.dg-svg .dg-st-a { fill: var(--c-dg-1-text); } .dg-svg .dg-st-b { fill: var(--c-dg-2-text); }
.dg-svg .dg-st-c { fill: var(--c-dg-3-text); } .dg-svg :is(.dg-st-neutral, .dg-st-dashed) { fill: var(--c-ink-2); }
.dg-svg .dg-st-muted { fill: var(--c-muted); }

/* Windows High Contrast / forced colours: the browser does not repaint SVG fills and strokes,
   so every paint is mapped to a system colour here. !important and the .dg .dg-svg prefix
   (0,2,x and up) are needed: the rules above are more specific (.dg-v-a > .dg-face, .dg-e-a
   .dg-ln, .dg-svg .dg-small) and would otherwise win, leaving pale washes under forced white
   text. Solid boxes (and a heatmap's top shade) become Highlight with HighlightText labels. */
@media (forced-colors: active) {
  .dg { border-color: CanvasText; }
  .dg .dg-svg text { fill: CanvasText !important; stroke: none !important; }
  .dg .dg-svg :is(.dg-face, .dg-seg) { fill: Canvas !important; stroke: CanvasText !important; }
  .dg .dg-svg .dg-halo { fill: Canvas !important; stroke: none !important; }
  .dg .dg-svg .dg-seg { stroke: none !important; }
  .dg .dg-svg :is(.dg-v-a-solid, .dg-v-b-solid, .dg-v-c-solid, .dg-shade-a-4, .dg-shade-b-4, .dg-shade-c-4) > :is(.dg-face, .dg-seg) { fill: Highlight !important; }
  .dg .dg-svg :is(.dg-v-a-solid, .dg-v-b-solid, .dg-v-c-solid, .dg-shade-a-4, .dg-shade-b-4, .dg-shade-c-4) > text { fill: HighlightText !important; }
  .dg .dg-svg .dg-slab { fill: CanvasText !important; stroke: CanvasText !important; }
  .dg .dg-svg :is(.dg-ln, .dg-axis, .dg-bound, .dg-mark, .dg-div, .dg-outline, .dg-segdiv, .dg-brk, path.dg-tick, .dg-grid, .dg-group) { stroke: CanvasText !important; }
  .dg .dg-svg path.dg-tick, .dg .dg-svg :is(.dg-ln, .dg-axis, .dg-bound, .dg-mark, .dg-div, .dg-outline, .dg-segdiv, .dg-brk, .dg-group) { fill: none !important; }
  .dg .dg-svg :is(.dg-hd, .dg-axhd) { fill: CanvasText !important; stroke: CanvasText !important; }
  .dg .dg-svg :is(.dg-bar, .dg-pt) { fill: Canvas !important; stroke: CanvasText !important; }
}

/* ================= Certification practice exams (app.js "certification practice exams") =================
   Hub, cert page, intro, the run (focus mode, timer, question card, exhibits, grid sheet, review &
   submit, submit dialog, paused card), result and review. Tokens only (no new colour token), nothing
   under 12px, 44px targets. Selected answer = ink fill (--c-fill / --c-on-fill): green is never used
   during the exam, because green means correct. Every state carries a word or a glyph. */

/* focus mode: the run hides the global navigation; the back key ("Save and leave the exam") is the way out */
html.lc-exam .tabbar, html.lc-exam .rail, html.lc-exam .topbar { display: none !important; }
html.lc-exam { --ui-tabbar-h: 0px; }

/* the exam frames keep a centred column (the hub and the cert page start at the page's left edge) */
.cx-page { max-width: 760px; margin: 0 auto; }
.cx-loading { margin: 28px 0; text-align: center; font: 400 13px/1.4 var(--mono); color: var(--c-muted); }
.cx-note { margin: 18px 2px 0; font: 400 13px/1.45 var(--sans); color: var(--c-muted); max-width: 62ch; }
.cx-banner {
  margin: 0 0 12px; padding: 10px 12px; background: var(--c-recess); color: var(--c-ink);
  border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px; font: 400 14.5px/1.45 var(--sans);
}
.cx-alert {
  margin: 0 0 14px; padding: 10px 12px; background: var(--c-bad-wash); color: var(--c-ink);
  border: var(--c-bw-sm) solid var(--c-bad); border-radius: 12px; font: 700 15px/1.45 var(--sans);
}
.cx-loadfail { display: grid; gap: 10px; justify-items: start; margin: 14px 0; }
.cx-loadfail-text { margin: 0; font: 700 15px/1.45 var(--sans); color: var(--c-ink); }
.cx-starterr:empty { display: none; }
.cx-study { margin: 6px 0 0; font: 400 13.5px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-study a, .cx-checked a, .cx-stats-link a {
  color: var(--c-go-ink); font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.st.ink { background: var(--c-fill); color: var(--c-on-fill); }                                   /* "Needs work" */
.st.half { background: var(--c-ok-wash); color: var(--c-ink); border-color: var(--c-ok-ink); }    /* "½ Partly" */
.cx-h1:focus, .cx-qnum:focus { outline: none; }

/* ---- the Practice switch (navigation, not toggles): Coding problems | Cert exams ---- */
.cx-switch {
  display: flex; width: fit-content; max-width: 100%; gap: 4px; padding: 4px; margin: 0 0 16px;
  background: var(--c-recess); border: var(--c-bw) solid var(--c-line); border-radius: 14px; box-shadow: inset 2px 2px 0 var(--c-inset);
}
.cx-switch-link {
  flex: 1 1 auto; min-width: 0; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; text-align: center;
  padding: 4px 12px; border-radius: 10px; font: 700 14px/1.2 var(--sans); color: var(--c-ink); text-decoration: none;
}
.cx-switch-link:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
.cx-switch-link[aria-current="page"] { background: var(--c-fill); color: var(--c-on-fill); box-shadow: 0 2px 0 var(--c-slab); text-decoration: none; }

/* ---- the LeetCode style tab (#lc and #practice/lc, app.js renderLC): a hero in the tab's colour (.ph-lc), the
   pattern and difficulty chip rows, then one section per pattern: its intro lesson card, its problem rows (the
   Practice rows) and its checkpoint link ---- */
.lc-h1:focus { outline: none; }
.lc-count { margin: 2px 2px 0; }
.lc-group { margin-top: 22px; }
.lc-group-h { display: flex; align-items: center; gap: 10px; margin: 0 2px 10px; font: 800 var(--fs-h3)/1.2 var(--sans); color: var(--c-ink); }
.lc-group-name { flex: 1; min-width: 0; }
.lc-group-count { flex: none; font: 400 13px/1.3 var(--mono); color: var(--c-muted); }
.lc-lesson { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-left-width: 8px; border-left-color: var(--pc); }
.lc-lesson-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lc-lesson .ui-label { color: var(--c-muted); }
.lc-lesson-title { font: 800 16px/1.2 var(--sans); }
.lc-lesson-line { font: 400 14px/1.35 var(--sans); color: var(--c-muted); }
.lc-check {
  display: inline-flex; align-items: center; min-height: 44px; margin: 4px 2px 0;
  color: var(--c-go-ink); font: 700 14.5px/1.3 var(--sans); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
/* a LeetCode style problem's Solution box (ex.reference) and its optional outside link (ex.goDeeper) */
.ex-reference { margin-top: 8px; }
.ex-reference .ex-complexity, .ex-reference .ex-lesson { margin: 8px 0 0; font: 400 14.5px/1.45 var(--sans); }
.ex-deeper { margin: 12px 0 0; padding: 10px 12px; border: var(--c-bw-sm) dashed var(--c-line); border-radius: 12px; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink); }
.ex-deeper-label { font-weight: 800; }
.ex-deeper a { color: var(--c-go-ink); font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }

/* ---- Learn's Cert Exams tab (#cert, app.js renderCertHub): the folder tabs and a hero in the tab's own
   colour (.ph-cert, --c-p9) like a phase page, then one section per vendor (h2) of cert cards (h3) ---- */
/* the hero has no Continue card: one column, and beside the title only Yuzu while nothing is taken */
@media (min-width: 1100px) {
  .ui-card.phero.cx-hubhead { grid-template-columns: minmax(0, 1fr); }
  .ui-card.phero.cx-hubhead.has-mascot { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "text mascot" "prog mascot"; }
  .phero.cx-hubhead.has-mascot .phero-top .mascot { align-self: center; margin: -6px 4px -6px 0; }
}
.cx-hub .phero { margin-bottom: 16px; }
.cx-openrun { margin: 0 0 14px; }
.cx-vendor { margin: 0 0 22px; }
.cx-vendor-h {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 8px; margin: 4px 2px 10px;
  font: 800 var(--fs-title)/1.15 var(--sans); letter-spacing: -.015em; color: var(--c-ink);
}
.cx-vendor-count { font: 400 13px/1.3 var(--mono); letter-spacing: 0; color: var(--c-muted); }
.cx-vendor-ladder { margin: -4px 2px 12px; font-size: 14px; }
.cx-outline-dom + .cx-outline-dom { margin-top: 16px; }
.cx-outline .exam-list, .cx-ladder .exam-list { margin-top: 6px; }
.cx-certs { display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 700px) { .cx-certs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } }
@media (min-width: 1500px) { .cx-certs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ui-card.cx-certcard { display: flex; align-items: center; gap: 12px; padding: 13px 14px; }
.cx-cc-main { flex: 1; min-width: 0; display: grid; gap: 4px; }
.cx-cc-top { display: flex; align-items: center; gap: 7px; min-width: 0; }
.cx-cc-top .ui-label { color: var(--c-muted); }
.cx-cc-title { margin: 0; font: 800 17px/1.2 var(--sans); letter-spacing: -.01em; color: var(--c-ink); }
.cx-cc-line { font: 400 13.5px/1.4 var(--sans); color: var(--c-muted); }
.cx-cc-prog { display: flex; align-items: center; gap: 10px; margin-top: 2px; }
.cx-cc-count { flex: none; font: 400 12.5px/1.3 var(--mono); color: var(--c-ink-2); white-space: nowrap; }
.cx-cc-prog .segbar { flex: 1; min-width: 48px; max-width: 160px; }
.cx-cc-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 2px; }

/* ---- cert page ---- */
.cx-certgrid { display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); }
.cx-certcol { display: grid; gap: 14px; align-content: start; min-width: 0; }
@media (min-width: 1100px) { .cx-certgrid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; } }
.cx-examlist, .cx-alist { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cx-examrow {
  display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 10px 8px 12px;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px;
  box-shadow: 0 2px 0 var(--c-slab); text-decoration: none;
}
.cx-examrow:hover { text-decoration: none; }
/* the name and its status chip share a line when they fit and stack when they do not; the round arrow stays at the right */
.cx-examrow-main { flex: 1; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.cx-examrow-name { flex: 1 1 auto; font: 700 15px/1.3 var(--sans); }
.cx-examrow .go-arrow { flex: none; width: 28px; height: 28px; margin-left: 0; }
/* the status chip wraps inside its row ("✓ Above our line · est. ≈ 610 · 10 attempts" is wider than a
   320-360 px phone's row): a chip that could not wrap made the whole cert page scroll sideways */
.cx-examrow .st { white-space: normal; text-align: left; }
.cx-ready-line, .cx-weak-line { margin: 0; font: 400 15px/1.45 var(--sans); color: var(--c-ink); }
.cx-ready-note { margin: 8px 0 0; font: 400 13.5px/1.45 var(--sans); color: var(--c-muted); }
.cx-factlist { margin: 0; display: grid; gap: 8px; }
.cx-factlist > div { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 10px; }
.cx-factlist dt { font: 700 12px/1.5 var(--mono); letter-spacing: .05em; text-transform: uppercase; color: var(--c-muted); }
.cx-factlist dd { margin: 0; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink); overflow-wrap: anywhere; }
.cx-checked { margin: 12px 0 0; font: 400 13px/1.45 var(--sans); color: var(--c-muted); }
.cx-arow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; min-height: 44px; padding: 7px 10px;
  color: var(--c-ink); text-decoration: none; border: var(--c-bw-sm) solid var(--c-line-soft); border-radius: 10px;
}
.cx-arow:hover { background: var(--c-raised); border-color: var(--c-line); text-decoration: none; }
.cx-arow[aria-current="page"] { background: var(--c-raised); border-color: var(--c-line); }
.cx-arow-main { flex: 1 1 auto; min-width: 0; font: 400 13px/1.4 var(--mono); }
.cx-arow-end { flex: none; margin-left: auto; display: inline-flex; align-items: center; gap: 10px; }
.cx-arow-score { flex: none; font: 700 13px/1.4 var(--mono); }

/* ---- domains with their weights (intro, cert page) ---- */
.cx-doms { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 12px; }
.cx-dom { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; grid-template-areas: "id name w" ". bar bar"; gap: 5px 8px; align-items: baseline; }
.cx-dom-id { grid-area: id; font: 700 13px/1.3 var(--mono); color: var(--c-ink); }
.cx-dom-name { grid-area: name; font: 600 14.5px/1.3 var(--sans); color: var(--c-ink); }
.cx-dom-w { grid-area: w; font: 700 12.5px/1.3 var(--mono); color: var(--c-ink); }
.cx-dom-bar { grid-area: bar; }

/* ---- intro ---- */
.cx-hero { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; }
.cx-hero .mascot { width: 76px; height: 76px; margin: -6px 0 -8px -6px; }
@media (min-width: 700px) { .cx-hero .mascot { width: 96px; height: 96px; } }
.cx-hero-text { min-width: 0; }
.cx-hero .ui-label { color: var(--c-muted); }
.cx-hero .ui-title { margin: 4px 0 4px; text-wrap: balance; }
.cx-hero-line { margin: 0; font: 400 15px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 0 0 14px; }
.cx-tiles .stat-tile { padding: 10px 10px 12px; }
.cx-tiles .stat-big { font-size: 22px; overflow-wrap: anywhere; }
@media (max-width: 359px) { .cx-tiles { gap: 8px; } .cx-tiles .stat-tile { padding: 9px 8px 10px; } .cx-tiles .stat-big { font-size: 19px; } }
.cx-how, .cx-keys, .cx-covers { margin: 0 0 14px; }
/* compact on a phone, so Start sits above the fold on a 390 x 844 screen (with the tab bar) */
.ui-card.cx-how { padding: 10px 14px 12px; }
.cx-how .exam-list { margin-top: 8px; gap: 6px; font-size: 14.5px; line-height: 1.4; }
.cx-how .exam-list li::before { top: .5em; }
@media (min-width: 700px) { .ui-card.cx-how { padding: 14px 18px 16px; } .cx-how .exam-list { gap: 9px; font-size: 15px; line-height: 1.5; } }
.cx-startbox { display: grid; gap: 10px; margin: 0 0 14px; padding: 12px 14px 14px; }
.cx-time .ui-label, .cx-kind .ui-label { margin: 0 0 8px; color: var(--c-muted); }
.cx-seg { max-width: none; }
.cx-seg .ui-chip { white-space: normal; line-height: 1.15; }
.cx-time-note { margin: 8px 0 0; font: 400 13px/1.4 var(--sans); color: var(--c-muted); }
.cx-notice {
  margin: 0; padding: 10px 12px; background: var(--c-recess); color: var(--c-ink);
  border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px; font: 400 14.5px/1.5 var(--sans);
}
.cx-start { min-height: 52px; font-size: 17px; }
.cx-discard { justify-self: center; }
/* an open attempt no screen can resume (its exam is no longer offered): the banner and its Discard key */
.cx-stale { display: grid; gap: 10px; justify-items: start; margin: 0 0 14px; }
.cx-stale .cx-banner { margin: 0; }
.cx-startbox .cx-stale { margin: 0; }
.cx-best { margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; font: 400 13px/1.4 var(--mono); color: var(--c-ink-2); }
.cx-keys .exam-list { margin: 0 0 12px; font-size: 14.5px; }
.cx-keyseg { max-width: 220px; margin: 0 0 14px; }

/* ---- the run: top bar timer and keys ---- */
.cx-top { margin-bottom: 12px; }
/* in the exam the top bar stays in view: the clock, its five-minute wash and the pause key are never
   scrolled away on a long question (match and order items run to about 1,100 px on a phone). It sits
   under the sheet (70) and the phone's docked footer (30); the shadow paints the notch strip above */
html.lc-exam .cx-run > .cx-top {
  position: sticky; top: 0; z-index: 25; margin-top: -6px; padding: 6px 0; background: var(--c-ground);
  box-shadow: 0 calc(-1 * env(safe-area-inset-top, 0px)) 0 var(--c-ground);
}
/* ...so keyboard focus scrolls clear of it */
html.lc-exam { scroll-padding-top: 76px; }
.cx-timer {
  flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 11px;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-line); border-radius: 12px;
  box-shadow: var(--c-sh-sm); font: 700 15px/1 var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.cx-timer svg { width: 16px; height: 16px; flex: none; }
.cx-tword { font: 700 13px/1 var(--mono); }
.cx-tword:empty { display: none; }
.cx-timer.low { background: var(--c-bad-wash); }                          /* five minutes or less: a wash and the word "left", no pulse */
.cx-timer.untimed { background: var(--c-card); color: var(--c-muted); box-shadow: none; }
.cx-iconkey, .cx-navkey {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 44px; min-height: 44px;
  padding: 0 10px; border-radius: 13px; cursor: pointer; background: var(--c-raised); color: var(--c-ink);
  border: var(--c-bw) solid var(--c-line); box-shadow: var(--c-sh-key); font: 700 13px/1 var(--mono);
  transition: transform .08s ease, box-shadow .08s ease; -webkit-tap-highlight-color: transparent;
}
.cx-iconkey { padding: 0; width: 44px; }
/* the Pause key: the icon and the word, 44 px tall, the same key look as the grid key */
.cx-pausekey {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 44px; min-height: 44px;
  padding: 0 12px; border-radius: 13px; cursor: pointer; background: var(--c-raised); color: var(--c-ink);
  border: var(--c-bw) solid var(--c-line); box-shadow: var(--c-sh-key); font: 700 14px/1 var(--sans);
  transition: transform .08s ease, box-shadow .08s ease; -webkit-tap-highlight-color: transparent;
}
.cx-pausekey svg { width: 18px; height: 18px; stroke-width: 2.6; flex: none; }
.cx-pausekey[hidden] { display: none; }
.cx-pausekey:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; }
@media (hover: hover) { .cx-pausekey:hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); } }
.cx-pausekey:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--c-slab); }
/* a 320 px phone: the topbar title gives way first (it truncates), the key keeps its word */
.cx-run > .cx-top .lrn-topbar-title { min-width: 0; }
.cx-iconkey svg, .cx-navkey svg { width: 18px; height: 18px; stroke-width: 2.6; flex: none; }
.cx-iconkey[hidden], .cx-navkey[hidden] { display: none; }
/* "Q 6/60" and "Q 12/60" take the same width, so the progress bar beside the key never shifts
   between questions (mono digits: 7ch holds "Q 90/90") */
.cx-run .cx-navkey-text { min-width: 7ch; font-variant-numeric: tabular-nums; }
@media (hover: hover) { .cx-iconkey:hover, .cx-navkey:hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--c-slab); } }
.cx-iconkey:active, .cx-navkey:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--c-slab); }
/* the sub-bar: answered and flagged counts over a thin bar, and the grid key */
.cx-sub { display: flex; align-items: center; gap: 12px; margin: 0 0 14px; }
.cx-sub[hidden] { display: none; }
.cx-sub-main { flex: 1; min-width: 0; }
.cx-sub-count { margin: 0 0 6px; font: 400 12.5px/1.3 var(--mono); color: var(--c-ink-2); }
.cx-practice .cx-sub-count { white-space: pre-line; }   /* practice: the running score, then the counts */
.cx-sub .ui-bar { height: 10px; }
/* the progress bars here are spans: make them blocks so their track and fill draw */
.cx-page span.ui-bar, .cx-certpage span.ui-bar { display: block; }

/* ---- the question card ---- */
.cx-qcard { padding: 14px 14px 16px; min-width: 0; }
@media (min-width: 700px) { .cx-qcard { padding: 18px 20px 20px; } }
.cx-qhead { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 10px; margin: 0 0 10px; }
.cx-qnum { margin: 0; font: 800 var(--fs-h3)/1.2 var(--sans); letter-spacing: -.01em; color: var(--c-ink); }
.cx-qtype { margin-right: 3px; }
.cx-stem { font: 400 16px/1.55 var(--sans); color: var(--c-ink); overflow-wrap: anywhere; }
.cx-stem p { margin: 0 0 8px; }
.cx-ask { margin: 14px 0 10px; font: 800 16.5px/1.35 var(--sans); letter-spacing: -.005em; color: var(--c-ink); overflow-wrap: anywhere; }
.cx-qcard code, .cx-take code, .cx-rs code, .cx-dialog code {
  font-family: var(--code); font-size: .92em; color: var(--c-ink); background: var(--c-recess); border-radius: 5px; padding: 0 4px; overflow-wrap: anywhere;
}
.cx-count { margin: 0 0 8px; color: var(--c-muted); }
.cx-answers { min-width: 0; }
.cx-opts { display: grid; gap: 9px; margin: 0; padding: 0; border: 0; min-width: 0; }
.cx-opt { cursor: pointer; }
/* the native input stays focusable but invisible; the whole key is its label */
.cx-in { position: absolute; left: 12px; top: 12px; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.cx-opt.cx-sel, .cx-opt:has(.cx-in:checked) { background: var(--c-fill); color: var(--c-on-fill); }
.cx-opt.cx-sel .qq-key, .cx-opt:has(.cx-in:checked) .qq-key { background: var(--c-on-fill); color: var(--c-fill); border-color: var(--c-on-fill); }
.cx-opt:has(.cx-in:focus-visible) { outline: 3px solid var(--c-focus); outline-offset: 3px; }
.cx-otext { overflow-wrap: anywhere; }

/* exhibits: text only. Logs, configs and code on the code slate under an ink caption bar; tables on the card */
.cx-ex { margin: 14px 0 0; min-width: 0; background: var(--c-code-bg); border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-md); overflow: hidden; box-shadow: var(--c-sh-sm); }
.cx-ex:has(.cx-extable) { background: var(--c-card); }
.cx-excap {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 7px 12px 8px;
  background: var(--c-fill); color: var(--c-on-fill); font: 700 12px/1.35 var(--mono); letter-spacing: .06em; text-transform: uppercase;
}
.cx-extitle { min-width: 0; overflow-wrap: anywhere; }
.cx-exlines { flex: none; }
pre.cx-expre {
  margin: 0; padding: 10px 12px 12px; max-width: none; background: var(--c-code-bg); color: var(--c-code-ink);
  border: 0; border-radius: 0; box-shadow: none; font: 400 13px/1.55 var(--code); white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
}
/* config and code: one block per line with a hanging indent (set per line by renderExhibit), so a wrapped
   value stays under its own key instead of falling back to column 0 */
.cx-expre .cx-exl { display: block; }
/* columns size to their content and words wrap only at spaces (fixed columns with break-anywhere chopped
   "DOWNLOAD" into "DOWNLOA / D" at 390 px); a table wider than the phone scrolls sideways inside its own box */
.cx-extable { padding: 4px 10px 8px; overflow-x: auto; scrollbar-width: thin; scrollbar-color: var(--c-muted) transparent; }
.cx-extable table { width: 100%; table-layout: auto; border-collapse: collapse; font: 400 13.5px/1.4 var(--sans); color: var(--c-ink); }
.cx-extable th, .cx-extable td { text-align: left; vertical-align: top; padding: 7px 6px; border-bottom: var(--c-bw-sm) solid var(--c-line-soft); overflow-wrap: normal; word-break: normal; }
.cx-extable th { font: 700 12px/1.3 var(--mono); letter-spacing: .04em; text-transform: uppercase; border-bottom-color: var(--c-line); }
.cx-extable tr:last-child td { border-bottom: 0; }
/* desktop: an item with an exhibit takes two columns, the exhibit on the left (sticky when it fits).
   The frame never changes width between questions: the run and the review may use up to 1180 px,
   but their top bar, sub-bar, footer keys and every card without an exhibit keep one centred 760 px
   column, and only an exhibit card uses the full width. So Next, Prev, Flag, the timer, the pause key
   and the grid key sit in the same place on every question, with or without an exhibit (they jumped
   about 217 px sideways before, under a running clock). */
@media (min-width: 1100px) {
  .cx-page.cx-run, .cx-page.cx-review { max-width: 1180px; }
  .cx-run > :not(.cx-region):not(.cx-foot):not(.cx-sheet),
  .cx-review > :not(.cx-region):not(.cx-foot):not(.cx-sheet),
  .cx-run .cx-foot-row, .cx-review .cx-foot-row,
  .cx-region > :not(.cx-qcard.has-ex) { max-width: 760px; margin-left: auto; margin-right: auto; }
  .cx-qcard.has-ex {
    display: grid; grid-template-columns: minmax(0, 45fr) minmax(0, 55fr); column-gap: 28px; align-items: start;
    grid-template-areas: "head head" "chips chips" "ex stem" "ex main"; grid-template-rows: auto auto auto 1fr;
  }
  .cx-qcard.has-ex > .cx-qhead { grid-area: head; }
  .cx-qcard.has-ex > .cx-ex, .cx-qcard.has-ex > .cx-exfold { grid-area: ex; margin-top: 0; }
  .cx-qcard.has-ex > .cx-chips { grid-area: chips; }
  .cx-qcard.has-ex > .cx-stem { grid-area: stem; }
  .cx-qcard.has-ex > .cx-qmain { grid-area: main; min-width: 0; }
  /* sticky below whatever stays on top: the app's 64 px topbar (the review, out of focus mode), or the
     exam's own sticky bar in the run */
  .cx-qcard.has-ex > .cx-ex.fits, .cx-qcard.has-ex > .cx-exfold.fits { position: sticky; top: calc(64px + 16px); }
  html.lc-exam .cx-qcard.has-ex > .cx-ex.fits { top: 84px; }
}

/* ---- the footer: ‹ Prev · Flag · Next ›, docked on a phone, under the question on desktop ---- */
.cx-foot {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  background: var(--c-ground); border-top: var(--c-bw) solid var(--c-line);
  padding: 10px 16px calc(10px + var(--ui-tabbar-h, 0px) + var(--ui-safe-b));
}
.cx-foot[hidden] { display: none; }
.cx-foot-row { display: flex; align-items: center; gap: 10px; max-width: 760px; margin: 0 auto; }
.cx-foot .ui-btn { min-height: 48px; flex: none; padding: 0 16px; }
.cx-foot .cx-next { margin-left: auto; }
.cx-flagkey svg { width: 16px; height: 16px; flex: none; }
.cx-flagkey.on { background: var(--c-fill); color: var(--c-on-fill); }
.cx-region { padding-bottom: calc(var(--ui-safe-b) + 92px); }
/* the review ends with the not-affiliated note (after the footer), so on a phone the note carries the room the
   docked footer needs instead of the question region */
@media (max-width: 899px) {
  .cx-review .cx-region:has(~ .cx-note) { padding-bottom: 0; }
  .cx-review > .cx-note { padding-bottom: calc(var(--ui-safe-b) + 92px); }
}
/* Keyboard focus never lands hidden behind the docked footer or the tab bar (WCAG 2.4.11): a
   focused key is scrolled at least this far above the bottom edge. Phones and tablets only; the
   footer is static and the tab bar gone at 900 px and wider. */
@media (max-width: 899px) {
  /* the lesson player: its docked step footer (about 78px with the Skip row) sits on the tab bar */
  html:has(.lrn-stepfoot) { scroll-padding-bottom: calc(88px + var(--ui-tabbar-h) + var(--ui-safe-b)); }
  html:has(.cx-page, .cx-certpage, .cx-hub) { scroll-padding-bottom: calc(var(--ui-tabbar-h) + var(--ui-safe-b) + 12px); }
  html:has(.cx-foot:not([hidden])) { scroll-padding-bottom: calc(84px + var(--ui-tabbar-h) + var(--ui-safe-b)); }
}
html.lc-steps-open .cx-foot { padding-right: calc(16px + var(--lc-sbw, 0px)); }
@media (min-width: 900px) {
  .cx-foot { position: static; margin-top: 20px; padding: 0; background: transparent; border: 0; }
  .cx-foot-row { max-width: none; }
  .cx-region { padding-bottom: 0; }
}

/* ---- the paused card: the questions are removed, resting Yuzu takes their place ---- */
.cx-paused { display: flex; align-items: center; gap: 14px; padding: 18px; }
.cx-paused .mascot { width: 104px; height: 104px; margin: -8px -4px -8px -8px; }
.cx-paused-main { min-width: 0; }
.cx-paused-time { margin: 6px 0; font: 700 20px/1.2 var(--mono); color: var(--c-ink); }
.cx-paused-line { margin: 0 0 14px; font: 400 15px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-resume { min-height: 50px; padding: 0 26px; }
@media (max-width: 480px) { .cx-paused { flex-direction: column; text-align: center; } .cx-paused .mascot { margin: -8px 0 -4px; } }

/* ---- the question grid: 44px cells. Answered = ink fill; not answered = dashed (an empty slot);
   flagged = an ink notch on the corner; you are here = a lifted key with an ink underbar ---- */
/* six 44px columns where they fit, fewer on the narrowest phones (never smaller cells, never a sideways
   scroll); app.js reads the real column count for the arrow keys */
.cx-grid { display: grid; grid-template-columns: repeat(auto-fill, 44px); gap: 10px; justify-content: start; max-width: 322px; padding: 4px 4px 12px; }
.cx-cell {
  position: relative; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; cursor: pointer;
  background: var(--c-fill); color: var(--c-on-fill); border: var(--c-bw) solid var(--c-line); border-radius: 11px;
  box-shadow: 0 2px 0 var(--c-slab); font: 700 13px/1 var(--mono); transition: transform .08s ease, box-shadow .08s ease;
  -webkit-tap-highlight-color: transparent;
}
.cx-cell[hidden] { display: none; }
.cx-cell.e { background: var(--c-card); color: var(--c-muted); border-style: dashed; border-color: var(--c-muted); box-shadow: none; }
.cx-cell.f::after {
  content: ""; position: absolute; top: -6px; right: -6px; width: 12px; height: 12px; border-radius: 4px;
  border: var(--c-bw-sm) solid var(--c-line); background: linear-gradient(135deg, var(--c-fill) 0 55%, var(--c-raised) 55%);
}
.cx-cell.cur { transform: translateY(-3px); box-shadow: 0 5px 0 var(--c-slab); }
.cx-cell.cur::before { content: ""; position: absolute; left: 7px; right: 7px; bottom: -12px; height: 3px; border-radius: 2px; background: var(--c-line); }
@media (hover: hover) { .cx-cell:not(.cur):hover { transform: translateY(-1px); } }
/* review states: correct green ✓, wrong bad-wash ✗, partial ok-wash ½, blank dashed –. The number stays
   the cell's text; the verdict glyph is a badge on the bottom-right corner (the flag notch is top-right) */
.cx-cell.r { background: var(--c-raised); color: var(--c-ink); }
.cx-cell-mark {
  position: absolute; right: -7px; bottom: -7px; box-sizing: border-box; min-width: 20px; height: 20px; padding: 0 3px;
  display: grid; place-items: center; border-radius: 6px; border: var(--c-bw-sm) solid var(--c-line);
  background: var(--c-card); color: var(--c-ink); font: 700 12px/1 var(--mono);
}
.cx-cell.r.ok { background: var(--c-ok); color: var(--c-on-color); }
.cx-cell.r.no { background: var(--c-bad-wash); color: var(--c-ink); border-color: var(--c-bad); }
.cx-cell.r.half { background: var(--c-ok-wash); color: var(--c-ink); border-color: var(--c-ok-ink); }
.cx-cell.r.e { background: var(--c-card); color: var(--c-muted); }
.cx-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: 12px 0 14px; font: 400 12.5px/1.3 var(--mono); color: var(--c-ink-2); }
.cx-lgi { display: inline-flex; align-items: center; white-space: nowrap; }
.cx-lg {
  display: inline-grid; place-items: center; flex: none; width: 18px; height: 18px; margin-right: 6px; border-radius: 5px;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-fill); color: var(--c-on-fill); font: 700 12px/1 var(--mono);
}
.cx-lg.e { background: var(--c-card); border-style: dashed; border-color: var(--c-muted); color: var(--c-muted); }
.cx-lg.f { background: linear-gradient(135deg, var(--c-fill) 0 55%, var(--c-raised) 55%); }
/* "you are here": a lifted key with an ink underbar, drawn like the real cell */
.cx-lg.cur { position: relative; background: var(--c-raised); box-shadow: 0 2px 0 var(--c-slab); transform: translateY(-2px); }
.cx-lg.cur::after { content: ""; position: absolute; left: 2px; right: 2px; bottom: -7px; height: 2px; border-radius: 1px; background: var(--c-line); }
.cx-lg.ok { background: var(--c-ok); color: var(--c-on-color); }
.cx-lg.no { background: var(--c-bad-wash); color: var(--c-ink); border-color: var(--c-bad); }
.cx-lg.half { background: var(--c-ok-wash); color: var(--c-ink); border-color: var(--c-ok-ink); }
/* the sheet (the Steps drawer's look, .lrn-stepsheet): a scrolling body and a docked foot */
.cx-sheet-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 12px 16px 8px 20px; scrollbar-width: thin; scrollbar-color: var(--c-muted) transparent; }
.cx-sheet-foot { flex: none; display: flex; gap: 10px; padding: 12px 16px calc(12px + var(--ui-safe-b)); border-top: var(--c-bw-sm) solid var(--c-line-soft); }
.cx-sheet-foot .ui-btn { flex: 1 1 0; min-height: 48px; padding: 0 10px; }
.cx-sheet .lrn-stepsheet-count { display: block; margin-top: 2px; }
.cx-filt { display: flex; flex-wrap: wrap; gap: 8px; }
.cx-filt .ui-chip { min-height: 44px; }   /* the grid's filters are touch targets like every exam key */

/* ---- review & submit ---- */
.cx-rs .cx-qnum { font-size: var(--fs-title); }
.cx-rs-line { margin: 6px 0 14px; font: 400 15px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-rs-grid { padding: 12px; margin: 0 0 14px; }
.cx-rs-grid .cx-grid { justify-content: center; margin: 0 auto; }
.cx-todo { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 8px; }
.cx-todo-row {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; min-height: 44px; padding: 10px 12px; text-align: left; cursor: pointer;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px;
  box-shadow: 0 2px 0 var(--c-slab); font: 400 14px/1.4 var(--sans);
}
.cx-todo-q { flex: none; min-width: 40px; font: 700 13px/1.4 var(--mono); }
.cx-todo-main { display: grid; gap: 2px; min-width: 0; }
.cx-todo-state { font: 700 12px/1.3 var(--mono); letter-spacing: .04em; text-transform: uppercase; color: var(--c-muted); }
.cx-todo-stem { overflow-wrap: anywhere; }
.cx-rs-actions { display: grid; gap: 10px; margin: 0 0 14px; }
.cx-rs-actions .ui-btn { min-height: 50px; }
.cx-todo-h { margin: 0 0 8px; }
.cx-todo li[hidden] { display: none; }
.cx-todo-more { min-height: 48px; margin: -4px 0 14px; }

/* ---- the submit dialog ---- */
.cx-dialog {
  width: min(440px, calc(100vw - 32px)); padding: 20px; color: var(--c-ink); background: var(--c-card);
  border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r); box-shadow: var(--c-sh);
}
.cx-dialog::backdrop { background: var(--c-scrim); }
.cx-dialog .ui-title { margin: 0; }
.cx-dialog-line { margin: 8px 0 16px; font: 400 15px/1.5 var(--sans); color: var(--c-ink-2); }
.cx-dialog-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.cx-dialog-actions .ui-btn { flex: 1 1 auto; min-height: 48px; }

/* ---- order items: rows with Move up / Move down keys (and a drag grip) ---- */
.cx-order-sub { margin: 0 0 10px; }
.cx-order { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cx-row {
  display: flex; align-items: center; gap: 8px; min-height: 56px; padding: 6px 6px 6px 4px; margin-right: 3px;
  background: var(--c-raised); color: var(--c-ink); border: var(--c-bw) solid var(--c-line); border-radius: 12px; box-shadow: var(--c-sh-key);
}
.cx-grip {
  flex: none; align-self: stretch; width: 22px; min-height: 36px; cursor: grab; touch-action: none;
  background: radial-gradient(circle, currentColor 1.5px, transparent 1.7px) center / 7px 6.5px repeat-y;
}
.cx-rownum {
  flex: none; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 7px;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-panel); font: 700 12px/1 var(--mono);
}
.cx-rowtext { flex: 1; min-width: 0; font: 500 15px/1.35 var(--sans); overflow-wrap: anywhere; }
.cx-rowkeys { flex: none; display: flex; gap: 6px; }
.cx-move {
  width: 44px; height: 44px; display: grid; place-items: center; padding: 0; cursor: pointer;
  background: var(--c-key); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 11px;
  box-shadow: 0 2px 0 var(--c-slab); transition: transform .08s ease, box-shadow .08s ease;
}
.cx-move svg { width: 18px; height: 18px; stroke-width: 2.8; }
.cx-move-up svg { transform: rotate(-90deg); }
.cx-move-down svg { transform: rotate(90deg); }
@media (hover: hover) { .cx-move:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 3px 0 var(--c-slab); } }
.cx-move:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 0 0 var(--c-slab); }
.cx-move:disabled { background: var(--c-dis-bg); color: var(--c-dis-ink); border-color: var(--c-dis-line); box-shadow: none; cursor: not-allowed; }
.cx-row.dragging { opacity: .35; }
.cx-row-ghost { position: fixed; left: 0; top: 0; z-index: 100; margin: 0; pointer-events: none; list-style: none; box-shadow: var(--c-sh-lift); }
/* narrow phones: the two keys stack, so the step text keeps its width */
@media (max-width: 419px) { .cx-rowkeys { flex-direction: column; } }

/* ---- the result ---- */
.cx-result, .cx-review { max-width: 760px; }
.cx-rcol { display: grid; gap: 14px; align-content: start; min-width: 0; }
@media (min-width: 1100px) {
  .cx-result { max-width: 1180px; }
  .cx-rgrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; }
}
@media (max-width: 1099px) { .cx-rgrid > .cx-rcol + .cx-rcol { margin-top: 14px; } }
.cx-rhero { text-align: center; }
.cx-rhero .sess-hero .mascot { width: 96px; height: 96px; }
.cx-rlabel { margin-top: 6px; color: var(--c-muted); }
.cx-verdict { margin: 4px 0; font: 800 var(--fs-title)/1.15 var(--sans); letter-spacing: -.01em; color: var(--c-ink); }
.cx-verdict b { font-weight: 800; }
.cx-points { margin: 0; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-scale { display: block; margin: 34px 6px 4px; text-align: left; }
.cx-scale-track { position: relative; display: block; height: 16px; border: var(--c-bw) solid var(--c-line); border-radius: 8px; background: var(--c-recess); }
.cx-scale-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 5px 0 0 5px; background: var(--c-fill); }
.cx-scale.ok .cx-scale-fill { background: var(--c-ok); }
/* the pass line: the ink colour with a card-coloured halo, so it stays visible where it crosses the
   green fill in every palette (the line colour alone sat too close to the fill) */
.cx-scale-line { position: absolute; top: -7px; bottom: -7px; width: 3px; margin-left: -1.5px; border-radius: 2px; background: var(--c-fill); box-shadow: 0 0 0 2px var(--c-card); }
.cx-scale-pin {
  position: absolute; bottom: calc(100% + 9px); transform: translateX(-50%); white-space: nowrap;
  padding: 2px 7px; border-radius: 6px; background: var(--c-fill); color: var(--c-on-fill); font: 700 12.5px/1.35 var(--mono);
}
.cx-scale-ends { position: relative; display: flex; justify-content: space-between; height: 34px; margin-top: 7px; font: 400 12px/1.35 var(--mono); color: var(--c-ink-2); }
.cx-scale-mid { position: absolute; top: 0; transform: translateX(-50%); text-align: center; white-space: nowrap; }
/* a pass line near an end: its label hangs off the inner side, clear of the "100%" / "900" end label */
.cx-scale-mid.end { transform: translateX(-100%); text-align: right; }
.cx-scale-mid.start { transform: none; text-align: left; }
.cx-estnote { margin: 8px 0 0; text-align: left; font: 400 13px/1.45 var(--sans); color: var(--c-muted); }
.cx-lines { display: grid; gap: 12px; }
.cx-lineitem .ui-label { color: var(--c-muted); }
.cx-lineitem p:last-child { margin: 4px 0 0; font: 400 15px/1.45 var(--sans); color: var(--c-ink); }
.cx-result .cx-tiles { margin: 0; }
.cx-modechip { margin: -4px 0 0; }
.cx-ractions { display: grid; gap: 10px; }
.cx-ractions .ui-btn { min-height: 50px; }
.cx-ractions-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.cx-ractions-row > :only-child { grid-column: 1 / -1; }
.cx-ractions-row:empty { display: none; }
.cx-dlines { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 16px; }
.cx-dtop { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.cx-dname { min-width: 0; font: 700 15px/1.3 var(--sans); color: var(--c-ink); }
.cx-dpct { flex: none; font: 700 13px/1.3 var(--mono); color: var(--c-ink); }
.cx-dmeta { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 6px 8px; margin: 4px 0 7px; font: 400 12.5px/1.3 var(--mono); color: var(--c-muted); }
.cx-dbar > span { background: var(--c-ok); }
.cx-misslist { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 12px; }
.cx-missrow { padding-bottom: 12px; border-bottom: var(--c-bw-sm) solid var(--c-line-soft); }
.cx-missrow:last-child { padding-bottom: 0; border-bottom: 0; }
.cx-misstop { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.cx-missobj { min-width: 0; font: 400 14.5px/1.4 var(--sans); color: var(--c-ink); }
.cx-missobj b { margin-right: 4px; font: 700 13px var(--mono); }
.cx-misscount { flex: none; font: 700 12.5px/1.4 var(--mono); color: var(--c-ink); }
.cx-miss-none { margin: 10px 0 0; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink-2); }
.cx-miss .cx-loading { margin: 12px 0 0; text-align: left; }

/* ---- the review ---- */
.cx-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 14px; }
a.ui-chip.cx-filter { min-height: 40px; padding: 0 12px; text-decoration: none; box-shadow: 0 2px 0 var(--c-slab); position: relative; }
a.ui-chip.cx-filter::after { content: ""; position: absolute; inset: -3px 0; }
a.ui-chip.cx-filter[aria-current="page"] { background: var(--c-fill); color: var(--c-on-fill); }
/* the domain select fills what is left of the chips' last row (it wrapped onto a row of its own
   before, three rows and about 170 px above the question on a phone) */
.cx-dsel {
  flex: 1 1 180px; min-width: 0;
  min-height: 44px; max-width: 100%; padding: 0 10px; border-radius: 10px; cursor: pointer;
  border: var(--c-bw-sm) solid var(--c-line); background: var(--c-raised); color: var(--c-ink); font: 600 14px/1.2 var(--sans);
}
.cx-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.cx-chips .chip svg { width: 12px; height: 12px; }
.cx-exfold { margin: 12px 0 0; min-width: 0; }
.cx-exfold > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; cursor: pointer; list-style: none;
  font: 700 14.5px/1.2 var(--sans); color: var(--c-ink); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.cx-exfold > summary::-webkit-details-marker { display: none; }
.cx-exfold > summary svg { width: 16px; height: 16px; stroke-width: 2.6; flex: none; }
.cx-exfold[open] > summary svg { transform: rotate(90deg); }
.cx-exfold > .cx-ex { margin-top: 4px; }
.cx-rblock { display: grid; gap: 12px; }
.cx-rlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.cx-rnote { margin: 0; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink); }
.cx-ropt { display: grid; gap: 6px; min-width: 0; }
.cx-rbox { padding: 9px 12px 10px; background: var(--c-key); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px; overflow-wrap: anywhere; }
.cx-ropt.ok .cx-rbox { background: var(--c-ok); color: var(--c-on-color); }
.cx-ropt.ok .cx-rbox .qq-key { background: var(--c-on-color); color: var(--c-ok); border-color: var(--c-on-color); }
.cx-ropt.bad .cx-rbox { background: var(--c-bad-wash); color: var(--c-ink); border-color: var(--c-bad); }
.cx-ropt.bad .cx-rbox .qq-key { color: var(--c-bad); border-color: var(--c-bad); }
.cx-ropt.miss .cx-rbox { background: var(--c-ok-wash); color: var(--c-ink); border-color: var(--c-ok-ink); box-shadow: inset 4px 0 0 var(--c-ok-ink); }
.cx-ropt.none .cx-rbox { background: var(--c-card); }
.cx-rhead { font: 400 15px/1.35 var(--sans); }
.cx-rhead::after { content: ""; display: table; clear: both; }
.cx-verd { margin: 5px 0 0; font: 700 12px/1.35 var(--mono); letter-spacing: .05em; text-transform: uppercase; }
.cx-ropt.bad .cx-verd { color: var(--c-bad); }
.cx-rdef { margin: 0; font: 400 15px/1.4 var(--sans); }
.cx-rright { margin: 4px 0 0; font: 400 14px/1.4 var(--sans); }
.cx-why { margin: 0 2px 2px 14px; font: 400 14.5px/1.5 var(--sans); color: var(--c-ink-2); overflow-wrap: anywhere; }
.cx-rdecoy-h { margin: 6px 0 0; color: var(--c-muted); }
.cx-take { margin: 16px 0 0; padding: 12px 14px; background: var(--c-recess); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 14px; }
.cx-take .ui-label { margin: 0 0 6px; }
.cx-take-text { font: 400 15px/1.5 var(--sans); }
.cx-take-text p { margin: 0 0 8px; }
.cx-take-text ul { margin: 0 0 8px; padding-left: 20px; }
.cx-take-text > :last-child { margin-bottom: 0; }
.cx-tip { margin: 8px 0 0; font: 400 14.5px/1.45 var(--sans); }
.cx-take .cx-study { margin-top: 8px; color: var(--c-ink); }
.cx-take .cx-study a { color: var(--c-ink); }   /* on the recess, go-ink is under 4.5:1 in Chunky Play light */

/* ---- practice mode: Check answer, then the verdict (an icon and a word, never color alone: ink on
   the ok or bad wash, the AA pairs the review chips use in all three palettes) ---- */
.cx-checkrow { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin: 14px 0 0; }
.cx-check { min-height: 48px; padding: 0 20px; }
.cx-check-hint { margin: 0; font: 400 13.5px/1.4 var(--sans); color: var(--c-ink-2); }
.cx-pfb { margin: 0 0 12px; padding: 10px 14px 12px; border: var(--c-bw) solid var(--c-line); border-radius: 14px; color: var(--c-ink); background: var(--c-card); }
.cx-pfb.ok { background: var(--c-ok-wash); border-color: var(--c-ok-ink); box-shadow: inset 5px 0 0 var(--c-ok-ink); }
.cx-pfb.half { background: var(--c-ok-wash); border-color: var(--c-ok-ink); }
.cx-pfb.no { background: var(--c-bad-wash); border-color: var(--c-bad); box-shadow: inset 5px 0 0 var(--c-bad); }
.cx-pfb-h { display: flex; align-items: center; gap: 8px; margin: 0; font: 800 18px/1.25 var(--sans); color: var(--c-ink); }
.cx-pfb-h:focus { outline: none; }
.cx-pfb-h:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 3px; }
.cx-pfb-ic {
  flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%;
  background: var(--c-card); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); font: 800 14px/1 var(--mono);
}
.cx-pfb-ic svg { width: 16px; height: 16px; stroke-width: 3; }
.cx-pfb-line { margin: 6px 0 0; font: 400 14.5px/1.45 var(--sans); color: var(--c-ink); }
/* the intro's mode choice sits over the time choice */
.cx-kind { margin: 0 0 14px; }

/* ---- Home and Stats entry points (Learn has its own Cert Exams tab, styled with the hub above) ---- */
.lrn-page .ui-card.act + .lrn-section-label { margin-top: 20px; }
@media (min-width: 1200px) {
  .home-page:has(> .cx-home) {
    grid-template-rows: auto auto auto 1fr auto auto;
    grid-template-areas: "top top" "lvl q" "cta q" "ex q" "a b" "st st";
  }
  .home-page > .cx-home { grid-area: ex; }
}
.cx-stats-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.cx-stats-grid .ui-label { color: var(--c-muted); }
.cx-stats-big { margin: 4px 0 2px; font: 800 22px/1.1 var(--sans); letter-spacing: -.01em; color: var(--c-ink); font-variant-numeric: tabular-nums; }
.cx-stats-weak { margin: 12px 0 0; font: 400 14px/1.45 var(--sans); color: var(--c-ink); }
.cx-stats-link { margin: 8px 0 0; font: 400 14px/1.4 var(--sans); }
@media (max-width: 359px) { .cx-stats-big { font-size: 19px; } }

/* ==== REDUCED MOTION: the one place that switches off press, lift and tilt ====
   Last in the last stylesheet, with !important, because the motion rules above carry
   :not() and hover media queries that out-rank a plain override (keys, answer keys and the
   tab icon still moved under reduce before). Static sticker rotations are not motion and
   stay; the tilt token is 0 (ui.css); styles.css already stops every transition. */
@media (prefers-reduced-motion: reduce) {
  :is(.ui-btn, .btn, .mark-done, .qq-opt, .ui-card.tap, button.ui-chip, .pr-row, .lrn-back-circle,
      .lrn-steps-btn, .lrn-stepsheet-close, .lrn-stepfoot-back, .lrn-cont, .attn-word, .match-chip,
      .cx-opt, .cx-cell, .cx-iconkey, .cx-pausekey, .cx-navkey, .cx-timer, .cx-move, .cx-row):is(:hover, :active),
  .tab-item:active .nav-ic, .match-chip.selected, .match-chip[aria-pressed="true"] { transform: none !important; }
}
/* ...and the same under Settings > Motion > Reduced (html data-motion="reduced") */
:root[data-motion="reduced"] :is(.ui-btn, .btn, .mark-done, .qq-opt, .ui-card.tap, button.ui-chip, .pr-row, .lrn-back-circle,
    .lrn-steps-btn, .lrn-stepsheet-close, .lrn-stepfoot-back, .lrn-cont, .attn-word, .match-chip,
    .cx-opt, .cx-cell, .cx-iconkey, .cx-pausekey, .cx-navkey, .cx-timer, .cx-move, .cx-row):is(:hover, :active),
:root[data-motion="reduced"] .tab-item:active .nav-ic, :root[data-motion="reduced"] .match-chip.selected,
:root[data-motion="reduced"] .match-chip[aria-pressed="true"] { transform: none !important; }

/* ---------- lesson videos ("Watch it", vid/player.js): a card above the lesson, then the player in place ----------
   Every class is xp-*; colours are the theme tokens, so all three palettes follow. The stage is 16:9; Yuzu (.xp-actor) is
   placed by the player in % of the stage; the narration bubble's tail follows Yuzu (--xp-tail). */
.xp-host { margin: 0 0 18px; }
.xp-card { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 12px 14px; background: var(--c-card);
  border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-md); box-shadow: var(--c-sh-sm); }
.xp-card .xp-watch { min-height: 44px; }
.xp-card-text { margin: 0; flex: 1 1 220px; color: var(--c-muted); font-size: 15px; }
.xp-frame { background: var(--c-card); border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r); box-shadow: var(--c-sh); overflow: hidden; }
.xp-stage { position: relative; background: var(--c-chart-surface); border-bottom: var(--c-bw) solid var(--c-line); overflow: hidden; aspect-ratio: 16 / 9; }
.xp-stage > svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.xp-actor { position: absolute; left: 0; top: 0; width: 17%; aspect-ratio: 1; transform-origin: 50% 93%; pointer-events: none; }
.xp-actor .mascot { display: block; width: 100%; height: 100%; }
.xp-fx { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.xp-badge { position: absolute; left: 2.5%; top: 17%; background: var(--c-p3); color: #17140F; border: var(--c-bw-sm) solid var(--c-line); border-radius: 12px;
  box-shadow: var(--c-sh-sm); font-weight: 800; padding: 5px 11px; font-size: clamp(12px, 2.2vw, 17px); opacity: 0; transform: translateY(-12px) rotate(-6deg) scale(.6);
  transition: opacity .3s, transform .45s cubic-bezier(.2, 1.6, .4, 1); }
.xp-badge.on { opacity: 1; transform: rotate(3deg) scale(1); }
.xp-chips { position: absolute; left: 2.5%; top: 4%; display: flex; gap: 8px; flex-wrap: wrap; max-width: 62%; }
.xp-chip { background: var(--c-go-wash); color: var(--c-ink); border: var(--c-bw-sm) solid var(--c-line); border-radius: 999px; padding: 2px 11px; font-weight: 700;
  font-size: clamp(12px, 2vw, 15px); opacity: 0; transform: scale(.5) translateY(8px); transition: opacity .25s, transform .4s cubic-bezier(.2, 1.6, .4, 1); }
.xp-chip.on { opacity: 1; transform: none; }
.xp-say { padding: 14px 14px 12px; }
.xp-bubble { position: relative; background: var(--c-raised); border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-md); box-shadow: var(--c-sh-sm);
  padding: 11px 15px; font-size: clamp(15px, 2.5vw, 19px); line-height: 1.45; min-height: 56px; color: var(--c-ink); }
.xp-bubble::before { content: ""; position: absolute; top: -11px; left: var(--tail, 12%); width: 18px; height: 18px; margin-left: -9px; background: var(--c-raised);
  border-left: var(--c-bw) solid var(--c-line); border-top: var(--c-bw) solid var(--c-line); transform: rotate(45deg); transition: left .25s; }
.xp-bubble.swap { animation: xp-bubblein .3s ease-out; }
@keyframes xp-bubblein { from { opacity: .2; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.xp-w { color: var(--c-muted); transition: color .12s; }
.xp-w.now, .xp-w.done { color: var(--c-ink); }
.xp-w.now { background: var(--c-go-wash); border-radius: 6px; }
.xp-ctrl { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; padding: 10px 14px 12px; border-top: var(--c-bw-sm) solid var(--c-line-soft); }
.xp-btn { font: 700 16px var(--sans); min-height: 44px; min-width: 44px; padding: 0 14px; border: var(--c-bw) solid var(--c-line); border-radius: var(--c-r-key);
  background: var(--c-raised); color: var(--c-ink); box-shadow: var(--c-sh-key); cursor: pointer; }
.xp-btn.go { background: var(--c-go); color: var(--c-on-go); }
.xp-btn:active { transform: translateY(2px); box-shadow: none; }
.xp :is(.xp-btn, .xp-scrub, .xp-vol, .xp-speed, .xp-dot, summary):focus-visible { outline: 3px solid var(--c-focus); outline-offset: 2px; }
.xp-scrub { flex: 1 1 180px; min-width: 120px; accent-color: var(--c-go); height: 28px; }
.xp-vol { width: 104px; accent-color: var(--c-go); height: 28px; }
.xp-speed { font: inherit; min-height: 40px; padding: 4px 8px; border: var(--c-bw-sm) solid var(--c-line); border-radius: 10px; background: var(--c-raised); color: var(--c-ink); }
.xp-time { font: 600 14px var(--mono); color: var(--c-muted); min-width: 84px; text-align: right; }
.xp-dots { display: flex; gap: 6px; padding: 0 14px 12px; flex-wrap: wrap; }
.xp-dot { width: 24px; height: 24px; border-radius: 50%; border: var(--c-bw-sm) solid var(--c-line); background: var(--c-raised); cursor: pointer; padding: 0; }
.xp-dot.done { background: var(--c-ok); } .xp-dot.now { background: var(--c-go); }
.xp-tr { margin: 10px 2px 0; } .xp-tr summary { cursor: pointer; font-weight: 700; min-height: 32px; } .xp-tr p { margin: 6px 0; }
.xp-note { color: var(--c-muted); font-size: 14px; }
.xp-spark-on { animation: xp-sparkle .9s ease-out; transform-box: fill-box; transform-origin: center; }
/* a scene that replays the lesson's own diagram: the figure sits in the stage above Yuzu, scaled down (never up) to fit;
   the newest box gets a highlight ring */
.xp-dgwrap { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.xp-dgwrap .dg { position: absolute; left: 0; top: 0; }
.xp-dgwrap .dg { margin: 0; padding: 0; transform-origin: 0 0; background: transparent; border: 0; box-shadow: none; }
.xp-dgwrap .dg-cap { display: none; }
.xp-dgwrap .xp-focus .dg-face { stroke: var(--c-go); stroke-width: 4; }
@keyframes xp-sparkle { 0% { opacity: 0; transform: scale(.2); } 20% { opacity: 1; } 100% { opacity: 0; transform: scale(1.7); } }
@media (prefers-reduced-motion: reduce) { .xp-badge, .xp-chip, .xp-bubble.swap, .xp-bubble::before { transition: none; animation: none; } }

/* ---------- code tabs: one program in Python, C++ and Rust (app.js enhanceCodeTabs) ---------- */
.codetabs { margin: 14px 0; }
.codetabs-bar { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 6px; }
.codetabs-tab { font: 700 13px/1.2 var(--mono); color: var(--c-ink); background: var(--c-card); border: var(--c-bw-sm) solid var(--c-line); border-radius: 10px; padding: 6px 12px; cursor: pointer; min-height: 32px; }
.codetabs-tab[aria-selected="true"] { background: var(--c-ink); color: var(--c-card); }
.codetabs-tab:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 2px; }
.codetabs-note { font: 400 12px/1.4 var(--sans); color: var(--c-muted); margin: 0 0 6px; }
.codetabs > pre[hidden] { display: none; }
