/* ==========================================================================
   Self — the earned autonomy layer for AI agents
   --------------------------------------------------------------------------
   Ground:   #0A0A0A void · #F4F1EA signal (light-on-dark, one ground for the
             whole page — the signal field runs behind every section)
   Type:     Geist (display + body) · JetBrains Mono (utility / data), both
             served from Google Fonts; see --sans / --mono for the fallbacks
   Color:    spent almost entirely on meaning — a neutral-to-amber ladder for
             the four oversight stages, and one shared verdict vocabulary
             borrowed from the operating boundary itself: cream reads as
             "act," cream outline as "audit," amber as "ask," red as "deny."
             Nothing decorative is colored.
   Motif:    the operating boundary — the live feed the hero opens on, and the
             same four-verdict language everywhere a decision needs a color.
   ========================================================================== */

:root {
  --void: #161614;
  /* The same ground as channels, for the translucent veils over the signal
     field and the nav's blur. These are the page's ground at partial alpha,
     not a color of their own: when --void moved and these did not, the nav
     and the hero veil stayed at the old value and showed as a seam. */
  --void-rgb: 22, 22, 20;
  --raise: #161614;
  --raise-2: #20201c;

  /* Four text weights, all cream-on-void. The floor is 0.5 — below that,
     #F4F1EA on this ground drops under 4.5:1 for anything but the largest
     labels. */
  --peak: #f4f1ea;
  --signal: rgba(244, 241, 234, 0.9);
  --dim: rgba(244, 241, 234, 0.72);
  --dimmer: rgba(244, 241, 234, 0.58);
  --faint: rgba(244, 241, 234, 0.5);

  --line: rgba(244, 241, 234, 0.14);
  --line-soft: rgba(244, 241, 234, 0.09);
  --line-hard: rgba(244, 241, 234, 0.28);

  /* Fixed ink — text set on a bright semantic chip (state badges, move
     chips) stays this regardless of which section theme it sits inside. */
  --ink: #0a0a0a;

  /* The boundary's own vocabulary — reused everywhere a verdict needs a
     color. */
  --amber: #f5b83d;
  --red: #e2483c;
  /* Live activity. The page's third accent, added for the profile card's
     freshness pulse; tuned to the saturation and lightness of the other two
     rather than dropped in at full strength. */
  --live: #4cc38a;

  /* Oversight stages 1–4 — sequential, low to high, ending on the one accent
     color the page spends: reaching delegated execution is the only thing
     that earns amber. Solid values, not tinted — the ladder appears on both
     grounds and needs to read the same on either. */
  --t1: #71716b;
  --t2: #9d9d94;
  --t3: #d4d0c4;
  --t4: #f5b83d;

  /* Risk, where a figure needs to mark something as consequential. */
  --sev-material: #d9762c;

  /* "Act" — proven work, running unattended. The one state the page ever
     colors positively, and it borrows the ground's own cream to do it. */
  --st-promote: #f4f1ea;

  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  /* Geist first, and it is actually loaded: the page had been requesting it
     from Google Fonts while setting Helvetica Neue here, so every visitor
     without Helvetica Neue installed — which is most of Windows — was
     reading this page in Arial. */
  --sans: "Geist", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --gutter: clamp(24px, 4vw, 64px);

  /* The fixed header's height. Load-bearing well beyond the header itself:
     the signal field starts below it, the hero clears it, and all three
     pinned sections offset their sticky by it and subtract it from the
     viewport they pin into. One value, so those cannot drift apart. */
  --nav-h: 76px;

  /* The page is deliberately flat — borders carry structure, not shadow. */
  --shadow-panel: none;
  --shadow-panel-sm: none;

  --radius: 14px;
  --radius-sm: 8px;

  /* Micro-labels. Every tracked-caps label on the page resolves to these two
     values. They used to run 8.5–10.5px at 0.17–0.26em across ten unrelated
     sizes: illegible on a laptop, and the scattered tracking read as decoration
     rather than a system. One size, one tracking, set at the legibility floor. */
  --label: 11px;
  --track: 0.14em;
  --track-tight: 0.1em;

  /* Text scale. Display sizes stay on their own clamp()s; everything from
     body down resolves to these five steps. It had drifted to thirteen
     distinct values inside a 9px band — including three different sizes for
     the same role (card headings at 14, 17 and 19px), which is what made the
     sections look subtly unrelated to each other. */
  --fs-xs: 12px;
  --fs-sm: 13.5px;
  --fs-md: 15px;
  --fs-lg: 18px;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--void);
  /* clip, not hidden: hidden makes this element a scroll container, which
     breaks position:sticky for any descendant (the authority envelope) —
     clip guards against horizontal overflow without that side effect. */
  overflow-x: clip;
}

body {
  /* Also set here, not only on .page: anything that ever renders outside the
     .page wrapper would otherwise fall back to the browser's serif default. */
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: var(--signal);
  text-decoration: none;
}
/* --peak, not a hardcoded #fff: .section--light flips --peak to near-black,
   so a literal here would hover cream-section links to white on cream. */
a:hover {
  color: var(--peak);
}

::selection {
  background: var(--amber);
  color: var(--ink);
}

input {
  font: inherit;
  color: inherit;
}
button {
  font: inherit;
}

:focus-visible {
  outline: 1px solid rgba(244, 241, 234, 0.85);
  outline-offset: 3px;
}

[hidden] {
  display: none !important;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Every figure that carries a number uses lining, tabular digits — numbers on
   this page exist to be compared against each other. */
.rung-num,
.gate-t,
.gate-value {
  font-variant-numeric: tabular-nums lining-nums;
}

/* Keyboard users land here first; invisible until focused. */
.skip-link {
  position: absolute;
  left: clamp(16px, 4vw, 52px);
  top: -100px;
  z-index: 80;
  padding: 12px 18px;
  background: var(--peak);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  text-transform: uppercase;
  border-radius: var(--radius-sm);
  transition: top 0.18s ease;
}
.skip-link:focus {
  top: 14px;
}
/* Same reason as .btn-ghost: this is an <a> on a cream chip, and once it is
   on screen it can be hovered as well as focused. Ink in every state, or the
   generic link hover paints it cream on cream. Position stays on :focus alone
   so the link never slides in for a pointer that never asked for it. */
.skip-link,
.skip-link:focus,
.skip-link:hover {
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   Motion — a handful of orchestrated moments (the gate feed, ledger flow,
   history draw); everything else stays at state-transition level.
   -------------------------------------------------------------------------- */

@keyframes riseIn {
  from {
    opacity: 0;
    transform: translateY(18px);
    filter: blur(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes pulseDot {
  0%,
  100% {
    opacity: 0.22;
  }
  50% {
    opacity: 1;
  }
}
@keyframes flowPulse {
  0% {
    transform: translateY(-100%);
    opacity: 0;
  }
  22% {
    opacity: 1;
  }
  78% {
    opacity: 1;
  }
  100% {
    transform: translateY(100%);
    opacity: 0;
  }
}
@keyframes drawLine {
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes rowIn {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* The only thing the sealed engine panel shows of itself: something is
   running in there.

   Applied by .ledger-engine.is-live, gated on the engine rather than on the
   signals-in diagram that used to wrap it — that wrapper was removed with its
   section, which left this switched off without anyone noticing. It runs while
   the ledger is being handed over and stops when the panel goes quiet, and
   prefers-reduced-motion drops it to a single frame. */
@keyframes sweep {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(100%);
  }
}

/* Reduced motion removes travel and looping, not feedback. Every animation on
   this page is either a loop (the pulses, the sweep) or an entrance, and both
   go straight to their end state; field.js takes the same branch and renders
   the scroll-driven sections whole rather than scrubbing them.

   Transitions are kept, cut to a single frame's worth. They carry hover,
   focus, open and close — the confirmation that a control responded — and a
   reader who asked for less motion still needs to see that a button reacted
   to them. Delay goes to zero either way: a 1.6s-delayed reveal is still
   something the reader has to wait through. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.08s !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */

.page {
  position: relative;
  background: var(--void);
  color: var(--signal);
  font-family: var(--sans);
  min-height: 100vh;
  overflow-x: clip;
}

.wrap {
  width: min(1280px, 100%);
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   Nav
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 0 clamp(16px, 4vw, 52px);
  border-bottom: 1px solid var(--line);
  background: rgba(var(--void-rgb), 0.85);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 44px;
}
.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  flex: none;
  display: block;
  object-fit: cover;
}
.brand-name {
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.nav-links {
  display: none;
  align-items: center;
  gap: clamp(18px, 2.2vw, 30px);
  margin-left: auto;
  margin-right: clamp(18px, 2.2vw, 30px);
  font-size: var(--fs-sm);
  letter-spacing: -0.01em;
}
.nav-links a {
  color: var(--dimmer);
  padding: 6px 0;
  border-bottom: 1px solid transparent;
  transition:
    color 0.15s ease,
    border-color 0.15s ease;
}
.nav-links a:hover {
  color: var(--peak);
  border-bottom-color: var(--line-hard);
}
.nav-links a[aria-current="page"] {
  color: var(--peak);
  border-bottom-color: var(--line-hard);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-size: var(--fs-xs);
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--ink);
  background: var(--peak);
  border: 0;
  border-radius: var(--radius-sm);
  padding: 0 16px;
  height: 40px;
  flex: none;
  cursor: pointer;
  transition:
    background 0.2s cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 0.12s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Pinned through hover and focus, because on every page but the homepage this
   control is an <a>, and the generic `a:hover` rule (0,1,1) outranks the bare
   `.btn-ghost` class (0,1,0) — which turned the nav's request button into
   cream-on-amber, 1.6:1, exactly when the pointer was on it. The chip's ink
   is fixed by design; nothing about being a link should change it. */
.btn-ghost:hover,
.btn-ghost:focus-visible,
.btn-ghost:active {
  color: var(--ink);
}
.btn-ghost:hover {
  background: var(--amber);
}
.btn-ghost:active {
  transform: translateY(1px);
}

/* Fixed cream-on-ink, not theme tokens: the button reads the same whether
   it sits on the dark hero or a cream section — same as the source files,
   where --peak/--ink would otherwise flip the button invisible on
   .section--light (dark text on dark background). */
.btn-solid {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-size: var(--fs-md);
  letter-spacing: -0.015em;
  white-space: nowrap;
  background: #f4f1ea;
  color: #0a0a0a;
  border: 0;
  border-radius: var(--radius-sm);
  height: 50px;
  padding: 0 28px;
  cursor: pointer;
  transition:
    background 0.2s cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 0.12s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.btn-solid:hover {
  background: var(--amber);
}
.btn-solid:active {
  transform: translateY(1px);
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

/* The hero fills the viewport on first paint at every breakpoint: min-height
   (not height) so it still grows rather than clipping if content ever needs
   more room than the screen gives it. padding-top clears the fixed nav;
   hero-grid is centered in whatever space is left. */
.hero {
  position: relative;
  z-index: 2;
  overflow: hidden;
  min-height: 100svh;
  padding-top: var(--nav-h);
  display: flex;
  flex-direction: column;
}

/* Signal field — the page-wide ground, drawn on canvas by field.js. Fixed to
   the viewport rather than parked in the hero, so every section stands on the
   same moving dark ground instead of the page alternating between grounds.
   Starts at the header's height so it clears the fixed nav rather than
   rendering under it.
   z-index 0 keeps it under the sections (z-index 2), which stay transparent
   and let it through. */
.field {
  position: fixed;
  inset: var(--nav-h) 0 0 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.field canvas {
  display: block;
  width: 100%;
  height: 100%;
}
.field-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    115% 85% at 26% 54%,
    rgba(var(--void-rgb), 0.94) 0%,
    rgba(var(--void-rgb), 0.74) 30%,
    rgba(var(--void-rgb), 0.18) 62%,
    rgba(var(--void-rgb), 0) 80%
  );
}
.field-fade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(var(--void-rgb), 0.85) 0%,
    rgba(var(--void-rgb), 0) 18%,
    rgba(var(--void-rgb), 0) 74%,
    rgba(var(--void-rgb), 0.92) 100%
  );
}

.hero-grid {
  position: relative;
  z-index: 3;
  flex: 1;
  display: grid;
  grid-template-columns: 1fr;
  align-content: center;
  gap: clamp(32px, 6vh, 80px);
  align-items: center;
  width: min(1280px, 100%);
  margin-inline: auto;
  padding: clamp(28px, 6vh, 64px) var(--gutter);
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: clamp(18px, 3vh, 34px);
  animation: riseIn 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) 0.05s both;
}
.eyebrow-rule {
  display: block;
  width: clamp(20px, 4vw, 44px);
  height: 1px;
  background: rgba(244, 241, 234, 0.35);
}
.eyebrow-text {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dim);
  text-wrap: balance;
}

.hero-title {
  margin: 0;
  font-size: clamp(38px, 5.8vw, 88px);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 0.96;
  color: var(--peak);
  text-wrap: balance;
  animation: riseIn 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.14s both;
}

.hero-lede {
  margin: clamp(18px, 2.6vh, 30px) 0 0;
  max-width: 44ch;
  font-size: clamp(16px, 1.35vw, 20px);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 1.45;
  color: var(--dim);
  text-wrap: pretty;
  animation: riseIn 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.26s both;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 26px;
  margin-top: clamp(26px, 3.6vh, 44px);
  animation: riseIn 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.46s both;
}

/* Waitlist / pilot-request capture */
.waitlist {
  display: flex;
  flex-direction: column;
  gap: 1px;
  width: min(460px, 100%);
  border: 1px solid var(--line-hard);
  border-radius: var(--radius);
  overflow: hidden;
  background: rgba(244, 241, 234, 0.02);
  transition: border-color 0.2s ease;
}
.waitlist:focus-within {
  border-color: rgba(244, 241, 234, 0.5);
}
.waitlist-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line-hard);
}
.waitlist-field {
  background: var(--void);
}
.waitlist input {
  width: 100%;
  height: 44px;
  padding: 0 14px;
  background: transparent;
  border: 0;
  outline: none;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--signal);
}
.waitlist input::placeholder {
  color: var(--dimmer);
}
.waitlist-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 44px;
  background: transparent;
  color: var(--signal);
  border: 0;
  border-top: 1px solid var(--line-hard);
  cursor: pointer;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  letter-spacing: -0.01em;
  transition:
    background 0.2s ease,
    color 0.2s ease;
}
.waitlist-submit:hover {
  background: var(--peak);
  color: var(--void);
}

/* In flight: the field keeps its shape, the controls stop responding. */
.waitlist[data-pending] {
  opacity: 0.55;
  pointer-events: none;
}
.waitlist[data-pending] .waitlist-submit {
  animation: pulseDot 1.1s ease-in-out infinite;
}

@media (max-width: 460px) {
  .waitlist-grid {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Touch
   --------------------------------------------------------------------------
   Keyed to the pointer, not the viewport: an iPad at 1024px is a touch device
   and a narrow desktop window is not.

   The input size is not cosmetic. Mobile Safari zooms the page whenever a
   focused input is set below 16px, and at the page's 11px label size that
   meant tapping "COMPANY" on the one form the site has threw the reader into
   a zoomed viewport they had to pinch back out of, mid-conversion.
   -------------------------------------------------------------------------- */
@media (pointer: coarse) {
  .waitlist input {
    height: 52px;
    font-size: 16px;
    letter-spacing: 0.05em;
  }
  .waitlist-submit,
  .btn-ghost {
    min-height: 48px;
  }
  .traj-point {
    min-height: 44px;
  }
  /* Grown to a real tap target without changing the type: the column reads
     the same, the rows just stop sharing edges. */
  .site-footer-col ul {
    gap: 0;
  }
  .site-footer-col a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

/* Failure sits under the actions row, in the same telemetry register. */
.form-error {
  flex: 1 0 100%;
  margin: 4px 0 0;
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--signal);
  animation: fadeIn 0.3s ease both;
}
.form-error::before {
  content: "";
  flex: none;
  width: 5px;
  height: 5px;
  border: 1px solid var(--red);
  display: block;
}

.joined {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 48px;
  padding: 0 20px;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--signal);
  animation: fadeIn 0.4s ease both;
}
.joined-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--st-promote);
  display: block;
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 48px;
  font-family: var(--sans);
  font-size: var(--fs-md);
  letter-spacing: -0.015em;
  color: var(--dim);
  border-bottom: 1px solid rgba(244, 241, 234, 0.2);
  transition:
    gap 0.22s ease,
    color 0.22s ease,
    border-color 0.22s ease;
}
.link-arrow:hover {
  gap: 15px;
  color: var(--peak);
  border-bottom-color: rgba(244, 241, 234, 0.6);
}

.status-pill {
  margin-top: clamp(22px, 3vh, 36px);
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--faint);
  animation: fadeIn 1.4s ease 0.9s both;
}
/* A marker, not a heartbeat: "PRIVATE PILOTS / 2026" is a programme status
   that is not changing while anyone reads it, and the page already spends its
   one live pulse on the decision feed above. */
.status-pill-dot {
  display: block;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--dimmer);
}

/* --------------------------------------------------------------------------
   The hero signature — self.gate, deciding in real time
   -------------------------------------------------------------------------- */

.hero-figure {
  margin: 0;
  animation: fadeIn 1.1s ease 0.5s both;
}

.gate {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--void);
}
.gate-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 13px clamp(14px, 1.6vw, 20px);
  border-bottom: 1px solid var(--line);
}
.gate-name {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: -0.01em;
  color: var(--dim);
}
.gate-dot {
  width: 6px;
  height: 6px;
  flex: none;
  display: block;
  background: var(--peak);
  animation: pulseDot 1.8s ease infinite;
}
.gate-count {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: -0.01em;
  color: var(--dimmer);
}

/* Every fixed column is sized to its own longest value at the mono label size
   — time and value run eight characters, the verdict runs "Audit" behind its
   dot — so the leftover width goes to the two columns that carry real names.
   Sized this tightly because the previous tracks ellipsed four of six agent
   names on a 1200px laptop: the hero's signature figure is a decision record,
   and a record that reads "finance.treas…" is not one. */
.gate-cols,
.gate-row {
  display: grid;
  grid-template-columns: 56px minmax(0, 1.1fr) minmax(0, 1.48fr) 56px 54px;
  gap: 0 clamp(8px, 1vw, 14px);
  align-items: center;
}
.gate-cols {
  padding: 9px clamp(14px, 1.6vw, 20px);
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--faint);
  border-bottom: 1px solid var(--line-soft);
}
.gate-rows {
  display: flex;
  flex-direction: column;
}
.gate-row {
  padding: 12px clamp(14px, 1.6vw, 20px);
  border-bottom: 1px solid var(--line-soft);
}
.gate-rows .gate-row:last-child {
  border-bottom: 0;
}
.gate-row.is-new {
  animation: rowIn 0.45s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.gate-t {
  font-family: var(--mono);
  font-size: var(--label);
  color: var(--faint);
}
.gate-agent {
  font-family: var(--mono);
  font-size: var(--label);
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gate-action {
  font-size: var(--fs-sm);
  letter-spacing: -0.012em;
  color: var(--peak);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gate-value {
  font-family: var(--mono);
  font-size: var(--label);
  color: var(--dimmer);
  text-align: right;
}
.gate-verdict {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: var(--label);
  justify-self: end;
}
.gate-verdict-dot {
  width: 6px;
  height: 6px;
  flex: none;
  display: block;
}
/* Four verdicts, one vocabulary — the same one the authority bands and the
   difference figures use. "Audit" is act with the dot left hollow: the action
   proceeded, the record gets read afterward. */
.gate-row[data-verdict="act"] .gate-verdict {
  color: var(--peak);
}
.gate-row[data-verdict="act"] .gate-verdict-dot {
  background: var(--peak);
}
.gate-row[data-verdict="audit"] .gate-verdict {
  color: var(--dim);
}
.gate-row[data-verdict="audit"] .gate-verdict-dot {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--dim);
}
.gate-row[data-verdict="ask"] .gate-verdict {
  color: var(--amber);
}
.gate-row[data-verdict="ask"] .gate-verdict-dot {
  background: var(--amber);
}
.gate-row[data-verdict="deny"] .gate-verdict {
  color: var(--red);
}
.gate-row[data-verdict="deny"] .gate-verdict-dot {
  background: var(--red);
}

@media (max-width: 560px) {
  .gate-cols {
    display: none;
  }
  .gate-row {
    grid-template-columns: 1fr auto;
    grid-template-areas: "action verdict" "meta meta";
    row-gap: 5px;
  }
  .gate-t {
    display: none;
  }
  .gate-agent {
    grid-area: meta;
  }
  .gate-action {
    grid-area: action;
    white-space: normal;
  }
  .gate-value {
    display: none;
  }
  .gate-verdict {
    grid-area: verdict;
  }
}

/* --------------------------------------------------------------------------
   The oversight ladder — used in the earned-autonomy section
   -------------------------------------------------------------------------- */

[data-tier-chip="1"] {
  background: var(--t1);
}
[data-tier-chip="2"] {
  background: var(--t2);
}
[data-tier-chip="3"] {
  background: var(--t3);
}
[data-tier-chip="4"] {
  background: var(--t4);
}

/* --------------------------------------------------------------------------
   Section scaffolding
   -------------------------------------------------------------------------- */

/* Asymmetric on purpose: a section's closing edge needs more air than its
   opening one, or the hairline above the next section crowds the last line
   of this one. */
.section {
  position: relative;
  z-index: 2;
  padding: clamp(72px, 9vw, 140px) var(--gutter) clamp(88px, 11vw, 168px);
  border-top: 1px solid var(--line-soft);
}

/* A section that opens the page in place of a hero: clears the fixed nav
   with a tighter top offset than the full section padding (scaled by
   viewport height, not width, so short/wide windows don't push the content
   below the fold), and drops the separator line since there's nothing
   above it. */
.page-first {
  padding-top: calc(var(--nav-h) + clamp(20px, 4vh, 56px));
  border-top: 0;
}

/* The cream ground — every token below drives backgrounds, text and
   hairlines throughout a section's content, so flipping them here flips
   the whole section without touching individual components. The homepage
   no longer alternates: it stands on one dark ground with the signal field
   behind it, so this is left in place for Solutions only. sev-*
   and st-* stay untouched here on purpose: they're also chip backgrounds
   (state-badge, move-chip) paired with fixed --ink text, so darkening them
   globally would kill that pairing's contrast instead of fixing it — see
   the targeted text-only overrides below. The autonomy-tier colors
   (t0–t4) are solid, not tinted, and left alone entirely — the ladder
   motif reads as one fixed identity everywhere it appears. */
.section--light {
  background: #f4f1ea;
  --void: #f4f1ea;
  --raise: #efece3;
  --raise-2: #e6e2d5;

  --peak: #0a0a0a;
  --signal: rgba(10, 10, 10, 0.9);
  --dim: rgba(10, 10, 10, 0.72);
  --dimmer: rgba(10, 10, 10, 0.58);
  --faint: rgba(10, 10, 10, 0.5);

  --line: rgba(10, 10, 10, 0.14);
  --line-soft: rgba(10, 10, 10, 0.09);
  --line-hard: rgba(10, 10, 10, 0.28);
}
.section--light :focus-visible {
  outline-color: rgba(10, 10, 10, 0.8);
}

/* "Act" is the ground's own cream on dark; on cream, its equivalent is ink. */
.section--light .joined-dot,
.section--light .fig-bar--good {
  background: #0a0a0a;
  fill: #0a0a0a;
}
.section--light .lane-verdict--good {
  color: #0a0a0a;
}

/* Decorative fills that were hand-tuned as translucent cream against the
   dark ground and need an ink equivalent on the light ground. */
.section--light .waitlist {
  background: rgba(10, 10, 10, 0.03);
}
.section--light .waitlist:focus-within {
  border-color: rgba(10, 10, 10, 0.4);
}

.sec-head {
  max-width: 78ch;
  margin-bottom: clamp(40px, 6vh, 68px);
}
.sec-eyebrow {
  margin: 0 0 18px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
}
.sec-title {
  margin: 0;
  max-width: 22ch;
  font-size: clamp(30px, 4vw, 60px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.03;
  color: var(--peak);
  text-wrap: balance;
}
.sec-lede {
  margin: clamp(18px, 2.4vh, 26px) 0 0;
  max-width: 62ch;
  font-size: var(--fs-md);
  line-height: 1.72;
  color: var(--dim);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   Shared figure primitives
   --------------------------------------------------------------------------
   Figure labels are HTML at the page's own label size, never SVG <text>. Text
   inside a viewBox scales with the box it is drawn into, so the same 8.5px
   declaration rendered anywhere from 8.2px to 9.7px depending on how wide its
   card happened to be — below the label floor, and inconsistent between two
   figures sitting side by side. Only marks are drawn now.
   -------------------------------------------------------------------------- */

.fig-label {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--faint);
}

/* The share bar in the comparison cards: label, then the bar and its value on
   one baseline. The value is the argument of that whole section, so it holds
   the same weight as the copy around it rather than the label's. */
.lane-fig {
  display: grid;
  gap: 10px;
  margin-bottom: 24px;
}
.fig-bar-row {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 14px;
}
.fig-bar-track {
  flex: 1;
  min-width: 0;
  height: 8px;
  display: block;
  background: rgba(244, 241, 234, 0.06);
}
.fig-bar-fill {
  display: block;
  height: 100%;
  background: rgba(244, 241, 234, 0.45);
}
.fig-bar-fill--good {
  background: var(--st-promote);
}
.fig-bar-val {
  flex: none;
  font-family: var(--mono);
  font-size: var(--label);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: var(--track-tight);
  color: var(--dim);
}

/* Learning — corrections thinning out. The plot is cropped to the bars: the
   old viewBox carried 50 units of empty space above them that read as a hole
   in the card rather than as headroom. */
.learn-fig {
  display: grid;
  gap: 10px;
}
/* Sized to sit between the capability rows and the authority bands either
   side of it: the three figures drive one shared card height, and the closing
   paragraphs are pushed to a common baseline, so a figure much shorter than
   its neighbours buys nothing and leaves a hole above the copy. The taller
   plot is also simply a better read — the run of twelve was squat enough that
   the last few bars were hard to tell apart. */
.learn-plot {
  display: block;
  width: 100%;
  height: 104px;
  border-bottom: 1px solid var(--line);
}
.fig-axis {
  margin: 0;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--faint);
}

/* --------------------------------------------------------------------------
   2 — The problem
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   6 — From observability to autonomy
   --------------------------------------------------------------------------
   Three lanes reading the same ten agent actions. Row one is identical in all
   three on purpose — the lanes differ only in what comes back and in how much
   of it a person still has to look at, which is the whole argument.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   6 — The difference, and what it results in
   --------------------------------------------------------------------------
   The comparison and its conclusion, merged. Both used to argue the same
   thing with two devices; now the cards make the case once and the kicker
   closes it. Pinned while scroll walks three beats: the pair, then Self,
   then the closing line.

   The grouping is carried by proximity first and labels second: the two
   incumbent categories sit tight together, Self sits apart. No competitor is
   named anywhere, because the claim is about a category gap, not a vendor.
   -------------------------------------------------------------------------- */

.cmp-track {
  position: relative;
}
.cmp-track.is-live {
  height: 150vh;
}
.cmp-sticky {
  display: flex;
  align-items: center;
}
.cmp-track.is-live .cmp-sticky {
  position: sticky;
  top: var(--nav-h);
  min-height: calc(100svh - var(--nav-h));
}
#difference {
  padding-bottom: 0;
}
.cmp-stage {
  display: grid;
  gap: clamp(28px, 3.4vw, 52px);
  width: 100%;
}

.cmp-groups {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* The gap between the groups is the argument; keep it well clear of the
     gap inside the pair. */
  gap: clamp(30px, 4vw, 60px);
}
.cmp-group {
  display: grid;
  align-content: start;
  gap: 14px;
}
.cmp-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(10px, 1.1vw, 14px);
}
.cmp-label {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
}
.cmp-label--accent {
  color: var(--amber);
}
/* The two incumbents recede a step so Self reads as the odd one out before
   any label is processed. */
.cmp-group--norm .lane-title {
  color: var(--signal);
  opacity: 0.82;
}

.cmp-kicker {
  display: grid;
  gap: clamp(12px, 1.4vw, 18px);
  padding-top: clamp(20px, 2.4vw, 32px);
  border-top: 1px solid var(--line-soft);
  max-width: 74ch;
}
/* One supporting line, deliberately a step below the headline: it carries the
   reversible half of the claim, which the headline alone does not. */
.cmp-kicker-copy {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--dim);
  text-wrap: pretty;
}
.cmp-kicker-title {
  margin: 0;
  font-size: clamp(26px, 3.2vw, 44px);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.04;
  color: var(--peak);
  text-wrap: balance;
}

/* Reveal. Everything ships visible; .is-live is what hides it, so the section
   reads in full with no JS and under reduced motion. */
.cmp-track.is-live [data-cmp-beat] {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity 0.55s ease,
    transform 0.55s ease;
  will-change: transform, opacity;
}
.cmp-track.is-live [data-cmp-beat].is-on {
  opacity: 1;
  transform: none;
}

@media (min-width: 900px) {
  .cmp-groups {
    grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
    align-items: stretch;
  }
  /* Label on its own row, card takes the rest, so all three cards end level
     even though their copy runs to different lengths. */
  .cmp-group {
    grid-template-rows: auto minmax(0, 1fr);
  }
  .lane {
    height: 100%;
  }
  .cmp-pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* No pin below 900px, and none in a window too short to hold the three cards
   and the closing line at once: the stage measures ~680px, so under 796px of
   viewport the pin used to hold the card titles above the nav line where the
   reader never saw them. Both cases play the same three beats once on
   intersection instead. */
@media (max-width: 899px), (max-height: 795px) {
  .cmp-track,
  .cmp-track.is-live {
    height: auto;
  }
  .cmp-track.is-live .cmp-sticky,
  .cmp-sticky {
    position: static;
    min-height: 0;
  }
}

.lane {
  padding: clamp(22px, 2.4vw, 32px);
  background: var(--void);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  transition:
    background 0.25s ease,
    border-color 0.25s ease;
}
.lane:hover {
  background: var(--raise-2);
  border-color: var(--line);
}
.lane--self {
  background: var(--raise);
  border-color: var(--amber);
  box-shadow: inset 0 2px 0 var(--amber);
}
.lane--self:hover {
  background: var(--raise-2);
}
.lane-title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--peak);
}
/* --track is documented for short uppercase labels; these run to 33
   characters ("DECIDE WHAT TO TRUST IT WITH NEXT"), which is a sentence
   wearing a label's clothes. Held in the same tracked-caps register as the
   rest of the card, at the system's tighter step — the one already carrying
   every longer mono string on the page. */
.lane-verdict {
  margin: 10px 0 26px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  text-transform: uppercase;
}
.lane-verdict--neutral {
  color: var(--dimmer);
}
.lane-verdict--good {
  color: var(--st-promote);
}
.lane-fig {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 24px;
}
/* The readout panel. One concrete event, shown three ways: the abstract mark
   rows this replaces asked the reader to decode a legend before the argument
   landed. The opening line is the same row the hero's self.boundary feed
   already showed, so the comparison pays off something they have seen. */
.readout {
  /* All three panels hold the same shape regardless of what they contain:
     three trace lines, three score rows and one badge are different amounts
     of content, and without a floor the review bars below them stopped
     lining up across the cards. */
  min-height: 132px;
  margin-bottom: 22px;
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: rgba(244, 241, 234, 0.025);
}
.readout-event {
  margin: 0 0 12px;
  padding-bottom: 11px;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--dim);
}
.readout-arrow {
  display: inline-block;
  margin-right: 8px;
  color: var(--faint);
}

/* Observability: the trace, and nothing derived from it. */
.readout-trace p {
  margin: 0 0 6px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--dimmer);
}
.readout-trace p:last-child {
  margin-bottom: 0;
}

/* Evaluation: magnitudes. */
.readout-score {
  margin: 0;
  display: grid;
  gap: 9px;
}
.readout-score-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(46px, 0.9fr) auto;
  align-items: center;
  gap: 12px;
}
.readout-score dt {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--dimmer);
}
.readout-score dd {
  margin: 0;
}
.readout-meter {
  height: 4px;
  background: rgba(244, 241, 234, 0.08);
}
.readout-meter span {
  display: block;
  height: 100%;
  background: rgba(244, 241, 234, 0.42);
}
.readout-num {
  font-family: var(--mono);
  font-size: var(--label);
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--signal);
  text-align: right;
}

/* Self: one stamped decision, in the hero table's status vocabulary. */
.readout-decision {
  margin: 0;
  display: flex;
  align-items: center;
}
.readout-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 11px;
  border: 1px solid var(--line-hard);
  border-radius: 2px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--peak);
}
.readout-badge-dot {
  width: 6px;
  height: 6px;
  flex: none;
  display: block;
  background: var(--peak);
}

.lane-copy {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--dim);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   The sealed engine
   --------------------------------------------------------------------------
   The sealed panel. Fixed dark regardless of the section it sits in: this is
   the one element on the page that is deliberately opaque, and it should read
   that way on any ground. The sweep is the only thing it shows of itself —
   something is running in there, and the page is not going to say what. */

.engine-box {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: clamp(30px, 4.5vw, 58px) clamp(20px, 3vw, 40px);
  text-align: center;
  border: 1px solid rgba(244, 241, 234, 0.28);
  border-radius: var(--radius);
  background-color: var(--void);
  background-image: repeating-linear-gradient(
    -45deg,
    rgba(244, 241, 234, 0.035) 0 1px,
    transparent 1px 7px
  );
}
.engine-box::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: translateX(-100%);
  background: linear-gradient(
    100deg,
    transparent 38%,
    rgba(244, 241, 234, 0.07) 50%,
    transparent 62%
  );
}
.ledger-engine.is-live::after {
  animation: sweep 4.6s cubic-bezier(0.55, 0, 0.45, 1) infinite;
}
.engine-name {
  margin: 0;
  font-family: var(--mono);
  font-size: clamp(12px, 1.5vw, 16px);
  letter-spacing: var(--track);
  color: #f4f1ea;
}
.engine-copy {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(15px, 1.4vw, 18px);
  line-height: 1.5;
  letter-spacing: -0.015em;
  color: rgba(244, 241, 234, 0.72);
  text-wrap: balance;
}
.engine-mark {
  margin: 4px 0 0;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: rgba(244, 241, 234, 0.5);
}
.engine-mark::before {
  content: "";
  width: 5px;
  height: 5px;
  flex: none;
  display: block;
  background: var(--amber);
}

/* --------------------------------------------------------------------------
   5 — Earned autonomy: one agent's trajectory
   --------------------------------------------------------------------------
   Twelve weeks of the same Accounts Payable Agent shown in the profile card
   above, stepping through the four oversight stages and getting pulled back
   once. The chart carries the argument the four-stage selector only asserted:
   authority is earned, and it is reversible.

   Colour follows the profile card's delta convention exactly, so the two
   sections agree: a promotion is the ground's own cream, a pull-back is the
   red the Restricted tier already carries. No third colour.
   -------------------------------------------------------------------------- */

/* The pin, on the same mechanism as the ledger and the envelope: a tall
   track, a sticky child, one rAF-batched tick. The track only exists while JS
   is driving it. */
.traj-track {
  position: relative;
}
.traj-track.is-live {
  height: 300vh;
}
.traj-sticky {
  display: flex;
  align-items: center;
}
.traj-track.is-live .traj-sticky {
  position: sticky;
  top: var(--nav-h);
  min-height: calc(100svh - var(--nav-h));
  padding: clamp(20px, 2.6vw, 40px) 0;
}
.traj-wrap {
  display: grid;
  gap: clamp(28px, 3.4vw, 48px);
  width: 100%;
  align-items: start;
}
/* Chart and panel side by side once there is room, so the whole thing fits a
   pinned viewport without the panel scrolling away from the line driving it. */
@media (min-width: 1100px) {
  .traj-wrap {
    grid-template-columns: minmax(0, 70fr) minmax(240px, 30fr);
    gap: clamp(24px, 2.6vw, 44px);
    /* Both columns run the full height of the row, so the identity box and
       the chart together match the panel top and bottom. */
    align-items: stretch;
  }
  .traj {
    grid-template-rows: auto minmax(0, 1fr);
  }
  /* The plot's height is set in pixels by field.js so the curve cannot
     restretch on a relayout; the figure just has to not constrain it. */
  .traj-wrap .traj-figure {
    min-height: 0;
  }
}
/* The pin needs room for the whole composition, and the composition is a
   fixed size set by the stage panel. At full spacing that is ~712px, needing
   ~845px of window once the nav and the sticky's padding are paid for, which
   is where the 876px bound came from. Under the tightening above it measures
   497-533px depending on how the panel column wraps — worst case 638px of
   window, at 1200px wide. Pin at 652px, which clears that worst case and
   reaches a 1366x768 laptop still showing its bookmarks bar. The fallback
   stack was checked and wraps narrower than Geist, so the webfont is the
   worst case, not a font that failed to load.

   The width half is unchanged: below 1100px there is no two-column layout to
   pin. Anything narrower, or shorter than the bound, reads the section as an
   ordinary block — and now does so at the compressed size, which fits inside
   a short viewport and so still has a stationary phase to animate in.

   Mirrored by tjPin in field.js; the two must agree. */
@media (max-width: 1099px), (max-height: 651px) {
  .traj-track,
  .traj-track.is-live {
    height: auto;
  }
  .traj-track.is-live .traj-sticky,
  .traj-sticky {
    position: static;
    min-height: 0;
    padding: 0;
  }
}
.traj {
  display: grid;
  align-content: start;
  gap: clamp(16px, 1.8vw, 26px);
}
/* The agent's identity bar. One box in two places: the profile card's header
   and the head of the trajectory, so the chart reads as the same agent's
   record rather than a second hypothetical example. Same fill and hairline as
   the panels it sits above. */
.agent-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px clamp(20px, 2.4vw, 36px);
  padding: clamp(16px, 1.8vw, 24px) clamp(18px, 2vw, 28px);
  background: var(--void);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
}
.agent-bar-id {
  display: grid;
  gap: 7px;
}
.agent-bar-tag {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
}
.agent-bar-name {
  margin: 0;
  font-size: clamp(19px, 2vw, 26px);
  font-weight: 500;
  letter-spacing: -0.028em;
  color: var(--peak);
}
.agent-bar-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 7px;
}

.traj-figure {
  display: grid;
  grid-template-columns: clamp(130px, 13vw, 172px) minmax(0, 1fr);
  align-items: stretch;
  gap: 10px clamp(14px, 1.6vw, 24px);
}

/* Four rows of equal height put each label on its gridline: the plot's lines
   sit at 12.5 / 37.5 / 62.5 / 87.5% of the box, which is exactly where the
   centres of four equal rows fall. */
/* Pinned to the same fractions the gridlines sit at (12.5 / 37.5 / 62.5 /
   87.5% of the plot), so the labels cannot drift out of register when the
   plot height changes. */
.traj-ylabels {
  position: relative;
  text-align: right;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--dimmer);
  white-space: nowrap;
}
.traj-ylabels span {
  position: absolute;
  right: 0;
  transform: translateY(-50%);
}
.traj-ylabels span:nth-child(1) {
  top: 12.5%;
}
.traj-ylabels span:nth-child(2) {
  top: 37.5%;
}
.traj-ylabels span:nth-child(3) {
  top: 62.5%;
}
.traj-ylabels span:nth-child(4) {
  top: 87.5%;
}
.traj-ylabels b {
  font-weight: 400;
  color: var(--faint);
}

.traj-plot {
  position: relative;
  height: clamp(240px, 30vw, 380px);
}
.traj-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.traj-grid line {
  stroke: var(--line-soft);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
/* non-scaling-stroke because the viewBox is stretched to the box width; the
   line would otherwise thin out horizontally and thicken vertically. */
.traj-line {
  fill: none;
  stroke: var(--peak);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.traj-line--down {
  stroke: var(--red);
  stroke-width: 2;
}

.traj-points {
  position: absolute;
  inset: 0;
}
.traj-point {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  padding: 0;
  display: grid;
  place-items: center;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.traj-point-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--dimmer);
  transition:
    background 0.2s ease,
    transform 0.2s ease,
    box-shadow 0.2s ease;
}
.traj-point:hover .traj-point-dot,
.traj-point:focus-visible .traj-point-dot {
  background: var(--peak);
  transform: scale(1.25);
}
.traj-point[aria-current="true"] .traj-point-dot {
  background: var(--peak);
  transform: scale(1.3);
  box-shadow: 0 0 0 4px rgba(244, 241, 234, 0.14);
}
/* The pullback week keeps the red wherever it appears, selected or not. */
.traj-point--down .traj-point-dot {
  background: var(--red);
}
.traj-point--down:hover .traj-point-dot,
.traj-point--down:focus-visible .traj-point-dot,
.traj-point--down[aria-current="true"] .traj-point-dot {
  background: var(--red);
}
.traj-point--down[aria-current="true"] .traj-point-dot {
  box-shadow: 0 0 0 4px rgba(226, 72, 60, 0.2);
}
.traj-point-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The panel sits in a 30% column now, which is narrower than the two-column
   definition list assumes. Stacking dt over dd gives the copy its measure
   back instead of wrapping it to five words a line. */
.traj-wrap .panel-dl {
  grid-template-columns: minmax(0, 1fr);
  column-gap: 0;
}
.traj-wrap .panel-dl dt {
  padding-top: 14px;
}
.traj-wrap .panel-dl dd {
  margin: 6px 0 16px;
  max-width: none;
}
.traj-wrap .panel-title {
  font-size: clamp(20px, 1.9vw, 26px);
}

/* Below the pin breakpoint the chart becomes a vertical staircase: the same
   twelve buttons, indented by stage, revealed on a timer instead of scrubbed.
   Tap selects, exactly as hover does above. */
@media (max-width: 899px) {
  .traj-figure {
    grid-template-columns: minmax(0, 1fr);
  }
  .traj-ylabels,
  .traj-svg {
    display: none;
  }
  .traj-plot {
    height: auto;
  }
  .traj-points {
    position: static;
    display: grid;
    gap: 2px;
  }
  .traj-point {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    /* The indent is the staircase: one step right per stage earned. */
    margin-left: calc((var(--stage) - 1) * clamp(14px, 5vw, 26px));
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 40px;
    padding: 0 12px;
    border-left: 1px solid var(--line-soft);
    text-align: left;
  }
  .traj-point[aria-current="true"] {
    border-left-color: var(--peak);
    background: var(--raise-2);
  }
  .traj-point--down[aria-current="true"] {
    border-left-color: var(--red);
  }
  .traj-point-label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    font-family: var(--mono);
    font-size: var(--label);
    letter-spacing: var(--track-tight);
    color: var(--dim);
  }
  .traj-point-label b {
    font-weight: 400;
    color: var(--faint);
    margin-right: 8px;
  }
  .traj.is-live .traj-point {
    opacity: 0;
    transform: translateX(-6px);
    transition:
      opacity 0.4s ease,
      transform 0.4s ease;
  }
  .traj.is-live .traj-point.is-on {
    opacity: 1;
    transform: none;
  }
}

.tier-panel {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: var(--raise);
  padding: clamp(22px, 2.6vw, 34px);
  animation: fadeIn 0.3s ease both;
}
.panel-tier {
  margin: 0 0 12px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
}
.panel-title {
  margin: 0 0 22px;
  font-size: clamp(21px, 2.2vw, 30px);
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--peak);
}
.panel-dl {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}
.panel-dl dt {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--faint);
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}
.panel-dl dd {
  margin: 8px 0 20px;
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--dim);
  max-width: 58ch;
  text-wrap: pretty;
}

/* The trajectory at laptop height. This composition is a fixed size and the
   stage panel is what sets it: four rows of prose at generous spacing come to
   ~712px, which needs ~845px of window once the nav and the sticky's own
   padding are paid for. Below that the section used to give up the pin
   entirely — and unpinned it has no stationary phase, so the chart drew
   itself while its lower half was still under the fold and had finished by
   the time the reader could see it.

   So rather than drop the pin, compress what the pin has to hold. Type and
   spacing tighten, nothing is removed, and the composition comes down far
   enough to pin inside a short laptop window. The bound is exactly the old
   unpin query, so any window that pins today is untouched by this: it only
   governs the range that used to be given up on.
   -------------------------------------------------------------------------- */
@media (min-width: 1100px) and (max-height: 875px) {
  .traj-track.is-live .traj-sticky {
    padding: clamp(10px, 1.2vw, 18px) 0;
  }
  .traj .agent-bar {
    padding: 13px clamp(16px, 1.8vw, 24px);
  }
  .tier-panels .tier-panel {
    padding: clamp(15px, 1.7vw, 21px);
  }
  .tier-panels .panel-tier {
    margin-bottom: 7px;
  }
  .tier-panels .panel-title {
    margin-bottom: 12px;
    font-size: clamp(18px, 1.5vw, 22px);
  }
  .tier-panels .panel-dl dt {
    padding-top: 10px;
  }
  .tier-panels .panel-dl dd {
    margin: 5px 0 12px;
    font-size: 14px;
    line-height: 1.5;
  }
  /* The last row's trailing margin is the panel's own padding twice over. */
  .tier-panels .panel-dl dd:last-child {
    margin-bottom: 0;
  }
}

/* --------------------------------------------------------------------------
   3 — The evaluation ledger
   --------------------------------------------------------------------------
   A scroll-pinned diagram: episodes accumulate into a ledger, then the whole
   ledger is handed to the engine. Built on the same mechanism the authority
   envelope uses (tall section + position:sticky + one rAF-batched tick in
   field.js), so there is one scroll pattern on this page rather than two.

   The table is a deliberate sibling of the hero's .gate feed — same mono,
   same hairlines, same radius — tracking different fields. Everything that
   moves is transform and opacity only.
   -------------------------------------------------------------------------- */

.ledger {
  position: relative;
  z-index: 2;
  margin-top: clamp(40px, 6vw, 88px);
}
/* The scroll track only exists once JS is driving the pin. Without it the
   section is an ordinary block holding a full ledger and a stacked list of
   annotations, which is also the no-JS and reduced-motion state. */
.ledger.is-live {
  height: 400vh;
}
.ledger-sticky {
  display: flex;
  align-items: center;
}
/* Pinned only while JS is driving. Without it this is an ordinary block that
   takes the height of its content, not a reserved viewport. */
.ledger.is-live .ledger-sticky {
  position: sticky;
  top: var(--nav-h);
  min-height: calc(100svh - var(--nav-h));
  padding: clamp(24px, 3vw, 44px) 0;
}
.ledger-stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: center;
}

/* ---- annotations ---------------------------------------------------------
   Pre-JS and under reduced motion these are a plain stacked list. .is-live
   stacks them so one can be promoted at a time. */
.ledger-notes {
  display: grid;
  gap: 18px;
}
.ledger-notes.is-live {
  display: block;
  position: relative;
  min-height: 8.5em;
}
.ledger-note {
  margin: 0;
  display: grid;
  gap: 10px;
  align-content: start;
}
.ledger-notes.is-live .ledger-note {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 0.4s ease,
    transform 0.4s ease;
  pointer-events: none;
}
.ledger-notes.is-live .ledger-note.is-on {
  opacity: 1;
  transform: none;
}
.ledger-note-label {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--dimmer);
}
.ledger-note-copy {
  font-size: var(--fs-lg);
  line-height: 1.6;
  color: var(--dim);
  max-width: 34ch;
  text-wrap: pretty;
}

/* ---- the ledger + the engine --------------------------------------------
   Both live in one column so the table can travel down into the engine. */
.ledger-figure {
  display: grid;
  gap: clamp(20px, 2.6vw, 34px);
  justify-items: stretch;
}

.ledger-table {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--void);
  will-change: transform, opacity;
}
/* Same reasoning as the hero feed: time and judgment were holding more width
   than their longest value needs, and the surplus was coming out of the agent
   and outcome columns, which ellipsed "procurement.agent" and "$19,270 ·
   recovered" on a 1200px laptop. */
.ledger-cols,
.ledger-row {
  display: grid;
  grid-template-columns:
    62px minmax(0, 1.12fr) minmax(0, 1.45fr) minmax(0, 0.66fr)
    minmax(0, 1.28fr);
  gap: 0 clamp(10px, 1.4vw, 20px);
  align-items: center;
  padding: 0 clamp(18px, 2vw, 26px);
}
.ledger-cols {
  min-height: 46px;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-tight);
  color: var(--faint);
  border-bottom: 1px solid var(--line-soft);
}
.ledger-row {
  min-height: 58px;
  border-top: 1px solid var(--line-soft);
}
.ledger-row:first-of-type {
  border-top: 0;
}
.lg-t,
.lg-agent,
.lg-j,
.lg-out {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lg-t {
  color: var(--faint);
}
.lg-out {
  font-variant-numeric: tabular-nums lining-nums;
}
.lg-action {
  font-size: var(--fs-md);
  letter-spacing: -0.012em;
  color: var(--peak);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Corrected / escalated: the one accent this page spends, same amber the
   boundary uses for "ask". */
.lg-j--flag {
  color: var(--amber);
}

/* Rows 2-5 drop in whole. The first row is typed field by field instead, so
   the reader learns what an episode contains before volume starts. */
.ledger.is-live .ledger-row {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 0.42s ease,
    transform 0.42s ease;
  will-change: transform, opacity;
}
.ledger.is-live .ledger-row.is-on {
  opacity: 1;
  transform: none;
}
/* The first row's cells are emptied by JS and refilled on scroll, so the row
   itself is present from the start. */
.ledger.is-live .ledger-row--first {
  opacity: 1;
  transform: none;
}
.ledger.is-live .ledger-row--first [data-ledger-field] {
  min-height: 1em;
}
[data-ledger-field].is-typing::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 1.05em;
  margin-left: 1px;
  vertical-align: -0.18em;
  background: var(--peak);
}

/* ---- the engine ----------------------------------------------------------
   .engine-box supplies the panel; these are the states it moves through. */
.ledger-engine {
  opacity: 0.34;
  border-color: var(--line-soft);
  transition:
    opacity 0.5s ease,
    border-color 0.5s ease;
  will-change: opacity;
}
.ledger-engine.is-holding {
  opacity: 1;
  border-color: var(--line-hard);
}
.ledger-engine.is-live {
  opacity: 1;
  border-color: rgba(245, 184, 61, 0.55);
  animation: ledgerHold 2.8s ease-in-out infinite;
}
/* A ring, not a glow: one hairline of amber breathing at the border. */
@keyframes ledgerHold {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(245, 184, 61, 0);
    border-color: rgba(245, 184, 61, 0.3);
  }
  50% {
    box-shadow: 0 0 0 1px rgba(245, 184, 61, 0.32);
    border-color: rgba(245, 184, 61, 0.62);
  }
}

@media (min-width: 1100px) {
  .ledger-stage {
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  }
}

/* Below the pin breakpoint the section is a normal block: no sticky, no
   travel. field.js swaps the scroll driver for an IntersectionObserver and
   the same beats play once, on a timer. The height half of the query is the
   same rule the other two pinned sections follow — the stage runs ~670px with
   its padding, so a window under 776px cannot hold it. */
@media (max-width: 899px), (max-height: 775px) {
  .ledger {
    height: auto !important;
  }
  .ledger.is-live .ledger-sticky,
  .ledger-sticky {
    position: static;
    min-height: 0;
    padding: 0;
  }
}

@media (max-width: 899px) {
  /* Edge to edge: the gutter is worth more spent on the columns than on
     margin, and it is what lets the type stay at system sizes here. */
  .ledger-table {
    margin-inline: calc(var(--gutter) * -1);
    border-inline: 0;
    border-radius: 0;
  }
  .ledger-cols,
  .ledger-row {
    grid-template-columns: 56px minmax(0, 1.02fr) minmax(0, 0.98fr);
    gap: 0 8px;
    /* Tighter than the page gutter: the table is edge to edge here, and the
       reclaimed 16px is what keeps the longest action label off the ellipsis. */
    padding: 0 16px;
  }
  .ledger-row {
    min-height: 52px;
  }
  /* Back to the system label size here: at 390px the three columns are sized
     so nothing ellipses, which is the whole reason the table is full-bleed. */
  .ledger-cols,
  .lg-t,
  .lg-out {
    font-size: var(--label);
  }
  .lg-action {
    font-size: var(--fs-sm);
  }
  /* Action and outcome carry the story on a narrow screen; agent and
     judgment repeat down the column and are dropped rather than crushed. */
  .ledger-cols span:nth-child(2),
  .ledger-cols span:nth-child(4),
  .lg-agent,
  .lg-j {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   4 — The living operating profile
   --------------------------------------------------------------------------
   One solid panel standing on the field. It pins the dark tokens rather than
   inheriting the section's, so it reads the same wherever it's used: the four
   verdict colors were tuned as accents against the dark ground and lose their meaning
   on cream — the same reason the Solutions field holds its own ground — and
   the section wants a single focal panel regardless.
   -------------------------------------------------------------------------- */

.profile {
  /* The .section--light token flip, run in the opposite direction. */
  --void: #161614;
  --raise: #161614;
  --raise-2: #20201c;

  --peak: #f4f1ea;
  --signal: rgba(244, 241, 234, 0.9);
  --dim: rgba(244, 241, 234, 0.72);
  --dimmer: rgba(244, 241, 234, 0.58);
  --faint: rgba(244, 241, 234, 0.5);

  --line: rgba(244, 241, 234, 0.14);
  --line-soft: rgba(244, 241, 234, 0.09);
  --line-hard: rgba(244, 241, 234, 0.28);

  color: var(--signal);
}

.agent-bar {
  margin-bottom: clamp(16px, 1.8vw, 26px);
}

/* Reads as a pulse, not a headline: the same mono micro-label the rest of the
   card uses, one step quieter, and in sentence case like the metadata beside
   it rather than the tracked caps the section tags use. */
.profile-pulse {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--faint);
  white-space: nowrap;
}
/* Steady, not pulsing. The card's own markup notes that "Updated 2m ago" is
   fixed copy with no data source behind it, and a heartbeat on a value that
   never changes is animation pretending to be telemetry. The colour still
   carries "this profile is live"; the motion was claiming more than that. */
.profile-pulse-mark {
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--live);
  box-shadow: 0 0 0 3px rgba(76, 195, 138, 0.16);
}

/* Prose, not a label — "Production · vendor verification and invoice
   matching" runs 53 characters. The 0.08em it used to carry is tracking meant
   for six-character chips, and at this length it pulls the words apart faster
   than they can be read. Mono keeps it in the card's telemetry register; the
   tracking goes back to something a sentence can survive. */
.profile-sub {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.01em;
  color: var(--dimmer);
}

/* Three readings of the same agent, side by side — the point being that they
   are three views of one thing, not three products. */
.dims {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}
.dim {
  display: flex;
  flex-direction: column;
  padding: clamp(22px, 2.4vw, 30px);
  background: var(--void);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
}
.dim-label {
  margin: 0 0 14px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--faint);
}
.dim-title {
  margin: 0 0 26px;
  font-size: var(--fs-lg);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--peak);
  text-wrap: balance;
}
.dim-fig {
  margin-bottom: 24px;
}
/* Pushed to the bottom so the three closing paragraphs align with each other
   however tall their figures turn out. */
.dim-copy {
  margin: auto 0 0;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--dimmer);
  text-wrap: pretty;
}

/* Capability — contextual competence, as bands rather than a number. Three
   segments carry "how far along" without publishing a score. */
.cap,
.bands {
  border-bottom: 1px solid var(--line-soft);
}
.cap-scope,
.bands-scope {
  margin: 0 0 4px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--dim);
}
.cap-row,
.band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 11px 0;
  border-top: 1px solid var(--line-soft);
}
.cap-name,
.band-name {
  flex: 1 1 110px;
  min-width: 0;
  font-size: var(--fs-sm);
  letter-spacing: -0.01em;
  color: var(--signal);
}
/* Authority moves in both directions, and this glyph is the only place the
   card says so. Sized and coloured to register on a scan without pulling
   rank on the Act/Ask/Deny column, which stays the primary read.

   No new hue: promotion brightens to the ground's own cream, and a pull-back
   borrows the red the Restricted tier already carries. */
.band-delta {
  display: inline-block;
  margin-left: 7px;
  font-family: var(--mono);
  font-size: var(--label);
  line-height: 1;
  vertical-align: baseline;
}
.band-delta--up {
  color: var(--peak);
}

/* The band label sets its own column width, so "STRONG", "DEVELOPING" and
   "NEEDS REVIEW" were pushing their meters to three different x positions —
   a 49px stagger down a figure whose whole purpose is comparing the rows
   against each other. Reserve the longest label's width and right-align into
   it, and the meters land in one column. */
.cap-band,
.band-verdict {
  flex: none;
  min-width: 6.5rem;
  text-align: right;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  text-transform: uppercase;
}

.meter {
  flex: none;
  display: flex;
  gap: 3px;
}
.meter span {
  display: block;
  width: 13px;
  height: 6px;
  background: var(--line);
}
.cap-row[data-band="strong"] .meter span {
  background: var(--peak);
}
.cap-row[data-band="developing"] .meter span:nth-child(-n + 2) {
  background: var(--dim);
}
.cap-row[data-band="review"] .meter span:nth-child(1) {
  background: var(--amber);
}
.cap-row[data-band="strong"] .cap-band {
  color: var(--peak);
}
.cap-row[data-band="developing"] .cap-band {
  color: var(--dimmer);
}
.cap-row[data-band="review"] .cap-band {
  color: var(--amber);
}

/* Learning — corrections on the same class of work, thinning out. The claim
   is the shape of the run, not any value on it, so the plot carries no scale.
   Layout and labels live with the shared figure primitives; this is only the
   mark colour. */
.learn-bars rect {
  fill: rgba(244, 241, 234, 0.42);
}

/* Authority — the operating boundary, in the page's four-verdict vocabulary.
   "Audit" is the hollow mark: it went through, and the record gets read. */
.band-mark {
  flex: none;
  display: block;
  width: 4px;
  height: 20px;
}
.band[data-verdict="act"] .band-mark {
  background: var(--peak);
}
.band[data-verdict="act"] .band-verdict {
  color: var(--peak);
}
.band[data-verdict="audit"] .band-mark {
  box-shadow: inset 0 0 0 1px var(--dim);
}
.band[data-verdict="audit"] .band-verdict {
  color: var(--dim);
}
.band[data-verdict="ask"] .band-mark {
  background: var(--amber);
}
.band[data-verdict="ask"] .band-verdict {
  color: var(--amber);
}
.band[data-verdict="deny"] .band-mark {
  background: var(--red);
}
.band[data-verdict="deny"] .band-verdict {
  color: var(--red);
}

@media (max-width: 720px) {
  .agent-bar-meta {
    align-items: flex-start;
  }
}

/* --------------------------------------------------------------------------
   7 — Questions
   --------------------------------------------------------------------------
   A hairline-separated list, not a stack of cards: the page already spends its
   borders on the figure panels, and boxing five questions as well would read
   as more structure than the content has.

   The open/close animates grid-template-rows 0fr -> 1fr rather than a measured
   pixel height, so there is no JS measurement in the transition and nothing to
   recompute on resize. The mark is a CSS plus that turns 45 degrees into a
   cross, keeping it on the page's hairline vocabulary instead of importing an
   icon set for one glyph.
   -------------------------------------------------------------------------- */

.faq {
  border-top: 1px solid var(--line-soft);
  max-width: 88ch;
}
.faq-item {
  border-bottom: 1px solid var(--line-soft);
}
.faq-q {
  margin: 0;
}
.faq-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(20px, 3vw, 48px);
  width: 100%;
  padding: clamp(18px, 2vw, 26px) 0;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--peak);
  transition: color 0.2s ease;
}
.faq-btn:hover {
  color: #fff;
}
.faq-label {
  font-family: var(--sans);
  font-size: var(--fs-lg);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.4;
  text-wrap: pretty;
}

.faq-mark {
  position: relative;
  flex: none;
  width: 12px;
  height: 12px;
  transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.faq-mark::before,
.faq-mark::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: var(--dim);
}
.faq-mark::before {
  width: 100%;
  height: 1px;
}
.faq-mark::after {
  width: 1px;
  height: 100%;
}
.faq-btn[aria-expanded="true"] .faq-mark {
  transform: rotate(45deg);
}
.faq-btn[aria-expanded="true"] .faq-mark::before,
.faq-btn[aria-expanded="true"] .faq-mark::after {
  background: var(--peak);
}

/* The closing space lives on the paragraph, not on the grid item: padding on
   the item itself sits outside the 0fr track and left every collapsed answer
   26px tall. */
.faq-a-inner {
  min-height: 0;
}
.faq-a-inner p {
  margin: 0;
  padding-bottom: clamp(18px, 2vw, 26px);
  max-width: 68ch;
  font-size: var(--fs-md);
  line-height: 1.72;
  color: var(--dim);
  text-wrap: pretty;
}

/* Collapsed only once JS is driving; without it every answer stays open. */
.faq.is-live .faq-a {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  opacity: 0;
  transition:
    grid-template-rows 0.34s cubic-bezier(0.2, 0.7, 0.2, 1),
    opacity 0.26s ease;
}
.faq.is-live .faq-a.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
}

/* --------------------------------------------------------------------------
   8 — The business case, and the ask
   -------------------------------------------------------------------------- */

/* The one section that does not need the full closing padding: nothing
   follows it but the footer, which opens with generous space of its own. At
   the standard 168px the request button sat in a visible pocket of nothing. */
.section--cta {
  border-top: 1px solid var(--line);
  padding-bottom: clamp(64px, 7vw, 104px);
}

/* Understand → improve → delegate. The rule above each step widens as the
   sequence advances: the structural device is the argument, which is why the
   steps carry no numbers — the order is already visible. */

/* The same list idiom the Solutions audiences use — one claim per line, no
   card, nothing to weigh up. */

/* The closing ask. Single column until there is genuinely room for two — the
   headline had been leaving the right half of the page empty on any desktop
   viewport, which read as an unfinished section rather than as breathing room
   at the one moment the page is asking for something. */
/* .cta-block is the only thing in this section now, so its own offset rule
   would draw a second hairline a few inches under .section--cta's. */
/* A centred stack: eyebrow, headline, one supporting line, then the action.
   The two-column split this replaces put the button out to the side, which
   only worked while there was a paragraph holding that column up. */
.cta-block {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: clamp(16px, 1.8vw, 24px);
}
.cta-lede {
  margin: 0;
  max-width: 46ch;
  font-size: var(--fs-lg);
  line-height: 1.6;
  color: var(--dim);
  text-wrap: pretty;
}
/* The action gets more room above it than the copy does between its own
   lines, so the stack reads as two groups rather than four evenly spaced
   items. */
.cta-side {
  margin-top: clamp(14px, 2vw, 26px);
}
.cta-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(20px, 2.4vw, 28px);
  width: 100%;
}
.cta-title {
  margin: 0;
  max-width: 20ch;
  font-size: clamp(32px, 4.6vw, 68px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.04;
  color: var(--peak);
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   Site footer
   --------------------------------------------------------------------------
   Brand and tagline on the left, real destinations on the right. Every link
   goes somewhere that exists: five in-page anchors, the privacy page, and the
   two social accounts. Nothing here is a placeholder.

   The mark and wordmark are the nav's own .brand component reused rather than
   redrawn, so there is one logo on the page, not two that drift apart.
   -------------------------------------------------------------------------- */

.site-footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--line);
  padding-top: clamp(44px, 5vw, 72px);
}
.site-footer-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(34px, 4vw, 64px);
  padding-inline: var(--gutter);
  padding-bottom: clamp(36px, 4vw, 60px);
}
.site-footer-brand {
  display: grid;
  gap: 16px;
  align-content: start;
}
.site-footer-tagline {
  margin: 0;
  max-width: 42ch;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--dimmer);
  text-wrap: pretty;
}

.site-footer-nav {
  display: grid;
  /* Auto-fit rather than a fixed two: one column left, and the track should
     not reserve space for a second that no longer exists. */
  grid-template-columns: repeat(auto-fit, minmax(0, max-content));
  gap: clamp(28px, 4vw, 72px);
}
.site-footer-col ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 11px;
}
/* Same weight and colour as the comparison card titles, a step down in size:
   a column heading has to sit under the wordmark, not compete with it. */
.site-footer-head {
  margin: 0 0 16px;
  font-size: var(--fs-md);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--peak);
}
.site-footer-col a {
  font-size: var(--fs-sm);
  color: var(--dimmer);
  transition: color 0.2s ease;
}
.site-footer-col a:hover,
.site-footer-col a:focus-visible {
  color: var(--peak);
}

.site-footer-bottom {
  padding: clamp(18px, 2vw, 24px) var(--gutter);
  border-top: 1px solid var(--line-soft);
}
.site-footer-bottom p {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track-tight);
  color: var(--faint);
}

@media (min-width: 760px) {
  .site-footer-top {
    grid-template-columns: minmax(0, 1.15fr) auto;
    gap: clamp(40px, 6vw, 120px);
  }
  .site-footer-nav {
    grid-auto-flow: column;
    justify-content: end;
  }
}

/* --------------------------------------------------------------------------
   404
   -------------------------------------------------------------------------- */

/* The nav is fixed and takes no flow space, so let flex do the arithmetic
   rather than hard-coding chrome heights. */
.page--sparse {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

/* Same measure as every other page: the 1280 wrap plus the page gutter. It
   used to run on a gutter of its own, which put the copy on a different left
   edge from the footer underneath it once both pages started sharing one. */
.notfound {
  position: relative;
  z-index: 2;
  flex: 1;
  width: min(1280px, 100%);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(88px, 16vh, 190px) var(--gutter);
}
.section-tag {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
  margin-bottom: clamp(30px, 5vh, 56px);
}
.notfound-title {
  margin: 0;
  max-width: 16ch;
  font-size: clamp(34px, 5.4vw, 74px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.02;
  color: var(--peak);
  text-wrap: balance;
  animation: riseIn 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.08s both;
}
.notfound-copy {
  margin: clamp(20px, 2.8vh, 30px) 0 clamp(32px, 4.4vh, 48px);
  max-width: 46ch;
  font-family: var(--mono);
  font-size: var(--fs-sm);
  line-height: 1.9;
  color: var(--dim);
  text-wrap: pretty;
  animation: riseIn 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.2s both;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

/* "X" is barely 8px of glyph. Grow the hit area to a comfortable tap target
   without growing the mark itself — the inset stays inside the flex gap, so
   the two links never overlap. */

/* --------------------------------------------------------------------------
   Breakpoints
   -------------------------------------------------------------------------- */

@media (min-width: 720px) {
  .panel-dl {
    grid-template-columns: 170px 1fr;
    column-gap: 28px;
  }
  .panel-dl dt {
    padding-top: 18px;
  }
  .panel-dl dd {
    margin: 0 0 20px;
    padding-top: 16px;
    border-top: 1px solid var(--line-soft);
  }
}

@media (min-width: 900px) {
  .nav-links {
    display: flex;
  }
}

/* One "wide" breakpoint for the whole page, shared with the trajectory. The
   hero feed and the ledger are both five-column tables of real strings; at
   900px a two-column parent left them around 430px and 595px, which ellipsed
   most of the agent names and outcomes. Below this they each take the full
   measure and read in full. */
@media (min-width: 1100px) {
  .hero-grid {
    grid-template-columns: 1fr 0.92fr;
  }
}

/* Phones: the hero has to fit one screen in a single stacked column, so the
   vertical rhythm tightens across the board rather than any one element
   giving up all the room. */
@media (max-width: 759px) {
  .hero-grid {
    gap: clamp(20px, 4vh, 40px);
    padding-block: clamp(16px, 3vh, 32px);
  }
  .eyebrow {
    margin-bottom: clamp(10px, 2vh, 20px);
  }
  .hero-lede {
    margin-top: clamp(12px, 2vh, 22px);
  }
  .hero-actions {
    margin-top: clamp(16px, 2.5vh, 28px);
  }
  .status-pill {
    margin-top: clamp(12px, 2vh, 20px);
  }
}

/* Small phones: the ladder's right-hand note column costs more than it earns. */

/* --------------------------------------------------------------------------
   Legal (privacy policy, etc.)
   -------------------------------------------------------------------------- */

.legal-main {
  position: relative;
  z-index: 2;
  width: min(1280px, 100%);
  margin-inline: auto;
  padding: clamp(96px, 14vh, 150px) var(--gutter) clamp(60px, 8vh, 96px);
}
.legal-head {
  max-width: 68ch;
  margin-bottom: clamp(36px, 5.5vh, 60px);
}
.legal-title {
  margin: 0;
  max-width: 20ch;
  font-size: clamp(30px, 4vw, 52px);
  font-weight: 500;
  letter-spacing: -0.036em;
  line-height: 1.05;
  color: var(--peak);
  text-wrap: balance;
}
.legal-updated {
  margin: 14px 0 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: var(--track);
  color: var(--dimmer);
}
.legal-body {
  max-width: 68ch;
}
.legal-body h2 {
  margin: clamp(40px, 5.5vh, 56px) 0 14px;
  font-size: clamp(18px, 1.8vw, 22px);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--peak);
}
.legal-body h2:first-child {
  margin-top: 0;
}
.legal-body p {
  margin: 0 0 16px;
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--dim);
  text-wrap: pretty;
}
.legal-body ul {
  margin: 0 0 16px;
  padding-left: 1.3em;
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--dim);
}
.legal-body li {
  margin-bottom: 6px;
}
.legal-body li::marker {
  color: var(--dimmer);
}
.legal-body strong {
  color: var(--signal);
  font-weight: 600;
}
.legal-body a {
  text-decoration: underline;
  text-decoration-color: var(--line-hard);
  text-underline-offset: 3px;
}
.legal-back {
  margin-top: clamp(40px, 6vh, 64px);
}

/* --------------------------------------------------------------------------
   Secondary pages — Solutions
   -------------------------------------------------------------------------- */

/* Audience list (Solutions): who they are, what they're stuck with, what
   they get, repeated per audience. No heading sits above the list and it's
   the last section before the footer, so it only needs enough top/bottom
   padding to clear the surrounding borders, not the full section padding
   a heading or a following section would need. */
#audiences {
  padding-top: clamp(32px, 4vw, 56px);
  padding-bottom: clamp(32px, 4vw, 56px);
}
.audience-list {
  border-top: 1px solid var(--line);
}
.audience-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 3.4vw, 64px);
  align-items: start;
  padding: clamp(34px, 4.4vw, 68px) 0;
  border-bottom: 1px solid var(--line-soft);
}
.audience-who {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: -0.005em;
  color: var(--amber);
}
.audience-head {
  font-size: clamp(23px, 2.9vw, 44px);
  line-height: 1;
  letter-spacing: -0.04em;
  font-weight: 500;
  margin: 16px 0 0;
  max-width: 15ch;
  color: var(--peak);
  text-wrap: balance;
}
.audience-pain {
  font-size: clamp(14px, 1.15vw, 17px);
  line-height: 1.45;
  color: var(--faint);
  margin: 20px 0 0;
  max-width: 38ch;
  text-wrap: pretty;
}
.audience-secondary {
  display: flex;
  flex-direction: column;
  padding-top: clamp(4px, 1vw, 28px);
}
.audience-gets {
  display: flex;
  flex-direction: column;
  gap: 0;
  list-style: none;
  margin: 0;
  padding-left: 0;
}
.audience-get {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: clamp(14px, 1.2vw, 18px);
  letter-spacing: -0.01em;
  color: var(--signal);
}
.audience-get::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--dimmer);
  flex: none;
  display: block;
}
@media (min-width: 720px) {
  .audience-row {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  }
}

/* Scroll reveal — a block fades and rises into place the first time it
   crosses into view. Applied via IntersectionObserver in field.js.

   Gated on html.js, which field.js sets on load. Without it a blocked or
   failed script would leave every revealed block at opacity 0 forever —
   the same reason the other hidden start states here hang off a class the
   script adds rather than being unconditional. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.7s cubic-bezier(0.2, 0.7, 0.3, 1),
    transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.js [data-reveal].on {
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   Solutions field — the one-hour, fifty-two-action grid. Fixed dark:
   act/ask/refuse are fixed cream/amber/red accents that need a dark ground
   to stay legible, so this section sits outside the light/dark alternation
   the rest of the page follows.
   -------------------------------------------------------------------------- */
.field-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  padding-bottom: 12px;
}
.field-head .sec-title {
  margin: 0;
  max-width: 24ch;
}
.field-head .sec-lede {
  max-width: 46ch;
  margin-top: clamp(10px, 1.4vh, 18px);
}
.field-chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: clamp(14px, 1.6vw, 22px);
}
.field-chip {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 14px;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: -0.005em;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  border: 1px solid var(--line-hard);
  border-radius: var(--radius-sm);
  color: var(--dimmer);
  background: transparent;
  transition: 0.15s ease;
}
.field-chip:hover {
  border-color: var(--peak);
  color: var(--dim);
}
.field-chip.is-active {
  background: var(--peak);
  color: var(--void);
  border-color: var(--peak);
}

/* Flex, not a breakpointed grid: the grid and role panel sit side by side
   on any viewport wide enough, and only wrap to stacked where they
   genuinely can't fit. */
.field-body {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(24px, 3vw, 60px);
  margin-top: clamp(16px, 2vw, 28px);
  align-items: flex-start;
}
.field-body > .field-figure {
  flex: 1.6 1 400px;
  min-width: 320px;
}
.field-grid {
  display: grid;
  grid-template-columns: repeat(13, minmax(0, 1fr));
  gap: clamp(4px, 0.6vw, 8px);
}
.field-cell {
  display: block;
  aspect-ratio: 1;
  transition: 0.3s cubic-bezier(0.2, 0.7, 0.3, 1);
  opacity: 0.5;
  border: 1px solid var(--line);
  background: transparent;
}
.field-cell--act.is-on {
  background: var(--peak);
  border-color: transparent;
  opacity: 1;
}
.field-cell--ask.is-on {
  background: var(--amber);
  border-color: transparent;
  opacity: 0.9;
}
.field-cell--no.is-on {
  background: var(--red);
  border-color: transparent;
  opacity: 0.9;
}
.field-panel {
  flex: 1 1 300px;
  min-width: 240px;
  max-width: 520px;
  border-left: 1px solid var(--line-hard);
  padding-left: clamp(20px, 2.4vw, 34px);
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 1vw, 14px);
}
.field-panel-who {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--amber);
}
.field-panel-head {
  font-size: clamp(20px, 2.4vw, 36px);
  line-height: 1.08;
  letter-spacing: -0.038em;
  font-weight: 500;
  margin: 0;
  max-width: 20ch;
  color: var(--peak);
  text-wrap: balance;
}
.field-panel-reading {
  font-size: clamp(15px, 1.25vw, 19px);
  line-height: 1.4;
  margin: 0;
  color: var(--dim);
  max-width: 46ch;
  text-wrap: pretty;
}
.field-panel-metric {
  margin-top: auto;
  padding-top: clamp(8px, 1vw, 14px);
  border-top: 1px solid var(--line);
}
.field-panel-metric-k {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--dimmer);
}
.field-panel-metric-v {
  display: block;
  font-size: clamp(32px, 4vw, 60px);
  letter-spacing: -0.05em;
  font-weight: 500;
  line-height: 1;
  margin-top: 10px;
  color: var(--peak);
  font-variant-numeric: tabular-nums;
}
