/* Skema landing — the editorial identity.
 *
 * Scoped entirely under `.lp` so it cannot leak into the portal, which is
 * still on the dark-glass theme. When M1 retones the workspace, these tokens
 * are the source it adopts.
 *
 * FONT: Geist / Geist Mono. The CSP is `font-src 'self'` and
 * `style-src-elem 'self'`, so a Google Fonts <link> is BLOCKED — the font
 * must be self-hosted under /static/fonts/ or the page silently falls back.
 * The @font-face blocks below are written for the self-hosted files and are
 * inert until those files exist; the stack degrades to a system grotesque
 * meanwhile rather than breaking. */

@font-face {
  font-family: "Geist";
  src: url("/static/fonts/Geist-Variable.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-display: swap;
}
/* Instrument Serif carries the headlines. A high-contrast display serif
 * against a neutral grotesque is the oldest premium pairing there is, and it
 * does something Geist alone cannot: it says the page was designed rather
 * than shipped. Geist keeps everything a reader actually works through -
 * body, cards, labels - because a display serif at 13px is unreadable.
 *
 * Real italic, not synthesised: the "why it compounds" headline hangs its
 * entire point on <em>your</em>, and a browser-slanted high-contrast serif
 * shears the thick/thin axis and looks broken. */
@font-face {
  font-family: "Instrument Serif";
  src: url("/static/fonts/InstrumentSerif-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Serif";
  src: url("/static/fonts/InstrumentSerif-Italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/static/fonts/GeistMono-Variable.woff2") format("woff2-variations");
  font-weight: 400 500;
  font-display: swap;
}

.lp {
  /* ground + ink */
  --bone: #f7f5f1;
  --paper: #fffdfa;
  --alt: #f1eee8;
  --ink: #17140f;
  --ink-2: #3a342c;
  --muted: #635d54;          /* darkened from #6C665C for AA on bone */
  --muted-q: #6f6961;
  --line: #e3ded4;
  --line-2: #cfc7ba;

  /* the one accent */
  --wine: #7e2230;
  --wine-deep: #5c161f;
  --wine-tint: #f6ebec;
  --wine-line: #e8c0c6;

  /* inverted band */
  --dark: #17140f;
  --dark-line: #2c271f;
  --dark-ink: #f7f5f1;
  --dark-muted: #a9a296;
  --dark-kicker: #8f887c;
  --dark-wine: #c08a93;

  /* semantic, separate from the accent */
  --ok: #2e6448;
  --warn: #8a5a12;

  --sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --display: "Instrument Serif", "Iowan Old Style", Georgia, "Times New Roman", serif;

  position: fixed;
  inset: 0;
  /* Above the sign-in gate (1200). The old landing sat at z-index 100, so
   * with auth enabled the gate covered it and NOBODY EVER SAW THIS PAGE.
   * The intended order is: read the pitch, choose to enter, then sign in.
   * landing.js keeps the gate inert while this is up so the password field
   * underneath cannot take focus. */
  z-index: 1300;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: opacity .55s cubic-bezier(.22,.61,.36,1);
}
.lp.lp-leaving { opacity: 0; pointer-events: none; }
.lp ::selection { background: var(--wine); color: var(--bone); }

.lp a { color: var(--wine); text-decoration: none; }
.lp a:hover { color: var(--wine-deep); }
.lp :focus-visible { outline: 2px solid var(--wine); outline-offset: 3px; border-radius: 4px; }

/* Reset the portal's GLOBAL ELEMENT rules before they leak in.
 *
 * style.css styles bare `h1`, `h2` and `button` for the workspace — `h2` in
 * particular is a 0.72rem uppercase --faint eyebrow. A class like `.lp-h2`
 * out-specifies it only for the properties it actually declares, so colour
 * and text-transform fell straight through and every section heading on this
 * page rendered as small-caps portal-blue. Reset the whole family here rather
 * than remembering to redeclare each property on each component. */
/* `:where()` contributes ZERO specificity, so each of these lands at exactly
 * element weight (0,0,1) — the same as style.css's bare `h2`, and later in
 * source order, so it wins. Crucially it still LOSES to `.lp-h2` (0,1,0), so
 * the components keep their own type scale. Writing this as `.lp h2` would
 * score (0,1,1) and silently flatten every heading size on the page. */
:where(.lp) h1, :where(.lp) h2, :where(.lp) h3, :where(.lp) h4 {
  color: inherit; text-transform: none; margin: 0;
  font-size: inherit; font-weight: inherit; letter-spacing: inherit;
  line-height: inherit;
}
.lp h1, .lp h2, .lp h3 { text-wrap: balance; }
.lp p { text-wrap: pretty; margin: 0; }
/* Same story for landmarks. style.css styles a bare `header` as the portal's
 * dark glass bar — `color:#fff`, a blue gradient, blur, max-width, margins —
 * and `.lp-nav` IS a <header>, so the landing's brand rendered white-on-bone
 * (1.09:1, invisible) until this reset. Neutralise the whole element rule and
 * let .lp-nav own its own appearance. */
:where(.lp) header, :where(.lp) main, :where(.lp) footer {
  color: inherit; background: none; backdrop-filter: none;
  -webkit-backdrop-filter: none; box-shadow: none; border: 0;
  max-width: none; width: auto; margin: 0; padding: 0;
  display: block; border-radius: 0;
}
:where(.lp) button { font-weight: inherit; letter-spacing: inherit; transition: none; }
:where(.lp) button:hover { filter: none; transform: none; }
:where(.lp) button:active { filter: none; }

/* ---------- shared rhythm ----------
 * Every section is a screen. You read one, scroll, read the next — so the
 * sections own the viewport height and centre their own content, and the
 * scroll container snaps between them.
 *
 * `proximity`, deliberately not `mandatory`: two sections (the six problems,
 * the eight-row ledger) exceed 100vh on a short window, and mandatory snap
 * makes the overflow of a taller-than-viewport section unreachable. Proximity
 * gives the slide feel where it fits and gets out of the way where it does not. */
.lp {
  scroll-snap-type: y proximity;
  /* The nav is sticky and 60px tall, so a section snapped flush to the
   * container top would tuck its first 60px underneath it. scroll-padding
   * moves the snap line down by exactly the header. */
  scroll-padding-top: 60px;
}

.lp-wrap { max-width: 1280px; margin: 0 auto; }
.lp-sec {
  /* vh, not vw: this is VERTICAL rhythm, and it must follow the height
     of the window rather than its width. One continuous rule instead of
     a base plus two height tiers, which snapped at 1010 and 1200. */
  /* A flat vh coefficient is too loose when short and too tight when
     tall - 4.4vh gave a 720px window MORE padding than the fixed tier
     it replaced. An offset slope is tight at the bottom and opens up
     as the window grows: 23px at 720, 32px at 1080, 41px at 1440. */
  padding: clamp(20px, calc(2.4vh + 6px), 80px) clamp(20px,5vw,64px);
  min-height: 100vh;
  display: flex; flex-direction: column; justify-content: center;
  scroll-snap-align: start;
}
/* The closing section carries the footer, which belongs at the bottom of the
 * screen rather than centred with the call to action. */
.lp-final { justify-content: space-between; }
.lp-final > .lp-wrap { margin-top: auto; }
.lp-final > .lp-footer { margin-top: auto; }
.lp-sec-dark { background: var(--dark); color: var(--dark-ink); }
.lp-sec-alt { background: var(--alt); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

.lp-kicker {
  font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 600; color: var(--muted-q); margin-bottom: 16px;
}
.lp-sec-dark .lp-kicker { color: var(--dark-kicker); }

.lp-h2 {
  font-size: clamp(28px,3.4vw,42px); font-weight: 500;
  letter-spacing: -.03em; line-height: 1.15; max-width: 24ch;
}
.lp-sub { margin-top: 14px; font-size: 16px; color: var(--muted); max-width: 58ch; }
.lp-sec-dark .lp-sub { color: var(--dark-muted); }

/* ---------- header ---------- */
.lp-nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 24px; height: 60px;
  padding: 0 clamp(20px,5vw,64px);
  background: linear-gradient(180deg, rgba(247,245,241,.985), rgba(247,245,241,.94));
  backdrop-filter: blur(12px) saturate(1.1);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
  /* Full-strength rule rather than the source design's rgba(...,.7): on bone,
   * a 70%-opacity hairline under a bone-on-bone bar is invisible, so the
   * header stopped reading as a header. */
  border-bottom: 1px solid var(--line);
}
.lp-brand { display: flex; align-items: baseline; gap: 9px; }
/* Deliberately NOT a flex container. `.lp-brand` aligns its children on
   the BASELINE, and a flex box takes its baseline from its first item -
   which would be the mark, an SVG with no text baseline, so the browser
   falls back to its bottom edge and drops the tagline below the wordmark.
   Left as inline text flow, `.lp-logo` keeps the wordmark's own baseline
   and the tagline sits where it always did. */
.lp-logo { font-family: var(--mono); font-weight: 500; font-size: 15px; letter-spacing: -.02em; }
.lp-logo__mark { width: 22px; height: 22px; vertical-align: -5px; margin-right: 8px; }
.lp-logo-tag { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-q); }
.lp-nav-links { display: flex; gap: 22px; margin-left: auto; align-items: center; }
.lp-nav-links a { font-size: 13.5px; color: var(--muted); }
.lp-nav-links a:hover { color: var(--ink); }

/* ---------- buttons ---------- */
.lp-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 44px; padding: 0 22px; border-radius: 10px;
  font-size: 15px; font-weight: 500; font-family: inherit;
  cursor: pointer; border: 1px solid transparent;
  transition: background .16s ease, border-color .16s ease, transform .16s ease;
  /* A button with a FIXED height cannot absorb a second line: the label
     leaves the pill and sits on the bar. It happened because the nav links
     were given `nowrap` and this was not, which made the button the only
     item in the row that could shrink - so every pixel of overflow landed
     here. Reproduced at 1536 (a 1920 screen at 125% zoom), 1500, 1420 and
     1200 before this. */
  white-space: nowrap; flex-shrink: 0;
}
.lp-btn-primary { background: var(--ink); color: var(--bone); }
.lp-btn-primary:hover { background: #2a251d; color: var(--bone); }
.lp-btn-ghost { border-color: var(--line-2); background: var(--paper); color: var(--ink); }
.lp-btn-ghost:hover { border-color: var(--ink); color: var(--ink); }
.lp-btn-sm { height: 32px; padding: 0 15px; font-size: 13px; border-radius: 8px; }
.lp-btn:active { transform: translateY(1px); }

/* ---------- hero ---------- */
/* The hero is FULL-BLEED and the inner column carries the measure.
 *
 * It used to be `max-width:1280px; margin:0 auto`, which centred the whole
 * thing — and because the tree is absolutely positioned inside it, the globe
 * was pinned to the edge of that centred box rather than the edge of the
 * screen. On a wide display it floated in the middle of the page with bone on
 * both sides. The globe belongs at the edge of the viewport, half off-screen,
 * so the canopy reads as growing INTO the page from outside it.
 *
 * The inner column keeps the same 1280 measure as `.lp-wrap`, so the headline
 * still lines up with every section below it. */
.lp-hero {
  position: relative; overflow: hidden;
  min-height: 100vh;
  display: flex; flex-direction: column; justify-content: center;
  scroll-snap-align: start;
  /* Top padding is smaller than the source design's clamp(64px,11vw,132px):
   * that assumed the hero owned the whole gap, but a 60px sticky header sits
   * above it, and on a wide viewport the two summed to 192px of dead space
   * before the first word. */
  /* Horizontal padding sits HERE, outside the 1280 measure — exactly the
   * `.lp-sec` + `.lp-wrap` pattern — so the headline lines up with every
   * section below it. Putting it on the inner column instead inset the hero
   * text by an extra 64px and broke that alignment.
   * The tree is unaffected: an absolutely positioned element resolves
   * `inset:0` against the padding box, so it still spans the full width. */
  padding: clamp(36px,4.5vw,80px) clamp(20px,5vw,64px) clamp(48px,7vw,88px);
}
.lp-tree { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
/* The schema model's own type. Mono, because every other label in this
   product is mono, and sized in `em` against a font-size the script solves
   for - so a label renders at 12.5px whatever the fit did to the drawing.
   It must read as the page's own diagram, not as an illustration with its
   own typography. */
/* A room's name sits IN its wall, letter-spaced and upper-case - the way
   a space is named on a plan. */
.lp-sm-room {
  font-family: var(--mono); font-size: 1em; fill: var(--ink-2);
  text-anchor: middle; letter-spacing: .16em;
}
.lp-sm-rel {
  font-family: var(--mono); font-size: .82em; fill: var(--wine);
  text-anchor: middle; letter-spacing: .04em;
}
.lp-sm-tag {
  font-family: var(--mono); font-size: .84em; fill: var(--wine);
  text-anchor: middle; letter-spacing: .14em; text-transform: uppercase;
}
/* The verification pulse scales about its own centre, which needs a box to
   scale in. Scoped to the slot's rect so the wall-crossing markers, which
   are also circles, stay exactly where they are drawn. */
.lp-tree rect { transform-box: fill-box; transform-origin: center; }
.lp-hero-inner {
  position: relative; z-index: 1;
  max-width: 1280px; margin: 0 auto; width: 100%;
}

.lp-pill {
  display: inline-flex; align-items: center; gap: 9px; height: 29px;
  padding: 0 13px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); margin-bottom: 30px;
}
.lp-pill-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--wine); flex-shrink: 0; }
.lp-pill-words { display: flex; gap: .36em; font-family: var(--mono); font-size: 11.5px; color: var(--muted); }
.lp-pill-words span { display: inline-block; }

.lp-title {
  /* phi-scaled. 80px set the current headline as three lines inside a
     16ch measure; 64px in 20ch sets it as two and leaves the hero able
     to hold its own proof row above the fold. */
  font-size: clamp(38px,5.2vw,64px); font-weight: 600; letter-spacing: -.035em;
  line-height: 1.04; max-width: 20ch; margin-bottom: 18px;
}
/* The hero splits on the golden ratio: prose takes the long side, the
   schema diagram behind it is left the short one. Without this the text
   ran the full measure and the drawing read as a small picture pinned to
   the right rather than as the other half of the composition. */
.lp-lede { font-size: clamp(17px,1.6vw,20px); color: var(--muted); max-width: 46ch; line-height: 1.55; margin-bottom: 34px; }
.lp-cta-row { display: flex; gap: 11px; flex-wrap: wrap; margin-bottom: clamp(28px, 3.4vw, 48px); }

/* FIVE children, so five columns. At `repeat(4, ...)` the fifth
   ("Full provenance") wrapped to a second row inside a hero that is
   `min-height:100vh; justify-content:center` - which pushed it off the
   bottom of the screen entirely. */
.lp-proof { display: grid; grid-template-columns: repeat(5, minmax(0,1fr)); border-top: 1px solid var(--line); }
@media (max-width: 1400px) and (min-width: 861px) {
  .lp-proof { grid-template-columns: repeat(3, minmax(0,1fr)); }
}
.lp-proof > div { padding: 20px 22px 0 0; }
.lp-proof-k { font-family: var(--mono); font-size: 15px; color: var(--wine); margin-bottom: 6px; }
.lp-proof-v { font-size: 13.5px; color: var(--muted); line-height: 1.5; }

/* ---------- card grids ---------- */
.lp-grid { display: grid; gap: 12px; }
.lp-grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }

.lp-card {
  border: 1px solid var(--line); border-radius: 13px;
  background: var(--paper); padding: 20px 20px 22px;
}
.lp-card-t { font-size: 15.5px; font-weight: 600; letter-spacing: -.012em; margin-bottom: 7px; }
.lp-card-b { font-size: 13px; color: var(--muted); line-height: 1.55; }

/* problems band, hairline-joined on the dark ground */

/* ---------- the review split ---------- */


/* ---------- capabilities as an index (#lp-capabilities) ----------
 *
 * Twelve equal cards is not a list, it is a wall: nothing is ranked,
 * every box competes, and the eye has no entry point. It was also the one
 * place on this page that broke the design note's own ban on repeated
 * rounded rectangles, while the rest of it does dense editorial rows
 * well - the ledger, the schema history.
 *
 * So: four themes, hairline rows, name and a five-word gist. The
 * paragraph is still there and opens in place, on the rule this codebase
 * already states elsewhere - DECISIONS ARE VISIBLE, JUSTIFICATION IS ON
 * DEMAND.
 *
 * Native <details>, not a JS accordion. Keyboard, touch and screen
 * readers work without a line of script, current browsers expand a closed
 * one for find-in-page, and there is no CSP surface to get wrong. */
/* The affordance is a plus that becomes a minus - a rotating chevron at
   this size reads as a stray hairline. */

@media (max-width: 1000px) {
}
@media (max-width: 620px) {
}

/* ---------- the canvas mock (#lp-canvas) ----------
 * Drawn, not screenshotted. A screenshot of the real canvas would be a
 * picture of one store's terms at one moment, and it would go stale the
 * first time either changed. What has to survive is the LANGUAGE: three
 * tiers of attention, direction on every edge, a relationship carrying
 * its own name, and properties arranged AROUND a concept rather than
 * inside it - which is the specific bug the real canvas had. */

/* the rest of the ontology: dimmed, never removed. Spatial awareness is
   the whole difference between drilling into a graph and being taken to
   a different screen. */


/* Fill is provenance, outline is lifecycle - the same two-axis reading
   the real canvas uses, so the legend below is telling the truth. */
/* Emphasis is size and stroke, not a fourth colour: the focused term is
   the same provenance as its neighbours and must not read as a different
   KIND of thing just because it is the one you clicked. */


/* Five points and a three-line headline: on a 768px-tall laptop the last
   point sat at y=714, and the reveal threshold is 0.9vh - so it was drawn,
   correct, and invisible unless you scrolled PAST the section it belongs
   to. Measured, then tightened until it clears. */

/* ---------- the honesty ledger ---------- */

/* ---------- final ---------- */
.lp-final { text-align: center; }
.lp-final .lp-h2 { max-width: 20ch; margin-inline: auto; font-size: clamp(30px,4vw,52px); font-weight: 600; letter-spacing: -.035em; }
.lp-final .lp-sub { margin-inline: auto; font-size: 17px; max-width: 52ch; }
.lp-final-row { display: flex; gap: 11px; justify-content: center; flex-wrap: wrap; margin-top: 32px; }
.lp-footer {
  border-top: 1px solid var(--line); padding: 26px clamp(20px,5vw,64px);
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  max-width: 1280px; margin: 0 auto;
}
.lp-footer-note { font-size: 12.5px; color: var(--muted-q); }
.lp-footer-tail { margin-left: auto; font-size: 12.5px; color: var(--muted-q); }

/* ---------- motion ---------- */
@keyframes lp-emerge { from { opacity: 0; } to { opacity: var(--o); } }
@keyframes lp-breathe { 0%,100% { opacity: var(--o); } 50% { opacity: var(--o2); } }
@keyframes lp-draw { to { stroke-dashoffset: 0; } }
/* The verification ring: opens once over the proposed slot, fades, waits.
   Two thirds of its cycle is the wait - a pulse with no rest in it reads as
   a spinner, which would say "working" where this has to say "pending". */
@keyframes lp-verify {
  0%   { opacity: 0; transform: scale(1); }
  12%  { opacity: .5; }
  38%  { opacity: 0; transform: scale(2.1); }
  100% { opacity: 0; transform: scale(2.1); }
}
@keyframes lp-word { from { opacity: 0; filter: blur(3px); transform: translateX(-6px); } to { opacity: 1; filter: none; transform: none; } }

.lp .reveal { opacity: 0; transform: translateY(14px); transition: opacity .6s cubic-bezier(.22,.61,.36,1), transform .6s cubic-bezier(.22,.61,.36,1); }
.lp .reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .lp *, .lp *::before, .lp *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .lp .reveal { opacity: 1; transform: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 1000px) {
  .lp-grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .lp-proof { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 900px) {
  .lp-tree { display: none; }
  .lp-nav-links a:not(.lp-btn) { display: none; }
}
@media (max-width: 620px) {
  /* 132px of verdict against 350px of screen leaves the term itself
     wrapping four ways. The verdict is still the first thing read. */
  .lp-grid-4, .lp-proof { grid-template-columns: minmax(0,1fr); }
}

/* The diagram draws the GRAPH, not a pipeline of boxes. The design note
   bans generic dashboard furniture - repeated rounded rectangles and
   arrows between them - and a flowchart of the ingestion steps was
   exactly that, while showing none of the thing being sold.

   Pure CSS, no JS: the CSP is script-src 'self' and the page ships no
   inline script. Under prefers-reduced-motion the `.lp *` block above
   collapses every duration, leaving the finished graph drawn in full. */

/* THE RESTING STATE IS THE FINISHED GRAPH.
 *
 * The first version looped, and every keyframe ended at opacity 0 so the
 * loop could restart. Under prefers-reduced-motion the `.lp *` block
 * collapses duration to .001ms and forces a single iteration - which
 * landed straight on that empty final frame, so a reduced-motion reader
 * got an EMPTY BOX where the product's centrepiece should be. Caught by
 * screenshotting with reduced motion emulated, not by reading the CSS.
 *
 * So: the base styles below draw the graph in full. The animation only
 * plays the entrance, keyed off the `.in` class the reveal observer
 * already adds, with `backwards` so it holds the hidden state during its
 * delay and returns to the drawn base afterwards. If the animation never
 * runs - reduced motion, no JS, an old browser - the graph is simply
 * there, which is the correct fallback for a diagram. */

/* entrance, once, when the section comes into view */

/* the three notes under the diagram */

@media (max-width: 860px) {
}

/* The CTA used to say "open the workspace" without saying what that does.
   Ambiguity at the click is where conversion dies. */
.lp-final-note {
  flex-basis: 100%; margin: 14px auto 0; max-width: 46ch;
  font-size: 12.5px; line-height: 1.6; color: var(--muted); text-align: center;
}

/* ---------- where this sits (lp-choice) ---------- */
.lp-choice {
  margin-top: 34px; display: grid; gap: 16px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.lp-choice-col {
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--paper); padding: 20px 20px 22px;
}
.lp-choice-us { border-color: var(--wine-line); background: var(--wine-tint); }
.lp-choice-h {
  font-size: 15px; font-weight: 600; color: var(--ink);
  padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--line);
}
.lp-choice-us .lp-choice-h { color: var(--wine-deep); border-bottom-color: var(--wine-line); }
.lp-choice-b { font-size: 13px; line-height: 1.65; color: var(--muted); }
.lp-choice-b strong { display: block; margin-top: 10px; color: var(--ink-2); font-weight: 600; }
.lp-choice-us .lp-choice-b { color: var(--ink-2); }
.lp-choice-us .lp-choice-b strong { color: var(--wine-deep); }
@media (max-width: 860px) { .lp-choice { grid-template-columns: 1fr; } }

/* ---------- fitting sections to the viewport ----------
 * Measured with a headless browser at 1366x768, 1512x860 and 1920x1080
 * rather than eyeballed. Before this block the ledger was 2473px - over
 * three screens on a laptop - and the graph section 1147px, so the snap
 * had nothing to snap to and a reader met half a section at a time.
 *
 * `dvh` with a `vh` fallback: on mobile browsers `100vh` is the height
 * with the URL bar HIDDEN, so a section sized in vh is taller than what
 * the reader can actually see and the bottom is cut off on first paint. */
/* NOT 100vh. `.lp-nav` is `position: sticky`, so it stays IN FLOW and eats
   60px: a 100vh section starting below it ends 60px past the fold, and once
   scrolled the nav overlays the same 60px again. A section that is one
   screen tall is one screen MINUS the bar - measured at 1920x1080, where a
   "fitting" 1080px section was really 60px over the visible area. */
:root { --lp-nav: 60px; }
.lp-sec, .lp-hero { min-height: calc(100vh - var(--lp-nav)); }
@supports (height: 100dvh) {
  .lp-sec, .lp-hero { min-height: calc(100dvh - var(--lp-nav)); }
}

/* The graph diagram was sized purely by its aspect ratio, so on a wide
   container it grew to ~500px tall and pushed the section past the fold.
   Cap it and let it centre instead. */

/* Two columns for the ledger. 21 sentences stacked is a scroll, not a
   section; side by side it is a page a reader can take in. */
@media (min-width: 900px) {
}

/* Vertical padding was clamp(56px,8vw,104px) top AND bottom - 208px of air
   on a 1512px viewport, which is most of what pushed the dense sections
   past the fold. Reduced globally; the sections that were already
   comfortable simply centre in more space. */
.lp-sec { padding-block: clamp(40px, 4.5vw, 72px); }

/* Denser ledger rows: 21 sentences have to read as one page, not a scroll. */
@media (min-width: 900px) {
}

/* Final fit pass, all four measured rather than guessed. */
.lp-hero { padding-block: clamp(28px, 3vw, 52px) clamp(32px, 4vw, 60px); }
@media (min-width: 900px) {
  #lp-ledger .lp-sub, #lp-ledger-trust .lp-sub { max-width: 62ch; font-size: 14px; }
}

/* Last 74px: the ledger heading block. A section whose own introduction
   costs a fifth of the screen is a section the reader meets sideways. */
@media (min-width: 900px) {
  #lp-ledger .lp-h2, #lp-ledger-trust .lp-h2 { font-size: clamp(26px, 2.6vw, 38px); }
  #lp-ledger .lp-sub, #lp-ledger-trust .lp-sub { font-size: 13.5px; max-width: 70ch; }
}
.lp-hero { padding-block: clamp(24px, 2.5vw, 44px) clamp(28px, 3.5vw, 52px); }

/* ---------- short viewports ----------
 * The constraint here is viewport HEIGHT, not width: a 1366x768 laptop is
 * wide enough for two ledger columns and still 90px short. Width media
 * queries cannot see that, so these key off height and tighten the
 * vertical rhythm only - measured at 768px, which is still the most
 * common laptop height in the wild. */
@media (max-height: 1010px) {
  .lp-sec { padding-block: clamp(28px, 3vw, 44px); }
  .lp-hero { padding-block: 20px 24px; }
  .lp-h2 { font-size: clamp(24px, 2.4vw, 34px); }
  .lp-sub { font-size: 13.5px; }
  .lp-card { padding: 14px 16px; }
}

/* The hero's four proof points and its lede are what push it past a short
   screen; the headline is the one thing that must not shrink. */
@media (max-height: 1010px) {
  .lp-title { font-size: clamp(32px, 4.2vw, 54px); }
  .lp-lede { font-size: 14px; line-height: 1.6; }
  .lp-lede + .lp-lede { margin-top: 8px; }
  .lp-cta-row { margin-top: 20px; }
  .lp-proof { margin-top: 22px; gap: 10px; }
  .lp-proof-v { font-size: 12px; line-height: 1.45; }
  .lp-pill { margin-bottom: 12px; }
  #lp-ledger .lp-sub { font-size: 13px; }
}

/* The ledger is the densest section on the page; on the shortest laptops it
   needs one more notch and nothing else does. */
@media (max-height: 800px) and (min-width: 900px) {
}

/* Hug the frame to the diagram. The SVG is height-capped, so on a wide
   viewport it stopped well short of a full-width stage and sat in a pool
   of empty box - which reads as a rendering fault rather than a choice. */

/* ---------- source to graph (#lp-transform) --------------------------------
 * A four-stage illustration of the one claim the product is making: messy
 * sources in, a governed ontology out. Three columns - what the world gave
 * you, what was found in it, and the graph that survived review.
 *
 * The stage machinery is CSS, driven by ONE attribute (`data-stage` on
 * `.lp-tf`) that landing.js sets. Two consequences worth keeping:
 *
 *   1. Nothing is built by JS, so there is no innerHTML and no DOM
 *      construction to review - the markup is in index.html where it can
 *      be read, and a screen reader gets the final state as real elements.
 *   2. The resting state is `data-stage="3"` - the FINISHED graph. With no
 *      JS, a dead script, or reduced motion, the reader sees the payoff
 *      rather than an empty frame. This is the same bug the hero diagram
 *      shipped once: an animation whose first keyframe is the empty state
 *      leaves nothing on screen when the animation never runs.
 *
 * So the rules below only ever say what has NOT ARRIVED YET. Anything the
 * current stage does not hide is visible by default. */

.lp-tf { margin-top: 22px; }

.lp-tf-blurbs { min-height: 3.4em; }
.lp-tf-blurb { margin: 0; font-size: 15px; color: var(--muted); max-width: 66ch; line-height: 1.55; }

/* One element per stage; exactly one is in the layout, and in the
   accessibility tree, at a time. */
.lp-tf [data-only] { display: none; }
.lp-tf[data-stage="0"] [data-only="0"],
.lp-tf[data-stage="1"] [data-only="1"],
.lp-tf[data-stage="2"] [data-only="2"],
.lp-tf[data-stage="3"] [data-only="3"] { display: block; }

/* -- the stage tabs -- */
.lp-tf-tabs { display: flex; gap: 2px; margin: 18px 0 16px; flex-wrap: wrap; }
.lp-tf-tab {
  flex: 1 1 150px; text-align: left; padding: 12px 14px 0;
  border: 0; background: transparent; font: inherit; cursor: pointer;
  color: var(--muted); transition: color .4s ease;
}
.lp-tf-tab[aria-pressed="true"] { color: var(--ink); }
.lp-tf-tab-n { display: block; font-family: var(--mono); font-size: 10.5px; margin-bottom: 4px; opacity: .75; }
.lp-tf-tab-l { display: block; font-size: 13.5px; font-weight: 500; }
.lp-tf-tab-bar {
  display: block; height: 2px; margin-top: 11px; border-radius: 2px;
  background: var(--line); transition: background .4s ease;
}
.lp-tf-tab[aria-pressed="true"] .lp-tf-tab-bar { background: var(--wine); }

/* -- the three-column panel -- */
.lp-tf-panel {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, .9fr) minmax(0, 1.3fr);
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: 16px; overflow: hidden;
}
.lp-tf-col { background: var(--paper); padding: 18px 18px 20px; }
.lp-tf-col-graph { background: var(--bone); display: flex; flex-direction: column; }
.lp-tf-h {
  font-size: 10px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted-q); font-weight: 600; margin-bottom: 14px;
}
.lp-tf-h-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.lp-tf-governed {
  font-size: 9.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  white-space: nowrap; padding: 2px 7px; border-radius: 4px;
  background: #e9f1ec; color: var(--ok); letter-spacing: .06em;
  opacity: 0; transition: opacity .5s ease;
}
.lp-tf[data-stage="3"] .lp-tf-governed { opacity: 1; }

/* -- column one: the sources -- */
.lp-tf-files { display: flex; flex-direction: column; gap: 7px; }
.lp-tf-file {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--bone);
  transition: opacity .55s ease, transform .55s cubic-bezier(.22,.61,.36,1), border-color .55s ease;
}
.lp-tf-ext { font-family: var(--mono); font-size: 10px; color: var(--wine); flex-shrink: 0; }
.lp-tf-name {
  flex: 1; font-size: 12.5px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lp-tf-foot {
  margin-top: 13px; padding-top: 11px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 10px; color: var(--muted-q);
}

/* -- column two: what was found -- */
.lp-tf-concepts { display: flex; flex-direction: column; gap: 6px; }
.lp-tf-concept {
  display: flex; flex-direction: column; gap: 3px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--bone);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1);
}
.lp-tf-c-name { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500; color: var(--ink); }
.lp-tf-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
  background: var(--wine); transition: background .5s ease;
}
.lp-tf[data-stage="3"] .lp-tf-dot { background: var(--ok); }
.lp-tf-c-origin { font-family: var(--mono); font-size: 10px; color: var(--muted-q); padding-left: 14px; }

/* -- column three: the graph -- */
.lp-tf-svg { width: 100%; max-height: min(38vh, 330px); display: block; margin-inline: auto; }
.lp-tf-edge {
  stroke: #c9a96e; stroke-width: 1.4; opacity: .85;
  transition: opacity .5s ease;
}
.lp-tf-node circle {
  fill: var(--paper); stroke: #c99aa3; stroke-width: 1.5;
  transition: stroke .5s ease, opacity .55s ease, transform .55s cubic-bezier(.34,1.4,.64,1);
}
.lp-tf[data-stage="3"] .lp-tf-node circle { stroke: var(--ok); }
.lp-tf-node text {
  font-family: var(--sans); font-size: 13px; font-weight: 500; fill: var(--ink);
  text-anchor: middle; dominant-baseline: middle;
}
/* Edge names are the part that says "this is an ontology, not a picture of
   dots", so they land only once the graph is governed. The halo is a stroke
   painted UNDER the fill - cheaper and more robust than measuring text to
   size a background rect. */
.lp-tf-elabel {
  font-family: var(--mono); font-size: 11px; fill: var(--muted-q);
  text-anchor: middle; dominant-baseline: middle;
  stroke: var(--bone); stroke-width: 3.5; paint-order: stroke fill;
  opacity: 0; transition: opacity .5s ease;
}
.lp-tf[data-stage="3"] .lp-tf-elabel { opacity: 1; }

.lp-tf-payoff {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line);
  opacity: 0; transform: translateY(6px);
  transition: opacity .6s ease .25s, transform .6s cubic-bezier(.22,.61,.36,1) .25s;
}
.lp-tf[data-stage="3"] .lp-tf-payoff { opacity: 1; transform: none; }
.lp-tf-payoff-k { font-family: var(--mono); font-size: 10.5px; color: var(--muted-q); margin-bottom: 9px; }
.lp-tf-exports { display: flex; gap: 6px; flex-wrap: wrap; }
.lp-tf-export {
  font-family: var(--mono); font-size: 10.5px; padding: 3px 8px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--paper); color: var(--ink-2);
}

/* THE ONLY RULES THAT HIDE ANYTHING: what has not arrived at this stage.
   Everything else is visible by default, which is what makes the no-JS and
   reduced-motion states correct rather than blank. */
.lp-tf[data-stage="0"] [data-at="1"],
.lp-tf[data-stage="0"] [data-at="2"],
.lp-tf[data-stage="1"] [data-at="2"] { opacity: 0; }
.lp-tf[data-stage="0"] .lp-tf-file[data-at="1"],
.lp-tf[data-stage="0"] .lp-tf-file[data-at="2"],
.lp-tf[data-stage="1"] .lp-tf-file[data-at="2"] { transform: translateX(-6px); border-color: transparent; }
.lp-tf[data-stage="0"] .lp-tf-concept[data-at="1"],
.lp-tf[data-stage="0"] .lp-tf-concept[data-at="2"],
.lp-tf[data-stage="1"] .lp-tf-concept[data-at="2"] { transform: translateY(8px); }
/* SVG children need the fill-box origin or `scale` pivots on the viewBox. */
.lp-tf[data-stage="0"] .lp-tf-node[data-at="2"] circle,
.lp-tf[data-stage="1"] .lp-tf-node[data-at="2"] circle {
  transform-box: fill-box; transform-origin: center; transform: scale(.5);
}
.lp-tf[data-stage="0"] .lp-tf-node[data-at="2"] text,
.lp-tf[data-stage="1"] .lp-tf-node[data-at="2"] text { opacity: 0; }

@media (max-width: 900px) {
  .lp-tf-panel { grid-template-columns: minmax(0, 1fr); }
}
@media (max-height: 1010px) {
  .lp-tf { margin-top: 14px; }
  .lp-tf-tabs { margin: 12px 0 12px; }
  .lp-tf-col { padding: 14px 14px 15px; }
  .lp-tf-svg { max-height: min(32vh, 270px); }
  .lp-tf-file, .lp-tf-concept { padding: 6px 9px; }
  .lp-tf-blurbs { min-height: 3em; }
  .lp-tf-blurb { font-size: 13.5px; }
}

/* Without JavaScript the whole landing page rendered BLANK. `.reveal` starts
   at `opacity: 0` and only `initReveals()` adds `.in`, so every section on
   the page - not just the newest one - depended on a script running to
   become visible at all. That is the same class of bug as an animation
   whose first keyframe is the empty state: the resting state has to be the
   readable one, and the script may only ever improve on it.

   `scripting: none` is the media feature for exactly this, and the rule is
   additive: engines that do not know it ignore it and nothing changes. */
@media (scripting: none) {
  .lp .reveal { opacity: 1; transform: none; }

  /* Same rule, extended. Each rebuilt section hides its own children and
     waits for a class or attribute only a script sets, so `.reveal` alone
     stopped being enough the moment those sections existed. Additive, and
     every one of these has a sensible FIRST state to fall back to. */
  .lp-cs-dot, .lp-cs-top, .lp-cs-h, .lp-cs-list,
  .lp-ev-v, .lp-fp-mn span, .lp-fp-chain li, .lp-fp-dom, .lp-fp-sf,
  .lp-fp-trace, .lp-fp-erow u, .lp-fp-still, .lp-fp-stamp,
  .lp-imp-c, .lp-imp-link u, .lp-imp-note,
  .lp-rv-f, .lp-rv-g, .lp-rv-comp,
  .lp-cp-list li, .lp-cp-said, .lp-cp-hull,
  .lp-q-look, .lp-q-e, .lp-q-drop u, .lp-q-why, .lp-q-valid,
  .lp-sh-o summary, .lp-af > *, .lp-af-gn, .lp-lens-ro, .lp-prop {
    opacity: 1 !important; transform: none !important;
  }
  /* the stacked slots: with no script to choose, show the first state */
  .lp-ev-panel[data-s="0"], .lp-fp-p[data-d="0"],
  .lp-q-slot > [data-for="0"], .lp-cp-slot > [data-s="0"],
  .lp-md-obs, .lp-md-card { opacity: 1; }
  /* the canvas is drawn by script: without one, the geometry does not
     exist. Its readouts are real text and say the same thing. */
  .lp-lens-svg { display: none; }
  .lp-lens-ro { position: static; }
  .lp-lens-ros { display: block; }
}

/* The nav is a single flex row with no wrap guard, so each link added to it
   pushed the row closer to breaking onto a second line - which on a sticky
   60px-tall bar means the second line is simply clipped. Measured: it was
   already wrapping at 1280px before "Source to graph" was added, and that
   link pushed the break up to 1440px.

   Tightening gap and size buys back the room without deciding which
   sections deserve a link, and the row is still comfortable: 13.5 -> 12.5px
   is a nav label, not body copy. Below 900px the links are hidden outright
   by the rule above, so this only has to carry 900-1440px. */
@media (max-width: 1440px) {
  .lp-nav-links { gap: 15px; }
  .lp-nav-links a:not(.lp-btn) { font-size: 12.5px; }
}
@media (max-width: 1340px) {
  .lp-nav { gap: 16px; padding-inline: clamp(16px, 3vw, 40px); }
  .lp-nav-links { gap: 11px; }
  .lp-nav-links a:not(.lp-btn) { font-size: 12px; }
}

/* The nav was at capacity. Two more section links pushed 1200-1366 from
   one row to two, and nine of the eleven broke MID-PHRASE - "Where this
   / sits" - which reads as damage rather than as a menu.
 *
 * So: a link never breaks inside itself, and the row sheds entries as it
 * narrows rather than stacking. What it sheds is chosen by how much the
 * scroll already gives you for free - the sections stay reachable either
 * way, and below 900px the whole set hides as it always did.
 * Breakpoints measured across 920-1600, not guessed. */
.lp-nav-links a:not(.lp-btn) { white-space: nowrap; }
@media (max-width: 1560px) {
  .lp-nav-links { gap: 10px; }
  .lp-nav-links a:not(.lp-btn) { font-size: 11.5px; }
  .lp-nav-links a[href="#lp-adopt"] { display: none; }
}
@media (max-width: 1240px) {
  .lp-nav-links a[href="#lp-choice"],
  .lp-nav-links a[href="#lp-learns"],
  .lp-nav-links a[href="#lp-ship"] { display: none; }
}

/* 720px-tall viewports (1280x720 is still a common laptop and the default
   for a lot of screen-share/projector setups). Measured, not guessed: at
   this height the transform panel ran 24px over and the first ledger 48px
   over, so both get one more notch and nothing else does. */
@media (max-height: 760px) {
  .lp-sec { padding-block: clamp(22px, 2.4vw, 34px); }
  .lp-tf { margin-top: 10px; }
  .lp-tf-blurbs { min-height: 2.8em; }
  .lp-tf-tabs { margin: 10px 0 10px; }
  .lp-tf-tab { padding-top: 9px; }
  .lp-tf-col { padding: 11px 13px 12px; }
  .lp-tf-svg { max-height: min(30vh, 230px); }
  .lp-tf-file, .lp-tf-concept { padding: 5px 9px; }
  .lp-tf-payoff { margin-top: 10px; padding-top: 9px; }
}
@media (max-height: 760px) and (min-width: 900px) {
}

/* ---------- ambient float layer (hero) -------------------------------------
 * Drifting type nodes and format tokens - the two things the product deals
 * in - behind the headline. Three rules keep it from becoming noise:
 *
 *   1. It never enters the text's box. landing.js seeds positions and
 *      REJECTS any that land in the reserved headline/lede/CTA rectangle,
 *      so this cannot creep over the copy the way an evenly scattered
 *      field would.
 *   2. Transform and opacity ONLY, so every frame is composited and the
 *      drift stays smooth next to the tree's own animation.
 *   3. Both keyframes start AND end on the resting value. Under
 *      prefers-reduced-motion the `.lp *` block collapses duration to
 *      .001ms with one iteration, which lands on the 100% frame - so the
 *      resting state is the visible one, not a blank layer. That is the
 *      bug the hero diagram shipped once; it does not get to recur here. */
/* The floating dots and file-extension tokens that used to live here are
   gone. They were the one element on the page that stated nothing: 18
   rings and five extensions scattered at random, avoiding the text by a
   measured keep-out pass on load. On a page whose argument is that
   nothing here is decoration - every number measured, every claim
   carrying its own limit - ambient particles contradict the argument, and
   the five surfaces already appear in "What you ship" as real code. */

/* ---------- staggered reveal ------------------------------------------------
 * The source design staggered each card by its index (70ms apart) so a row
 * arrives as a sequence rather than a slab. `.reveal` had no stagger at all.
 * The delay is set by landing.js on the element's own style (CSSOM, so no
 * CSP surface) and CAPPED, because an uncapped index * 70ms means the last
 * card in a 21-row ledger waits 1.5s after the reader is already looking at
 * it. Motion should follow the eye, never make it wait. */
.lp .reveal {
  transition: opacity .62s cubic-bezier(.22,.61,.36,1),
              transform .62s cubic-bezier(.22,.61,.36,1);
}

/* ---------- hover: the lift the source design carried on every card --------
 * transform + box-shadow + border only. No layout property is touched, so
 * hovering a card never reflows the grid it sits in. */
.lp-card, .lp-point, .lp-choice-col, .lp-ledger-row {
  transition: transform .35s cubic-bezier(.22,.61,.36,1),
              box-shadow .35s ease,
              border-color .35s ease,
              background-color .35s ease;
}
.lp-card { position: relative; }
.lp-card::before {
  content: ""; position: absolute; left: 20px; right: 20px; top: 0; height: 2px;
  border-radius: 0 0 2px 2px; background: var(--wine);
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s cubic-bezier(.22,.61,.36,1);
}
/* `.lp ` prefix is load-bearing, not decoration. Nearly every card here is
   also a `.reveal`, and `.lp .reveal.in { transform: none }` is a 3-class
   selector - it outranks a bare `.lp-card:hover` (2) and silently swallowed
   the lift, while the `::before` bar (not a .reveal) animated fine. Matching
   the specificity and coming later in the file is what makes these apply. */
.lp .lp-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgba(23,20,15,.09);
  border-color: var(--line-2);
}
.lp .lp-card:hover::before { transform: scaleX(1); }

.lp .lp-choice-col:hover { transform: translateY(-3px); box-shadow: 0 14px 34px rgba(23,20,15,.09); }
.lp .lp-point:hover { transform: translateX(3px); }
.lp .lp-ledger-row:hover { background: var(--paper); }

/* Hover lift is a pointer affordance; a touch screen has no hover state and
   sticky :hover on tap just leaves a card stuck in its raised position. */
@media (hover: none) {
  .lp .lp-card:hover, .lp .lp-choice-col:hover, .lp .lp-point:hover {
    transform: none; box-shadow: none;
  }
  .lp .lp-card:hover::before { transform: scaleX(0); }
}

/* ---------- section diagrams -----------------------------------------------
 * Most sections were 40-66% empty vertical space, because `min-height: 100vh`
 * guarantees a screen but nothing was filling it. Each of these draws the one
 * claim its section is making - a fan into five surfaces, a curve that
 * steepens, a spine through seven steps - rather than adding generic shapes.
 *
 * Shared primitives, three rules:
 *   1. The RESTING state is the FINISHED drawing. Animations are scoped to
 *      `.reveal.in`, which only JS adds, so no-JS and reduced-motion readers
 *      get the completed diagram instead of a blank frame.
 *   2. `animation-fill-mode: backwards` holds the start state during the
 *      stagger delay, so a node cannot flash before its turn.
 *   3. `pathLength="1"` on every drawn path, so one dash value works for
 *      curves of wildly different real lengths. The hero diagram shipped a
 *      stroke-dasharray shorter than its path once and the line stopped in
 *      mid-air; normalising removes the whole class of error. */
.lp-dia {
  --dia-line: var(--wine);
  --dia-fill: var(--paper);
  --dia-text: var(--muted-q);
  margin: 26px 0 0;
}
.lp-sec-dark .lp-dia {
  --dia-line: var(--dark-wine);
  --dia-fill: var(--dark);
  --dia-text: var(--dark-muted);
}
.lp-dia svg { display: block; width: 100%; margin-inline: auto; }

.lp-dia-line {
  fill: none; stroke: var(--dia-line); stroke-width: 1.4;
  stroke-linecap: round; opacity: .55;
}
.lp-dia-node { fill: var(--dia-fill); stroke: var(--dia-line); stroke-width: 1.5; }
.lp-dia-node.is-solid { fill: var(--dia-line); }
.lp-dia-label {
  font-family: var(--mono); font-size: 11px; fill: var(--dia-text);
  text-anchor: middle; dominant-baseline: middle;
}
.lp-sec-dark .lp-dia-tag { fill: var(--dark-ink); }

/* draw + pop, played once when the section scrolls into view */
.lp-dia.in .lp-dia-line {
  animation: lp-dia-draw .95s cubic-bezier(.22,.61,.36,1) var(--d, 0s) backwards;
}
.lp-dia.in .lp-dia-pop {
  transform-box: fill-box; transform-origin: center;
  animation: lp-dia-pop .5s cubic-bezier(.34,1.4,.64,1) var(--d, 0s) backwards;
}
.lp-dia.in .lp-dia-fade {
  animation: lp-dia-fade .6s ease var(--d, 0s) backwards;
}
@keyframes lp-dia-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes lp-dia-pop  { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }
@keyframes lp-dia-fade { from { opacity: 0; } to { opacity: 1; } }
.lp-dia-line { stroke-dasharray: 1; stroke-dashoffset: 0; }

/* A diagram is texture on a phone, where the section is already a scroll. */
@media (max-width: 900px) { .lp-dia { display: none; } }
@media (max-height: 760px) { .lp-dia { margin-top: 16px; } }

/* The growth diagram is a single small graph, not a full-width band: at
   1200 units wide it would render as five specks on a huge empty field. */

/* Column glyphs sit above their heading. They used to be capped at 250px,
   which was fine when each was a squiggle and wrong now that all three are
   the SAME canvas in three states: a 220-unit viewBox at 250px renders a
   validation tick four pixels tall, and the comparison the three of them
   are making cannot be read at four pixels. They take the card's width
   instead, and a rule under them separates the drawing from the heading
   the way the heading is already separated from the body. */
.lp-dia-glyph { max-width: 100%; margin: 2px 0 18px; padding-bottom: 16px; }
.lp-dia-glyph .lp-dia-line { stroke-width: 1.5; }
.lp-choice-col .lp-dia-glyph { border-bottom: 1px solid var(--line); }
.lp-choice-us .lp-dia-glyph { border-bottom-color: var(--wine-line); }
/* Type and stroke inside an SVG scale with the box. At the old 250px cap
   these were tuned to render near their nominal size; at the card's full
   width everything is drawn about 1.8x, and "by hand" came out larger than
   the card's own body copy. Both are set back down in USER UNITS so the
   rendered size lands where it did before. */
#lp-choice .lp-dia-label { font-size: 8px; }
#lp-choice .lp-dia-flow { stroke-width: 1.9; }
#lp-choice .lp-dia-glyph .lp-dia-line { stroke-width: 1.25; }

@media (max-height: 760px) {
  .lp-dia-glyph { max-width: 210px; margin-bottom: 10px; padding-bottom: 10px; }
}

/* `.lp-wrap` had `max-width` and `margin: 0 auto` but no width. As a flex
   item with auto cross-axis margins it does NOT stretch - it shrinks to fit
   its contents. Every existing wrap got away with it because block children
   (headings, grids) report a wide max-content; a wrap holding only an SVG
   does not, so the blast-radius diagram collapsed to the SVG's 300px
   intrinsic default. `width: 100%` is the other half of the centring idiom
   and is a no-op for the wraps that were already filling. */
.lp-wrap { width: 100%; }
.lp-dia { width: 100%; }

/* ---------- diagrams that keep moving --------------------------------------
 * A one-shot draw-in is a picture that happened to arrive animated. These
 * sections are claims about things that KEEP happening - a source that keeps
 * emitting five surfaces, a pipeline that keeps carrying work, three names
 * that keep drifting - so the loop is the argument, not decoration.
 *
 * `lp-dia-flow` is a second copy of the same path carrying a single 6% dash.
 * Animating its offset walks that dash along the curve, which gives a packet
 * travelling a wire using nothing but stroke properties - no motion path, no
 * JS, no per-frame work in script.
 *
 * Everything here is scoped to `.lp-dia.in`, so a section nobody has scrolled
 * to yet is not animating, and the whole layer is REMOVED under reduced
 * motion rather than frozen: a stalled packet parked mid-wire reads as a
 * rendering fault, and a flow with no motion has nothing left to say. */
.lp-dia-flow {
  fill: none; stroke: var(--dia-line); stroke-width: 2.6;
  stroke-linecap: round; stroke-dasharray: .05 .95;
  opacity: 0;
}
.lp-dia.in .lp-dia-flow {
  opacity: .92;
  animation: lp-dia-flow var(--fd, 3.4s) linear var(--d, 0s) infinite;
}
@keyframes lp-dia-flow { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }

/* Marching ants: a dashed outline whose dashes crawl. On the problem section
   it reads as three URIs still being flagged as one concept, which is the
   complaint that section is making. */
.lp-dia.in .lp-dia-ants {
  animation: lp-dia-ants 3.6s linear infinite;
}
@keyframes lp-dia-ants { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -26; } }

/* Arrival: the endpoint swells and fills as its packet lands. Timed off the
   same duration and delay as the flow that feeds it, so the pop happens when
   the dash actually gets there rather than on its own rhythm. */

/* Slow drift: the three names pulling apart and settling, over and over. */
/* Drift is a pure translate, so it needs no transform-box - and applying it
   to the GROUP keeps each name welded to its dot. Drifting the circle alone
   detached "Supplier" from the node it labels, which is the opposite of the
   point being made. A negative delay starts each one mid-cycle. */

@media (prefers-reduced-motion: reduce) {
  /* Not frozen - gone. A packet parked mid-wire is worse than no packet. */
  .lp-dia-flow { display: none; }
}

/* ---------- what you ship: the artifacts, not a list of their names --------
 * The previous version was a fan diagram labelled .ttl / .json / .d.ts /
 * .graphql / .md sitting 40px above five cards reading "Turtle / OWL",
 * "JSON Schema", "TypeScript", "GraphQL SDL", "Data dictionary". The same
 * five things, twice, in one eyeline - a diagram whose entire content is the
 * list printed underneath it has no reason to exist.
 *
 * What the section actually claims is that these five CANNOT DRIFT, because
 * they are one reviewed term recompiled. So show the same term - Customer -
 * in all five syntaxes, and let the regeneration sweep say the rest. */


.lp-out-code .k { color: var(--wine); }
.lp-out-code .s { color: var(--ok); }

.lp .lp-out:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgba(23,20,15,.09);
  border-color: var(--line-2);
}


@media (max-width: 1180px) {
}
@media (max-width: 900px) {
}
@media (max-height: 1010px) {
}
@media (max-height: 760px) {
}

/* ---------- the close: show the promise, do not illustrate it --------------
 * This section makes a specific, testable claim - "if the first five
 * proposals do not tell you something about your own data that you did not
 * know, nothing else here will matter" - and the previous version answered
 * it with a node-and-satellites graphic. Three things were wrong: it was
 * captioned "one domain" while drawing six nodes; a hub with spokes is the
 * single most generic diagram in enterprise software; and it said nothing
 * about the promise directly above it.
 *
 * So: print the five proposals. The fifth is the one that earns the claim -
 * two types the customer already had, which the machine scored as the same
 * thing and refused to merge on its own. */
.lp-props {
  text-align: left; max-width: 720px; margin: 26px auto 0;
  border: 1px solid var(--line); border-radius: 13px;
  background: var(--paper); overflow: hidden;
}
.lp-props-h {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--line); background: var(--alt);
}
.lp-props-f { font-family: var(--mono); font-size: 11.5px; color: var(--wine); }
.lp-props-c {
  margin-left: auto; font-size: 9.5px; letter-spacing: .13em;
  text-transform: uppercase; font-weight: 600; color: var(--muted-q);
}
.lp-prop {
  position: relative;
  display: grid; grid-template-columns: 30px minmax(0, 150px) minmax(0, 1fr) auto;
  align-items: baseline; gap: 12px;
  padding: 9px 16px; border-top: 1px solid var(--line);
}
.lp-prop:first-of-type { border-top: 0; }
.lp-prop-n { font-family: var(--mono); font-size: 10.5px; color: var(--muted-q); }
.lp-prop-t { font-size: 13px; font-weight: 600; color: var(--ink); }
.lp-prop-d { font-size: 12px; color: var(--muted); }
.lp-prop-d b { font-family: var(--mono); font-weight: 400; font-size: 11px; color: var(--ink-2); }
.lp-prop-s {
  font-family: var(--mono); font-size: 10px; color: var(--muted-q);
  white-space: nowrap; text-align: right;
}
/* The one that makes the point gets the accent - and says a person decides. */
.lp-prop.is-flag { background: var(--wine-tint); }
.lp-prop.is-flag .lp-prop-t,
.lp-prop.is-flag .lp-prop-s { color: var(--wine); }

/* The five arrive in order and then STOP. This was a 7s infinite cursor
   running down the queue forever, which is the one thing a closing section
   must not do - the page is meant to end here, not idle. */
.lp-prop { opacity: 0; }
.lp-props.in .lp-prop {
  animation: lp-prop-in .45s cubic-bezier(.22,.61,.36,1) calc(var(--i, 0) * .22s) forwards;
}
@keyframes lp-prop-in { from { opacity: 0; transform: translateY(5px); }
                        to   { opacity: 1; transform: none; } }
/* The fifth waits. Four proposals resolved themselves; this one is holding
   for a person, so it arrives half a second after the cadence predicts. */
.lp-props.in .lp-prop.is-flag { animation-delay: 1.38s; }
.lp-prop::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--wine); transform-origin: top; transform: scaleY(0);
}
/* and its marker stays: the only permanent accent in the card. */
.lp-props.in .lp-prop.is-flag::before {
  animation: lp-prop-hold .5s cubic-bezier(.22,.61,.36,1) 1.86s forwards;
}
@keyframes lp-prop-hold { to { transform: scaleY(1); } }

/* the three zones, named once so the row reads as a progression */
.lp-props-k {
  display: grid; grid-template-columns: 30px minmax(0, 150px) minmax(0, 1fr) auto;
  gap: 12px; padding: 8px 16px 7px; border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--line-2);
}
.lp-props-k span:last-child { text-align: right; }

/* The note used to live INSIDE the button row with `flex-basis: 100%` and
   still landed beside the buttons, so a three-line paragraph read as
   overflow rather than layout. It is its own block now. */
.lp-final-row { margin-top: 26px; }
/* `.lp p { margin: 0 }` is (0,1,1) and outranks a bare `.lp-final-note`
   (0,1,0), so this note's `margin: auto` had NEVER applied - which is why it
   sat hard against the left edge of the measure while the buttons were
   centred, and read as overflow rather than layout. The `.lp ` prefix takes
   it to (0,2,0) and the centring finally lands. */
.lp .lp-final-note { margin: 14px auto 0; max-width: 52ch; }

@media (max-width: 700px) {
  .lp-prop { grid-template-columns: 26px 1fr; row-gap: 3px; }
  .lp-prop-d, .lp-prop-s { grid-column: 2; text-align: left; }
}
@media (max-height: 1010px) {
  .lp-props { margin-top: 18px; }
  .lp-prop { padding: 7px 14px; }
  .lp-prop-t { font-size: 12.5px; }
  .lp-prop-d { font-size: 11.5px; }
  .lp-final-row { margin-top: 18px; }
}

/* All five code blocks reserve four lines, so the descriptions beneath them
   sit on one baseline instead of stepping with each snippet's length. */
@media (max-height: 760px) { .lp-out-code { min-height: calc(4 * 1.5em + 16px); } }

/* ---------- display type ---------------------------------------------------
 * Headlines move to the serif. The metrics change with the face, not just the
 * name: Geist was set at 600 with -.04em tracking because a geometric sans
 * needs weight and tightening to hold a big line. A high-contrast serif needs
 * the opposite - 400 weight, tracking near zero, and a little more size,
 * because its thick/thin contrast already supplies the presence that letter-
 * spacing was faking. Keeping the old numbers would have made it look like a
 * font swap rather than a design. */
.lp-title,
.lp-h2,
.lp-final .lp-h2 {
  font-family: var(--display);
  font-weight: 400;
}
.lp-title {
  /* phi-scaled, and this is the rule that WINS - the base declaration
     far above is overridden from here, so a size set there is a no-op.
     88px put the current headline on three lines and pushed the proof
     row under the fold; 64px sets it in two. */
  font-size: clamp(38px, 5.2vw, 64px);
  letter-spacing: -.022em;
  line-height: 1.04;
  max-width: 20ch;
}

/* The hero splits on the golden ratio: prose takes the long side, the
   schema diagram behind it is left the short one. Placed AFTER the rule
   above deliberately - source order decides between two single-class
   selectors, and this has to win. */
@media (min-width: 1100px) {
  .lp-title, .lp-hero-thesis, .lp-cta-row { max-width: 61.8%; }
  .lp-title { max-width: min(20ch, 61.8%); }
  .lp-lede { max-width: min(46ch, 52%); }
}
.lp-h2 {
  font-size: clamp(32px, 3.8vw, 48px);
  letter-spacing: -.012em;
  line-height: 1.1;
}
.lp-final .lp-h2 { font-size: clamp(34px, 4.4vw, 58px); letter-spacing: -.015em; }
/* The one place italic is load-bearing rather than decorative. */
.lp-h2 em { font-style: italic; font-family: var(--display); }

@media (max-height: 1010px) {
  .lp-title { font-size: clamp(36px, 4.8vw, 56px); }
  .lp-h2 { font-size: clamp(29px, 3.2vw, 40px); }
  .lp-final .lp-h2 { font-size: clamp(30px, 3.6vw, 46px); }
}

/* ---------- headline typesetting -------------------------------------------
 * Words arrive in sequence, lifting and sharpening out of a blur. Kept to
 * 38ms apart and capped by the fact that headlines are short - the ledger
 * lesson applies here too: nobody should wait for the last word of a
 * sentence they have already finished reading.
 *
 * `.lp-split-text` suppresses the block-level `.reveal` fade, otherwise the
 * heading fades in as a slab AND its words fade in individually, which
 * reads as a stutter. The words carry the entrance on their own. */
.lp-w { display: inline-block; will-change: transform, opacity, filter; }
.lp .reveal.lp-split-text { opacity: 1; transform: none; transition: none; }
.lp .lp-split-text .lp-w { opacity: 0; }
.lp .lp-split-text.in .lp-w {
  animation: lp-word-rise .72s cubic-bezier(.22,.61,.36,1) calc(var(--wi, 0) * 38ms) both;
}
@keyframes lp-word-rise {
  from { opacity: 0; transform: translateY(.36em); filter: blur(5px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* The kicker above each headline gets a hairline that draws itself, so the
   section opens with a gesture rather than just appearing. */
.lp-kicker { position: relative; padding-bottom: 9px; }
.lp-kicker::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 46px; height: 1px;
  background: var(--wine); transform: scaleX(0); transform-origin: left;
}
.lp-kicker.in::after { animation: lp-rule-in .7s cubic-bezier(.22,.61,.36,1) .1s forwards; }
@keyframes lp-rule-in { to { transform: scaleX(1); } }

/* Lede paragraphs settle a beat after their headline. Block-level, not
   per-word: body copy animated word-by-word is unreadable, not premium. */
.lp .lp-sub.reveal.in, .lp .lp-lede.reveal.in { animation: lp-settle .8s cubic-bezier(.22,.61,.36,1) .18s backwards; }
@keyframes lp-settle { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  /* JS does not split under reduced motion, but belt and braces: if a word
     span exists it must be visible, never parked at the animation's start. */
  .lp .lp-split-text .lp-w { opacity: 1; }
  .lp-kicker::after { transform: scaleX(1); }
}

/* The serif headline is a few px taller than the grotesque it replaced, which
   pushed the transform panel 5px past a 720px viewport. Measured, not
   guessed: it is the diagram column that has the slack. */
@media (max-height: 760px) {
  .lp-tf-svg { max-height: min(27vh, 205px); }
  .lp-tf-blurbs { min-height: 2.6em; }
}

/* 720px-tall viewports: the serif headline runs to two lines in most
   sections, so on the tightest screens it gives back a size step and some
   of its bottom margin. Measured at 1280x720 - the transform panel was the
   only section that actually needed it. */
@media (max-height: 760px) {
  .lp-h2 { font-size: clamp(27px, 2.9vw, 36px); margin-bottom: 10px; }
  .lp-title { font-size: clamp(33px, 4.3vw, 50px); }
  .lp-final .lp-h2 { font-size: clamp(28px, 3.2vw, 42px); }
}

/* 768px-tall viewports (1366x768 is still the most common laptop panel in
   the world) fall in the gap between the 820px and 760px tiers, and the
   taller serif headline pushed the transform panel 10px past the fold there.
   The diagram column is where the slack is - measured, not guessed. */
@media (max-height: 1010px) {
  .lp-tf-svg { max-height: min(28vh, 215px); }
  .lp-tf { margin-top: 12px; }
  /* The panel is driven by the CONCEPTS column - six rows, not the diagram,
     which is why capping the SVG only bought 2px. Five inter-row gaps at
     6px are where the height actually is. */
  .lp-tf-concepts, .lp-tf-files { gap: 4px; }
  .lp-tf-c-origin { font-size: 9.5px; }
  .lp-tf-tabs { margin: 11px 0 11px; }
}

/* ---------- the problem, as the history your schema already has -----------
 * The old version was a dashed box holding three named circles. It drew ONE
 * of the six problems (the duplicate names) and then six prose cards below
 * restated all six - so the box both under-covered the section and repeated
 * part of it. Exactly the label-repeater failure the "what you ship" fan had.
 *
 * This replaces both. It is a change log with a column missing. Six rows,
 * one per symptom, and a first column that is an em dash on every single
 * line. The argument is not written anywhere in it - the empty column IS the
 * argument, and it is the same column the product spends its whole life
 * filling in. The close does the mirror image of this in light, with the
 * columns full; the two tables are meant to rhyme. */
/* ---------- the problem: six unfiled cases ----------------------------
 *
 * The content is unchanged - three fields per row, six rows, a count at
 * the head, a conclusion at the foot. What changed is that it stopped
 * being a TABLE OF SIX ROWS and became A PILE OF SIX CARDS, because the
 * headline says the schema was not decided, it ACCUMULATED, and a pile is
 * what accumulation looks like. A ruled table is what a decision looks
 * like, which is the one thing that never happened here.
 *
 * Four moves make it a pile rather than a list:
 *
 * 1. THE FRAME IS GONE. The bordered panel was the thing that read as an
 *    admin grid. The cards sit directly on the dark ground now, and the
 *    file line and the count become a caption above them.
 * 2. THEY OVERLAP AND THEY ARE OFF-SQUARE. A tenth of a degree either
 *    way, a few pixels of horizontal drift, each card landing over the
 *    one before it. Nothing in this pile was filed by anybody.
 * 3. LATER CARDS SIT ON TOP. Reading order and stacking order agree, so
 *    the pile grows toward the reader as the symptoms get worse.
 * 4. THEY DEAL, ONCE, ON ARRIVAL. The accumulation happens in TIME rather
 *    than in scroll distance - the section stays one screen, as every
 *    other section on this page does, and nothing is hidden behind a
 *    control. Every word is on screen when the dealing stops.
 */
.lp-hist { margin-top: 26px; }

/* The file line and the count, as a caption over the pile rather than a
   toolbar across the top of a panel. */
.lp-hist-top {
  display: flex; align-items: baseline; gap: 12px;
  padding: 0 4px 10px;
}
.lp-hist-file { font-family: var(--mono); font-size: 11.5px; color: var(--dark-wine); }
/* An absence, sized like a finding. The zero carries the weight; the words
   after it stay at label size, so the pair reads as one statement rather
   than as a metric in a widget - and it sits directly over the column of
   six empty signatures it is counting. */
.lp-hist-stat {
  margin-left: auto; font-family: var(--mono); font-size: 10.5px;
  color: var(--dark-wine); letter-spacing: .1em; text-transform: uppercase;
  display: inline-flex; align-items: baseline; gap: 10px;
}
.lp-hist-stat b { font-size: 19px; font-weight: 500; letter-spacing: 0; line-height: 1; }

.lp-hist-head, .lp-hist-row {
  display: grid;
  grid-template-columns: 34px 118px minmax(0, 250px) minmax(0, 1fr) 92px;
  gap: 16px; align-items: center;
}
.lp-hist-head {
  padding: 0 20px 9px; font-size: 9.5px; letter-spacing: .13em;
  text-transform: uppercase; font-weight: 600; color: var(--dark-kicker);
  align-items: baseline;
}
.lp-hist-head span:last-child { text-align: center; }

/* -- a card ------------------------------------------------------------
   Paper on a dark desk: a light catch along the top edge, a shadow under
   the bottom. Both are needed - one alone reads as a border. */
.lp-hist-row {
  position: relative;
  z-index: calc(var(--i, 0) + 1);
  /* The overlap has to clear the signature rule at the bottom of each
     card - at -9px the next card landed on it and cut it in half, which
     read as a rendering fault rather than as a pile. */
  margin-bottom: -6px;
  padding: 12px 20px 16px;
  border: 1px solid rgba(247,245,241,.09);
  border-radius: 10px;
  background: #191510;
  box-shadow: 0 -1px 0 rgba(247,245,241,.05), 0 10px 22px rgba(0,0,0,.5);
  transform: translateX(var(--dx, 0)) rotate(var(--r, 0deg));
  transition: transform .3s cubic-bezier(.22,.61,.36,1),
              box-shadow .3s cubic-bezier(.22,.61,.36,1);
}
.lp-hist-row:last-of-type { margin-bottom: 0; }
/* Off-square by a fraction of a degree. Enough that the pile reads as
   dropped rather than ruled; not enough to look like a mistake. */
.lp-hist-row:nth-of-type(1) { --r: .13deg;  --dx: -2px; }
.lp-hist-row:nth-of-type(2) { --r: -.1deg;  --dx: 1px; }
.lp-hist-row:nth-of-type(3) { --r: .08deg;  --dx: -1px; }
.lp-hist-row:nth-of-type(4) { --r: -.15deg; --dx: 2px; }
.lp-hist-row:nth-of-type(5) { --r: .11deg;  --dx: -1px; }
.lp-hist-row:nth-of-type(6) { --r: -.07deg; --dx: 1px; }
/* Lifting one card is the whole interaction: it is paper, you can pick it
   up, and nothing is hidden underneath that picking it up reveals. */
.lp-hist-row:hover {
  transform: translateX(var(--dx, 0)) translateY(-3px) rotate(var(--r, 0deg));
  box-shadow: 0 -1px 0 rgba(247,245,241,.08), 0 16px 30px rgba(0,0,0,.55);
}

.lp-hist-step {
  justify-self: center;
  font-family: var(--mono); font-size: 10px; letter-spacing: .06em;
  color: var(--dark-kicker);
}

/* -- the figures ---------------------------------------------------------
   One palette, three roles: `s` is the schema as it should be, `a` is the
   thing going wrong, `g` is what has already gone. Squares, not circles -
   the same cell the hero plan uses for a term. */
.lp-fig { display: block; width: 118px; height: 46px; }
/* Hairlines that work on a light page disappear on a near-black one. These
   are set against #191510, not against bone, and were unreadable at the
   weights the rest of the page uses. */
.lp-fig .s { stroke: rgba(247,245,241,.62); stroke-width: 1; fill: none; }
.lp-fig rect.s { fill: none; }
.lp-fig .n { fill: rgba(247,245,241,.8); stroke: none; }
.lp-fig .a { stroke: var(--dark-wine); stroke-width: 1; fill: none; }
.lp-fig .af { fill: var(--dark-wine); stroke: none; }
.lp-fig .g { stroke: rgba(247,245,241,.2); stroke-width: 1; fill: none; }
.lp-fig .faint { opacity: .5; }
.lp-fig .dash { stroke-dasharray: 3 3; }
.lp-fig .dot { stroke-dasharray: 1 3; }
/* The consequences never arrive: the lines are there and they do not
   connect. */
.lp-fig .cut { stroke-dasharray: 5 6; opacity: .55; }
.lp-fig .bar { stroke-width: 1.8; }

/* The only field that never has a value, drawn as what it is: a signature
   line with nothing on it, six deep, under the number that counts them. */
.lp-hist-who {
  position: relative; font-family: var(--mono); font-size: 15px;
  color: var(--dark-wine); opacity: .55; text-align: center;
  padding-bottom: 7px;
}
.lp-hist-who::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: 0;
  height: 1px; background: rgba(192,138,147,.3);
}
.lp-hist-what { font-size: 13.5px; font-weight: 600; color: var(--dark-ink); letter-spacing: -.01em; }
.lp-hist-detail { font-size: 12.5px; line-height: 1.5; color: var(--dark-muted); }

/* The conclusion of the pile, not the footer of a panel. It sits clear of
   the last card with the rule running into it, and it is the only line in
   this section set larger than the cards - it is what they add up to. */
.lp-hist-foot {
  display: flex; align-items: baseline; gap: 14px;
  margin-top: 26px; padding: 0 4px;
  font-size: 15px; color: var(--dark-ink); letter-spacing: -.01em;
}
.lp-hist-arrow {
  width: 34px; height: 1px; background: var(--dark-wine); flex: 0 0 auto;
  align-self: center;
}

/* THE DEAL. Each card lands over the one before it, from slightly above
   and turned a little further than it will end up - paper dropped, not a
   panel fading in. One shot: the pile is a statement, and a pile that
   re-deals every time you scroll past would be an animation about itself.

   The stagger runs the height of the section, so the accumulation happens
   in TIME. That is the whole reason this works in one screen: the six
   cards do not need scroll distance to arrive one after another, and when
   they stop, every word is on screen. */
.lp-hist.in .lp-hist-row {
  animation: lp-case-deal .6s cubic-bezier(.2,.72,.3,1)
             calc(.18s + var(--i, 0) * .13s) backwards;
}
@keyframes lp-case-deal {
  from {
    opacity: 0;
    transform: translate(calc(var(--dx, 0px) - 10px), -26px)
               rotate(calc(var(--r, 0deg) * 5));
  }
  to {
    opacity: 1;
    transform: translateX(var(--dx, 0)) rotate(var(--r, 0deg));
  }
}
/* Then a search runs down the "who decided" column, card by card, and
   comes back empty every time. */
.lp-hist.in .lp-hist-who {
  animation: lp-hist-seek 8s ease-in-out calc(var(--i, 0) * .3s) infinite;
}
@keyframes lp-hist-seek {
  0%, 6%   { opacity: .55; }
  10%      { opacity: 1; }
  20%      { opacity: .28; }
  34%, 100%{ opacity: .55; }
}
.lp-hist.in .lp-fig {
  animation: lp-hist-settle .7s cubic-bezier(.22,.61,.36,1)
             calc(.45s + var(--i, 0) * .13s) backwards;
}
@keyframes lp-hist-settle {
  from { opacity: 0; transform: translateX(-5px); }
  to   { opacity: 1; transform: none; }
}
/* The conclusion waits for the pile. It was sitting there in its final
   position while cards two to six were still in the air - a verdict
   printed before the evidence had finished arriving. */
.lp-hist.in .lp-hist-foot {
  animation: lp-hist-settle .7s cubic-bezier(.22,.61,.36,1) 1.15s backwards;
}
@media (prefers-reduced-motion: reduce) {
  .lp-hist.in .lp-hist-row, .lp-hist.in .lp-hist-who, .lp-hist.in .lp-fig,
  .lp-hist.in .lp-hist-foot {
    animation: none;
  }
  .lp-hist-row, .lp-hist-row:hover { transition: none; }
}

/* Tablet: the figure survives, the third column folds under the second.
   The figures are the part that makes the six sentences land before they
   are read, so they are the last thing to go, not the first. */
@media (max-width: 1180px) {
  .lp-hist-head, .lp-hist-row {
    grid-template-columns: 30px 96px minmax(0, 1fr) 74px; gap: 14px;
  }
  .lp-hist-head span:nth-child(4) { display: none; }
  .lp-hist-detail { grid-column: 3; }
  .lp-hist-who { grid-column: 4; grid-row: 1 / span 2; }
  .lp-hist-row { align-items: start; row-gap: 3px; }
  .lp-hist-row::before { left: 30px; }
  .lp-fig { width: 96px; height: 38px; }
}
/* Mobile: a vertical narrative, not a squeezed table. Number and title on
   one line, the account of what happened beneath it, and the figure
   dropped - at this width it would be 60px of hairlines nobody can read,
   and the sentence says it perfectly well on its own. */
@media (max-width: 720px) {
  .lp-hist-head { display: none; }
  .lp-hist-fig { display: none; }
  .lp-hist-head, .lp-hist-row {
    grid-template-columns: 30px minmax(0, 1fr) 30px; gap: 12px;
    padding: 13px 16px;
  }
  .lp-hist-what { grid-column: 2; }
  .lp-hist-detail { grid-column: 2; }
  .lp-hist-who { grid-column: 3; grid-row: 1; font-size: 13px; }
  .lp-hist-row { align-items: start; row-gap: 5px; }
  .lp-hist-row::before { left: 30px; }
  .lp-hist-stat b { font-size: 16px; }
}
@media (max-height: 1010px) {
  .lp-hist { margin-top: 16px; }
  .lp-hist-head, .lp-hist-row { padding: 8px 16px; }
  .lp-hist-detail { font-size: 11.5px; line-height: 1.45; }
}
@media (max-height: 1010px) {
  .lp-fig { height: 38px; }
}
@media (max-height: 780px) {
  .lp-hist-row { padding: 6px 16px; }
  .lp-hist-what { font-size: 12.5px; }
  .lp-hist-detail { font-size: 11px; }
  .lp-fig { width: 96px; height: 32px; }
  .lp-hist-stat b { font-size: 16px; }
}

/* ---------- how it works: the diagram IS the control -----------------------
 * The old version stacked a decorative spine on top of seven prose cards.
 * The spine drew the sequence; the cards restated it. Same duplication as
 * everywhere else on this page.
 *
 * So the spine becomes the selector. Seven nodes on a progress rail, one
 * shared detail pane beneath, and the rail fills as you move along it - the
 * drawing now tells you where you are AND takes you there.
 *
 * Deliberately NOT hover-expand. There is no hover on touch; an in-flow
 * expansion would break the one-screen invariant every section here is held
 * to; and a large panel that fires as the pointer crosses a card on its way
 * somewhere else is the most irritating pattern on the web. Click and focus
 * both work, the pane is a fixed region so nothing reflows, and step 01 is
 * showing before any script runs. */
.lp-flow { margin-top: 26px; }

.lp-steps {
  position: relative;
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  padding-top: 4px;
}
/* The rail sits behind the dots, inset by half a column so it starts and
   ends ON the first and last node rather than floating past them. */
.lp-steps-rail, .lp-steps-fill {
  position: absolute; top: 10px; height: 1px;
  left: calc(100% / 14); right: calc(100% / 14);
}
.lp-steps-rail { background: var(--line-2); }
.lp-steps-fill {
  right: auto; width: calc((100% - 100% / 7) * var(--p, 0));
  background: var(--wine);
  transition: width .55s cubic-bezier(.22,.61,.36,1);
}
.lp-step {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 0 4px 4px; border: 0; background: transparent;
  font: inherit; color: var(--muted); cursor: pointer;
  transition: color .3s ease;
}
.lp-step-dot {
  width: 13px; height: 13px; border-radius: 50%;
  border: 1.5px solid var(--line-2); background: var(--alt);
  transition: background .3s ease, border-color .3s ease, transform .3s cubic-bezier(.34,1.4,.64,1);
}
.lp-step-n { font-family: var(--mono); font-size: 10px; color: var(--muted-q); transition: color .3s ease; }
.lp-step-l { font-size: 12px; letter-spacing: -.005em; }
/* Steps already passed read as done; the current one is filled and larger. */
.lp-step.is-done .lp-step-dot { background: var(--wine); border-color: var(--wine); opacity: .45; }
.lp-step[aria-pressed="true"] { color: var(--ink); }
.lp-step[aria-pressed="true"] .lp-step-dot { background: var(--wine); border-color: var(--wine); transform: scale(1.35); }
.lp-step[aria-pressed="true"] .lp-step-n { color: var(--wine); }
.lp-step:hover .lp-step-dot { border-color: var(--wine); }

/* One region, fixed height, so switching step never moves the page. */
/* min-height must clear the TALLEST step (04, four tiers) or the pane
   resizes when you reach it - which is the one thing this layout exists to
   avoid. Sized to 04 and centred, so the shorter steps carry ~15px of even
   padding above and below rather than a lump of void at the bottom. */
.lp-stepbody {
  /* The card is a block child sized by its own content, so `align-items` on
     the CARD centres nothing - the centring has to happen here, on the box
     that actually has the spare height. */
  display: grid; align-content: center;
  margin-top: 22px; min-height: 194px;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--paper); padding: 22px 24px;
}
.lp-stepcard {
  display: none;
  grid-template-columns: minmax(0, 196px) 1px minmax(0, 1fr);
  gap: 0 34px;
  align-items: center;            /* was top-aligned, which dumped 46-67px of
                                     dead space in one lump at the bottom */
}
.lp-flow[data-step="0"] .lp-stepcard[data-for="0"],
.lp-flow[data-step="1"] .lp-stepcard[data-for="1"],
.lp-flow[data-step="2"] .lp-stepcard[data-for="2"],
.lp-flow[data-step="3"] .lp-stepcard[data-for="3"],
.lp-flow[data-step="4"] .lp-stepcard[data-for="4"],
.lp-flow[data-step="5"] .lp-stepcard[data-for="5"],
.lp-flow[data-step="6"] .lp-stepcard[data-for="6"] { display: grid; }

/* Left: an identifier, nothing else. The numeral carries it, set in the
   display serif at a size that gives the column enough weight to balance a
   paragraph of text opposite - previously it was 11px mono and the whole
   left side read as an afterthought. */
.lp-stepcard-head { align-self: center; }
.lp-stepcard-n {
  display: block; font-family: var(--display); font-size: 46px;
  line-height: 1; color: var(--wine); opacity: .38;
}
.lp-stepcard-t {
  margin: 10px 0 0; font-family: var(--display); font-weight: 400;
  font-size: 29px; letter-spacing: -.012em; line-height: 1.1; color: var(--ink);
}
/* A hairline instead of a gap, so the two halves read as one panel. */
.lp-stepcard::after {
  content: ""; grid-column: 2; grid-row: 1;
  width: 1px; height: 100%; background: var(--line);
  align-self: stretch;
}
/* Right: lede and facts as ONE column of prose, capped to a readable
   measure. They were 876px wide, which is roughly twice the line length
   anyone reads comfortably. */
.lp-stepcard-body { max-width: 66ch; }
.lp-stepcard-lede {
  font-size: 14.5px; line-height: 1.55; color: var(--ink-2);
  padding-bottom: 13px; margin-bottom: 13px;
  border-bottom: 1px solid var(--line);
}
.lp-stepcard-facts { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.lp-stepcard-facts li {
  position: relative; padding-left: 18px;
  font-size: 13px; line-height: 1.55; color: var(--muted);
}
.lp-stepcard-facts li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 7px; height: 1px; background: var(--wine);
}
.lp-stepcard-facts b { font-weight: 600; color: var(--ink); }

/* The pane fades its content in on change - a swap with no transition reads
   as a glitch rather than a response to the click. */
.lp-flow .lp-stepcard { animation: lp-step-in .42s cubic-bezier(.22,.61,.36,1) both; }
@keyframes lp-step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

@media (max-width: 1000px) {
  .lp-stepcard { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .lp-step-l { display: none; }
  .lp-stepbody { min-height: 250px; }
}
@media (max-height: 1010px) {
  .lp-flow { margin-top: 18px; }
  .lp-stepbody { margin-top: 16px; min-height: 182px; padding: 16px 18px; }
  .lp-stepcard-t { font-size: 26px; }
  .lp-stepcard-facts { gap: 9px; }
  .lp-stepcard-facts li { font-size: 12.5px; }
}
@media (max-height: 780px) {
  .lp-stepbody { min-height: 166px; padding: 13px 16px; }
  .lp-stepcard-t { font-size: 23px; margin: 6px 0 8px; }
  .lp-stepcard-lede { font-size: 13px; }
  .lp-stepcard-facts li { font-size: 12px; line-height: 1.5; }
}

/* The tree's domain names. Deliberately unmasked and in mono: they are the
   one part of the drawing that is information rather than texture, and they
   say the same thing the URI scheme does - one root, branches that never
   swap, terms born where they grow. */

/* -- P011: the answer section --------------------------------------------
   The claim is set as prose because it IS prose the system assembled from
   the record; the citations sit under it in the same tier list the review
   demo uses, so the two read as the same kind of evidence. */
/* The gap is styled to be READ, not tucked away. A system that says what
   it cannot answer only earns credit if the admission is legible. */

/* ---------- one line, at the end, for saying something -------------------
   Not a modal, not a floating bubble, not a survey. It sits where a
   reader who has been through the whole argument is already standing,
   and there is nothing to dismiss - so there is nothing to resent. */
.lp-say { margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--line); }
.lp-say__label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 9px; }
.lp-say__row { display: flex; gap: 9px; max-width: 620px; }
.lp-say__input {
  flex: 1 1 auto; min-width: 0; padding: 10px 13px;
  border: 1px solid var(--line-2); border-radius: 9px;
  background: var(--paper); color: var(--ink);
  font-family: inherit; font-size: 14px;
}
.lp-say__input:focus-visible { outline: 2px solid var(--wine); outline-offset: 2px; }
.lp-say__send {
  padding: 0 18px; border: 1px solid var(--ink); border-radius: 9px;
  background: var(--ink); color: var(--bone); font-size: 14px; cursor: pointer;
}
.lp-say__send:disabled { opacity: .5; cursor: default; }
.lp-say__said { display: block; margin-top: 8px; font-size: 12.5px; color: var(--wine); min-height: 18px; }

/* -- landing: hero thesis line, added beneath the promoted hook -------- */
.lp-hero-thesis {
  /* Two phi steps below the title (64 / phi^2 ~= 24.5) and set in the
     SANS. As a second display line at 27px it competed with the headline
     instead of answering it - close sizes in the same voice read as an
     accident. */
  font-size: clamp(18px, 1.9vw, 24px);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -.011em;
  color: var(--ink);
  margin: 0 0 16px;
  max-width: 34ch;
}

/* The induction diagram runs the full measure rather than sitting in a
   column, so it needs its own ceiling: at 900x200 an unconstrained width
   makes it 280px tall on a 1280 wrap and it starts competing with the
   points beneath it. */
/* The induction section carries more than any other: a heading, a lede,
   a diagram, four points, the flow strip and a closing note. `.lp-sec` is
   `min-height:100vh` with up to 104px of padding top AND bottom, so at
   1080 the real budget is ~872px - and unscoped this section wanted 981,
   which overflowed a centred flex box in both directions at once.
   Everything below buys that back without shrinking type. */
#lp-induce .lp-h2 { max-width: 34ch; }          /* 3 lines -> 2 */
#lp-induce .lp-sub { max-width: 64ch; }
#lp-induce .lp-sub:last-child { margin-top: 10px; }

/* LEFT-ALIGNED, not centred. `.lp-dia svg` sets `margin-inline:auto`,
   which on a capped width floats the drawing into the middle of the wrap
   while the prose above it starts at the left edge - two different left
   margins in the same section reads as a mistake. */

/* Same family as the induction diagram: full measure, left-aligned to the
   prose, and its own ceiling so it does not push the section past the
   ~872px a 100vh `.lp-sec` actually leaves for content. */

/* The proposals table breathes slightly less, which survives from the
   first attempt at fitting this section. */
.lp-final .lp-prop { padding-block: 9px; }

/* ==========================================================================
   The closing section, recomposed.
   Was: one centred column of nine stacked things, taller than a viewport,
   with the heading clipped under the sticky nav. Now: dark ground, two
   columns, and a single closing bar. See closing_redesign.py.
   ========================================================================== */

/* The page opens dark and now closes dark - a bookend, and it lights the
   proposals card instead of leaving it pale-on-pale. */
.lp-final { text-align: left; padding-block: clamp(44px, 5vw, 76px); }
.lp-final .lp-h2 { margin-inline: 0; max-width: 18ch; font-size: clamp(30px, 3.6vw, 46px); }
.lp-final .lp-sub { margin-inline: 0; max-width: 44ch; color: var(--dark-muted); }
.lp .lp-final-note { margin: 0; max-width: 46ch; text-align: left; color: var(--dark-muted); }
.lp .lp-final-note span { display: block; margin-top: 7px; color: var(--dark-kicker); }
.lp-final-row { justify-content: flex-start; margin-top: 26px; }

/* Two columns. The section's height becomes the taller column rather than
   the sum of everything, which is what actually fixed the overflow. */
@media (min-width: 980px) {
  .lp-final > .lp-wrap {
    display: grid; grid-template-columns: 1.1fr 1fr;
    column-gap: clamp(32px, 4vw, 72px); align-items: start;
  }
  .lp-final .lp-h2        { grid-column: 1; grid-row: 1; }
  .lp-final .lp-sub       { grid-column: 1; grid-row: 2; }
  .lp-final .lp-final-row { grid-column: 1; grid-row: 3; }
  .lp-final .lp-final-note{ grid-column: 1; grid-row: 4; margin-top: 16px; }
  .lp-final .lp-props     { grid-column: 2; grid-row: 1 / span 4; margin: 4px 0 0; }
  /* The feedback bar is injected by JS as the last child, so it lands here. */
  .lp-final .lp-say       { grid-column: 1 / -1; grid-row: 5; }
}

/* The proposals card stays light - a lit object on the dark ground, which
   is the point of closing dark. Its own inner colours are already tuned
   for a paper background, so they need no change. */
.lp-final .lp-props { max-width: none; box-shadow: 0 18px 50px rgba(0,0,0,.28); }

/* Buttons need the dark treatment: `--ink` on `--dark` is invisible. */
.lp-final .lp-btn-primary {
  background: var(--bone); color: var(--dark);
  transition: background .2s ease, transform .2s ease, box-shadow .2s ease;
}
/* a 1px lift, and `:active` already pushes it back down by one - so the
   two states read as one physical control rather than two effects. */
.lp-final .lp-btn-primary:hover {
  background: #fff; color: var(--dark);
  transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0,0,0,.32);
}
.lp-final .lp-btn-primary:hover { color: var(--wine-deep); }
.lp-final .lp-btn-ghost {
  background: transparent; color: var(--dark-ink); border-color: var(--dark-line);
}
.lp-final .lp-btn-ghost:hover { border-color: var(--dark-wine); color: var(--dark-wine); }

/* ONE closing bar. Feedback and footer were two bands with a rule each. */
.lp-final .lp-say { margin-top: clamp(44px, 5vw, 76px); padding-top: 26px; }
.lp-final .lp-footer { margin-top: clamp(30px, 3.4vw, 48px); }
.lp-final .lp-say {
  margin-top: clamp(30px, 4vw, 54px); padding-top: 22px;
  border-top: 1px solid var(--dark-line);
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.lp-final .lp-say__label { margin-bottom: 0; color: var(--dark-kicker); white-space: nowrap; }
.lp-final .lp-say__row { margin-left: auto; flex: 0 1 460px; }
.lp-final .lp-say__input {
  background: rgba(247,245,241,.06); border-color: var(--dark-line); color: var(--dark-ink);
}
.lp-final .lp-say__input::placeholder { color: var(--dark-kicker); }
.lp-final .lp-say__send { background: var(--bone); border-color: var(--bone); color: var(--dark); }
.lp-final .lp-say__said { flex-basis: 100%; text-align: right; color: var(--dark-wine); }

.lp-final .lp-footer { border-top: 0; padding-top: 18px; }
.lp-final .lp-footer-note,
.lp-final .lp-footer-tail { color: var(--dark-kicker); }

@media (max-width: 979px) {
  .lp-final .lp-props { margin: 26px 0 0; }
  .lp-final .lp-say__row { margin-left: 0; flex: 1 1 300px; }
}

/* ==========================================================================
   hero recomposition: proportion, hierarchy, principles band
   ========================================================================== */

/* -- 45:55. The copy takes the SHORT side; the drawing is the other half
   of the composition rather than an inset picture. `initTree` measures
   the real title/lede width to place itself, so this hands it the space
   without a single coordinate being hard-coded to match. */
@media (min-width: 1100px) {
  .lp-title, .lp-hero-thesis, .lp-cta-row { max-width: 45%; }
  .lp-title { max-width: min(17ch, 45%); }
  .lp-lede { max-width: min(42ch, 43%); }
}

/* -- Optical balance. Centred, the drawing and the text block read as two
   stacked rectangles; lifted slightly, the composition gains upward
   momentum and the two halves lock together. */
@media (min-width: 1100px) {
  .lp-tree { transform: translateY(-3.5%); }
}

/* -- Headline. Balanced breaks rather than ragged ones, and a touch more
   negative tracking now that it sets in a narrower measure. */
.lp-title { text-wrap: balance; letter-spacing: -.026em; }
.lp-hero-thesis { text-wrap: balance; }

/* -- CTA hierarchy. Two bordered buttons read as two equal choices. The
   secondary becomes a quiet ruled link: still obviously clickable, no
   longer competing with the primary. */
.lp-hero .lp-btn-ghost {
  border-color: transparent; background: transparent; padding-inline: 4px;
  border-radius: 0; box-shadow: inset 0 -1px 0 var(--wine-line);
}
.lp-hero .lp-btn-ghost:hover {
  border-color: transparent; color: var(--wine);
  box-shadow: inset 0 -1px 0 var(--wine);
}
.lp-cta-row { align-items: center; gap: 20px; }

/* -- Quieter wayfinding. Eleven destinations at 13.5px formed a second
   hierarchy across the top of the page. The CTA is untouched. */
.lp-nav-links a { font-size: 12.5px; color: var(--muted-q); }
.lp-nav-links a:hover { color: var(--ink); }
.lp-nav-links { gap: 18px; }

/* -- The principles band. Was five cards with a rule over each, competing
   with the headline. Now a quiet band: separators BETWEEN rather than
   above, mono keys at label scale, wine reserved for the key. All five
   keep their full text. */
.lp-proof {
  border-top: 1px solid var(--line);
  gap: 0; margin-top: clamp(30px, 4vw, 52px);
}
.lp-proof > div {
  padding: 18px 24px 0 0; position: relative;
}
.lp-proof > div + div {
  padding-left: 24px;
  box-shadow: inset 1px 0 0 var(--line);
}
.lp-proof-k {
  font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 600; color: var(--wine); margin-bottom: 8px;
}
.lp-proof-v { font-size: 12.5px; line-height: 1.55; color: var(--muted); }

/* -- And the band points DOWN. A short hairline continuing past the last
   row, in the same architectural line language the drawing uses, so the
   hero ends mid-sentence instead of terminating. */
.lp-proof::after {
  content: ""; position: absolute; left: 0; bottom: -26px;
  width: 1px; height: 20px; background: var(--wine-line);
}
.lp-proof { position: relative; }

@media (max-width: 1099px) {
  .lp-proof > div + div { padding-left: 0; box-shadow: none; }
}

/* ==========================================================================
   chapter two: acceleration, deterioration, isolation, payoff
   ========================================================================== */

/* -- The deal ACCELERATES. Evenly spaced cards read as a list being
   populated; closing gaps read as something getting away from you. The
   first lands deliberately, the last three almost together. */
.lp-hist.in .lp-hist-row { animation-delay: var(--deal, .18s); }
.lp-hist.in .lp-hist-row:nth-of-type(1) { --deal: .18s; }
.lp-hist.in .lp-hist-row:nth-of-type(2) { --deal: .34s; }
.lp-hist.in .lp-hist-row:nth-of-type(3) { --deal: .47s; }
.lp-hist.in .lp-hist-row:nth-of-type(4) { --deal: .57s; }
.lp-hist.in .lp-hist-row:nth-of-type(5) { --deal: .64s; }
.lp-hist.in .lp-hist-row:nth-of-type(6) { --deal: .69s; }

/* -- The pile DETERIORATES as it descends. Six symptoms that are really
   one failure getting worse: each card turns a little further off square
   and its top edge catches a little less light. The TEXT keeps its full
   strength - legibility is not the thing degrading. */
.lp-hist-row:nth-of-type(1) { --r: .06deg;  --dx: -1px; --edge: .085; }
.lp-hist-row:nth-of-type(2) { --r: -.13deg; --dx: 2px;  --edge: .075; }
.lp-hist-row:nth-of-type(3) { --r: .19deg;  --dx: -2px; --edge: .065; }
.lp-hist-row:nth-of-type(4) { --r: -.26deg; --dx: 3px;  --edge: .055; }
.lp-hist-row:nth-of-type(5) { --r: .34deg;  --dx: -3px; --edge: .045; }
.lp-hist-row:nth-of-type(6) { --r: -.42deg; --dx: 4px;  --edge: .035; }
.lp-hist-row {
  border-color: rgba(247,245,241, var(--edge, .09));
  box-shadow: 0 -1px 0 rgba(247,245,241, calc(var(--edge, .09) * .6)),
              0 10px 22px rgba(0,0,0,.5);
}

/* -- The absence gets ISOLATED. It was a column with the same gap as the
   others, so the eye ran straight across it. A hairline and real space in
   front of it make the reader stop: symptom, event, then a pause, then
   nothing. */
@media (min-width: 900px) {
  .lp-hist-head, .lp-hist-row {
    grid-template-columns: 34px 118px minmax(0, 250px) minmax(0, 1fr) 118px;
  }
  .lp-hist-who {
    padding-left: 26px;
    box-shadow: inset 1px 0 0 rgba(247,245,241,.06);
  }
  .lp-hist-head span:last-child { padding-left: 26px; }
}

/* -- The conclusion is the FINDING, not a caption under a table. */
.lp-hist-foot { margin-top: clamp(34px, 4vw, 58px); }
/* -- COUPLING. The figures and the conclusion were timed off the old
   linear deal (`.45s + i * .13s`, `1.15s`). Accelerating the cards left
   row 6's figure arriving .4s after its own card, and the conclusion
   landing before the last card had finished falling. Both now follow the
   deal itself, so changing the rhythm in one place changes it
   everywhere. */
.lp-hist.in .lp-fig { animation-delay: calc(var(--deal, .18s) + .27s); }
.lp-hist.in .lp-hist-foot { animation-delay: 1.62s; }

/* ==========================================================================
   chapter three: 2 + 1, not 3
   ========================================================================== */

/* -- The grid says 2 + 1. The incumbents share a tight gap; Skema sits
   past a wider one, so the eye reads a PAIR and then a conclusion rather
   than three equivalent options. */
@media (min-width: 861px) {
  .lp-choice {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.06fr);
    gap: 14px;
    column-gap: 14px;
    position: relative;
  }
  .lp-choice-us { margin-left: 26px; }

  /* The connector: the two approaches joined, turning into the third.
     Same hairline language as the hero drawing - drawn, not asserted. */
  .lp-choice::before {
    content: ""; position: absolute; left: 0; right: 0; top: -17px;
    height: 1px; background: var(--line);
    /* stops short of Skema: it belongs to the pair */
    right: calc(33.5% + 20px);
  }
  .lp-choice::after {
    content: ""; position: absolute; top: -17px; height: 19px; width: 1px;
    background: var(--wine-line);
    left: calc(66.5% + 6px);
  }
}

/* -- Skema is a semantic state, not a featured card. The incumbents keep
   the neutral hairline; Skema's boundary is the one that resolves. */
.lp-choice-col { border-radius: 12px; }
.lp-choice-us {
  border-color: var(--wine); border-width: 1px;
  box-shadow: inset 0 0 0 1px rgba(126,34,48,.06);
}

/* -- The closing line is the section's thesis, not another bold sentence.
   Someone should be able to leave the page remembering only this. */
.lp-choice-us .lp-choice-b strong {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--wine-line);
  font-family: var(--display); font-weight: 400;
  font-size: 17px; letter-spacing: -.015em; color: var(--wine-deep);
}

/* -- The word that sets up the comparison. */
.lp-h2 .lp-two {
  box-shadow: inset 0 -2px 0 var(--wine-line);
}

/* -- The animation argues: a half, the other half, a pause, the join,
   then the answer.
   Driven from the CONTAINER's `.in`, the way `.lp-hist` already drives its
   rows. `initReveals` writes `transitionDelay` as an INLINE style, so a
   stylesheet `transition-delay` on a `.reveal` element is dead on arrival;
   an animation is not affected by it. */
.lp-choice.in .lp-choice-col {
  animation: lp-choice-rise .55s cubic-bezier(.22,.61,.36,1)
             var(--d, 0s) backwards;
}
.lp-choice.in .lp-choice-col:nth-of-type(1) { --d: .06s; }
.lp-choice.in .lp-choice-col:nth-of-type(2) { --d: .32s; }
/* the pause, then the synthesis */
.lp-choice.in .lp-choice-col:nth-of-type(3) { --d: .78s; }
@keyframes lp-choice-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
/* The connector draws across the pair before Skema arrives. */
.lp-choice.in::before { animation: lp-choice-draw .5s ease .52s backwards; }
.lp-choice.in::after  { animation: lp-choice-draw .35s ease .70s backwards; }
@keyframes lp-choice-draw { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .lp-choice.in .lp-choice-col,
  .lp-choice.in::before, .lp-choice.in::after { animation: none; }
}

@media (max-width: 860px) {
  .lp-choice-us { margin-left: 0; }
}

/* ==========================================================================
   chapter four: governance is earned, not announced
   ========================================================================== */

/* Two signatures were a WORD in a metadata line. The whole argument of
   this product is that a machine may draft and validate but a person
   decides, and the stage that is supposed to show that decision showed a
   badge turning green. These draw, in order, before the badge. */
.lp-tf-sign { height: 22px; margin-bottom: 8px; }
.lp-tf-sign svg { display: block; width: 116px; height: 22px; overflow: visible; }
.lp-tf-ink {
  fill: none; stroke: var(--wine); stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .78;
  stroke-dasharray: 120; stroke-dashoffset: 120;
}
.lp-tf[data-stage="3"] .lp-tf-ink {
  animation: lp-tf-sign .62s cubic-bezier(.3,.7,.4,1) var(--sd, 0s) forwards;
}
@keyframes lp-tf-sign { to { stroke-dashoffset: 0; } }

/* The badge waits for the second signature; the exports wait for the
   badge. Governance is reached, then it is usable - in that order. */
.lp-tf[data-stage="3"] .lp-tf-governed { transition-delay: 1.02s; }
.lp-tf-payoff { transition-delay: 0s; }
.lp-tf[data-stage="3"] .lp-tf-payoff {
  transition: opacity .6s ease 1.24s,
              transform .6s cubic-bezier(.22,.61,.36,1) 1.24s;
}

/* Leaving the governed stage, the ink is simply not there again - no
   reverse scribble, which would read as an undo animation rather than as
   a different state. */
.lp-tf:not([data-stage="3"]) .lp-tf-ink { stroke-dashoffset: 120; }

@media (prefers-reduced-motion: reduce) {
  .lp-tf[data-stage="3"] .lp-tf-ink { animation: none; stroke-dashoffset: 0; }
  .lp-tf[data-stage="3"] .lp-tf-governed,
  .lp-tf[data-stage="3"] .lp-tf-payoff { transition-delay: 0s; }
}
/* The strokes are a SIBLING of the payoff, not a child. Nested, they sat
   inside a block that is opacity:0 until 1.24s - so they finished drawing
   at 1.14s while invisible and were revealed already-signed, which is the
   opposite of the point. They need their own reveal. */
.lp-tf-sign { opacity: 0; transition: opacity .3s ease; }
.lp-tf[data-stage="3"] .lp-tf-sign { opacity: 1; }

/* ==========================================================================
   chapter discovery: watch a sentence become a model
   ========================================================================== */

/* 38 / 62. The demonstration IS the explanation, so it takes the long
   side; the rules take the short one. */
.lp-md { margin-top: clamp(24px, 3vw, 40px); }
.lp-md-grid { display: grid; gap: clamp(24px, 3vw, 54px); align-items: start; }
@media (min-width: 1000px) {
  .lp-md-grid { grid-template-columns: 38fr 62fr; }
}

/* -- the four rules. One line each, and each one LIGHTS when the stage
   that earns it is reached, so the copy is a consequence of the
   demonstration rather than a caption beside it. */
.lp-md-rules { display: flex; flex-direction: column; gap: 18px; padding-top: 6px; }
.lp-md-rule {
  opacity: .3; transition: opacity .5s ease;
  padding-left: 14px; box-shadow: inset 2px 0 0 var(--line);
}
.lp-md-rule b {
  display: block; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--wine);
  margin-bottom: 5px; font-weight: 600;
}
.lp-md-rule span { font-size: 13px; line-height: 1.5; color: var(--muted); }
.lp-md-rule.is-on { opacity: 1; box-shadow: inset 2px 0 0 var(--wine); }

/* -- the stage. A quiet field, not a card. */
.lp-md-stage {
  position: relative;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--paper); padding: clamp(20px, 2.4vw, 30px);
}

/* -- state 1: the sentence, and it never leaves. */
.lp-md-sentence {
  font-family: var(--display); font-size: clamp(17px, 1.7vw, 21px);
  line-height: 1.5; letter-spacing: -.012em; color: var(--ink);
  max-width: 40ch; margin: 0;
}
.lp-md-w { position: relative; transition: color .4s ease; }
/* evidence attaches UNDER the words - the source is annotated, never
   replaced. */
.lp-md-w::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 1px; background: var(--wine);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s cubic-bezier(.22,.61,.36,1);
}
.lp-md[data-stage="1"] .lp-md-w::after,
.lp-md[data-stage="2"] .lp-md-w::after,
.lp-md[data-stage="3"] .lp-md-w::after,
.lp-md[data-stage="4"] .lp-md-w::after,
.lp-md[data-stage="5"] .lp-md-w::after,
.lp-md[data-stage="6"] .lp-md-w::after { transform: scaleX(1); }
.lp-md-w[data-f="1"]::after { transition-delay: .1s; }
.lp-md-w[data-f="2"]::after { transition-delay: .2s; }
.lp-md-w[data-f="3"]::after { transition-delay: .3s; }

/* -- state 2: the observations. Named, and named as OBSERVATIONS. */
.lp-md-obs {
  margin-top: 18px; opacity: 0; transform: translateY(4px);
  transition: opacity .45s ease, transform .45s ease;
}
.lp-md[data-stage="2"] .lp-md-obs,
.lp-md[data-stage="3"] .lp-md-obs { opacity: 1; transform: none; }

/* -- the slot. The field and the candidate are two answers to the same
   question, so they share ONE grid cell: the slot is exactly as tall as
   the taller of them, nothing reflows between stages, and no state can
   be drawn over another at any wrap or width. This replaces two
   hand-measured `top:` constants that were wrong the moment the
   sentence took a second line. */
.lp-md-slot { display: grid; margin-top: clamp(18px, 2vw, 26px); }
.lp-md-slot > * { grid-area: 1 / 1; align-self: start; }
.lp-md-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.lp-md-tag {
  font-family: var(--mono); font-size: 10.5px; padding: 3px 8px;
  border: 1px dashed var(--wine-line); border-radius: 5px;
  color: var(--wine-deep); background: var(--wine-tint);
}
.lp-md-note {
  margin-top: 8px; font-family: var(--mono); font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted-q);
}

/* -- state 3: accumulation, and the bar. */
.lp-md-field {
  opacity: 0; transition: opacity .4s ease; pointer-events: none;
}
.lp-md-flab {
  font-family: var(--mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted-q); margin-bottom: 10px;
}
.lp-md[data-stage="3"] .lp-md-field { opacity: 1; }
.lp-md-marks { display: flex; flex-wrap: wrap; gap: 5px; max-width: 330px; }
.lp-md-mark {
  width: 5px; height: 5px; border-radius: 1px; background: var(--wine);
  opacity: 0; transform: scale(.4);
}
.lp-md[data-stage="3"] .lp-md-mark {
  animation: lp-md-land .3s ease calc(var(--n) * .022s) forwards;
}
@keyframes lp-md-land { to { opacity: .8; transform: none; } }
.lp-md-bar {
  position: relative; margin-top: 14px; height: 1px;
  background: var(--line); max-width: 330px; overflow: hidden;
}
.lp-md-bar i {
  position: absolute; inset: 0; background: var(--wine);
  transform: scaleX(0); transform-origin: left;
}
.lp-md[data-stage="3"] .lp-md-bar i {
  animation: lp-md-bar .5s cubic-bezier(.22,.61,.36,1) 1.05s forwards;
}
@keyframes lp-md-bar { to { transform: scaleX(1); } }
.lp-md-count {
  margin-top: 12px; font-family: var(--mono); font-size: 11px;
  color: var(--muted-q); opacity: 0;
}
.lp-md[data-stage="3"] .lp-md-count {
  animation: lp-md-in .4s ease 1.35s forwards;
}
.lp-md-count b { font-size: 15px; color: var(--wine); font-weight: 500; }
@keyframes lp-md-in { to { opacity: 1; } }

/* -- state 4: THE CANDIDATE. The moment to remember: discovered, and
   explicitly not written. Dashed until governance resolves it. */
.lp-md-card {
  justify-self: start; width: min(300px, 100%);
  border: 1px dashed var(--wine); border-radius: 10px;
  background: var(--wine-tint); padding: 16px 18px 18px;
  opacity: 0; transform: translateY(8px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1),
              border-style .3s ease, background .5s ease;
}
.lp-md[data-stage="4"] .lp-md-card,
.lp-md[data-stage="5"] .lp-md-card,
.lp-md[data-stage="6"] .lp-md-card { opacity: 1; transform: none; }
.lp-md-card-k {
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-md-card-t {
  font-family: var(--display); font-size: 26px; letter-spacing: -.02em;
  color: var(--ink); margin: 6px 0 4px;
}
.lp-md-card-m { font-family: var(--mono); font-size: 10.5px; color: var(--muted-q); }
.lp-md-card-x {
  margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--wine-line);
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--wine);
}
/* governed: the boundary stops being provisional. */
.lp-md[data-stage="6"] .lp-md-card {
  border-style: solid; border-color: var(--ok); background: #eef4f0;
}
.lp-md[data-stage="6"] .lp-md-card-k { color: var(--ok); }
.lp-md[data-stage="6"] .lp-md-card-x {
  color: var(--ok); border-top-color: rgba(46,100,72,.3);
}

/* the two signatures, drawn on the candidate at the proposal stage */
.lp-md-sign { height: 20px; margin-top: 10px; opacity: 0; transition: opacity .3s ease; }
.lp-md[data-stage="5"] .lp-md-sign,
.lp-md[data-stage="6"] .lp-md-sign { opacity: 1; }
.lp-md-sign svg { display: block; width: 108px; height: 20px; overflow: visible; }
.lp-md-ink {
  fill: none; stroke: var(--wine); stroke-width: 1.3; stroke-linecap: round;
  opacity: .8; stroke-dasharray: 110; stroke-dashoffset: 110;
}
.lp-md[data-stage="5"] .lp-md-ink,
.lp-md[data-stage="6"] .lp-md-ink {
  animation: lp-md-sign .6s cubic-bezier(.3,.7,.4,1) var(--sd, 0s) forwards;
}
@keyframes lp-md-sign { to { stroke-dashoffset: 0; } }
.lp-md[data-stage="6"] .lp-md-ink { stroke: var(--ok); }

/* -- the write rule. Never a paragraph: a system state. */
.lp-md-write {
  position: absolute; right: clamp(20px, 2.4vw, 30px);
  bottom: clamp(18px, 2vw, 26px);
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase;
}
.lp-md-write span { display: none; }
.lp-md[data-stage="4"] .lp-md-write [data-w="draft"] { display: block; color: var(--wine); }
.lp-md[data-stage="5"] .lp-md-write [data-w="draft"] { display: block; color: var(--wine); }
.lp-md[data-stage="6"] .lp-md-write [data-w="signed"] { display: block; color: var(--ok); }

/* -- the spine. A track with states on it, not a tab bar. */
.lp-md-spine {
  position: relative; margin-top: clamp(26px, 3vw, 44px);
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
}
.lp-md-track {
  position: absolute; left: 7%; right: 7%; top: 5px; height: 1px;
  background: var(--line);
}
.lp-md-step {
  position: relative; background: none; border: 0; padding: 0;
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  cursor: pointer; font: inherit;
}
.lp-md-dot {
  width: 11px; height: 11px; border-radius: 50%;
  border: 1px solid var(--line-2); background: var(--bone);
  transition: background .35s ease, border-color .35s ease, transform .35s ease;
}
.lp-md-name {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted-q);
  transition: color .35s ease;
}
.lp-md-step:hover .lp-md-name { color: var(--ink); }
.lp-md-step:focus-visible { outline: 2px solid var(--wine); outline-offset: 4px; }
/* passed states fill; the current one is wine; governed resolves green. */
.lp-md-step.is-done .lp-md-dot { background: var(--wine-line); border-color: var(--wine-line); }
.lp-md-step.is-on .lp-md-dot { background: var(--wine); border-color: var(--wine); transform: scale(1.25); }
.lp-md-step.is-on .lp-md-name { color: var(--wine); font-weight: 600; }
.lp-md[data-stage="6"] .lp-md-step.is-on .lp-md-dot { background: var(--ok); border-color: var(--ok); }
.lp-md[data-stage="6"] .lp-md-step.is-on .lp-md-name { color: var(--ok); }

/* -- the axis. Evidence accumulates for a long time before anything is
   authoritative, which is the point of the whole section. */
.lp-md-axis {
  display: flex; align-items: center; gap: 10px; margin-top: 14px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-md-axis i { flex: 1; height: 1px; background: linear-gradient(90deg, var(--line), var(--wine-line)); }

/* -- the thesis. Present as a rule the whole way through, answered at
   the end. */
.lp-md-thesis {
  margin-top: clamp(18px, 2vw, 28px);
  font-family: var(--display); font-size: clamp(19px, 2vw, 26px);
  letter-spacing: -.02em; color: var(--muted-q);
  transition: color .6s ease;
}
.lp-md-thesis em { font-style: normal; color: var(--wine); }
.lp-md[data-stage="6"] .lp-md-thesis { color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .lp-md-mark, .lp-md-bar, .lp-md-count, .lp-md-ink { animation: none; }
  .lp-md-mark { opacity: .8; transform: none; }
  .lp-md-bar i { transform: scaleX(1); }
  .lp-md-count { opacity: 1; }
  .lp-md-ink { stroke-dashoffset: 0; }
}
@media (max-width: 720px) {
  .lp-md-name { display: none; }
  .lp-md-card { width: 100%; }
  .lp-md-write { position: static; margin-top: 18px; }
}

/* discovery fix: states stack, nothing escapes */

/* ==========================================================================
   chapter five: post-decision reality
   ==========================================================================
   The five states were a table, which has no "afterwards" - and afterwards
   is the whole idea. One claim is now the hero, fixed on white paper in a
   dark archive, and the evidence around it changes. The claim column
   carries NO state-dependent rule; that is deliberate and load-bearing. */

.lp-ev {
  margin-top: clamp(30px, 3.6vw, 50px);
  /* --ok is tuned for white paper; on #17140f it reads as a smudge. */
  --ev-ok: #7fae93;
}
#lp-states .lp-sub { max-width: 44ch; }

/* -- true / false, and the moment it stops being enough. ------------------ */
.lp-ev-open { margin-bottom: clamp(34px, 4vw, 58px); }
.lp-ev-bin {
  display: flex; align-items: center; gap: 14px; max-width: 240px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dark-muted);
}
.lp-ev-bin i { flex: 1; height: 1px; background: var(--dark-line); }
.lp-ev-open.in .lp-ev-bin { animation: lp-ev-dim .9s ease 1.1s forwards; }
@keyframes lp-ev-dim { to { opacity: .3; } }
.lp-ev-arrow {
  width: 1px; height: 24px; margin: 10px 0 12px 4px;
  background: var(--dark-line); transform-origin: top;
}
.lp-ev-open.in .lp-ev-arrow { animation: lp-ev-drop .5s ease 1.15s backwards; }
@keyframes lp-ev-drop { from { transform: scaleY(0); } }
.lp-ev-vocab { display: flex; flex-wrap: wrap; gap: 10px 22px; }
.lp-ev-v {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--dark-ink);
  opacity: 0; transform: translateY(5px);
}
.lp-ev-open.in .lp-ev-v {
  animation: lp-ev-rise .5s cubic-bezier(.22,.61,.36,1) calc(1.3s + var(--d, 0s)) forwards;
}
@keyframes lp-ev-rise { to { opacity: 1; transform: none; } }

/* -- the state vocabulary. Geometric, never a status icon set, and never a
   traffic light: these are epistemic conditions, not pass and fail. Green
   marks the one state that is still validated; withdrawn takes the muted
   rose the page already uses for attention, never a red. */
.lp-ev-m { width: 9px; height: 9px; border-radius: 50%; flex: none; position: relative; }
.lp-ev-m0 { background: var(--ev-ok, #7fae93); }
.lp-ev-m1 {
  box-shadow: inset 0 0 0 1px var(--dark-ink);
  background: linear-gradient(90deg, var(--dark-ink) 0 50%, transparent 50%);
}
.lp-ev-m2 { box-shadow: inset 0 0 0 1px var(--dark-muted); }
.lp-ev-m3::before, .lp-ev-m3::after {
  content: ""; position: absolute; left: -1px; right: -1px; top: 4px;
  height: 1px; background: var(--dark-wine);
}
.lp-ev-m3::before { transform: rotate(45deg); }
.lp-ev-m3::after { transform: rotate(-45deg); }
.lp-ev-m4 { border: 1px dashed var(--dark-muted); }

/* -- the composition: a fixed record, a changing support. ----------------- */
.lp-ev-grid { display: grid; gap: clamp(26px, 3.2vw, 58px); align-items: start; }
@media (min-width: 940px) {
  .lp-ev-grid { grid-template-columns: 39fr 61fr; }
}
.lp-ev-cap {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dark-kicker); margin-bottom: 15px;
}
.lp-ev-cap em { font-style: normal; color: var(--dark-wine); }

/* The record is a physical document placed in a dark archive. Every colour
   here is set explicitly: the component this replaced inherited --dark-ink
   onto --paper and rendered its own headings invisible. */
.lp-ev-card {
  background: var(--paper); color: var(--ink);
  border-radius: 12px; padding: clamp(20px, 2.2vw, 28px);
  box-shadow: 0 20px 44px rgba(0,0,0,.5);
}
.lp-ev-k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-ev-t {
  font-family: var(--display); font-size: clamp(21px, 2.1vw, 27px);
  line-height: 1.22; letter-spacing: -.022em; color: var(--ink);
  margin: 11px 0 17px;
}
.lp-ev-meta {
  display: flex; flex-wrap: wrap; gap: 5px 20px; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 10.5px; color: var(--muted);
}
.lp-ev-fix {
  margin-top: 15px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ok);
}

/* The five supports are alternatives to one another, so they share a single
   grid cell: the panel is as tall as the tallest of them, the record beside
   it never shifts, and no state can be drawn over another. */
.lp-ev-slot { display: grid; }
.lp-ev-slot > * { grid-area: 1 / 1; align-self: start; }
.lp-ev-panel { opacity: 0; transition: opacity .45s ease; pointer-events: none; }
.lp-ev[data-state="0"] .lp-ev-panel[data-s="0"],
.lp-ev[data-state="1"] .lp-ev-panel[data-s="1"],
.lp-ev[data-state="2"] .lp-ev-panel[data-s="2"],
.lp-ev[data-state="3"] .lp-ev-panel[data-s="3"],
.lp-ev[data-state="4"] .lp-ev-panel[data-s="4"] { opacity: 1; }

.lp-ev-name {
  display: flex; align-items: center; gap: 11px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--dark-ink); font-weight: 500;
}
.lp-ev-say {
  margin: 12px 0 0; font-family: var(--display);
  font-size: clamp(18px, 1.8vw, 23px); line-height: 1.32;
  letter-spacing: -.018em; color: var(--dark-ink); max-width: 30ch;
}
.lp-ev-rows { margin-top: 22px; }
.lp-ev-r, .lp-ev-rule {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 18px; padding: 10px 0; border-top: 1px solid var(--dark-line);
  font-family: var(--mono); font-size: 11px;
}
.lp-ev-src { color: var(--dark-ink); }
.lp-ev-when {
  font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dark-kicker); white-space: nowrap;
}
.lp-ev-note {
  margin-top: 18px; font-family: var(--mono); font-size: 9.5px;
  line-height: 1.7; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dark-kicker); max-width: 44ch;
}

/* EVIDENCE MOVED is the hero: the superseded source leaves the cluster
   while the claim beside it does not move a pixel. */
.lp-ev[data-state="1"] .lp-ev-r.is-out {
  animation: lp-ev-out .95s cubic-bezier(.4,0,.2,1) .5s forwards;
}
@keyframes lp-ev-out { to { opacity: .28; transform: translateX(22px); } }
.lp-ev-r.is-new { opacity: 0; }
.lp-ev[data-state="1"] .lp-ev-r.is-new { animation: lp-ev-fade .55s ease 1s forwards; }
.lp-ev[data-state="1"] .lp-ev-r.is-new + .is-new { animation-delay: 1.2s; }
@keyframes lp-ev-fade { to { opacity: 1; } }

/* HELD: the support line stops halfway. Suspended, not refuted. */
.lp-ev-half { margin-top: 22px; }
.lp-ev-half i {
  display: block; height: 1px; background: var(--dark-muted);
  transform: scaleX(0); transform-origin: left;
}
.lp-ev[data-state="2"] .lp-ev-half i {
  animation: lp-ev-half .95s cubic-bezier(.22,.61,.36,1) .45s forwards;
}
@keyframes lp-ev-half { to { transform: scaleX(.44); } }
.lp-ev-half span {
  display: block; margin-top: 10px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dark-muted);
}

/* WITHDRAWN: the same threshold the discovery section drew, falling under
   it. Reused deliberately - a second metaphor for one idea is a cost. */
.lp-ev-bar { position: relative; margin: 30px 0 34px; height: 1px; background: var(--dark-line); }
.lp-ev-bar i {
  position: absolute; left: 0; top: 0; height: 1px; width: 100%;
  background: var(--dark-wine); transform: scaleX(.62); transform-origin: left;
}
.lp-ev[data-state="3"] .lp-ev-bar i {
  animation: lp-ev-fall 1.05s cubic-bezier(.4,0,.2,1) .45s forwards;
}
@keyframes lp-ev-fall { from { transform: scaleX(.62); } to { transform: scaleX(.3); } }
.lp-ev-bar b { position: absolute; left: 62%; top: -9px; width: 1px; height: 19px; background: var(--dark-muted); }
.lp-ev-bar u {
  position: absolute; left: 62%; top: 15px; margin-left: -13px;
  text-decoration: none; font-family: var(--mono); font-size: 9px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dark-muted);
}
.lp-ev-only {
  margin-top: 14px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dark-wine);
}

/* UNACCOUNTED: superseded, not struck through. A line through it would say
   the claim was wrong, and the entire point is that it is not. */
.lp-ev-rule b { color: var(--dark-ink); font-weight: 500; }
.lp-ev-rule span {
  font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dark-kicker);
}
.lp-ev-rule.is-old { opacity: .42; }

/* -- the re-reads. The dates ARE the selectors, so exploration and the
   timeline are one object rather than a tab bar sitting near a graphic.
   The rail is drawn per node at the dot's own row, so it cannot drift out
   of alignment when the labels change length. */
.lp-ev-time { margin-top: clamp(38px, 4.4vw, 64px); }
.lp-ev-timecap {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dark-kicker); margin-bottom: 20px;
}
.lp-ev-nodes { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
.lp-ev-node {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  display: grid; gap: 11px; justify-items: center; text-align: center;
}
.lp-ev-node:focus-visible { outline: 2px solid var(--dark-wine); outline-offset: 5px; }
.lp-ev-date {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--dark-kicker); transition: color .35s ease;
}
.lp-ev-rail { position: relative; width: 100%; height: 11px; display: grid; place-items: center; }
.lp-ev-rail::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; background: var(--dark-line);
}
.lp-ev-node:first-child .lp-ev-rail::before { left: 50%; }
.lp-ev-node:last-child .lp-ev-rail::before { right: 50%; }
.lp-ev-dot {
  position: relative; width: 9px; height: 9px; border-radius: 50%;
  background: var(--dark); box-shadow: inset 0 0 0 1px var(--dark-line);
  transition: background .35s ease, box-shadow .35s ease, transform .35s ease;
}
.lp-ev-nm {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--dark-kicker); transition: color .35s ease;
}
.lp-ev-node:hover .lp-ev-nm { color: var(--dark-ink); }
.lp-ev-node.is-done .lp-ev-dot { background: var(--dark-muted); box-shadow: none; }
.lp-ev-node.is-on .lp-ev-dot {
  background: var(--dark-ink); box-shadow: 0 0 0 4px rgba(247,245,241,.08);
  transform: scale(1.12);
}
.lp-ev-node.is-on .lp-ev-nm { color: var(--dark-ink); }
.lp-ev-node.is-on .lp-ev-date { color: var(--dark-muted); }

/* -- the payoff. Grey while the claim still stands; it earns its ink the
   moment something underneath it has actually moved. */
.lp-ev-end { margin-top: clamp(48px, 5.4vw, 80px); }
.lp-ev-big {
  margin: 0; max-width: 22ch; font-family: var(--display);
  font-size: clamp(26px, 3.1vw, 44px); line-height: 1.14; letter-spacing: -.024em;
  color: var(--dark-kicker); transition: color .8s ease;
}
.lp-ev:not([data-state="0"]) .lp-ev-big { color: var(--dark-ink); }
.lp-ev-small {
  margin: 18px 0 0; max-width: 50ch; font-size: 14px; line-height: 1.62;
  color: var(--dark-muted);
}

@media (prefers-reduced-motion: reduce) {
  .lp-ev-bin, .lp-ev-arrow, .lp-ev-v, .lp-ev-r, .lp-ev-half i, .lp-ev-bar i {
    animation: none !important;
  }
  .lp-ev-v, .lp-ev-r.is-new { opacity: 1; transform: none; }
  .lp-ev-half i { transform: scaleX(.44); }
  .lp-ev-bar i { transform: scaleX(.3); }
}
@media (max-width: 720px) {
  .lp-ev-nodes { gap: 4px; }
  .lp-ev-nm { font-size: 8.5px; letter-spacing: .04em; }
  .lp-ev-date { font-size: 8.5px; letter-spacing: .06em; }
  .lp-ev-r, .lp-ev-rule { flex-wrap: wrap; gap: 4px 12px; }
}

/* ==========================================================================
   chapter six: one fact, four dimensions
   ==========================================================================
   Four long paragraphs and a static diagram explained the same idea five
   times. One fact is now held still while four dimensions attach to it, and
   the fact column carries no dimension-dependent rule at all - the thing
   being inspected must not move while it is inspected. */

.lp-fp { margin-top: clamp(30px, 3.6vw, 52px); }
#lp-account .lp-h2 { max-width: 26ch; }
#lp-account .lp-sub { max-width: 58ch; }

.lp-fp-stage { display: grid; gap: clamp(24px, 2.6vw, 46px); align-items: start; }
@media (min-width: 1080px) {
  .lp-fp-stage { grid-template-columns: 17fr 29fr 54fr; }
}

/* -- the four inspection points. They read as places on the fact, not as
   tabs above a panel: a label, the question it answers, and a hairline that
   reaches toward the fact when it is the one being looked through. */
.lp-fp-rail { display: flex; flex-direction: column; gap: 2px; }
.lp-fp-pt {
  position: relative; background: none; border: 0; font: inherit;
  cursor: pointer; text-align: left; padding: 13px 0 13px 15px;
  box-shadow: inset 2px 0 0 var(--line);
  transition: box-shadow .4s ease;
}
.lp-fp-pt:focus-visible { outline: 2px solid var(--wine); outline-offset: 3px; }
.lp-fp-ptk {
  display: block; font-family: var(--mono); font-size: 11px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted-q);
  transition: color .4s ease;
}
.lp-fp-ptq {
  display: block; margin-top: 4px; font-size: 12.5px; color: var(--muted-q);
  transition: color .4s ease; opacity: .75;
}
.lp-fp-ptl {
  position: absolute; left: 100%; top: 50%; height: 1px; width: 0;
  background: var(--wine-line); transition: width .5s cubic-bezier(.22,.61,.36,1);
}
.lp-fp-pt.is-done { box-shadow: inset 2px 0 0 var(--wine-line); }
.lp-fp-pt.is-done .lp-fp-ptk { color: var(--muted); }
.lp-fp-pt.is-on { box-shadow: inset 2px 0 0 var(--wine); }
.lp-fp-pt.is-on .lp-fp-ptk { color: var(--wine); }
.lp-fp-pt.is-on .lp-fp-ptq { color: var(--ink-2); opacity: 1; }
@media (min-width: 1080px) {
  .lp-fp-pt.is-on .lp-fp-ptl { width: clamp(14px, 2.2vw, 40px); }
}

/* -- the fact. A semantic record, not a card: serif for the fact itself,
   mono for everything the machine put there. */
.lp-fp-fact {
  background: var(--paper); border: 1px solid var(--line-2); border-radius: 12px;
  padding: clamp(20px, 2.1vw, 27px);
  box-shadow: 0 1px 0 var(--line), 0 14px 30px rgba(23,20,15,.05);
}
.lp-fp-k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-fp-t { margin: 15px 0 18px; }
.lp-fp-t b {
  display: block; font-family: var(--display); font-weight: 400;
  font-size: clamp(25px, 2.5vw, 33px); line-height: 1.1; letter-spacing: -.024em;
  color: var(--ink);
}
.lp-fp-t em {
  display: block; margin: 5px 0 5px 2px; font-style: normal;
  font-family: var(--mono); font-size: 11px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--wine-deep);
}
.lp-fp-meta {
  display: flex; flex-direction: column; gap: 5px; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 10.5px; color: var(--muted);
}
.lp-fp-fid { color: var(--muted-q); }
/* the one thing the fact earns: all four attached, and it is complete. */
.lp-fp-stamp {
  margin-top: 14px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ok);
  opacity: 0; transition: opacity .7s ease;
}
.lp-fp[data-dim="3"] .lp-fp-stamp { opacity: 1; transition-delay: 1.7s; }

/* -- what attaches. Four alternatives, one grid cell, constant height. */
.lp-fp-slot { display: grid; }
.lp-fp-slot > * { grid-area: 1 / 1; align-self: start; }
.lp-fp-p { opacity: 0; transition: opacity .45s ease; pointer-events: none; }
.lp-fp[data-dim="0"] .lp-fp-p[data-d="0"],
.lp-fp[data-dim="1"] .lp-fp-p[data-d="1"],
.lp-fp[data-dim="2"] .lp-fp-p[data-d="2"],
.lp-fp[data-dim="3"] .lp-fp-p[data-d="3"] { opacity: 1; }
.lp-fp-say {
  margin: 0 0 22px; font-family: var(--display);
  font-size: clamp(18px, 1.75vw, 23px); line-height: 1.32;
  letter-spacing: -.018em; color: var(--ink); max-width: 32ch;
}
.lp-fp-note {
  margin-top: 20px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .11em; text-transform: uppercase; color: var(--muted-q);
}

/* WHO: mentions converge, and the identifier does not move when a fourth
   document turns up eighteen months later. */
.lp-fp-who { display: flex; align-items: center; gap: 0; }
.lp-fp-mn { display: flex; flex-direction: column; gap: 6px; }
.lp-fp-mn span {
  font-family: var(--mono); font-size: 11px; color: var(--ink-2);
  padding: 4px 10px; border: 1px solid var(--line); border-radius: 5px;
  background: var(--paper); opacity: 0; transform: translateX(-5px);
}
.lp-fp[data-dim="0"] .lp-fp-mn span {
  animation: lp-fp-in .45s cubic-bezier(.22,.61,.36,1) var(--d, 0s) forwards;
}
.lp-fp-mn .is-late { border-style: dashed; border-color: var(--wine-line); }
@keyframes lp-fp-in { to { opacity: 1; transform: none; } }
.lp-fp-conv { position: relative; width: clamp(26px, 3vw, 52px); height: 96px; }
.lp-fp-conv i, .lp-fp-conv u { position: absolute; background: var(--line-2); }
.lp-fp-conv i { left: 42%; top: 14px; bottom: 14px; width: 1px; }
.lp-fp-conv u { left: 42%; right: 0; top: 50%; height: 1px; }
.lp-fp-res { display: flex; flex-direction: column; gap: 7px; }
.lp-fp-reslab {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-fp-id {
  font-family: var(--mono); font-size: 13px; color: var(--wine-deep);
  padding: 6px 12px; border: 1px solid var(--wine-line); border-radius: 6px;
  background: var(--wine-tint);
}
.lp-fp-still {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ok); opacity: 0;
}
.lp-fp[data-dim="0"] .lp-fp-still { animation: lp-fp-fade .5s ease 1.85s forwards; }
@keyframes lp-fp-fade { to { opacity: 1; } }

/* WHY: small nodes on one hairline. */
.lp-fp-chain { list-style: none; margin: 0; padding: 0 0 0 17px; position: relative; }
.lp-fp-chain::before {
  content: ""; position: absolute; left: 3px; top: 8px; bottom: 8px;
  width: 1px; background: var(--line-2);
}
.lp-fp-chain li {
  position: relative; display: flex; align-items: baseline; gap: 14px;
  padding: 7px 0; opacity: 0;
}
.lp-fp[data-dim="1"] .lp-fp-chain li { animation: lp-fp-fade .45s ease var(--d, 0s) forwards; }
.lp-fp-chain li::before {
  content: ""; position: absolute; left: -17px; top: 13px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--paper); box-shadow: inset 0 0 0 1px var(--wine);
}
.lp-fp-chain li:last-child::before { background: var(--wine); }
.lp-fp-chain b {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
  min-width: 78px;
}
.lp-fp-chain span { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }

/* WHERE: two domains, the same two facts, different answers. Boundary
   geometry - never a map. */
.lp-fp-scope { display: flex; flex-wrap: wrap; gap: 14px; }
.lp-fp-dom {
  flex: 1 1 190px; padding: 13px 15px 14px; border-radius: 9px;
  opacity: 0; transform: translateY(5px);
}
.lp-fp[data-dim="2"] .lp-fp-dom {
  animation: lp-fp-in .5s cubic-bezier(.22,.61,.36,1) var(--d, 0s) forwards;
}
.lp-fp-dom.is-in { border: 1px solid var(--wine-line); background: var(--wine-tint); }
.lp-fp-dom.is-out { border: 1px dashed var(--line-2); background: transparent; }
.lp-fp-domn {
  display: block; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; margin-bottom: 10px;
}
.lp-fp-dom.is-in .lp-fp-domn { color: var(--wine); }
.lp-fp-dom.is-out .lp-fp-domn { color: var(--muted-q); }
.lp-fp-domr {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 5px 0; font-family: var(--mono); font-size: 11px; color: var(--ink-2);
}
.lp-fp-y, .lp-fp-n, .lp-fp-q { flex: none; width: 10px; height: 10px; position: relative; }
.lp-fp-y::before {
  content: ""; position: absolute; left: 1px; top: 1px; width: 4px; height: 7px;
  border: solid var(--ok); border-width: 0 1.4px 1.4px 0; transform: rotate(42deg);
}
.lp-fp-n::before {
  content: ""; position: absolute; left: 0; right: 0; top: 5px; height: 1px;
  background: var(--muted-q);
}
.lp-fp-q {
  font-family: var(--mono); font-size: 11px; color: var(--warn); line-height: 10px;
}
.lp-fp-q::before { content: "?"; }

/* HOW: the source goes, the fact does not, and the trace reports what it
   could not reach as well as what it did. */
.lp-fp-erow, .lp-fp-sf {
  display: flex; align-items: baseline; gap: 12px; padding: 8px 0;
  font-family: var(--mono); font-size: 11px; border-top: 1px solid var(--line);
}
.lp-fp-erow:first-child { border-top: 0; }
.lp-fp-erow b {
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted-q); font-weight: 600; min-width: 62px;
}
.lp-fp-erow span { color: var(--ink-2); }
.lp-fp-erow u {
  margin-left: auto; text-decoration: none; font-size: 9.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--wine);
  opacity: 0;
}
.lp-fp[data-dim="3"] .lp-fp-erow.is-src { animation: lp-fp-gone .7s ease .35s forwards; }
@keyframes lp-fp-gone { to { opacity: .38; } }
.lp-fp[data-dim="3"] .lp-fp-erow.is-src u { animation: lp-fp-fade .4s ease .5s forwards; }
.lp-fp-erow.is-head b { color: var(--wine); }
.lp-fp-trace {
  padding: 9px 0 9px 62px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted-q);
  opacity: 0;
}
.lp-fp[data-dim="3"] .lp-fp-trace { animation: lp-fp-fade .4s ease .85s forwards; }
.lp-fp-sf { padding-left: 62px; opacity: 0; }
.lp-fp[data-dim="3"] .lp-fp-sf { animation: lp-fp-fade .45s ease var(--d, 0s) forwards; }
.lp-fp-sf span { color: var(--ink-2); }
.lp-fp-sf em {
  margin-left: auto; font-style: normal; font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted-q);
}

/* -- the payoff, grey until the fact has acquired all four. */
.lp-fp-end { margin-top: clamp(44px, 5vw, 74px); }
.lp-fp-big {
  margin: 0; max-width: 20ch; font-family: var(--display);
  font-size: clamp(25px, 3vw, 42px); line-height: 1.14; letter-spacing: -.024em;
  color: var(--muted-q); transition: color .8s ease;
}
.lp-fp[data-dim="3"] .lp-fp-big { color: var(--ink); }
.lp-fp-small {
  margin: 17px 0 0; max-width: 56ch; font-size: 14px; line-height: 1.6;
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .lp-fp-mn span, .lp-fp-chain li, .lp-fp-dom, .lp-fp-sf,
  .lp-fp-trace, .lp-fp-still, .lp-fp-erow, .lp-fp-erow u {
    animation: none !important; opacity: 1; transform: none;
  }
}

/* -- the rail turns horizontal before the columns get too narrow to read;
   the fact stays first and stays primary. */
@media (max-width: 1079px) {
  .lp-fp-stage { grid-template-columns: minmax(0, 1fr); }
  .lp-fp-rail { flex-direction: row; flex-wrap: wrap; order: 2; gap: 0 10px; }
  .lp-fp-pt { flex: 1 1 150px; padding: 11px 0 11px 13px; }
  .lp-fp-factcol { order: 1; }
  .lp-fp-fact { max-width: 420px; }
  .lp-fp-detail { order: 3; }
}
@media (max-width: 620px) {
  .lp-fp-ptq { display: none; }
  .lp-fp-pt { flex: 1 1 44%; }
  .lp-fp-who { flex-direction: column; align-items: flex-start; gap: 12px; }
  .lp-fp-conv { width: 1px; height: 26px; margin-left: 18px; }
  .lp-fp-conv u { display: none; }
  .lp-fp-conv i { left: 0; top: 0; bottom: 0; }
  .lp-fp-chain b, .lp-fp-erow b { min-width: 0; }
  .lp-fp-chain li, .lp-fp-erow { flex-wrap: wrap; gap: 2px 10px; }
  .lp-fp-sf, .lp-fp-trace { padding-left: 0; }
}

/* ==========================================================================
   chapter seven: the canvas is the lens
   ==========================================================================
   The canvas was an illustration beside five paragraphs, which cannot make
   the section's argument: the same ontology looks different depending on
   what you are asking, and a still image has one answer in it. The graph is
   now the subject and the copy is the caption - 38 / 62, not 50 / 50. */

.lp-lens-wrap {
  display: grid; gap: clamp(28px, 3.4vw, 62px); align-items: center;
}
@media (min-width: 1040px) {
  .lp-lens-wrap { grid-template-columns: 38fr 62fr; }
}
#lp-canvas .lp-h2 { max-width: 15ch; }
#lp-canvas .lp-sub { max-width: 40ch; }
.lp-lens-copy { max-width: 500px; }

/* -- the four verbs. What the canvas actually does, in the page's own
   label language - not five bullets restyled as four. */
.lp-lens-gram {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 20px; margin-top: clamp(26px, 3vw, 40px);
  padding-top: clamp(22px, 2.4vw, 30px); border-top: 1px solid var(--line);
}
.lp-lens-g b {
  display: block; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--wine);
  font-weight: 600; margin-bottom: 5px;
}
.lp-lens-g span { font-size: 12.5px; line-height: 1.45; color: var(--muted); }

/* -- one instrument: rail, stage and readout inside a single frame. */
.lp-lens-frame {
  border: 1px solid var(--line-2); border-radius: 16px; background: var(--paper);
  box-shadow: 0 1px 0 var(--line), 0 22px 46px rgba(23,20,15,.06);
  overflow: hidden;
}
.lp-lens-rail { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.lp-lens-mode {
  background: none; border: 0; font: inherit; cursor: pointer; text-align: left;
  padding: 15px clamp(12px, 1.4vw, 20px) 14px;
  border-bottom: 1px solid var(--line);
  box-shadow: inset 0 0 0 0 var(--wine);
  transition: background .45s ease, box-shadow .45s ease;
}
.lp-lens-mode + .lp-lens-mode { border-left: 1px solid var(--line); }
.lp-lens-mode:focus-visible { outline: 2px solid var(--wine); outline-offset: -3px; }
.lp-lens-mn {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  color: var(--line-2); transition: color .45s ease;
}
.lp-lens-mk {
  display: block; margin-top: 6px; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted-q);
  transition: color .45s ease;
}
.lp-lens-mq {
  display: block; margin-top: 4px; font-size: 12px; color: var(--muted-q);
  opacity: .7; transition: color .45s ease, opacity .45s ease;
}
.lp-lens-mode.is-on { background: var(--wine-tint); box-shadow: inset 0 -2px 0 var(--wine); }
.lp-lens-mode.is-on .lp-lens-mn { color: var(--wine-line); }
.lp-lens-mode.is-on .lp-lens-mk { color: var(--wine); }
.lp-lens-mode.is-on .lp-lens-mq { color: var(--ink-2); opacity: 1; }

.lp-lens-stage { position: relative; padding: clamp(8px, 1.2vw, 16px); }
.lp-lens-svg { display: block; width: 100%; height: auto; }
/* only the nodes swallow touch: the canvas is tall, and a reader who
   puts a finger on it must still be able to scroll past it. */
.lp-lens-n, .lp-lens-rel { touch-action: none; }

/* -- the graph. Colour answers where a term came from and nothing else. */
.lp-lens-ctx circle { fill: #efece6; stroke: var(--line-2); stroke-width: 1; }
.lp-lens-ctx path { fill: none; stroke: var(--line-2); stroke-width: 1; }
.lp-lens-ctx { opacity: .5; transition: transform .7s cubic-bezier(.4,0,.2,1); }
.lp-lens-e { stroke: var(--line-2); stroke-width: 1.5; }
.lp-lens-e.is-rel { stroke: var(--wine); stroke-width: 1.7; }
.lp-lens-n { cursor: grab; }
.lp-lens-n.is-drag { cursor: grabbing; }
.lp-lens-n circle { stroke-width: 1.7; }
.lp-lens-n.is-min circle { fill: var(--wine-tint); stroke: var(--wine); }
.lp-lens-n.is-imp circle { fill: #ece7f2; stroke: #9a8fb0; }
.lp-lens-n.is-subject circle { stroke-width: 2.6; }
.lp-lens-nl {
  text-anchor: middle; font-family: var(--sans); font-size: 13px;
  fill: var(--ink-2); letter-spacing: -.01em;
}
.lp-lens-n.is-subject .lp-lens-nl { fill: var(--ink); font-weight: 600; font-size: 14.5px; }
.lp-lens-props text {
  text-anchor: end; font-family: var(--mono); font-size: 11px; fill: var(--muted);
}
.lp-lens-rel rect { fill: var(--paper); stroke: var(--wine); stroke-width: 1.4; }
.lp-lens-rel.is-object rect { fill: var(--wine-tint); stroke-width: 2.2; }
.lp-lens-rl {
  text-anchor: middle; dominant-baseline: central;
  font-family: var(--mono); fill: var(--wine-deep); letter-spacing: .04em;
}

/* dragging is the claim, so it gets its own confirmation. */
.lp-lens-kept {
  position: absolute; right: clamp(14px, 1.6vw, 22px); bottom: clamp(12px, 1.4vw, 18px);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ok);
  opacity: 0; transition: opacity .5s ease; pointer-events: none;
}
.lp-lens.is-kept .lp-lens-kept { opacity: 1; }

/* -- the readout belongs to the graph, so it sits inside the frame and
   changes with it. The colour key is constant and sits beside it. */
.lp-lens-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px;
  padding: 13px clamp(14px, 1.6vw, 22px); border-top: 1px solid var(--line);
  background: var(--bone);
}
.lp-lens-ros { display: grid; flex: 1 1 260px; }
.lp-lens-ro { grid-area: 1 / 1; opacity: 0; transition: opacity .4s ease; }
.lp-lens[data-mode="0"] .lp-lens-ro[data-r="0"],
.lp-lens[data-mode="1"] .lp-lens-ro[data-r="1"],
.lp-lens[data-mode="2"] .lp-lens-ro[data-r="2"] { opacity: 1; }
.lp-lens-ro b {
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-lens-ro span {
  display: block; margin-top: 3px; font-family: var(--mono); font-size: 10.5px;
  color: var(--muted);
}
.lp-lens-ro em { font-style: normal; color: var(--ink-2); }
.lp-lens-keys {
  display: flex; flex-wrap: wrap; gap: 6px 15px; font-family: var(--mono);
  font-size: 9.5px; letter-spacing: .06em; color: var(--muted-q);
}
.lp-lens-keys span { display: inline-flex; align-items: center; gap: 6px; }
.lp-lens-k { width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid; }
.lp-lens-k.is-min { background: var(--wine-tint); border-color: var(--wine); }
.lp-lens-k.is-imp { background: #ece7f2; border-color: #9a8fb0; }
.lp-lens-k.is-ctx { background: #efece6; border-color: var(--line-2); opacity: .7; }

.lp-lens-next {
  grid-column: 1 / -1; margin: clamp(30px, 3.4vw, 52px) 0 0;
  font-family: var(--display); font-size: clamp(18px, 1.9vw, 24px);
  letter-spacing: -.018em; color: var(--muted-q);
}

@media (max-width: 1039px) {
  .lp-lens-copy { max-width: none; }
  #lp-canvas .lp-h2 { max-width: 22ch; }
}
@media (max-width: 620px) {
  .lp-lens-gram { grid-template-columns: minmax(0, 1fr); gap: 13px; }
  .lp-lens-mq { display: none; }
  .lp-lens-mode { padding: 12px 10px; }
  .lp-lens-foot { padding: 12px 14px; }
}

/* ==========================================================================
   chapter eight: nothing crosses without a verdict
   ==========================================================================
   Four paragraphs explained a decision the card beside them was making
   badly. The card is now the argument: a dashed boundary down the middle,
   the standard on one side, your ontology on the other, and three
   connectors that cross it one at a time - each ending in a different
   verdict. 40 / 60, narrative to engine. */

.lp-imp-wrap { display: grid; gap: clamp(28px, 3.4vw, 60px); align-items: center; }
@media (min-width: 1040px) {
  .lp-imp-wrap { grid-template-columns: 40fr 60fr; }
}
#lp-adopt .lp-h2 { max-width: 17ch; }
#lp-adopt .lp-sub { max-width: 42ch; }
.lp-imp-copy { max-width: 520px; }

/* -- the reasoning rail. Four stages that LIGHT as the engine reaches them,
   so the copy is a consequence of the demonstration and not a caption. */
.lp-imp-rail {
  list-style: none; margin: clamp(26px, 3vw, 40px) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 3px;
}
.lp-imp-step {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 0 12px;
  padding: 11px 0 11px 14px; box-shadow: inset 2px 0 0 var(--line);
  opacity: .38; transition: opacity .55s ease, box-shadow .55s ease;
}
.lp-imp-step.is-on { opacity: 1; box-shadow: inset 2px 0 0 var(--wine); }
.lp-imp-step b {
  grid-row: 1 / 3; font-family: var(--mono); font-size: 10px; color: var(--wine);
  font-weight: 600; letter-spacing: .08em; padding-top: 2px;
}
.lp-imp-step em {
  font-style: normal; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink);
  font-weight: 600;
}
.lp-imp-step span { font-size: 12.5px; line-height: 1.45; color: var(--muted); margin-top: 3px; }

/* -- the engine. */
.lp-imp-frame {
  border: 1px solid var(--line-2); border-radius: 14px; background: var(--paper);
  box-shadow: 0 1px 0 var(--line), 0 20px 44px rgba(23,20,15,.06);
  overflow: hidden;
}
.lp-imp-head {
  display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap;
  padding: 16px clamp(15px, 1.8vw, 22px); border-bottom: 1px solid var(--line);
}
.lp-imp-k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-imp-term {
  font-family: var(--display); font-size: 21px; letter-spacing: -.02em; color: var(--ink);
}
.lp-imp-org { font-family: var(--mono); font-size: 11px; color: var(--muted-q); }
.lp-imp-tag {
  margin-left: auto; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted-q);
  border: 1px solid var(--line); border-radius: 4px; padding: 3px 8px;
}

/* the machine's own progress: source, match, decision. */
.lp-imp-spine {
  display: flex; align-items: center; gap: 10px;
  padding: 11px clamp(15px, 1.8vw, 22px); border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--line-2);
}
.lp-imp-spine i { flex: 1; height: 1px; background: var(--line); }
.lp-imp-spine span { transition: color .5s ease; }
.lp-imp.s0 .lp-imp-spine [data-s="0"],
.lp-imp.s1 .lp-imp-spine [data-s="1"],
.lp-imp.s3 .lp-imp-spine [data-s="2"] { color: var(--wine); }

/* -- the comparison. Column two is the boundary: a dashed rule that runs
   the height of the block, crossed only by a verdict. */
.lp-imp-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(44px, 5.5vw, 74px)
                         minmax(0, 1.35fr) clamp(100px, 11vw, 132px);
}
.lp-imp-h {
  font-family: var(--mono); font-size: 9px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted-q);
  padding: 12px clamp(12px, 1.4vw, 18px) 10px;
}
.lp-imp-h:nth-child(2) { border-left: 1px dashed var(--line-2); padding-left: 0; padding-right: 0; }
.lp-imp-c {
  padding: 15px clamp(12px, 1.4vw, 18px);
  opacity: 0; transition: opacity .55s ease;
}
.lp-imp-c.is-rule { border-top: 1px solid var(--line); }
.lp-imp-link {
  border-left: 1px dashed var(--line-2);
  padding-left: 0; padding-right: 0; position: relative;
  display: flex; align-items: center; opacity: 1;
}
.lp-imp-link.is-rule { border-top: 0; }
.lp-imp-src b, .lp-imp-tgt b {
  display: block; font-family: var(--display); font-size: 19px;
  letter-spacing: -.02em; color: var(--ink); font-weight: 400;
}
.lp-imp-neq {
  display: block; margin-top: 5px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--warn);
}
.lp-imp-tn {
  display: block; margin-top: 6px; font-size: 12px; line-height: 1.45; color: var(--muted);
}

/* the connector. It draws across the boundary, and only then. */
.lp-imp-link i {
  flex: 1; height: 1px; background: var(--wine);
  transform: scaleX(0); transform-origin: left;
}
.lp-imp-link i.is-dashed {
  background: none;
  border-top: 1px dashed var(--wine); height: 0;
}
.lp-imp-link u {
  width: 0; height: 0; border-left: 5px solid var(--wine);
  border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent;
  opacity: 0; transition: opacity .3s ease;
}
.lp-imp.s2 .lp-imp-link i {
  animation: lp-imp-draw .6s cubic-bezier(.22,.61,.36,1) calc(var(--r) * .16s) forwards;
}
.lp-imp.s2 .lp-imp-link u { transition-delay: calc(.5s + var(--r) * .16s); opacity: 1; }
@keyframes lp-imp-draw { to { transform: scaleX(1); } }

/* confidence stops being a number in a parenthesis. */
.lp-imp-conf { display: flex; align-items: center; gap: 9px; margin-top: 8px; }
.lp-imp-dots { display: inline-flex; gap: 3px; }
.lp-imp-dots i {
  width: 6px; height: 6px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.lp-imp-dots i.is-on { background: var(--ink-2); box-shadow: none; }
.lp-imp-score { font-family: var(--mono); font-size: 11px; color: var(--ink-2); }
.lp-imp-none {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted-q);
}

/* three verdicts, and they must not read as one control repeated. */
.lp-imp-v {
  display: inline-block; font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; font-weight: 600;
  padding: 5px 9px; border-radius: 5px;
}
.lp-imp-v.is-match { background: #e6efe9; color: var(--ok); }
.lp-imp-v.is-new { background: #eef1f4; color: #3c4a5a; }
.lp-imp-v.is-unsure { background: #f6efe2; color: var(--warn); }
.lp-imp-vs {
  display: block; margin-top: 7px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted-q);
}

/* the machine looking before it answers. One sweep, never a loop. */
.lp-imp-scan {
  position: absolute; left: 0; right: 0; top: 0; height: 34px; opacity: 0;
  background: linear-gradient(180deg, transparent, rgba(126,34,48,.06), transparent);
  pointer-events: none;
}
.lp-imp.s1 .lp-imp-scan { animation: lp-imp-scan 1.1s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes lp-imp-scan {
  0% { opacity: 0; transform: translateY(0); }
  20% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; transform: translateY(230px); }
}

.lp-imp-note {
  margin: 0; padding: 13px clamp(15px, 1.8vw, 22px);
  border-top: 1px solid var(--line);
  font-size: 12.5px; line-height: 1.5; color: var(--muted);
  opacity: 0; transition: opacity .5s ease;
}

/* -- inspection is not mutation, and that is the point of the section. */
.lp-imp-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px;
  padding: 15px clamp(15px, 1.8vw, 22px);
  border-top: 1px solid var(--line); background: var(--bone);
}
.lp-imp-state { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0 9px; }
.lp-imp-state i {
  grid-row: 1 / 3; align-self: center; width: 9px; height: 9px; border-radius: 50%;
  box-shadow: inset 0 0 0 1.4px var(--muted-q);
}
.lp-imp-state b {
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink); font-weight: 600;
}
.lp-imp-state span { font-family: var(--mono); font-size: 10px; color: var(--muted-q); margin-top: 3px; }
.lp-imp-chain {
  display: flex; align-items: center; gap: 7px; flex: 1 1 210px;
  font-family: var(--mono); font-size: 9px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--line-2);
}
.lp-imp-chain i { flex: 1; height: 1px; background: var(--line); }
.lp-imp-chain .is-on { color: var(--wine); }
.lp-imp-cta {
  margin-left: auto; background: var(--ink); color: var(--bone);
  font-size: 13px; font-weight: 500; padding: 10px 17px; border-radius: 8px;
  opacity: .35; transition: opacity .6s ease;
}

/* -- the reveal order IS the argument: look, compare, decide, then say that
   nothing has happened yet. */
.lp-imp.s2 .lp-imp-src { opacity: 1; transition-delay: calc(var(--r) * .16s); }
.lp-imp.s3 .lp-imp-tgt, .lp-imp.s3 .lp-imp-vd {
  opacity: 1; transition-delay: calc(var(--r) * .28s);
}
.lp-imp.s4 .lp-imp-note { opacity: 1; }
.lp-imp.s4 .lp-imp-state i { box-shadow: inset 0 0 0 1.4px var(--wine); }
.lp-imp.s5 .lp-imp-cta { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .lp-imp-link i, .lp-imp-scan { animation: none; }
  .lp-imp-link i { transform: scaleX(1); }
  .lp-imp-link u { opacity: 1; }
  .lp-imp-scan { display: none; }
}
@media (max-width: 1039px) {
  .lp-imp-copy { max-width: none; }
  #lp-adopt .lp-h2 { max-width: 22ch; }
}
@media (max-width: 700px) {
  .lp-imp-grid { grid-template-columns: minmax(0, 1fr) 30px minmax(0, 1.1fr); }
  /* the verdict stops being a fourth column and becomes the row's own line */
  .lp-imp-h:nth-child(4) { display: none; }
  .lp-imp-vd { grid-column: 1 / -1; padding-top: 0; }
  .lp-imp-vd .lp-imp-vs { display: inline; margin-left: 10px; }
  .lp-imp-src b, .lp-imp-tgt b { font-size: 17px; }
  .lp-imp-cta { margin-left: 0; }
}

/* ==========================================================================
   chapter nine: seven stages, one object
   ==========================================================================
   Seven different operations were rendered as one component seven times: a
   numeral, a title, a bulleted list. That teaches "here are seven things we
   do". Each stage now produces its own ARTIFACT, shaped like the operation
   it performs, and a burgundy thread runs from the active node down into
   the panel and slides along the rail as the step changes - so the panel is
   visibly produced by the node above it, and the reader is watching one
   object move rather than seven cards swap. */

/* -- the identity column now carries the lede: where am I, and what is
   happening here. The body column becomes the visual. */
.lp-stepcard { grid-template-columns: minmax(0, 250px) 1px minmax(0, 1fr); }
.lp-stepcard-lede {
  margin: 14px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--muted);
}
.lp-stepcard-body { max-width: none; display: grid; gap: 18px; }

/* -- the artifact. A fixed floor so the seven shapes sit on one baseline
   and the pane never resizes between steps. */
.lp-af-frame {
  min-height: 132px; display: grid; align-content: center;
  padding: 16px 18px; border-radius: 10px;
  background: var(--bone); border: 1px solid var(--line);
}
.lp-af { display: grid; gap: 10px; justify-items: start; }
.lp-af > * { opacity: 0; }
.lp-flow .lp-stepcard .lp-af > * {
  animation: lp-af-rise .45s cubic-bezier(.22,.61,.36,1)
             calc(.14s + var(--i, 0) * .07s) both;
}
@keyframes lp-af-rise { from { opacity: 0; transform: translateY(5px); }
                        to { opacity: 1; transform: none; } }

/* 01 SOURCE - four formats converging, and the pointer that survives it */
.lp-af-src { justify-items: center; width: 100%; }
.lp-af-tiles { display: flex; gap: 8px; }
.lp-af-tiles span {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); padding: 5px 9px;
  border: 1px solid var(--line-2); border-radius: 4px; background: var(--paper);
}
.lp-af-fan { display: flex; gap: 8px; height: 22px; }
.lp-af-fan i {
  width: 44px; border-right: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-2); border-bottom-right-radius: 6px;
}
.lp-af-fan i:nth-child(3), .lp-af-fan i:nth-child(4) {
  border-right: 0; border-left: 1px solid var(--line-2);
  border-bottom-right-radius: 0; border-bottom-left-radius: 6px;
}
.lp-af-out { display: flex; align-items: baseline; gap: 10px; }
.lp-af-out b {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-af-out span { font-family: var(--mono); font-size: 10px; color: var(--muted-q); }

/* 02 CORRECT - a rename, a datatype, and a column that is refused */
.lp-af-map { width: 100%; gap: 7px; }
.lp-af-m { display: flex; align-items: center; gap: 10px; width: 100%; }
.lp-af-m code {
  font-family: var(--mono); font-size: 11px; color: var(--ink-2);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 4px; padding: 3px 8px;
}
.lp-af-m i { width: 26px; height: 1px; background: var(--line-2); flex: none; }
.lp-af-m em {
  font-style: normal; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted-q);
}
.lp-af-m.is-off code:last-of-type { border-style: dashed; color: var(--muted-q); }

/* 03 ALIGN - a ladder, and minting is the last rung */
.lp-af-tier { width: 100%; gap: 6px; }
.lp-af-t {
  display: grid; grid-template-columns: 18px 140px minmax(0, 1fr) auto;
  align-items: center; gap: 12px; width: 100%; padding: 6px 0;
  border-top: 1px solid var(--line); opacity: .5;
}
.lp-af-t:first-child { border-top: 0; }
.lp-af-t b { font-family: var(--mono); font-size: 10px; color: var(--muted-q); font-weight: 500; }
.lp-af-t span { font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); }
.lp-af-t code { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }
.lp-af-t em {
  font-style: normal; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted-q);
}
.lp-af-t.is-hit { opacity: 1; }
.lp-af-t.is-hit b, .lp-af-t.is-hit em { color: var(--wine); }

/* 04 GAUNTLET - gates, and the fourth one only advises */
.lp-af-gate { display: flex; flex-wrap: wrap; align-items: stretch; gap: 8px; }
.lp-af-g {
  display: grid; gap: 5px; justify-items: center; padding: 9px 12px;
  border: 1px solid var(--line-2); border-radius: 6px; background: var(--paper);
  position: relative;
}
.lp-af-g + .lp-af-g { margin-left: 14px; }
.lp-af-g + .lp-af-g::before {
  content: ""; position: absolute; left: -19px; top: 50%; width: 12px;
  height: 1px; background: var(--line-2);
}
.lp-af-g b {
  font-family: var(--mono); font-size: 10px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-2); font-weight: 600;
}
.lp-af-g u {
  text-decoration: none; font-family: var(--mono); font-size: 9px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ok);
}
.lp-af-g.is-advice u { color: var(--warn); }
.lp-af-g.is-end { border-color: var(--wine); background: var(--wine-tint); }
.lp-af-g.is-end b, .lp-af-g.is-end u { color: var(--wine); }

/* 05 DECIDE - two signatures, and they cannot be one person */
.lp-af-sig { width: 100%; gap: 8px; }
.lp-af-s { display: flex; align-items: center; gap: 14px; }
.lp-af-s b {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); font-weight: 600; min-width: 84px;
}
.lp-af-s svg { width: 84px; height: 18px; overflow: visible; }
.lp-af-s path {
  fill: none; stroke: var(--wine); stroke-width: 1.3; stroke-linecap: round;
  stroke-dasharray: 90; stroke-dashoffset: 90;
}
.lp-flow .lp-stepcard .lp-af-s path {
  animation: lp-af-ink .6s cubic-bezier(.3,.7,.4,1) calc(.4s + var(--i, 0) * .3s) both;
}
@keyframes lp-af-ink { to { stroke-dashoffset: 0; } }
.lp-af-s em {
  font-style: normal; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ok);
}
.lp-af-rule {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted-q); padding-top: 8px;
  border-top: 1px solid var(--line); width: 100%;
}

/* 06 COMMIT - a version transition that cannot be edited afterwards */
.lp-af-ver { grid-auto-flow: column; align-items: center; gap: 14px; }
.lp-af-v { display: grid; gap: 3px; justify-items: center; padding: 8px 14px;
  border-radius: 7px; border: 1px solid var(--line-2); background: var(--paper); }
.lp-af-v b { font-family: var(--mono); font-size: 14px; color: var(--ink); }
.lp-af-v span {
  font-family: var(--mono); font-size: 9px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-af-v.is-old { opacity: .55; }
.lp-af-v.is-new { border-color: var(--wine); background: var(--wine-tint); }
.lp-af-v.is-new b { color: var(--wine-deep); }
.lp-af-vline { display: flex; align-items: center; }
.lp-af-vline i { width: 34px; height: 1px; background: var(--wine); }
.lp-af-vline u {
  width: 0; height: 0; border-left: 5px solid var(--wine);
  border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent;
}
.lp-af-hash {
  grid-row: 2; grid-column: 1 / -1; justify-self: start;
  font-family: var(--mono); font-size: 9.5px; color: var(--muted-q);
}

/* 07 COMPOUND - the payoff. The graph draws, and the whole rail lights. */
.lp-af-graph { justify-items: start; width: 100%; }
.lp-af-graph svg { width: 100%; max-width: 250px; height: auto; }
.lp-af-ge {
  fill: none; stroke: var(--line-2); stroke-width: 1.2;
  stroke-dasharray: 60; stroke-dashoffset: 60; opacity: 1;
}
.lp-flow .lp-stepcard .lp-af-ge {
  animation: lp-af-ink .5s ease calc(.2s + var(--i, 0) * .09s) both;
}
.lp-af-gn { fill: var(--wine-tint); stroke: var(--wine); stroke-width: 1.4; opacity: 0; }
.lp-flow .lp-stepcard .lp-af-gn {
  animation: lp-af-pop .4s cubic-bezier(.22,.61,.36,1) calc(.3s + var(--i, 0) * .09s) both;
}
@keyframes lp-af-pop { from { opacity: 0; } to { opacity: 1; } }
.lp-af-gn.is-hub { fill: var(--wine); }
.lp-af-gn.is-new { fill: var(--paper); stroke-dasharray: 3 3; }
.lp-af-cite {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--wine);
}
/* the whole pipeline resolves at the last step */
.lp-flow[data-step="6"] .lp-step-dot {
  background: var(--wine); border-color: var(--wine); opacity: .55;
}
.lp-flow[data-step="6"] .lp-step[aria-pressed="true"] .lp-step-dot { opacity: 1; }

/* -- the thread. It connects the active node to the panel it produced, and
   slides along the rail rather than being redrawn - the reader is following
   one object, not watching seven cards arrive. */
.lp-pipe-sig, .lp-pipe-land {
  position: absolute; width: 1px; background: var(--wine);
  left: calc((var(--at, 0) * 2 + 1) * 100% / 14);
  transition: left .55s cubic-bezier(.22,.61,.36,1);
}
.lp-pipe-sig { bottom: -22px; height: 22px; }
.lp-pipe-land { top: 0; height: 13px; }
.lp-stepbody { position: relative; min-height: 278px; }

/* -- the facts drop to a supporting register. Every one of them is kept:
   several are the only place a real claim appears on this page. */
.lp-stepcard-facts { gap: 7px; }
.lp-stepcard-facts li { font-size: 12.5px; line-height: 1.5; }

@media (prefers-reduced-motion: reduce) {
  .lp-flow .lp-stepcard .lp-af > *,
  .lp-flow .lp-stepcard .lp-af-s path,
  .lp-flow .lp-stepcard .lp-af-ge,
  .lp-flow .lp-stepcard .lp-af-gn { animation: none; opacity: 1; }
  .lp-af-s path, .lp-af-ge { stroke-dashoffset: 0; }
  .lp-pipe-sig, .lp-pipe-land { transition: none; }
}
@media (max-width: 900px) {
  .lp-stepcard { grid-template-columns: minmax(0, 1fr); }
  .lp-stepcard-lede { margin-top: 10px; }
  .lp-stepbody { min-height: 0; }
  .lp-af-t { grid-template-columns: 16px minmax(0, 1fr); }
  .lp-af-t code, .lp-af-t em { grid-column: 2; }
  .lp-af-gate { gap: 6px; }
  .lp-af-g + .lp-af-g { margin-left: 0; }
  .lp-af-g + .lp-af-g::before { display: none; }
}

/* ==========================================================================
   chapter ten: evidence assembles, then a person decides
   ==========================================================================
   The card had the right facts and the wrong grammar: three figures, a list,
   a note and three buttons, all arriving at once and all weighted the same.
   Nothing in it said that the machine measured, then validated, then argued
   - and then stopped. It is now one evidence map that assembles downward,
   and the rule near the bottom is the argument: everything above it was
   produced by a machine, and the only thing below it is a person. */

.lp-rv-top {
  display: grid; gap: clamp(16px, 2vw, 40px); align-items: end;
  margin-bottom: clamp(30px, 3.6vw, 54px);
}
@media (min-width: 1000px) {
  .lp-rv-top { grid-template-columns: 54fr 46fr; }
  .lp-rv-top .lp-sub { padding-bottom: 6px; }
}
#lp-review .lp-h2 { max-width: 15ch; }
#lp-review .lp-sub { max-width: 44ch; margin: 0; }

.lp-rv { display: grid; gap: clamp(26px, 3vw, 54px); align-items: start; }
@media (min-width: 1000px) {
  .lp-rv { grid-template-columns: 26fr 74fr; }
}

/* -- four statements, and they light as the evidence that earns them
   arrives. Each one is a claim the five paragraphs used to make. */
.lp-rv-rail { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.lp-rv-s {
  display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 0 11px;
  padding: 12px 0 12px 14px; box-shadow: inset 2px 0 0 var(--line);
  opacity: .34; transition: opacity .55s ease, box-shadow .55s ease;
}
.lp-rv-s.is-on { opacity: 1; box-shadow: inset 2px 0 0 var(--wine); }
.lp-rv-s b {
  grid-row: 1 / 3; font-family: var(--mono); font-size: 10px; color: var(--wine);
  font-weight: 600; letter-spacing: .08em; padding-top: 2px;
}
.lp-rv-s em {
  font-style: normal; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink); font-weight: 600;
}
.lp-rv-s span { font-size: 12.5px; line-height: 1.45; color: var(--muted); margin-top: 4px; }

/* -- the map. Hairlines and open space, not a rounded slab. */
.lp-rv-map { display: grid; justify-items: center; }
.lp-rv-prop {
  display: grid; justify-items: center; gap: 7px; text-align: center;
  border: 1px solid var(--line-2); border-radius: 10px;
  background: var(--paper); padding: 16px clamp(18px, 2.4vw, 34px) 15px;
  max-width: 420px;
}
.lp-rv-k, .lp-rv-gk, .lp-rv-dk {
  font-family: var(--mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-rv-t {
  font-family: var(--display); font-size: clamp(22px, 2.4vw, 30px);
  letter-spacing: -.022em; color: var(--ink); line-height: 1.1;
}
.lp-rv-flag {
  font-family: var(--mono); font-size: 9px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
  background: var(--wine-tint); border-radius: 4px; padding: 3px 9px;
}
.lp-rv-route { font-family: var(--mono); font-size: 10px; color: var(--muted-q); }

/* the fan: one stem, a bar, three drops. It draws before the figures land,
   so the consequences read as reached rather than listed. */
.lp-rv-fan { position: relative; width: 100%; max-width: 620px; height: 40px; }
.lp-rv-fan u, .lp-rv-fan i { position: absolute; background: var(--line-2); }
.lp-rv-fan u {
  left: 16.66%; right: 16.66%; top: 20px; height: 1px;
  transform: scaleX(0); transform-origin: center;
}
.lp-rv-fan i { width: 1px; transform: scaleY(0); }
.lp-rv-fan i:nth-of-type(1) { left: 50%; top: 0; height: 20px; transform-origin: top; }
.lp-rv-fan i:nth-of-type(2) { left: 16.66%; top: 20px; height: 20px; transform-origin: top; }
.lp-rv-fan i:nth-of-type(3) { left: 50%; top: 20px; height: 20px; transform-origin: top; }
.lp-rv-fan i:nth-of-type(4) { left: 83.33%; top: 20px; height: 20px; transform-origin: top; }
.lp-rv.s1 .lp-rv-fan i:nth-of-type(1) { animation: lp-rv-y .3s ease forwards; }
.lp-rv.s1 .lp-rv-fan u { animation: lp-rv-x .4s ease .28s forwards; }
.lp-rv.s1 .lp-rv-fan i:nth-of-type(2),
.lp-rv.s1 .lp-rv-fan i:nth-of-type(3),
.lp-rv.s1 .lp-rv-fan i:nth-of-type(4) { animation: lp-rv-y .28s ease .62s forwards; }
@keyframes lp-rv-y { to { transform: scaleY(1); } }
@keyframes lp-rv-x { to { transform: scaleX(1); } }

/* the figures COUNT. A number that fades in has not measured anything. */
.lp-rv-figs {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  width: 100%; max-width: 620px; text-align: center;
}
.lp-rv-f { opacity: 0; transition: opacity .45s ease; }
.lp-rv.s2 .lp-rv-f { opacity: 1; transition-delay: calc(var(--i) * .12s); }
.lp-rv-f b {
  display: block; font-family: var(--mono); font-size: clamp(30px, 3.6vw, 46px);
  font-weight: 500; letter-spacing: -.03em; color: var(--ink);
  font-variant-numeric: tabular-nums; line-height: 1;
}
.lp-rv-f span {
  display: block; margin-top: 8px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted-q);
}

.lp-rv-join { height: 36px; display: grid; place-items: center; width: 100%; }
.lp-rv-join i { width: 1px; height: 100%; background: var(--line-2); transform: scaleY(0); transform-origin: top; }
.lp-rv.s3 .lp-rv-join i { animation: lp-rv-y .32s ease forwards; }

/* -- the gauntlet. Four rows that resolve one at a time. */
.lp-rv-gaunt {
  display: grid; gap: 2px; width: 100%; max-width: 460px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--paper); padding: 14px 18px 15px;
}
.lp-rv-gk { margin-bottom: 6px; }
.lp-rv-g {
  display: grid; grid-template-columns: 8px minmax(0, 1fr) auto;
  align-items: center; gap: 11px; padding: 7px 0;
  border-top: 1px solid var(--line); opacity: 0; transform: translateY(3px);
}
.lp-rv-g:nth-of-type(1) { border-top: 0; }
.lp-rv.s3 .lp-rv-g {
  animation: lp-rv-in .38s cubic-bezier(.22,.61,.36,1) calc(var(--i) * .22s) forwards;
}
@keyframes lp-rv-in { to { opacity: 1; transform: none; } }
.lp-rv-g i { width: 7px; height: 7px; border-radius: 50%; }
.lp-rv-g i.is-pass { background: var(--ok); }
.lp-rv-g i.is-concern { background: #b57a18; }
.lp-rv-g span { font-size: 13px; color: var(--ink-2); }
.lp-rv-g em {
  font-style: normal; font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase;
}
.lp-rv-g em.is-pass { color: var(--ok); }
.lp-rv-g em.is-concern { color: #b57a18; }

/* the sentence that proves it reasons about consequences, not syntax. */
.lp-rv-comp {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  justify-content: center; margin-top: 22px;
  opacity: 0; transition: opacity .5s ease;
}
.lp-rv.s4 .lp-rv-comp { opacity: 1; }
.lp-rv-comp b {
  font-family: var(--mono); font-size: 22px; font-weight: 500;
  letter-spacing: -.02em; color: var(--wine); font-variant-numeric: tabular-nums;
}
.lp-rv-comp span {
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--wine-deep);
}

/* -- the boundary. Everything above it was produced by a machine. */
.lp-rv-hand {
  display: flex; align-items: center; gap: 14px; width: 100%; max-width: 620px;
  margin: clamp(28px, 3.2vw, 44px) 0 clamp(20px, 2.4vw, 30px);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-rv-hand i { flex: 1; height: 1px; background: var(--line-2); transform: scaleX(0); }
.lp-rv.s5 .lp-rv-hand i { animation: lp-rv-x .6s cubic-bezier(.22,.61,.36,1) forwards; }
.lp-rv-hand span:last-child { color: var(--wine); font-weight: 600; }

.lp-rv-dec { display: grid; justify-items: center; gap: 12px; width: 100%; max-width: 460px; }
.lp-rv-btns {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px; width: 100%;
  opacity: .32; transition: opacity .6s ease;
}
.lp-rv.s5 .lp-rv-btns { opacity: 1; }
.lp-rv-btns > span {
  text-align: center; padding: 11px 10px; border-radius: 8px;
  font-size: 13.5px; letter-spacing: -.005em;
}
.lp-rv-accept { background: var(--ink); color: var(--bone); font-weight: 500; }
.lp-rv-modify { border: 1px solid var(--line-2); color: var(--muted); }
.lp-rv-reject { border: 1px solid var(--wine-line); color: var(--wine); }

.lp-rv-foot {
  margin: clamp(30px, 3.4vw, 50px) 0 0; max-width: 62ch;
  font-size: 13px; line-height: 1.6; color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .lp-rv-fan u, .lp-rv-fan i, .lp-rv-join i, .lp-rv-g, .lp-rv-hand i {
    animation: none !important; transform: none; opacity: 1;
  }
}
@media (max-width: 620px) {
  .lp-rv-f b { font-size: 28px; }
  .lp-rv-f span { font-size: 8.5px; letter-spacing: .08em; }
  .lp-rv-btns { grid-template-columns: minmax(0, 1fr); }
  .lp-rv-hand { gap: 9px; letter-spacing: .12em; }
}

/* -- Restored. `.lp-tiers` / `.lp-tier` are ALSO the "Cited" list in
   #lp-ask, which the review section's rebuild removed the rules for. The
   review no longer uses them; #lp-ask still does. */
.lp-tier-dot.pass { background: var(--ok); }
.lp-tier-dot.concern { background: #b57a18; }
.lp-tier-s.pass { color: var(--ok); }
.lp-tier-s.concern { color: #b57a18; }

/* ==========================================================================
   chapter eleven: the field fills with your decisions
   ==========================================================================
   A curve going up is what every SaaS page draws, and it says "number gets
   bigger". The claim here is narrower: the system is not improving, YOUR
   ORGANISATION'S DECISIONS ARE ACCUMULATING. So the field is literal -
   fifteen hollow marks anybody would know, and twenty-one that fill in as
   your reviewers decide. The ratio is the argument. */

.lp-cp { margin-top: clamp(30px, 3.6vw, 52px); --cp-ok: #7fae93; }
#lp-learns .lp-sub { max-width: 40ch; }

/* -- three periods. The dots are the control and the clock at once. */
.lp-cp-rail { display: flex; flex-wrap: wrap; gap: 0 clamp(20px, 3vw, 44px); }
.lp-cp-t {
  display: flex; align-items: center; gap: 9px; background: none; border: 0;
  font: inherit; cursor: pointer; padding: 8px 0 14px;
  position: relative;
}
.lp-cp-t::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--dark-wine); transform: scaleX(0); transform-origin: left;
  transition: transform .5s cubic-bezier(.22,.61,.36,1);
}
.lp-cp-t.is-on::after { transform: scaleX(1); }
.lp-cp-t:focus-visible { outline: 2px solid var(--dark-wine); outline-offset: 3px; }
.lp-cp-td {
  width: 9px; height: 9px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--dark-line);
  transition: background .4s ease, box-shadow .4s ease;
}
.lp-cp-t.is-done .lp-cp-td { background: var(--dark-muted); box-shadow: none; }
.lp-cp-t.is-on .lp-cp-td { background: var(--dark-wine); box-shadow: none; }
.lp-cp-tl {
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--dark-kicker); transition: color .4s ease;
}
.lp-cp-t.is-on .lp-cp-tl { color: var(--dark-ink); }

/* -- the loop: proposal, decisions, conventions, and back again. */
.lp-cp-stage {
  position: relative; display: grid; gap: clamp(16px, 2vw, 30px);
  align-items: start; padding: clamp(22px, 2.6vw, 34px) 0 clamp(46px, 5vw, 68px);
  border-top: 1px solid var(--dark-line);
}
@media (min-width: 1000px) {
  .lp-cp-stage { grid-template-columns: 27fr 26px 34fr 26px 27fr; }
}
.lp-cp-ck {
  font-family: var(--mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--dark-kicker); margin-bottom: 15px;
}
.lp-cp-gap { display: flex; align-items: center; gap: 3px; padding-top: 46px; }
.lp-cp-gap i { flex: 1; height: 1px; background: var(--dark-line); }
.lp-cp-gap u {
  width: 0; height: 0; border-left: 4px solid var(--dark-line);
  border-top: 3px solid transparent; border-bottom: 3px solid transparent;
}

/* the slots stack their states in one cell, so nothing reflows between
   periods and the columns beside them never move. */
.lp-cp-slot { display: grid; }
.lp-cp-slot > * { grid-area: 1 / 1; align-self: start; opacity: 0; transition: opacity .5s ease; }
.lp-cp[data-t="0"] [data-s="0"], .lp-cp[data-t="1"] [data-s="1"],
.lp-cp[data-t="2"] [data-s="2"] { opacity: 1; }

.lp-cp-p {
  border: 1px solid var(--dark-line); border-radius: 10px;
  padding: 15px 17px; display: grid; gap: 10px;
}
.lp-cp-p b {
  font-family: var(--display); font-weight: 400; font-size: clamp(19px, 1.9vw, 24px);
  letter-spacing: -.02em; color: var(--dark-ink); line-height: 1.15;
}
.lp-cp-hint {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; padding-top: 10px; border-top: 1px solid var(--dark-line);
}
.lp-cp-hint.is-none { color: var(--dark-kicker); }
.lp-cp-hint.is-match { color: var(--dark-muted); }
.lp-cp-hint.is-sug { color: var(--cp-ok, #7fae93); }

/* -- the field. Hollow is what any tool knows; filled is what you decided. */
.lp-cp-field { position: relative; display: inline-block; }
.lp-cp-grid {
  display: grid; grid-template-columns: repeat(9, 10px); gap: 13px;
}
.lp-cp-d {
  width: 10px; height: 10px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--dark-line);
  transition: background .5s ease, box-shadow .5s ease, opacity .5s ease;
}
.lp-cp-d[data-at] { opacity: .34; }
.lp-cp[data-t="0"] .lp-cp-d[data-at="0"],
.lp-cp[data-t="1"] .lp-cp-d[data-at="0"], .lp-cp[data-t="1"] .lp-cp-d[data-at="1"],
.lp-cp[data-t="2"] .lp-cp-d[data-at] { opacity: 1; }
.lp-cp[data-t="0"] .lp-cp-d[data-at="0"].is-acc,
.lp-cp[data-t="1"] .lp-cp-d[data-at="0"].is-acc, .lp-cp[data-t="1"] .lp-cp-d[data-at="1"].is-acc,
.lp-cp[data-t="2"] .lp-cp-d[data-at].is-acc,
.lp-cp-d.is-lit.is-acc { background: var(--cp-ok, #7fae93); box-shadow: none; }
.lp-cp[data-t="0"] .lp-cp-d[data-at="0"].is-rej,
.lp-cp[data-t="1"] .lp-cp-d[data-at="0"].is-rej, .lp-cp[data-t="1"] .lp-cp-d[data-at="1"].is-rej,
.lp-cp[data-t="2"] .lp-cp-d[data-at].is-rej,
.lp-cp-d.is-lit.is-rej { background: var(--dark-wine); box-shadow: none; }
.lp-cp[data-t="0"] .lp-cp-d[data-at="0"].is-mod,
.lp-cp[data-t="1"] .lp-cp-d[data-at="0"].is-mod, .lp-cp[data-t="1"] .lp-cp-d[data-at="1"].is-mod,
.lp-cp[data-t="2"] .lp-cp-d[data-at].is-mod,
.lp-cp-d.is-lit.is-mod { background: var(--dark-ink); box-shadow: none; opacity: .8; }

/* the hull: a loose boundary round the marks that started agreeing. */
.lp-cp-hull {
  position: absolute; left: 10px; top: 15px; width: 132px; height: 78px;
  border: 1px dashed var(--dark-wine); border-radius: 12px;
  opacity: 0; transform: scale(.94); transform-origin: center;
  transition: opacity .6s ease, transform .6s cubic-bezier(.22,.61,.36,1);
  pointer-events: none;
}
.lp-cp[data-t="1"] .lp-cp-hull, .lp-cp[data-t="2"] .lp-cp-hull { opacity: 1; transform: none; }
.lp-cp[data-t="2"] .lp-cp-hull { border-style: solid; }
.lp-cp-hull span {
  position: absolute; left: 0; top: -19px; white-space: nowrap;
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--dark-wine);
}
.lp-cp[data-t="2"] .lp-cp-hull span::after { content: " \00b7 held"; }

.lp-cp-cap {
  margin-top: 20px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--dark-kicker);
}
.lp-cp-cap em { font-style: normal; color: var(--dark-ink); }
.lp-cp-rs { margin-top: 12px; min-height: 44px; }
.lp-cp-r { font-size: 13px; line-height: 1.5; color: var(--dark-muted); }
.lp-cp-r em {
  display: block; font-style: normal; font-family: var(--mono); font-size: 9px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dark-wine);
  margin-bottom: 5px;
}

/* -- the conventions, which are the thing that actually compounds. */
.lp-cp-num { display: flex; align-items: baseline; gap: 10px; }
.lp-cp-num b {
  font-family: var(--mono); font-size: clamp(34px, 4vw, 52px); font-weight: 500;
  letter-spacing: -.03em; color: var(--dark-ink); font-variant-numeric: tabular-nums;
  line-height: 1;
}
.lp-cp-num span {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--dark-kicker);
}
.lp-cp-list { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 2px; }
.lp-cp-list li {
  font-family: var(--mono); font-size: 11px; color: var(--dark-ink);
  padding: 6px 0; border-top: 1px solid var(--dark-line);
  opacity: 0; transform: translateY(3px);
  transition: opacity .5s ease, transform .5s ease;
}
.lp-cp[data-t="0"] .lp-cp-list li[data-from="0"],
.lp-cp[data-t="1"] .lp-cp-list li[data-from="0"], .lp-cp[data-t="1"] .lp-cp-list li[data-from="1"],
.lp-cp[data-t="2"] .lp-cp-list li { opacity: 1; transform: none; }

/* -- the return line. Without it the three columns are a pipeline; with it
   they are the reason the section is called compounds. */
.lp-cp-loop {
  position: absolute; left: 0; right: 0; bottom: clamp(18px, 2vw, 26px);
  display: flex; align-items: center; gap: 12px;
}
.lp-cp-loop i {
  width: 0; height: 0; border-right: 5px solid var(--dark-wine);
  border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent;
}
.lp-cp-loop u { flex: 1; height: 1px; background: var(--dark-line); }
.lp-cp-loop span {
  font-family: var(--mono); font-size: 9px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dark-wine); white-space: nowrap;
}

/* -- the distinction the section lives on, named. */
.lp-cp-key {
  display: flex; flex-wrap: wrap; gap: 8px 22px; padding-top: 16px;
  border-top: 1px solid var(--dark-line);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .08em;
  color: var(--dark-kicker);
}
.lp-cp-key span { display: inline-flex; align-items: center; gap: 8px; }

.lp-cp-notes { display: grid; gap: 4px; margin-top: clamp(26px, 3vw, 40px); }
@media (min-width: 780px) { .lp-cp-notes { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; } }
.lp-cp-note {
  padding: 13px 0 13px 16px; box-shadow: inset 2px 0 0 var(--dark-line);
  opacity: .32; transition: opacity .55s ease, box-shadow .55s ease;
}
.lp-cp[data-t="0"] .lp-cp-note[data-s="0"],
.lp-cp[data-t="1"] .lp-cp-note[data-s="1"],
.lp-cp[data-t="2"] .lp-cp-note[data-s="2"] { opacity: 1; box-shadow: inset 2px 0 0 var(--dark-wine); }
.lp-cp-note b {
  display: block; font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dark-wine); font-weight: 600; margin-bottom: 6px;
}
.lp-cp-note span { font-size: 13px; line-height: 1.5; color: var(--dark-muted); }

/* month 6 earns its own sentence. */
.lp-cp-said {
  margin: clamp(24px, 2.8vw, 36px) 0 0; max-width: 46ch;
  font-family: var(--display); font-size: clamp(17px, 1.8vw, 22px);
  letter-spacing: -.018em; line-height: 1.3; color: var(--dark-ink);
  opacity: 0; transition: opacity .7s ease;
}
.lp-cp[data-t="2"] .lp-cp-said { opacity: 1; }

.lp-cp-end { margin-top: clamp(38px, 4.4vw, 62px); }
.lp-cp-big {
  margin: 0; max-width: 22ch; font-family: var(--display);
  font-size: clamp(24px, 3vw, 42px); line-height: 1.14; letter-spacing: -.024em;
  color: var(--dark-ink);
}
.lp-cp-small {
  margin: 17px 0 0; max-width: 56ch; font-size: 13.5px; line-height: 1.6;
  color: var(--dark-muted);
}

@media (max-width: 999px) {
  .lp-cp-gap { display: none; }
  .lp-cp-loop { position: static; margin-top: 26px; }
  .lp-cp-stage { padding-bottom: 0; }
}
@media (max-width: 620px) {
  .lp-cp-grid { grid-template-columns: repeat(9, 8px); gap: 10px; }
  .lp-cp-d { width: 8px; height: 8px; }
  .lp-cp-hull { left: 8px; top: 12px; width: 104px; height: 62px; }
  .lp-cp-loop span { white-space: normal; letter-spacing: .1em; }
}

/* ==========================================================================
   chapter twelve: four stations on one line
   ==========================================================================
   Fifteen capabilities in four equal columns read as a matrix, and left the
   reader to work out what the columns were for. The grouping was always the
   best thing here - read, see, keep honest, hand on - and it is a SEQUENCE:
   the arc the rest of the page has just walked. */

.lp-cs { margin-top: clamp(30px, 3.6vw, 52px); }
#lp-capabilities .lp-h2 { max-width: 17ch; }
#lp-capabilities .lp-sub { max-width: 44ch; }

/* Unequal on purpose. Govern holds five capabilities and Release holds two;
   four equal columns is exactly what made this read as a spreadsheet. */
.lp-cs-stages { position: relative; display: grid; gap: clamp(24px, 3vw, 46px); }
@media (min-width: 1000px) {
  .lp-cs-stages { grid-template-columns: 1fr 1.05fr 1.2fr .8fr; }
  /* the line. It runs past the last station rather than stopping at it -
     a release is the point at which this leaves the building. */
  .lp-cs-stages::before {
    content: ""; position: absolute; left: 0; right: 0; top: 5px; height: 1px;
    background: linear-gradient(90deg, var(--line-2) 0 76%, transparent);
    transform: scaleX(0); transform-origin: left;
  }
  .lp-cs.in .lp-cs-stages::before {
    animation: lp-cs-draw 1.1s cubic-bezier(.22,.61,.36,1) .1s forwards;
  }
}
@keyframes lp-cs-draw { to { transform: scaleX(1); } }

.lp-cs-stage { position: relative; }
.lp-cs-dot {
  display: block; width: 11px; height: 11px; border-radius: 50%;
  background: var(--bone); box-shadow: inset 0 0 0 1.5px var(--line-2);
  position: relative; z-index: 1; opacity: 0;
}
.lp-cs-stage:first-child .lp-cs-dot { box-shadow: inset 0 0 0 1.5px var(--wine); }
.lp-cs-stage:last-child .lp-cs-dot { background: var(--wine); box-shadow: none; }
.lp-cs.in .lp-cs-dot {
  animation: lp-cs-in .45s cubic-bezier(.22,.61,.36,1) calc(.5s + var(--i) * .13s) forwards;
}
@keyframes lp-cs-in { from { opacity: 0; transform: translateY(4px); }
                      to { opacity: 1; transform: none; } }

.lp-cs-top { display: flex; align-items: baseline; gap: 9px; margin-top: 17px; }
.lp-cs-top b {
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  color: var(--wine); font-weight: 600;
}
.lp-cs-top span {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-q);
}
.lp-cs-h {
  margin: 9px 0 0; font-family: var(--display); font-weight: 400;
  font-size: clamp(20px, 2vw, 25px); letter-spacing: -.02em;
  line-height: 1.12; color: var(--ink); max-width: 11ch;
}
.lp-cs-list { margin-top: clamp(16px, 1.8vw, 24px); }
.lp-cs-top, .lp-cs-h, .lp-cs-list { opacity: 0; }
.lp-cs.in .lp-cs-top { animation: lp-cs-in .5s ease calc(.6s + var(--i) * .13s) forwards; }
.lp-cs.in .lp-cs-h { animation: lp-cs-in .5s ease calc(.68s + var(--i) * .13s) forwards; }
.lp-cs.in .lp-cs-list { animation: lp-cs-in .55s ease calc(.8s + var(--i) * .13s) forwards; }

/* -- a capability. Three tiers: the name is always there, the gist arrives
   on hover, the paragraph opens on click. */
.lp-cs-c { border-top: 1px solid var(--line); transition: opacity .22s ease; }
.lp-cs-c summary {
  position: relative; list-style: none; cursor: pointer;
  padding: 11px 22px 12px 15px;
}
.lp-cs-c summary::-webkit-details-marker { display: none; }
.lp-cs-c summary:focus-visible { outline: 2px solid var(--wine); outline-offset: -2px; }
.lp-cs-mk {
  position: absolute; left: 0; top: 17px; width: 7px; height: 1px;
  background: var(--wine); transform: scaleX(0); transform-origin: left;
  transition: transform .2s ease;
}
.lp-cs-c summary:hover .lp-cs-mk, .lp-cs-c[open] .lp-cs-mk { transform: scaleX(1); }
.lp-cs-n {
  display: block; font-size: 14.5px; font-weight: 500; letter-spacing: -.012em;
  color: var(--ink); transition: color .2s ease;
}
.lp-cs-c summary:hover .lp-cs-n, .lp-cs-c[open] .lp-cs-n { color: var(--wine); }
/* the gist keeps its space at all times, so hovering never reflows a column */
.lp-cs-g {
  display: block; min-height: 17px; margin-top: 3px;
  font-size: 12px; line-height: 1.4; color: var(--muted);
}
@media (hover: hover) {
  .lp-cs-g { opacity: 0; transform: translateY(-2px); transition: opacity .22s ease, transform .22s ease; }
  .lp-cs-c summary:hover .lp-cs-g { opacity: 1; transform: none; }
  /* inspecting one row quietens the others - the section behaves like an
     instrument rather than a list */
  .lp-cs-list:hover .lp-cs-c:not(:hover):not([open]) { opacity: .45; }
}
.lp-cs-c[open] .lp-cs-g { opacity: 0; min-height: 0; margin: 0; height: 0; overflow: hidden; }
.lp-cs-c summary::after {
  content: "+"; position: absolute; right: 2px; top: 10px;
  font-family: var(--mono); font-size: 13px; color: var(--line-2);
  transition: color .2s ease;
}
.lp-cs-c[open] summary::after { content: "\2013"; color: var(--wine); }
.lp-cs-c summary:hover::after { color: var(--wine); }
.lp-cs-b {
  margin: 0; padding: 0 22px 15px 15px;
  font-size: 12.5px; line-height: 1.62; color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .lp-cs-stages::before, .lp-cs-dot, .lp-cs-top, .lp-cs-h, .lp-cs-list {
    animation: none !important; opacity: 1; transform: none;
  }
  .lp-cs-g { opacity: 1; transform: none; }
}
/* Below the four-across, the line turns vertical: each station keeps its
   place in the sequence instead of becoming a free-floating card. */
@media (max-width: 999px) {
  .lp-cs-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lp-cs-stage { padding-left: 20px; box-shadow: inset 1px 0 0 var(--line); }
  .lp-cs-dot { position: absolute; left: -5px; top: 0; opacity: 1; animation: none; }
  .lp-cs-top { margin-top: 0; }
  .lp-cs-h { max-width: none; }
}
@media (max-width: 640px) {
  .lp-cs-stages { grid-template-columns: minmax(0, 1fr); }
  .lp-cs-g { opacity: 1; transform: none; }
}

/* ==========================================================================
   chapter thirteen: the answer assembles out of the record
   ==========================================================================
   The card put the claim first and its citations underneath, which is the
   exact order this section argues against. Inverted: the record is
   searched, the evidence lights row by row, a lineage bracket draws down
   its left, and the claim resolves at the foot of that bracket. */

.lp-q-wrap { display: grid; gap: clamp(28px, 3.4vw, 58px); align-items: start; }
@media (min-width: 1000px) {
  .lp-q-wrap { grid-template-columns: 40fr 60fr; }
}
#lp-ask .lp-h2 { max-width: 14ch; }
#lp-ask .lp-sub { max-width: 40ch; }

/* -- three principles. ~250 words of bullets become about 30, and the
   paragraphs are kept intact behind them. */
.lp-q-prin { margin-top: clamp(26px, 3vw, 42px); border-top: 1px solid var(--line); }
.lp-q-p { border-bottom: 1px solid var(--line); }
.lp-q-p summary {
  list-style: none; cursor: pointer; padding: 13px 22px 13px 0; position: relative;
}
.lp-q-p summary::-webkit-details-marker { display: none; }
.lp-q-p summary:focus-visible { outline: 2px solid var(--wine); outline-offset: -2px; }
.lp-q-p summary::after {
  content: "+"; position: absolute; right: 2px; top: 12px;
  font-family: var(--mono); font-size: 13px; color: var(--line-2);
  transition: color .2s ease;
}
.lp-q-p[open] summary::after { content: "\2013"; color: var(--wine); }
.lp-q-p summary:hover::after { color: var(--wine); }
.lp-q-p b {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
  display: block; margin-bottom: 5px;
}
.lp-q-p summary span { font-size: 14px; color: var(--ink); letter-spacing: -.01em; }
.lp-q-p p { margin: 0; padding: 0 22px 15px 0; font-size: 12.5px; line-height: 1.6; color: var(--muted); }

/* -- the surface. Not a chat window: two questions a governed system can
   be asked, and no text input anywhere. */
.lp-q-frame {
  border: 1px solid var(--line-2); border-radius: 14px; background: var(--paper);
  box-shadow: 0 1px 0 var(--line), 0 20px 44px rgba(23,20,15,.06);
  overflow: hidden;
}
.lp-q-head { padding: 15px clamp(15px, 1.8vw, 22px) 8px; border-bottom: 1px solid var(--line); }
.lp-q-k {
  font-family: var(--mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-q); margin-bottom: 11px;
}
.lp-q-ask {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  font: inherit; cursor: pointer; padding: 9px 0 10px 15px;
  box-shadow: inset 2px 0 0 var(--line);
  transition: box-shadow .3s ease, opacity .3s ease; opacity: .45;
}
.lp-q-ask:focus-visible { outline: 2px solid var(--wine); outline-offset: 2px; }
.lp-q-ask.is-on { opacity: 1; box-shadow: inset 2px 0 0 var(--wine); }
.lp-q-qt {
  display: block; font-family: var(--display); font-size: clamp(17px, 1.7vw, 21px);
  letter-spacing: -.02em; color: var(--ink); line-height: 1.2;
}
.lp-q-qm {
  display: block; margin-top: 4px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .1em; color: var(--muted-q);
}

.lp-q-body { padding: 16px clamp(15px, 1.8vw, 22px) clamp(18px, 2vw, 24px); }
.lp-q-look {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted-q);
  opacity: 0; transition: opacity .35s ease;
}
.lp-q.s1 .lp-q-look { opacity: 1; }
.lp-q.s4 .lp-q-look { opacity: .35; }

/* the two states share a cell, so switching question never resizes the
   panel and the page never jumps under the reader. */
.lp-q-slot { display: grid; margin-top: 14px; }
.lp-q-slot > * { grid-area: 1 / 1; align-self: start; opacity: 0; transition: opacity .4s ease; }
.lp-q[data-q="0"] [data-for="0"], .lp-q[data-q="1"] [data-for="1"] { opacity: 1; }

/* -- the lineage. The evidence hangs off one spine, and the spine
   continues down into the claim: the answer sits at the foot of the
   record it was built from. */
.lp-q-ev { position: relative; padding-left: 20px; }
.lp-q-spine {
  position: absolute; left: 0; top: 9px; bottom: 9px; width: 1px;
  background: var(--wine-line); transform: scaleY(0); transform-origin: top;
}
.lp-q.s3 .lp-q-spine { animation: lp-q-y .5s cubic-bezier(.22,.61,.36,1) forwards; }
@keyframes lp-q-y { to { transform: scaleY(1); } }
.lp-q-e {
  position: relative; display: flex; align-items: baseline; gap: 12px;
  padding: 8px 0; opacity: 0; transform: translateX(-4px);
  transition: opacity .2s ease, background .2s ease;
}
.lp-q.s2 .lp-q-e {
  animation: lp-q-in .4s cubic-bezier(.22,.61,.36,1) calc(var(--i) * .17s) forwards;
}
@keyframes lp-q-in { to { opacity: 1; transform: none; } }
.lp-q-e::before {
  content: ""; position: absolute; left: -20px; top: 15px; width: 13px; height: 1px;
  background: var(--wine-line);
}
.lp-q-ed {
  width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--ok);
  transform: translateY(-1px);
}
.lp-q-e.is-off .lp-q-ed { background: none; box-shadow: inset 0 0 0 1px var(--line-2); }
.lp-q-el { flex: 1; font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }
.lp-q-e em {
  font-style: normal; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ok);
}
.lp-q-e.is-off em { color: var(--muted-q); }
.lp-q-e:hover { background: var(--wine-tint); border-radius: 5px; }

.lp-q-drop { display: flex; flex-direction: column; align-items: flex-start; padding-left: 0; }
.lp-q-drop i { width: 1px; height: 20px; background: var(--wine-line); transform: scaleY(0); transform-origin: top; }
.lp-q-drop u {
  width: 0; height: 0; margin-left: -3.5px;
  border-top: 5px solid var(--wine-line);
  border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
  opacity: 0; transition: opacity .3s ease;
}
.lp-q.s3 .lp-q-drop i { animation: lp-q-y .35s ease .35s forwards; }
.lp-q.s3 .lp-q-drop u { opacity: 1; transition-delay: .65s; }

/* -- the claim. It arrives last, which is the argument. */
.lp-q-out { margin-top: 4px; }
.lp-q-badge {
  display: inline-block; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; font-weight: 600;
  padding: 4px 9px; border-radius: 4px;
}
.lp-q-badge.is-yes { background: #e6efe9; color: var(--ok); }
/* NOT ANSWERED is a governed state, not an error. Same weight, never red. */
.lp-q-badge.is-no { background: var(--alt); color: var(--ink); }
.lp-q-claim {
  margin: 13px 0 0; font-family: var(--display);
  font-size: clamp(19px, 2vw, 25px); line-height: 1.3; letter-spacing: -.02em;
  color: var(--ink); max-width: 34ch;
}
.lp-q-r {
  font-weight: 400; border-radius: 3px; padding: 0 2px; margin: 0 -2px;
  transition: background .2s ease, color .2s ease;
}
.lp-q[data-hi="alice"] .lp-q-r[data-r="alice"],
.lp-q[data-hi="owner"] .lp-q-r[data-r="owner"],
.lp-q[data-hi="prop"] .lp-q-r[data-r="prop"] {
  background: var(--wine-tint); color: var(--wine-deep);
}
.lp-q-why {
  margin: 16px 0 0; padding-left: 14px; border-left: 1px solid var(--wine-line);
  font-size: 13px; line-height: 1.6; color: var(--muted); font-style: italic;
  opacity: 0; transition: opacity .5s ease;
}
.lp-q.s5 .lp-q-why { opacity: 1; }
.lp-q-valid {
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted-q);
  opacity: 0; transition: opacity .5s ease;
}
.lp-q.s5 .lp-q-valid { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .lp-q-spine, .lp-q-e, .lp-q-drop i { animation: none !important; transform: none; opacity: 1; }
  .lp-q-drop u, .lp-q-why, .lp-q-valid, .lp-q-look { opacity: 1; }
}
@media (max-width: 620px) {
  .lp-q-claim { font-size: 18px; }
  .lp-q-e { flex-wrap: wrap; gap: 4px 10px; }
  .lp-q-el { flex: 1 1 100%; order: 2; }
}

/* ==========================================================================
   chapter fourteen: one root, five branches
   ==========================================================================
   Five equal cards in a row say "we support five export formats". The claim
   is the opposite of a feature list: the term is governed once and every
   surface is that decision recompiled - which cards cannot say, because
   nothing among them is the parent. So the source is the root and the
   surfaces hang off it. */

.lp-sh { margin-top: clamp(28px, 3.2vw, 46px); }
#lp-ship .lp-sub { max-width: 46ch; }
.lp-sh-tree { display: grid; gap: clamp(18px, 2vw, 26px); align-items: center; }
@media (min-width: 940px) {
  .lp-sh-tree { grid-template-columns: minmax(0, 34fr) 46px minmax(0, 62fr); gap: 0; }
}

/* -- the root. It is not another export panel: it has the definition, the
   signatures and the version, and it is the only wine-bordered thing here. */
.lp-sh-root {
  border: 1px solid var(--wine-line); border-radius: 12px;
  background: var(--paper); padding: clamp(18px, 2vw, 26px);
  position: relative;
}
.lp-sh-k {
  display: block; font-family: var(--mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--wine); font-weight: 600;
}
.lp-sh-name {
  display: block; margin: 12px 0 10px; font-family: var(--mono);
  font-size: clamp(22px, 2.3vw, 29px); font-weight: 500; letter-spacing: -.02em;
  color: var(--wine-deep);
}
.lp-sh-def { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-2); max-width: 30ch; }
.lp-sh-meta {
  display: flex; flex-wrap: wrap; gap: 5px 16px; margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 10.5px; color: var(--muted-q);
}
.lp-sh-sig { color: var(--ok); }
.lp-sh-sig::before { content: "\2713  "; }
/* what the root reports while a branch is being inspected */
.lp-sh-gen {
  margin-top: 12px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--wine);
  opacity: 0; transition: opacity .25s ease;
}
.lp-sh-tree:has(.lp-sh-o:hover) .lp-sh-gen { opacity: 1; }

/* -- the stem, from the root to the spine. */
.lp-sh-stem { display: flex; align-items: center; }
.lp-sh-stem i {
  width: 24px; height: 1px; background: var(--wine-line);
  transform: scaleX(0); transform-origin: left;
}
.lp-sh.in .lp-sh-stem i { animation: lp-sh-x .45s cubic-bezier(.22,.61,.36,1) .55s forwards; }
@keyframes lp-sh-x { to { transform: scaleX(1); } }

/* -- the branches. Each surface owns the segment of spine beside it, so the
   bracket is exact at any row height without a single measured offset: the
   first row's segment starts at its own midpoint, the last one's ends at
   its own. */
.lp-sh-outs { position: relative; }
.lp-sh-o { position: relative; border-top: 1px solid var(--line); }
.lp-sh-o:first-of-type { border-top: 0; }
.lp-sh-o::after {
  content: ""; position: absolute; left: -22px; top: 0; bottom: 0; width: 1px;
  background: var(--wine-line); transform: scaleY(0); transform-origin: top;
}
.lp-sh-o:first-of-type::after { top: 50%; }
.lp-sh-o:last-of-type::after { bottom: 50%; }
.lp-sh-o::before {
  content: ""; position: absolute; left: -22px; top: 50%; width: 22px; height: 1px;
  background: var(--wine-line); transform: scaleX(0); transform-origin: left;
}
.lp-sh.in .lp-sh-o::after {
  animation: lp-sh-y .3s ease calc(.95s + var(--i) * .16s) forwards;
}
.lp-sh.in .lp-sh-o::before {
  animation: lp-sh-x .3s ease calc(1.05s + var(--i) * .16s) forwards;
}
@keyframes lp-sh-y { to { transform: scaleY(1); } }
@media (max-width: 939px) {
  .lp-sh-o::after, .lp-sh-o::before { display: none; }
  .lp-sh-stem { justify-content: center; }
  .lp-sh-stem i { width: 1px; height: 26px; transform: scaleY(0); transform-origin: top; }
  .lp-sh.in .lp-sh-stem i { animation: lp-sh-y .45s ease .55s forwards; }
  .lp-sh-outs { box-shadow: inset 1px 0 0 var(--wine-line); padding-left: 18px; }
}

.lp-sh-o summary {
  list-style: none; cursor: pointer; display: grid; gap: 4px 18px;
  padding: 13px 22px 13px 14px; position: relative;
  opacity: 0;
}
@media (min-width: 700px) {
  .lp-sh-o summary { grid-template-columns: minmax(0, 150px) minmax(0, 1fr); align-items: center; }
}
.lp-sh.in .lp-sh-o summary {
  animation: lp-sh-in .45s cubic-bezier(.22,.61,.36,1) calc(1.15s + var(--i) * .16s) forwards;
}
@keyframes lp-sh-in { from { opacity: 0; transform: translateX(-4px); }
                      to { opacity: 1; transform: none; } }
.lp-sh-o summary::-webkit-details-marker { display: none; }
.lp-sh-o summary:focus-visible { outline: 2px solid var(--wine); outline-offset: -2px; }
.lp-sh-o summary::after {
  content: "+"; position: absolute; right: 4px; top: 13px;
  font-family: var(--mono); font-size: 13px; color: var(--line-2); transition: color .2s ease;
}
.lp-sh-o[open] summary::after { content: "\2013"; color: var(--wine); }
.lp-sh-ot { font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; color: var(--ink); }
.lp-sh-ox { font-family: var(--mono); font-size: 10px; color: var(--wine); margin-left: 9px; }
.lp-sh-code {
  margin: 0; font-family: var(--mono); font-size: 11px; line-height: 1.55;
  color: var(--ink-2); white-space: pre; overflow-x: auto;
}
.lp-sh-code .k { color: var(--wine); }
.lp-sh-code .s { color: var(--ok); }

/* the same word, five times. It lights in turn once the branches are drawn,
   then settles - the recurrence IS the argument. */
.lp-sh-t {
  font-weight: inherit; border-radius: 3px; padding: 0 2px; margin: 0 -2px;
  background: var(--wine-tint); transition: background .3s ease, color .3s ease;
}
.lp-sh.in .lp-sh-root .lp-sh-t { animation: lp-sh-say 1s ease 2.2s 1; }
.lp-sh.in .lp-sh-o .lp-sh-t {
  animation: lp-sh-say 1s ease calc(2.34s + var(--i) * .14s) 1;
}
@keyframes lp-sh-say {
  0%, 100% { background: var(--wine-tint); color: inherit; }
  35%, 55% { background: var(--wine); color: var(--bone); }
}

.lp-sh-ob { padding: 0 22px 15px 14px; }
.lp-sh-ob p { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.lp-sh-from {
  display: block; margin-top: 9px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--wine);
}

/* -- hover shows LINEAGE. Click shows detail. Two questions, two answers. */
@media (hover: hover) {
  .lp-sh-outs:hover .lp-sh-o:not(:hover):not([open]) { opacity: .4; }
  .lp-sh-o { transition: opacity .22s ease; }
  .lp-sh-o:hover::before, .lp-sh-o:hover::after { background: var(--wine); }
  .lp-sh-o:hover .lp-sh-ot { color: var(--wine); }
}

.lp-sh-end { margin-top: clamp(34px, 4vw, 56px); }
.lp-sh-big {
  margin: 0; font-family: var(--display); font-size: clamp(22px, 2.7vw, 36px);
  line-height: 1.16; letter-spacing: -.024em; color: var(--ink); max-width: 20ch;
}
.lp-sh-small { margin: 14px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--muted); max-width: 52ch; }

@media (prefers-reduced-motion: reduce) {
  .lp-sh-stem i, .lp-sh-o::after, .lp-sh-o::before, .lp-sh-o summary, .lp-sh-t {
    animation: none !important; transform: none; opacity: 1;
  }
}
@media (max-width: 699px) {
  .lp-sh-code { font-size: 10px; }
  .lp-sh-o summary { padding: 11px 22px 12px 12px; }
}

/* ==========================================================================
   chapter fifteen: problem, mechanism, outcome
   ==========================================================================
   Twelve quotes each followed by its full paragraph is nine hundred words
   arriving at once, all at the same weight. The structure underneath is
   sharper: a thing teams say, the machinery that answers it, one word. So
   the row is three zones and one line, and the paragraph opens on click.
   Twelve rows of one line scan faster than eight rows of prose. */

.lp-dg { margin-top: clamp(28px, 3.2vw, 44px); border-top: 1px solid var(--line-2); }
#lp-ledger .lp-sub { max-width: 62ch; }

.lp-dg-h {
  display: none; padding: 10px 0 11px; border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-q);
}
@media (min-width: 900px) {
  .lp-dg-h { display: grid; grid-template-columns: minmax(0, 1fr) 200px 104px; gap: 0 26px; }
}

/* -- a row. Thin rules and typography, never a card. */
.lp-dg-r { border-bottom: 1px solid var(--line); transition: opacity .2s ease; }
.lp-dg-r summary {
  list-style: none; cursor: pointer; display: grid; gap: 6px 26px;
  padding: 15px 0 16px; position: relative;
}
.lp-dg-r summary::-webkit-details-marker { display: none; }
.lp-dg-r summary:focus-visible { outline: 2px solid var(--wine); outline-offset: -2px; }
@media (min-width: 900px) {
  .lp-dg-r summary {
    grid-template-columns: minmax(0, 1fr) 200px 104px;
    grid-template-areas: "q m o" "g m o";
    align-items: start;
  }
  .lp-dg-q { grid-area: q; }
  .lp-dg-g { grid-area: g; }
  .lp-dg-m { grid-area: m; align-self: center; }
  .lp-dg-o { grid-area: o; align-self: center; }
}

/* the quote dominates - it is the thing a reader recognises */
.lp-dg-q {
  font-size: clamp(15px, 1.5vw, 17px); line-height: 1.4; letter-spacing: -.012em;
  color: var(--ink); max-width: 46ch;
}
.lp-dg-g { font-size: 12.5px; line-height: 1.5; color: var(--muted); max-width: 52ch; }
/* the mechanism is the answer, set quietly in the machine's own typeface */
.lp-dg-m {
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted-q); transition: color .2s ease;
}
/* the lede says prevented and recoverable are not the same promise; twelve
   identical green pills said they were. Only that distinction is drawn. */
.lp-dg-o {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; font-weight: 600;
  padding-left: 13px; position: relative; white-space: nowrap;
}
.lp-dg-o::before {
  content: ""; position: absolute; left: 0; top: 50%; width: 7px; height: 1px;
}
.lp-dg-o.is-hard { color: var(--wine); }
.lp-dg-o.is-hard::before { background: var(--wine); }
/* matched to #lp-ledger-trust: wine is `it cannot happen`, green is
   `it holds, or it comes back`. One rule across both ledgers. */
.lp-dg-o.is-soft { color: var(--ok); }
.lp-dg-o.is-soft::before { background: var(--ok); }

.lp-dg-r summary::after {
  content: "+"; position: absolute; right: 0; top: 15px;
  font-family: var(--mono); font-size: 13px; color: var(--line-2);
  transition: color .2s ease;
}
.lp-dg-r[open] summary::after { content: "\2013"; color: var(--wine); }
@media (min-width: 900px) {
  .lp-dg-r summary { padding-right: 22px; }
  .lp-dg-h { padding-right: 22px; }
}

.lp-dg-b {
  margin: 0; padding: 0 22px 18px 0; max-width: 78ch;
  font-size: 13px; line-height: 1.65; color: var(--muted);
}

/* -- hover raises one row and quietens the rest: a field guide being read
   down, not twelve controls waiting to be pressed. */
@media (hover: hover) {
  .lp-dg:hover .lp-dg-r:not(:hover):not([open]) { opacity: .5; }
  .lp-dg-r summary:hover .lp-dg-m { color: var(--wine); }
  .lp-dg-r summary:hover::after { color: var(--wine); }
}

@media (max-width: 899px) {
  /* mechanism and outcome share one line under the quote - never a tiny
     three-column table squeezed onto a phone. */
  .lp-dg-r summary { grid-template-columns: minmax(0, 1fr) auto; }
  .lp-dg-q, .lp-dg-g { grid-column: 1 / -1; }
  .lp-dg-m { padding-top: 4px; }
  .lp-dg-o { justify-self: end; padding-top: 4px; }
}

/* ==========================================================================
   chapter sixteen: what survives a failure
   ==========================================================================
   Ten rows each showing their whole paragraph, all at one weight, so a
   section about what survives a failure read as a spreadsheet. The
   guarantee stays on screen; the mechanism that earns it opens on click.
   The two columns stay - these are paired hard questions, not a list to be
   read down - but the rounded container goes. Rules and whitespace only. */

.lp-hq { margin-top: clamp(38px, 4.6vw, 68px); }
#lp-ledger-trust .lp-sub { max-width: 58ch; }

.lp-hq-grid { display: grid; border-top: 1px solid var(--line-2); }
@media (min-width: 900px) {
  .lp-hq-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 0; }
  /* one hairline between the columns, and row rules from the second row on */
  .lp-hq-i:nth-child(even) { border-left: 1px solid var(--line); padding-left: clamp(24px, 2.6vw, 40px); }
  .lp-hq-i:nth-child(odd) { padding-right: clamp(24px, 2.6vw, 40px); }
  .lp-hq-i:nth-child(n+3) { border-top: 1px solid var(--line); }
}
@media (max-width: 899px) {
  .lp-hq-i + .lp-hq-i { border-top: 1px solid var(--line); }
}

.lp-hq-i summary {
  list-style: none; cursor: pointer; position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 9px clamp(14px, 1.6vw, 24px);
  padding: clamp(18px, 2vw, 26px) 22px clamp(18px, 2vw, 26px) 0;
}
.lp-hq-i summary::-webkit-details-marker { display: none; }
.lp-hq-i summary:focus-visible { outline: 2px solid var(--wine); outline-offset: -2px; }

/* the question dominates; it is the thing a reader recognises as their own */
.lp-hq-q {
  grid-column: 1 / -1;
  font-size: clamp(15.5px, 1.55vw, 18px); line-height: 1.35; letter-spacing: -.014em;
  color: var(--ink); max-width: 40ch; transition: color .2s ease;
}
.lp-hq-q em { font-style: italic; }
/* what the system does, secondary */
.lp-hq-m {
  font-size: 12.5px; line-height: 1.5; color: var(--muted); max-width: 46ch;
  transition: color .2s ease;
}
/* and the final answer to the question, quiet and aligned right */
.lp-hq-o {
  align-self: start; justify-self: end; white-space: nowrap;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; font-weight: 600;
  padding-left: 13px; position: relative;
}
.lp-hq-o::before {
  content: ""; position: absolute; left: 0; top: 7px; width: 7px; height: 1px;
}
/* wine: it cannot happen. green: it holds, or it comes back. The same two
   words mean the same two things in the section above this one. */
.lp-hq-o.is-hard { color: var(--wine); }
.lp-hq-o.is-hard::before { background: var(--wine); }
.lp-hq-o.is-soft { color: var(--ok); }
.lp-hq-o.is-soft::before { background: var(--ok); }

.lp-hq-i summary::after {
  content: "+"; position: absolute; right: 0; top: clamp(18px, 2vw, 26px);
  font-family: var(--mono); font-size: 13px; color: var(--line-2);
  transition: color .2s ease;
}
.lp-hq-i[open] summary::after { content: "\2013"; color: var(--wine); }
.lp-hq-b {
  margin: 0; padding: 0 22px clamp(18px, 2vw, 24px) 0; max-width: 62ch;
  font-size: 12.5px; line-height: 1.65; color: var(--muted);
}
@media (min-width: 900px) {
  .lp-hq-i:nth-child(even) .lp-hq-b { padding-left: clamp(24px, 2.6vw, 40px); }
}

/* -- hover: the question darkens, the mechanism gains contrast, and a
   burgundy rule appears at the left of the item. */
.lp-hq-i { position: relative; }
.lp-hq-i::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--wine); transform: scaleY(0); transform-origin: top;
  transition: transform .25s cubic-bezier(.22,.61,.36,1);
}
@media (min-width: 900px) {
  .lp-hq-i:nth-child(even)::before { left: -1px; }
}
@media (hover: hover) {
  .lp-hq-i:hover::before, .lp-hq-i[open]::before { transform: scaleY(1); }
  .lp-hq-i:hover .lp-hq-q { color: #000; }
  .lp-hq-i:hover .lp-hq-m { color: var(--ink-2); }
  .lp-hq-i:hover summary::after { color: var(--wine); }
}
.lp-hq-i[open] .lp-hq-q { color: #000; }

/* -- the two the grid does not lead with. Demoted, never deleted: both
   carry a claim that appears nowhere else on the page. */
.lp-hq-more { margin-top: clamp(30px, 3.4vw, 48px); }
.lp-hq-mk {
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--muted-q); margin-bottom: 12px;
}
.lp-hq-i.is-more .lp-hq-q { font-size: clamp(14px, 1.35vw, 15.5px); }
.lp-hq-i.is-more summary { padding-top: 15px; padding-bottom: 15px; }
.lp-hq-i.is-more summary::after { top: 15px; }

/* chapter seventeen: the close settles */

/* the close must still settle for a reader who has asked for no motion */
@media (prefers-reduced-motion: reduce) {
  .lp-props.in .lp-prop, .lp-props.in .lp-prop.is-flag::before {
    animation: none !important;
  }
  .lp-prop { opacity: 1; }
  .lp-prop.is-flag::before { transform: scaleY(1); }
}

/* ==========================================================================
   REFITTING THE REBUILT SECTIONS TO ONE SCREEN
   ==========================================================================
   `.lp-sec { min-height: 100vh }` and the rhythm above it are not new. What
   is new is fourteen rebuilt sections that were never measured against it -
   at 1366x768 ten of eighteen overflowed, the worst by 853px, and a section
   taller than the viewport has nothing to snap to.

   Measured with headless Chromium at 1366x768, 1512x860 and 1920x1080, the
   same three sizes the original block used. Everything here is a HEIGHT
   query: none of it fires on a tall window, where the sections already fit
   and the air is doing its job. */

@media (max-height: 940px) {
  /* 208px of vertical padding on every section - `clamp(56px,8vw,104px)`
     resolves to its own ceiling at any width past 1300. Buying it back once
     here fixes four sections outright and dents every other one. */
  .lp-sec { padding-block: clamp(40px, 5.4vh, 68px); }
  .lp-h2 { font-size: clamp(26px, 3.1vw, 40px); }
  .lp-sub { font-size: 14px; }
  .lp-kicker { margin-bottom: 10px; }
}

@media (max-height: 880px) {
  /* Row-level tightening, in the order the measurement said to. */
  .lp-dg-r summary { padding-block: 11px; }
  .lp-dg-g { font-size: 12px; }
  .lp-hq-i summary { padding-block: 13px; }
  .lp-hq-q { font-size: 15px; }
  .lp-hq-more { margin-top: 20px; }
  .lp-cp-stage { padding-block: 18px 34px; }
  .lp-cp-notes { margin-top: 20px; }
  .lp-cp-end { margin-top: 26px; }
  .lp-ev { margin-top: 20px; }
  .lp-ev-hand { margin-block: 20px 14px; }
  .lp-ev-end { margin-top: 28px; }
  .lp-rv-top { margin-bottom: 22px; }
  .lp-rv-f b { font-size: clamp(26px, 3vw, 38px); }
  .lp-rv-hand { margin-block: 20px 14px; }
  .lp-rv-foot { margin-top: 22px; }
  .lp-sh-end { margin-top: 24px; }
  .lp-md { margin-top: 18px; }
  .lp-fp { margin-top: 20px; }
  .lp-cs { margin-top: 22px; }
  .lp-imp-wrap, .lp-q-wrap, .lp-lens-wrap { gap: clamp(20px, 2.4vw, 40px); }
}

/* -- Pass 2. The first pass gated the two-column ledger behind
   `max-height: 940px`, so it never fired on a 1080-tall window - where
   `.lp-dg` still measured 1333px inside a 1080 viewport. Twelve
   one-per-row diagnoses is structurally too tall for any screen, not just
   a short one, so the columns are a WIDTH decision and always were. */
@media (min-width: 1000px) {
}

/* The remaining four are over at 1080 as well, so their trims cannot be
   height-gated either. Modest and structural: nothing here removes a
   claim, it removes air the rebuilds added. */
@media (min-width: 1000px) {
  /* Twelve one-per-row diagnoses is structurally too tall for any screen.
     The rows are direct children of `.lp-dg` - an earlier attempt at this
     targeted a `.lp-dg-grid` wrapper that does not exist, and silently
     matched nothing. Two columns halves the height; auto-flow pairs them
     left-to-right, which reads as a list of symptoms rather than a queue. */
  .lp-dg {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(28px, 3vw, 52px);
  }
  /* the header row labelled one column; with two it labels neither */
  .lp-dg-h { display: none; }

  .lp-ev { margin-top: clamp(18px, 2vw, 26px); }
  .lp-ev-stage { padding: clamp(16px, 1.8vw, 24px) 0 clamp(30px, 3vw, 44px); }
  .lp-ev-end { margin-top: clamp(26px, 3vw, 40px); }
  .lp-ev-big { font-size: clamp(22px, 2.4vw, 34px); }

  .lp-cp { margin-top: clamp(20px, 2.2vw, 30px); }
  .lp-cp-stage { padding: clamp(16px, 1.8vw, 24px) 0 clamp(28px, 3vw, 42px); }
  .lp-cp-notes { margin-top: clamp(18px, 2vw, 28px); }
  .lp-cp-end { margin-top: clamp(24px, 2.8vw, 38px); }
  .lp-cp-big { font-size: clamp(21px, 2.4vw, 34px); }

  .lp-rv-top { margin-bottom: clamp(20px, 2.4vw, 34px); }
  .lp-rv-hand { margin: clamp(18px, 2.2vw, 30px) 0 clamp(14px, 1.8vw, 22px); }
  .lp-rv-foot { margin-top: clamp(20px, 2.4vw, 34px); }

  .lp-hq { margin-top: clamp(24px, 3vw, 44px); }
  .lp-hq-more { margin-top: clamp(20px, 2.4vw, 34px); }
}

/* -- Pass 3. Three sections are still over at 1080 and nine at 768, so the
   remaining trims are graduated by height rather than applied flat: a tall
   window keeps its air, a laptop gets it back only where it must. Every
   number below came from re-measuring, not from taste. */
@media (max-height: 1200px) {
  .lp-dg-r summary { padding-block: 13px; }
  .lp-dg-q { font-size: 14.5px; }
  .lp-dg-g { font-size: 12px; line-height: 1.45; }
  .lp-ev-hand { margin: 18px 0 14px; }
  .lp-ev-small, .lp-cp-small { font-size: 13px; }
  .lp-cp-stage { padding-bottom: clamp(24px, 2.6vw, 34px); }
  .lp-cp-note span, .lp-ev-r, .lp-hq-b { font-size: 12px; }
}

@media (max-height: 1010px) {
  /* A 768-tall laptop is the tightest real target. Type scale holds; what
     goes is leading and gap, which is air rather than information. */
  .lp-h2 { font-size: clamp(24px, 2.8vw, 34px); line-height: 1.08; }
  .lp-sub { font-size: 13.5px; line-height: 1.55; }
  .lp-dg-r summary { padding-block: 10px; }
  .lp-dg { column-gap: 32px; }
  /* NOT `.lp-hq-grid`: it separates its two columns with a border and
     carries no row gap by design, so a `gap` shorthand added 27px between
     all five rows and made that section 125px TALLER. Column only. */
  .lp-ev-grid, .lp-cp-stage, .lp-rv { gap: clamp(16px, 2vw, 28px); }
  .lp-hq-grid { column-gap: clamp(20px, 2.4vw, 34px); }
  .lp-ev-t, .lp-cp-num b { font-size: clamp(19px, 2vw, 24px); }
  .lp-ev-say, .lp-rv-say, .lp-fp-say, .lp-q-claim { font-size: clamp(16px, 1.6vw, 19px); }
  .lp-hq-i summary { padding-block: 11px; }
  .lp-hq-q { font-size: 14.5px; }
  .lp-sh-tree { gap: clamp(14px, 1.6vw, 22px); }
  .lp-seq__stage, .lp-cs-list { padding-block: 10px; }
  .lp-md-stage, .lp-imp-frame, .lp-q-frame, .lp-lens-frame { border-radius: 12px; }
}

/* -- Pass 4. The last of it, and the floor is legibility: leading, gaps and
   padding go, type does not drop below 12.5px. Measured after each change,
   not estimated. */
@media (max-height: 1200px) {
  /* six visual rows, so a pixel here is worth six - 1093px against a
     1080px window closed on row padding alone */
  .lp-dg-r summary { padding-block: 9px; }
  .lp-cp-end { margin-top: clamp(20px, 2.2vw, 30px); }
}
@media (max-height: 1010px) {
  .lp-kicker { margin-bottom: 8px; font-size: 10px; }
  .lp-h2 { margin-bottom: 10px; }
  .lp-sub { margin-top: 8px; }
  /* the ledger: six visual rows, so every pixel here counts six times */
  .lp-dg-r summary { padding-block: 8px; }
  .lp-dg-q { font-size: 13.5px; line-height: 1.3; }
  .lp-dg-g { font-size: 11.5px; line-height: 1.4; }
  .lp-ev-e, .lp-rv-g, .lp-hq-i summary { padding-block: 8px; }
  .lp-ev-figs, .lp-rv-figs { margin-block: 0; }
  .lp-cp-note { padding-block: 9px; }
  .lp-cp-list li, .lp-fp-chain li, .lp-q-e { padding-block: 5px; }
  .lp-rv-top { margin-bottom: 16px; }
  .lp-rv-gaunt { padding-block: 11px 12px; }
  .lp-rv-comp { margin-top: 16px; }
  .lp-hq-more { margin-top: 16px; }
  .lp-seq__stage { padding-block: 9px; }
}

/* -- Pass 5. The four content-densest sections and the last 13px of the
   ledger. Closing statements carry the most reducible height on this page:
   they are one or two lines of display type sized for a tall window, and a
   short one does not have the room to spend on them. */
@media (max-height: 1010px) {
  .lp-ev-big, .lp-cp-big, .lp-fp-big, .lp-sh-big {
    font-size: clamp(20px, 2.2vw, 28px); line-height: 1.16;
  }
  .lp-ev-end, .lp-cp-end, .lp-fp-end, .lp-sh-end { margin-top: clamp(18px, 2vw, 26px); }
  .lp-ev-small, .lp-cp-small, .lp-fp-small, .lp-sh-small { margin-top: 10px; font-size: 12.5px; }
  .lp-ev-time, .lp-cp-rail { margin-top: clamp(20px, 2.4vw, 32px); }
  .lp-ev-timecap, .lp-cp-timecap { margin-bottom: 12px; }
  .lp-rv-top { margin-bottom: 14px; }
  .lp-rv-dec { gap: 9px; }
  .lp-rv-btns > span { padding-block: 9px; }
  .lp-cp-said { margin-top: clamp(16px, 1.8vw, 24px); font-size: clamp(15px, 1.6vw, 19px); }
  .lp-cp-key { padding-top: 12px; }
  .lp-cp-notes { margin-top: 16px; }
}

/* -- The three-zone row ("q m o" across) needs ~900px of column. In two
   columns it gets 250, so every quote wrapped to three lines and the
   mechanism sat on one line beside a hand's width of dead space - tall AND
   awkward. Restacked for the narrower column: the quote pairs with its
   verdict, the gist pairs with its mechanism. Two lines instead of three,
   and the claim now sits directly beside the answer to it. */
@media (min-width: 1000px) {
  .lp-dg-r summary {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "q o" "g m";
    gap: 5px 18px;
  }
  .lp-dg-q, .lp-dg-g { max-width: none; }
  .lp-dg-m { align-self: baseline; justify-self: end; text-align: right; }
  .lp-dg-o { align-self: baseline; justify-self: end; }
}

/* -- The last three, re-measured against the visible area rather than the
   full viewport. Small, and taken from leading and gap rather than type. */
@media (min-width: 1000px) {
  .lp-cp-stage { padding-bottom: clamp(20px, 2.2vw, 30px); }
  .lp-cp-key { padding-top: 12px; }
  .lp-cp-notes { margin-top: clamp(14px, 1.6vw, 22px); }
  .lp-cp-end { margin-top: clamp(18px, 2vw, 26px); }
  .lp-ev-time { margin-top: clamp(20px, 2.4vw, 32px); }
  .lp-ev-end { margin-top: clamp(20px, 2.2vw, 30px); }
  .lp-rv { gap: clamp(18px, 2.2vw, 34px); }
  .lp-rv-gaunt { padding: 12px 16px 13px; }
  .lp-rv-comp { margin-top: 16px; }
  .lp-rv-hand { margin: clamp(16px, 1.8vw, 24px) 0 clamp(12px, 1.4vw, 18px); }
}

/* -- Closing the last 45px and 20px at 1080, and pulling the short-window
   tiers down with them. The compound section's four period notes and the
   review's figure band are the two tallest remaining blocks. */
@media (min-width: 1000px) {
  .lp-cp-note { padding: 10px 0 10px 14px; }
  .lp-cp-note span { line-height: 1.45; }
  .lp-cp-said { margin-top: clamp(14px, 1.6vw, 22px); }
  .lp-rv-f span { margin-top: 5px; }
  .lp-rv-join { height: 26px; }
  .lp-rv-dec { gap: 10px; }
}
@media (max-height: 1010px) {
  .lp-cp-note { padding-block: 8px; }
  .lp-cp-key { padding-top: 10px; gap: 6px 16px; }
  .lp-rv-join { height: 20px; }
  .lp-rv-gaunt { padding: 10px 14px 11px; }
  .lp-ev-panel .lp-ev-say, .lp-rv-say { line-height: 1.26; }
  .lp-ev-rows, .lp-ev-gaunt { margin-top: 14px; }
}

/* -- lp-learns, the last section over a 1020px visible area. 39px, taken
   from the notes row and the closing block. */
@media (min-width: 1000px) {
  .lp-cp-notes { margin-top: 12px; }
  .lp-cp-note { padding-block: 8px; }
  .lp-cp-note b { margin-bottom: 4px; }
  .lp-cp-end { margin-top: clamp(14px, 1.6vw, 22px); }
  .lp-cp-small { margin-top: 12px; }
  .lp-cp-said { margin-top: 10px; font-size: clamp(15px, 1.5vw, 18px); }
  .lp-cp-stage { padding-top: 12px; }
  .lp-cp-rail { margin-top: 0; }
}

/* -- The six problem rows sat at six different left edges (317-324px,
   measured) because each carried a rotation and an x-offset meant to read
   as "deterioration". It does not read as deterioration; it reads as six
   boxes somebody failed to line up - and rows five and six had settled
   with no transform at all, so the stagger was not even consistent.

   The deterioration survives where it belongs: the top-edge light still
   fades down the pile (`--edge`), which is a change in TONE rather than in
   ALIGNMENT. A list of failures should look precise. */
.lp-hist-row { --r: 0deg; --dx: 0px; }

/* -- "discover != decide" sat below the fold while the demonstration
   above it reserved 407px and showed content in the top third. The slot
   keeps a fixed height on purpose - switching stage must not reflow the
   card - but it was reserving for a taller panel than any stage renders. */
.lp-md-stage { padding: clamp(16px, 1.8vw, 22px) clamp(18px, 2vw, 26px); }
.lp-md-obs { margin-top: 12px; }
.lp-md-slot { margin-top: clamp(12px, 1.4vw, 18px); }
.lp-md-spine { margin-top: clamp(18px, 2vw, 28px); }
.lp-md-axis { margin-top: 10px; }
.lp-md-thesis { margin-top: clamp(12px, 1.4vw, 20px); }

/* -- the governed-claim section: the closing statement was off-screen. */
.lp-ev-open { margin-bottom: clamp(20px, 2.4vw, 32px); }
.lp-ev-grid { gap: clamp(18px, 2vw, 30px); }
.lp-ev-card { padding: clamp(16px, 1.8vw, 22px); }
.lp-ev-t { margin: 8px 0 12px; }
.lp-ev-meta { padding-top: 10px; }
.lp-ev-time { margin-top: clamp(16px, 2vw, 26px); }
.lp-ev-timecap { margin-bottom: 12px; }
.lp-ev-end { margin-top: clamp(16px, 2vw, 26px); }

/* -- Continuous, not tiered. These three carry the most reducible height
   and each is within ~40px on a 1020px visible area; the leading and gaps
   scale with the window rather than snapping at a breakpoint. */
@media (min-width: 1000px) {
  .lp-cp-stage { padding-block: clamp(10px, 1.2vh, 18px) clamp(16px, 2vh, 28px); }
  .lp-cp-notes { margin-top: clamp(10px, 1.2vh, 16px); }
  .lp-cp-end, .lp-rv-foot { margin-top: clamp(12px, 1.6vh, 24px); }
  .lp-hq { margin-top: clamp(16px, 2vh, 34px); }
  .lp-hq-i summary { padding-block: clamp(9px, 1.1vh, 15px); }
  .lp-hq-more { margin-top: clamp(12px, 1.6vh, 26px); }
  .lp-rv-top { margin-bottom: clamp(12px, 1.6vh, 26px); }
  .lp-rv-hand { margin: clamp(12px, 1.6vh, 24px) 0 clamp(10px, 1.2vh, 18px); }
}

/* ==========================================================================
   THE THREE TALL SECTIONS: USE THE WIDTH, CUT NOTHING
   ==========================================================================
   These three stayed 890-920px tall at every width because their height is
   content stacked in one column - while the column itself was up to 300px
   wider than anything in it. Nothing here shrinks type or removes a claim;
   it pairs blocks that were sitting one above the other with empty space
   beside them. Measured at 1440x900, where all three now fit. */

@media (min-width: 1100px) {
  /* -- the governed claim. The timeline and the closing statement were
     stacked; the statement is 22ch wide and was using a third of the row. */
  .lp-ev {
    display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    column-gap: clamp(30px, 3.2vw, 60px); align-items: start;
  }
  .lp-ev-open, .lp-ev-grid { grid-column: 1 / -1; }
  .lp-ev-time { grid-column: 1; }
  .lp-ev-end { grid-column: 2; margin-top: 0; align-self: center; }

  /* -- why it compounds. Same move: the four period notes and the sentence
     month 6 earns were stacked, and the sentence is 46ch. */
  .lp-cp {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    column-gap: clamp(28px, 3vw, 54px); align-items: start;
  }
  .lp-cp-rail, .lp-cp-stage, .lp-cp-key { grid-column: 1 / -1; }
  .lp-cp-notes { grid-column: 1; }
  .lp-cp-said { grid-column: 2; margin-top: 0; align-self: center; }

  /* -- the review. The map was 924px wide and never used more than 620.
     Everything the MACHINE does now sits left of the boundary and the
     human decision sits right of it, so the rule that was a horizontal
     line near the bottom becomes the vertical one it always described:
     machine on one side, person on the other. */
  .lp-rv-map {
    grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
    column-gap: 0; justify-items: stretch;
  }
  .lp-rv-prop, .lp-rv-fan, .lp-rv-figs, .lp-rv-join { grid-column: 1 / -1; justify-self: center; }
  .lp-rv-gaunt, .lp-rv-comp { grid-column: 1; }
  .lp-rv-gaunt { max-width: none; margin-right: clamp(24px, 2.6vw, 44px); }
  .lp-rv-comp { justify-content: flex-start; margin-right: clamp(24px, 2.6vw, 44px); }
  /* `align-self: center` with a spanned row left the decision at the foot
     of an otherwise empty column, and the divider - which is the boundary
     between machine and person - was only as tall as the buttons. Stretched,
     it runs the full height of the machine's work beside it, which is what
     a boundary between the two should do. */
  .lp-rv-dec {
    grid-column: 2; grid-row: 6 / span 2; max-width: none; align-content: start;
    padding-left: clamp(24px, 2.6vw, 44px); border-left: 1px solid var(--line);
  }
  /* the boundary label rides the divider it names */
  .lp-rv-hand {
    grid-column: 1 / -1; grid-row: 5; display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
    column-gap: 0; margin: clamp(14px, 1.8vh, 24px) 0 10px; max-width: none;
  }
  .lp-rv-hand i { display: none; }
  .lp-rv-hand span:first-child { justify-self: start; }
  .lp-rv-hand span:last-child { justify-self: start; padding-left: clamp(24px, 2.6vw, 44px); }
}

/* -- The last of it at 1440x900. The compound section's legend row was
   spanning both columns for 26px of chips; it belongs with the notes it
   labels. The review's boundary label no longer needs the air a full-width
   horizontal rule needed. */
@media (min-width: 1100px) {
  .lp-cp-key { grid-column: 1; }
  .lp-cp-said { grid-row: span 2; }
  .lp-cp-notes { margin-top: clamp(8px, 1vh, 14px); }
  .lp-rv-hand { margin: clamp(10px, 1.2vh, 18px) 0 8px; }
  .lp-rv-join { height: clamp(14px, 1.6vh, 22px); }
  .lp-rv-figs { margin-top: 0; }
  .lp-rv-gaunt { padding-block: clamp(9px, 1.1vh, 13px) clamp(10px, 1.2vh, 14px); }
}

/* -- The canvas draws at its viewBox aspect, so on a wide column it grew
   past the fold purely from width. Capped against the WINDOW instead, which
   is the dimension that actually constrains it. */
.lp-lens-svg { max-height: min(46vh, 470px); }
.lp-lens-frame { display: grid; }

@media (min-width: 1100px) {
  /* the compound field and its three columns carry the remaining height */
  .lp-cp-stage { row-gap: clamp(12px, 1.6vh, 22px); }
  .lp-cp-grid { gap: clamp(9px, 1.1vh, 13px); }
  .lp-cp-list li { padding-block: clamp(4px, .55vh, 7px); }
  .lp-cp-num b { font-size: clamp(28px, 3.4vh, 46px); }
  .lp-rv-prop { padding-block: clamp(12px, 1.5vh, 18px) clamp(11px, 1.4vh, 16px); }
  .lp-sh-tree { row-gap: clamp(12px, 1.5vh, 20px); }
  .lp-sh-o summary { padding-block: clamp(9px, 1.1vh, 14px); }
}

/* -- lp-learns is the last one, and its height is the stage: three columns
   whose tallest is the seven-item conventions list. Row rhythm only. */
@media (min-width: 1100px) {
  .lp-cp-list { margin-top: clamp(10px, 1.3vh, 18px); }
  .lp-cp-list li { padding-block: clamp(3px, .45vh, 6px); font-size: 10.5px; }
  .lp-cp-num b { font-size: clamp(26px, 3vh, 40px); }
  .lp-cp-p { padding: clamp(11px, 1.4vh, 15px) clamp(13px, 1.4vw, 17px); }
  .lp-cp-p b { font-size: clamp(17px, 1.8vw, 22px); }
  .lp-cp-hint { padding-top: clamp(7px, .9vh, 10px); }
  .lp-cp-cap { margin-top: clamp(12px, 1.5vh, 20px); }
  .lp-cp-rs { margin-top: 9px; min-height: 40px; }
  .lp-rv-btns > span { padding-block: clamp(8px, 1vh, 11px); }
}

/* -- 12px and 10px. The headline block is the same three elements on every
   section and is the cheapest place left to find them. */
@media (min-width: 1100px) and (max-height: 1010px) {
  #lp-learns .lp-h2, #lp-review .lp-h2 { margin-bottom: 6px; }
  #lp-learns .lp-sub, #lp-review .lp-sub { margin-top: 6px; line-height: 1.5; }
  .lp-cp-rail { padding-bottom: 8px; }
  .lp-rv-top { margin-bottom: clamp(10px, 1.2vh, 18px); }
}

@media (min-width: 1100px) and (max-height: 1010px) {
  .lp-cp-stage { padding-top: clamp(8px, 1vh, 14px); }
  .lp-cp-ck { margin-bottom: clamp(8px, 1vh, 13px); }
}

/* ---------- legal / ownership strip ----------
   Sits under the existing footer row on the PUBLIC page only. Quiet by
   design: it must be findable without competing with the primary CTA,
   so it borrows the footer's muted tone and adds no weight of its own. */
.lp-legal {
  border-top: 1px solid var(--line);
  padding: 18px clamp(20px,5vw,64px) 30px;
  max-width: 1280px; margin: 0 auto;
  display: flex; align-items: baseline; gap: 12px 26px; flex-wrap: wrap;
}
.lp-legal__links { display: flex; gap: 18px; flex-wrap: wrap; }
.lp-legal__links a {
  font-size: 12.5px; color: var(--muted-q); text-decoration: none;
}
.lp-legal__links a:hover,
.lp-legal__links a:focus-visible {
  color: var(--wine); text-decoration: underline;
}
.lp-legal__owner {
  margin: 0; margin-left: auto; font-size: 12.5px; color: var(--muted-q);
}
.lp-sec-dark .lp-legal { border-top-color: var(--dark-line); }
.lp-sec-dark .lp-legal__links a,
.lp-sec-dark .lp-legal__owner { color: var(--dark-muted); }
.lp-sec-dark .lp-legal__links a:hover,
.lp-sec-dark .lp-legal__links a:focus-visible { color: var(--dark-wine); }
@media (max-width: 640px) {
  .lp-legal__owner { margin-left: 0; width: 100%; }
}
