/* THE LEARN BOARD (BRIEF-80, CJ-169) — the Learn family's own stylesheet.
 *
 * 🔒 WHY THIS IS A SEPARATE FILE AND NOT AN ADDITION TO shell.css. `00 CLAIMS` names shell.css as
 *    the single most collision-prone file in the project — "every layout defect this project has had
 *    lives here" — and `A-34` is what one stale read of it costs. Four sessions write to this tree at
 *    once. A family that ships its own file can be built without opening the shared one at all.
 *
 * 🔒 EVERY CLASS HERE IS PREFIXED `cj-practice`, AND NOTHING HERE OVERRIDES shell.css. That is the
 *    whole rule that makes a second stylesheet safe, and `test/learnStyles.test.ts` fails the build
 *    on either half of it. Two files silently disagreeing about one class is exactly the failure a
 *    second file invites, so it is checked rather than promised.
 *
 * 🔴 AND THE CHECK CAUGHT A REAL ONE ON ITS FIRST RUN. The prefix was `cj-practice` second, not
 *    first: it was `cj-learn`, which the LIVE `/learning` page has owned in shell.css since it
 *    shipped — `.cj-learn__note` was defined in both files, styling two unrelated things, decided by
 *    load order. Nothing would have 404'd or errored; the explanation under a wrong answer would
 *    simply have been drawn as a card from a page it has nothing to do with, and only on the pages
 *    that load both.
 *    🔒 The board is `cj-practice` because it is the BOARD, and `/learning` is the page. Naming them
 *    apart is clearer than the collision was subtle.
 *
 * 🔒 EVERY COLOUR IS A TOKEN, AND THE TOKEN IS ONE THAT EXISTS. `BRIEF-77 §13` makes warm cream, soft
 *    off-white cards, the brand rust as the action colour and a restrained palette MANDATORY, and
 *    bans neon, glossy mobile gradients, explosive particles, casino rewards, flashing WIN labels and
 *    purple-blue tech dashboards. Not one hex literal appears below; the family accent
 *    (`data-accent="learn"`, honey, hue 60°) does the colouring and dark mode comes free.
 *
 * 🔴 THE FIRST DRAFT WROTE `var(--cj-card, var(--card, #fff))` AND BOTH OF THOSE ARE GHOSTS. Neither
 *    `--cj-card` nor `--card` is defined anywhere in tokens.css; the card token is `--cj-surface`.
 *    A ghost variable with a hex fallback is the tip-jar bug exactly — the owner reported on
 *    18 August that the /about panel was invisible at night, because only one of its two colours was
 *    overridden in the dark block — and tokens.css already carries four other "ghosts" found the same
 *    way. It looks perfect in light mode, which is the only mode anyone checks.
 *    🔒 `test/learnStyles.test.ts` now fails on any custom property this file reads that tokens.css
 *    does not define, so the next one is caught by the build rather than by the owner.
 *
 * 🔒 AND NOTHING MEANS ANYTHING BY COLOUR ALONE (`§15`). Right and wrong carry a glyph and a text
 *    note as well as a tint; the jar states carry a fill and a label. That is not only accessibility
 *    — a child who is colour-blind being told they were wrong by a shade they cannot see is the
 *    "wrong answers must not be humiliating" rule failing in the quietest possible way.
 */

/* ------------------------------------------------------------------ the board --- */

.cj-practice {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 46rem;
  margin: 0 auto;
}

.cj-practice__how {
  margin: 0;
  font-size: 1rem;
  color: var(--ink-muted);
}

.cj-practice__set {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  /* Counter, not list-style: the number belongs beside the prompt, and a child reading with a
     screen reader gets it from the <ol> semantics either way. */
  counter-reset: cj-practice-q;
}

.cj-practice__q {
  counter-increment: cj-practice-q;
  position: relative;
  background: var(--cj-surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 1rem 1rem 1rem 3rem;
  /* Soft, not glossy. §13 bans the mobile-game gradient. */
  box-shadow: 0 1px 2px rgb(0 0 0 / 6%);
}

.cj-practice__q::before {
  content: counter(cj-practice-q);
  position: absolute;
  left: 0.75rem;
  top: 0.9rem;
  width: 1.6rem;
  height: 1.6rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-tint);
  color: var(--accent-deep);
  font-size: 0.85rem;
  font-weight: 600;
}

.cj-practice__prompt {
  margin: 0 0 0.75rem;
  /* Large. This is a child reading a maths question on a phone, not body copy. */
  font-size: 1.35rem;
  line-height: 1.35;
  color: var(--ink);
}

/* ------------------------------------------------------------------ answering --- */

.cj-practice__opts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.5rem;
}

.cj-practice__opt {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* 🔒 44px MINIMUM, and it is the option LABEL that is the target, not the radio dot. §15 asks for
     touch targets; a 13px radio with a label beside it technically has one and is unusable at six. */
  min-height: 3rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--cj-surface);
  font-size: 1.15rem;
  cursor: pointer;
}

.cj-practice__opt:hover { border-color: var(--accent); }

.cj-practice__opt input { width: 1.15rem; height: 1.15rem; accent-color: var(--accent); }

/* 🔒 FOCUS IS VISIBLE AND IT IS ON THE LABEL. `:focus-within` rather than `:focus` because the
   focusable element is the radio inside; styling only the radio leaves a keyboard user hunting for a
   3px ring inside a card. */
.cj-practice__opt:focus-within {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.cj-practice__type,
.cj-practice__seq select,
.cj-practice__sortrow select {
  min-height: 3rem;
  padding: 0.5rem 0.75rem;
  font-size: 1.15rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--cj-surface);
  color: var(--ink);
}

.cj-practice__type { width: 100%; max-width: 14rem; }

.cj-practice__type:focus-visible,
.cj-practice__seq select:focus-visible,
.cj-practice__sortrow select:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* Sequence: one slot per position, wrapping. The select is the no-JS fallback AND the accessible
   path; a drag-and-drop board would sit on top of this, never instead of it. */
.cj-practice__seq {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.cj-practice__slot {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  align-items: center;
}

.cj-practice__slotn {
  font-size: 0.75rem;
  color: var(--ink-muted);
}

.cj-practice__sort { display: flex; flex-direction: column; gap: 0.5rem; }

.cj-practice__sortrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  font-size: 1.1rem;
}

/* ------------------------------------------------------ concrete representations --- */
/* §7 CJL-002: questions must not rely entirely on digits. The pips are decorative — the count is in
   the parent's aria-label — so a screen reader hears "8 counters out of 10" and never 10 bullets. */

.cj-practice__visual {
  margin: 0 0 0.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.cj-practice__pip {
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  background: transparent;
}

.cj-practice__pip[data-on="1"] { background: var(--accent); }

/* Ten frame: two rows of five, which is the point of a ten frame — five is seen, not counted. */
.cj-practice__visual[data-shape="tenFrame"] {
  display: grid;
  grid-template-columns: repeat(5, 1.1rem);
  gap: 0.3rem;
  width: max-content;
  padding: 0.35rem;
  border: 1px solid var(--hairline);
  border-radius: 6px;
}

.cj-practice__visual[data-shape="numberLine"] {
  position: relative;
  height: 2rem;
  width: 100%;
  max-width: 22rem;
  border-bottom: 2px solid var(--accent);
}

.cj-practice__mark {
  position: absolute;
  bottom: -0.4rem;
  left: calc(var(--at, 0) * 100%);
  width: 0.7rem;
  height: 0.7rem;
  margin-left: -0.35rem;
  border-radius: 50%;
  background: var(--accent-deep);
}

.cj-practice__visual[data-shape="letterTiles"] {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.6rem;
  letter-spacing: 0.35em;
  color: var(--accent-deep);
}

/* --------------------------------------------------------------- marked state --- */
/* 🔒 A GLYPH, A NOTE AND A TINT — never a tint alone (§15). And no green/red pair carries the
   meaning on its own, because roughly one boy in twelve cannot reliably tell them apart, and the one
   place that must never happen is telling a child they got something wrong. */

.cj-practice__q[data-marked] { border-width: 2px; }

.cj-practice__q[data-marked="right"] { border-color: var(--accent); }
.cj-practice__q[data-marked="wrong"] { border-color: var(--ink-muted); }

.cj-practice__q[data-marked]::after {
  position: absolute;
  right: 0.9rem;
  top: 0.9rem;
  font-size: 1.1rem;
  line-height: 1;
}
.cj-practice__q[data-marked="right"]::after { content: "✓"; color: var(--accent-deep); }
/* ⚠️ NOT A CROSS. A red ✗ beside a nine-year-old's answer is the schoolbook mark this whole family
   is trying not to be; the dot says "this one" and the note says what the answer was. */
.cj-practice__q[data-marked="wrong"]::after { content: "•"; color: var(--ink-muted); }

.cj-practice__note {
  margin: 0.75rem 0 0;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--hairline);
  font-size: 1rem;
  color: var(--ink-muted);
}

.cj-practice__q[data-marked] input,
.cj-practice__q[data-marked] select { opacity: 0.75; }

/* ------------------------------------------------------------------ the bar --- */

.cj-practice__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding-top: 0.5rem;
}

.cj-practice__status {
  margin: 0;
  font-size: 1.05rem;
  color: var(--ink);
}

/* 🔒 THE TWO BUTTONS CARRY `cj-btn` AS WELL, so the shell's button styling does the work and these
 *    rules only size them for a child's hands. That is the correct relationship between the two
 *    stylesheets: shell.css owns what a button IS, this file owns what this board needs it to be. A
 *    per-title sheet that restyled a shared component from scratch would be the collision this whole
 *    arrangement exists to avoid, one indirection further along.
 *
 * ⚠️ These two are added by `learn.js` and exist only when it loads. Without JavaScript the board is
 *    still readable and answerable — it just cannot mark itself — so there is nothing here to style
 *    in that state, deliberately. */
.cj-practice__go,
.cj-practice__next {
  min-height: 3rem;
  padding: 0.6rem 1.2rem;
  font-size: 1.05rem;
}

.cj-practice__next { text-decoration: none; }

/* ------------------------------------------------------------------ the clue --- */
/* 🔒 ONE BUTTON, NO COUNTER, NO COST LINE. The shared allowance panel — "Two free hints and two free
 *    skips… hints run −1%, −3%, −6%, −10%, −15%… a watched advert costs exactly the same as a free
 *    one" — rendered on every Learn rung until `CJ-172`, complete with a Skip button, to whoever was
 *    practising their seven times table. `§4.3` bans artificial scarcity aimed at children, `§4.1`
 *    bans purchase pressure, and naming adverts on a child-directed page is its own problem.
 *
 * ⚠️ The clue button is NOT styled to compete with "Check my answers". Asking for help should look
 *    like a normal thing to do and not like the exciting thing to do — `§4.3` again, from the other
 *    direction. */

.cj-practice__helprow {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-start;
  max-width: 46rem;
  margin: 0 auto;
}

.cj-practice__hint { min-height: 3rem; }

.cj-practice__hintnote,
.cj-practice__hintout {
  margin: 0;
  font-size: 0.95rem;
  color: var(--ink-muted);
  max-width: 42ch;
}

.cj-practice__hintout { color: var(--ink); }

/* 🔒 A HINTED QUESTION IS MARKED, AND MARKED GENTLY. The point is that a child can see which question
 *    the clue was about, and — after marking — why that one is not filling the jar. It is a dotted
 *    keyline and a word in the note, never a warning colour: taking help is allowed here. */
.cj-practice__q[data-hinted] { border-style: dashed; }

/* --------------------------------------------------------------- what it practises --- */
/* Collapsed by default and never hidden. A parent glancing over a shoulder can open it; a child is
   not made to read curriculum language to play (§4.4). */

.cj-practice__what {
  font-size: 0.95rem;
  color: var(--ink-muted);
}

.cj-practice__what summary {
  cursor: pointer;
  padding: 0.5rem 0;
  /* 🔴 `A-34`: a Chrome release shipped the interoperable `<details>` model and took the desktop
     header down, because `::details-content` gets `content-visibility: hidden` and a block box.
     Nothing here depends on `<details>` laying out any particular way — it is a list inside a
     disclosure and nothing more — but it is worth the reader knowing the trap exists in this element.
     🔒 20 Aug, Lane C: CONFIRMED by measurement, not by reading. All nine boards were opened in
     Chromium 140 and Firefox 141 at 400px, 1280px and 1440px; this disclosure lays out identically
     in both, including in the engine that does NOT support `::details-content`. The header did not
     get off so lightly — see `A-98`. */
  /* A-100: 39px high on every one of the nine boards, on the surface aimed at children. */
  display: flex;
  align-items: center;
  min-height: 44px;
}

.cj-practice__what ul { margin: 0.25rem 0 0; padding-left: 1.25rem; }
.cj-practice__what li { margin: 0.2rem 0; }

/* ------------------------------------------------------------------ the jar --- */
/* 🔒 THE MASTERY JAR (CJ-157, BRIEF-77 §6.5) — the five states a child sees instead of the five a
 *    parent does. It is the one item in `BRIEF-77 §28`'s asset queue that is angle 1 AND has no
 *    artwork in `BRIEF-79`, and it turns out to need none: a jar outline and a fill level.
 *
 * 🔴 IT MUST NOT RENDER AT ALL FOR AN UNKNOWN MASTERY. `mastery.ts` keeps `null` distinct from
 *    `"new"` on purpose — an empty jar claims a child TRIED and got nowhere, which is a guess printed
 *    as a fact, and a parent reading it cannot tell the difference. There is deliberately no
 *    `data-jar` value for null; the caller renders nothing. That is `CJ-154`'s job to honour when the
 *    number is finally persisted, and this comment is here to be found on the day it is.
 */

.cj-practice__jar {
  --fill: 0;
  position: relative;
  width: 2.2rem;
  height: 2.8rem;
  border: 2px solid var(--accent);
  border-radius: 0.35rem 0.35rem 0.7rem 0.7rem;
  overflow: hidden;
  background: transparent;
  flex: none;
}

/* The lid, so it reads as a jar rather than a battery meter. */
.cj-practice__jar::before {
  content: "";
  position: absolute;
  inset: 0 0.35rem auto;
  top: -0.15rem;
  height: 0.3rem;
  border-radius: 0.15rem;
  background: var(--accent);
}

.cj-practice__jar::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: calc(var(--fill) * 100%);
  background: var(--accent-tint);
  border-top: 2px solid var(--accent);
}

.cj-practice__jar[data-jar="new"]        { --fill: 0; }
.cj-practice__jar[data-jar="learning"]   { --fill: 0.25; }
.cj-practice__jar[data-jar="practising"] { --fill: 0.5; }
.cj-practice__jar[data-jar="secure"]     { --fill: 0.8; }
.cj-practice__jar[data-jar="mastered"]   { --fill: 1; }

/* 🔒 The label is not optional and is not decoration. Five fill levels are five shades of the same
   tint to a child who cannot see them, so the state is always written next to the jar. */
.cj-practice__jarrow {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0;
}

.cj-practice__jarlabel { font-size: 0.95rem; color: var(--ink); }

/* ------------------------------------------------------------------ motion --- */
/* §15: reduced motion. There is very little to reduce here on purpose — §13 bans hyperactive
   transitions and explosive particles — but the jar fill and the marked state both animate, and a
   child with vestibular sensitivity should not have to sit through either. */

@media (prefers-reduced-motion: no-preference) {
  .cj-practice__jar::after { transition: height 400ms ease-out; }
  .cj-practice__q { transition: border-color 150ms ease-out; }
}

/* ------------------------------------------------------------------ narrow --- */
/* 🔴 `A-32` WAS A LIVE TITLE UNPLAYABLE ON A PHONE THAT 157 TEST FILES COULD NOT SEE, and the
 *    handoff's headline is that nine titles went live without a 400px walk. So the narrow case is
 *    written first-class here rather than left to `auto-fit`: at 400px the options go to one column,
 *    because two 9rem columns plus padding does not fit and the fallback is a horizontal scroll on a
 *    maths question.
 *
 * ⚠️ THIS IS STILL UNWALKED. Written to survive 400px is not measured at 400px, and this project's
 *    own rule is that the difference is the whole point. `CJ-169` is not closed until §7b and §7c run.
 *
 * ✅ WALKED 20 August 2026 (Lane C, `CJ-276`). §7b, §7c and §7d run on all nine boards at 400px,
 *    1280px and 1440px, in Chromium 140 AND Firefox 141: `documentElement.scrollWidth === clientWidth`
 *    on every one, no unlabelled control, no missing alt, no duplicate id, no heading jump. THE
 *    NARROW BLOCK BELOW SURVIVES 400px, measured rather than reasoned. Re-run it yourself with
 *    `node test/browserWalk.mjs <engine> <out.json> test/browserWalk.urls.json`.
 *
 * ⚠️ AND THE HALF THAT IS STILL TRUE: this block turns on at 30rem (480px) and has only ever been
 *    OBSERVED at 400px. The narrow end of its own range — 320px, 360px — remains unwalked, which is
 *    the same sentence this comment opened with, one range down. `CJ-566`, folding into `CJ-556`.
 */
@media (max-width: 30rem) {
  .cj-practice__q { padding: 0.85rem 0.85rem 0.85rem 2.6rem; }
  .cj-practice__prompt { font-size: 1.2rem; }
  .cj-practice__opts { grid-template-columns: 1fr; }
  .cj-practice__seq { gap: 0.35rem; }
  .cj-practice__slot select { min-width: 4.5rem; }
  .cj-practice__sortrow { flex-direction: column; align-items: stretch; }
}
