/* ==========================================================================
   MAPS — Maryland Advocates for Peer Support
   Site design system.

   Structure is lifted from the Neuralink reference in
   `Templates & Design.MD Files/DESIGN.md`: full-bleed -> contained ->
   full-bleed rhythm, one thin persistent nav that adapts to the surface
   beneath it, a 1200px content measure, generous section gaps, three
   surface levels alternating to create rhythm without extra colour, and a
   flat no-shadow depth model.

   Identity is entirely MAPS and comes from the pitch deck: the warm paper /
   brick / gold / harbor palette, Bricolage Grotesque 800 uppercase for
   display, Fraunces for prose, and the nautical chart motif (route lines,
   chart-grid fragments, the compass rose).

   Deliberate departures from the reference, because the brief kept the
   deck's look:
     - No monochrome and no synapse gradient. The palette is chromatic.
     - No 80px pill geometry. The deck is hard-edged, so controls are square
       with hairline rules. Pills would read as a different brand.
     - No weight-300 display. Bricolage 800 uppercase is the MAPS voice.
     - Tracking follows the deck (-0.012em), not the reference's -7.92px,
       which is calibrated for a different typeface entirely.
   ========================================================================== */

:root{
  /* ---- Palette (from the deck, unchanged) ---- */
  --ink-950:#151A1D; --ink-900:#1F2528; --ink-800:#30383C; --ink-700:#485156; --ink-600:#626B6F;
  --paper-050:#F5F1E8; --paper-100:#EEE8DE; --paper-200:#E3DBCE;
  --white:#FFFFFF;
  --brick-050:#F8ECEA; --brick-100:#F0D8D5; --brick-300:#D99A94; --brick-500:#B85C58;
  --brick-700:#9E2A2B; --brick-800:#7C2022; --brick-900:#5C1719;
  --gold-050:#FCF6E8; --gold-100:#F7EAC5; --gold-300:#E8C879; --gold-500:#D6A33A;
  --gold-700:#936B16; --gold-800:#6D4E10;
  --harbor-050:#EAF2F3; --harbor-100:#D6E6E9; --harbor-300:#91BBC4; --harbor-500:#568A97;
  --harbor-700:#2F6575; --harbor-800:#244F5C; --harbor-900:#193A44;
  --sage-050:#F0F4EF; --sage-100:#DEE7DB; --sage-500:#7D9277; --sage-700:#53644F;
  --stone-050:#F7F5F2; --stone-100:#ECE8E1; --stone-200:#DED8CD; --stone-300:#C8C1B7;
  --stone-500:#8A8984; --stone-700:#5D6061;
  /* NOTE: --stone-500 fails WCAG AA as a text colour on the paper and white
     surfaces (3.5:1 at small sizes). It is a rule/hairline colour only;
     small text uses --stone-700. Verified by qa/layout-audit contrast pass. */

  /* ---- Surfaces (the reference's 3-level model, mapped onto MAPS) ----
     Obsidian -> harbor-900, Paper -> white, Ash -> paper-050. */
  --surface-deep: var(--harbor-900);
  --surface-white: var(--white);
  --surface-paper: var(--paper-050);
  --surface-ink: var(--ink-950);

  /* ---- Type ---- */
  --font-display:'Bricolage Grotesque', system-ui, sans-serif;
  --font-serif:'Fraunces', Georgia, serif;

  --fs-display: clamp(42px, 7.1vw, 94px);
  --fs-h1:      clamp(34px, 5.2vw, 66px);
  --fs-h2:      clamp(27px, 3.5vw, 44px);
  --fs-h3:      clamp(19px, 1.9vw, 25px);
  --fs-lead:    clamp(19px, 2.05vw, 26px);
  --fs-body:    17.5px;
  --fs-small:   15px;
  --fs-meta:    12.5px;
  --fs-numeral: clamp(52px, 7vw, 92px);

  /* ---- Layout (reference: 1200px measure, 80px section gap) ---- */
  --wrap: 1200px;
  --wrap-narrow: 760px;
  --pad-x: clamp(20px, 5vw, 56px);
  --section-pad: clamp(60px, 8.5vw, 108px);
  --gap: clamp(20px, 2.6vw, 32px);
  --card-pad: clamp(24px, 2.6vw, 34px);

  /* ---- Per-section colour ----------------------------------------------
     Each page's header block takes one colour from the brand palette — the
     four hues of the compass mark (red, teal, green, gold) plus neutrals.
     `--sec` drives the page header and, on mobile, the contents panel.
     The fixed nav bar deliberately does NOT use it: it keeps its own
     light/dark adaptation so the bar reads as constant site chrome.

     `--sec-accent` is gold-100, not the gold-300 used elsewhere on dark.
     gold-300 drops to 3.93:1 on sage-700 and 4.00:1 on harbor-700, which
     fails at the 12.5px eyebrow size. gold-100 clears 4.5:1 on every
     section colour, with 5.31 as the worst case.
     Verified: min contrast across all eight sections is 4.95:1. */
  --sec: var(--harbor-900);
  --sec-accent: var(--gold-100);

  /* ---- Shape: hard-edged, per the deck ---- */
  --radius: 2px;
  --rule: 1px solid var(--stone-200);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --nav-h: 68px;
}

/* ---- Laptop: use the width that is there --------------------------------
   At 1200px the body measure left 120px of dead margin at 1440 and 250px at
   1700, with content stuck at 1088px however wide the screen got. In the
   laptop range the measure now scales with the viewport instead.

   The cap is a plain 1520px, NOT `min(1520px, 94vw)`: `.wrap` is already
   `width:100%` with `max-width:var(--wrap)`, so a vw-based cap shrinks the
   wrap AND then the padding eats more on top — at 1024 that made the content
   narrower than before (897px against 921px). The gutter is `--pad-x`'s job.

   Above 1700px the original 1200px measure returns deliberately — a desktop
   monitor does not want 1500px of text across. */
@media (min-width: 1024px) and (max-width: 1700px){
  :root{
    /* Margin raised by half, 25 Aug 2026 — 1520px read too wide. BOTH values
       have to move together: --pad-x alone stops mattering above ~1624px,
       where the --wrap cap takes over and swallows the change. 1430px is the
       width that yields 1.5x the old gutter at the top of the band (90 -> 135
       at 1700), and the clamp is the old one scaled by 1.5. */
    --wrap: 1430px;
    --pad-x: clamp(42px, 5.1vw, 78px);
  }
}

/* Fidelity guard: widening the page must not turn body copy into 100-character
   lines. Grids, cards and step lists take the extra width; running prose is
   held to a readable measure. */
.col-body .t-body, .boundary p, .step-body p{ max-width: 68ch; }


/* Section colours. Each is a deck palette token; the four chromatic ones
   are the compass mark's own quadrant hues. */
body[data-section="home"]       { --sec: var(--harbor-900); }  /* deep teal   */
body[data-section="the-case"]   { --sec: var(--brick-800);  }  /* deep red    */
body[data-section="the-model"]  { --sec: var(--harbor-800); }  /* teal        */
body[data-section="governance"] { --sec: var(--sage-700);   }  /* green       */
body[data-section="partner"]    { --sec: var(--gold-800);   }  /* gold        */
body[data-section="faq"]        { --sec: var(--ink-900);    }  /* near-black  */
body[data-section="survey"]     { --sec: var(--brick-700);  }  /* red         */
body[data-section="contact"]    { --sec: var(--harbor-700); }  /* mid teal    */
body[data-section="privacy"]    { --sec: var(--ink-900);    }  /* near-black  */
body[data-section="for-peers"]  { --sec: var(--brick-900);  }  /* deep red    */

*,*::before,*::after{ box-sizing:border-box; }

html{ scroll-behavior:smooth; -webkit-text-size-adjust:100%; scroll-padding-top: calc(var(--nav-h) + 16px); }
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

body{
  margin:0;
  background: var(--surface-paper);
  color: var(--ink-900);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}

img{ max-width:100%; height:auto; display:block; }

::selection{ background: var(--gold-100); color: var(--ink-950); }

/* Visible focus everywhere — the deck had none, which is a real a11y gap
   on a site you can tab through. */
:focus-visible{
  outline:2px solid var(--brick-700);
  outline-offset:3px;
}
.on-deep :focus-visible, .band--deep :focus-visible, .sitefoot :focus-visible,
.navpanel :focus-visible, .pagehero :focus-visible{
  outline-color: var(--gold-300);
}

.skip{
  position:absolute; left:-9999px; top:0; z-index:2000;
  background: var(--brick-700); color: var(--white);
  padding:12px 20px; font-family:var(--font-display); font-weight:700;
  text-transform:uppercase; letter-spacing:.06em; font-size:14px; text-decoration:none;
}
.skip:focus{ left:0; }

/* ==========================================================================
   TYPE PRIMITIVES
   ========================================================================== */

.t-display,.t-h1,.t-h2,.t-h3{
  font-family: var(--font-display);
  font-weight:800;
  text-transform:uppercase;
  letter-spacing:-.012em;
  margin:0;
  text-wrap:balance;
}
.t-display{ font-size: var(--fs-display); line-height:.94; }
.t-h1{ font-size: var(--fs-h1); line-height:.98; }
.t-h2{ font-size: var(--fs-h2); line-height:1.04; }
.t-h3{ font-size: var(--fs-h3); line-height:1.15; letter-spacing:-.008em; }

/* Fraunces italic is the deck's body voice. It carries beautifully at
   display and lead sizes, but italic across long web paragraphs is tiring,
   so prose runs roman and italic is reserved for leads and pull quotes. */
.t-lead{
  font-family: var(--font-serif); font-style:italic; font-weight:400;
  font-size: var(--fs-lead); line-height:1.42; color: var(--ink-800);
  margin:0; text-wrap:pretty;
}
.t-body{ margin:0 0 1.1em; text-wrap:pretty; }
.t-body:last-child{ margin-bottom:0; }
.t-body a{ color: var(--brick-700); text-underline-offset:3px; text-decoration-thickness:1px; }
.t-body a:hover{ color: var(--brick-900); }

.eyebrow{
  display:inline-block;
  font-family: var(--font-serif); font-style:italic; font-weight:400;
  font-size: var(--fs-meta); letter-spacing:.17em; text-transform:uppercase;
  color: var(--stone-700); margin:0 0 14px;
}
.eyebrow--accent{ color: var(--brick-700); }

.rule-mark{
  width:64px; height:3px; background: var(--brick-700);
  margin:20px 0 26px; border:0;
}
.rule-mark--gold{ background: var(--gold-500); }
.rule-mark--harbor{ background: var(--harbor-500); }

/* Source lines and legal hedges. These carry the deck's careful qualifying
   language and must stay legible — never drop them below 13px. */
.note{
  font-family: var(--font-serif); font-style:italic;
  font-size:13.5px; line-height:1.5; color: var(--stone-700);
  border-top:1px dashed var(--stone-300);
  padding-top:14px; margin:30px 0 0;
}
/* SOURCE LINKS ONLY. This rule was added 25 Aug 2026 because `.note a` was
   unstyled and rendering in browser-default blue once citations were linked.
   `.t-body a` was already brick-700 and was NOT changed — this matches it, so
   citations look like every other body link.

   The underline is NOT decoration and must stay. Against the note's own
   stone-700 text brick-700 is only 1.17:1 — near-identical in luminance — so
   colour alone cannot mark these as links (WCAG 1.4.1). The underline is what
   distinguishes them; the colour is what makes them feel like the site. */
.note a{
  color: var(--brick-700);              /* 6.61:1 on paper, 7.45:1 on white */
  text-underline-offset:3px; text-decoration-thickness:1px;
}
.note a:hover{ color: var(--brick-900); }

/* Links inside cards. Same reason `.note a` exists: a link whose ancestor has
   no colour rule falls back to browser-default blue, which is off-brand and
   easy to ship without noticing — it has happened three times now, which is
   why qa/audit.py checks for it. Cards sit on light bands, so they take the
   body link colour. */
.card a{
  color: var(--brick-700); text-underline-offset:3px; text-decoration-thickness:1px;
}
.card a:hover{ color: var(--brick-900); }
.band--deep .note, .band--ink .note, .on-deep .note{
  color: var(--harbor-300); border-top-color: rgba(145,187,196,.35);
}

/* ==========================================================================
   SURFACES + BANDS  (reference: full-bleed -> contained -> full-bleed)
   ========================================================================== */

.wrap{ width:100%; max-width: var(--wrap); margin-inline:auto; padding-inline: var(--pad-x); }
.wrap--narrow{ max-width: calc(var(--wrap-narrow) + var(--pad-x) * 2); }

.band{
  position:relative;
  padding-block: var(--section-pad);
  overflow:hidden; /* keeps the chart motifs from creating a scrollbar */
}
/* Short sections do not need a full section's worth of air above and below.
   Used where the copy is a couple of paragraphs and the default padding leaves
   the band looking mostly empty.

   Padding alone is not enough. The left-column route motif is ~200px tall, so
   on a short section IT sets the height, not the copy beside it — trimming the
   padding under a motif taller than the text gains almost nothing. So a tight
   band scales the motif down rather than dropping it: the mark stays, at a
   size proportionate to the section it decorates. */
.band--tight{ padding-block: clamp(38px, 5vw, 66px); }
.band--tight .twocol > div:first-child::after{
  width:min(150px, 62%);
  margin-top:clamp(18px, 2.2vw, 26px);
  opacity:.45;
}
.band--paper{ background: var(--surface-paper); }
.band--white{ background: var(--surface-white); }
.band--deep { background: var(--surface-deep); }
.band--ink  { background: var(--surface-ink); }

.band--deep, .band--ink, .on-deep{ color: var(--paper-050); }
.band--deep .t-lead, .band--ink .t-lead, .on-deep .t-lead{ color: var(--harbor-100); }
.band--deep .eyebrow, .band--ink .eyebrow, .on-deep .eyebrow{ color: var(--gold-300); }

.band-head{ max-width: 900px; margin-bottom: clamp(34px, 4.5vw, 56px); }
.band-head .t-lead{ margin-top:18px; }

/* ==========================================================================
   NAUTICAL CHART MOTIF
   Ported from the deck's .route-svg / .grid-fragment. Purely decorative and
   always aria-hidden. Kept low-contrast so it never competes with text —
   the deck shipped a defect where hand-placed motifs collided with
   variable-height headlines, so these are anchored to band corners rather
   than guessed coordinates.
   ========================================================================== */

.motif{
  position:absolute; inset:0; pointer-events:none; z-index:0;
  opacity:.5;
}
.band > .wrap{ position:relative; z-index:1; }

.motif svg{ position:absolute; overflow:visible; }
.motif .route{ fill:none; stroke: var(--stone-300); stroke-width:1.25; }
.motif .route--dash{ stroke-dasharray:7 9; }
.band--deep .motif .route, .band--ink .motif .route{ stroke: rgba(145,187,196,.34); }
.band--white .motif .route{ stroke: var(--stone-200); }

.motif--tr svg{ top:-70px; right:-90px; width:min(560px,52vw); height:auto; }
.motif--bl svg{ bottom:-80px; left:-100px; width:min(520px,48vw); height:auto; }

/* Chart-grid fragment, masked to a soft ellipse exactly as the deck did. */
.gridfrag{
  position:absolute; width:min(620px,55vw); aspect-ratio:6/5;
  background-image:
    linear-gradient(to right, var(--stone-300) 1px, transparent 1px),
    linear-gradient(to bottom, var(--stone-300) 1px, transparent 1px);
  background-size:54px 54px;
  -webkit-mask-image: radial-gradient(ellipse at 60% 50%, #000 0%, transparent 70%);
          mask-image: radial-gradient(ellipse at 60% 50%, #000 0%, transparent 70%);
  opacity:.55;
}
.band--deep .gridfrag, .band--ink .gridfrag{
  background-image:
    linear-gradient(to right, rgba(145,187,196,.4) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(145,187,196,.4) 1px, transparent 1px);
}
.gridfrag--tr{ top:-60px; right:-120px; }
.gridfrag--br{ bottom:-90px; right:-110px; }

/* ==========================================================================
   NAVIGATION
   One thin persistent bar (the reference's only sticky element). It flips
   between light and dark text depending on the surface scrolled under it —
   set by site.js via [data-surface].
   ========================================================================== */

.sitenav{
  position:fixed; inset:0 0 auto 0; z-index:900;
  height: var(--nav-h);
  display:flex; align-items:center;
  border-bottom:1px solid transparent;
  transition: background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
.sitenav[data-surface="light"]{
  background: rgba(245,241,232,.92);
  -webkit-backdrop-filter:saturate(140%) blur(10px); backdrop-filter:saturate(140%) blur(10px);
  border-bottom-color: var(--stone-200);
  color: var(--ink-900);
}
.sitenav[data-surface="dark"]{
  background: rgba(25,58,68,.82);
  -webkit-backdrop-filter:saturate(140%) blur(10px); backdrop-filter:saturate(140%) blur(10px);
  border-bottom-color: rgba(145,187,196,.28);
  color: var(--paper-050);
}
.sitenav .wrap{ display:flex; align-items:center; gap:24px; width:100%; }

/* The brand lockup is the compass emblem plus CSS-set type rather than the
   full logo image. The logo's own wordmark is dark maroon, which drops below
   contrast on the deep harbor surface; setting the words in CSS lets them
   flip with the surface while the compass — which is gold/coral/blue and
   reads on either — stays as artwork. */
.nav-brand{ display:flex; align-items:center; gap:10px; text-decoration:none; color:inherit; margin-right:auto; }
.nav-brand-emblem{
  height:34px; width:34px; flex-shrink:0;
  transition: transform .65s var(--ease);   /* same spin as the deck's compass */
}
@media (hover: hover) and (pointer: fine){
  .nav-brand:hover .nav-brand-emblem{ transform: rotate(360deg); }
}

.nav-brand-mobile{ display:none; }
.nav-brand-txt{ display:flex; flex-direction:column; gap:1px; }
.nav-brand-mark{
  font-family:var(--font-display); font-weight:800; text-transform:uppercase;
  font-size:19px; letter-spacing:-.01em; line-height:1;
}
.nav-brand-sub{
  font-family:var(--font-serif); font-style:italic; font-size:10.5px;
  letter-spacing:.07em; text-transform:uppercase; line-height:1;
  color: var(--stone-700); white-space:nowrap;
}
.sitenav[data-surface="dark"] .nav-brand-sub{ color: var(--harbor-300); }

/* The brand subline is `nowrap` and costs ~180px of bar width. Just above
   the 900px mobile breakpoint the desktop links and the CTA come back but
   there is not yet room for all three, and the CTA overflowed the bar
   between 901px and ~950px. Dropping the subline through that band frees
   enough room for the full nav; the compass and "MAPS" still identify it,
   and the full name is in the footer lockup on every page.
   Below 900px the links are hidden anyway, so the subline fits again —
   except on the narrowest phones, hence the second rule. */
@media (max-width: 420px){ .nav-brand-sub{ display:none; } }

/* ---- Mobile brand lockup -------------------------------------------------
   Below 901px the bar carries the stacked lockup instead of the emblem plus
   CSS-set type.

   This block MUST come after the base `.nav-brand-txt` / `.nav-brand-emblem`
   rules. Both are single class selectors (0,1,0), so an earlier media query
   loses to a later plain rule and the old wordmark reappears beside the new
   lockup — which is exactly what happened.

   The source artwork carries a tagline set in WHITE; it is CROPPED OFF in
   `maps-logo-mobile.png`, because at the height a nav bar allows it rendered
   4px tall — a smudge rather than text. The remaining mark is still drawn
   for a dark ground, which is why the mobile home bar is forced dark. */
@media (max-width: 900px){
  :root{ --nav-h: 96px; }
  .nav-brand-emblem, .nav-brand-txt{ display:none; }
  .nav-brand-mobile{
    display:flex; flex-direction:column; align-items:flex-start; gap:5px;
    min-width:0;
  }
  .nav-brand-mobile img{ width:auto; height:52px; display:block; }
  /* The org name is LIVE TEXT, not the artwork's own tagline. That tagline is
     cropped out of maps-logo-mobile.png because at this size it rendered 4px
     tall. Set in real type it is 12px at 10.77:1 on the dark bar, so it is
     both legible and available to a screen reader. */
  .nav-brand-orgname{
    display:block;
    font-family: var(--font-serif); font-style:italic;
    line-height:1.15; letter-spacing:.04em;
    text-transform:uppercase; color: var(--paper-050);
    white-space:nowrap;
    /* Sized proportionally, because the space it has scales with the
       viewport while a fixed size does not. Measured largest size that fits
       on ONE line beside the 46px toggle: 9.7px at 320, 11.6px at 375,
       12.2px at 390, 13.8px at 430. 2.95vw sits just under that curve at
       every step, and the 13px cap stops it growing on tablets. */
    font-size: clamp(9px, 2.95vw, 13px);
  }
}

.nav-links{ display:flex; align-items:center; gap:clamp(14px,1.9vw,28px); }
.nav-links a{
  color:inherit; text-decoration:none;
  font-family:var(--font-serif); font-size:15px; line-height:1;
  padding:6px 0; position:relative; white-space:nowrap;
}
.nav-links a::after{
  content:''; position:absolute; left:0; right:0; bottom:0; height:1.5px;
  background: var(--brick-700); transform:scaleX(0); transform-origin:left;
  transition:transform .25s var(--ease);
}
.sitenav[data-surface="dark"] .nav-links a::after{ background: var(--gold-300); }
.nav-links a:hover::after,
.nav-links a[aria-current="page"]::after{ transform:scaleX(1); }
.nav-links a[aria-current="page"]{ font-style:italic; }

/* Square, hairline-bordered action — the deck's geometry, not the
   reference's 80px pill. */
.btn{
  -webkit-tap-highlight-color: transparent;
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--font-display); font-weight:700; text-transform:uppercase;
  letter-spacing:.03em; font-size:13.5px; line-height:1;
  padding:13px 20px; border-radius:var(--radius);
  text-decoration:none; cursor:pointer;
  border:1.5px solid currentColor; background:transparent; color:inherit;
  transition: background .22s var(--ease), color .22s var(--ease), border-color .22s var(--ease);
}
.btn .arw{ transition:transform .22s var(--ease); }
.btn:hover .arw{ transform:translateX(4px); }

.btn--solid{ background: var(--brick-700); border-color: var(--brick-700); color: var(--white); }
.btn--solid:hover{ background: var(--brick-900); border-color: var(--brick-900); }

/* Harbor-900 — the same dark blue as the nav bar's dark state, the deck's
   dark slides and the default section colour. */
.btn--harbor{ background: var(--harbor-900); border-color: var(--harbor-900); color: var(--paper-050); }
.btn--harbor:hover{ background: var(--harbor-800); border-color: var(--harbor-800); }

/* Brand gold. Carries DARK type, not white: paper on gold-500 measures
   2.29:1, ink-950 on gold-500 is 7.65:1. The hover darkens to gold-700 and
   flips to light type, which holds 4.72:1. */
.btn--gold{ background: var(--gold-500); border-color: var(--gold-500); color: var(--ink-950); }
.btn--gold:hover{ background: var(--gold-700); border-color: var(--gold-700); color: var(--paper-050); }
.btn--ghost:hover{ background: var(--ink-900); border-color: var(--ink-900); color: var(--paper-050); }
.on-deep .btn--ghost:hover, .band--deep .btn--ghost:hover, .band--ink .btn--ghost:hover{
  background: var(--paper-050); border-color: var(--paper-050); color: var(--ink-950);
}
.btn--lg{ font-size:15px; padding:16px 26px; }

/* nowrap: without it both CTAs broke onto two lines in the bar, which reads
   as a layout accident. Widening them tightens the 901-1120px band, which is
   why the brand subline is hidden through that range. */
.nav-cta{ font-size:12.5px; padding:10px 15px; white-space:nowrap; }

/* The narrow-desktop band. Between 901px and ~1079px the bar carries the
   brand, six links and one CTA, and does not fit at full size. Two things
   give way, cheapest first: the brand subline, then the link gap and CTA
   padding.

   This bound tracks the bar's contents and has moved four times:
     1000 -> 1120  Resource Hub button added
     1120 -> 1160  CTAs set to `nowrap`
     1160 -> 1280  "For Peers" added as a sixth link (26 Aug 2026)
     1280 -> 1079  Resource Hub button moved to /for-peers (26 Aug 2026)

   The last move also removed a second, tighter 901-1010 tier that the two-CTA
   bar had needed; with one CTA the main band alone leaves 45px clear at 901,
   so the extra squeeze was deleted rather than left in place making the bar
   needlessly cramped.

   Re-run the 880-1600 sweep after touching ANYTHING in the bar — measured
   fit, not estimated: at full size six links plus one CTA need 1080px. */
@media (min-width: 901px) and (max-width: 1079px){
  .nav-brand-sub{ display:none; }
  .nav-links{ gap:14px; }
  .nav-cta{ font-size:11.5px; padding:11px 10px; }   /* height, not width */
}

/* Mobile menu trigger — the deck's .contents-toggle, brought over almost
   verbatim: a circular paper disc carrying the real MAPS emblem, not a
   hand-drawn glyph. This is the only mark on screen at rest on a phone, so
   it should be the logo.

   The paper disc is what lets one button sit on both nav surfaces: on the
   light bar it is defined by its stone hairline, on the dark bar by the
   contrast of paper against harbor-900. */
.nav-toggle{
  display:none; align-items:center; justify-content:center;
  width:46px; height:46px; padding:0;
  background: var(--paper-050);
  border:0;
  border-radius:50%;
  cursor:pointer;
  /* Mobile browsers paint a RECTANGULAR tap highlight over a button on
     touch, which on a round control reads as a square box appearing around
     it. Suppressing it is what removes that; the disc itself was already
     `border-radius:50%`. Focus styling is unaffected — :focus-visible still
     draws the keyboard ring. */
  -webkit-tap-highlight-color: transparent;
  /* No border, so the disc is defined by a soft shadow instead. On the dark
     bar it is defined by its own 10.77:1 contrast against harbor-900. */
  box-shadow: 0 1px 4px rgba(31,37,40,.20), 0 0 0 1px rgba(31,37,40,.10);
  transition: box-shadow .25s ease;
}
.sitenav[data-surface="dark"] .nav-toggle{
  box-shadow: 0 1px 6px rgba(0,0,0,.28);
}
.nav-toggle:hover{ box-shadow: 0 2px 10px rgba(31,37,40,.26); }

.nav-toggle-mark{
  width:34px; height:34px; display:block; pointer-events:none;
  transition: transform .3s var(--ease);
}

/* The spin is driven by OPENING the panel, not by hover.

   A hover-driven 360deg transition was the cause of the mark twisting on
   page load and on scroll: `:hover` latches on touch browsers and persists
   after a tap, and losing it later transitions the mark *backwards* from
   360deg to 0 — a reverse spin at an arbitrary moment. On a narrow desktop
   window it also fires on load if the pointer happens to rest where the
   button appears. `(hover: hover)` does not prevent this; plenty of touch
   browsers report it (this harness reports hover:hover AND pointer:fine).

   Tying it to `aria-expanded` makes it deterministic — it can only run when
   someone actually opens the menu. The keyframe ends at 405deg, which is a
   full turn plus the 45deg resting tilt, so there is no snap when the
   animation hands back to the static rule. */
@keyframes nav-toggle-open{
  from{ transform: rotate(0deg); }
  to  { transform: rotate(405deg); }
}
.nav-toggle[aria-expanded="true"] .nav-toggle-mark{
  transform: rotate(45deg);
  animation: nav-toggle-open .65s var(--ease) 1;
}

/* ---- Slide-in contents panel (the deck's ContentsNav, kept) ---- */
.navpanel{
  position:fixed; top:0; right:0; bottom:0; z-index:960;
  width:min(400px, 88vw);
  /* Carries the page's section colour. The panel is inherently mobile —
     the toggle that opens it is hidden above 900px — so this is the
     small-screen counterpart to the coloured page header. */
  background: var(--sec);
  color: var(--paper-050);
  border-left:3px solid var(--sec-accent);
  transform:translateX(101%);
  transition:transform .38s var(--ease);
  padding:26px var(--pad-x) 40px;
  overflow-y:auto;
  display:flex; flex-direction:column;
}
.navpanel.open{ transform:translateX(0); }
.navpanel-head{ display:flex; align-items:center; gap:11px; margin-bottom:26px; }
.navpanel-head .toc-label{
  margin-right:auto;
  font-family:var(--font-serif); font-style:italic; font-size:14px;
  letter-spacing:.13em; text-transform:uppercase; color: var(--sec-accent);
}
.navpanel-close{
  -webkit-tap-highlight-color: transparent;
  width:44px; height:44px; border:1.5px solid rgba(245,241,232,.45); background:transparent;
  color: var(--paper-050); font-size:22px; line-height:1; cursor:pointer; border-radius:var(--radius);
}
.navpanel-close:hover{ background: var(--paper-050); border-color: var(--paper-050); color: var(--ink-950); }

.navpanel a.toc-item{
  display:flex; align-items:baseline; gap:14px;
  padding:15px 0; border-bottom:1px solid rgba(245,241,232,.20);
  text-decoration:none; color: var(--paper-050);
  transition:padding-left .2s var(--ease), color .2s var(--ease);
}
.navpanel a.toc-item:hover{ padding-left:9px; color: var(--sec-accent); }
.navpanel a.toc-item[aria-current="page"]{ color: var(--sec-accent); font-style:italic; }
.navpanel .toc-num{
  font-family:var(--font-serif); font-style:italic; color: var(--sec-accent);
  font-size:15px; flex-shrink:0;
}
.navpanel .toc-txt{
  font-family:var(--font-display); font-weight:800; text-transform:uppercase;
  letter-spacing:-.008em; font-size:19px; line-height:1.1;
}
.navpanel-foot{ margin-top:auto; padding-top:28px; }
.navpanel-foot .btn{ width:100%; justify-content:center; }

/* The compass mark in the contents panel.

   It sits on a paper disc, exactly as the deck's .contents-toggle does — and
   that is not decoration, it is what makes it legible. The panel background
   is the section colour (dark) and the emblem was drawn for a light ground:
   measured directly on the section colours, 48-57% of the mark fell under
   3:1, with a median as low as 1.58:1 on sage-700.

   Sizing matters here. `box-sizing:border-box` means padding and border eat
   into the declared width: at 44px with 5px padding the compass itself was
   only 31px and read as an empty disc rather than a logo. The disc is now
   56px so the mark inside it is ~44px.

   The spin is the deck's contents-toggle gesture — 360deg over .65s on
   var(--ease). On a phone there is no hover, so it runs once as the panel
   opens; pointer devices also get it on hover. The global reduced-motion
   block collapses both. */
.toc-compass{
  width:56px; height:56px; flex-shrink:0;
  padding:4px; border-radius:50%;
  background: var(--paper-050);
  border:1.5px solid rgba(245,241,232,.6);
  box-sizing:border-box;
  transition: transform .65s var(--ease);
}
@keyframes toc-compass-spin{ from{ transform: rotate(0deg); } to{ transform: rotate(360deg); } }
.navpanel.open .toc-compass{ animation: toc-compass-spin .65s var(--ease) 1; }
/* Same reasoning as the toggle: hover-driven spins latch on touch and
   unwind at random. `pointer: fine` restricts this to real mice. */
@media (hover: hover) and (pointer: fine){
  .toc-compass:hover{ transform: rotate(360deg); }
}

.navscrim{
  position:fixed; inset:0; z-index:950; background:rgba(21,26,29,.55);
  opacity:0; pointer-events:none; transition:opacity .3s ease;
}
.navscrim.open{ opacity:1; pointer-events:auto; }

@media (max-width: 900px){
  .nav-links, .nav-cta{ display:none; }
  .nav-toggle{ display:inline-flex; }
}
/* Last-resort guard: above the mobile breakpoint the contents panel must not
   be on screen even if JS missed the breakpoint crossing. This cannot undo a
   stranded body{overflow:hidden} — site.js handles that from three separate
   events — but it stops an orphaned panel covering a desktop layout. */
@media (min-width: 901px){
  /* `.navpanel.open` is (0,2,0) and would outrank a bare `.navpanel` here,
     so the guard has to match the open state explicitly or it does nothing. */
  .navpanel, .navpanel.open{ transform: translateX(101%); }
  .navscrim, .navscrim.open{ opacity:0; pointer-events:none; }
}

/* ==========================================================================
   HERO  (reference: full-bleed, no max-width, type anchored lower-left,
   one action beneath. The reference is deliberately imageless, which suits
   MAPS — the chart motif carries the visual weight instead of a photo.)
   ========================================================================== */

.hero{
  /* Fills the viewport exactly: photo stage on top, a solid band beneath it
     carrying the meta line. Splitting it this way is what makes the cover
     sit in one screen "neatly" — previously the hero stopped at 860px and
     left a gap below it on tall displays. */
  position:relative;
  display:flex; flex-direction:column;
  background: var(--paper-050);
}
@media (min-width: 901px){
  .hero{ height: 100svh; }
}
@media (max-width: 900px){
  .hero{ min-height: 88svh; }
}

.hero-stage{
  position:relative;
  flex:1 1 auto; min-height:0;
  display:flex; align-items:stretch;
  padding-top: calc(var(--nav-h) + clamp(20px, 3.2vh, 44px));
  padding-bottom: clamp(20px, 2.6vh, 38px);
  overflow:hidden;
  background-color: var(--paper-050);
  background-image: url('/assets/hero-cover.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
@media (min-width: 1600px){ .hero-stage{ background-image: url('/assets/hero-cover-2560.webp'); } }
@media (max-width: 900px) and (max-resolution: 1.5dppx){
  .hero-stage{ background-image: url('/assets/hero-cover-1280.webp'); }
}

/* ------------------------------------------------------------------
   Mobile hero parallax — iOS-style depth behind the glass card.

   Built on CSS scroll-driven animations, so the photo layer is driven by the
   scroller off the main thread. No JS, no scroll listener, nothing to throttle.
   Three guards, all deliberate:

     @supports (animation-timeline: scroll())
         browsers without it keep the plain background-image on .hero-stage and
         simply get no parallax. Nothing breaks, nothing to fall back to.

     @media (prefers-reduced-motion: no-preference)
         parallax is a vestibular trigger. This site's audience includes people
         managing health conditions, and a moving background is one of the
         clearest things to withhold from someone who asked for less motion.
         There is NO reduced version — it is off, not gentler.

     @media (max-width: 900px)
         mobile only. Desktop keeps the static cover.

   `background-image: none` on the stage happens ONLY inside the supports
   block, so the photo can never go missing on a browser that cannot animate
   it. The layer is inset -9% top and bottom, giving 18% of headroom to travel
   without exposing an edge — which is why it needs no compensating scale and
   stays as sharp as the static version.
   ------------------------------------------------------------------ */
@supports (animation-timeline: scroll()){
  @media (max-width: 900px) and (prefers-reduced-motion: no-preference){
    .hero-stage{ background-image: none; }
    .hero-stage::before{
      content:""; position:absolute; z-index:0; pointer-events:none;
      left:0; right:0; top:-9%; bottom:-9%;
      background-image: url('/assets/hero-cover.webp');
      background-size: cover; background-position: center;
      background-repeat: no-repeat;
      will-change: transform;
      animation: hero-parallax linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100svh;
    }
    @media (max-resolution: 1.5dppx){
      .hero-stage::before{ background-image: url('/assets/hero-cover-1280.webp'); }
    }
    /* The card drifts up slightly against the photo's downward lag. Two layers
       moving at different rates is what makes depth; one moving layer just
       looks like a slow background. */
    .hero .t-lead{
      animation: hero-card-lift linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100svh;
    }
  }
}
@keyframes hero-parallax{
  from{ transform: translate3d(0, 0, 0); }
  to  { transform: translate3d(0, 9%, 0); }
}
@keyframes hero-card-lift{
  from{ transform: translate3d(0, 0, 0); }
  to  { transform: translate3d(0, -14px, 0); }
}

/* The band. Solid harbor-900 — the site's dark blue, same as the nav's dark
   state and the "Read the case" button — so the meta sits on a known colour
   instead of on the photograph. That is what clears the contrast exception
   the meta used to carry: 10.77:1 here, against 1.12:1 over the picture. */
.hero-band{
  flex:0 0 auto;
  background: var(--harbor-900);
  color: var(--paper-050);
  padding-block: clamp(16px, 2.3svh, 28px);
}

/* .hero-ceiling — the deck's .cover-ceiling. Grid values verbatim: 1.5px
   rules every 58px at rgba(138,137,132,.11), masked so the photograph
   emerges rather than cutting on a hard line. This panel is what removes the
   ceiling from the picture; do not crop the photo to do it. */
.hero-ceiling{
  position:absolute; left:0; right:0; top:0; height:74%;
  z-index:0; pointer-events:none;
  background:
    repeating-linear-gradient(0deg,  rgba(138,137,132,.11) 0 1.5px, transparent 1.5px 58px),
    repeating-linear-gradient(90deg, rgba(138,137,132,.11) 0 1.5px, transparent 1.5px 58px),
    var(--paper-050);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 66%, rgba(0,0,0,.45) 84%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 66%, rgba(0,0,0,.45) 84%, transparent 100%);
}

/* .hero-veil — LIGHT, per the brief. The deck's own two-part construction
   (left wash + bottom-left lift) at close to the deck's own alphas. It is
   deliberately not strong enough to carry text over the darkest parts of the
   photograph; the copy is kept inside the ceiling panel instead. */
.hero-veil{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  /* LIGHT veil — the deck's own two-part construction at close to the deck's
     own alphas, chosen deliberately for the look of the photograph.

     KNOWN ACCESSIBILITY EXCEPTION. This is not strong enough to carry the
     lead and meta where they sit below the ceiling panel; both fail WCAG AA
     on desktop. That is an accepted trade, not an oversight — see the
     "Cover: accepted contrast exception" section of README.md for the
     measured figures and the one-block change that fixes it. */
  background:
    radial-gradient(ellipse 46% 34% at 0% 100%, rgba(245,241,232,.78) 0%, rgba(245,241,232,.44) 52%, rgba(245,241,232,0) 88%),
    linear-gradient(to right, rgba(245,241,232,.62) 0%, rgba(245,241,232,.44) 28%, rgba(245,241,232,.20) 46%, rgba(245,241,232,0) 62%);
}
@media (max-width: 900px){
  .hero-ceiling{ height:66%; }
  .hero-veil{
    background:
      linear-gradient(to top, rgba(245,241,232,.80) 0%, rgba(245,241,232,.58) 34%,
                              rgba(245,241,232,.28) 60%, rgba(245,241,232,0) 88%);
  }
}

/* Liquid-glass lead band — MOBILE ONLY.

   The lead sits over the photograph and, on a phone, over the busiest part of
   it. Measured at 390px the darkest ground behind it gave ink text 2.34:1,
   against the 4.5:1 that ~16.5px regular copy needs. This is an accessibility
   fix wearing a material.

   The material is built from five layers, in the order they composite:

     1. a warm paper wash at .62  — THIS is what carries the contrast
     2. a diagonal specular sheen — the "lit from upper-left" cue
     3. backdrop blur + saturate + a touch of brightness — the refraction
     4. a hairline rim, brighter along the top edge than the bottom, which is
        what reads as thickness rather than a flat tint
     5. a soft drop shadow so it floats above the photograph instead of
        sitting in it

   ⚠ LAYER 1 IS LOAD-BEARING AND LAYERS 2-5 ARE NOT. `backdrop-filter` is an
   enhancement: browsers without it, and users who switch it off, still get the
   flat wash, which is the value that gets measured.

   The wash was taken .62 -> .50 on 26 Aug 2026 for more transparency, and
   RE-MEASURED rather than assumed: 10.63:1 at the worst point, against the
   4.5:1 that ~16.5px copy needs. There is still margin, but less of it. .50 is
   about as far as this can go while the photo crop still varies by device —
   below it, verify against a real handset before shipping. */
@media (max-width: 900px){
  .hero .t-lead{
    position:relative;
    margin-inline: calc(var(--pad-x) * -0.55);
    padding: clamp(15px,3vw,19px) clamp(16px,4vw,22px);
    border-radius: 22px;
    color: var(--ink-900);

    background:
      /* specular sheen, upper-left to centre */
      linear-gradient(158deg, rgba(255,255,255,.34) 0%, rgba(255,255,255,.10) 38%,
                              rgba(255,255,255,0) 62%),
      /* the wash that does the accessibility work */
      rgba(245,241,232,.50);

    -webkit-backdrop-filter: blur(20px) saturate(165%) brightness(1.05);
    backdrop-filter: blur(20px) saturate(165%) brightness(1.05);

    box-shadow:
      inset 0 1.5px 0 rgba(255,255,255,.78),      /* lit top edge */
      inset 0 0 0 1px rgba(255,255,255,.34),      /* rim */
      inset 0 -1.5px 0 rgba(255,255,255,.16),     /* faint underside lip */
      inset 0 -14px 26px -18px rgba(21,26,29,.30),/* inner depth toward the base */
      0 12px 30px -14px rgba(21,26,29,.34),       /* lift */
      0 2px 8px -3px rgba(21,26,29,.20);
  }

  /* A second, tighter highlight riding the top curve — on iOS the specular
     follows the corner radius rather than the box, which is most of why the
     material reads as glass and not as a translucent rectangle. */
  .hero .t-lead::before{
    content:""; position:absolute; inset:0; border-radius:inherit;
    pointer-events:none;
    background: radial-gradient(120% 62% at 22% -10%,
                rgba(255,255,255,.50) 0%, rgba(255,255,255,.16) 34%,
                rgba(255,255,255,0) 70%);
  }

  /* Without backdrop-filter the sheen alone can look like a smear, so the
     wash is raised slightly to compensate and keep it looking deliberate. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
    .hero .t-lead{ background: rgba(245,241,232,.62); }
    .hero .t-lead::before{ display:none; }
  }
}

.hero .wrap{
  position:relative; z-index:1;
  display:flex; flex-direction:column; width:100%;
}


.hero .t-display{
  /* Wide measure: the ceiling panel is full-bleed paper, so the headline can
     use the width the 1200px body measure leaves sitting empty. At 15ch it
     ran to four lines while using only 793px of 1200 available. */
  max-width:23ch;
  font-size: clamp(32px, min(5.4vw, 9.4svh), 88px);
  color: var(--brick-700);
}
.hero .t-lead{
  max-width:62ch;
  margin-top: clamp(12px, 2svh, 22px);
  font-size: clamp(16.5px, min(1.35vw, 2.3svh), 21px);
  color: var(--ink-800);
}
.hero-actions{ display:flex; flex-wrap:wrap; gap:14px; margin-top: clamp(18px, 2.8svh, 30px); }

/* Laptop only: drop the CTAs to the foot of the stage so they sit just above
   the meta band instead of floating mid-frame. `.hero .wrap` is a flex column
   filling the stage, so `margin-top:auto` on the last child pushes it down.

   Scoped to 1024-1700px on purpose. Below that the stage is short enough that
   the buttons already sit close to the band; above it (1920 and wider) the
   gap is 430-775px and dropping the buttons that far would strand them from
   the copy entirely. Re-measure if you widen this range. */
@media (min-width: 1024px) and (max-width: 1700px){
  .hero-actions{ margin-top:auto; padding-top: clamp(24px, 4svh, 44px); }
}
.hero-meta{
  margin:0; max-width:120ch;
  font-family:var(--font-serif); font-style:italic; font-size:14.5px;
  color: var(--paper-050);
}
.hero .eyebrow{ color: var(--harbor-700); }

/* Page hero for interior pages — shorter, same language. */
.pagehero{
  position:relative; background: var(--sec); color: var(--paper-050);
  padding-top: calc(var(--nav-h) + clamp(44px, 6.5vw, 84px));
  padding-bottom: clamp(44px, 6vw, 78px);
  overflow:hidden;
}
.pagehero .wrap{ position:relative; z-index:1; }
.pagehero .eyebrow{ color: var(--sec-accent); }
.pagehero .t-lead{ max-width:62ch; margin-top:22px; color: var(--harbor-100); }

/* --- Partner (/partner): the one LIGHT section header ----------------------
   Every other section colour is a dark tint, so `.pagehero` above is written
   light-on-dark: paper text, gold-100 eyebrow, harbor-100 lead, a pale ghost
   numeral and a pale stone motif. Brand gold (--gold-500 #D6A33A) is a light
   surface, so all five of those layers have to inverted, not just the
   background. Ratios measured against #D6A33A; paper-050 lands at 2.03:1
   there, which is the failure this block exists to prevent — do not
   reintroduce a light value for "consistency" with the other heroes.

   Two things deliberately NOT changed:
     * the mobile ToC panel stays on gold-800. It reads `--sec`, and it is a
       light-on-dark surface of its own; it is still the Partner colour, just
       the deep tint. Only the hero was asked to change.
     * the fixed nav needs no override. site.js marks `.pagehero` a dark zone,
       but the dark bar paints its own rgba(25,58,68,.82), which composites
       over gold to (59,77,66) — still dark, so its light text keeps 7.4:1.
   -------------------------------------------------------------------------- */
body[data-section="partner"] .pagehero{
  background: var(--gold-500);
  color: var(--ink-950);                                    /* 7.65:1 */
}
body[data-section="partner"] .pagehero .eyebrow{
  color: var(--brick-900);                                  /* 5.75:1 — brand red, echoes the logo lockup */
}
body[data-section="partner"] .pagehero .t-lead{
  color: var(--ink-800);                                    /* 5.21:1 */
}
body[data-section="partner"] .pagehero :focus-visible{
  /* The shared rule above gives .pagehero a gold-300 ring — 1.35:1 on gold,
     i.e. invisible. Nothing in this hero is focusable today; this is here so
     that adding a link to it later cannot silently lose the focus ring. */
  outline-color: var(--ink-950);
}
body[data-section="partner"] .pagehero .motif .route{
  /* stone-300 at the motif's .5 opacity all but vanishes on gold. This is the
     dark equivalent, delta-matched to how the motif reads on the deep bands. */
  stroke: rgba(21,26,29,.30);
}

/* --- ...and the mobile contents panel, to match the hero -------------------
   The panel normally carries `--sec` and is written light-on-dark just like
   `.pagehero`, so making it brand gold means inverting the same way. Two
   things here that the hero did not have to deal with:

     * `.navpanel-close` is a real UI control, so its border has to clear the
       3:1 of SC 1.4.11 against gold, not merely be visible. Gold is light
       enough that a dark border needs a HIGH alpha to get there: .45 (the
       mirror of the light value it replaces) reaches only 2.40:1 and .55 only
       just ties 3.00:1, so it is set at .65 = 3.77:1. Do not lower it to
       match the .45 used on the dark panels — the maths does not mirror.
     * the footer buttons need NO override and must not be given one. `.btn`
       is `border:1.5px solid currentColor; color:inherit`, so it picks up the
       panel's new ink-950 by itself, and `.btn--solid` paints its own
       brick-700 (3.25:1 against gold, so it still reads as a button).

   The compass keeps its paper disc — the emblem was drawn for a light ground
   and that is what the disc is for. Only its ring flips, because a light ring
   on a light disc against gold had nothing to define it.
   -------------------------------------------------------------------------- */
body[data-section="partner"] .navpanel{
  background: var(--gold-500);
  color: var(--ink-950);
  border-left-color: var(--brick-900);
}
body[data-section="partner"] .navpanel-head .toc-label{
  color: var(--brick-900);                          /* 5.75:1 */
}
body[data-section="partner"] .navpanel a.toc-item{
  color: var(--ink-950);                            /* 7.65:1 */
  border-bottom-color: rgba(21,26,29,.22);          /* the row rule, inverted */
}
body[data-section="partner"] .navpanel a.toc-item:hover,
body[data-section="partner"] .navpanel a.toc-item[aria-current="page"],
body[data-section="partner"] .navpanel .toc-num{
  color: var(--brick-900);                          /* 5.75:1 at the 15px numeral */
}
body[data-section="partner"] .navpanel-close{
  border-color: rgba(21,26,29,.65);                 /* 3.77:1 — SC 1.4.11 */
  color: var(--ink-950);
}
body[data-section="partner"] .navpanel-close:hover{
  background: var(--ink-950); border-color: var(--ink-950); color: var(--gold-500);
}
body[data-section="partner"] .navpanel :focus-visible{
  outline-color: var(--ink-950);                    /* shared rule gives gold-300: 1.42:1 here */
}
body[data-section="partner"] .toc-compass{
  border-color: rgba(21,26,29,.35);
}

/* ==========================================================================
   PHOTOGRAPHS

   The site carries very few, on purpose. Rules that keep them honest:

   - `width`/`height` are always set so the browser reserves the space and the
     page does not jump as they load (CLS).
   - `loading="lazy"` — every photo is below the fold by design; the cover is a
     CSS background and is not affected.
   - The caption ALWAYS states that the people shown are not MAPS members.
     This is not decoration: the Pexels licence forbids implying endorsement by
     people in the imagery, and this workforce's whole vulnerability is being
     identified. A reader must never conclude that a person in a photograph is
     a peer in recovery.
   ========================================================================== */

/* Deliberately small. These are supporting images beside prose, not features:
   at full column width they dominated the section and pushed the text they
   were meant to support below the fold. Capped at 380px on desktop; full
   width on a phone, where the columns stack and 380px would look stranded. */
.photo{ margin:0 0 clamp(26px,3.4vw,40px); padding:0; max-width:380px; }
@media (max-width:860px){ .photo{ max-width:none; } }
.photo img{
  display:block; width:100%; height:auto;
  border-radius:2px; background:var(--stone-100);
}
.photo figcaption{
  margin-top:12px; font-family:var(--font-serif); font-size:14.5px;
  line-height:1.5; color:var(--stone-700); max-width:62ch;
}
.photo-credit{ display:block; margin-top:5px; font-size:12.5px; color:var(--stone-500); }
@media print{ .photo{ display:none; } }

/* ==========================================================================
   DIAGRAMS

   Inline SVG so the shapes inherit the palette and both themes work from one
   source. Every diagram carries <title> and <desc> referenced by
   aria-labelledby — the site claims WCAG AA, and a picture that only works
   visually would break that claim.
   ========================================================================== */

/* Maryland, with the pilot area marked. The outline is real geometry — US
   state boundary GeoJSON, equirectangular with a cos(lat) correction so the
   state is not stretched, then Ramer-Douglas-Peucker simplified to ~320
   points. Do not hand-edit the path data; regenerate it if it ever changes. */
.mdmapfig{ margin:clamp(30px,4vw,46px) 0 0; padding:0; }
.mdmap{ display:block; width:100%; height:auto; overflow:visible; }
.mdmap-shape{ fill:var(--stone-100); stroke:var(--stone-500); stroke-width:1.1; stroke-linejoin:round; }
.mdmap-halo{ fill:var(--brick-700); opacity:.13; }
.mdmap-dot{ fill:var(--brick-700); }
.mdmap-lead{ stroke:var(--brick-700); stroke-width:1.2; }
.mdmap-label{
  font-family:var(--font-display); font-weight:800; font-size:13px;
  letter-spacing:.06em; fill:var(--ink-950);
  /* A halo, so the label stays readable wherever it lands. The first version
     put it above the pin, where it sat directly on Maryland's northern border
     and collided with the outline. Moving it was the fix; this is the belt. */
  paint-order:stroke fill;
  stroke:var(--surface-paper); stroke-width:4px; stroke-linejoin:round;
}
.band--white .mdmap-label{ stroke:var(--surface-white); }
.mdmap-cap{
  display:flex; gap:clamp(14px,2.4vw,24px); align-items:flex-start;
  margin-top:18px; padding-top:16px; border-top:1px dashed var(--stone-300);
}
.mdmap-cap-n{
  font-family:var(--font-display); font-weight:800; line-height:.9;
  font-size:clamp(40px,5vw,64px); letter-spacing:-.03em; color:var(--brick-700);
  font-variant-numeric:tabular-nums; flex-shrink:0;
}
.mdmap-cap-l{
  font-family:var(--font-serif); font-size:15.5px; line-height:1.5;
  color:var(--stone-700); max-width:60ch;
}
/* The pilot marker settles in rather than appearing — one small movement on a
   page that otherwise only fades. */
@media (prefers-reduced-motion: no-preference){
  .js-reveal .mdmapfig .mdmap-pin{ opacity:0; transform-box:fill-box; }
  .js-reveal .mdmapfig.in .mdmap-pin{ animation: mdpin .7s var(--ease) .35s forwards; }
  @keyframes mdpin{ from{ opacity:0; } to{ opacity:1; } }
}
@media (max-width:620px){
  .mdmap-label{ font-size:17px; }
  .mdmap-cap{ flex-direction:column; gap:8px; }
}

.routefig{ margin:clamp(28px,4vw,44px) 0 0; padding:0; }
/* ---- Per-capita comparison ------------------------------------------------
   This fact used to be a run-on line of text — "Leaders: Kentucky 186 ·
   Oregon 119 · New Hampshire 97" — which is the most persuasive number on the
   page set as punctuation. As bars, Maryland's 9.4 is a 27px stub against
   Kentucky's 540px and the gap lands before it is read. The values are the
   same ones the copy already cites and the source note below already covers.
   Comparator bars measure 6.48:1 on the white band and Maryland 7.45:1, so
   the chart does not rely on colour: bar length carries it, and Maryland is
   additionally named in bold and flagged in words. */
.pdfig{ margin:clamp(28px,3.6vw,44px) 0 0; padding:0; }
.pdchart{ display:block; width:100%; height:auto; overflow:visible; }
.pd-axis{ stroke:var(--stone-300); stroke-width:1; }
.pd-bar{ fill:var(--harbor-700); }
.pd-bar--md{ fill:var(--brick-700); }
.pd-name{ font-family:var(--font-display); font-weight:600; font-size:15px; fill:var(--ink-800); }
.pd-name--md{ font-weight:800; fill:var(--ink-950); }
.pd-val{
  font-family:var(--font-display); font-weight:800; font-size:15px;
  fill:var(--stone-700); font-variant-numeric:tabular-nums;
}
.pd-val--md{ fill:var(--brick-700); }
.pd-flag{ font-family:var(--font-serif); font-style:italic; font-size:12.5px; fill:var(--brick-700); }
/* Same trick the map and the routing diagram use: the SVG scales down with the
   column, so the nominal size goes up on small screens to land near 12px real. */
.pd-abbr{ display:none; }
@media (max-width: 620px){
  /* The chart renders at ~0.45 scale in a phone column, so nominal sizes are
     roughly doubled to land near 12px on glass. At that size "New Hampshire"
     no longer fits the 150px label gutter and would clip off the left edge,
     so the full name and an abbreviation are both in the markup and swapped
     here. The italic flag is dropped rather than shrunk — "bottom third
     nationally" is already stated twice in the copy directly above it. */
  .pd-name{ font-size:26px; }
  .pd-val{ font-size:26px; }
  .pd-flag{ display:none; }
  .pd-full{ display:none; }
  .pd-abbr{ display:inline; }
}

.routediagram{ display:block; width:100%; height:auto; overflow:visible; }

.rd-src{ fill:var(--harbor-050); stroke:var(--harbor-700); stroke-width:1.4; }
.rd-srch{ font-family:var(--font-display); font-weight:800; font-size:15px; fill:var(--ink-950); }
.rd-srcs{ font-family:var(--font-serif); font-style:italic; font-size:12px; fill:var(--stone-700); }
.rd-lines{ stroke:var(--stone-300); stroke-width:1.6; }
.rd-node rect{ stroke-width:1.3; }
.rd-node text{ font-family:var(--font-display); font-weight:700; font-size:14px; fill:var(--ink-950); }
.rd-node .rd-sub{ font-family:var(--font-serif); font-style:italic; font-weight:400; font-size:11.5px; fill:var(--stone-700); }
.rd-node--gold rect{ fill:var(--gold-050); stroke:var(--gold-700); }
.rd-node--harbor rect{ fill:var(--harbor-050); stroke:var(--harbor-700); }
.rd-node--stone rect{ fill:var(--stone-050); stroke:var(--stone-500); }
.rd-node--sage rect{ fill:var(--sage-050); stroke:var(--sage-700); }
.rd-meta text{ font-family:var(--font-serif); font-style:italic; font-size:11.5px; fill:var(--stone-700); }

/* The route lines draw themselves as the figure enters view — the motif is a
   path, so drawing suits it better than a fade. Collapsed under reduced
   motion, and only when the reveal system is actually running. */
.js-reveal .routefig .rd-lines path{ stroke-dasharray:240; stroke-dashoffset:240; }
.js-reveal .routefig.in .rd-lines path{ animation: rd-draw 1.1s var(--ease) forwards; }
.js-reveal .routefig.in .rd-lines path:nth-child(2){ animation-delay:.09s; }
.js-reveal .routefig.in .rd-lines path:nth-child(3){ animation-delay:.18s; }
.js-reveal .routefig.in .rd-lines path:nth-child(4){ animation-delay:.27s; }
@keyframes rd-draw{ to{ stroke-dashoffset:0; } }
@media (prefers-reduced-motion: reduce){
  .js-reveal .routefig .rd-lines path{ stroke-dasharray:none; stroke-dashoffset:0; animation:none; }
}
@media (max-width: 620px){
  .rd-node text{ font-size:16px; }
  .rd-node .rd-sub{ font-size:13px; }
  .rd-srch{ font-size:17px; }
}

/* ==========================================================================
   THE LEFT COLUMN

   26 of the site's 29 two-column sections put an eyebrow, a heading and a rule
   in the left column and then nothing — roughly 400px wide by 300-500px tall
   of empty paper beside every block of prose, repeating down the page. This
   fills it from CSS so that no section markup had to change.

   `.col-lead--bare` opts a section OUT, for the few that carry a pulled
   statistic or a quote instead. The motif is decorative only: it is a
   background image on a ::after with no text, so it is invisible to assistive
   technology by construction.
   ========================================================================== */

.twocol > div:first-child{ position:relative; }
.twocol > div:first-child::after{
  content:""; display:block;
  margin-top:clamp(26px,3.4vw,40px);
  aspect-ratio:13/10; width:min(260px,78%);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 260 200' fill='none'%3E%3Cellipse cx='118' cy='104' rx='96' ry='58' stroke='%23C8C1B7' stroke-width='1.25'/%3E%3Cellipse cx='118' cy='104' rx='62' ry='90' stroke='%23C8C1B7' stroke-width='1.25' stroke-dasharray='7 9'/%3E%3Cpath d='M8 172 C64 130 156 142 244 52' stroke='%23C8C1B7' stroke-width='1.25' stroke-dasharray='7 9'/%3E%3Ccircle cx='118' cy='104' r='4' stroke='%23C8C1B7' stroke-width='1.25'/%3E%3C/svg%3E") left top / contain no-repeat;
  opacity:.55;
}
/* Stamped identically down a page it becomes wallpaper, so alternate sections
   mirror it — enough variation to read as considered, not enough to distract. */
.band:nth-of-type(even) .twocol > div:first-child::after{
  transform: scaleX(-1); transform-origin:left center;
  margin-left:12%;
}
.col-lead--bare::after{ display:none !important; }

/* Below the two-column breakpoint the columns stack, so the motif would sit
   between a heading and its own prose. It is decoration; it goes. */
@media (max-width: 860px){
  .twocol > div:first-child::after{ display:none; }
}
@media print{ .twocol > div:first-child::after{ display:none; } }

/* A statistic pulled out of the prose beside it. Used where a section has a
   number worth seeing before the paragraph explains it. */
.pullstat{ margin-top:clamp(26px,3.4vw,40px); }
.pullstat .n{
  font-family:var(--font-display); font-weight:800; line-height:.9;
  font-size:clamp(46px,5.4vw,72px); letter-spacing:-.03em;
  color:var(--brick-700); font-variant-numeric:tabular-nums;
}
.pullstat .l{
  display:block; margin-top:10px; max-width:26ch;
  font-family:var(--font-serif); font-style:italic; font-size:15px;
  line-height:1.45; color:var(--stone-700);
}
.pullstat .src{
  display:block; margin-top:8px; font-size:12.5px; color:var(--stone-500);
  font-family:var(--font-serif);
}

/* A short line lifted from the adjacent paragraph. */
.pullquote-sm{
  margin-top:clamp(26px,3.4vw,40px); max-width:24ch;
  font-family:var(--font-serif); font-style:italic;
  font-size:clamp(19px,2.1vw,24px); line-height:1.35; color:var(--ink-800);
  border-left:2px solid var(--gold-500); padding-left:16px;
}
@media (max-width:860px){ .pullstat, .pullquote-sm{ display:none; } }

/* ==========================================================================
   "AVAILABLE NOW" STATUS BLOCK

   /for-peers described services in the present tense — "we help you build
   one", "we can go with you", "all of this is free to peers" — for services
   that have not started. A peer in distress could reasonably have concluded
   help was already available. This block is the correction: it appears before
   any service description and says plainly that MAPS cannot take a case yet,
   with three things that ARE available.

   Keep it above the fold on mobile. It is a safety message, not a banner.
   ========================================================================== */

.statusband{ scroll-margin-top: calc(var(--nav-h) + 8px); }
.status-note{
  max-width:74ch; border-left:4px solid var(--brick-700);
  padding:clamp(20px,2.6vw,28px) 0 clamp(20px,2.6vw,28px) clamp(18px,2.4vw,28px);
}
.status-note h2{ margin:0 0 10px; }
.status-note .t-body{ margin-bottom:16px; }
.status-choices{ display:flex; flex-wrap:wrap; gap:12px; margin:18px 0 16px; }
.status-note .t-small{
  margin:0; font-family:var(--font-serif); font-size:14px; line-height:1.5;
  color:var(--stone-700);
}
@media (max-width:620px){
  .status-choices .btn{ width:100%; justify-content:center; }
}

/* ==========================================================================
   OWL ATTRIBUTION (footer)

   A flex ROW — mark, then sentence — not an inline-flex link inside a
   paragraph. The first version made the mark and the name one link and set it
   `display:inline-flex`, which produced an atomic inline box the sentence had
   to flow around: the mark landed on one line, the name on the next, and the
   rest of the sentence beside the mark. Keep this structural.

   Only the NAME is a link. The mark carries alt="" and aria-hidden because the
   adjacent link text already says it — marking both would be the same
   destination twice, which a screen reader announces as a duplicate link.

   External SVG rather than inline: the footer is duplicated across all seven
   pages with no build step, so inlining a 4.7KB path would add ~33KB of markup
   for something one cached request covers.
   ========================================================================== */

.owl-attrib{ margin-top:14px; }
.owl-attrib p{ margin:0; }

/* The mark itself sits BELOW the footer as a signature — its own band, so it
   reads as "who made this" rather than as part of the site's own navigation.
   The link text lives in aria-label because the image is decorative; without
   it the link would announce as nothing at all. */
.owl-sig{
  display:flex; align-items:center; justify-content:center;
  padding:clamp(30px,4.5vw,54px) var(--pad-x) clamp(34px,5vw,60px);
  background:var(--surface-ink);
  text-decoration:none;
}
.owl-sig img{
  width:34px; height:34px; display:block;
  /* .42 is the floor, not a taste call: below it the mark drops under 3:1 on
     the ink ground, and it is a link target, not decoration (SC 1.4.11).
     Measured: .35 -> 3.00:1, .42 -> 3.75:1. Do not dim it further. */
  opacity:.42; transition:opacity .25s var(--ease);
}
.owl-sig:hover img, .owl-sig:focus-visible img{ opacity:.95; }
.owl-sig:focus-visible{ outline:2px solid var(--gold-300); outline-offset:-4px; }
@media (prefers-reduced-motion: reduce){ .owl-sig img{ transition:opacity .01ms; } }
@media print{ .owl-sig{ display:none; } }
/* The footer's nav links sit in lists, where being a link is obvious from
   context. This one is inline inside a sentence, so it needs more than a
   colour shift to be identifiable as a link (WCAG 1.4.1). */
.owl-attrib a{
  text-decoration:underline; text-underline-offset:3px;
  text-decoration-thickness:1px; text-decoration-color:rgba(245,241,232,.45);
}
.owl-attrib a:hover{ text-decoration-color:var(--gold-300); color:var(--gold-300); }
@media (max-width:520px){
  .owl-attrib{ gap:10px; }
  .owl-attrib img{ width:22px; height:22px; }
}

/* ==========================================================================
   HOME LINK — nav bar and mobile panel

   The brand lockup already links to "/", which is the web's oldest
   convention. This is an explicit, labelled second route for people who do not
   know that convention or do not think to try it.

   ⚠ It is in the markup on EVERY page and hidden on the homepage with CSS,
   not omitted there. `qa/audit.py` requires the nav, panel and footer to be
   byte-identical across pages — a home link present on six and absent on one
   would fail that check, and rightly: chrome that varies per page is how
   things drift. Visibility is a styling concern, so CSS handles it.
   ========================================================================== */

/* Visually hidden, still read aloud. The icon alone would announce as nothing. */
.vh{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.nav-home{
  display:inline-flex; align-items:center; justify-content:center;
  width:30px; height:30px; flex-shrink:0;
  color:inherit; opacity:.78;
  transition:opacity .2s var(--ease), transform .2s var(--ease);
}
.nav-home svg{ width:19px; height:19px; display:block; }
.nav-home svg path{
  stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.nav-home:hover{ opacity:1; }
.nav-home:focus-visible{ outline:2px solid var(--gold-300); outline-offset:3px; border-radius:4px; }
/* The nav links carry an underline-on-hover ::after; the icon must not. */
.nav-links a.nav-home::after{ display:none; }

.toc-home .toc-num{ display:flex; align-items:center; }
.toc-home .toc-num svg{ width:19px; height:19px; display:block; }
.toc-home .toc-num svg path{
  stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}

/* Hidden on the homepage — you are already there. display:none also removes
   it from the accessibility tree, so it is not announced either. */
body[data-section="home"] .nav-home,
body[data-section="home"] .toc-home{ display:none; }

@media print{ .nav-home{ display:none; } }

/* ==========================================================================
   BACK TO TOP
   ========================================================================== */

.to-top{
  position:fixed; right:clamp(14px,2.4vw,26px); bottom:clamp(14px,2.4vw,26px);
  width:48px; height:48px;            /* >= 44px, SC 2.5.8 */
  display:flex; align-items:center; justify-content:center;
  border:0; border-radius:50%; cursor:pointer;
  background:var(--harbor-900); color:var(--paper-050);
  font-size:19px; line-height:1;
  -webkit-tap-highlight-color:transparent;
  box-shadow:0 2px 10px rgba(21,26,29,.28), 0 0 0 1px rgba(245,241,232,.14);
  /* Sits BELOW the scrim (950) and panel (960) so it can never float over the
     open mobile menu; JS also hides it while the panel is open. */
  z-index:940;
  opacity:0; visibility:hidden; transform:translateY(8px);
  transition:opacity .22s var(--ease), transform .22s var(--ease), visibility .22s var(--ease), background .2s var(--ease);
}
.to-top.is-on{ opacity:1; visibility:visible; transform:none; }
.to-top:hover{ background:var(--brick-700); }
.to-top:focus-visible{ outline:2px solid var(--gold-300); outline-offset:3px; }
@media (prefers-reduced-motion: reduce){
  .to-top{ transition:opacity .01ms; transform:none; }
}
@media print{ .to-top{ display:none; } }

/* ==========================================================================
   MAILING LIST SIGNUP  (the site's only form)
   ========================================================================== */

.signup{ margin-top:22px; display:flex; flex-direction:column; gap:16px; max-width:34rem; }
.signup-row{ display:flex; flex-direction:column; gap:6px; }
.signup label{
  font-family:var(--font-display); font-weight:700; font-size:12.5px;
  text-transform:uppercase; letter-spacing:.05em; color:var(--ink-800);
}
.signup .req{ color:var(--brick-700); }
.signup input[type="text"], .signup input[type="email"], .signup select{
  font-family:var(--font-serif); font-size:16px;   /* 16px or iOS zooms on focus */
  padding:12px 14px; border:1.5px solid var(--stone-300); border-radius:var(--radius);
  background:var(--surface-white); color:var(--ink-950); width:100%;
  transition:border-color .2s var(--ease);
}
.signup input:focus, .signup select:focus{ border-color:var(--harbor-700); }
.signup-note{ margin:0; font-size:13px; color:var(--stone-700); font-family:var(--font-serif); font-style:italic; }

.signup-consent{ display:flex; gap:11px; align-items:flex-start; }
.signup-consent input{ width:22px; height:22px; margin-top:2px; flex-shrink:0; accent-color:var(--harbor-700); }
.signup-consent label{
  font-family:var(--font-serif); font-size:14.5px; font-style:normal;
  text-transform:none; letter-spacing:0; font-weight:400; color:var(--ink-800); line-height:1.5;
}

/* Honeypot. Must be invisible to people but reachable by a bot, so it cannot
   use display:none — many bots skip those. Off-screen, untabbable instead. */
.signup-hp{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

.signup button{ align-self:flex-start; }
.signup-status{ margin:0; font-size:14.5px; line-height:1.5; font-family:var(--font-serif); }
.signup-status.is-ok{ color:var(--sage-700); font-weight:600; }
.signup-status.is-error{ color:var(--brick-700); font-weight:600; }   /* 6.61:1 on paper */
.signup-status.is-warn{ color:var(--gold-800); }                      /* 7.02:1 on paper */
.signup--inert input, .signup--inert select, .signup--inert .signup-consent{ opacity:.55; }
/* The button must LOOK disabled too. A solid brand-red button that reads as
   clickable while `disabled` is set is worse than no button at all. */
.signup--inert button[disabled]{ opacity:.5; cursor:not-allowed; }
.signup button[disabled]{ cursor:not-allowed; }

/* ==========================================================================
   /about — jump nav and part markers

   /about carries what used to be three pages, so it needs two things the
   single-topic pages never did: a way to reach a part without scrolling
   through the ones above it, and a visible seam between parts so a reader
   knows which of the three they are in.
   ========================================================================== */

.jumpnav{
  display:flex; flex-wrap:wrap; gap:10px;
  margin-top:clamp(22px,3vw,32px);
}
.jumpnav a{
  display:inline-flex; align-items:baseline; gap:9px;
  padding:10px 16px; border-radius:var(--radius);
  border:1.5px solid rgba(245,241,232,.32);
  color:var(--paper-050); text-decoration:none;
  font-family:var(--font-display); font-weight:700; font-size:13.5px;
  text-transform:uppercase; letter-spacing:.03em; line-height:1;
  transition: background .22s var(--ease), border-color .22s var(--ease), color .22s var(--ease);
}
.jumpnav a:hover{ background:var(--paper-050); border-color:var(--paper-050); color:var(--ink-950); }
/* Where you are, not just where you can go. Marked with a filled state AND a
   left rule — colour alone would not survive a monochrome or high-contrast
   rendering (WCAG 1.4.1). */
.jumpnav a.is-current{
  background:var(--paper-050); color:var(--ink-950); border-color:var(--paper-050);
  box-shadow: inset 3px 0 0 var(--brick-700);
}
.jumpnav a.is-current .jump-num{ color:var(--brick-700); }
.jump-num{
  font-family:var(--font-serif); font-style:italic; font-weight:400;
  font-size:12.5px; color:var(--sec-accent); text-transform:none; letter-spacing:0;
}
.jumpnav a:hover .jump-num{ color:var(--brick-700); }

/* The three parts of /about, as native <details>.

   The page ran to 22,694px with everything expanded, which is four times any
   other page. Collapsing it is what makes it usable — but it has to survive
   three things that a div-and-JS accordion would break:

     * no JS  -> <details> still opens. The content is never unreachable.
     * keyboard -> <summary> is focusable and toggles on Enter/Space for free.
     * deep links -> /about#rights must open the part containing it, which
       site.js handles in openHashTarget().

   `scroll-margin-top` is load-bearing on every anchor target: the nav bar is
   fixed, so without it a jump lands with the heading underneath the bar. */
.part{
  border-top:1px solid var(--stone-200);
  scroll-margin-top: calc(var(--nav-h) + 8px);
}
.part:last-of-type{ border-bottom:1px solid var(--stone-200); }

.part-summary{
  display:grid; grid-template-columns:auto 1fr auto; gap:clamp(16px,2.6vw,30px);
  align-items:center; cursor:pointer; list-style:none;
  padding:clamp(26px,3.6vw,44px) var(--pad-x);
  max-width:var(--wrap); margin-inline:auto;
  transition:background .2s var(--ease);
}
.part-summary::-webkit-details-marker{ display:none; }
.part-summary:hover{ background:var(--paper-100); }
.part-summary:focus-visible{ outline:2px solid var(--harbor-700); outline-offset:-3px; }

.part-num{
  font-family:var(--font-display); font-weight:800; line-height:.85;
  font-size:clamp(34px,4.4vw,58px); letter-spacing:-.03em; color:var(--stone-300);
  font-variant-numeric:tabular-nums; transition:color .2s var(--ease);
}
.part[open] .part-num{ color:var(--brick-700); }
.part-text{ display:block; min-width:0; }
.part-title{
  display:block; font-family:var(--font-display); font-weight:800;
  text-transform:uppercase; letter-spacing:-.012em; line-height:1.05;
  font-size:clamp(24px,3.2vw,38px); color:var(--ink-950);
}
.part-blurb{
  display:block; margin-top:8px; max-width:64ch;
  font-family:var(--font-serif); font-size:15.5px; line-height:1.5; color:var(--stone-700);
}

/* The chevron is the only thing that says "this opens". It must not be the
   ONLY cue though — the numeral changes colour too, so the state is not
   carried by a single rotating glyph (WCAG 1.4.1). */
.part-chev{
  width:16px; height:16px; flex-shrink:0;
  border-right:2.5px solid var(--brick-700); border-bottom:2.5px solid var(--brick-700);
  transform:rotate(45deg); transform-origin:60% 60%;
  transition:transform .28s var(--ease);
}
.part[open] .part-chev{ transform:rotate(-135deg); }
@media (prefers-reduced-motion: reduce){ .part-chev{ transition:none; } }

.part-body > section:first-child{ border-top:1px solid var(--stone-200); }

/* Every anchor inside a part needs the fixed-bar offset too. */
#mission, #navigation, #boundaries, #rights{ scroll-margin-top: calc(var(--nav-h) + 8px); }

@media (max-width:620px){
  .part-summary{ grid-template-columns:auto 1fr; gap:14px; }
  .part-chev{ grid-column:2; justify-self:end; margin-top:-6px; }
}
/* Printing a collapsed page would print three headings and nothing else;
   site.js opens them on beforeprint, and this keeps the summary readable. */
@media print{
  .part-summary{ cursor:auto; }
  .part-chev{ display:none; }
}

@media (prefers-reduced-motion: no-preference){ html{ scroll-behavior:smooth; } }

/* ==========================================================================
   TWO-COLUMN CONTENT  (reference: heading left, prose right)
   ========================================================================== */

.twocol{
  display:grid; grid-template-columns: minmax(0,.85fr) minmax(0,1.15fr);
  gap: clamp(28px, 5vw, 76px); align-items:start;
}
.twocol > .col-body > * + *{ margin-top:22px; }
@media (max-width: 860px){ .twocol{ grid-template-columns:1fr; gap:26px; } }

/* ==========================================================================
   CARDS + GRIDS
   ========================================================================== */

.grid{ display:grid; gap: var(--gap); }
.grid--2{ grid-template-columns:repeat(2,minmax(0,1fr)); }
.grid--3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
.grid--4{ grid-template-columns:repeat(4,minmax(0,1fr)); }
@media (max-width: 980px){
  .grid--3,.grid--4{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (max-width: 640px){
  .grid--2,.grid--3,.grid--4{ grid-template-columns:1fr; }
}

.card{
  background: var(--white);
  border:1px solid var(--stone-200);
  border-top:3px solid var(--brick-700);
  border-radius: var(--radius);
  padding: var(--card-pad);
  display:flex; flex-direction:column; gap:12px;
}
.band--white .card{ background: var(--stone-050); }
.card--gold{ border-top-color: var(--gold-500); }
.card--harbor{ border-top-color: var(--harbor-700); }
.card--sage{ border-top-color: var(--sage-500); }
.card .t-h3{ color: var(--ink-950); }
.card p{ margin:0; font-size:16px; color: var(--ink-700); line-height:1.6; }
.card-num{
  font-family:var(--font-display); font-weight:800; font-size:14px;
  letter-spacing:.05em; color: var(--gold-700);
}
.card-kicker{
  font-family:var(--font-serif); font-style:italic; font-size:13px;
  letter-spacing:.13em; text-transform:uppercase; color: var(--stone-700);
}

.band--deep .card, .band--ink .card{
  background: rgba(255,255,255,.045);
  border-color: rgba(145,187,196,.28);
  border-top-color: var(--gold-500);
}
.band--deep .card .t-h3, .band--ink .card .t-h3{ color: var(--paper-050); }
.band--deep .card p, .band--ink .card p{ color: var(--harbor-100); }
.band--deep .card-kicker, .band--ink .card-kicker{ color: var(--harbor-300); }

/* ---- Numerals / statistics ---- */
.statgrid{ display:grid; gap: var(--gap); grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr)); }
.stat{ border-top:1px solid var(--stone-300); padding-top:18px; }
.band--deep .stat, .band--ink .stat{ border-top-color: rgba(145,187,196,.32); }
.stat-num{
  font-family:var(--font-display); font-weight:800; line-height:.86;
  font-size: var(--fs-numeral); color: var(--brick-700);
  letter-spacing:-.02em;
}
.band--deep .stat-num, .band--ink .stat-num{ color: var(--gold-300); }
.stat-label{
  margin-top:12px; font-family:var(--font-serif); font-style:italic;
  font-size:15.5px; line-height:1.42; color: var(--ink-700);
}
.band--deep .stat-label, .band--ink .stat-label{ color: var(--harbor-100); }
.stat-sub{ margin-top:7px; font-size:13.5px; color: var(--stone-700); font-style:italic; }

/* ---- Dash list (the deck's .dash-list) ---- */
.dash-list{ list-style:none; margin:0; padding:0; }
.dash-list li{
  position:relative; padding-left:26px; margin-bottom:12px; line-height:1.55;
}
.dash-list li::before{
  content:''; position:absolute; left:0; top:.62em;
  width:14px; height:2px; background: var(--accent, var(--brick-700));
}
.dash-list li:last-child{ margin-bottom:0; }
.band--deep .dash-list li::before, .band--ink .dash-list li::before{ background: var(--gold-500); }

/* ---- Numbered process steps ---- */
.steps{ counter-reset:step; display:grid; gap:2px; }
.step{
  display:grid; grid-template-columns:64px 1fr; gap:20px; align-items:start;
  padding:20px 0; border-bottom:1px solid var(--stone-200);
}
.step:first-child{ border-top:1px solid var(--stone-200); }
.band--deep .step, .band--ink .step{ border-color: rgba(145,187,196,.25); }
.band--deep .step:first-child, .band--ink .step:first-child{ border-top-color: rgba(145,187,196,.25); }
.step-num{
  font-family:var(--font-display); font-weight:800; font-size:20px;
  color: var(--gold-600, var(--gold-700)); line-height:1.2;
  position:relative; z-index:1;
}

/* A rail through the numbers, so a list of steps reads as a sequence.

   Used by the complaint pathway on /about#navigation, the organizational
   staging and the first-year roadmap on /partner — the three places the site
   describes something that happens in order. Drawn on `.step` rather than the
   container so it stops correctly at the last item, and sits behind the
   numeral via z-index rather than by guessing at offsets. */
.step{ position:relative; }
.step::before{
  content:""; position:absolute; left:13px; top:0; bottom:0;
  width:2px; background:var(--stone-200);
}
.step:first-child::before{ top:34px; }
.step:last-child::before{ bottom:auto; height:34px; }
.step::after{
  content:""; position:absolute; left:8px; top:26px;
  width:12px; height:12px; border-radius:50%;
  background:var(--surface-paper); border:2px solid var(--gold-700);
}
.band--white .step::after{ background:var(--surface-white); }
.step-num{ padding-left:34px; }

/* On a phone the rail costs horizontal room the text needs more. */
@media (max-width:620px){
  .step::before, .step::after{ display:none; }
  .step-num{ padding-left:0; }
}
@media print{ .step::before, .step::after{ display:none; } .step-num{ padding-left:0; } }
.band--deep .step-num, .band--ink .step-num{ color: var(--gold-300); }
.step-body .t-h3{ margin-bottom:6px; }
.step-body p{ margin:0; color: var(--ink-700); font-size:16px; }
.band--deep .step-body p, .band--ink .step-body p{ color: var(--harbor-100); }
@media (max-width: 560px){
  .step{ grid-template-columns:1fr; gap:8px; }
}

/* ---- Timeline (pilot phases) ---- */
.phase{
  border-top:3px solid var(--gold-500);
  padding-top:20px;
}
.phase-when{
  font-family:var(--font-display); font-weight:800; font-size:13px;
  letter-spacing:.08em; color: var(--brick-700); margin-bottom:8px;
}
.band--deep .phase-when, .band--ink .phase-when{ color: var(--gold-300); }

/* ---- Pull quote (the deck's signature editorial moment) ---- */
.pullquote{
  font-family:var(--font-serif); font-style:italic; font-weight:400;
  font-size: clamp(23px, 3.4vw, 46px); line-height:1.22;
  max-width:20ch; margin:0; text-wrap:balance;
}
.pullquote--wide{ max-width:26ch; }
.pullquote cite{
  display:block; margin-top:24px; font-size:15px; font-style:italic;
  color: var(--stone-700); letter-spacing:.08em; text-transform:uppercase;
}
.band--deep .pullquote cite, .band--ink .pullquote cite{ color: var(--harbor-300); }

/* ---- Definition-style boundary list ("What MAPS Is Not") ---- */
.boundary{
  border-left:3px solid var(--brick-700);
  padding:4px 0 4px 22px;
}
.boundary + .boundary{ margin-top:26px; }
.boundary .t-h3{ margin-bottom:8px; }
.boundary p{ margin:0 0 8px; color: var(--ink-700); font-size:16px; }
.boundary .who{
  font-family:var(--font-serif); font-style:italic; font-size:14.5px;
  color: var(--harbor-700);
}
.band--deep .boundary{ border-left-color: var(--gold-500); }
.band--deep .boundary p{ color: var(--harbor-100); }
.band--deep .boundary .who{ color: var(--gold-300); }

/* ==========================================================================
   FAQ  (native <details> — keyboard and screen-reader behaviour for free)
   ========================================================================== */

.faq{ border-top:1px solid var(--stone-300); }
.faq details{ border-bottom:1px solid var(--stone-300); }
.faq summary{
  list-style:none; cursor:pointer;
  display:flex; align-items:flex-start; justify-content:space-between; gap:24px;
  padding:24px 0;
  font-family:var(--font-display); font-weight:800; text-transform:uppercase;
  letter-spacing:-.008em; font-size:clamp(17px,1.9vw,23px); line-height:1.2;
  color: var(--ink-950);
}
.faq summary::-webkit-details-marker{ display:none; }
.faq summary:hover{ color: var(--brick-700); }
.faq .sign{
  flex-shrink:0; width:26px; height:26px; position:relative; margin-top:2px;
}
.faq .sign::before,.faq .sign::after{
  content:''; position:absolute; background: var(--brick-700);
  left:50%; top:50%; transform:translate(-50%,-50%);
}
.faq .sign::before{ width:16px; height:2px; }
.faq .sign::after{ width:2px; height:16px; transition:transform .25s var(--ease); }
.faq details[open] .sign::after{ transform:translate(-50%,-50%) scaleY(0); }
.faq .answer{ padding:0 0 26px; max-width:72ch; color: var(--ink-700); }
.faq .answer p{ margin:0 0 .9em; }
.faq .answer p:last-child{ margin-bottom:0; }

/* ==========================================================================
   CTA BAND + FOOTER
   ========================================================================== */

.cta-inner{ max-width:820px; }
.cta-inner .t-h2{ margin-bottom:18px; }
.cta-actions{ display:flex; flex-wrap:wrap; gap:14px; margin-top:30px; }

.sitefoot{
  background: var(--surface-ink); color: var(--paper-050);
  padding-block: clamp(50px, 6vw, 78px) 34px;
}
.foot-grid{
  display:grid; gap: var(--gap);
  grid-template-columns: 1.5fr 1fr 1fr 1.2fr;
}
@media (max-width: 900px){ .foot-grid{ grid-template-columns:1fr 1fr; } }
@media (max-width: 560px){ .foot-grid{ grid-template-columns:1fr; } }

/* The footer carries the real stacked lockup. It must be the *dark-surface*
   artwork (maps-logo-stack-dark.png), whose tagline is set in white — the
   light-surface version's tagline is black and vanishes against ink-950. */
.foot-lockup{
  width:auto; height:auto;
  max-width:min(230px, 60%);
  margin-bottom:20px;
}
.sitefoot p{ color: var(--stone-300); font-size:15px; line-height:1.6; margin:0 0 12px; }
.sitefoot h3{
  font-family:var(--font-display); font-weight:800; text-transform:uppercase;
  font-size:12.5px; letter-spacing:.11em; color: var(--gold-300);
  margin:0 0 14px;
}
.sitefoot ul{ list-style:none; margin:0; padding:0; }
.sitefoot li{ margin-bottom:5px; }
/* Footer links are stacked navigation, not prose, so each one is its own
   touch target. At the bare line height they were 19px tall. Their 38px
   centre-to-centre spacing already satisfied WCAG 2.5.8's spacing
   exception, but 19px is still an unkind tap target on a phone, so the
   padding lifts them past the 24px minimum outright. */
.sitefoot a{
  color: var(--paper-050); text-decoration:none; font-size:15px;
  display:inline-block; padding-block:4px;
}
.sitefoot a:hover{ color: var(--gold-300); text-decoration:underline; text-underline-offset:3px; }

.foot-bottom{
  margin-top: clamp(36px,4.5vw,54px); padding-top:24px;
  border-top:1px solid rgba(245,241,232,.16);
}
.foot-bottom p{ font-size:13.5px; color: var(--stone-300); line-height:1.6; }
.foot-bottom strong{ color: var(--paper-050); }

/* ==========================================================================
   REVEAL — light entrance, disabled under reduced-motion by the block above.
   Elements are visible by default and only hidden once JS confirms it will
   reveal them, so content is never trapped invisible if JS fails.
   ========================================================================== */
.js-reveal .reveal{ opacity:0; transform:translateY(14px); }
.js-reveal .reveal.in{
  opacity:1; transform:none;
  transition:opacity .6s var(--ease), transform .6s var(--ease);
}
@media (prefers-reduced-motion: reduce){
  .js-reveal .reveal{ opacity:1; transform:none; }
}


/* ==========================================================================
   MOBILE-ONLY OVERRIDES  (<= 900px)
   Scoped deliberately: these differ from the desktop treatment on purpose.
   ========================================================================== */
@media (max-width: 900px){

  /* --- The home bar is dark blue on mobile ---------------------------------
     On desktop the home bar is light, because it sits on the cover's paper
     grid panel. On mobile it is forced to harbor-900 regardless of what
     site.js computes for `data-surface`, because the mobile brand lockup has
     a white tagline and would disappear on a light bar. Both selectors are
     needed: site.js writes data-surface, and `[data-surface]` rules are the
     ones being overridden. */
  body[data-section="home"] .sitenav,
  body[data-section="home"] .sitenav[data-surface="light"],
  body[data-section="home"] .sitenav[data-surface="dark"]{
    background: rgba(25,58,68,.94);
    -webkit-backdrop-filter:saturate(140%) blur(10px); backdrop-filter:saturate(140%) blur(10px);
    border-bottom-color: rgba(145,187,196,.28);
    color: var(--paper-050);
  }
  body[data-section="home"] .sitenav .nav-toggle{
    box-shadow: 0 1px 6px rgba(0,0,0,.28);
  }

  /* The cover CTAs are NOT overridden here any more. They were briefly
     swapped on mobile (gold Partner / red Read); once Read the case became
     gold that made the pair identical, so both viewports now use the same
     colours: Partner = brick-700, Read the case = gold-500. */
}

/* ==========================================================================
   PRINT
   ========================================================================== */
@media print{
  .sitenav,.navpanel,.navscrim,.nav-toggle,.motif,.gridfrag{ display:none !important; }
  body{ background:#fff; color:#000; font-size:11pt; }
  .band{ padding-block:18pt; background:#fff !important; color:#000 !important; }
  .hero,.pagehero{ background:#fff !important; color:#000 !important; padding-top:18pt; }
  .faq details{ break-inside:avoid; }
  .faq .answer{ display:block !important; }
  a[href^="http"]::after{ content:" (" attr(href) ")"; font-size:9pt; color:#444; }
}
