/* PHASE·ARTICLE (605) — the read behind "Get the bigger picture". D-660, D-662.
 *
 * SIX READS ON ONE RAIL: slide 0 is the YEAR read (D-662, 450–550w), slides 1–5 are the
 * five phase reads (765–935w). Swiping the hero changes the WHOLE ARTICLE, not the header.
 *
 * ⚠️ THE DESK CHROME DID NOT COME WITH IT (same rule as weeks/read.css): body, .wrap,
 * .page-…, .states, .state-… dress the WB review page, not the surface. `body { background }`
 * shipped into the app would repaint every screen. Those stay inline in article.html.
 *
 * 🔴 THE BAR BUILDS, IT DOES NOT SWITCH (Andrew, 2026-07-27). Every pill up to and including
 * the current phase carries its own --phase-N. A single coloured pill says WHICH read this is;
 * a building ramp says HOW FAR THROUGH THE YEAR it sits — and the deck card already fills by
 * index, so the two surfaces now agree. ⚠️ TIME LIVED, NEVER ACHIEVEMENT (D-630): the year has
 * a direction, nothing has been completed. No counts, no progress language.
 *
 * 🔴 X3 TYPOGRAPHY, AND THE GREY IS NOT A FREE CHOICE. Name --nav-active at --size-20, range
 * --text-secondary at --size-16 — hierarchy by size AND colour. --text-tertiary was built and
 * REJECTED: it measures 3.38:1 on --cream-50 and fails AA for normal text, and D-660 makes the
 * range hero-level information, not decoration. If it ever reads heavy, cut the SIZE, never the
 * contrast (--text-secondary is 6.74:1).
 *
 * ⚠️ THE CARETS MAY POINT BUT MUST NEVER INVITE A TAP — 10px, --brand, pointer-events:none.
 * D-458 rules "stops at the ends, NO arrows" for this shape; two rounds established that a
 * pressable-looking affordance here is wrong (see _bakeoffs/article-hero-r3.html, where
 * tappable pills and a foot door were both rejected).
 *
 * ⚠️ WEEK RANGES ARE COMPUTED FROM BWPhases, NEVER AUTHORED (D-660). Slide 0's range is the
 * UNION of all five. A hand-written "Weeks 17–26" is correct until someone re-cuts a boundary
 * and then silently wrong with nothing to catch it — and the spine has already moved once
 * this year (D-626, four phases to five).
 */
/* 🔴 THE READ IS A SURFACE, NOT A CARD ON THE GROUND. Without this the article rendered on
   --surface-ground — the cream the TAB uses behind its stack of cards — so a full-screen read
   looked like a card that had lost its background. The Phases tab is a stack on the ground;
   the read it opens is a page. min-height:100% so a short read still fills the screen. */
/* 🔴 THE COLUMN (Gate 2 item 8, 2026-07-30). The host mounts position:fixed outside #app, so it
   never inherits the app's column — at desktop the read ran the full viewport while the tab that
   opened it sat in its 420px column. Same token the tab uses, carried by the same element that
   carries the page background, exactly as .wkr does for the week read (read.css:21). */
.pha-read{background:var(--surface-card);min-height:100%;max-width:var(--layout-col-max);margin-inline:auto}
/* 🔴 --space-16, NOT --space-20 — MATCHING .wkr EXACTLY. The week read's article container is
   `padding: 0 var(--space-16) 0`; I had used 20, so every measure on this surface was 4px
   narrower each side than the week read's and the two feet could never line up however the
   band itself was tuned. The end padding lives INSIDE the C3 band so it runs to the page
   bottom (read.css's own note, Andrew 2026-07-21) — hence the 0 at the foot. */
.pha{padding:0 var(--space-16) 0}
  /* ── THE MASTHEAD — read.css lines 65–70, copied value for value, not re-derived. ──
     Wordmark flush LEFT at the canonical --size-20 / --weight-wordmark (token-exception in
     read.css too: it matches topbar.css, D-411); the 403 chevron right, wearing the
     masthead's round --surface-card circle + --accent glyph. The bespoke bar this replaces
     (back-chevron · centred 15px wordmark · empty spacer) is written up in article.render.js
     above mast() — three separate rule breaks, so it is recorded rather than just deleted. */
  .pha-read .mast-bar{display:flex;align-items:center;justify-content:space-between;padding:var(--space-4) 0 var(--space-8)}
  .pha-read .mast-word{font-family:var(--font-display);font-weight:var(--weight-wordmark);font-size:var(--size-20);letter-spacing:var(--tracking-neg-01);color:var(--text-primary)} /* token-exception: canonical wordmark size, matches topbar.css (D-411) */
  .pha-read .mast-word b{color:var(--brand)}
  .pha-read .mast-r{display:flex;align-items:center;gap:var(--space-8)}
  .pha-read .mast-r .act-chev{width:var(--dim-40);height:var(--dim-40);background:var(--surface-card);box-shadow:var(--shadow-card);color:var(--accent)}
  .pha-read .mast-r .act-chev svg{width:var(--size-18);height:var(--size-18)}
  /* ── THE × — OPTION E, SUNKEN. Settled from _bakeoffs/mast-close.html (Andrew, 2026-07-27:
     "E · sunken circle works for me"). Five options ran in the frame; A kept both controls
     identical, B/C put --green-900 on the glyph or the fill, D dropped the circle.

     WHY E AND NOT B (the forest glyph, which was the opening suggestion): E DIFFERENTIATES BY
     DEPTH, NOT BY HUE. Same 40px circle, same forest glyph — but recessed into the paper
     instead of raised off it. That says "a different KIND of control" without spending
     --green-900, which D-650 sanctions as the system's ONE non-teal accent and which the
     Phases tab is currently short of (hero.css files its loss as an open palette question).
     Spending it on a close button would have answered that question by accident.
     ⚠️ C was the one to be careful of: hero.css pulled a solid --green-900 button off the
     Phases tab precisely because it became the heaviest object on the screen, and C
     reintroduced that shape one level down.
     Contrast, measured: --green-900 on --cream-400 = 9.32:1 (the raised chevron beside it is
     --accent on --surface-card = 4.33:1, so the × is also the DARKER mark — right, since it
     is the control she reaches for when lost). Structure derives from 401's .mast-btn
     (workbench/shared/masthead.html lines 52–55); only ground and glyph differ. */
  .pha-read .mast-btn{width:var(--dim-40);height:var(--dim-40);border-radius:var(--radius-round);background:var(--surface-well);box-shadow:none;color:var(--green-900);border:0;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none;padding:0}
  .pha-read .mast-btn svg{width:var(--size-18);height:var(--size-18);display:block}
  .pha-read .mast-btn:active{opacity:0.72}
  .pha-read .mast-btn:focus-visible{outline:var(--focus-ring);outline-offset:var(--focus-offset)}

  .pha-hero{text-align:center;padding-top:var(--space-12);position:relative}
  .pha-eyebrow{font-family:var(--font-label);font-size:var(--size-12);font-weight:var(--weight-600);letter-spacing:var(--tracking-14);text-transform:uppercase;color:var(--accent);margin-top:0}
  .pha-num{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-60);line-height:var(--leading-100);color:var(--nav-active);letter-spacing:var(--tracking-neg-015);margin-top:var(--space-4)}
  /* X3 — hierarchy by SIZE and COLOUR, both inside legal contrast. */
  /* The two-line reserve added earlier today is GONE with the break it existed to absorb
     (Andrew: "put the first year on 1 line"). It bought the weeks-line alignment at the cost
     of an empty line under all five phase names; with every name back on one line the
     alignment comes free and the air was pure tax. ⚠️ If a future phase name ever wraps, its
     slide's weeks line WILL drop below the others — the reserve is the fix, not a nudge on
     that one slide. */
  .pha-name{font-family:var(--font-display);font-weight:var(--weight-500);font-size:var(--size-20);line-height:var(--leading-115);color:var(--nav-active);margin-top:var(--space-8)}
  .pha-weeks{font-family:var(--font-display);font-weight:var(--weight-500);font-size:var(--size-16);line-height:var(--leading-115);color:var(--text-secondary);margin-top:var(--space-4)}

  /* the year read's identity block — no numeral, so the stack stands in for it, and an
     invisible eyebrow keeps its name on the same baseline as every phase read's. */
  .yspacer{visibility:hidden}
  /* 🔴 margin-top MATCHES .pha-num's --space-4. The box was already the numeral's --size-60
     height, but the numeral carries a 4px top margin and this did not — so the year slide sat
     4px HIGH of the phase slides all the way down the column, name and weeks included.
     Measured, not spotted: 476.3 vs 480.3 on the name, 526.3 vs 530.3 on the weeks. */
  /* 🔴 THE GLYPH'S BOTTOM SITS ON THE NUMERAL'S BASELINE, NOT ON ITS LINE BOX.
     (Andrew, 2026-07-27: "put the bottom line of the glyph on same plane as the bottom of the
     phase numbers.")

     THE BUG: the box was --size-60 tall with the glyph flex-end — so the glyph's bottom landed
     on the LINE BOX bottom of .pha-num, which is 10px BELOW where the digit actually stops.
     Measured at 60px Fraunces: ascent 53, descent 13, line-height 60 → half-leading −3, so the
     baseline sits 50px down a 60px box and the last 10px is descender space no digit uses.
     Numeral ink ended at 484.3; the glyph ended at 493.3. Nine pixels, and visible.

     THE FIX IS DERIVED, NOT NUDGED. Nudging up by 9 or 10px would hard-code one font's metrics
     into a magic number that goes silently wrong the day Fraunces is swapped or its size
     changes. Instead the box establishes a TEXT STRUT at the numeral's own size and leading,
     and the glyph is an inline-block aligned to that strut's BASELINE. An inline-block with no
     in-flow line boxes takes its bottom margin edge as its baseline (CSS2.1 §10.8.1) — and the
     glyph's spans are flex items, not inline content, so it has none. The bottom of the stack
     therefore lands exactly where a digit's baseline lands, computed from the same font metrics
     the numeral uses. Change the font and both move together.
     ⚠️ .yglyph must stay display:inline-block with the flex column on the INNER element. Make
     it inline-flex and the baseline becomes the FIRST flex item's, and the stack hangs off its
     top row instead. */
  .yglyphbox{height:var(--size-60);margin-top:var(--space-4);text-align:center;font-family:var(--font-display);font-size:var(--size-60);line-height:var(--leading-100)}
  .yglyphbox::before{content:"\200b"} /* the strut — zero-width, so it establishes the baseline and prints nothing */
  /* 🔴 overflow:hidden IS LOad-BEARING, NOT TIDYING. Without it the inline-block does NOT use
     its bottom edge as its baseline: the inner flex container propagates a baseline of its own
     (its first flex item's, and an empty span's baseline is that span's bottom) — so the stack
     hung off its TOP row and sat 44px low. CSS2.1 §10.8.1: an inline-block with overflow other
     than `visible` takes its bottom MARGIN EDGE as its baseline, which is the whole mechanism
     here. Nothing overflows; the property is doing structural work. */
  .yglyph{display:inline-block;vertical-align:baseline;overflow:hidden;width:9rem} /* token-exception */
  .yglyph i{display:flex;flex-direction:column;align-items:center;gap:5px;font-size:0;line-height:0} /* token-exception */
  .yglyph span{min-height:6px;height:6px;border-radius:var(--radius-pill)} /* token-exception */
  .yglyph span:nth-child(1){width:17.3%}
  .yglyph span:nth-child(2){width:15.4%}
  .yglyph span:nth-child(3){width:17.3%}
  .yglyph span:nth-child(4){width:25%}
  .yglyph span:nth-child(5){width:25%}

  .rail{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;cursor:grab}
  .rail::-webkit-scrollbar{display:none}
  .rail.dragging{cursor:grabbing;scroll-snap-type:none}
  .rail .slide{flex:0 0 100%;scroll-snap-align:center}

  .tick{display:flex;align-items:center;justify-content:center;gap:var(--space-12);pointer-events:none;margin-top:var(--space-16)}
  .tick svg{width:10px;height:10px;flex:none;color:var(--brand)} /* token-exception */
  .tick .bar{width:9rem;max-width:none;margin:0;flex:none} /* token-exception */
  .bar{display:flex;gap:var(--space-4);align-items:center}
  .bar span{border-radius:var(--radius-pill);background:var(--teal-100);height:7px;transition:background var(--duration-200) var(--ease-standard)} /* token-exception */

  .art{transition:opacity 450ms cubic-bezier(.22,.61,.36,1)}
  .art.out{opacity:0}
  @media (prefers-reduced-motion: reduce){.art{transition:none}}

  .pha-headline{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-28);line-height:var(--leading-115);text-align:left;margin-top:var(--space-20)}
  .pha-headline .fs{color:var(--brand)}
  .pha-stand{font-family:var(--font-display);font-weight:var(--weight-400);font-style:italic;font-size:var(--size-17);line-height:var(--leading-155);color:var(--text-secondary);margin:var(--space-12) 0 var(--space-24)}
  .pha-p{font-size:var(--size-15);line-height:var(--leading-165);color:var(--text-primary);margin-top:var(--space-12)}
  /* 🔴 THE KEY-MESSAGE BOX — Full's "This week" object, re-scoped (Andrew, 2026-07-27).
   Same tone-lifted card, same position between standfirst and body; the label changes with
   the read's scope ("In this phase" / "Across the year") and each bullet JUMPS to its section.
   ⚠️ ONE BOX, TWO JOBS ON PURPOSE. Deep's numbered mini-contents was rejected here: it lists
   TOPIC NAMES, and at 4–5 sections it spends the screen on which a parent decides whether to
   stay. A message list says what she would LEARN and navigates, so the same real estate does
   both. ⚠️ THEREFORE THE BULLETS MAP 1:1 ONTO THE SECTIONS. Full's box carries three bullets
   against five or six sections because it is a summary, not a jump list. Change the section
   count here and the box must follow, or it starts lying about what is below it.
   ⚠️ ONE LEVEL OF CARDING (D-435): this is a row of text in a tone-lift, not a box inside a
   box — no border, no nested panels. */
/* 🔴 SIZE THE GLYPH OR IT FILLS THE BOX. Icons.get() returns a whole <svg> with no
   intrinsic size — unconstrained it took the full width of the key-message box and rendered
   as a 300px book above the bullets. Every other glyph on this surface is sized by its own
   rule; this one was added last and was missed. Same class of bug as 604's "a nested svg's
   bbox is a layout rect, not the artwork". */
/* Deep's numbered spine survives even though its mini-contents does not — at 4–5 sections a
   read still wants a spine, and the numerals are the cheapest one available. */

/* ═══ FULL'S GRAMMAR, MIRRORED FROM web/css/cards/weeks/read.css ═════════════════
   🔴 REBUILT 2026-07-27 AFTER GETTING IT WRONG. The first pass wrote these components from
   memory of the SPEC and imported Deep's furniture. Every value below is now read off the
   shipped Full read (feat/read-port-wire) rather than recalled. What was wrong:

   1. NUMBERED SECTIONS ARE DEEP'S, NOT FULL'S. read.render.js calls subrow('…') for Full and
      subrow('…', '01') for Deep — same function, and only Deep passes the numeral. I added
      teal 01–04 numerals to a Full-architecture read and even wrote a comment defending them
      as "the cheapest spine". They are Deep's spine. Removed.
   2. ITEM FACES ARE NEUTRAL, NOT TINTED. Every rule-item in the shipped read is
      --surface-item-panel with a --dim-4 kind-coloured LEFT RULE and radius 0/card/card/0 —
      the kind colour is a 4px edge, not a fill. I filled them with --clay-100 and
      --slate-100, which is the D-618 kind-wash the item-styles round explicitly REPLACED
      ("rest is now NEUTRAL"). So the read was carrying a superseded treatment.
   3. "In this phase" IS NOT A BOX. .wkr-hl has no background and no radius — an eyebrow and
      bullets on bare paper. I put it in a --surface-sunken card.
   4. "Worth checking" IS THE SAME PANEL AS THE OTHERS with a gold left rule (.wkr-watchbox),
      not a gold wash.
   5. THE FORWARD-LOOK IS AN UNBOXED HERO-ECHO (.wkr-cuhero) and the STEPPER is the C3 band
      at the very bottom. I had one boxed block doing both jobs.
   6. FAQ ROWS ARE <details>/<summary> with a top hairline — mine were plain divs, so the
      answers were unreachable.
   ⚠️ These are MIRRORED values, not shared code. If read.css changes, this drifts. The right
   end-state is a shared item stylesheet both surfaces import; until then this comment is the
   only thing tying them together. */

/* 🔴 --surface-item-panel DOES NOT EXIST ON main. It is the rule-item fill the 502
   item-styles round introduced (cream-150 → cream-200, Andrew 2026-07-21 "washed out") and
   it lives on feat/read-port-wire's tokens.css, which is not merged. Declared here as a
   LOCAL fallback so this card renders correctly today; ⚠️ DELETE THIS BLOCK when the read
   branch lands, or the token will have two definitions and they will drift. Value copied
   from that branch verbatim — not re-picked by eye. */
.pha-read{--surface-item-panel:var(--cream-200)}

/* 🔴 THE FIRST-PASS KEY-MESSAGE BOX AND THE NUMBERED SUB-HEAD WERE REMOVED HERE (2026-07-27).
   Both were written from memory of the spec rather than from the shipped Full read, and both
   were Deep's furniture: a --surface-sunken CARD around the bullets (Full's .wkr-hl has no
   background at all) and teal 01–NN numerals on the sub-heads (read.render.js passes a
   numeral to subrow() for DEEP only). ⚠️ They were struck by SELECTOR, line by line — not by
   cutting between two offsets, which has eaten neighbouring rules twice in this file's
   history and once in phase/hero.css. */
/* ── paragraphs + sections. Full's tightened rhythm: consecutive paragraphs PULL UP. ── */
.pha-p{font-size:var(--size-15);line-height:var(--leading-165);color:var(--text-primary);margin-top:var(--space-12)}
.pha-p + .pha-p{margin-top:calc(-1 * (var(--space-8) + var(--nudge-2)))}
.pha-sub{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--text-subtitle);line-height:var(--leading-120);margin:0;flex:1;min-width:0}
.pha-subrow{display:flex;align-items:center;gap:var(--space-8);margin:var(--space-24) 0 0}
.pha-subrow + .pha-p{margin-top:var(--nudge-1)}
.pha-read .cv{width:var(--dim-16);height:var(--dim-16);color:var(--text-tertiary);flex:none}
.pha-prov{display:flex;justify-content:center;align-items:center;margin:var(--space-4) 0 0;font-family:var(--font-display)}
.pha-prov .rev{color:var(--text-secondary);font-weight:var(--weight-500);font-size:var(--size-13)}

/* ── the eyebrow used by every foot block (.wkr-hl .hh / .wkr-foot .fl / .wkr-sources .ttl) ── */
.pha-ey{display:flex;align-items:center;gap:var(--space-8);font-family:var(--font-label);font-size:var(--size-11);font-weight:var(--weight-600);letter-spacing:var(--tracking-05);text-transform:uppercase;color:var(--accent);margin-bottom:var(--space-8)}
.pha-ey svg{width:var(--dim-16);height:var(--dim-16);flex:none}

/* ── "In this phase" — .wkr-hl. NO BOX. ── */
.pha-keys{margin:var(--space-16) 0 0}
.pha-keys ul{list-style:none;margin:0;padding:0}
.pha-keys li{font-size:var(--size-14);line-height:var(--leading-150);padding-left:var(--space-20);position:relative;margin-bottom:var(--space-8)}
.pha-keys li::before{content:'';position:absolute;left:var(--space-8);top:calc(var(--space-8) - var(--nudge-1));width:var(--dim-5);height:var(--dim-5);border-radius:var(--radius-round);background:var(--accent)} /* token-exception */
.pha-keys a{color:var(--text-primary);text-decoration:none;display:block}

/* ── RULE ITEMS — one face, kind colour on the 4px left rule only (D-454 · item-styles). ── */
.pha-item,.pha-fig{background:var(--surface-item-panel);border:0;border-radius:0 var(--radius-card) var(--radius-card) 0;margin:var(--space-12) 0 0;padding:var(--space-8) var(--space-16) var(--space-16)}
.pha-item.track{border-left:var(--dim-4) solid var(--kind-track-icon)}
.pha-item.do{border-left:var(--dim-4) solid var(--kind-do-icon)}
.pha-item.tool{border-left:var(--dim-4) solid var(--kind-track-icon);display:flex;align-items:flex-start;gap:var(--space-12);padding:var(--space-12) var(--space-16)}
.pha-worth{background:var(--surface-item-panel);border:0;border-left:var(--dim-4) solid var(--gold-700);border-radius:0 var(--radius-card) var(--radius-card) 0;margin:var(--space-12) 0 0;padding:var(--space-8) var(--space-16) var(--space-16)}
.pha-item .qk,.pha-worth .qk{display:flex;align-items:center;gap:var(--space-8);font-family:var(--font-display);font-size:var(--size-16);font-weight:var(--weight-600);margin-bottom:var(--space-4)}
.pha-item .qk svg,.pha-worth .qk svg{width:var(--dim-16);height:var(--dim-16)}
.pha-item.track .qk{color:var(--kind-track-icon)}
.pha-worth .qk{color:var(--gold-700);margin-bottom:var(--space-8)}
.pha-worth p{font-size:var(--size-13);line-height:var(--leading-150);margin:0;color:var(--text-primary)}
.pha-item.track .q{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-15);color:var(--text-primary);margin-bottom:calc(var(--space-8) + var(--nudge-2))}
.pha-item.track .opts{display:flex;flex-wrap:wrap;gap:var(--space-8)}
.pha-item.track .opts button{font-family:var(--font-body);font-size:var(--size-13);font-weight:var(--weight-500);color:var(--kind-track-icon);background:var(--surface-card);border:1px solid var(--slate-300);border-radius:var(--radius-pill);padding:var(--space-4) var(--space-12);cursor:pointer} /* token-exception */
.pha-item.track .opts button:focus-visible{outline:var(--focus-ring);outline-offset:var(--focus-offset)}
.pha-item.do .head{display:flex;align-items:center;gap:var(--space-8);margin-bottom:var(--nudge-2)}
.pha-item .ti{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-14);flex:1;min-width:0}
.pha-item .d{font-size:var(--size-13);line-height:var(--leading-150);color:var(--text-secondary);margin-top:var(--space-4)}
.pha-item.tool .tic{flex:none;width:var(--dim-32);height:var(--dim-32);border-radius:var(--radius-round);background:var(--slate-200);color:var(--kind-track-icon);display:flex;align-items:center;justify-content:center}
.pha-item.tool .tic svg{width:var(--dim-16);height:var(--dim-16)}
.pha-item.tool .k{font-family:var(--font-label);font-size:var(--size-10);font-weight:var(--weight-600);text-transform:uppercase;letter-spacing:var(--tracking-05);color:var(--kind-track-icon)}
.pha-item.tool .ti{font-size:var(--size-16);margin-top:var(--nudge-2)}

/* ── THE ONE PHASE-NATIVE FIGURE — the window band, in the same item face.
   🔴 IT PLOTS A POPULATION RANGE AND MARKS THE PHASE. No per-child input, no prop for one,
   no branch that could draw one (D-396 r5/7 · D-283 · D-334). A range with her baby on it is
   an individualised conclusion — the single thing this app may never compute. Adding that
   affordance later is a CLINICAL change, not a UI tweak.
   ⚠️ THE ARC IS GONE (Andrew, 2026-07-27: "remove phase across weeks"). It restated the
   section heads above it in a box — the key-message list already carries that, and Full has
   no infographic slot at all (§4: infographic is Deep-only). ── */
.pha-fig{border-left:var(--dim-4) solid var(--kind-track-icon)}
.pha-fig .k{font-family:var(--font-label);font-size:var(--size-10);font-weight:var(--weight-600);text-transform:uppercase;letter-spacing:var(--tracking-05);color:var(--kind-track-icon)}
.pha-fig .ti{font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-16);margin-top:var(--nudge-2)}
.pha-fig .scale{position:relative;height:var(--dim-6);border-radius:var(--radius-pill);background:var(--slate-200);margin-top:var(--space-12)}
.pha-fig .band{position:absolute;top:0;bottom:0;border-radius:var(--radius-pill);background:var(--kind-track-icon)}
.pha-fig .here{position:absolute;top:calc(-1 * var(--nudge-2));bottom:calc(-1 * var(--nudge-2));border-radius:var(--radius-pill);border:1px solid var(--green-900)} /* token-exception */
.pha-fig .ends{display:flex;justify-content:space-between;font-family:var(--font-label);font-size:var(--size-10);color:var(--text-tertiary);margin-top:var(--space-4)}
.pha-fig .d{font-size:var(--size-13);line-height:var(--leading-150);color:var(--text-secondary);margin-top:var(--space-8)}

/* ── FAQ — <details>, top hairline, no box (.wkr-faq) ── */
.pha-faq{margin:var(--space-16) 0 0;padding:0;border:0;border-radius:0}
.pha-faq details{border-top:1px solid var(--border-hairline);padding:var(--space-8) 0} /* token-exception */
.pha-faq summary{font-size:var(--size-14);font-weight:var(--weight-600);cursor:pointer;list-style:none;display:flex;justify-content:space-between;gap:var(--space-12)}
.pha-faq summary::-webkit-details-marker{display:none}
.pha-faq .a{font-size:var(--size-13);line-height:var(--leading-150);color:var(--text-secondary);margin:var(--space-8) 0 0}
.pha-faq .src{font-family:var(--font-label);font-size:var(--size-10);text-transform:uppercase;letter-spacing:var(--tracking-05);color:var(--text-tertiary);margin-top:var(--space-4)}

/* ── SOURCES — size-12 secondary, dim-6 dots (.wkr-sources) ── */
.pha-sources{margin:var(--space-20) 0 0}
.pha-sources ul{list-style:none;margin:0;padding:0}
.pha-sources li{font-size:var(--size-12);line-height:var(--leading-150);padding-left:var(--space-16);position:relative;margin-bottom:var(--space-4);color:var(--text-secondary)}
.pha-sources li::before{content:'';position:absolute;left:2px;top:calc(var(--space-4) + var(--nudge-2));width:var(--dim-6);height:var(--dim-6);border-radius:var(--radius-round);background:var(--accent)} /* token-exception */
.pha-sources li b{color:var(--text-primary)}

/* ── the hand-down (D-660) in the "Keep exploring" chip grammar (.wkr-foot) ── */
.pha-areas{margin:var(--space-20) 0 0}
.pha-areas .chips{display:flex;flex-wrap:wrap;gap:var(--space-8)}
.pha-areas .chip{display:inline-flex;align-items:center;gap:var(--space-4);font-family:var(--font-body);font-size:var(--size-13);font-weight:var(--weight-500);color:var(--nav-active);background:var(--surface-card);border:1px solid var(--teal-200);border-radius:var(--radius-pill);padding:var(--space-4) var(--space-12);cursor:pointer} /* token-exception */
.pha-areas .chip:focus-visible{outline:var(--focus-ring);outline-offset:var(--focus-offset)}

/* ── THE FOREWARD-LOOK AND THE STEPPER ARE ONE CONTINUOUS BAND (.wkr-cuhero + .wkr-stepper).
      🔴 THIS IS WHAT WAS MISALIGNED. .wkr-cuhero is NOT unboxed — it carries the SAME
      --surface-item-panel fill as the stepper and the same full-bleed negative margins, with
      `padding: … 0` at the foot so the stepper butts straight onto it. The two read as one
      C3 band. I had the forward-look on bare paper and the stepper on cream, so the band
      started halfway down and the teaser looked detached from the thing it introduces.
      ⚠️ Read off read.css, not recalled — that is the second time on this card that writing
      from memory produced something that looked plausible and was wrong. ── */
.pha-cu{background:var(--surface-item-panel);margin:var(--space-8) calc(-1 * var(--space-16)) 0;padding:var(--space-12) var(--space-16) 0}
.pha-cu .t{font-size:var(--size-14);color:var(--text-secondary);margin:var(--nudge-1) 0 0}

.pha-stepper{display:flex;align-items:stretch;gap:var(--space-8);background:var(--surface-item-panel);margin:0 calc(-1 * var(--space-16));padding:var(--space-8) var(--space-16) var(--space-12)}
.pha-step{flex:1;display:flex;align-items:center;gap:var(--space-8);color:var(--text-primary);background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-card);padding:var(--space-12);cursor:pointer;text-align:left} /* token-exception */
.pha-step.next{justify-content:flex-end;text-align:right}
/* the arrow is a 32px ROUND CHIP, not a bare character — .wkr-step .ar */
/* --surface-well, not --surface-sunken (D-664): a 32px round button is the smallest case the
   rule was written for, and it sits on --surface-card exactly as the masthead × does. Migrated
   in the same pass rather than left as the one control on this card still wearing the band
   depth — that inconsistency is how a rule stops being believed. */
.pha-step .ar{flex:none;width:var(--dim-32);height:var(--dim-32);border-radius:var(--radius-round);background:var(--surface-well);color:var(--nav-active);display:flex;align-items:center;justify-content:center;font-size:var(--size-20);line-height:1}
.pha-step .lab .e{display:block;font-family:var(--font-label);font-size:var(--size-10);font-weight:var(--weight-700);text-transform:uppercase;letter-spacing:var(--tracking-05);color:var(--accent)}
/* 🔴 TWO LINES ALWAYS RESERVED. Measured before the fix: the band was 69px on reads whose
   neighbour names wrapped and 58px on reads where neither did, so it changed height as she
   stepped. Reserving the second line makes the band one height for every read regardless of
   how long a phase gets named — the alternative (relying on 'The first year' now breaking to
   two lines) works today by accident of string length. line-height is pinned so the reserve
   is exactly 2 lines, not a font-metric guess. */
.pha-step .lab .t{display:block;font-family:var(--font-display);font-weight:var(--weight-600);font-size:var(--size-14);line-height:var(--leading-115);min-height:calc(2 * var(--size-14) * 1.15);color:var(--text-primary)}
.pha-step:active{transform:scale(0.99)}
.pha-step:focus-visible{outline:var(--focus-ring);outline-offset:var(--focus-offset)}
/* one neighbour ⇒ one card, full width — never a hidden placeholder holding a gap open */
.pha-step.solo{flex:1 1 100%}
