/* ============================================================
   brain.css

   Everything new on the Brain page, loaded after product-pages.css
   so the shared bundle stays untouched for the Acquisitions session.

   The page is one dark instrument. Backgrounds only vary by
   shading. Two pinned sequences carry the demonstration; the rest
   is short, still copy in the structure of the one-page brief at
   ai.realzono.com/RealZono-Brain.
   ============================================================ */

.brain-page {
  --st0: #0a0b0e;   /* deepest: pinned stages */
  --st1: #0d0e11;   /* base band */
  --st2: #101318;   /* raised band */
  --st3: #14171d;   /* panel */
  --st4: #171b21;   /* raised panel */
  --wln: rgba(233,235,238,.16);
  --wln2: rgba(233,235,238,.08);
  --wtx: #eceef1;
  --wdim: rgba(233,235,238,.6);
  --wfnt: rgba(233,235,238,.4);
  background: var(--st0);
  color: var(--wtx);
}
.brain-page .atmos { display: none; }
.brain-page::before {
  background:
    linear-gradient(to right, rgba(233,235,238,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(233,235,238,.05) 1px, transparent 1px);
  background-size: 62px 62px;
  opacity: .5;
  -webkit-mask-image: none;
  mask-image: none;
}
.brain-page .topscrim { display: none; }
.brain-page .band { padding: clamp(72px, 9.5vh, 112px) 0; }
.brain-page .dark-act.shade-a { background: var(--st1); }
.brain-page .dark-act.shade-b { background: var(--st2); }
.brain-page .dark-act.shade-c { background: var(--st0); }
.brain-page .corner { border-color: rgba(233,235,238,.5); }
.brain-page .kicker .num { color: var(--wtx); }
.brain-page h1, .brain-page h2, .brain-page h3 { color: #eceef1; }
.brain-page h1 em, .brain-page h2 em {
  background: linear-gradient(120deg, #f2f3f5, #9aa1ab);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ------------------------------------------------------------------
   THE ASK PANEL. One instrument that asks and answers on a loop,
   rather than three cards sitting still.
   ------------------------------------------------------------------ */
.askpanel { position: relative; overflow: hidden; }
/* the page itself is drawn in dots, like the record the compile makes */
.ap-page { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; }
.ap-bar {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 13px 22px;
  border-bottom: 1px solid var(--wln2);
  color: var(--wfnt);
  font: 500 9px/1 'JetBrains Mono', monospace;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.ap-host { color: rgba(233,235,238,.7); }
.ap-idx { margin-left: auto; }
.ap-idx b { color: var(--wtx); font-weight: 500; }
.ap-live { display: inline-flex; align-items: center; gap: 7px; color: var(--wtx); }
.ap-live::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--wtx); animation: pulse 1.7s ease-in-out infinite; }

.ap-body {
  position: relative;
  z-index: 1;
  padding: clamp(26px, 3.2vw, 40px) 26% clamp(26px, 3.2vw, 40px) clamp(20px, 2.6vw, 30px);
  /* fixed, not minimum: the panel used to grow as the answer and its
     citations landed, so the whole section jumped on every cycle */
  height: clamp(300px, 34vh, 380px);
  overflow: hidden;
}
/* the answer block is reserved whether or not it is showing yet */
.ap-a { min-height: 132px; }
/* start, not baseline: both columns are canvases now, and a shared
   baseline drags the gutter and the prompt to the bottom of them */
.ap-line { display: grid; grid-template-columns: 26px 18px 1fr; gap: 0 10px; align-items: start; }
.ap-line .ap-gut, .ap-line .ap-prompt { padding-top: 7px; }
/* a line gutter, the way a terminal numbers what it has run */
.ap-gut { color: rgba(233,235,238,.22); font: 500 9px/1.9 'JetBrains Mono', monospace; }
.ap-prompt { color: rgba(233,235,238,.55); font: 500 14px/1.5 'JetBrains Mono', monospace; }
.ap-prompt.out { color: var(--wtx); }
.ap-q .ap-text { color: var(--wtx); font: 500 clamp(15px, 1.7vw, 20px)/1.5 'JetBrains Mono', monospace; }
.ap-cur {
  display: inline-block;
  width: 8px;
  height: 15px;
  margin-left: 3px;
  background: var(--wtx);
  vertical-align: -2px;
  opacity: 0;
}
.ap-cur.on { animation: bcaret 1s steps(1) infinite; opacity: 1; }
.ap-a {
  /* the answer column is a canvas, so a shared baseline drags the gutter
     and the return arrow down to the bottom of it, next to the citations
     rather than beside the line they belong to */
  margin-top: clamp(20px, 2.6vw, 30px);
  padding-top: clamp(18px, 2.4vw, 26px);
  border-top: 1px solid var(--wln2);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.2,.7,.2,1);
}
.ap-a.in { opacity: 1; transform: none; }
.ap-ans { min-width: 0; }
.ap-ans p {
  max-width: 52ch;
  color: #f1f2f4;
  font: 400 clamp(14px, 1.5vw, 18px)/1.72 'JetBrains Mono', monospace;
  letter-spacing: -.005em;
  min-height: 1.72em;
}
.ap-cites { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px; }
.ap-cites .cite-chip { opacity: 0; transform: translateY(4px); transition: opacity .4s ease, transform .4s ease; }
.ap-cites .cite-chip.in { opacity: 1; transform: none; }

/* the status line a terminal keeps at its foot */
.ap-status {
  position: relative;
  z-index: 1;
  display: flex;
  gap: clamp(16px, 3vw, 40px);
  /* inset, so it sits inside the drawn page rather than across its edge */
  margin: 0 16px 14px;
  padding: 11px 16px;
  border-top: 1px solid var(--wln2);
  background: rgba(0,0,0,.28);
  color: var(--wfnt);
  font: 500 8.5px/1 'JetBrains Mono', monospace;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.ap-status b { color: rgba(233,235,238,.85); font-weight: 500; }
.ap-blink { margin-left: auto; animation: statusblink 2.6s ease-in-out infinite; }
@keyframes statusblink { 50% { opacity: .3; } }

/* the progress rail is gone: it read as a stray line across the page */
.ap-rail { display: none; }
@media (max-width: 720px) {
  .ap-ans p { font-size: 14px; max-width: none; }
  .ap-body { height: 360px; padding-right: 22px; }
  .ap-a { min-height: 176px; }
  .ap-line { grid-template-columns: 20px 14px 1fr; }
  .ap-status { flex-wrap: wrap; gap: 12px; }
}

/* ------------------------------------------------------------------
   THE SEAM
   A quiet run of traffic between the walkthrough and the objects, the
   same idea as the seam on the acquisitions page and inverted for a dark
   page: faint rules with a brighter segment travelling along each one at
   its own speed, some of them backwards.

   That one animates `left`, which is a layout property, so every frame
   of it costs a reflow and a repaint. This one moves a transform, which
   the compositor handles on its own thread and which a weak machine
   never has to think about. The segment is the full width of its rule
   with a band painted into it, so a single translate of its own width
   carries it the whole way across whatever the band is doing.
   ------------------------------------------------------------------ */
.seam {
  position: relative;
  height: clamp(88px, 12vh, 146px);
  /* The band it sits between is one continuous shade, and leaving the
     seam transparent let the page's grid show through it, so a stretch
     of grey squares appeared in the middle of an otherwise unbroken
     column. It carries the same background as the sections either side
     of it and reads as part of them. */
  background: var(--st1);
  /* Pulled up, not spaced down. The walkthrough centres its photograph
     in a full height sticky, so once the pin ends there is a run of dead
     space under it that no margin of ours can shrink: measured at 900px
     tall it was 140px above the seam against 68 below, and the elements
     read as unevenly spaced because they were.

     The negative margin takes the seam into that dead space, which the
     photograph never reaches, and the two gaps come out close to equal.
     It also closes the strip that used to sit between the section and
     the seam, where nothing carried a background and the page's fixed
     grid and dither showed through as a band of grey dots. */
  /* The dead space is (100vh - min(74vh, 620px)) / 2, so on a viewport
     taller than 838px it grows with the window while a clamped padding
     below does not, and the two gaps drift apart again. The second term
     cancels exactly that growth, which holds the gap above the seam at
     a constant 86px on any tall window. */
  margin: calc(-6vh - max(0px, 44vh - 396px)) 0 0;
  overflow: hidden;
  pointer-events: none;
}
.brain-page #role { padding-top: clamp(30px, 5.5vh, 72px); }
/* Seven rules at fifteen percent read as grey bars laid across the
   column, which is the opposite of quiet. Four of them, at a sixteenth,
   so the structure is felt rather than seen, and the travelling marks
   are greys rather than white and no two the same. */
.seam i { position: absolute; left: 0; right: 0; height: 1px; background: rgba(233,235,238,.06); }
.seam i::after {
  --a: 44%; --b: 56%; --g: .30;
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    transparent 0 var(--a), rgba(233,235,238,var(--g)) var(--a) var(--b), transparent var(--b) 100%);
  transform: translateX(-100%);
  will-change: transform;
}
/* nothing runs until the seam is actually on screen */
.seam.live i::after { animation: seamrun 15s linear infinite; }
@keyframes seamrun { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@keyframes seamrun-back { from { transform: translateX(100%); } to { transform: translateX(-100%); } }

.seam i:nth-child(1) { top: 18%; }
.seam i:nth-child(1)::after { --a: 42%; --b: 58%; --g: .30; animation-duration: 15s; animation-delay: -4s; }
.seam i:nth-child(2) { top: 41%; left: 8%; right: 22%; }
.seam i:nth-child(2)::after { --a: 46%; --b: 54%; --g: .20; animation-duration: 11s; animation-delay: -7s; animation-name: seamrun-back; }
.seam i:nth-child(3) { top: 64%; right: 12%; }
.seam i:nth-child(3)::after { --a: 39%; --b: 61%; --g: .38; animation-duration: 19s; animation-delay: -2s; }
.seam i:nth-child(4) { top: 87%; left: 30%; }
.seam i:nth-child(4)::after { --a: 47%; --b: 53%; --g: .24; animation-duration: 9s; animation-delay: -5s; }

@media (prefers-reduced-motion: reduce) {
  .seam.live i::after { animation: none; transform: translateX(-12%); }
}

/* ------------------------------------------------------------------
   IN PRACTICE, and the floater canvases. Same protected zone: these
   were lost to range deletions, which collapsed the three question
   cards into one column and left the canvases at their intrinsic size.
   ------------------------------------------------------------------ */
.ex-grid { display: grid; grid-template-columns: repeat(3, 1fr); }
.exq { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 16px; min-height: 210px; padding: 24px 22px 26px; }
.exq + .exq { border-left: 1px solid var(--wln2); }
.exq .q {
  display: flex;
  align-items: baseline;
  gap: 10px;
  color: var(--wtx);
  font: 500 14px/1.5 'JetBrains Mono', monospace;
}
.exq .q .ask-caret { align-self: center; }
.q-tag {
  flex: none;
  color: var(--wfnt);
  font-size: 9px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.exq .a { color: var(--wdim); font-size: 14.5px; line-height: 1.62; font-weight: 300; }
.exq .a strong { color: rgba(233,235,238,.9); font-weight: 500; }

.vig {
  display: block;
  width: 100%;
  height: 300px;
  margin-bottom: 18px;
  image-rendering: pixelated;
  opacity: .95;
  cursor: crosshair;
}
@media (max-width: 900px) { .vig { height: 240px; } }

/* ------------------------------------------------------------------
   THE THREE STEP ROW. Also kept high in this file: these rules were
   removed with the band that used to carry them, which collapsed the
   row into a single column and stranded the floaters in it.
   ------------------------------------------------------------------ */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); }
.step { position: relative; z-index: 1; padding: 26px 24px 30px; }
.step + .step { border-left: 1px solid var(--wln2); }
.s-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
  color: var(--wtx);
  font: 500 12px/1 'JetBrains Mono', monospace;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.s-head .n { color: var(--wfnt); font-size: 9px; }
.step p { color: var(--wdim); font-size: 14px; line-height: 1.6; font-weight: 300; }

/* ------------------------------------------------------------------
   THE ANSWER IS DRAWN, NOT SET. The record and the compile fragments
   are rasterised into dots, and the answer is a piece of that same
   record, so it is written in the same hand: a canvas of dots that
   accumulates. The <p> stays in the markup, visually hidden, because
   the canvas is worth nothing to a screen reader.
   ------------------------------------------------------------------ */
.ap-qc {
  display: block; width: 100%;
  height: clamp(40px, 4.4vw, 58px);
  image-rendering: pixelated;
}
.ap-ansc {
  /* height is set by the script once the line count is known; this is
     only the reservation before the first answer lands */
  display: block; width: 100%;
  height: clamp(52px, 6.4vw, 84px);
  image-rendering: pixelated;
}
.ap-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden;
  white-space: nowrap;
}

/* ------------------------------------------------------------------
   DOT TYPE BLOCKS. Kept high in this file on purpose: these rules have
   now been destroyed three times by range deletions further down, and
   without .ctype-sr the visually hidden heading paints and every dot
   line renders twice. Do not move them next to a section that might
   be cut.
   ------------------------------------------------------------------ */
.ctype { position: relative; margin: 0 auto; width: min(1000px, 100%); }
.ctype canvas { display: block; width: 100%; height: auto; }
.ctype-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.act-head { max-width: 900px; margin-bottom: 40px; }
.act-head h2 { margin-top: 16px; }
.act-head .lede { margin-top: 20px; }
.prose-band .lede { margin-top: 22px; }
.prose-band h2 { margin-top: 16px; max-width: 900px; }

/* ============================================================
   RIG . the instrument chrome every module wears
   ============================================================ */
.rig {
  position: relative;
  background: var(--st3);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07), 0 34px 90px -60px rgba(0,0,0,.9);
}
.rig::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: .55;
  background:
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) left 10px top 10px/14px 1px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) left 10px top 10px/1px 14px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) right 10px top 10px/14px 1px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) right 10px top 10px/1px 14px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) left 10px bottom 10px/14px 1px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) left 10px bottom 10px/1px 14px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) right 10px bottom 10px/14px 1px no-repeat,
    linear-gradient(rgba(233,235,238,.6),rgba(233,235,238,.6)) right 10px bottom 10px/1px 14px no-repeat;
}
.rig::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: .22;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,.3) 0 1px, transparent 1px 3px);
}

.bstage-cap {
  position: absolute;
  z-index: 4;
  color: var(--wfnt);
  font: 500 10px/1 'JetBrains Mono', monospace;
  letter-spacing: 1.7px;
  text-transform: uppercase;
}
.bstage-cap b { color: var(--wtx); font-weight: 500; }
.bstage-cap.tl { top: 96px; right: 26px; }
.bstage-cap.bl { left: 26px; bottom: 24px; }
.bstage-cap.br { right: 26px; bottom: 24px; }

.cite-chip {
  padding: 6px 9px;
  border: 1px solid rgba(233,235,238,.2);
  color: rgba(233,235,238,.62);
  font: 500 8.5px/1 'JetBrains Mono', monospace;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.conf {
  display: inline-block;
  margin-right: 6px;
  padding: 3px 6px;
  font: 500 8px/1 'JetBrains Mono', monospace;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.conf.firm { color: #0f1217; background: #dfe1e4; }
.conf.inferred { color: rgba(233,235,238,.8); border: 1px dashed rgba(233,235,238,.4); }

.ask-caret {
  display: none;
  width: 6px;
  height: 13px;
  background: var(--wtx);
  animation: bcaret 1s steps(1) infinite;
}
.ask-caret.on { display: inline-block; }
@keyframes bcaret { 50% { opacity: 0; } }

/* ============================================================
   HERO . brain -> chat
   ============================================================ */
.bhero {
  position: relative;
  height: 420vh;
  padding: 0 !important;
  background: var(--st0);
}
.bhero-navmask, .cpin-navmask, .ppin-navmask {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 100%;
  visibility: hidden;
  pointer-events: none;
}
.bhero-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--st0);
}
.bhero-sticky::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: calc(1 - var(--copyout, 0));
  background: linear-gradient(100deg, rgba(10,11,14,.94) 0%, rgba(10,11,14,.82) 30%, rgba(10,11,14,0) 58%);
}
.bhero-sticky::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  opacity: .2;
  background: radial-gradient(rgba(233,235,238,.16) .7px, transparent .8px);
  background-size: 4px 4px;
}
.bstage {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}
.bstage canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  image-rendering: pixelated;
}
.bstage.plate-only::before {
  content: "";
  position: absolute;
  inset: -2%;
  z-index: 1;
  background: url("/img/brain/hero-office.webp") center/cover no-repeat;
  filter: grayscale(1) contrast(1.12) brightness(1.42);
  /* a very slow drift, so a still frame is never quite still */
  animation: heroBreath 34s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes heroBreath {
  from { transform: scale(1.0) translate3d(0, 0, 0); }
  to   { transform: scale(1.05) translate3d(-1%, -0.6%, 0); }
}
@media (prefers-reduced-motion: reduce) { .bstage.plate-only::before { animation: none; } }
.bstage-frame {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: .6;
  background:
    radial-gradient(120% 100% at 50% 46%, transparent 55%, rgba(0,0,0,.55) 100%),
    repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px);
}
.bstage .corner { z-index: 4; width: 20px; height: 20px; opacity: .6; }

/* The hero says one thing, off to the side, and it is not there when the
   page opens: the room and the cloud on the monitor get the first beat to
   themselves and the title rises into the margin a little way down. */
.bhero-copy {
  --out: 0;
  --in: 0;
  position: absolute;
  z-index: 5;
  left: max(24px, calc((100vw - 1280px) / 2));
  top: 64%;
  width: min(400px, 34vw);
  padding-left: 22px;
  transform: translateY(calc(18px * (1 - var(--in)))) translateY(calc(-26px * var(--out)));
  opacity: calc(var(--in) * (1 - var(--out)));
  color: var(--wtx);
}
/* a rule down the margin, so the title reads as sitting in the edge of
   the frame rather than floating loose over the photograph */
.bhero-copy::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 6px;
  width: 1px;
  background: linear-gradient(to bottom, rgba(236,238,241,.62), rgba(236,238,241,0));
}
.bhero-copy h1 {
  margin: 0;
  color: #f3f4f6;
  font-size: clamp(38px, 4.6vw, 68px);
  line-height: 1.02;
  letter-spacing: -.022em;
}

.bhero-turn {
  --in: 0;
  position: absolute;
  z-index: 5;
  left: max(24px, calc((100vw - 1200px) / 2));
  bottom: clamp(64px, 12vh, 130px);
  opacity: var(--in);
  transform: translateY(calc(16px * (1 - var(--in))));
  pointer-events: none;
}
.bhero-turn::before {
  content: "";
  position: absolute;
  inset: -34px -60px -30px -46px;
  z-index: -1;
  background: radial-gradient(70% 130% at 26% 50%, rgba(10,11,14,.93), rgba(10,11,14,0) 74%);
}
.bhero-turn p {
  color: rgba(233,235,238,.62);
  font: 400 clamp(20px, 2.5vw, 33px)/1.3 'Fraunces', serif;
  letter-spacing: -.02em;
}
.bhero-turn p.em { color: #f2f3f5; font-weight: 500; }

.bhero-hint {
  position: absolute;
  z-index: 5;
  left: 50%;
  transform: translateX(-50%);
  bottom: 30px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--wfnt);
  font: 500 9px/1 'JetBrains Mono', monospace;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.bhero-hint::after {
  content: "";
  width: 30px;
  height: 1px;
  background: rgba(233,235,238,.3);
  animation: hintpulse 2.4s ease-in-out infinite;
}
@keyframes hintpulse { 50% { transform: translateX(8px); opacity: .35; } }

/* ============================================================
   02 . compile: scroll pulls the mess into the record
   ============================================================ */
/* ------------------------------------------------------------------
   THE PROBLEM. Its own pinned act rather than a band: the claim is
   split across the frame, the subject counting up in the top left and
   the consequence landing in the bottom right once the counting stops.
   ------------------------------------------------------------------ */
.ppin { position: relative; height: 300vh; padding: 0 !important; background: var(--st1); }
.ppin-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--st1);
}
.pstage { position: absolute; inset: clamp(18px, 3.4vh, 40px) clamp(18px, 3.4vw, 46px); }
.pstage .corner { width: 20px; height: 20px; opacity: .5; }
.pst { position: absolute; width: min(920px, 66vw); }
.pst-a { left: 0; top: 15%; }
.pst-b { right: 0; bottom: 17%; }
.pst canvas { display: block; width: 100%; height: auto; }
@media (max-width: 900px) {
  .ppin { height: 260vh; }
  .pst { width: calc(100% - 4px); }
  .pst-a { top: 12%; }
  .pst-b { bottom: 14%; }
}

.cpin { position: relative; height: 240vh; padding: 0 !important; background: var(--st0); }
.cpin-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--st0);
}
.cstage { position: absolute; inset: 0; }
.clines { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; pointer-events: none; }
.cstage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .2;
  background: radial-gradient(rgba(233,235,238,.16) .7px, transparent .8px);
  background-size: 4px 4px;
}
.cstage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .5;
  background:
    radial-gradient(120% 100% at 50% 46%, transparent 58%, rgba(0,0,0,.5) 100%),
    repeating-linear-gradient(0deg, rgba(0,0,0,.14) 0 1px, transparent 1px 3px);
}
.cstage .corner { z-index: 4; width: 20px; height: 20px; opacity: .6; }
.cstage-head {
  position: absolute;
  z-index: 3;
  left: max(24px, calc((100vw - 1200px) / 2));
  top: clamp(96px, 14vh, 150px);
  max-width: 520px;
}
.cstage-head h2 { margin-top: 14px; color: #f0f1f4; font-size: clamp(30px, 3.4vw, 48px); }

/* the raw material: dotted white documents. The page itself is drawn
   in points on a canvas; HTML carries only the type label and one
   grainy snippet, so nothing reads as a crisp UI box */
.frag {
  position: absolute;
  z-index: 2;
  width: min(196px, 17vw);
  aspect-ratio: 4 / 5;
  will-change: transform, opacity;
}
.fragc {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}
.frag.f1 { left: 43%; top: 11%; }
.frag.f2 { left: 71%; top: 15%; }
.frag.f3 { left: 84%; top: 46%; }
.frag.f4 { left: 72%; top: 76%; }
.frag.f5 { left: 45%; top: 83%; }
.frag.f6 { left: 19%; top: 78%; }
.frag.f7 { left: 6%;  top: 50%; }
.frag.f8 { left: 21%; top: 36%; }

/* the record, as a file entry: header, an infobox of fields, the claim
   with numbered references under it, and a reconciliation footer. Hidden
   until the compile starts, then its dots accumulate as documents arrive */
.crec {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 55%;
  width: min(560px, 45vw);
  transform: translate(-50%, -50%);
  padding: 0;
  aspect-ratio: 11 / 10;
  opacity: 0;
  transition: opacity .5s ease;
}
.crecc { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; }
/* ============================================================
   03 . the record at work
   Pinned, so the copy holds still and only the highlight moves.
   The old version scrolled a text column past a fixed frame and
   picked the active step from a 16vh observer band, which meant
   the thing you were reading was always sliding and the highlight
   flickered whenever two steps straddled the band.
   ============================================================ */
.ipin { position: relative; height: 520vh; padding: 0 !important; background: var(--st1); }
.ipin-navmask {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 100%;
  visibility: hidden;
  pointer-events: none;
}
.ipin-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--st1);
}
/* no width here: the .wrap class on the same element owns the measure,
   and setting width:100% was overriding it into a full bleed row */
.ipin-grid {
  display: grid;
  grid-template-columns: .82fr 1.18fr;
  gap: clamp(30px, 4.5vw, 72px);
  align-items: center;
}
.ipin-copy { min-width: 0; }
.ipin-copy h2 { max-width: 14ch; margin-bottom: clamp(22px, 3vw, 38px); font-size: clamp(30px, 3.9vw, 54px); }

/* the whole list stays on screen: you can see where you are and what
   is coming, and only the lit row and its description change */
.ipin-list { list-style: none; margin: 0; padding: 0; }
.istep {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 4px 12px;
  padding: 14px 0;
  border-top: 1px solid var(--wln2);
  transition: opacity .45s ease;
  opacity: .32;
}
.istep:last-child { border-bottom: 1px solid var(--wln2); }
.istep.on { opacity: 1; }
.in-n {
  color: var(--wfnt);
  font: 500 9.5px/1.9 'JetBrains Mono', monospace;
  letter-spacing: 1.4px;
  transition: color .45s ease;
}
.istep.on .in-n { color: var(--wtx); }
.istep h3 {
  margin: 0;
  color: #f0f1f4;
  font-size: clamp(19px, 1.9vw, 25px);
  font-weight: 520;
  letter-spacing: -.02em;
}
/* the description opens only for the lit row, so the block never jumps */
.in-d {
  grid-column: 2;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .45s cubic-bezier(.2,.7,.2,1), opacity .35s ease;
  opacity: 0;
}
.istep.on .in-d { grid-template-rows: 1fr; opacity: 1; }
.in-d p {
  overflow: hidden;
  margin: 0;
  color: var(--wdim);
  font-size: 14.5px;
  line-height: 1.6;
  font-weight: 300;
  max-width: 42ch;
}
.istep.on .in-d p { padding-top: 8px; }

.ipin-frame {
  position: relative;
  height: min(74vh, 620px);
  margin: 0;
  background: var(--st2);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1), 0 44px 100px -64px rgba(0,0,0,.95);
  overflow: hidden;
}
@media (min-width: 1051px) {
  .ipin-frame { margin-right: calc(-1 * max(24px, (100vw - 1200px) / 2)); }
}
/* Opacity and transform only. The previous version animated mask-image
   to dissolve one plate into the next, which is correct looking and very
   expensive: a mask that changes every frame forces a full repaint of a
   1600 by 900 image, which is what made this section stutter on scroll.
   Both properties below are composited, so the swap costs nothing. */
.ipin-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.03);
  transition: opacity .8s cubic-bezier(.3,.7,.3,1);
  will-change: opacity, transform;
  backface-visibility: hidden;
}
.ipin-img.on { opacity: 1; animation: breathe 26s linear infinite; }
.ipin-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  box-shadow: inset 0 0 90px rgba(0,0,0,.5), inset 0 0 0 1px rgba(255,255,255,.08);
  background: repeating-linear-gradient(0deg, rgba(0,0,0,.12) 0 1px, transparent 1px 3px);
  opacity: .8;
}
.ipin-frame .corner { position: absolute; z-index: 4; opacity: .7; }
.ipin-rail {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 16px;
  z-index: 4;
  height: 1px;
  background: rgba(233,235,238,.18);
}
.ipin-rail i {
  display: block;
  height: 100%;
  width: 0;
  background: rgba(233,235,238,.85);
  transition: width .3s linear;
}
.ipin-rail::after {
  content: "";
  position: absolute;
  inset: -3px 0;
  background: repeating-linear-gradient(90deg, rgba(233,235,238,.5) 0 1px, transparent 1px 20%);
  opacity: .55;
}

/* ============================================================
   05 . proof pillars
   ============================================================ */
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); }
.pillar { position: relative; z-index: 1; padding: 26px 24px 30px; }
.pillar + .pillar { border-left: 1px solid var(--wln2); }
.p-name { margin-bottom: 12px; color: #f0f1f4; font: 500 19px/1.2 'Fraunces', serif; letter-spacing: -.02em; }
.pillar p { color: var(--wdim); font-size: 14px; line-height: 1.6; font-weight: 300; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1100px) {
  .crec { width: min(440px, 44vw); }
}
@media (max-width: 900px) {
  .bhero { height: 380vh; }
  .bhero-sticky::before {
    background: linear-gradient(180deg, rgba(10,11,14,.96) 0%, rgba(10,11,14,.88) 44%, rgba(10,11,14,0) 78%);
  }
  .bhero-copy { width: calc(100% - 48px); top: 62%; }
  .bhero-turn { bottom: 76px; }
  .bhero-hint { display: none; }
  .bstage-cap.tl { display: none; }
  .cpin { height: 260vh; }
  .cstage-head { top: 88px; max-width: calc(100% - 48px); }
  .frag { width: min(132px, 36vw); }
  .frag.f1 { left: 6%;  top: 26%; }
  .frag.f2 { left: 56%; top: 24%; }
  .frag.f3 { left: 74%; top: 44%; }
  .frag.f4 { left: 60%; top: 66%; }
  .frag.f5 { left: 8%;  top: 68%; }
  .frag.f6 { left: 30%; top: 78%; }
  .frag.f7 { left: 2%;  top: 46%; }
  .frag.f8 { left: 34%; top: 30%; }
  .crec { left: 50%; top: auto; bottom: 5vh; width: min(520px, calc(100% - 32px)); transform: translateX(-50%); padding: 40px 22px 20px; }
  .crec-top { left: 22px; right: 22px; }
  /* nothing is pinned down here, so there is no dead space to pull the
     seam into and the negative margin would sit it on top of the list */
  .seam { margin-top: 0; }
  .ipin { height: auto; }
  .ipin-sticky { position: static; height: auto; padding: clamp(64px, 9vh, 100px) 0; }
  .ipin-grid { grid-template-columns: 1fr; gap: 24px; }
  .ipin-frame { order: -1; height: 42vh; margin-right: 0; }
  /* nothing is pinned here, so every row reads open */
  .istep { opacity: 1; }
  .in-d { grid-template-rows: 1fr; opacity: 1; }
  .istep .in-d p { padding-top: 8px; }
  .ipin-rail { display: none; }
  .steps, .ex-grid, .pillars { grid-template-columns: 1fr; }
  .step + .step, .exq + .exq, .pillar + .pillar { border-left: 0; border-top: 1px solid var(--wln2); }
  .exq { min-height: 0; }
}
@media (max-width: 720px) {
  .bhero { height: 320vh; }
  .bstage-cap.br { display: none; }
}

/* The fragments are placed by percentage but sized in pixels, so the rightmost
   one walks off the screen as the viewport narrows: f3 at left:74% plus a
   132px card needs 507px to fit, and every phone is narrower than that. The
   others clear it. They are meant to pile up and overlap, but one sliced flat
   by the viewport edge while its neighbours sit whole reads as a bug rather
   than as composition, so f3 comes inboard where the arithmetic works down to
   the narrowest phones. */
@media (max-width: 520px) {
  .frag.f3 { left: 62%; }
}

/* ============================================================
   Reduced motion: everything renders finished, nothing moves
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .bhero { height: 100vh; }
  .bhero-sticky { position: relative; }
  .bhero-copy { --out: 0; --in: 1; width: min(400px, 34vw); }
  .bhero-turn, .bhero-hint { display: none; }
  .bstage canvas { display: none; }
  .cpin { height: auto; }
  .cpin-sticky { position: relative; height: auto; min-height: 100vh; }
  .frag { opacity: .3; }
  .crec { opacity: 1; transition: none; }
  .crec-claim { opacity: 1; transform: none; transition: none; }
  .crec-cites .cite-chip { opacity: 1; transform: none; }
  .crec-conf { opacity: 1; }
  .crec-refs li { opacity: 1; transform: none; }
  .ask-caret, .bhero-hint::after { animation: none; }
  .crec, .crec-cites .cite-chip { transition: none !important; }
}
