/* ==========================================================================
   UHR Advisory - one-page site (2026-07-12 revision)
   Grayscale only. Canvas #FAFAF8, ink #0A0A0A. No chromatic color anywhere.
   The pipeline card is the sole dark application surface; every other window
   is dark title-bar chrome over a white body.
   ========================================================================== */

/* ---------- Fonts (self-hosted, assets/fonts/) --------------------------- */
/* Instrument Sans and IBM Plex Mono, SIL Open Font License 1.1.
   Reserved Font Names: Instrument Sans, IBM Plex. */
@font-face {
  font-family: 'Instrument Sans';
  src: url('assets/fonts/InstrumentSans-Variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('assets/fonts/IBMPlexMono-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('assets/fonts/IBMPlexMono-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- Tokens -------------------------------------------------------- */
:root {
  /* light surfaces */
  --canvas: #FAFAF8;
  --paper:  #FFFFFF;
  --wash:   #F1F1EF;
  /* ink ladder */
  --ink:    #0A0A0A;
  --body:   #333331;
  --muted:  #666661;
  --faint:  #90908B;
  --rule:   #E4E4E0;
  --rule-2: #D2D2CE;
  --tint:   #DCDCD8;   /* light exhibit fill */
  /* the dark objects */
  --card:      #101010;
  --card-hi:   #191919;
  --card-rule: #2A2A2A;
  --card-text: #F2F2F0;
  --card-mut:  #A3A3A0;
  --card-dim:  #6E6E6A;
  /* type */
  --sans: 'Instrument Sans', -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --mono: 'IBM Plex Mono', 'SF Mono', Menlo, monospace;
  --measure: 34em;
}

/* ---------- Reset / base -------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* 69px = the sticky header (68px + 1px rule): anchor jumps land the target
   section's divider just under the frozen header (2026-07-17) */
html { scroll-behavior: smooth; scroll-padding-top: 69px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  background: var(--canvas);
  color: var(--body);
  font: 400 16px/1.6 var(--sans);
  /* tabular everywhere a figure can appear (canon: non-negotiable); prose
     with dollar amounts inherits it too — the hero subhead, stat sub-lines,
     exhibit read line, and CIM paragraphs all carry figures. Deliberate
     resets (.fin label column) and mono chrome (fixed-width digits anyway)
     still win locally. */
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg { display: block; max-width: 100%; }
a { color: var(--ink); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
/* buttons inherit the page family (2026-07-17 port, BUILD-NOTES §54): without
   this, everything inside a <button> that doesn't set its own font falls back
   to the UA's Arial — live Exhibit A's .vstep-n/.vsub shipped in Arial until
   today. FAMILY-ONLY on purpose: the generic `font: inherit` was measured and
   REJECTED (it imports body's line-height 1.6, grows Exhibit A's rail +8.4px
   and the row-1 rail +14px — a silent relayout). At (0,0,1) this correctly
   loses to every class that sets its own font (.btn, .vnav-b, .ph-chip). */
button { font-family: inherit; }
/* display leading on every heading: without this, a wrapping h2/h3 inherits
   the body's 1.6 and reads double-spaced (caught on "Start with a
   conversation.", 2026-07-12) */
h1, h2, h3 { color: var(--ink); font-weight: 600; letter-spacing: -0.02em; line-height: 1.15; }
strong { color: var(--ink); font-weight: 600; }

/* ragging (progressive enhancement; ignored where unsupported) */
h1, .stats-thesis { text-wrap: balance; }
.hero-sub, .sec-sub, .stat-d, .footer-disc p, .gap-copy p, .contact-sub { text-wrap: pretty; }
.nb { white-space: nowrap; }

.fig, td.fig, .stat-n { font-variant-numeric: tabular-nums; }

.wrap { max-width: 1160px; margin: 0 auto; padding: 0 48px; }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--paper); padding: 8px 16px; z-index: 99;
}
.skip-link:focus { left: 0; }

/* ---------- Small voices --------------------------------------------------- */
.eyebrow {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.btn {
  display: inline-block;
  background: var(--ink);
  color: var(--paper);
  font: 500 14px/1 var(--sans);
  padding: 14px 26px;
  border: 1px solid var(--ink);
  border-radius: 2px;
  letter-spacing: 0.01em;
  transition: background 0.15s ease;
}
.btn:hover { background: #2E2E2C; text-decoration: none; }

/* ---------- Header --------------------------------------------------------- */
/* frozen pane (the founder, 2026-07-17): the header rides the scroll for the whole
   page, so the nav and "Schedule a call" never leave the screen. Sticky (not
   fixed) keeps it in flow - zero layout shift, fold math untouched. z-index
   above the transformed reveal/window content, below the 99 skip-link. */
.top {
  position: sticky; top: 0; z-index: 60;
  border-bottom: 1px solid var(--rule);
  background: var(--canvas);
}
.top-inner {
  height: 68px;
  display: flex; align-items: center; justify-content: space-between;
}
.wordmark {
  /* 650/21px since 2026-07-20 (founder-picked, board option 3; was 600/16px
     at 0.34em — he rated the old mark 4/10, too recessive): reads as a
     firm's mark, keeps the wide-tracked caps identity. Bar height unchanged. */
  font: 650 21px/1 var(--sans);
  letter-spacing: 0.26em;
  color: var(--ink);
  text-indent: 0.05em; /* optically balance the tracked caps */
}
.wordmark:hover { text-decoration: none; }
.top-right { display: flex; align-items: center; gap: 34px; }
.top-nav { display: flex; gap: 26px; }
.top-nav a { font: 500 13.5px/1 var(--sans); color: var(--body); letter-spacing: 0.01em; }
/* hover rejoins the site's own link grammar (the global a:hover underline) —
   the old darken-only state was near-imperceptible (the founder, 2026-07-20).
   Bold-on-hover rejected: weight reflows the row and the nav jiggles;
   color-coding rejected: grayscale canon. */
.top-nav a:hover { color: var(--ink); }
.top .btn { padding: 11px 20px; font-size: 13px; }
/* ---------- Phone menu (2026-07-22, §89) ------------------------------------
   ≤768 the section links collapse (below); the .menu-btn takes their place
   and toggles the .mnav overlay — every section, Team, and Client Sign-in
   (moved INTO the menu, the founder's pick: the §78 bar pin existed only
   because there was no menu then). House restraint: three ink hairline bars,
   canvas overlay fixed under the 69px bar, one link per hairline row. The
   bar morph is a state change (X = "this closes"), kept instant under
   reduced motion. */
.menu-btn { display: none; }
.mnav {
  position: fixed; top: 69px; left: 0; right: 0; bottom: 0; z-index: 59;
  background: var(--canvas); overflow-y: auto;
  /* keep a stray touch-scroll inside the overlay, off the page behind */
  overscroll-behavior: contain;
}
.mnav .wrap { padding-top: 6px; }
.mnav a {
  display: block; font: 550 17px/1 var(--sans); color: var(--ink);
  letter-spacing: 0.01em; padding: 19px 0; border-bottom: 1px solid var(--rule);
}
.mnav a:hover { text-decoration: none; }
/* scroll lock on the BODY only (2026-07-22, measured): overflow:hidden on
   the root breaks position:sticky, so the header walked off-screen the
   moment the menu opened — body-level overflow still propagates to the
   viewport and locks the page, and the sticky bar keeps sticking. */
html.menu-open body { overflow: hidden; }

/* ---------- Hero ----------------------------------------------------------- */
/* --hero-pt is the hero's TOP PADDING as a token, not a literal, because the
   §107 rule `.hxwide .hero { padding-top: calc(72px + var(--hxair)/2) }` is a
   top-level (0,2,1) selector and silently outranked the (0,1,1) responsive
   override in the <=960 block — media queries add no specificity, so every
   phone and iPad-portrait width quietly took 72px instead of 52px (§108,
   measured: 72px at 820/768/390 where 52 was intended). Overriding the TOKEN
   at the breakpoint is what makes the cascade honest again, and it survives
   any future .hxwide-scoped rule; re-scoping the §107 rule into each media
   block would not. Change the value here and at the <=960 override, never in
   the calc. */
.hero { --hero-pt: 72px; padding: var(--hero-pt) 0 0; }
.hero .eyebrow { display: block; margin-bottom: 26px; }
.hero h1 {
  font-size: clamp(42px, 4.6vw, 64px);
  line-height: 1.04;
  letter-spacing: -0.025em;
  /* 14em (~896px at 64px) holds the four-line hero: the longest line,
     "Don't leave value on the table.", measures ~840px at 64px (13.1em),
     so 14em leaves a modest buffer. Em-based so it scales with the
     vw-clamped font — the fit ratio holds at every clamp size; stays inside
     the 1064px .wrap content column at 1440. Re-measure if any line changes:
     line 1 "You sell once." ~384px, line 2 "They buy for a living." ~579px,
     line 3 "We were the buyer." ~543px, line 4 ~840px at 64px. */
  max-width: 14em;
}
.hero-sub {
  margin-top: 26px;
  font-size: 19px;
  line-height: 1.55;
  color: var(--body);
  /* 2026-07-13 round 2: the band went pure track record, so the subhead
     regained the "$1M – $10M of EBITDA, roughly $5M – $100M in revenue."
     line. 2026-07-19 (the founder): the top of the range is $100M again — the round-3
     $50M back-solve assumed 20% margins on both ends and screened out
     lower-margin companies ($10M EBITDA at ~10% margin IS a $100M revenue
     company). 1024px holds the widened line on ONE row at desktop; phones wrap
     naturally within the .wrap padding, .nb keeping BOTH ranges whole.
     Re-measure the fold if this copy changes. */
  max-width: 1024px;
}
/* .hero-cta removed 2026-07-14 (T3): no hero button — the header CTA carries
   the action and the elevated band thesis owns the space below the subhead */

/* Hero entrance (2026-07-14, Option S "Snappier" — the founder's pick from the
   timing lab after two variant rounds; supersedes the 2026-07-13 three-line
   S4 spec): one-shot on load, ~4.0s for the H1, ~7.1s including the band
   thesis mirror (below). The they-vs-us arc: the two muted "them" lines rise
   from overflow-hidden masks and settle at the ANCHOR tone (permanent — the
   emphasis survives static); a 0.30em caesura separates the camps; the two
   ink "us" lines are SPOKEN word by word (line 3 "We were the buyer.", then
   line 4 "Don't leave value on the table."), and the rule draws beneath
   line 4 once the sentence finishes. Option S pacing: rises 620ms (line 2
   at 780ms), 140ms word cadence at 320ms per word (line 4 starts 280ms
   after line 3's last word — a sentence beat), pen 520ms at 3450ms → done
   ~3970ms. Base styles ARE the final frame: hidden pre-states exist only
   under .motion (flowchart grammar), so no-JS, ?static=1, and
   reduced-motion serve the finished headline — anchored lines 1-2, ink
   lines 3-4, rule drawn — and a mid-session reduced-motion flip (which
   drops .motion) snaps to it.
   The h1's 1.04 line-height clips descenders under overflow:hidden, so
   masks carry 0.12em padding-bottom pulled back with an equal negative
   margin (tops of lines 1-2 stay 1.04em apart; lines 3-4 sit one caesura
   +0.30em below — verify offsetTop deltas if this block changes). Lines
   3-4 drop overflow:hidden — their words fade/rise above the mask floor
   and must never clip.
   .hline because .hl is taken (CIM exec-summary highlights list); the
   anchor literal #52524E (82/82/78, spread 4) passes the grayscale audit
   and lives between --body and --muted. */
.hline { display: block; overflow: hidden; padding-bottom: 0.12em; margin-bottom: -0.12em; }
.hline-i { display: block; }
.hero .hline:nth-child(-n+2) .hline-i { color: #52524E; }
.hero .hline:nth-child(n+3) { overflow: visible; }
/* the caesura: the they-vs-us break between the muted setup pair and the
   ink answer pair (2026-07-14, Iteration 3 — "the break makes it better") */
.hero h1 .hline:nth-child(3) { margin-top: 0.30em; }
/* THE PEN IS A PER-LINE BACKGROUND since 2026-07-19 (iPhone overshoot fix).
   The old absolutely-positioned ::after rectangle overshot on phones: at 390px
   line 4 wraps, and a wrapped inline-block resolves shrink-to-fit to the FULL
   available width, so a left:0/right:0 bar ran far past the short last line's
   text ("…the table." underlined to the column edge). A single rectangle can
   never hug a multi-line box, so the rule is now an inline background with
   box-decoration-break: clone — each line fragment paints its own hairline
   that ends exactly at its own last character, at every breakpoint. Geometry
   matches the old pen: rule spans 0.03–0.10em below the text (padding-bottom
   0.10em seats it; inline padding adds no layout height). The draw becomes a
   background-size sweep (same 520ms curve/delay); it is a paint animation,
   but a 0.07em hairline's dirty rect is negligible for one 520ms one-shot. */
.hero-ul {
  display: inline;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding-bottom: 0.10em;
  background-image: linear-gradient(var(--ink), var(--ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.07em;
}
/* pre-states, .motion only */
.motion .hero .hline:nth-child(-n+2) .hline-i {
  transform: translateY(118%);
  transition: transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
}
.motion .hero .hw {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.35em);
  transition: opacity 320ms ease, transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* §99: the §87 phone-wrap glue made STRUCTURAL. WebKit permits line breaks
   BETWEEN inline-block word spans even across &nbsp; text (Chrome does not),
   so under .motion — where .hw is inline-block — line 4 could orphan "table."
   (reproduced in Safari 2026-07-29: 430 broke "on the / table.", 390 broke
   "on / the table."). .hw-g is a nowrap inline wrapper around the last three
   words; the entities stay as belt and braces for the plain-inline modes.
   The line-4 delay selectors below are scoped so the wrapped trio keeps its
   2770/2910/3050ms cadence — behavior identical to the ratified entrance. */
.hero-ul .hw-g { white-space: nowrap; }
.motion .hero .hero-ul {
  background-size: 0 0.07em;
  transition: background-size 520ms cubic-bezier(0.16, 1, 0.3, 1) 3450ms;
}
/* Safari/iOS compositor promotion (2026-07-19 lag fix): Chrome auto-layerizes
   these transform/opacity transitions; Safari only promotes when told to, and
   without the hint ~22 staggered transforms paint on a main thread that is
   busiest exactly at first load — the reported "slow-motion" entrance. Scoped
   to .motion and released via .is-set (site.js, ~7.4s) so the layers never
   persist past the one-shot. */
.motion .hero h1:not(.is-set) .hline-i,
.motion .stats-thesis:not(.is-set) .th-i { will-change: transform; }
.motion .hero h1:not(.is-set) .hw,
.motion .stats-thesis:not(.is-set) .th-w { will-change: transform, opacity; }
/* the one-shot: site.js adds .is-in after fonts settle (the .hline hop
   keeps this above the pre-state's specificity) */
.motion .hero h1.is-in .hline .hline-i { transform: none; }
.motion .hero h1.is-in .hline:nth-child(1) .hline-i { transition-delay: 0ms; }
.motion .hero h1.is-in .hline:nth-child(2) .hline-i { transition-delay: 780ms; }
.motion .hero h1.is-in .hw { opacity: 1; transform: none; }
.motion .hero h1.is-in .hline:nth-child(3) .hw:nth-child(1) { transition-delay: 1650ms; } /* "We" — the ink answer begins */
.motion .hero h1.is-in .hline:nth-child(3) .hw:nth-child(2) { transition-delay: 1790ms; } /* 140ms word cadence */
.motion .hero h1.is-in .hline:nth-child(3) .hw:nth-child(3) { transition-delay: 1930ms; }
.motion .hero h1.is-in .hline:nth-child(3) .hw:nth-child(4) { transition-delay: 2070ms; }
.motion .hero h1.is-in .hline:nth-child(4) .hero-ul > .hw:nth-child(1) { transition-delay: 2350ms; } /* sentence beat, then line 4 speaks */
.motion .hero h1.is-in .hline:nth-child(4) .hero-ul > .hw:nth-child(2) { transition-delay: 2490ms; }
.motion .hero h1.is-in .hline:nth-child(4) .hero-ul > .hw:nth-child(3) { transition-delay: 2630ms; }
.motion .hero h1.is-in .hline:nth-child(4) .hw-g .hw:nth-child(1) { transition-delay: 2770ms; } /* §99: the trio, scoped inside .hw-g */
.motion .hero h1.is-in .hline:nth-child(4) .hw-g .hw:nth-child(2) { transition-delay: 2910ms; }
.motion .hero h1.is-in .hline:nth-child(4) .hw-g .hw:nth-child(3) { transition-delay: 3050ms; }
.motion .hero h1.is-in .hero-ul { background-size: 100% 0.07em; }

/* ---------- Stat bar --------------------------------------------------------
   Four CENTERED three-tier tiles (2026-07-13 round 2, decided from rendered
   variants): big numeral over a mono-caps label that answers "X what?" at
   skim speed ("40+ ACQUISITIONS CLOSED"), over one quiet support line. Pure
   track record: 40+ / $400M+ / 80%+ / ~25%+; the $1M – $10M focus range lives
   in the hero subhead. No stagger: numeral tops align across tiles.
   Tile 5 (.stat-key, the ~25%+ value-capture observation — "~1x+ / Turns of
   EBITDA" until §105, the founder's percent swap) is the band's one dark
   surface — the buyer's voice rendered in the machine tokens; grayscale
   emphasis in place of the banned chromatic accent. THE THESIS LEADS the
   band since 2026-07-14 (T3): one centered line above the tiles, mirroring
   the hero's grammar (muted setup / ink payoff + pen) — styles and motion
   below the tile rules. */
/* no border-bottom: the following .sec's border-top is the same hairline —
   doubling them stacked a 2px rule at the stats/Sell-Side seam */
/* Fold math (2026-07-14, four-line hero + elevated thesis, NO hero button):
   the T3 button removal more than paid for the added H1 line + thesis lead —
   the band foot lands ~786px at 1440×900, well inside the fold. Re-measure
   whenever hero, thesis, or tile copy changes. (§105: the tile-row air
   moved the foot to ~888 — measured, ~12px of headroom left.) */
/* 34/34 around the band's top rule (2026-07-17, was 38/30): the ONE seam
   tighter than the uniform 72 - hero + FULL band must clear the 900px fold
   at 1440, so this seam mirrors at compressed scale instead (margin-top here
   = above the rule; .stats-thesis padding-top = below it; the 68px sum is
   unchanged, so the band foot didn't move). padding-bottom 45: tiles carry
   27px of their own, 27 + 45 = 72 above the orientation divider - the band's
   EXIT seam joins the uniform rhythm. */
.stats { margin-top: 34px; padding-bottom: 45px; border-top: 1px solid var(--rule); }
/* minmax(0,…) so no tile's content can raise its column's min-content and
   unbalance the five equal tiles */
/* margin-top 32 (§105, the founder's air ruling): the tiles drop so the row
   floats between the photo's raised bottom edge (--hxgap above the row) and
   the band's exit hairline. This spends most of the fold headroom — band
   foot 856 → 888 at 1440×900 against the protected 900 line; ANY growth
   above the band must now be measured, ~12px is all that's left. */
.stats-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin-top: 32px; }
.stat {
  /* 10px horizontal (was 22px at four-across) so five tiles + the longest
     support ("Founder-owned companies.", ~187px) hold one line down to the
     1148 fold edge; the 2-col fold restores 22px */
  padding: 26px 10px 27px;
  text-align: center;
}
.stat + .stat { border-left: 1px solid var(--rule); }
.stat-n {
  /* five-across (2026-07-15): tile content is ~193px at 1440, ~190px at the
     1148 fold edge (10px padding). Longest numeral "$400M+" (~135px) clears
     it easily. The binding elements are the widest LABEL ("TOTAL TRANSACTION
     VALUE", held to one line by the 0.105em tracking on .stat-l below) and the
     longest SUPPORT ("Founder-owned companies.", ~187px); re-measure if
     numeral, label, or support copy changes. */
  font-size: clamp(26px, 2.5vw, 36px); font-weight: 600; color: var(--ink);
  letter-spacing: -0.02em; line-height: 1.1;
}
/* label tier: the figure-label voice (eyebrow/window-status grammar) in ink */
.stat-l {
  margin-top: 13px;
  font: 500 11px/1.5 var(--mono);
  /* 0.105em (was 0.14em): the tighter tracking lets "TOTAL TRANSACTION VALUE"
     hold one line in the ~189px five-across tile (2026-07-15) */
  letter-spacing: 0.105em;
  text-transform: uppercase;
  color: var(--ink);
}
.stat-d { margin: 9px auto 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); max-width: 24em; }
/* tile 4 — the buyer's voice: window-kin dark card (radius + rule match the
   product windows). 25px top pad + 1px border keeps its numeral top level
   with the open tiles' 26px. Grid-stretch fills the row height. */
.stats-row .stat-key {
  background: var(--card);
  border: 1px solid var(--card-rule);
  border-radius: 6px;
  padding: 25px 24px 26px;
}
.stat-key .stat-n { color: var(--card-text); }
.stat-key .stat-l { color: var(--card-text); }
.stat-key .stat-d { color: var(--card-mut); }
/* ---------- Band thesis (2026-07-14: the band LEAD, above the tiles) --------
   One centered line mirroring the hero's they-vs-us grammar: the setup
   sentence at the anchor tone (#52524E, same literal as hero lines 1-2)
   inside a rise mask (.th-m > .th-i, the .hline pattern at thesis scale),
   the payoff sentence in ink as seven word spans (.th-w) inside .th-ul,
   the pen carrier. 27px was the founder's size (+5 from the 22px draft); the
   clamp keeps the whole line on ONE row down to ~861px (27px line measures
   ~1027px in the 1064px content column at 1440 — re-measure if the copy
   changes), and below 861px the nowrap lifts so phones wrap naturally,
   each sentence as its own unit. Base styles are the finished frame. */
.stats-thesis {
  /* padding-top 34 mirrors .stats margin-top 34 around the band rule
     (2026-07-17; sum preserved vs the old 38/30 - fold unmoved) */
  padding: 34px 0 34px;
  text-align: center;
  font-size: clamp(19px, 2.3vw, 27px);
  font-weight: 500; line-height: 1.36;
  letter-spacing: -0.01em;
}
@media (min-width: 861px) { .stats-thesis { white-space: nowrap; } }
.stats-thesis .th-m {
  display: inline-block; overflow: hidden; vertical-align: top;
  padding-bottom: 0.16em; margin-bottom: -0.16em;
  color: #52524E;
}
.stats-thesis .th-i { display: inline-block; }
.stats-thesis .th-ink { display: inline-block; vertical-align: top; color: var(--ink); }
/* same per-line background pen as .hero-ul (2026-07-19): the thesis pen had
   the identical latent overshoot the moment its sentence ever wraps — one
   mechanism for both pens. Rule spans 0.04–0.09em below the text. */
.stats-thesis .th-ul {
  display: inline;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding-bottom: 0.09em;
  background-image: linear-gradient(var(--ink), var(--ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.05em;
}
/* thesis entrance: the EXACT hero replica on the hero's own clock (site.js
   adds .is-in to the thesis at the same moment as the h1; every delay below
   is absolute from that moment). Hero pen ends ~3970ms; a 500ms beat, then
   the thesis re-runs the hero grammar with the hero's own values: 620ms
   mask rise @4470, a 250ms gray-to-ink gap, 320ms words at the 140ms
   cadence @5340..6180, an 80ms breath, pen 520ms @6580 → done ~7100ms.
   Pre-states .motion-gated so static/no-JS/reduced-motion serve the
   finished line. */
.motion .stats-thesis .th-i {
  transform: translateY(120%);
  transition: transform 620ms cubic-bezier(0.16, 1, 0.3, 1) 4470ms;
}
.motion .stats-thesis .th-w {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.35em);
  transition: opacity 320ms ease, transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
.motion .stats-thesis .th-ul {
  background-size: 0 0.05em;
  transition: background-size 520ms cubic-bezier(0.16, 1, 0.3, 1) 6580ms;
}
.motion .stats-thesis.is-in .th-i { transform: none; }
.motion .stats-thesis.is-in .th-w { opacity: 1; transform: none; }
.motion .stats-thesis.is-in .th-w:nth-child(1) { transition-delay: 5340ms; } /* "Now" — gray landed (5090) + the 250ms gap */
.motion .stats-thesis.is-in .th-w:nth-child(2) { transition-delay: 5480ms; } /* 140ms word cadence, the hero's own */
.motion .stats-thesis.is-in .th-w:nth-child(3) { transition-delay: 5620ms; }
.motion .stats-thesis.is-in .th-w:nth-child(4) { transition-delay: 5760ms; }
.motion .stats-thesis.is-in .th-w:nth-child(5) { transition-delay: 5900ms; }
.motion .stats-thesis.is-in .th-w:nth-child(6) { transition-delay: 6040ms; }
.motion .stats-thesis.is-in .th-w:nth-child(7) { transition-delay: 6180ms; }
.motion .stats-thesis.is-in .th-ul { background-size: 100% 0.05em; }

/* ---------- Section template ------------------------------------------------ */
/* 72px MIRRORED on every section (2026-07-17, the founder - was 110px): one value
   both sides of every hairline, so each divider reads 72 above / 72 below.
   72 was already the tablet value, so the responsive ladder is now 72 -> 60.
   The ONE sanctioned tighter seam is hero->band (34/34, mirrored): the
   above-fold composition can't afford 72s - see .stats. */
.sec { padding: 72px 0; border-top: 1px solid var(--rule); }
.sec h2 { font-size: 30px; letter-spacing: -0.02em; }
/* §108: /buy-side needs a document h1, and its section title IS that h1. Sized
   to the h2 exactly so the ported section is pixel-identical to the one that
   left index.html — the row-1 flush and the boot measurements both depend on
   it. Never restyle this to "look like a page title"; the page deliberately
   opens on the section, not on a hero. */
.sec h1.sec-h1 { font-size: 30px; letter-spacing: -0.02em; }
.sec-sub { margin-top: 14px; font-size: 16.5px; color: var(--body); }
/* section eyebrow: "For" + audience, on every section (2026-07-12). ONE
   authored eyebrow-to-heading gap for every .sec context - orientation, the
   three offerings, both row-2 eyebrows, contact (2026-07-17: rendered gaps
   had drifted to 4/18/22/40px - the orientation eyebrow was unstyled, and
   flex columns stacked eyebrow + heading margins instead of collapsing them).
   The eyebrow alone carries the gap; headings below it take no margin-top.
   The hero eyebrow (26px, H1 scale) stays its own rule. */
.sec .eyebrow { display: block; margin-bottom: 18px; }
/* quiet CTA links (Sell-Side value row, Buy-Side process row) - not .btn */
.cta-link {
  display: inline-block;
  margin-top: 26px;
  font: 500 14px/1 var(--sans);
  color: var(--ink);
  letter-spacing: 0.01em;
}
.cta-link:hover { text-decoration: underline; text-underline-offset: 3px; }

.svc-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 88px;
  /* copy tops out level with the card chrome in every section (2026-07-10 -
     centering left dead air above the short copy column) */
  align-items: start;
}
/* .svc-list: the three offerings + the process row, on the SAME square marker
   as the orientation and contact lists (2026-07-17, the founder - one bullet species
   site-wide; the checkmark and its "claims voice" are RETIRED, BUILD-NOTES §52).
   Only the SCALE differs from .rlist's compact one-liners: section body copy at
   15.5px/1.55 vs 14.5/1.45, so the square rides lower to stay optically centred
   on the taller line box (top = lineBox/2 - half the 5px square: 24.03/2 - 2.5
   = 9.5; the base .rlist's 8px is that same formula at 21.03).
   grid + gap (not li margins) is the point: gap is immune to margin-collapse,
   so a flex parent (.svc-top, .gap-flex) and a block parent now render the SAME
   spacing. The old .checks rendered 52/18, 34/18, 40/14, 34/18 across the four
   lists purely from that collapse quirk plus a .gap-flex override. */
.svc-copy .svc-list, .gap-copy .svc-list { margin: 34px 0 0; gap: 18px; }
.svc-copy .svc-list li, .gap-copy .svc-list li {
  padding-left: 26px;
  font-size: 15.5px;
  line-height: 1.55;
  text-wrap: pretty;
}
.svc-copy .svc-list li::before, .gap-copy .svc-list li::before { top: 9.5px; }

/* ---------- Orientation ("One discipline") - routing block under the stat band
   (2026-07-15). Full-width header + three de-boxed route columns, each with a
   fixed triad of one-line bullets (situation / what we do / value). The three
   route links are NAV (#sell-side/#investing in page, /buy-side since §108
   moved that section to its own page), a distinct
   species from the two contact CTAs (.cta-link -> #contact): the "exactly two
   CTA links, never on Investing" rule counts CONTACT CTAs only. Copy grid lives
   in ORIENTATION-COPY.md. --------------------------------------------------- */
/* No padding override since 2026-07-17: the §49 compressed 60/72 special case
   died when EVERY section moved to the uniform mirrored 72px - the whole-site
   cut delivers what the local compression was for, with one less rule. */
.orient h2 { font-size: clamp(31px, 3vw, 37px); }
.orient .sec-sub { margin-top: 16px; }
/* margin-top 30 (was 44): the founder 2026-07-17, "cut that padding by about 30%" -
   the method line was floating too far off the three route rules */
.orient-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; margin-top: 30px; }
.ocard { position: relative; display: flex; flex-direction: column; border-top: 1px solid var(--ink); padding: 22px 0 0; }
/* Whole card = one click target (the founder, 2026-07-20): the route link
   STRETCHES over its card (::after overlay — no nested anchors, link text and
   tab order unchanged; the anchor's own cursor covers the card). Hover/focus
   answer with the top rule thickening — an overlay bar above the 1px border,
   never a border-width change, so nothing reflows — plus the link's underline. */
.ocard::before {
  content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 3px;
  background: var(--ink); opacity: 0; transition: opacity 0.15s ease;
}
.ocard:hover::before, .ocard:focus-within::before { opacity: 1; }
.ocard:hover .o-link, .ocard:focus-within .o-link { text-decoration: underline; text-underline-offset: 3px; }
.o-link::after { content: ""; position: absolute; inset: 0; }
.o-eye { font: 500 11px/1 var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.o-name { margin-top: 14px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); line-height: 1.15; }
/* three parallel bullets, each one line at desktop; square ink dot (CIM .hl kin) */
.rlist { list-style: none; margin: 16px 0 22px; display: grid; gap: 9px; }
.rlist li { position: relative; padding-left: 18px; font-size: 14.5px; line-height: 1.45; color: var(--body); }
.rlist li::before { content: ""; position: absolute; left: 0; top: 8px; width: 5px; height: 5px; background: var(--ink); }
/* route links: quiet look, bottom-aligned across all three columns (one
   baseline via margin-top:auto + equal-height flex columns), but they NAVIGATE
   to a section rather than drive #contact */
.o-link { margin-top: auto; align-self: flex-start; font: 500 14px/1 var(--sans); color: var(--ink); letter-spacing: 0.01em; }
.o-link .arw { margin-left: 4px; }
.o-link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Product cards - shared window chrome ----------------------------- */
.product { margin: 0; min-width: 0; }
.win {
  background: var(--card);
  border: 1px solid var(--card-rule);
  border-radius: 6px;
  overflow: hidden;
}
.win-bar {
  display: flex; align-items: center; gap: 14px;
  height: 38px; padding: 0 14px;
  border-bottom: 1px solid var(--card-rule);
}
.dots { display: inline-flex; gap: 7px; flex: none; }
.dots i {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
}
.dots i:nth-child(1) { background: #ff5f57; }
.dots i:nth-child(2) { background: #febc2e; }
.dots i:nth-child(3) { background: #28c840; }
/* no file-path label since 2026-07-12: dots left, status + pause right */
.win-status {
  margin-left: auto;
  font: 500 10.5px/1 var(--mono);
  color: var(--card-mut);
  letter-spacing: 0.08em;
  /* never wrap inside the fixed 38px bar; ellipsize on the narrowest phones */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.win-pause {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; margin-right: -6px; flex: none;
  background: none; border: 0; padding: 0; border-radius: 2px;
  /* 0.7 rest opacity keeps the pause glyph ≥3:1 on the dark bar (WCAG 1.4.11) */
  color: var(--card-mut); opacity: 0.7; cursor: pointer;
}
.win-pause:hover, .win-pause:focus-visible { opacity: 1; }
.win-pause:focus-visible { outline: 2px solid var(--card-text); outline-offset: 2px; }
.win-pause svg { fill: currentColor; }
.win-pause .pp-play { display: none; }
.win-pause.is-paused .pp-a, .win-pause.is-paused .pp-b { display: none; }
.win-pause.is-paused .pp-play { display: block; }
html:not(.motion) .win-pause { display: none; }
/* Exhibit A only (the founder, 2026-07-14): a replay control beside pause so a viewer
   can re-trigger the one-shot roll-in on demand. Grouped tight with pause; the
   group hugs the bar edge exactly as the lone pause button did (-6px). */
.win-ctrls { display: inline-flex; align-items: center; gap: 3px; flex: none; margin-right: -6px; }
.win-ctrls .win-pause { margin-right: 0; }
.win-replay {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: none;
  background: none; border: 0; padding: 0; border-radius: 2px;
  /* matches .win-pause: 0.7 rest opacity keeps the glyph >=3:1 on the dark bar */
  color: var(--card-mut); opacity: 0.7; cursor: pointer;
}
.win-replay:hover, .win-replay:focus-visible { opacity: 1; }
.win-replay:focus-visible { outline: 2px solid var(--card-text); outline-offset: 2px; }
.win-replay svg { fill: none; stroke: currentColor; }
/* tour control (2026-07-18): the stepper windows' button is two-state - the
   replay arrow at rest, the pause bars while the one-pass tour runs
   (.is-touring set by site.js, which swaps the aria-label with it). The
   pipeline's frozen button carries its own pause/play pair and is untouched. */
.win-replay .tc-p { display: none; fill: currentColor; stroke: none; }
.win.is-touring .win-replay .tc-r { display: none; }
.win.is-touring .win-replay .tc-p { display: block; }
/* ---------- Phone window tabs (2026-07-22, §89) -----------------------------
   ≤680 the three card windows (sample analysis / value exhibit / fit) carry
   a category-tab strip under the title bar — site.js builds it from the
   rail's own chips and wires swipe on the stage; the copy-column rails hide
   at that width (html.js-gated below, so no-JS phones keep the rails and
   their nav). Desktop and iPad never show the strip: the rails are the
   navigation there. Mono figure-label voice; active tab = ink + 2px rule. */
.swtabs { display: none; }
@media (max-width: 680px) {
  .swtabs { display: flex; background: var(--paper); border-bottom: 1px solid var(--rule); }
  .swtab {
    flex: 1 1 0; min-width: 0; padding: 11px 2px 9px;
    font: 500 9.5px/1 var(--mono); letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--muted); background: none; border: 0;
    border-bottom: 2px solid transparent; margin-bottom: -1px;
    cursor: pointer;
  }
  .swtab.is-on { color: var(--ink); border-bottom-color: var(--ink); }
  /* the rails go ONE-AT-A-TIME on phones (2026-07-22 §89 addendum — the
     founder's correction of this round's first cut, which hid them
     entirely: "these questions are really important, and it informs the
     visuals below it... the key questions and then the visual below". The
     ACTIVE step — black chip + committee question + its sub-bullets —
     stays above the window and swaps in sync with the card; the existing
     .is-on tracking IS the sync, so every path (tab, swipe, Next/Back,
     tour) drives both. JS present only: without JS the full rails stay
     and navigate. Since the §90 restructure the step's box IS the <li>
     (button + sibling .vsub), so the hidden thing is the li itself. */
  html.js .vq .vsteps > li:not(.is-on),
  html.js #value .vsteps > li:not(.is-on),
  html.js #process .fv-rail > li:not(.is-on),
  html.js .bx-rail > li:not(.is-on) { display: none; }
  /* ^ the bx-rail JOINED 2026-07-23 (§91, the founder: the Buy-Side
     coverage/pipeline/decision rail "is the only section that doesn't do
     it and I want it to mirror the other ones") — the live-legend .is-on
     tracking IS the sync, so the visible claim follows the pipeline view
     exactly as the card rails follow their cards. */
}
html:not(.motion) .win-replay { display: none; }
/* replay mechanism lives with the exhibit: .vcard.vstrip strips the .vb
   beats so removing the class re-applies them from frame 0 (site.js). */
.product-note {
  margin-top: 14px;
  font: 400 12px/1.5 var(--sans);
  color: var(--muted);
}

/* ---------- (CIM viewer card RETIRED 2026-07-17, BUILD-NOTES §54) --------------
   The 17-panel Caliper viewer left row 1 for the SAMPLE ANALYSIS stepper;
   the complete window is FROZEN at demos/caliper-cim.html (+ its own frozen
   CSS copy). The .cim-* engine rules were deleted with it. The CIM-INTERIOR
   classes below (.pg-*, .kf-*, .cov, .toc, .cap, charts, map, org) are KEPT:
   .pg-head/.pg-name/.pg-conf/.pg-kicker/.pg-foot are REUSED by the new
   window's page chrome, and the rest await a dead-rule sweep (recorded §54)
   rather than risk a bulk deletion in the port commit. */

.pg-head {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-bottom: 10px; border-bottom: 1px solid var(--ink);
}
.pg-head .pg-name { font: 500 10px/1 var(--mono); letter-spacing: 0.18em; color: var(--ink); }
.pg-head .pg-conf { font: 400 8.5px/1 var(--mono); letter-spacing: 0.14em; color: var(--faint); }
.pg-body { flex: 1; padding-top: 16px; min-height: 0; }
.pg-foot {
  display: flex; justify-content: space-between;
  padding-top: 10px; border-top: 1px solid var(--rule);
  font: 400 8.5px/1 var(--mono); color: var(--faint); letter-spacing: 0.06em;
}
.pg-title { font-size: 15px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.pg-kicker { font: 500 8.5px/1 var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.pg-body p { font-size: 11.5px; line-height: 1.6; color: var(--body); margin-top: 10px; max-width: 40em; }

/* key-figure row (exec summary) */
.kf-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--rule); }
.kf .kf-n { font-size: 17px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.kf .kf-l { font-size: 8.5px; font-family: var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-top: 4px; line-height: 1.4; }
.kf .kf-d { font: 500 7.5px/1 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); margin-top: 4px; font-variant-numeric: tabular-nums; }
.kf-row.kf-3 { grid-template-columns: repeat(3, 1fr); }
.kf-row.kf-3 .kf-n { font-size: 20px; }

/* quantified highlights (exec summary) */
.hl { list-style: none; margin-top: 16px; }
.hl li { position: relative; padding-left: 14px; margin-top: 7px; font-size: 10.5px; line-height: 1.5; color: var(--body); font-variant-numeric: tabular-nums; }
.hl li::before { content: ""; position: absolute; left: 0; top: 5.5px; width: 5px; height: 5px; background: var(--ink); }

/* exhibit head line: title left, units declared once at right */
.pg-exline { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; }
.pg-units { font: 400 8.5px/1 var(--mono); letter-spacing: 0.08em; color: var(--faint); white-space: nowrap; }

/* exhibit footnotes - small type, set directly beneath the exhibit */
p.pg-fn { margin-top: 10px; font-size: 9.5px; line-height: 1.5; color: var(--faint); }

/* financial table */
.fin { width: 100%; border-collapse: collapse; margin-top: 14px; font-variant-numeric: tabular-nums; }
.fin th, .fin td { font-size: 11px; padding: 4.5px 0; text-align: right; }
.fin th:first-child, .fin td:first-child { text-align: left; font-variant-numeric: normal; }
.fin thead th { font: 500 9px var(--mono); letter-spacing: 0.08em; color: var(--muted); border-bottom: 1px solid var(--ink); }
.fin tbody td { border-bottom: 1px solid var(--rule); color: var(--body); }
.fin tbody tr.fin-key td { color: var(--ink); font-weight: 600; border-top: 1px solid var(--ink); background: var(--wash); }
/* labeled foot blocks: Growth Rate Analysis / Margin Analysis */
.fin tbody tr.fin-lab td {
  font: 500 8px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); padding-top: 12px; border-bottom: 1px solid var(--rule-2);
}

/* legend rows (end-market panel) */
.mix { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 18px; }
.legend { list-style: none; min-width: 13em; }
.legend li { display: flex; justify-content: space-between; gap: 18px; font-size: 10.5px; color: var(--body); padding: 6.5px 0; border-bottom: 1px solid var(--rule); }
.legend li span:last-child { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }

/* paired chart figures (growth panel) */
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 14px; }
.ch { margin: 0; min-width: 0; }
.ch svg { width: 100%; height: auto; }
.ch-t { font: 500 8px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }

/* capex exhibit: chart left, conversion callout right */
.cap { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 22px; align-items: center; margin-top: 14px; }
.cap svg { width: 100%; height: auto; }
.cap-call { border-left: 1px solid var(--rule-2); padding-left: 20px; min-width: 10.5em; max-width: 12em; }
.cap-call .kf + .kf { margin-top: 16px; }

/* revenue-mix donut + side column */
.donut { max-width: 220px; margin: 0 auto; }
.mix-side { min-width: 14em; }
.rr { list-style: none; margin-top: 10px; }
.rr li { display: grid; grid-template-columns: 2.6em 1fr 2.4em; align-items: center; gap: 8px; font-size: 10px; color: var(--body); margin-top: 7px; }
.rr .bar { height: 10px; background: var(--wash); position: relative; }
.rr .bar i { position: absolute; inset: 0 auto 0 0; background: var(--ink); display: block; }
.rr li span:last-child { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }

/* org chart + headcount table */
.orgc { margin-top: 12px; width: 100%; height: auto; }
.hc { width: 100%; border-collapse: collapse; margin-top: 12px; font-variant-numeric: tabular-nums; }
.hc td { font-size: 10.5px; padding: 4px 0; border-bottom: 1px solid var(--rule); color: var(--body); }
.hc td:last-child { text-align: right; color: var(--ink); font-weight: 600; }
.hc tr.hc-tot td { border-top: 1px solid var(--ink); border-bottom: none; color: var(--ink); font-weight: 600; }

/* footprint map */
.map-strip { margin-top: 12px; font: 500 8.5px/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.map-svg { margin-top: 10px; width: 100%; height: auto; }

/* cover / contents (panel 01) */
.cov .cov-kick { font: 500 9px/1 var(--mono); letter-spacing: 0.2em; color: var(--muted); margin-top: 8px; }
.cov .cov-title { font-size: 26px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); margin-top: 10px; padding-bottom: 16px; border-bottom: 1px solid var(--ink); }
.toc { list-style: none; margin-top: 12px; }
.toc li { display: flex; align-items: baseline; gap: 10px; font-size: 11px; color: var(--body); padding: 5.5px 0; }
.toc .toc-s { font: 500 8.5px/1 var(--mono); color: var(--faint); min-width: 1.4em; }
.toc .toc-lead { flex: 1; border-bottom: 1px dotted var(--rule-2); transform: translateY(-2px); }
.toc .toc-pg { font: 500 9.5px/1 var(--mono); color: var(--ink); font-variant-numeric: tabular-nums; }

/* KPI board (panel 04): three-tier tiles, hairline dividers, no boxes */
.kpi { display: grid; grid-template-columns: repeat(4, 1fr); gap: 30px 0; margin-top: 26px; }
.kpi .kf { border-left: 1px solid var(--rule); padding: 4px 0 18px 14px; }
.kpi .kf:nth-child(4n + 1) { border-left: 0; padding-left: 0; }
.kpi .kf:nth-child(-n + 4) { border-bottom: 1px solid var(--rule); }
.kpi .kf-n { font-size: 22px; }

/* lone chart exhibits (waterfalls, histogram) */
.pg-svg { margin-top: 22px; width: 100%; height: auto; display: block; }

/* mono KPI chips above an exhibit */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chip-m { font: 500 7.5px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--body); border: 1px solid var(--rule-2); padding: 5px 8px; white-space: nowrap; }

/* footprint: the map stays the panel's hero (capped so the branch table
   beneath it still clears the page foot), ranked table below-left */
.fp { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.fp .map-svg { margin-top: 0; max-width: 408px; align-self: center; }
.fp .hc { margin-top: 0; max-width: 17em; }
.fp .hc td { padding: 3.5px 0; }
.hc thead th { font: 500 8px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; background: var(--ink); color: var(--paper); padding: 5px 0; text-align: left; }
.hc thead th:last-child { text-align: right; }

/* organization: headcount donut beside the function table
   (the donut carries an explicit width: with viewBox only, its intrinsic
   width is zero and an auto grid track would collapse to 0px) */
.og { display: grid; grid-template-columns: auto 1fr; gap: 24px; align-items: center; margin-top: 10px; }
.og .hc { margin-top: 0; }
.donut-s { width: 132px; }

/* concentration-panel key figures in the donut side column */
.mix-side .kf .kf-n { font-size: 15px; }

/* ---------- Pipeline card ------------------------------------------------------
   Three stacked panels inside a fixed square frame: executive dashboard,
   stage-sorted table (the reduced-motion poster; site.js scrolls it to show
   depth), and one target file. Crossfaded by site.js; transform/opacity only. */
/* 7/8 since 2026-07-19 (was 1/1): the tear-sheet build-out needs the extra
   height; the dashboard absorbs its share as air and the table view simply
   shows more rows before the scroll — measured, not assumed */
.pipe-frame { position: relative; aspect-ratio: 7 / 8; overflow: hidden; }
.pipe-panel { position: absolute; inset: 0; opacity: 0; transition: opacity 0.35s ease; }
.pipe-panel.is-active { opacity: 1; }

.pipe-scroll { overflow-x: auto; overflow-y: hidden; height: 100%; }
/* inset light outline: the global ink outline is invisible on the #101010
   body and would be clipped by .pipe-frame's overflow:hidden anyway */
.pipe-scroll:focus-visible { outline: 2px solid var(--card-text); outline-offset: -2px; }
/* will-change moved to JS (2026-07-22 §89): the CSS declaration held the
   whole 48-row table on a permanently rasterized compositor layer — real
   memory and raster cost on older iPads even while the window rests.
   site.js now sets it on pipeCtl.start() and clears it on stop()/rest, so
   the layer exists only while the one ~18s cycle actually runs. */
.pipe { width: 100%; min-width: 560px; border-collapse: collapse; }
.pipe th {
  font: 500 9px var(--mono); letter-spacing: 0.08em; text-transform: uppercase;
  color: #8F8F8C; text-align: left;
  padding: 12px 8px 10px; border-bottom: 1px solid var(--card-rule);
}
.pipe th:first-child, .pipe td:first-child { padding-left: 14px; }
.pipe th:last-child, .pipe td:last-child { padding-right: 14px; }
.pipe td {
  font-size: 11.5px; color: var(--card-mut);
  padding: 11px 6px; border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  white-space: nowrap;
}
/* sector names truncate rather than widen the grid - enterprise tables ellipsize */
.pipe td:nth-child(2) { max-width: 9.5em; overflow: hidden; text-overflow: ellipsis; }
.pipe tr:last-child td { border-bottom: none; }
.pipe td.t-name { color: var(--card-text); font-weight: 500; }
.pipe td.fig { text-align: right; font-variant-numeric: tabular-nums; }
.pipe th.fig { text-align: right; }
/* token columns center — Geography, Touch, Status read as tokens, so header
   and cells center together; prose (Target, Sector) stays left and the EBITDA
   money column stays right, IB grammar (2026-07-20 owner ruling on the
   pipeline board). */
.pipe td.tch { text-align: center; font-variant-numeric: tabular-nums; color: var(--card-dim); }
.pipe th.tch { text-align: center; }
.pipe th:nth-child(4), .pipe td:nth-child(4),
.pipe th:nth-child(6), .pipe td:nth-child(6) { text-align: center; }
/* stage register rows (2026-07-20): group headers make the stage sort
   physical — one hairline and a mono label per stage, counts footing the
   funnel (LOI 1 ... Contacted 21 = 48). Inserted <tr>s; the colspan cell is
   nth-child(1) so the centering above skips it, and the 48 data rows are
   untouched (their EBITDA en dashes never re-render). */
.pipe tr.stg td {
  padding: 15px 8px 6px 14px;
  border-bottom: 1px solid var(--card-rule);
  font: 500 9px var(--mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--card-dim); white-space: nowrap;
}
.pipe tbody tr.stg:first-child td { padding-top: 8px; }
.stg-c { color: var(--card-mut); margin-left: 6px; font-variant-numeric: tabular-nums; }
.pipe-note {
  padding: 14px 14px 18px;
  font: 400 10px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--card-dim);
}

.chip {
  display: inline-block;
  font: 500 9px/1 var(--mono);
  letter-spacing: 0.05em; text-transform: uppercase;
  padding: 4px 7px; border-radius: 2px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.chip--sourced   { border-color: #3A3A3A; color: #8F8F8C; }
.chip--contacted { border-color: #4A4A4A; color: #ABABA8; }
.chip--nda       { border-color: #6E6E6E; color: #CDCDCA; }
.chip--cim       { border-color: #8F8F8F; color: #E2E2E0; }
.chip--ioi       { border-color: #8F8F8F; background: rgba(255,255,255,0.07); color: #ECECEA; }
.chip--loi       { border-color: #A9A9A9; background: rgba(255,255,255,0.15); color: #F6F6F4; }
.chip--closed    { background: #F2F2F0; border-color: #F2F2F0; color: #101010; }

.chip--fit       { border-color: #C2C2C2; background: rgba(255,255,255,0.18); color: #F6F6F4; }
.chip--pass      { border-color: #4A4A4A; color: #ABABA8; }

/* the one animated cell: two chips stacked, crossfaded by site.js */
.chip-swap { position: relative; display: inline-grid; }
.chip-swap .chip { grid-area: 1 / 1; transition: opacity 1s ease; }
.chip-swap .chip-b { opacity: 0; }
.chip-swap.is-adv .chip-a { opacity: 0; }
.chip-swap.is-adv .chip-b { opacity: 1; }
.chip-swap.is-reset .chip { transition-duration: 0.18s; }

/* -- Panel 1: executive dashboard ------------------------------------------ */
.pipe-dash {
  padding: 4.7% 7.5%;
  display: flex; flex-direction: column;
  /* the "middle" half of the founder's centering ruling: residual air splits
     evenly; `safe` falls back to top-anchored where a narrow frame would clip */
  justify-content: safe center;
}
.pd-kicker {
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--card-mut);
}
.pd-kpis {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
  margin-top: 11px; padding-bottom: 10px;
  border-bottom: 1px solid var(--card-rule);
}
/* tiles center — the stat band's grammar (founder ruling, §63) */
.pd-kpi { text-align: center; }
.pd-n {
  font-size: 30px; font-weight: 600; color: var(--card-text);
  letter-spacing: -0.02em; line-height: 1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.pd-l { margin-top: 8px; font-size: 11px; color: var(--card-mut); }
.pd-d {
  margin-top: 3px;
  font: 400 9px/1.3 var(--mono);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--card-dim);
}
.pd-sub {
  margin-top: 11px;
  font: 500 9px/1 var(--mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--card-dim);
}
.pd-funnel { margin-top: 9px; display: grid; gap: 5.5px; }
.pd-frow { display: grid; grid-template-columns: 7.4em 1fr 2.6em; align-items: center; gap: 10px; }
.pd-fl { font-size: 10.5px; color: var(--card-mut); white-space: nowrap; }
.pd-fbar { height: 8px; background: rgba(255,255,255,0.06); position: relative; }
.pd-fbar i { position: absolute; inset: 0 auto 0 0; display: block; background: rgba(255,255,255,0.3); }
/* one tint step per stage, darkest at the top of the funnel - mirrors the chip ramp */
.pd-frow:nth-child(1) .pd-fbar i { background: rgba(255,255,255,0.16); }
.pd-frow:nth-child(2) .pd-fbar i { background: rgba(255,255,255,0.22); }
.pd-frow:nth-child(3) .pd-fbar i { background: rgba(255,255,255,0.30); }
.pd-frow:nth-child(4) .pd-fbar i { background: rgba(255,255,255,0.40); }
.pd-frow:nth-child(5) .pd-fbar i { background: rgba(255,255,255,0.52); }
.pd-frow:nth-child(6) .pd-fbar i { background: rgba(255,255,255,0.66); }
.pd-fn {
  text-align: right;
  font: 500 10.5px/1 var(--mono);
  color: var(--card-text);
  font-variant-numeric: tabular-nums;
}
/* flex:none — an empty flex child is the first thing flex-shrink crushes (§63) */
.pd-split { margin-top: 10px; height: 8px; background: rgba(255,255,255,0.10); position: relative; flex: none; }
.pd-split i { position: absolute; inset: 0 auto 0 0; display: block; background: rgba(255,255,255,0.44); }
.pd-splitlab {
  display: flex; justify-content: space-between;
  margin-top: 6px;
  font: 400 9px/1 var(--mono);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--card-dim);
}

/* the week's movement: the KPI tiers at mini scale (band ships 2026-07-19) */
.pd-minis {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin-top: 8px;
}
.pd-minis .pd-n { font-size: 19px; }
.pd-minis .pd-l { margin-top: 4px; font-size: 10.5px; }

/* the week ahead: mono day stamp / event / codename */
.pd-sched { margin-top: 8px; display: grid; gap: 5px; }
.pd-wrow {
  display: grid; grid-template-columns: 2.9em 1fr auto; gap: 10px;
  align-items: baseline; line-height: 1.35;
}
.pd-wd {
  font: 500 9px/1.3 var(--mono); letter-spacing: 0.08em;
  color: var(--card-dim);
}
.pd-we { font-size: 11px; color: var(--card-mut); }
.pd-wt {
  font-size: 11px; font-weight: 500; color: var(--card-text);
  white-space: nowrap;
}

/* the decisions queue: name / gate / verdict chip. FIXED tracks — per-row
   grids drift columns row-to-row otherwise (§63) */
.pd-dec { margin-top: 8px; }
.pd-drow {
  display: grid; grid-template-columns: 6.4em 1fr auto; gap: 10px;
  align-items: center; padding: 3.5px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.pd-drow:last-child { border-bottom: none; padding-bottom: 0; }
.pd-dn { font-size: 11px; font-weight: 500; color: var(--card-text); white-space: nowrap; }
.pd-dq { font-size: 10.5px; color: var(--card-mut); }
.pd-dc { text-align: right; }
.pd-dec .chip { padding: 2.5px 6px; }

/* -- Panel 3: target file (tear sheet; BUILT OUT 2026-07-19, freeze lifted) --
   Five bands: masthead / KPI strip / situation+fit beside the dual-axis
   trend / summary P&L beside service lines / process foot. Fixed padding
   (the old 7%/7.5% ballooned with the taller frame). */
.pipe-tear { padding: 26px 30px; display: flex; flex-direction: column; }
.pt-head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;
  padding-bottom: 12px; border-bottom: 1px solid var(--card-rule);
}
.pt-name { font-size: 19px; font-weight: 600; color: var(--card-text); letter-spacing: -0.01em; }
.pt-desc { margin-top: 6px; font-size: 11px; color: var(--card-mut); }
.pt-strip {
  display: grid; grid-template-columns: repeat(5, auto);
  justify-content: space-between; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--card-rule);
}
.pt-n { font-size: 15px; font-weight: 600; color: var(--card-text); font-variant-numeric: tabular-nums; }
.pt-l {
  margin-top: 4px;
  font: 400 8.5px/1.3 var(--mono);
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--card-dim);
}
.pt-sub {
  font: 500 8.5px/1 var(--mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--card-dim);
}
.pt-sit p { margin-top: 10px; font-size: 11.5px; line-height: 1.6; color: var(--card-mut); max-width: 26em; }
.pt-fit { display: flex; align-items: center; gap: 12px; margin-top: 18px; }
.pt-trend svg { margin-top: 10px; width: 100%; max-width: 208px; height: auto; }
/* tear-sheet bands (2026-07-19): air delimits band 3, a hairline opens the
   evidence band; the foot's margin-top:auto absorbs the residual */
.pt-band { display: grid; gap: 26px; }
/* band padding tightened 12 → 8/6 (2026-07-20): the tear now carries the
   considerations block and the quick screen, so the bands buy the room back */
.pt-b3 { grid-template-columns: 54fr 46fr; padding-top: 8px; }
.pt-b4 { grid-template-columns: 58fr 42fr; margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--card-rule); }
/* dark summary P&L: IB grammar in the machine tokens — right-aligned tabular
   figures, hairline-topped subtotals, italic ratio rows, parens negatives */
.pt-fin { margin-top: 9px; }
.pt-fin .th, .pt-fin .r { display: grid; grid-template-columns: minmax(0, 1fr) 50px 50px 50px; gap: 10px; }
.pt-fin .th { font: 500 8px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--card-dim); padding-bottom: 6px; border-bottom: 1px solid var(--card-rule); }
.pt-fin .th span + span, .pt-fin .r span + span { text-align: right; }
.pt-fin .r { padding: 3.5px 0; font-size: 11px; color: var(--card-mut); font-variant-numeric: tabular-nums; }
.pt-fin .r.tot { border-top: 1px solid var(--card-rule); color: var(--card-text); font-weight: 600; }
.pt-fin .r.sub { padding-top: 0; font-size: 10px; font-style: italic; color: var(--card-dim); }
/* service-line mini-table + recurring readout */
.pt-svc { margin-top: 9px; }
.pt-svc .r { display: grid; grid-template-columns: minmax(0, 1fr) 48px 36px; gap: 8px; align-items: center; padding: 6.5px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.05); font-size: 11px; color: var(--card-mut); white-space: nowrap; }
.pt-svc .r span:nth-child(2), .pt-svc .r span:nth-child(3) { text-align: right; font-variant-numeric: tabular-nums; color: var(--card-text); }
.pt-svfoot { margin-top: 6px; font: 400 8.5px/1.5 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--card-dim); }
/* the MD's pass/pursue reads (2026-07-20 owner ask): considerations under the
   fit verdict = facts already on the sheet (mix, transition, footprint);
   quick screen in the service cell's foot = the three decisive screens
   growth / concentration / safety. The quick screen rides the service column,
   so it yields with it at phone (.pt-b4 > div + div hides ≤680). */
.pt-cons { margin-top: 8px; }
.pt-crow { margin-top: 4px; font-size: 10px; line-height: 1.4; color: var(--card-mut); }
.pt-cons .pt-sub + .pt-crow { margin-top: 6px; }
.pt-qsh { margin-top: 10px; }
.pt-qs { margin-top: 4px; }
.pt-qs .r {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px;
  align-items: center; padding: 4.5px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  font-size: 11px; color: var(--card-mut); white-space: nowrap;
}
.pt-qs .r:last-child { border-bottom: none; padding-bottom: 0; }
.pt-qs .r span:last-child { text-align: right; font-variant-numeric: tabular-nums; color: var(--card-text); }
.pt-foot {
  display: flex; justify-content: space-between; gap: 14px;
  margin-top: auto; padding-top: 14px;
  border-top: 1px solid var(--card-rule);
  font: 400 9px/1 var(--mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--card-dim);
}

/* ---------- Sell-Side compaction (2026-07-10, the founder) --------------------------------
   Row 1 top-aligns copy with the CIM card and bottom-flushes the 1,000+ bridge
   into the column's air; row 2 (the value exhibit) rides the same grid so both
   windows foot flush on the right rail. Air alone delimits the rows - hairline
   rules stay reserved for true section boundaries. */
/* .svc-top adds only the flex column that bottom-flushes the value-row copy;
   top-alignment itself is base .svc-grid grammar. The auto margin on the CTA wrap
   (the value row's .cta-wrap, Buy-Side's .bx-cta) absorbs whatever the row leaves
   over, pinning the copy column's last line level with the card's caption baseline
   (deliberate: text pairs with text). If copy outgrows the card the column simply
   runs longer - nothing collides. */
.svc-top .svc-copy { align-self: stretch; display: flex; flex-direction: column; }
.svc-top .svc-copy .svc-list { flex: 0 0 auto; }

/* ---------- Value exhibit - Sell-Side row 2 (takeaway-first stepper, 2026-07-15) ------
   Back on the 5fr/7fr section grid (the v4 full-width plate moved to the
   frozen pitch demo demos/value-exhibit.html). Left column = the story
   index: three clickable steps (VALUE / LEVER 01 / LEVER 02 chips + titles
   + punchy sub-bullets), active step tracked with an ink left rule. Right =
   a CIM-footprint window (.vx-stage, aspect 10/11 minimum) stepping three
   cards: VALUE (equation header SUPPORTED EARNINGS x COMPETITIVE MULTIPLE
   = ENTERPRISE VALUE over the zero-based staircase + the compact difference
   band) -> LEVER 01 (the $K bridge on its broken y-axis) -> LEVER 02 (the
   multiple scale + the dollar-translation note). Next/Back rail + counter;
   replay button in the chrome (NO pause button: each roll is ~1.8s, under
   WCAG 2.2.2's 5s line). Every number on the plate is a multiplication of
   two numbers already shown (sequential re-pricing); the formula line and
   the WITHOUT/WITH AN ADVISOR chips are DEAD on-page (2026-07-15).
   Base styles are the FINAL frame: with no .motion class (reduced motion /
   ?static=1 / no JS) every card stands fully assembled and the stepper
   still navigates. Card roll-in: site.js assigns .vb beats + --d delays;
   .motion gates the animation and .win.is-live supplies --vx-play, so the
   first roll fires on reveal, pauses offscreen, and stepping/replay
   re-trigger via the .vstrip reflow (mirrors the old vg-restart). */
.gap-grid { margin-top: 72px; }
.gap-copy { max-width: 40em; }
/* no margin-top: .gap-flex is a flex column, so a heading margin would STACK
   with the eyebrow's 18px instead of collapsing (the shared .sec .eyebrow
   rule carries the whole gap) */
.gap-copy h3 { font-size: 26px; }
.gap-copy p { margin-top: 14px; font-size: 15.5px; color: var(--body); }
.vg-foot { margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--rule); font-size: 11.5px; line-height: 1.6; color: var(--muted); }

/* window-local mono voices (the .eyebrow class is the section voice) */
.ml { font: 500 10.5px/1.5 var(--mono); letter-spacing: 0.12em; color: var(--ink); text-transform: uppercase; }
.ml-sub { font: 400 9.5px/1.5 var(--mono); letter-spacing: 0.12em; color: var(--faint); text-transform: uppercase; }

/* ----- lever chrome (the statement pair's pa- / pvc / ph-mini styles left
   with the pair itself, 2026-07-15 - the pair is pitch-demo-only now) ----- */
.ph-chip { display: inline-flex; align-items: center; flex: none; height: 22px; padding: 0 9px; border-radius: 2px; background: var(--ink); color: var(--paper); font: 600 9.5px/1 var(--mono); letter-spacing: 0.1em; white-space: nowrap; }
.ph-op { font: 600 12px/1 var(--mono); color: var(--ink); }
.pvc-m { display: flex; align-items: center; height: 16px; padding: 0 6px; width: fit-content; border-radius: 2px; font: 600 7.5px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; }
.pvc-m-ghost { border: 1px solid var(--ink); color: var(--ink); background: var(--paper); }
.pvc-m-ink { background: var(--ink); color: var(--paper); }
.quad-h { display: flex; align-items: center; gap: 12px; }
.quad-sub { margin-top: 7px; }
/* the band framing (margin/border) died with the full-width plate: inside
   the stepper each card owns the whole stage */
.phband-h { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }

/* ----- LEVER 01: EBITDA bridge (broken y-axis) ----- */
.wf { --barw: 54px; position: relative; display: grid; grid-template-columns: repeat(6, 1fr); gap: 0 16px; margin-top: 18px; }
.wf::before { content: ''; position: absolute; left: 0; right: 0; top: 232px; border-top: 1px solid var(--rule-2); }
.wf-plot { position: relative; height: 232px; }
.wf-bar { position: absolute; left: 50%; width: var(--barw); margin-left: calc(var(--barw) / -2); transform-origin: bottom; }
.wf-bar.wf-rep { background: var(--faint); }
.wf-bar.wf-step { background: var(--tint); border: 1px solid var(--rule-2); }
.wf-bar.wf-adj { background: var(--ink); }
/* connector spans the true gap between adjacent bars (plot child, not a bar
   stub): right edge sits at this bar's left edge, width = col - bar + gap */
.wf-conn2 { position: absolute; right: calc(50% + var(--barw) / 2); width: calc(100% - var(--barw) + 16px); border-top: 1px dashed var(--rule-2); }
/* y-axis break glyph: white slash band across a full-height bar */
.wf-break { position: absolute; left: -3px; right: -3px; height: 5px; background: var(--paper); transform: rotate(-6deg); }
.wf-val { position: absolute; left: -8px; right: -8px; text-align: center; font: 500 10px/1 var(--mono); color: var(--ink); }
.wf-cat { margin-top: 10px; text-align: center; font: 500 7.5px/1.5 var(--mono); letter-spacing: 0.05em; color: var(--muted); text-transform: uppercase; }
.wf-brk { grid-column: 2 / 6; margin-top: 12px; height: 7px; border: 1px solid var(--rule-2); border-top: none; }
.wf-brk-l { grid-column: 2 / 6; margin-top: 8px; text-align: center; font: 500 9.5px/1.5 var(--mono); letter-spacing: 0.12em; color: var(--ink); }

/* ----- LEVER 02: multiple scale ----- */
.mscale { position: relative; margin: 84px 20px 0; height: 116px; }
.mscale-rule { position: absolute; left: 0; right: 0; top: 40px; border-top: 1px solid var(--rule-2); }
.mscale-seg { position: absolute; top: 39px; height: 3px; background: var(--ink); transform-origin: left; }
.mscale-tick { position: absolute; top: 40px; width: 1px; height: 7px; background: var(--rule-2); }
.mscale-tl { position: absolute; top: 54px; transform: translateX(-50%); font: 400 8.5px/1 var(--mono); color: var(--faint); }
.mscale-mark { position: absolute; top: 35.5px; width: 11px; height: 11px; transform: translateX(-50%); border-radius: 50%; background: var(--paper); border: 1.5px solid var(--ink); }
.mscale-mark.is-ink { background: var(--ink); border-radius: 2px; }
.mscale-cap { position: absolute; top: 74px; transform: translateX(-50%); text-align: center; font: 500 8.5px/1.5 var(--mono); letter-spacing: 0.08em; color: var(--ink); white-space: nowrap; }
.mscale-cap .pvc-m { margin: 5px auto 0; }
.mscale-brk { position: absolute; top: 6px; height: 7px; border: 1px solid var(--ink); border-bottom: none; }
.mscale-brk-l { position: absolute; left: 50%; top: -16px; transform: translateX(-50%); font: 600 10.5px/1 var(--mono); color: var(--ink); }
.mscale-note { margin: 26px 20px 0; font-size: 11.5px; line-height: 1.6; color: var(--muted); }

/* ----- VALUE: staircase + compact difference band (stepper card 1) ----- */
.res { display: flex; flex-direction: column; align-items: stretch; gap: 20px; margin-top: 18px; }
.res-stair { flex: 1; min-width: 0; }
.stair { display: grid; grid-template-columns: repeat(3, 118px); gap: 0 44px; justify-content: center; margin-top: 16px; }
.st-dim { grid-column: 1 / 4; position: relative; height: 30px; margin: 0 60px 10px; }
.st-dim-line { position: absolute; left: 0; right: 0; top: 12px; border-top: 1px solid var(--ink); }
.st-dim-line::before, .st-dim-line::after { content: ''; position: absolute; top: 0; width: 1px; height: 6px; background: var(--ink); }
.st-dim-line::before { left: 0; } .st-dim-line::after { right: 0; }
.st-dim-tag { position: absolute; left: 50%; top: 5px; transform: translateX(-50%); background: var(--paper); padding: 0 10px; font: 600 11px/1.3 var(--mono); color: var(--ink); }
.st-plot { position: relative; height: 260px; border-bottom: 1px solid var(--rule-2); }
.st-bar { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; transform-origin: bottom; }
.st-base { background: var(--tint); }
.sg { position: relative; display: flex; align-items: center; justify-content: center; font: 500 10px/1 var(--mono); }
/* phase 01 = solid ink; phase 02 = diagonal hatch (the W3 wedge) */
.sg-01 { background: var(--ink); color: var(--paper); }
.sg-02 { background: repeating-linear-gradient(45deg, var(--ink) 0 1.5px, var(--paper) 1.5px 5.5px); color: var(--ink); }
.sg-02 .sg-tag { background: var(--paper); padding: 2px 6px; box-shadow: 0 0 0 1px var(--ink); }
.st-top { position: absolute; left: -26px; right: -26px; text-align: center; font: 600 12px/1 var(--mono); color: var(--ink); }
.st-conn { position: absolute; right: 100%; width: 64px; border-top: 1px dashed var(--rule-2); }
.st-x { margin-top: 10px; text-align: center; }
.st-x-m { font: 500 11px/1.5 var(--mono); color: var(--ink); }
.st-x-c { margin-top: 6px; display: flex; justify-content: center; }
/* compact difference band: legend rows left, the +$4.4M payoff right (it
   lands under the far bar); the formula line is DEAD (the founder, 2026-07-15) */
.call2 {
  max-width: 490px; margin: 4px auto 0; padding-top: 16px;
  border-top: 1px solid var(--rule-2);
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
}
.call2-keys { display: flex; flex-direction: column; gap: 10px; }
.k2row {
  display: flex; align-items: center; gap: 8px;
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--body);
}
.k2row b { font-weight: 600; margin-left: 2px; }
.call2-d { text-align: right; }
.call2-d .ml { display: block; }
.call2-v {
  margin-top: 6px;
  font: 700 clamp(30px, 3vw, 40px)/1 var(--sans);
  letter-spacing: -0.01em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.kswatch { flex: none; width: 12px; height: 12px; }
.kswatch.k01 { background: var(--ink); }
.kswatch.k02 { background: repeating-linear-gradient(45deg, var(--ink) 0 1.5px, var(--paper) 1.5px 5.5px); box-shadow: inset 0 0 0 1px var(--ink); }

/* ----- stepper: copy column, stage, cards, nav (2026-07-15) ----- */
/* no margin-top: .vx-copy is a flex column - a heading margin would stack
   with the eyebrow's 18px (this pair rendered 40px before 2026-07-17) */
.vx-copy h3 { font-size: 26px; }
.vx-copy > p { margin-top: 14px; font-size: 15.5px; color: var(--body); max-width: 26em; }
/* CTA pinned to the window's foot line via the svc-top flex column */
.vx-copy .cta-wrap { margin-top: auto; padding-top: 34px; }
/* the window body: CIM footprint (10/11 is a MINIMUM - the box grows if a
   card needs more); flex column so the nav rail and disclaimer stack under
   the card area */
.vx-stage { aspect-ratio: 10 / 11; display: flex; flex-direction: column; background: var(--paper); padding: 26px 28px 22px; }
/* cards grid-stack so the tallest (VALUE) sets the height and switching
   never reflows the window */
.vx-stage .vcards { flex: 1 0 auto; display: grid; align-content: start; }
.vx-stage .vcard { grid-area: 1 / 1; visibility: hidden; }
.vx-stage .vcard.is-on { visibility: visible; }
.vx-stage .vcard.v-center { align-self: center; }
.vx-stage .vpad { margin-top: 18px; }
/* nav rail: Back ghost (hidden on card 1), mono counter, ink Next that
   names its destination. The counter is absolutely CENTRED at base since
   2026-07-19 (was .vq-only): the founder's every-window-steps round unified the
   treatment, closing the recorded Exhibit A flush-counter divergence — one
   nav grammar on all four multi-view windows. */
.vnav { position: relative; display: flex; align-items: center; gap: 14px; margin-top: 26px; }
.vnav-b {
  font: 500 10px/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
  background: none; border: 1px solid var(--ink); color: var(--ink);
  padding: 8px 12px; cursor: pointer; border-radius: 2px;
}
.vnav-b.vnav-next { background: var(--ink); color: var(--paper); margin-left: auto; }
.vnav-ct {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  font: 400 10px/1 var(--mono); letter-spacing: 0.14em; color: var(--muted);
}
/* ---------- .rnav — the rail's own Back/Next, PHONES ONLY (§108) -----------
   Built by site.js at the foot of each one-at-a-time rail, mirroring that
   window's .vnav labels and counter live. Same grammar as .vnav (mono caps,
   1px ink border, ink-filled Next) at a phone-legible size, so it reads as
   the control species the reader already knows rather than a fourth kind of
   thing. NOT a new button species — a phone restyle of the existing nav.
   44px minimum thumb target, which the window's own 28px .vnav-b misses;
   that one is left alone deliberately (raising it adds ~32px to every
   window's phone height and re-opens the boot min-heights for no gain, the
   new control being the one in reach).
   Hidden by default so desktop and iPad are byte-identical. */
.rnav { display: none; }
@media (max-width: 680px) {
  .rnav { position: relative; display: flex; align-items: center; gap: 12px; margin-top: 14px; }
  .rnav-b {
    font: 500 10px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
    background: none; border: 1px solid var(--ink); color: var(--ink);
    min-height: 44px; padding: 8px 14px; cursor: pointer; border-radius: 2px;
  }
  .rnav-b.rnav-next { background: var(--ink); color: var(--paper); margin-left: auto; }
  /* the counter RETURNS here (§89 hid .vnav-ct inside the window's nav row for
     a collision that does not exist in this one) — "01 / 05" is the missing
     "there are five of these" signal the founder was asking for.
     §114: IN FLEX FLOW, not absolute — the 50%-centered form sat UNDER the
     Next button whenever Back was ghosted and the label ran long
     ("NEXT: CUSTOMERS →" at 390 covered the counter's right half; latent
     since §108, caught when the two-row nav put more eyes on this row).
     flex:1 centers it in the space the buttons leave, so overlap is
     impossible at any label length. */
  .rnav-ct {
    flex: 1; text-align: center;
    font: 400 10px/1 var(--mono); letter-spacing: 0.12em; color: var(--muted);
    pointer-events: none;
  }
}

/* pipeline nav (2026-07-19, the freeze lifted): the same grammar in the
   machine tokens, footed under the frame like the steppers' rails */
.pipe-vnav { margin: 0; padding: 12px 14px 14px; border-top: 1px solid var(--card-rule); }
.pipe-vnav .vnav-b { border-color: #5A5A5A; color: var(--card-mut); } /* 3:1 non-text contrast */
.pipe-vnav .vnav-b:hover { color: var(--card-text); border-color: #6E6E6E; }
.pipe-vnav .vnav-b:focus-visible { outline-color: var(--card-text); }
.pipe-vnav .vnav-b.vnav-next { background: var(--card-text); color: #101010; border-color: var(--card-text); }
.pipe-vnav .vnav-b.vnav-next:hover { background: #FFFFFF; color: #101010; }
.pipe-vnav .vnav-ct { color: var(--card-mut); } /* --card-dim was 3.72:1, under AA */
/* fit-window nav sits inside the white plate under the stacked views */
.fv-plate .vnav { margin-top: 14px; }
/* ---------- §112 (2026-08-03): the stepper nav rides the TOP of every
   multi-view window at >=681px (the founder, off the BL analysis board: on
   a laptop the bottom nav sat below the fold, so a window read as a static
   page — "it's clear Next and Back... easy to see when you're at the top
   of the page"). CSS-ONLY relocation (flex order), no markup move: <=680
   never enters these rules, so the phone layout he ratified stays
   byte-identical by construction (his explicit carve-out — "I like how it
   currently looks on an iPhone"), the .rnav keeps reading the same nav
   live, and DOM/reading order stays the shipped content-then-nav
   everywhere. Each window's nav keeps its original vertical budget
   EXACTLY (the §91 EARNINGS foot holds 1.8px of slack, so net-zero is
   load-bearing, not tidiness): sample 16 = 7+8+1, value 26 = 12+13+1,
   fit 14 = 6+7+1; the pipe's padding is unchanged and its separator
   border swaps sides. Paper navs take the plate hairline tone, the
   pipe's stays the machine rule. ---------- */
@media (min-width: 681px) {
  .vq .b-stage > .vnav { order: -1; margin: 0 0 7px; padding-bottom: 8px; border-bottom: 1px solid #E4E4E0; }
  .vx-stage > .vnav { order: -1; margin: 0 0 12px; padding-bottom: 13px; border-bottom: 1px solid #E4E4E0; }
  .fv-plate { display: flex; flex-direction: column; }
  .fv-plate > .vnav { order: -1; margin: 0 0 6px; padding-bottom: 7px; border-bottom: 1px solid #E4E4E0; }
  .win[data-card="pipe"] { display: flex; flex-direction: column; }
  .pipe-frame { order: 1; }
  .pipe-vnav { border-top: 0; border-bottom: 1px solid var(--card-rule); }
}
/* §113's analysis-row compression block lives at the FOOT of this file —
   its ≥681 overrides tie the base .vq rules at (0,2,0) and must come
   LATER in source to win (media queries add no specificity; the §107/§108
   lesson). Do not move it up here. */
/* left index: clickable steps, ink rule + ink bullets track the active card */
.vsteps { list-style: none; margin-top: 34px; }
/* Desktop compensation for the 4-line bridge paragraph (2026-07-17 A2 port,
   BUILD-NOTES §53): the bridge cost 15px the 764px window does not have, so
   the column fits EXACTLY at 1440 with the rail gap at 19 (the bridge's colon
   hands off to the step index, so the tightened seam supports the grammar).
   §115 (2026-08-03): the 764 window and its exact-fit contract are DEAD —
   the §115 foot block retires the aspect and the window sits at its content
   floor (690, running 6px past the column). The 19px gap stays AS RATIFIED
   on the founder's BR board pick; do not churn it back to 34.
   Stacked layouts (<1148) have no window-height constraint and keep the 34px.
   Copy discipline: shortening the bridge is safe (the CTA's auto margin
   absorbs slack); ANY growth breaks the CTA flush. Re-measure under ?static=1
   after any bridge change - and after the five-cut round's pending
   button-font fix lands (font-family: inherit changes the vstep buttons'
   glyph metrics; this fit has zero slack, so re-verify and adjust the 19). */
@media (min-width: 1148px) { .vsteps { margin-top: 19px; } }
/* §90 RESTRUCTURE (audit-confirmed a11y): the .vsub list used to live INSIDE
   the .vstep <button> — invalid HTML (button permits phrasing content only)
   that flattened chip + question + all three bullets into one ~200-char
   accessible name and erased the list semantics for screen readers. The
   <li> is now the step's box (ink left rule, padding, rhythm, .is-on state,
   mirrored by JS alongside the button's) and the button holds ONLY the chip
   + question; .vsub is its sibling. Clicks bind on the li, so the bullets
   stay part of the click target exactly as they visually were. */
.vsteps > li { border-left: 2px solid var(--rule); padding: 2px 0 6px 18px; margin-top: 24px; }
.vstep {
  display: block; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  padding: 0;
}
.vstep .vstep-t { display: flex; align-items: center; gap: 10px; }
.vstep .vstep-n { font-size: 15.5px; font-weight: 600; color: var(--muted); }
.vsteps > li.is-on { border-left-color: var(--ink); }
.vstep.is-on .vstep-n { color: var(--ink); }
.vstep:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* hover affordance on the user-paced steppers (sample analysis + Exhibit A) so the
   rail steps read as clickable, mirroring the Buy-Side rail's hover (2026-07-17,
   the founder: signal the steppers are interactive without auto-motion). Excludes
   .bx-rail, which keeps its own hover + .bx-static default-cursor legend state; the
   active step is excluded so hovering it never lightens its ink rail. On the li
   since §90 — the whole step (bullets included) is the click target. */
.vsteps:not(.bx-rail) > li { cursor: pointer; }
.vsteps:not(.bx-rail) > li:not(.is-on):hover { border-left-color: var(--faint); }
.vsteps:not(.bx-rail) > li:hover .vstep-n { color: var(--ink); }
/* (the §56 one-time rail wave lived here; retired 2026-07-18 when the one-pass
   tours shipped - during a pass the rails light for real via .is-on, the
   Buy-Side legend grammar, so the simulated wave had nothing left to do) */
.vsub { list-style: none; margin-top: 8px; }
.vsub li {
  position: relative; padding-left: 15px; margin-top: 5px;
  font-size: 14px; line-height: 1.5; color: var(--muted);
}
.vsub li::before {
  content: ""; position: absolute; left: 0; top: 0.52em;
  width: 4px; height: 4px; background: var(--faint);
}
.vsteps > li.is-on .vsub li { color: var(--body); }
.vsteps > li.is-on .vsub li::before { background: var(--ink); }

/* ----- card roll-in (2026-07-15; replaces the v4 vg01-vg40 timeline) -----
   site.js assigns .vb + a --d delay per beat group; one shared 400ms rise.
   Gated by .motion (base styles ARE the assembled frame) and play-state
   gated by .win.is-live exactly like the old one-shot, so the first roll
   fires on reveal and pauses offscreen. Stepping and the replay button
   re-trigger via the .vstrip reflow (the vg-restart mechanism). Each
   card's full roll is ~1.8s - under WCAG 2.2.2's 5s line, so the window
   carries NO pause button (replay only). */
@keyframes vroll { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
.motion .vb {
  animation: vroll 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--d, 0ms);
  /* play-state via longhand: pauses and resumes on the same frame;
     .win.is-live supplies --vx-play (deleting that rule freezes every
     beat invisible at frame 0 - see the CIM/pipeline note) */
  animation-play-state: var(--vx-play, paused);
}
.vcard.vstrip .vb { animation: none !important; }
.win.is-live { --vx-play: running; }

/* ---------- Buy-Side rows 1-2: capacity lead + rail, fit hexagon
   (2026-07-17 repositioning, variant F ported; BUILD-NOTES §55). Supersedes the
   2026-07-12 dark process flowchart (.flow/.fc/.fgate/.fsplit/.flanes/.fnote) and
   the 2026-07-15 docked redacted-rows fit profile (.fit-dock/.fit-plate/.fit-rows)
   - both removed when row 2 became "how fit is decided" + the six-axis hexagon.
   Shared fit primitives below are reused by the hexagon head and its per-category
   scored readout rows. --------------------------------------------------------- */
.gap-flex { display: flex; flex-direction: column; align-self: stretch; }
.fit-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 12px; border-bottom: 1px solid var(--rule);
}
.fit-proj { font: 600 15px/1.2 var(--sans); color: var(--ink); letter-spacing: -0.01em; }
.fit-chip {
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.08em;
  color: var(--ink); border: 1px solid var(--ink);
  padding: 5px 8px; border-radius: 2px; white-space: nowrap;
}
.fit-row { display: flex; align-items: center; gap: 16px; margin-top: 11px; }
/* score meter: a hairline track filled to the category's illustrative 0-5 score
   (fill width = score/5). Was the redacted criteria bar; the fit readout reuses it. */
.fit-track { flex: 1; height: 6px; border-radius: 2px; background: #EFEFEB; overflow: hidden; }
.fit-track i { display: block; height: 100%; background: var(--ink); border-radius: 2px; }
.fit-foot {
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--rule);
  font: 500 9.5px/1.5 var(--mono); letter-spacing: 0.08em; color: var(--muted);
}

/* Row 1: the capacity credential leads (.bx-lead h3 + para), a colon hands off
   to the rail. The rail reuses the site stepper species (.vsteps/.vstep/
   .ph-chip); .bx-rail scopes a tighter rhythm so the three claims + six subs
   fit beside the pipeline window. */
.bx-lead { margin-top: 14px; }
.bx-lead h3 {
  font-size: 24px; line-height: 1.25; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; text-wrap: balance; max-width: 19em;
}
.bx-lead p { margin-top: 12px; font-size: 15.5px; color: var(--body); max-width: 28em; }
.bx-lead .bx-colon { margin-top: 12px; }
/* ----- the SPOKEN LEAD (2026-07-20, board pick T; BUILD-NOTES §67) ---------
   The hero grammar downpage: sentence 2 speaks word by word inside a drawn
   pen, one-shot on first half-view (site.js flips .is-in; threshold 0.5 so
   the pass starts with the headline properly on screen, not at the fold
   edge). Third carrier of the per-line background pen (.hero-ul / .th-ul
   precedent: each carrier duplicates the device with its own comment; the
   hero geometry — 0.07em rule seated 0.10em under the text — reads right
   at 24px). ALL delays live here or inline (--d), no timer chain. Base
   styles ARE the settled frame. No will-change: the §60 compositor hint
   was a LOAD-contention fix; this fires mid-scroll on an idle thread. */
.bx-ul {
  display: inline;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding-bottom: 0.10em;
  background-image: linear-gradient(var(--ink), var(--ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.07em;
}
/* pre-states, .motion only (the static/no-JS/reduced poster is the base) */
.motion .bx-speak .bx-w {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.35em);
  transition: opacity 320ms ease, transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--d, 0ms);
}
.motion .bx-speak .bx-w.bx-w1 { transition-duration: 620ms; } /* sentence 1 settles as one unit */
.motion .bx-speak .bx-ul {
  background-size: 0 0.07em;
  transition: background-size 520ms cubic-bezier(0.16, 1, 0.3, 1) 3160ms;
}
.motion .bx-speak.is-in .bx-w { opacity: 1; transform: none; }
.motion .bx-speak.is-in .bx-ul { background-size: 100% 0.07em; }
.svc-copy .vsteps.bx-rail { margin-top: 14px; }
/* rhythm loosened 2026-07-19 (fresh-eyes): the 13/5/3 compression existed to
   fit 3x2 bullets beside the old 1/1 window; with 3x3 rails and the taller
   7/8 frame + nav, the looser rhythm re-flushes the column to the caption */
.bx-rail > li { margin-top: 24px; padding-bottom: 2px; } /* §90: box moved to the li */
.bx-rail .vsub { margin-top: 8px; }
.bx-rail .vsub li { margin-top: 5px; }
/* the rail is a live legend of the pipeline window AND clickable (site.js).
   Hover cues the affordance. Since §91 the rail NAVIGATES under reduced
   motion / ?static=1 too (site.js drives the panels through __pipeNav), so
   .bx-static — the cursor-default legend — is only the null-guard fallback
   when that nav is missing; real no-JS renders the full rail, clicks inert. */
.bx-rail:not(.bx-static) > li:hover { border-left-color: var(--faint); }
.bx-rail:not(.bx-static) > li:hover .vstep-n { color: var(--ink); }
.bx-rail:not(.bx-static) > li { cursor: pointer; }
.bx-rail.bx-static > li, .bx-rail.bx-static .vstep { cursor: default; }

/* Row 2: scope-note under the bullets; the CTA pins to the hexagon window's
   foot line via the gap-flex column (margin-top:auto). */
.gap-copy p.scope-note { margin-top: 18px; font-size: 13.5px; color: var(--muted); }
.bx-cta { margin-top: auto; padding-top: 26px; }

/* the fit hexagon plate: white paper under the standard dark title bar. Six
   category labels on five unnumbered rings, an illustrative polygon, no
   composite score (a plotted score UHR would have to evidence). */
.fitx-plate { background: var(--paper); padding: 20px 24px 16px; }
.fitx-plate .fit-head { padding-bottom: 14px; }
.fitx-hex { display: block; width: 100%; height: auto; margin: 2px 0 0; }
.fitx-hex .fx-l { font: 500 9.5px var(--mono); letter-spacing: 0.08em; fill: var(--ink); }
/* §91: OPERATIONAL CAPABILITY's phone-only two-line form rests hidden at
   desktop (the ≤680 block swaps the pair — see the phone hexagon note) */
.fitx-hex .fx-2l { display: none; }
.fitx-plate .fit-foot { margin-top: 12px; }
/* committee one-pager: a per-category fit readout beneath the chart - each of the
   six axes with a score meter (.fit-track) filled to its illustrative 0-5 score and
   the number at right. The criteria behind the scores stay confidential (plate foot). */
.fitx-crit { margin-top: 6px; }
.fitx-crit-h {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 12px 0 8px;
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.fitx-scale { letter-spacing: 0.1em; }
.fitx-crit .fit-row { display: flex; align-items: center; gap: 14px; margin-top: 9px; }
.fx-cat {
  flex: none; width: 150px; white-space: nowrap;
  font: 500 9.5px/1.2 var(--mono); letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--ink);
}
.fx-sc {
  flex: none; width: 15px; text-align: right;
  font: 600 12.5px/1 var(--sans); font-variant-numeric: tabular-nums; color: var(--ink);
}

/* ---------- fit window views (2026-07-19, variant M ported; §58) ------------
   Row 2's fit window is a THREE-VIEW stepper driven by the copy-column rail,
   the same species as row 1's pipeline legend: GEOGRAPHY (program territory on
   a US silhouette) -> SECTORS (core / adjacent / out of scope) -> SCORECARD
   (the .fitx-* hexagon above, carried over verbatim from the 2026-07-17 static
   window). Species reused rather than redefined: .win/.win-bar/.win-status/
   .win-ctrls/.win-replay[data-tour], .vsteps/.vstep/.ph-chip/.vsub,
   .fit-head/.fit-proj/.fit-chip/.fit-foot, .fitx-*. The retired tile-grid map
   form (variant G: .fv-map, .fm-* and .fv-sw-dot) was pruned at port - the
   silhouette is the shipped form. */
.gap-copy .vsteps.fv-rail { margin-top: 14px; }
.fv-rail > li { margin-top: 13px; padding-bottom: 2px; } /* §90: box moved to the li */
.fv-rail .vsub { margin-top: 5px; }
.fv-rail .vsub li { margin-top: 3px; }
/* the advise line sits between the rail and the scope note, body voice */
.gap-copy p.fv-advise { margin-top: 20px; }

/* views grid-stack so the tallest (scorecard) sets the plate height */
.fv-plate { background: var(--paper); padding: 20px 24px 16px; }
.fv-views { display: grid; }
.fv-view { grid-area: 1 / 1; visibility: hidden; display: flex; flex-direction: column; }
.fv-view > * { flex: 0 0 auto; }
/* each view's foot stamp anchors to the plate bottom (2026-07-19): the views
   grid-stack to the tallest (scorecard), and before this the shorter map
   view left ~100px of blank plate between its stamp and the new nav rail */
.fv-view .fit-foot { margin-top: auto; padding-top: 11px; }
.fv-view.is-on { visibility: visible; }
.fv-kick { font: 500 9.5px/1 var(--mono); letter-spacing: 0.1em; color: var(--muted); }
.fv-view .fit-head { margin-top: 10px; padding-bottom: 12px; }
.fv-read { margin-top: 10px; font-size: 13px; line-height: 1.5; color: var(--body); }
/* .fv-view .fit-foot margin now auto (foot anchors to plate bottom, above) */
.fv-view .fitx-crit { margin-top: 6px; }

/* view 1: program territory on the US silhouette (Wikimedia PD state paths).
   Encoding is FILL-level - dots cramp the small eastern states: footprint ink,
   active-target states mid, white space light, AK/HI outside the territory.
   Canvas-tone strokes separate adjacent fills; every value is neutral, so the
   grayscale audit passes (#C4C4C0 and #4A4A46 are spread 4 and 4). */
.fv-usmap { display: block; width: 100%; height: auto; margin-top: 16px; }
.fv-usmap path { stroke: var(--canvas); stroke-width: 1; }
.fv-usmap .fs-fp { fill: var(--ink); }
.fv-usmap .fs-act { fill: #C4C4C0; }
.fv-usmap .fs-ws { fill: #EFEFEB; }
.fv-usmap .fs-out { fill: var(--paper); stroke: var(--rule); }
.fv-usmap .fs-l { font: 500 15px var(--mono); letter-spacing: 0.06em; fill: var(--canvas); stroke: none; }
/* All-state annotation. 14px in the 959-unit viewBox renders 7.58px at the
   ACTUAL 519px plate — the first pass sized this 12.5px against an assumed
   592px plate and shipped at 6.77px, under the site's 7.5px type floor;
   re-measured and corrected 2026-07-19, verified 0 label collisions at 14px.
   Measure the plate, never assume it. The six small Atlantic states sit
   offshore with hairline leaders; the whole layer hides ≤680px (see the phone
   block — 48 labels do not fit a 316px map above the floor). */
.fv-usmap .fs-l2 { font: 500 14px var(--mono); letter-spacing: 0.03em; fill: #4A4A46; stroke: none; }
.fv-usmap .fs-ld { stroke: #90908B; stroke-width: 0.75; }
.fv-legend {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px;
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.08em; color: var(--muted);
}
.fv-legend .fv-ct { margin-left: auto; letter-spacing: 0.1em; color: var(--ink); }
.fv-sw { display: inline-block; width: 9px; height: 9px; margin-right: 6px; vertical-align: -1px; }
.fv-sw-fp { background: var(--ink); }
.fv-sw-act { background: #C4C4C0; }
.fv-sw-mkt { background: #EFEFEB; }
/* silhouette is landscape by nature; give its legend row extra air */
.fv-view[data-fview="geo"] .fv-usmap + .fv-legend { margin-top: 18px; }

/* view 2: fit attributes, four bands (high fit / core / adjacent / low fit) */
.fv-band { margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--rule); }
.fv-band:first-of-type { margin-top: 12px; border-top: 0; padding-top: 0; }
.fv-band-h {
  display: flex; align-items: baseline; justify-content: space-between;
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.1em; color: var(--muted);
}
.fv-band-h .fv-bn { letter-spacing: 0.08em; color: var(--faint); }
.fv-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 11px; }
/* adjacent chips: outlined kin of .ph-chip (core uses .ph-chip solid) */
.fv-chip {
  display: inline-flex; align-items: center; flex: none; height: 22px; padding: 0 9px;
  border-radius: 2px; border: 1px solid var(--rule-2);
  font: 500 9.5px/1 var(--mono); letter-spacing: 0.06em; color: var(--body);
  white-space: nowrap;
}
.fv-oos { margin-top: 10px; font-size: 13px; line-height: 1.5; color: var(--muted); }
/* high-fit signal list (2026-07-21): square-bullet kin of .rlist at window
   scale; illustrative screen excerpt, qualitative only, no weights/thresholds
   (the moat lives in what the low-fit band withholds). */
.fv-hi { list-style: none; margin: 9px 0 0; padding: 0; display: grid; gap: 8px; }
.fv-hi li { position: relative; padding-left: 15px; font-size: 12.5px; line-height: 1.45; color: var(--body); }
.fv-hi li::before { content: ""; position: absolute; left: 0; top: 6px; width: 5px; height: 5px; background: var(--ink); }

/* ---------- Investing visual - static window (2026-07-12) ----------------------------
   Title-bar-only chrome over a white plate; a three-row plain-terms table
   describing the capital itself. No loop, no pause button, no data-card. */
.iv-plate { background: var(--paper); padding: 26px 28px 24px; }
.iv-head {
  font-size: 15px; font-weight: 600; color: var(--ink);
  letter-spacing: -0.01em;
  padding-bottom: 14px; border-bottom: 1px solid var(--rule-2);
}
/* the FIXED AND OPEN ledger (2026-07-19; replaces the .iv-terms dl): two
   columns whose asymmetry argues — 2 fixed items against 5 open ones */
/* THREE ENDINGS board (2026-07-19 §62, the founder's pick off the runner-up
   board; replaces the FIXED AND OPEN ledger's .fo). Geometry is
   board-faithful — the rendering he ratified — incl. the 18px first-column
   indent; the phone block stacks like the old ledger did. */
.t3 { display: grid; grid-template-columns: 1fr 1fr 1fr; margin-top: 10px; }
.t3 > div { padding: 18px 18px 22px; }
.t3 > div + div { border-left: 1px solid var(--rule); }
.t3-k { font: 500 9.5px/1 var(--mono); letter-spacing: 0.12em; color: var(--faint); }
.t3-s { margin-top: 13px; font-size: 15.5px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; line-height: 1.3; }
.t3-u { margin-top: 7px; font-size: 13px; line-height: 1.5; color: var(--muted); }
.t3-close { margin-top: 4px; padding-top: 15px; border-top: 1px solid var(--rule); text-align: center; font-size: 13.5px; color: var(--body); }
/* one-shot roll-out (2026-07-21, the founder — supersedes §62's always-static
   ruling; the §62 motion ceiling "one-shot CSS draw-on-reveal" is exactly what
   ships): endings 01 -> 02 -> 03 -> closer rise in sequence, ~2.6s, then the
   board is still. The beats are ARMED BY JS (.iv-arm, added at wiring time)
   so a script failure can never strand the board invisible — the §59 lesson;
   base styles ARE the settled frame. .is-live runs the play-state (the value
   exhibit's --vx-play grammar), .iv-set snaps every beat to its finished
   frame (engagement / completion / mid-session reduced-motion), .ivstrip is
   the reflow restart hook for replay. Delays absolute on one clock. */
@keyframes ivroll { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.motion .iv-anim.iv-arm .t3 > div, .motion .iv-anim.iv-arm .t3-close {
  animation: ivroll 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-play-state: var(--iv-play, paused);
}
.motion .iv-anim.iv-arm .t3 > div:nth-child(1) { animation-delay: 150ms; }
.motion .iv-anim.iv-arm .t3 > div:nth-child(2) { animation-delay: 800ms; }
.motion .iv-anim.iv-arm .t3 > div:nth-child(3) { animation-delay: 1450ms; }
.motion .iv-anim.iv-arm .t3-close { animation-delay: 2100ms; }
.motion .iv-anim.is-live { --iv-play: running; }
.motion .iv-anim.iv-set .t3 > div, .motion .iv-anim.iv-set .t3-close,
.iv-anim.ivstrip .t3 > div, .iv-anim.ivstrip .t3-close { animation: none !important; }

/* ---------- Contact -------------------------------------------------------------------- */
/* honeypot (2026-07-21, real-sender round): visually removed, unfocusable —
   bots fill it, the contact function then sends nothing */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 88px;
  align-items: start;
}
.contact h2 { font-size: clamp(32px, 3.4vw, 46px); letter-spacing: -0.025em; }
.contact-sub { margin-top: 18px; font-size: 17px; color: var(--body); max-width: var(--measure); }
/* contact reuses the orientation squares (.rlist). These bullets WRAP, unlike
   the orientation cards' one-liners, so the gap opens up and the measure is
   capped; the NDA/confidence line rides at body tone rather than the old
   fine-print muted, which is deliberate (it is a trust signal, not fine print) */
.contact-list { margin: 22px 0 0; gap: 14px; max-width: 34em; }
/* these wrap, so they orphan ("...the people who / do."); same progressive
   enhancement the subheads and footer disclaimer already use */
.contact-list li { text-wrap: pretty; }

/* the form - plain fields, hairline borders, nothing decorative */
.contact-form { display: grid; gap: 22px; }
.ff-row { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.ff { display: grid; gap: 9px; min-width: 0; }
.ff label {
  font: 500 10.5px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
/* --muted: "(optional)" is the sole optionality indicator, so it is
   load-bearing label text and must clear AA at label size */
.ff label span { text-transform: none; letter-spacing: 0.02em; color: var(--muted); }
.ff input,
.ff select,
.ff textarea {
  width: 100%;
  font: 400 15px/1.4 var(--sans);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule-2);
  border-radius: 2px;
  padding: 12px 14px;
}
.ff select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23666661' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  padding-right: 36px;
}
.ff textarea { resize: vertical; min-height: 128px; }
.ff input:focus-visible,
.ff select:focus-visible,
.ff textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -1px;
}
.contact-form .btn { cursor: pointer; }
.form-actions { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
/* --muted, not --faint: this is load-bearing instruction + privacy disclosure
   (the only place the mailto fallback address appears near the form) and must
   clear WCAG AA at 12px; the link is underlined at rest — at this size color
   alone cannot distinguish it */
.form-note { font-size: 12px; line-height: 1.6; color: var(--muted); max-width: 30em; }
.form-note a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.form-note a:hover { text-decoration-thickness: 2px; }

/* ---------- Footer ----------------------------------------------------------------------- */
/* padding-top 72 (2026-07-17, was 54): the footer divider joins the uniform
   72-both-sides rhythm; the 64 bottom edge has no rule below it and stays */
.footer { border-top: 1px solid var(--rule); padding: 72px 0 64px; }
.footer-top { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; flex-wrap: wrap; }
.footer .wordmark { font-size: 13px; }
.footer-legal { font-size: 12.5px; color: var(--muted); }
.footer-disc {
  margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--rule);
  font-size: 11.5px; line-height: 1.65; color: var(--muted);
  /* full .wrap width (2026-07-13, the founder): a normal footnote disclosure runs
     the whole content column — the old 56em cap wrapped it at ~half the page
     and left the right side empty. The .nb spans still guard the legal sense
     units at any width. §70: .footer-disc became a WRAPPER (two <p>s) — this
     rule now carries the ONE divider (border-top/padding-top/margin-top) and
     the inherited text styling; the paragraphs take the spacing below. */
}
/* §70: modest separation between the two disclaimer paragraphs (the reset zeroes
   <p> margins, so this is the only gap). 12px sits in the 10–14px band and
   echoes the footer's restrained rhythm without reading as a section break. */
.footer-disc p + p { margin-top: 12px; }

/* ---------- Team page (team.html — 2026-07-22 §78 board AD; §79 own page) -- */
/* Moved off the main page the same day it shipped (the founder: the scroll
   to contact ran too long). Slim cards: photo / name / role only — the
   founder's ruling and the researched convention — each expanding the ONE
   shared detail panel (.tmd), which JS parks under the clicked card's row.
   Five dashed PLACEHOLDER seats + the founder LAST (§80: alphabetical by
   last name, "Uhr" sorts late): the dashed frame + label is the honesty
   device — labeled slots, never invented people. The frame is an OUTLINE,
   not a border+padding+negative-margin sandwich (§80): outlines are painted
   outside the box with zero layout impact, so every card shares one
   baseline. The old trick lifted placeholder cards 17px, which was
   invisible while a real card led the grid and would have pulled the whole
   first row off its top margin once the founder moved to the end. */
.tm-page { padding: 56px 0 84px; }
.tm-page .eyebrow { display: block; margin-bottom: 18px; }
.tm-h1 { font-size: 34px; letter-spacing: -0.02em; }
/* FULL CONTENT COLUMN, GREEDY FILL (§86, the founder: "it should go all the
   way to the right before going down to the next line"). Two causes were
   stacked: a 44em cap held the line to 726px inside a 1064px column (the
   text was filling 97% of its own box, just a box two-thirds the width of
   the page), and the site-wide `text-wrap: pretty` on .sec-sub reserves
   words for the last line, which is exactly the early break he was seeing.
   No cap matches the main site's own full-width subhead (.orient .sec-sub
   is uncapped too); `auto` restores ordinary greedy wrapping. `pretty`
   still governs every NARROW .sec-sub, where avoiding an orphan is worth
   more than filling the line. This holds whatever copy he writes here. */
.tm-page .sec-sub { max-width: none; text-wrap: auto; }
/* §117 (2026-08-03, the go-live nit): FOUR columns — the open seats left the
   page, and the founder wants the four named people on ONE row at desktop.
   Cards go ~329px -> ~238px at the 1064px column (his knowing trade, "we
   might need to shrink the photos"); every master still clears 2x at the
   new width (smallest is Jeff's 800px against a ~476px need). The 2-col
   tiers below are untouched — four seats fold 2x2 at ≤1147 and ≤680 with
   no orphan row anywhere. */
.tm-grid { margin-top: 44px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 44px 38px; }
/* (§85's specialist-advisor group was removed the same session — the founder
   agreed the tax/accounting seats contradicted the footer disclaimer. The
   multi-grid support in the page JS is kept: it is general, proven, and
   costs nothing with one grid.) */
.tm-card { min-width: 0; cursor: pointer; }
.tm-card.is-ph { outline: 1px dashed var(--rule-2); outline-offset: 16px; }
.tm-photo { aspect-ratio: 1 / 1; background: var(--wash); display: flex; flex-direction: column; gap: 12px; align-items: center; justify-content: center; overflow: hidden; }
/* real headshots (§81, the sanctioned no-photography exception): ONE square
   master fills both frames — the square card and the 4/5 detail crop — via
   cover.
   COLOR-ON-ENGAGEMENT (§82, the founder's idea): the page is monochrome AT
   REST and a face comes to life when you reach for it — hover, keyboard
   focus, or the open card, and the open profile's photo. This REVERSES
   §81's baked-in grayscale: the file is now a COLOR master and CSS decides
   when the color shows. The §81 argument (never `filter: grayscale()`)
   assumed color was contraband; here color is the deliberate payoff, so it
   has to exist in the asset. The grayscale AUDIT is unaffected — it reads
   computed CSS colors, and a filter is not a color; the page's own tokens
   are still 100% neutral. Cost of the reversal, accepted: a saved copy of
   the image is in color, and the deployed asset carries chroma. */
.tm-photo img, .tmd-photo img {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(1);
  transition: filter 0.5s ease;
}
/* §108: the HOVER trigger is now behind a real-pointer query. iOS Safari
   applies :hover on touch — on a tap, and often mid-scroll on a finger that
   grazes a card — so the founder saw photos "come to life" while he was just
   scrolling and dragging. The other three triggers are untouched, and the
   touch path is still fully served: .is-open lands on his tap. Keyboard
   parity stays with :focus-within. The §82 four-trigger grammar is intact;
   only the pointer type that can fire the first one changed. */
@media (hover: hover) and (pointer: fine) {
  .tm-card:hover .tm-photo img { filter: grayscale(0); }
}
.tm-card:focus-within .tm-photo img,
.tm-card.is-open .tm-photo img,
.tmd.is-open .tmd-photo img { filter: grayscale(0); }
.tm-sil { width: 64px; height: 64px; fill: var(--tint); }
.tm-phl { font: 500 9.5px/1 var(--mono); letter-spacing: 0.16em; color: var(--faint); }
.tm-name { margin-top: 18px; font-size: 16.5px; letter-spacing: -0.01em; }
.tm-name.tm-ghost { font: 500 11px/1.2 var(--mono); letter-spacing: 0.14em; color: var(--faint); text-transform: uppercase; margin-top: 20px; }
.tm-role { margin-top: 7px; font: 500 9.5px/1.4 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
/* the whole card is clickable; the name button is the accessible control */
.tm-open { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; letter-spacing: inherit; text-align: left; text-transform: inherit; }
.tm-card.is-open .tm-open { text-decoration: underline; text-underline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .tm-card:hover .tm-open { text-decoration: underline; text-underline-offset: 3px; }
}
.tm-bar { display: block; height: 8px; background: var(--wash); }
.tm-bar + .tm-bar { margin-top: 8px; }
/* the shared detail panel: a full grid row wherever JS parks it (AmSec
   profile family — name / small-caps role / bio left, large photo right) */
.tmd { grid-column: 1 / -1; display: none; position: relative; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 34px 0 40px; margin: 4px 0; }
.tmd.is-open { display: block; }
.tmd:focus { outline: none; }
/* stretch, not start (§83): the photo keeps its 4/5 height and sets the row,
   the copy column stretches to match, and the ghost bio flexes into whatever
   is left — so its bottom edge lands flush with the photo's at any height,
   on every seat, with nothing hand-measured */
.tmd-grid { display: grid; grid-template-columns: 7fr 5fr; gap: 0 56px; align-items: stretch; }
.tmd-copy { display: flex; flex-direction: column; }
.tmd-name { font-size: 27px; letter-spacing: -0.02em; }
.tmd-name.tm-ghost { font: 500 13px/1.2 var(--mono); letter-spacing: 0.14em; color: var(--faint); text-transform: uppercase; }
.tmd-role { margin-top: 9px; font: 500 10px/1.4 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
/* Labels, not addresses (§82, the founder): every seat's mail link points at
   info@uhradvisory.com, so printing the address six times would be noise —
   "Email" and "LinkedIn" carry it. Sentence case in the mono face keeps the
   family while separating them from the caps role label above. Ghost seats
   show the same pair, inert and unlinked. */
.tmd-links { margin-top: 14px; font: 400 12px/1.6 var(--mono); color: var(--muted); }
.tmd-links a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.tmd-links a:hover { text-decoration-thickness: 2px; }
.tmd-links .sep { padding: 0 4px; color: var(--rule-2); }
.tmd-links.is-ghost { color: var(--faint); }
/* 36em is the SHIPPED cap and it stays (2026-07-28). Note the em resolves
   against the PANEL's 16px, not the bio's own 14px, so this measures 576px
   and sets an 85-character line — 10 over the 45-75 band §59 made the
   standard. It was tried at 31em/72 chars and REVERTED the same session:
   the copy column is 588px, so capping to 496 left a 148px hole between the
   text and the photo (the founder's "a lot of white space… wrapping almost
   weird"). 36em keeps the gutter at 68px, near the grid's own 56px, so it
   reads as a gutter and not a void. Composition won; the measure overage is
   recorded and accepted. Removing the cap entirely would close the gutter
   to exactly 56px at 89 chars if that trade is ever preferred. */
.tmd-bio { margin-top: 18px; max-width: 36em; flex: 1; min-height: 0; }
.tmd-bio p { font-size: 14px; line-height: 1.65; color: var(--body); }
.tmd-bio p + p { margin-top: 12px; }
/* the ghost box: ruled lines on the bio's own 17px rhythm (8px bar + 9px
   gap), painted as a repeating gradient so the block fills ANY height to the
   pixel — a fixed stack of bars could never stay flush as the photo scales.
   TWO layers: the top one punches a blank line every sixth (period 102px =
   5 lines of text + 1 of air), so the block reads as paragraphs rather than
   a loading skeleton. The punch-out is --canvas because the panel sits on
   the page ground; if the panel ever gets its own fill, change both. */
.tmd-bio.is-ghost {
  background-image:
    repeating-linear-gradient(transparent 0 85px, var(--canvas) 85px 102px),
    repeating-linear-gradient(var(--wash) 0 8px, transparent 8px 17px);
}
.tmd-photo { align-self: start; aspect-ratio: 4 / 5; background: var(--wash); display: flex; flex-direction: column; gap: 14px; align-items: center; justify-content: center; overflow: hidden; }
/* FLUSH BY CONSTRUCTION (2026-07-28, the founder: "exactly flush with the
   bottom of the photo"). A real bio is TALLER than a 4/5 photo at every
   width this column allows — measured: even uncapped the copy still ran
   91px past it — so widening the text can never close the gap. The PHOTO
   stretches to the copy instead. Nothing is hand-measured, so it holds for
   any bio length and any future seat. The square master + object-fit:cover
   just crops a taller portrait (0.66 here vs 4/5); verified the head and
   shoulders survive it.
   SCOPED TO .has-bio ON PURPOSE: a GHOST seat runs the opposite contract —
   there the photo's 4/5 SETS the row height and the ghost box flexes to
   meet it (§83). Stretch both and the row has nothing to size against and
   collapses. site.js sets has-bio in the same branch that renders the
   template, so the two can never disagree. */
.tmd.has-bio .tmd-photo { align-self: stretch; aspect-ratio: auto; }
.tmd-photo.is-ph { background: transparent; border: 1px dashed var(--rule-2); }
.tmd-photo .tm-sil { width: 84px; height: 84px; }
.tmd-close { position: absolute; top: 12px; right: 0; font: 500 9.5px/1 var(--mono); letter-spacing: 0.14em; color: var(--muted); background: none; border: 0; cursor: pointer; padding: 6px 2px; }
.tmd-close:hover { color: var(--ink); }

/* ---------- Client sign-in page (clients.html, 2026-07-22 §78: board AH) ---
   A second deployed page, so its rules live here with the site's. Reuses the
   global .ff field species and .btn; everything else is .cs-*. The page is a
   credibility device — see the authoring comment in clients.html. */
.cs-body { min-height: 100vh; display: flex; flex-direction: column; }
.cs-top { border-bottom: 1px solid var(--rule); background: var(--canvas); }
.cs-topin { max-width: 1160px; width: 100%; margin: 0 auto; padding: 0 48px; height: 64px; display: flex; align-items: center; justify-content: space-between; }
.cs-back { font: 500 10.5px/1 var(--mono); letter-spacing: 0.12em; color: var(--muted); }
.cs-back:hover { color: var(--ink); text-decoration: none; }
.cs-main { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 56px 24px; }
.cs-card { width: 100%; max-width: 404px; background: var(--paper); border: 1px solid var(--rule); border-radius: 6px; padding: 36px 36px 30px; }
.cs-h { font-size: 21px; letter-spacing: -0.015em; }
.cs-sub { margin-top: 9px; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.cs-form { margin-top: 26px; display: grid; gap: 18px; }
/* THE SECOND SANCTIONED CHROMATIC EXCEPTION (2026-07-22 §84, the founder's
   call, made knowing it defies the palette): an error message has to read as
   an error, and grayscale cannot say "this failed" on a form. Scope is this
   ONE selector — bar and text share the single value, deep oxblood rather
   than a signal red so it still sits in the house register (#8A1616 on
   --paper measures 9.5:1, well past AA). The custom property is declared ON
   the selector, never in :root, so the chroma has no path to leak: nothing
   else can inherit it or reuse it by name. Excluded from the grayscale audit
   BY SELECTOR, exactly like `.dots i`. */
.cs-err { --err: #8A1616; display: none; font-size: 13px; line-height: 1.5; font-weight: 600; color: var(--err); border-left: 2px solid var(--err); padding-left: 10px; }
.cs-err.is-on { display: block; }
.cs-form .btn { width: 100%; text-align: center; cursor: pointer; padding: 13px 26px; }
.cs-form .btn[disabled] { opacity: 0.55; cursor: default; }
.cs-trouble { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--rule); font-size: 12px; line-height: 1.6; color: var(--muted); }
.cs-trouble a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.cs-prov { margin-top: 20px; text-align: center; font-size: 12.5px; line-height: 1.6; color: var(--muted); }
.cs-foot { padding: 26px 24px; text-align: center; font-size: 11.5px; color: var(--faint); }
@media (max-width: 680px) {
  .cs-topin { padding: 0 22px; }
  .cs-card { padding: 28px 24px 24px; }
}

/* ---------- Motion --------------------------------------------------------------------------
   Reveal state exists only when JS adds .motion to <html>; no-JS and
   prefers-reduced-motion render everything fully visible and static.  */
.motion .reveal {
  opacity: 0.06;
  transform: translateY(16px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.motion .reveal.is-in { opacity: 1; transform: none; }

/* ---------- First-load boot (2026-07-22 §89 — supersedes §87's
   content-visibility deferral) --------------------------------------------
   The §87 fix deferred the five below-fold sections with content-visibility:
   auto so the ~7.1s entrance owns the first seconds. Two field defects
   (the founder's iPad/iPhone reports): (1) older-iPad Safari has no
   content-visibility, so those devices — exactly the ones that lag — got
   nothing; (2) where it IS supported, sections render on scroll APPROACH,
   which on a slower GPU reads as content "loading in" while you scroll.
   Now an inline <head> script (index.html — it runs before the parser
   builds the body, same timing as parse-time CSS) sets html.boot, these
   rules suppress the sections' children with plain display:none (universal
   support), and the SAME script releases them: staged top-to-bottom from
   7500ms (just after the entrance settles), or all at once on first user
   intent / beforeprint / a reduced-motion flip. After release the page is
   FULLY rendered — no on-scroll pop-in anywhere, on any engine. The
   min-heights are the measured section heights (1440 / 768 / 390; §87,
   re-measured at §91 and again at §108 when Buy-Side left the page) and
   only steer the scrollbar during the boot window, never layout after it.
   Boot never engages for #hash loads, ?static=1, reduced motion, or no-JS
   — every documented measurement recipe keeps full-layout semantics.
   Release is INLINE in the head script, not site.js (§59 lesson: the hide
   and the restore must live or die together). */
html.boot #approach:not(.lit) > *, html.boot #sell-side:not(.lit) > *,
html.boot #investing:not(.lit) > *,
html.boot #contact:not(.lit) > * { display: none; }
html.boot #approach:not(.lit)  { min-height: 495px; }
html.boot #sell-side:not(.lit) { min-height: 2090px; }  /* §113 re-measure */
html.boot #investing:not(.lit) { min-height: 516px; }
html.boot #contact:not(.lit)   { min-height: 627px; }
@media (max-width: 1147px) {
  html.boot #approach:not(.lit)  { min-height: 995px; }
  html.boot #sell-side:not(.lit) { min-height: 3691px; }  /* §113 re-measure */
  html.boot #investing:not(.lit) { min-height: 823px; }
  html.boot #contact:not(.lit)   { min-height: 1038px; }
}
@media (max-width: 680px) {
  /* re-measured 2026-07-22 twice: after the §89 rail hiding, then again
     when the addendum brought the rails back one-step-at-a-time */
  html.boot #approach:not(.lit)  { min-height: 1020px; }
  html.boot #sell-side:not(.lit) { min-height: 4075px; }  /* §113 re-measure */
  html.boot #investing:not(.lit) { min-height: 1067px; }
  html.boot #contact:not(.lit)   { min-height: 1406px; }
}
/* belt and braces under the head script's beforeprint release: print must
   never ship a hidden section. §101 (fleet-caught, §90-era defect): the old
   selectors here lacked :not(.lit), so at (1,1,1) they LOST to the (1,2,1)
   hide rule above and were DEAD for exactly the unlit sections they existed
   for — a mid-boot print shipped blank sections over min-height padding
   (reproduced: the mid-boot PDF carried ~26% of the settled one's bytes).
   The selectors now mirror the hide rule and win by source order, and the
   boot min-heights zero under print so a snapshot racing the release
   carries no placeholder padding. The §100 "no beforeprint in headless
   printToPDF" note is ALSO outdated — current Chrome fires it — which is
   why the boot's release(0) went synchronous the same round. */
@media print {
  html.boot #approach:not(.lit) > *, html.boot #sell-side:not(.lit) > *,
  html.boot #investing:not(.lit) > *,
  html.boot #contact:not(.lit) > * { display: revert; }
  html.boot #approach:not(.lit), html.boot #sell-side:not(.lit),
  html.boot #investing:not(.lit),
  html.boot #contact:not(.lit) { min-height: 0; }
  /* §90 (audit-confirmed): the boot release alone was not enough — a
     print/save-as-PDF before scrolling shipped every un-revealed section at
     6% opacity and every un-toured window's beats at frame 0 (blank
     exhibits). Print always serves the SETTLED page: reveals complete,
     entrance landed, pens drawn, every beat at its base (assembled) frame. */
  .motion .reveal { opacity: 1 !important; transform: none !important; }
  .motion .hero .hline-i, .motion .stats-thesis .th-i { transform: none !important; }
  .motion .hero .hw, .motion .stats-thesis .th-w,
  .motion .bx-speak .bx-w { opacity: 1 !important; transform: none !important; }
  .motion .hero .hero-ul { background-size: 100% 0.07em !important; }
  .motion .stats-thesis .th-ul { background-size: 100% 0.05em !important; }
  .motion .bx-speak .bx-ul { background-size: 100% 0.07em !important; }
  .vb, .vq .b-card .bv,
  .iv-anim .t3 > div, .iv-anim .t3-close { animation: none !important; }
}

/* static poster state (reduced motion / ?static=1 / no JS): pipeline poster =
   the table panel at rest (is-active in markup); the row-1 stepper's poster
   is card 1 assembled (base styles ARE the final frame) */
html:not(.motion) .chip-swap .chip { transition: none; }
html:not(.motion) .pipe-panel { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .chip-swap .chip, .pipe-panel, .pipe-rows, .motion .reveal,
  .motion .hero .hline-i, .motion .hero .hw,
  .motion .hero .hero-ul,
  .motion .stats-thesis .th-i, .motion .stats-thesis .th-w,
  .motion .stats-thesis .th-ul,
  .motion .bx-speak .bx-w, .motion .bx-speak .bx-ul { transition: none !important; }
  /* the exhibit and row-1 card rolls must stop even if the preference flips
     on mid-session before site.js's change listener reacts */
  #value .vb { animation: none !important; }
  .vq .b-card .bv { animation: none !important; }
  /* the Investing roll-out gets the same belt and braces (2026-07-21) */
  .iv-anim .t3 > div, .iv-anim .t3-close { animation: none !important; }
  /* headshot color reveal still HAPPENS under reduced motion (it is a state
     change, not motion, and it is the affordance that says "this is
     clickable") — it just arrives instantly instead of fading */
  .tm-photo img, .tmd-photo img { transition: none !important; }
}

/* ---------- Responsive ------------------------------------------------------------------------ */
@media (max-width: 1147px) {
  /* stack here (not 960, not 1080) so the pipeline table never clips: the
     7fr column only reaches the table's 560px min-width from 1148px up
     (at 1100 the column measures 532px and the Status chips clipped) */
  .svc-grid { grid-template-columns: 1fr; gap: 44px; }
  .product { max-width: 640px; }
  .contact-grid { grid-template-columns: 1fr; gap: 48px; }
  .contact-form { max-width: 640px; }
  /* Copy columns take the SAME 640px cap as the window/form they stack above
     (2026-07-19 iPad pass). .gap-copy already carried it (40em, line 900); the
     .product / .contact-form caps were authored here from the start; only
     .svc-copy and .contact-copy were ever left uncapped, so at 681-1147 they
     ran the full 928px wrap while their own figure sat at 640 — a visibly
     ragged right edge on every stacked row, and a 98-103 character measure on
     iPad portrait (the readable band is 45-75; .gap-copy's capped column
     measured 67). Capping here aligns both edges of every stacked pair and
     brings the measure to ~68. Desktop (>=1148) is untouched: the 5fr/7fr
     grid still sets the 407px column, so the value row's exact 764px fit and
     both CTA flushes are unaffected. */
  .svc-copy, .contact-copy { max-width: 640px; }
  /* stat band folds five-across to 2 + 2 + 1 below 1148 (the section-grid
     breakpoint): rows [40+ $400M+] [1,000+ 80%+], the dark ~25%+ tile spanning
     full width as the closer */
  .stats-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* wider 2-col tiles restore the roomier padding; centered tiles keep
     symmetric padding when the border drops */
  .stat { padding-left: 22px; padding-right: 22px; }
  .stat:nth-child(odd) { border-left: none; }
  .stat:nth-child(n+3) { border-top: 1px solid var(--rule); }
  .stats-row .stat-key { grid-column: 1 / -1; border: 1px solid var(--card-rule); }
  .orient-grid { gap: 32px; }
  /* six nav items + the button no longer hold one line at the old spacing
     below ~1150 (measured 2026-07-22 after Team + Client Sign-in joined):
     compress the header's air, not its content */
  .top-nav { gap: 14px; }
  .top-nav a { font-size: 13px; }
  .top-right { gap: 22px; }
  .top .btn { padding: 11px 16px; }
  /* team cards fold to two per row with the section grid (§117: four seats,
     a clean 2×2); the detail panel stacks and its photo comes down to a
     portrait, not a wall */
  .tm-grid { grid-template-columns: repeat(2, 1fr); }
  /* stacked: the photo sits BELOW the copy, so there is no bottom edge to be
     flush with — the ghost takes a fixed paragraph-ish height instead */
  .tmd-grid { grid-template-columns: 1fr; gap: 28px 0; }
  .tmd-photo { max-width: 340px; }
  /* stacked, the photo is its own row with no sibling to size against, so
     the 4/5 lock comes BACK (the .has-bio stretch is a desktop contract) */
  .tmd.has-bio .tmd-photo { align-self: start; aspect-ratio: 4 / 5; }
  .tmd-bio { flex: none; }
  .tmd-bio.is-ghost { height: 136px; }
}
@media (max-width: 960px) {
  .wrap { padding: 0 28px; }
  /* .sec padding override gone 2026-07-17: the desktop base IS 72 now */
  /* §108: overrides the TOKEN, not padding-top — see the .hero base rule. A
     bare `padding-top: 52px` here loses to `.hxwide .hero` on specificity. */
  .hero { --hero-pt: 52px; }
  .stats { margin-top: 44px; }
  .gap-grid { margin-top: 56px; }
  .mscale { margin-top: 72px; }
  /* orientation routes stack below the small-laptop breakpoint (3 narrow
     columns would cramp the one-line bullets); the header stays full-width */
  .orient-grid { grid-template-columns: 1fr; gap: 34px; }
}
@media (max-width: 768px) {
  /* Header collapse ≤768 (2026-07-22 §78; REWORKED §89): the section links
     go and the MENU BUTTON takes their place — the §78 "Client Sign-in
     survives in the bar" pin is superseded (his pick: the sign-in link is
     the menu's first item; the pin existed only because there was no menu).
     Bar reads: wordmark · Start a conversation · menu. */
  .top-nav { display: none; }
  .top-right { gap: 16px; }
  .menu-btn {
    display: inline-flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 5px;
    width: 44px; height: 44px; margin-right: -10px;
    background: none; border: 0; cursor: pointer;
  }
  .menu-btn span {
    display: block; width: 20px; height: 1.5px; background: var(--ink);
    transition: transform 0.18s ease, opacity 0.18s ease;
  }
  .menu-btn.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .menu-btn.is-open span:nth-child(2) { opacity: 0; }
  .menu-btn.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
}
@media (prefers-reduced-motion: reduce) {
  .menu-btn span { transition: none; }
}
@media (max-width: 680px) {
  /* Fit window views. STATE LABELS RETURN ON PHONES (2026-07-22 §89, the
     founder: "I sort of want to go back to it all being consistent, so even
     if it's small"). §58 dropped the whole layer after measuring 6.3px
     rendered at 390 (under the 7.5px floor) and 6 collision pairs when
     sized up; §89 restored the 39 in-state labels at 23px svg units
     ≈ 7.6px rendered at 390 (scale 316/959), clearing the floor.
     THE SIX OFFSHORE STATES RETURN TOO (2026-07-23 §90 — the founder's
     phone-feedback round: "for those smaller states we could have lines
     like we do on the main websites"; supersedes §89's offshore hide):
     MA/RI/CT/NJ/DE/MD render at the same 23px with their hairline leaders.
     At 23px text on the 26-unit offshore pitch the label boxes clear
     vertically (cap-height ~16 units against the 26 pitch); screenshot-
     verified at 390 in §90. VA/WV and VT/NH sat in §58's collision list,
     but the §76 label re-seats opened them up; NH/VT still ride the §89
     nudge below. Desktop is untouched (14px base). */
  .fv-plate { padding: 16px 14px 12px; }
  .fv-usmap .fs-l2 { font-size: 23px; letter-spacing: 0.02em; }
  /* the ONE collision at 23px (bbox-audited 2026-07-22: NH/VT overlapped
     7×18 svg units; every other shown pair clears): nudge the two apart on
     phones only — cosmetic layer, the aria-label never names labels */
  .fv-usmap .fs-vt { transform: translate(-5px, -3px); }
  .fv-usmap .fs-nh { transform: translate(5px, 4px); }
  .fv-usmap .fs-l { font-size: 28px; }   /* ~9.2px rendered; above the floor */

  .wrap { padding: 0 22px; }
  /* header CTA to a >=44px thumb target on phones (2026-07-20 external-review
     round; horizontal padding trimmed 22 -> 14 on 2026-07-22 so the button,
     the surviving Client Sign-in link, and the wordmark share a 390 row —
     measured 368px right edge, no overlap). 12.5px font + 2px borders + 15px
     vertical padding -> ~44.5px box, still over the thumb line. The sign-in
     link's own 15px vertical padding gives it a ~43px tap height. */
  .top .btn { padding: 15px 14px; font-size: 12.5px; }
  .top-right { gap: 14px; }
  /* team: TWO per row since §108 (the founder wanted the roster to stop being
     a long scroll; he asked for three, and took two after the measurement —
     three tracks at 390 leave 90px per photo, an avatar, with "Jeff Crosson"
     wrapping to two lines and "Chief Technology Officer" to three. Two gives
     ~154px, halves the scroll, and the faces still read as portraits).
     Four seats become two rows (§117). Everything below is scoped to .tm-grid so it
     cannot leak into the detail panel: fill() clones a card's photo markup
     into .tmd-photo with innerHTML, and an unscoped .tm-phl/.tm-sil rule
     would follow it into a 340px box that never needed the change. */
  .tm-grid { grid-template-columns: repeat(2, 1fr); gap: 30px 20px; }
  /* the dashed frame tucks in so two adjacent outlines clear each other AND
     the 22px page padding: 20px of gap with 8px offsets leaves 4px between */
  .tm-card.is-ph { outline-offset: 8px; }
  .tm-grid .tm-photo { gap: 8px; }
  .tm-grid .tm-sil { width: 44px; height: 44px; }
  .tm-grid .tm-phl { font-size: 8px; letter-spacing: 0.1em; }
  .tm-grid .tm-name { margin-top: 13px; font-size: 14.5px; }
  .tm-grid .tm-name.tm-ghost { font-size: 10px; letter-spacing: 0.1em; margin-top: 14px; }
  .tm-grid .tm-role { margin-top: 5px; font-size: 8.5px; letter-spacing: 0.08em; }
  /* the subhead goes back to `pretty` on phones (§86): greedy fill is the
     fix for a WIDE line that was breaking early, but at a 346px column it
     just strands the last word alone (measured 22% of the column). Same
     principle the desktop rule states — fill the line when the line is
     long, dodge the orphan when it is short. */
  .tm-page .sec-sub { text-wrap: pretty; }
  .ff-row { grid-template-columns: 1fr; }
  .hero h1 { font-size: 36px; }
  /* the wrapped payoff needs air under the pen (2026-07-22, from the founder's
     iPhone screenshot): at the desktop 1.04 leading a WRAPPED line 4 stacks
     its fragments so tight that fragment 1's cloned pen cuts through the next
     fragment's ascenders (measured at 390: pen bottom 325.2px vs ascender
     tops ~323px — it reads as a strikethrough). 1.22 opens the fragment
     pitch ~6.5px so the pen clears by ~4px. Line 4 only: it is the one pen
     carrier in the h1, and lines 1-3 keep the ratified 1.04 rhythm. Between
     517-680px line 4 still fits ONE line, where this costs only ~6px of box
     height above the subhead. The other pen carriers never collide: .th-ul
     rides 1.36 leading, .bx-ul 1.25, .lc-ul body leading. */
  .hero h1 .hline:nth-child(4) { line-height: 1.22; }
  /* subhead holds TWO lines on phones ≥390 (2026-07-22 §89, the founder:
     "really trying to fit that on two lines only... trim it from a visual
     perspective") — the sentence is canon (matches the metadata verbatim),
     so the trim is SIZE, not words. MEASURED at 390: the best split's
     binding line ("$1M – $10M of EBITDA, roughly $5M – $100M in revenue.")
     needs ≤13.0px against the 346px column, so the ramp is 3.34vw with a
     13px floor — 13.03px at 390, scaling up with the viewport (the 2-line
     fit holds by ratio from ~380px up; at 680 the cap 17px is back).
     RECORDED LIMIT: at 375-wide iPhones (SE/mini) the floor pins 13px and
     the line re-wraps to three — a true 2-liner there needs a copy trim,
     which is the founder's call, not a CSS one (option surfaced to him
     2026-07-22). balance evens whatever count renders. Re-measure at 390
     AND 375 on any subhead copy change. */
  .hero-sub { font-size: clamp(13px, 3.34vw, 17px); text-wrap: balance; }
  /* stat band folds 2 + 2 + dark bar on PHONES TOO (2026-07-22 §89, the
     founder: "a 2x2... I think that would look a lot better visually if you
     can just see it all in one spot" — the whole band in one phone screen).
     The ≤1147 grid, nth-child borders, and stat-key span INHERIT; this block
     only sizes down: tighter tiles, 24px numerals, 10px labels at 0.06em
     (the binding "TOTAL TRANSACTION VALUE" measures ~152px against ~161px
     of tile content at 390 — re-measure on any label change), 12.5px
     supports. The old single-column stack is dead. */
  .stat { padding: 16px 6px 18px; }
  /* §105 air, phone scale: 20px drop under the thesis (32 at desktop) pairs
     with the 28px photo gap; the §89 one-screen check keeps ~360px of slack */
  .stats-row { margin-top: 20px; }
  .stat-n { font-size: 24px; }
  .stat-l { margin-top: 10px; font-size: 10px; letter-spacing: 0.06em; }
  .stat-d { margin-top: 7px; font-size: 12.5px; }
  .stats-row .stat-key { padding: 15px 16px 17px; }
  /* thesis wraps on phones (nowrap lifts <861px); each sentence is its own
     inline-block unit, so the mask rise still moves whole sentences */
  .stats-thesis { padding: 26px 0 28px; font-size: 17px; }
  .sec { padding: 60px 0; }
  .footer { padding-top: 60px; }
  .sec h2 { font-size: 26px; }
  .orient h2 { font-size: 25px; }
  /* ALL SIX COLUMNS on phones since §91 (2026-07-23, the founder: "every
     single thing in all the windows... even if it's small font" — the old
     drop-Sector/Geography/Touch yield is DEAD). Compact grammar: 8.5px
     cells, prose columns wrap (sector's desktop ellipsis lifts — clipped
     text is hidden text), money/touch/chips stay nowrap, chips slim to the
     7.5px floor. No horizontal scroll at 390 — the panel swipe owns the
     horizontal axis. */
  .pipe { min-width: 0; table-layout: fixed; }
  /* fixed layout + authored column widths: prose (Target, Sector) wraps
     inside its column — never more than ~2 lines — and the EBITDA range,
     Touch, and chips hold one line. Widths sum under the 344px frame, so
     the table never scrolls sideways (the panel swipe owns that axis). */
  .pipe th:nth-child(1) { width: 56px; }
  .pipe th:nth-child(2) { width: 70px; }
  .pipe th:nth-child(3) { width: 62px; }
  .pipe th:nth-child(4) { width: 50px; }
  .pipe th:nth-child(5) { width: 32px; }
  .pipe th:nth-child(6) { width: 66px; }
  .pipe td { font-size: 8.5px; padding: 7px 4px; white-space: normal; }
  .pipe th { font-size: 7.5px; letter-spacing: 0.02em; padding-left: 4px; padding-right: 4px; }
  .pipe td.fig, .pipe td.tch { white-space: nowrap; }
  .pipe td.fig { font-size: 8px; }
  .pipe td:nth-child(2) { max-width: none; overflow: visible; text-overflow: clip; }
  .pipe th:first-child, .pipe td:first-child { padding-left: 10px; }
  .pipe th:last-child, .pipe td:last-child { padding-right: 10px; }
  .pipe td .chip { font-size: 7.5px; letter-spacing: 0.02em; padding: 3px 3px; }
  .pipe tr.stg td { font-size: 8px; }
  .pipe-dash, .pipe-tear { padding: 18px; }
  .pipe-dash { padding: 10px 18px; }
  .pd-n { font-size: 22px; }
  .pd-kpis { grid-template-columns: repeat(2, 1fr); gap: 7px 10px; margin-top: 9px; padding-bottom: 8px; }
  .pd-minis { grid-template-columns: repeat(2, 1fr); row-gap: 9px; }
  .pd-minis .pd-n { font-size: 17px; }
  /* MOVED THIS WEEK restored §91 (the founder: every band ships on phones);
     the 2x2 minis fold above already sizes it */
  .pd-sched { gap: 4px; }
  .pd-wrow { line-height: 1.3; }
  .pd-drow { padding: 3px 0; }
  .pd-split { margin-top: 8px; }
  .pd-splitlab { margin-top: 5px; }
  .pd-frow { grid-template-columns: 6.4em 1fr 2.4em; }
  .pt-name { font-size: 16px; }
  /* §91: the KPI strip mirrors desktop's five-across (was a 3+2 fold) —
     13px numerals + 7.5px-floor labels hold one row at 390 */
  .pt-strip { grid-template-columns: repeat(5, auto); gap: 8px; }
  .pt-strip .pt-n { font-size: 13px; }
  .pt-strip .pt-l { font-size: 7.5px; letter-spacing: 0.04em; }
  /* phone tear sheet: bands stack — and since §91 (2026-07-23) NOTHING
     yields: the trend chart, the service-lines column (quick screen
     included), and the italic ratio rows all ship (the founder: "it just
     doesn't have all the details that are included on the website and I
     want to include it all... even if it's small font"). The old
     secondary-exhibits-yield pattern is DEAD in this window. */
  .pt-band { grid-template-columns: 1fr; gap: 16px; }
  .pt-trend svg { max-width: 300px; margin: 0 auto; display: block; }
  .pt-cons { margin-top: 6px; }
  /* THE WINDOW FOLLOWS THE ACTIVE PANEL ≤680 (§91 — the §90 card-window
     grammar applied to the machine): the restored dashboard band and the
     full tear sheet want different heights, so the aspect locks (4/5,
     4/7.5) are DEAD; non-active panels leave the flow and the frame ends
     where the active panel's content ends. The table panel alone keeps a
     fixed height — it is a scrolling view, and the ride's depth is
     measured against it (site.js scrollDepth at cycle time, table active).
     Crossfades become cuts at this width (display swaps suppress the
     opacity transition) — the §90 pattern's accepted cost. */
  .pipe-frame { aspect-ratio: auto; }
  .pipe-panel { position: static; transition: none; }
  .pipe-panel:not(.is-active) { display: none; }
  .pipe-panel[data-panel="table"] { height: 620px; }
  .pg-title { font-size: 13.5px; }
  .pg-body p { font-size: 10.5px; }
  .kf-row { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .kf .kf-n { font-size: 15px; }
  .mix { gap: 12px; }
  .legend { min-width: 11em; }
  /* (§91: the .m-hide yield died with the everything-ships rule — the class
     left the markup; .fin/.pg-units rules below are retired-CIM leftovers
     with zero live matches, kept for the recorded dead-rule sweep) */
  .fin tr.fin-lab, .fin tr.fin-x { display: none; }
  .fin th, .fin td { padding: 3.5px 0; font-size: 10.5px; }
  .pg-units { display: none; }
  .duo { gap: 12px; }
  .cap { grid-template-columns: 1fr; gap: 6px; }
  .cap svg { max-width: 180px; }
  .cap-call { border-left: none; border-top: 1px solid var(--rule-2); padding: 12px 0 0; max-width: none; display: flex; gap: 30px; }
  .cap-call .kf + .kf { margin-top: 0; }
  .donut { max-width: 130px; }
  .mix-side { min-width: 12em; }
  .orgc { max-width: 280px; }
  .hc { margin-top: 8px; }
  .hc td { padding: 3px 0; font-size: 10px; }
  p.pg-fn { margin-top: 6px; }
  .map-svg text { font-size: 10.5px; }
  .kpi { grid-template-columns: repeat(2, 1fr); gap: 14px 0; }
  .kpi .kf { padding: 2px 0 10px 10px; }
  .kpi .kf:nth-child(4n + 1) { border-left: 1px solid var(--rule); padding-left: 10px; }
  .kpi .kf:nth-child(2n + 1) { border-left: 0; padding-left: 0; }
  .kpi .kf:nth-child(-n + 6) { border-bottom: 1px solid var(--rule); }
  .fp { grid-template-columns: 1fr; gap: 12px; }
  .og { grid-template-columns: 1fr; gap: 12px; justify-items: start; }
  .cov .cov-title { font-size: 20px; }
  .toc li { font-size: 10px; padding: 4.5px 0; }
  /* exhibit on phones: stage slims, bridge bars slim so six columns fit,
     staircase columns go fluid, the difference band stacks and centers;
     chips tighten tracking to hold one line */
  .vx-stage { padding: 20px 16px 18px; }
  .call2 { flex-direction: column; align-items: center; gap: 16px; }
  .call2-d { text-align: center; }
  .wf { --barw: 34px; gap: 0 10px; }
  .wf-conn2 { width: calc(100% - var(--barw) + 10px); }
  .mscale { margin: 70px 6px 0; }
  .mscale-note { margin: 20px 6px 0; }
  .pvc-m { font-size: 7px; letter-spacing: 0.04em; padding: 0 4px; }
  .stair { grid-template-columns: repeat(3, 1fr); gap: 0 18px; }
  /* Drop the value label's -26px side bleed on phones (2026-07-19). The bleed
     exists so a wide label can centre over a narrow desktop column; at <=680
     the staircase columns go fluid (92px at a 390 viewport) while the widest
     label "$14.4M" measures 44px, so the bleed buys nothing and pushed the
     third column's label 10px past the plate's right edge, outside the white
     surface. Zero bleed still centres it with ~24px of clearance a side. */
  .st-top { left: 0; right: 0; }
  .st-conn { width: 18px; }
  .st-dim { margin: 0 24px 10px; }
  .st-x-m { font-size: 9.5px; }
  .gap-grid { margin-top: 48px; }
  .gap-copy h3 { font-size: 24px; }
  /* investing ledger stacks on phones: OPEN below FIXED, rule turns horizontal */
  .iv-plate { padding: 18px 16px 14px; }
  .t3 { grid-template-columns: 1fr; }
  .t3 > div { padding: 14px 0 16px; }
  .t3 > div + div { border-left: 0; border-top: 1px solid var(--rule); }
}

/* ==========================================================================
   Sell-Side ROW 1 — the SAMPLE ANALYSIS · EXCERPT stepper (2026-07-17 port,
   BUILD-NOTES §54; the five-cut round's variant J, founder-ratified "99%").
   Replaces the 17-panel Caliper CIM viewer (frozen: demos/caliper-cim.html).
   .vstepper (row grammar: rail + sub-heads) and .vq (question/exhibit
   system) ride the ROW-1 WRAP DIV ONLY — row 2 (#value, Exhibit A) shares
   .vsteps/.vstep/.vsub/.vnav and must NOT inherit these overrides (.vq
   .vsteps 18px would break Exhibit A's 34/19px §53 zero-slack rail).
   Figure canon: pitch-reference/FIVE-CUT-CONSENSUS-2026-07-16.json
   figures.final/derived (the audited Millwright set) — zero mints.
   Grayscale literals all hand-audited, spread <= 5: #F1F1EE(3) #EDEDEA(3)
   #E4E4E0(4) #B9B9B4(5) #6E6E69(5) #A5A5A0(5) #D8D8D3(5) #3F3F3B(4)
   #3A3A3A(0) #FCFCFA(2); donut conic-gradients and hatch gradients reuse
   the same literals (the computed-style audit reads solids only).
   ========================================================================== */

/* the two sub-heads share one treatment (the founder 2026-07-16: "needs to be
   consistent" — five axes unified: size/color/tracking/leading/wrap).
   17.5px is MEASURED, not chosen: the 103-char sub-header holds two lines at
   the 407px column, 18px rolls it to three. SCOPED to the row on purpose:
   .sec-sub is global (four uses) and the founder never ruled a page-wide retune. */
/* §108: the analysis row's own heading, added when the section header hoisted
   above the value row and this column stopped opening on "Sell-Side". Sized to
   the site's other ROW headings (.vx-copy h3 / .gap-copy h3, both 26px) so the
   three rows of this section and Buy-Side's two read as one grammar. It sits
   ABOVE the 17.5px .sec-sub, so the column now reads heading -> lead sentence
   -> bullets; the 17.5px .b-frame h3 further down is a sub-head that rolls
   into the rail, not a second row heading, which is why only this one is 26. */
.svc-copy h3.row-h { font-size: 26px; }
/* the CTA moved into this column at §108 (it closed the value row until then).
   margin-top:auto against the .svc-top flex column is what bottom-flushes it to
   the window's caption baseline — the same mechanism .vx-copy .cta-wrap used,
   and the reason the flush needs no hand measurement. */
.vq .svc-copy .cta-wrap { margin-top: auto; padding-top: 34px; }
.vstepper .sec-sub,
.vstepper .b-frame {
  font-size: 17.5px; font-weight: 400; line-height: 1.35;
  letter-spacing: -0.01em; color: var(--ink); text-wrap: balance;
}
.vstepper .b-frame { margin-top: 22px; }
/* executive-summary lead bullets: square marker at the section-bullet scale.
   TWO-LINE BUDGET ~104 chars at the 407px column (shipped bullets run
   86/84/98/104/100) — re-measure on ANY copy change. Consolidation into
   .rlist.svc-list is a recorded open item (§54): .svc-list's 18px gap vs
   13px here would change the ratified composition, so the port kept it. */
.vstepper .lead-pts { list-style: none; margin-top: 12px; flex: 0 0 auto; }
.vstepper .lead-pts li {
  position: relative; padding-left: 20px; margin-top: 13px;
  font-size: 15.5px; line-height: 1.55; color: var(--body);
}
.vstepper .lead-pts li:first-child { margin-top: 0; }
.vstepper .lead-pts li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 4px; height: 4px; background: var(--ink);
}
/* THE THREE MOVES (§113, the founder's BP lock — the five lead bullets
   restructured into numbered process order). The mono numeral is the
   site's figure-label voice at the bullet position, NOT a new chip
   species, and it SUPPRESSES the square: one marker per list item. The
   rail's own 01/02/03 numerals stay retired (§60) — these claim PROCESS
   ORDER, a different thing, recorded in CLAUDE.md. Bold head + block
   body; base type is .lead-pts' 15.5 (phones keep it), §113's ≥681
   block takes the moves to the 14.5 compact scale. */
.vstepper .lead-mv li { padding-left: 27px; }
.vstepper .lead-mv li::before { content: none; }
.vstepper .lead-mv .mv-n {
  position: absolute; left: 0; top: 0;
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  line-height: 24px; letter-spacing: 0.06em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.vstepper .lead-mv .mv-h { display: block; font-weight: 600; color: var(--ink); }
.vstepper .lead-mv .mv-b { display: block; margin-top: 2px; }
/* the lead block's closing declaration (§62): who the work is FOR — the
   page-level conflict answer. One line at the 407px column (measured; see
   §62/§69) — re-measure on any copy change. Not a bullet (the five are
   locked); flush left. 2026-07-20 (§69): bold + a STILL drawn pen (.lc-ul)
   under "one side of the table: yours.", mirroring the Buy-Side lead's
   bold-then-pen grammar AT REST (board pick X; kept still, not spoken — a
   fourth speaking moment would dilute the device). The 600 no longer needs
   to hold back for "spine": smaller but heavier than the 17.5px/400 heads,
   it reads as emphasis, not a third head. */
.vstepper .lead-close {
  margin-top: 18px; font-size: 15.5px; font-weight: 600;
  line-height: 1.55; color: var(--ink); text-wrap: pretty;
}
/* the alignment line's pen: the FOURTH carrier of the per-line background
   underline (.hero-ul / .th-ul / .bx-ul precedent — each carrier duplicates
   the device with its own comment). The only STILL one: always drawn, never
   animated (no .motion pre-state), so at rest it mirrors the Buy-Side lead's
   bold-then-pen grammar — the whole point of §69. Geometry is em-relative,
   so the .bx-ul 0.10em/0.07em values read right at 15.5px too (verified on
   the board); box-decoration-break clones the rule per wrapped fragment on
   phones ("…of the / table: yours." each underlined to its last character). */
.lead-close .lc-ul {
  display: inline;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding-bottom: 0.10em;
  background-image: linear-gradient(var(--ink), var(--ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.07em;
}

/* rail: the IC-voice steps (the founder's verbatim committee questions; the rail
   contracts — "What's driving…" — the window keeps the written IC form).
   Headlines hold the 299px slot, bullets one line at 407px; measure on ANY
   change. */
.vq .vsteps { margin-top: 18px; }
/* §108 REPAIR of a §90 slip: §90 moved the step's 24px rhythm from .vstep to
   .vsteps > li and gave every OTHER rail a matching "> li" override — .vq was
   missed, so this 12px compression silently stopped overriding anything and
   this rail alone went from 12px steps to 24+12=36px. Measured cost at the
   time of the fix: the copy column overhung the window by 107px, against a
   §76 record of "EXACTLY flush". Both selectors ship: the li carries the
   rhythm, the button keeps its own for anything that reads it. */
.vq .vsteps > li { margin-top: 12px; }
.vq .vstep { margin-top: 12px; }
.vq .vsub { margin-top: 6px; }
.vq .vsub li { font-size: 13px; margin-top: 3px; }

/* ---------- the question rail as an ACCORDION (§108, the founder: "there's
   just a lot of information there, and I think it would be more visually
   appealing... I don't want to change any of the content") ------------------
   All five committee questions stay visible; only the ACTIVE step shows its
   three sub-bullets. Nothing is deleted — no-JS renders all fifteen (the whole
   block is html.js-gated), print restores them, and screen readers keep them
   in the tree, so the collapse is visual emphasis rather than hidden content.
   MECHANISM: grid-template-rows auto 0fr -> auto 1fr on the <li> itself. No
   wrapper, no markup change, no measured max-height to rot — and the .vsub
   stays the button's SIBLING, which the §90 restructure requires. The .vsub's
   own margin becomes padding INSIDE the clipped row, or the collapsed state
   would still spend 8px a step.
   THIS IS A FIT REMEDY, not decoration: it is what pays for the §108 section
   reorder (the row gained an eyebrow, an h3 and the CTA). .vsteps grows into
   whatever the collapse frees and space-between spreads it across the steps,
   so the column-to-window flush is MECHANISED — never hand-measured again,
   the same idiom that already flushes the value row's CTA.
   Scoped to the .vq rail only, at the founder's instruction; the other three
   rails have no window-height slack to reclaim. Above 680 only — phones
   already render one step at a time (§89 addendum, the block up top). */
html.js .vq .vsteps > li {
  display: grid;
  grid-template-rows: auto 0fr;
}
html.js .vq .vsteps > li.is-on { grid-template-rows: auto 1fr; }
/* the gap above the bullets moves onto the FIRST bullet, not the list: a
   border-box element cannot shrink below its own padding, so padding here
   would leave 6px showing on every collapsed step (measured). A margin on the
   first child sits inside the clipped row and collapses to nothing. */
html.js .vq .vsteps > li > .vsub { overflow: hidden; min-height: 0; margin-top: 0; }
html.js .vq .vsteps > li > .vsub > li:first-child { margin-top: 9px; }
/* motion-gated so ?static=1 and prefers-reduced-motion SNAP between steps —
   the disclosure is layout, and stepping must stay instant there (§57). */
html.motion .vq .vsteps > li { transition: grid-template-rows 320ms cubic-bezier(0.16, 1, 0.3, 1); }
/* §113 (2026-08-03, the founder's BP lock): the §108 space-between
   distribution is RETIRED — once the column runs FULLER than the window,
   distributed slack inverts into floating air between rail steps (the
   board's BJ finding). The rail is a plain block again; the close CLUSTER
   (.lead-close margin-top:auto + the CTA behind it) pins to the column
   foot instead, so any future word-trim self-levels the bottom edges.
   The deleted rule read: html.js .vq .svc-copy .vsteps { flex: 1 0 auto;
   display: flex; flex-direction: column; justify-content: space-between; }
   (min-width 1148, §108 "the flush is now MECHANISED"). */
/* EVERY rail's chips equal-width and centered (2026-07-21, the founder: the fit
   rail's GEOGRAPHY/SCREEN/SCORECARD ran ragged) — promoted from .vq-only to
   all four rails (.vq, #value, .bx-rail, .fv-rail; all are .vsteps). 78px =
   the measured natural width of the widest (CUSTOMERS; GEOGRAPHY/SCORECARD
   are the same 9 mono chars) — re-measure if any chip renames. In-window
   chips (.phband-h, .fv-chips) stay content-sized: they are labels, not a
   legend column. */
.vsteps .ph-chip { width: 78px; justify-content: center; }
/* (the ACTIVE step's 01/02/03 mono numerals RETIRED 2026-07-19, the founder: the
   numbering implied an exact bullet-to-exhibit mapping the window doesn't
   keep, and the square is the site's one bullet species. The active step's
   bullets now stay squares; the base .vstep.is-on rules already swap them
   from --faint to ink. The em-on-pseudo trap note lives in git history.) */

/* stage: the paper. 8.5/12.6 since §113 (the founder's max-shrink lock —
   the aspect sits at the TALLEST CARD'S packed floor under the §113
   compression set: GROWTH/PEOPLE hold 5px of residual air, measured; go
   lower and the flex silently squeezes exhibits behind overflow:hidden).
   The §54 "height is forced by the rail" era ended with BP: the column now
   deliberately outruns the window (~93px) and the window's height is the
   CONTENT's. ≤680 overrides to auto (the §90 grammar) — untouched. */
.vq .b-stage {
  aspect-ratio: 8.5 / 12.6; display: flex; flex-direction: column;
  background: var(--paper); padding: 22px 26px 18px; overflow: hidden;
}
.vq .b-cards { flex: 1 1 auto; display: grid; grid-template-columns: minmax(0, 1fr); min-height: 0; }
/* ^ minmax(0,1fr) (2026-07-19 fresh-eyes BLOCKER): with no column template the
   stacked cards' single auto track sized to the WIDEST card's max-content
   (~360px, driven by the GROWTH ribbon) and every card clipped ~68px inside
   the 292px phone plate — overflow:hidden, so no scrollbar ever betrayed it. */
.vq .b-card { grid-area: 1 / 1; visibility: hidden; display: flex; flex-direction: column; min-height: 0; }
.vq .b-card.is-on { visibility: visible; }
.vq .b-khead { padding-top: 12px; }
.vq .b-q { font-size: 15.5px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; line-height: 1.3; }
.vq .b-read { margin-top: 9px; font-size: 13px; line-height: 1.5; color: var(--body); }
.vq .vnav { margin-top: 16px; }
/* (the centred counter moved to the BASE .vnav rule 2026-07-19 — the
   every-window-steps round unified the grammar and closed the recorded
   Exhibit A flush-counter divergence) */
/* IB footnote: sup 1 rides the plate name; the page foot IS the footnote
   (right-aligned, synthetic oblique — Instrument Sans ships no italic).
   The 2px sup margin is the WHOLE marker gap; no literal space in markup. */
.vq .pg-name sup { font: 500 7px/0 var(--mono); letter-spacing: 0.06em; margin-left: 2px; }
.vq .pg-foot { justify-content: flex-end; }
.vq .pg-foot span {
  font: italic 400 9.5px/1.45 var(--sans);
  letter-spacing: 0.01em; color: var(--muted); text-align: right;
}
.vq .pg-foot sup { font-size: 7px; line-height: 0; margin-right: 2px; }
/* the window caption is GONE since §113 (the founder's BK ruling carried
   into BP): its keeper notes were woven into the moves in the copy column,
   the exports/assembly pair left the page (recorded loss, his call). The
   .win-notes rules died with it. */

/* ----- the exhibits: .gx grammar + .jx IC-grade set (banded tables,
   donuts, org chart, coverage bridge). IB conventions: right-aligned
   tabular figures, $ on first data row + totals, parens negatives, italic
   ratio rows, header band states the unit, "0" never a dash, 7.5px floor. */
.vq .gx { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-top: 18px; }
.vq .gx.jx { justify-content: space-between; } /* residual BETWEEN blocks, never one bottom void */
.vq .gx-2 { display: flex; gap: 30px; }
.vq .gx-2 > div { flex: 1; min-width: 0; }
.vq .gx-h { font: 500 8.5px/1.4 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.vq .gx-fn { margin-top: 9px; font-size: 10.5px; line-height: 1.5; color: var(--muted); }
.vq .gxc { display: flex; align-items: flex-end; gap: 22px; margin-top: 14px; }
.vq .gxc .c { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 5px; }
.vq .gxc .c b { font-size: 12px; line-height: 1; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.vq .gxc .c .d { font: 500 8px/1 var(--mono); letter-spacing: 0.06em; color: var(--muted); }
.vq .gxc .c i { font: 500 8px/1 var(--mono); font-style: normal; letter-spacing: 0.08em; color: var(--faint); }
.vq .gxc .bar { width: 100%; max-width: 74px; background: var(--ink); display: flex; flex-direction: column; }
/* .bcap — RENAMED from the board's .cap on port: styles.css already owns
   .cap (the caption-grid component above), and that collision shoved every
   hatch bar-cap 14px down its bar on the board (the "black sliver"). */
.vq .gxc .bar .bcap { width: 100%; display: flex; align-items: center; justify-content: center; background: repeating-linear-gradient(135deg, #E4E4E0 0 3px, #B9B9B4 3px 4px); }
/* segment values (2026-07-21, the founder: label the reported/adjustments split):
   .gxb-r flex-fills the solid area below the cap so it self-centers in the ink;
   .gxb-a rides the hatch cap on a paper pill for legibility over the pattern */
.vq .gxc .bar .gxb-r { flex: 1; display: flex; align-items: center; justify-content: center; font: 500 8.5px/1 var(--mono); letter-spacing: 0.05em; color: var(--paper); }
.vq .gxc .bar .gxb-a { font: 500 8px/1 var(--mono); letter-spacing: 0.03em; color: var(--ink); background: var(--paper); padding: 2px 3px; border-radius: 2px; }
.vq .gxc .sp { width: 100%; max-width: 74px; }
.vq .gxc .bar.ref { background: #F1F1EE; box-shadow: inset 0 0 0 1px #D8D8D3; }
.vq .gxc .bar.hatch { background: repeating-linear-gradient(135deg, #E4E4E0 0 3px, #B9B9B4 3px 4px); }
.vq .gx-key { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px; }
/* EARNINGS only (§91, the founder: "scoot up the REPORTED/ADJUSTMENTS legend...
   closer to the FY23/FY24 LTM"): its column is the card's tall pole, so the
   space-between slack left the key 1.8px off the foot hairline while every
   sibling key held 7.8-37.7px below (measured 2026-07-23). 10 -> 4 reads the
   key with the axis labels and returns the 6px to the seam below. The shared
   rule above is untouched — the other cards measured healthy. */
.vq .b-earn .gx-key { margin-top: 4px; }
.vq .gx-key span { display: inline-flex; align-items: center; gap: 6px; font: 500 8px/1.4 var(--mono); letter-spacing: 0.07em; color: var(--muted); }
.vq .gx-key i { width: 8px; height: 8px; flex: none; background: var(--ink); }
.vq .gxb { display: flex; height: 22px; margin-top: 12px; }
.vq .gxb span { height: 100%; }
.vq .gxr { margin-top: 12px; }
.vq .gxr .r { display: grid; grid-template-columns: 122px 1fr 92px; gap: 12px; align-items: center; margin-top: 9px; }
.vq .gxr .rl { font: 500 8px/1.35 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.vq .gxr .rt { position: relative; height: 12px; background: #F1F1EE; }
.vq .gxr .rt i { position: absolute; top: 0; bottom: 0; left: 0; background: var(--ink); }
.vq .gxr .rv { font-size: 11.5px; font-weight: 600; color: var(--ink); text-align: right; white-space: nowrap; }
/* anchored foot KPI strip — INK-CENTERED between its own top hairline and
   the pg-foot rule (session 8, the founder). 16.3px = the measured leading
   asymmetry: 12px box + 7.19px numeral leading above the cap vs 0 + 2.90px
   label leading below the baseline (canvas actualBoundingBox). ONE value
   serves all five cards. Re-measure if gs-n/gs-l fonts or pg-foot change.
   (gs-l 8 -> 7.5px 2026-07-20, the founder's wrap flag: EVERY label must
   hold ONE line in the 160px desktop column — a wrapped label sat 12px
   deeper than its neighbors and read as overlapping the pg-foot rule.
   7.5px is the document's established type floor (.jx-tbl .th); the label
   box shrinks 12 -> 11.25px, shifting the measured asymmetry ~0.2px —
   inside tolerance, 16.3 stands. Longest label ~29 chars; re-measure ALL
   FIFTEEN labels at 1440 AND the 640 stacked cap on any label change.) */
.vq .gxs { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--rule); display: flex; gap: 18px; }
.vq .gxs .gs { flex: 1; min-width: 0; }
.vq .gs-n { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.vq .gs-l { margin-top: 4px; font: 500 7.5px/1.5 var(--mono); letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
.vq .jx-foot .gxs { margin-top: 0; padding-bottom: 16.3px; }
/* banded IC table (grid columns per table via --jc, class-set so the 680
   media query can retune them; inline --jc would beat the media rule) */
.vq .jx-tbl { margin-top: 10px; }
.vq .jx-tbl .th, .vq .jx-tbl .r { display: grid; grid-template-columns: var(--jc); gap: 10px; }
.vq .jx-tbl .th { background: var(--ink); color: #FAFAF8; font: 500 7.5px/1.4 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; padding: 6px 9px; align-items: center; }
.vq .jx-tbl .th span + span, .vq .jx-tbl .r span + span { text-align: right; }
.vq .jx-tbl .r { padding: 6.5px 9px; border-bottom: 1px solid #EDEDEA; font-size: 11px; color: var(--body); align-items: baseline; }
.vq .jx-tbl .r span:first-child { display: flex; align-items: center; gap: 7px; min-width: 0; }
.vq .jx-tbl .r.tot { border-top: 1px solid var(--ink); border-bottom: 0; margin-top: -1px; font-weight: 600; color: var(--ink); }
.vq .jx-tbl .r.sub { border-bottom: 0; padding-top: 1px; font-size: 10px; font-style: italic; color: var(--muted); }
.vq .jx-tbl .no { width: 13px; height: 13px; border-radius: 50%; flex: none; background: var(--ink); color: #FAFAF8; font: 600 7.5px/13px var(--mono); font-style: normal; text-align: center; }
.vq .jt3y { --jc: minmax(0, 1fr) 72px 72px 72px; }
.vq .jt4c { --jc: minmax(0, 1fr) 58px 58px 58px 66px; } /* tier table, 3yr history + LTM share (2026-07-19) */
.vq .jt2y { --jc: minmax(0, 1fr) 52px 52px; }
.vq .jtcv { --jc: minmax(0, 1fr) 76px 76px; }
.vq .jtnw { --jc: minmax(0, 1fr) 90px; }
/* KPI chip ribbon */
.vq .jx-kpi { display: flex; gap: 10px; margin-top: 12px; }
.vq .jx-kpi .k { flex: 1; min-width: 0; border: 1px solid var(--rule); padding: 10px 11px; text-align: center; }
.vq .jx-kpi .k b { display: block; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.vq .jx-kpi .k span { display: block; margin-top: 4px; font: 500 7.5px/1.45 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
/* donut: conic ring, paper hole, center label (gradient stops hand-audited) */
.vq .jx-donut { display: flex; align-items: center; gap: 22px; margin-top: 12px; }
.vq .jx-donut .ring { position: relative; width: 168px; height: 168px; border-radius: 50%; flex: none; }
.vq .jx-donut .ring i { position: absolute; inset: 21%; border-radius: 50%; background: var(--paper); }
.vq .jx-donut .ring b { position: absolute; inset: 21%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; font-size: 15px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.vq .jx-donut .ring b small { margin-top: 3px; font: 500 7.5px/1.4 var(--mono); letter-spacing: 0.07em; color: var(--muted); }
.vq .jx-donut .gx-key { flex-direction: column; align-items: flex-start; gap: 8px; margin-top: 0; }
.vq .jx-donut.col { flex-direction: column; align-items: center; gap: 12px; }
/* org chart: titles-only; gap via .ob margins (NOT flex gap) so the four
   cell centers land at exactly 12.5/37.5/62.5/87.5% and the connector rule
   + drops meet to the pixel; cells stretch + titles reserve two line-slots
   so the counts share one baseline even when only one title wraps */
.vq .jx-org { margin-top: 12px; }
.vq .jx-org .ob { border: 1px solid #D8D8D3; background: #FCFCFA; padding: 8px 6px; text-align: center; }
.vq .jx-org .ob b { display: block; font: 500 7.5px/1.4 var(--mono); letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
.vq .jx-org .ob .n { display: block; margin-top: 2px; font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.vq .jx-org > .ob { width: 200px; margin: 0 auto; }
.vq .jx-org .stem { width: 1px; height: 13px; margin: 0 auto; background: #3A3A3A; }
.vq .jx-org .row { display: flex; position: relative; padding-top: 13px; }
.vq .jx-org .row::before { content: ''; position: absolute; top: 0; left: 12.5%; right: 12.5%; border-top: 1px solid #3A3A3A; }
.vq .jx-org .row > div { flex: 1; min-width: 0; position: relative; padding-top: 13px; margin: 0 5px; display: flex; }
.vq .jx-org .row > div::before { content: ''; position: absolute; top: -13px; left: 50%; width: 1px; height: 26px; background: #3A3A3A; }
.vq .jx-org .row .ob { position: relative; background: #FCFCFA; flex: 1; display: flex; flex-direction: column; justify-content: center; }
.vq .jx-org .row .ob b { min-height: 21px; display: flex; flex-direction: column; justify-content: flex-end; }
/* headcount-bridge seam connectors (2026-07-19): dashed hand-offs across the
   22px column gaps at the exact seam levels, the .wf-conn2 grammar carried
   into the .gxc species (the column turns position:relative for them; no
   other card has absolute children, so this is inert elsewhere) */
.vq .gxc .c { position: relative; }
.vq .hb-c { position: absolute; right: 100%; width: 22px; border-top: 1px dashed var(--rule-2); display: block; }

/* J bar-chart feet: fixed-height, centered, wrappable — one shared baseline */
.vq .gx.jx .gxc .c i { height: 24px; line-height: 1.35; display: flex; align-items: flex-start; justify-content: center; text-align: center; }

/* ----- GROWTH one-ruler exhibit (2026-07-19 redesign) -----------------------
   Both former card-3 charts merged on ONE baseline at the shipped 8.4px/$M:
   year bars 143/155/168 with ink contract segments 83/93/104 (58/60/62%,
   canon figures.final[14]), an 18px seam track, the hatch backlog riser
   (40 over a 104 offset — the session-7 margin technique, now bottom-offset
   absolute), and the self-footing subtotal stack (104 ink + 40 hatch = 144).
   Grid kin of Exhibit A's .wf. The dashed ledgers/carry-rule are inline-
   positioned in markup and cross WHITESPACE only — the banned form is a
   trend line OVER solid ink bars. Values are absolute .wf-val kin so the
   caption row keeps one shared baseline. */
.vq .rb { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) 18px repeat(2, minmax(0, 1fr)); gap: 0 12px; margin-top: 14px; }
.vq .rb::before { content: ''; position: absolute; left: 0; right: 0; top: 196px; border-top: 1px solid var(--rule-2); }
.vq .rb-plot { position: relative; height: 196px; }
.vq .rb-bar { position: absolute; left: 50%; bottom: 0; width: 100%; max-width: 64px; transform: translateX(-50%); display: block; }
.vq .rb-mix { background: #F1F1EE; box-shadow: inset 0 0 0 1px #D8D8D3; }
.vq .rb-seg { position: absolute; left: 0; right: 0; bottom: 0; background: var(--ink); display: block; }
.vq .rb-seg b { position: absolute; left: 0; right: 0; top: 6px; text-align: center; font: 500 7.5px/1 var(--mono); letter-spacing: 0.04em; color: #FAFAF8; }
/* value label (the year total), on a paper background so it reads over the bar */
.vq .rb-val { position: absolute; left: -14px; right: -14px; text-align: center; font-size: 12px; line-height: 1; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); background: var(--paper); font-variant-numeric: tabular-nums; }
.vq .rb-val .d { display: block; margin-bottom: 4px; font: 500 8px/1 var(--mono); letter-spacing: 0.06em; color: var(--muted); }
.vq .rb-cat { margin-top: 8px; text-align: center; font: 500 8px/1.35 var(--mono); letter-spacing: 0.07em; color: var(--faint); text-transform: uppercase; height: 24px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; }
/* ----- GROWTH card recurring-engine additions (2026-07-21, §71) -------------
   The revenue-build chart became 3-bar (the coverage walk + its ledgers/hatch/
   subtotal retired); each segment now labels its % (top) and $ (centered), a
   CAGR connector bracket sits above, and a growth-by-source split bar + a
   forward-visibility strip replace the old table's backlog rows. Every figure
   foots (index.html card comment + BUILD-NOTES §71). */
.vq .rb.rb-g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 46px; }
/* in-bar labels: % at the segment top, $ vertically centered in each segment */
.vq .rb-pw { position: absolute; left: 0; right: 0; z-index: 2; text-align: center; font: 500 7.5px/1 var(--mono); letter-spacing: 0.04em; color: var(--ink); }
.vq .rb-dw, .vq .rb-db { position: absolute; left: 0; right: 0; z-index: 2; text-align: center; font-size: 10.5px; line-height: 1; font-weight: 600; letter-spacing: -0.01em; transform: translateY(-50%); font-variant-numeric: tabular-nums; }
.vq .rb-dw { color: var(--ink); }        /* dollars on the light (project) segment */
.vq .rb-db { color: #FAFAF8; }           /* dollars on the ink (recurring) segment */
/* CAGR bracket: the chip centered below the header; a hairline rises above
   $17.1M, crosses to above $20.0M, WHITESPACE only (the banned form is a trend
   line drawn over solid bars). Stubs land a few px above each end value. */
.vq .rb-bk-h { position: absolute; top: -30px; left: calc((100% - 24px) / 6); right: calc((100% - 24px) / 6); border-top: 1px solid #B9B9B4; }
.vq .rb-bk-l { position: absolute; top: -30px; left: calc((100% - 24px) / 6); height: 56px; border-left: 1px solid #B9B9B4; }
.vq .rb-bk-r { position: absolute; top: -30px; left: calc(100% - (100% - 24px) / 6); height: 24px; border-left: 1px solid #B9B9B4; }
.vq .rb-bk-c { position: absolute; top: -30px; left: 50%; transform: translate(-50%, -50%); }
/* §77: the growth card's ink/light key serves BOTH exhibits (revenue build +
   growth by source), so it rides the title lockup above the bars — 5px binds it
   to the header (generic 10 read as a floating line), and the CAGR chip keeps
   ~12px clearance below it. Below the bars nothing now crowds the second
   exhibit's header (the founder's catch: the key read as that header's subtitle). */
.vq .b-growth .gx-key { margin-top: 5px; }
/* growth-by-source split bar: recurring vs project, flex = the exact +$M deltas */
.vq .gsrc { margin-top: 14px; }
.vq .gsrc-bar { display: flex; gap: 4px; height: 48px; }
.vq .gsrc-bar > div { position: relative; display: flex; align-items: center; justify-content: center; }
.vq .gsrc-rec { background: #0A0A0A; }
.vq .gsrc-prj { background: #F1F1EE; box-shadow: inset 0 0 0 1px #D8D8D3; }
.vq .gsrc-bar span { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.vq .gsrc-rec span { color: #FAFAF8; }
.vq .gsrc-prj span { color: var(--ink); }
/* forward-visibility strip: renewals + signed backlog (backlog is FORWARD, so it
   lives here, not blended into a trailing % as the retired coverage walk did) */
.vq .rb-fwd { display: flex; gap: 10px; }
.vq .rb-f { flex: 1; border: 1px solid var(--rule); padding: 10px 12px; text-align: center; }
.vq .rb-fn { font-size: 15px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.vq .rb-fl { margin-top: 4px; font: 500 7.5px/1.5 var(--mono); letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
/* schedule swatches: the chart's encoding carried into the table rows */
.vq .jx-tbl .sw { width: 8px; height: 8px; flex: none; display: inline-block; }
/* the CAGR chip: header-row form ONLY (session 8, the founder killed the trend
   line AND the on-line pill — "no investment bank would position like that
   in the black line, with a white border on it"; the YoY bar labels carry
   the growth read; do not reintroduce a line over solid ink bars) */
.vq .jx-cagr { background: var(--ink); color: #FAFAF8; font: 500 7.5px/1 var(--mono); letter-spacing: 0.08em; padding: 5px 8px; white-space: nowrap; }
/* compact gxr template for J's half-column use (stock 122/1fr/92 was
   authored for a full-width plate) */
.vq .gx.jx .gxr .r { grid-template-columns: 74px 1fr 26px; gap: 8px; }
/* paired half-column chart headers share a height so both baselines level */
.vq .gx.jx .gx-2 > div > .gx-h { min-height: 18px; }
/* CENTERING PASS (the founder: titles/legends/KPI strips centered; TABLES keep IB
   grammar — labels left, figures right — and .gx-fn stays left, annotation
   voice; do not "finish the job" on those) */
.vq .gx.jx .gx-h { text-align: center; justify-content: center; }
.vq .gx.jx .gx-key { justify-content: center; }
.vq .gx.jx .jx-donut.col { align-items: center; }
.vq .gx.jx .gxs .gs { text-align: center; }

/* roll-in: one shared 400ms rise, --d beat delays inline in markup
   (0/.16/.34/.5/.62 cadence), ~1.0s per card — under WCAG 2.2.2's 5s line,
   so NO pause button; NO replay (replay stays Exhibit A's alone). .motion-
   gated: base styles ARE the assembled frame, so ?static=1 / reduced motion
   / no-JS serve finished cards; site.js re-triggers via .is-roll strip/
   reflow/restore on every arrival after the first reveal. */
.motion .vq .b-card.is-roll .bv { animation: gxup 400ms cubic-bezier(0.16, 1, 0.3, 1) both; animation-delay: var(--d, 0s); }
@keyframes gxup { from { opacity: 0; transform: translateY(7px); } }

@media (max-width: 680px) {
  /* the 8.5/14 aspect lock overflows every card at phone widths (found on
     the board, pre-existing): the stage sizes to content instead; 681-1147
     stacked keeps the lock (reviewed) */
  .vq .b-stage { aspect-ratio: auto; padding: 20px 16px 16px; }
  .vq .gx-2 { flex-direction: column; gap: 20px; }
  /* foot KPI strips hold ONE ROW of three on phones (§91, the founder:
     "the 9 yrs, 143K, and 92% all fit on one... shrink it a little...
     the subtitles can break to two lines" — the old 2+1 wrap is dead).
     Numerals step 17 -> 13.5; the 7.5px mono sublabels wrap freely. */
  .vq .gxs { flex-wrap: nowrap; gap: 10px; }
  .vq .gs-n { font-size: 13.5px; }
  .vq .jx-kpi { flex-wrap: wrap; }
  .vq .jx-kpi .k { flex: 1 1 40%; }
  .vq .jx-donut { flex-direction: column; align-items: flex-start; }
  .vq .jx-org .row { flex-wrap: wrap; row-gap: 10px; }
  .vq .jx-org .row::before, .vq .jx-org .row > div::before, .vq .jx-org .stem { display: none; }
  .vq .jx-org .row > div { flex: 1 1 40%; padding-top: 0; }
  /* §91: every schedule label holds ONE line at 390 (the founder's 1b —
     the shortened "Excess owner comp." still needs more than the old 88px
     label column, so the columns rebalance WITH the label change: figure
     columns trim to what "$18,500" actually needs, the grid gap tightens,
     and the label column takes the rest). */
  .vq .jx-tbl .th, .vq .jx-tbl .r { gap: 6px; }
  .vq .jx-tbl .r { font-size: 10px; }
  .vq .jt3y { --jc: minmax(0, 1fr) 46px 46px 48px; }
  .vq .jt2y, .vq .jtcv { --jc: minmax(0, 1fr) 54px 54px; }
  /* "( $ in thousands )" held to ONE line (2026-07-22 §89 addendum, the
     founder's fix-it: at 390 the jt3y label column measures ~90px and the
     unit label needs ~92 at the house 0.08em, so the lone ")" wrapped).
     Tracking trims to 0.02em on THIS span only — the 7.5px floor holds. */
  .vq .jx-tbl .th span:first-child { white-space: nowrap; letter-spacing: 0.02em; }
  .vq .jt4c { --jc: minmax(0, 1fr) 42px 42px 42px 50px; }
  /* GROWTH revenue-build bars at phone widths (§71: the 5-column coverage walk
     retired, so the old mobile 5-col template + its last-column val fix are
     gone; .rb-g3 sets the 3 columns, this contributes the tighter gap + a
     smaller value tier + the 7.5px cat floor). */
  .vq .rb { gap: 0 6px; }
  .vq .rb-val { font-size: 10px; left: -6px; right: -6px; }
  .vq .rb-cat { font-size: 7.5px; letter-spacing: 0.06em; }
  /* (§71's GROWTH-scoped 15px block seam GENERALIZED to every sample card
     by the §91 audit — the same zero-slack collapse §71 fixed here showed
     up on CUSTOMERS and PEOPLE; the rule now lives un-scoped in the
     §90/§91 phone-polish block further down this file.) */
  /* the centred vnav counter collides with the destination-naming Next
     button on a 292-344px rail (fresh-eyes MAJOR): hide it on phones — Back
     and the named Next carry the position */
  .vnav-ct { display: none; }
}

/* ==========================================================================
   §90 PHONE POLISH (2026-07-23, the founder's phone-feedback round — "a lot
   of white space… the formatting needs to be great"; total creative freedom,
   mirror desktop, smaller is fine). Everything here is ≤680-scoped; desktop
   and iPad render byte-identically.
   ========================================================================== */
@media (max-width: 680px) {
  /* THE WHITE-SPACE CURE — the window follows its ACTIVE card (all three
     card windows). The stacks used to stretch every card to the tallest
     sibling (sample: all five at the tallest's height; fit: GEOGRAPHY
     carried ~570px of empty plate under the legend because SCREEN is the
     phone height driver; value: the 10/11 aspect held ~500px of blank
     under levers 1-2). On phones the non-active cards leave the flow
     entirely, so the plate ends where the active card's content ends.
     Desktop/iPad keep the shared-height grammar (a window that never
     changes height while touring is the ratified desktop behavior).
     Tours, swipes, tabs, and rails all still work: they toggle .is-on,
     and display swaps re-run entrance beats from frame 0 by nature. */
  .vq .b-card:not(.is-on),
  .vx-stage .vcard:not(.is-on),
  .fv-views .fv-view:not(.is-on) { display: none; }
  .vx-stage { aspect-ratio: auto; padding: 18px 14px 16px; }

  /* Exhibit A equation: the founder's centered two-line break ("Supported
     earnings / competitive multiple equals enterprise value"). 483px of
     chips cannot hold one 312px line at any legible size, so the band
     centers and breaks after the ×: "SUPPORTED EARNINGS x" over
     "COMPETITIVE MULTIPLE = ENTERPRISE VALUE". The chip trim below keeps
     line 2 whole down to 360px; under ~340px it re-centers on three lines
     (rare devices, still composed). Chip trim is scoped to the equation
     band ONLY — rail chips keep the 78px uniform (§76). */
  .phband-h { justify-content: center; gap: 10px 12px; }
  .phband-h .ph-chip { height: 20px; padding: 0 7px; font-size: 8.5px; letter-spacing: 0.07em; }

  /* map legend: the flex row wrapped ragged (2 items / 1 item / count).
     A 2-column grid reads composed: swatches align, the ink count closes.
     §91 (the founder's screenshot note): the block CENTERS across the
     plate and LIFTS off the foot bar — it used to sit flush on the gray
     stamp (measured 0px); 12px of floor + centering read composed. */
  .fv-legend { display: grid; grid-template-columns: auto auto; justify-content: center; gap: 9px 22px; margin-bottom: 12px; }
  .fv-view[data-fview="geo"] .fv-usmap + .fv-legend { margin-top: 14px; }
  .fv-legend .fv-ct { margin-left: 0; width: auto; }

  /* scorecard hexagon axis names: 9.5 svg units rendered ~4.8px at 390 —
     far under the 7.5px floor (audit-confirmed; the same fix the map
     labels got in §89). 15 units ≈ 7.7px rendered. §91: at 15 units the
     22-char OPERATIONAL CAPABILITY ran 51 units off the viewBox left edge
     (end-anchored at its vertex; the ONE label that clips — measured) so
     the phone swaps in its two-line form authored in the markup. */
  .fitx-hex .fx-l { font-size: 15px; letter-spacing: 0.05em; }
  .fitx-hex .fx-1l { display: none; }
  .fitx-hex .fx-2l { display: block; }

  /* §91 audit minor: the SCORECARD foot stamp (54 chars, the longest of the
     three) wrapped "…DEFINED WITH / YOUR TEAM" while its siblings held one
     line — all three fit feet take the same one-line trim so the mono
     chrome rhythm mirrors across the views (8.5px ≥ the 7.5px floor). */
  #process .fit-foot { font-size: 8.5px; letter-spacing: 0.05em; white-space: nowrap; }

  /* §91 audit major: the GROWTH split bar's +$0.4M chip is width-encoded
     (flex 0.42 vs 2.48) and at the phone column its proportional share
     falls below the label's min-content — flexbox clamped the chip to the
     text exactly, glyphs on both hairlines (desktop pads 14px a side).
     Smaller label + authored padding restore breathing room; the ~6px the
     recurring segment cedes is invisible at this scale, and the desktop
     encoding is untouched. */
  .vq .gsrc-bar span { font-size: 11px; }
  .vq .gsrc-bar > div { padding: 0 6px; }

  /* §91 audit minor: the block-to-block seams inside the sample cards had
     NO authored margin — desktop rhythm was space-between slack from the
     aspect-locked stage, and §90's aspect-ratio:auto zeroed it, collapsing
     two seams to 0 (the CUSTOMERS footnote read as the donut's caption,
     PEOPLE's WORKFORCE FLOW title sat closer to the legend above than to
     its own table). One authored seam for every card — the §71 GROWTH
     rule, generalized. */
  .vq .gx.jx > .bv + .bv:not(.jx-foot) { margin-top: 15px; }

  /* SCREEN view rhythm: with per-card heights the tallest view sets the
     window's swipe-to-swipe variance, and SCREEN was ~240px taller than
     the scorecard at 390 — tighten its bands toward its siblings. */
  .fv-band { margin-top: 11px; padding-top: 10px; }
  .fv-band:first-of-type { margin-top: 8px; }
  .fv-chips { margin-top: 8px; }
  .fv-hi { margin-top: 7px; gap: 6px; }
  .fv-oos { margin-top: 8px; }
}

/* §90: the smallest phones (SE/mini at 375, and narrower). Two measured
   steps, both closing recorded limits: */
@media (max-width: 380px) {
  /* the subhead's 13px floor re-wrapped it to three lines at 375 (the §89
     recorded limit, surfaced to the founder — his round: fit it without
     touching the copy). MEASURED at settled fonts: the 2-line threshold at
     375 sits between 12.5 and 12.525px (razor-thin — 3.34vw lands 12.525
     and wraps three), so this step lowers the PREFERRED value, not just
     the floor: 3.3vw is 12.375px at 375 with the 12.4px cap holding ≤380
     under the threshold throughout. A half-point under §89's floor,
     invisible; the copy is untouched (canon, matches the metadata).
     320-class devices may still wrap three at the 11.9px floor
     (recorded, not fixed — the copy is canon). */
  .hero-sub { font-size: clamp(11.9px, 3.3vw, 12.4px); }
}
@media (max-width: 374px) {
  /* "TOTAL TRANSACTION VALUE" (the binding stat label) wraps under ~372px
     viewports, breaking the band's one-line tier alignment (audit-confirmed
     at 360, the common Android width). 9px + 0.04em holds it one line to
     ~340px; iPhones ≥375 never see this block. */
  .stat-l { font-size: 9px; letter-spacing: 0.04em; }
}
/* §91: the six-column pipe table steps down with the frame BELOW 390 — the
   390 widths sum 338 and a 375 frame holds ~329, which would wake the
   table's own horizontal scroll and fight the panel swipe for the axis.
   302px of columns + 8px cells (money at the 7.5px floor) fit to ~345
   viewports; GEOGRAPHY (the widest header word) keeps its 50px.
   ~330-class devices may see a few px of in-table scroll (recorded limit,
   the §90 320-class precedent). */
@media (max-width: 389px) {
  .pipe th:nth-child(1) { width: 48px; }
  .pipe th:nth-child(2) { width: 54px; }
  .pipe th:nth-child(3) { width: 58px; }
  .pipe th:nth-child(4) { width: 50px; }
  .pipe th:nth-child(5) { width: 26px; }
  .pipe th:nth-child(6) { width: 66px; }
  .pipe td { font-size: 8px; }
  .pipe td.fig { font-size: 7.5px; }
  .pipe td .chip { letter-spacing: 0; padding: 3px 2px; }
  /* the two prose columns hyphenate at this width — "Timberline" and
     "Instrumentation" outrun any honest column here, and a clipped
     letter is hidden text */
  .pipe td:nth-child(1), .pipe td:nth-child(2) { overflow-wrap: anywhere; hyphens: auto; }
  /* §91 audit: the EARNINGS schedule's one-line-per-row grammar re-wraps
     below ~368px at the 390 column split — the same step-down the pipe
     table takes above: 9.5px rows and figure columns sized to "$18,500"
     at that size buy the label column the width back (measured at 360). */
  .vq .jx-tbl .r { font-size: 9.5px; }
  .vq .jt3y { --jc: minmax(0, 1fr) 42px 42px 46px; }
}

/* ==========================================================================
   §91 (2026-07-23, the founder's final-nits round): the pipeline window
   joins the phone tab + swipe grammar — "I want it to mirror the other
   ones". Its .swtabs strip is built by the same site.js routine from the
   bx-rail's own chips (COVERAGE / PIPELINE / DECISION), but the strip
   wears the MACHINE tokens: a paper strip under the dark title bar would
   read as a hole in the machine. .swtabs is display:none outside ≤680, so
   these are phone-only by inheritance. All tokens neutral (grayscale
   audit-safe).
   ========================================================================== */
.win[data-card="pipe"] .swtabs { background: var(--card); border-bottom-color: var(--card-rule); }
.win[data-card="pipe"] .swtab { color: var(--card-mut); }
.win[data-card="pipe"] .swtab.is-on { color: var(--card-text); border-bottom-color: var(--card-text); }

/* ==========================================================================
   §99 (2026-07-29, the founder's AZ pick — HERO BACKGROUND PHOTOGRAPH,
   photography exception #2, sanctioned knowingly; counsel item (bbb)):
   the mirrored boardroom render v14 runs behind the hero and the stat
   band's thesis line, ending --hxgap above the tile row since §105 (the
   founder's air ruling; it ended exactly at the row before). Geometry,
   treatment, and text tones are VERBATIM from the ratified variant board
   (pitch-reference record in BUILD-NOTES §99): the photo layer is absolute
   inside the .hxwide wrapper, its height pinned by site.js to .stats-row's
   top (--hxcut; the 76% fallback is the no-JS floor — base styles ARE the
   final frame). §101 SUPERSEDED the color+filter model: the at-rest photo
   is the GRAY BAKE by file (no filter — see the §101 comment below), the
   color set lazy-arrives on the .hxc layer, and the bloom is an opacity
   crossfade gated by .hx-ready. Hover blooms color on
   desktop, .hx-alive does it on touch (site.js tap block); img pixels are
   not computed colors either way, so the grayscale audit was never in
   play. Scrim literals
   are neutral rgb(8,8,8); every text tone below is a neutral gray, spread
   at most 5 — audit-safe. The DARK-SURFACE AMENDMENT lives in CLAUDE.md:
   this photographic hero is founder-sanctioned and does not join the
   two-dark-surfaces count (those are UI surfaces in the machine tokens).
   --hxcut is declared on the element, never :root (containment rule).
   ========================================================================== */
.hxwide { position: relative; }
/* §107 (2026-07-30, the founder's iPad-framing ruling): on a WIDE window the
   full-bleed band is wider than the photograph's own 3200x1246 aspect, so
   `cover` crops the room top and bottom — at 2560 (his Studio Display) only
   ~58% of the image height survived and the boardroom table ran out of frame.
   His iPad shows the whole room precisely because a narrower box is TALLER
   than the photo needs. So the hero takes the air the aspect asks for:
   --hxair is the shortfall between the height the photo WANTS
   (100vw x 1246/3200) and the height the locked hero composition PRODUCES
   (581px — MEASURED, and constant at every width >= 1174 where the hero,
   subhead and thesis clamp() sizes have all hit their caps; RE-MEASURE on any
   hero/subhead/thesis copy or type change, it is the one magic number here).
   It is SECOND-CAPPED so the §52 above-fold invariant always wins: the band
   foot (888px at rest, §105) may never pass 24px short of the fold, so a wide
   but SHORT window (1600x900) takes no air at all and keeps the whole band
   above the fold. Below ~1495px both terms are zero and NOTHING moves —
   1440x900, the canonical measuring point, is byte-identical. The air is
   split evenly above the eyebrow and below the subhead, so the headline stays
   centred in the taller room (the composition he ratified off the iPad).
   The photo grows into it automatically: site.js still pins --hxcut to the
   tile row, so the §105 gap holds at every width. */
.hxwide { --hxair: min(max(0px, calc(100vw * 0.389375 - 581px)), max(0px, calc(100vh - 912px))); }
.hxwide .hero { padding-top: calc(var(--hero-pt) + var(--hxair) / 2); padding-bottom: calc(var(--hxair) / 2); }
/* §105 (2026-07-30, the founder's air ruling): the photo no longer ends AT
   the tile row — it stops --hxgap ABOVE it, so the tiles float on light
   canvas between the room and the band's exit hairline (40px above the row
   vs 45px below the dark card at 1440; 28px above at phone). The pin is
   untouched: site.js still writes the row's top into --hxcut; the
   subtraction lives here, and the no-JS floor becomes calc(76% - gap). */
.hxwide .hxbg { position: absolute; top: 0; left: 0; right: 0; --hxgap: 40px; height: calc(var(--hxcut, 76%) - var(--hxgap)); z-index: 0; overflow: hidden; }
/* §101 (2026-07-30, tone ratified by the founder off the side-by-side —
   measured 1.5/255 mean difference): the at-rest photo is the GRAY BAKE,
   no CSS filter. The permanent filtered full-bleed layer was the arc's
   heaviest raster (his recordings: the line-2 freeze as it landed). The
   color rendition is the second stacked <picture class="hxc"> — [hidden]
   + loading=lazy in markup, so zero bytes until site.js un-hides it —
   and the §82 bloom is now an OPACITY crossfade on that layer, same
   0.5s, gated by .hx-ready (set on the color img's load; a hover before
   it loads blooms late, never pops). PAINT ORDER IS DOM ORDER (gray,
   color, scrim ::after) — no z-index on purpose: any z-index here lifts
   a picture above the scrim. */
.hxwide .hxbg picture { position: absolute; inset: 0; }
.hxwide .hxbg img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%; display: block; }
.hxwide .hxbg .hxc img { opacity: 0; transition: opacity 0.5s ease; }
.hxwide .hxbg::after { content: ""; position: absolute; inset: 0; transition: opacity 0.5s ease; background-image:
  linear-gradient(90deg, rgba(8,8,8,0.34) 0%, rgba(8,8,8,0.10) 55%, rgba(8,8,8,0.22) 100%),
  linear-gradient(180deg, rgba(8,8,8,0.30) 0%, rgba(8,8,8,0.44) 58%, rgba(8,8,8,0.56) 100%); }
.hxwide .hero > .wrap, .hxwide .stats > .wrap { position: relative; z-index: 1; }
/* the hero/band hairline would slice the room; the band's exit hairline
   below the tiles is untouched */
.hxwide .stats { border-top: 0; }
/* §108: the SCRIM lift is gated on .hx-ready too. It was not, while the color
   image always has been — so a hover before the color layer had loaded lifted
   22% of the scrim off a still-GRAY photo. That intermediate state is exactly
   what the founder reported during the entrance ("a weird, a little bit
   lighter grayscale, and you have to wait till the end for the color"), and
   gating it makes the state structurally impossible: either color and a
   lifted scrim together, or the composed gray frame. It is also what let
   site.js drop its arcBusy defer — an arm during the arc is now visually
   silent until the frame decodes, so hover can always arm. */
@media (hover: hover) and (pointer: fine) {
  .hxwide.hx-ready:hover .hxbg .hxc img { opacity: 1; }
  .hxwide.hx-ready:hover .hxbg::after { opacity: 0.78; }
}
.hxwide.hx-ready.hx-alive .hxbg .hxc img { opacity: 1; }
.hxwide.hx-ready.hx-alive .hxbg::after { opacity: 0.78; }
/* the bloom is a state change, not motion — under reduced motion it lands
   instantly, the §82 grammar */
@media (prefers-reduced-motion: reduce) { .hxwide .hxbg img, .hxwide .hxbg::after { transition: none !important; } }

/* White-text overrides for the dark treatment. Neutral grays only: eyebrow
   #B4B4AF (lifted one step 2026-07-29 — #A9A9A4 read weak over the bright
   glass; spread 5), muted "them" lines and thesis setup #C8C8C3, ink lines
   and pens #FAFAF8, subhead #E7E7E3. The entrance animates transforms,
   opacity, and background-size only, so recoloring changes nothing
   mechanical. The two-tone grammar (muted setup / bright answer) survives
   the flip. */
.hero .eyebrow { color: #B4B4AF; }
.hero .hline:nth-child(-n+2) .hline-i { color: #C8C8C3; }
.hero h1 { color: #FAFAF8; }
.hero-ul { background-image: linear-gradient(#FAFAF8, #FAFAF8); }
.hero-sub { color: #E7E7E3; }
.stats-thesis { color: #FAFAF8; }
.stats-thesis .th-m .th-i { color: #C8C8C3; }
.stats-thesis .th-ink, .stats-thesis .th-w { color: #FAFAF8; }
.stats-thesis .th-ul { background-image: linear-gradient(#FAFAF8, #FAFAF8); }

/* Phones: the painting side of the square, no glass letters (the founder's
   ruling — the ~37% window seats over the canvas at 0%), under the denser
   single-axis scrim. §105 scales the tile-row air down (28px photo gap;
   the 20px tile drop lives in the §89 stat block). */
@media (max-width: 680px) {
  .hxwide .hxbg { --hxgap: 28px; }
  .hxwide .hxbg img { object-position: 0% 50%; }
  .hxwide .hxbg::after { background-image:
    linear-gradient(180deg, rgba(8,8,8,0.42) 0%, rgba(8,8,8,0.50) 60%, rgba(8,8,8,0.60) 100%); }
}

/* Print serves the PAPER hero (the founder's port ruling, 2026-07-29):
   engines keep content images but drop background layers, which would
   strand white text on the bright glass. A printed page is a document —
   photo off, every tone restored to its base value, the hairline back. */
@media print {
  .hxwide .hxbg { display: none; }
  .hxwide .stats { border-top: 1px solid var(--rule); }
  .hero .eyebrow { color: var(--muted); }
  .hero .hline:nth-child(-n+2) .hline-i { color: #52524E; }
  .hero h1 { color: var(--ink); }
  .hero-ul { background-image: linear-gradient(var(--ink), var(--ink)); }
  .hero-sub { color: var(--body); }
  .stats-thesis { color: inherit; }
  .stats-thesis .th-m .th-i { color: #52524E; }
  .stats-thesis .th-ink, .stats-thesis .th-w { color: var(--ink); }
  .stats-thesis .th-ul { background-image: linear-gradient(var(--ink), var(--ink)); }
}

/* ==========================================================================
   §100 (2026-07-29) — clean-URL navigation focus seat. In-page anchors now
   scroll programmatically (site.js §100 block) and seat focus on the
   destination section with tabindex="-1" so keyboard/AT reading order
   follows the jump. A whole-section focus rectangle is noise, not
   affordance — suppressed. Keyboard :focus-visible on real controls is
   untouched (sections are never tabbable; this focus is programmatic).
   ========================================================================== */
.sec:focus { outline: none; }


/* ==========================================================================
   §113 (2026-08-03) — THE ANALYSIS-ROW COMPRESSION. The founder's BP lock
   off the BF–BP variant board ("Lock BP. That is the one"): the MAX-shrink
   window (aspect 8.5/12.6, set in the base .vq .b-stage rule) with EVERY
   word kept and the click-to-expand accordion intact.
   POSITION IS LOAD-BEARING: these ≥681 overrides tie the base .vq rules at
   (0,2,0), so they must sit LATER in source to win — media queries add no
   specificity (the §107/§108 lesson, which also bit the board's own phone
   rendering; see BUILD-NOTES §113). This block replaced the board's
   working-tree-only BOARD-ONLY block at the same seat.
   ≥681 ONLY, all of it: phones keep the §90/§91 grammar byte-identical
   (his standing carve-out — the ≤680 block already re-derives stage
   padding, table columns, and card sizing). Chart BAR heights are never
   scaled: the proportions are the data. The column deliberately runs
   ~93px past the window's bottom edge (his acceptance; word-trims
   reserved to him — the close cluster pins to the column foot, so a trim
   self-levels the edges with no CSS change). The .vq vnav margins below
   supersede §112's 7/8 for THIS window only (8/8 — the board-measured
   values the 12.6 aspect was tuned against); the other three windows
   keep §112's budgets untouched.
   ========================================================================== */
@media (min-width: 681px) {
  /* column: rail + pivot + moves + close, the board's measured spacing */
  .vq .vsteps { margin-top: 14px; }
  .vq .vsteps > li { margin-top: 7px; }
  .vq .b-frame { margin-top: 12px; }
  .vq .lead-mv { margin-top: 8px; }
  .vq .lead-mv li { margin-top: 9px; font-size: 14.5px; line-height: 1.5; }
  .vq .lead-close { margin-top: auto; padding-top: 12px; }
  .vq .svc-copy .cta-wrap { margin-top: 0; } /* ONE auto margin in the close cluster — two split the slack (board-recorded trap) */
  /* window: the max-shrink set (plate, seams, tables, donut, foot strips) */
  .vq .b-stage { padding: 14px 22px 10px; }
  .vq .b-khead { padding-top: 6px; }
  .vq .b-read { margin-top: 6px; }
  .vq .gx { margin-top: 9px; }
  .vq .gxc { margin-top: 8px; gap: 18px; }
  .vq .gx-key { margin-top: 6px; } /* the .b-earn/.b-growth scoped 4px keys outrank this — untouched */
  .vq .gx-fn { margin-top: 5px; }
  .vq .jx-tbl { margin-top: 7px; }
  .vq .jx-tbl .r { padding: 4.5px 9px; }
  .vq .jx-tbl .th { padding: 5px 9px; }
  .vq .jx-kpi { margin-top: 8px; }
  .vq .jx-kpi .k { padding: 7px 10px; }
  .vq .jx-donut { margin-top: 8px; }
  .vq .jx-donut .ring { width: 136px; height: 136px; }
  .vq .gxr { margin-top: 8px; }
  .vq .gxr .r { margin-top: 6px; }
  .vq .gxs { padding-top: 8px; }
  .vq .jx-foot .gxs { padding-bottom: 11px; }
  .vq .b-stage > .vnav { margin: 0 0 8px; padding-bottom: 8px; }
}

/* ==========================================================================
   §114 (2026-08-03): PHONE NAV-ON-TOP + THE SEQUENTIAL PHONE ORDER — the
   founder's ruling, a KNOWING reversal of §112's phone carve-out ("I like
   how it currently looks on an iPhone" superseded by "they should be at the
   top, consistent with how we've done it elsewhere... intuitive for older
   generations"). POSITION IS LOAD-BEARING: this block stays at the
   STYLESHEET FOOT, after the §113 compression block — media queries add no
   specificity and every ≤680 rule here wins its ties by source order (the
   §107/§108/§113 lesson, fourth sighting).
   (1) THE NAV SEAT ≤680: all four multi-view windows' Back/Next rides the
   window TOP — §112's four relocations, phone edition, verbatim budgets.
   The §60 grammar is now one SEAT as well as one grammar, at every width.
   The .rnav at the rail foot STAYS (his call: both rows — "repetitive is
   fine, they can't miss it"); .vnav-ct stays hidden ≤680 (the .rnav
   carries the counter, §108).
   (2) THE SEQUENTIAL ORDER ≤680, analysis row + fit row: the copy column
   flattens (display: contents) so the question rail sits DIRECTLY on the
   window it drives, and everything after the rail (analysis: pivot + three
   moves + alignment line + CTA; fit: advise line + scope note + CTA)
   re-seats BELOW the window. The grid gap zeroes (a flattened column would
   inherit 44px between EVERY child) and the seams are re-authored as
   margins below. Desktop and iPad (≥681) never enter this block — the §113
   contract is untouched by construction. A11y note, recorded: visual order
   diverges from DOM order on phones (readers hear pivot/moves before the
   window); the §90 rail semantics are untouched.
   ========================================================================== */
@media (max-width: 680px) {
  /* (1) the nav seat — mirrors §112's ≥681 block */
  .vq .b-stage > .vnav { order: -1; margin: 0 0 8px; padding-bottom: 8px; border-bottom: 1px solid #E4E4E0; }
  .vx-stage > .vnav { order: -1; margin: 0 0 10px; padding-bottom: 10px; border-bottom: 1px solid #E4E4E0; }
  .fv-plate { display: flex; flex-direction: column; }
  .fv-plate > .vnav { order: -1; margin: 0 0 6px; padding-bottom: 7px; border-bottom: 1px solid #E4E4E0; }
  .win[data-card="pipe"] { display: flex; flex-direction: column; }
  .pipe-frame { order: 1; }
  .pipe-vnav { border-top: 0; border-bottom: 1px solid var(--card-rule); }
  /* (2a) sequential order — the analysis row (index) */
  .vq .svc-copy { display: contents; }
  .vq.gap-grid { gap: 0; }
  .vq .b-frame, .vq .lead-mv, .vq .lead-close, .vq .cta-wrap { order: 1; }
  .vq figure.product { margin-top: 22px; }
  .vq .b-frame { margin-top: 40px; }
  .vq .cta-wrap { margin-top: 0; padding-top: 26px; }
  /* (2b) sequential order — the fit row (/buy-side #process) */
  #process .gap-copy { display: contents; }
  #process.gap-grid { gap: 0; }
  #process .fv-advise, #process .scope-note, #process .bx-cta { order: 1; }
  #process figure.product { margin-top: 22px; }
  #process .fv-advise { margin-top: 36px; }
  #process .bx-cta { margin-top: 0; padding-top: 8px; }
}

/* ==========================================================================
   §115 (2026-08-03): THE VALUE WINDOW AT ITS CONTENT FLOOR — the founder's
   BR pick off the BQ–BT board ("BR"; the BS broken-axis staircase and the
   BT lawyer-indent bridge are DEAD — his eyes, after the BS objection was
   argued: the zero base stays the teaching-chart rule and the bridge keeps
   the page's ONE axis break). The §54-era 10/11 aspect minimum is RETIRED
   ≥681 exactly as §113 retired the sample window's: content sizes the
   stage. Ratified numbers at 1440: window 690 (was 764), running 6px past
   the column's last line ("The multiple can move.") — his "aligned with
   the multiple that can move" target. The staircase bars are re-authored
   INLINE at 14px/$M (140/168/201.6 — proportions identical to the old
   16.5px/$M set; a uniform re-scale is not the banned bar-squeeze) and
   .st-plot trues to 225 at ALL widths (the board mock left phones at 260,
   which was 58px of accidental head air nobody ratified; 225 restores the
   pre-round ~23px proportion). Fine print 11.5 → 10.5px ≥681; phones keep
   §90's own paddings and the 11.5 base fine print. POSITION IS
   LOAD-BEARING: stylesheet foot, after §114 (media queries add no
   specificity — fifth sighting).
   ========================================================================== */
@media (min-width: 681px) {
  .vx-stage { aspect-ratio: auto; padding: 20px 24px 16px; }
  .vg-foot { font-size: 10.5px; line-height: 1.5; margin-top: 16px; padding-top: 10px; }
  .stair { margin-top: 8px; }
  .call2 { margin-top: 14px; padding-top: 12px; }
  .phband-h { margin-bottom: 4px; }
}
.st-plot { height: 225px; }
