/* ============================================================
   Rine business landing — biz.css
   Zero-build static styles. Tokens per SPEC §2; two themes
   (cream hero + dark network world) per §3; responsive §7;
   reduced-motion §4.8. No external network dependencies —
   fonts are served locally from /fonts (production brand faces).
   ============================================================ */

/* ---- Local fonts (no CDN). Newsreader is the editorial serif (SPEC G3);
   Inter + JetBrains Mono are the production brand faces standing in for
   Hanken Grotesk / Geist Mono. All served locally so the page is
   self-contained with zero external requests. ---- */
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/fonts/newsreader-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url(/fonts/newsreader-italic-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(/fonts/inter-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/fonts/jetbrains-mono-latin.woff2) format('woff2');
}

:root {
  /* Neutrals: warm cream (light hero) */
  --cream: #F4F1E9;
  --cream-raised: #FBFAF4;
  --card: #FFFFFF;
  --ink: #1A1916;
  --ink-deep: #131211;
  --ink-card: #232120;

  /* Neutral text ramp (on cream) */
  --text-ink: #1A1916;
  --text-body: #57534B;
  --text-chip: #3A372F;
  --text-muted: #8C887E;
  --text-faint: #A8A294;
  --hairline: #E5E0D5;
  --chip-border: #E2DDD0;

  /* Dark-surface text (post-hero network world). --d-muted (5.2:1 on the dark world)
     is the QUIETEST ink allowed on text: every tier below it fails AA at the 11-13px
     the labels, lamps and footer meta are set in. */
  --d-bright: #ECE8DE;
  --d-body: #B8B2A6;
  --d-muted: #908B80;
  --d-hairline: rgba(138, 134, 125, 0.20);

  /* Brand teal (production ramp) */
  --teal-300: #33F5DD;
  --teal-400: #00E0C8;
  --teal-500: #00BBA8;
  --teal-ink: #1F7A72;

  /* Signal amber (production ramp) */
  --amber-300: #FFD04F;
  --amber-400: #FFB814;
  --amber-500: #E0A000;
  /* Secondary accent. LARGE TEXT AND MARKS ON CREAM ONLY — 3.06:1, which clears
     AA-large (≥3:1) and fails AA-normal. Never use it for body or mono text on
     cream. --amber-400/--amber-500 both fail AA-large on cream: never substitute. */
  --amber-ink: #C27A00;
  /* The small-text cream-world member of the amber ramp (round 7), the amber analogue of
     --teal-ink-deep / --mint-ink: amber's hue taken down until it clears AA-normal on the
     cream card, for the 11px signal kicker where --amber-ink (3.06:1) fails. Marks stay on
     --amber-ink — they are graphics, and 3:1 is their bar. Measured 4.7:1 on --cream-raised. */
  --amber-ink-deep: #935E00;

  /* Role accents (roles chain composition, item 13). Round 5 moved the cream boundary above
     `.roles`, so the chain now has to compose in BOTH worlds — these four are re-pointed as a
     set by `body.light-bottom .roles` and every node, rule, kicker and link in the chain
     follows, because `.rstation` reads them through one `--accent`. The light values are each
     the cream-world member of the SAME ramp, so the chain keeps its identity across the flip:
     neutral / mint / teal, only inked for the surface they are standing on. */
  --role-org:   #ECE8DE;   /* Organizations — neutral bright */
  --role-prin:  #8AD9BC;   /* Principals — mint/green */
  --role-agent: #00E0C8;   /* Agents — teal */
  --role-seg:   #00E0C8;   /* the marching connector between stations */

  /* Verification green + ember */
  --green: #2E8B73;
  --mint: #8AD9BC;
  --ember: #C15F3C;
  /* The two cream-world accents the ROLES CHAIN needs, and the only place on the page that
     carries 12-13px accent text over a live globe in the cream world.

     --mint-ink is the cream member of the mint ramp: mint's own hue (158°) taken down until it
     clears AA on cream (5.04:1). --mint is 1.46:1 there and --green only 3.68:1 — AA-LARGE —
     so both fail the mono the Principals kicker and link are set in.

     --teal-ink-deep is --teal-ink's hue (175°) one stop further down. --teal-ink is 4.55:1 on
     FLAT cream, which has no margin, and MEASURES 4.47:1 once the globe's lines are behind it:
     a fail. Every other cream-world use of --teal-ink is either large text (the hero H1, the two
     h2 ems — 3:1 bar) or sits on an opaque surface (.cta__sub's plate, the solid footer), so
     this is the first place the missing margin actually bit. --teal-ink is left alone: moving it
     would restyle the hero to fix a bug that only exists down here. */
  --mint-ink: #2A7358;        /* 5.04:1 on cream */
  --teal-ink-deep: #1C6E67;   /* 5.35:1 on cream */

  /* Globe / scroll world */
  --globe-line: #3A372F;
  --globe-line-d: #6E6A60;
  --scrim: 10, 10, 12;
  --panel: rgba(19, 18, 17, 0.62);
  --panel-raised: rgba(35, 33, 32, 0.72);

  /* Brand wordmark — one gradient per polarity, shared by the nav and the footer
     wordmark (item 10). Defined once here so there is a single teal→amber ramp. */
  --wm-cream: linear-gradient(135deg, var(--ink) 0%, var(--teal-500) 42%, var(--amber-500) 78%);
  --wm-dark:  linear-gradient(135deg, var(--d-bright) 0%, var(--teal-400) 35%, var(--amber-400) 72%);

  /* Type */
  --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
  --font-sans: "Inter", "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

  /* Radii / layout */
  --r-card: 18px;
  --r-panel: 16px;
  --r-menu: 14px;
  --r-chip: 999px;
  --maxw: 1320px;
  --pad: 40px;
  --nav-h: 72px;
}

/* ---- Reset / base ---- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  padding: 0;
  background: var(--ink-deep);
  color: var(--text-ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
a:hover { opacity: 0.88; }
img, svg { display: block; }
::selection { background: color-mix(in srgb, var(--teal-ink) 22%, transparent); }
:focus-visible { outline: 2px solid var(--teal-ink); outline-offset: 2px; border-radius: 4px; }
.dark-world :focus-visible,
.sec--dark :focus-visible,
footer :focus-visible { outline-color: var(--teal-300); }

.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--ink); color: var(--cream);
  padding: 10px 18px; border-radius: 999px; font-size: 14px;
  transition: top .2s;
}
.skip-link:focus { top: 12px; }

/* ============================================================
   Fixed globe layers (§4.1)
   ============================================================ */
/* 🔴 INVISIBLE BUT LOAD-BEARING. The canvas above is opaque (alpha:false, D-3) and covers this
   layer at all times, so it can never contribute a pixel — but the globe READS this element's
   computed background-color to detect a CSS-rewriting extension (the D-3 probe, ink.js:55).
   Deleting it as "dead" would silently kill the Dark Reader rescue.
   No `will-change`: promoting a permanently occluded full-viewport layer pins ~33 MB on a 4K
   display and can never pay it back. */
#globe-cream {
  position: fixed; inset: 0; z-index: 0;
  background: var(--cream);
  pointer-events: none;
}
#globe-canvas {
  position: fixed; inset: 0; z-index: 1;
  pointer-events: none;       /* always: the drag hit-target is #hero-globebox (item 2) */
  touch-action: none;
  width: 100vw; height: 100vh;
}
#globe-scrim {
  position: fixed; inset: 0; z-index: 2;
  background: rgba(var(--scrim), 0);
  pointer-events: none;
  will-change: opacity, backdrop-filter;
}

/* Content sits above the globe */
.page { position: relative; z-index: 3; }

/* ============================================================
   Layout helpers
   ============================================================ */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad); }
.eyebrow {
  font-family: var(--font-mono); font-size: 12px;
  letter-spacing: 0.2em; text-transform: uppercase;
}
.mono { font-family: var(--font-mono); }
.serif { font-family: var(--font-serif); font-weight: 400; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-sans); font-weight: 500;
  border-radius: var(--r-chip); border: 1px solid transparent;
  transition: background .25s, border-color .25s, color .25s;
  cursor: pointer;
}
.btn--dark { background: var(--ink); color: var(--cream); }
.btn--dark:hover { background: var(--teal-ink); opacity: 1; }
.btn--outline { color: var(--ink); border-color: #C9C3B7; }
.btn--outline:hover { border-color: var(--ink); opacity: 1; }
.dark-world .btn--dark { background: var(--teal-500); color: var(--ink-deep); }
.dark-world .btn--dark:hover { background: var(--teal-400); }
.dark-world .btn--outline { color: var(--d-bright); border-color: var(--d-hairline); }
.dark-world .btn--outline:hover { border-color: var(--teal-300); }

/* ============================================================
   NAV (§3.1)
   ============================================================ */
/* The BAR itself carries nothing — no fill, no blur, no rule, in any state. What
   holds the nav legible over a backdrop that is mid-way through a theme ramp are the
   ISLANDS: one blurred plate under each content group, clear air between them (item 3).
   A plate only has to be as opaque as the ink standing on it needs, and the globe
   keeps the width of the page. */
.nav { position: sticky; top: 0; z-index: 60; background: transparent; }

/* One island treatment; the polarity supplies the fill, the hairline and the blur as
   custom properties, so the GEOMETRY is identical in every state — the plates cannot
   move the bar when the world flips, and over the hero (neither class) all three
   resolve to nothing and the nav is seamless on the cream.

   NOTHING IN THE BAR TRANSITIONS, and that is the point. No rule has ever transitioned a
   nav ink — the links, the wordmark's gradient and the logo mark all SNAP the frame the
   world class lands, which is rule (2) of LIGHT BOTTOM: 12–16px type owes 4.5:1, and
   nothing reaches that over a backdrop half-way between two worlds. The PLATE, though,
   used to ease over .3s underneath them, which is the identical defect seen from the
   other side — for .3s the new ink stood on the outgoing world's surface. Measured at
   the flip on the shipped tree (paused mid-lerp, frozen globe), and the nav is STICKY,
   so every reader crosses this twice: the links went literally INVISIBLE descending (not
   one glyph pixel differed from its backdrop, 0–40ms) and 1.18:1 ascending; the logo
   mark 1.01:1; the wordmark's dark stop on the still-dark plate 1.16:1. A surface and
   the ink read against it flip together or not at all. */
.nav__logo, .nav__links, .nav__cta, .nav__burger {
  height: 46px; border-radius: var(--r-chip);
  background-color: var(--isl-bg, transparent);
  backdrop-filter: var(--isl-blur, none); -webkit-backdrop-filter: var(--isl-blur, none);
}
.nav__logo, .nav__links, .nav__cta { border: 1px solid var(--isl-line, transparent); }
/* Each plate's negative margin equals its own side padding, so the logo glyph and the
   CTA pill stay flush with the page gutter — and with the H1 beneath them — while the
   plate bleeds past it. */
.nav__logo { padding: 0 14px; margin-left: -14px; }
.nav__links { padding: 0 20px; }
.nav__cta { padding: 0 6px; margin-right: -6px; }

body.dark-world {
  --isl-bg: rgba(19, 18, 17, 0.62); --isl-line: var(--d-hairline);
  --isl-blur: blur(14px) saturate(1.2);
}
body.light-bottom {
  --isl-bg: rgba(251, 250, 244, 0.72); --isl-line: var(--chip-border);
  --isl-blur: blur(14px) saturate(1.2);
}
/* Without a backdrop-filter the plate is no longer smoothing the globe behind it — a
   bright line can shine straight through a 62% tint. Then it stops being a frosting
   and has to be a surface. Same for a reader who has asked for less transparency. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  body.dark-world { --isl-bg: rgba(19, 18, 17, 0.92); }
  body.light-bottom { --isl-bg: rgba(251, 250, 244, 0.94); }
}
@media (prefers-reduced-transparency: reduce) {
  body.dark-world { --isl-bg: rgba(19, 18, 17, 0.95); }
  body.light-bottom { --isl-bg: rgba(251, 250, 244, 0.96); }
}
body.dark-world .nav__links, body.dark-world .nav__links a { color: var(--d-body); }
body.dark-world .nav__links a:hover, body.dark-world .navdrop__btn:hover { color: var(--d-bright); }
body.dark-world .nav__logo svg { color: var(--teal-300); }
body.dark-world .nav__burger { border-color: var(--d-hairline); color: var(--d-bright); }
.nav__inner {
  max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad);
  height: var(--nav-h); display: flex; align-items: center; gap: 38px;
}
.nav__logo { display: flex; align-items: center; gap: 10px; }
.nav__logo svg { color: var(--teal-ink); width: 30px; height: 30px; }
.nav__logo:hover svg { animation: rine-hop .7s ease-in-out; }
/* Gradient-clipped wordmark. ONE rule, shared by both wordmarks on the page (item 10);
   each only has to name the polarity it is standing in. The nav opens in the cream
   world and flips dark; the footer opens dark and flips cream (see FOOTER). */
.nav__wordmark, .footer__brand .wordmark {
  background-image: var(--wm-grad);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.nav__wordmark {
  font-family: var(--font-sans);          /* Inter — match live logo (item 1) */
  font-weight: 600; letter-spacing: -0.04em; font-size: 22px;
  --wm-grad: var(--wm-cream);
}
body.dark-world .nav__wordmark { --wm-grad: var(--wm-dark); }
.nav__links { display: flex; align-items: center; gap: 24px; font-size: 14.5px; color: var(--text-body); }
.nav__links a:hover, .navdrop__btn:hover { color: var(--ink); opacity: 1; }

/* ---- "Network" disclosure (round 6) — the three role pages under one trigger ----
   NO SCRIPT. The panel is shown by `:hover` on fine pointers and by `:focus-within` on
   every pointer, which is what makes it work identically on the eight document pages,
   none of which load a line of JS: a tap focuses the button (it is a real <button>, so
   it takes focus on touch), a tap anywhere else blurs it, Tab walks in and out of the
   three links, and Shift-Tab leaves the way it came. `visibility` is what keeps the
   links out of the tab order while closed — `opacity: 0` alone leaves three focusable
   stops floating in an invisible panel — and it is in the transition list so it flips
   only after the fade has run.

   The trigger itself is inert (no href): every destination in the panel is a real page,
   and a trigger that also navigated would make the hover state a trap for the reader who
   meant to open it. */
.navdrop { position: relative; display: flex; align-items: center; }
.navdrop__btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  font: inherit; font-size: inherit; color: inherit; line-height: inherit;
}
.navdrop__chev {
  width: 6px; height: 6px; border-right: 1.4px solid currentColor;
  border-bottom: 1.4px solid currentColor; transform: translateY(-2px) rotate(45deg);
  opacity: 0.55; transition: transform .28s ease, opacity .28s ease;
}
.navdrop:is(:hover, :focus-within) .navdrop__chev { transform: translateY(1px) rotate(-135deg); opacity: 1; }

/* The panel hangs off a bar with no surface of its own, so — like the mobile drawer — it
   brings its own, and takes the polarity with it. `--menu-bg` is the drawer's token; over
   the hero neither world class is set and it falls back to the opaque cream. The gap
   between bar and panel is PADDING on the wrapper (`padding-top` on the menu's own box
   would be inside the surface), so the pointer can cross it without the hover dropping. */
.navdrop__menu {
  position: absolute; top: 100%; left: -18px; z-index: 70;
  margin-top: 10px; padding: 8px; min-width: 268px;
  display: flex; flex-direction: column; gap: 2px;
  border-radius: var(--r-menu); border: 1px solid var(--isl-line, var(--hairline));
  background-color: var(--menu-bg, var(--cream));
  backdrop-filter: var(--isl-blur, none); -webkit-backdrop-filter: var(--isl-blur, none);
  box-shadow: 0 18px 44px -22px rgba(20, 18, 15, 0.45);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .2s ease, transform .2s ease, visibility 0s linear .2s;
}
/* The hover half is gated on a real pointer: on a touch screen `:hover` sticks after the
   tap that opened the panel and then never lifts, so the chevron would stay flipped on a
   panel that focus has already closed. */
@media (hover: hover) and (pointer: fine) {
  .navdrop:hover .navdrop__menu { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
}
.navdrop:focus-within .navdrop__menu { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.navdrop__menu::before {          /* the bridge: pointer-crossable, invisible, no surface */
  content: ""; position: absolute; left: 0; right: 0; top: -12px; height: 12px;
}
.navdrop__menu a {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 12px; border-radius: 10px; color: var(--ink); opacity: 1;
  transition: background-color .18s ease;
}
.navdrop__menu a:hover, .navdrop__menu a:focus-visible { background-color: rgba(20, 18, 15, 0.05); }
.navdrop__menu b { font-weight: 600; font-size: 14.5px; }
.navdrop__menu span { font-size: 12.5px; line-height: 1.35; color: var(--text-muted); }
body.dark-world .navdrop__menu a { color: var(--d-bright); }
body.dark-world .navdrop__menu a:hover, body.dark-world .navdrop__menu a:focus-visible { background-color: rgba(236, 232, 222, 0.07); }
body.dark-world .navdrop__menu span { color: var(--d-muted); }
/* One pill, so the plate is a 6px frame around it rather than a bar holding a row —
   symmetric padding, and the negative margin still lands the pill on the page gutter. */
.nav__cta { margin-left: auto; display: flex; align-items: center; }
/* `.btn`'s `transition: background, border-color, color` was written for :hover, but it also
   catches the world flip and walks the pill through the grey between the two worlds: the fill
   lerps --teal-500 → --ink while the label lerps --ink-deep → --cream, which is grey-on-grey at
   the midpoint — 1.09:1 measured, at every desktop viewport, in BOTH directions, at BOTH
   crossings (hero→dark as well as dark→light), and on all nine pages. It snaps instead, with the
   plate behind it and with every other ink in the bar; the CTA's two buttons take the same cure
   for the same reason (`.cta .btn`). Price: the pill's hover fill snaps too. Its border-color is
   `transparent` in both worlds AND on hover — `.btn--dark:hover` only moves `background` — so
   `transition: none` and the CTA's `transition: border-color` are the same rule on this element;
   this one just says so, rather than easing a property that never changes. */
.nav__pill { padding: 10px 20px; font-size: 14px; transition: none; }
/* The burger is its own island: it already carries a visible outline in both worlds,
   so it takes the plate and the blur but keeps that border rather than the hairline. */
.nav__burger {
  display: none; margin-left: auto;
  border: 1px solid #C9C3B7; padding: 0 16px;
  cursor: pointer; font-family: var(--font-mono); font-size: 12px; color: var(--ink);
  align-items: center; justify-content: center;
}
/* The drawer is an island too — it hangs off a bar with no surface of its own, so it
   has to bring its own, and it takes the polarity with it. (It is near-opaque, not a
   62% tint: a menu is a surface you read a list on, not a frosting.) Before this it was
   a solid CREAM sheet with cream-world ink, which in the dark world was a white slab. */
.nav__mobile {
  display: none; flex-direction: column; gap: 2px;
  margin: 2px var(--pad) 12px; padding: 12px 16px 18px;
  border-radius: var(--r-menu); border: 1px solid var(--isl-line, var(--hairline));
  background-color: var(--menu-bg, var(--cream));
  backdrop-filter: var(--isl-blur, none); -webkit-backdrop-filter: var(--isl-blur, none);
}
body.dark-world { --menu-bg: rgba(19, 18, 17, 0.94); }
body.light-bottom { --menu-bg: rgba(251, 250, 244, 0.96); }
.nav__mobile.open { display: flex; }
/* 44px is the touch-target floor, and every row in the sheet is now a peer — the
   Network group heading and its three indented children are gone with the dropdown. */
.nav__mobile a { display: flex; align-items: center; min-height: 44px; padding: 10px 4px; font-size: 16px; font-weight: 500; color: var(--ink); }
.nav__mobile a.pill { justify-content: center; margin-top: 14px; background: var(--ink); color: var(--cream); padding: 13px 20px; border-radius: 999px; }
body.dark-world .nav__mobile a { color: var(--d-bright); }
body.dark-world .nav__mobile a.pill { background: var(--teal-500); color: var(--ink-deep); }

/* ============================================================
   HERO (§3.2) — light, opaque cream via #globe-cream
   ============================================================ */
.hero { position: relative; overflow: hidden; padding: 96px var(--pad) 88px; }
.hero__grid {
  position: relative; max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center;
}
/* The seal stands alone above the kicker — it is the emblem, not a bullet for a
   label. Rings inherit `color`, the check reads the inherited --seal-check, so
   the same <symbol> is legible in the cream world and in the dark one. */
.seal { color: var(--ink); --seal-check: var(--green); transition: color .45s; }
body.dark-world .seal { color: var(--d-bright); --seal-check: var(--mint); }
.hero__seal { margin-bottom: 24px; }
.hero__seal .seal { width: 64px; height: 64px; }
.hero__get { display: block; margin-bottom: 30px; color: var(--text-chip);
             text-transform: none; letter-spacing: 0.02em; font-size: 13px; }
.hero__get .net { color: var(--teal-ink); }
.hero h1 {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(40px, 5vw, 76px); line-height: 1.04;
  letter-spacing: -0.02em; color: var(--ink); margin: 0 0 26px;
}
.hero h1 em { font-style: italic; color: var(--teal-ink); }
.hero h1 .accent-amber { color: var(--amber-ink); }   /* #C27A00 — 3.06:1, AA-large on cream */
.hero__sub { font-size: 19px; line-height: 1.6; color: var(--text-body); max-width: 480px; margin: 0 0 38px; }
.hero__ctas { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 34px; }
.hero__ctas .btn { font-size: 15.5px; padding: 15px 28px; }
.hero__trust { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.05em; color: var(--text-muted); }
.rine-rise { animation: rine-rise .8s cubic-bezier(.22, .6, .2, 1) both; }
.rine-rise.d1 { animation-delay: .1s; }
.rine-rise.d2 { animation-delay: .22s; }
.rine-rise.d3 { animation-delay: .34s; }
.rine-rise.d4 { animation-delay: .46s; }

.hero__globe { position: relative; }
/* The globebox is also the drag hit-target (G↔C contract, item 2): pointer-events
   auto, physically covering the hero globe render area. Cursor classes are toggled
   on it by scroll.js (Track G). */
.hero__globebox { width: 100%; max-width: 560px; aspect-ratio: 1 / 1; margin: 0 auto; pointer-events: auto; touch-action: none; }
.hero__globebox.grab { cursor: grab; }
.hero__globebox.grabbing { cursor: grabbing; }
.hero__cap {
  text-align: center; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); margin-top: 14px;
}

/* ============================================================
   DARK NETWORK WORLD — shared section scaffolding (§3)
   ============================================================ */
.sec { padding: 140px var(--pad); scroll-margin-top: var(--nav-h); position: relative; }
.sec--dark { color: var(--d-bright); }
.sec--dark .eyebrow { color: var(--teal-300); }
.sec--dark h2 { font-family: var(--font-serif); font-weight: 400; font-size: clamp(34px, 4.2vw, 58px); line-height: 1.06; letter-spacing: -0.018em; margin: 0 0 20px; color: var(--d-bright); }
.sec--dark h2 em { font-style: italic; color: var(--teal-300); }
/* Local dark backing for text that sits directly over the globe world
   (not inside a panel/card) so contrast holds over any globe pixel (M3). A soft glow is all
   this needs: these sections never leave the dark world, so the glow only has to cover a
   passing globe line, and the ink already has ~9-15:1 on the world behind it.
   `.roles` is deliberately EXCLUDED (`:not`) — since round 5 it CROSSES, and a crossing
   section needs a plate, not a glow. Its halo is the block below. */
.sec--dark h2, .sec--dark:not(.roles) > .wrap > .eyebrow, .ledger .eyebrow, .statement .line,
.live__sub, .live__law, .dev__sub, .eco__head h2, .eco__head p, .dev .eyebrow, .live .eyebrow {
  text-shadow: 0 1px 16px rgba(10, 10, 12, 0.6), 0 0 3px rgba(10, 10, 12, 0.55);
}

/* THE ROLES CHAIN'S SMALL COPY — the densest text on the page that has to cross the theme
   boundary, at 12-16.5px, which owes 4.5:1. Mid-crossing the backdrop is a flat grey that
   caps ANY ink at ~4.3:1, and the soft glow above is worth almost nothing against it:
   measured, it left --d-body at 2.09:1 and the mint kicker at 2.43:1 at the worst point of
   the fade. Unreadable, and it is a scroll position you can come to rest on.

   So here the halo stops being a glow and becomes a PLATE. Stacked tight shadows composite
   (each is painted independently, so coverage is 1 - Π(1-a)) to near-opaque within ~3px of
   the glyph, which means the ink is read against ITS OWN WORLD'S SURFACE — --ink-deep here,
   --cream in the light world — instead of against the crossing. That is the same answer
   `.cta__sub` gives, and the only one that works: no colour choice survives the grey, so the
   grey has to be covered. It buys ~2 stops (see the measured table in AGENT_OUT_r5_transition).

   It SNAPS with the world class — deliberately absent from the .45s transition at the end of
   this file. A plate that lerped would walk the glyph through exactly the grey it exists to
   hide. Headings are the opposite case and keep the glow above: 34-72px rides the crossing on
   the 3:1 large-text bar, and a plate that heavy behind a 58px serif would read as a smudge. */
.roles .eyebrow, .roles .rstation__kicker, .roles .rstation p, .roles .rstation__more {
  text-shadow: 0 0 3px rgba(19, 18, 17, 0.85), 0 0 3px rgba(19, 18, 17, 0.85),
               0 0 6px rgba(19, 18, 17, 0.80), 0 1px 18px rgba(19, 18, 17, 0.70);
  --plate: var(--ink-deep);
}
/* The glyph EDGE is where the stacked glow still loses — a gaussian is ~50% covered there,
   which is why the cream side of the plate stalled at 2.6:1 on the teal accent with the glow
   alone (cream is a long luminance climb: a dark ink needs its backdrop pulled ~0.88 up, not
   0.18 down). A stroke is not a gaussian. `paint-order: stroke fill` lays 1px of the world's
   OWN SURFACE COLOUR around every glyph and then puts the fill back on top, so the letterform
   keeps its weight and gains a hard, opaque ring exactly where the fade was showing through.
   At both resting ends the ring is the colour of the page and is invisible; it only does work
   in the grey — the same trick, and the same reason, as `.cta__sub`'s plate.
   The stroke is centred on the outline, so 2px buys 1px OUTWARD, and that is the whole ring:
   at 1px (0.5px outward) the anti-aliasing eats it and the crossing comes straight back
   (measured on the CTA button: 2.75-4.35:1, i.e. no better than no ring at all). Not heavier
   than 2px either — the outward half starts closing the counters on 12px mono. Behind @supports
   because a browser without `paint-order` would paint the stroke OVER the fill and hollow the
   text out — a worse defect than the one this fixes.
   `.cta .btn--outline` is on this list for exactly the same reason (see CTA): it is the only
   other ink on the page that crosses the boundary with no surface under it. */
@supports (paint-order: stroke) {
  .roles .eyebrow, .roles .rstation__kicker, .roles .rstation p, .roles .rstation__more,
  .cta .btn--outline {
    paint-order: stroke fill;
    -webkit-text-stroke: 2px var(--plate);
  }
  /* The reduced path stands `.roles` and the CTA on a SOLID cream block and zeroes every halo on
     the page. There is no crossing left to cover there, and `--plate` would still be resolving to
     the DARK surface (nothing sets `light-bottom` on that path — no scroll controller runs), i.e.
     an ink-deep ring around ink-coloured text. The ring comes off with the halos. */
  html.reduced .roles .eyebrow, html.reduced .roles .rstation__kicker,
  html.reduced .roles .rstation p, html.reduced .roles .rstation__more,
  html.reduced .cta .btn--outline {
    -webkit-text-stroke-width: 0;
  }
}

html.reduced .sec--dark h2, html.reduced .statement .line, html.reduced .live__sub,
html.reduced .live__law, html.reduced .dev__sub, html.reduced .eco__head h2, html.reduced .eco__head p,
html.reduced .sec--dark .eyebrow, html.reduced .rstation__kicker,
html.reduced .rstation p, html.reduced .rstation__more { text-shadow: none; }

/* Reveal (§3 staggered fade-in) */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .85s cubic-bezier(.22, .6, .2, 1), transform .85s cubic-bezier(.22, .6, .2, 1); }
.reveal.is-visible { opacity: 1; transform: none; }

/* STATEMENT (§3.3) */
.statement .wrap { max-width: 1100px; }
.statement .eyebrow { margin-bottom: 36px; }
.statement .line { font-family: var(--font-serif); font-weight: 400; font-size: clamp(34px, 4.6vw, 64px); line-height: 1.14; letter-spacing: -0.018em; }
.statement .line1 { color: var(--cream); }
.statement .line2 { color: var(--d-muted); }
.statement .line3 { font-style: italic; color: var(--teal-300); }

/* Panels/cards over the globe world */
.panel { background: var(--panel); border: 1px solid var(--d-hairline); border-radius: var(--r-card); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.panel-raised { background: var(--panel-raised); border: 1px solid var(--d-hairline); border-radius: var(--r-card); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }

/* SIX GUARANTEES (round 7) — the section title IS the index, and the six guarantees are
   cream "paper" cards floating over the dark globe. See phases/biz-homepage/ROUND7.md.

   TWO LAYOUTS, ONE MARKUP. Baseline (no `.is-enhanced` — the no-JS, reduced-motion and
   mobile paths) is six stacked, fully-visible cards under a real <h2>. The enhanced path
   pins the stage and shows one card at a time, cross-faded, as SCROLL names the active card.
   Everything the enhanced layout needs is scoped under `.ledger.is-enhanced`, so the moment
   that class is absent the page falls back to a plain, keyboard-clean stack. */
.ledger .eyebrow { margin-bottom: 22px; }
/* Six words no longer fit one line at 1440 — balance the wrap (3 + 3) so the second line
   reads as a chosen couplet, not a dangling last word. */
.ledger__title { margin-bottom: 40px; text-wrap: balance; }
/* The index words are the <h2> itself (`.sec--dark h2` gives the serif + the crossing halo,
   which the words inherit). Interactivity is added only when enhanced, so a no-JS reader just
   sees the section title. */
.ledger.is-enhanced .lx { color: var(--d-muted); cursor: pointer; border-radius: 4px;
                          transition: color .4s ease; -webkit-tap-highlight-color: transparent; }
.ledger.is-enhanced .lx:hover { color: var(--d-bright); }
.ledger.is-enhanced .lx.is-active { color: var(--teal-300); }
.ledger.is-enhanced .lx[data-band="gdpr"].is-active,
.ledger.is-enhanced .lx[data-band="aiact"].is-active { color: var(--amber-300); }

/* THE CARD — opaque cream (never a backdrop-filter: an opaque surface is free, a blurred one
   re-runs under every compositor frame — see the round-5 diet). It reads on its OWN cream
   surface, so the flat-cream text ramp applies at full margin. Per-card `--accent` (teal for
   identity/messaging/delivery, amber for the two --signal guarantees) tints only large text
   and the 24px marks; small mono tags stay neutral, where amber would fail AA. */
.ledger__cards { position: relative; }
.lcard {
  max-width: 620px; margin: 0 0 26px; padding: 26px 32px 22px;
  background: var(--cream-raised); border: 1px solid var(--hairline); border-radius: var(--r-card);
  box-shadow: 0 30px 60px -34px rgba(0, 0, 0, 0.55), 0 2px 10px -6px rgba(0, 0, 0, 0.35);
}
.lcard--l { margin-right: auto; }   /* baseline zig-zag: odd cards hug left, even hug right */
.lcard--r { margin-left: auto; }
/* Kicker is 11px = normal text, so it owes 4.5:1. `--accent-text` is the accent's AA-normal
   cream member: unset on teal cards (--teal-ink already clears it at 4.9:1), set to
   --amber-ink-deep on the signal cards where --amber-ink would fail. Marks below stay on the
   brighter --accent — they are graphics (3:1). */
.lcard__sub { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
              text-transform: uppercase; color: var(--accent-text, var(--accent)); margin-bottom: 10px; }
.lcard__hi { font-size: 16px; line-height: 1.45; font-weight: 500; color: var(--text-ink);
             max-width: 52ch; margin: 0 0 4px; }

/* Rows: the same real doc links, re-inked for the cream surface. Padding and leading are held
   tight so the six-row `messaging` card — the tallest — fits the pinned stage at 1440×900. The
   ↗ on the tag is always laid out and only changes opacity, so it can never reflow the row. */
.lrow {
  display: grid; grid-template-columns: 26px 1fr auto; gap: 0 16px;
  align-items: start; padding: 12px 0; border-top: 1px solid var(--hairline);
}
.lcard__rows { margin-top: 6px; }
.lrow__mark { display: flex; align-items: flex-start; justify-content: center; padding-top: 2px; }
.lmark { width: 24px; height: 24px; color: var(--accent); }
.lrow__body { min-width: 0; }
.lrow__name { font-size: 15px; color: var(--text-ink); margin-bottom: 2px; }
.lrow__name b { font-weight: 600; }
.lrow__name span { color: var(--text-muted); font-weight: 400; }
.lrow__sentence { font-size: 14px; line-height: 1.45; color: var(--text-body); max-width: 60ch; }
.lrow__tag { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-chip);
             white-space: nowrap; padding-top: 2px; }
a.lrow:is(:hover, :focus-visible) .lrow__name b { text-decoration: underline; text-underline-offset: 3px; }
a.lrow .lrow__tag::after { content: " ↗"; opacity: 0; transition: opacity .3s; color: var(--accent); }
a.lrow:is(:hover, :focus-visible) .lrow__tag::after { opacity: 1; }

/* ---- ENHANCED: the pinned scroll-stage ---- */
/* The section becomes a tall track; `.ledger__stage` sticks below the nav for the whole
   track. JS reads scrollY off the track to name the active card and toggles `.is-active`;
   the pin itself is pure CSS. Card height is capped to the stage so nothing spills below the
   fold, with `overflow-y:auto` as the safety valve for the tallest card on a short window. */
.ledger.is-enhanced { --l-stage: calc(100svh - var(--nav-h)); --l-step: 56svh;
                      padding: 0; height: calc(var(--l-stage) + 6 * var(--l-step)); }
.ledger.is-enhanced .ledger__stage {
  position: sticky; top: var(--nav-h); height: var(--l-stage);
  display: flex; flex-direction: column; justify-content: center; padding: 14px 0; overflow: hidden;
}
.ledger.is-enhanced .eyebrow { margin-bottom: 12px; }
/* width:100% is load-bearing: these two are `.wrap`s (margin-inline:auto), and an auto cross
   margin DISABLES a flex item's stretch — so without an explicit width `.ledger__cards`, whose
   children are all absolute, collapses to its horizontal padding and the card's `min(…,100%)`
   resolves against ~80px. An explicit width gives it a definite box the auto margins just centre. */
.ledger.is-enhanced .ledger__head { flex: none; width: 100%; }
.ledger.is-enhanced .ledger__title { margin-bottom: 0; }
.ledger.is-enhanced .ledger__cards { flex: 1 1 auto; min-height: 0; margin-top: 12px; width: 100%; }
/* Every enhanced card sits on ONE centred axis — horizontally AND vertically — and
   cross-fades in place; no left/right hug. The baseline zig-zag (`.lcard--l/--r` margins
   above) is a stack affordance only; the pinned stage overrides it so a fixed centre carries
   the eye card to card. Vertical centring (top:50% + translateY(-50%)) is what keeps the
   stage from reading as a small card welded under the title with dead air below: whatever
   the card's height, the air splits evenly around it. Motion is a quiet vertical rise
   (a whisper up + fade), which the varying card sizes never disturb, because the centre
   never moves. The pinned card also scales UP from the baseline stack — wider box, larger
   highlight and row type — because on the pinned stage one card owns the whole viewport,
   where the baseline sizes were tuned for five-in-a-column reading. */
.ledger.is-enhanced .lcard {
  position: absolute; top: 50%; left: 50%; width: min(640px, 100%); margin: 0;
  max-width: none;              /* the baseline stack's 620px cap would clamp both widths here */
  padding: 34px 42px 28px;
  max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, calc(-50% + 24px));
  transition: opacity .5s ease, transform .55s cubic-bezier(.22, .61, .36, 1), visibility 0s linear .55s;
}
.ledger.is-enhanced .lcard__hi { font-size: 19px; line-height: 1.5; max-width: 54ch; margin-bottom: 8px; }
.ledger.is-enhanced .lcard__rows { margin-top: 10px; }
.ledger.is-enhanced .lrow { padding: 15px 0; }
.ledger.is-enhanced .lrow__name { font-size: 16px; }
.ledger.is-enhanced .lrow__sentence { font-size: 15px; }
/* `messaging` carries six standards — twice any other card. Rather than shrink every card's
   type to make its worst case clear the pinned fold at 1440×900, the one dense card goes wide
   and lays its rows in two columns (three tracks tall), which fits with room to spare. The tag
   drops beneath the row body at this width. Baseline (mobile/reduced) keeps the single column. */
.ledger.is-enhanced .lcard--wide { width: min(880px, 100%); }
.ledger.is-enhanced .lcard--wide .lcard__rows { display: grid; grid-template-columns: 1fr 1fr; column-gap: 34px; }
.ledger.is-enhanced .lcard--wide .lrow { grid-template-columns: 26px 1fr; }
.ledger.is-enhanced .lcard--wide .lrow__tag { grid-column: 2; justify-self: start; padding-top: 3px; }
.ledger.is-enhanced .lcard.is-active {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, -50%);
  transition: opacity .5s ease, transform .55s cubic-bezier(.22, .61, .36, 1);
}

/* LIVE CONVERSATION (§3.5) */
.live .eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 22px; }
.live .eyebrow .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--mint); animation: rine-pulse 1.8s ease-in-out infinite; }
.live__sub { font-size: 18px; line-height: 1.6; color: var(--d-body); max-width: 620px; margin: 0 0 32px; }

/* Three interaction types, all live at once (item 4) — drawn as ONE ruled sheet in
   three columns, not as three floating cards (item 6, round 4). The lexicon is the
   page's own: the roles chain next door is already a composition of accent rules and
   columns rather than boxes, and the ledger above is ruled paper. So: no radius, no
   outline, no gap — a hairline between the columns, an accent rule at the head of each,
   a wash of that accent falling out of it, and a foot rule over the routing line.
   The three accents ARE the three role accents, because that is what the three
   exchanges are: org↔org, a principal reaching a business, a mesh of agents.
   The COLUMNS run edge to edge of the content column — that is the sheet. The CONTENT
   is inset from them by the same --lp-inset in all three, so the hairline between two
   columns always has the same air on either side of it. (Round 4 zeroed the outer
   columns' outer padding to line their copy up with the h2 above; the cost was that the
   left card's text was welded to the left edge of the page and the right card's to the
   right, while only the middle one was framed. One of those two alignments has to give,
   and a card whose copy touches its own edge is the one that reads as a defect.) */
.live__grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; align-items: stretch;
  margin-top: 10px; border-bottom: 1px solid var(--d-hairline); counter-reset: lp;
}
/* A surface, not a frosting — see the note above `--isl-bg`. These three cards used to
   be a 72% tint over a blur(6px), and that blur was 80 of the section's 113 CPU points:
   every compositor frame re-runs a backdrop-filter in full, so ONE packet animating over
   the glass re-blurred all three cards 60x/s. The tint is `--ink-card` at full opacity —
   the identical colour, so the cards read the same — and the globe now passes behind them
   sharp instead of smoothed. `--panel-raised` is deliberately not used here: at 0.72 alpha
   a bright limb line shines straight through once the blur is gone. */
.lp {
  --lp-inset: 26px;
  position: relative; counter-increment: lp;
  display: flex; flex-direction: column; padding: 26px var(--lp-inset) 18px;
  background-color: var(--ink-card);
  background-image: linear-gradient(180deg, color-mix(in srgb, var(--lp-accent) 11%, transparent) 0%, transparent 44%);
}
.lp--b2b { --lp-accent: var(--role-org); }
.lp--p2b { --lp-accent: var(--role-prin); }
.lp--group { --lp-accent: var(--role-agent); }
.lp + .lp { border-left: 1px solid var(--d-hairline); }
.lp::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
              background: var(--lp-accent); opacity: .85; }
.lp__head { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.16em;
            text-transform: uppercase; color: var(--lp-accent); margin-bottom: 12px; }
.lp__head::before { content: counter(lp, decimal-leading-zero) " · "; color: var(--d-muted); }
/* Fixed boxes: the panel must not change height between vignettes, at any width, however
   the caption or the routing line wraps. Every box above the log is fixed, so the log's
   height is `body − those` — and the body is sized FOR the log, not the other way round.
   At 268px the 1:1 log measured 66px, which is one bubble: a four-turn conversation was
   playing out inside a slot that could show one line of it, under a mask that dissolved
   whatever the graph above did not already crowd out. 402px gives the log ~200px — the
   last three turns, legibly, with the mask doing what it is for (softening what leaves
   the top) instead of eating the exchange. The panel is ~135px taller for it; the whole
   section exists to be read, so that is the trade. */
.lp__cap { font-size: 14.5px; line-height: 1.45; color: var(--d-bright); margin: 0 0 16px;
           height: 63px; overflow: hidden; }
.lp__body { height: 402px; overflow: hidden; display: flex; flex-direction: column; gap: 8px; }
.lp__foot { margin-top: auto; padding-top: 12px; height: 48px; overflow: hidden;
            border-top: 1px solid var(--d-hairline);
            font-family: var(--font-mono); font-size: 11px; line-height: 1.5; color: var(--d-muted); }
.lp__foot.is-ok { color: var(--mint); }
.lp__foot.is-amber { color: var(--amber-300); }
/* Bottom-anchored: older lines scroll out of the top instead of growing the panel, and the
   mask fades them out rather than slicing them. The bottom padding is the log's own gutter
   against the foot rule below it — with the body's box ending exactly on that rule, the
   newest bubble was sitting ON the separator. Nothing on this sheet touches a rule. */
.lp__log { flex: 1; min-height: 0; display: flex; flex-direction: column;
           justify-content: flex-end; gap: 6px; overflow: hidden; padding-bottom: 12px;
           -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 22px);
           mask-image: linear-gradient(180deg, transparent 0, #000 22px); }
.lp__log .athink { align-self: flex-start; }
.lp__log .athink--sent { align-self: flex-end; }

/* 1:1 — the two parties, and the wire between them with rine on it.
   One radius rule across the sheet (item 6): the CONTAINERS are crisp plates, and only
   the two things that are not containers stay round — the rine node, which is the brand
   token sitting on the wire, and the bubbles, which are utterances. */
.lpc { display: flex; flex-direction: column; gap: 3px; padding: 8px 12px; border-radius: 3px;
       border: 1px solid var(--d-hairline); background: rgba(244, 241, 233, 0.04);
       transition: border-color .3s, box-shadow .3s; }
.lpc.is-active { border-color: var(--teal-400); box-shadow: 0 0 18px -6px rgba(0, 224, 200, 0.5); }
.lpc__h { font-family: var(--font-mono); font-size: 13px; color: var(--teal-300); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lpc__s { font-family: var(--font-mono); font-size: 10.5px; color: var(--mint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lpw { position: relative; height: 74px; flex: none; }
.lpw::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 2px;
               transform: translateX(-50%);
               background: repeating-linear-gradient(180deg, rgba(138, 134, 125, 0.4) 0 5px, transparent 5px 10px); }
.lpw__pkt { position: absolute; left: 50%; top: 0; width: 9px; height: 9px; margin-left: -4.5px;
            border-radius: 50%; background: var(--teal-300);
            box-shadow: 0 0 12px rgba(51, 245, 221, 0.9); opacity: 0; }
.lpw__node { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
             display: flex; align-items: center; gap: 8px; white-space: nowrap;
             font-family: var(--font-mono); font-size: 11px; color: var(--d-bright);
             background: var(--ink); border: 1px solid rgba(0, 224, 200, 0.28); border-radius: 999px;
             padding: 6px 12px; transition: border-color .3s, box-shadow .3s; }
.lpw__node.is-hit { border-color: rgba(0, 224, 200, 0.75); box-shadow: 0 0 26px -8px rgba(0, 224, 200, 0.6); }
/* The lamp's suffix is always laid out (only its opacity changes), so lighting a
   lamp can never reflow the pill it sits in. */
.lpw__lamp { color: var(--d-muted); transition: color .3s; }
.lpw__lamp::after { opacity: 0; transition: opacity .3s; }
.lpw__lamp[data-lamp="sig"]::after { content: " ✓"; }
.lpw__lamp[data-lamp="enc"]::after { content: " ▓▓▓▓"; }
.lpw__lamp.on::after { opacity: 1; }
.lpw__lamp.on[data-lamp="sig"] { color: var(--mint); }
.lpw__lamp.on[data-lamp="enc"] { color: var(--ember); }

/* Groups — one channel bar, three connectors, three members: a post fans out to
   all of them at once. The connectors and the chips share one 3-column grid, so
   they line up by construction (no geometry maths, no runtime measurement). */
/* Two fixed rows — channel + member count, then the lamps — so a long channel
   name can never rewrap the bar into a different height. */
.lpch { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 5px 10px;
        padding: 8px 12px; border-radius: 3px; font-family: var(--font-mono); font-size: 11px;
        border: 1px solid rgba(0, 224, 200, 0.28); background: var(--ink); color: var(--d-bright);
        transition: border-color .3s, box-shadow .3s, color .3s; }
.lpch__h { font-size: 13px; color: var(--teal-300); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lpch__n { color: var(--d-muted); justify-self: end; white-space: nowrap; }
.lpch__lamps { grid-column: 1 / -1; display: flex; gap: 10px; }
.lpch.is-hit { border-color: rgba(0, 224, 200, 0.75); box-shadow: 0 0 26px -8px rgba(0, 224, 200, 0.6); }
.lpch.is-bcast { border-color: var(--amber-400); box-shadow: 0 0 30px -8px rgba(255, 184, 20, 0.55); }
.lpch.is-bcast .lpch__h { color: var(--amber-300); }
.lpbus, .lpm { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.lpbus { height: 44px; flex: none; }
.lpstub { position: relative; }
.lpstub::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 2px;
                  transform: translateX(-50%);
                  background: repeating-linear-gradient(180deg, rgba(138, 134, 125, 0.4) 0 5px, transparent 5px 10px); }
.lpstub__pkt { position: absolute; left: 50%; top: 0; width: 8px; height: 8px; margin-left: -4px;
               border-radius: 50%; background: var(--teal-300);
               box-shadow: 0 0 12px rgba(51, 245, 221, 0.9); opacity: 0; }
.lpm__chip { display: flex; flex-direction: column; gap: 2px; padding: 7px 8px; border-radius: 3px;
             border: 1px solid var(--d-hairline); background: rgba(244, 241, 233, 0.04);
             font-family: var(--font-mono); font-size: 11px; min-width: 0;
             transition: border-color .3s, background .3s, box-shadow .3s; }
.lpm__chip b { font-weight: 500; color: var(--d-bright); }
.lpm__chip span { color: var(--teal-300); }
.lpm__chip b, .lpm__chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lpm__chip.is-lit { border-color: var(--teal-400); background: rgba(0, 224, 200, 0.12);
                    box-shadow: 0 0 18px -6px rgba(0, 224, 200, 0.5); }
.lpm__chip.is-amber { border-color: var(--amber-400); background: rgba(255, 184, 20, 0.12);
                      box-shadow: 0 0 18px -6px rgba(255, 184, 20, 0.55); }
.lpm__chip.is-amber b, .lpm__chip.is-amber span { color: var(--amber-300); }

/* Message log (shared by all three panels) */
.bubble { max-width: 88%; padding: 9px 13px; border-radius: 12px; font-size: 13.5px; line-height: 1.5; animation: rine-feed-in .45s both; }
.bubble--sent { align-self: flex-end; background: rgba(0, 224, 200, 0.12); border: 1px solid rgba(0, 224, 200, 0.34); color: var(--d-bright); border-bottom-right-radius: 4px; }
.bubble--recv { align-self: flex-start; background: rgba(244, 241, 233, 0.05); border: 1px solid var(--d-hairline); color: #C9C3B7; border-bottom-left-radius: 4px; }
.bubble--chip { align-self: flex-start; font-family: var(--font-mono); font-size: 11px; color: var(--mint); padding: 2px 0; }
.clog { align-self: flex-start; max-width: 96%; padding: 8px 12px; border-radius: 12px; border-bottom-left-radius: 4px; font-size: 13px; line-height: 1.45; background: rgba(244, 241, 233, 0.05); border: 1px solid var(--d-hairline); color: #C9C3B7; animation: rine-feed-in .45s both; }
.clog b { font-family: var(--font-mono); font-size: 11px; font-weight: 500; color: var(--teal-300); display: block; margin-bottom: 3px; }
.clog--amber { border-color: rgba(255, 184, 20, 0.34); background: rgba(255, 184, 20, 0.08); }
.clog--amber b { color: var(--amber-300); }

/* The section's thesis, once, full width, beneath the three panels */
.live__law { font-family: var(--font-serif); font-size: clamp(19px, 2.1vw, 26px); line-height: 1.4;
             color: var(--d-bright); max-width: 860px; margin: 34px 0 10px; }
.live__law b { font-weight: 400; color: var(--teal-300); }
.live__law .ok { color: var(--mint); }
.live__law .enc { color: var(--ember); }
.live__foot { margin-top: 10px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--d-muted); }

/* DEVELOPERS (§3.6) */
.dev .split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }
.dev .eyebrow { margin-bottom: 22px; }
.dev h2 { font-size: clamp(34px, 4.2vw, 56px); }
.dev__sub { font-size: 18px; line-height: 1.6; color: var(--d-body); max-width: 460px; margin: 0 0 30px; }
.dev__steps { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 38px; }
.dev__step { font-family: var(--font-mono); font-size: 12.5px; color: var(--d-body); background: var(--panel-raised); border: 1px solid var(--d-hairline); border-radius: 999px; padding: 8px 16px; }
.dev__step em { font-style: normal; color: var(--teal-300); }
.dev__ctas { display: flex; gap: 14px; flex-wrap: wrap; }
.dev__ctas .btn { font-size: 15px; padding: 13px 24px; }
.term { background: var(--ink); border: 1px solid var(--d-hairline); border-radius: var(--r-card); overflow: hidden; box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.6); }
.term__bar { display: flex; align-items: center; gap: 8px; padding: 16px 22px; border-bottom: 1px solid var(--d-hairline); }
.term__bar .l { width: 11px; height: 11px; border-radius: 50%; }
.term__bar .l1 { background: var(--ember); }
.term__bar .l2 { background: var(--amber-500); }
.term__bar .l3 { background: var(--mint); }
.term__bar .name { margin-left: 12px; font-family: var(--font-mono); font-size: 12px; color: var(--d-muted); }
.term__body { padding: 28px 26px; font-family: var(--font-mono); font-size: 13.5px; line-height: 1.95; color: #C9C3B7; min-height: 270px; }

/* Agentic session (item 12) */
.term__body.agent { display: flex; flex-direction: column; gap: 4px; }
.aline { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; opacity: 0; transition: opacity .3s; }
.aline.show { opacity: 1; }
.aline--head { color: var(--d-bright); margin-top: 2px; }
.aline--head .glyph { width: 9px; height: 9px; border-radius: 50%; background: var(--teal-400); box-shadow: 0 0 10px rgba(0, 224, 200, 0.7); animation: rine-pulse 2s ease-in-out infinite; align-self: center; }
.aline--head .goal { color: var(--teal-300); }
.aline--tool { padding-left: 18px; }
.aline--tool .arrow { color: var(--d-muted); }
.aline--tool .call { color: var(--d-bright); }
.aline--tool .args { color: var(--teal-300); }
.aline--tool .res { color: var(--mint); }
.aline--done { color: var(--mint); margin-top: 6px; font-weight: 500; }
.athink { display: inline-flex; gap: 4px; align-items: center; color: var(--d-muted); }
.athink span { width: 4px; height: 4px; border-radius: 50%; background: currentColor; animation: rine-tdot 1s infinite; }
.athink span:nth-child(2) { animation-delay: .15s; }
.athink span:nth-child(3) { animation-delay: .3s; }

/* ECOSYSTEM (§3.7) */
.eco { padding: 110px 0 120px; scroll-margin-top: var(--nav-h); }
.eco__head { max-width: var(--maxw); margin: 0 auto 52px; padding: 0 var(--pad); display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.eco__head h2 { font-size: clamp(30px, 3.6vw, 48px); margin: 0 0 18px; }
.eco__head p { font-size: 17.5px; line-height: 1.6; color: var(--d-body); margin: 0; max-width: 760px; }
.eco__link { font-weight: 500; font-size: 16px; color: var(--teal-300); white-space: nowrap; }
.eco__mask { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.eco__track { display: flex; gap: 14px; width: max-content; animation: rine-marquee 36s linear infinite; }
.eco__pill { display: inline-flex; align-items: center; gap: 10px; background: var(--panel-raised); border: 1px solid var(--d-hairline); border-radius: 999px; padding: 8px 18px 8px 9px; font-family: var(--font-mono); font-size: 14px; color: var(--d-body); white-space: nowrap; transition: border-color .25s, transform .25s; }
.eco__pill:hover { border-color: var(--brand, var(--teal-400)); transform: translateY(-2px); opacity: 1; }
/* Official icon (item 7): neutral tile, glyph carries the brand color via --brand */
.eco__badge { width: 27px; height: 27px; border-radius: 8px; background: rgba(255, 255, 255, 0.04); color: var(--brand, var(--teal-300)); display: inline-flex; align-items: center; justify-content: center; flex: none; }
.eco__badge svg { width: 18px; height: 18px; display: block; }

/* WHO JOINS (item 13) — color-differentiated chain composition, no cards */
.roles h2 { margin-bottom: 52px; }
.roles .eyebrow { margin-bottom: 22px; }
.roles__chain { display: flex; align-items: flex-start; gap: 0; }
/* The fallback accent is the NEUTRAL role token, not a raw teal: every accent in this chain
   has to resolve in both worlds now, and a hardcoded --teal-400 default would be a 1.5:1
   invisible on cream the day someone adds a fourth station. No station is unmodified today. */
.rstation { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; --accent: var(--role-org); }
.rstation--org { --accent: var(--role-org); }
.rstation--prin { --accent: var(--role-prin); }
.rstation--agent { --accent: var(--role-agent); }
.rstation__node { width: 14px; height: 14px; border-radius: 50%; margin-bottom: 20px; background: var(--accent); flex: none; }
.rstation--prin .rstation__node { background: var(--ink-deep); border: 2.5px solid var(--role-prin); }
.rstation__seg { flex: 0 0 60px; align-self: flex-start; margin-top: 6px; height: 2px; background: repeating-linear-gradient(90deg, var(--role-seg) 0 6px, transparent 6px 12px); background-size: 24px 2px; animation: rine-march 1.2s linear infinite; }
.rstation__block { display: flex; flex-direction: column; border-top: 2px solid var(--accent); padding: 20px 28px 0 0; transition: opacity .3s; }
.rstation__block:hover { opacity: 1; }
.rstation__kicker { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); margin-bottom: 16px; }
.rstation p { font-size: 16.5px; line-height: 1.58; color: var(--d-body); margin: 0 0 26px; flex: 1; }
.rstation__more { font-family: var(--font-mono); font-size: 13px; color: var(--accent); }
.rstation__block:hover .rstation__more { text-decoration: underline; text-underline-offset: 3px; }

/* FINAL CTA (§3.9) — the bottom cream world is the hero inversed, and like the hero
   it OWNS A FULL VIEWPORT. This is load-bearing, not decoration. The cream ramp is
   anchored to the top edge of the bottom region (`.roles` since round 5 — scroll.js),
   and that edge can only travel far enough to complete the ramp if the region below it
   is taller than the screen. When the CTA was content-height (~740px), a viewport taller
   than `ctaH + footerH - outPad` could never bring the anchor's top edge up to the ramp's
   start, so the page came to rest fully dark: the cream bottom simply did not happen above
   ~1286px. The region now carries `.roles` as well, so it clears the screen by a wide
   margin at every viewport — but this min-height is still what puts the floor under it,
   and shrinking it back to content height would put the degrade one long viewport away.
   Content is centred in the stage, so the height it gains is never a void below the copy. */
.cta {
  min-height: 100vh;
  min-height: 100svh;   /* svh, not dvh: a stage that resizes under a retracting mobile
                           toolbar would move the very anchors the ramp is measured against. */
  display: flex; flex-direction: column; justify-content: center;
  padding: 150px var(--pad); text-align: center; scroll-margin-top: var(--nav-h);
}
.cta .wrap { max-width: 960px; }
.cta__seal { width: 112px; height: 112px; margin: 0 auto 36px; }
.cta h2 { font-family: var(--font-serif); font-weight: 400; font-size: clamp(38px, 5.2vw, 72px); line-height: 1.05; letter-spacing: -0.02em; margin: 0 0 40px; color: var(--d-bright); }
.cta h2 em { font-style: italic; color: var(--teal-300); }
.cta__ctas { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-bottom: 28px; }
.cta__ctas .btn { font-size: 16px; padding: 16px 32px; }
/* "Talk to the team" is the last ink on the page with no surface of its own. `.btn--dark` is an
   opaque pill and `.cta__sub` carries an opaque plate; the outline button is 16px of type on a
   transparent box — which is the CTA's whole point, the globe shows THROUGH it — so it is the one
   element still read against the crossing itself, where the half-mixed backdrop caps any ink at
   ~4.3:1. Measured across the whole band, not just at its edge: sub-AA from pTheme .60 all the way
   down to the flip — worst 2.39:1 descending / 2.75:1 ascending at 1440x1600, and 1.41 / 2.42 at
   1440x2160. (At 1440x900 and on mobile the CTA does not reach the screen until the fade is over,
   which is the only reason this was ever survivable.)
   The instrument is the roles chain's, for the same reason and with the same 2px: a hard ring of
   the world's own surface colour under the glyph (see the @supports block above), so the label is
   read against ink-deep or cream instead of against the grey between them. It measures 15.29:1 at
   EVERY point of the fade, both directions, with min = p05 — every glyph pixel lands on the ring.
   An opaque fill measures identically and was rejected on the axis that decides it. Against a
   frozen-globe oracle (the only kind that works — two page loads never show the same globe) the
   ring moves 0.01% of the button's pixels in the full dark world and 0-0.15% in the cream one; the
   fill moves 0.55% and 4.6% at those same two, and 27% at the tall-desktop stop where the button
   first appears. Filling the pill is the same act as deleting the globe behind it, and the globe
   showing through IS the design. No halo either: the ring already puts every glyph pixel on the
   surface, so a stacked plate on top measures 15.46 — paint with nothing left to do, at double
   the cost to the resting look. */
.cta .btn--outline { --plate: var(--ink-deep); }
/* The one line on the page whose ink and whose backdrop cross polarity at the same
   moment. 13px, so its bar is 4.5:1 — and mid-crossing the half-mixed backdrop caps
   what ANY ink can reach at 4.79:1 (pure white) / 4.38:1 (pure black), so no colour
   choice survives the fade. The line therefore carries its own OPAQUE plate and is
   read against that, never against the crossing. Plate and ink both snap with the
   world class (they are deliberately absent from the .45s colour transition below):
   a lerp would walk the plate through the same grey the backdrop is walking through.
   Each plate is its own world's surface colour, so at both resting ends the plate is
   invisible against the page and only the halo-through-the-globe effect remains. */
.cta__sub {
  display: inline-block; max-width: 100%;
  font-family: var(--font-mono); font-size: 13px; line-height: 1.55;
  color: var(--d-body); background: var(--ink-deep);
  padding: 11px 18px; border-radius: var(--r-chip);
}
.cta__sub a { color: var(--teal-300); }

/* FOOTER (§3.10) */
.footer {
  background: var(--ink-deep); color: var(--cream);
  padding: 72px var(--pad) 48px; position: relative; z-index: 3;
  --trim-a: var(--teal-400); --trim-b: var(--amber-400);
}
/* The trim (item 4): a single hairline across the top edge, primary → secondary. It IS
   the footer's border — the plain hairline the cream footer used to carry is gone, so
   there is one line, not two. Each world takes the member of the teal/amber ramp that
   reads on it (the bright pair on ink, the ink pair on cream, `--amber-ink` being the
   only gold that clears 3:1 there), so the trim is equally present in both. */
.footer::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: linear-gradient(90deg, var(--trim-a) 0%, var(--trim-b) 100%);
}
/* Brand block + five columns. The column gap is tighter than the row gap because six
   tracks in the content column leave ~165px each at 1440 — enough for the longest label
   ("All integrations"), and nothing to spare. From the tablet breakpoint down the brand
   takes a row of its own: its paragraph is 280px wide, and letting it compete for a track
   is what squeezes a link column into a two-words-per-line ladder. */
.footer__grid { display: grid; grid-template-columns: 1.6fr repeat(5, 1fr); gap: 44px 32px; margin-bottom: 56px; }
.footer__brand a { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.footer__brand svg { width: 26px; height: 26px; color: var(--teal-300); }
/* The clip/fill half of this lives with `.nav__wordmark` (item 10) — the footer only
   names the polarity it opens in: the ink-deep world. */
.footer__brand .wordmark { font-size: 21px; font-weight: 700; letter-spacing: -0.02em; --wm-grad: var(--wm-dark); }
.footer__brand p { font-size: 14.5px; line-height: 1.6; color: var(--d-muted); max-width: 280px; margin: 0; }
.footer__col h3 { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--d-muted); margin: 0 0 16px; font-weight: 400; }
.footer__col .links { display: flex; flex-direction: column; gap: 11px; font-size: 14.5px; color: var(--text-muted); }
.footer__col .links a:hover { color: #fff; opacity: 1; }
.footer__note { font-family: var(--font-mono); font-size: 11.5px; line-height: 1.7; color: var(--d-muted); margin-top: 16px; }
.footer__note a { color: var(--teal-300); }
.footer__bar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; padding-top: 28px; border-top: 1px solid rgba(138, 134, 125, 0.12); font-size: 13px; color: var(--d-muted); }
.footer__bar .links { display: flex; gap: 22px; }
.footer__bar .links a:hover { color: var(--text-muted); opacity: 1; }

/* ============================================================
   LIGHT BOTTOM (item 6; boundary moved in round 5) — the cream world returns for
   `.roles`, the final CTA and the footer, the hero inversed. `body.light-bottom` is
   set by the scroll controller; `html.reduced` is the no-JS path, where the bottom is
   cream too. `.roles` and the CTA stay transparent over the globe (that IS the effect);
   the footer is a solid cream block, because holding AA for dense small text over a
   live globe is not defensible. Dark-world inks are unreadable on cream — every one of
   them is swapped here, not merely inherited.

   The cream backdrop is one fixed layer behind the WHOLE viewport, so the nav — which
   floats over the ramp for its entire length — is swapped here too. It carries its own
   bar in both worlds (see NAV): a transparent nav is only ever as readable as whatever
   happens to be under it, and what is under it here is a half-mixed backdrop. Nothing
   above `.roles` needs a light counterpart: `scroll.js` holds the cream until `.eco`'s
   last content pixel has left the screen.

   TWO RULES GOVERN EVERY SELECTOR BELOW, and they are the whole reason this is not a
   colour swap. Mid-crossing the backdrop is a flat grey (cream 0.575 under the scrim)
   that caps ANY ink at ~4.3:1 — no colour choice survives it. So:

   (1) POLE INKS ONLY. Each crossing ink is the strongest member its ramp has on the
       surface it lands on. Mid-tones are not an option: --d-body measures 2.07:1 on the
       crossing grey and --text-body 1.47:1, and the section is read THROUGH that grey,
       not just at its ends. What carries them there is the halo, which is a local plate
       and swaps polarity with the world — a dark glow behind ink on cream is a smudge.
   (2) ONLY HEADINGS CROSS-FADE. h2 is 34-72px, so it rides the crossing on the 3:1
       large-text bar (transition at the end of this block). Everything else down here is
       12-16.5px and owes 4.5:1, which nothing reaches mid-crossing — so ink AND halo SNAP
       together with the world class, inside the ~7px of scroll the dead-band flips in. A
       lerp between opposite poles passes through grey-ink-on-grey-halo at its midpoint;
       a snap never does. `.cta__sub` is the extreme case and carries an opaque plate.
   ============================================================ */

/* WHO JOINS — the section the boundary now runs through, and the only one on the page
   that is read in both worlds. Re-pointing the four role tokens re-inks the whole chain
   at once — nodes, top rules, kickers, links and the marching connector all resolve
   through `.rstation`'s single `--accent` — so the composition survives the flip with its
   identity intact: neutral / mint / teal in both worlds, each inked for its own surface.

   Scoped to `.roles`, NOT to `body.light-bottom`, and that is load-bearing: the three
   live-conversation panels read the same three tokens (`--lp-accent`, see LIVE), and `.live`
   is a dark-only section far above the boundary. Re-pointing them on `body` would inherit
   straight into it and paint ink-on-ink cards nobody asked for. */
body.light-bottom .roles, html.reduced .roles {
  color: var(--text-ink);
  --role-org: var(--ink);              /* neutral bright -> neutral ink   15.6:1 on cream */
  --role-prin: var(--mint-ink);        /* mint  -> the mint ramp's ink     5.0:1 */
  --role-agent: var(--teal-ink-deep);  /* teal  -> the teal ramp's ink     5.4:1 */
  --role-seg: var(--teal-ink-deep);
}
body.light-bottom .roles h2, html.reduced .roles h2 { color: var(--ink); }
/* The heading's em keeps the page's standard --teal-ink: it is 34-58px, so it answers to the
   3:1 large-text bar, and matching the hero H1 and the CTA heading matters more there. */
body.light-bottom .roles h2 em, html.reduced .roles h2 em { color: var(--teal-ink); }
body.light-bottom .roles .eyebrow, html.reduced .roles .eyebrow { color: var(--teal-ink-deep); }
body.light-bottom .rstation p, html.reduced .rstation p { color: var(--text-body); }
/* The Principals node is a ring, not a disc: its hole is whatever surface it stands on. */
body.light-bottom .rstation--prin .rstation__node,
html.reduced .rstation--prin .rstation__node { background: var(--cream); }
/* The cream counterparts of the two halos (see DARK NETWORK WORLD) — a dark glow behind ink on
   cream is a smudge, so both swap polarity with the world. The heading takes the glow and
   cross-fades with its ink; the small copy takes the PLATE and snaps with its ink. Same split,
   same reasons, mirrored surface. `html.reduced` is absent on purpose: it already zeroes every
   halo on the page and stands `.roles` on a solid cream block, so either would be paint with
   nothing to do. */
body.light-bottom .roles h2 {
  text-shadow: 0 1px 16px rgba(244, 241, 233, 0.85), 0 0 3px rgba(244, 241, 233, 0.75);
}
body.light-bottom .roles .eyebrow, body.light-bottom .roles .rstation__kicker,
body.light-bottom .roles .rstation p, body.light-bottom .roles .rstation__more {
  text-shadow: 0 0 3px rgba(244, 241, 233, 0.92), 0 0 3px rgba(244, 241, 233, 0.92),
               0 0 6px rgba(244, 241, 233, 0.88), 0 1px 18px rgba(244, 241, 233, 0.80);
  --plate: var(--cream);          /* the stroke ring follows the world; see @supports above */
}

body.light-bottom .cta, html.reduced .cta { color: var(--text-ink); }
body.light-bottom .cta h2, html.reduced .cta h2 { color: var(--ink); }
body.light-bottom .cta h2 em, html.reduced .cta h2 em { color: var(--teal-ink); }
body.light-bottom .cta__sub, html.reduced .cta__sub { color: var(--text-body); background: var(--cream); }
body.light-bottom .cta__sub a, html.reduced .cta__sub a { color: var(--teal-ink); }
/* The outline button's ring follows the world, like every other plate down here (see CTA).
   `html.reduced` is absent on purpose: the ring is zeroed on that path, so pointing it at a
   surface it never paints on would be a lie in the cascade. */
body.light-bottom .cta .btn--outline { --plate: var(--cream); }

/* The dark backing halo becomes a cream one — a dark glow behind ink text on
   cream reads as a smudge, but the CTA still sits over the globe. (.cta__sub is not
   here: its plate is a stronger backing than any halo, and a halo inside an opaque
   plate is a smudge with nothing to do.) */
body.light-bottom .cta h2, html.reduced .cta h2 {
  text-shadow: 0 1px 16px rgba(244, 241, 233, 0.85), 0 0 3px rgba(244, 241, 233, 0.75);
}

/* --teal-300 is 1.22:1 on cream — an invisible focus ring. The three role links are the
   only keyboard stops in `.roles`, and they went light with it. */
body.light-bottom .roles :focus-visible, body.light-bottom .cta :focus-visible,
body.light-bottom .footer :focus-visible, html.reduced .roles :focus-visible,
html.reduced .cta :focus-visible, html.reduced .footer :focus-visible { outline-color: var(--teal-ink); }

body.light-bottom .footer, html.reduced .footer {
  background: var(--cream); color: var(--text-ink);
  --trim-a: var(--teal-500); --trim-b: var(--amber-ink);
}
body.light-bottom .footer__brand svg, html.reduced .footer__brand svg { color: var(--teal-ink); }
body.light-bottom .footer__brand .wordmark, html.reduced .footer__brand .wordmark { --wm-grad: var(--wm-cream); }
body.light-bottom .footer__brand p, html.reduced .footer__brand p { color: var(--text-body); }
body.light-bottom .footer__col h3, html.reduced .footer__col h3 { color: var(--text-body); }
body.light-bottom .footer__col .links, html.reduced .footer__col .links { color: var(--text-body); }
body.light-bottom .footer__col .links a:hover, html.reduced .footer__col .links a:hover { color: var(--ink); }
body.light-bottom .footer__note, html.reduced .footer__note { color: var(--text-body); }
body.light-bottom .footer__note a, html.reduced .footer__note a { color: var(--teal-ink); }
body.light-bottom .footer__bar, html.reduced .footer__bar { color: var(--text-body); border-top-color: var(--hairline); }
body.light-bottom .footer__bar .links a:hover, html.reduced .footer__bar .links a:hover { color: var(--ink); }

/* Cross-fade rather than snap: the class flips once, CSS eases the rest. ONLY the two
   headings are on this ramp — they ride the grey crossing out on the 3:1 large-text bar
   and a halo. Nothing else in the bottom region is large enough to (rule 2 above), so
   nothing else is listed: `.cta__sub`, the eyebrow, and every kicker, paragraph and link
   in the roles chain snap with the world class instead. The footer is a solid block, so
   it fades its surface and its ink together and never shows a crossing at all. */
.footer { transition: background-color .45s, color .45s; }
.cta, .cta h2, .cta h2 em,
.roles h2, .roles h2 em { transition: color .45s, text-shadow .45s; }
/* The two CTA buttons are 16px labels, so rule (2) governs them: ink and surface SNAP together
   with the world class. `.btn`'s own `transition: background, border-color, color` was written
   for :hover, but it also catches the world flip and walks both buttons through the grey for
   .25s — the outline label lerps --d-bright -> --ink over a ring that has already snapped, and
   the dark pill lerps its ink over a fill going teal -> ink, which is grey-on-grey at the
   midpoint. Neither is a state a reader can stop on, but neither is a state this page allows
   either: it is the exact lerp `.cta__sub`'s plate and the roles chain's ink are kept off.
   Only border-color survives — and border-color is the ONLY thing `.btn--outline:hover` changes,
   so the button under review loses nothing at all. `.btn--dark`'s fill now snaps on hover
   instead of easing over .25s; that is the whole price, and it is paid by the CTA's two buttons
   only (the hero, the dev band, the nav pill and the 5 ancillary pages keep `.btn` as it was). */
.cta .btn { transition: border-color .25s; }

/* ============================================================
   Keyframes (§ draft)
   ============================================================ */
@keyframes rine-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes rine-pulse { 0%, 100% { opacity: .3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.18); } }
@keyframes rine-rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
@keyframes rine-feed-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes rine-march { to { background-position: 24px 0; } }
@keyframes rine-tdot { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
@keyframes rine-hop { 0%, 100% { transform: translateY(0) rotate(0deg); } 35% { transform: translateY(-5px) rotate(-6deg); } 65% { transform: translateY(-1px) rotate(2deg); } }

/* ============================================================
   Responsive (§7)
   ============================================================ */
@media (max-width: 1024px) {
  /* The nav collapses to the menu HERE, not at 768px. Round 5 added Product to the flat
     link set: six links plus the Documentation pill no longer fit one un-wrapped row
     below ~1020px, and because the row cannot wrap it pushed the pill straight off the
     viewport — measured, not assumed: 148px of horizontal overflow at 770px, the pill
     sliced to a single "D". The band 769–1024px was invisible to every earlier check
     because 360/390/768/1440 step clean over it.
     This rule is UNSCOPED on purpose: it is the one breakpoint for all nine pages. The
     ancillary pages load biz.css first and inherit it, so pages.css only has to reveal
     its own no-script `.navm` sheet at the same width — the trigger differs (JS burger
     here, <details> there), the breakpoint must not (item 4). */
  .nav__links, .nav__cta { display: none; }
  .nav__burger { display: inline-flex; }
  .hero__grid, .dev .split { grid-template-columns: 1fr !important; }
  .footer__grid { grid-template-columns: repeat(3, 1fr); }
  .footer__brand { grid-column: 1 / -1; }
  /* Three interactions: a row on desktop, a column here (founder item 4). The sheet's
     column rules become row rules; the inset shrinks with the gutter but never goes to
     zero — a card whose copy is welded to its own edge is the defect this fixes. */
  .live__grid { grid-template-columns: 1fr; }
  .lp { --lp-inset: 22px; }
  .lp + .lp { border-left: 0; border-top: 1px solid var(--d-hairline); }
  /* Keep the globe on top but small enough that the H1 + first CTA
     clear the fold on phones/tablets (F1): cap by viewport height. */
  .hero__globe { order: -1; }
  .hero { padding-top: 52px; }
  .hero__grid { gap: 24px; }
  .hero__globebox { max-width: min(300px, 34vh); }
  .hero__seal { margin-bottom: 16px; }
  .hero__seal .seal { width: 52px; height: 52px; }
  .hero__get { margin-bottom: 18px; }
  .hero h1 { margin-bottom: 18px; }
  .hero__sub { margin-bottom: 24px; }
  /* Roles chain goes vertical, stations stack with an accent left-rule */
  .roles__chain { flex-direction: column; }
  .rstation { width: 100%; }
  .rstation__node { display: none; }
  .rstation__block { border-top: none; border-left: 2px solid var(--accent); padding: 4px 0 6px 20px; }
  .rstation p { margin-bottom: 16px; }
  .rstation__seg { flex: none; width: 2px; height: 30px; margin: 0 0 0 6px; background: repeating-linear-gradient(0deg, var(--role-seg) 0 6px, transparent 6px 12px); background-size: 2px 24px; }
}
@media (max-width: 768px) {
  :root { --pad: 24px; }
  .footer__grid { grid-template-columns: 1fr 1fr; gap: 36px 24px; }
  .sec { padding: 96px var(--pad); }
  .statement, .cta { padding: 110px var(--pad); }
  /* Terminal: shrink long tool-call rows, keep them wrapping */
  .term__body { font-size: 12px; padding: 22px 18px; }
  .aline { gap: 6px; }
  /* Guarantee cards go full-width (mobile is never enhanced — the stacked baseline stands),
     tighten their padding, and drop the row tag beneath the row body. */
  .ledger__title { margin-bottom: 32px; }
  .lcard { max-width: none; padding: 24px 22px; }
  .lrow { grid-template-columns: 26px 1fr; gap: 4px 12px; padding: 14px 0; }
  .lrow__tag { grid-column: 2; justify-self: start; padding-top: 0; }
}
@media (max-width: 480px) {
  .footer__grid { grid-template-columns: 1fr; }
  .hero__ctas, .dev__ctas, .cta__ctas { flex-direction: column; align-items: stretch; }
  /* The narrowest phone is 312px of content column. The inset still has to be visible
     — it is what stops the copy touching the card edge — but every pixel it takes comes
     off the three member chips below, which are the tightest thing on the sheet. */
  .lp { --lp-inset: 16px; }
  /* Three members stay side by side (that is the fan-out read), so the org-slug
     wraps rather than ellipsising — a personal namespace only makes its point if
     you can read all of it. The channel handle is the same convention and the most
     load-bearing string in the panel, so it wraps too rather than losing its slug
     to an ellipsis. The bar's own row grows; .lp__log absorbs it, so the panel
     height does not move. */
  .lpm__chip { font-size: 10px; padding: 7px 6px; }
  .lpm__chip span { white-space: normal; overflow-wrap: anywhere; }
  .lpch__h { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
  /* The routing line needs three lines here (from → to · type). At 46px the type —
     the exact metadata the panel exists to expose — was clipped. (+2px for the foot
     rule, which is inside the box.) */
  .lp__foot { height: 64px; }
}

/* Park the two infinite animations while their section is off-screen. `rine-marquee` keeps the
   compositor re-masking a moving layer; `rine-march` animates background-position, which is NOT a
   composited property — it repaints on the main thread every frame, forever, viewport or not.
   Both are pure waste when nobody can see them. Zero visual delta while on screen. */
.is-offscreen .eco__track,
.is-offscreen .rstation__seg { animation-play-state: paused; }

/* ============================================================
   Reduced motion (§4.8)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
}
/* When JS flags reduced motion: hide scrim, make the network world
   solid + opaque so readability never depends on motion. The bottom is still
   cream (item 6) — the colour rules for it carry `html.reduced` themselves. */
html.reduced #globe-scrim { display: none; }
html.reduced .statement, html.reduced .live { background: var(--ink); }
html.reduced .ledger, html.reduced .dev, html.reduced .eco { background: var(--ink-deep); }
/* `.roles` crossed the boundary in round 5 and comes with it — this is the no-JS mirror of
   `body.light-bottom`, and the two lists must always name the same sections. */
html.reduced .roles, html.reduced .cta, html.reduced .footer { background: var(--cream); }
/* No scroll controller runs on this path, so `dark-world` is never set and the nav's
   cream-world ink would stand on the solid dark sections with nothing behind it. The
   islands (see NAV) are the answer here too — they just have to be present at every
   scroll position rather than switching, and near-opaque, since nothing is ramping. */
html.reduced { --isl-bg: rgba(251, 250, 244, 0.94); --isl-line: var(--chip-border); }
html.reduced .panel-raised, html.reduced .dev__step,
html.reduced .lpm__chip { background: var(--ink-card); backdrop-filter: none; }
html.reduced .lpw__node, html.reduced .lpch { background: var(--ink-deep); }
/* The fixed boxes exist so an ANIMATED panel cannot change height between
   vignettes. Nothing animates on this path: the panel renders one resolved
   vignette and must show all of it, so the boxes give way to the content and the
   log fills from the top instead of scrolling its head out of view. */
html.reduced .lp__cap, html.reduced .lp__body, html.reduced .lp__foot { height: auto; overflow: visible; }
html.reduced .lp__log { justify-content: flex-start; overflow: visible;
                        -webkit-mask-image: none; mask-image: none; }
