/* =====================================================================
   LANDING — CGT page sheet (CGT-WP-01). THE MOCKUP'S STYLE BLOCKS 3-7,
   CONSOLIDATED IN THEIR ORIGINAL ORDER — the order IS the cascade (blocks
   5-7 override earlier rules at equal specificity by source order) and it
   must survive every future edit: append, never reorder.
   Source of truth: cgt-landing-mockup-v5-28.html (sha256 e1d84c0f…).
   Blocks 1-2 are deliberately NOT here: 1 is the mockup's stand-in token
   copy (its own header bars copying it), 2 is chrome CSS the theme ships.

   THE ONLY EDITS vs the mockup, per the dispatch:
     1. --lattice: data URI -> the real asset (the mockup's own install note).
     2. The :root colour/role definitions removed — tokens.css owns them.
     3. This prelude: the two NON-COLOUR layout tokens the mockup's stand-in
        block carried (--head-h = the header bar height header.css sets;
        --tex-tile = 18px, the mockup's "one unverified number", now VERIFIED
        against quote-block.css:251's live mask-size), and the scoped
        --on-slate override below.

   ⚠ SCOPED --on-slate OVERRIDE, A MEASURED DECISION FLAGGED AT GATE 2.
   tokens.css pairs --ground-slate with --on-slate:var(--cream); the mockup
   ships --on-slate:var(--white). Cream on slate is 4.3009 — legal for the
   LARGE quote type, FAILING 4.5 for the 10.5px figcaption. White is 4.88,
   passing both; the mockup chose it for exactly that reason. Reusing the
   theme pair at its theme value would ship an AA failure the approved
   design avoids, so this page re-points the SAME NAME (no second name,
   R348; no new value — --white is Layer 1) within its own band only. If
   the palette ever rules slate bands site-wide, re-measure the figcaption.
   ===================================================================== */
:root{
  --head-h:80px;
  --tex-tile:18px;
  --lattice:url(../../img/longitude-texture.svg);
}
.band-slate{--on-slate:var(--white)}


/* ================== MOCKUP STYLE BLOCK 3 ================== */
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--ground-page);color:var(--on-page);
  font-family:var(--sans);font-size:16.5px;line-height:1.65}

section{padding:110px 34px}
.in{max-width:1180px;margin:0 auto}
.in--hero{max-width:1320px}
.in--tight{max-width:1040px}
.band-cream{background:var(--ground-alt);color:var(--on-alt)}
.band-plum{background:var(--ground-dark);color:var(--on-dark);
  position:relative;isolation:isolate}
.band-accent{background:var(--ground-accent);color:var(--on-accent);
  position:relative;isolation:isolate}

/* ---- dark-band lattice, matching the pattern the live dark sections carry.
   APPROXIMATION: measured off a screenshot at ~17.5px pitch, r6.6, 1.5 stroke.
   THE REAL ASSET IS:
     assets/img/longitude-texture.svg
   This mockup is a standalone file and cannot load it, so shell 4 replaces
   the --lattice value below with
     url("<?php echo get_template_directory_uri(); ?>/assets/img/longitude-texture.svg")
   and drops the mask-size override if the real tile has its own pitch.
   That is the ONLY line that changes at install.
   Drawn as a MASK, not an image, so no colour literal enters the build: the
   white in the data URI is mask alpha, and the visible tint comes from
   --cream through color-mix, exactly like --rule-on-dark. */
/* --lattice now points at the real asset — defined in the prelude above. */
.band-plum::before,.band-accent::before{content:"";position:absolute;inset:0;z-index:-1;
  pointer-events:none;
  -webkit-mask-image:var(--lattice);mask-image:var(--lattice);
  -webkit-mask-size:var(--tex-tile) var(--tex-tile);mask-size:var(--tex-tile) var(--tex-tile);
  -webkit-mask-repeat:repeat;mask-repeat:repeat}
.band-plum::before{background:color-mix(in srgb, var(--cream) 5%, transparent)}
.band-accent::before{background:color-mix(in srgb, var(--white) 7%, transparent)}

h1,h2,h3{font-family:var(--serif);font-weight:600;margin:0;letter-spacing:-.012em}
.band-h2{font-size:clamp(24px,2.2vw,32px);line-height:1.18;max-width:26ch}
h3{font-size:19px;line-height:1.3}
p{margin:0 0 1.1em}
.lede{max-width:66ch;font-size:17.5px;line-height:1.62;color:var(--on-page-body)}
.band-plum .lede{color:var(--on-dark-body)}
.band-accent .lede,.band-accent .kick,.band-accent .sub-cta{color:var(--on-accent)}
.kick{font-family:var(--mono);font-size:11px;letter-spacing:.26em;
  text-transform:uppercase;color:var(--slate);margin:0 0 22px}
.band-plum .kick{color:var(--on-dark-body)}
/* on accent the button inverts the other way: white ground, accent text */
.band-accent .btn--invert{background:var(--on-accent);color:var(--ground-accent)}
.band-accent .btn--invert:hover{background:var(--white)}

/* .btn now comes from the real components/buttons.css above — removed */

/* ---- shared keyframes: defined once, never inside a component block ---- */
@keyframes drawX{to{background-size:100% 100%}}
@keyframes rise{to{opacity:1;transform:none}}

/* ============ S1 — EDITORIAL HERO (no competing object) ============ */
/* measured with the real chrome in place: at 92px the CGT mark cleared the
   fixed header by 12px at 1400 and sat BEHIND it by 15px at 760. The hero's
   top padding now pays the header's 80px before its own breathing room. */
/* RICK'S LAYOUT. Three changes from v5-16, each with a consequence:
   1. The mark is the CGT globe ALONE, at 88px rather than a 46px lockup. The
      wordmark leaving the page body is a fix, not a loss: the fixed header
      already carries LONGITUDE°, so the lockup was printing it twice within
      ~130px of vertical space. This closes the open "double logo" decision.
   2. Headline and lede sit SIDE BY SIDE from the top. The hairline rule is
      gone — with two columns the gutter does the dividing the rule used to.
   3. The pull-quote and the ruled clarity block leave the hero. Neither is
      lost: "Built by health systems, for health systems." is already the H2
      of S4a, and the clarity sentence is promoted to S1b below. */
.hero{padding-top:calc(var(--head-h) + 54px);padding-bottom:100px}
.u-mark{display:block;height:88px;width:auto;margin:0 0 42px}
.hero-top{display:grid;grid-template-columns:1.62fr 1fr;gap:5.5vw;align-items:start}
.hero h1{
  /* 16ch, measured not guessed: at 14ch the headline broke to five lines and
     split "and gene therapy" across two. 15-17ch all hold the four-line break
     Rick drew, so 16 sits in the middle of that stable band. */
  font-size:clamp(40px,5.7vw,80px);line-height:1.03;max-width:16ch;
  letter-spacing:-.022em;margin:0
}
.hero h1 em{font-style:normal;color:var(--accent)}
/* the lede column is narrow by design — at 42ch it sets a 7-9 line block that
   finishes near the headline's last line, so the CTA lands on the same optical
   baseline as "programs." rather than floating above or below it. */
.hero-sub{font-size:17px;line-height:1.62;color:var(--on-page-body);margin:0 0 30px;max-width:42ch}

/* ============ S1b — THE STATEMENT ============ */
/* Gold carrying type, which it does nowhere else on this page. The reason is
   measured, not stylistic: --gold #F0B83F on --plum #292631 is 8.22, while the
   same token on cream is 1.59. Plum is the only ground in the palette where
   gold can hold a sentence. */
.statement{padding-top:100px;padding-bottom:100px}
.statement .in{max-width:1100px}
.statement-line{
  font-family:var(--serif);text-align:center;margin:0;
  font-size:clamp(25px,3.4vw,45px);line-height:1.24;letter-spacing:-.012em;
  color:var(--on-dark);text-wrap:balance
}
.statement-line em{font-style:normal;color:var(--gold)}

/* ============ S2 — FIVE CAPABILITIES ============ */
/* Centred heading and lede. The ledger below is the section's whole argument
   now, so it gets real air above it rather than sitting under a diagram. */
/* measured against Rick's comp: his heading sits on ONE line at desktop and
   runs ~1042px wide inside the 1180 spine. 24ch was forcing a two-line break
   that isn't in the drawing, so the measure comes off and the container does
   the bounding. It breaks to two lines on its own below ~1270px. */
.caps .band-h2{font-size:clamp(28px,3.9vw,54px);line-height:1.1;
  max-width:none;margin:0 auto;text-align:center;letter-spacing:-.015em;
  text-wrap:balance}
.caps .band-h2 em{font-style:normal;color:var(--accent)}
.caps-lede{max-width:86ch;margin:36px auto 0;text-align:center;
  font-size:17.5px;line-height:1.62;color:var(--on-page-body)}

.caplist{list-style:none;margin:92px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(5,1fr);
  border-top:1px solid var(--rule-hair)}
.caprow{position:relative;display:block;width:100%;text-align:left;
  border-right:1px solid var(--rule-hair);padding:26px 28px 28px 28px;margin:0}
/* only the first column sits flush on the spine, so the ledger's left edge
   lines up with the rule above it and with every other section's spine. */
.caplist li:first-child .caprow{padding-left:0}
.caplist li:last-child .caprow{border-right:0}
.caprow .n{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;
  color:var(--accent);margin-bottom:9px}
.caprow h3{font-family:var(--serif);font-size:17px;line-height:1.28;margin:0 0 7px;font-weight:600}
.caprow p{margin:0;color:var(--on-page-body);font-size:14.5px;line-height:1.55}

/* ============ S3 — pillars, meridian-derived marks ============ */
.pillars{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:50px}
.pillar{border:1px solid var(--rule-hair);border-radius:8px;
  padding:30px 28px 32px;background:var(--ground-page)}
.pillar svg{display:block;margin:0 0 22px}
.pillar h3{font-family:var(--serif);margin-bottom:10px}
.pillar p{margin:0;color:var(--on-page-body);font-size:16px;max-width:60ch}

/* ============ S4 — outcome cards (plum) ============ */
/* Each card is self-contained and carries its own marker, so 4-up, 2x2 and
   1-col reflow for free. The old shared dotted line with absolutely-placed
   nodes could only ever work as a single row — it broke the moment it wrapped. */
.oline{margin-top:56px}
.outcomes{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
.outcome{position:relative;background:var(--tint-on-dark);
  border:1px solid var(--rule-on-dark);border-radius:8px;
  padding:30px 24px 28px;overflow:hidden;
  opacity:0;transform:translateY(12px);
  transition:opacity .5s ease, transform .55s cubic-bezier(.2,.9,.25,1),
             border-color .25s ease, background .25s ease}
.outcome::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;
  background:var(--gold);transform:scaleX(0);transform-origin:left center;
  transition:transform .55s cubic-bezier(.4,0,.2,1)}
.oline.is-in .outcome{opacity:1;transform:none}
.oline.is-in .outcome::before{transform:scaleX(1)}
.oline.is-in .outcome:nth-child(1)::before{transition-delay:0s}
.oline.is-in .outcome:nth-child(2)::before{transition-delay:.14s}
.oline.is-in .outcome:nth-child(3)::before{transition-delay:.28s}
.oline.is-in .outcome:nth-child(4)::before{transition-delay:.42s}
.oline.is-in .outcome:nth-child(1){transition-delay:.18s}
.oline.is-in .outcome:nth-child(2){transition-delay:.32s}
.oline.is-in .outcome:nth-child(3){transition-delay:.46s}
.oline.is-in .outcome:nth-child(4){transition-delay:.60s}
.oline.is-in .outcome:hover{transform:translateY(-3px);
  border-color:color-mix(in srgb,var(--cream) 38%,transparent);
  background:color-mix(in srgb,var(--cream) 12%,transparent)}
.outcome h3{font-family:var(--serif);font-size:19px;margin:0 0 9px;color:var(--on-dark)}
.outcome p{margin:0;color:var(--on-dark-body);font-size:15.5px;line-height:1.55;max-width:60ch}

/* ============ Partner strip — the /our-team treatment ============ */
/* Three changes from the old strip, to match Governing Members on /our-team:
   a serif heading instead of a mono kicker, a NODE on the rule above each
   logo, and the logos in full colour instead of greyscale.
   The nodes are each column's own ::before rather than hand-placed points, so
   a node is dead-centre over its logo at every width and cannot drift on
   reflow — the failure the absolutely-placed nodes in the old outcome row hit.
   That requires the grid items to share a top edge, hence align-items:stretch
   on the row with the centring done inside each cell. */
.mstrip-h2{font-family:var(--serif);text-align:center;margin:0 0 58px;
  font-size:clamp(28px,3.4vw,44px);line-height:1.12;letter-spacing:-.012em;
  color:var(--on-alt)}
.mstrip{text-align:center}
.mstrip .row{position:relative;display:grid;grid-template-columns:repeat(5,1fr);
  align-items:stretch;gap:2vw;max-width:1040px;margin:0 auto;padding-top:46px}
.mstrip .row::before{content:"";position:absolute;top:0;left:0;right:0;height:1px;
  background-image:repeating-linear-gradient(to right,var(--stone) 0 3px,transparent 3px 9px);
  background-repeat:no-repeat;background-size:0 100%}
.mstrip.is-in .row::before{animation:drawX 1.3s linear forwards}
.mem{position:relative;display:flex;align-items:center;justify-content:center;
  opacity:0;transform:translateY(8px)}
/* 9px node, pulled back onto the 1px rule 46px above the cell's top edge.
   46 measured off /our-team: the rule sits ~32px clear of the shortest logo,
   and the cells are as tall as the tallest mark, so the padding carries the
   difference. */
.mem::before{content:"";position:absolute;top:-46px;left:50%;
  width:9px;height:9px;margin:-4px 0 0 -4.5px;border-radius:50%;
  background:var(--ink)}
.mstrip.is-in .mem{animation:rise .52s ease forwards}
.mstrip.is-in .m-mic{animation-delay:.123s}
.mstrip.is-in .m-pro{animation-delay:.386s}
.mstrip.is-in .m-nov{animation-delay:.635s}
.mstrip.is-in .m-mem{animation-delay:.899s}
.mstrip.is-in .m-bay{animation-delay:1.177s}
/* full colour, as on /our-team — no grayscale filter, no opacity knockback */
.mem img{display:block;height:auto;max-width:100%;max-height:72px;width:auto}

/* measured: at 430px the five columns squeezed every logo to 53px wide, which
   is unreadable. Below 640 they wrap to two columns — and the nodes come OFF,
   because a node-per-column only reads as a row of stops while the logos are
   one row. Five dots scattered over two rows is noise, so the rule reverts to
   a plain divider. */
@media (max-width:640px){
  .mstrip-h2{margin-bottom:42px}
  .mstrip .row{grid-template-columns:repeat(2,1fr);gap:42px 26px;padding-top:44px}
  .mem::before{display:none}
  .mem img{max-height:58px}
  /* the fifth logo is an orphan on a 2-up grid, so it spans both columns —
     and its image is capped at half width, or spanning would print it at
     325px against the 169px its row-mates get. */
  .mstrip .row .mem:last-child{grid-column:1 / -1}
  .mstrip .row .mem:last-child img{max-width:50%}
}

/* ============ S5 — PROOF, in the established quote style ============
   Rebuilt to the component already running on longitudehealth.org: slate
   ground with the lattice, oversized gold quote mark, big circular portrait
   on the left, serif quote on the right, mono attribution beneath.
   MEASURED on --slate #5E7484:
     white 4.88  -> passes AA for normal text, not just large
     gold  2.70  -> which is why the gold is ONLY the decorative mark. It is
                    aria-hidden and carries no content, consistent with the
                    standing rule that gold is ornament and never carries
                    state or meaning on its own.
   The two quotes cycle. Timing is measured, not picked: the longer quote is
   40 words, ~12s at 200wpm, so the dwell is 14s — anything near the usual
   5-8s carousel interval would pull the slide before it can be read. It
   pauses on hover and on keyboard focus, stops for good on any interaction,
   and never runs under prefers-reduced-motion. */
.band-slate{background:var(--ground-slate);color:var(--on-slate);
  position:relative;isolation:isolate}
.band-slate::before{content:"";position:absolute;inset:0;z-index:-1;
  pointer-events:none;
  -webkit-mask-image:var(--lattice);mask-image:var(--lattice);
  -webkit-mask-size:var(--tex-tile) var(--tex-tile);mask-size:var(--tex-tile) var(--tex-tile);
  background:color-mix(in srgb, var(--ink) 16%, transparent)}

.qstage{position:relative}
/* MEASURED FIX. First pass locked the whole stage — nav included — to the
   tallest slide, which left 155px of dead slate BELOW the dots whenever the
   shorter quote was showing. The frame now holds only the stacked slides and
   is locked to the tallest of them; the nav sits under the frame in normal
   flow, so the dots never move and the slack falls above them.
   Slides are anchored to the frame's TOP (inset:0 0 auto 0), not stretched to
   it — stretching plus align-items:center would re-centre the shorter slide
   and make the portrait jump vertically on every change. */
.qframe{position:relative}
/* MEASURED FIX 2. align-items:center made the portrait sit 144px down on the
   short quote and 222px down on the long one — a 78px vertical jump every
   time the slide changed, with the portrait being the largest object on the
   band. Top-aligned instead, with the portrait pushed down by exactly the
   quote mark's own height (52 + 16 margin), so it starts level with the first
   line of the quote and lands in the same place on every slide. */
.qslide{margin:0;display:grid;grid-template-columns:320px 1fr;gap:5vw;
  align-items:start;
  position:absolute;inset:0 0 auto 0;opacity:0;visibility:hidden;
  transition:opacity .55s ease}
.qport{margin-top:68px}
.qslide.is-on{opacity:1;visibility:visible}

.qport{position:relative;width:320px;height:320px;justify-self:center}
/* the soft halo behind the circle, as on the live component */
.qport::before{content:"";position:absolute;inset:-14px;border-radius:50%;
  background:radial-gradient(circle,
    color-mix(in srgb, var(--white) 22%, transparent) 55%, transparent 72%)}
.qport img{position:relative;width:100%;height:100%;border-radius:50%;
  object-fit:cover;display:block}

.qmark{display:block;font-family:var(--serif);font-size:84px;line-height:1;
  height:52px;overflow:hidden;color:var(--gold);margin:0 0 16px}
.qslide blockquote{margin:0}
.qslide blockquote p{font-family:var(--serif);font-weight:600;
  font-size:clamp(21px,2.1vw,31px);line-height:1.32;margin:0;
  max-width:24ch;color:var(--on-slate)}
.qslide figcaption{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--on-slate);margin-top:30px;line-height:1.7}

/* controls — hairlines, not plates, to match the rest of the page */
.qnav{display:flex;gap:10px;margin-top:34px}
.qdot{width:11px;height:11px;padding:0;border-radius:50%;cursor:pointer;
  background:none;border:1px solid color-mix(in srgb, var(--white) 55%, transparent);
  transition:background .2s ease,border-color .2s ease}
.qdot[aria-current="true"]{background:var(--gold);border-color:var(--gold)}
.qdot:focus-visible{outline:3px solid var(--white);outline-offset:3px}

/* measured: at 430px the fixed 320px portrait column left 114px for the quote
   and pushed the document into horizontal overflow. Below 860 the slide
   stacks, the portrait drops to 200px and loses the 68px offset that only
   exists to align it with the first line of a quote sitting beside it. */
@media (max-width:860px){
  .qslide{grid-template-columns:1fr;gap:30px}
  .qport{width:200px;height:200px;margin-top:0;justify-self:start}
  .qslide blockquote p{max-width:30ch}
  .qmark{font-size:68px;height:44px;margin-bottom:12px}
  .qslide figcaption{margin-top:24px}
}

/* ============ S6 — CTA, now the homepage form block ============
   The accent band is GONE. This section was the page's one dark terminal
   beat; it is now the cream-ground heading-plus-form block the homepage uses
   for Join Us, carrying the CGT copy and an accent button.

   CONSEQUENCE WORTH NAMING: --ground-accent is no longer used anywhere on
   this page. The token pair stays in :root because the Rural page may still
   want it, but CGT no longer forces that tokens.css ruling by itself.

   MEASURED on --paper #FBF8F2:
     --accent  5.42  -> carries "demo." as display type, and the button fill
     --ink    13.99  -> labels and field borders
     --focus   3.93  -> the only true purple in the palette. It FAILS AA for
                        normal text, and it is the focus-ring token, so
                        borrowing it for display type would both dim the word
                        and overload a reserved role.
   Button: white on accent = 5.74. */
.cta{background:var(--ground-page);color:var(--on-page);
  padding-top:118px;padding-bottom:118px}
.cta-grid{display:grid;grid-template-columns:1fr 1.15fr;gap:6vw;align-items:start}
.cta-h2{font-family:var(--serif);font-weight:600;letter-spacing:-.02em;
  font-size:clamp(34px,4.6vw,60px);line-height:1.04;max-width:9ch;margin:0}
.cta-h2 em{font-style:normal;color:var(--accent)}
.cta-lede{margin-top:26px;max-width:42ch;font-size:17px;line-height:1.62;
  color:var(--on-page-body)}

/* ---- the form. A VISUAL STAND-IN, not a working form: no action, and the
   script hard-stops submit. Field names, order and labels mirror the live
   homepage form so the HubSpot embed drops in against a known shape. ---- */
.f-note{font-size:14px;color:var(--on-page-soft);margin:0 0 24px}
.f-row{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.f-field{margin-bottom:22px}
.f-field > label{display:block;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--on-page);
  margin-bottom:9px}
.f-field input,.f-field select,.f-field textarea{
  display:block;width:100%;box-sizing:border-box;
  background:var(--white);color:var(--on-page);
  border:1px solid var(--ink);border-radius:6px;
  padding:13px 14px;font-family:var(--sans);font-size:16px;line-height:1.3}
.f-field textarea{min-height:124px;resize:vertical}
.f-field input:focus-visible,.f-field select:focus-visible,
.f-field textarea:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.f-send{margin-top:8px;border:0;cursor:pointer;font-family:var(--sans)}
.f-standin{margin:18px 0 0;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--on-page-soft)}
.sub-cta{font-size:15px;color:var(--on-page-soft);margin:0}

@media (max-width:860px){
  .cta-grid{grid-template-columns:1fr;gap:46px}
  .cta-h2{max-width:14ch}
  .cta-lede{max-width:58ch}
}
@media (max-width:560px){
  .f-row{grid-template-columns:1fr;gap:0}
}

.rv{opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .6s ease}
.rv.is-in{opacity:1;transform:none}

@media (max-width:920px){
  section{padding:84px 34px}
  .hero-top{grid-template-columns:1fr;gap:38px}
  .hero h1{max-width:18ch}
  .hero-sub{max-width:62ch}
  .caplist{grid-template-columns:1fr 1fr;margin-top:64px}
  .caprow{border-right:1px solid var(--rule-hair);
    border-bottom:1px solid var(--rule-hair);padding:24px 22px 26px 22px}
  .caplist li:nth-child(odd) .caprow{padding-left:0}
  .caplist li:nth-child(even) .caprow{border-right:0}
  .caplist li:last-child .caprow{border-right:0}
  .cta{padding-top:96px;padding-bottom:96px}
}
/* measured: 4-up outcome paragraphs fall to 18.8ch at 921 — a 40px window
   that is worse than the 2-up it was about to become. Break at 960, where
   two columns pick up at 44ch. */
@media (max-width:960px){
  .outcomes{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:1000px){
  .quotes{gap:40px}
  
  blockquote p{font-size:18px}
  /* measured: 4-up outcomes fell to 20.6ch at 940 with 24px sides;
     reclaiming 6px a side holds them above 22ch until the 2-col break. */
  .outcome{padding:26px 18px 24px}
}
@media (max-width:900px){
  /* measured: with gap 16 and 18px side padding, three columns hold a
     one-line heading and a 24-25ch measure all the way to 740px.
     Stacking at 920 was ~160px premature. */
  .pillars{gap:16px}
  .pillar{padding:22px 18px 24px}
  .pillar h3{font-size:17.5px}
  .pillar p{font-size:15px}
  .pillar svg{width:48px;height:48px;margin-bottom:18px}
}
@media (max-width:760px){
  section{padding:64px 34px}
  .quotes{grid-template-columns:1fr;gap:46px}
  
  blockquote p{font-size:18.5px;max-width:52ch}
  .hero{padding-top:calc(var(--head-h) + 34px)}
  .u-mark{height:68px;margin-bottom:34px}
  .statement{padding-top:72px;padding-bottom:72px}
  .pillars{grid-template-columns:1fr;gap:20px}
  .pillar{padding:26px 24px 28px}
  .pillar h3{font-size:19px}
  .pillar p{font-size:16px}
  .caplist{grid-template-columns:1fr}
  .caprow,.caplist li:nth-child(odd) .caprow{border-right:0;padding:24px 0 26px 0}
  .outcomes{grid-template-columns:1fr;gap:14px}
  .outcome{padding:26px 22px 24px}
  .mstrip .row{flex-direction:column;gap:24px}
  .mstrip .line{display:none}
  /* one column at last: the full 692px spine carries the portrait beside the
     text again, with the measure capped so it does not run to 63ch. */
  .quotes{grid-template-columns:1fr;gap:40px}
  /* the unit is capped, not the paragraph inside it, so the text fills its
     own cell exactly and leaves no hole beside itself. */
  blockquote{grid-template-columns:78px 1fr;gap:20px;max-width:580px}
  
  blockquote p{font-size:18px;max-width:none}
  blockquote .qt{padding-top:4px}
  blockquote .qt::before{top:-20px;left:-5px;font-size:54px}
  .cta{padding-top:76px;padding-bottom:76px}
  .cta-rule{margin-bottom:32px}
}
@media (prefers-reduced-motion:reduce){
  .rv{opacity:1;transform:none;transition:none}
  .dw{stroke-dashoffset:0;animation:none !important}
  .nd,.nlab{opacity:1;transform:none;animation:none !important}
  .mstrip .line{background-size:100% 100%!important;animation:none!important}
  .outcome,.outcome::before{opacity:1!important;transform:none!important;transition:none!important}
  .mem{opacity:1;transform:none;animation:none!important}
  .cta-rule{transform:none!important;transition:none!important}
  .btn{transition:none}
}

/* ===== S5 attribution layout — appended to the PAGE SHEET so it wins,
   the manifest's load order being tokens -> base -> components -> page ===== */

/* ---- the portrait joins the ATTRIBUTION rather than leading the quote.
   The quote is what the section is for, so it reads first; the face and the
   credential arrive together as one block, which is what a reader checks after
   deciding the claim is interesting. 96px is nearly a third taller than the
   86px it replaces and now carries the name and title with it, so it reads as
   a credential rather than an avatar.
   The pair is bottom-aligned: the two quotes are different lengths, so without
   this the bylines float at unrelated heights. ---- */
.quotes{align-items:stretch}
blockquote{display:flex;flex-direction:column}
.portrait{margin-bottom:0;flex:0 0 auto}
.byline{display:flex;align-items:center;gap:20px;margin-top:auto;padding-top:32px}
.byline cite{margin-top:0}
blockquote p{margin-bottom:0}

.portrait{width:96px;height:96px}
.byline cite{font-size:10.5px;letter-spacing:.12em;line-height:1.75}
/* The portrait must not shrink below its 96px baseline on the way down —
   that was the original complaint. Between 1000 and 761 the two columns are
   genuinely tight, so it gives up 8px; at one column there is more room than
   at desktop, not less, so it goes back up. */
@media (max-width:1000px){.portrait{width:88px;height:88px}}
@media (max-width:760px){.portrait{width:104px;height:104px}.byline{gap:22px}}

/* ================== MOCKUP STYLE BLOCK 4 ================== */
/* ======================================================================
   S2 + S3 REPLACEMENT — Rick's rework, supplied 2026-10-07.

   WHAT THIS REPLACES. Two sections come out of the page:
     - "Five capabilities. One connected platform." (the five-column ledger)
     - "How it works / An integrated technology platform..." (three pillars)
   and one continuous block goes in: an intro band over the helix photograph
   carrying the three pillars as cards, then three numbered sections — 01 The
   Operating Platform, 02 Consulting & Managed Services, 03 National CGT
   Network — that expand them in order. The band's three cards and the three
   numbered sections are the SAME three things, named the same way, in the same
   order. That is the structure; it is not decoration.

   NO NEW COLOUR. Every value below is an existing tokens.css entry or a
   color-mix of two of them. One role pair is needed and it is the SAME one the
   quote band already needs: --ground-slate / --on-slate.

   TWO THINGS RICK DREW THAT ARE CHANGED, BOTH FOR MEASURED REASONS, BOTH
   FLAGGED IN THE RULING DOC:
     1. The glass cards are more opaque than his comp. At the translucency he
        drew (card interior measures #CACDD1) the accent card titles read
        3.60:1 — below AA. At --paper 92% they read 4.87:1. The alternative,
        if the glass matters more than the colour, is to set the titles in
        --ink, which reads 9.30:1 at his original translucency.
     2. The body copy in 03 is ink, not the blue he drew. Ruled separately.
   ====================================================================== */

/* :root role pair removed — tokens.css owns --ground-slate/--on-slate; see the prelude. */

/* ---------- A. the intro band ---------------------------------------- */

/* The photograph is PRE-TREATED, not scrimmed in CSS. A CSS overlay would
   darken the cards sitting on top of it as well, and the treatment has to be
   measured against the type anyway — doing it in the asset means the number
   that was verified is the number that ships. Treatment: a flat 82% scrim of
   color-mix(in srgb, var(--slate) 80%, var(--ink)), which is the LOWEST alpha
   that clears AA 4.5 at the worst single pixel under the type box. */
.dband{
  background-color:var(--ground-slate);
  background-image:url(../../img/cgt/dband-bg.jpg);
  background-size:cover;background-position:50% 38%;
  color:var(--on-slate);
  padding:104px 34px 112px}
.dband .in{max-width:1180px}

.dband-h2{font-family:var(--serif);font-weight:600;margin:0 auto;
  text-align:center;color:var(--white);
  font-size:clamp(26px,2.9vw,38px);line-height:1.22;letter-spacing:-.012em;
  /* 36ch, MEASURED. Rick's break is "An integrated technology platform and /
     services for cell & gene therapy". It holds from 34ch to 38ch; 36 is the
     middle. At 32ch "and" falls to line two; at 40ch "services" climbs to
     line one. */
  max-width:36ch}
.dband-sub{margin:20px auto 0;text-align:center;max-width:72ch;
  font-size:16px;line-height:1.6;color:var(--white)}

.gcards{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:52px}
/* 92% --paper, not the ~70% Rick drew — see note 1 in the header. backdrop
   blur still reads as glass at this opacity; the helix behind it does not. */
.gcard{border-radius:14px;padding:26px 24px 28px;text-align:center;
  background:color-mix(in srgb, var(--paper) 92%, transparent);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  box-shadow:0 10px 26px -14px color-mix(in srgb, var(--ink) 55%, transparent),
             inset 0 0 0 1px color-mix(in srgb, var(--white) 60%, transparent)}
.gcard svg{display:block;margin:0 auto 14px}
/* RICK'S ICONS, supplied as 512px PNGs with the disc baked in. Measured: the
   band set's disc is #25222B against --plum #292631, and the 01 set's is
   #EEAF37 against --gold #F0B83F — both within noise of the token, and both
   stay raster content rather than becoming surface colour. Stroke contrast on
   their own discs is 15.64:1 (white on plum) and 8.06:1 (ink on gold). */
.gcard .gicon{display:block;width:52px;height:52px;margin:0 auto 14px}
.gcard h3{font-family:var(--serif);font-size:18px;line-height:1.28;
  color:var(--accent);margin:0 0 10px}
.gcard p{margin:0;font-size:14.5px;line-height:1.55;color:var(--on-page-body)}

/* ---------- B. the numbered sections, 01 / 02 / 03 -------------------- */

/* THE EYEBROW IS NOT .kick, AND THAT IS NOW SETTLED RATHER THAN A DEVIATION.
   .kick (mono, uppercase, .26em) stays on the unnumbered sections. The
   numbered sequence gets its own eyebrow, because the number has to carry
   weight against the label and mono small-caps cannot do that. It is used
   three times here, which is what makes it a component rather than a one-off. */
.nsec-eyebrow{font-family:var(--sans);font-size:15px;line-height:1.4;
  letter-spacing:.005em;color:var(--on-page);margin:0 0 30px}
.nsec-eyebrow b{font-weight:700}
.nsec-eyebrow span{font-weight:400}

/* Larger than .band-h2 (32px cap) on purpose: in Rick's rework these three are
   the page's primary sections and the unnumbered ones are supporting. The
   hierarchy change is the point, not a side effect. */
.nsec-h2{font-family:var(--serif);font-weight:600;margin:0 0 26px;
  font-size:clamp(28px,3.35vw,41px);line-height:1.17;letter-spacing:-.012em}
.nsec-h2 .lead{color:var(--accent);display:block}

/* EACH HEADING GETS ITS OWN MEASURE, MEASURED NOT GUESSED. A single shared
   max-width cannot hold three different breaks: at one shared value 02 and 03
   both start a line with a bare ampersand. Each value below is the middle of
   the band of widths that produce the break Rick drew, so a font-metric
   difference between Charter and a fallback cannot tip any of them.
     01  holds from 18ch up (no upper failure: ".lead" is its own line and
         "Every stage of care." cannot share a line with anything)   -> 20ch
     02  "Expert Services / for Every Stage of / Your Cell & Gene /
         Therapy Journey" holds 16-18ch                              -> 17ch
     03  "Expand Your Reach / Through Our National / Cell & Gene Therapy /
         Network" holds 19-22ch                                      -> 21ch
   Verified in Charter (installed) and in Georgia, Palatino and Times. */
.nsec-h2--a{max-width:20ch}
.nsec-h2--b{max-width:17ch}
.nsec-h2--c{max-width:21ch}
.nsec-body{font-size:16.5px;line-height:1.66;color:var(--on-page-body);margin:0}

.nsec-grid{display:grid;gap:5%;align-items:start}
.nsec-grid--text-left {grid-template-columns:52fr 44fr}
.nsec-grid--text-right{grid-template-columns:44fr 52fr}
/* The sides alternate 01 left / 02 right / 03 left. On narrow the copy always
   comes first regardless of which side it sat on, so 02's source order puts
   the cards first and the media query re-orders it — the ONLY place an order
   property is used, and it is used because the desktop zigzag requires it. */
@media (max-width:900px){ .nsec-grid--text-right .nsec-copy{order:-1} }

/* ---------- 01: the three feature rows ------------------------------- */
.featlist{list-style:none;margin:0;padding:0;display:grid;gap:30px}
.featrow{display:grid;grid-template-columns:52px 1fr;gap:18px;align-items:start}
/* the disc is part of the supplied artwork now, so the tile carries no ground */
.featicon{display:block;width:52px;height:52px}
.featrow p{margin:0;font-size:16px;line-height:1.55;color:var(--on-page-body)}
/* ink on gold is 8.22:1 — the label can carry the weight it needs */
.featrow b{color:var(--on-page);font-weight:700}

/* ---------- 02: the two stacked service cards ------------------------ */
.svcstack{display:grid;gap:22px}
.svccard{border-radius:14px;padding:34px 30px 38px;text-align:center;
  min-height:168px;display:grid;align-content:center;justify-items:center;gap:18px}
/* white on accent 5.74:1, white on plum 14.83:1 — both clear AA */
.svccard--a{background:var(--accent);color:var(--white)}
.svccard--b{background:var(--plum); color:var(--white)}
/* THE WHITE DISC STAYS. Rick's art for these two is transparent-cornered line
   work with no disc of its own, and measured on the card grounds it disappears:
   the blue strokes read 1.15:1 on --accent and the ink strokes 1.05:1 on
   --plum. On the white disc they are 6.58:1 and 15.64:1. */
.svcdisc{width:52px;height:52px;border-radius:50%;background:var(--white);
  display:grid;place-items:center}
/* 50 inside 52: the supplied art carries its own generous padding, so sizing it
   to the disc lands the glyph at the same optical size as the 52px icons in 01
   and the band. At 44 it read a size smaller than everything around it. */
.svcicon{display:block;width:50px;height:50px}
/* 34ch, not 26: the two lines Rick drew are set with an explicit <br>, and a
   measure narrower than the longer of them makes the browser add a THIRD break
   inside a line the designer had already broken. Measured: the longer line,
   "Optimize the Performance of Your", needs 32ch at this size. */
.svccard h3{font-family:var(--sans);font-weight:700;font-size:17px;
  line-height:1.45;margin:0;max-width:34ch;color:inherit}

/* ---------- 03: the map plate ---------------------------------------- */
/* Decorative, ruled. aspect-ratio from the file's own 2035x1066 so the plate
   reserves its space before decode and nothing below it shifts. */
.netplate{margin:6px 0 0;position:relative;border-radius:16px;overflow:hidden;
  aspect-ratio:2035/1066;background:var(--ink);
  box-shadow:0 1px 0 color-mix(in srgb, var(--ink) 10%, transparent),
             0 18px 34px -16px color-mix(in srgb, var(--ink) 38%, transparent),
             0 2px 6px color-mix(in srgb, var(--ink) 8%, transparent)}
.netplate img{display:block;width:100%;height:100%;object-fit:cover}
.netplate::after{content:"";position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ink) 22%, transparent)}

/* ---------- responsive ------------------------------------------------ */
@media (max-width:900px){
  .dband{padding:72px 22px 78px;background-position:50% 40%}
  .gcards{grid-template-columns:1fr;gap:16px;margin-top:36px}
  .nsec-grid,.nsec-grid--text-left,.nsec-grid--text-right{
    grid-template-columns:1fr;gap:38px}
  .nsec-h2{max-width:20ch}
  .netplate{margin-top:0}
}

/* ======================================================================
   S4a — NETWORK ADVANTAGE, restyled to Rick's comp (2026-10-07).

   WHAT CHANGED, AND THE EVIDENCE. Rick's comp was sampled rather than
   eyeballed, and every colour in it is already a tokens.css entry:

     band ground   #292730  ->  --plum    #292631   (delta 1)
     headline      #EBB954  ->  --gold    #F0B83F   (nearest by 148)
     card ground   #F5F0E7  ->  --cream   #F6F0E6   (delta 2)
     card title    #3065C3  ->  --accent  #2B61C9   (delta 15)

   So this is a restyle inside the existing palette. No new colour, no new
   token, no ruling needed.

   Four changes:
     1. The "THE NETWORK ADVANTAGE" kicker is gone. Removed from the MARKUP,
        not hidden with display:none — a kicker hidden in CSS is still read
        aloud and still in the document outline.
     2. Headline and lede are centred, and the headline is GOLD.
        gold on plum measures 8.22:1. This is also the one place the standing
        rule allows it: gold sets type on plum and nowhere else.
     3. The cards invert — cream ground, accent sans-bold title, ink body —
        instead of a tinted panel on the dark band.
        accent on cream 5.07:1, --on-page-body on cream 7.56:1.
     4. The gold top rule on each card goes. It was the card's only accent
        when the card was dark; on a cream card it fights the accent title,
        and Rick's comp does not have it.
   ====================================================================== */

.navd .band-h2{text-align:center;color:var(--gold);margin:0 auto;
  /* one line at 1180, which is how Rick drew it */
  max-width:46ch}
.navd .lede{text-align:center;margin:20px auto 0;color:var(--on-dark-body);
  /* 104ch, MEASURED. Rick's lede is three centred lines spanning ~87% of the
     band. Three lines hold from 96ch up to the 1180 container ceiling (~120ch);
     104ch is 1012px, which is that 87% and leaves margin on both sides. At 92ch
     it breaks to four, and at the default .lede measure of 66ch, to five. */
  max-width:104ch}

.navd .outcome{background:var(--ground-alt);color:var(--on-alt);
  border:0;border-radius:14px;padding:26px 22px 28px;text-align:center;
  box-shadow:0 10px 24px -16px color-mix(in srgb, var(--ink) 70%, transparent)}
/* The gold bar was the dark card's only accent. Removed, with its staggered
   reveal — the card reveal itself is kept. */
.navd .outcome::before{content:none}
.navd .outcome h3{font-family:var(--sans);font-weight:700;font-size:17px;
  line-height:1.35;color:var(--accent);margin:0 0 10px}
.navd .outcome p{color:var(--on-page-body);font-size:15px;line-height:1.55;
  max-width:none;margin:0}
/* The inherited hover lightened the card with a cream mix, which on a cream
   card does nothing visible. Lift and shadow instead. */
.navd .oline.is-in .outcome:hover{transform:translateY(-3px);
  background:var(--paper);border-color:transparent;
  box-shadow:0 16px 30px -16px color-mix(in srgb, var(--ink) 80%, transparent)}

@media (max-width:900px){
  .navd .outcomes{grid-template-columns:1fr 1fr;gap:14px}
  .navd .lede{max-width:none}
}
@media (max-width:560px){
  .navd .outcomes{grid-template-columns:1fr}
}


/* ======================================================================
   v5-22 POLISH PASS — three measure fixes, 2026-10-07.
   All three are overrides of rules that live in the base file, kept here so
   v5-21 stays untouched as the fallback. This block is last in <head>, so
   each override wins on source order at equal specificity.
   ====================================================================== */

/* ---- 1. HERO: no dangling conjunction, no widow -----------------------
   The old 16ch set four lines and left "programs." alone on the last:

     16ch   The operating / platform for cell / and gene therapy / programs.
     18ch   The operating / platform for cell and / gene therapy / programs.

   18ch is worse, not better — it ends a line on "and". The break only
   resolves once the measure clears 20ch, where it settles into three even
   lines and stops moving:

     20ch   The operating platform / for cell and gene / therapy programs.
     22ch   same          24ch  same          uncapped  same

   22ch is inside that terminal band with room on both sides. Line lengths
   are 22 / 17 / 17 characters — no widow, no orphaned conjunction, and the
   accent span still breaks after "gene", as it did before. */
.hero h1{max-width:22ch}

/* ---- 2. S2b (02): headline takes the paragraph's measure ---------------
   The headline was capped at 17ch and the paragraph below filled the column,
   so the two stacked blocks had visibly different right edges. Both now run
   to the column, which is the alignment that was asked for.
   CONSEQUENCE HANDLED: at the full measure the natural break stranded "&" at
   the end of line two. "Cell & Gene" is bound with non-breaking spaces in the
   markup so the phrase moves down whole. */
.nsec-h2--b{max-width:none}

/* ---- 3. TESTIMONIAL: the quote fills its column ----------------------
   blockquote p carried max-width:24ch, which rendered 363px inside a 788px
   column — 46% of the space — and pushed the longer quote to eleven lines.
   Uncapped it is five lines across the full 788px. The column is itself
   bounded (the .in wrapper caps at 1180, so the quote column stops growing
   at ~788px however wide the window gets), so no upper measure is needed
   here to stop it running away. */
.qslide blockquote p{max-width:none}

/* ---- 4. TESTIMONIAL: the portrait top-aligns with the quote block -----
   The portrait carried margin-top:68px — the quote mark's own height (52)
   plus its margin (16) — which put the circle's apex level with the first
   line of quote TEXT, one line below the top of the testimonial.

   Two problems with that, both measured:
     a) A circle aligned by its bounding box reads low against a flat line of
        type, because a circle's visual weight sits at its middle and its apex
        is a single point. Even when the apex is on the cap line — it was,
        within 2px at 1440 — the portrait looks like it starts below the quote.
     b) It pushed the portrait block to 388px while the quote text ran 236px
        (short slide) to 316px (long slide), leaving up to 152px of empty band
        under the caption.

   Top-aligning to the testimonial block fixes both. The portrait block becomes
   320px, and because that is still taller than the text on every desktop slide
   the frame stays 320px on ALL of them — so the slide heights remain identical
   and nothing jumps when the quote changes, which is what the original
   top-alignment fix was protecting. Slack drops from 152/72 to 84/4.

   Below 860px the stacked rule already sets this to 0; this is the desktop
   half of the same decision. */
.qport{margin-top:0}


/* ---- 5. nowrap utility, and why it is not &nbsp; ---------------------
   The first attempt bound these phrases with &nbsp;. Charter has no glyph for
   U+00A0, so the browser fell back to a different font for that one character
   and set a visibly WIDER space than the normal one beside it — "and  gene"
   and "therapy  programs." both rendered with a double-width gap. A nowrap
   span binds the phrase using the real space glyph, so the bind is invisible.
   Used on the hero headline and on 02's heading. */
.nb{white-space:nowrap}

/* ---- 6. TESTIMONIAL: headshot centred against the quote ---------------
   Supersedes note 4's top alignment, at the CD's direction.
   The portrait is the taller column on every desktop slide, so the row height
   is a constant 320px and the portrait does not move; what centres is the
   TEXT, within that row.
   THE COST, STATED: the two quotes differ in height, so the quote mark sits at
   a different point on each slide and moves when the slide changes. That is
   the trade the original top-alignment was avoiding — it is smaller now (the
   text blocks differ by ~80px, so the shift is ~40px, against the 78px
   portrait jump the first fix killed) and it moves the lighter object, not the
   heaviest one on the band. Measured below 900px it does not arise: there the
   text is the taller column and the stack is single-file. */
.qslide{align-items:center}


/* ---- 7. HERO, second copy round (2026-10-07) ------------------------
   Rick's new comp returns to the four-line break and puts "programs." on its
   own line deliberately, so R354a's "therapy programs." bind is removed (see
   the splice). 16ch, measured: the break holds from 15ch to 18ch and 16 sits
   in the middle. Outside that band 14ch splits "and gene / therapy" and 20ch
   collapses to three lines. */
.hero h1{max-width:16ch}

/* The lede is two paragraphs now and the column has to carry them. 1.35fr
   leaves the headline column 713px against the 640px its 16ch measure needs,
   so the headline is unaffected and the body gets 528px instead of 474px. */
@media (min-width:1100px){ .hero-top{grid-template-columns:1.35fr 1fr} }
/* 56ch, measured: the first width at which both paragraphs settle at 3 and 4
   lines rather than 4 and 5. It clamps to the column, so it is a ceiling
   rather than a measure. */
.hero-sub{max-width:56ch}
.hero-sub + .hero-sub{margin-top:-8px}
.hero-sub b{color:var(--on-page);font-weight:700}

/* ---- 8. S1b statement band: break at the sentence --------------------
   Uncapped, the band broke mid-sentence —
     "…deliver the therapies. Longitude CGT helps / those programs work…"
   — which puts the full stop in the middle of a line of 45px display type and
   makes the two sentences read as one run-on. 32ch, measured: the sentence
   break holds from 30ch up to the container ceiling, so 32 sits inside it with
   room. text-wrap:balance still evens the two lines of the second sentence. */
.statement-line{max-width:36ch;margin-left:auto;margin-right:auto}  /* v5-24: statement grew 68→104 chars; 34–42ch all hold 3 lines (fonts-ready sweep), 36 gives the fullest last line */

/* ================== MOCKUP STYLE BLOCK 5 ================== */
/* ===== v5-23 copy round ===== */
/* The hero's bold lead-in is gone with its sentence, so the -8px that tucked
   para 2 under it no longer has a lead-in to tuck under.  Two equal-weight
   paragraphs need real separation. */
.hero-sub + .hero-sub{margin-top:0}
/* The CTA headline went from 2 words to 8.  14ch was sized for "Request a
   demo."  Re-measured below. */
.cta-h2{max-width:13ch}

/* ================== MOCKUP STYLE BLOCK 6 ================== */
/* ---------- 03 · the drawn network plate (v5-26) ------------------------
   Light plate on the paper page, like the footprint map's light build: the
   country in hairlines, HQ states a shade deeper, partner pins in accent,
   Longitude's home in ink, routes between them as dashed hairlines that draw
   on reveal. No glow, no gradient, no new colour. */
.netplate--drawn{aspect-ratio:975/610;background:var(--ground-alt)}
.netplate--drawn .netmap{display:block;width:100%;height:100%}
.netmap .st{fill:var(--ground-page);stroke:var(--rule-hair);stroke-width:1;vector-effect:non-scaling-stroke;stroke-linejoin:round}
.netmap .st--hq{fill:color-mix(in srgb, var(--slate) 11%, var(--ground-page))}
.netmap .arc{fill:none;stroke:var(--slate);stroke-width:1.25;vector-effect:non-scaling-stroke;
  stroke-dasharray:.012 .014;stroke-dashoffset:0;opacity:.75}
.netmap .pin-dot{fill:var(--accent);stroke:var(--ground-alt);stroke-width:3;vector-effect:non-scaling-stroke}
.netmap .pin-halo{fill:var(--accent);opacity:.14}
.netmap .home-dot{fill:var(--ink)}
.netmap .home-ring{fill:none;stroke:var(--ink);stroke-width:1.25;vector-effect:non-scaling-stroke;opacity:.6}
.netmap .lab{font-family:var(--mono);font-size:15px;letter-spacing:.14em;fill:var(--on-page-soft);
  paint-order:stroke;stroke:var(--ground-alt);stroke-width:5px;stroke-linejoin:round}
.netmap .lab--home{fill:var(--ink)}
/* reveal: pins land in order, west to east as listed; routes draw once the pins are down */
.netmap .pin{transform-box:fill-box;transform-origin:center;opacity:0;transform:scale(.6);
  transition:opacity .5s ease,transform .6s cubic-bezier(.2,.8,.2,1);transition-delay:calc(.25s + var(--i) * .14s)}
.netmap .arc{stroke-dasharray:1 1;stroke-dashoffset:1;transition:stroke-dashoffset 1.1s cubic-bezier(.4,0,.2,1) 1s}
.rv.is-in .netmap .pin{opacity:1;transform:scale(1)}
.rv.is-in .netmap .arc{stroke-dashoffset:0}
@media (max-width:600px){.netmap .lab{font-size:26px;letter-spacing:.1em}}
@media (prefers-reduced-motion:reduce){
  .netmap .pin{opacity:1;transform:none;transition:none}
  .netmap .arc{stroke-dashoffset:0;transition:none}
}

/* ================== MOCKUP STYLE BLOCK 7 ================== */
/* ---------- 03 · illustrative network plate (v5-27, five nodes from v5-28) -------------------------
   Naomi (R375): "more illustrative, less longitude-leaning … speaks strongly to
   the national network." No state borders, no home node, no spokes to HQ. The
   country is a dot matrix; the four partners are nodes joined to each other;
   each node blooms accent into the dots around it. Nodes land, then the mesh
   draws, then the pulses breathe once. Reduced motion: static. */
.netmap--illus .dot{fill:var(--ink);opacity:.26}
.netmap--illus .dot-on{fill:var(--accent);opacity:.7}
.netmap--illus .edge{fill:none;stroke:var(--accent);stroke-width:1.4;vector-effect:non-scaling-stroke;
  stroke-linecap:round;opacity:.85;stroke-dasharray:1 1;stroke-dashoffset:1;
  transition:stroke-dashoffset 1.2s cubic-bezier(.4,0,.2,1);transition-delay:calc(.95s + var(--i) * .16s)}
.netmap--illus .node-dot{fill:var(--accent)}
.netmap--illus .node-ring{fill:var(--ground-alt);stroke:var(--accent);stroke-width:1.5;vector-effect:non-scaling-stroke}
.netmap--illus .node-pulse{fill:var(--accent);opacity:0;transform-box:fill-box;transform-origin:center}
.netmap--illus .lab{font-family:var(--mono);font-size:15px;letter-spacing:.14em;fill:var(--ink);
  paint-order:stroke;stroke:var(--ground-alt);stroke-width:6px;stroke-linejoin:round}
.netmap--illus .node{transform-box:fill-box;transform-origin:center;opacity:0;transform:scale(.5);
  transition:opacity .45s ease,transform .6s cubic-bezier(.2,.8,.2,1);transition-delay:calc(.2s + var(--i) * .16s)}
.rv.is-in .netmap--illus .node{opacity:1;transform:scale(1)}
.rv.is-in .netmap--illus .edge{stroke-dashoffset:0}
@keyframes nm-pulse{0%{transform:scale(.4);opacity:.35}100%{transform:scale(1.15);opacity:0}}
.rv.is-in .netmap--illus .node-pulse{animation:nm-pulse 1.8s ease-out 2 both;animation-delay:calc(2.2s + var(--i) * .22s)}
.netplate--drawn:has(.netmap--illus){aspect-ratio:1010/610}
@media (max-width:600px){.netmap--illus .lab{font-size:22px;letter-spacing:.06em}}
@media (prefers-reduced-motion:reduce){
  .netmap--illus .node{opacity:1;transform:none;transition:none}
  .netmap--illus .edge{stroke-dashoffset:0;transition:none}
  .netmap--illus .node-pulse{animation:none}
}
