/* school.css — only what the school pages need.
   ⚠️ A SEPARATE SHEET, not more rules in style.css: style.css is loaded by the
   game on every visit and the school is a page most players never open.
   ⚠️ THE INDEX STYLES ARE GONE — `.mod`, `.lessons`, `.l-title`, `.prog-line`.
   The school stopped being a list of 202 links, and CSS for markup nobody
   writes any more is the kind of thing that survives three redesigns. */
/* ⚠️ THE READING COLUMN, INSIDE THE PAGE FRAME. The frame is the same on every
   page (style.css --page); this is how wide the WORDS get, and it is narrower
   than the frame on purpose. */
/* .wrap-narrow moved to style.css — the guide uses it too and never
   loaded this file, so the class did nothing there. See style.css. */
.free-tag{ display:inline-block; font-size:.8rem; letter-spacing:.08em; text-transform:uppercase; opacity:.7 }

/* ── where am I ──────────────────────────────────────────────────────────
   ⚠️ A POSITION, NOT A SCORE. It says which session out of how many, and it
   never congratulates anybody: people finish what they can see the end of. */
/* ⚠️ THE NAV IS STICKY, so the first thing on the page has to start below it.
   Without this the progress bar sat under the bar and was sliced in half — a
   detail that reads as a broken page rather than as a missing margin. */
/* ⚠️ CJ lessons ui — round 8 review (Женя, 13.09), item 1+2: "уровень / ступень /
   категория" used to be three ideas run into ONE line, and the bar sat BESIDE
   that line with no caption. `.crumb` is a column now, not a row: a small
   trail (group › stage number), the stage's own name as a heading under it,
   then the bar, then the bar's own caption underneath — top to bottom, never
   side by side, so nothing can read as "the bar comes before the level". */
.crumb{ display:flex; flex-direction:column; gap:3px;
        margin:26px 0 22px; opacity:.9 }
.crumb-trail{ margin:0; font-size:.78rem; letter-spacing:.04em; opacity:.7 }
.crumb-sep{ margin:0 .4em; opacity:.65 }
.crumb-stage{ margin:2px 0 0; font-size:1.08rem; font-weight:700; letter-spacing:normal }
.crumb .bar{ width:100%; height:4px; border-radius:2px; margin-top:8px;
             background:rgba(128,128,128,.22); overflow:hidden }
.crumb .bar i{ display:block; height:100%; background:var(--brass-2,#c4a45a) }
.crumb-count{ margin:6px 0 0; font-size:.78rem; letter-spacing:.04em; opacity:.7 }
.crumb .free-left{ display:block; margin-top:4px; color:var(--brass-2,#c4a45a); font-size:.78rem }
/* ── BUG-131 · one door to the contents, one pager at the foot ───────────
   ⛔ WHAT WAS HERE: `.crumb-link` (underlined words inside the crumb) and
   `.lesson-nav` («‹ Попередній · Ця ступінь · Наступний ›», underlined, hard
   against the «ВИМІРЯНО» label below it). Reported 18.09: it reads as three
   stray hyperlinks, not as lesson navigation — and «Ця ступінь» named a thing
   where a control has to name an action. Both classes are gone; see the
   comment over `contentsLink()`/`pager()` in lesson.js for the sources.
   ⚠️ QUIET BUTTONS, NOT UNDERLINED TEXT. `.ghost.small` is the site's own
   quiet button (style.css) — bordered, uppercase, no underline — so these read
   as controls at a glance while the one loud control on the screen stays the
   lesson's own action. */
.lesson-contents{ margin:0 0 4px }
a.contents-link{ gap:.55em; text-transform:none; letter-spacing:.02em }
.contents-glyph{ font-size:1.05em; line-height:1; opacity:.8 }
/* ⚠️ THE LABEL'S AIR, MADE EXPLICIT. Nothing stands between the crumb and the
   «ВИМІРЯНО» eyebrow any more; this floor is what stops a future row
   from quietly closing the gap again. `--gap-actions` is the page's own
   "distance between two controls" token (style.css). */
.crumb + .ch-eyebrow{ margin-top:var(--gap-actions) }
/* The pager: two equal halves, the neighbour's title on its own second line.
   ⚠️ 44px OF HEIGHT (WCAG 2.5.8 with room to spare) and real anchors, so Tab
   reaches both in reading order and a thumb can hit them on a phone. */
.lesson-pager{ display:flex; flex-wrap:wrap; gap:var(--gap-actions);
               margin:30px 0 0; padding-top:18px; border-top:1px solid var(--edge-2) }
.lesson-pager > a, .lesson-pager > .lp-off{
  flex:1 1 44%; min-width:0; min-height:44px; box-sizing:border-box;
  display:flex; align-items:center; gap:.6em; text-decoration:none }
/* The anchors take `.ghost.small`'s own padding (9px 15px, style.css); the
   end-of-level word is not a button and has to match it by hand. */
.lesson-pager > .lp-off{ padding:9px 15px }
.lesson-pager > .lp-prev{ justify-content:flex-start }
.lesson-pager > .lp-next{ justify-content:flex-end }
.lesson-pager .lp-text{ display:flex; flex-direction:column; min-width:0; text-align:left }
.lesson-pager > .lp-next .lp-text{ text-align:right }
.lesson-pager .lp-word{ font-size:.72rem; letter-spacing:.08em; text-transform:uppercase; opacity:.75 }
.lesson-pager .lp-title{ margin-top:3px; font-family:Lato,-apple-system,BlinkMacSystemFont,sans-serif;
                         font-size:.9rem; letter-spacing:normal; text-transform:none; line-height:1.3;
                         color:var(--bone); overflow-wrap:anywhere }
.lesson-pager .lp-chev{ font-size:1.2rem; line-height:1; opacity:.6 }
/* ⚠️ AN END OF THE LEVEL IS A WORD, NOT A DEAD BUTTON — no border, no focus,
   nothing to press: the honest shape for "there is nothing that way" (a
   disabled control is a dead end that looks like a fault). */
.lesson-pager > .lp-off{ border:1px solid transparent; border-radius:3px; color:var(--bone-3); opacity:.55 }
@media (max-width:520px){
  .lesson-pager{ flex-direction:column }
  .lesson-pager > a, .lesson-pager > .lp-off{ flex:1 1 auto }
}
.review-tag{ color:var(--brass-2,#c4a45a) }
.review-foot{ margin-top:18px }
.review-foot a{ text-decoration:underline; text-underline-offset:2px }
/* The reader's own pick from that attempt, beside the right one the painter
   marks: a left edge, never a colour that could be read as "correct". */
.opt.picked{ box-shadow:inset 2px 0 0 var(--bone-3) }

/* ── the door, before the server says where the reader is ────────────────── */
.door-how{ list-style:none; padding:0; margin:18px 0 6px }
.door-how li{ padding:7px 0 7px 18px; position:relative; line-height:1.5 }
.door-how li::before{ content:'·'; position:absolute; left:4px; color:var(--brass-2,#c4a45a) }

/* ── the lesson ──────────────────────────────────────────────────────────── */
/* ⚠️ CJ lessons ui — round 8 review, item 3: the comparison numbers ("54% /
   71%", "pct / avg / base") used to be set at TWO sizes — 2.4rem for the
   highlighted one, 1.6rem for the other two ("otherwise"/"anybody") — which
   is what read as "different height". They keep their meaning (the dimmed
   ones still read as secondary, via colour/opacity only) but now share one
   font-size, one line-height and one baseline, with tabular figures so a "1"
   and a "7" take the same width next to each other.
   ⚠️ STILL `align-items:flex-end`, NOT `baseline`. The label under each number
   reserves a fixed multi-line height (`.lab{min-height:4.35em}`, below) so the
   dots stay lined up on a phone even when one label wraps to more lines than
   its neighbours — lesson-chart-test.mjs's own "three columns, one row" check
   proves this at 360px. `flex-end` aligns every column's BOTTOM edge no matter
   how tall an individual column's content actually is; `baseline` aligns on
   the number's own baseline instead and let a longer-wrapping label push that
   column's bottom edge down past the others — caught by that same test the
   moment it was tried here. The numbers still land on one baseline in
   practice, because flex-end plus one shared font-size/line-height puts the
   same glyph metrics at the same offset from the (now equal) bottom edge. */
.big-num{ font-size:2.4rem; font-weight:700; line-height:1.1; color:var(--brass-2,#c4a45a);
          font-variant-numeric:tabular-nums }
.num-row{ display:flex; gap:26px; flex-wrap:wrap; align-items:flex-end; margin:14px 0 6px }
.num-row .lab{ display:block; font-size:.8rem; opacity:.65; margin-top:2px }
.dim .big-num{ color:inherit; opacity:.5 }
/* Сто точек под числом (lesson.js → dots). Колонки сжимаются, а не переносятся:
   три массива рядом — это и есть сравнение, и на телефоне оно не должно распадаться. */
.num-row.has-dots{ flex-wrap:nowrap; gap:18px; align-items:flex-end }
.num-row.has-dots > div{ flex:0 1 116px; min-width:0 }
/* Подпись занимает три строки всегда: иначе число над короткой подписью стоит
   ниже числа над длинной, и три колонки перестают читаться как одна строка. */
.num-row.has-dots .lab{ line-height:1.45; min-height:4.35em }
.num-row .dots{ display:block; width:100%; max-width:90px; height:auto; margin:8px 0 0 }
.num-row .dots circle{ fill:none; stroke:var(--bone-4,#7C6E5E); stroke-width:1 }
.num-row .dots circle.on{ fill:var(--bone-3,#A2957F); stroke:none }
.num-row .dots.lit circle.on{ fill:var(--brass-2,#A08320) }
.dots-key{ margin-top:4px }

.quiz{ list-style:none; padding:0; margin:0 }
.q{ margin:0 0 22px; padding:0 0 18px; border-bottom:1px solid rgba(128,128,128,.16); list-style:none }
.q:last-of-type{ border-bottom:0 }
.q-lead{ margin:0 0 3px; font-size:1.02rem }
/* ⚠️ THE INPUT TYPE IS NAMED IN WORDS. A checkbox question that looks like a
   radio question is answered wrongly by people who knew the answer. */
.q-kind{ margin:0 0 9px; font-size:.76rem; letter-spacing:.06em; text-transform:uppercase; opacity:.55 }
.opts{ display:flex; flex-direction:column; gap:7px; margin:0 0 4px }
/* True/false is two words, so it sits on one line where there is room. */
.opts.tf{ flex-direction:row; gap:22px; flex-wrap:wrap }
.opts.tf .opt{ min-width:120px }
/* ⚠️ A BROWSER'S DEFAULT RADIO IS 13×13 PIXELS AND THAT IS NOT A TAP TARGET.
   The responsive suite caught ten of them on this page at 360px wide: a person
   answering a quiz on a phone was aiming at something a third the size of the
   smallest thing a finger can reliably hit. The row is the target now — a whole
   line, 44px tall, which is what a thumb actually presses — and the control
   itself is 24px so it can still be seen. */
.opt{ display:flex; gap:11px; align-items:flex-start; cursor:pointer;
      padding:10px 0; min-height:44px }
.opt input{ margin-top:1px; flex:none; width:24px; height:24px; accent-color:var(--brass-2,#c4a45a) }
.q.marked .opt{ cursor:default }
.q.marked .opt.right{ font-weight:600 }
.q.marked .opt.right::after{ content:' ✓'; color:var(--brass-2,#c4a45a) }
/* ⚠️ A MISSED QUESTION IS MARKED IN BRASS, NOT IN RED. Red is the game's kill
   colour and it means somebody died; borrowing it to say "wrong answer" tells a
   learner that being wrong is the same kind of event as losing, which is the
   one belief that stops people answering at all. */
.q.marked.q-miss{ border-left:2px solid rgba(196,164,90,.45); padding-left:12px; margin-left:-14px }
/* ⛔ AND THE OPTION TEXT MAY NOT SHRINK. `.opt` is a flex row of a 24px control
   and a span; the span is `flex:0 1 auto`, so anything that squeezes the row
   squeezes the words instead of wrapping them. It has been squeezed once
   already, by a class collision, and one word per line is not a thing a reader
   should ever see. */
.opt > span{ flex:1 1 auto; min-width:0 }
/* ⚠️ A PUZZLE'S NUMBER/ORDER ANSWER GETS ITS OWN CONTROL, NOT A RADIO ROW —
   but the same 44px tap-target rule from `.opt` above still applies: a
   number field or a dropdown a thumb cannot reliably hit is the same bug
   in a new shape. */
.opts.num, .opts.order{ flex-direction:row; flex-wrap:wrap; gap:10px }
.opt-num input, .opt-order select{
  min-height:44px; min-width:64px; padding:8px 10px; font-size:1rem;
  border:1px solid rgba(128,128,128,.35); border-radius:3px; background:transparent; color:inherit;
}
.opt-num input{ width:120px }
.opt-order{ display:flex; flex-direction:column; align-items:center; gap:3px }
.opt-num.right input, .opts.order.right select{ border-color:var(--brass-2,#c4a45a) }
.opt-num.wrong input, .opts.order.wrong select{ border-color:var(--blood,#8a2c2c) }
.q-why{ margin:8px 0 0; border-left:2px solid var(--brass-2,#c4a45a); padding:2px 0 2px 12px; font-size:.93rem }
.verdict{ margin:18px 0 0; padding:14px 0 0; border-top:1px solid rgba(128,128,128,.22) }
/* CJ lessons ui: bigger, not bolder — size alone keeps the score readable as
   the verdict's own number, without the "two weights in one message" bug the
   round-8 review reported for exactly this line. */
.verdict b{ font-size:1.1rem; font-weight:400 }
.src{ font-size:.82rem; opacity:.6; margin-top:22px; word-break:break-word }
.src a{ opacity:.85 }

/* ── the two ways out, side by side ──────────────────────────────────────── */
.act-bar{ display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin:26px 0 0 }
button.cta{
  display:inline-block; padding:13px 26px; border-radius:3px; cursor:pointer;
  font-family:Lato,-apple-system,BlinkMacSystemFont,sans-serif; letter-spacing:.09em; text-transform:uppercase; font-size:.88rem;
  color:#fff; background:linear-gradient(180deg,var(--blood),var(--blood-2)); border:1px solid var(--blood-2);
}
button.cta:hover{ filter:brightness(1.12) }
button.cta[disabled]{ opacity:.5; cursor:default; filter:none }

/* ── BR actions spacing (round 8) ────────────────────────────────────────
   ⛔ REPORTED: CHECK and "Report a problem" sat ≈8px apart at every width —
   the two read as one stuck control instead of a loud action and a quiet,
   unrelated one below it. Root cause was margin collapsing: `#markNote`,
   the optional due/gate note and `#verdict` all sit between them, and every
   one of the three renders empty far more often than not — an empty box has
   no height, so its top and bottom margins collapse straight through it and
   combine with whatever is on the other side. `.act-bar`'s own margin-bottom
   is already 0, so the entire visible gap was `.sub-hint`'s 7px margin-top,
   landing wherever the chain of empty boxes happened to end.
   ⚠️ PADDING, NOT A BIGGER MARGIN. A bigger margin collapses exactly the same
   way and reproduces the same bug at a new number the next time a note above
   it is empty. Padding is never collapsed, so this floor holds regardless of
   what is empty above it — lesson.js's own comment on this class explains why
   `.sub-hint` stays for colour/size and this rule only overrides the margin.
   `!important`-free: `p.report-row` (element+class, specificity 0,1,1) beats
   `.sub-hint` alone (0,1,0) regardless of which stylesheet loads second, so
   this holds even if a future page reorders the two `<link>` tags. */
/* ⛔ BUG-111 (owner, 17.09.2026) — THE CLASS OUTLIVED THE BUTTON IT WAS NAMED
   AFTER, and it had to: "Report a problem" left this screen (the strip on the
   right edge of every page does that job now), so the line that trails the
   action bar is the copy-guard line instead. The bug this rule fixes is about
   the CHAIN OF EMPTY BOXES above, not about which paragraph happens to come
   last — remove the floor and the next line down inherits the same collapsing
   7px gap. `.lesson-copy` is that line today, so it carries the same floor. */
p.report-row,
p.lesson-copy{ margin-top:0; padding-top:var(--gap-actions) }

/* ── the price ───────────────────────────────────────────────────────────── */
.wall{ padding:26px 0 0 }
.wall h1{ margin:6px 0 10px }
.next-up{ margin:0 0 18px; padding:10px 14px; border-left:2px solid var(--brass-2,#c4a45a);
          background:rgba(196,164,90,.06) }

.votes{ width:100%; border-collapse:collapse; margin:14px 0; font-size:.95rem }
.votes th{ text-align:left; font-weight:600; opacity:.7; padding:6px 8px; border-bottom:1px solid rgba(128,128,128,.3) }
.votes td{ padding:6px 8px; border-bottom:1px solid rgba(128,128,128,.18) }
.votes tr.agree td{ background:rgba(196,164,90,.10) }
@media (max-width:420px){
  .votes{ font-size:.86rem } .votes th,.votes td{ padding:5px 4px }
  .big-num{ font-size:2rem }
  .act-bar{ gap:9px } .act-bar>*{ flex:1 1 auto; text-align:center }
}

/* ⚠️ THE LAST LINK ON THE PAGE IS A TARGET, AND IT WAS 87×19. The accessibility
   suite measured it the day these pages were added to its list: a standalone
   link in its own paragraph is a control somebody has to hit, not prose, so
   WCAG 2.2 SC 2.5.8 applies and 19px of height does not meet it. It is the only
   way off the bottom of a lesson, which makes it the worst one to leave small.
   `.ch-end` was never styled anywhere — these pages inherited a bare <a>. */
.ch-end{ margin-top:34px; padding-top:18px; border-top:1px solid rgba(128,128,128,.16) }
.ch-end p{ margin:0 }
.ch-end a{ display:inline-flex; align-items:center; min-height:24px; padding:5px 0 }

/* ⚠️ THE ONE FACT THAT MAKES SOMEBODY CURIOUS. It used to sit on the front door
   inside a bordered card below five paragraphs, which is why it was reported as
   not selling and getting lost. Here it is the second thing on the page a
   person reaches by pressing Learn — and the number is read from the sweep by
   the generator, so it cannot drift from what the course measured. */
.ch-proof{ margin:14px 0 0; padding:12px 0 0; border-top:1px solid rgba(128,128,128,.16);
           color:var(--bone-2); font-size:.95rem; line-height:1.6 }
.ch-proof b{ color:var(--brass); font-size:1.08rem }

/* CH nav lists — the guide's two chapter links, and any other "pick a page"
   list built the same way: a card each, because a chapter is a decision and a
   bare underlined line is not.
   ⚠️ 2026-09-13 — REPORTED AS "the whole item reads gold and underlined, and
   nobody could tell it was a link to another page" (review, guide.ru, 1440).
   Root cause: the title (`b`) was --brass at rest with no other cue, so colour
   was the ONLY signal it was a link — exactly what WCAG 1.4.1 forbids, and
   NN/g's "Guidelines for Visualizing Links" warns reads as decoration, not
   affordance, the moment a page has more than one gold thing on it. Owner's
   decision: links read --bone at rest, --brass only on hover/focus. Research
   (5 sources, docs/UX/2026-09-13---ССЫЛКИ-ПЕРЕХОДЫ--практика.md — NN/g, WCAG
   1.4.1 + 2.4.4, GOV.UK Design System "Links", Material lists, Apple HIG
   disclosure rows) converges on: the row is a title-link + a plain caption + a
   trailing arrow, and the link keeps a second, non-colour cue (a thin
   underline) at rest. So `b` carries the underline and the colour swap; `span`
   (the caption) never underlines, so the row reads as "heading + sentence",
   not as one solid block of link. */
.guide-list{ list-style:none; padding:0; margin:16px 0 0 }
.guide-list li{ margin:0 0 12px }
.guide-list a{ display:block; padding:14px 16px; border:1px solid var(--brass-2);
               border-radius:4px; text-decoration:none; color:inherit;
               background:linear-gradient(180deg, rgba(201,162,39,.07), rgba(201,162,39,.02));
               transition:border-color .15s, background .15s }
.guide-list a:hover, .guide-list a:focus-visible{
  border-color:var(--brass); background:linear-gradient(180deg, rgba(201,162,39,.13), rgba(201,162,39,.04)) }
.guide-list b{ display:block; color:var(--bone); font-size:1rem; margin:0 0 5px;
               text-decoration:underline; text-decoration-color:currentColor;
               text-decoration-thickness:1px; text-underline-offset:3px /* same offset as .back-to-game */ }
.guide-list a:hover b, .guide-list a:focus-visible b{ color:var(--brass) }
.guide-list span{ display:block; color:var(--bone-2); font-size:.9rem; line-height:1.55; text-decoration:none }

/* ⚠️ A SESSION ALREADY PASSED SAYS SO, ABOVE EVERYTHING ELSE ON THE PAGE.
   Quiet — brass on the page's own ground, no box — because it is a fact about
   the reader's history, not an instruction and not an award. */
/* CJ lessons ui: no more `.already b` — the note's <b> was removed at the
   source (lesson.js), so this line reads at one weight, one colour. */
.already{ margin:0 0 14px; font-size:.88rem; color:var(--bone-3,#a2957f) }

/* ── what the wall may say about a locked session ──────────────────────────
   ⛔ THIS WAS A PREVIEW CARD SHOWING THE SESSION'S OPENING LINE AND ITS TWO
   MEASURED PERCENTAGES, and the school gate refused it: on a measured session
   the number IS the lesson, so a wall printing it gives the session away and
   then asks for money. What is left names the KIND of session and where it
   sits in the course — an expectation, not an answer. */
.taste-nums{
  margin:14px 0 4px; font-size:.82rem; letter-spacing:.06em;
  text-transform:uppercase; opacity:.6;
}

/* ── Схема или картинка внутри урока ────────────────────────────────────────
   ⚠️ Ширина ограничена шириной ЧИТАТЕЛЬСКОЙ колонки, а не экрана: схема шире
   текста заставляет глаз прыгать между двумя разными ширинами на одной странице.
   Фон белый всегда — mermaid экспортируется с прозрачностью, и в тёмной теме
   чёрные подписи на тёмном фоне становятся невидимыми. */
.ch-art{margin:26px 0;text-align:center}
.ch-art img{max-width:100%;height:auto;border-radius:10px;background:#fff;padding:14px;
  box-shadow:0 1px 3px rgba(0,0,0,.25)}
.ch-art figcaption{margin-top:9px;font-size:.86rem;line-height:1.45;color:var(--bone-3);
  max-width:44ch;margin-left:auto;margin-right:auto}
@media (max-width:520px){.ch-art{margin:18px 0}.ch-art img{padding:8px}}

/* ── the generated diagram (src/client/diagrams.js) ──────────────────────────
   ⚠️ NO FIXED PIXEL WIDTH ON THE SVG ITSELF — every one of the six generators
   sets its own viewBox and `width="100%"`, so the picture scales to whatever
   this box is. Capped at the reading column's own width, same reasoning as
   `.ch-art` above — one picture, one width, on every page it appears on, at
   390px included (tests/browser/lesson-flow-test.mjs checks this in a page). */
.ch-diagram{margin:24px 0;text-align:center}
.ch-diagram svg{max-width:min(100%,320px);height:auto;display:inline-block}
.ch-diagram figcaption{margin-top:9px;font-size:.86rem;line-height:1.45;color:var(--bone-3);
  max-width:44ch;margin-left:auto;margin-right:auto}
@media (max-width:520px){.ch-diagram{margin:16px 0}.ch-diagram svg{max-width:100%}}
/* A crossing question's OWN scene/diagram (levels.mjs buildLevelTest) sits
   inside one short `.q`, not under a whole lesson's heading — tighter than
   the lesson-level `.ch-diagram` above so it doesn't read as its own section. */
.q .q-diagram{margin:10px 0}
.q .q-scene{margin:0 0 8px}

/* ⚠️ АБЗАЦ ИЗ ОДНОЙ ССЫЛКИ — ЭТО КНОПКА, А НЕ ПРЕДЛОЖЕНИЕ. WCAG 2.5.8 освобождает от
   размера цели ссылку ВНУТРИ текста, потому что слово в строке не сделать высоким.
   Но «Create an account to keep your progress» стоит одна в своём абзаце, и была
   17 пикселей в высоту — a11y-test её поймал. Текст не меняется, растёт зона нажатия. */
.sub-hint > a:only-child{ display:inline-flex; align-items:center; min-height:44px }

/* ⚠️ THE FEDERATION BOX IS A MARKED CALLOUT, NOT A THEORY PARAGRAPH — RULE 4e
   §2 (one highlighted sentence per lesson) is about the lesson's own prose;
   this is UI chrome around a citation, same family as .quota/.turn-who in
   style.css, reusing their brass-accent card rather than inventing a new one.
   Lives here rather than in style.css because only the school (this file)
   ever renders it — school.css already falls back with its own hex when a
   variable from style.css is missing, same pattern as the rest of the file. */
.fed-box{
  margin:14px 0; padding:10px 14px; border-left:2px solid var(--brass-2,#c4a45a);
  background:rgba(201,162,39,.06); border-radius:0 3px 3px 0;
}
.fed-box p{ margin:0 0 6px; }
.fed-box p:last-child{ margin-bottom:0; }
.fed-box a{ color:var(--bone,#EFE7D8); }   /* BUG-63: white at rest, brass on hover (sitewide a:hover) */
.fed-note a{ color:var(--bone-3,#8a8580); }

/* ⚠️ BUG-143 (owner, 18.09.2026) — the switcher's question and its `<select>`
   share one `<p class="fed-switch">` (lesson.js), text node then element, so
   with no rule here the select sits flush under the question the moment it
   wraps to its own line — no space at all between "Playing under a different
   rulebook?" and the dropdown, in every language. `display:block` forces the
   select onto its own line always (not only when the text happens to wrap),
   and `--gap-actions` — the page's own token for "distance between one action
   and the next", already used by `.lesson-pager` and `.cur-list` above — is
   the margin, never a new number. */
.fed-switch select{ display:block; margin-top:var(--gap-actions); }

/* ── CJ lessons ui — round 8 review, item 4 ──────────────────────────────────
   ⚠️ "не надо в одном сообщении менять текст по весу" — RULE: THE FIX IS IN
   src/client/lesson.js, NOT HERE, AND ON PURPOSE. The first pass of this fix
   was a blanket `.lesson-body p b{font-weight:400}`, and it was wrong: it also
   un-bolded the theory's own **highlighted sentence** — RULE 4e §2, two lines
   above in `.fed-box`'s own comment ("one highlighted sentence per lesson…
   is about the lesson's OWN PROSE"), a cited, tested, deliberate signaling
   technique (Mayer & Fiorella, d≈0.7) that this exact codebase already
   distinguishes from UI chrome. A CSS selector cannot tell "the one sentence
   the lesson author chose to highlight" apart from "an ordinary theory
   paragraph" — both are a bare `<p>` with no distinguishing class — so the
   fix had to move into the generator: `.already`, the flips/englishOnly/
   clears/convicts notes, `When:`/`Where to look:`, the post-quiz verdict
   score+comment, "reread"/"seeIt" and the positions-answer bold verdict word
   all had their `<b>` markup REMOVED at the source (see lesson.js) — never
   wrapped in `**…**` in the first place, so `rich()`'s theory-only bolding is
   completely unaffected. Short WHOLE-line labels (`.fed-box`'s own name line,
   `.src`, `.next-up`, a practice title, a badge name) keep their bold: they
   are single labels, not a sentence mixing two weights, and RULE 4e's own
   language calls that "UI chrome", not "the lesson's own prose". */

/* BUG-49 (Женя, 16.09): lesson prose in one secondary colour — a <b> keeps
   its place in the sentence, not a brighter colour or a heavier weight. */
.lesson-body p, .lesson-body li{ color:var(--bone-2); }
.lesson-body p b, .lesson-body p strong, .lesson-body li b, .lesson-body li strong{ color:inherit; font-weight:inherit; }

/* BUG-64 (owner, 16.09): "Answer every question first." clears when the last
   answer lands — but the line keeps its height, so nothing under it jumps. */
#markNote{ min-height:1.5em; display:block; }
/* BUG-67: a spent Check bar or note never keeps its room */
#actBar[hidden], #markNote[hidden]{ display:none; }

/* ── THE COURSE LANDING (/learn.html, 12 blocks) ───────────────────────────
   ⚠️ THE PAGE IS HELD BACK ONLY FOR A READER WE ALREADY BELIEVE IS MID-COURSE.
   `learn.js` adds this class in <head> when `mafia.started` is set, and takes
   it off the moment the server has said where that reader goes — so the one
   person who is about to be sent to their own lesson never sees a frame of a
   page selling them the course. A first-time visitor gets no class at all and
   the landing paints immediately: it IS the page, not a placeholder.
   ⚠️ THE KEYFRAME IS THE BELT, NOT DECORATION — same idiom as `appReveal` in
   style.css. If learn.js throws before it can show the page, the stylesheet
   reveals it anyway at 3s. A reveal that depends on script is a blank page. */
html.school-redirect body{ visibility:hidden; animation:learn-reveal 0s linear 3s forwards }
@keyframes learn-reveal{ to{ visibility:visible } }

/* A block of the landing: its own heading, a hairline above it, and the
   reading column's width — the same shape `.ch-proof-below` already had, which
   is why the two share their heading rule in style.css. */
.ch-block{ margin-top:30px; padding-top:22px; border-top:1px solid var(--edge-2); max-width:64ch }
.ch-block > h2{
  margin:0 0 12px; font-family:Bitter,Georgia,serif; font-weight:600;
  font-size:1.3rem; line-height:1.2; color:var(--bone);
}
.ch-block .door-how{ margin-top:6px }
.lang-row{ margin-top:20px }

/* ── block 6 · the programme, ten folded levels ────────────────────────────
   ⚠️ A SHUT `<summary>` HAS TO CARRY ENOUGH TO DECIDE WITH (NN/g, progressive
   disclosure): the step number, the level's name, which group it belongs to,
   how many sessions it holds, and whether it is the free one. */
details.fold.lvl{ margin-bottom:9px }
.fold.lvl > summary{ gap:9px }
.fold.lvl .lvl-n{ font-family:"JetBrains Mono",monospace; font-size:.78rem;
                  color:var(--bone-3); flex:none; min-width:1.3em }
.fold.lvl .lvl-t{ color:var(--bone); font-weight:600 }
.fold.lvl .free-tag{ flex:none; color:var(--brass-2,#c4a45a); opacity:1 }
.cur-item{ margin:12px 0 0; font-size:.93rem; line-height:1.5; color:var(--bone-2) }
/* ⚠️ A ROW THAT IS ENTIRELY ONE LINK IS A BUTTON IN A LINK'S CLOTHES (WCAG 2.2
   SC 2.5.8 — the inline exception covers a word inside a sentence, not this). */
.cur-item a{ display:inline-block; min-height:24px; padding:4px 0 }
.cur-idea{ display:block; margin-top:2px; color:var(--bone-3); font-size:.87rem; line-height:1.5 }
.cur-meta{ margin-top:14px }
/* ── BUG-126 · the map's three states ──────────────────────────────────────
   ⚠️ QUIET, ALL THREE. This page has ONE loud thing on it and it is the price
   button; a map is a place to look, not a place to be pushed. The tick and the
   "you are here" line are both drawn in the brass the rest of the school uses
   for a position marker (see `.crumb .bar i`), never in the red that means
   "press this".
   ⚠️ THE TICK IS DECORATION AND THE WORD IS THE STATE — the glyph carries
   aria-hidden, the `.cur-state` word is what a screen reader reads. */
.cur-mark{ display:inline-block; min-width:1.1em; margin-right:.35em;
           color:var(--brass-2,#c4a45a); font-weight:700 }
.cur-state{ display:block; margin-top:1px; font-size:.78rem; letter-spacing:.04em;
            color:var(--bone-3); opacity:.85 }
.cur-item.is-current{ color:var(--bone) }
.cur-item.is-current > a{ font-weight:700 }
.cur-item.is-current .cur-state{ color:var(--brass-2,#c4a45a); opacity:1 }
/* ⛔ BUG-110 (owner, 17.09.2026) — "the intro line sits flush against the first
   level card". PADDING, not margin, and from the existing token rather than a
   number invented for this one block: a margin between a `.sub-hint` and a
   `<details>` collapses through an empty box exactly the way `--gap-actions`
   own note in style.css describes, and the gap then depends on whatever
   happens to be between them. */
.cur-list{ padding-top:var(--gap-actions) }
