/* =========================================================================
   Schoolio — Rails-specific components (flashes, errors, skip-link,
   page shell layout). Design tokens come from tokens.css.
   ========================================================================= */

/* Skip link for keyboard/screen-reader users ------------------------------ */
.skip-link {
  position: absolute;
  left: -999px;
  top: auto;
  padding: .6rem 1rem;
  background: var(--ink);
  color: var(--paper);
  font: var(--fw-600) var(--fs-16) var(--font-educating);
  z-index: 9999;
}
.skip-link:focus { left: 1rem; top: 1rem; outline: 3px solid var(--highlighter); }

/* Page shell ------------------------------------------------------------- */
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-educating);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  margin: 0;
}
main { min-height: 60vh; }

/* Header / Footer -------------------------------------------------------- */
.site-header {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}
/* Brand row — wordmark left, the quiet "About" utility link right. Sits on
   its own line above the nav so the three topic menus get the full width to
   themselves (and never share the mobile line with the logo). */
.site-header__brand {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem;
  max-width: var(--container-max); margin: 0 auto;
  padding: .85rem var(--container-gutter) .6rem;
}
.site-header__about {
  font-family: var(--font-educating);
  font-size: var(--fs-14);
  font-weight: 600;
  color: #7c7263;                 /* quiet, secondary — not a peer of the menus */
  text-decoration: none;
  letter-spacing: .02em;
  white-space: nowrap;
  padding: .25rem .1rem;
}
.site-header__about:hover,
.site-header__about:focus-visible,
.site-header__about.is-active { color: var(--ink-blue); }

/* Right-hand cluster of the brand row: the "About" link and — on phones —
   the hamburger button beside it. */
.site-header__brand-actions {
  display: flex;
  align-items: center;
  gap: .75rem;
}

/* Hamburger — hidden on desktop, revealed at ≤640px (see the mobile block).
   Three ink bars drawn from the inner span + its ::before/::after; they
   collapse into an "×" when .site-header.is-menu-open. */
.site-header__burger {
  display: none;            /* desktop: no hamburger */
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 1px solid rgba(28, 28, 28, .18);
  border-radius: var(--radius-md, 8px);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.site-header__burger:hover,
.site-header__burger:focus-visible { border-color: var(--ink-blue); color: var(--ink-blue); }
.site-header__burger-bars,
.site-header__burger-bars::before,
.site-header__burger-bars::after {
  content: "";
  display: block;
  width: 1.25rem;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .18s ease, opacity .18s ease;
}
.site-header__burger-bars { position: relative; }
.site-header__burger-bars::before { position: absolute; top: -6px; left: 0; }
.site-header__burger-bars::after  { position: absolute; top:  6px; left: 0; }
/* Open state → morph the three bars into an "×". */
.site-header.is-menu-open .site-header__burger-bars { background: transparent; }
.site-header.is-menu-open .site-header__burger-bars::before { top: 0; transform: rotate(45deg); }
.site-header.is-menu-open .site-header__burger-bars::after  { top: 0; transform: rotate(-45deg); }

/* Nav row — now holds ONLY the three topic menus, left-aligned under the
   wordmark, with a hairline separating it from the brand row above. */
.site-header__inner {
  display: flex; align-items: center;
  gap: 1.5rem;
  max-width: var(--container-max); margin: 0 auto;
  padding: .5rem var(--container-gutter) .75rem;
  border-top: 1px solid rgba(28, 28, 28, .10);
}
.site-header__logo {
  display: flex; align-items: center; gap: .75rem;
  text-decoration: none; color: var(--ink);
}
.site-header__logo img { height: 52px; width: auto; }
.site-header__logo .wordmark {
  font: var(--fw-700) var(--fs-22)/1 var(--font-display);
  letter-spacing: .02em;
}

/*
 * The `.nav` rule in tokens.css was designed for a standalone, full-width
 * header in the style guide. Inside `.site-header__inner` we need to neutralize
 * its padding, border, and background, and give the flex children real spacing
 * (space-between does nothing on a shrink-to-fit flex item).
 */
.site-header__inner .nav {
  padding: 0;
  background: transparent;
  border-bottom: 0;
  justify-content: flex-start;
  gap: 1.35rem;
  flex-wrap: nowrap;   /* nav has its own row now — keep all three on one line */
}
.site-header__inner .nav a {
  padding: .25rem .1rem;
}

/* Dropdown nav groups -----------------------------------------------------
   A NavItem with children renders as <details><summary>…</summary><ul>…</ul></details>.
   Default <details> styles are ugly; we hide the marker and roll our own. */
.site-header__inner .nav .nav-group {
  position: relative;
  display: inline-block;
}
.site-header__inner .nav .nav-group__label {
  list-style: none;        /* Firefox marker */
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .25rem .1rem;
  color: var(--ink);
  font: inherit;
}
.site-header__inner .nav .nav-group__label::-webkit-details-marker { display: none; }
.site-header__inner .nav .nav-group__caret {
  font-size: .8em;
  opacity: .6;
  transition: transform .12s ease;
}
.site-header__inner .nav .nav-group[open] .nav-group__caret { transform: rotate(180deg); }

/* Lead arrow — the ink-blue chevron carried by every top-level menu except
   the first, so the desktop row reads as a sequence: More than hope ›
   Science confirms › Choose your school system › Services. Rendered by
   ApplicationHelper#nav_label from the NavItem::LEAD_ARROW_PREFIX marker.
   Nudges right on hover. */
.site-header__inner .nav .nav-lead {
  display: inline-flex;
  align-items: center;
  color: var(--lo-color-2);
  transition: transform .16s ease;
}
.site-header__inner .nav .nav-lead__icon { display: block; }
.site-header__inner .nav .nav-group__label:hover .nav-lead,
.site-header__inner .nav .nav-group__label:focus-visible .nav-lead,
.site-header__inner .nav a:hover .nav-lead {
  transform: translateX(2px);
}

/* Inline ink-blue bold accent inside a top-level nav label (the "your" in
   "Choose your school system"). Rendered by ApplicationHelper#nav_label from
   the `**…**` marker. */
.site-header__inner .nav .nav-accent {
  color: var(--ink-blue);
  font-weight: 700;
}

.site-header__inner .nav .nav-group__menu {
  position: absolute;
  top: 100%;
  margin-top: .35rem;          /* visual gap below the label */
  left: 0;                     /* nav is left-aligned now — open rightward so
                                  the leftmost menu doesn't spill off-screen */
  min-width: 18rem;
  padding: .75rem 0;
  list-style: none;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px -16px rgba(28, 28, 28, .35);
  z-index: 50;
}
/* Invisible bridge across the visual gap above the menu — without it
   the cursor briefly leaves :hover when crossing from the label down
   into the menu, and the dropdown collapses. */
.site-header__inner .nav .nav-group__menu::before {
  content: "";
  position: absolute;
  top: -.35rem;
  left: 0;
  right: 0;
  height: .35rem;
}
.site-header__inner .nav .nav-group__menu a {
  display: block;
  padding: .35rem 1rem;
  text-decoration: none;
  color: var(--ink);
}
.site-header__inner .nav .nav-group__menu a:hover,
.site-header__inner .nav .nav-group__menu a:focus {
  background: var(--paper-2, #F3ECD6);
}
/* Current page WITHIN the dropdown. The deep link for the page you're on
   gets the same ink-blue underline as the top-level section indicator. The
   extra specificity here is required to beat the `.nav-group__menu a
   { text-decoration: none }` reset above and the `.nav-group__sublist a`
   reset below — otherwise the active link renders with no underline. */
.site-header__inner .nav .nav-group__menu a.is-active {
  color: var(--ink-blue);
  text-decoration: underline;
  text-decoration-color: var(--ink-blue);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

/* Second-level grouping inside the dropdown (e.g. "Team", "What science
   says is the Right Problem"). The label is non-clickable when its path is
   "#", or a link when it carries its own path; children indent slightly. */
.site-header__inner .nav .nav-group__section {
  padding: .35rem 0;
}
.site-header__inner .nav .nav-group__section + .nav-group__section {
  border-top: 1px solid var(--rule);
  margin-top: .35rem;
  padding-top: .6rem;
}
.site-header__inner .nav .nav-group__section-label {
  display: block;
  padding: 0 1rem .15rem;
  font: var(--fw-600, 600) var(--fs-14, .875rem) var(--font-display, "Source Serif 4", serif);
  letter-spacing: .01em;
  opacity: .65;
  text-transform: uppercase;
  font-size: .72rem;
}
/* When a section header carries its own path it is a real landing page, not
   just a grouping label — promote it so it reads as a confident doorway:
   mixed-case, larger, full-strength, in the display serif. The quiet
   uppercase whisper above is reserved for non-clickable grouping labels
   (e.g. "Team"), so the hierarchy sharpens instead of flattening. */
.site-header__inner .nav a.nav-group__section-label {
  color: var(--ink);
  text-decoration: none;
  text-transform: none;
  letter-spacing: normal;
  opacity: 1;
  /* A touch larger than 1rem so the top-level "doorways" read confident and
     even across every header menu. The Beautiful Problem's small-caps label
     is nudged just above this to stay optically level (see below). */
  font-size: 1.06rem;
  padding-top: .1rem;
  padding-bottom: .2rem;
}
.site-header__inner .nav a.nav-group__section-label:hover,
.site-header__inner .nav a.nav-group__section-label:focus-visible {
  opacity: 1;
  text-decoration: underline;
}
/* Each menu's "front door" — its primary landing page — carries a standing
   "→" so it reads as *the* place to start: "Hope — in seconds" (More than
   hope), "How to choose?" (If you choose), and "Choosing an implementation"
   (To implement). nowrap keeps the arrow on the same line as its label (the
   long "Choosing an implementation" would otherwise wrap the → onto its own
   line); inline-block keeps the hover underline from running under it. */
.site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/hope-in-a-few-seconds"],
.site-header__inner .nav a.nav-group__section-label[href="/two-choices-in-depth/how-to-choose"],
.site-header__inner .nav a.nav-group__section-label[href="/services/choosing-an-implementation"] {
  white-space: nowrap;
}
.site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/hope-in-a-few-seconds"]::after,
.site-header__inner .nav a.nav-group__section-label[href="/two-choices-in-depth/how-to-choose"]::after,
.site-header__inner .nav a.nav-group__section-label[href="/services/choosing-an-implementation"]::after {
  content: "\2192";            /* → */
  display: inline-block;
  margin-left: .4em;
  opacity: .9;
}
/* "The Beautiful Problem" is the pivot of the whole argument, so it earns
   its named-idea signature even here in the menu: small caps with the ✦
   sparkle mark leading it. Kept in the nav's normal ink (not the terracotta
   used in page content) so the chrome stays quieter than the copy. */
.site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/the-beautiful-problem"] {
  color: var(--ink);
  font-variant-caps: small-caps;
  letter-spacing: .03em;
  /* Small caps read optically a hair smaller than the mixed-case siblings at
     the same size, so sit just above the shared 1.06rem doorway size to stay
     level with them — distinguished by treatment (small caps + ✦), not size. */
  font-size: 1.08rem;
}
.site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/the-beautiful-problem"]::before {
  content: "\2726";                                  /* ✦ */
  font-variant-caps: normal;
  font-weight: 400;
  font-size: .82em;
  margin-right: .34em;
  vertical-align: .04em;
  display: inline-block;
}
/* "The Beautiful Problem" carries a quiet, non-bold second line naming what
   solves it. Rendered as generated content (there's no subtitle field on
   NavItem) on its own line, lighter and smaller than the label. The extra
   margin below sets it apart from the "Eva Fugitt" sub-link that follows.
   text-decoration:none keeps the label's hover underline off the subtitle.
   color/font-variant are reset so it stays quiet ink prose rather than
   inheriting the label's terracotta small caps. */
.site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/the-beautiful-problem"]::after {
  content: "\2014 solved by The Lead Out Method";   /* — solved by … */
  display: block;
  margin-top: .1rem;
  margin-bottom: .55rem;
  color: var(--ink);
  font-variant-caps: normal;
  font-weight: 400;
  font-size: .8rem;
  letter-spacing: .01em;
  opacity: .68;
  text-decoration: none;
}
/* The "Science confirms" doorway reads as two lines within a single link: the
   mixed-case label on top, and beneath it — indented to line up with the
   author sub-links — the named idea it proves out, "The Beautiful Problem", in
   that idea's standard small-caps ✦ signature. Rendered as generated content
   (there's no subtitle field on NavItem), mirroring the Beautiful Problem
   doorway's own subtitle. white-space:normal lets the label wrap to two lines;
   text-decoration:none keeps the label's hover underline off the second line. */
.site-header__inner .nav a.nav-group__section-label[href="/science-confirms"] {
  white-space: normal;
}
.site-header__inner .nav a.nav-group__section-label[href="/science-confirms"]::after {
  content: "\2726 The Beautiful Problem";   /* ✦ The Beautiful Problem */
  display: block;
  margin-top: .12rem;
  margin-left: .5rem;            /* aligns with the .nav-group__sublist links */
  color: var(--ink);
  font-variant-caps: small-caps;
  font-weight: 400;
  letter-spacing: .03em;
  font-size: .95rem;
  opacity: .9;
  text-decoration: none;
}
.site-header__inner .nav .nav-group__sublist {
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-header__inner .nav .nav-group__sublist a {
  padding-left: 1.5rem;
}

/* Linked variant — About is a real link with a hover-revealed dropdown
   beside it AND a separate toggle button so touch users can open the
   dropdown without giving up the link's own tap target. */
.site-header__inner .nav .nav-group--linked {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0;                       /* button supplies its own breathing room */
  padding: .25rem .1rem;
}
.site-header__inner .nav .nav-group--linked .nav-group__label {
  /* Override the .nav a padding above so the link sits flush with the
     toggle button in the same baseline. */
  padding: 0;
}
/* The tap-to-toggle button beside the link. Sized at 44×44 minimum for
   touch (Apple/Google guidelines) so the caret has a real target on
   phones. On desktop the hover behavior still works without ever
   needing to click — the button is just a redundant affordance. */
.site-header__inner .nav .nav-group--linked .nav-group__toggle {
  background: transparent;
  border: 0;
  margin: 0;
  padding: .25rem .35rem;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
}
.site-header__inner .nav .nav-group--linked .nav-group__toggle:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Hidden by default; the JS controller flips .is-open on tap, and the
   hover media query below also reveals it on hover/focus. */
.site-header__inner .nav .nav-group--linked > .nav-group__menu {
  display: none;
}
.site-header__inner .nav .nav-group--linked.is-open > .nav-group__menu {
  display: block;
}
.site-header__inner .nav .nav-group--linked.is-open .nav-group__caret {
  transform: rotate(180deg);
}

/* Hover-to-open on devices that actually have hover. Touch devices get
   tap-to-toggle via <details> on the non-linked variant. */
@media (hover: hover) and (pointer: fine) {
  .site-header__inner .nav .nav-group:hover > .nav-group__menu,
  .site-header__inner .nav .nav-group:focus-within > .nav-group__menu {
    display: block;
  }
  .site-header__inner .nav details.nav-group:not([open]) > .nav-group__menu {
    display: none;
  }
  .site-header__inner .nav .nav-group:hover .nav-group__caret,
  .site-header__inner .nav .nav-group:focus-within .nav-group__caret {
    transform: rotate(180deg);
  }
}

/* Mobile / narrow viewports — anchor every dropdown to the full width
   of the header instead of the small .nav-group wrapper, otherwise the
   panel (min-width 18rem, right:0) extends off the LEFT edge of the
   screen when its parent sits near the left of the (now left-aligned,
   wrapped) nav bar. Applies to both the <details> variant (About,
   Guides) and the .nav-group--linked variant. The wrappers go
   position:static on small screens so the absolute menu picks up
   .site-header__inner as its positioning context. */
@media (max-width: 720px) {
  .site-header__inner {
    position: relative;
  }
  .site-header__inner .nav .nav-group,
  .site-header__inner .nav .nav-group--linked {
    position: static;
  }
  .site-header__inner .nav .nav-group > .nav-group__menu,
  .site-header__inner .nav .nav-group--linked > .nav-group__menu {
    top: 100%;
    margin-top: .35rem;
    left: var(--container-gutter, 1rem);
    right: var(--container-gutter, 1rem);
    min-width: 0;
    max-width: none;
    width: auto;
    /* Distinguish the panel from the header's paper bg so the
       dropdown reads as a discrete surface on a phone where it
       spans the full width. Slightly warmer paper + a heavier ink
       border + a deeper shadow do the work. */
    background: var(--paper-2, #F3ECD6);
    border: 1px solid var(--ink);
    box-shadow: 0 16px 40px -18px rgba(28, 28, 28, .55);
  }
  /* Hover bridge is unnecessary on touch (no hover) and would land in
     the wrong place once the anchor changes. */
  .site-header__inner .nav .nav-group > .nav-group__menu::before,
  .site-header__inner .nav .nav-group--linked > .nav-group__menu::before {
    display: none;
  }
  /* The front-door "→" reads tiny on a phone; scale it up so it stays a
     clear "start here" cue on the full-width mobile panel. */
  .site-header__inner .nav a.nav-group__section-label[href="/more-than-hope/hope-in-a-few-seconds"]::after,
  .site-header__inner .nav a.nav-group__section-label[href="/two-choices-in-depth/how-to-choose"]::after,
  .site-header__inner .nav a.nav-group__section-label[href="/services/choosing-an-implementation"]::after {
    font-size: 1.35em;
    vertical-align: -.06em;
  }
}

/* Phones — the four topic menus no longer fit on one line, so they collapse
   behind the hamburger to the right of "About". Tapping it drops the nav down
   as a full-width, in-flow accordion: each top-level menu is a row whose
   sub-items expand below it (native <details>), instead of an absolute
   overlay. */
@media (max-width: 640px) {
  /* Trim the header's side padding so the drawer has more room. */
  .site-header__brand { padding-left: 16px; padding-right: 16px; }

  /* Reveal the hamburger; hide the nav panel until the menu is toggled. */
  .site-header__burger { display: inline-flex; }
  .site-header__inner {
    display: none;
    padding: .25rem 16px .85rem;
  }
  .site-header.is-menu-open .site-header__inner { display: block; }

  /* Stack the top-level menus vertically with hairline separators. */
  .site-header__inner .nav {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: 100%;
  }
  .site-header__inner .nav > * { border-top: 1px solid rgba(28, 28, 28, .10); }
  .site-header__inner .nav > *:first-child { border-top: 0; }

  /* Full-width menu rows; caret pushed to the trailing edge. */
  .site-header__inner .nav .nav-group,
  .site-header__inner .nav .nav-group--linked { display: block; width: 100%; }
  .site-header__inner .nav .nav-group__label {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: .7rem .1rem;
    font-size: 1.05rem;
    white-space: normal;
  }
  .site-header__inner .nav > a {           /* childless top-level links */
    display: block;
    padding: .7rem .1rem;
    font-size: 1.05rem;
  }
  .site-header__inner .nav .nav-group__caret { font-size: .9em; opacity: .7; }

  /* Drop the lead arrow in the drawer. Along the desktop row the chevrons sit
     between the menus and read as "then", which is the whole point of them.
     Stacked vertically that sequence is already carried by the order of the
     rows, and the chevron instead reads as a control — every row here has a ▾
     on the trailing edge, so a second chevron on the leading edge of all but
     the first row looks like an expander missing from that one.

     Hidden here rather than unset at the source: the ═► markers in nav.rake
     still do their job everywhere there is room for them to be legible. */
  .site-header__inner .nav .nav-lead { display: none; }

  /* Sub-menu flows in the document (accordion) instead of the ≤720px absolute
     overlay — same selector/specificity so this wins the cascade below it. */
  .site-header__inner .nav .nav-group > .nav-group__menu,
  .site-header__inner .nav .nav-group--linked > .nav-group__menu {
    position: static;
    top: auto; left: auto; right: auto;
    margin: 0 0 .5rem;
    padding: .1rem 0 .35rem .85rem;
    min-width: 0; max-width: none; width: auto;
    background: transparent;
    border: 0;
    box-shadow: none;
  }
  /* An expanded <details> shows its panel regardless of the hover-media rule. */
  .site-header__inner .nav details.nav-group[open] > .nav-group__menu { display: block; }
}

.site-footer {
  background: var(--ink);
  color: var(--paper);
  margin-top: 5rem;
  padding: 2.5rem var(--container-gutter);
}
.site-footer__inner {
  max-width: var(--container-max); margin: 0 auto;
  display: flex; flex-wrap: wrap; gap: 2rem; justify-content: space-between;
}
/* Footer links (brand wordmark + nav) read clean at rest — position and
   grouping signal they're clickable — and reveal an underline on hover/focus
   for affordance and keyboard visibility. Share links manage their own. */
.site-footer a { color: var(--paper); text-decoration: none; }
.site-footer nav a:hover,
.site-footer nav a:focus-visible,
.site-footer a.site-footer__brand:hover,
.site-footer a.site-footer__brand:focus-visible { text-decoration: underline; text-decoration-color: var(--highlighter); }
.site-footer small { color: color-mix(in srgb, var(--paper) 70%, transparent); }

/* Share row — centered, directly beneath the main footer row. */
.site-footer__share {
  max-width: var(--container-max);
  margin: .4rem auto 0;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: .6rem 1.15rem;
  padding-top: .4rem;
  border-top: 1px solid color-mix(in srgb, var(--paper) 15%, transparent);
}
.site-footer__share-label {
  font: var(--fw-600) var(--fs-14) var(--font-educating);
  color: color-mix(in srgb, var(--paper) 70%, transparent);
  letter-spacing: .02em;
}
.site-footer .share-link {
  display: inline-flex; align-items: center; gap: .4rem;
  color: var(--paper); text-decoration: none;
  background: none; border: 0; padding: 0; cursor: pointer;
  font: var(--fw-600) var(--fs-14) var(--font-educating);
  line-height: 1;
}
/* The rule above is a class selector and so outranks the browser's own
 * `[hidden] { display: none }`, which is an attribute selector. Without this
 * line the hidden attribute on the "Share…" button does nothing at all and the
 * button appears on desktop Linux and Firefox, where navigator.share does not
 * exist — visible, hoverable, and inert. Any `hidden` in this row needs to win
 * here, not just be set. */
.site-footer .share-link[hidden] { display: none; }
.site-footer .share-link svg { width: 18px; height: 18px; fill: currentColor; flex: none; }
.site-footer .share-link:hover .share-link__text,
.site-footer .share-link:focus-visible .share-link__text {
  text-decoration: underline; text-decoration-color: var(--highlighter);
}
.site-footer .share-link--copy.is-copied { color: var(--highlighter); }

/* Flash messages --------------------------------------------------------- */
.flash {
  max-width: var(--container-max); margin: 1rem auto;
  padding: .85rem 1rem; border-radius: var(--radius-md);
  font: var(--fw-600) var(--fs-16) var(--font-educating);
}
.flash--notice { background: color-mix(in srgb, var(--chalkboard) 18%, var(--paper)); color: var(--chalkboard-ink); border: 1px solid var(--chalkboard); }
.flash--alert  { background: color-mix(in srgb, var(--rose) 22%, var(--paper)); color: color-mix(in srgb, var(--rose) 80%, black); border: 1px solid var(--rose); }

/* Error summary in forms ------------------------------------------------- */
.error-summary {
  background: color-mix(in srgb, var(--rose) 18%, var(--paper));
  border-left: 4px solid var(--rose);
  padding: 1rem 1.25rem; border-radius: var(--radius-md);
  margin-bottom: 1.25rem;
}
.error-summary h3 { margin: 0 0 .5rem; font: var(--fw-700) var(--fs-18) var(--font-display); }
.field--invalid .field-input,
.field--invalid .field-textarea { border-color: var(--rose); outline-color: var(--rose); }
.field-error { color: color-mix(in srgb, var(--rose) 80%, black); font-size: var(--fs-14); margin-top: .25rem; }

/* Paper-2 prose bands (guide/choice pages) — hairline seams top & bottom so
   the band reads as a deliberate standout zone rather than a faint accident,
   matching the home page's .lo-sec[data-bg="paper-2"] treatment. */
.paragraph-part--paper-2 {
  box-shadow: inset 0 1px 0 rgba(28, 28, 28, .14),
              inset 0 -1px 0 rgba(28, 28, 28, .14);
}

/* Admin bridge (minimal — enough to feel like an admin, not a public page) */
.admin-body { background: color-mix(in srgb, var(--paper) 85%, var(--chalkboard) 15%); }
.admin-shell {
  display: grid; grid-template-columns: 220px 1fr; min-height: 100vh;
}
.admin-sidebar {
  background: var(--ink); color: var(--paper);
  padding: 1.25rem 1rem; position: sticky; top: 0; height: 100vh;
}
.admin-sidebar h1 { font: var(--fw-700) var(--fs-22)/1 var(--font-display); margin: 0 0 1rem; }
.admin-sidebar ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .3rem; }
.admin-sidebar a {
  display: block; color: var(--paper); text-decoration: none;
  padding: .45rem .6rem; border-radius: var(--radius-sm);
}
.admin-sidebar a:hover { background: color-mix(in srgb, var(--paper) 12%, transparent); }
.admin-sidebar a.is-active { background: var(--highlighter-soft); color: var(--ink); }

.admin-main { padding: 2rem; max-width: 1100px; }
.admin-main h1 { font: var(--fw-700) var(--fs-32) var(--font-display); margin: 0 0 1rem; }
.admin-main table { width: 100%; border-collapse: collapse; background: var(--paper); border: 1px solid var(--rule); border-radius: var(--radius-md); overflow: hidden; }
.admin-main th, .admin-main td { text-align: left; padding: .6rem .85rem; border-bottom: 1px solid var(--rule); }
.admin-main th { background: color-mix(in srgb, var(--paper) 92%, var(--ink) 8%); font-weight: var(--fw-700); }
.admin-main .actions { display: flex; gap: .5rem; }

/* Guides prev/next pager -------------------------------------------------- *
 * Rendered at the bottom of every Guides page via app/views/pages/_guide_pager.
 * Source of truth for the order is the nav menu (lib/tasks/nav.rake) — the
 * GuidesHelper walks the "Guides" header dropdown and skips placeholder ("#")
 * entries.
 * --------------------------------------------------------------------- */
.guide-pager {
  width: min(100%, var(--container-max));
  margin: clamp(48px, 6vw, 96px) auto 0;
  padding: clamp(28px, 3vw, 40px) var(--gutter, 1.25rem);
  border-top: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  display: flex;
  justify-content: space-between;
  align-items: stretch;
  gap: 1.5rem;
}
/* Inline variant — the pager placed directly below a video sits closer to
   it than the full bottom-of-page pager. */
.guide-pager--inline {
  margin-top: clamp(20px, 2.5vw, 36px);
}
.guide-pager__link {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  text-decoration: none;
  color: var(--ink);
  max-width: 28rem;
  /* Big tappable target on mobile, but no visual chrome unless hovered. */
  padding: 0.25rem 0;
  border-bottom: 1px solid transparent;
  transition: border-color 120ms ease, color 120ms ease;
}
.guide-pager__link--next {
  text-align: right;
  align-items: flex-end;
}
/* At the ends of the chain only one link renders. Keep a lone "next" link
   (first page — no "previous") pinned to the right so the arrow still reads
   correctly against the right edge. */
.guide-pager__link--next:first-child {
  margin-left: auto;
}
.guide-pager__link:hover,
.guide-pager__link:focus-visible {
  color: var(--link, var(--ink-blue));
  border-bottom-color: var(--link-underline, currentColor);
}
.guide-pager__link:focus-visible {
  outline: 2px solid var(--focus-ring, var(--ink-blue));
  outline-offset: 4px;
}
.guide-pager__direction {
  font-family: var(--font-mono, "IBM Plex Mono", monospace);
  font-size: var(--fs-12, 0.75rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.7;
}
.guide-pager__title {
  font-family: var(--font-display, "Source Serif 4", Georgia, serif);
  font-weight: 500;
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  line-height: 1.2;
  letter-spacing: -.01em;
}
/* The Beautiful Problem keeps its named-idea signature in the pager too —
   small caps so it reads as a titled concept wherever it appears, but in the
   pager's normal ink (not the terracotta used in page content) so the chrome
   stays quiet. The ✦ sparkle is held back here (unlike the menu and page
   heroes) so the prev/next link set keeps its uniform rhythm rather than one
   link looking like a highlighted or active state. */
.guide-pager__link[href="/more-than-hope/the-beautiful-problem"] .guide-pager__title {
  color: var(--ink);
  font-variant-caps: small-caps;
  letter-spacing: .03em;
}

@media (max-width: 600px) {
  /* Keep prev / next side by side on small screens rather than stacking.
     Each link takes half the row and is allowed to shrink (min-width: 0)
     so long titles wrap within their column instead of forcing a stack. */
  .guide-pager {
    gap: 1rem;
  }
  .guide-pager__link {
    flex: 1 1 0;
    min-width: 0;
  }
  .guide-pager__title {
    font-size: 1rem;
  }
}

/* Lead statement --------------------------------------------------------- */
/* An oversized standout line (e.g. the "already been done" promise that
   sits above the Hope video). Larger than body prose, and its bold words
   pick up the terracotta accent for extra emphasis. */
.lead-statement {
  font-size: clamp(1.5rem, 3.4vw, 2.125rem);
  line-height: 1.3;
  margin: 0;
}
/* Slightly bump an emphasized word (e.g. an italic "not") a touch above the
   surrounding text so it lands harder. Relative em keeps it in scale. */
.emph-up {
  font-size: 1.12em;
}
.lead-statement strong {
  color: var(--terracotta);
}
/* Explicit accent override — lets a bold phrase inside a lead statement take
   the ink-blue accent instead of the default terracotta (e.g. an emphasized
   ink-blue question). */
.lead-statement strong.lo-accent {
  color: var(--ink-blue);
}
/* Narrow variant — pulls the left/right margins in for a tighter column. */
.lead-statement--narrow {
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
}
/* Indent variant — nudges a single statement line in to set it apart. */
.lead-statement--indent {
  padding-left: 1.5rem;
}
/* Space-after variant — adds a little breathing room beneath a statement
   line so the one that follows reads as a separate beat (used to give the
   Beautiful Problem statement air above and below on the-beautiful-problem). */
.lead-statement--space-after {
  margin-bottom: .55em;
}
/* (A --tight variant lived here. Its only user was the old two-column
   Beautiful Problem question, which .bp-statement replaced; verified unused in
   both the local and production DBs before removal.) */

/* Beat heading ----------------------------------------------------------- */
/* A compact display heading that marks a turn in the argument mid-section
   (e.g. "Bottom line"), set off from the prose above it by a hairline rule
   so it reads as a distinct concluding beat rather than another paragraph. */
.prose .beat-head {
  font-family: var(--font-display);
  font-weight: 600;
  /* Matches the "modest" section-title size so this beat heading reads as a
     peer of the section's own heading above it. */
  font-size: clamp(1.5rem, 3vw, var(--fs-30));
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: var(--sp-6) 0 var(--sp-3);
  padding-top: var(--sp-4);
  border-top: 1px solid rgba(28, 28, 28, 0.18);
}

/* Problem-provocation build (Lead Out Method) ---------------------------- */
/* Turns the "we need a new problem" beat into a short rhetorical ladder:
   two bold display statements — the second (the thesis) largest and ink-blue —
   each followed by smaller supporting lines, so the block reads as a build
   with clear hierarchy rather than a wall of same-size statements. */
.prose .problem-provoke {
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid rgba(28, 28, 28, 0.18);
}
/* The hairline exists to divide the ladder from the prose it follows. At
   position 42 that prose was deleted on 2026-08-28 and the ladder became the
   whole part, which left the rule floating across the top of the band with
   nothing above it to divide — a line that looked like a mistake rather than
   a device. A separator with nothing on one side of it is not a separator,
   so it comes off whenever the ladder opens its section. */
.prose .problem-provoke:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.prose .problem-provoke__major {
  font-family: var(--font-display);
  /* Matches the "modest" section-title scale (weight + size) so the three
     major statements read as peers of the heading above. */
  font-weight: 600;
  font-size: clamp(1.5rem, 3vw, var(--fs-30));
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
  /* Display lines get balanced wrapping. Measured on the live page: the prose
     column is 646px, and "What problem does a good school system address?"
     wants 713px at the desktop end of the clamp — 67px more than it can have.
     Left alone the browser fills line one and drops "address?" onto line two
     by itself, which reads as a mistake at this size. `balance` splits the
     two lines evenly instead. It only engages on lines that actually wrap, so
     the three short statements in this ladder are untouched, and below 768px
     the clamp drops the size enough that the long question fits on one line
     anyway. Browsers without support fall back to the ragged break. */
  text-wrap: balance;
}
/* The line that opens the band, sized up at the author's request.

   It is standing in for a deleted heading. Position 42 used to carry an h2
   ("Today's system cannot work because") at the "modest" title scale, and
   when that was cut this line inherited the job of opening the band without
   inheriting the size — __major is pegged to the modest title scale precisely
   so the ladder's rungs read as PEERS of a heading, which is wrong for a rung
   that no longer has a heading above it.

   --fs-36 is the step the house already has between the modest title (30px)
   and the h1 beat (48px), and it is the right one: a visible rise over the
   ladder below without claiming the page-heading scale that position 43's own
   title does not use either. The two rungs below stay at __major, so the
   author's "ladder at ONE size" still holds for the ladder itself — this line
   is now the thing the ladder hangs from rather than its first rung.

   The clamp floor rises with it (1.5rem -> 1.75rem) so the step survives at
   phone widths, where __major has already clamped down to 24px. */
.prose .problem-provoke__open {
  font-size: clamp(1.75rem, 3.6vw, var(--fs-36));
  margin-bottom: 0;
}

/* Keep an emphasized clause in a display line whole. Measured at 375px:
   "By now you know we need a new system." balances to two lines and the split
   fell inside the italic, leaving "we" stranded at the end of line one and
   "need a new system" starting the next — the emphasis marks a fragment
   instead of a clause. Held whole, the line breaks before the italic instead,
   which is where the sense breaks anyway. Longest such phrase is 227px at the
   24px mobile end of the clamp, against a 280px column at 320px, so nothing
   overflows in exchange. */
.prose .problem-provoke__major em {
  white-space: nowrap;
}
/* A parenthetical link hung under a display line — "(Today's system cannot be
   fixed.)" under "By now you know we need a new system."

   It stays at BODY scale on purpose. Everything else in this ladder is at the
   display scale, and the whole point of the aside is that it is a door out of
   the argument rather than a step in it; raising it would put a fourth rung
   on a three-rung ladder. __major sets margin: 0, so the gap below the
   display line has to come from here, and it is small — .55rem binds the
   aside to the line it qualifies, well inside __peak's 1.5rem below, so the
   reader sees two groups rather than three evenly spaced lines. */
.prose .problem-provoke__aside {
  margin-top: .55rem;
  margin-bottom: 0;
}
.prose .problem-provoke__peak {
  /* No size bump — sits at the same title scale as the other majors,
     just with extra breathing room above. */
  margin-top: 1.5rem;
}
/* The question that "But first:" opens onto. It is __major as well, because
   the author asked for the ladder at ONE size — the colon makes "But first:"
   a stem the question completes, and a stem that outsized what it introduces
   would read as a heading over a caption instead. Since __major sets
   `margin: 0`, two majors in a row would collide; this supplies the only
   thing they need, which is a gap, deliberately much smaller than __peak's
   1.5rem so the question binds tightly to the line above it.

   It was briefly a two-item bulleted list (.problem-provoke__asks, in git at
   8fb48e7). The author then deleted the second question, and a list of one
   marks nothing — the bullet reads as a list that lost an item, which is
   exactly what happened — so the remaining question went back to being a
   line. Restore the list markup from git if a second question returns. */
.prose .problem-provoke__ask {
  margin-top: 0.5rem;
}
.prose .problem-provoke__sub {
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  line-height: 1.4;
  /* Full ink at normal weight — matches the .impossible-statement scale so
     the supporting questions read as peers of the section's opening claim. */
  color: var(--ink);
  margin: .3rem 0 0;
  max-width: 40rem;
}
/* The supporting questions as a bulleted list — same scale/colour as the
   __sub lines above, just presented as two bullets.
   UNUSED as of 2026-08-28: the two bullets it styled ("Why design a new
   system without knowing the problem?" / "how would we know if we're making
   any progress?") were cut at the author's direction, and no other part in
   the codebase or the database carries this class. Kept rather than deleted
   because the markup may come back; safe to remove if it doesn't. Same goes
   for __sub above, which has been unused for longer. */
.prose .problem-provoke__list {
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  line-height: 1.4;
  color: var(--ink);
  max-width: 40rem;
  margin: .6rem 0 0;
  padding-left: 1.3em;
}
.prose .problem-provoke__list > li + li {
  margin-top: .5rem;
}
/* The section's opening claim reads a touch smaller than a full lead
   statement, and shares its size with the provocation's supporting lines so
   all the section's context text sits at one scale below the bold headers.

   UNUSED as of 2026-08-28: the one line it styled ("Get students, all
   different, to learn at the same pace.") was cut with the rest of position
   42's opening, and no other part in the codebase or the database carries
   this class. Kept because it still DEFINES the context-text scale that
   .pivot-line and ul.context-list are documented as sharing — deleting it
   would orphan those comments — and because the statement may come back. */
.prose .impossible-statement {
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  line-height: 1.4;
  margin: 0 0 .35rem;
  max-width: 40rem;
}

/* Two short claims ABOUT the problem — "science confirms it", "you can
   recognize it" — presented as bullets directly above a longer bulleted list
   of symptoms ("sit up", "pay attention", …). Joins the context-text family
   (.impossible-statement, .problem-provoke__sub, .problem-provoke__list) at
   the shared clamp(1.2rem, 2.6vw, 1.5rem) scale.

   The scale is the whole point. At body size these two claims render exactly
   like the symptom bullets a few lines below them, and the eye reads one
   six-item list with an odd two-item preamble instead of two claims followed
   by their evidence. Raising them to the section's context scale — the same
   size the opening claim and the provocation's questions already use — puts
   them a rung above the symptoms and restores the order of the argument. */
.prose ul.context-list {
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  line-height: 1.4;
  color: var(--ink);
  max-width: 40rem;
  margin: .9rem 0 1.25rem;
  padding-left: 1.3em;
}
.prose ul.context-list > li + li {
  margin-top: .5rem;
}

/* Run-on list — four short items that FINISH the sentence above them rather
   than standing on their own ("…don't yet have the ability to: sit up ·
   pay attention · …"). The author wrote both of these lists on a single line
   with the items separated by marks, and that is the right reading: stacked
   as four full-width bullets, two- and three-word fragments claim four lines
   of vertical space each way and the sentence they complete is broken into
   pieces. Inline they read at the speed they are meant to.

   Still a real <ul> — the items are a list to anything that isn't looking at
   the screen — with the markers turned off and a middot supplied between
   items instead. The middot is set slightly back from full ink so the items
   read and the separators recede. The tight top margin binds the run to its
   lead-in line; without it the two would sit a paragraph apart and the
   sentence would come apart again. */
.prose ul.inline-bullets {
  list-style: none;
  /* Measured: house prose rhythm is margin-bottom 16px on every <p>, and
     adjacent margins collapse, so a top margin here can only ever lose to the
     lead-in's 16px. The bind has to come from the paragraph side (rule
     below); this side just restores the normal 16px gap BELOW the run, which
     the browser would otherwise leave at zero and jam the next line against
     the items. Left alone the spacing came out exactly backwards — a full
     gap above the list and none below. */
  margin: 0 0 1rem;
  padding: 0;
}
/* Kill the lead-in's bottom margin so the run sits directly under the line it
   finishes. Scoped by :has to paragraphs that actually precede one of these
   runs, so no other prose spacing moves. Browsers without :has just show the
   normal paragraph gap — looser than intended, never broken. */
.prose p:has(+ ul.inline-bullets) { margin-bottom: .2rem; }
.prose ul.inline-bullets > li {
  display: inline;
  margin: 0;
  /* Items break BETWEEN themselves, never inside. In a run-on list the only
     thing telling the reader where one item ends is the separator, so an item
     split across a line break ("have stress or / trauma") reads as two items.
     The run itself still wraps freely — this only moves where. Longest item
     here is 21 characters against a 280px column at 320px, so nothing is at
     risk of overflowing instead. */
  white-space: nowrap;
}
/* The separator IS this list's bullet — there is no marker anywhere else, so
   the dot carries the whole job of saying "new item". At body size a middot
   is a punctuation mark and it read as one: too faint to divide the run at a
   glance. Enlarged at the author's request.

   It is DRAWN, not typed. Scaling the "\00B7" glyph was the obvious way and
   it is wrong: a middot sits a fixed fraction of its own em above the
   baseline, so at 1.7em it rose with its size and the dots ended up level
   with the ascenders instead of the middle of the text (measured, and
   plainly visible in a screenshot at 1280). A border-radius box takes
   vertical-align: middle, which puts it on the parent's own x-height centre
   and keeps it there at every clamped font size on the page.

   Sized in em so it tracks the text down to 320px. .34em is 6.8px against
   the 20px body — roughly twice the ink of the old glyph, which is what was
   asked for. The inline box is far shorter than the 31px line box, so no
   line grows; measured old-vs-new, both runs keep identical heights and
   identical wrap positions at 1440/1280/1024/768/414/375/320. The margins
   are trimmed from .6em to .5em to pay for the dot's extra width, which is
   what holds those wrap positions still. Opacity drops as size rises, since
   both read as weight and the mark should divide the items, not compete. */
.prose ul.inline-bullets > li + li::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: .34em;
  height: .34em;
  border-radius: 50%;
  background: rgba(28, 28, 28, .38);
  margin: 0 .5em;
}
/* --led adds the SAME dot in front of the first item, at the author's request
   (2026-08-28), so every item in the run carries one and the dot reads as an
   item marker rather than as a separator between items.

   ON BOTH RUNS at position 43. It went on the first one alone to begin with,
   on the argument that its lead-in ends "…have the ability to" with no colon
   while the other's ends on a colon that already marks where the items start.
   True about the grammar, wrong about the pair: the two runs are the visual
   rhyme the two panels are built on, and a marker on one and not the other
   reads as a difference before it reads as a reason. Kept as a modifier
   rather than folded into .inline-bullets because the class is site-wide and
   other pages' runs are not part of a matched pair.

   Left margin trimmed to zero on this one dot only. The separator's .5em is
   there to hold two items apart; in front of the first item there is nothing
   to its left but the list's own edge, and .5em of it pushed the run visibly
   off the flush left the paragraph above sets. The right margin stays, so the
   gap between dot and word is identical to every other dot in the run. */
.prose ul.inline-bullets--led > li:first-child::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: .34em;
  height: .34em;
  border-radius: 50%;
  background: rgba(28, 28, 28, .38);
  margin: 0 .5em 0 0;
}

/* The two problem panels at position 43 — one movement each, boxed at the
   author's request (2026-08-28), each closing on "(This is a problem.)".

   NOT NAMED .problem-box, THOUGH THAT WAS THE OBVIOUS NAME. That class already
   exists further down this file (search "Problem box — a raised") and is in use
   on /science-confirms for the Beautiful Problem callout. It is a *different*
   card: --paper on a paper-2 ground, centred, with its own p sizing. Writing
   `.prose .problem-box` here out-specified it and silently restyled that page —
   the callout's background flipped to paper-2, the exact colour of the band it
   is supposed to lift off, so the card all but disappeared. Caught by measuring
   a 640px box inside a 646px column: the 640 was that rule's max-width:40rem
   leaking in, not anything set here. Hence a name of its own.

   PAPER-2 ON A PAPER BAND, which is the house relationship: a card is the
   slightly warmer thing settled into a lighter surround. This is deliberately
   the OPPOSITE of .key-box at position 42, which inverts that relationship to
   make itself the exception. Two boxes that both wanted to be exceptional
   would leave neither one exceptional, and the key box is the page's one
   stopping point.

   THE PANELS CARRY NO INTERNAL TREATMENT beyond the frame. Everything inside
   is at body size — including the pivot line, which the author dropped to the
   surrounding scale in this same pass. That is the point of boxing: the panel
   marks the movement off, so nothing inside it needs to be raised to say
   "this group belongs together" a second time.

   The first and last children give up their outer margins so the padding is
   the only thing setting the box's interior. That matters here because both
   panels end on .problem-tally, whose 1.75rem bottom margin would otherwise
   add to the padding and leave the verdict floating well above the floor. */
.prose .problem-panel {
  background: var(--paper-2, #EADFC2);
  border: 1px solid rgba(28, 28, 28, .16);
  border-radius: var(--radius-md, 8px);
  padding: clamp(20px, 3vw, 32px) clamp(20px, 3.2vw, 36px);
  margin: clamp(20px, 2.8vw, 30px) 0;
}
.prose .problem-panel > :first-child { margin-top: 0; }
.prose .problem-panel > :last-child  { margin-bottom: 0; }
/* The band already sets its own floor (128px at desktop, shared by every
   .lo-sec on the site). Whatever ends the band gives up its bottom margin
   rather than adding to that floor — the space below the band is the band's
   business. Covers both the panels and the two-column split that now closes
   the beat below them. */
.prose > .problem-panel:last-child,
.prose > .problem-split:last-child { margin-bottom: 0; }

/* The claim each panel opens on, boxed and enlarged at the author's request
   (2026-08-28). Panel one's box holds the lead-in and its inline list as one
   unit — they are one sentence — and panel two's holds the opening paragraph
   with its .restate continuation.

   THIS IS THE SECOND CREAM-ON-PAPER-2 CARD ON THIS PAGE, and the note on
   .key-box below says that inversion is "most of why it looks special". That
   claim is now weaker and it is worth being honest about it. What keeps the
   key box distinct is the other two things it does and this does not: the
   double frame (the inset hairline 6px inside the border, which is on nothing
   else on the site) and display type, centred. This card is body face, ragged
   left, single frame — it reads as a raised sentence, not as a plaque. If the
   key box ever stops feeling exceptional, this is the first place to look.

   ON A PAPER BAND the cream fill lands on the same colour as the band showing
   past the panel, so the box reads as a hole punched back through the card to
   the page. That is the intended effect, not an accident of the token: the
   claim is what the panel is about, so it sits at the level of the page rather
   than in the card's own warmer surface.

   SIZE IS SET ON THE BOX, NOT ON ITS PARAGRAPHS, so everything inside comes up
   together. Both the inline-bullet separator (.34em) and the .restate hanging
   indent (1.1em) are already in em, so they track the new size without a
   second rule; setting --fs-24 on the <p>s alone would have left the <ul> in
   panel one at body size and split the sentence across two scales. */
.prose .panel-claim {
  background: var(--paper, #FBF6EA);
  border: 1px solid rgba(28, 28, 28, .20);
  border-radius: var(--radius-md, 8px);
  padding: clamp(16px, 2.2vw, 26px) clamp(18px, 2.6vw, 30px);
  /* No top margin: the box IS the top of the panel, and the panel's own
     padding is the only thing that should separate it from the frame. The
     bottom margin clears the 16px house rhythm so the working below reads as
     a response to the claim rather than as its next paragraph. */
  margin: 0 0 1.75rem;
  font-size: var(--fs-24);
  /* Tighter than body's line-height: at 24px the default leading opens gaps
     the box then has to pay for in height, and the claim is at most three
     lines. */
  line-height: 1.35;
}
.prose .panel-claim > :first-child { margin-top: 0; }
.prose .panel-claim > :last-child  { margin-bottom: 0; }

/* The verdict of the whole problem stretch, added 2026-08-28: two headings
   that name where the problem is NOT, then the same claim drawn as two
   columns. Sits below the two .problem-panel boxes and closes the band.

   THE TWO HEADINGS ARE A MATCHED BLUE PAIR. .lo-blue falls on "not" and
   "before" — the two words the contrast turns on — at the author's direction.
   That also repairs something the earlier cut broke: blue was introduced on
   this page as a pair ("wrong problem" / "right problem"), and deleting the
   opening of position 42 left "right problem" as a single unpaired mark. Two
   marks that answer each other put the device back on its feet.

   THE COLUMNS ARE NOT THE HOUSE .two-column BLOCK, though the content maps
   onto it. That block paints column 1 rose, and rose is this site's colour
   for the EDUCATING column — including at "Solving it happens in two columns"
   further down THIS page. A rose column here would say "solution" exactly
   where the text says "problem". So column 1 takes the same paper-2 as the
   problem panels above it and column 2 takes green, which already means
   "Learning" everywhere else. The colours then carry the headings' argument
   on their own: the problem is the left column, and the right column —
   learning — is untouched.

   Column 2 keeps --font-learning, the site's serif for learning, but NOT the
   house --chalkboard fill. The reason is written out at
   .problem-split__col--learning below; read it before repainting. */
.prose .problem-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr;
  column-gap: clamp(12px, 1.8vw, 20px);
  row-gap: 0;
  align-items: stretch;
  margin: clamp(20px, 2.8vw, 30px) 0;
}
/* Two explicit rows: captions on top, boxes beneath. Placement is explicit
   rather than left to auto-flow because the source order has to stay
   caption, box, caption, box — that is the order the block reads in when it
   stacks, and the order a screen reader takes it in. Explicit rows also keep
   the two boxes starting at the same y if one caption ever wraps and the
   other does not; auto-flow would let each column set its own top. */
.prose .problem-split__cap { grid-row: 1; }
.prose .problem-split__col { grid-row: 2; }
.prose .problem-split__cap--a,
.prose .problem-split__col--before   { grid-column: 1; }
.prose .problem-split__cap--b,
.prose .problem-split__col--learning { grid-column: 2; }
/* 720px, which is where .lo-twocol stacks (home_v1.css:1611) — that is the
   page's other two-column block, at positions 52/53. The house .two-column
   stacks at 720px too (tokens.css:479), so the number is right either way,
   but .lo-twocol is the one that actually renders here. Keep them equal:
   two two-column blocks stacking at two different widths reads as a bug. */
@media (max-width: 720px) {
  .prose .problem-split {
    grid-template-columns: 1fr;
    grid-template-rows: none;
  }
  .prose .problem-split__cap,
  .prose .problem-split__col { grid-column: auto; grid-row: auto; }
}
.prose .problem-split__col {
  border-radius: var(--radius-md, 8px);
  padding: clamp(18px, 2.6vw, 26px) clamp(16px, 2.4vw, 24px);
  /* Both columns carry the same hairline, so neither variant has to argue for
     an exception. box-sizing is border-box, so this costs no geometry: at
     1280px the two columns measure 479x197 at the same top with or without. */
  border: 1px solid rgba(28, 28, 28, .16);
}
.prose .problem-split__col--before {
  background: var(--paper-2, #EADFC2);
}
.prose .problem-split__col--learning {
  /* NOT --chalkboard, which is the house fill for a Learning column. This one
     is an argument diagram whose whole claim is "the problem is NOT here" —
     and at --chalkboard it was the loudest object in the block, so the eye
     landed on the column being dismissed. A Learning column that is being
     offered can shout; one that is being ruled out should not.

     Nothing else on the page has to match: the lead-out two-column block at
     positions 52/53 uses .lo-col-edu / .lo-col-lrn, which carry no fill at
     all. The house .two-column > .col-learning rule at tokens.css:464 does
     paint --chalkboard, but its only consumer is parts/_two_column.html.erb
     and no two_column part exists in the database (checked 2026-08-28), so
     that rule currently renders nowhere.

     Measured against the real sage band #D9E4D4 (2026-08-28), fill-vs-band:
       --chalkboard #2F4A3A  7.40:1   <- shouts; column 1 is only 1.09:1
       #46614F               5.19:1   <- still a dark panel
       this  #A7C09E         1.50:1   <- reads as a box, doesn't lead
       #C3D8BC               1.15:1   <- fill all but vanishes into the band
     Text stays well clear: ink on #A7C09E is 8.66:1 for body, and the mono
     __label at opacity .75 composites to #3f453d = 5.01:1 (was 5.32:1 on the
     chalkboard), so lightening the fill did not cost the label its AA pass.

     A deeper tint of the band itself was chosen over a paper/near-white fill
     because green is this site's colour for learning and this column carries
     half the argument the two columns make. */
  background: #A7C09E;
  color: var(--ink, #1C1C1C);
  font-family: var(--font-learning);
}
.prose .problem-split__col > :first-child { margin-top: 0; }
.prose .problem-split__col > :last-child  { margin-bottom: 0; }
/* Column labels, in the house mono eyebrow the .two-column block uses, so the
   two two-column blocks on the page label their columns the same way.

   The one departure is size: the house .col-label is --fs-12, and these are
   --fs-16, enlarged at the author's request (2026-08-28). At 12px they were
   the smallest type in a block that had just grown to the full band width and
   gained a 36px heading, and the eyebrow stopped registering as a label and
   started reading as a caption someone forgot to delete. The tracking and
   the opacity still hold it below the lead line beneath it, so the hierarchy
   inside the box is unchanged. */
.prose .problem-split__label {
  font-family: var(--font-mono);
  font-size: var(--fs-16);
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .75;
  margin: 0 0 var(--sp-3, 12px);
}
.prose .problem-split__lead {
  font-weight: 600;
  margin: 0 0 .5rem;
}
/* The inside/outside pair, hanging-indented exactly as .bp-statement sets it:
   at this column width both lines wrap, and without the hang the continuation
   would sit under the branded glyph instead of under the words after it, so
   the two lines would stop reading as a pair. The rule is restated rather than
   shared because .bp-line is scoped to .bp-statement, whose display serif and
   sizing do NOT apply here. */
.prose .problem-split__line {
  display: block;
  padding-left: 1.15em;
  text-indent: -1.15em;
  margin: 0 0 .35rem;
}
.prose .problem-split__line:last-child { margin-bottom: 0; }
/* Weld each branded glyph to its own letters. The mark is an <img>, so the
   line is otherwise free to break after it and print a lone "O" at the end of
   one line with "utside" starting the next — the same failure .bp-statement
   guards against, and it bites harder here because the column is narrower. */
.prose .problem-split__line .lo-accent:has(> .lo-mark-letter) {
  white-space: nowrap;
}

/* The two headings above the split. Enlarged at the author's request
   (2026-08-28): the lead now runs to --fs-36 and the second to --fs-30.

   THE LEAD IS DELIBERATELY LARGER THAN THE SECTION'S OWN TITLE, which is a
   "modest" h2 measuring 30px. Ordinarily that would be backwards — a section
   has one top and everything under it sits below that top. The exception was
   made knowingly: this pair is the verdict the whole problem stretch has been
   building toward, and the h2 above it only asks a question ("You might
   recognize the right problem!"). If the section ever needs its title back on
   top, the fix is to reduce these, not to inflate the h2 past --fs-36. */
.prose .split-head {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -.01em;
  font-size: clamp(1.375rem, 3.2vw, var(--fs-30));
  margin: 0 0 1rem;
}
.prose .split-head--lead {
  font-size: clamp(1.75rem, 4vw, var(--fs-36));
  margin: 2rem 0 .35rem;
}
/* The pair is one two-line statement, so the emphasis is colour and italic,
   not a weight change that would fight the heading's own weight. */
.prose .split-head em {
  font-style: italic;
}

/* The two captions that point at the boxes. They are a smaller echo of the
   headings — same display face, same blue on the word that carries the
   contrast — so the four marks (not / before / here / Not) read as one chain
   of argument rather than as four unrelated highlights. Set below the second
   heading so the eye still goes headings first, then captions, then boxes.

   RAISED FROM 20px TO 24px on 2026-08-28 at the author's request. The
   captions are the two words the whole beat turns on — "here" and "Not" —
   and at 20px they sat close enough to the 20px .panel-claim type above to
   read as more body copy. 24px is the next step on the scale and still one
   clear step below the 30px second heading, so the ladder (36 lead / 30
   second / 24 caption / 20 body) survives the change. The clamp floor moves
   with it, keeping the same proportion on phones. */
.prose .problem-split__cap {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.25rem, 2.4vw, var(--fs-24));
  line-height: 1.25;
  /* 1rem, NOT the .5rem this was, because the first caption now carries a
     squiggle that hangs below its line box. Measured at .5rem: the wave's
     bottom edge landed on the box's top border with 0px between them, at
     1440, 768 and 414 alike — the mark stopped reading as an underline on
     "here" and started reading as a rule on top of the box, which points at
     the wrong thing. 1rem restores 8px of air under the wave, the same gap
     the caption had before the mark existed.
     Both captions take it, not just the marked one: they are a matched pair
     and an 8px difference between them would show. */
  margin: 0 0 1rem;
}
.prose .problem-split__cap strong { font-weight: 700; }

/* The hand-drawn squiggle under "here", added 2026-08-28 at the author's
   request for "the wavy underline like we do under 'educating' on the
   the-beautiful-problem page". Same mark, same hand: the path lives in
   --squiggle-blue (tokens.css) and the other call site is
   .lo-col-edu .lo-col-eye strong::after in home_v1.css.

   WHY IT EARNS ITS PLACE HERE. The caption says "The problem is here." and
   then points at a box. The squiggle is what makes "here" the pointing
   finger rather than one more coloured word — and the page already teaches
   the reader what this mark means, since "Educating" wears it on
   the-beautiful-problem. It deliberately does NOT go under "Not here.":
   the mark means "this is the one being pointed at", and putting it on the
   denial would say the opposite of what the sentence says.

   THE GEOMETRY IS SET FOR THIS TYPE, NOT COPIED, and it is in em where
   home_v1's is in px. That call site draws under a 16-20px mono eyebrow;
   this one sits under a caption that clamps between 20px and 24px, so px
   offsets would make the wave 20% heavier on a phone than on a desktop
   relative to the word it marks. In em it is the same drawing at both ends.

   THE OFFSET IS MEASURED FROM THE LINE BOX, NOT THE BASELINE, which is the
   one thing worth knowing before touching these numbers. The host is an
   inline-block, so its border box is the caption's full line box — at
   line-height 1.25 that puts the host's bottom edge ~0.29em BELOW the
   baseline before this rule contributes anything. So `bottom: -.33em`
   lands the wave's lower edge 0.62em under the baseline and its upper
   edge 0.20em under — the band just clear of the "e" bowls. Measured:
   4.8px and 14.9px at 1440, 4.2px and 12.6px at 768 and 414.

   THAT IS DELIBERATELY THE SAME PLACE THE HOME PAGE MARK SITS. Measured
   there too, rather than assumed: .lo-col-edu's wave runs 5.0px to 14.0px
   below its baseline at 1440 (20px type) and 3.8px to 12.8px at 768 (16px
   type). Within a pixel of these at both ends, from completely different
   declared offsets — which is the point of measuring from the baseline
   instead of copying the px values across.

   The bleed is the same idea as home_v1's -2px, scaled: the wave starts
   and finishes just outside the word so it looks drawn through it rather
   than fitted to it. Verified that it does exactly that — the host's
   border box and the ink box of "here" measure identically (53.7px at
   1440), so the .125em is the whole of the overhang, not padding plus. */
.prose .lo-squiggle {
  position: relative;
  display: inline-block;
}
.prose .lo-squiggle::after {
  content: "";
  position: absolute;
  left: -.125em;
  right: -.125em;
  bottom: -.33em;
  height: .42em;
  pointer-events: none;
  background-image: var(--squiggle-blue);
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
/* Stacked, the second caption follows the FIRST box, so it needs the space the
   column gap was giving it side-by-side. Kept as a margin rather than a
   row-gap so the caption stays tight to the box it actually labels.

   The figure is deliberately large. A caption sits 8px above its own box, so
   whatever sits above the caption has to be several times that or the caption
   reads as the closing line of the box ABOVE it — which, for a caption that
   says "Not here.", would attach the denial to the very column it is denying.
   Measured at 375 the first attempt gave 20 over 8 and did exactly that.

   AND IT LIVES HERE, AFTER THE SHORTHAND, NOT UP IN THE STACKING MEDIA QUERY
   WHERE IT BELONGS BY TOPIC. `.prose .problem-split__cap` above sets `margin`,
   the shorthand, which writes margin-top: 0; a media query adds no
   specificity, so the same-specificity shorthand later in the file simply won
   and the override did nothing at all. The first screenshot after the "fix"
   came back the same pixel height as the one before it, which is the only
   reason it was caught. */
@media (max-width: 720px) {
  .prose .problem-split__cap--b { margin-top: clamp(28px, 4.5vw, 34px); }
}

/* ---- The breakout ------------------------------------------------------
   The verdict trespasses past the reading column out to the edges of the
   band, at the author's request (2026-08-28).

   THE TARGET IS THE BAND, NOT THE SCREEN. .lo-wrap is `max-width: 1080px`
   with `padding: 0 clamp(20px, 4vw, 56px)`, so its content box is 968px at
   1440 and 977.6px at 1280 — and that is exactly the width of this part's own
   h2 title, which is not inside .prose and already spans the full wrap. The
   block therefore lines up with the heading of its own section instead of
   landing on an arbitrary width.

   WHY A CONTAINER QUERY AND NOT vw MATH. The obvious version of this is
   `margin-inline: calc(50% - 50vw + <gutter>)`. It is wrong twice over: 100vw
   includes the classic scrollbar on Windows and Linux, so the block would
   overhang the viewport by half a scrollbar at any width below 1080 and
   introduce a horizontal scroll; and the wrap's padding is a vw clamp that
   would have to be restated here and kept in sync by hand forever. 100cqw is
   the wrap's real content width, measured, so both problems disappear.

   It also self-cancels on phones for free. Below roughly 692px the wrap's
   content box is narrower than 65ch, so .prose fills it exactly, 100% == 100cqw
   and the margins compute to zero — no media query needed to switch the
   breakout off where there is no room for it.

   THE CONTAINER IS SCOPED WITH :has() ON PURPOSE. `container-type` brings
   layout and style containment with it, and .lo-wrap is a shared primitive
   used by every band on this site — including .four-steps, which runs a CSS
   counter that style containment would reset. Restricting the container to
   the one wrap that actually holds a .problem-split keeps that blast radius
   at exactly one band on one page. Do not lift this to a bare .lo-wrap.

   THE TWO PROBLEM PANELS TAKE THE SAME BREAKOUT, added 2026-08-28 at the
   author's request to make both outer boxes wider. Widening them to anything
   short of the band edge would have put a third vertical edge in one section —
   the h2 and verdict at 968px, the panels at some middle width, the remaining
   prose at 65ch — so they go the whole way and the beat ends up with two
   edges instead of three: everything boxed on the band edge, everything
   unboxed on the reading column.

   .problem-panel IS THEREFORE ALSO A CONTAINER TRIGGER above. It only ever
   appears alongside .problem-split today (both are in position 43's body_html
   and nowhere else in the app), so this changes nothing now; it is here so
   that a panel reused on its own in future still finds a container. Without
   it, cqw units with no container ancestor resolve against the *viewport*,
   and the panel would silently break out past the band instead of not
   breaking out at all. Still scoped to wraps that hold one of these two
   blocks — do not lift it to a bare .lo-wrap. */
.lo-wrap:has(.problem-split, .problem-panel) { container-type: inline-size; }
/* The headings come with the columns so the whole verdict shares one left
   edge; left behind, they would start 161px inside the boxes they introduce
   and read as a misalignment rather than as a choice.

   .problem-panel's margin-inline MUST STAY LATER IN THE FILE than its
   `margin` shorthand up in the panel rule, which writes margin-inline: 0 at
   equal specificity. Source order is the only thing deciding this, exactly as
   with .problem-split__cap--b above. */
.prose .problem-panel,
.prose .problem-split,
.prose .split-head,
.prose .bp-name-line {
  width: 100cqw;
  margin-inline: calc(50% - 50cqw);
}
/* THE CALLOUT NEEDS A SCOPE THE OTHERS DO NOT, and this is the whole reason
   the selector above is a plain class list while this one is not.
   .problem-panel, .problem-split, .split-head and .bp-name-line exist in
   exactly two places in the app — positions 43 and 44 of this page — so
   naming them bare is naming this beat. .bp-callout is different: it comes
   out of the shared beautiful_problem_callout_html helper and appears
   wherever the site states The Beautiful Problem. Listing it bare would
   break every one of those out to the band edge.

   Worse than "wide": cqw units with NO container ancestor resolve against
   the viewport, and the other callouts do not sit in a .lo-wrap that this
   file gives `container-type` to. They would break out to the full window,
   scrollbar and all. This is not hypothetical — it is exactly what
   .problem-box--bp, which used to be listed here, was silently doing to the
   card at the foot of guides.rake's "science of learning motivation" beat.
   That selector is gone now: the box it targeted was replaced on this page
   by the labelled callout on 2026-08-28, so the only page it still reached
   was the one it was breaking.

   :has(.problem-split) is the same test the container trigger uses, one
   level down — it asks "is this the prose block that holds the verdict
   columns?", which is true of position 44's body and of nothing else. */
.prose:has(.problem-split) .bp-callout {
  width: 100cqw;
  margin-inline: calc(50% - 50cqw);
}

/* The line that names The Beautiful Problem, and the standard statement card
   under it, close the band.

   THE CARD IS AT THE BAND EDGE HERE AND ONLY HERE. Every other instance of
   .bp-callout on the site sits on the reading column, and CLAUDE.md's rule
   for the statement is "full content width — do not cap them". Widening is
   not capping, so the three lines still hold without wrapping; what changes
   is only which edge "full width" means on this one page. It is worth the
   exception because the verdict directly above it is already at the band
   edge and a 65ch card underneath would read as a mis-set block rather than
   as an indent.

   The naming line travels with it, on the same reasoning as .split-head.

   IT IS THE LABELLED CALLOUT, NOT THE PLAIN BOX, as of 2026-08-28. The
   author's first direction here was the bare statement; his correction
   ("my mistake") asked for the standard box "complete with the statement
   '[icon] The Beautiful Problem / How to get...'" — that is
   beautiful_problem_callout_html, which adds the mark and the "The
   Beautiful Problem:" label above the same three lines. He is right that
   this is the house standard: a reader meeting the name for the first time
   should meet it labelled. See the note on the breakout selector above for
   why the switch also fixed a bug on a different page.

   CREAM ON A SAGE BAND. The card was written to lift off a paper-2 ground;
   position 44's band is sage, which is darker still, so the cream fill now
   does the lifting on its own and the border and shadow only draw the edge.
   That is a stronger relationship than the paper-on-paper one this note
   used to describe, when the whole beat lived in position 43's paper band.
   It is also the same figure/ground the .panel-claim boxes use one band up,
   so the two bands stay related. Confirm in the render after any band
   colour change — this is the one thing the band colour actually decides.

   THE THREE LINES STILL HOLD. Measured by distinct rect tops (getClientRects
   on a Range returns one rect per inline fragment, not per line, so a raw
   count reads 2/5/3 and means nothing): 1/1/1 at 1440, 1280, 1024, 768, 414,
   375 and 320. Widening cannot cause the wrap that CLAUDE.md warns about —
   only narrowing can — but it was worth confirming rather than assuming.
   Re-checked after the callout swap: the label sits above the statement, so
   it takes a line of its own and changes nothing about the three below it. */
.prose .bp-name-line {
  /* THE 65ch CAP IS NO LONGER THE HAZARD IT WAS, but the reset stays.
     The naming line used to be a <p>, and tokens.css caps every <p> at
     `max-width: var(--prose-max)` — 65ch, 646px. The breakout applied its
     negative margin-inline, the cap held the width at 646, and the line
     started on the band edge and stopped 236px short of the box it
     introduces: worse than not breaking out at all. It is an <h3> now (see
     below) so the `p` cap no longer reaches it — and this line is exactly
     one edit away from being a <p> again. Keeping the reset costs nothing
     and means that edit cannot silently re-break the alignment. */
  max-width: none;
  /* A HEADING NOW, at the author's request on 2026-08-28: "Make this a
     heading". It was body copy, which put the sentence that names the whole
     idea at the same weight as the prose describing the columns.

     30px, NOT 36. It sits under a 36px lead heading in the same band, and
     the second heading there is already 30px — so this takes the same step,
     and the band reads as one two-level structure (36 opens, 30 turns, 30
     concludes) instead of growing a third heading size. It does not need to
     out-shout the lead: the callout directly beneath it is the emphasis.

     Display face and 600 to match .split-head exactly; the only difference
     between them is the extra space above, which .split-head--lead also
     takes, because this line closes one movement and opens another. */
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.375rem, 3.2vw, var(--fs-30));
  line-height: 1.15;
  letter-spacing: -.01em;
  margin-top: clamp(28px, 3.4vw, 40px);
  margin-bottom: .9rem;
}
/* The band sets its own 128px floor; whatever ends the band gives up its
   bottom margin rather than adding to it. The statement card is the last
   thing in this one, so it joins the pair already listed above.

   SCOPED THE SAME WAY THE BREAKOUT IS, and for the same reason: .bp-callout
   is a site-wide component, and a bare `.prose > .bp-callout:last-child`
   would strip the bottom margin off callouts on other pages where nothing
   is supplying a floor underneath them. */
.prose:has(.problem-split) > .bp-callout:last-child { margin-bottom: 0; }

/* "(This is a problem.)" — the verdict that closes each half of the
   right-problem beat. The pair is the spine of the section, and the only
   thing they need in order to read as a matched pair is room: the parentheses
   already mark them as asides, so any further styling would be a second
   signal saying the same thing. The space above sets each one off from the
   line it judges; the space below opens the next movement. */
.prose .problem-tally {
  /* Measured against the house rhythm: prose paragraphs are 16px apart, so
     1.1rem (17.6px) collapsed to a gap of 18px and the verdicts read as two
     more paragraphs. 1.75rem clears it properly. */
  margin-top: 1.75rem;
  margin-bottom: 1.75rem;
}

/* A dash-led restatement set on its own line inside the sentence it belongs
   to ("…are not able to use freedom / — freedom they need to…"). A block span
   rather than a second <p> because it is the same sentence: a paragraph break
   would put house rhythm between a noun and its own gloss.

   The hanging indent is the point of the rule. The dash sits out in the
   margin and the continuation's own wrapped lines align to the text after it,
   so the dash reads as a mark introducing a clause instead of drifting into
   the left margin like a list bullet — which is how it looked flush, since
   the line below it starts a run of ordinary paragraphs. 1.1em is the em dash
   plus its following space at body size.

   USED TWICE IN A ROW as of 2026-08-28, where it was written for one: the
   author split the gloss into two dash-led clauses ("— freedom they need to
   learn / — and help each other learn"). Two consecutive blocks need no
   margin between them — they are lines of one sentence, so the box's own
   line-height is the correct gap and anything more would make them read as
   two paragraphs. The hanging indent then does a second job it was not
   designed for and happens to do well: it stacks the two dashes in the same
   column, so the pair reads as a pair. */
.prose .restate {
  display: block;
  padding-left: 1.1em;
  text-indent: -1.1em;
}
/* The tail the dash-led clauses share ("in their own learning zones (for
   parts of the day)."), on its own line and NOT dash-led — it belongs to both
   clauses above it, so giving it a dash of its own would make it a third
   sibling instead of their common ending.

   FLUSH LEFT, aligning with the paragraph's first line rather than with the
   text after the dashes. That is what makes the grammar visible: the sentence
   is "…are not able to use freedom … in their own learning zones", and the
   two dashed lines are an aside inside it. Indented to 1.1em instead, it read
   as a continuation of "and help each other learn" alone, which is not what
   it means. Set as its own block span rather than left as bare text after the
   second .restate because bare text would simply run on to the end of that
   clause's line. */
.prose .restate-tail { display: block; }

/* The pivot of the beat — the one-and-many stated in a single line.

   IT NO LONGER SITS ABOVE BODY SIZE. It used to take the section's
   context-text scale, clamp(1.2rem, 2.6vw, 1.5rem), on the reasoning that it
   was doing the work the deleted Beautiful-Problem callout panel used to do.
   The author dropped it to the surrounding size on 2026-08-28, and the boxing
   in the same pass is why that reads correctly now: the box is the thing
   marking this movement off, so a raised line inside it was a second frame
   around content that already had one, and it made the pivot compete with the
   panel instead of sitting inside it.

   What is left still sets the line apart, without size: the author's italic,
   and room above and below that clears the 16px house rhythm. */
.prose .pivot-line {
  line-height: 1.4;
  max-width: 40rem;
  /* Same arithmetic as .problem-tally: 1.1rem collapsed against the 16px
     prose rhythm to an 18px gap, which is no separation at all. */
  margin: 1.75rem 0;
  text-wrap: balance;
}

/* The key box — the one panel on this page that is meant to stop the reader.
   It closes the provocation ladder by naming what the whole beat has been
   building to, so it has to look unlike every other box on the site rather
   than like a slightly warmer .choice-box.

   Three things make it distinct, and each is doing work:

   1. CREAM ON PAPER-2. Every other panel in the house style is a paper-2 card
      on a paper band. This sits on the paper-2 band at position 42, so it
      inverts the relationship — the card is the lighter thing, lifted out of
      its surroundings instead of settled into them. It is the only panel on
      the site that reads that way, which is most of why it looks special.
   2. A DOUBLE FRAME. The outer border plus an inset hairline 6px inside it.
      Drawn with two inset shadows: the first paints a 6px ring in the card's
      own fill (invisible), the second draws the hairline at its edge. Nothing
      else on the site is framed twice.
   3. DISPLAY TYPE, CENTRED. The lines are statements, not prose, so they take
      the display face at the context scale rather than the body face.

   The accent inside is TERRACOTTA, not ink-blue, and that is deliberate: this
   section already spends its blue on the matched pair "wrong problem" /
   "right problem" (position 42's subtitle and its question). A blue "key"
   would make that pair a run of three and spend the device. Terracotta is the
   house's other text accent (.lo-terra) and appears nowhere else in the
   section, so it reads as this box's own colour.

   Bold would buy nothing here — the type is already display serif at 600 —
   which is why the author's ** on "key" is carried by colour, and his * on
   "heart" by the italic he asked for. */
.prose .key-box {
  background: var(--paper, #FBF6EA);
  border: 1px solid rgba(28, 28, 28, .24);
  border-radius: var(--radius-md, 8px);
  box-shadow: inset 0 0 0 6px var(--paper, #FBF6EA),
              inset 0 0 0 7px rgba(28, 28, 28, .20);
  padding: clamp(24px, 3.4vw, 38px) clamp(22px, 3.6vw, 42px);
  /* Bigger than the 0.5rem that binds the question to its stem: the box is
     the answer to the ladder, not another rung of it. */
  margin: 1.6rem 0 0;
  text-align: center;
}
.prose .key-box p {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.2rem, 2.5vw, 1.55rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}
/* Two lines, one statement — a gap, not a paragraph break. */
.prose .key-box p + p { margin-top: .45rem; }
/* "right problem" is the phrase the beat turns on, and inside the box it is a
   verbatim echo of the question directly above. Measured at 375px the balanced
   wrap broke it after "right", which reads as two ideas rather than one name;
   held whole. The longest unbreakable run is then 13 characters, which fits
   the 236px inner column at 320px. */
.prose .key-box .hold { white-space: nowrap; }

/* .see-also-box WAS HERE, deleted 2026-08-28. It was the light cousin of
   .choice-box — same paper-2 fill, hairline border and radius, none of the
   display type or heavy padding — for a short aside offering a detour rather
   than advancing the argument. Its only user in the app was the "…see this
   video." part at position 45 of lead-out-method, and when that copy was cut
   the same day the class went with it. Recoverable from git at 6d172f0~ if a
   detour aside is ever wanted again; the sizing was deliberately left to the
   part's own body_size and the width to the prose column. */

/* Beautiful-Problem callout — frames the two-line statement in a soft
   paper-2 panel so it reads as a discrete "here's the problem" block rather
   than relying on whitespace alone. Matches the house .choice-box treatment
   (paper-2 + thin ink border + rounded) with lighter padding. */
.bp-callout {
  /* Full content width, not the old 38rem cap. The statement inside is three
     parallel lines sharing a left edge (see .bp-statement); narrowing the box
     only forces those lines to wrap, which is the one thing that breaks the
     parallel reading. The prose column is the real limit. */
  margin: 1.5rem auto;
  padding: 1.1rem 1.5rem 1.25rem;
  background: var(--paper-2, #F3ECD6);
  border: 1px solid rgba(28, 28, 28, .16);
  border-radius: var(--radius-md, .5rem);
}
/* Inside the panel the narrow statements no longer need their own centering
   frame — let them fill the panel's padded width. */
.bp-callout .lead-statement--narrow {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}
/* Header row of the callout: the Schoolio mark (an "i" — inside — within an
   "O" — outside) sits beside the "The Beautiful Problem:" label, so the mark
   visually restates the inside/outside idea the statement below spells out. */
.bp-callout__head {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-bottom: .55em;
}
.bp-callout__head .lead-statement {
  margin: 0;
}
.bp-callout__mark {
  flex: 0 0 auto;
  width: 3rem;
  height: auto;
  display: block;
}
@media (max-width: 640px) {
  .bp-callout__mark { width: 2.5rem; }
  /* Buy back width where it is scarcest. On a 414px phone the box's own
     padding is 48 of the 96px separating the viewport from the text, and each
     16px returned is 16px the statement does not have to wrap. The card still
     reads as a card at 1rem. (The matching override for .problem-box--bp has
     to live further down, after .problem-box's own padding shorthand — see
     the note there.) */
  .bp-callout { padding-left: 1rem; padding-right: 1rem; }
}
/* Branded "inside" / "outside" words. The Schoolio mark does letter duty:
   the bare "i" glyph (schoolio-mark-i.svg) replaces the "i" in "inside", and
   the full mark (schoolio-mark.svg — an "i" within an "O") replaces the "O" in
   "outside". Reusable anywhere the inside/outside idea appears; pair with the
   branded_inside_html / branded_outside_html rake helpers in guides.rake, or
   hand-write the same <img class="lo-mark-letter lo-mark-letter--i|--o"> markup.
   Heights/baselines are tuned so each glyph sits like a capital-height letter. */
.lo-mark-letter { width: auto; vertical-align: -0.14em; }
.lo-mark-letter--i { height: 1.18em; }
.lo-mark-letter--o { height: 1em; vertical-align: -0.18em; }
/* The last line shouldn't add margin below the panel's own bottom padding. */
.bp-callout > :last-child {
  margin-bottom: 0;
}
/* The Beautiful Problem statement — the site-wide standard treatment, emitted
   by the bp_statement_html helper in guides.rake. Three lines: a bold lead-in
   ("How to get students"), then the inside/outside pair, each opening with its
   branded glyph and hinged on an en dash.

   This replaced a two-column .bp-split treatment that put "inside …" and
   "outside …" either side of a hairline seam. The parallel structure is what
   carries the idea, and a shared left edge shows it far better than a seam
   did: the two lines start the same way, so the eye compares the halves
   directly instead of reading them as two separate fragments. It also frees
   the box to be full width, which is why .bp-callout no longer caps at 38rem.

   On size vs. line count. This first shipped with a viewport-tracking
   font-size floor copied from the home hero sub-line, chosen to hold three
   lines at every width. That was the wrong trade here, and the measurement
   says why the home version gets away with it and this one cannot: the hero
   spans nearly the whole viewport (40px of chrome), while this sits inside a
   section (24px each side) inside a box (24px each side) — 96px gone, leaving
   318px of text on a 414px phone. Three lines at a proper statement size
   (24px x the measured 15.3 width-to-size ratio = 367px) does not fit in 318,
   and would not fit even with the box padding removed entirely.

   So the floor was buying line count with type size, and the bill came due on
   phones: 15px text against 15px body copy, when every other .lead-statement
   on the page is 24px. It read as body copy, not as the statement of the
   problem the whole site is about.

   The floor is kept, but re-derived from constants that are now correct
   rather than guessed, which is what was actually wrong the first time:
     - chrome is 80px, not 96 — the box's phone padding is trimmed to 1rem
       below 640px (see the media query above), returning 16px of text width;
     - the divisor is 15.8, close to the measured 15.3 width-to-size ratio of
       the longest line plus a little safety. The original 18.5 was picked
       conservatively rather than measured, and that alone cost ~3px.
   Together those lift a 360px phone from 15.1px to 17.7px and a 414px phone
   from 18.1px to 21.1px, while still holding three lines — so this is not a
   trade of size against line count, it is both.

   The wrap case is still handled rather than merely avoided: each line is its
   own block (.bp-line) with a hanging indent, so if a line does wrap — user
   font scaling, a narrower device than any tested — its continuation sits
   inboard of the branded glyph and the three lines still start on a shared
   left edge. .lo-nowrap-beat keeps "need to succeed" whole so the break lands
   somewhere sensible. */
.bp-statement {
  /* The display serif, explicitly — not the inherited page voice. This is the
     home hero's sub-line promoted to a standard, and the serif is part of that
     treatment: it sets the statement apart from the body copy around it as a
     thing being quoted rather than another paragraph. Naming the family here
     also makes the callout look identical on "educating" pages (sans voice)
     and "learning" pages (serif voice), which a standard treatment should. */
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(min(1.5rem, calc((100vw - 5rem) / 15.8)), 3.4vw, 2.125rem);
  line-height: 1.3;
  letter-spacing: -.008em;
  margin: 0;
  text-align: left;
}
/* One block per line, with a hanging indent for the wrap case. The indent is
   sized to clear the branded glyph plus its following space, so a continuation
   line starts under the word rather than under the mark. */
.bp-statement .bp-line {
  display: block;
  padding-left: 1.15em;
  text-indent: -1.15em;
}
/* The statement is a <p>, so inside a guide page `.page-paper .prose p`
   (tokens.css) out-specifies the class above — two classes plus an element
   beats one class — and would add a bottom margin that pushes the last line
   past the box's own padding. Match it with three classes rather than !important. */
.page-paper .prose .bp-statement,
.prose .bp-callout .bp-statement,
.prose .problem-box .bp-statement {
  margin: 0;
}
/* .lead-statement sets bold runs in terracotta, which would collide with the
   red "The Beautiful Problem:" label directly above. Here the bold is doing
   structural work, not colour work — it just anchors the lead-in — so keep it
   ink and let the ink-blue accents carry the emphasis, exactly as on home. */
.bp-statement strong {
  color: inherit;
  font-weight: 600;
}
.bp-statement .lo-accent em {
  font-style: italic;
}
/* Weld a branded glyph to the rest of its word. The mark is an <img>, so a
   line is otherwise free to break between it and the letters after it, which
   printed "outside" as a lone O-mark followed by "utside". Matching on :has()
   targets only the wrapper branded_inside_html / branded_outside_html emit,
   leaving ordinary .lo-accent runs free to wrap. Same rule as the home hero. */
.bp-statement .lo-accent:has(> .lo-mark-letter) {
  white-space: nowrap;
}
/* Keep "need to succeed" whole if its line ever does overflow, so the beat
   moves down intact rather than leaving a two-word orphan. The floor above
   should mean this never fires; it is a fallback for engines that set the
   line wider than the slack the floor allows. */
.bp-statement .lo-nowrap-beat {
  white-space: nowrap;
}
/* Forward-pointer aside that sits between a section title and the content
   below it (e.g. "you'll see the exact same steps on the Education page").
   Set a touch larger than the body/step text and gently emphasised — italic,
   accent colour, with a soft accent hairline on the left — so it reads as a
   quiet standout without shouting. */
.prose .steps-note,
.steps-note {
  margin: .35rem 0 1.35rem;
  padding-left: .9rem;
  border-left: 3px solid var(--terracotta);
  font-family: "Source Serif 4", Georgia, serif;
  font-style: italic;
  font-size: clamp(1.3rem, 2.4vw, 1.65rem);
  line-height: 1.4;
  color: var(--terracotta);
}
.prose .steps-note em,
.steps-note em {
  font-style: normal;
  font-weight: 600;
}
/* Smaller variant of the forward-pointer note — for a full-sentence note
   (rather than a one-line aside) that should read quieter, closer to body
   size, while keeping the italic terracotta accent-rule treatment. */
.prose .steps-note--sm,
.steps-note--sm {
  font-size: clamp(1.05rem, 1.7vw, 1.25rem);
  line-height: 1.45;
}
/* "The trap" line in the Beautiful Problem "significance" block. Set off
   with a terracotta left-rule (echoing steps-note) but kept in ink and a
   touch smaller than the surrounding prose, so it reads as a subordinate
   aside rather than a louder beat — and the sentence above it stays the
   dominant line. The bold anchor + italic question inside stay visible. */
.prose .problem-note,
.problem-note {
  margin: .35rem 0 1.35rem;
  padding-left: .9rem;
  border-left: 3px solid var(--terracotta);
  font-size: .92em;
  line-height: 1.5;
}
/* Quiet qualifier line beneath a section title (e.g. "The problem" /
   "— as understood by Taylor's method"). Sits on its own line, sized well
   down from the heading and set in a softer weight/colour so it reads as a
   subordinate framing note rather than a second heading. */
.title-qualifier {
  display: block;
  margin-top: .2rem;
  font-size: .5em;
  font-weight: 500;
  font-style: italic;
  line-height: 1.25;
  color: rgba(28, 28, 28, .6);
}

/* Problem box — a raised "here's the problem" card. Used inside the paper-2
   "science of learning motivation" section, so it takes the *lighter* --paper
   bg (plus a thin border + paper shadow) to lift off the paper-2 ground. */
.problem-box {
  max-width: 40rem;
  margin: 1rem auto 1.5rem;
  padding: 1.1rem 1.6rem 1.2rem;
  background: var(--paper, #FBF6EA);
  border: 1px solid rgba(28, 28, 28, .16);
  border-radius: var(--radius-md, 8px);
  box-shadow: var(--shadow-paper, 4px 4px 0 0 rgba(28, 28, 28, .12));
  text-align: center;
}
/* Excludes .bp-statement deliberately. This rule out-specifies a bare class
   (one class + one element beats one class), so without the :not() it would
   override .bp-statement's font-size and line-height — and the only way to win
   it back would be to restate the measured clamp here, giving that constant a
   second home to drift from. Narrowing this selector keeps one source. */
.problem-box p:not(.bp-statement) {
  margin: 0;
  /* Sized to keep the single statement on one line within the box on
     desktop; it may wrap on the narrowest phones, which is fine. */
  font-size: clamp(1.05rem, 2.3vw, 1.35rem);
  line-height: 1.25;
}
/* When the box holds the standard Beautiful Problem statement, it is the same
   full-width, left-aligned block as the .bp-callout — only the card styling
   differs (this one lifts off a paper-2 ground). */
.problem-box--bp {
  max-width: none;
  text-align: left;
}
/* Phone padding, matching .bp-callout's, so the statement gets the same text
   width in both containers. This must sit *after* .problem-box above: both
   selectors are a single class, so the cascade falls to source order, and
   .problem-box's `padding` shorthand would otherwise reinstate its wider
   1.6rem sides. That is exactly what happened when this override was first
   written up beside the .bp-callout one — the callout took the extra width
   and this box silently did not, wrapping its second line on every phone
   width while the callout beside it held three lines. */
@media (max-width: 640px) {
  .problem-box--bp { padding-left: 1rem; padding-right: 1rem; }
}

/* Tiny utilities --------------------------------------------------------- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.text-center { text-align: center; }
.mt-4 { margin-top: 2rem; }
.mt-6 { margin-top: 3rem; }

/* Thought bubble --------------------------------------------------------- */
/* A student's inner voice, rendered as a rounded thought balloon with two
   trailing dots to the lower-left. Used on the Dan Pink guide's closing
   "Did Mr Pink succeed?" beat (the Purpose line). */
.thought-bubble {
  position: relative;
  display: inline-block;
  margin: 0.5rem 0 1.25rem 1.9rem;
  padding: 0.85rem 1.15rem;
  max-width: 48ch;
  background: var(--paper-2);
  border: 1px solid rgba(28, 28, 28, 0.15);
  border-radius: 1.4rem;
  box-shadow: var(--shadow-paper);
  font-style: italic;
  line-height: 1.4;
}
.thought-bubble::before,
.thought-bubble::after {
  content: "";
  position: absolute;
  background: var(--paper-2);
  border: 1px solid rgba(28, 28, 28, 0.15);
  border-radius: 50%;
}
.thought-bubble::before {
  width: 0.9rem; height: 0.9rem;
  left: -0.7rem; bottom: 0.5rem;
}
.thought-bubble::after {
  width: 0.5rem; height: 0.5rem;
  left: -1.3rem; bottom: 0.05rem;
}

/* ------------------------------------------------------------------ *
 * Classroom-proof "results after the video" beat (Eva Fugitt &
 * Marva Collins pages).
 * Shared, page-agnostic pieces are prefixed `.proof-`; each page adds
 * its own results graphic (`.eva-read` growth bar, `.marva-read`
 * reading list, `.marva-outcomes` life-outcomes contrast). All styling
 * is class-based so it survives the paragraph part's rich_text
 * sanitiser (inline styles are stripped).
 * ------------------------------------------------------------------ */
.proof-result { margin: 0 auto; }
.proof-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(28, 28, 28, 0.6);
  margin: 1.6rem 0 0.35rem;
}
.proof-result > .proof-eyebrow:first-child { margin-top: 0; }
/* Cohort descriptor: meaningful context, so it reads stronger than the
   quiet section-label eyebrows. */
.proof-eyebrow--cohort {
  color: var(--ink);
  font-weight: 600;
  font-size: var(--fs-16);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.proof-eyebrow--cohort::before {
  content: "";
  flex: none;
  width: 1.7rem;
  height: 3px;
  border-radius: 2px;
  background: var(--terracotta);
}
/* "Yes — spectacularly." subtitle, lifted in terracotta so the verdict pops. */
.proof-yes { color: var(--terracotta); }
.proof-caption {
  margin: 0.5rem 0 0;
  font-size: var(--fs-16);
  line-height: 1.5;
  color: var(--ink);
}

/* Shared: a paper card that lifts a results graphic off the paper-2 band. */
.proof-card {
  background: var(--paper);
  border-radius: 12px;
  box-shadow: var(--shadow-paper);
  padding: 1.25rem 1.4rem;
  margin: 1rem 0 0;
  max-width: 44rem;
}
.proof-card .marva-read { max-width: none; }
.proof-card .marva-read__row:last-child { border-bottom: 0; padding-bottom: 0; }

/* Shared: the people's own voices (parents, reporters, students) */
.proof-voices { display: grid; gap: 1rem; margin: 1.7rem 0 0; }
.proof-voice {
  border-left: 3px solid var(--terracotta);
  padding: 0.15rem 0 0.15rem 1rem;
}
.proof-voice__quote {
  font-style: italic;
  font-size: var(--fs-20);
  line-height: 1.4;
  margin: 0;
}
.proof-voice__who {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(28, 28, 28, 0.6);
}

/* Feature voice — a highlighted story card (e.g. the two hidden gifts). */
.proof-voice--feature {
  border-left: 0;
  padding: 1.15rem 1.3rem;
  margin: 1.4rem 0 0;
  max-width: 44rem;
  background: var(--paper);
  border-top: 4px solid var(--terracotta);
  border-radius: 0 0 12px 12px;
  box-shadow: var(--shadow-paper);
}
.proof-voice__tag {
  display: inline-block;
  margin: 0 0 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--fs-12);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--terracotta);
}
.proof-voice--feature .proof-voice__quote { font-size: var(--fs-20); }

/* Shared: the point — educating, not just same-pace learning */
.proof-point {
  margin: 2rem 0 0;
  padding: 1.6rem 0 0;
  border-top: 2px solid rgba(28, 28, 28, 0.14);
  max-width: 44rem;
}
.proof-bp { margin: 2.4rem 0 0; }
.proof-point__head {
  font-size: clamp(1.5rem, 3vw, var(--fs-30));
  line-height: 1.15;
  margin: 0 0 0.6rem;
}

/* Eva Fugitt: reading-level growth bar (grade-equivalent 2.4 -> 6.0) */
.eva-read { max-width: 40rem; margin: 0 0 0.4rem; }
.eva-read__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  font-weight: 600;
  color: rgba(28, 28, 28, 0.55);
}
.eva-read__track {
  position: relative;
  height: 2.5rem;
  margin-top: 0.45rem;
  background: rgba(28, 28, 28, 0.08);
  border-radius: 7px;
}
.eva-read__fill {
  position: absolute;
  top: 0; bottom: 0;
  left: 28%;            /* grade-equivalent 2.4 on a 1–6 scale */
  right: 0;             /* grade-equivalent 6.0 */
  background: var(--chalkboard);
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 0.8rem;
  box-shadow: var(--shadow-paper);
}
.eva-read__from,
.eva-read__to {
  font-weight: 700;
  font-size: var(--fs-18);
  color: #F7F1E1;
  line-height: 1;
}
.eva-read__gain {
  text-align: center;
  margin: 0.6rem 0 0;
  font-weight: 700;
  font-size: var(--fs-18);
  color: var(--chalkboard);
}

/* Eva Fugitt: hero-stat card — the big "+3.6 years" figure beside the bar,
   lifted off the paper-2 band on its own paper card. */
.eva-result {
  display: flex;
  align-items: stretch;
  gap: 1.1rem;
  max-width: 44rem;
  margin: 1rem 0 0;
  padding: 1.25rem;
  background: var(--paper);
  border-radius: 12px;
  box-shadow: var(--shadow-paper);
}
.eva-result__figure {
  flex: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.35rem;
  padding: 1rem 1.2rem;
  background: var(--chalkboard);
  border-radius: 10px;
  text-align: center;
}
.eva-result__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.75rem, 8vw, var(--fs-60));
  line-height: 0.9;
  color: #F7F1E1;
}
.eva-result__unit {
  font-family: var(--font-mono);
  font-size: var(--fs-12);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1.35;
  color: rgba(247, 241, 225, 0.85);
}
.eva-result__bar {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}
.eva-result__bar .eva-read { margin: 0; max-width: none; }

/* Marva Collins: what her young children were reading (age -> authors) */
.marva-read { max-width: 40rem; margin: 0; display: grid; gap: 0.55rem; }
.marva-read__row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  align-items: baseline;
  gap: 0.9rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid rgba(28, 28, 28, 0.12);
}
.marva-read__grade {
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--chalkboard);
}
.marva-read__authors {
  margin: 0;
  font-size: var(--fs-18);
  line-height: 1.35;
}

/* Marva Collins: life-outcomes contrast (predicted vs. her students) */
.marva-outcomes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: 1.25rem;
  max-width: 48rem;
  margin: 0.6rem 0 0;
}
.marva-outcomes__vs {
  align-self: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-style: italic;
  font-size: var(--fs-20);
  color: var(--terracotta);
}
.marva-outcome {
  align-self: stretch;
  border-radius: 10px;
  padding: 1.3rem 1.5rem;
}
.marva-outcome--predicted {
  background: rgba(28, 28, 28, 0.06);
  border: 1px solid rgba(28, 28, 28, 0.12);
}
.marva-outcome--actual {
  background: var(--chalkboard);
  color: #F7F1E1;
  box-shadow: var(--shadow-paper);
}
.marva-outcome__label {
  font-family: var(--font-mono);
  font-size: var(--fs-16);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
  margin: 0 0 0.6rem;
  opacity: 1;
}
.marva-outcome__list { margin: 0; padding: 0; list-style: none; }
.marva-outcome__list li {
  font-weight: 700;
  font-size: var(--fs-24);
  line-height: 1.5;
}
@media (max-width: 34rem) {
  .marva-outcomes { grid-template-columns: 1fr; }
  .marva-outcomes__vs { justify-self: center; padding: 0.15rem 0; }
  .marva-read__row { grid-template-columns: 1fr; gap: 0.15rem; }
  .eva-result { flex-direction: column; align-items: stretch; }
  .eva-result__figure { flex-direction: row; align-items: baseline; justify-content: center; gap: 0.6rem; }
}

/* --- Book endorsements ---------------------------------------------------
 * Long-form, attributed endorsements: several paragraphs each, under the
 * endorser's name and credentials. Used on /team/robert-j-caveney for the
 * five endorsements of SCHOOLING For Readiness And Drive.
 *
 * These deliberately do NOT take the default `blockquote` treatment from
 * tokens.css. That one — display serif at fs-24 on a yellow highlighter wash
 * — is built for a single arresting line; five multi-paragraph quotes in it
 * would be a wall of yellow with nothing left to emphasise. Here the quote
 * is body-sized prose behind a quiet accent rule, and the attribution above
 * does the work of announcing whose voice it is.
 *
 * The endorsements arrive through rich_text, whose sanitizer allows `class`
 * but strips `style` — which is why this lives in CSS rather than inline on
 * the generated markup.
 */
.book-endorsement { margin: var(--sp-7) 0 0; }

.book-endorsement + .book-endorsement {
  border-top: var(--hairline);
  padding-top: var(--sp-6);
}

.book-endorsement__name {
  font-family: var(--font-display);
  font-size: var(--fs-24);
  line-height: 1.2;
  margin: 0 0 0.35rem;
}

/* Sentence case, not the uppercase mono the site uses for short eyebrow
 * labels. These credentials run long — "Former VP of the California
 * Federation of Teachers (CFT) and former president of CFT's Early
 * Childhood/K-12 Council" — and uppercase with letter-spacing turns a line
 * that length into something you decode rather than read. */
.book-endorsement__credit {
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  line-height: 1.5;
  opacity: 0.75;
  margin: 0 0 0.15rem;
}

/* Outweigh the element selector in tokens.css without !important. */
.prose blockquote.book-endorsement__quote {
  margin: var(--sp-4) 0 0;
  padding: 0 0 0 var(--sp-4);
  background: none;
  border-left: 3px solid var(--highlighter);
  font-family: inherit;
  font-size: inherit;
  line-height: 1.55;
}

.book-endorsement__quote p { margin: 0 0 var(--sp-3); }
.book-endorsement__quote p:last-child { margin-bottom: 0; }

/* --- Scripts (extended quotation) ----------------------------------------
 * A passage quoted at length from a book, meant to be READ ALOUD or worked
 * through step by step, not glanced at. Used for Eva Fugitt's exercise
 * scripts on the example-elementary-school-day page — the longest runs to
 * around five hundred words across seven paragraphs.
 *
 * Like .book-endorsement__quote above, this opts out of the default
 * `blockquote` in tokens.css. That treatment — display serif at fs-24 on a
 * yellow highlighter wash — is a PULL-QUOTE: it exists to lift one arresting
 * line out of the prose. Setting a five-hundred-word script in it would put
 * a page and a half of the page under a yellow wash at heading size, which
 * shouts the whole thing evenly and so emphasises nothing. It would also
 * misdescribe the material: a pull-quote is the author's own words made
 * loud, and these are somebody else's words handed over intact.
 *
 * So: body size, the serif reading face (--font-learning) rather than the
 * page's sans, and a quiet ink rule down the left. The rule is the only
 * ornament, and it is what makes the script's extent legible at a glance —
 * you can see where the teacher's script starts and stops without reading a
 * word of it. The serif is doing real work too, not decoration: it marks
 * the switch from the site explaining something to a voice you are meant to
 * speak in, and it matches the "learning" voice the site already uses for
 * material addressed to a student.
 *
 * Scripts arrive through rich_text, whose sanitizer allows `class` but
 * strips `style`, which is why this is a class here and not inline on the
 * generated markup.
 */
.prose blockquote.script {
  margin: var(--sp-4) 0 var(--sp-5);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-5);
  background: none;
  border-left: 2px solid rgba(28, 28, 28, 0.22);
  font-family: var(--font-learning);
  font-size: var(--fs-16);
  line-height: var(--lh-loose);
}

/* --lh-loose above, not the body 1.55. These are lines somebody has to find
 * their place in while looking up at a room full of children; the extra
 * leading is what makes a line easy to come back to. */
.prose blockquote.script p { margin: 0 0 var(--sp-3); }
.prose blockquote.script p:last-child { margin-bottom: 0; }

/* Fugitt's Will exercise numbers its steps inside the quotation. Keep the
 * list tight to the script's left rule rather than letting it take the
 * prose list's full indent, so the numbers read as part of the script. */
.prose blockquote.script ol,
.prose blockquote.script ul { margin: var(--sp-3) 0; padding-left: 1.5em; }
.prose blockquote.script li { margin: 0 0 var(--sp-2); }
.prose blockquote.script li:last-child { margin-bottom: 0; }

/* A stage direction inside a script — Fugitt's "[Pause]", or a note about
 * what the teacher does rather than says. Mono at label size, the same
 * register .caption uses, so it is visibly NOT part of the spoken line. */
.prose blockquote.script .stage {
  font-family: var(--font-mono);
  font-size: var(--fs-14);
  letter-spacing: 0.02em;
  opacity: 0.75;
}

@media (max-width: 34rem) {
  .prose blockquote.script { padding-left: var(--sp-4); }
}

/* ── Open positions ─────────────────────────────────────────────────────────
 * The vacancy cards under the team on /team.
 *
 * Same auto-fit grid as the team roster above, but with a wider minimum track
 * (280px vs 240px): these cards hold a job title and a sentence rather than a
 * portrait, so a narrow column would set a two-word title on three lines.
 *
 * The cards are text-only and left-aligned, where the team cards are centred
 * around a portrait. That difference is the point — a vacancy should not be
 * mistakeable for a colleague at a glance. */
.open-position-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--sp-6);
}

.open-position {
  background: var(--paper);
  padding: var(--sp-6);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-paper);
  text-align: left;
  /* A column with the "read the description" line pinned to the bottom, so
   * cards of unequal teaser length still line their calls to action up. */
  display: flex;
  flex-direction: column;
}

/* --fs-22 to match the team member names on the same page. This originally
 * said --fs-20 because --fs-22 was referenced site-wide but never defined; it
 * is defined in tokens.css now, so the two headings on /team are the same size
 * again, which is the point. */
.open-position__title {
  font-family: var(--font-display);
  font-size: var(--fs-22);
  line-height: 1.2;
  margin: 0;
}

/* Inherit the ink colour rather than the link blue: the whole card is
 * clickable-looking already, and a blue heading over a blue "read the
 * description" line below it is two shouts where one will do. Underline on
 * hover keeps it discoverable as a link. */
.open-position__title a {
  color: inherit;
  text-decoration: none;
}

.open-position__title a:hover,
.open-position__title a:focus-visible {
  text-decoration: underline;
}

/* Matches the uppercase mono role label on the team cards. */
.open-position__details {
  font-family: var(--font-mono);
  font-size: var(--fs-12);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-top: 0.35rem;
}

.open-position__teaser {
  font-size: var(--fs-16);
  line-height: 1.55;
  margin: var(--sp-3) 0 0;
}

/* margin-top:auto is what pins this to the bottom; see the flex column above.
 * The padding keeps it clear of the teaser on a card that is short enough
 * that there is no free space for the auto margin to absorb. */
.open-position__more {
  margin: auto 0 0;
  padding-top: var(--sp-4);
}
