/* shared/ks4-lesson.css — GENERATED by build_ks4.py: every distinct <style> block found in the
   <helmet> of the 14 lessons + 11 blocks, deduplicated (exact text match), first-seen order.
   Never hand-edit; re-run build_ks4.py. */

/* from ks4-chemistry-5.2.1.1-chemical-bonds.dc.html */
html, body { margin: 0; padding: 0; background: #FBF3E6; }
  a { color: var(--ks3-accent-text); }
  a:hover { color: var(--ks3-accent-hover); }
  @keyframes ks4-arrive { 0% { transform: translateY(6px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
  [data-arrive] { animation: ks4-arrive .34s ease-out both; }
  @media (prefers-reduced-motion: reduce) { [data-arrive] { animation: none !important; } * { transition: none !important; } }
  button:focus-visible, a:focus-visible, select:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--ks3-accent-text); outline-offset: 2px; }

/* from ks4-chemistry-5.2.2.4-properties-small-molecules.dc.html */
html, body { margin: 0; padding: 0; background: #FBF3E6; }
  a { color: var(--ks3-accent-text); }
  a:hover { color: var(--ks3-accent-hover); }
  @keyframes ks4-arrive { 0% { transform: translateY(6px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
  [data-arrive] { animation: ks4-arrive .34s ease-out both; }
  @media (prefers-reduced-motion: reduce) { [data-arrive] { animation: none !important; } * { transition: none !important; } }
  button:focus-visible, a:focus-visible, select:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--ks3-accent-text); outline-offset: 2px; }
  input[type="range"] { accent-color: #A93411; }

/* from Ks4Chrome.dc.html */
[data-rail="side"] { display: none; }
  @media (min-width: 1340px) { [data-rail="side"] { display: block; } [data-rail="top"] { display: none !important; } }

/* from Ks4Choice.dc.html */
@keyframes ks4-arrive { 0% { transform: translateY(6px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
  [data-arrive] { animation: ks4-arrive .34s ease-out both; }
  @media (prefers-reduced-motion: reduce) { [data-arrive] { animation: none !important; } }

/* from Ks4Sort.dc.html */
@keyframes ks4-arrive { 0% { transform: translateY(6px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
  [data-arrive] { animation: ks4-arrive .3s ease-out both; }
  @media (prefers-reduced-motion: reduce) { [data-arrive] { animation: none !important; } }

/* ⊕ D8 (theme-run audit, 27 Sep 2026) — every rule below is guarded inside
   `@media screen`. All five fixes key off `[data-theme="dark"]` (directly,
   or via `html[data-theme="dark"] body`'s inherited colour), and the
   attribute is unconditional — it is written by THEME_HEAD/theme.js on
   every load of every one of these 54 pages, in EVERY medium, including
   print. Un-guarded, printing a pilot page in dark mode printed the dark
   ground (`html[data-theme="dark"] body`'s own rule a few lines down being
   the clearest case: it sets print's own text colour to the dark-mode
   cream) with "print background graphics" on, or faint low-contrast text
   without it — both wrong; rule 7 is print stays light text on white
   regardless of the viewed theme. Matches the guard `shared/ks3-theme.css`
   already uses for the identical reason. */
@media screen {
/* ⊕ KS4-DARK-1 (DEPARTURES-PILOT.md) — disabled .ks3-reveal-btn/.ks3-retry
   measured 2.01:1 in dark mode (contrast_audit.py, disabled-control floor
   3.0). Design's own compiled Component sets `style="opacity:.45"` inline
   per instance when a control is disabled; that inline opacity fades an
   (in dark mode) light-cream fill and a near-black label toward the same
   dark page ground by the SAME factor, collapsing their mutual contrast
   from ~16:1 down to ~2:1. Only `!important` in a stylesheet can outrank
   an inline style, so this raises that one number. .7 keeps the control
   visibly duller than its enabled (opacity 1) state — still reads as
   "disabled" — while composited contrast clears the floor: measured
   4.57:1.

   ⊕ THEME RUN (26 Sep 2026) — UNGATED from dark-only, having measured the
   IDENTICAL collapse in LIGHT mode (1.60:1, same floor 3.0) the first time
   this run's `contrast_audit.py --themes light,dark` actually reached a
   disabled control on these 54 pages. The mechanism is symmetric, not
   theme-specific: these buttons' filled/label pair is (fill=--ks3-ink,
   label=--ks3-ground) in EITHER theme — a near-black fill under
   cream-coloured label text — and `--ks3-ground` in light mode IS the
   page's own cream ground, so opacity-fading the label toward that same
   page ground converges label-onto-page just as catastrophically as the
   dark-mode case converges it onto the dark ground. This was not
   introduced by the theme run; it is a pre-existing defect this run's
   dual-theme, real-disabled-state measurement was the first thing to
   surface (Decisions/Deviations, ks4-pilot theme-run report). One
   unconditional rule now covers both floors: measured 4.57:1 dark,
   3.03:1 light.

   `.ks3-check-btn:disabled` joins the same rule for the same reason,
   found by the same sweep — a ghost-style button (cream fill, ink label,
   ~12:1 apart) whose SAME opacity:.45 fade collapses it to 2.76:1 in
   LIGHT mode only (its dark pairing already cleared the floor at .45,
   so raising it here only widens that margin, never regresses it). */
.ks3-reveal-btn:disabled,
.ks3-retry:disabled,
.ks3-check-btn:disabled {
  opacity: .7 !important;
}

/* ⊕ KS4-DARK-2 (DEPARTURES-PILOT.md) — the end-matter `.ks3-tutor` card's
   h2/p measured 2.35:1 in dark mode (floor 3.0, both text large enough to
   qualify — see ks4-ds.css's own comment on the 19px/700 reclassification
   for the light-mode equivalent of this exact defect). `--ks3-ink` (light
   cream, #F3ECE0) and `--ks3-accent` (#F07A4E) BOTH flip light under the
   dark remap, so ink-on-accent — dark text on a mid orange in light mode —
   becomes light-on-light in dark mode. `--ks3-on-dark` (#16120E) is
   Design's own token for precisely this situation ("ink-filled controls
   ...flip to light fills in dark mode, so their label flips dark",
   shared/ks4-theme.css) — the accent card is exactly such a filled, bright
   surface. Measured 6.74:1. Nothing minted. */
.rd[data-mode="ks3"][data-theme="dark"] .ks3-endmatter .ks3-tutor h2,
.rd[data-mode="ks3"][data-theme="dark"] .ks3-endmatter .ks3-tutor p,
[data-theme="dark"] .rd[data-mode="ks3"] .ks3-endmatter .ks3-tutor h2,
[data-theme="dark"] .rd[data-mode="ks3"] .ks3-endmatter .ks3-tutor p {
  color: var(--ks3-on-dark);
}

/* ⊕ KS4-DARK-3 (DEPARTURES-PILOT.md) — the Ks4Write rung's bare
   `<textarea>` AND the FIFA-method calc rungs' bare `<input>` fields
   (Ks4Choice/Ks4Cfifa's per-line numeric/formula inputs, e.g.
   `#np-q1-line0`, `#<slug>-r2n`) carry no `::placeholder` rule anywhere in
   ks4-ds.css or ks4-theme.css, so both fall through to Chrome's own
   UA-default placeholder grey (~#757575) — measured 3.75:1 on
   `--ks3-card` (textarea) and 4.04:1 on `--ks3-ground` (input) in dark
   mode, both under the 4.5 floor for ordinary text (placeholders are real
   informational text a student reads, per this gate's own docstring).
   Found on all 14 lessons, not just the one this job's contrast_audit
   --only run first measured — contrast_audit.py --quick --gate --only
   "ks4 pilot" (job 4's full-pilot sweep) is what surfaced the `<input>`
   half of this; the fix is the SAME defect, same cause, one extra
   selector. `--ks3-ink-muted` is the SAME token the Write rung's own
   "Your answer" label immediately above its textarea already uses, so
   reusing it here gives every placeholder a properly
   de-emphasized-but-legible tone consistent with that label. Measured
   8.66:1 on --ks3-card, 9.35:1 on --ks3-ground. Nothing minted.

   ⊕ THEME RUN (26 Sep 2026) — UNGATED from dark-only, having measured the
   SAME UA-default placeholder grey failing in LIGHT mode too (4.18:1 on
   --ks3-ground, 4.50:1 on --ks3-card — both under the 4.5 floor; not
   introduced by this run, the same pre-existing gap KS4-DARK-1 above
   turned out to have). `--ks3-ink-muted` already carries its OWN correct
   value in EITHER theme (5.6:1 on light --ks3-ground per its own token
   comment, 8.66/9.35:1 in dark per this rule's original measurement), so
   ONE unconditional rule — not two theme-gated copies — is both correct
   and sufficient: the token resolves per-theme on its own. */
.rd[data-mode="ks3"] input::placeholder,
.rd[data-mode="ks3"] textarea::placeholder {
  color: var(--ks3-ink-muted);
  opacity: 1;
}

/* ⊕ KS4-DARK-4 (THEME RUN, 26 Sep 2026) — the tutor chat overlay
   (#chatOverlay, build_ks3.KS3_CHAT_OVERLAY, mounted verbatim by every one
   of these 54 pages' tutor_block()) ships with NO stylesheet of its own —
   its rules (`.chat-head-info h3`, `.chat-modal`, …) live only in
   shared/styles.css, which these pages do not load (a pre-existing,
   unrelated gap: KS3 lesson pages load it, KS4 pilot pages never have).
   So every one of those rules is a no-op here, and the overlay's h3/p
   render with NO explicit colour of their own — they simply INHERIT
   `body`'s, which ks4-ds.css sets, unscoped, to `--st-ink` (a 3D-Studio
   token bundled in from Design's concatenated tokens export, landing here
   only because build_ds_css() ships her whole chain). `--st-ink` carries
   no dark remap anywhere in this file, so in dark mode the overlay's text
   stayed the SAME near-black (#1A1714) while its background — composited
   straight through, since every layer between it and `body` is
   transparent — correctly followed body's OWN dark ground (#16120E, this
   file's own `html,body` rule below): 1.04:1. `#chatOverlay` sits OUTSIDE
   `.rd[data-mode="ks3"]` (a sibling of #ks4-mount, both direct children of
   `body`), so it cannot see `--ks3-ink`'s `.rd`-scoped dark remap by
   inheritance — CSS custom properties cascade down a subtree, never
   sideways to a sibling — so the value below is that SAME dark ink
   (#F3ECE0, shared/ks4-theme.css) written literally, because the custom
   property itself is out of scope at `body`. Nothing else lives directly
   under `body` outside `.rd` (`.rd` sets its own inline `color`, which
   always wins there regardless of body's), so this cannot touch lesson
   content. Measured 15.98:1. */
html[data-theme="dark"] body {
  color: #F3ECE0;
}

/* ⊕ KS4-DARK-5 (THEME RUN, 26 Sep 2026) — same unstyled-overlay cause as
   KS4-DARK-4, one door down: `#chatOverlay`'s `<input id="ci">` (the chat
   text box) carries no background/border of its own either (again,
   because shared/styles.css never loads here), so it renders as a bare
   NATIVE form control — and `html.style.colorScheme` (set by theme.js/
   THEME_HEAD, needed everywhere else on the page so the OS's own chrome —
   scrollbars, native pickers — matches the site's choice) makes Chrome
   skin that native control with its OWN dark widget theme: a dark grey
   fill (#3B3B3B) under Chrome's OWN placeholder grey (#757575, the exact
   value KS4-DARK-3's docstring already names as the UA default) — 2.43:1,
   under the 4.5 floor. In light mode the same native pairing (white fill,
   #757575 placeholder) already clears it, which is exactly why this
   never needed fixing before: the overlay predates dark mode entirely and
   has no design of its own to give it. Rather than invent one, `color-
   scheme: light` pins the overlay's native controls to the SAME
   appearance they have always had, in either theme — the accurate
   "unchanged" for a component nothing here has redesigned. */
#chatOverlay {
  color-scheme: light;
}
} /* @media screen — D8 */

/* ⊕ KS4-CHIP-1 (Mide's ruling, 27 Sep 2026) — replaces the two static
   "Combined · Triple" / "Foundation · Higher" header chips with one
   chip stating the page's own route in words, as a native disclosure.
   Enter/Space toggles a native <details>/<summary> with no script; Tab
   reaches the menu's links (already static <a> elements in the prerendered
   HTML, not a runtime fetch). shared/ks4-runtime.js adds only Esc-to-close
   plus keeping aria-expanded in sync with the open state. */
.ks3-route-switch { position: relative; }
.ks3-route-chip {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-family: var(--ks3-font-mono); font-size: 13px; font-weight: 500;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 11px; border-radius: 99px; border: 2px solid var(--ks3-ink);
  color: var(--ks3-ink); background: var(--ks3-card);
  -webkit-tap-highlight-color: transparent;
}
.ks3-route-chip::-webkit-details-marker { display: none; }
.ks3-route-chip::marker { content: ""; }
.ks3-route-chip:hover { border-color: var(--ks3-accent-text); }
.ks3-route-chip:focus-visible { outline: 3px solid var(--ks3-accent-text); outline-offset: 2px; }
.ks3-route-chip svg { flex: 0 0 auto; transition: transform .15s ease; }
.ks3-route-switch[open] > .ks3-route-chip svg { transform: rotate(180deg); }
.ks3-route-menu {
  /* ⚠️ `display: none` here is LOAD-BEARING, not a default this selector
     happens to start from. The browser's own UA stylesheet already hides a
     closed <details>'s non-summary content (`details:not([open]) >
     *:not(summary) { display: none }`), but an AUTHOR stylesheet's rule
     beats a UA rule at equal-or-lower specificity regardless of source
     order — an unconditional `display: flex` here would force the menu
     visible EVEN WHILE CLOSED (found live via ks4_parity's G-keyboard
     layer: 3 always-focusable <a> with non-zero rects). `[open] >` below
     is the ONLY rule that may ever show it. */
  display: none;
  list-style: none; margin: 6px 0 0; padding: 6px;
  flex-direction: column; gap: 2px;
  position: absolute; top: 100%; left: 0; z-index: 5;
  min-width: 15rem; max-width: min(20rem, calc(100vw - 32px));
  background: var(--ks3-card); border: 2px solid var(--ks3-option-border);
  border-radius: var(--ks3-r-panel); box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
}
.ks3-route-switch[open] > .ks3-route-menu { display: flex; }
.ks3-route-menu a {
  display: block; padding: 9px 10px; border-radius: 8px; min-height: 44px;
  font-family: var(--ks3-font-body); font-size: 15px; font-weight: 500;
  line-height: 1.3; color: var(--ks3-ink); text-decoration: none;
}
.ks3-route-menu a:hover { background: var(--ks3-band); }
.ks3-route-menu a:focus-visible { outline: 3px solid var(--ks3-accent-text); outline-offset: -3px; background: var(--ks3-band); }
@media (max-width: 400px) {
  .ks3-route-menu { left: 0; right: auto; }
}

/* ⊕ Front door run, 12 Oct 2026 (Part 4) — THE PHONE STRIP, pilot lessons.
   The template carries the strip's padding inline, which made it 47px; up to
   700px it is 44px at most, flush at top:0, and slides off while the reader
   scrolls down (`ks4-rail-away` on <html>, set by ks4-lib.js). `!important`
   because the template styles are inline. `transform` only: nothing reflows. */
@media (max-width: 700px) {
  nav[data-rail="top"] {
    box-sizing: border-box !important; height: 44px !important;
    padding: 0 16px !important; top: 0 !important;
    display: flex; align-items: center;
    transition: transform .2s ease;
  }
  nav[data-rail="top"] > div { width: 100%; }
  html.ks4-rail-away nav[data-rail="top"] { transform: translateY(-100%); }
}
@media (max-width: 700px) and (prefers-reduced-motion: reduce) {
  nav[data-rail="top"] { transition: none; }
}

/* ⊕ Loose-ends run, 17 Oct 2026 (fix 7a) — figure text floor on phones. ks4-runtime.js figFit() publishes each
   figure's viewBox width (--fig-vb) and its smallest font-size in viewBox units (--fig-fs); the <svg> is
   then never narrower than 11px x vb / fs, so its smallest label draws at >= 11px. Wider than the screen,
   the frame scrolls sideways (nothing is reflowed or re-worded); a figure that already reads at 11px gets a
   min-width below 100% and is unchanged. Phones and small tablets only: >= 720px never matches. */
@media (max-width: 719.98px) {
  [data-fig-fit] { overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
    scrollbar-width: thin; }
  [data-fig-fit] > svg { max-width: none; min-width: calc(11px * var(--fig-vb) / var(--fig-fs)); }
  [data-fig-over]:not([data-fig-end]) {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
  [data-fig-over]:focus-visible { outline: 2px solid var(--ks3-accent-text, #E4572E); outline-offset: 2px; }
}
