/* site-pairing-p2a.css */
/* ============================================================================
   HEARTH pairing P2A — "Warm paper, cool signals" · editorial · quiet
   APPLIED TO THE PUBLIC SITE
   ----------------------------------------------------------------------------
   Owner call 2026-08-30bi (tracker §13 row 85 · study record §6a-xxvii). Source of
   every value below:
     ui_kits/Brand-And-Surfaces-Handoff/pairings/tokens/P2A-warm-paper-cool-signals.css
   Values are TRANSCRIBED from that sheet, not re-derived. Do not "improve" one here —
   change the study sheet and re-transcribe, or the two silently diverge.

   ✅ THE TYPE HALF IS NOW APPLIED (2026-08-30bq, §13 row 88 leg ① — owner: "go ahead and
   vendor the fonts"). **Newsreader** and **Hanken Grotesk** are vendored as SIL OFL 1.1
   latin-subset variable woff2 in `fonts/`, declared in the root `fonts.css`, so this sheet
   sets `--font-display` and `--font-sans` from the study spec. ⛔ The Google-Fonts `@import`
   in the study sheet is STILL not copied and never will be — the repo bans a remote font
   outright (check.sh guard 1); vendoring is what made the token settable.
   ⚠ `--font-mono` is deliberately NOT set: P2A names JetBrains Mono, which IS the canon's
   mono already, and the canon's fallback stack is richer than the study sheet's. Setting it
   would narrow the stack for no gain.
   ⚠ `--font-display-weight: 400` from the study sheet is also NOT set — measured, that token
   has ZERO consumers anywhere in the tree, so it would be a declaration nothing reads.

   ⛔ THE 9 `--signal-*` TOKENS ARE DELIBERATELY OMITTED. Measured 2026-08-30bi: ZERO
   consumers across ui_kits/public-site, and the canon does not define them. The site
   already carries that layer as `--sev-*` / `--status-*` — 48 consumer references here —
   which P2A correctly leaves alone ("severity and status keep their own hues in every
   direction"). Their values live in the study sheet if that layer is ever wired.
   ⚠ NOTE THE ONE REAL LOSS: P2A's stated character is that cool signals "free clay to
   mean failure", and its `--signal-failure: #A94E2E` IS clay. That re-assignment lands
   only when the signal layer is wired; today failure still reads from `--sev-*`.

   ⚠ GROUND CHANGE, CHECKED: canon canvas #F6F1E7 → #FAF8F4 (a cooler, lighter paper).
   All eight severity/status inks re-measured against the new grounds and all pass —
   5.01 → 7.41 on canvas, 5.31 → 7.41 on surface, none below AA 4.5:1. The site's own
   text inks as APPLIED: 16.87 (text) / 6.97 (secondary) on canvas, and the canon's muted
   #6D6355 at 5.55 — see the muted note in the block below, the one token that deviates.
   Guarded from here on — this file is in `hearth-contrast-audit.py`'s APPLIED_PAIRINGS
   set, which re-checks every canon severity ink against the grounds this sheet moved, so
   a future edit that breaks a pair fails check.sh instead of shipping.

   ⚠ DARK THEME IS NOT ADDRESSED AND DOES NOT NEED TO BE. All 17 public-site pages are
   hard-coded `<html data-theme="light">` (site.js:54 says so explicitly), so the canon's
   `:root[data-theme="dark"]` block and its `prefers-color-scheme` twin (guarded
   `:root:not([data-theme="light"])`) never match. If the site ever gains a dark mode,
   `:root[data-theme="dark"]` outranks this file's plain `:root` and it falls back to the
   canon dark — deliberately. P2A's own dark counterpart is **P2C · Ink base, signals
   only**, in the same study directory.

   ⚠ NOT LINKED FROM `motion-lab.html` — that page deliberately links no external
   stylesheet and is self-contained by design. 16 of the 17 pages carry this.

   LOAD ORDER MATTERS: must come AFTER colors_and_type.css, which redefines 14 of these
   token names. The pages link it after hearth-components.css; site.css / site-v2.css /
   site-motion.css define no tokens of their own (measured: 0), so nothing downstream
   re-overrides these.
   ============================================================================ */

:root {
  /* ---- ground + ink: warm paper ---------------------------------------- */
  --hearth-canvas:        #FAF8F4;
  --hearth-surface:       #FFFFFF;
  --hearth-raised:        #FFFFFF;
  --hearth-sunken:        #F1EEE8;

  --hearth-border:        #E7E3DB;
  --hearth-border-strong: color-mix(in srgb, #191713 14%, #FAF8F4);  /* = #DAD8D4 */
  --hearth-border-subtle: color-mix(in srgb, #191713  6%, #FAF8F4);  /* = #ECEAE6 */

  --hearth-text:           #191713;   /* 16.87:1 on canvas */
  --hearth-text-secondary: #5A554D;   /*  6.97:1 on canvas */
  /* ⛔ P2A's OWN muted ink #6E6A61 IS DELIBERATELY NOT APPLIED — the canon's #6D6355 stands.
     Measured 2026-08-30bi by `hearth-contrast-audit.py`'s APPLIED_PAIRINGS leg: #6E6A61 on the
     canon severity/status CHIP backgrounds bottoms out at 4.27:1, below AA 4.5 — this repo
     already holds a text ink to EVERY ground it can land on, and those chip fills are
     grounds. The canon ink clears all of them (worst 4.66) and reads 5.55:1 on this
     direction's #FAF8F4 canvas, so the deviation costs a barely-perceptible shift in one
     de-emphasised grey and buys back 4 failing pairs. ⚠ THIS IS THE ONE TOKEN OF THE 19
     THAT DEVIATES from the study sheet — every other value here is transcribed verbatim.
     Revisit it the day the severity chip fills are restated for this paper. */
  /* NON-TEXT ONLY — hairlines, dashed borders, dots. Never a text carrier
     (post-2026-08-28l canon; check.sh guard 26 enforces it). ≈ #928F88, the 3:1 non-text value (2026-10-05fp; 62% gave #A3A099 at 2.46:1) */
  --hearth-text-faint:     color-mix(in srgb, #6E6A61 74%, #FAF8F4);
  --hearth-text-on-accent: #FFFFFF;

  /* ---- accent: solid dual-accent hierarchy (2026-11-07g, CT-01) --------- */
  /* 2026-11-07r: the primary action is Royal Cobalt #1F5FAE (6.35:1 vs #FFFFFF), NOT terracotta —
     #A84420 sat one shade from the failure clay #A94E2E, so a primary button read as an error.
     Previously (07g): Hearth Terracotta (#A84420) carried primary conversion actions;
     Signal Cobalt (#1E4560) carries semantic text emphasis, eyebrows, and links
     (8.74:1 on #FAF8F4, 8.69:1 on #E4EFF7). */
  --accent:           #1F5FAE;
  --accent-hover:     #1D4F91;
  --accent-active:    #163E73;
  --accent-solid-bg:  #1F5FAE;
  --accent-subtle-bg: #E4EFF7;
  --accent-text:      #1E4560;
  --accent-border:    #B8D4E8;

  /* ---- type: the study spec, now that both faces are self-hosted ------- */
  /* Fallbacks are the study sheet's own. Georgia/system-ui are what render in the
     swap window, so they are the shape the page briefly wears, not dead text. */
  --font-display: 'Newsreader', Georgia, serif;
  --font-sans:    'Hanken Grotesk', system-ui, sans-serif;

  /* ---- Hearth Editorial Reserve & Solid Section Grounds (2026-11-07g) --- */
  --hearth-editorial-warm: #F6F3EC;
  --hearth-editorial-tint: #EAE5DC;
  --band-ivory:            #F5EFE4;
  --band-ivory-border:     #DFD5C3;
  --band-mineral:          #EFF4F8;
  --band-mineral-border:   #D5E2EC;
  --band-amber:            #F7F1E6;
  --band-amber-border:     #E5D7C0;
  --band-sage:             #EDF5F2;
  --band-sage-border:      #CCE0D9;
  --band-stone:            #ECE6DA;
  --band-stone-border:     #CFC7B8;
  /* 2026-11-07r: the obsidian band is retired (no dark island in a light page); the showcase
     ground is a saturated cobalt tint carrying dark ink (14.4:1). */
  --band-showcase:         #DCE8F3;
  --band-showcase-border:  #B8D4E8;

  /* ---- 4 Architectural Planes & 9 Product Line Solid Jewel Tones -------- */
  --plane-1-ink:  #1E4560; --plane-1-acc:  #2F6DB5; --plane-1-tint:  #E4EFF7; --plane-1-bdr:  #B8D4E8;
  --plane-2-ink:  #343888; --plane-2-acc:  #5B5FC7; --plane-2-tint:  #ECECFB; --plane-2-bdr:  #C5C7F0;
  --plane-3-ink:  #1B5744; --plane-3-acc:  #1E7E62; --plane-3-tint:  #E0F2EC; --plane-3-bdr:  #AEDAD0;
  --plane-4-ink:  #562D70; --plane-4-acc:  #8A4F9E; --plane-4-tint:  #F2EAF7; --plane-4-bdr:  #D7C0E6;
  --line-ver-ink: #255429; --line-ver-acc: #4E8A1F; --line-ver-tint: #E6F2E2; --line-ver-bdr: #BBDAB2;
  --line-pos-ink: #125366; --line-pos-acc: #0086A8; --line-pos-tint: #E0F2F7; --line-pos-bdr: #AEDCE8;
  --line-exp-ink: #734C00; --line-exp-acc: #A87400; --line-exp-tint: #FBF0D9; --line-exp-bdr: #E8CE9B;
  --line-ast-ink: #7D2440; --line-ast-acc: #C24F72; --line-ast-tint: #F9E8EE; --line-ast-bdr: #E6BCCE;
  --line-obs-ink: #6E3219; --line-obs-acc: #C4552F; --line-obs-tint: #F8E8E0; --line-obs-bdr: #E5C0AE;

  --signal-wash:           rgba(39, 80, 107, 0.08);
  --signal-rule:           #DCE7EE;
  --verdict-allow-ink:     #1F5C3A;
  --verdict-allow-tint:    #EBF4EE;
  --verdict-hold-ink:      #7C580A;
  --verdict-hold-tint:     #FBF3E0;
  --verdict-refuse-ink:    #8E3B1F;
  --verdict-refuse-tint:   #F9EBE6;

  color-scheme: light;
}

/* site-nav.css */
/* 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. */

/* THE 12px TYPE FLOOR (design audit 2026-11-10, WEB-13). Hearth's two smallest steps are 10px and
   11px, sized for a dense operator Console. On the public site a buyer reads them on a phone, so
   here, and only here, both resolve to the 12px step. This sheet is the one every site page links,
   which is why the override lives in it; the tokens themselves are shared and stay as they are.
   Literal sizes are floored where they are written (render-site-pages.py `type_floor`). */
:root { --text-micro: 0.75rem; --text-2xs: 0.75rem; }

/* THE H1 SCALE (design audit 2026-11-10, WEB-05). Thirteen H1 sizes became three, named for the job
   the page does. LANDING: the home page, Platform, the two event stories. READING: every page that
   is read top to bottom. TOOL: a page whose first screen is a form, a calculator or a list.
   Every H1 on the site takes one of these; render-site-pages.py `h1_scale` assigns the generated
   pages. Each is a clamp(), so a phone gets a phone size without a breakpoint. */
:root {
  --site-h1-landing: clamp(40px, 4.8vw, 64px);
  --site-h1-reading: clamp(34px, 4.4vw, 52px);
  --site-h1-tool:    clamp(28px, 3.6vw, 42px);
}

/* ONE LEFT EDGE (WEB-05). The site column is 1140px with a 40px gutter: 1060px of content, the
   same box the masthead sits in, so a page's H1 starts under the logo. The hand-written tool pages
   each centred a narrower column of their own (720 to 1180px), which put the H1 at nine different
   left edges at 1440. From the width where the site column stops growing, every one of them sits in
   the site column instead; the narrow ones keep their reading measure, left-aligned.
   `body` is in the selector only to outrank the page's own <style>, which loads after this sheet. */
@media (min-width: 1141px) {
  body .ac-wrap, body .rx-wrap, body .pf-wrap, body .ck-wrap, body .dn-wrap,
  body .gs-wrap, body .sr-wrap, body .nc-wrap, body .sz-wrap {
    max-width: 1140px; padding-left: 40px; padding-right: 40px;
  }
  body .ck-wrap > *, body .dn-wrap > * { max-width: 852px; }
  body .gs-wrap > * { max-width: 832px; }
  body .sr-wrap > * { max-width: 772px; }
  body .nc-wrap > * { max-width: 672px; }
}

.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: 12px; 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;
}

/* Cross-document view transitions (2026-11-06k): a short cross-fade between pages of this
   site, no script. The keyframes are namespaced (`el-vt-*`) because a bare `fade-in` is the
   name every stylesheet reaches for, and a later sheet's same-named @keyframes silently
   replaces this one. Reduced motion turns the transition off entirely — the never-blank
   rule: a pseudo-element that starts at opacity 0 must have a path that never animates. */
@view-transition {
  navigation: auto;
}
::view-transition-old(root) {
  animation: var(--duration-instant) var(--ease-standard, ease) both el-vt-out;
}
::view-transition-new(root) {
  animation: var(--duration-base) var(--ease-standard, ease) both el-vt-in;
}
@keyframes el-vt-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes el-vt-in  { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* One button geometry on every page (2026-11-06k): 8px, so the masthead CTA no longer morphs
   from a pill (home.css) into a rectangle (hearth-components.css) between pages. home.css
   carries the same 8px for its higher-specificity `.home .btn`. */
.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;
  /* 94% + saturate: at 85% a heading scrolling under the bar ghosted through it (2026-11-07w). */
  background: color-mix(in srgb, var(--hearth-canvas) 94%, transparent);
  backdrop-filter: saturate(1.4) 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(--accent-text); font-weight: 650; border-bottom: 2px solid var(--accent-text); padding-bottom: 2px; }

.sitehead__cta,
.nav__cta { display: flex; gap: 10px; align-items: center; margin-left: 16px; }
/* ONE size and one ink for the bar's two buttons on every page (2026-11-07w). The home page drew them
   from home.css (14px, ink "Sign in") and every other page from hearth-components' `.btn-sm` (12px,
   accent-blue "Sign in"), so the bar changed height and voice on the first click away from home.
   `:is()` carries (0,3,0), above both `.hearth .btn-sm` and `.hearth .btn-ghost`. */
:is(.nav, .sitehead) :is(.nav__cta, .sitehead__cta) .btn { padding: 9px 16px; font-size: 14px; font-weight: 600; line-height: 1.2; }
:is(.nav, .sitehead) :is(.nav__cta, .sitehead__cta) .btn-ghost { background: transparent; border-color: transparent; color: var(--hearth-text); }
:is(.nav, .sitehead) :is(.nav__cta, .sitehead__cta) .btn-ghost:hover { background: var(--hearth-sunken); }

/* The footer, on the same measure as the nav above it. */
.sitefoot { border-top: 2px solid #CFC7B8; background: #ECE6DA; }
.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; }
  [data-drawer="open"] > .nav__links,
  [data-drawer="open"] > .sitehead__links { font-size: 16px; }
}
/* The sheet's own Sign in + Start trial (site-console.js). Shown only where the bar's pair is hidden
   (≤440px, below), so a phone never shows the same two actions twice. */
.navdrawer-cta { display: none; }
@media (max-width: 440px) {
  [data-drawer="open"] .navdrawer-cta { display: flex; gap: 10px; padding: 6px 0 12px; border-bottom: 1px solid var(--hearth-border-subtle); }
  [data-drawer="open"] .navdrawer-cta > a {
    flex: 1 1 0; justify-content: center; min-height: 44px; border-radius: var(--radius-md, 10px);
    font-size: 15px; font-weight: 600; border: 1px solid var(--hearth-border-strong);
  }
  [data-drawer="open"] > .nav__links .navdrawer-cta > .navdrawer-cta__go,
  [data-drawer="open"] > .sitehead__links .navdrawer-cta > .navdrawer-cta__go {
    background: var(--accent-solid-bg); border-color: var(--accent-solid-bg); color: var(--fg-on-accent);
  }
  [data-drawer="open"] > .nav__links .navdrawer-cta > .navdrawer-cta__in,
  [data-drawer="open"] > .sitehead__links .navdrawer-cta > .navdrawer-cta__in { color: var(--hearth-text); }
}

/* 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 { background: #ECE6DA; border-top: 2px solid #CFC7B8; 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: 12px; 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; } }

/* WEB-09 (design audit 2026-11-10): a phone tap target under 24px is under the WCAG 2.2 AA
   line (2.5.8). On touch and narrow screens every link in the page body gets 4px of block
   padding. On an inline link that only grows the hit box, never the line; a link laid out as
   a block grows by the same 8px. Zero specificity (`:where`), so any link that already sets
   its own padding keeps it. The masthead and the footer are styled where they live. */
@media (pointer: coarse), (max-width: 760px) {
  :where(main, aside, article, section, .gs-strip) :where(a[href]:not(.btn, nav a, footer a, .sitehead a)) { padding-block: 4px; }
}

/* WEB-09, the footer half (design audit 2026-11-10, batch 9): the base row's "Contact" and
   "Legal · DPDP" were 18px tall on a phone — two targets under the 24px line on every page.
   On touch and narrow screens every footer link is at least 24px tall; the base-row links
   centre their text in that box, so the row only grows by the difference. The column links
   already clear it with their 4px padding; the floor holds them there too. Desktop with a
   fine pointer is untouched. */
@media (pointer: coarse), (max-width: 760px) {
  footer a[href] { min-height: 24px; }
  .foot__base a { display: inline-flex; align-items: center; }
}

/* home.css */
/* home.css — the apex home page (index.html), 2026-10-08.
   The platform page moved to platform.html; this page is the buyer's front door.
   Palette is P2A "Warm paper, cool signals" (site-pairing-p2a.css), light only. */
/* Layout: an editorial buyer's page on warm paper. Thesis headline, then one large
   interactive stage (eleven tools collapsing onto one record), then four proofs,
   the one-meter price, measured coverage, the trial path. Light only, by owner call. */
:root{
  /* P2A "Warm paper, cool signals" + Solid Architectural Grounds (2026-11-07g, CT-02) */
  --canvas:#FAF8F4; --surface:#FFFFFF; --sunken:#F1EEE8;
  --border:#E7E3DB; --border-strong:#DAD8D4;
  --ink:#191713; --ink-2:#5A554D; --muted:#6D6355;
  --signal:#1E4560;               /* emphasis / link: Signal Cobalt */
  --signal-wash:rgba(30,69,96,.10);
  --clay:#A94E2E;                 /* failure only */
  --cta:#1F5FAE; --cta-hover:#1D4F91;  /* 2026-11-07r: action = Royal Cobalt, never the failure-adjacent terracotta */
  --ivory:#F5EFE4; --ivory-border:#DFD5C3;
  --mineral:#EFF4F8; --mineral-border:#D5E2EC;
  --amber:#F7F1E6; --amber-border:#E5D7C0;
  --sage:#EDF5F2; --sage-border:#CCE0D9;
  --showcase:#DCE8F3; --showcase-border:#B8D4E8;  /* 2026-11-07r: replaces the obsidian dark island */
  --ochre-ink:#734C00; --ochre-acc:#A87400; --ochre-tint:#FBF0D9;
  --plum-ink:#562D70; --plum-tint:#F2EAF7;
  --cobalt-ink:#1E4560; --cobalt-acc:#2F6DB5; --cobalt-tint:#E4EFF7; --cobalt-bdr:#B8D4E8;
  --indigo-ink:#343888; --indigo-acc:#5B5FC7; --indigo-tint:#ECECFB; --indigo-bdr:#C5C7F0;
  --emerald-ink:#1B5744; --emerald-acc:#1E7E62; --emerald-tint:#E0F2EC; --emerald-bdr:#AEDAD0;
  --plum-ink:#562D70; --plum-acc:#8A4F9E; --plum-tint:#F2EAF7; --plum-bdr:#D7C0E6;
  --teal-ink:#125366; --teal-acc:#0086A8; --teal-tint:#E0F2F7; --teal-bdr:#AEDCE8;
  --display:"Newsreader",Georgia,"Times New Roman",serif;
  --sans:"Hanken Grotesk",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --gutter:clamp(16px,4.5vw,40px); --max:1140px; /* WEB-05: the site column (1060 of content), so the H1 starts under the logo */
  color-scheme:light;
}
.home *{box-sizing:border-box}
html{scroll-behavior:smooth}
body.home{margin:0;background:var(--canvas);color:var(--ink);font-family:var(--sans);font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased}
.home a{color:inherit}
.home :focus-visible{outline:2px solid var(--signal);outline-offset:3px;border-radius:4px}
.home .wrap{max-width:var(--max);margin-inline:auto;padding-inline:var(--gutter)}
.home .eyebrow{display:inline-flex;align-items:center;gap:8px;width:fit-content;font-family:var(--mono);font-size:12px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--cobalt-ink);background:var(--cobalt-tint);border:1px solid var(--cobalt-bdr);padding:5px 12px;border-radius:999px;margin:0}
.home .eyebrow::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--emerald-acc);flex:none}
.home h1,.home h2,.home h3{font-family:var(--display);font-weight:400;letter-spacing:-.02em;text-wrap:balance;margin:0}
.home h1{font-size:var(--site-h1-landing);line-height:1.03;font-weight:380}
.home h2{font-size:clamp(32px,3.8vw,52px);line-height:1.06}
.home h3{font-size:clamp(22px,2vw,27px);line-height:1.16;font-weight:450}
.home h1 em,.home h2 em{font-style:italic;color:var(--cobalt-ink)}
.home p{margin:0}
.home .lede{color:#433E37;font-size:clamp(17px,1.35vw,19.5px);line-height:1.62;max-width:36em;text-wrap:pretty}
.home .small{font-size:14px;color:var(--muted)}
.home .mono{font-family:var(--mono)}
.home .btn{display:inline-flex;align-items:center;gap:10px;font:600 15px/1 var(--sans);text-decoration:none;border-radius:8px;padding:14px 22px;border:1px solid transparent;cursor:pointer;transition:transform var(--duration-base),background var(--duration-base),border-color var(--duration-base),box-shadow var(--duration-base)}
.hearth.home .btn.ink,.home .btn.ink{background:var(--cta);color:#FFFFFF;box-shadow:0 2px 8px rgba(31,95,174,.24)}
.hearth.home .btn.ink:hover,.home .btn.ink:hover{background:var(--cta-hover);transform:translateY(-1px)}
.hearth.home .btn.line,.home .btn.line{border-color:#C8C2B6;color:var(--ink);background:var(--surface);box-shadow:0 1px 2px rgba(25,23,19,.05)}
.hearth.home .btn.line:hover,.home .btn.line:hover{border-color:var(--cobalt-ink)}
.home .link{color:var(--signal);text-decoration:none;font-weight:600;border-bottom:1px solid rgba(30,69,96,.32)}
.home .link:hover{border-color:var(--signal)}


/* hero — solid Warm Ivory Reserve ground */
.home .hero{background:var(--ivory);border-bottom:1px solid var(--ivory-border);padding-block:clamp(40px,6vw,80px) clamp(48px,6vw,72px)}
.home .hero-top{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:clamp(28px,5vw,72px);align-items:end}
.home .hero-top .side{display:grid;gap:26px}
.home .ctas{display:flex;flex-wrap:wrap;gap:12px}
.home .facts{display:flex;flex-wrap:wrap;gap:8px 22px;font-family:var(--mono);font-size:12px;color:#433E37;letter-spacing:.04em}
.home .facts span::before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--cobalt-acc);margin-right:8px;vertical-align:1px}
@media (max-width:900px){.home .hero-top{grid-template-columns:1fr;align-items:start}}

/* the stage */
.home .stage-wrap{margin-top:clamp(40px,6vw,72px);background:var(--surface);border:1px solid var(--ivory-border);border-radius:20px;overflow:hidden;box-shadow:0 8px 28px rgba(25,23,19,.06)}
.home .stage-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:14px 18px;background:#EFEAE0;border-bottom:1px solid var(--ivory-border)}
.home .seg{display:inline-flex;background:var(--surface);border:1px solid var(--ivory-border);border-radius:999px;padding:4px;gap:2px}
.home .seg button{all:unset;cursor:pointer;font:600 14px/1 var(--sans);padding:10px 16px;border-radius:999px;color:var(--ink-2);transition:background calc(var(--duration-base) * 1.5),color calc(var(--duration-base) * 1.5)}
.home .seg button[aria-pressed="true"]{background:var(--cobalt-ink);color:#FFFFFF;box-shadow:0 1px 3px rgba(25,23,19,.16)}
.home .seg button:focus-visible{outline:2px solid var(--signal)}
.home .pause{all:unset;cursor:pointer;display:inline-flex;align-items:center;gap:8px;font:500 13px/1 var(--sans);color:var(--ink-2);padding:9px 12px;border-radius:8px}
.home .pause:hover{background:var(--sunken)}
.home .pause:focus-visible{outline:2px solid var(--signal)}
.home .pause svg{width:12px;height:12px}
.home .stage{position:relative;width:100%;aspect-ratio:2.15;min-height:440px;
  background-image:radial-gradient(circle at 1px 1px,rgba(25,23,19,.07) 1px,transparent 0);background-size:22px 22px}
.home .stage svg.wires{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.home .host,.home .rec,.home .tool{position:absolute;left:0;top:0;will-change:transform}
.home .host{width:132px;padding:12px 14px;border-radius:12px;background:var(--cobalt-ink);color:#fff;font-size:13px;line-height:1.3;border:1px solid var(--cobalt-ink)}
.home .host b{display:block;font-family:var(--mono);font-weight:500;font-size:13px}
.home .host span{opacity:.78;font-size:12px}
.home .tool{width:var(--cw,176px);padding:10px 12px;border-radius:10px;background:var(--surface);border:1px solid var(--border-strong);border-left:3px solid var(--cobalt-acc);font-size:13.5px;line-height:1.25;transition:border-color calc(var(--duration-base) * 2.5),background calc(var(--duration-base) * 2.5)}
.home .tool:nth-of-type(5n+2){border-left-color:var(--indigo-acc)}
.home .tool:nth-of-type(5n+3){border-left-color:var(--emerald-acc)}
.home .tool:nth-of-type(5n+4){border-left-color:var(--plum-acc)}
.home .tool:nth-of-type(5n+5){border-left-color:var(--teal-acc)}
.home .tool b{display:block;font-weight:600;font-size:13.5px}
.home .tool .sub{position:relative;display:block;height:16px;margin-top:4px;font-family:var(--mono);font-size:12px;color:var(--muted)}
.home .tool .sub i{position:absolute;inset:0;font-style:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity calc(var(--duration-base) * 3)}
.home .tool .sub .b{opacity:0;color:var(--cobalt-ink);font-weight:500}
.home .stage.b .tool{border-color:var(--cobalt-bdr);border-left-color:var(--cobalt-acc)}
.home .stage.b .tool .sub .a{opacity:0}
.home .stage.b .tool .sub .b{opacity:1}
.home .tool.lit{background:var(--cobalt-tint)}
.home .rec{width:212px;padding:16px 18px;border-radius:14px;background:var(--surface);border:2px solid var(--cobalt-acc);box-shadow:0 0 0 6px var(--signal-wash);opacity:0;transition:opacity calc(var(--duration-base) * 3);font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--ink-2);pointer-events:none}
.home .rec .t{font-family:var(--display);font-size:21px;color:var(--ink);line-height:1.1;margin-bottom:6px;font-weight:450}
.home .rec .seal{color:var(--emerald-ink);background:var(--emerald-tint);padding:2px 7px;border-radius:5px;display:inline-block;margin-top:3px;font-weight:600}
.home .stage.b .rec{opacity:1}
.home .rec.pulse{animation:recpulse calc(var(--duration-base) * 3.5) ease-out}
@keyframes recpulse{0%{box-shadow:0 0 0 6px var(--signal-wash)}40%{box-shadow:0 0 0 14px rgba(30,69,96,.18)}100%{box-shadow:0 0 0 6px var(--signal-wash)}}
.home .stage-cap{margin:0;padding:12px 18px;border-top:1px solid var(--border);font-family:var(--mono);font-size:12px;color:var(--muted);background:#FAF8F4}
.home .meters{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border-top:1px solid var(--border)}
.home .meter{padding:18px 20px;border-left:1px solid var(--border);display:grid;gap:2px;min-width:0}
.home .meter:first-child{border-left:0}
.home .meter .v{font-family:var(--display);font-size:clamp(34px,3.6vw,48px);line-height:1;color:#8E3718;font-variant-numeric:lining-nums tabular-nums;transition:color calc(var(--duration-base) * 2.5)}
.home .stage-wrap.b .meter .v{color:var(--emerald-ink)}
.home .meter .l{font-size:13.5px;color:var(--ink-2)}
@media (max-width:760px){
  .home .stage{aspect-ratio:.6;min-height:0}
  .home .host{width:auto;padding:9px 12px}
  .home .tool{padding:7px 8px;font-size:12px}
  .home .tool b{font-size:12px}
  .home .tool .sub{display:none}
  .home .rec{width:116px;padding:9px 10px;font-size:12px}
  .home .rec .t{font-size:18px}
  .home .meters{grid-template-columns:repeat(2,minmax(0,1fr))}
  .home .meter:nth-child(3){border-left:0}
  .home .meter:nth-child(n+3){border-top:1px solid var(--border)}
}

.home section{padding-block:clamp(88px,11vw,152px)}
.home section[aria-labelledby="why-h"]{background:var(--mineral);border-block:1px solid var(--mineral-border)}
.home section[aria-labelledby="price-h"]{background:var(--amber);border-bottom:1px solid var(--amber-border);padding-top:clamp(72px,9vw,120px)}
.home section[aria-labelledby="trial-h"]{background:var(--sage);border-block:1px solid var(--sage-border);padding-top:clamp(72px,9vw,120px)}
.home .head{display:grid;gap:20px;max-width:46em}

/* proofs */
.home .proofs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;margin-top:56px}
.home .pf{background:var(--surface);border:1px solid var(--border);border-top:3px solid var(--cobalt-acc);border-radius:16px;padding:clamp(22px,3vw,34px);display:grid;gap:14px;align-content:start;min-width:0;box-shadow:0 4px 16px rgba(25,23,19,.04)}
.home .pf:nth-child(2){border-top-color:var(--indigo-acc)}
.home .pf:nth-child(3){border-top-color:var(--emerald-acc)}
.home .pf:nth-child(4){border-top-color:#8A4F9E}
.home .pf .n{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--cobalt-ink);background:var(--cobalt-tint);padding:3px 9px;border-radius:999px;width:fit-content}
.home .pf:nth-child(2) .n{color:var(--indigo-ink);background:var(--indigo-tint)}
.home .pf:nth-child(3) .n{color:var(--emerald-ink);background:var(--emerald-tint)}
.home .pf:nth-child(4) .n{color:var(--plum-ink);background:var(--plum-tint)}
.home .pf p{color:var(--ink-2);font-size:15.5px;max-width:34em}
.home .viz{margin-top:10px;background:var(--canvas);border:1px solid var(--border);border-radius:12px;padding:18px;min-height:170px;display:grid;align-content:center;min-width:0;overflow:hidden}
@media (max-width:860px){.home .proofs{grid-template-columns:1fr}}
/* measured coverage (2026-11-14): the platform page's guarded ATT&CK figure, beside the proofs */
.home .measured{margin-top:28px;padding:24px 28px;border:1px solid var(--cobalt-bdr);border-inline-start:4px solid var(--cobalt-acc);border-radius:14px;background:var(--surface);display:grid;gap:10px}
.home .measured-fig{margin:4px 0 0;display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px}
.home .measured-fig b{font-family:var(--display);font-weight:400;font-size:clamp(44px,6vw,64px);line-height:1;letter-spacing:-.02em;color:var(--cobalt-ink);font-variant-numeric:lining-nums tabular-nums}
.home .measured-of{font-size:17px;line-height:1.45;color:var(--ink);max-width:28em}
.home .measured-note{margin:0;font-size:14px;line-height:1.55;color:var(--muted);max-width:44em}
.home .measured-go{margin:4px 0 0}
@media (max-width:560px){.home .measured{padding:20px 18px}}

/* proof 1: agents collapse */
.home .agents{position:relative;height:132px;display:flex;align-items:center;justify-content:center;gap:28px}
.home .host-box{border:1px dashed var(--border-strong);border-radius:10px;padding:14px;display:grid;gap:6px;width:200px;position:relative}
.home .host-box .hl{position:absolute;top:-9px;left:12px;background:var(--canvas);padding:0 6px;font-family:var(--mono);font-size:12px;color:var(--muted)}
.home .ag{font-family:var(--mono);font-size:12px;padding:4px 8px;border-radius:6px;border:1px solid var(--border-strong);background:var(--surface);color:var(--muted);animation:fold calc(var(--duration-base) * 35) cubic-bezier(.6,0,.3,1) infinite}
.home .ag:nth-child(3){animation-delay:calc(var(--duration-base) * 0.4)}.home .ag:nth-child(4){animation-delay:calc(var(--duration-base) * 0.8)}.home .ag:nth-child(5){animation-delay:calc(var(--duration-base) * 1.2)}.home .ag:nth-child(6){animation-delay:calc(var(--duration-base) * 1.6)}
@keyframes fold{0%,30%{transform:none;opacity:1}48%,88%{transform:translateY(var(--up,0));opacity:0}100%{transform:none;opacity:1}}
.home .ag:nth-child(3){--up:-27px}.home .ag:nth-child(4){--up:-54px}.home .ag:nth-child(5){--up:-81px}.home .ag:nth-child(6){--up:-108px}
.home .ag.first{animation-name:becomes;color:var(--ink)}
@keyframes becomes{0%,30%{background:var(--surface);color:var(--muted);border-color:var(--border-strong)}48%,88%{background:var(--cobalt-ink);color:#fff;border-color:var(--cobalt-ink)}100%{background:var(--surface)}}
.home .ag.first{position:relative;z-index:1}
.home .ag.first .w2{position:absolute;left:8px;top:4px;opacity:0;animation:sw2 calc(var(--duration-base) * 35) cubic-bezier(.6,0,.3,1) infinite}
.home .ag.first .w1{animation:sw1 calc(var(--duration-base) * 35) cubic-bezier(.6,0,.3,1) infinite}
@keyframes sw1{0%,30%{opacity:1}44%,92%{opacity:0}100%{opacity:1}}
@keyframes sw2{0%,34%{opacity:0}48%,88%{opacity:1}100%{opacity:0}}
.home .agents-legend{font-family:var(--mono);font-size:12px;color:var(--muted);display:grid;gap:6px}
.home .agents-legend b{color:var(--ink);font-weight:500}

/* proof 2: lesson becomes the rule */
.home .loop{display:grid;gap:10px;font-family:var(--mono);font-size:12px}
.home .lrow{display:grid;grid-template-columns:62px minmax(0,1fr) auto;gap:10px;align-items:center;padding:9px 12px;border-radius:8px;background:var(--surface);border:1px solid var(--border);animation:step calc(var(--duration-base) * 45) infinite;min-width:0}
.home .lrow span:nth-child(2){overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink-2)}
.home .lrow:nth-child(2){animation-delay:calc(var(--duration-base) * 11)}.home .lrow:nth-child(3){animation-delay:calc(var(--duration-base) * 22)}
@keyframes step{0%,6%{border-color:var(--border);box-shadow:none}12%,30%{border-color:var(--signal);box-shadow:0 0 0 4px var(--signal-wash)}40%,100%{border-color:var(--border);box-shadow:none}}
.home .tag{font-size:12px;padding:3px 8px;border-radius:999px;white-space:nowrap}
.home .tag.s{background:var(--cobalt-tint);color:var(--cobalt-ink);font-weight:600}
.home .tag.k{background:var(--emerald-ink);color:#fff}
.home .tag.m{background:var(--sunken);color:var(--ink-2)}

/* proof 3: actions are events */
.home .stream{display:grid;gap:0;font-family:var(--mono);font-size:12px}
.home .srow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:12px;padding:8px 4px;border-bottom:1px dashed var(--border);align-items:center;min-width:0}
.home .srow:last-child{border-bottom:0}
.home .srow .w{color:var(--muted)}
.home .srow .x{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.home .srow.act .x{color:var(--signal);font-weight:500}
.home .srow .ok{color:var(--emerald-ink);font-weight:600}

/* proof 4: tamper demo */
.home .seal-demo{font-family:var(--mono);font-size:12px;display:grid;gap:12px}
.home .seal-demo dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 18px;margin:0}
.home .seal-demo dt{color:var(--muted)}
.home .seal-demo dd{margin:0;overflow-wrap:anywhere}
.home .seal-demo mark{background:transparent;color:inherit;transition:background calc(var(--duration-base) * 1.5)}
.home .seal-demo.tampered mark{background:rgba(169,78,46,.14);color:var(--clay)}
.home .seal-line{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding-top:12px;border-top:1px solid var(--border)}
.home .verdict{font-weight:600;color:var(--emerald-ink)}
.home .seal-demo.tampered .verdict{color:var(--clay)}
.home .mini{all:unset;cursor:pointer;font:500 12.5px/1 var(--sans);padding:9px 14px;border-radius:999px;border:1px solid var(--border-strong);background:var(--surface)}
.home .mini:hover{border-color:var(--ink)}
.home .mini:focus-visible{outline:2px solid var(--signal)}

/* price */
.home .price{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:clamp(32px,6vw,88px);align-items:start}
.home .meterbox{background:var(--surface);border:1px solid var(--border);border-radius:18px;padding:clamp(20px,3vw,34px);display:grid;gap:26px;min-width:0;box-shadow:0 6px 22px rgba(25,23,19,.05)}
.home .vol{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap}
.home .vol .big{font-family:var(--display);font-size:clamp(44px,5vw,64px);line-height:1;font-variant-numeric:lining-nums tabular-nums}
.home .vol .big small{font-family:var(--mono);font-size:14px;color:var(--muted);margin-left:8px}
.home .plan{font-family:var(--mono);font-size:12.5px;color:var(--signal);text-align:right;font-weight:600}
.home input[type=range]{width:100%;accent-color:var(--cta);height:28px;margin:0}
.home .bands{position:relative;display:grid;grid-template-columns:var(--b1) var(--b2) var(--b3) var(--b4) var(--b5);height:10px;border-radius:5px;overflow:hidden;margin-top:-8px}
.home .bands i{display:block;background:var(--sunken);border-right:2px solid var(--surface)}
.home .bands i.on{background:var(--cobalt-acc)}
.home .bandlabels{display:grid;grid-template-columns:var(--b1) var(--b2) var(--b3) var(--b4) var(--b5);font-family:var(--mono);font-size:12px;color:var(--muted);margin-top:6px}
.home .bandlabels span{padding-right:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.home .flat{display:grid;gap:10px}
.home .flat div{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:14px;align-items:center;font-size:14px}
.home .flat .line{height:1px;background:var(--border-strong)}
.home .flat .meterline{height:3px;background:var(--sunken);border-radius:2px;position:relative;overflow:hidden}
.home .flat .meterline i{position:absolute;inset:0 auto 0 0;background:var(--cobalt-acc);border-radius:2px;transition:width calc(var(--duration-base) * 1.5)}
.home .flat em{font-style:normal;font-family:var(--mono);font-size:12px;color:var(--muted)}
.home .included{display:flex;flex-wrap:wrap;gap:8px}
.home .included span{font-size:13px;padding:6px 11px;border-radius:999px;border:1px solid var(--emerald-bdr);background:var(--emerald-tint);color:var(--ink);display:inline-flex;gap:6px;align-items:center}
.home .included span::before{content:"✓";color:var(--emerald-ink);font-weight:700}
.home .included.ping span{animation:ping calc(var(--duration-base) * 3) ease-out both;animation-delay:calc(var(--i) * calc(var(--duration-base) * 0.125))}
@keyframes ping{40%{border-color:var(--signal);background:#F4F7F9}}
@media (max-width:900px){.home .price{grid-template-columns:1fr}}
/* BUG-01: the deployment model is chosen before the volume, so the unit is never misread */
.home .seg.deploy{justify-self:start;flex-wrap:wrap}
.home .seg.deploy button{font-size:13.5px;padding:9px 14px}

/* ── transformation spine: INGEST → SEAL → ACT (Phase 4) ── */
.home .xform{list-style:none;margin:32px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.home .xform li{background:var(--surface);border:1px solid var(--border);border-top:3px solid var(--cobalt-acc);border-radius:16px;padding:22px 24px;display:grid;gap:8px;align-content:start;min-width:0;position:relative;box-shadow:0 2px 10px rgba(25,23,19,.04)}
.home .xform li:nth-child(2){border-top-color:var(--indigo-acc)}
.home .xform li:nth-child(3){border-top-color:var(--emerald-acc)}
.home .xform .xk{font:600 12px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--cobalt-ink);background:var(--cobalt-tint);border:1px solid var(--cobalt-bdr);padding:4px 10px;border-radius:999px;width:fit-content}
.home .xform li:nth-child(2) .xk{color:var(--indigo-ink);background:var(--indigo-tint);border-color:var(--indigo-bdr)}
.home .xform li:nth-child(3) .xk{color:var(--emerald-ink);background:var(--emerald-tint);border-color:var(--emerald-bdr)}
.home .xform b{font-family:var(--display);font-weight:450;font-size:clamp(21px,2vw,26px);line-height:1.15;color:var(--ink)}
.home .xform span:not(.xk){font-size:14px;line-height:1.55;color:var(--ink-2)}
.home .xform a{font-size:13.5px;font-weight:600;color:var(--signal);margin-top:4px}
.home .xform a:hover{text-decoration:underline;text-underline-offset:4px}
@media (max-width:860px){.home .xform{grid-template-columns:1fr}}

/* ── start where you sit: five stakeholder doors (2026-10-21, audit "something for every stakeholder").
   No-JS / print: the five cards stand in a grid — the whole content. With JS: a tablist over one card. ── */
.home .roles-sec{padding-bottom:0}
.home .roles{margin-top:48px}
.home .roles-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:20px}
.home .roles-tabs[hidden]{display:none}
.home .roles-tabs button{all:unset;cursor:pointer;font:500 14.5px/1 var(--sans);padding:12px 18px;border-radius:999px;border:1px solid var(--border-strong);background:var(--surface);color:var(--ink-2);transition:background var(--duration-base),color var(--duration-base),border-color var(--duration-base)}
.home .roles-tabs button:hover{border-color:var(--cobalt-ink);color:var(--cobalt-ink)}
.home .roles-tabs button[aria-selected="true"]{background:var(--cobalt-ink);border-color:var(--cobalt-ink);color:#fff}
.home .roles-tabs button:focus-visible{outline:2px solid var(--signal);outline-offset:3px}
.home .roles:not(.is-tabs){display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:16px}
.home .role{background:var(--surface);border:1px solid var(--border);border-top:3px solid var(--role-acc,var(--cobalt-acc));border-radius:20px;padding:clamp(24px,3.4vw,44px);display:grid;gap:14px;align-content:start;min-width:0;box-shadow:0 4px 16px rgba(25,23,19,.05)}
#rp-ciso{--role-acc:var(--cobalt-acc);--role-ink:var(--cobalt-ink);--role-tint:var(--cobalt-tint)}
#rp-soc{--role-acc:var(--indigo-acc);--role-ink:var(--indigo-ink);--role-tint:var(--indigo-tint)}
#rp-arch{--role-acc:var(--teal-acc);--role-ink:var(--teal-ink);--role-tint:var(--teal-tint)}
#rp-audit{--role-acc:var(--emerald-acc);--role-ink:var(--emerald-ink);--role-tint:var(--emerald-tint)}
#rp-proc{--role-acc:var(--ochre-acc);--role-ink:var(--ochre-ink);--role-tint:var(--ochre-tint)}
.home .roles.is-tabs .role{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);column-gap:clamp(24px,5vw,72px);align-items:start}
.home .roles.is-tabs .role>*:not(.role-path){grid-column:1}
.home .roles.is-tabs .role .role-path{grid-column:2;grid-row:1 / span 3}
.home .role[hidden]{display:none}
.home .role-k{font-family:var(--mono);font-size:12px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--role-ink,var(--cobalt-ink));background:var(--role-tint,var(--cobalt-tint));padding:4px 10px;border-radius:999px;width:fit-content}
.home .role h3{font-size:clamp(24px,2.4vw,34px)}
.home .role p:not(.role-k){color:var(--ink-2);font-size:16px;max-width:36em}
.home .role-path{list-style:none;margin:0;padding:0;display:grid;gap:10px;counter-reset:rp}
.home .role-path li{counter-increment:rp}
.home .role-path a{display:grid;grid-template-columns:34px minmax(0,1fr) auto;align-items:center;gap:12px;padding:14px 16px;border-radius:12px;border:1px solid var(--border);background:var(--canvas);font-weight:500;transition:border-color var(--duration-base),background var(--duration-base)}
.home .role-path a::before{content:counter(rp,decimal-leading-zero);font:600 12px/1 var(--mono);color:var(--role-ink,var(--cobalt-ink))}
.home .role-path a::after{content:"→";color:var(--role-ink,var(--cobalt-ink))}
.home .role-path a:hover{border-color:var(--role-acc,var(--cobalt-acc));background:var(--surface)}
@media (max-width:760px){.home .roles.is-tabs .role{grid-template-columns:1fr}.home .roles.is-tabs .role .role-path{grid-column:1;grid-row:auto}}

/* trial */
.home .terms{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:40px}
.home .terms div{padding-top:16px;border-top:2px solid var(--emerald-acc);display:grid;gap:6px}
.home .terms b{font-weight:600}
.home .terms p{color:var(--ink-2);font-size:15px}
@media (max-width:900px){.home .terms{grid-template-columns:1fr}}

/* close */
.home .close{background:var(--showcase);border:1px solid var(--showcase-border);color:var(--ink);border-radius:28px;padding:clamp(40px,7vw,96px) clamp(22px,6vw,88px);display:grid;gap:28px;position:relative;overflow:hidden;box-shadow:0 18px 42px rgba(30,69,96,.12);margin-top:clamp(56px,7vw,96px)}
.home .close .eyebrow{background:#FFFFFF;border-color:var(--showcase-border);color:var(--cobalt-ink)}
.home .close h2{font-size:clamp(42px,6vw,84px);max-width:13em;color:var(--ink)}
.home .close h2 em{color:var(--cobalt-ink)}
.home .close .row .lede{max-width:30em;color:var(--ink-2)}
.home .close .row{display:flex;justify-content:space-between;align-items:end;gap:24px;flex-wrap:wrap}
.hearth.home .close .btn.line,.home .close .btn.line{background:#FFFFFF;border-color:var(--showcase-border);color:var(--ink)}
.hearth.home .close .btn.line:hover,.home .close .btn.line:hover{border-color:var(--cobalt-ink)}
.home .close .mesh{position:absolute;right:-150px;top:50%;width:min(620px,80%);height:auto;transform:translateY(-50%);opacity:.32;pointer-events:none;z-index:0}
/* 2026-10-31y: the closing mesh no longer spins for ever (motion-graphics-scope.md §7: no infinite loop in
   peripheral vision but the one live indicator). It SEALS once when scrolled into view (data-mm="seal-on-view",
   ../mark-motion.js), then rests. The .spin class stays on the group as a harmless hook. */
.home .close .mesh .spin{transform-origin:200px 200px}
.home .close>*:not(.mesh){position:relative;z-index:1}
@media (max-width:760px){.home .close .mesh{right:-170px;width:420px;opacity:.16}}

.motion-off .home *,.motion-off .home *::before,.motion-off .home *::after{animation-play-state:paused!important}
/* home.js marks a section .offscreen while it is out of view, so its infinite loops stop compositing there */
.home .offscreen *,.home .offscreen *::before,.home .offscreen *::after{animation-play-state:paused!important}
@media (prefers-reduced-motion:reduce){.home *,.home *::before,.home *::after{animation:none!important;transition:none!important}html{scroll-behavior:auto}}

/* the canonical nav's buttons: site.css is not loaded on this page (its .hero/.btn/.wrap
   rules would collide with this page's own), so the primary's fill lives here. Their SIZE and the
   ghost's ink are site-nav.css's (one rule for every page, 2026-11-07w) — not restated here. */
.hearth.home .btn-primary,.home .btn-primary{background:var(--cta);color:#fff}
.hearth.home .btn-primary:hover,.home .btn-primary:hover{background:var(--cta-hover)}
.home .closing{margin-bottom:0}

/* colors_and_type.css sets `.hearth a` (0,1,1); this page's links and buttons choose their own */
.home a{text-decoration:none}
.home .link{border-bottom:1px solid rgba(39,80,107,.3)}

/* mark-motion.css */
/* mark-motion.css — the EventLake mark in motion (session 2026-10-31y).
 *
 * Spec: docs/reference/logo-motion.md. Doctrine: docs/reference/motion-graphics-scope.md §5 (the seven
 * principles, the ten verbs) and §7 (where motion must NOT go). This file states the mark's states as
 * selectors on [data-mm-state]; mark-motion.js only sets that attribute and the per-ribbon indices.
 *
 *  ⛔ The geometry is NOT here and NOT in the JS. The mark is the generator's own SVG
 *     (conduit/cmd/eventlake-mark → assets/logo/), inlined, and MarkMotion.enhance() classifies its
 *     ribbons / nodes / core. A redraw of the mark therefore moves every animated surface with it.
 *  ⛔ NEVER-BLANK: every rule animates FROM a hidden/offset frame TO the base style (fill-mode
 *     `backwards`, never `both`), so a paused, printed, PDF'd or reduced-motion frame is the static mark.
 *  ⛔ Every time value is a hearth-tokens.css duration token, so the global reduced-motion net (which
 *     re-points every --duration-* to 0ms) stops these too. The explicit @media blocks below are the
 *     belt to that braces: a page that forgot to load hearth-tokens.css still holds still.
 *
 * States (docs/reference/logo-motion.md §2):
 *   intro   once per session, skippable — ribbons weave in, nodes travel in, the core seals
 *   breathe the ONE live indicator's verb, bounded: three breaths, then rest
 *   weave   indeterminate work — an ink highlight laps the C; only while work is genuinely pending
 *   event   one event enters the aperture and the arms absorb it; driven by MarkMotion.pulse()
 *   seal    a record was sealed / verified: the ribbons draw in ink once, then settle. No overshoot.
 *   fail    verification failed: ONE clay cycle (the `attend` verb's one pulse), always with words
 *   rest    the base style (also what reduced motion, print, PDF and email get)
 */

/* Colour is the GENERATOR'S, not this file's: mark-motion.js copies the inlined SVG's own ribbon stroke and
   node fill into --mm-ribbon / --mm-ink (so eventlake-mid.svg animates in #27506B and eventlake-mid-dark.svg
   in its own #9CC0DC), and at rest nothing here repaints a single stroke. The fallbacks only matter for an
   SVG that carries no colour attributes. */
.mm { --mm-ribbon: #27506B; --mm-ink: #191713; --mm-fail: var(--clay-600, #A94E2E);
      --mm-d-step: var(--motion-stagger, 30ms); }
.mm .mm-node { transform-box: fill-box; transform-origin: center; }
.mm .mm-core { transform-box: fill-box; transform-origin: center; }
.mm .mm-weave { transform-box: view-box; transform-origin: 200px 200px; }
/* The two overlays MarkMotion adds. Base style: invisible, so they cost nothing at rest. */
.mm .mm-ripple { fill: none; stroke: var(--mm-ribbon); stroke-width: 1.4; opacity: 0;
                 transform-box: fill-box; transform-origin: center; pointer-events: none; }
.mm .mm-packet { fill: var(--mm-ink); opacity: 0; transform-box: fill-box; transform-origin: center;
                 pointer-events: none; }
/* MarkMotion.place() (queue row 880): the chrome's <img> of the mark hides only AFTER its inlined copy is in
   the page beside it, so the mark is never missing; the copy takes the <img>'s place in the line. */
.mm-src { display: none !important; }
svg.mm-placed { display: block; flex: none; overflow: hidden; }
/* Paused by the controller (off-screen, hidden tab, idle). The frame it rests on is a base frame. */
.mm.mm-paused, .mm.mm-paused * { animation-play-state: paused !important; }

/* ── intro ─────────────────────────────────────────────────────────────── */
@keyframes mm-draw   { from { stroke-dashoffset: 1; opacity: 0; } to { stroke-dashoffset: 0; opacity: 1; } }
@keyframes mm-travel { from { opacity: 0; transform: translate(var(--mm-dx, 0), var(--mm-dy, 0)) scale(.4); } to { opacity: 1; transform: none; } }
@keyframes mm-close  { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: none; } }
@keyframes mm-fade   { from { opacity: 0; } to { opacity: 1; } }
@keyframes mm-ripple { 0% { opacity: .6; transform: scale(.3); } 100% { opacity: 0; transform: scale(5.5); } }
.mm[data-mm-state="intro"] .mm-rib {
  stroke-dasharray: 1 1;
  animation: mm-draw var(--duration-slower, 480ms) var(--ease-standard, ease) backwards;
  animation-delay: calc(var(--mm-i, 0) * var(--mm-d-step)); }
.mm[data-mm-state="intro"] .mm-node {
  animation: mm-travel var(--duration-deliberate, 720ms) var(--ease-emphasized, ease) backwards;
  animation-delay: calc(var(--duration-slower, 480ms) + var(--mm-i, 0) * 80ms); }
.mm[data-mm-state="intro"] .mm-core {
  animation: mm-close var(--duration-slow, 320ms) var(--ease-spring, ease) backwards;
  animation-delay: calc(var(--duration-deliberate, 720ms) + var(--duration-slower, 480ms)); }
.mm[data-mm-state="intro"] .mm-dot {
  animation: mm-fade var(--duration-base, 200ms) var(--ease-standard, ease) backwards;
  animation-delay: calc(var(--duration-deliberate, 720ms) + var(--duration-slower, 480ms)); }
.mm[data-mm-state="intro"] .mm-ripple {
  animation: mm-ripple calc(var(--duration-deliberate, 720ms) * 2) var(--ease-standard, ease);
  animation-delay: calc(var(--duration-deliberate, 720ms) + var(--duration-slower, 480ms) + var(--duration-base, 200ms)); }

/* ── breathe (bounded: three cycles, then the base style) ──────────────── */
@keyframes mm-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.mm[data-mm-state="breathe"] .mm-rib {
  animation: mm-breathe calc(var(--duration-slower, 480ms) * 5) ease-in-out 3;
  animation-delay: calc(var(--mm-i, 0) * -120ms); }

/* ── weave (indeterminate; the controller removes it the moment work ends) ─ */
@keyframes mm-lap { 0% { stroke: var(--mm-ink); stroke-width: 3; opacity: 1; }
                    30%, 100% { stroke: var(--mm-ribbon); opacity: .35; } }
.mm[data-mm-state="weave"] .mm-rib {
  animation: mm-lap calc(var(--mm-n, 20) * 60ms) linear infinite;
  animation-delay: calc(var(--mm-i, 0) * 60ms); }
.mm[data-mm-state="weave"] .mm-node { opacity: .35; }

/* ── event (one pulse per MarkMotion.pulse(); the controller restarts it, rate-capped) ─ */
@keyframes mm-enter  { 0% { opacity: 0; transform: translateX(190px); } 15% { opacity: 1; }
                       85% { opacity: 1; transform: none; } 100% { opacity: 0; transform: scale(.2); } }
@keyframes mm-absorb { 0% { stroke: var(--mm-ink); stroke-width: 3; } 100% { stroke: var(--mm-ribbon); } }
@keyframes mm-tick   { 0% { transform: none; } 40% { transform: scale(1.4); } 100% { transform: none; } }
.mm[data-mm-state="event"] .mm-packet {
  animation: mm-enter var(--duration-deliberate, 720ms) var(--ease-emphasized, ease); }
.mm[data-mm-state="event"] .mm-rib {
  animation: mm-absorb var(--duration-deliberate, 720ms) var(--ease-standard, ease) backwards;
  animation-delay: calc(var(--duration-deliberate, 720ms) + var(--mm-j, 0) * 45ms); }
.mm[data-mm-state="event"] .mm-core {
  animation: mm-tick var(--duration-slow, 320ms) var(--ease-standard, ease) var(--duration-deliberate, 720ms); }
.mm[data-mm-state="event"] .mm-ripple {
  animation: mm-ripple calc(var(--duration-deliberate, 720ms) * 1.5) var(--ease-standard, ease) var(--duration-deliberate, 720ms); }

/* ── seal (settles; never celebrates — no cinch overshoot, no burst) ──── */
@keyframes mm-seal { from { stroke: var(--mm-ink); stroke-dashoffset: 1; } to { stroke: var(--mm-ribbon); stroke-dashoffset: 0; } }
.mm[data-mm-state="seal"] .mm-rib {
  stroke-dasharray: 1 1;
  animation: mm-seal var(--duration-slow, 320ms) var(--ease-standard, ease) backwards;
  animation-delay: calc(var(--mm-j, 0) * var(--mm-d-step)); }
.mm[data-mm-state="seal"] .mm-core {
  animation: mm-close var(--duration-slow, 320ms) var(--ease-standard, ease) backwards;
  animation-delay: calc(10 * var(--mm-d-step) + var(--duration-slow, 320ms)); }

/* ── fail (ONE cycle; the words carry the meaning, never colour alone) ── */
@keyframes mm-fail { 0%, 100% { stroke: var(--mm-ribbon); } 30% { stroke: var(--mm-fail); stroke-width: 2.6; } }
@keyframes mm-faildot { 0%, 100% { fill: var(--mm-ribbon); } 30% { fill: var(--mm-fail); } }
.mm[data-mm-state="fail"] .mm-rib {
  animation: mm-fail calc(var(--duration-deliberate, 720ms) * 2) var(--ease-standard, ease);
  animation-delay: calc(var(--mm-j, 0) * var(--mm-d-step)); }
.mm[data-mm-state="fail"] .mm-dot { animation: mm-faildot calc(var(--duration-deliberate, 720ms) * 2) var(--ease-standard, ease); }
.mm[data-mm-state="fail"] .mm-ripple { stroke: var(--mm-fail);
  animation: mm-ripple calc(var(--duration-deliberate, 720ms) * 2) var(--ease-standard, ease); }

@media (prefers-reduced-motion: reduce) { .mm, .mm * { animation: none !important; transition: none !important; } }
@media print { .mm, .mm * { animation: none !important; } }

