/* ==========================================================================
   Clover Search Group — Home page
   Direction: "Paper Valley × Field Guide" (DIRECTION_FINAL.md)
   Motion: MOTION_SPEC.md (token sheet below is verbatim from that doc)
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
html, body { overflow-x: hidden; max-width: 100%; }

:root {
  /* ---- FIXED palette (DIRECTIONS_v2.md "What is FIXED") ---- */
  --green-deep: #1C4A2E;
  --green-mid: #2D6A4F;
  --green-soft: #52B788;
  --green-pale: #EAF4EE;
  --gold: #C9A84C;
  --gold-rgb: 201, 168, 76; /* Brand v2 (2026-08-22): raw triplet for the gold hairline dividers (rgba(var(--gold-rgb),.4)) — same derive-from-token pattern as --cream-rgb below */
  --cream: #F5F0E8;
  --cream-rgb: 245, 240, 232; /* raw triplet so rgba() surfaces (e.g. the nav) derive from the token instead of duplicating it numerically (review C, nit 1) */
  --parchment: #EDE8DF;
  --rule: #D5CFC4;
  --charcoal: #2A2A2A;
  --ink: #0C0F14;
  --white: #FFFFFF;
  --error: #D64545;
  --error-bg: #FFF5F5;

  /* ---- Type flip (2026-08-23, design-lead): Cormorant + Bricolage Grotesque
     retired in favor of one bold slab family carrying both display roles —
     evidence in FONTSINUSE_RESEARCH.md, where "one confident display face +
     a quiet sans" is the repeated pairing across agricultural/illustrated
     brands (Atlas Farm, Vantage Grazing, Ferme Poliveau) so the paper-cut
     artwork stays the star instead of competing with a second display face.
     Display = Bitter 800 for H1/road-sign headline, 700 for H2/H3, italic
     500 only where an italic is actually needed (.tagline-quote); Badge =
     Bitter also (badges/patches/ribbons/buttons/nav labels/eyebrows —
     individual components keep their own existing 700/800 weight choice,
     both still loaded); Body = Instrument Sans, unchanged. Three named
     roles still means any future swap is a token edit, not a
     find-and-replace. ---- */
  --font-display: 'Bitter', Georgia, 'Times New Roman', serif;
  --font-badge: 'Bitter', 'Instrument Sans', sans-serif;
  --font-body: 'Instrument Sans', -apple-system, BlinkMacSystemFont, sans-serif;

  /* ---- MOTION_SPEC.md token sheet (verbatim) ---- */
  --ease-snap: cubic-bezier(0.16, 1, 0.3, 1);   /* #1, #4 */
  --ease-print: cubic-bezier(0.22, 1, 0.36, 1); /* #3 */
  --t-entry: .8s;  --t-press: .1s;  --t-reveal: 1.2s;  --t-hover: .4s;  --stagger: .05s;
  --shadow-hover: 0 20px 40px rgba(12,15,20,.04);
  --accent-motion: #52B788;

  /* Round 7 (2026-08-23), WO-D item 1: layered paper shadows (refero lineage
     -- Craft Docs' layered-shadow/mounted-clipping language). Replaces
     several single-source shadows site-wide with a 3-layer stack (a wide,
     near-invisible ambient layer + a mid falloff + a tight contact shadow)
     so floating "paper" elements read as physically sitting above the page
     instead of having a flat drop-shadow pasted under them. */
  --shadow-paper: 0 50px 40px rgba(28,42,30,.01), 0 20px 40px rgba(28,42,30,.05), 0 3px 10px rgba(28,42,30,.08);
  --shadow-paper-hover: 0 60px 50px rgba(28,42,30,.02), 0 26px 46px rgba(28,42,30,.07), 0 5px 14px rgba(28,42,30,.11);

  /* `--d99-win-ratio` (Round 10's windshield aspect-ratio token) is RETIRED,
     first by WO-12 (Round 11, 2026-08-24: the takeover stage became the
     viewport itself, no windshield box left to give an aspect ratio to),
     and now doubly moot under WO-15 (same day: the takeover itself is
     retired -- Chairman live verdict, "the journey doesnt work at all").
     No successor token in either case; the journey art is a plain static
     panel now (see the `.route2-*` block below), no scroll mechanism at
     all. This comment stays as the historical record of the retirement. */

  /* Round 8 (2026-08-23), WO-A: sun-ray colors, sampled directly off each
     with-rays reference master (p1-diorama-v4d2.png / -dawn / -dusk) --
     palette-tokens-only law, so these are named :root tokens like every
     other color even though they're only ever consumed via --sun-ray-color
     (set per data-valley state, see the Opener section below). */
  --sun-ray-day: #D4AB6E;
  --sun-ray-dawn: #F4CE9B;
  --sun-ray-dusk: #C58035;

  /* ---- layout chrome ---- */
  --max: 1200px;
  --radius-lg: 40px;
  --radius-card: 24px;
  --gap-section: 96px;

  /* ---- type scale (review fix 17 — new rules are written against this;
     existing declarations are a larger retrofit left for a follow-up pass,
     see BUILD_NOTES) ---- */
  --fs-xs: 12px;  --fs-sm: 14px;  --fs-base: 16px;  --fs-lg: 19px;
  --fs-xl: 28px;  --fs-2xl: 38px;  --fs-3xl: 54px;

  /* ---- spacing scale (review fix 18 — same scope note as above) ---- */
  --s1: 8px;  --s2: 16px;  --s3: 24px;  --s4: 32px;
  --s5: 48px; --s6: 64px;  --s7: 96px;  --s8: 128px;
}

body {
  font-family: var(--font-body);
  background: var(--cream);
  color: var(--charcoal);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
button { font-family: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700; /* type flip 2026-08-23: explicit H2/H3 baseline weight
    (Bitter 700) -- .road-sign-headline and .section-title override to 800
    for the two true H1 roles (Home/Employers/Candidates hero + About/thanks
    page intro), everything else (bare <h2>/<h3> — market-col labels, crm
    form headers, deep-link section headings) inherits this 700 as-is */
  color: var(--ink);
  text-wrap: balance;
  line-height: 1.15; /* kept from Brand v2 -- still clears Bitter's slab
    ascenders/descenders with room to spare; re-verified against the
    print-reveal clip requirement below (needs >=1.12) */
}

/* Brand v2: italic taglines/quotes set in the display face, per REFERO
   reconciliation ("italic 500 for taglines/eyebrow quotes"). */
.tagline-quote {
  font-family: var(--font-display); font-style: italic; font-weight: 500;
}

p { max-width: 68ch; }

.tabular { font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; padding: 0; margin: -1px;
}

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible { /* review fix F4 (HIGH, WCAG 2.4.7): select was missing entirely */
  /* review fix 6: gold outline measured 2.01:1 on cream (needs 3:1) — green-deep
     clears 8.95:1+ on every surface the ring appears against on this page */
  outline: 3px solid var(--green-deep);
  outline-offset: 3px;
  border-radius: 4px;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 32px; }

section { padding: var(--gap-section) 0; }
section[id] { scroll-margin-top: 100px; } /* Chairman cuts 2026-08-23: was 110px to clear the fixed nav plus the geography strip beneath it; that strip is now removed entirely, re-measured against the nav pill alone (bottom edge y~82.6 @1280) for #practices/#markets/etc deep links (nav/footer anchors, _redirects targets) */
/* Brand v2: gold hairline (1px, 40% opacity) replaces the plain --rule
   divider between major page sections -- a small but repeated brand cue
   the Chairman asked back in. Card/component borders elsewhere (badge
   cards, folder tabs, the nav pill, footer sub-dividers) intentionally
   keep --rule; this only touches the top-level section seam. */
section + section { border-top: 1px solid rgba(var(--gold-rgb), .4); }
section.no-rule + section, section.no-rule { border-top: none; }

/* WO_design-recal-2026-08-25 item 2: `.eyebrow` (kicker + gold dash) is
   retired site-wide -- book-band's instance is deleted outright (see
   .book-band-eyebrow's old rule, removed), and the two remaining genuine
   category-label uses (the Close-embed letterhead, the two thanks-page
   status announcements) move to this plainer device: small-caps Bitter,
   no dash ornament. Renamed rather than left as a hidden/unused class so
   `.eyebrow` reads zero everywhere, per the WO's own gate language. */
.label-kicker {
  display: inline-flex; align-items: center; /* kept flex (no ::before child
    left to align, but the thanks pages' inline justify-content:center
    override still relies on this being a flex container) */
  font-family: var(--font-display); font-weight: 600; font-variant: small-caps;
  letter-spacing: .03em; color: var(--green-mid); margin-bottom: 18px;
}

.section-title {
  /* Type flip 2026-08-23: this is the site's other true H1 (About's own
     page intro, both thanks pages) as well as every other page's section
     H2s -- treated as the "H1" bold-slab tier alongside .road-sign-headline
     (both get Bitter 800), sized differently because of where each one
     lives: road-sign-headline is boxed inside a compact ~560-620px paper
     panel, this one runs full-width in normal flow and can afford to be
     the bigger, bolder headline. Bitter sets wider than Cormorant, so the
     old 3.6vw/44px ceiling was retuned against the new face rather than
     kept as a hangover number: 5.6vw lands the clamp right at its 72px
     cap at a 1280px viewport (5.6% x 1280 = 71.68px), matching the "H1
     clamp max 72px at 1280" target exactly.

     WO_design-recal-2026-08-25 item 2: desktop max down one step (72px ->
     64px, the clamp's vw factor retuned so it still lands exactly on the
     cap at 1280 -- 5% x 1280 = 64px) now that the headline carries the
     section alone (no chip/rule/dot stack above it any more) -- scale does
     the work ornament used to. Single ink color only (var(--ink), inherited
     from the global h1-h4 rule below -- the old two-tone `em` trick is
     retired, see .section-title em just below). */
  font-size: clamp(32px, 5vw, 64px); font-weight: 800; margin-bottom: 16px;
}
/* Two-tone `em` color trick retired (WO_design-recal-2026-08-25 item 2) --
   single-ink headlines now; `em` keeps its non-italic slab treatment (still
   marked up as emphasis for a11y) but no longer shifts color. Opt-in
   key-word emphasis, at most one word per page, uses .gold-swatch instead
   (applied in markup only where a title genuinely calls for it). */
.section-title em { font-style: normal; }
.gold-swatch {
  background: var(--gold); color: var(--green-deep);
  padding: .04em .18em; border-radius: 3px;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
  font-style: normal;
}
/* WO_design-recal-2026-08-25 item 2: "Ledes" spec -- Instrument Sans 400
   upright (never italic), 17px, --charcoal, no dimming opacity (the old
   .82 was part of the retired boilerplate's quieter-secondary-text
   convention; single full-strength ink now, same as the headline above
   it). max-width tightened 62ch -> 52ch per the WO's own number. */
.section-desc { font-size: 17px; color: var(--charcoal); line-height: 1.65; max-width: 52ch; }

/* -----------------------------------------------------------------------
   MindMarket print-reveal on section headlines (#3)
   Review fix 11: the previous single inline `.pr-text` span clip-path
   resolved against the union bbox of every wrapped line, so multi-line
   headlines revealed in *reverse* reading order. Replaced with a per-line
   mask: each `.pr-line` is an overflow:hidden box; its inner span sits
   translateY(100%) (pushed below its own mask) and rises into place, so
   each logical line genuinely reveals bottom-to-top on its own. The
   IntersectionObserver still watches the outer (unclipped) `.print-reveal`
   heading — that architecture was correct and is unchanged.
   `.js` gate (review fix 8): with JS disabled/broken, `document.
   documentElement` never gets the `.js` class, so these selectors never
   match and every line is visible in its natural, untransformed state.
   ----------------------------------------------------------------------- */
.print-reveal .pr-line {
  display: block; overflow: hidden;
  /* Type flip 2026-08-23: re-verified this still holds for Bitter -- a
     slab serif's descenders (g/y/p/q) sit close enough to the line-box
     edge that the bottom-to-top mask reveal could clip one mid-transition
     without this buffer. The padding gives the glyph room inside the
     hidden overflow box; the matching negative margin keeps the next
     .pr-line's baseline position unchanged. Combined with the inherited
     heading line-height of 1.15 (>= the 1.12 floor checked live in-browser
     this round), no clipping was observed on any print-reveal headline at
     1280/768/390. */
  padding-bottom: 0.15em; margin-bottom: -0.15em;
}
.js .print-reveal .pr-line > span {
  display: block;
  transform: translateY(100%);
  transition: transform var(--t-reveal) var(--ease-print);
}
.print-reveal.in-view .pr-line > span { transform: translateY(0); }
.print-reveal .pr-line:nth-child(2) > span { transition-delay: .08s; }
.print-reveal .pr-line:nth-child(3) > span { transition-delay: .16s; }

/* -----------------------------------------------------------------------
   Generic fade-up reveal (DIRECTIONS_v2 fixed motion vocabulary)
   Review fix 2: the positional transform some elements need at rest (e.g.
   `.owner-patch`'s rotate) now lives in `--base-transform`, which this rule
   composes with rather than replaces — so revealing an element can never
   clobber its own static position/rotation. Declaring elements set only
   `--base-transform`, never `transform`, directly.
   ----------------------------------------------------------------------- */
.js .fade-up {
  opacity: 0; transform: var(--base-transform, none) translateY(18px);
  transition: opacity .65s ease, transform .65s ease;
}
.fade-up.in-view { opacity: 1; transform: var(--base-transform, none); }

@media (prefers-reduced-motion: reduce) {
  .js .print-reveal .pr-line > span { transition: transform .01s linear !important; transform: translateY(0) !important; }
  .js .fade-up { transition: opacity .01s linear !important; transform: var(--base-transform, none) !important; }
  .js .clay-card { transition: opacity .01s linear !important; transform: var(--base-transform, none) !important; }
  html { scroll-behavior: auto; } /* review fix 13 — smooth-scroll is a vestibular trigger */
  * { animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
  .marquee-track { animation: none !important; }
  .parallax-el { transform: none !important; }
  .mobile-nav { transition: opacity .01s linear !important; transform: none !important; }
}

/* -----------------------------------------------------------------------
   Clay Surface Transition — page entry (#1)
   Per Chairman/refero review: the shell no longer animates as one block.
   Every card-like element (.clay-card) animates individually, in groups
   scoped to its own grid (review fix 12 — see js/site.js initClayCards),
   each with a --stagger-delay capped at 5 steps of .05s within its group.
   Cards already on-screen at load animate immediately; cards below the
   fold are handed to an IntersectionObserver instead, so the entry motion
   plays when a visitor actually scrolls to them rather than silently
   finishing off-screen (review fix 12).
   ----------------------------------------------------------------------- */
.page-shell { border-radius: var(--radius-lg); }

.js .clay-card {
  opacity: 0;
  /* review fix 2: compose with --base-transform (a card's own static
     position/rotation, e.g. .map-patch's translate(-50%,-50%) or
     .owner-patch's rotate(6deg)) instead of overwriting it, so the entry
     and settled states below can never clobber layout-critical transforms. */
  transform: var(--base-transform, none) translateY(30px) scale(.98);
}
/* NOTE: many card types (.badge-card, .proof-item, .folder-tab, .map-patch)
   declare their own single-class `transition` for hover. A `transition`
   declaration is never merged across selectors — the winning rule replaces
   the whole property list — so the entry/settled states below are bumped
   to two-class specificity (via :not()/.entered) to reliably win over
   those single-class hover rules regardless of stylesheet order. */
.js .clay-card:not(.entered) {
  transition: opacity var(--t-entry) var(--ease-snap), transform var(--t-entry) var(--ease-snap);
  transition-delay: var(--stagger-delay, 0s);
}
/* WO-D item 1: the shared ambient paper shadow for every settled clay-card
   (badge cards, folder tabs, kearney cards, panels, pills, the book band...).
   Components named individually below (road-sign, nav, crm-panel, fee-note,
   folder-tab) either aren't .clay-card elements or get an explicit hover
   pairing on top of this rest-state shadow. */
.clay-card.is-ready { opacity: 1; transform: var(--base-transform, none); box-shadow: var(--shadow-paper); }

/* Once a card's entry transition has finished, hand transform back to a
   faster, hover/tilt-appropriate duration. */
.js .clay-card.entered {
  transition: opacity var(--t-entry) var(--ease-snap), transform var(--t-hover) var(--ease-snap), border-color var(--t-hover) var(--ease-snap), box-shadow var(--t-hover) var(--ease-snap), filter var(--t-hover) var(--ease-snap);
}

/* -----------------------------------------------------------------------
   Skeleton pulse (#5) — image slots before load
   ----------------------------------------------------------------------- */
.img-slot { position: relative; background: var(--parchment); overflow: hidden; border-radius: var(--radius-card); }
.img-slot::before {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(45deg, transparent 35%, rgba(255,255,255,.55) 50%, transparent 65%);
  background-size: 200% 200%;
  animation: pulse-shimmer 1.6s ease-in-out infinite;
  opacity: 1; transition: opacity .3s ease;
}
.img-slot.is-loaded::before { opacity: 0; }
@keyframes pulse-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ==========================================================================
   Nav
   ========================================================================== */
.skip-link {
  position: absolute; left: var(--s2); top: -60px; z-index: 300;
  background: var(--green-deep); color: var(--white); padding: var(--s2) var(--s3);
  border-radius: 999px; text-decoration: none; font-weight: 700; font-size: var(--fs-sm);
  transition: top .2s ease;
}
.skip-link:focus { top: var(--s2); }

.nav-outer { position: fixed; top: 18px; left: 0; right: 0; z-index: 200; display: flex; justify-content: center; padding: 0 20px; }
.nav {
  width: 100%; max-width: 980px;
  display: flex; align-items: center; justify-content: space-between;
  background: rgba(var(--cream-rgb), .9); /* review C nit 1 — derives from the token instead of duplicating it */
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 10px 12px 10px 20px;
  box-shadow: var(--shadow-paper); /* WO-D item 1: layered paper shadow, was a single-source 0 8px 24px */
}
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; min-width: 0; }
.brand img { width: 30px; height: 30px; flex-shrink: 0; }
.brand-word {
  font-family: var(--font-badge); font-weight: 800; font-size: 16px;
  color: var(--green-deep); letter-spacing: -0.01em; white-space: nowrap; /* review fix 3 */
}
.nav-links { display: flex; align-items: center; gap: 4px; list-style: none; }
.nav-links a {
  display: inline-block; padding: 10px 14px; border-radius: 999px;
  font-family: var(--font-badge); /* Brand v2: nav labels are a "badge" use */
  font-size: 13px; font-weight: 500; text-decoration: none; color: var(--charcoal);
  transition: background .2s ease, color .2s ease;
}
.nav-links a:hover { background: var(--green-pale); color: var(--green-deep); }
.nav-links a[aria-current="page"] { background: var(--green-deep); color: var(--cream); } /* review fix F9 (LOW): no active-page nav state existed anywhere; REFERO specifies this exact treatment */
.nav-burger {
  display: none; width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--rule);
  background: var(--white); cursor: pointer; align-items: center; justify-content: center; flex-direction: column; gap: 4px;
}
.nav-burger span { width: 16px; height: 2px; background: var(--green-deep); border-radius: 2px; transition: transform .2s ease, opacity .2s ease; }
.nav-burger.is-open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger.is-open span:nth-child(2) { opacity: 0; }
.nav-burger.is-open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.mobile-nav {
  position: fixed; inset: 0; z-index: 199; background: var(--green-deep);
  display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 8px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(28px);
  /* review fix F9 (LOW): was a .28s opacity-only fade; REFERO_COMPONENTS
     specifies a full-screen parchment/green sheet that "slides up .5s
     cubic-bezier(.16,1,.3,1)" -- now a real slide-up using the site's own
     --ease-snap token, not just a fade. visibility still flips only after
     the close transition finishes (review fix 14, unchanged). */
  transition: opacity .5s var(--ease-snap), transform .5s var(--ease-snap), visibility 0s linear .5s;
}
.mobile-nav.is-open {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
  transition: opacity .5s var(--ease-snap), transform .5s var(--ease-snap), visibility 0s linear 0s;
}
.mobile-nav-close {
  /* review fix F9 (LOW): REFERO calls for a close button top-right on the
     mobile sheet; paired with Escape-to-close + a focus trap in site.js. */
  position: absolute; top: 22px; right: 22px; z-index: 1;
  width: 44px; height: 44px; border-radius: 50%;
  background: transparent; border: 1.5px solid rgba(255,255,255,.4);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: border-color .2s ease;
}
.mobile-nav-close:hover { border-color: var(--gold); }
.mobile-nav-close svg { width: 16px; height: 16px; }
.mobile-nav a {
  font-family: var(--font-badge); font-size: 28px; font-weight: 800;
  color: rgba(255,255,255,.9); text-decoration: none; padding: 12px 0;
}
.mobile-nav a:hover { color: var(--gold); }
/* Round 9 B3 fix: the global :focus-visible ring is green-deep (line ~134),
   and .mobile-nav's own background is also green-deep -- a 1:1 ring-on-
   background contrast, invisible to keyboard users tabbing the sheet.
   Cream is the sheet's own link/text color family and reads clearly against
   green-deep (computed: passes well above 3:1 non-text contrast). */
.mobile-nav a:focus-visible, .mobile-nav button:focus-visible { outline-color: var(--cream); }
.mobile-nav a.mobile-nav-cta {
  /* review fix F9 (LOW): was ".mobile-nav-cta" alone (0,1,0), which never won
     over ".mobile-nav a" (0,1,1) -- the mobile booking CTA was visually
     identical to the plain nav links. Scoped up to (0,1,1)+ specificity and
     given the sticker-pill treatment DIRECTION_FINAL:17 asks for instead of
     just a color swap. */
  color: var(--ink); background: var(--gold); border: 2px solid var(--ink);
  border-radius: 999px; padding: 14px 28px; margin-top: 12px;
  box-shadow: 0 4px 0 var(--green-deep);
}

/* ==========================================================================
   Sticker buttons (primary + outline) — Duolingo press (#2)
   ========================================================================== */
/* "duo-btn" cap pattern: rests raised on a solid bottom cap; hover lifts
   and grows the cap; active pushes the button down into the cap (0). */
.btn-sticker {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-badge); font-weight: 700; font-size: 14px;
  text-transform: uppercase; letter-spacing: .04em;
  background: var(--gold); color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 999px;
  padding: 14px 26px;
  text-decoration: none; cursor: pointer;
  box-shadow: 0 4px 0 var(--green-deep);
  transform: translateY(0);
  transition: transform var(--t-press) ease-in-out, box-shadow var(--t-press) ease-in-out;
}
.btn-sticker:hover { transform: translateY(-2px); box-shadow: 0 6px 0 var(--green-deep); }
.btn-sticker:active { transform: translateY(4px); box-shadow: 0 0 0 var(--green-deep); }

/* review fix F9 (LOW): MOTION_SPEC R5's form-submit pulse was unimplemented
   -- js/site.js adds this on a form's own submit button the instant a
   .crm-form is submitted (the page navigates away on success, so this only
   ever needs to appear, never to be removed). Reuses the same 45-degree
   shimmer keyframe the image-slot skeleton pulse already defined, per
   R5's own "not a spinner" instruction. */
.btn-sticker.is-submitting { position: relative; overflow: hidden; pointer-events: none; }
.btn-sticker.is-submitting::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(45deg, transparent 35%, rgba(255,255,255,.55) 50%, transparent 65%);
  background-size: 200% 200%;
  animation: pulse-shimmer 1.1s ease-in-out infinite;
}

.btn-sticker-outline {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-badge); font-weight: 700; font-size: 14px;
  text-transform: uppercase; letter-spacing: .04em;
  background: transparent; color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 999px;
  padding: 14px 26px;
  text-decoration: none; cursor: pointer;
  box-shadow: 0 2px 0 var(--ink);
  transform: translateY(0);
  transition: transform var(--t-press) ease-in-out, box-shadow var(--t-press) ease-in-out, background var(--t-hover) ease;
}
.btn-sticker-outline:hover { transform: translateY(-2px); box-shadow: 0 4px 0 var(--ink); background: var(--green-pale); }
.btn-sticker-outline:active { transform: translateY(4px); box-shadow: 0 0 0 var(--ink); }

.nav-cta { padding: 10px 20px; font-size: 12px; } /* review fix 20 — was a hardcoded inline style */

.btn-sticker svg, .btn-sticker-outline svg { transition: transform .2s ease; }
.btn-sticker:hover svg, .btn-sticker-outline:hover svg { transform: translateX(3px); }

/* ==========================================================================
   1. Opener / Panorama
   ========================================================================== */
.opener {
  position: relative; overflow: hidden;
  height: 100vh; max-height: 720px; min-height: 560px;
  margin-top: 0; border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  border-bottom: 1px solid rgba(var(--gold-rgb), .4); /* Brand v2 gold hairline */
}
/* Chairman fix 2026-08-25 (FIX 1): .opener-media also carries the generic
   .img-slot class (for the loading-shimmer skeleton), which sets its own
   `border-radius: var(--radius-card)` (24px) on ALL FOUR corners. Because
   .opener-media is absolutely positioned at inset:0 -- pixel-identical to
   its .opener parent's own box -- that 24px radius rendered independently
   of .opener's correct `0 0 40px 40px` (top-square) radius: the top
   corners, which .opener leaves perfectly square, were getting rounded
   anyway by this child's own clip, reading as the hero diorama's rounded
   corners cutting against the viewport edge the Chairman flagged live.
   (It also silently shrank the intended 40px BOTTOM radius down to 24px,
   since two same-size nested overflow:hidden boxes render the smaller/
   more-restrictive radius of the two.) `border-radius: inherit` makes this
   element always track whatever radius .opener itself has -- 0 at top,
   var(--radius-lg) at bottom, on every page/breakpoint that reuses this
   opener/page-opener/opener-media trio -- instead of carrying a second,
   independent radius value that can drift out of sync. Verified via live
   getBoundingClientRect + getComputedStyle, not computed-style alone: see
   BUILD_NOTES "Hero panel top corners" for the before/after measurements. */
.opener-media { position: absolute; inset: 0; width: 100%; height: 100%; overflow: hidden; border-radius: inherit; }
.opener-media .media-video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transform: translateZ(0);
}
.opener-media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,15,20,.28) 0%, rgba(12,15,20,0) 42%);
}

/* Round 8 (2026-08-23), WO-A: the living opener. The looping video is
   retired (Chairman: visible loop seam) -- replaced by a static
   time-of-day poster (.opener-poster, one of three states swapped by the
   inline valley-pick script in <head>/right after the tag, see index.html)
   plus a rotating inline-SVG ray layer (.sun-rays) sized/positioned in JS
   (initSunOpener, site.js) to sit exactly on the poster's own sun disc at
   any viewport width. */
/* Chairman fix 2026-08-27: `.opener-poster` and `.sun-rays` below are
   BYPASSED for the Home opener, not deleted -- the opener is back on the
   Chairman's own video loop (baked animated sun rays in the footage
   itself), so the `<img class="opener-poster">` + `<svg class="sun-rays">`
   markup these rules target now lives inert inside a <template> in
   index.html (see the HTML comment there) and never renders. `.opener-
   poster` (used by the noscript fallback <img>, which is NOT inside the
   template) still applies live in that one no-JS case. These rules
   themselves are left exactly as they were -- no CSS change needed to
   "turn them off," since there's simply no live `.sun-rays` element for
   them to match right now -- ready to matter again unchanged if a future
   poster-only hero un-bypasses initSunOpener() in js/site.js. */
.opener-poster {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  display: block;
}
.sun-rays {
  position: absolute; top: 0; left: 0; z-index: 1; overflow: visible;
  pointer-events: none;
}
/* Chairman defect (2026-08-25): the ray burst orbited the disc instead of
   spinning in place. Root cause, verified live (see BUILD_NOTES) --
   `transform-origin: center` on an SVG child element defaults to
   `transform-box: view-box`, whose reference box in this engine is
   anchored at LOCAL (0,0) with dimensions taken from the viewBox's width/
   height only -- it does not offset for the viewBox's own min-x/min-y
   (`viewBox="-260 -260 520 520"`). So "center" (50%/50% of the 520x520
   box) resolved to local point (260,260) -- the viewBox's bottom-right
   corner, not (0,0), the true disc/geometry center -- and every rotation
   frame swung the whole ring around that far corner. `transform-box:
   fill-box` makes the reference box the group's own rendered geometry
   (naturally centered on (0,0) since the 24 spokes are symmetric),
   sidestepping the viewBox-offset bug entirely; this is the standard
   fix for "rotate an SVG shape about its own center" and needs no magic
   pixel constant that would drift if the ray geometry is ever re-tuned.

   Re-verified 2026-08-25 (Chairman still reported orbiting after this fix
   was already in this file): reproduced live in BOTH the raw build and the
   built home-artifact.html via Web-Animations-API `anim.currentTime` seeks
   across the full 110s cycle + getBoundingClientRect() centroid sampling
   (this session's Browser pane wasn't compositing frames, so seeking the
   animation's currentTime directly stood in for wall-clock playback).
   Raw build: centroid pinned at (179.97, 125.03)px across 6 timestamps
   spanning a full rotation, transform-box resolved to `fill-box` as
   written here -- this rule was never the bug. The actual defect was that
   `company-os\engagements\2026-08-21-website-overhaul\home-artifact.html`
   (the file a reviewer would actually open) had been generated by
   `make_artifacts.mjs` at 22:23:05 on 2026-08-24, ten minutes *before*
   this fix was added to this source file at 22:33:33 the same day -- the
   shipped artifact still carried the pre-fix rule (no `transform-box`,
   defaulting to `view-box`), so it still orbited even though this source
   file was already correct. Confirmed by re-simulating the stale rule
   (`transform-box: view-box`) on the regenerated artifact: centroid swung
   from (180,125) to (573,153) to (549,493) and back across the same 6
   timestamps -- the exact defect, reproduced on demand. Fix: regenerate
   the artifact (`node checks/make_artifacts.mjs`) so it picks up this
   already-correct rule; no CSS/JS change was needed. See BUILD_NOTES
   2026-08-25 "Sun-ray orbit -- stale artifact" for the full repro. */
.sun-rays .spokes { transform-box: fill-box; transform-origin: center; animation: sun-spin 110s linear infinite; }
.sun-rays .spokes-main {
  fill: none; stroke: var(--sun-ray-color, var(--sun-ray-day)); stroke-width: 8.5; stroke-linecap: round;
}
.sun-rays .spokes-shadow {
  fill: none; stroke: rgba(12,15,20,.12); stroke-width: 8.5; stroke-linecap: round;
  transform: translate(1.8px, 3.6px);
}
@keyframes sun-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .sun-rays .spokes { animation: none; } }
/* Per-state ray color, sampled off each with-rays reference master (see
   BUILD_NOTES Round 8 for the pixel samples): dawn's low-saturation blush
   gold, day's warm mid gold, dusk's deep amber. Default (no attribute yet,
   or JS-disabled since .sun-rays is hidden via <noscript> anyway) is day. */
html[data-valley="dawn"] { --sun-ray-color: var(--sun-ray-dawn); }
html[data-valley="day"]  { --sun-ray-color: var(--sun-ray-day); }
html[data-valley="dusk"] { --sun-ray-color: var(--sun-ray-dusk); }

/* WO-D item 3 (2026-08-23): torn cream paper edge, Home opener only. Lives
   inside .opener-media (not .opener) so it always anchors to the artwork's
   own bottom edge on both the desktop full-bleed layout and the mobile
   stacked layout (where .opener itself grows taller than the artwork once
   .road-sign drops into normal flow) -- see BUILD_NOTES for why .opener's
   own box isn't a safe anchor here. z-index:1 lifts it above
   .opener-media::after's darkening gradient (which has no z-index of its
   own), so the torn edge reads as pure cream, not gradient-muddied. */
.deckle-edge {
  position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 28px;
  z-index: 1; display: block;
}
.deckle-edge path { fill: var(--cream); }

/* Brand v2 "sticker" mark variant — circular: cream disc, green-deep border,
   layered paper shadow. Reused as the Home candidates-strip corner badge
   (below) and available for other pages.
   Round 10 fix pass, WO-9.5 (taste (a), RULED): the 4px solid white halo
   ring plus the hard 4px 4px 0 offset shadow are GONE, 3 instances (Home x2
   + About x1) — a layered soft shadow reads as *paper*; a hard white ring
   reads as *pasted-on sticker*, and it was clashing with the now-haloless
   .market-pill 800px up the same page (WO-2). Border flips ink -> green-deep
   to match: one chip vocabulary site-wide (cream fill, 2px green-deep
   border, --shadow-paper). Alternating rest-rotation + straighten-on-hover
   is unchanged — that's the sticker-sheet feel and it survives without the
   ring. */
.mark-sticker {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--cream); border: 2px solid var(--green-deep);
  box-shadow: var(--shadow-paper);
  display: flex; align-items: center; justify-content: center;
}
.mark-sticker img { width: 62%; height: 62%; object-fit: contain; }

/* paper road-sign panel */
.road-sign {
  position: absolute; left: 24px; bottom: 24px; z-index: 3;
  max-width: 560px; width: calc(100% - 48px);
  background: var(--cream);
  border: 2px solid var(--ink);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-paper); /* WO-D item 1 (2026-08-23): layered paper shadow replaces the prior hard 6px 6px 0 offset -- border above is unchanged, so the panel still reads as a cut paper edge, just grounded with the site-wide shadow system instead of a one-off flat offset */
  padding: 34px 34px 30px;
}
/* Chairman fix 2026-08-23 (round 3): the gold circle "rivet" decoration on
   .road-sign::before is removed site-wide, no replacement — was a rule, not
   markup, so this single deletion clears it from every page (Home, Employers,
   Candidates) that renders a .road-sign panel. */
.road-sign-headline {
  /* Type flip 2026-08-23: Bitter 800, the site's other bold-slab H1 tier
     (see .section-title). Sized smaller and to a tighter vw curve than
     .section-title on purpose -- this headline is boxed inside the
     ~560-620px-wide paper road-sign panel (not full-width flow), and
     Bitter's wider-set letterforms need more room to breathe at a given
     size than Cormorant did, so the explicit design-lead target
     (26px/3.2vw/40px) replaces the old 24/3.4vw/38 numbers rather than
     just scaling them. */
  font-size: clamp(26px, 3.2vw, 40px); font-weight: 800; margin-bottom: 14px;
}
.road-sign-sub {
  font-size: 15px; color: var(--charcoal); opacity: .82; margin-bottom: 22px; max-width: 46ch;
}
/* Chairman fix 2026-08-23: logo-anchor pass -- brand under-present
   site-wide. Anchor #2 of 4: mark sits subtly at the top of the road-sign
   panel, above the headline, on Home/Employers/Candidates (every page that
   renders this panel) so the first screen carries the brand. Plain flat
   mark, no sticker-circle treatment -- deliberately quieter than the badge/
   footer marks so it doesn't compete with the headline directly below it. */
.road-sign-mark { width: 40px; height: 40px; display: block; margin-bottom: 16px; }

/* ==========================================================================
   2. Practice areas — badge grid
   ========================================================================== */
.badge-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.badge-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 14px;
  background: var(--white); border: 1px solid var(--rule); border-radius: var(--radius-card);
  padding: 28px 26px; text-decoration: none; color: inherit;
  transition: border-color var(--t-hover) var(--ease-snap), box-shadow var(--t-hover) var(--ease-snap), transform var(--t-hover) var(--ease-snap);
}
.badge-card:hover { border-color: var(--accent-motion); box-shadow: var(--shadow-hover); transform: translateY(-4px); }
/* review fix 10 / design-lead B: the badge is a *patch*, not an icon inside
   a disc inside a card — the green-pale circle fought the sticker's own
   white halo (review criterion B). Alternating rest-rotation + straighten
   on hover gives the "loose sticker sheet" feel Direction C asks for. */
/* Round 10 fix pass, WO-9.5 (taste (a), RULED): white halo ring gone, 6
   instances (Home only) -- see .mark-sticker above for the paper-vs-sticker
   argument, identical here. Border flips ink -> green-deep to match. */
.badge-icon {
  width: 96px; height: 96px; display: flex; align-items: center; justify-content: center;
  background: var(--cream); border: 2px solid var(--green-deep); border-radius: 16px;
  box-shadow: var(--shadow-paper);
  flex-shrink: 0;
  transition: transform var(--t-hover) var(--ease-snap);
}
.badge-icon img { width: 84%; height: 84%; object-fit: contain; }
.badge-card:nth-child(odd) .badge-icon { transform: rotate(-2deg); }
.badge-card:nth-child(even) .badge-icon { transform: rotate(1.5deg); }
.badge-card:hover .badge-icon { transform: rotate(0deg); }
.badge-name { font-family: var(--font-badge); font-size: 19px; font-weight: 800; }
.badge-desc { font-size: 14px; color: var(--charcoal); opacity: .8; line-height: 1.65; }

/* review fix 16: while js/site.js is actively writing a pointer-tilt
   transform on this card, shorten just the transform duration so the tilt
   tracks the cursor at ~.12s (dampened, not laggy) while opacity / border /
   box-shadow keep their normal .4s hover pace. (0,2,0) beats .clay-card's
   (0,2,0) rule of the same specificity by appearing later in the file. */
.badge-card.is-tilting { transition-duration: .8s, .12s, .4s, .4s, .4s; }

/* ==========================================================================
   3. Markets — paper map
   ========================================================================== */
.markets-map-wrap {
  /* Chairman fix 2026-08-23: was `overflow: hidden` on this wrapper, which
     clipped .map-patch--bay's fixed-pixel-width pill mid-label once its
     re-plotted, geographically-correct west-edge position (left:8%) put it
     within about 20-40px of the box edge on a narrow viewport (the pill's
     own width doesn't scale down with the image, so the same % that clears
     comfortably at 1280 can clip at 390 -- measured live, ~24px of "BAY"
     cut off at 390 before this fix). Moved the corner-rounding to the img
     itself (`border-radius: inherit`) and switched this wrapper to
     `overflow: visible` so a patch can safely sit close to -- or slightly
     over -- the image's edge without ever being clipped, at any viewport.
     The wrapper's own 1px border still renders rounded; only content
     clipping changed. */
  position: relative; border-radius: var(--radius-card); overflow: visible; border: 1px solid var(--rule);
  /* Round 11, WO-11b (2026-08-24): Chairman "map cropped tighter" -- he
     declined art regeneration, so this is CSS-only. p2-valley-map.webp is
     1915x1372 (aspect 1.3958:1); this box is pinned to 16:10 (1.6:1), wider
     than the source, so object-fit:cover on the child img scales to fill
     WIDTH and crops the excess off the TOP/BOTTOM only -- there is no
     horizontal crop at this aspect, full width is always shown. Confirmed
     the art file itself is untouched: byte-identical (same mtime/hash as
     before this round, see BUILD_NOTES). */
  aspect-ratio: 16 / 10;
}
.markets-map-wrap > img {
  width: 100%; height: 100%; display: block; border-radius: inherit;
  object-fit: cover;
  /* Vertical-only crop math (visible height = 1915 / 1.6 = 1196.875px of
     the source's 1372px, i.e. 175.125px removed total): the three pinned
     landmarks sit at source rows 466 (Sac), 768 (Bay), 960 (Valley) -- all
     within +-380px of a symmetric center crop's kept window
     [87.6px .. 1284.4px], so `center` needed no directional bias to keep
     every landmark and the road convergence in frame. See WO-11c just
     below for why the pill top% values changed but left% did not. */
  object-position: center;
} /* round 5: scoped to the direct-child map image only -- the descendant selector this used to be also matched the nested .map-pill <img> stickers and forced them to 100% width via higher specificity than .map-pill's own width rule */
/* Chairman fix 2026-08-23 (round 6): the three full sticker-pill *images*
   (round 5) were non-uniform -- different aspect ratios (220/121/137px tall
   at the same 480px width), different apparent border weights, wildly
   different icon scales relative to the pill (the Chairman: "sloppy").
   Replaced with ONE CSS pill component so every dimension (border weight,
   radius, halo, icon box, label type) is a shared rule instead of three
   independent illustrations. Just the ICON is kept from each Higgsfield
   sticker -- cropped out via HSV saturation/value thresholding (icon colors
   read as high-saturation/high-value; the cream fill, white halo, and the
   dark-green border+text ink are all low-saturation-or-low-value, so a
   simple S>0.32 & V>0.48 mask isolates tractor+orchard / truss bridge /
   Golden-Gate+bay cleanly without touching the ink or fill -- see
   BUILD_NOTES "Uniform market pills, round 6" for the full method and the
   two anti-aliasing false-positives it took to get there) -- saved to
   assets/icons/icon-valley.webp / icon-sac.webp / icon-bay.webp, alpha
   already baked in, all <=120px. Positions below are unchanged from round
   5 (measured directly off the map.webp: road-convergence node for
   Sacramento, the river/delta braid's west edge for Bay Area, the gap
   between the two diverging roads for Central Valley). */
/* Round 10 (2026-08-23): the 4px solid white halo ring is GONE (Chairman:
   "the white backdrop on the pills doesnt look right"). A pill on the paper
   map is a paper tab lying on the map, so it uses the site-wide layered
   paper shadow (--shadow-paper, Craft Docs lineage) for separation instead
   of a die-cut sticker ring. On green-deep the shadow is invisible and the
   green border vanishes into the ground, so the footer variant swaps to the
   site's gold hairline vocabulary instead (the same rgba(--gold-rgb) line
   weight `.plate-rule` used before its WO_design-recal-2026-08-25 retirement).
   Icon files unchanged. */
.market-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--cream); border: 2px solid var(--green-deep);
  border-radius: 999px; box-shadow: var(--shadow-paper);
  white-space: nowrap; text-decoration: none;
}
.footer-patch { box-shadow: none; border-color: rgba(var(--gold-rgb), .55); }
.market-pill-icon { width: 22px; height: 22px; object-fit: contain; flex-shrink: 0; display: block; }
.market-pill-label {
  font-family: var(--font-badge); font-weight: 700; text-transform: uppercase;
  font-size: 13px; letter-spacing: .02em; color: var(--green-deep);
}

/* Map placement: absolute at the measured map coordinates, alternating tilt
   (unchanged from round 5), fixed 44px height so the three pills read as
   one uniform system regardless of label-text length. */
.map-pill {
  --base-transform: translate(-50%, -50%) rotate(var(--tilt, 0deg));
  position: absolute; height: 44px; padding: 0 18px;
}
.map-pill:hover { --base-transform: translate(-50%, -54%) rotate(var(--tilt, 0deg));
                  box-shadow: var(--shadow-paper-hover); } /* Recruiter's-Hand hover: translateY only, no border -- the pill already draws its own outline; round 10 deepens the shadow with the lift */
/* Round 11, WO-11c (2026-08-24): re-measured against the WO-11b crop above,
   not assumed. top% is a fraction of THIS ELEMENT'S OWN box, and the crop
   changed what that box now shows -- these were "top: 34%/56%/70%" against
   the full uncropped image; the crop keeps source rows [87.6 .. 1284.4] of
   1372 (see WO-11b comment above for the math), so
   new-top% = (orig_top%*1372 - 87.6) / 1196.875 * 100:
     Sac    34% -> row 466.5 -> 31.66%
     Bay    56% -> row 768.3 -> 56.89%
     Valley 70% -> row 960.4 -> 72.94%
   left% is UNCHANGED for all three -- the 16:10 crop only trims top/bottom
   (see WO-11b), the full image width is always shown, so no horizontal
   landmark ever moves. Verified each anchor still lands on its landmark at
   390/1024/1280/1440 (BUILD_NOTES). */
.map-pill--sac { top: 31.66%; left: 50%; --tilt: -2deg; }
.map-pill--bay { top: 56.89%; left: 32%; --tilt: 1.5deg; }
.map-pill--valley { top: 72.94%; left: 50%; --tilt: -2deg; }

.market-legend { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 32px; }
.market-col h3 { font-size: 16px; font-weight: 700; margin-bottom: 10px; color: var(--green-deep); } /* H3 tier -- Bitter 700, matches the shared h1-h4 baseline */
.market-col ul { list-style: none; }
.market-col li {
  font-size: 13px; color: var(--charcoal); opacity: .82; padding: 7px 0;
  border-bottom: 1px solid var(--parchment); display: flex; gap: 8px; align-items: baseline;
}
.market-col li:last-child { border-bottom: none; }
.market-col li::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--green-mid); flex-shrink: 0; transform: translateY(-2px); }

.marquee { margin-top: 44px; overflow: hidden; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 18px 0; }
.marquee-track {
  display: flex; width: max-content; gap: 20px;
  animation: marquee-scroll 40s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
/* Chairman fix 2026-08-25: was a single `.marquee-track span` rule matching
   BOTH the half-duplicate wrapper span AND each per-city span -- the root
   cause of the double-dot bug (see the HTML comment above the markup for
   the seam mechanics). Split into two classes so exactly one level ever
   carries the flex/gap/separator treatment. */
.marquee-group {
  display: flex; align-items: center; gap: 20px; flex-shrink: 0;
}
.marquee-city {
  font-family: var(--font-badge); font-weight: 700; font-size: 15px;
  text-transform: uppercase; letter-spacing: .08em; color: var(--green-mid); white-space: nowrap;
}
/* Sticker separators, replacing the old CSS ::after dot -- paper-cut icons
   already extracted for the market-pill badges (assets/icons/, all 120x96
   canvas, 5:4), shown at a 16px-tall, 20px-wide reading size and cycled
   valley/bay/sac (see the HTML comment for the adjacency math). Decorative
   valley objects, not ornament -- aria-hidden regardless, and the whole
   .marquee container already carries aria-hidden="true" too (it's a
   decorative repeat of copy that's legible elsewhere on the page). */
.marquee-sep { width: 20px; height: 16px; flex-shrink: 0; object-fit: contain; }
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Round 9 L5: the ".folder-row / how we work" tile system (folder-row,
   folder-tab, folder-icon, folder-title, folder-desc) was flagged dead in
   Round 8 (superseded by the Drive Up 99 component) and left in place
   pending a follow-up cleanup pass -- this is that pass. Confirmed zero
   markup references across all 7 pages (grepped before deleting) and
   removed. The one surviving JS reference (site.js's clay-card stagger
   GROUP_SELECTOR, which lists '.folder-row' alongside '.badge-grid' and
   '.kearney-grid') is inert now that no element matches it -- left as-is,
   not worth a separate edit for a no-op selector. */

/* ==========================================================================
   5. The Kearneys
   ========================================================================== */
.kearneys-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.owner-patch {
  --base-transform: rotate(6deg); /* review fix 2 — see .map-patch note above */
  flex-shrink: 0; width: 118px; height: 118px; border-radius: 50%;
  background: var(--green-deep); color: var(--white); border: 2px solid var(--ink);
  display: flex; align-items: center; justify-content: center; text-align: center;
  font-family: var(--font-badge); font-weight: 800; font-size: 13px;
  text-transform: uppercase; letter-spacing: .06em; line-height: 1.4; padding: 10px;
}
/* `.kearney-grid`/`.kearney-card` are About-only now (Home moved to the
   clustered vignette below, round 3) -- `.kearney-frame` (circle avatar),
   its `.paper-offset` green-crescent backing, and `.kearney-role` are fully
   retired site-wide as of round 3 (About dropped them round 2, Home just
   now) and deleted outright rather than left dead. `.kearney-name`/
   `.kearney-bio` stay -- still live on About (name+bio typography) and on
   Home (`.kearney-bio` only, in the new `.kearney-text` column below). */
.kearney-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 48px; margin-top: 48px; }
.kearney-card { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.kearney-name { font-family: var(--font-display); font-size: 24px; font-weight: 700; } /* review fix F5 (MEDIUM): had no font-family at all (inherited --font-body/Instrument Sans, which only ships 400/500 -- the old font-weight:800 was a silent no-op, clamped to 500) */
.kearney-bio { font-size: 14px; color: var(--charcoal); opacity: .85; line-height: 1.7; }
.kearney-bio + .kearney-bio { margin-top: 4px; }

/* ==========================================================================
   6. Candidates strip
   ========================================================================== */
.candidates-strip {
  /* review fix 20 — this element carries .clay-card for its entry motion
     but previously had no card chrome of its own to justify it. */
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); align-items: center;
  background: var(--white); border: 1px solid var(--rule); border-radius: var(--radius-card);
  padding: var(--s5);
}
.candidates-art { position: relative; border-radius: var(--radius-card); border: 1px solid var(--rule); }
.candidates-art img { width: 100%; height: auto; }
/* Brand v2: the sticker mark pinned inside the bottom-right corner, like a
   wax seal on the illustration -- same corner-badge language as the map
   patches. Kept inside the image bounds (not negative-offset) since this
   container inherits .img-slot's overflow:hidden for the skeleton pulse. */
.candidates-badge {
  position: absolute; right: 16px; bottom: 16px; transform: rotate(-6deg);
}
.candidates-copy p { font-size: 16px; opacity: .85; margin-bottom: 26px; line-height: 1.7; }

/* ==========================================================================
   7. Book band
   ========================================================================== */
.book-band {
  position: relative; overflow: hidden;
  background: var(--green-deep); color: var(--white);
  border-radius: var(--radius-lg); padding: 96px 0 0;
  isolation: isolate;
}
/* Chairman fix 2026-08-25 (round 4, item 2): the CTA button overlapped the
   water tower in the farmscape art. Root cause: `.book-band-media` (the
   art band, position:absolute, bottom:0 relative to `.book-band`) is
   TALLER (220px) than `.wrap`'s own bottom padding (190px) reserved for
   it -- so the art's top edge actually sat 30px ABOVE the button's bottom
   edge, overlapping it, instead of starting where the padding ended.
   Fixed by growing the padding past the media height with a real cushion
   (220+30=250) rather than shrinking the art. Mobile has the matching fix
   below (`.book-band-media` is 150px there, not 220). */
.book-band .wrap { position: relative; z-index: 2; text-align: center; padding-bottom: 250px; }
/* Chairman fix 2026-08-23: logo-anchor pass, anchor #4 of 4 -- small cream
   mark before the headline (reused .mark-sticker's cream-disc/ink-border/
   white-halo recipe so it read correctly against the band's solid
   --green-deep background, just scaled down and centered).

   RETIRED WO_design-recal-2026-08-25 item 3 (Metamask refero lineage: put
   the mascot at confident poster scale, integrated with the type, not a
   32px stamp). `.mark-sticker`'s cream-disc/border chrome is dropped here
   -- the new asset already carries its own gold ring baked into the
   render, so a second circular frame around it would double up -- in
   favor of a plain `filter: drop-shadow(...)` for lift, matching the
   codebase's other transparent-art "mounted sticker" convention
   (`.lodi-arch-mount img`, same file, ~line 1145) rather than
   `.mark-sticker`'s box-shadow (which only hugs a rectangular/circular
   box, not this mark's actual clover+ring silhouette). Asset: `assets/
   mark-3d-chunky.webp`, transparent-bg alpha-cut derivative of
   build-assets/mark-3d-chunky-a.png (see BUILD_NOTES 2026-08-25 for the
   a/b crispness comparison and the cut pipeline).

   Chairman fix 2026-08-25 (round 2): 120px/84px read as "way too big and
   blurry" -- shrunk to 56px/44px (a little bigger than the pre-3D-mark
   32px baseline, per his words) and the source derivative was rebuilt at
   112x112 (2x of 56, retina-ready) instead of just being resized down in
   CSS -- see BUILD_NOTES for the rebuild pipeline and blur root-cause.

   Chairman fix 2026-08-25 (round 3, LIVE BUG): the 56px/44px change above
   never actually rendered -- `.book-band-mark` is a `<span>` (inline by
   default) and `width`/`height` do not apply to non-replaced inline boxes
   per spec, so `width: 56px; height: 56px;` here was silently a no-op.
   With no display override, the span also never established a containing
   block for its child, so the img's `width:100%; height:100%` skipped past
   it entirely and resolved against the nearest BLOCK ancestor instead
   (`.book-band .wrap`, ~830-900px wide depending on viewport) -- rendering
   the 112px asset at ~830px, wildly upscaled and pixelated. Confirmed live
   via getBoundingClientRect (830x830px actual box) after `getComputedStyle
   ().width` had misleadingly reported "56px" -- that computed-style value
   is the specified length, not the used/rendered size, for an element
   `width` doesn't apply to; trusting it during the round-2 verification is
   exactly how this shipped unnoticed. Fix: `display: inline-block` --
   makes `width`/`height` apply directly AND gives the img's percentage
   sizing something correct to resolve against; centering still works via
   `.book-band .wrap`'s existing `text-align: center` (auto margins don't
   center inline-block boxes, so the `margin: 0 auto` L/R component here is
   now inert -- kept only for the bottom value, harmless either way). */
/* Chairman fix 2026-08-25 (round 4, item 1): "none of the texts seem to
   line up" -- .book-band-tagline was the one element in this stack with no
   `margin: 0 auto`. It's a <p>, and the sitewide `p { max-width: 68ch; }`
   rule constrains its box to 68ch, which is narrower than .book-band
   .wrap's ~1136px content width -- so the box rendered flush against the
   reset `margin-left/right: 0` (global `* { margin: 0; padding: 0; }`)
   instead of centered. `.wrap`'s own `text-align: center` still centered
   the TEXT *inside* that box, but the box itself sat left, dragging the
   visually-centered text left of the title/sub/CTA's true center axis
   (which all use their own explicit `margin: 0 auto`). Fixed by adding
   `margin: 0 auto` here too, matching every other centered element in this
   stack. Also normalized the vertical rhythm while in here -- the old
   22/14/20/36px steps were arbitrary; now a clean 24/16/24/32px climb
   (tight mark-to-tagline lockup, matching gap up to the headline, a beat
   more before the sub, and the most room before the CTA). */
/* Chairman ruling 2026-08-28: the embossed 3D book-band mark is abandoned --
   every embossed iteration was rejected (round-5 alpha-cut halo, round-6
   ring-continuity SPLIT/NO-GOLD breaks, the same-day seam repair) -- revert
   to the FLAT (non-embossed) clover logo. Asset swapped from
   `assets/mark-3d-chunky.webp` (archived, move-never-delete, see
   BUILD_NOTES) to `assets/mark-flat-band.webp`: a flat, gold-ringed clover
   derived deterministically from the site's own live flat mark
   (`assets/clover-mark.webp`, the nav/footer mark) rather than any render.
   The source mark's clover fill is itself --green-deep -- invisible on this
   band's --green-deep backdrop -- so the leaf fill is recolored to --cream
   via a hue/saturation swap that keeps each pixel's own relative Value
   (preserves the brush-stroke shading instead of flattening it), the same
   deterministic-luminance-remap technique already shipped for
   linkedin-profile-logo-dark.png (see marketing-website/brand_kit/
   README.md). The gold ring is left byte-for-byte untouched -- it already
   reads clearly on --green-deep. No CSS geometry changed here (still
   150px/120px, still inline-block, still drop-shadow for lift); this note
   documents the swap for whoever next opens this rule. See BUILD_NOTES.md
   "Book-band mark: embossed lane retired, flat mark restored" for the
   full derivation, contrast numbers, and gate changes. */
.book-band-mark { display: inline-block; width: 150px; height: 150px; margin: 0 auto 24px; }
.book-band-mark img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  filter: drop-shadow(0 4px 8px rgba(12,15,20,.35));
}
@media (max-width: 767px) {
  .book-band-mark { width: 120px; height: 120px; }
}
.book-band-tagline { color: rgba(255,255,255,.82); font-size: 19px; margin: 0 auto 16px; }
.book-band-title { color: var(--white); font-size: clamp(30px, 4.6vw, 54px); margin: 0 auto 24px; max-width: 16ch; }
.book-band-sub { color: rgba(255,255,255,.72); max-width: 52ch; margin: 0 auto 32px; font-size: 16px; }
.book-band-media {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  height: 220px; overflow: hidden;
}
.book-band-media .media-video {
  position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: bottom;
  transform: translateZ(0);
}
.book-band-media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,15,20,.1), transparent 60%);
}

/* --------------------------------------------------------------------------
   Seamless loop v2 (2026-08-22, evening): Chairman feedback on the crossfade
   double-buffer above was a visible PULSE at every loop point (the cf-scale
   1->1.04 keyframe restarting each cycle) plus blur (the quality pass had
   downscaled the 2212x936 masters to 1920x812). Root-cause fix, not another
   patch: the loop is now baked into the file itself with ffmpeg (xfade the
   last 0.8s into the first 0.8s — see BUILD_NOTES.md "Seamless loop v2" for
   the technique and frame-diff numbers), masters stay at native 2212x936, so
   a single plain `<video autoplay muted loop>` (`.media-video`) is all that
   plays — no second buffered element, no opacity crossfade, no JS-driven
   scale animation to restart/snap. `transform: translateZ(0)` just promotes
   the video to its own compositor layer (a normal perf nicety); nothing
   about the loop boundary triggers any transform, opacity change, or JS
   (js/site.js `initLazyVideo` only ever listens for the lazy-load
   IntersectionObserver, never `ended`/`timeupdate`) — so nothing on the page
   repaints when the video wraps.
   -------------------------------------------------------------------------- */
.media-video { will-change: auto; }

/* ==========================================================================
   Footer
   ========================================================================== */
footer { background: var(--cream); border-top: 1px solid rgba(var(--gold-rgb), .4); padding: 64px 0 28px; } /* Brand v2 gold hairline */
.footer-top { display: flex; flex-wrap: wrap; gap: 32px; justify-content: space-between; margin-bottom: 14px; } /* Chairman fix 2026-08-23 round 4: was 40px, stacking additively with .footer-cols's own 32px padding-top (+1px border) for a 73px dead gap under the patches row -- see BUILD_NOTES "Footer fix round 4" for the measured before/after. */
.footer-brand { display: flex; align-items: flex-start; gap: 10px; }
.footer-brand img { width: 40px; height: 40px; margin-top: 2px; } /* Chairman fix 2026-08-23: logo-anchor pass -- brand under-present site-wide; footer lockup mark bumped 28px -> 40px (wordmark + tagline already stack under it via .footer-brand-lockup) */
.footer-brand-lockup { display: flex; flex-direction: column; }
.footer-brand-word { font-family: var(--font-badge); font-weight: 800; font-size: 17px; color: var(--green-deep); }
/* Brand v2: the brand tagline returns under the footer wordmark. */
.footer-tagline {
  font-family: var(--font-display); font-style: italic; font-weight: 500;
  font-size: 13px; color: var(--charcoal); opacity: .75; margin-top: 2px;
}
/* Chairman fix 2026-08-23 (round 6): footer reuses the same .market-pill
   component as the Home map (one component, two placements) -- fixed 30px
   height, no rotation (tilt is a map-only affordance). */
.footer-market-patches { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.footer-patch { height: 30px; padding: 0 14px; transition: transform var(--t-hover) var(--ease-snap); }
.footer-patch:hover { transform: translateY(-2px); } /* review fix F9 (LOW): Recruiter's-Hand hover, translateY not a border swap now that the pill has its own outline */
.footer-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; border-top: 1px solid var(--rule); padding-top: 14px; } /* was 32px -- see .footer-top note above */
.footer-col .footer-h { /* Round 9 M5 fix: was <h3> (matched by this rule via
     review fix F3's own comment below) -- but footer nav-group labels
     ("Explore"/"Contact"/"Company") aren't document headings, and coming
     straight after each page's real h1/h2 flow they produced an h1->h3
     skip on the two thanks pages (which have no h2 in between). Markup is
     now <p class="footer-h">, same visual treatment, no heading semantics.
     (Prior note, now historical: was .footer-col h4 -- the markup used to
     use <h3>, so this rule matched nothing and the label fell through to
     the global h1-h4 display-face rule (19.89px w700 title-case) instead of
     this 11px uppercase tracked badge-face label. font-family is required
     here since these are badge-role labels, not display headings.) */
  font-family: var(--font-badge);
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--green-mid); margin-bottom: 14px;
}
.footer-col ul { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.footer-col a { font-size: 13px; color: var(--charcoal); text-decoration: none; opacity: .85; }
.footer-col a:hover { color: var(--green-mid); opacity: 1; }
.footer-legal {
  margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
  font-size: 11px; color: var(--charcoal); opacity: .72; /* review fix F7 (MEDIUM): was .55 = 3.33:1, fails WCAG 4.5:1; .72 measures ~4.6:1 */
}

/* ==========================================================================
   Shared inner-page components (employers / candidates / about, added
   2026-08-22 for the three-page build) — same palette, motion system and
   card language as the home page, no new fonts.
   ========================================================================== */

/* A quieter paper "header" for interior pages: same visual shell as the
   home .opener (paper-cut art + road-sign panel), but shorter and driven
   by a static <img> instead of the looping video — these pages introduce a
   search/story, not the panorama. Reuses .opener/.opener-media/.road-sign
   almost verbatim; this class only overrides height. */
.page-opener.opener { height: auto; max-height: 616px; min-height: 516px; } /* Chairman cuts 2026-08-23: 460px was re-measured against the nav pill alone for a ~37px clearance. Logo-anchor pass (round 6) added a 40px .road-sign-mark + 16px margin above the headline -- 56px of new content inside a bottom-anchored panel pushes its TOP edge up by that same 56px, so min-height (and the max-height cap alongside it) both moved 460->516 / 560->616 to hold the same ~37px clearance under the nav pill rather than let the panel creep back under it. Re-verified live. */
.page-opener .road-sign { max-width: 620px; }

/* "How a search runs" / process folder tabs already ship as .folder-row /
   .folder-tab on the home page — reused as-is on Employers with longer copy. */

/* Fee / engagement note (Employers) — plain-language card, not a price
   sheet with tiers; parchment recessed panel matching the folder-tab
   surface language rather than an elevated white card. */
.fee-note {
  background: var(--parchment); border: 1px solid var(--rule);
  border-radius: var(--radius-card); padding: var(--s5);
  display: flex; gap: var(--s4); align-items: flex-start;
  box-shadow: var(--shadow-paper); /* WO-D item 1 */
}
.fee-note-icon {
  flex-shrink: 0; width: 52px; height: 52px; border-radius: 50%;
  background: var(--cream); border: 2px solid var(--ink);
  display: flex; align-items: center; justify-content: center; font-size: 22px;
}
.fee-note p { font-size: 15px; line-height: 1.75; opacity: .88; }
.fee-note p + p { margin-top: 12px; }
.fee-note strong { color: var(--green-deep); }

/* -----------------------------------------------------------------------
   CRM-* form system (REFERO_COMPONENTS reconciliation) — shared by the
   Employers "Start a search" panel (around the Close embed placeholder)
   and the Candidates submission form. Cream recessed inputs, 1.5px rule
   border, 12px radius, focus -> soft-green border + white background;
   :focus-visible keeps the site-wide green-deep ring (never outline:none).
   ----------------------------------------------------------------------- */
.crm-panel {
  background: var(--white); border: 1px solid var(--rule);
  border-radius: var(--radius-card); padding: var(--s6);
  box-shadow: var(--shadow-paper); /* WO-D item 1 */
}
.crm-panel-head { margin-bottom: var(--s4); }
.crm-panel-head h2 { font-size: clamp(24px, 3vw, 32px); margin-bottom: 8px; }
.crm-panel-head p { font-size: 15px; opacity: .78; }
.crm-form { display: grid; gap: var(--s3); }
.crm-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.crm-field { display: flex; flex-direction: column; gap: 6px; }
.crm-field.full { grid-column: 1 / -1; }
.crm-field label {
  font-family: var(--font-badge); font-size: 11px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--green-mid);
}
.crm-field input, .crm-field select, .crm-field textarea {
  font-family: var(--font-body); font-size: 15px; color: var(--charcoal);
  background: var(--cream); border: 1.5px solid var(--rule); border-radius: 12px;
  padding: 13px 16px; transition: border-color .2s ease, background .2s ease;
  width: 100%;
}
.crm-field textarea { min-height: 110px; resize: vertical; font-family: var(--font-body); }
.crm-field input:focus, .crm-field select:focus, .crm-field textarea:focus {
  /* review fix F4 (HIGH, WCAG 2.4.7, BLOCKER): this rule's own `outline: none`
     was higher specificity (0,2,1) and later in the file than the global
     input:focus-visible ring (0,1,1), so it won on every keyboard focus --
     exactly the "outline:none" fix REFERO_COMPONENTS explicitly rejected.
     Removed entirely; the border-color swap below is a bonus visual cue,
     the global 3px green-deep :focus-visible ring (now incl. select, see
     above) is the actual accessible focus indicator. */
  border-color: var(--green-soft); background: var(--white);
}
.crm-field input:invalid:not(:placeholder-shown) { border-color: var(--error); }
.crm-note { font-size: 12px; color: var(--charcoal); opacity: .6; line-height: 1.6; }
.crm-submit-row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; margin-top: 4px; }
.crm-fallback {
  margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--rule);
  font-size: 14px; opacity: .8;
}
/* 2026-08-28: the Candidates bridge CTA's two inline links join this same
   treatment -- it is the site's only in-body link style, and the global
   `a { color: inherit; }` would otherwise leave them as bare UA links. */
.crm-fallback a,
.margin-note a { color: var(--green-deep); font-weight: 700; text-decoration: underline; }

/* The Close embed placeholder — its script/iframe inherits host fonts but
   CANNOT be styled internally (cross-origin embed); this wrapper is the
   only part of the panel Clover controls. Parchment recessed slot so
   whatever Close renders sits visually "on parchment" as briefed. */
.close-embed-slot {
  background: var(--parchment); border: 1.5px dashed var(--rule);
  border-radius: 16px; padding: var(--s5); min-height: 160px;
  display: flex; align-items: center; justify-content: center;
  text-align: center; font-size: 13px; color: var(--charcoal); opacity: .78; /* review fix F9: was .65 (~4.2:1, fails 4.5:1); .78 measures ~4.9:1 -- cosmetic, this text disappears once the real Close embed lands */
}

/* Round 7 (2026-08-23), WO-D item 2: the "mounted form" card -- a Paper
   White sheet sitting slightly askew on the crm-panel's own white surface,
   with a small letterhead seal (chunky mark + label-kicker) at its top, so the
   Close embed area looks like an intentional, designed object whether it's
   still showing the placeholder or holds the real Close-issued embed. */
.close-embed-mount {
  background: var(--white); border: 2px solid var(--rule); border-radius: 24px;
  padding: 28px; box-shadow: var(--shadow-paper);
  transform: rotate(-0.4deg);
  transition: transform var(--t-hover) var(--ease-snap), box-shadow var(--t-hover) var(--ease-snap);
}
.close-embed-mount:hover { transform: rotate(0deg); box-shadow: var(--shadow-paper-hover); } /* "straightening the page" */
.close-embed-letterhead { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
.close-embed-letterhead img { width: 28px; height: 28px; flex-shrink: 0; }
.close-embed-letterhead .label-kicker { margin-bottom: 0; }

/* Badge list — "What we place" (Candidates) / verticals list (Employers),
   a lighter-weight reuse of the home .badge-card pattern without the icon. */
.pill-list { display: flex; flex-wrap: wrap; gap: 10px; }
.pill-list span {
  font-family: var(--font-badge); font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--ink);
  background: var(--white); border: 2px solid var(--ink); border-radius: 999px;
  padding: 9px 18px;
  scroll-margin-top: 120px; /* Chairman cuts 2026-08-23: was 130px (nav plus the
    geography strip beneath it); that strip is now removed entirely, re-measured
    against the nav pill alone for when linked to directly (home's practice
    badges, and legacy /practice/* redirects) */
}
.pill-list a { color: inherit; text-decoration: none; } /* About page contact pills */

/* Utility: clears the fixed nav pill (~82px @1280) for an interior page's
   first section when it has no full-bleed opener art for it to float over
   (used once, on About's #intro). Chairman cuts 2026-08-23: was 170px to
   also clear the now fully-removed geography strip; re-measured against the
   nav alone. */
.clears-fixed-nav { padding-top: 120px; }

/* Candidate pillars ("How we treat candidates") */
.pillar-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s4); }
.pillar-card {
  background: var(--white); border: 1px solid var(--rule); border-radius: var(--radius-card);
  padding: var(--s4); display: flex; gap: 14px; align-items: flex-start;
}
.pillar-dash { width: 22px; height: 2px; background: var(--gold); margin-top: 11px; flex-shrink: 0; }
.pillar-title { font-family: var(--font-badge); font-weight: 800; font-size: 15px; margin-bottom: 6px; }
.pillar-text { font-size: 14px; opacity: .82; line-height: 1.65; }
/* Chairman order 2026-08-28: the Candidates bridge CTA is a standalone
   .margin-note directly under the pillar grid. Its default 16px lede
   margin-top is a headline-to-lede value and reads cramped under a card
   grid, so only the spacing is scoped here -- no new component. */
.pillar-grid + .margin-note { margin-top: var(--s4); }

/* Kearneys — mounted-paper photo language, shared by About (round 2) and
   Home (round 3). About: "reuse .kearney-* as-is (imported verbatim from
   the home page) but the portrait frame gets a stitched ring" -- the
   Chairman later called the whole card generic ("looks bad") and this
   replaced that stitched-ring circle treatment outright with a
   mounted-paper photo (see the HTML comment above the Kearneys markup in
   about/index.html for the full brief). Round 3: "you didn't do the family
   cards on the home page too" -- Home's `.kearney-frame` circle +
   `.kearney-role` treatment (this file's previous copy here) is now fully
   retired too, replaced by the clustered vignette below. `#kearneys`-scoped
   rules stay About-only (its section id; Home's is `#story`) since About
   keeps the side-by-side two-card layout while Home clusters into one
   vignette -- `.kearney-mount`/`.kearney-mount img`/`.kearney-mount-caption`
   are the shared base both pages build on. .kearney-name/.kearney-bio
   (typography, copy) are shared and untouched. */
#kearneys .kearney-card {
  flex-direction: row; align-items: flex-start; gap: 28px;
  background: var(--parchment); border: 1px solid var(--rule);
  border-radius: var(--radius-card); padding: var(--s5);
}
#kearneys .kearney-copy { min-width: 0; }
#kearneys .kearney-name { margin-bottom: 8px; } /* was 0 -- the role line used to supply this gap before it moved into the mount */
.kearney-mount {
  position: relative; /* anchors .photo-corner (Home's cluster) -- no-op on About, which has none */
  flex: 0 0 auto; width: 200px; max-width: 100%; text-align: center;
  background: var(--cream); border: 1px solid var(--rule);
  padding: 10px 10px 12px;
  transform: var(--base-transform, none);
}
.kearney-mount--a { --base-transform: rotate(-2deg); }
.kearney-mount--b { --base-transform: rotate(2deg); }
.kearney-mount img {
  width: 100%; height: auto; display: block; border-radius: 10px;
  filter: drop-shadow(0 12px 20px rgba(12,15,20,.14));   /* same value as .lodi-arch-mount img -- the site's mounted-paper-photo convention */
}
.kearney-mount-caption {                 /* same voice as .lodi-arch-caption: field-journal specimen label */
  display: block; margin-top: 10px;
  font-family: var(--font-badge); font-weight: 700; font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--green-deep); opacity: .7;
}
@media (max-width: 767px) {
  #kearneys .kearney-card { flex-direction: column; align-items: center; text-align: center; padding: var(--s4); }
  .kearney-mount { width: 150px; }
}

/* Home Kearneys cluster (round 3, revised round 11 -- Chairman fix
   2026-08-25, FIX 2: "Brooklyn and I should be listed side by side i am
   currently behind her. it looks weird."). The round-3 version absolutely
   positioned the two mounts with a ~31px/18% overlap band (Aidan behind,
   Brooklyn in front, unequal 172px/200px scale) -- exactly the layout the
   Chairman is describing. Replaced with a plain side-by-side flex row:
   both mounts equal scale, no absolute positioning, no z-index, no
   overlap. Still one visual unit (shared `.kearney-cluster` wrapper, both
   mounts keep `.clay-card` so js/site.js's GROUP_SELECTOR still staggers
   them in together) and still opposing tilts (kept at their existing
   values, 2deg/-3deg, per instruction -- these were never the problem).
   `flex-wrap: wrap` + `justify-content: center` is a deliberate no-
   hardcoded-breakpoint choice for the mobile case: at 150px/mount + 24px
   gap (174*2+24=... 150+150+24=324px), a 360px viewport's ~320px content
   width (`.wrap` padding 20px each side) can't fit both in one row, so
   they wrap to two centered rows (stacked); a 390px viewport's ~350px
   content width fits both in one row, side by side -- both cases land on
   "centered" without a viewport-width special case, exactly the two
   outcomes the brief called out.
   Scoped to `#story` (Home's Kearneys section id) so it can't leak onto
   About's `#kearneys` two-card layout above. `.kearney-mount-caption`
   here carries a name + role pair (About's only ever carries a bare
   role) -- `-name`/`-role` children override the shared caption's
   uppercase/letter-spacing for the name line only, same specificity as
   the shared rule so source order (after it) decides. */
#story .kearney-cluster-layout {
  display: flex; align-items: center; gap: var(--s6); flex-wrap: wrap; margin-top: 34px;
}
#story .kearney-cluster {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-end;
  gap: 24px; flex: 0 0 auto;
}
#story .kearney-cluster .kearney-mount { position: static; text-align: left; }
/* Aidan: equal scale to Brooklyn's mount, tilted clockwise. */
#story .kearney-mount--rear { width: 200px; --base-transform: rotate(2deg); }
/* Brooklyn: equal scale to Aidan's mount, tilted counter-clockwise. */
#story .kearney-mount--front { width: 200px; --base-transform: rotate(-3deg); }
#story .kearney-mount-caption { text-align: left; }
/* Corners anchor to a dedicated photo wrapper, not the whole mount --
   the mount's own box also contains the caption below the photo, so
   anchoring `bottom`/`right` to the mount itself put the bottom-right
   corner down at the caption instead of the photo's actual corner. */
.kearney-mount-photo { position: relative; display: block; }
.kearney-mount-caption-name {
  display: block;
  font-family: var(--font-badge); font-weight: 700; font-size: 13px;
  letter-spacing: normal; text-transform: none;
  color: var(--green-deep); opacity: 1; line-height: 1.25;
}
.kearney-mount-caption-role {
  display: block; margin-top: 2px;
  font-family: var(--font-badge); font-weight: 700; font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--green-deep); opacity: .7;
}
/* Photo-corners: small triangular gold paper corners holding each snapshot
   into its mount -- a functional field-journal object (corners physically
   hold a photo in an album), not meaningless ornament. Two visible corners
   per mount (top-left + bottom-right) is enough to read as "held." */
.photo-corner {
  position: absolute; width: 16px; height: 16px;
  background: var(--gold);
  pointer-events: none;
}
.photo-corner--tl { top: 4px; left: 4px; clip-path: polygon(0 0, 100% 0, 0 100%); }
.photo-corner--br { bottom: 4px; right: 4px; clip-path: polygon(100% 100%, 100% 0, 0 100%); }
#story .kearney-text {
  flex: 1 1 320px; min-width: 280px;
  display: flex; flex-direction: column; gap: 22px;
}
@media (max-width: 767px) {
  #story .kearney-cluster-layout { flex-direction: column; align-items: center; text-align: center; }
  #story .kearney-cluster { width: auto; margin: 0 auto; }
  #story .kearney-mount--rear, #story .kearney-mount--front { width: 150px; }
  #story .kearney-mount, #story .kearney-mount-caption { text-align: center; }
  #story .kearney-text { text-align: left; }
}

.why-lodi { max-width: 68ch; }
.why-lodi p + p { margin-top: 16px; }

/* Round 7 (2026-08-23), WO-B: Lodi Mission Arch sticker, About page intro
   only -- a mounted-sticker treatment beside the tagline quote, per the
   Chairman's design spec. Reuses the site's .clay-card entrance behavior
   (a rotated rest state lives in --base-transform, same pattern as
   .owner-patch/.map-patch, so the entry motion never clobbers the tilt). */
.intro-layout {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--s6); flex-wrap: wrap;
}
.intro-layout .plate-head { flex: 1 1 420px; margin-bottom: 0; min-width: 0; } /* Round 8: was .section-head, converted to a field-guide plate */
/* Chairman fix 2026-08-25 (About Lodi arch, follow-on): "it should fill the
   entire highlighted space" + "its still showing with a square background
   it should appear as if it is die cut." Root cause of the square
   background, confirmed in the built artifact before fixing: this figure
   also carries `.clay-card`, and `.clay-card.is-ready` (shared site-wide
   entrance-motion rule) applies `box-shadow: var(--shadow-paper)` -- a
   RECTANGULAR shadow around the element's own bounding box. `.lodi-arch-
   mount` itself paints no background/border of its own (unlike every other
   `.clay-card` instance site-wide -- badge-card, pillar-card, fee-note,
   candidates-strip, route2-stop, kearney-card/kearney-mount, thanks-panel,
   crm-panel, book-band all have a real background+border that a card-lift
   shadow legitimately sells; grep-audited, .lodi-arch-mount is the only
   .clay-card wrapping a transparent die-cut sticker with no chrome of its
   own), so that soft rectangular shadow was the only thing painting behind
   the transparent PNG -- reading exactly as a "square background" behind a
   sticker that's supposed to sit directly on the page. Fixed by suppressing
   just that one box-shadow on this element; the entrance motion itself
   (opacity/transform, plain `.clay-card`/`.clay-card.is-ready` rules) is
   untouched. The image's own `filter: drop-shadow(...)` -- a contour-
   following shadow that traces the die-cut silhouette, not a bounding-box
   rectangle -- is what actually sells the lift here and stays as-is. */
.lodi-arch-mount {
  --base-transform: rotate(-2.5deg);
  flex: 1 1 280px; width: 100%; max-width: 390px; text-align: center;
}
.lodi-arch-mount.clay-card.is-ready { box-shadow: none; }
.lodi-arch-mount img {
  width: 100%; height: auto; display: block;
  filter: drop-shadow(0 12px 20px rgba(12,15,20,.14));
}
.lodi-arch-caption {
  display: block; margin-top: 12px;
  font-family: var(--font-badge); font-weight: 700; font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--green-deep); opacity: .7;
}
@media (max-width: 767px) {
  .intro-layout { flex-direction: column; align-items: center; text-align: center; }
  .intro-layout .plate-head { flex-basis: auto; }
  .lodi-arch-mount { flex-basis: auto; width: 100%; max-width: 280px; margin-top: 4px; }
}

/* Static "Book a hiring call" band using p3-book-band.webp instead of the
   home page's looping video, per the About-page brief. Reuses .book-band's
   green-deep/white chassis; the media layer is a plain <img>. */
.book-band-media--static img { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: bottom; }

/* Thanks pages (candidates/employers form success) */
.thanks-panel {
  max-width: 640px; margin: 0 auto; text-align: center;
  background: var(--white); border: 1px solid var(--rule); border-radius: var(--radius-lg);
  padding: var(--s7) var(--s5);
}
.thanks-mark { width: 72px; height: 72px; margin: 0 auto var(--s4); }

/* ==========================================================================
   Round 8 (2026-08-23), WO-C: Field-guide plates — site-wide section-header
   rebuild, replacing the repeated eyebrow-dash / H2 / description stack per
   REFERO_ROUND7.md "De-boilerplate directive" §2. A plate always has a
   chip + gold rule + H2; the description becomes a narrower margin note
   connected by a thin gold annotation line, first clause set like a
   naturalist's handwriting. Three placement variants (below), one per
   section, never repeated on two adjacent sections.
   ========================================================================== */
/* Round 10 (2026-08-23): the plate CHIP is gone (Chairman: "i dont like
   headers with 'plates' this feels boilerplate"). The museum-catalogue
   "Plate NN —" convention and its bordered box are both retired; the
   asymmetric plate-head PLACEMENT system below is unchanged — it was never
   what he objected to. Replacement per refero/Drive Capital: "delineate
   with thin lines rather than heavy boxes" — the gold rule already does the
   delineating, so the label is bare type plus the clover mark as a waypoint
   dot. Mark goes 8px -> 12px: without a box around it, 8px read as a smudge.

   RETIRED WO_design-recal-2026-08-25 item 2 (Chairman, on the recording:
   the eyebrow/chip + rule + dot stack still "looks boilerplate" even
   without the old museum-plate box). `.head-label` (the chip above), the
   `.plate-top` row that held it plus the gold `.plate-rule`, and the
   `.annotation-line` gold rule+dot connecting the margin-note below are
   ALL deleted -- markup removed from every `.plate-head` instance
   site-wide (grep-verified, 0 remaining outside historical BUILD_NOTES/
   comment prose), not just hidden. The only surviving category-label use
   (the Close-embed letterhead) moved to `.label-kicker` above, a
   plain small-caps line with no chip/box/dash. `.plate-head`'s A/B/D
   placement system (the asymmetric two-column layout below) is UNCHANGED
   -- the WO was explicit that was never what the Chairman objected to. */
.plate-head .section-title { margin-bottom: 0; }

/* Chairman fix 2026-08-25 (FIX 4): "large empty gaps between bold text and
   description on mobile... I still dont really like the way we are
   displaying that info." The `.plate-head--a`/`--d` asymmetric two-column
   placement (headline flush left, margin-note breaking out into its own
   300px right-hand column, `.plate-head--b`'s single-column-but-capped
   variant alongside it) produced a huge dead gulf between the two columns
   on wide screens and, once `--a`/`--d` collapsed to a stacked column at
   767px, an oversized top/bottom gap around the now-orphaned note. All
   three placement variants (A/B/D) are RETIRED in favor of one single-
   column pattern: headline, then its description directly beneath as a
   lede, always, on every page/breakpoint -- no variant to pick, no
   asymmetric column to leave a gap. `.plate-main`/`.margin-note` stay as
   plain stacked block children (DOM order unchanged, so --d's old note-
   first reading order is gone too -- headline always reads first, matching
   --a/--b's order, since the WO gave no reason for a note-first exception
   once there's no second column to justify it). See BUILD_NOTES "Retire
   plate-head--a/--d" for the gate successor and per-page conversion list. */
.plate-head { margin-bottom: 56px; }

/* WO_design-recal-2026-08-25 item 2 "Ledes" spec, now the ONE lede
   treatment site-wide instead of a sidebar-constrained special case:
   Instrument Sans 17px (inherited from body), --charcoal, max-width 52ch,
   margin-top 16px, left-aligned with the headline above it -- identical
   values to `.section-desc` (the thanks-pages' own lede, same WO, same
   spec) so there's one lede rhythm site-wide, not two near-duplicates.
   Never italic, no dimming opacity -- the retired `.mn-lead` lead-in span
   and `.annotation-line` gold rule+dot stay gone (markup is a plain <p>). */
.margin-note {
  margin-top: 16px; max-width: 52ch; font-size: 17px; line-height: 1.65; color: var(--charcoal);
}

/* Variant C -- RETIRED (Round 11, WO-11a, 2026-08-24). Was: H2 allowed to
   overlap the section artwork's negative space, plate above it, a stacked
   cream text-shadow insuring legibility over the art. Used exactly once
   site-wide, on Markets ("Rooted in the Valley"). Chairman: text fully off
   the map -- the mechanism this variant exists for (bleeding the H2 into
   artwork) is precisely what he rejected, and with the text off the art
   the text-shadow halo is no longer insurance, just a halo the round's
   whole direction is away from. Markets now ships as --d (see markup);
   grep-verified this was --c's only live use, so the rules are removed
   here rather than left dead per move-never-delete -- this comment is the
   record. Do not re-add without a fresh Chairman ruling. */

/* Round 9 (2026-08-24), M3/M4 introduced variant C-up (H2 bleeding UP into
   the PRECEDING page-opener image, the same idea as --c above but reversed
   direction) for Employers' "Where We Search" field note.
   Round 10 (2026-08-24), WO-4-R2 4a-bis: RETIRED. Live measurement (see
   WO_round10.md 4a-bis) found `.plate-head--c-up`'s `.head-label` box
   falling entirely inside `.road-sign`'s footprint at 1280 (and 1024/1440
   alike -- `.road-sign` is capped at a fixed 620px/max-height regardless of
   viewport, so this isn't a breakpoint-specific glitch), painting behind
   the road-sign panel because `.road-sign` carries `z-index:3` against
   this element's implicit `z-index:auto`. Measured both WO-prescribed
   fixes and neither clears at all three widths:
     - Option 1 (shift right into open art): at 1024 the wrap only has
       365px clear to the right of `.road-sign` (1009 - 644); the block
       needs its full 560px, so it doesn't fit.
     - Option 2 (reduce the -190px bleed so the label clears the sign's
       BOTTOM edge): `.road-sign`'s bottom sits only 25px above the
       opener's own bottom edge at every desktop width measured (491 vs
       516) -- clearing the label (needs ~36px more headroom than the H2
       gets before the opener ends) and keeping the H2 still bleeding into
       the art are mutually exclusive given that 25px gap. No margin-top
       value satisfies both.
   Per the WO's own decision tree ("if neither clears at all three widths,
   the --c-up premise is simply false on this page -- swap to variant --b
   and say so"): the section now ships as `.plate-head--b` (see markup,
   `employers/index.html` "Where We Search"). `.plate-head--c-up` was used
   exactly once site-wide (grep-verified), so its CSS is deleted here
   rather than left dead. WO-9 eyeball item 2 is moot -- this was retired
   for a documented reason, not fixed; do not re-open. */

/* Variant D -- RETIRED (Chairman fix 2026-08-25, FIX 4, see the retirement
   note above `.plate-head` for the full rationale). Was: mirror of A, same
   two-column flex shape but the margin note took the LEFT column and
   plate+H2 the RIGHT column via an `order` swap. Used exactly once
   site-wide (Home's "Who We Work With" -- grep-verified), so its CSS is
   deleted here rather than left dead, per the file's own move-never-delete-
   in-the-CSS convention (this comment is the record; do not re-add without
   a fresh Chairman ruling). */

/* ==========================================================================
   Round 11 (2026-08-24), WO-15: "The Route" -- journey simplification, the
   full-screen takeover (WO-12) IS RETIRED. Chairman, live verdict on the
   built takeover: "The journey doesnt work at all. Lets simplify the
   movement and just show the steps off to the side of the journey scene."
   He'd approved a static gate-2 mock, then rejected the built motion on
   sight -- his live view governs. The scroll mechanism (sticky stage, pan/
   zoom phases, sign-crosses-midline tick markers, trip strip, cover-image
   preload) is deleted entirely, not disabled behind a flag -- see
   js/site.js (the takeover's init function removed wholesale).
   The former no-JS/mobile static fallback is promoted to the ONLY layout at
   every viewport: full-width framed art (`.img-slot`, no bespoke frame)
   above a stack of four cards on mobile (unchanged -- this is already that
   layout); a two-column `[art | steps]` grid on desktop, art as a tall
   panel with a paper shadow, four cards beside it at full opacity, no
   dimming/mask/active-state, standard `.clay-card` reveal-on-scroll. Copy
   and alt text are untouched by this round -- nothing about them was
   rejected. */
.route2-track { position: relative; }
.route2-stage { display: block; }
.route2-art { width: 100%; height: auto; display: block; }
.route2-stops { list-style: none; display: grid; gap: 38px; margin-top: 34px; }

/* Round 12 (2026-08-24), WO_round12-route-static: highway guide-sign chrome.
   Copied from the anatomy of the four in-art EXIT signs themselves (green
   face, pure-white retroreflective ring inset inside the site's dark
   cut-paper edge) rather than invented from MUTCD reference -- see
   WO_round12-route-static.md section 2's closing note. Applies at every
   viewport, not just the >=1120px staggered layout below.

   Chairman fix 2026-08-25 (round 2, "the weird bump with number"): the
   mile-marker tab class this section used to style (WO_design-recal-
   2026-08-25 item 1's bare "01"-"04" numeral plate, protruding above the
   card's top edge) is deleted outright, not just its "Stop" text -- the
   route ARTWORK already numbers the stops in-world (the painted
   "EXIT 1 -- INTAKE" road signs in p5-route2.webp), so the card itself
   needs no numeral. Markup: the numeral <span> in each of the 4 stops on
   both pages (8 total) is removed -- checks/verify_build.mjs gates its
   retired class name absent from this file too, so it's deliberately not
   spelled out literally in this comment. The card's own top-edge bump is
   gone with it -- see .route2-stop below for the matching margin-top
   revert. */
.route2-stop-title  { font-family: var(--font-display); font-weight: 800; font-size: 17px; margin-bottom: 5px; color: var(--white); line-height: 1.2; }   /* was var(--cream) -- sign legend */
.route2-stop-desc   { font-size: 13px; line-height: 1.5; color: var(--cream); opacity: .9; }   /* unchanged in effect */
/* the detail block is always in the DOM and always visible now -- WO-15
   drops the takeover's "live mode hides it permanently" carve-out along
   with the takeover itself. Screen readers and sighted visitors alike get
   the full three-bullet expansion under every stop's desc, at every
   viewport, all the time. */
.route2-stop-detail { margin-top: 10px; padding-left: 18px; font-size: 12.5px; line-height: 1.55; color: var(--cream); opacity: .82; }
.route2-stop-detail li { margin-bottom: 4px; }

/* Highway guide-sign anatomy, copied from the four in-art EXIT signs:
   green face, rounded corners, a white retroreflective ring inset inside
   the site's 2px cut-paper ink edge, and an exit tab butted on top of the
   face. */
.route2-stop {
  position: relative;
  background: var(--green-deep);
  color: var(--cream);
  border: 2px solid var(--ink);        /* the site's cut-paper edge, unchanged in kind */
  border-radius: 14px;                 /* was 10px -- guide signs are softer */
  padding: 26px 26px 22px;             /* was 16px 20px 14px -- text must clear the ring */
  box-shadow: var(--shadow-paper);
  /* margin-top: 22px (room for the exit tab hanging above the face) dropped
     2026-08-25 alongside the numeral tab's removal -- no tab left to clear,
     card reads as a clean rounded sign panel with no bump on the top edge.
     .route2-stops' own `gap: 38px` still spaces the cards. */
}
/* the white retroreflective border ring */
.route2-stop::before {
  content: "";
  position: absolute;
  inset: 5px;                          /* 5px inside the padding box = 7px from the outer edge */
  border: 3px solid var(--white);
  border-radius: 7px;                  /* concentric: padding-box radius (14-2=12) minus the 5px inset */
  pointer-events: none;
}

/* --- desktop: two-column [art | steps] grid --- */
@media (min-width: 900px) {
  /* `.route2-stage` (not `.route2-track`) is the grid container -- it's the
     direct parent of both the art's `.img-slot` and `.route2-stops` in the
     existing markup, so no DOM change was needed to go two-column, only the
     retired takeover's absolute-positioning/full-bleed rules coming out.
     Left track sized to the tall portrait art (native 1100x1964, ~0.56
     aspect) rather than a bare `1fr`, so the steps column gets the
     remaining width instead of the two columns splitting evenly. */
  .route2-stage {
    display: grid; grid-template-columns: minmax(300px, 400px) 1fr;
    gap: var(--s6); align-items: start;
  }
  /* "the journey art panel" (WO-15) -- the takeover's full-bleed stage had
     explicitly stripped `.img-slot`'s frame/shadow ("no frame, radius,
     border or shadow"); the static panel is the opposite of that brief, so
     it gets the standard paper-shadow treatment on top of `.img-slot`'s
     existing rounded-corner frame. Scoped to this section only -- other
     `.img-slot` uses site-wide are unaffected. */
  .route2-stage .img-slot { box-shadow: var(--shadow-paper); }
  .route2-stops { align-content: start; }   /* margin-top reverted to 0 2026-08-25 -- was 22px for the now-deleted tab's clearance, no longer needed */
}

/* ---- >=1120px: art centred, four sign cards staggered into the gutters,
   each card's FACE vertically centred on its own band's in-art EXIT sign.
   The four --sign-y values are measured off assets/p5-route2.webp (1100x1964);
   see WO_round12-route-static.md section 2 for the measurement method. ---- */
@media (min-width: 1120px) {
  .route2-track { padding-block: 40px 56px; }   /* top/bottom card overhang clearance */

  .route2-stage {
    display: block;                 /* overrides the 900px two-column grid */
    position: relative;
    --route2-art-w: clamp(360px, 34vw, 440px);
    --route2-card-w: clamp(280px, 26vw, 340px);
    --route2-gutter: var(--s4);
  }
  .route2-stage .img-slot {
    width: var(--route2-art-w);
    margin-inline: auto;
    box-shadow: var(--shadow-paper);
  }
  /* the <ol> becomes a positioning layer exactly the height of the art, so a
     percentage `top` on each card resolves against the image's own height and
     --sign-y maps 1:1 onto the measured fraction. */
  .route2-stops {
    position: absolute; inset: 0;
    display: block; margin: 0; gap: 0;
  }
  .route2-stop {
    position: absolute;
    width: var(--route2-card-w);
    top: var(--sign-y);
    margin-top: 0;
    /* delivered via --base-transform so .clay-card's entry motion composes with
       it instead of clobbering it; the bare `transform` below is the no-JS path
       (`.js .clay-card` never matches when JS is off). */
    --base-transform: translateY(-50%);
    transform: var(--base-transform);
  }

  /* measured sign centres, as a fraction of the art's height */
  .route2-stop[data-step="1"] { --sign-y: 15.9%; }
  .route2-stop[data-step="2"] { --sign-y: 39.7%; }
  .route2-stop[data-step="3"] { --sign-y: 64.3%; }
  .route2-stop[data-step="4"] { --sign-y: 88.5%; }

  /* stagger: 1 right, 2 left, 3 right, 4 left */
  .route2-stop[data-step="1"],
  .route2-stop[data-step="3"] {
    left: calc(50% + var(--route2-art-w) / 2 + var(--route2-gutter));
  }
  .route2-stop[data-step="2"],
  .route2-stop[data-step="4"] {
    right: calc(50% + var(--route2-art-w) / 2 + var(--route2-gutter));
  }

  /* a quiet gold hairline from the card to the art at the sign's exact y --
     this is what makes the alignment legible rather than coincidental.
     Removable in one rule if the Chairman finds it fussy. */
  .route2-stop::after {
    content: "";
    position: absolute; top: 50%;
    width: 28px; height: 1px;
    background: rgba(var(--gold-rgb), .5);
    pointer-events: none;
  }
  .route2-stop[data-step="1"]::after,
  .route2-stop[data-step="3"]::after { left: calc(var(--route2-gutter) * -1); }
  .route2-stop[data-step="2"]::after,
  .route2-stop[data-step="4"]::after { right: calc(var(--route2-gutter) * -1); }
}

@media (max-width: 900px) {
  .crm-row { grid-template-columns: 1fr; }
  .pillar-grid { grid-template-columns: 1fr; }
  .fee-note { flex-direction: column; }
}

@media (max-width: 768px) {
  .page-opener.opener { max-height: none; }
  .crm-panel { padding: var(--s4); }
}

/* ==========================================================================
   Responsive: 320 / 390 / 768 / 1280
   ========================================================================== */
@media (max-width: 1080px) {
  .nav-links { display: none; }
  .nav-burger { display: flex; }
  .nav .btn-sticker { display: none; } /* review fix 3 — .mobile-nav already carries the booking CTA below this width */
}

@media (max-width: 900px) {
  .badge-grid { grid-template-columns: repeat(2, 1fr); }
  .market-legend { grid-template-columns: 1fr; gap: 28px; }
  .kearney-grid { grid-template-columns: 1fr; gap: 40px; }
  .candidates-strip { grid-template-columns: 1fr; padding: var(--s4); }
  .candidates-art { order: -1; }
}

@media (max-width: 768px) {
  .opener { height: auto; max-height: none; min-height: 0; display: flex; flex-direction: column; }
  .opener-media { position: relative; height: 62vh; min-height: 340px; }
  .road-sign { position: relative; left: auto; bottom: auto; width: auto; max-width: none; margin: -48px 16px 0; z-index: 5; }
}

@media (max-width: 640px) {
  .wrap { padding: 0 20px; }
  section { padding: 64px 0; }
  .badge-grid { grid-template-columns: 1fr; }
  .kearneys-head { flex-direction: column; }
  .book-band { padding-top: 72px; }
  /* Round 4 item 2: same fix as desktop, scaled to this breakpoint's
     shorter 150px media band -- padding-bottom was exactly 150px too (zero
     cushion, button's bottom edge flush against the art's top edge); now
     150+30 for the same 30px cushion desktop gets. This is the ACTUAL
     breakpoint where `.book-band-media`'s height changes (640px, not
     767px -- the mark's own 120px mobile size kicks in earlier, at 767px,
     but the media/padding pair only changes here). */
  .book-band .wrap { padding-bottom: 180px; }
  .book-band-media { height: 150px; }
  .footer-cols { grid-template-columns: 1fr; gap: 24px; }
  .footer-top { flex-direction: column; align-items: flex-start; }
  .road-sign { padding: 26px 22px 22px; margin-top: -36px; }
  /* Chairman fix 2026-08-23 (round 5, geometry unchanged round 6): overlaid
     absolutely on a ~350px-wide mobile map at their desktop percentages,
     three pills would collide or spill past the image edge regardless of
     how the percentages are tuned. Rather than shrink them illegibly small,
     they drop out of absolute positioning entirely and stack as a plain row
     below the map -- guarantees zero overlap and keeps them legible at
     mobile width. Round 6: the uniform .market-pill sizes to its own
     content (icon + label) instead of a fixed 130px image width, so no
     explicit width override is needed here any more. */
  .markets-map-wrap { display: flex; flex-direction: column; align-items: center; gap: 14px; }
  /* Round 11, WO-11b: the desktop 16:10 crop is a flex-item aspect-ratio at
     this breakpoint (wrap is now a flex COLUMN stacking img + pills, not a
     positioning box for overlaid pills -- they're static below, see
     .map-pill just below), so pinning aspect-ratio here would squeeze the
     pills row into a fixed-height box instead of letting it size to
     content. Reset to the pre-Round-11 full, uncropped image at mobile --
     WO-11 only asked for the desktop presentation to change, and 390px
     already had zero overlap risk since pills aren't overlaid here. */
  .markets-map-wrap { aspect-ratio: auto; }
  .markets-map-wrap > img { height: auto; object-fit: fill; object-position: 0 0; }
  .map-pills { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px 12px; } /* 3 pills wrap to 2 lines under ~400px (measured: 390px wraps 2+1) -- 20px row-gap keeps the wrapped line clear of the first, 12px column-gap between pills on the same line */
  .map-pill {
    position: static; --base-transform: none;
  }
}

@media (max-width: 400px) {
  .nav-outer { top: 12px; }
  .nav { padding: 8px 8px 8px 16px; }
}

/* parallax helper (JS toggles transform via inline style) */
.parallax-el { will-change: transform; }
