/* site-nav.css — the "More ▾" menu, and nothing else.

   ONE definition for TWO audiences. The pages rendered from the design drop
   (`render-site-pages.py`) lay their nav out with the design's own inline
   styles and load `site-pages.css`; the hand-authored kit pages lay theirs out
   with `site.css`'s `.nav` classes. Both carry the same menu, so the menu lives
   in a sheet both of them link rather than in a copy in each — a nav that
   drifts between halves of one site is worse than a nav that is plain.

   ⛔ CSS-ONLY, on :hover AND :focus-within, deliberately. The delivered
   homepage drove this menu from component state with `onMouseEnter` and a
   `display:` binding; the delivered SUB-pages drove the identical menu from
   CSS. The CSS half is the one that ships: the apex serves `script-src 'self'`
   and refuses inline handlers outright (check.sh guard 11), and — the reason
   that matters rather than merely constrains — a menu that opens only once a
   script has run is a menu a keyboard user can lose entirely. `:focus-within`
   is what makes tabbing into it work; do not replace it with `:hover` alone.

   Loaded AFTER site.css on the kit pages, so `.navmore-menu a` wins the tie
   with `.nav__links a` (equal specificity — order decides). If you reorder the
   links in a page's <head>, the menu's colours go with them. */

.navmore { position: relative; display: flex; align-items: center; }

.navmore > button {
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 13.5px;
  color: var(--hearth-text-secondary);
  display: flex;
  align-items: center;
  gap: 5px;
}
.navmore > button:hover { color: var(--hearth-text); }
.navmore > button > span { font-size: 9px; position: relative; top: 1px; }

.navmore-menu { display: none; position: absolute; top: 100%; right: 0; padding-top: 14px; z-index: 30; }
.navmore:hover .navmore-menu,
.navmore:focus-within .navmore-menu,
.navmore[data-open="true"] .navmore-menu { display: block; }
.navmore[data-closed="true"] .navmore-menu { display: none; }

.navmore-menu > span {
  display: flex;
  flex-direction: column;
  min-width: 214px;
  background: var(--hearth-surface);
  border: 1px solid var(--hearth-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 8px;
}
.navmore-menu a {
  display: block;
  color: var(--hearth-text-secondary);
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.navmore-menu a:hover { background: var(--hearth-sunken); color: var(--hearth-text); }
/* A menu item for the page you are already on. Both halves of the site mark the
   TOP-LEVEL current item, and four of the generated pages already marked their
   item inside this menu; `resources` and `security` are the hand-authored two
   that reach the site only through here, and they said nothing at all. Weight,
   not colour alone — the rule the design system states for every signal. */
.navmore-menu a[aria-current="page"] { color: var(--hearth-text); font-weight: 600; }

/* ---------------------------------------------------------------------------
   The masthead and footer geometry — ONE definition, both halves of the site.

   The menu above was unified here in 2026-08; the CHROME AROUND IT was not, and
   the drop drew it per page. Measured across the 33 served pages that draw a
   masthead (of 34 files — `platform.html` is a redirect stub) before this block
   existed: four nav container widths (1080 · 1140 · 1180 · 1240), three
   vertical paddings (20 · 22 · 24), `position:sticky` on the homepage and on
   the fifteen hand-authored pages but on none of the other seventeen, and a
   footer pinned at 1180 on fifteen pages whose own nav was not 1180. The
   visible result is the defect this block removes: the wordmark slides
   sideways, the nav changes height and stops sticking as you move through the
   site, and on most pages the wordmark at the top of a page does not sit above
   the wordmark at the bottom of it.

   1140/40 is the grid the SUB-PAGE CONTENT already uses (`max-width:1140px`
   with 40px gutters, so a 1060px measure). The nav is sized to it rather than
   the other way round, because content width is a design decision per page
   family and chrome alignment is not: picking the content's own number is what
   makes the logo land on the same vertical as the first heading under it.
   `site.css`'s `.nav__in`/`.wrap` are set to the same two numbers for the
   hand-authored half — change these four together or the halves drift again.

   `.sitehead` is the generated half's class; `.nav` is the hand-authored one.
   They are listed together on every rule so neither can be corrected alone. */

/* The masthead's own height, named once because three other things are measured
   from it: `scroll-padding-top` below, the in-page sticky rails the generated
   pages draw (`render-site-pages.py`'s `clear_masthead` rewrites their `top` to
   `calc(var(--sitehead-h) + …)`), and `.platform-claim` on the hand-authored
   half. 22px padding twice, plus a 172px wordmark, plus the 1px border — rounded
   up to an even px so a fractional layout never leaves a hairline of content
   showing above it.

   ⭐ RE-DERIVED 2026-09-09, AND THE REASON IS THE WHOLE POINT OF THIS COMMENT.
   This number is not a taste decision, it is arithmetic on the LOCKUP'S ASPECT
   RATIO, so it moves when the lockup does. The brand flag day swapped
   `legacy-signature-compact.svg` (viewBox 819.62x150) for
   `eventlake-signature-compact.svg` (683.91x143.25). Same mark, same 172px width,
   different ratio — so the rendered wordmark went 31.478px -> 36.027px tall and
   the bar went 76.478 -> 81.027, i.e. 78px -> 82px.

   ⚠ 143.25, not the 140 this comment said for one afternoon. The lockup was
   REALIGNED at source the same day (the mark's centre now sits 24.25 units above
   the wordmark's baseline, the identity sheet's placement, instead of on the
   wordmark block's centre — `conduit/cmd/eventlake-mark/signature.go`, wmRise). That
   made the box 3.25 units taller. The bar rounds to 82px either way, which is
   exactly why the arithmetic is written out: the answer did not move, so nothing
   would have told you the inputs had.

   ⛔ A NAME-ONLY SWAP OF THAT FILE IS A SILENT LAYOUT BUG. Nothing measures the
   image at runtime; the bar is `padding + content`, so the img would simply have
   made the header 4px taller than the constant claims, and every anchor jump,
   every in-page sticky rail and `.platform-claim` would have come to rest 4px
   under the bar they were supposed to clear. It looks like a rounding artefact
   and reads as "the anchors are slightly off" — which is why the arithmetic is
   written out here rather than left to be re-derived by whoever notices.


   ⭐ RAISED AGAIN 2026-11-01g, ON THE SAME ARITHMETIC — owner ask: the masthead
   lockup and wordmark are to be BIGGER on every page, as the footer's already is.
   Two things were wrong, and only the second one was visible. (a) The lockup is
   260px wide now, not 220. (b) `.nav__brand img` / `.sitehead__in > a > img`
   carried `max-height: 36px`, which is BELOW the height a 220px lockup wants
   (46.08px) — and because an `<img>` preserves the SVG's aspect ratio inside the
   box it is given, the masthead rendered a 172x36 lockup letterboxed inside a
   220px slot on BOTH page families, while `.foot__brand` matches no clamp at all
   and so rendered its 224px lockup at full height. That asymmetry is the whole of
   the "bottom bigger than top" report. The clamp is now 56px, above the 54.46px a
   260px lockup wants, so it bounds a broken asset without shrinking a good one.
   260 * (143.25 / 683.91) = 54.46 -> 44 + 54.46 + 1 = 99.46 -> 100px.
   The phone rule (<=440px) stays deliberately smaller, 200px/44px: the 320px
   reflow (2026-10-05e) has to keep the Menu glyph beside the lockup.

   If the lockup changes again: height = <lockup width> * (viewBox_h / viewBox_w),
   then 44 + that + 1, rounded up to an even px. */
:root {
  --sitehead-h: 100px;
  --site-max: 1200px;
}

@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: var(--duration-instant) var(--ease-standard, ease) both fade-out;
}
::view-transition-new(root) {
  animation: var(--duration-base) var(--ease-standard, ease) both fade-in;
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Hearth double-hairline card treatment for rich visual elevation */
.card-double-hairline {
  border: 1px solid var(--hearth-border);
  box-shadow: 0 0 0 1px var(--hearth-border-subtle), var(--shadow-sm);
  background: var(--hearth-surface);
  border-radius: 8px;
}

/* Hearth P2A button geometry alignment */
.hearth .btn,
.btn {
  border-radius: 8px;
}

/* An anchor jump lands under a sticky bar unless the scroll port is padded for
   it. `site.css` has carried this for the hand-authored half since the bar first
   stuck there; the generated half had no media query and no scroll padding of
   any kind, and did not need either while its masthead still scrolled away. It
   sticks now, so the rule moves here where both halves read it. The extra 18px
   is clearance, not decoration: it is what stops a heading from landing flush
   against the underside of the bar. */
html { scroll-padding-top: calc(var(--sitehead-h) + 18px); }

.sitehead,
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--hearth-canvas) 85%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hearth-border-subtle);
}

/* One rule per part, both class names on it. `.sitehead__*` is the generated
   half, `.nav__*` the hand-authored one; listing them together is what makes a
   correction impossible to apply to only one, which is how they came apart.
   `site.css` keeps only `.nav__brand`, which has no counterpart here. */
.sitehead__in,
.nav__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  max-width: 1140px;
  margin: 0 auto;
  padding: 22px 40px;
}

.sitehead__links,
.nav__links {
  display: flex;
  gap: 26px;
  align-items: center;
  margin-left: auto;      /* both groups travel as one right-hand cluster */
  font-size: var(--text-sm);
  color: var(--hearth-text-secondary);
}
.sitehead__links > a,
.nav__links a { color: var(--hearth-text-secondary); font-weight: 500; transition: color var(--duration-fast); }
.sitehead__links > a:hover,
.nav__links a:hover { color: var(--hearth-text); }
.sitehead__links > a[aria-current="page"],
.nav__links a[aria-current="page"] { color: var(--hearth-text); font-weight: 650; }

.sitehead__cta,
.nav__cta { display: flex; gap: 10px; align-items: center; margin-left: 16px; }

/* The footer, on the same measure as the nav above it. */
.sitefoot { border-top: 1px solid var(--hearth-border); background: var(--hearth-sunken); }
.sitefoot--rule { background: none; border-top: 0; }
.sitefoot__in {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  flex-wrap: wrap;
  max-width: 1140px;
  margin: 0 auto;
  padding: 40px;
}
.sitefoot--rule .sitefoot__in { border-top: 1px solid var(--hearth-border); padding: 20px 40px 44px; }

/* ⚠ `flex-wrap` is deliberately NOT set on the link row. The drop shipped
   `flex-wrap:wrap` there with no media query anywhere in `site-pages.css`, so
   on a phone the six items wrapped onto two and three rows and the nav's
   height changed with the viewport — the same displacement as above, just
   driven by width instead of by page. Below 900px the links collapse and the
   wordmark keeps the CTA company, which is what the hand-authored half has
   always done (`site.css`'s `.nav__links{display:none}`); both halves are
   stated here so they cannot diverge again.
   The former KNOWN GAP (a phone with only a wrapped row of links) is closed by
   the phone menu below 620px (site-console.js + the `[data-drawer]` rules,
   2026-10-26ag); without script the wrapped row is still what a phone gets. */
.sitehead__in > a,
.nav__brand { flex: 0 1 auto; min-width: 0; }
.sitehead__in > a > img,
.nav__brand > img,
.nav__brand img { max-width: 100%; height: auto; max-height: 56px; }

@media (max-width: 960px) {
  .sitehead__in,
  .nav__in {
    flex-wrap: wrap;
    row-gap: 10px;
  }
  .sitehead__in > a,
  .nav__brand {
    flex: 1 1 0;
    max-width: 260px;
    min-width: 0;
  }
  .sitehead__cta,
  .nav__cta {
    flex: 0 0 auto;
    margin-left: auto;
  }
  .sitehead__links,
  .nav__links {
    order: 3;
    flex: 1 0 100%;
    margin-left: 0;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 8px 18px;
    padding-top: 8px;
    border-top: 1px solid var(--hearth-border-subtle);
    position: relative;
  }
}

@media (max-width: 620px) {
  .sitehead__in,
  .nav__in { padding: 12px 18px; gap: 10px; }
  .sitehead__cta,
  .nav__cta { gap: 8px; }
  .sitehead__cta .btn-sm,
  .nav__cta .btn-sm { padding: 8px 13px; }
  .sitehead__links,
  .nav__links { gap: 6px 14px; font-size: var(--text-xs); }
  .navmore { position: static; }
  .navmore-menu { left: 0; right: 0; padding-top: 8px; }
  .navmore-menu > span { min-width: 0; width: 100%; box-sizing: border-box; }
  .sitefoot__in { padding: 28px 18px; }
  .sitefoot--rule .sitefoot__in { padding: 18px 18px 32px; }
}
/* The phone menu (site-console.js). Only a row the script has equipped (`data-drawer`) hides its
   links, so the no-script page keeps the wrapped row above. Inside the open sheet the links stack one
   per line at a 44px touch height and the "More" items are listed in place rather than behind a
   second disclosure. */
.navtoggle { display: none; }
@media (max-width: 620px) {
  [data-drawer] > .navtoggle {
    display: inline-flex; align-items: center; gap: 6px; order: 2;
    min-height: 44px; min-width: 44px; padding: 0 12px; margin-left: 0;
    font: inherit; font-size: var(--text-sm); font-weight: 600;
    color: var(--hearth-text); background: var(--hearth-surface);
    border: 1px solid var(--hearth-border); border-radius: 999px; cursor: pointer;
  }
  [data-drawer] > .navtoggle::after { content: "\2261"; font-size: 1.1em; line-height: 1; }
  [data-drawer="open"] > .navtoggle::after { content: "\00D7"; }
  [data-drawer] > .navtoggle:focus-visible { outline: none; box-shadow: var(--focus-ring); }
  [data-drawer="closed"] > .nav__links,
  [data-drawer="closed"] > .sitehead__links { display: none; }
  [data-drawer="open"] > .nav__links,
  [data-drawer="open"] > .sitehead__links {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    font-size: var(--text-sm);
  }
  [data-drawer="open"] > .nav__links a,
  [data-drawer="open"] > .sitehead__links a {
    display: flex; align-items: center; min-height: 44px;
    border-bottom: 1px solid var(--hearth-border-subtle);
  }
  [data-drawer="open"] .navmore { display: block; }
  [data-drawer="open"] .navmore > button { display: none; }
  [data-drawer="open"] .navmore-menu,
  [data-drawer="open"] .navmore[data-closed="true"] .navmore-menu { display: block; position: static; padding-top: 0; }
  [data-drawer="open"] .navmore-menu > span {
    display: flex; flex-direction: column; padding: 0; border: 0; box-shadow: none; background: none;
  }
  [data-drawer="open"] .navmore-menu a { padding: 0; }
}

/* Small phones (320-440: iPhone SE, Android compact). */
@media (max-width: 440px) {
  .sitehead__cta,
  .nav__cta { display: none; }
  .sitehead__in > a,
  .nav__brand { flex: 0 0 auto; min-width: 200px; }
  .sitehead__in > a > img,
  .nav__brand > img,
  /* ⛔ `width:` IS DEAD HERE and that is the trap this rule was carrying. The lockup's
     width is an INLINE style on the <img> (260px, written by the page and by
     render-site-pages.py), so a stylesheet `width` never wins — only `max-width` /
     `max-height` can size it down. A box wider than the artwork does not crop, it
     LETTERBOXES: the SVG preserves its ratio and centres, which is exactly how the
     masthead came to paint a 172x36 lockup inside a 220px slot. Measured at 320px and
     390px before this was corrected: the box reported 260x44 with 210px of artwork in
     it. So the phone size is stated as a max-width, and the max-height below it is only
     a backstop (200px wants 41.9px, so it never binds). */
  .nav__brand img { max-width: 200px; min-width: 0; height: auto; max-height: 44px; }
}
@media (max-width: 400px) {
  /* The Menu button keeps its accessible name and drops to its glyph, so the wordmark keeps its room. */
  [data-drawer] > .navtoggle { padding: 0; justify-content: center; font-size: 0; }
  [data-drawer] > .navtoggle::after { font-size: 20px; }
  .sitehead__cta .btn-sm,
  .nav__cta .btn-sm { padding: 8px 11px; font-size: var(--text-xs); }
}

/* ---------------------------------------------------------------------------
   The skip link — moved here from `site.css` so the generated half stops
   carrying its own inline copy. See that file for what was wrong with two. */
/* ⛔⛔ `.hearth .skip-link`, NOT `.skip-link` — at (0,1,0) this rule LOSES its colour to
   `colors_and_type.css:199`'s `.hearth a { color: var(--accent-text) }` (0,1,1), and the skip link
   is an <a>. Measured on the public site (2026-09-13w-v): `--accent-text` is #191713 under the P2A
   pairing and `--accent-solid-bg` is ALSO #191713, so the focused skip link rendered at **1.00:1 —
   invisible**, on every page. ⛔ It is the worst possible element to lose this way: it is the
   keyboard user's only way past a nav that repeats on all 32 pages, it is invisible until focused
   BY DESIGN, so nothing about the sighted mouse-driven page ever looked wrong. The intended pair
   (`--hearth-text-on-accent` #FFFFFF on #191713) measures 16.87:1.
   ⭐ Same trap and same fix as `.hearth .store` in site.css — see the long note there. */
.hearth .skip-link {
  position: absolute;
  inset-inline-start: var(--space-4);
  inset-block-start: var(--space-4);
  z-index: 100;
  padding: var(--space-3) var(--space-5);
  background: var(--accent-solid-bg);
  color: var(--hearth-text-on-accent);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-lg);
  /* Visually hidden, still focusable and still announced. */
  clip-path: inset(50%);
  white-space: nowrap;
}
.hearth .skip-link:focus-visible,
.hearth .skip-link:focus {
  clip-path: none;
  outline: none;
  box-shadow: var(--shadow-lg), var(--focus-ring);
}
/* The target takes programmatic focus, so suppress the ring it would otherwise draw around the
   whole page region — the skip itself is the feedback, and a viewport-wide outline reads as a bug. */
main[tabindex="-1"]:focus { outline: none; }

/* ---- Cross-document view transitions (2026-08-23) ---------------------------------------
   955d804d made this a pure MPA: six nav items, every one a real page navigation, no in-page
   anchors left. A full document load between pages that share an identical masthead and footer
   is the exact case this feature exists for — the shared chrome persists visually across the
   swap instead of blinking, so the four destinations feel as deliberate as the old scroll did.

   Progressive enhancement in the strictest sense: a browser without support performs its normal
   instant navigation, so there is nothing to fall back to and nothing to break. Both the source
   AND the destination must opt in, which is why this lives in site-nav.css — the one stylesheet
   BOTH halves of the site link — rather than per page or in site.css, which only the
   fifteen hand-authored pages load.

   Gated on no-preference, never `reduce`: this is decorative motion across a whole document, and
   the repo's never-blank rule applies with extra force here, because a transition that stalls
   would hold the OLD page's pixels over the new one. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }

  /* Pull the masthead OUT of the root snapshot (2026-08-23).
     `navigation: auto` alone does NOT buy the persistence this feature is famous for.
     Un-named, the entire document is one `::view-transition-group(root)` that cross-
     fades — so an identical nav dissolves into an identical nav, and the reader watches
     the bar dim for no reason on every single navigation. Given a name it becomes its
     own group whose old and new boxes are the same rectangle, so it simply HOLDS while
     the content beneath it swaps. That is the whole effect.

     `.nav`/`.sitehead` is MEASURED to occur exactly once on each of the 33 pages
     that draw a masthead — the 34th file, `platform.html`, is a redirect stub with
     none, which is not a duplicate and so cannot abort anything. That count is a
     precondition rather than a nicety: a duplicated `view-transition-name` anywhere in
     one document aborts the WHOLE transition, and it fails SILENTLY — the navigation
     merely looks un-transitioned, so nothing tells you the feature stopped working. A
     new page must keep it to one, and a new name must not be reused. */
  /* BOTH masthead classes. `.sitehead` is the generated half's; a page carries one
     or the other and never both, so the name still occurs exactly once per
     document — which the note above explains is a precondition, not a nicety. */
  .nav,
  .sitehead { view-transition-name: site-nav; }

  /* The root group is now everything EXCEPT the nav, so it can carry a direction
     instead of a plain dissolve. Deliberately small and quick: this fires on every
     navigation, and motion a reader notices twice is motion they resent by the fifth.

     NEVER-BLANK — and the two halves have to be read together to see why this is safe.
     At frame 0 the backwards fill leaves the OUTGOING snapshot at full opacity while
     the incoming one is still at 0, and the incoming is painted above it. So a stalled
     transition shows the OLD page: exactly the failure the block above already weighed
     and accepted, not a blank viewport. The rule to keep when editing these: the old
     snapshot must never be zeroed faster than the new one arrives, or a stall becomes
     the blank screen this repo keeps re-learning about. */
  ::view-transition-old(root) { animation: vt-fade calc(var(--duration-base) * .9) linear both; }
  ::view-transition-new(root) { animation: vt-rise calc(var(--duration-base) * 1.2) var(--ease-standard) both; }
}
@keyframes vt-fade { to   { opacity: 0; } }
@keyframes vt-rise { from { opacity: 0; transform: translateY(10px); } }

/* ---------------------------------------------------------------------------
   THE ONE FOOTER — moved here from site.css on 2026-09-12ae, when the footer
   stopped being two designs and became one.

   ⛔⛔ IT LIVES IN THIS FILE AND NOT IN site.css BECAUSE OF WHO LOADS WHAT. The
   public site is two page families: 14 hand-authored pages load site.css, and 18
   pages rendered from the design drop (plus index.html) load site-pages.css. Only
   site-nav.css is loaded by BOTH. Before this move the full six-column footer was
   styled from site.css, so it could only ever appear on 14 of 34 pages — which is
   exactly what the site shipped: 14 pages with the whole IA in the footer, 16 with
   a logo and one sentence, no copyright, no contact and no links at all, and one
   page (research-coverage-gates.html) with no footer whatever. Putting the markup
   everywhere without moving these rules would have produced the worse failure: the
   links present in the DOM and unstyled on half the site.

   `.wrap` came along for the ride: the footer's markup is wrapped in it and
   site-pages.css does not define it.
   --------------------------------------------------------------------------- */
.wrap { max-width: 1140px; margin: 0 auto; padding: 0 40px; }

/* the footer proper */
footer { border-top: 1px solid var(--hearth-border); padding: 48px 0 36px; margin-top: 40px; }
.foot { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 30px 24px; }
/* The brand sits on its own row above the columns. It used to be the first
   track of a fixed 2fr-1fr-1fr-1fr grid, which fixed the footer at three link
   columns — and the 2026-09-02d IA has six. `auto-fill` lets the column count
   follow the content instead of the content following the grid. */
.foot__brand { grid-column: 1 / -1; }
.foot__brand .wm { font-size: var(--text-md); } .foot__brand p { font-size: var(--text-sm); color: var(--hearth-text-muted); margin-top: 10px; max-width: 68ch; line-height: 1.55; }
.foot__col h5 { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .08em; color: var(--hearth-text-muted); margin-bottom: 12px; }
.foot__col a { display: block; font-size: var(--text-sm); color: var(--hearth-text-secondary); padding: 4px 0; }
.foot__col a:hover { color: var(--hearth-text); }
.foot__base a { color: var(--hearth-text-muted); text-decoration: underline; text-underline-offset: 2px; }
.foot__base a:hover { color: var(--hearth-text); }
/* `flex-wrap` is ON THE BASE RULE, not in a phone tier (2026-10-04z): the 09-12ae move
   left `.foot__base { flex-wrap: wrap }` behind in site.css's 560px tier, which only the
   hand-authored half loads, so on every generated page the row could not wrap and a
   390px phone crushed "Legal · DPDP" into a 32px column, three lines tall. Wrap only
   engages when the row overflows, so at any width where it fits this changes nothing. */
.foot__base { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 36px; padding-top: 20px; border-top: 1px solid var(--hearth-border-subtle); font-size: var(--text-xs); color: var(--hearth-text-muted); }

/* ---------------------------------------------------------------------------
   THE SCOPE STRIP — one component for "what this page does not promise"
   (public-site audit 2026-10-20 §9.2 / §4.1 cluster 5, built 2026-10-22).

   Fifteen pages used to END on a grid of four to six dashed cards of limits, so a
   reader moving through three pages met the same downbeat wall three times. The
   limits stay — they are the site's credibility — but they now read as one strip:
   every TITLE is always visible (nothing is hidden behind a click), each body opens
   in place, and the strip hands the reader on to the whole ledger and the next step.

   ⛔ The bodies are real text inside <details>, so the limits ledger's build-time
   drift check (render-site-pages.py limits_drift) still finds every sentence on the
   page that publishes it. site-console.js opens every strip before printing, so a
   printed page carries the limits in full. Lives here because both page families
   load this sheet.
   --------------------------------------------------------------------------- */
.scope { max-width: 1140px; margin: 0 auto; padding: 28px 40px 8px; }
.scope__in { border: 1px solid var(--hearth-border); border-radius: var(--radius-lg); background: var(--hearth-surface); padding: 22px 24px 18px; }
.scope__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 20px; }
.scope__k { font-family: var(--font-label, var(--font-mono)); font-size: var(--text-xs); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--hearth-text-muted); }
.scope__head h2 { font-family: var(--font-display); font-weight: 500; font-size: var(--text-xl); line-height: 1.2; margin: 6px 0 0; color: var(--hearth-text); }
.scope__all { font-size: var(--text-sm); font-weight: 600; white-space: nowrap; }
.scope__list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 8px 14px; }
.scope__list details { border-top: 1px solid var(--hearth-border-subtle); padding: 10px 0 2px; }
.scope__list summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 8px; align-items: baseline; font-size: var(--text-sm); font-weight: 600; color: var(--hearth-text); }
.scope__list summary::-webkit-details-marker { display: none; }
.scope__list summary::before { content: "+"; font-family: var(--font-mono); font-weight: 500; color: var(--hearth-text-muted); transition: transform var(--duration-fast); }
.scope__list details[open] summary::before { content: "−"; }
.scope__list summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.scope__list details p { margin: 6px 0 4px 26px; font-size: var(--text-sm); line-height: 1.6; color: var(--hearth-text-secondary); text-wrap: pretty; }
/* the forward step every page now ends on, instead of the wall */
.nextstep { max-width: 1140px; margin: 0 auto; padding: 18px 40px 72px; }
.nextstep__in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px 28px; padding: 24px 26px; border-radius: var(--radius-lg); background: var(--hearth-sunken); }
.nextstep__in p { margin: 0; font-family: var(--font-display); font-size: var(--text-xl); line-height: 1.25; color: var(--hearth-text); max-width: 34ch; }
.nextstep__in .nextstep__go { display: flex; flex-wrap: wrap; gap: 10px; }

/* Paired-page view switcher bar (audit §4.2: capabilities ↔ capability-atlas, anatomy ↔ event-story) */
.viewswitch { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 4px; border: 1px solid var(--hearth-border-strong); border-radius: 999px; background: var(--hearth-surface); margin-top: 16px; }
.viewswitch__lbl { font-family: var(--font-mono, monospace); font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--hearth-text-muted); padding: 0 10px 0 12px; }
.viewswitch a { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: 999px; font-size: 12.5px; font-weight: 600; text-decoration: none; color: var(--hearth-text-secondary); transition: background var(--duration-fast), color var(--duration-fast); }
.viewswitch a:hover { color: var(--hearth-text); background: var(--hearth-sunken); }
.viewswitch a[aria-current="page"] { background: var(--hearth-text); color: var(--hearth-canvas); }

@media (max-width: 620px) { .scope, .nextstep { padding-left: 18px; padding-right: 18px; } }
@media print { .scope__list summary::before { content: none; } }
