/* ============================================================
   MATTERA v3 · JS-driven animation stages
   ============================================================
   EXTRACTED VERBATIM from assets/mattera-v2-sections.css (v2).
   These blocks style the six stages that assets/v3/v3.js animates:
   build, packet dossier, red-team, exposure gauge, deadlines clock,
   action plan, and the "ask the record" scene.

   They are reused rather than rewritten because they contain zero
   hardcoded colours — every value is a CSS custom property. The alias
   layer below re-points v2's token names at v3's tone tokens, so these
   stages render correctly on paper-white AND inside .tone-dark with no
   edits to the geometry or timing.

   Layout/chrome for the surrounding sections is NOT here — that is
   v3-sections.css, written fresh for the light editorial direction.
   ============================================================ */

/* ---------- v2 -> v3 token alias layer ----------
   v2's palette names described a navy canvas ("cream" ink on "green"
   paper). v3 keeps the same ROLES under tone-neutral names. Aliasing
   here (rather than renaming inside the extracted CSS) keeps the blocks
   below diff-able against v2 if they ever need to be re-synced.

   CRITICAL: this selector must list EVERY scope that re-points --ink/--paper.
   A custom property containing var() is resolved at the element where it is
   DECLARED, not where it is used — so "--cream: var(--ink)" on :root bakes in
   the light-mode ink and descendants inherit that fixed dark value. Omitting
   .surface-blue here is exactly what put black text on the blue cards. */
:root, .tone-dark, .surface-blue {
  --cream:       var(--ink);
  --cream-2:     var(--ink-2);
  --sage:        var(--ink-3);
  --sage-dim:    var(--ink-4);
  --green:       var(--paper);
  --green-deep:  var(--paper-3);
  --green-soft:  var(--paper-2);
  --green-line:  var(--line);
  --serif:       var(--display);
}

/* ===== [v2 sections.css:83-246] showcase, glass cards, build, red-team, exposure, deadlines, action plan ===== */
/* ========== Showcase: glass cards + Build/Red-team micro-animations ========== */

/* [v3] v2's version of this was a GLASS panel: a translucent cream wash plus
   backdrop-filter, which only works because it floated over v2's navy WebGL
   canvas. On paper the same rule brightens the white behind it into a flat
   grey and, worse, its background beat .surface-blue in the cascade (this
   file loads after v3.css). v3 gives these cards a real textured blue surface
   instead, so the glass treatment is dropped here rather than fought later. */
.glass-card {
  position: relative;
  border-radius: 0;
  overflow: hidden;
}


/* The six verdict rows read as SMOOTH blue over the grainy ground. Their base
   fill is a translucent .025 ink wash — a window, which is right on a flat
   gradient but wrong over the glass texture: the grain showed through inside
   every card. This solid is the wash composited onto the island gradient at
   the rows' band (#22406a mid + 2.5% of 221,232,248), so the cards keep the
   exact tone they had pre-texture while now occluding the canvas behind them.
   Scoped to .caps-viz — the only place the glass layer exists. */
.caps-viz .rt-row { background: #254269; }

/* Fluted-glass layer on the four capability panels. z-index 0: above the
   island's gradient and its ::before noise (z-index -1 inside the isolated
   card), below .show-stage (z-index 1) — texture on the ground, never on the
   graphics. Opacity-gated on mount like every other shader layer. */
.stage-glass {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity .6s var(--ease);
}
.stage-glass.is-on { opacity: 1; }

/* Solution ("The packet") section head — wider than the shared 800px default so the
   H2 sits on one line; the .lead paragraph keeps its own read below (unaffected). */
.solution .sec-head { max-width: 1100px; }

/* 2-column showcase layout (rollups-style: label/copy above each card) */
.show-grid { margin-top: clamp(48px, 6vw, 84px); display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 56px); align-items: start; }
.show-col { display: flex; flex-direction: column; }
.show-eyebrow { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ember); margin-bottom: 14px; }
.show-label { font-family: var(--sans); font-size: clamp(20px, 2vw, 27px); font-weight: 500;
  letter-spacing: -.01em; line-height: 1.14; color: var(--cream); margin: 0 0 12px; }
.show-blurb { margin: 0 0 clamp(22px, 2.4vw, 30px); font-size: 14.5px; line-height: 1.6;
  color: var(--sage); max-width: 42ch; }
/* Reeled back to a fixed shared measure: the exact width at which 02 wraps right
   after "population," — applied identically to both blurbs. */
.solution .show-col:first-child .show-blurb { max-width: 390px; }
.solution .show-col:last-child .show-blurb { max-width: 411px; }
.show-stage { position: relative; z-index: 1; aspect-ratio: 16 / 9; padding: clamp(18px, 2.2vw, 26px);
  display: flex; flex-direction: column;
  /* v3: --warn is inherited from the active tone (see v3.css) rather than
     re-scoped here, so gap flags stay legible on paper AND on dark. */ }

/* ----- Build card — stepped records feed → 5-line pulse network → logo node → live packet ----- */
.bld-sys { position: relative; flex: 1; min-height: 0; }
/* stepped records feed (left): rows snap one notch per beat, depth-faded top + bottom */
.bld-feed { position: absolute; left: 0; top: 0; bottom: 0; width: 29%; z-index: 2; overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 92%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 92%, transparent 100%); }
.bld-feed-track { display: flex; flex-direction: column; will-change: transform; }
.bld-rec { box-sizing: border-box; height: var(--recH, 44px); flex: 0 0 auto;
  /* minmax(0,1fr) for the same reason as .rt-row: a bare 1fr floors at the
     track's min-content. The ellipsis on .bld-rec-n cannot save it, because the
     grid item is the unstyled <span> WRAPPING the label and its meta line, and
     that wrapper has no overflow of its own — so its automatic minimum stays at
     the widest nowrap child. Measured at 488px: a 97px label holding open a
     71px slot, running the text out to the card's border ("Meal-period policy"
     reading as "Meal-period pol"). A zero floor lets the label ellipsize inside
     the card the way it was always meant to. */
  display: grid; grid-template-columns: 16px minmax(0, 1fr); align-items: center; gap: 9px;
  border: 1px solid var(--line); background: rgba(221,232,248,.025); padding: 0 9px; }
.bld-rec-ic { width: 16px; height: 16px; color: var(--sage); }
.bld-rec-ic svg { width: 100%; height: 100%; display: block; }
.bld-rec-n { display: block; font-family: var(--mono); font-size: clamp(9px,1.1vw,10.5px); color: var(--cream-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bld-rec-m { display: block; font-family: var(--mono); font-size: clamp(7.5px,.95vw,9px); color: var(--sage-dim); white-space: nowrap; margin-top: 1px; }
/* connector network (svg overlay): fan-in curves + tight parallel bundle + traveling dots + logo node */
.bld-net { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.bld-link { fill: none; stroke: rgba(221,232,248,.13); stroke-width: 1; vector-effect: non-scaling-stroke; }
.bld-glow  { fill: none; stroke: rgba(221,232,248,1); stroke-width: 1.5; stroke-linecap: butt; }
.bld-node { position: absolute; z-index: 3; pointer-events: none; box-sizing: border-box;
  display: grid; place-items: center; transform-origin: center; will-change: transform;
  border: 1px solid rgba(221,232,248,.26); background: #1a2f4d;
  -webkit-backdrop-filter: none; backdrop-filter: none; }
.bld-node .bld-logo-m { width: 74%; height: auto; display: block; }
.bld-logo-m polygon { fill: var(--cream); }
/* packet (right): live counters + coverage ring */
.bld-out { position: absolute; right: 0; top: 2px; bottom: 2px; width: 41%; z-index: 2;
  border: 1px solid var(--line); background: rgba(221,232,248,.03); padding: clamp(11px,1.5vw,15px);
  display: flex; flex-direction: column; }
.bld-out-h { font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--sage); margin-bottom: clamp(8px,1.3vw,12px); }
.bld-stat { display: flex; justify-content: space-between; align-items: baseline; padding: clamp(4px,.7vw,6px) 0; border-top: 1px solid var(--line-soft); }
.bld-stat:first-of-type { border-top: none; }
.bld-stat-l { font-family: var(--mono); font-size: clamp(8.5px,1vw,10px); color: var(--sage); }
.bld-stat-v { font-family: var(--mono); font-size: clamp(11px,1.5vw,14.5px); color: var(--cream); }
.bld-gauge { margin-top: auto; padding-top: clamp(8px,1.3vw,12px); display: flex; align-items: center; gap: 12px; }
.bld-gauge svg { width: clamp(42px,6.4vw,56px); height: clamp(42px,6.4vw,56px); flex-shrink: 0; transform: rotate(-90deg); }
.bld-gtrack { fill: none; stroke: rgba(221,232,248,.10); stroke-width: 3.5; }
.bld-gfill { fill: none; stroke: var(--ember); stroke-width: 3.5; stroke-linecap: round; }
.bld-gauge-tx .v { display: block; font-family: var(--mono); font-size: clamp(14px,1.9vw,18px); color: var(--cream); }
.bld-gauge-tx .l { display: block; font-family: var(--mono); font-size: 8.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--sage); margin-top: 2px; }

/* ----- Animation B: red-team — a stable "defensibility board"; everything laid out, only soft ambient motion ----- */
.rt-sys { position: relative; flex: 1; min-height: 0; display: flex; align-items: center; gap: clamp(14px,3vw,30px); }

.rt-ledger { position: relative; flex: 1.55; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: clamp(7px,1.4vw,12px); }
.rt-grp { display: flex; flex-direction: column; gap: clamp(7px,1.1vw,10px); }
.rt-grp-h { display: flex; align-items: baseline; gap: 7px; }
.rt-grp-l { font-family: var(--mono); font-size: clamp(8.5px,1.05vw,10px); letter-spacing: .14em; text-transform: uppercase; }
.rt-grp-l--ok  { color: var(--ember); }
.rt-grp-l--gap { color: var(--warn); }
.rt-grp-n { font-family: var(--mono); font-size: clamp(9px,1.1vw,10.5px); color: var(--sage); }

/* minmax(0,1fr), never a bare 1fr. `1fr` is shorthand for minmax(AUTO,1fr),
   and that auto floor is the content's min-content width — which for the
   nowrap statute number is the whole string. Once the row got narrower than
   20 + 68 + 46 + gaps the middle track simply refused to give, the grid grew
   past its own border box, and the confidence bar was pushed 16px out through
   the right edge of the card (visible on any phone). A zero floor lets the
   track yield, and the ellipsis on .rt-n below absorbs the difference. */
.rt-row { box-sizing: border-box; display: grid; grid-template-columns: 20px minmax(0,1fr) clamp(46px,7vw,72px); align-items: center; gap: 10px;
  border: 1px solid var(--line); background: rgba(var(--ink-rgb),.025); padding: clamp(4px,0.9vw,7px) 9px;
  box-shadow: inset 3px 0 0 var(--line), 7px 7px 0 rgba(var(--shadow-rgb),.33); }   /* verdict accent (left) + dry offset shadow */
.rt-row.is-ok  { box-shadow: inset 3px 0 0 var(--ember), 7px 7px 0 rgba(var(--shadow-rgb),.33); }
.rt-row.is-gap { box-shadow: inset 3px 0 0 var(--warn),  7px 7px 0 rgba(var(--shadow-rgb),.33); }
.rt-mark { display: flex; align-items: center; justify-content: center; }
.rt-mark svg { width: 15px; height: 15px; display: block; }
.rt-row.is-ok  .rt-mark { color: var(--ember); }
.rt-row.is-gap .rt-mark { color: var(--warn); }
.rt-n { display: block; font-family: var(--mono); font-size: clamp(9px,1.1vw,10.5px); line-height: 1.35; color: var(--cream-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rt-m { display: block; font-family: var(--mono); font-size: clamp(7.5px,.95vw,9px); line-height: 1.35; color: var(--sage-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.rt-bar { position: relative; height: 3px; background: rgba(var(--ink-rgb),.1); overflow: hidden; }
.rt-bar-f { position: absolute; left: 0; top: 0; bottom: 0; }
.rt-row.is-ok  .rt-bar-f { background: var(--ember); }
.rt-row.is-gap .rt-bar-f { background: var(--warn); }

.rt-sweep { display: none; }   /* scanning sheen removed — the board is a still visual now */

.rt-panel { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; }
.rt-ring-wrap { position: relative; display: grid; place-items: center; }
.rt-ring { width: clamp(72px,12vw,104px); height: clamp(72px,12vw,104px); transform: rotate(-90deg); overflow: visible; }
.rt-ring-t   { fill: none; stroke: var(--line);  stroke-width: 4; }
.rt-ring-ok  { fill: none; stroke: var(--ember); stroke-width: 4; }
.rt-ring-gap { fill: none; stroke: var(--warn);  stroke-width: 4; opacity: .7; }
.rt-ring-v { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); font-family: var(--mono); font-size: clamp(16px,2.6vw,23px); color: var(--cream); line-height: 1; }
.rt-ring-v i { font-style: normal; font-size: .55em; color: var(--sage); margin-left: 1px; }
.rt-ring-cap { font-family: var(--mono); font-size: clamp(8px,1vw,9.5px); letter-spacing: .14em; text-transform: uppercase; color: var(--sage); }
.rt-sum { font-family: var(--mono); font-size: clamp(8.5px,1.05vw,10px); color: var(--sage); margin-top: 2px; }
.rt-sum b { color: var(--cream-2); font-weight: 400; }
.rt-sum b.rt-sum-gap { color: var(--warn); }
.rt-sum span { color: var(--line); margin: 0 2px; }

/* ---------- Exposure card (02) — semicircular min–max gauge: square-tick arc, green→amber sweep, dry offset shadow ---------- */
.exp-sys { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: clamp(12px, 2.2vh, 22px); }
.exp-gauge { width: 100%; max-width: clamp(300px, 40vw, 430px); height: auto; display: block; overflow: visible; }
.exp-ends { width: 100%; max-width: clamp(300px, 40vw, 430px); box-sizing: border-box; display: flex; justify-content: space-between; align-items: flex-start; padding: 0 6px; }
.exp-end--max { text-align: right; }
.exp-v { font-family: var(--sans); font-size: clamp(20px,2.5vw,27px); font-weight: 500; letter-spacing: .01em; line-height: 1; color: var(--cream); }
.exp-l { font-family: var(--mono); font-size: clamp(8.5px,1.05vw,10px); letter-spacing: .16em; text-transform: uppercase; margin-top: 7px; }
.exp-l--min { color: var(--ember); }
.exp-l--max { color: var(--warn); }

/* ---------- Deadlines card (03) — analog clock, cloned from the Problem section.
   For continuity with 01/02 the dry block-shadow is applied UNIFORMLY across the dial
   markers — both the numerals AND the hour dots — at the same hard, equal down-right offset
   (rgba(6,11,20,.5), 0 blur, scaled per element), so the depth reads as one cohesive
   treatment instead of one element popping. Numeral brightness pulled back so nothing
   out-shines the rest; the rotating hands + central starburst stay flat. ---------- */
.dl-clock { position: relative; width: 100%; max-width: clamp(300px, 44vw, 440px); aspect-ratio: 300 / 215; margin: auto; }
/* numerals 12/3/6/9 take the common 01/02 green (--ember), with the dry offset shadow */
.dl-clock .clock-num { fill: var(--ember); stroke: var(--ember); opacity: 0.95; filter: drop-shadow(2.5px 2.5px 0 rgba(var(--shadow-rgb),.5)); }
/* dots filled with the exact 01-card border colour (--line, rgba(221,232,248,.16)); shadow kept */
.dl-clock .clock-dot { fill: var(--line); opacity: 1; filter: drop-shadow(2px 2px 0 rgba(var(--shadow-rgb),.5)); }
.dl-clock .clock-starburst { opacity: 0.25; }
.dl-clock .clock-svg__hand--minute, .dl-clock .clock-svg__hand--hour { opacity: 0.55; }
.dl-clock .clock-svg__hand--second rect { fill: var(--warn); }

/* ---------- Action Plan card (04) — the prioritized next-steps list. Four action
   rows in the Validate board's exact row language: the same solid row tone over the
   glass (#254269, see .caps-viz .rt-row), the inset accent edge + dry 7/7 block-shadow,
   mono type. Done rows wear ember, open rows stay neutral; numbers carry the priority. ---------- */
.ap-sys { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }
.ap-list { width: 100%; max-width: clamp(320px, 44vw, 470px); display: flex; flex-direction: column; gap: clamp(9px,1.6vw,13px); }
.ap-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2px; }
.ap-h-l { font-family: var(--mono); font-size: clamp(8.5px,1.05vw,10px); letter-spacing: .14em; text-transform: uppercase; color: var(--sage); }
.ap-h-n { font-family: var(--mono); font-size: clamp(8.5px,1.05vw,10px); color: var(--sage); }
.ap-h-n b { color: var(--cream-2); font-weight: 400; }
.ap-row { box-sizing: border-box; display: grid; grid-template-columns: 20px auto 1fr auto; align-items: center; gap: 10px;
  border: 1px solid var(--line); background: #254269; padding: clamp(8px,1.3vw,11px) 11px; }
.ap-row.is-done { box-shadow: inset 3px 0 0 var(--ember), 7px 7px 0 rgba(var(--shadow-rgb),.33); }
/* open = NEUTRAL, not warn: an open step is simply "not yet", not a defect — amber
   here would echo the Validate board's flagged rows and read as something wrong. */
.ap-row.is-open { box-shadow: inset 3px 0 0 var(--line-strong), 7px 7px 0 rgba(var(--shadow-rgb),.33); }
.ap-mark { display: flex; align-items: center; justify-content: center; }
.ap-mark svg { width: 15px; height: 15px; display: block; }
.ap-row.is-done .ap-mark { color: var(--ember); }
.ap-row.is-open .ap-mark { color: var(--sage); }
.ap-n { font-family: var(--mono); font-size: clamp(7.5px,.95vw,9px); color: var(--sage-dim); }
.ap-t { font-family: var(--mono); font-size: clamp(9px,1.1vw,10.5px); line-height: 1.35; color: var(--cream-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ap-st { font-family: var(--mono); font-size: clamp(7.5px,.95vw,9px); letter-spacing: .14em; text-transform: uppercase; }
.ap-row.is-done .ap-st { color: var(--ember); }
.ap-row.is-open .ap-st { color: var(--sage); }
/* ≤480px: the status word yields so the full action labels never ellipsize — the
   checkbox + accent edge already carry the state (the Validate rows' convention). */
@media (max-width: 480px) { .ap-st { display: none; } .ap-row { gap: 7px; padding-left: 9px; padding-right: 9px; } }

/* Showcase responsive */
/* The `@media (max-width: 1080px) { .show-grid { grid-template-columns: 1fr } }`
   that used to sit here was dead code: v3-sections.css declares `.show-grid`
   with two columns at the top level and loads after this file, so a later rule
   of equal specificity won at every width and this one never applied. The
   showcase's one-column breakpoint now lives in that file, next to the rule it
   has to beat, at the width where two columns actually measures clean. */
@media (max-width: 760px)  { .show-stage { aspect-ratio: 3 / 2; } .show-blurb { max-width: none; } }

/* .chip is shared vocabulary (proof band, packet chips) — kept when the
   Features section was removed. */
.chip { font-family: var(--mono); font-size: 11px; letter-spacing: .02em; color: var(--cream-2); border: 1px solid var(--line); border-radius: 0; padding: 4px 9px; white-space: nowrap; }



/* ===== [v2 sections.css:23-49] clock face base =====
   The deadlines card's numerals are set in Michroma — v2's geometric display
   face. Without this block the <text> nodes fall back to a plain system font
   and the clock reads as a bare wireframe rather than an instrument. Michroma
   is carried into v3's font stack for this one component. ===== */
.clock-face-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.clock-num {
  font-family: 'Michroma', 'Michroma Fallback', var(--sans);
  font-weight: 400;
  font-size: 29px;
  fill: var(--ink-3);
  stroke: var(--ink-3);
  stroke-width: 1.2;
  paint-order: stroke fill;
}

.clock-starburst { filter: brightness(0); opacity: 0.35; }
.clock-dot       { fill: var(--ink-3); opacity: 0.45; }
.clock-num       { opacity: 0.55; }
.clock-svg__hand--minute path,
.clock-svg__hand--hour path { fill: var(--paper); }

/* ===== [v2 sections.css:509-545] capabilities sticky-stack mechanics ===== */
/* ---------- Capabilities — sticky-stack feature animations (left rail + covering cards) ---------- */
/* Borders live on the CARDS only (full box). The rail carries no dividers, and there is no
   line above the menu area — just the boxed cards, with a short centred active accent. */
.caps { --caps-rail-w: clamp(225px, 25vw, 330px); }   /* ~1.5x wider left menu; the right content area slims to match */
.caps .sec-head { margin-bottom: clamp(22px, 3.5vw, 44px); padding-left: var(--caps-rail-w); max-width: clamp(720px, 84vw, 1340px); }   /* align to where the cards start, with room so the heading/subtext don't squash */
.caps-body { display: grid; grid-template-columns: var(--caps-rail-w) minmax(0, 1fr); align-items: start; }

.caps-rail { position: sticky; top: clamp(100px, 33vh, 330px); align-self: start; display: flex; flex-direction: column; padding: 6px 0; }   /* pinned a little below the top (upper-third), not flush under the nav */
.caps-tab { display: flex; align-items: baseline; gap: 9px; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font-family: var(--mono); font-size: 13px; letter-spacing: .02em; color: var(--sage); padding: 9px 0;
  transition: color .25s var(--ease); }
.caps-tab-n { font-size: 10.5px; color: var(--sage-dim); transition: color .25s var(--ease); }
.caps-tab:hover { color: var(--cream-2); }
.caps-tab.is-active { color: var(--cream); }
.caps-tab.is-active .caps-tab-n { color: var(--ember); }

.caps-cards { position: relative; min-width: 0; }
.caps-card { scroll-margin-top: 76px; box-sizing: border-box; min-height: min(78vh, 640px);
  border: 1px solid var(--line); display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  align-items: center; gap: clamp(20px, 3vw, 46px); padding: clamp(22px,3vw,40px) clamp(20px,2.4vw,38px); }
/* The cards stack flush (no gap, no margin), so each pair's bottom + top
   border abutted into a 2px rule while the outer edges stayed 1px — measured
   2px at all three junctions. Collapsing the top border on every card after
   the first makes every horizontal line in the stack exactly 1px, and leaves
   the group's outer frame intact. */
.caps-card + .caps-card { border-top: 0; }

.caps-copy { min-width: 0; order: 2; }   /* text on the right */
.caps-copy .show-label { margin-top: 6px; }
.caps-viz { min-width: 0; order: 1; }    /* graphic on the left */
/* [v3] v2 stripped the container here because the graphic sat straight on the
   navy canvas. v3's page is white, so these need the same blue panel the
   Assemble/Inspect cards get — and this rule (0,2,0) was silently outbidding
   .surface-blue (0,1,0), leaving the cards at almost the section colour.
   Background handed back to .surface-blue; overflow clipped to the panel now
   that there IS a panel edge to respect. */
.caps-viz .glass-card { overflow: hidden; }
.caps-viz .show-stage { aspect-ratio: auto; height: clamp(360px, 48vh, 460px); }                                     /* use the available height so the graphic isn't clipped */

.caps-ph { display: flex; align-items: center; justify-content: center; }
.caps-ph span { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--sage-dim); }

@media (max-width: 900px) {
  .caps .sec-head { padding-left: 0; }
  .caps-body { grid-template-columns: 1fr; }
  .caps-card { position: static; min-height: 0; grid-template-columns: 1fr; gap: 18px; }
  /* The lying-down rail itself is owned by v3-sections.css, which loads after
     this file and turns it into an equal-track grid. The wrapping-flex version
     that used to live here is gone rather than left to be overridden. */
}

/* ---- Validate board (01) on phones ----
   The board is a side-by-side instrument: a ledger of verdict rows next to a
   defensibility ring, split 1.55 / 1. That split is fine down to about 450px
   of viewport and then falls apart — at 393px the ledger resolves to 148px, of
   which the fixed columns and gaps claim 106, leaving the statute number and
   its theory to fight over ~42px. The rows do not just crowd, they burst (see
   the minmax note above), and the ring's summary line wraps back across them.

   Stacked, both halves get the width they need: the ring becomes a compact
   stat strip along the top — ring, then DEFENSIBLE over its tally, laid out as
   a small 2-col grid — and the ledger takes the full panel underneath. */
@media (max-width: 520px) {
  .rt-sys { flex-direction: column; align-items: stretch; justify-content: center; gap: 13px; }
  .rt-panel {
    order: -1;
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 12px; row-gap: 1px;
    align-items: center;
    padding-bottom: 11px;
    border-bottom: 1px solid var(--line-soft);
  }
  .rt-ring-wrap { grid-row: 1 / 3; }
  .rt-ring { width: 54px; height: 54px; }
  .rt-ring-v { font-size: 15px; }
  .rt-ring-cap { grid-column: 2; align-self: end;   justify-self: start; }
  .rt-sum     { grid-column: 2; align-self: start; justify-self: start; margin-top: 0; }
  /* flex:0 0 auto, not the 1.55 above: in a COLUMN the flex-basis:0 in that
     shorthand governs height, so the ledger would be sized by leftover space
     rather than by its rows. */
  .rt-ledger { flex: 0 0 auto; }

  /* ---- and the panel is sized by its content, not the other way round ----
     The capability stage takes `height: clamp(360px, 48vh, 460px)`, which is a
     VIEWPORT-HEIGHT measure — so on a short phone (375x667, an SE) it floors at
     360px however much is inside it. Stacked, the Validate board wants 341px of
     content in the 324px that leaves, and the bottom of the ledger was being
     cut off by the card's overflow. The stage grows to whatever it holds, with
     min-height keeping the sparser graphics (the clock is only 132px) from
     collapsing into a letterbox.

     `flex: 0 0 auto` on the systems is what makes `height: auto` mean anything
     here: they carry `flex: 1`, i.e. flex-basis 0, so an auto-height column
     would resolve their hypothetical height to 0 and the stage would sit at its
     min-height while the content spilled out exactly as before. Reset the basis
     and the stage is sized by its contents, which is the only version of this
     that cannot break again. justify-content centres whatever is shorter. */
  .caps-viz .show-stage {
    height: auto;
    min-height: clamp(330px, 44vh, 400px);
    justify-content: center;
  }
  .caps-viz .show-stage > * { flex: 0 0 auto; }
}

/* ---- build stage: the packet panel needs room to stand up ----
   Both solution stages are poured into a 3:2 box, which is a fine ratio until
   the box gets small: at 320px the stage is 262x175, and the packet readout
   pinned down its right-hand 41% (a header, three counters and the coverage
   ring) needs about 226px of that 139px interior. The ring and its "Coverage"
   label were running 51px out through the bottom of the card. The type inside
   is already at the floor of its clamps, so the panel cannot compress further —
   the box has to give instead. A flat height below 520px, chosen to meet 3:2
   almost exactly where it takes over (a 519px viewport would compute 309px), so
   nothing jumps as the breakpoint passes. */
@media (max-width: 520px) {
  #build-stage { aspect-ratio: auto; height: 300px; }
}

/* The coverage readout sets its ring BESIDE the percentage, which needs about
   114px. The packet panel is a fixed 41% of the stage, so that row stops
   fitting at around 420px of viewport and then quietly runs out through the
   panel's padding — 3px over on a 393px phone, 11px at 375, 29px at 320, the
   label crossing the panel edge every time. The ring's own width is the floor
   here (the type is already at its clamp minimum), so the row becomes a stack
   and the readout needs only that. */
@media (max-width: 420px) {
  .bld-gauge { flex-direction: column; align-items: flex-start; gap: 7px; }
}


/* ===== [v2 sections.css:546-573] solution card 2 — packet dossier ===== */
/* ---------- Solution card 2: "inside the packet" dossier — one allegation + source-linked records ---------- */
.pk-sys { position: relative; flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); align-items: center; gap: clamp(26px,6vw,68px); }
.pk-net { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; overflow: visible; }
.pk-link { stroke: rgba(221,232,248,.14); stroke-width: 1; vector-effect: non-scaling-stroke; }
.pk-pulse { stroke: rgba(221,232,248,.45); stroke-width: 1.6; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.pk-hub { fill: rgba(221,232,248,.7); }

.pk-claim { position: relative; z-index: 1; box-sizing: border-box; border: 1px solid var(--line); border-left: 2px solid rgba(221,232,248,.4);
  background: rgba(221,232,248,.03); padding: clamp(12px,1.8vw,18px); display: flex; flex-direction: column; }
.pk-head { display: flex; align-items: baseline; gap: 9px; }
.pk-statute { font-family: var(--mono); font-size: clamp(17px,2.3vw,22px); color: var(--cream); line-height: 1; }
.pk-theme { font-family: var(--mono); font-size: clamp(11px,1.3vw,13px); color: var(--sage); }
.pk-theory { font-family: var(--mono); font-size: clamp(10px,1.1vw,11.5px); color: var(--sage-dim); line-height: 1.45; margin-top: 9px; }
.pk-fields { display: flex; flex-direction: column; gap: clamp(6px,1vw,9px); margin-top: clamp(12px,1.7vw,16px); }
.pk-field { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.pk-field-l { font-family: var(--mono); font-size: clamp(8.5px,1vw,10px); letter-spacing: .1em; text-transform: uppercase; color: var(--sage-dim); }
.pk-field-v { font-family: var(--mono); font-size: clamp(10.5px,1.15vw,12.5px); color: var(--cream-2); white-space: nowrap; }

.pk-ev { position: relative; z-index: 1; display: flex; flex-direction: column; gap: clamp(5px,0.9vw,8px); }
.pk-chip { box-sizing: border-box; display: flex; align-items: center; gap: 9px; border: 1px solid var(--line); background: rgba(221,232,248,.025); padding: clamp(6px,1vw,9px) 11px; will-change: opacity; }
.pk-chip-ic { width: 15px; height: 15px; color: var(--sage); flex: 0 0 auto; }
.pk-chip-ic svg { width: 100%; height: 100%; display: block; }
.pk-chip-l { font-family: var(--mono); font-size: clamp(9.5px,1.1vw,11px); color: var(--cream-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 760px) {
  .pk-sys { grid-template-columns: 1fr; gap: 16px; }
  /* The connector network is a TWO-COLUMN idea: a hub parked just off the
     claim card's right edge, with one line reaching to the left edge of each
     record chip in the neighbouring column. Stacked, those two anchors still
     resolve but their geometry no longer means anything — the hub lands off
     the top-right corner (measured: cx=302 inside a 299px box) while every
     line still starts at x=0, so all five rake back across the chips and over
     each other. The wiring is a desktop grace note, and one column leaves
     nowhere honest to redraw it: full-width chips have no margin for a spine.
     It stands down, and the two groups read as claim-then-evidence. */
  .pk-net { display: none; }

  /* Stacked, the dossier is also TALLER than the 3:2 box it is being poured
     into — at 393px it wants 342px of content inside a 187px stage. The card
     clips its overflow, so the bottom of the dossier was being cut off
     silently: four of the five record chips simply were not on the page. The
     evidence half of an evidence-backed graphic, gone. Sized to its content
     instead. Its sibling build stage keeps the ratio deliberately — that one
     positions every part absolutely and needs a resolved height to sit in. */
  #packet-stage { aspect-ratio: auto; }
  #packet-stage .pk-sys { flex: 0 0 auto; }
}


/* ===== [v2 sections.css:574-689] ask the record — scroll-pinned scene ===== */
/* ================= ASK THE RECORD (scroll-pinned scene) =================
   Tall track + sticky 100vh stage; every visual state is a pure function of
   pin progress (driven from mattera.js), so scrubbing back replays in reverse. */
.ask { padding-block: 0; }
.ask-track { height: 340vh; }
.ask-stage { position: sticky; top: 0; height: 100vh; overflow: hidden;
  /* v3: --warn inherited from the active tone — see note on .show-stage. */ }

/* scattered record field — inset to the frame rails so no card bleeds the gutter */
.ask-field { position: absolute; top: 0; bottom: 0; left: var(--frame); right: var(--frame); z-index: 1; }
.ask-doc { position: absolute; will-change: transform, opacity; }
.ask-doc-sh { filter: drop-shadow(7px 7px 0 rgba(var(--shadow-rgb), .33)); }   /* follows the dog-ear silhouette */
.ask-doc-card { width: 200px; height: 270px; position: relative; overflow: hidden;
  /* a hair LIGHTER than the page (paper catching light), never darker — the
     dark-slab reading is the failure mode. ~5.5% cream over --page-bg. */
  background: var(--paper-3); border: 1px solid var(--line-strong);
  clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%);
  display: flex; flex-direction: column; }
.ad-fold { position: absolute; top: 0; right: 0; width: 16px; height: 16px; pointer-events: none; }
.ad-fold path { fill: rgba(var(--ink-rgb), .14); }
.ask-doc-cap { margin-top: 12px; font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--cream-2); display: flex; flex-direction: column; gap: 3px; }
.ask-doc-cap span { color: var(--sage-dim); letter-spacing: .06em; text-transform: none; }
.ask-doc-cap { display: none; }   /* trial: captions hidden — delete this line to restore */

/* skeleton vocabulary — 1:1 geometry port of the designed doc-intel (.di-*)
   wireframes. The originals were removed with the doc-intel section; THESE
   RULES ARE NOW THE CANONICAL COPY of those designs — preserve the geometry
   (3px lines, 6px bars, paddings, table structures) exactly. */
.ad-hdr { padding: 12px; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.ad-sq  { width: 10px; height: 10px; background: rgba(var(--ink-rgb), .21); border-radius: 1px; flex-shrink: 0; }
.ad-rect { width: 28px; height: 10px; border: 1px solid rgba(var(--ink-rgb), .21); border-radius: 1px; flex-shrink: 0; }
.ad-body { padding: 0 12px 12px; display: flex; flex-direction: column; gap: 6px; flex: 1; overflow: hidden; }
.ad-l   { flex-shrink: 0; height: 3px; background: rgba(var(--ink-rgb), .19); border-radius: 0.5px; }
.ad-b   { flex-shrink: 0; height: 6px; background: rgba(var(--ink-rgb), .12); border-radius: 0.5px; width: 100%; }
.ad-gap { height: 3px; flex-shrink: 0; }
.ad-hr  { height: 1px; background: rgba(var(--ink-rgb), .11); flex-shrink: 0; }
/* pdf table */
.ad-tbl { border: 1px solid rgba(var(--ink-rgb), .19); border-radius: 1px; overflow: hidden; margin-top: 6px; }
.ad-tr  { display: flex; } .ad-tr-b { border-bottom: 1px solid rgba(var(--ink-rgb), .11); }
.ad-tc  { flex: 3; padding: 5px 6px; display: flex; align-items: center; }
.ad-tc-l { flex: 2; border-right: 1px solid rgba(var(--ink-rgb), .11); }
.ad-box { border: 1px solid rgba(var(--ink-rgb), .19); border-radius: 1px; padding: 6px; display: flex; flex-direction: column; gap: 5px; flex: 1; margin-top: 6px; }
.ad-pdf-footer { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 6px; flex-shrink: 0; }
.ad-badge { width: 36px; height: 10px; background: rgba(var(--ink-rgb), .12); border-radius: 1px; }
/* spreadsheet */
.ad-grid { border: 1px solid rgba(var(--ink-rgb), .19); border-radius: 1px; overflow: hidden; flex: 1; display: flex; flex-direction: column; min-height: 0; margin-top: 4px; }
.ad-thead { display: flex; border-bottom: 1px solid rgba(var(--ink-rgb), .21); background: rgba(var(--ink-rgb), .045); flex-shrink: 0; }
.ad-chk-cell { width: 18px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-right: 1px solid rgba(var(--ink-rgb), .12); }
.ad-chk { width: 6px; height: 6px; border: 1px solid rgba(var(--ink-rgb), .19); border-radius: 0.5px; }
.ad-hcell { flex: 1; padding: 4px 3px; display: flex; align-items: center; justify-content: center; border-right: 1px solid rgba(var(--ink-rgb), .12); }
.ad-hcell-l { flex: 1.3; background: rgba(var(--ink-rgb), .07); border-right-color: rgba(var(--ink-rgb), .21); justify-content: flex-start; }
.ad-hcell-e { border-right: none; }
.ad-dr  { display: flex; flex: 1; border-bottom: 1px solid rgba(var(--ink-rgb), .08); min-height: 0; }
.ad-dc  { flex: 1; padding: 0 3px; display: flex; align-items: center; justify-content: center; border-right: 1px solid rgba(var(--ink-rgb), .08); }
.ad-dc-l { flex: 1.3; background: rgba(var(--ink-rgb), .03); border-right: 1px solid rgba(var(--ink-rgb), .12); justify-content: flex-start; }
.ad-dc-e { border-right: none; }
/* email / form */
.ad-email-body { padding: 12px; display: flex; flex-direction: column; gap: 6px; flex: 1; overflow: hidden; }
.ad-erow { display: flex; gap: 4px; align-items: center; flex-shrink: 0; }
.ad-einput { flex: 1; height: 10px; border: 1px solid rgba(var(--ink-rgb), .12); border-radius: 1px; }

/* headline in front of the pile */
.ask-head { position: absolute; left: 50%; top: 44%; transform: translate(-50%,-50%);
  z-index: 3; width: min(940px, 92%); text-align: center;
  will-change: transform, opacity; pointer-events: none; }
.ask-head .eyebrow { margin-bottom: 22px; }

/* query box + cited answer */
.ask-search { position: absolute; left: 50%; top: 39%; transform: translateX(-50%);
  z-index: 4; width: min(620px, 88%); }
.ask-box { display: flex; align-items: center; gap: 14px; height: 58px; padding: 0 18px;
  border: 1px solid var(--line-strong); background: var(--paper-2);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 7px 7px 0 rgba(var(--shadow-rgb), .33); opacity: 0; will-change: transform, opacity; }
.ask-box svg { width: 17px; height: 17px; flex-shrink: 0; color: var(--sage); }
.ask-q { font-family: var(--mono); font-size: 13.5px; letter-spacing: .01em; color: var(--cream);
  white-space: nowrap; overflow: hidden; }
.ask-caret { width: 8px; height: 17px; background: var(--cream); flex-shrink: 0; }
@media (prefers-reduced-motion: no-preference) {
  .ask-caret { animation: askBlink 1.1s steps(1) infinite; }
}
@keyframes askBlink { 50% { opacity: 0; } }
.ask-result { margin-top: 14px; border: 1px solid var(--line); background: var(--paper-2);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 7px 7px 0 rgba(var(--shadow-rgb), .33); opacity: 0; will-change: transform, opacity; }
.ask-resh, .ask-resf { display: flex; justify-content: space-between; gap: 12px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  padding: 11px 16px; }
.ask-resh { color: var(--cream-2); border-bottom: 1px solid var(--line-soft); }
.ask-resh span + span, .ask-resf span + span { color: var(--sage-dim); }
.ask-resf { color: var(--sage); border-top: 1px solid var(--line-soft);
  letter-spacing: .06em; text-transform: none; font-size: 11px; }
.ask-row { display: grid; grid-template-columns: 76px minmax(0,1fr) minmax(0,1fr) auto; align-items: center; gap: 10px;
  padding: 10px 16px 10px 19px; font-family: var(--mono); font-size: 11.5px; color: var(--cream-2);
  box-shadow: inset 3px 0 0 var(--warn); will-change: opacity; }
.ask-row + .ask-row { border-top: 1px solid var(--line-soft); }
.ask-rid { color: var(--sage); }
.ask-flag { color: var(--warn); justify-self: end; }

/* static composition (reduced motion) */
.ask-stage.is-static .ask-head { top: 20%; transform: translate(-50%,0); }
.ask-stage.is-static .ask-search { top: 42%; }
.ask-stage.is-static .ask-caret { display: none; }

@media (max-width: 900px) {
  .ask-track { height: 300vh; }
  .ask-doc:nth-child(n+6) { display: none; }
  /* cards keep their exact 200x270 wireframes; JS scales the whole card (K) */
  .ask-box { height: 52px; }
  .ask-q { font-size: 11.5px; }
  .ask-row { font-size: 10px; grid-template-columns: 62px minmax(0,1fr) minmax(0,1fr) auto; gap: 7px; }
  .ask-resh, .ask-resf { font-size: 9px; }
  .ask-resf { font-size: 10px; }
}


/* ===== [v2 sections.css:247-408] process timeline + proof terminus =====
   Structural and JS-driven (.proc-line-progress and .proc-node are
   advanced by the scroll handler in v3.js), and entirely token-driven —
   no hardcoded colours — so it carries into the dark tone unchanged.
   v3-sections.css restyles the TEXT inside the cards; the geometry is
   v2's and stays here. ===== */
/* ---------- Process (alternating timeline) ---------- */
.process { overflow: hidden; }
.proc-timeline {
  position: relative;
  margin-top: clamp(48px, 6vw, 84px);
  max-width: 1100px;
  margin-inline: auto;
}
.proc-stack {
  position: relative;
}
.proc-line {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
  transform: translateX(-50%);
}
/* the travelled segment of the spine — house green, scroll-scrubbed scaleY */
.proc-line-progress {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--ember);
  transform: translateX(-50%) scaleY(0);
  transform-origin: top center;
  pointer-events: none;
  will-change: transform;
}
.proc-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
/* Steps sit subdued until the progress line reaches their node (JS adds
   .is-on). No .reveal here — the spine owns this section's entrance. */
.proc-step {
  position: relative;
  margin-bottom: clamp(84px, 9vw, 132px);
  min-height: 64px;
  opacity: .45;
  transition: opacity .5s var(--ease);
}
.proc-step:last-child { margin-bottom: 0; }
.proc-step.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .proc-step { opacity: 1; } }
.proc-step--left {
  padding-right: calc(50% + clamp(22px, 2.6vw, 40px));
  text-align: right;
}
.proc-step--right {
  padding-left: calc(50% + clamp(22px, 2.6vw, 40px));
  text-align: left;
}
.proc-node {
  position: absolute;
  left: 50%;
  top: 4px;
  width: 9px;
  height: 9px;
  background: var(--sage-dim);
  transform: translateX(-50%);
  box-shadow: 0 0 0 4px var(--green);
  transition: background .4s var(--ease);
}
.proc-step.is-on .proc-node { background: var(--ember-bright); }
.proc-card {
  display: inline-block;
  max-width: 400px;
}
.ps-tag {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--sage);
  margin-bottom: 10px;
}
.ps-title {
  font-family: var(--sans);
  font-size: clamp(18px, 1.6vw, 25px);
  font-weight: 500;
  line-height: 1.18;
  color: var(--cream);
  margin-bottom: 10px;
  letter-spacing: -.01em;
}
.ps-body {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--sage);
  text-wrap: pretty;
}
.ps-note {
  margin-top: 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ember);
  text-transform: uppercase;
}
/* ---------- Proof standard — the spine's terminus ---------- */
.proc-proof {
  position: relative;
  margin-top: clamp(76px, 8.5vw, 116px);
  padding-top: clamp(44px, 5vw, 62px);
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
}
/* the square the spine lands on — the standard is the destination */
.proc-terminal {
  position: absolute;
  top: 0;
  left: 50%;
  width: 11px;
  height: 11px;
  background: var(--ember-bright);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 4px var(--green);
}
.pp-eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--sage);
  margin-bottom: 14px;
}
.pp-title {
  font-family: var(--sans);
  font-size: clamp(22px, 2.2vw, 30px);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.15;
  color: var(--cream);
  margin: 0 0 14px;
}
.pp-line {
  margin: 0 auto;
  font-size: 15px;
  line-height: 1.65;
  color: var(--sage);
  max-width: 58ch;
  text-wrap: pretty;
}
.pp-chips {
  margin-top: 24px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
}

/* ---- process timeline on phones: the spine moves to the left edge ----
   The alternating layout is a two-column idea. Each step reserves
   `50% + gap` of padding on one side so its card clears the centre spine, and
   on a phone that reservation costs more than half the screen: a 337px step
   was handing its card 147px, so every body paragraph broke into a ragged
   three-words-per-line column pushed against the wrong margin (and the
   right-hand steps were set right-aligned on top of it). There is no room for
   two columns here, so there is no reason to reserve one — the spine goes to
   the left edge and each card takes the full measure, which is the ordinary
   mobile timeline and reads far better than a squeezed zigzag.

   The spine is not retired: nodes still light in sequence and the green still
   travels, so the section keeps the behaviour it was designed around. */
@media (max-width: 720px) {
  .proc-line, .proc-line-progress, .proc-node, .proc-terminal { left: 4px; }
  .proc-step--left,
  .proc-step--right { padding-left: 30px; padding-right: 0; text-align: left; }
  .proc-step { margin-bottom: clamp(46px, 11vw, 74px); min-height: 0; }
  .proc-card { display: block; max-width: none; }
  /* The terminus follows the same spine, so its block squares up with the
     steps above rather than sitting centred under a left-hand rule. */
  .proc-proof { max-width: none; padding-left: 30px; text-align: left; }
  .pp-line { margin-inline: 0; }
  .pp-chips { justify-content: flex-start; }
}

