/* ============================================================
   JC PLUMBING AND BOILER SOLUTIONS — the brand layer.

   Loads AFTER css/aw-base.css, which is AnchorWorks' production
   stylesheet (Three/css/styles-kk.css) copied UNMODIFIED from the
   anchorworks-website repo on 16 Sep 2026. Every component, spacing
   value, easing and transition on these pages is his. This file adds
   the pieces his homepage does not carry (they come from his HVAC
   report page: theme toggle, progress bar, chips, curtain-rise hero,
   outlined numerals, takeaways, pull quotes, print) and the handful
   of page-level layouts JC needs that his site does not (service
   chapters, the opt-in form card, the calendar frame, the video
   frame).

   THE RETINT SLOT (Chris, 16 Sep 2026): "design the whole thing
   based off the AnchorWorks brand, then tweak the color scheme at
   the end, and then replace the photos and logos at the end."
   So the palette below is AnchorWorks' own, on purpose. When Chris
   picks JC's colours, edit ONLY the two :root blocks marked RETINT.
   Nothing else in this file or in any page names a colour.

   Sources: DESIGN-SYSTEM.md · Three/css/styles-kk.css ·
   Three/hvac-report/index.html (inline <style>) · Three/js/main-kk.js
   ============================================================ */

/* ============================================================
   1. TOKENS
   ============================================================ */
:root{
  /* ======= RETINT · DARK — "Graphite and navy". Chris, 16 Sep. =======
     Dark stays the DEFAULT (expressed as NO data-theme attribute, as before).
     Light is what the toggle goes to. Chris: "let's start with dark mode, and
     then they're allowed to switch to light mode."

     ⛔ WHY THERE IS NO WARM METAL LEFT ANYWHERE IN THIS FILE.
     A near-black page plus one warm metal accent IS the AnchorWorks recipe, and
     this site is built on AnchorWorks' layout, so any copper or brass accent made
     it read as Chris's brand wearing Jeremy's name. Chris ruled twice: "that's
     too similar to AnchorWorks... we can't just copy our brand into his", then,
     on a navy-and-brass option, "the reason why I don't want to do the brass in
     navy is because it looks too much like AnchorWorks." So TWO things changed
     together, and neither works without the other: the ground LIFTED out of
     near-black into mid graphite, and the only hue left on the page is navy.

     ⛔ THE LOGO IS NOT THE BRIEF. An earlier pass derived candidate palettes from
     Jeremy's mark (cobalt drop, steel letters, copper ring). Chris killed it:
     "his logo is ugly and I don't want his entire website looking like his logo.
     That would be ugly. We need to recommend what makes him look professional
     and trustworthy in his town. We are the consultants." The mark is a
     CONSTRAINT — it sits at 40px in the header and must not clash. It is not a
     colour source. Do not sample it again.

     Navy is not taste. ui-ux-pro-max's landing pattern `trust-authority-conversion`
     states the strategy verbatim: "Navy/Grey corporate. Trust blue. Accent for CTA
     only." Its Home Services and Legal Services palettes both lead with deep blue.
     Strategy kept, execution raised: deep navy, never that pattern's stock royal
     blue #1E40AF, and none of its alarm orange — those are the template version
     every plumber in America already has.

     ⚠ --gold is a LEGACY NAME owned by aw-base.css, which is untouchable and holds
     65 references to it. It now carries NAVY. Re-point it; never rename it. */
  --ocean:#26292C; --ocean-2:#2F3337; --panel:#22262A; --charcoal:#1F2225; --charcoal-2:#191C1E;
  --bone:#ECEEF0; --steel:#A9B0B6;
  --gold:#5E9BC9; --gold-deep:#3E7BA8; --gold-bright:#9AC6E8;
  --bone-dim:rgba(236,238,240,.72); --bone-faint:rgba(236,238,240,.60);
  --hairline:rgba(236,238,240,.13); --hairline-2:rgba(236,238,240,.07);
  --gold-glow:rgba(94,155,201,.24); --gold-tint:rgba(94,155,201,.10);
  --gold-line:rgba(94,155,201,.32);       /* card/icon borders that aw-base hard-codes */
  --gold-line-hi:rgba(154,198,232,.55);   /* hover border */
  --on-gold:#0C1218;                      /* text on a navy button */
  /* The button keeps its own two gradient stops, the shape the copper palette
     established. On DARK it runs the LIGHT half of the navy range under dark ink:
     measured 10.42:1 at stop A and 6.28:1 at stop B. */
  --btn-a:var(--gold-bright); --btn-b:var(--gold);
  /* ink for labels sitting ON --gold-tint (the takeaway title). Alpha-composited
     against all eight grounds this tint can sit on: 6.11:1 worst case. */
  --tint-ink:var(--gold-bright);
  /* ⛔ NEW — the neutral the dosage cut moves ten roles onto. See §12.
     The rule: the accent means "press me". Anything that is not the primary
     button or the one press-me link takes --label instead. */
  --label:#A9B0B6; --label-line:rgba(169,176,182,.55); --neutral-tint:rgba(169,176,182,.10);
  --alert:#F2848C;                        /* emergency only. Nothing uses it yet. */
  --grain-o:.42; --ledger:rgba(236,238,240,.045);
  --card-top:var(--ocean-2); --card-bot:var(--charcoal);   /* card gradient ends */
  --veil:25,28,30;                                          /* rgb triple for photo veils */
  --frost:rgba(25,28,30,.86);                               /* scrolled header */
  --overlay:rgba(21,24,26,.97);                             /* mobile nav */

  /* aliases used by the report-derived components */
  --bg:var(--ocean); --bg-alt:var(--panel); --bg-deep:var(--charcoal); --bg-card:#2B2F32;
  --ink:var(--bone); --ink-dim:var(--bone-dim); --ink-faint:var(--bone-faint);
  --accent:var(--gold); --accent-hi:var(--gold-bright);
  /* Accent used as SMALL TEXT. On DARK it runs the LIGHT half of the navy range:
     7.04:1 worst case (on a card top), 9.47:1 best. */
  --accent-text:var(--gold-bright);

  /* the one number every page shares: the sticky header height (anchor offset) */
  --hdr-h:68px;
}

/* ---- RETINT · LIGHT — "White and navy". The toggle, not the default. ---- */
:root[data-theme="light"]{
  /* Chris: "when I press the light version it looks gorgeous" - so the FORM is
     unchanged, only the hue. The page is paper white, the ink is near-black, and
     navy darkens here so it still clears AA on white. Same accent family as dark,
     so the two themes are ONE palette at two exposures rather than two designs.
     Every value below was alpha-composited against all eight grounds it can sit
     on BEFORE it was written: 0 failures, 5.67:1 worst case. */
  --ocean:#F7F8F9; --ocean-2:#FFFFFF; --panel:#FFFFFF; --charcoal:#EDF0F2; --charcoal-2:#E3E7EA;
  --bone:#101820; --steel:#4E5A66;
  --gold:#17527F; --gold-deep:#0F3A5C; --gold-bright:#17527F;
  /* ⚠ --gold-bright is deliberately EQUAL to --gold here, not lighter. On a white
     page a "brighter" navy is a contrast failure everywhere aw-base uses
     --gold-bright as TEXT (.ocard__sub, .svc__usp, .share-link input,
     .header-tel:hover). Holding them equal makes that whole class of bug
     impossible. Hover emphasis is carried by --gold-line-hi, a border, instead. */
  --bone-dim:rgba(16,24,32,.82);
  /* The old light palette ran dim .75 / faint .72 — one point apart, which is not
     a hierarchy step. Reopened to .82 / .66 now the ink is darker and the page is
     lighter. .66 still measures 6.37:1 on the DEEPEST ground (--charcoal-2), and
     that is the one that fails first: never audit a faint token on --ocean alone. */
  --bone-faint:rgba(16,24,32,.66);
  --hairline:rgba(16,24,32,.13); --hairline-2:rgba(16,24,32,.07);
  --gold-glow:rgba(23,82,127,.22); --gold-tint:rgba(23,82,127,.09);
  --gold-line:rgba(23,82,127,.30); --gold-line-hi:rgba(23,82,127,.55);
  --on-gold:#FFFFFF;
  --btn-a:var(--gold); --btn-b:var(--gold-deep);
  --tint-ink:var(--gold-deep);
  /* On LIGHT the accent text runs the DARK half: 6.62:1 worst case. */
  --accent-text:var(--gold);
  --label:#4E5A66; --label-line:rgba(78,90,102,.55); --neutral-tint:rgba(78,90,102,.09);
  --alert:#B3261E;
  --grain-o:.22; --ledger:rgba(16,24,32,.06);
  --card-top:#FFFFFF; --card-bot:#F5F7F8;
  --veil:247,248,249;
  --frost:rgba(247,248,249,.88);
  --overlay:rgba(247,248,249,.98);
  --bg-card:#FFFFFF;
  --shadow-soft:0 30px 80px -30px rgba(16,24,32,.18);
  --shadow-card:0 20px 50px -30px rgba(16,24,32,.28);
}
/* ============================================================
   1B. THE TEXTURE AND THE TYPE — what makes it Jeremy's, not Chris's
   ============================================================ */

/* His logo's letters are milled out of brushed steel, so the ground is brushed
   steel too. Same component, same opacity machinery, different material.
   assets/steel-tile.webp is generated seamless (512x512) - see the build note. */
:root{ --grain:url("../assets/steel-tile.webp"); }

/* Headlines: plain, big and bold, the way Chris asked for. DM Serif Display is
   AnchorWorks' signature and it is the single loudest reason the page read as
   AnchorWorks. --serif now points at Inter so every h1-h4 in aw-base follows
   without touching his file; weight and tracking are set here because aw-base
   sets headings to 400. */
:root{ --serif:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; }
h1,h2,h3,h4{font-weight:800;letter-spacing:-.032em;line-height:1.03}
/* ⚠ Headings had NO wrap rule, so a heading could drop its last word onto a
   line of its own ("...Your Home Depends / On."). `balance` evens the lines of
   a short block, which is exactly what a headline is. aw-base only ever set
   this on .hero h1; every other heading was unprotected. */
h1,h2,h3,h4,.bridge__t,.brand__word{text-wrap:balance}
h3,h4{letter-spacing:-.022em}
/* his emphasis spans were italic serif; italic sans reads cheap, so emphasis is
   carried by COLOUR and weight instead */
h1 em,h2 em,h3 em,.magnetstrip__copy h3 em,blockquote em{font-style:normal;font-weight:800;color:var(--gold-bright)}
/* ⚠ aw-base sets `.hero h1 em{white-space:nowrap}`. That is safe on his site,
   where an emphasis is two short words. JC's is a three-word OFFER NAME
   ("Water Safety Inspection"), and Inter 800 is far wider per character than
   DM Serif Display, so it laid out as one 824px line that painted straight
   over the form card. Emphasis may wrap; text-wrap:balance keeps it tidy. */
.hero h1 em{white-space:normal}
.brand__word{font-family:var(--sans);font-weight:800;letter-spacing:-.022em;line-height:1.05}
/* mirrors the logo's own lockup: PLUMBING large, AND BOILER SOLUTIONS small
   beneath it. This is a wordmark, not body copy, so it sits below the 14px
   content floor on purpose. */
.brand__word small{display:block;font-size:.72rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--gold);margin-top:.22rem}
.footer__brand .brand__word small{color:var(--gold)}
.pull{font-family:var(--sans);font-weight:700;letter-spacing:-.022em;line-height:1.22}
.numeral{font-family:var(--sans);font-weight:800;letter-spacing:-.04em}
.stat__num{font-family:var(--sans);font-weight:800;letter-spacing:-.035em}
.letter__salute{font-family:var(--sans);font-weight:800;letter-spacing:-.028em}
.founder blockquote{font-family:var(--sans);font-weight:700;letter-spacing:-.02em;line-height:1.25}
.faq__q{font-family:var(--sans);font-weight:700;letter-spacing:-.015em}
/* the two italic-serif support lines become plain, confident sans */
.ocard__sub{font-family:var(--sans);font-style:normal;font-weight:700;font-size:1rem;letter-spacing:-.01em}
.svc__usp{font-family:var(--sans);font-style:normal;font-weight:700;letter-spacing:-.018em}
.reason{font-family:var(--sans);font-style:normal;font-weight:700;letter-spacing:-.015em}
.fnote__sig{font-family:var(--sans);font-style:normal;font-weight:800;letter-spacing:-.02em;font-size:1.35rem}
.bridge__t{font-family:var(--sans);font-weight:800;letter-spacing:-.022em}
.cal-help .tel{font-family:var(--sans);font-weight:800;letter-spacing:-.03em}

/* The mark is his real logo, full colour, on both themes. It carries the copper
   ring and the steel letters, so nothing else has to shout. */
.brand img,.footer__brand .brand img{height:40px;width:auto}
.letter__sign img,.founder__sign img{width:48px;height:48px}

body{transition:background-color .35s var(--ease),color .35s var(--ease)}
/* his theme-aware pieces that hard-code a dark rgba in aw-base.css */
.site-header.is-scrolled{background:var(--frost)}
.btn--primary,.btn--primary:hover{background:linear-gradient(135deg,var(--btn-a),var(--btn-b));color:var(--on-gold)}
.btn--dark{background:color-mix(in srgb,var(--charcoal) 60%,transparent)}
.adv,.ocard,.tcard,.scorecard{background:linear-gradient(180deg,var(--card-top),var(--card-bot))}
.adv:hover,.ocard:hover,.tcard:hover{border-color:var(--gold-line-hi)}
.adv__icon,.step__num,.tcard__av{border-color:var(--gold-line)}
.adv--primary,.ocard--paid{border-color:var(--gold-line)}
.hero__badge{background:color-mix(in srgb,var(--charcoal) 40%,transparent)}
.magnetstrip{background:var(--charcoal)}
.inline-form input{background:var(--ocean);color:var(--bone)}
.site-footer{background:var(--charcoal-2)}
.topbar{background:var(--charcoal-2)}
::selection{background:var(--gold);color:var(--on-gold)}
.hero__bg::after{background:
  radial-gradient(120% 80% at 50% 0%,rgba(var(--veil),.05),rgba(var(--veil),.55) 70%,var(--ocean) 100%),
  linear-gradient(180deg,rgba(var(--veil),.45) 0%,rgba(var(--veil),.30) 40%,var(--ocean) 100%)}
.finale__bg::after{background:radial-gradient(100% 100% at 50% 50%,rgba(var(--veil),.4),var(--charcoal) 80%)}
.grain-plate::after{background:radial-gradient(120% 125% at 50% 48%,transparent 50%,rgba(var(--veil),.35) 100%)}
.grain-plate::before,.hero__grain,.adv::before,.scorecard::after{opacity:var(--grain-o)}
:root[data-theme="light"] .hero__bg img{opacity:.42}
:root[data-theme="light"] .hero__bg::after{background:
  radial-gradient(120% 80% at 50% 0%,rgba(var(--veil),.35),rgba(var(--veil),.7) 70%,var(--ocean) 100%),
  linear-gradient(180deg,rgba(var(--veil),.55) 0%,rgba(var(--veil),.35) 40%,var(--ocean) 100%)}
:root[data-theme="light"] .finale__bg img{opacity:.14}
:root[data-theme="light"] .brand__mark--dark,:root[data-theme="light"] .logo--dark{display:block}
:root[data-theme="light"] .brand__mark--light,:root[data-theme="light"] .logo--light{display:none}
.brand__mark--dark,.logo--dark{display:none}
@media (max-width:980px){ .nav{background:var(--overlay)} }

/* ---- The overlay's own CTA. Shown wherever the nav is collapsed. ---- */
.nav__cta{display:none}
@media (max-width:1100px){
  .nav__cta{display:block;margin-top:1.4rem;text-align:center;border-bottom:0 !important;
    background:linear-gradient(135deg,var(--gold-bright),var(--gold) 55%,var(--gold-deep));
    color:var(--on-gold) !important;font-family:var(--sans);font-weight:700;font-size:1.05rem !important;
    letter-spacing:.02em;border-radius:var(--radius);padding:1rem 1.4rem !important}
}

/* ============================================================
   2. CHROME — progress bar, theme toggle, header additions
   ============================================================ */
.progress{position:fixed;top:0;left:0;height:2px;width:0;z-index:210;pointer-events:none;
  background:linear-gradient(90deg,var(--gold-deep),var(--gold-bright));transition:width .08s linear}

.theme-toggle{width:38px;height:38px;border-radius:10px;cursor:pointer;border:1px solid var(--hairline);
  background:transparent;color:var(--bone-dim);display:inline-flex;align-items:center;justify-content:center;flex:none;
  transition:border-color .25s var(--ease),color .25s var(--ease)}
.theme-toggle:hover{border-color:var(--gold);color:var(--gold)}
.theme-toggle svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
:root[data-theme="light"] .icon-sun{display:none}
:root:not([data-theme="light"]) .icon-moon{display:none}

/* brand = monogram + serif wordmark. Swapping the logo later is one <img>. */
.brand{display:inline-flex;align-items:center;gap:.7rem;color:var(--bone)}
.brand img{height:34px;width:auto}
.brand__word{font-family:var(--serif);font-size:1.22rem;letter-spacing:.01em;line-height:1;white-space:nowrap}
/* the wordmark sub-line is defined once, in §1B. */

/* phone in the header: a ghost pill on desktop, an icon-only button on phones */
.header-tel{display:inline-flex;align-items:center;gap:.5rem;flex:none;padding:.62rem .95rem;border-radius:var(--radius);
  border:1px solid var(--hairline);color:var(--bone);font-size:.9rem;font-weight:600;white-space:nowrap;
  transition:border-color .3s var(--ease),color .3s var(--ease),transform .3s var(--ease)}
.header-tel svg{width:16px;height:16px;stroke:var(--gold);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.header-tel:hover{border-color:var(--gold);color:var(--gold-bright);transform:translateY(-2px)}
.header-tel span{display:inline}
/* The header carries six nav items, a toggle, a phone and a button. That row
   is wider than the viewport until ~1480px, so the phone drops to icon-only
   EARLIER than the nav collapses. Raised 1180 -> 1479 on 16 Sep: with the nav
   no longer allowed to shrink (see the nav block below), the full phone label
   made the row overflow by 38px at 1400px. The number is still one tap away on
   the icon; it returns to a labelled pill at 1480px, verified 1479 vs 1480. */
@media (max-width:1479px){
  .header-tel{width:42px;height:42px;padding:0;justify-content:center;border-radius:10px}
  .header-tel span{display:none}
  .header-cta{gap:.6rem}
}
.nav a.is-active{color:var(--bone)}

/* JC's header is heavier than his: a wordmark beside the mark, six nav items,
   a theme toggle, a phone and a button. Measured at 1440px the row wanted
   1173px inside a 1144px container, so .brand shrank and the nowrap wordmark
   spilled straight over "Boilers". The brand never shrinks; the nav gives up
   the space instead. */
@media (min-width:981px){ .brand{flex:none} }
@media (max-width:1479px){ .nav{gap:1rem} }

/* ⛔ NAV LABELS NEVER BREAK MID-LABEL, AND THE NAV NEVER SHRINKS. 16 Sep.
   Three of the six labels ("Sewer & Drains", "Emergency Service", "Safety
   Inspection") rendered as TWO lines at 1280px, doubling the header height.

   The cause is NOT overflow, and this is the trap: `.nav` is `flex: 0 1 auto`,
   so flex SHRANK the nav box and the labels wrapped inside it. Measuring the
   .nav BOX says everything fits (552px inside a 1240px row) while the LINKS
   run 84px past its right edge, straight under the phone pill. Measure the
   links, never the box — the same mistake as measuring .chapter-head instead
   of the headline.

   So nowrap alone is NOT enough: it converts a wrap into an OVERLAP. It must
   be paired with flex:none, and the burger breakpoint must sit at the width
   where the row genuinely fits. Six labels need 523px of text plus gaps; with
   the phone icon-only the whole row needs ~1180px. The old 1100px breakpoint
   was ~80px too low, so 1101-1179px was showing a nav that never fitted.

   Measured after, links-to-CTA gap / horizontal overflow:
     1179 burger, 0  ·  1180 +24, 0  ·  1280 +42, 0  ·  1479 +40, 0  ·  1480 +24, 0 */
@media (min-width:1180px){
  .site-header .nav{flex:none}
  .site-header .nav a{white-space:nowrap}
}
/* Below 1180px the row cannot hold six labels at any gap, so it collapses to
   the burger. These are his own 980px overlay rules, mirrored up here — the
   NAV ones only, not the grid changes in the same block. Below 980 both blocks
   apply and say the same thing, which is harmless. white-space returns to
   normal because in the overlay the links are stacked rows that MUST wrap. */
@media (max-width:1179px){
  .nav{position:fixed;inset:0 0 auto;top:0;flex-direction:column;align-items:stretch;
    background:var(--overlay);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    padding:6rem 2rem 2.5rem;gap:.3rem;transform:translateY(-100%);
    transition:transform .5s var(--ease);height:100vh;z-index:55;overflow-y:auto}
  .nav.is-open{transform:none}
  .nav a{font-size:1.3rem;padding-block:1rem;border-bottom:1px solid var(--hairline-2);
    white-space:normal}
  .nav a::after{display:none}
  .nav-toggle{display:flex;z-index:60}
  .header-cta .btn{display:none}
}

/* ============================================================
   3. HERO ADDITIONS — the report page's curtain rise + drift
   ============================================================ */
@keyframes heroIn{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
@keyframes heroDrift{from{transform:scale(1.10)}to{transform:scale(1.02)}}
@media (prefers-reduced-motion:no-preference){
  .hero--rise .hero__badge,.hero--rise h1,.hero--rise .hero__sub,.hero--rise .hero__lines,.hero--rise .adventure,.hero--rise .hero__actions,.hero--rise .scroll-cue{
    opacity:0;animation:heroIn .9s var(--ease) forwards}
  .hero--rise .hero__badge{animation-delay:.15s}
  .hero--rise h1{animation-delay:.32s}
  .hero--rise .hero__sub{animation-delay:.58s}
  .hero--rise .hero__lines{animation-delay:.74s}
  .hero--rise .adventure,.hero--rise .hero__actions{animation-delay:.95s}
  .hero--rise .scroll-cue{animation-delay:1.7s}
  .hero--rise .hero__bg img{animation:heroDrift 14s var(--ease) forwards}
}
.hero--rise .hero__bg img{object-position:62% 30%}
.hero{padding-block:clamp(4.5rem,3rem + 7vw,8rem) clamp(4.5rem,3rem + 6vw,8rem)}
.hero h1{max-width:16ch}
.hero__lines{font-size:var(--fs-lead);color:var(--bone-dim);max-width:58ch;margin:-.4rem auto 2.6rem;line-height:1.55}
.hero__lines span{display:block;text-wrap:balance}
.hero__lines strong{color:var(--bone);font-weight:700;display:block;margin-top:.9rem;text-wrap:balance}
.scroll-cue{position:absolute;bottom:1.6rem;left:50%;transform:translateX(-50%);z-index:2;color:var(--bone-faint);
  font-size:.7rem;letter-spacing:.3em;text-transform:uppercase}
.scroll-cue::after{content:"";display:block;width:1px;height:34px;margin:.7rem auto 0;
  background:linear-gradient(180deg,var(--gold),transparent);animation:cue 2.2s var(--ease) infinite}
@keyframes cue{0%{transform:scaleY(0);transform-origin:top}45%{transform:scaleY(1);transform-origin:top}
  55%{transform:scaleY(1);transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}
@media (max-width:760px){.scroll-cue{display:none}}
/* the two doors: the adventure card is already his; icons get a hairline ring */
.adv__icon svg{stroke-width:1.7}
.adventure{margin-top:.4rem}

/* chips (report page) — small uppercase pills */
.chip{display:inline-flex;align-items:center;gap:.4rem;font-size:.74rem;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;padding:.34em .85em;border-radius:999px;border:1px solid var(--hairline);color:var(--bone-dim)}
.chip--gold{color:var(--gold);border-color:var(--gold-line);background:var(--gold-tint)}
.chips{display:flex;flex-wrap:wrap;gap:.6rem}
.chips--center{justify-content:center}

/* ============================================================
   4. TYPE ADDITIONS
   ============================================================ */
.section-head .lead{margin-top:0}
.section-head--center .lead{margin-inline:auto}
.h2--tight{letter-spacing:-.015em}
.lines p{margin-bottom:.35rem;color:var(--bone-dim)}
.lines p:last-child{margin-bottom:0}
.lines p strong{color:var(--bone);font-weight:600}
.lines--lead p{font-size:var(--fs-lead);line-height:1.5}
.lines--letter p{font-size:var(--fs-letter);line-height:1.55}
.lines--tight p{margin-bottom:.15rem}
.lines--close p:last-child{color:var(--bone);font-weight:600;font-size:1.06em;margin-top:.6rem}

/* ---- Orphans ----
   Chris, 16 Sep: "the last line of every third sentence is just one or two
   words at the bottom, so it just creates these really ugly, not proportioned
   paragraphs." That is an orphan, and the browser will fix it if asked:
   text-wrap:pretty makes the line breaker look ahead and steal a word from the
   line above rather than leave one stranded. h1-h3 keep `balance`, which is
   the right algorithm for short headings. Both degrade to normal wrapping on
   older browsers, so nothing breaks. */
/* Body paragraphs on these pages are short, 2-4 lines, which is exactly the
   range `balance` is for: it evens every line instead of only guarding the
   last one. `pretty` was leaving "the spot." / "its job." / "the truth."
   stranded on their own line. Browsers cap `balance` at a handful of lines and
   fall back to normal wrapping beyond that, so a long paragraph is unaffected
   and nothing can break. */
p,li,figcaption{text-wrap:pretty}
.lines--lead p,
.takeaway p,
.ocard p,
.step p{text-wrap:balance}
/* left-aligned body prose FILLS its measure; only the last line is protected */
.lines--letter p,
.prose-narrow p,
.svc__body p,
.faq__a-inner p,
.letter__inner p{text-wrap:pretty}
/* a chapter lead is one short sentence by definition, which is the length
   `balance` handles best. It out-specifies the .prose-narrow p rule above. */
.prose-narrow p.chapter-lead,
p.chapter-lead{text-wrap:balance}
/* ⚠ `pretty` only protects the LAST line. On a SHORT CENTRED block it still
   leaves "explain why." and "say yes." stranded, because it never rebalances
   the lines above. `balance` equalises every line in the block, which is
   exactly what centred text needs and what it was designed for (browsers cap
   it at a handful of lines, so it is safe to apply broadly here).
   Chris, 16 Sep, on the Honest Plumber Promise. */
.guarantee-banner p,
.section-head--center .lead,
.section-head--center p,
.book-sub,
.undervideo,
.microcopy,
.chapter-lead,
.pull,
.hero__sub,
.magnetstrip__copy p{text-wrap:balance}

/* pull quote that underlines its own gold phrase (report page) */
.pull{font-family:var(--serif);font-size:clamp(1.5rem,1.15rem + 1.6vw,2.3rem);line-height:1.28;color:var(--bone);
  text-align:center;max-width:26em;margin:2.8rem auto}
.pull .text-gold{background-image:linear-gradient(var(--gold-bright),var(--gold-bright));background-repeat:no-repeat;
  background-position:0 96%;background-size:0% 1.5px;transition:background-size .9s var(--ease) .5s}
.pull.is-in .text-gold{background-size:100% 1.5px}

/* outlined serif numeral (report page chapter mark) */
.numeral{font-family:var(--serif);font-size:clamp(3.2rem,2.2rem + 3.4vw,5.4rem);line-height:.9;color:transparent;
  -webkit-text-stroke:1px color-mix(in srgb,var(--gold) 60%,transparent);display:block;margin-bottom:.6rem;user-select:none}

/* takeaway (report page) — a note with a gold tab */
.takeaway{border:1px solid color-mix(in srgb,var(--gold) 40%,transparent);background:var(--gold-tint);
  padding:1.5rem 1.7rem;margin-top:1.6rem;position:relative;border-radius:0 var(--radius) var(--radius) 0}
.takeaway::before{content:"";position:absolute;top:-1px;left:1.7rem;width:56px;height:2px;background:var(--gold);
  transition:width .7s var(--ease) .35s}
.takeaway.reveal::before{width:0}
.takeaway.reveal.is-in::before{width:56px}
.takeaway__title{display:flex;align-items:center;gap:.6rem;font-weight:700;font-size:var(--fs-sm);
  letter-spacing:.08em;text-transform:uppercase;color:var(--tint-ink);margin-bottom:.5rem}
.takeaway__title svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.takeaway p{font-size:var(--fs-sm);color:var(--bone-dim);margin:0 0 .4rem}
.takeaway p:last-child{margin-bottom:0}
.takeaway p strong{color:var(--bone)}

/* gold-check list = his .book__list, with a 2-column option */
.book__list li span{color:var(--bone-dim)}
.book__list--2{grid-template-columns:1fr 1fr;column-gap:1.6rem}
@media (max-width:620px){.book__list--2{grid-template-columns:1fr}}
.book__list--x svg{stroke:var(--bone-faint)}

/* ============================================================
   5. HOMEPAGE LAYOUTS
   ============================================================ */
/* stats band footnote */
.stats__note{text-align:center;color:var(--bone-faint);font-size:.86rem;margin-top:1.4rem}
.stat__num--text{font-size:clamp(1.9rem,1.3rem + 2vw,3rem)}

/* the letter — his .letter, JC's salutation is a statement not a greeting */
.letter__salute{max-width:22ch}
/* His own markup sizes the signature mark with an inline style
   (width:44px;height:44px). We size it in CSS instead, because JC's mark is a
   nearly square 640x557 house monogram and unsized it renders ~150px tall and
   swallows the signature block. */
.letter__sign img,.founder__sign img{width:44px;height:44px;object-fit:contain;border-radius:10px;flex:none}

/* the method: his .platform__grid + .steps, with a rule that draws down between the numerals */
.steps--draw{position:relative;padding-left:0}
.steps--draw::before{content:"";position:absolute;left:21px;top:42px;bottom:42px;width:1px;
  background:linear-gradient(180deg,var(--gold),var(--gold-line));opacity:.7;transform:scaleY(0);transform-origin:top;
  transition:transform 1.1s var(--ease) .25s}
.steps--draw.is-in::before{transform:scaleY(1)}
.steps--draw .step__num{position:relative;z-index:1;background:var(--ocean)}
.section--alt .steps--draw .step__num{background:var(--panel)}
.section--deep .steps--draw .step__num{background:var(--charcoal)}
.steps--draw .step{opacity:0;transform:translateY(14px);transition:opacity .6s var(--ease),transform .6s var(--ease)}
.steps--draw.is-in .step{opacity:1;transform:none}
.steps--draw.is-in .step:nth-child(2){transition-delay:.22s}
.steps--draw.is-in .step:nth-child(3){transition-delay:.44s}
.steps--draw.is-in .step:nth-child(4){transition-delay:.66s}
@media (prefers-reduced-motion:reduce){.steps--draw::before{transform:none}.steps--draw .step{opacity:1;transform:none}}
.step .lines p{font-size:.98rem}
.platform__media img{aspect-ratio:4/5;object-position:60% 50%}
@media (max-width:980px){.platform__media img{aspect-ratio:16/10}}

/* horizontal steps row — "what happens when you call" */
.steps--row{grid-template-columns:repeat(4,1fr);gap:1.6rem 1.4rem;margin-top:2.6rem}
.steps--row .step{flex-direction:column;gap:1rem}
.steps--row .step h3{font-size:1.25rem}
.steps--row::before{top:21px;left:42px;right:42px;bottom:auto;width:auto;height:1px;
  background:linear-gradient(90deg,var(--gold),var(--gold-line));transform:scaleX(0);transform-origin:left}
.steps--row.is-in::before{transform:scaleX(1)}
@media (max-width:980px){.steps--row{grid-template-columns:1fr 1fr}.steps--row::before{display:none}}
@media (max-width:520px){.steps--row{grid-template-columns:1fr}}

/* the founder story as a letter under his founder grid */
.founder__story{max-width:var(--container-narrow);margin:3.5rem auto 0}
.founder__photo img{object-position:64% 40%}
.founder blockquote{text-wrap:balance}

/* service overview cards: numbered tags */
.ocard__tag .n{color:var(--bone-faint);margin-right:.5rem}
.ocard__sub{font-family:var(--serif);font-weight:400;font-size:1.05rem;font-style:italic;color:var(--gold-bright)}

/* ---- service chapters ---- */
.svc{display:grid;grid-template-columns:.9fr 1.1fr;gap:clamp(2rem,1rem + 4vw,5rem);align-items:start}
.svc__intro{position:sticky;top:calc(var(--hdr-h) + 1.5rem)}
.svc__intro h2{margin-bottom:1rem}
.svc__usp{font-family:var(--serif);font-style:italic;font-size:clamp(1.25rem,1.1rem + .7vw,1.6rem);color:var(--gold-bright);
  line-height:1.3;margin:1.4rem 0 1.8rem;border-left:2px solid var(--gold);padding-left:1.2rem}
.svc__body{background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--hairline);
  border-radius:var(--radius-lg);padding:clamp(1.6rem,1.2rem + 1.5vw,2.4rem);position:relative;overflow:hidden;box-shadow:var(--shadow-card)}
.svc__body::before{content:"";position:absolute;inset:0;background-image:var(--grain);background-repeat:repeat;
  opacity:calc(var(--grain-o)*.4);mix-blend-mode:overlay;pointer-events:none}
.svc__body>*{position:relative}
.svc__body .lines p{font-size:1rem}
.svc__body h3{font-size:1.25rem;margin:1.6rem 0 .8rem}
.svc__body h3:first-child{margin-top:0}
.svc__body .book__list{margin:1rem 0 0}
.svc__body .book__list li{font-size:.97rem}
@media (max-width:980px){.svc{grid-template-columns:1fr}.svc__intro{position:static}}

/* the one accent plate: the Safety Inspection */
.svc--feature{text-align:center}
.svc--feature .section-head{margin-inline:auto}
.svc--feature__grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.5rem,1rem + 2vw,3rem);max-width:980px;margin:2.6rem auto 0;text-align:left}
.svc--feature .svc__body{height:100%}
.svc--feature .outcomes{display:grid;gap:.9rem;margin-top:.4rem}
.svc--feature .outcome{display:flex;gap:.9rem;align-items:flex-start;padding:1rem 1.1rem;border:1px solid var(--hairline);border-radius:var(--radius)}
.svc--feature .outcome .step__num{width:36px;height:36px;font-size:1.05rem;border-radius:9px}
.svc--feature .outcome p{color:var(--bone);font-weight:500;margin:0;padding-top:.45rem}
@media (max-width:820px){.svc--feature__grid{grid-template-columns:1fr}}
.feature-icon{width:64px;height:64px;margin:0 auto 1.6rem;border-radius:16px;display:grid;place-items:center;
  background:var(--gold-tint);border:1px solid var(--gold-line)}
.feature-icon svg{width:30px;height:30px;stroke:var(--gold);fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}

/* background photo bands (faded, texture not portrait) */
.band-photo{position:relative;overflow:hidden}
.band-photo__img{position:absolute;inset:0;z-index:0}
.band-photo__img img{width:100%;height:100%;object-fit:cover;opacity:.18;filter:saturate(.7)}
.band-photo__img::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,var(--charcoal) 0%,rgba(var(--veil),.55) 50%,var(--charcoal) 100%)}
.band-photo>.container{position:relative;z-index:2}
:root[data-theme="light"] .band-photo__img img{opacity:.14}

/* FAQ: his accordion, JC's headline sits centred */
.faq__q{font-size:clamp(1.1rem,1rem + .5vw,1.35rem)}
.faq__a-inner p{margin-bottom:.35rem}
.faq__a-inner p:last-child{margin-bottom:0}

/* finale note fits a longer trust line */
.finale .finale__note{max-width:520px;font-size:.74rem}
.finale__bg img{object-position:50% 40%}

/* footer: JC only has three real columns */
.footer__grid{grid-template-columns:1.8fr 1fr 1fr 1.2fr}
.footer__brand .brand{margin-bottom:1rem}
.footer__brand img{height:32px;margin-bottom:0}
.footer__meta{color:var(--bone-faint);font-size:.9rem;line-height:1.7;margin-top:.8rem}
.footer__meta strong{color:var(--bone-dim);font-weight:600}
@media (max-width:980px){.footer__grid{grid-template-columns:1fr 1fr}.footer__brand{grid-column:1/-1}}
@media (max-width:620px){.footer__grid{grid-template-columns:1fr}}

/* ============================================================
   6. FUNNEL PAGES — opt-in · calendar · thank-you
   ============================================================ */
.funnel-header{position:sticky;top:0;z-index:60;border-bottom:1px solid transparent;
  transition:background .4s var(--ease),border-color .4s var(--ease)}
.funnel-header.is-scrolled{background:var(--frost);backdrop-filter:blur(14px) saturate(140%);-webkit-backdrop-filter:blur(14px) saturate(140%);border-bottom-color:var(--hairline)}
.funnel-header__inner{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding-block:.9rem}
.funnel-header .header-cta{gap:.7rem}

/* the opt-in hero: copy left, form right */
.hero--funnel{text-align:left;padding-block:clamp(3rem,2rem + 5vw,6rem) clamp(3.5rem,2rem + 5vw,6.5rem)}
.hero--funnel .hero__inner{text-align:left}
.hero--funnel .hero__grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(2rem,1rem + 4vw,5rem);align-items:center}
/* the clamp was tuned for a serif; Inter 800 needs less size to carry the same
   weight, and this h1 only ever gets half the page */
.hero--funnel h1{margin-inline:0;max-width:15ch;font-size:clamp(2.2rem,1.3rem + 2.9vw,3.7rem)}
.hero--funnel .hero__sub{margin-inline:0;max-width:52ch}
.hero--funnel .eyebrow{color:var(--gold-bright)}
.hero--funnel .hero__bg img{object-position:30% 40%;opacity:.5}
.reason{font-family:var(--serif);font-style:italic;font-size:clamp(1.15rem,1rem + .8vw,1.5rem);line-height:1.35;color:var(--bone);
  border-left:2px solid var(--gold);padding:.3rem 0 .3rem 1.3rem;margin:0 0 1.6rem;max-width:40ch;position:relative}
.reason::before{content:"";position:absolute;left:-2px;top:0;bottom:0;width:2px;background:var(--gold);
  transform:scaleY(0);transform-origin:top;transition:transform .9s var(--ease) .9s}
.hero--rise .reason::before{transform:scaleY(1)}
.hero--funnel .reason{border-left-color:transparent}
.hero--funnel .reason::before{transform:scaleY(1)}
.hero__enter{font-size:var(--fs-lead);color:var(--bone);font-weight:500;margin-bottom:1.6rem}
.hero--rise .reason,.hero--rise .hero__enter,.hero--rise .formcard,.hero--rise .proofline{opacity:0;animation:heroIn .9s var(--ease) forwards}
.hero--rise .reason{animation-delay:.74s}
.hero--rise .hero__enter{animation-delay:.9s}
.hero--rise .formcard{animation-delay:.5s}
.hero--rise .proofline{animation-delay:1.15s}
@media (prefers-reduced-motion:reduce){.hero--rise .reason,.hero--rise .hero__enter,.hero--rise .formcard,.hero--rise .proofline{opacity:1;animation:none}}
@media (max-width:980px){
  .hero--funnel .hero__grid{grid-template-columns:1fr;gap:2rem}
  .hero--funnel h1{max-width:100%}
  .hero--funnel .reason{margin-bottom:1rem}
}

/* the form card = his scorecard treatment */
.formcard{width:100%;max-width:460px;margin-inline:auto;
  background:linear-gradient(180deg,var(--card-top),var(--card-bot));border:1px solid var(--gold-line);border-radius:var(--radius-lg);
  padding:clamp(1.5rem,1.2rem + 1vw,2.1rem);box-shadow:var(--shadow-card);position:relative;overflow:hidden}
.formcard::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--gold),transparent)}
.formcard::after{content:"";position:absolute;inset:0;background-image:var(--grain);background-repeat:repeat;opacity:calc(var(--grain-o)*.45);mix-blend-mode:overlay;pointer-events:none}
.formcard>*{position:relative;z-index:1}
.formcard__head{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:1.3rem}
.formcard__label{font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold);font-weight:600}
.formcard__icon{width:30px;height:30px;stroke:var(--gold);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.field{margin-bottom:.9rem}
.field label{display:block;font-size:.8rem;font-weight:600;letter-spacing:.04em;color:var(--bone-dim);margin-bottom:.4rem}
.field input{width:100%;background:var(--ocean);border:1px solid var(--hairline);border-radius:var(--radius);color:var(--bone);
  padding:.95rem 1.1rem;font-size:1rem;font-family:var(--sans);transition:border-color .3s var(--ease),box-shadow .3s var(--ease)}
.field input::placeholder{color:var(--bone-faint)}
.field input:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px var(--gold-tint)}
.formcard .btn--block{margin-top:.4rem}
.microcopy{text-align:center;font-size:.86rem;color:var(--bone-dim);margin-top:.9rem}
/* texting consent boxes (optional, unticked) */
.smsconsent{display:flex;align-items:flex-start;gap:.65rem;margin:.2rem 0 .9rem}
.smsconsent input{flex:none;width:1.25rem;height:1.25rem;margin:.15rem 0 0;accent-color:var(--gold);cursor:pointer}
.smsconsent label{font-size:.78rem;line-height:1.5;color:var(--bone-dim);cursor:pointer}
.smsconsent label strong{color:var(--bone)}
.consent{font-size:.78rem;line-height:1.55;color:var(--bone-faint);margin-top:1rem;padding-top:1rem;border-top:1px solid var(--hairline-2)}
.consent a{color:var(--gold);text-decoration:underline;text-underline-offset:2px}
.proofline{display:flex;flex-wrap:wrap;gap:.5rem .6rem;margin-top:1.6rem}
.proofline .chip{font-size:.7rem}

/* objections as his ocards */
.objection h3{font-size:1.35rem}
.objection .lines p{font-size:.98rem}

/* second CTA: copy allows it only where the form has scrolled away (phones) */
.second-cta{display:none}
@media (max-width:980px){.second-cta{display:block}}

/* funnel footer */
.funnel-footer{background:var(--charcoal-2);border-top:1px solid var(--hairline);padding-block:2.6rem 2rem}
.funnel-footer__inner{display:grid;gap:.5rem;justify-items:center;text-align:center;color:var(--bone-faint);font-size:.86rem;line-height:1.7}
.funnel-footer__inner .brand{margin-bottom:.6rem}
.funnel-footer__inner strong{color:var(--bone-dim);font-weight:600}
.funnel-footer__inner a{color:var(--bone-dim);transition:color .3s var(--ease)}
.funnel-footer__inner a:hover{color:var(--gold)}

/* ---- The step bar, from his strategy-session booking page ----
   `Three/css/funnel.css` calls this component `.progress`. That name is
   already taken in this file by the 2px fixed scroll line on the homepage,
   so it is `.stepbar` here. Values are his, unchanged. */
.stepbar{max-width:640px;margin:0 auto 2.2rem}
.stepbar__label{display:flex;justify-content:space-between;align-items:baseline;
  font-size:.82rem;letter-spacing:.03em;color:var(--bone-dim);margin-bottom:.55rem}
.stepbar__label strong{color:var(--gold);font-weight:600}
.stepbar__track{height:10px;border-radius:100px;background:var(--hairline);overflow:hidden}
.stepbar__fill{height:100%;border-radius:100px;
  background:linear-gradient(90deg,var(--gold-deep),var(--gold-bright));
  transition:width .9s var(--ease)}
/* The fill's real width is an inline style, so if the script never runs the bar
   is already correct. Only html.js-anim - added by JS at the moment it wires the
   observer - collapses it to animate. Same opt-in rule as .reveal; see LEARNINGS
   2026-07-19, the day an unscoped hide blanked a live page. */
@media (prefers-reduced-motion:no-preference){
  .js-anim .stepbar__fill{width:0 !important}
  .js-anim .stepbar__fill.is-in{width:var(--pct) !important}
}

/* ---- The booking page. The calendar is the only thing on it. ----
   Chris, 16 Sep: no hero image, no big headline, no three-line subhead, and
   the calendar visible the moment the page opens on any screen. His own
   booking page centres the logo and drops everything else, so this does too. */
.funnel-header--center .funnel-header__inner{justify-content:center;position:relative}
.funnel-header--center .header-cta{position:absolute;right:0;top:50%;transform:translateY(-50%)}
.book-top{padding-block:clamp(1.8rem,1.2rem + 2vw,2.8rem) 0;text-align:center}
.book-top h1{font-size:clamp(1.9rem,1.25rem + 2.1vw,3rem);line-height:1.08;margin:0 auto;max-width:18ch;text-wrap:balance}
.book-top .book-sub{margin:.7rem auto 0;max-width:46ch;color:var(--bone-dim);font-size:var(--fs-lead);line-height:1.45}
.book-cal{padding-block:clamp(1.2rem,.8rem + 1.5vw,2rem) clamp(2.5rem,2rem + 2vw,4rem)}
.book-cal .ghl-cal{margin-top:0}
.book-note{text-align:center;margin-top:1.6rem;color:var(--bone-dim);font-size:.92rem;line-height:1.7}
.book-note strong{color:var(--bone);font-weight:600}
.book-note a{color:var(--gold);font-weight:600;white-space:nowrap}
@media (max-width:980px){
  .funnel-header--center .funnel-header__inner{justify-content:flex-start}
  .funnel-header--center .header-cta{position:static;transform:none;margin-left:auto}
}

/* compact step hero (calendar, thank-you) */
.hero--compact{min-height:0;padding-block:clamp(3.5rem,2.5rem + 4vw,6rem) clamp(3rem,2rem + 3vw,4.5rem);background:var(--charcoal)}
/* ⚠ CARRIED RULING (funnel.css §3, 15 Sep): the LEFT THIRD of the doorstep
   photograph carries a legible painted service list (PLUMBING / REPAIRS /
   WATER HEATERS / DRAIN CLEANING). It is placeholder art, but on screen it
   reads as another plumber's van on Jeremy's page. Panning right crops the
   lettering out and keeps the two figures, which were doing the work anyway.
   Nothing in the placeholder art may be read as a claim about Jeremy.
   A real photograph of Jeremy retires this rule. */
.hero--compact .hero__bg img{opacity:.28;object-position:50% 42%}
/* The homepage "what happens next" band still runs the doorstep photograph.
   It sits at .18 opacity under a three-stop veil, so the lettering is not
   legible, but it is panned right as well so the rule holds if anyone ever
   raises that opacity. */
.band-photo__img img{object-position:72% 40%}
.hero--compact h1{max-width:18ch;font-size:clamp(2.4rem,1.5rem + 3.6vw,4.2rem)}
.hero--compact .chips{margin-top:1.4rem}
.stepchip{display:inline-flex;align-items:center;gap:.55rem;font-size:.72rem;font-weight:600;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold);margin-bottom:1.6rem}
.stepchip i{display:inline-block;width:22px;height:2px;border-radius:2px;background:var(--hairline)}
.stepchip i.on{background:var(--gold)}

/* the calendar frame: reserves space; reads as a frame, never as text */
.ghl-cal{position:relative;max-width:820px;margin:2rem auto 0}
.ghl-cal:has(iframe[src*="leadconnectorhq.com"]){min-height:580px}
@media (max-width:900px){.ghl-cal:has(iframe[src*="leadconnectorhq.com"]){min-height:780px}}
.ph--silent{min-height:580px;border-radius:var(--radius-lg);border:1px solid var(--hairline);
  background:linear-gradient(180deg,var(--card-top),var(--card-bot));position:relative;overflow:hidden;box-shadow:var(--shadow-card)}
.ph--silent::before{content:"";position:absolute;inset:0;background-image:var(--grain);background-repeat:repeat;opacity:calc(var(--grain-o)*.4);mix-blend-mode:overlay}
.ph--silent::after{content:"";position:absolute;inset:0;
  background-image:repeating-linear-gradient(180deg,transparent 0,transparent 27px,var(--ledger) 27px,var(--ledger) 28px);pointer-events:none}
.ph__mark{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:72px;height:72px;border-radius:50%;
  background:var(--gold-tint);border:1px solid var(--gold-line);display:grid;place-items:center;z-index:1}
.ph__mark svg{width:28px;height:28px;stroke:var(--gold);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
@media (prefers-reduced-motion:no-preference){
  .ph__mark{animation:phWait 3.2s var(--ease) infinite}
  @keyframes phWait{0%,100%{box-shadow:0 0 0 0 var(--gold-glow)}55%{box-shadow:0 0 0 18px transparent}}
}
@media (max-width:900px){.ph--silent{min-height:520px}}
.cal-help{text-align:center;margin-top:2rem;color:var(--bone-dim)}
.cal-help strong{color:var(--bone);font-weight:600;display:block;margin-bottom:.6rem;font-size:1.05rem}
.cal-help .tel{font-family:var(--serif);font-size:clamp(1.5rem,1.2rem + 1.4vw,2.1rem);color:var(--gold-bright);display:inline-block;margin-top:.3rem}

/* the video frame */
.vsl{max-width:860px;margin:2.4rem auto 0}
.vsl__frame{aspect-ratio:16/9;border-radius:var(--radius-lg);overflow:hidden;border:1px solid var(--gold-line);
  background:linear-gradient(180deg,var(--card-top),var(--card-bot));position:relative;box-shadow:var(--shadow-soft)}
.vsl__frame::before{content:"";position:absolute;inset:0;background-image:var(--grain);background-repeat:repeat;opacity:calc(var(--grain-o)*.4);mix-blend-mode:overlay}
.vsl__frame::after{content:"";position:absolute;inset:0;background:radial-gradient(60% 60% at 50% 50%,var(--gold-tint),transparent 70%)}
.vsl__frame iframe,.vsl__frame video{position:absolute;inset:0;width:100%;height:100%;border:0;z-index:2}
.vsl__frame .ph__mark{z-index:1}
.confirm-icon{width:72px;height:72px;border-radius:50%;margin:0 auto 1.6rem;display:grid;place-items:center;
  background:var(--gold-tint);border:1px solid var(--gold-line);box-shadow:0 0 0 8px var(--gold-tint)}
.confirm-icon svg{width:32px;height:32px;stroke:var(--gold);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* thank-you chapters */
/* The numeral used to sit BESIDE the heading, which pushed every headline
   86-102px right of its own paragraph, by a different amount per section
   because the digits differ in width. Measured on /apply/thank-you/.
   It now stacks above, so the numeral, the headline and the body text all
   begin on exactly one left edge. */
.chapter-head{display:block;margin-bottom:1.3rem}
.chapter-head .numeral{display:block;font-size:clamp(2rem,1.7rem + 1.2vw,2.8rem);line-height:.95;margin:0 0 .35rem}
.chapter-head h2{margin:0}
.prose-narrow{max-width:var(--container-narrow);margin-inline:auto}
/* A chapter gets ONE line of lead, never a paragraph stack. Held to a measure
   that cannot produce more than two lines at this size. */
.chapter-lead{max-width:56ch;font-size:var(--fs-lead);line-height:1.5;color:var(--bone-dim);margin:0}
.chapter-lead strong{color:var(--bone);font-weight:600}

/* the founder note (report page) */
/* The mark used to sit in a 96px column, which pushed the founder text 125px
   right of every other paragraph on the page. It stacks above instead, so this
   block keeps the same single left edge as the chapters. */
.fnote{display:block;margin-top:2rem}
.fnote__mark{margin-bottom:1.1rem}
.fnote__mark{width:96px;height:96px;border-radius:50%;overflow:hidden;flex:none;border:1px solid var(--gold-line);
  background:var(--bg-card);box-shadow:0 0 0 4px var(--gold-tint);display:grid;place-items:center}
.fnote__mark img{width:76%;height:76%;object-fit:contain}
.fnote__sig{font-family:var(--serif);font-style:italic;font-size:1.5rem;color:var(--gold-bright);margin-top:1rem}
.fnote__role{font-size:.8rem;color:var(--bone-faint);letter-spacing:.08em;text-transform:uppercase}


/* ============================================================
   THE FUNNEL COLUMN SYSTEM
   Measured on /apply/thank-you/ at 1440px: nine sections produced SIX
   different left edges (192, 39, 171, 171, 132, 111, 171, 171, 39) because
   every component carried its own max-width. Nothing was broken; there was
   simply no shared column, and the eye reads that as crooked.

   Two widths, one centre line. Text sits in the narrow column, anything
   visual (cards, the video, the PDF drop, the share strip) sits in the wide
   one. Nothing else may invent a third.
   ============================================================ */
body.funnel{--col-text:680px; --col-wide:980px}
/* The Promise headline ran to 3.6rem over a 2-line paragraph, so the heading
   was roughly four times the weight of the text under it. Brought closer. */
body.funnel .guarantee-banner h2{font-size:clamp(1.9rem,1.4rem + 2vw,2.9rem);max-width:20ch;margin-inline:auto}
body.funnel .guarantee-banner .lines{max-width:48ch;margin-inline:auto}

/* Two kinds of element need two different sums, and mixing them up is what
   made the share strip 980px wide inside a 947px container (the "bleed").
     A. an element that IS the .container carries the gutter itself,
        so its max-width must be the column PLUS two gutters
     B. an element INSIDE a .container is already past the gutter,
        so its max-width is the column exactly
   Get this wrong and the block either bleeds past its neighbours or sits
   78px narrower than them. */

/* A — these carry .container */
body.funnel .container.prose-narrow,
body.funnel .container.guarantee-banner__inner{max-width:calc(var(--col-text) + 2 * var(--gutter))}
/* a .prose-narrow that is NOT also the container carries no gutter of its own */
body.funnel .prose-narrow:not(.container){max-width:var(--col-text);margin-inline:auto}
body.funnel .container.magnetstrip__inner,
body.funnel .container.funnel-footer__inner{max-width:calc(var(--col-wide) + 2 * var(--gutter))}

/* B — these sit inside one */
body.funnel .stepbar,
body.funnel .book-top h1,
body.funnel .book-top .book-sub,
body.funnel .undervideo,
body.funnel .chapter-lead{max-width:var(--col-text);margin-inline:auto}
body.funnel .pdfdrop,
body.funnel .section .cardgrid,
body.funnel .ghl-cal{max-width:var(--col-wide);margin-inline:auto}
body.funnel .vsl--top{max-width:min(var(--col-wide), max(420px, calc((100svh - 430px) * 16 / 9)))}

/* a chapter's body text lines up with its own heading */
body.funnel .prose-narrow > .lines,
body.funnel .prose-narrow > .chapter-lead,
body.funnel .prose-narrow > .takeaway,
body.funnel .prose-narrow > .fnote,
body.funnel .prose-narrow > ul{max-width:100%}

/* the share strip read as a left-heavy orphan beside centred content */
body.funnel .magnetstrip__inner{flex-direction:column;align-items:center;text-align:center;gap:1.4rem}
body.funnel .magnetstrip__copy p{margin-inline:auto;max-width:56ch}
body.funnel .share-link{width:100%;max-width:520px}

/* nothing slides under the sticky header */
body.funnel main :is(h1,h2,.chapter-head){scroll-margin-top:calc(var(--hdr-h) + 24px)}

/* ---- Thank-you: the video must be above the fold ----
   Chris, 16 Sep. The confirmation and the video are one block, so every value
   here is about buying vertical space for the frame. Measured target: the top
   of .vsl__frame inside the first viewport on a 375x812 phone. */
.book-top--tight{padding-block:clamp(1.2rem,.9rem + 1vw,1.9rem) clamp(2.2rem,1.6rem + 2vw,3.4rem)}
.book-top--tight .stepbar{margin-bottom:1.5rem}
.confirm-icon--sm{width:46px;height:46px;margin-bottom:1rem;box-shadow:0 0 0 5px var(--gold-tint)}
.confirm-icon--sm svg{width:21px;height:21px}
.book-top--tight h1{font-size:clamp(2.1rem,1.4rem + 2.4vw,3.4rem)}
.book-top--tight .book-sub{margin-top:.6rem}
/* The frame is 16:9, so on a short laptop window a full-width video runs off
   the bottom even when it starts above the fold. Sizing it by the space that
   is actually left means the WHOLE frame fits, at every height, without ever
   growing past his 860px. 430px is the measured chrome above it: header, step
   bar, check, headline and one line of subhead.
   svh, not vh, so mobile browser chrome is counted. */
.vsl--top{margin-top:clamp(1.3rem,1rem + 1.2vw,2rem);
  max-width:min(860px, max(420px, calc((100vh - 430px) * 16 / 9)))}
@supports (height:100svh){
  .vsl--top{max-width:min(860px, max(420px, calc((100svh - 430px) * 16 / 9)))}
}
.undervideo{max-width:62ch;margin:1.4rem auto 0;text-align:center;color:var(--bone-dim)}

/* ---- The PDF drop: a real 3D mockup of the checklist, and a real download ----
   The cover is page 1 of the actual PDF, rendered at 150dpi, not an invented
   jacket. If the PDF is redesigned the image is regenerated from it, so the
   mockup can never drift from the document it promises. */
.pdfdrop{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(2rem,1rem + 4vw,4.5rem);align-items:center;max-width:1000px;margin-inline:auto}
.pdf3d{perspective:1700px;display:grid;place-items:center;padding-block:1rem}
.pdf3d__doc{position:relative;width:min(300px,78%);transform-style:preserve-3d;
  transform:rotateY(-19deg) rotateX(5deg) rotate(-1.4deg);
  transition:transform .8s var(--ease),box-shadow .8s var(--ease);
  border-radius:3px 9px 9px 3px;
  box-shadow:0 34px 60px -22px rgba(0,0,0,.65),0 8px 18px -10px rgba(0,0,0,.5)}
.pdf3d:hover .pdf3d__doc,.pdf3d:focus-within .pdf3d__doc{
  transform:rotateY(-9deg) rotateX(2deg) rotate(-.4deg)}
.pdf3d__doc img{display:block;width:100%;height:auto;border-radius:inherit;
  border:1px solid var(--hairline)}
/* the stack of pages down the right edge */
.pdf3d__doc::before{content:"";position:absolute;top:1.6%;right:-7px;bottom:1.6%;width:7px;
  border-radius:0 3px 3px 0;transform:rotateY(22deg);transform-origin:left center;
  background:repeating-linear-gradient(180deg,
    color-mix(in srgb,var(--bone) 88%,transparent) 0 1px,
    color-mix(in srgb,var(--bone) 55%,transparent) 1px 2px)}
/* one soft sheen across the face so it reads as a physical sheet */
.pdf3d__doc::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(104deg,rgba(255,255,255,.22) 0%,rgba(255,255,255,0) 34%,
    rgba(255,255,255,0) 66%,rgba(255,255,255,.10) 100%)}
.pdfdrop__actions{display:flex;flex-wrap:wrap;gap:.9rem;margin-top:1.8rem}
.pdfdrop__note{font-size:.84rem;color:var(--bone-faint);margin-top:1rem}
@media (prefers-reduced-motion:reduce){
  .pdf3d__doc{transform:none;border-radius:4px}
  .pdf3d:hover .pdf3d__doc{transform:none}
}
@media (max-width:860px){
  .pdfdrop{grid-template-columns:1fr;gap:2rem}
  .pdf3d{order:-1}
  .pdf3d__doc{width:min(240px,62%)}
  .pdfdrop__actions .btn{width:100%;justify-content:center}
}

/* the bridge to the checklist (report page score-bridge) */
.bridge{display:flex;align-items:center;gap:1.5rem;flex-wrap:wrap;justify-content:space-between;
  border:1px solid color-mix(in srgb,var(--gold) 40%,transparent);border-radius:var(--radius-lg);
  background:var(--gold-tint);padding:1.8rem 2rem;position:relative;overflow:hidden}
.bridge::after{content:"";position:absolute;inset:0;background-image:var(--grain);background-repeat:repeat;opacity:calc(var(--grain-o)*.2);pointer-events:none}
.bridge>*{position:relative;z-index:1}
.bridge__ico{width:54px;height:54px;flex:none;border-radius:50%;border:1px solid var(--gold-line);background:var(--bg-card);display:grid;place-items:center}
.bridge__ico svg{width:26px;height:26px;stroke:var(--gold);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.bridge__body{flex:1;min-width:240px}
.bridge__k{font-size:var(--fs-label);letter-spacing:.22em;text-transform:uppercase;color:var(--gold);font-weight:600;margin-bottom:.35rem}
.bridge__t{font-family:var(--serif);font-size:clamp(1.35rem,1.1rem + .9vw,1.8rem);color:var(--bone);line-height:1.2;margin-bottom:.5rem}
.bridge__s{font-size:var(--fs-sm);color:var(--bone-dim);margin:0 0 .3rem}
.bridge .btn{flex:none}
@media (max-width:620px){.bridge{flex-direction:column;align-items:flex-start}.bridge .btn{width:100%}}

/* share strip: his magnetstrip with a readonly link field */
.share-link{flex:1;min-width:280px;max-width:560px}
.share-link input{width:100%;background:var(--ocean);border:1px solid var(--hairline);border-radius:var(--radius);
  color:var(--gold-bright);padding:1rem 1.2rem;font-size:.95rem;font-family:var(--sans)}

/* ============================================================
   7. SAFETY — reveal stays opt-in (aw-base already scopes it to
   html.js-anim). Elements that animate themselves must also finish
   when js-anim is absent.
   ============================================================ */
html:not(.js-anim) .steps--draw::before{transform:none}
html:not(.js-anim) .steps--draw .step{opacity:1;transform:none}
html:not(.js-anim) .pull .text-gold{background-size:100% 1.5px}
html:not(.js-anim) .takeaway.reveal::before{width:56px}

/* ============================================================
   8. TEXT-ZOOM + SMALL-SCREEN GUARDS (from the ledger)
   ============================================================ */
header,main,footer{overflow-wrap:break-word}
.container>*,.cardgrid>*,.stats>*,.adventure>*,.footer__grid>*,.svc>*,.hero__grid>*{min-width:0}
/* Hyphenation is OFF at every width. LEARNINGS 2026-09-16 kept it below 420px
   as zoom insurance, but that entry's own conclusion is that overflow-wrap +
   min-width:0 is what actually prevents word loss and "hyphenation only made
   the break prettier". §8B now provides that protection, so the only thing
   left here was visible "re-ceive" and "mes-sage" on a phone, which the design
   critic ranked as the fastest way to read as a template. */
:root{hyphens:manual}
@media (max-width:600px){
  .hero{padding-block:3.5rem 3.5rem}
  .hero__lines{font-size:1.05rem}
  .stat{padding:1.8rem 1.2rem}
  .letter p{font-size:1.06rem}
  .svc__body{padding:1.4rem}
}

/* ============================================================
   9. PRINT — dark-on-white, ink-frugal (house rule)
   ============================================================ */
@media print{
  /* ⛔ THIS BLOCK WAS A THIRD PALETTE, AND IT WAS THE RETIRED ONE. Until 16 Sep it
     hard-coded #8f7135 — AnchorWorks' old olive gold — three times with
     !important, so the site PRINTED a brand nobody has used for months and the
     retint could never reach it. Fixed two ways: the values below are now the
     navy palette on paper, and every literal further down this block was
     re-pointed at a token. Nothing inside @media print may name a colour again.
     Grep check: the only literals left here are #fff, which is paper. */
  :root{--ocean:#fff;--ocean-2:#fff;--panel:#fff;--charcoal:#fff;--charcoal-2:#fff;--bone:#10181F;
    --bone-dim:#2E3841;--bone-faint:#4E5A66;--hairline:#C9CFD4;--hairline-2:#E1E5E8;
    --gold:#17527F;--gold-bright:#17527F;--gold-deep:#0F3A5C;--gold-tint:transparent;--gold-glow:transparent;
    --label:#4E5A66;--label-line:#9AA4AD;--neutral-tint:transparent;--accent-text:#17527F;
    --card-top:#fff;--card-bot:#fff;--grain-o:0;--shadow-card:none;--shadow-soft:none;--on-gold:#fff}
  html{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  body{background:#fff;color:var(--bone)}
  .topbar,.site-header,.funnel-header,.progress,.theme-toggle,.scroll-cue,.hero__bg,.hero__grain,.finale__bg,.band-photo__img,
  .grain-plate::before,.grain-plate::after,.adv::before,.svc__body::before,.formcard::after,.ph--silent::before,.vsl__frame::before,
  .nav-toggle,.share-link,.second-cta{display:none!important}
  .hero,.section,.finale,.magnetstrip,.site-footer,.funnel-footer{background:#fff!important;padding-block:1.2rem}
  .hero *,.section *,.finale *{color:var(--bone)}
  /* the label roles print neutral too — same dosage rule as the screen (§12) */
  .eyebrow,.adv__tag,.ocard__tag,.svc__usp,.stat__num{color:var(--label)!important}
  .reveal,.steps--draw .step,.hero--rise *{opacity:1!important;transform:none!important;animation:none!important}
  .steps--draw::before{transform:none}
  .adv,.ocard,.tcard,.svc__body,.formcard,.stat,.takeaway,.bridge{break-inside:avoid;box-shadow:none;border-color:var(--hairline)}
  .btn{border:1px solid var(--gold);background:none!important;color:var(--gold)!important;box-shadow:none}
  .btn::after{display:none}
  .faq__a{max-height:none!important}
  .svc__intro{position:static}
  a[href^="http"]::after{content:""}
  @page{margin:16mm 15mm 18mm}
}

/* ============================================================
   8B. TEXT-ZOOM PROTECTION
   LEARNINGS: at 200% text zoom six service cards clipped their own labels by
   ~57px and scrollWidth never grew, so the words were silently lost with no
   scrollbar to recover them. Media queries cannot see text zoom, so no
   breakpoint will ever catch it. The cure is not hyphenation (that was a
   separate bug): it is overflow-wrap plus min-width:0 on every grid/flex
   child, because a grid child defaults to min-width:auto and widens its
   track rather than wrapping. Button padding is clamped with a vw term and
   PX bounds so rem padding cannot scale past the viewport.

   ⚠ This protection used to live in css/scale.css, which the 16 Sep rebuild
   stopped loading. It is re-stated here so it cannot be lost again.
   ============================================================ */
.topbar,.site-header,main,.site-footer,.nav{overflow-wrap:break-word}
.header-inner>*,
.container>*,
.cardgrid>*,
.stats>*,
.steps>*,
.step>*,
.svc>*,
.svc--feature__grid>*,
.platform__grid>*,
.founder__grid>*,
.adventure>*,
.magnetstrip__inner>*,
.outcomes>*,
.outcome>*,
.footer__grid>*,
.book__list li>*{min-width:0}
.btn{padding-inline:clamp(20px,0.8rem + 3.2vw,34px)}
/* A chip's text is an anonymous flex item, so it defaults to min-width:auto and
   clipped "The Camera-First Sewer Method" by 29px at 200% zoom. */
.chip{max-width:100%;white-space:normal;overflow-wrap:anywhere}
/* Below 981px the header has no nav to give space back, so the brand wraps
   rather than pushing the row past the viewport. */
@media (max-width:980px){ .brand__word{white-space:normal} .brand{min-width:0} }

/* ============================================================
   9. LEGIBILITY FLOOR ON PHONES — LAST BLOCK IN THE FILE
   LEARNINGS: the floor is 14px and it has to be audited BY CLASS; the last
   build lost words behind classes nobody would guess. These labels are his
   production sizes and stay untouched on desktop, where they sit on a wide,
   calm page. On a phone they fall to 11.5-12.5px.

   ⚠ This block must stay LAST. An earlier position loses every tie to the
   later single-class declarations in §3-§6, which is exactly what happened
   on the first attempt.
   ============================================================ */
@media (max-width:640px){
  :root{--fs-label:.875rem}            /* .eyebrow · .ocard__tag · .adv__tag · .n */
  .chip,
  .finale .finale__note,
  .stats__note,
  .hero__badge,
  .topbar__updated,
  .topbar__rating,
  .footer__bottom,
  .footer__legal p,
  .header-tel,
  /* funnel pages. The consent line is the one with legal teeth: automated
     marketing texts without proper consent carry penalties PER MESSAGE, so it
     has to be genuinely readable, not technically present. */
  .consent,
  .microcopy,
  .field label,
  .formcard__label,
  .proofline .chip,
  .stepchip,
  .cal-help p,
  .funnel-footer__inner{font-size:.875rem}
  .brand__word{font-size:1.12rem}
  /* The wordmark's second line is part of a LOGO LOCKUP, not reading content,
     and it must stay visibly smaller than the name above it. Held at 12.5px
     rather than the 14px content floor. This is the one documented exception. */
  .brand__word small{font-size:.78rem;letter-spacing:.1em}
}

/* ============================================================
   10. TAP TARGETS — 44px, the floor the 15 Sep critique set
   Measured on /apply/ at 375px: the theme toggle was 38px and the consent and
   footer links were 15-17px. Inline links get the height from padding so the
   paragraph they sit in is unchanged.
   ============================================================ */
@media (max-width:980px){
  .theme-toggle{width:44px;height:44px}
  .consent a,.funnel-footer__inner a,.footer__col a,.footer__legal a{
    display:inline-block;padding-block:.85rem;line-height:1.2}   /* 14px text + 2x13.6px = 44px */
  .funnel-footer__inner a{padding-inline:.35rem}
}

/* ============================================================
   11. HOMEPAGE PHONE TYPOGRAPHY — 16 Sep
   The homepage was the one page that never got a typography pass. Measured at
   375x812 with the stylesheet confirmed loaded AND web fonts confirmed ready
   (see the ledger: measuring before document.fonts.ready reads FALLBACK-font
   layout and invents defects that do not exist).

   ⛔ Scoped to body:not(.funnel). /apply/, /apply/book/ and /apply/thank-you/
   were verified block by block and approved; .section-head--center and .ocard
   are shared, so an unscoped rule here would silently re-open three signed-off
   pages.
   ============================================================ */
@media (max-width:640px){

  /* --- Card measure. At 375px the bullet text had only 241px to live in:
     20+20 container, 28.8+28.8 card, and 22+12.8 for the tick and its gutter.
     That is ~28 characters, so ordinary 7-word bullets broke to a two-word
     last line. Reclaiming the card padding gives 262px and lands most of them
     on one line. Going tighter than this was tested (1.05 / 0.95 / 0.85rem)
     and buys nothing more, so the last two were shortened in the HTML
     instead. */
  body:not(.funnel) .ocard{padding-left:1.15rem;padding-right:1.15rem}
  body:not(.funnel) .book__list li{gap:.62rem}
  body:not(.funnel) .book__list li span{text-wrap:pretty}

  /* --- Centred section heads go left on phones.
     Chris's rule: centred text holds for one or two SHORT lines; longer must
     be cut or left-aligned. Six centred blocks ran 3-4 lines at 375px.
     The heading moves WITH its paragraph, never on its own, because the other
     rule is that a headline starts on the same left edge as its own
     paragraph. Left-aligning only the prose would trade one defect for the
     other. Verified after: misaligned pairs = 0. */
  body:not(.funnel) .section-head--center{text-align:left}
  body:not(.funnel) .section-head--center .eyebrow--center{text-align:left;margin-inline:0}
  body:not(.funnel) .section-head--center h2,
  body:not(.funnel) .section-head--center h3{text-align:left}
  body:not(.funnel) .section-head--center .lead,
  body:not(.funnel) .section-head--center .lines--lead,
  body:not(.funnel) .section-head--center .lines--lead p,
  body:not(.funnel) .section-head--center p{
    text-align:left;text-wrap:pretty;margin-inline:0;max-width:none}
  body:not(.funnel) .pull{text-align:left;text-wrap:pretty}

  /* .finale .finale__note is 0,2,0 in aw-base.css, so a bare .finale__note
     here LOSES the tie and silently does nothing. Match the specificity. */
  body:not(.funnel) .finale .finale__inner{text-align:left}
}

/* --- The finale legal line, deterministically.
   It carried text-wrap:balance and STILL rendered 519px + a 100px orphan tail
   ("· Colorado License #600566"). Balance is a best-effort heuristic: measured
   immediately after load it gave 519/100, and after document.fonts.ready it
   gave 292/326 — the SAME element, same width, two different answers depending
   on when layout happened to run. Anything that depends on when the browser
   re-lays out will regress silently, so this does not rely on it.
   The string wants 622px on one line. Above 768px the finale column is wider
   than that, so an explicit 42rem (672px) measure puts it on ONE line, where
   an orphan is impossible. Below 768px it goes left-aligned with `pretty`,
   which protects the last line instead. */
@media (max-width:767px){
  body:not(.funnel) .finale .finale__note{
    text-align:left;text-wrap:pretty;margin-inline:0;max-width:none}
}
@media (min-width:768px){
  .finale .finale__note{max-width:42rem}
}


/* ============================================================
   12. THE DOSAGE CUT + ACCENT TEXT CONTRAST — 16 Sep
   Originally this block existed only to fix contrast: it put every accent-
   coloured small text onto --accent-text, which is the light end of the range in
   dark and the dark end in light. That fix stays, and the per-theme split is
   still what holds contrast at 0 failures. Do not collapse it.

   ⛔ WHAT CHANGED WITH THE NAVY RETINT — the dosage.
   The accent was counted at 157 references across the two stylesheets: buttons,
   eyebrows, chips, card tags, step numerals, links, icon strokes, borders, tints,
   glows, the progress bar and the checkmarks. The brand doc the site was built
   from names the premium move as "one saturated accent, used sparingly, and only
   on the thing you are meant to press", and 157 is not sparing. Swapping the hue
   alone would have produced a navy version of the same flatness — that finding is
   the top entry in website-learnings.md.

   So the rule is now ONE LINE: the accent means "press me."
   KEEPS the accent  — .btn--primary, .adv__link, .ocard__link, .nav__cta, and
                       headline emphasis (h1/h2/h3 em).
   TAKES --label     — everything else. Eyebrows, chips, tags, numerals, stat
                       figures, icon strokes, ticks, rules, tints, the progress
                       bar. Neutral, quiet, and it is what makes the two things
                       that DID keep the colour read as deliberate.
   Independently corroborated: ui-ux-pro-max's `trust-authority-conversion`
   pattern states "Accent for CTA only" in its own colour-strategy field.
   ============================================================ */

/* ---- KEEPS THE ACCENT. Two roles plus headline emphasis. ----
   ⚠ The four DESCENDANT forms below are not decoration, they are required.
   aw-base.css sets `.hero h1 em`, `.finale h2 em`, `.subhero h1 em` and
   `.guarantee-banner h2 em` to var(--gold) at specificity 0-1-2, which BEATS a
   bare `h1 em` at 0-0-2 no matter how late this file loads. Caught by reading
   the computed colour off the live page, not by looking at it: the hero emphasis
   was silently rendering #5E9BC9, the DARK half of the navy range, on a
   photographic ground where the sweep cannot evaluate contrast at all. A bare
   `h1 em` looks like it covers this. It does not. Do not remove these. */
.ocard__link,
.adv__link,
h1 em, h2 em, h3 em,
.hero h1 em, .subhero h1 em, .finale h2 em,
.guarantee-banner h2 em, .magnetstrip__copy h3 em{
  color:var(--accent-text);
}

/* ---- TAKES THE NEUTRAL. Every other role the accent used to own. ----
   Only classes that actually appear on the four live pages are listed; the dead
   ones in aw-base (.stars, .book3d__kicker, .scorecard__*, .tcard__*,
   .subhero__rule, .breadcrumb) are deliberately not carried, so this block does
   not grow into a second place naming values nobody renders. */
.chip--gold,
.step__num,
.step__arrow,
.adv__tag,
.ocard__tag,
.ocard__sub,
.eyebrow,
.stat__num,
.takeaway__title,
.text-gold,
.brand__word small,
.footer__brand .brand__word small,
blockquote em,
.letter p em,
.founder blockquote em,
.fnote__sig,
.svc__usp{
  color:var(--label);
}
/* icon strokes: was the accent, now neutral */
.adv__icon svg,
.feature-icon svg,
.book__list svg,
.guarantee-banner__shield,
.header-tel svg{
  stroke:var(--label);
}
/* tinted chips and pills lose the accent wash */
.chip--gold,
.step__num,
.feature-icon{
  background:var(--neutral-tint);
  border-color:var(--hairline);
}
/* rules, bars and drawn lines */
.numeral{-webkit-text-stroke:1px var(--label-line)}
.svc__usp{border-left-color:var(--label-line)}
.letter blockquote{border-left-color:var(--label-line)}
.faq__q .ic::before,.faq__q .ic::after{background:var(--label)}
.faq__item.is-open .faq__q .ic{background:var(--neutral-tint);border-color:var(--hairline)}
.progress{background:linear-gradient(90deg,var(--label-line),var(--label))}
.scroll-cue{background:linear-gradient(180deg,var(--label),transparent)}
.steps--row::before{background:linear-gradient(90deg,var(--label-line),var(--hairline))}
.nav a::after{background:var(--label)}
.topbar__updated .pulse{background:var(--label);box-shadow:0 0 0 0 var(--neutral-tint)}
/* the takeaway keeps its shape and loses its hue */
.takeaway{border-color:var(--hairline);background:var(--neutral-tint)}
.takeaway::before{background:var(--label)}
/* hover affordances go to ink, not to the accent */
.theme-toggle:hover{border-color:var(--label);color:var(--label)}
.header-tel:hover{border-color:var(--label);color:var(--bone)}
.btn--ghost:hover,.btn--dark:hover{border-color:var(--label);color:var(--bone)}
.footer__social a:hover{border-color:var(--label);color:var(--bone)}
.footer__col a:hover,.footer__contact a:hover,.footer__company a:hover{color:var(--bone)}

/* ============================================================
   12B. THE DOSAGE CUT, CARRIED THROUGH THE FUNNEL — 16 Sep
   ⛔ THE SAME MISTAKE THIS PROJECT ALREADY MADE ONCE. When the card ladder
   shipped it was scoped `body:not(.funnel)` for safety, and Chris found it
   immediately: "did you upgrade the other three pages, because I could only see
   the homepage?" The ruling that came out of it is in BUILD-DECISIONS.md — one
   rule everywhere, only the plate's identity changes per page. §12 above
   repeated the error in a new form: it named the HOMEPAGE's accent roles and
   left the funnel's own components (§8-9 of this file, roughly lines 580-915)
   still spending the accent about forty more times. Caught by counting, not by
   looking: the raw grep was 94 when the homepage-only cut predicted ~20.

   Same rule as §12, no exceptions: the accent means "press me."
   ⚠ Several of these need a selector at least as specific as the original —
   `.hero--funnel .eyebrow` (0-2-0) and `.pull .text-gold` (0-2-0) both BEAT a
   bare `.eyebrow` / `.text-gold` in §12, so they are restated here rather than
   assumed. Specificity, not source order, is what was silently losing.
   ============================================================ */

/* ---- these two out-specify §12 and must be restated ---- */
.hero--funnel .eyebrow{color:var(--label)}
.pull .text-gold{background-image:linear-gradient(var(--label),var(--label))}

/* ---- the opt-in form (/apply/) ---- */
.formcard{border-color:var(--hairline)}
.formcard::before{background:linear-gradient(90deg,transparent,var(--label),transparent)}
.formcard__label{color:var(--label)}
.formcard__icon{stroke:var(--label)}
.consent a{color:var(--accent-text)}          /* a real link. Keeps it. */
/* ⛔ .field input:focus KEEPS the accent on purpose. A focus ring is the one
   place colour is load-bearing for accessibility, not decoration. Same reason
   .skip-link and .adv:focus-visible keep it. */

/* ---- the step bar across the funnel ---- */
.stepbar__label strong{color:var(--label)}
.stepbar__fill{background:linear-gradient(90deg,var(--label-line),var(--label))}
.stepchip i.on{background:var(--label)}

/* ---- the calendar page (/apply/book/) ---- */
.ph__mark{background:var(--neutral-tint);border-color:var(--hairline)}
.ph__mark svg{stroke:var(--label)}
.cal-help .tel{color:var(--accent-text)}      /* a tel: link. Pressable, keeps it. */

/* ---- the thank-you page (/apply/thank-you/) ---- */
.vsl__frame{border-color:var(--hairline)}
.confirm-icon{background:var(--neutral-tint);border-color:var(--hairline);box-shadow:0 0 0 8px var(--neutral-tint)}
.confirm-icon--sm{box-shadow:0 0 0 5px var(--neutral-tint)}
.confirm-icon svg{stroke:var(--label)}
.fnote__mark{border-color:var(--hairline);box-shadow:0 0 0 4px var(--neutral-tint)}
.bridge{border-color:var(--hairline);background:var(--neutral-tint)}
.bridge__ico{border-color:var(--hairline)}
.bridge__ico svg{stroke:var(--label)}
.bridge__k{color:var(--label)}
.share-link input{color:var(--accent-text)}   /* the link being copied. Keeps it. */
.book-note a{color:var(--accent-text)}        /* a real link. Keeps it. */
.funnel-footer__inner a:hover{color:var(--bone)}

/* ---- the quoted "reason" rule on /apply/ ---- */
.reason{border-left-color:var(--label-line)}
.reason::before{background:var(--label-line)}

/* ---- card hover borders: the de-boxed cards no longer flash the accent ---- */
.adv:hover,.ocard:hover,.tcard:hover{border-color:var(--label-line)}
.adv--primary,.ocard--paid{border-color:var(--hairline)}

/* ============================================================
   13. SKIP LINK — 16 Sep
   DESIGN-REVIEW-HANDOFF §"Post-critique fixes" claims skip links already move
   focus via tabindex="-1" on #apply, #book and #main, and that the homepage was
   "already correct". Checked: there was no skip link on ANY page, and no #main
   anywhere — the homepage's <main> is id="top". So a keyboard user tabbed the
   wordmark, six nav links, the theme toggle, the phone and Apply Now before
   reaching content, on every page load.
   The homepage now has one pointing at #top, and <main> carries tabindex="-1"
   so focus MOVES rather than the page merely scrolling.
   ⚠ /apply/, /apply/book/ and /apply/thank-you/ still have none.
   Visible only on keyboard focus, never for pointer users.
   ============================================================ */
/* `fixed`, not `absolute`: absolute pins it to the DOCUMENT top, so a keyboard
   user who tabs after the page has scrolled gets a "revealed" link sitting
   hundreds of px above the viewport. Measured that exact failure at top:-643. */
.skip-link{
  position:fixed;left:-9999px;top:0;z-index:100;
  padding:.85rem 1.25rem;border-radius:0 0 var(--radius) 0;
  background:var(--base);color:var(--ink);
  border:1px solid var(--gold-line);border-top:0;
  font-size:.95rem;font-weight:600;text-decoration:none;
}
.skip-link:focus,
.skip-link:focus-visible{ left:0; outline:2px solid var(--accent-text); outline-offset:2px; }
/* <main tabindex="-1"> is a focus TARGET, not a control: never ring it. */
main[tabindex="-1"]:focus{ outline:none; }

/* ============================================================
   12. THE SECOND VOICE — 16 Sep 2026
   Aesthetic audit item #1: "Give the display type a second voice."

   ⚠ The audit's DIAGNOSIS is right and its EVIDENCE is wrong. It claims the
   scale runs "41 -> 21 -> 16 -> 12px, a 3.4x range" and reviews "at 1280 in
   the light theme". Re-measured at 1280 after document.fonts.ready:
   h1 102px · h2 56px · body 23-25px · label 11.5px = 8.8x, already inside the
   8-10x band the audit says to aim for. The 3.4x number reproduces at 375px
   (46/32/18/14 = 4.1x), so it was measured on a PHONE-width pane. See the
   ledger. Do NOT inflate desktop type: the range is not the defect.

   The defect is real and it is the other half of the sentence: EVERY leaf
   element on the homepage computes to Inter. One family, one texture, top to
   bottom. So this section adds a genuine second instrument rather than a
   louder first one.

   The instrument: IBM Plex Mono, drawn for an engineering company, on the
   SMALL technical roles only — eyebrows, chips, card tags, step numerals,
   stats, form labels, footer heads. On a licensed plumber's site these read
   as gauge plates and spec stamps, which is what he actually is. Headlines
   and body stay Inter, so no headline changes shape and the AnchorWorks
   framework is untouched.

   The contrast the audit asked for ("900 against 300, -3% tracking against
   +14%") is delivered as tracking, not size: display runs -4.2%, the
   technical voice runs +16%. Twenty points apart, at opposite ends of the
   scale.

   ⛔ NO COLOUR. Every rule here is family, weight, tracking and case. The
   copper is untouched, per Chris 16 Sep: colour is last.
   ============================================================ */
:root{
  --tech:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --tech-track:.16em;   /* the +16% end */
  --display-track:-.042em; /* the -4.2% end */
}

/* ---- The technical voice. Small, wide, uppercase. ---- */
.eyebrow,
.chip,
.ocard__tag,
.footer__col h4,
.formcard__label,
.stepbar__label,
.stats__note,
.role{
  font-family:var(--tech);
  letter-spacing:var(--tech-track);
  font-weight:500;
}
/* aw-base sets these at 600-700 for Inter. Mono carries more colour per stem,
   so it needs LESS weight to hold the same presence; 700 mono at 12px fills in
   and turns to mud at the exact sizes these labels live at. */
.eyebrow,.chip,.footer__col h4{font-weight:500}
/* the step bar is a progress READOUT ("Step 2 of 3 · You're 75% done"), which is
   the same object as a gauge face. It is also the only small label on
   /apply/book/, so without it that page downloads a font it never paints.
   Austere is not the same as unsystematic: the audit's "leave book alone" is
   about not ADDING furniture, and this adds none. */
.stepbar__label{font-weight:500;letter-spacing:.1em}
.ocard__tag{font-weight:600;letter-spacing:.12em}
/* the numeral inside a card tag is a figure, not a word: no word-tracking */
.ocard__tag .n{font-family:var(--tech);letter-spacing:.04em;font-weight:600}
/* .role and .stats__note are sentences, not labels — they take the family for
   texture but must NOT take uppercase tracking or they stop being readable. */
.role,.stats__note{letter-spacing:.01em;font-weight:400;text-transform:none}

/* ---- The big figures. A stamped number, not a headline. ----
   These were Inter 800 at -.035em, i.e. the display voice at a smaller size —
   which is exactly the sameness the audit describes. As mono with positive
   tracking they become a different object on the page. font-variant-numeric
   keeps multi-digit figures on a common width so a column of them aligns. */
.numeral,.stat__num,.step__num{
  font-family:var(--tech);
  font-weight:600;
  letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
}

/* ---- The display voice, pushed to the far end. ----
   Size is already right (8.8x). What was missing is DENSITY: Inter 800 at
   -3.2% sits close to body Inter 400 at 0%. Taking the largest type to 900 and
   -4.2% opens a visible gap against the +16% labels without changing a single
   font-size. Scoped to the two sizes that are actually large — h3/h4 are
   mid-scale and stay where they are, or the whole page goes tight again and
   the contrast collapses a second time. */
h1,h2{font-weight:900;letter-spacing:var(--display-track)}
/* aw-base gives .hero h1 its own tracking; match it or the hero alone stays
   loose and reads as the odd one out. */
.hero h1{letter-spacing:var(--display-track)}

/* ---- Guards ----
   ⛔ The nav must never take the technical voice. Mono is ~12% wider per
   character and the header row is already measured to the pixel: six labels,
   a toggle, a phone and a button. Widening a label breaks the rule that nav
   labels never break mid-label. The wordmark's sub-line is excluded for the
   same reason AND because it mirrors the logo's own lockup. */
.nav a,.brand__word,.brand__word small{font-family:var(--sans)}

/* ============================================================
   13. THE ANCHORED HEAD — 16 Sep 2026
   Aesthetic audit item #2: "Stop centring everything."

   Verified before acting: 9 of 18 homepage sections are centre-stacked, not
   the 7 the audit counted, and they are not consecutive. They form two clumps:
   sections 2-3 at the open, and 14-15-16-17 at the close. The middle already
   alternates properly.

   So three heads go hard-left with a deliberately empty right column, chosen
   to break both clumps and to build one long left run that makes the offer
   land as an arrival:

     3  Know What Is Wrong...      breaks the opening clump
     8  One Local Team...          opens its own five left-aligned chapters
     15 What Happens When You Call breaks the closing run

   Result: hero(C) doors(L) band(C) 3(L) letter(L) method(L) choices(C)
   jeremy(L) 8(L) chapters(L x5) INSPECTION(C) 15(L) faq(C) finale(C).
   The inspection plate is now the only centred thing after a six-section left
   run, so the offer reads as a destination instead of one more centred band.

   The composition is stolen from /apply/'s hero grid, which the audit calls
   the best page on the site, rather than invented: same 1.05fr/.95fr split,
   same gap clamp.
   ============================================================ */
/* ---- 641-1023px: left, but FULL WIDTH. ----
   ⛔ The grid cannot start at 641. Measured at 800px: the left column is ~350px
   while the h2 clamp is already 51px, so "One Local Team For The Plumbing Your
   Home Depends On." laid out as FIVE lines. A five-line headline is not a
   composition, it is a column of words. Below 1024 the head keeps the new left
   alignment and gives up the empty column, which is the half that needs room. */
@media (min-width:641px) and (max-width:1023.98px){
  .section-head--anchor{max-width:820px;margin-inline:0;text-align:left}
  .section-head--anchor > *{text-align:left;margin-inline:0}
  .section-head--anchor .lead{max-width:52ch}
}

@media (min-width:1024px){
  /* ⛔ 1024px floor, not 641: below this the left column is too narrow to carry
     a headline at the anchored size. §11 already sends every centred head left
     at <=640px, and the block above covers the middle. */
  .section-head--anchor{
    max-width:none;margin-inline:0;text-align:left;
    /* ⚠ NOT /apply/'s 1.05fr/.95fr. That split is right when the right column
       holds a FORM. Here it is empty, and at 1024 a 467px column turned "One
       Local Team For The Plumbing Your Home Depends On." into FIVE lines - a
       column of words, not a composition. An empty right THIRD still reads as
       deliberate and gives the headline room to breathe. */
    display:grid;grid-template-columns:minmax(0,1.3fr) .7fr;
    gap:clamp(2rem,1rem + 4vw,5rem);
  }
  /* Everything sits in column one. Column two is empty ON PURPOSE — that
     emptiness is the whole effect, and it is why this is a grid and not a
     text-align. */
  .section-head--anchor > *{grid-column:1;text-align:left;margin-inline:0}
  .section-head--anchor .lead{max-width:46ch}
  /* The head now owns ~55% of the width instead of 100%, so the headline can
     grow without running long. This is the one place the page gets a bigger
     moment, and it costs nothing: same section, same copy, more scale. */
  .section-head--anchor h2{max-width:20ch;font-size:clamp(2.6rem,1.4rem + 3.6vw,4.6rem)}
}

/* The pull quote is a SIBLING of the head, not a child, so it kept its centred
   default and sat centred directly under a hard-left headline whose own lead
   was left — which reads as a mistake rather than a contrast. A section that
   composes left composes left all the way down. Measure is capped so the line
   still breaks where it did, rather than running the full container. */
@media (min-width:641px){
  .section--anchored .pull{text-align:left;margin-inline:0;max-width:26ch}
}

/* ============================================================
   14. THE CARD LADDER — 16 Sep 2026
   Aesthetic audit item #5: "Roughly twenty identical cards. Border, fill,
   radius and shadow each say 'separate object'. Spent evenly on everything,
   they say nothing. Spend them by role."

   MEASURED at 1280px, light, after document.fonts.ready — 20 containered
   cards sharing effectively TWO treatments:
     .ocard x8 · .ocard--paid x3 · .adv x2   1px hairline | 22px | no shadow | gradient
     .svc__body x7                            the same, plus a shadow
   Already subtracted and working, left alone: .step x10 · .faq__item x8 ·
   .stat x4 · .takeaway x3.

   THE MOVE IS SUBTRACTION. Nineteen cards stop being cards. Nothing is added
   to make the twentieth loud — the Water Safety Inspection simply ends up the
   only filled + bordered + shadowed CONTAINER left in <main>. Emphasis is
   free when everything else goes quiet.

   ⛔ NO NEW HUE, AND NO RECOLOURED BORDER. An earlier draft put --gold-line
   (copper) on the plate and on the framed door. That is a recolour carrying a
   meaning, which is exactly what Chris froze on 16 Sep. Both use --hairline.
   The plate does not need copper: it is already the only filled object, the
   only bordered object, the only shadowed object, the widest object, the only
   internally divided object, and the owner of the largest h3. Six signals,
   none of them hue. If Chris wants copper here at the final swap it is one
   token on one line.

   ⛔ SCOPING IS LOAD-BEARING. Verified by grep, not assumed:
     .ocard        home 11 · /apply/ 3 · /apply/thank-you/ 3
     .cardgrid     home 3  · /apply/ 1 · /apply/thank-you/ 1
     .ocard--paid  home 3  · /apply/thank-you/ 1
   Those three are therefore body:not(.funnel) everywhere below — §11 already
   warns in writing that an unscoped .ocard rule "would silently re-open three
   signed-off pages". .adv, .svc__body, .svc--feature*, .adventure and
   .outcome are homepage-only (grepped across all 7 pages), so they run bare.

   ⛔ .svc--feature IS NOT .svc. The five chapters are <div class="svc">
   (index.html 483,523,559,604,663); the offer is <section ... svc--feature>
   with its own .svc--feature__grid. That is what makes `.svc > .svc__body`
   safe, and it is the load-bearing fact for this whole block.

   Real baselines (checked, not inferred): .svc__body h3 was ALREADY 1.25rem
   (jc.css:497) — chapters were never at 1.5rem. .ocard h3 is 1.5rem
   (aw-base.css:620). FIVE chapters, not six.

   The ladder:
     PLATE  fill + border + shadow + widest + divided   x1   the offer
     FRAME  border + radius + inset, no fill/shadow     x1   the flagged door
     RULE2  2px top rule, keeps its 1.5rem heading      x3   the ranked card
     RULE1  1px top or left rule, heading demoted       x15  everything else
     BARE   untouched                                   —    step/faq/stat/takeaway
   ============================================================ */

/* ---- THE SUBTRACTION. Nineteen cards give up the box. ---- */
body:not(.funnel) .ocard,
.adv,
.svc__body{background:none;border:0;border-radius:0;box-shadow:none;padding:0}
/* the grain belonged to the box, not to the words. The plate re-hosts it. */
.adv::before,
.svc__body::before{display:none}
/* ⚠ aw-base.css:627 paints a 3px COPPER gradient bar as .ocard--paid::after,
   inset against the PADDING box. Once the padding is 0 and the radius is 0 it
   no longer reads as a cap on a card — it renders as a full-bleed copper bar
   stacked under the new grey rule, which would put RANK BACK ON HUE, the exact
   defect this block exists to remove. Removing a mark is subtraction, not a
   colour change. (A computed-style diff cannot see a pseudo-element, which is
   why this was missed on the first pass.) */
body:not(.funnel) .ocard--paid::after{display:none}
/* a block with no container must not levitate, and cannot cast a shadow. The
   --gold-line-hi border-color hover survives and now brightens the RULE, so
   every card keeps its hover affordance without a box. */
body:not(.funnel) .ocard:hover,
.adv:hover{transform:none;box-shadow:none}
/* .ocard--paid and .adv are <a>. De-boxing removes the only thing that read as
   their edge, so give them the house focus ring (same pattern as .skip-link). */
body:not(.funnel) .ocard:focus-visible,
.adv:focus-visible{outline:2px solid var(--accent-text);outline-offset:3px}

/* ---- RULE 1 · grouped cards become newspaper columns. ----
   One shared gutter variable so the vertical seam in a chapter sits dead
   centre of a symmetric gap instead of floating 80px from its own text. */
body:not(.funnel) .cardgrid,
.adv,
.svc{--seam:clamp(1.75rem,1rem + 2.2vw,3rem)}

body:not(.funnel) .ocard,
.adv{border-top:1px solid var(--hairline);padding-top:1.5rem}
body:not(.funnel) .cardgrid{
  column-gap:var(--seam);
  row-gap:clamp(2.25rem,1.5rem + 2vw,3.25rem);
  /* ⛔ .ocard is flex-column and .ocard__link is margin-top:auto (aw-base 616,
     623). Grid items stretch by default, so with the box gone the link would
     float far below its own text, orphaned in white space. */
  align-items:start;
}
/* rank is rule weight and type size, never hue: the ORDINARY card is demoted
   rather than the ranked one promoted, so no new large type enters the page. */
body:not(.funnel) .ocard:not(.ocard--paid) h3{font-size:1.28rem}

/* ---- RULE 2 · the ranked card in each group. ----
   2px against its siblings' 1px, and it keeps aw-base's full 1.5rem heading
   while they drop to 1.28rem. Two signals, both weight. */
body:not(.funnel) .ocard--paid{border-top-width:2px}

/* ---- The service chapter: a two-column spread with one seam. ---- */
.svc{column-gap:var(--seam)}
.svc > .svc__body{border-left:1px solid var(--hairline);padding-left:var(--seam)}
@media (max-width:980px){                    /* .svc's own stack point */
  .svc > .svc__body{border-left:0;padding-left:0;
    border-top:1px solid var(--hairline);padding-top:1.6rem}
}

/* ---- FRAME · one door is in a box, the other is not. ----
   ⚠⚠ FLAG FOR CHRIS — a business call, not a CSS defect. index.html:149 shows
   .adv--primary is the EMERGENCY PHONE card (href="tel:", "24-Hour Plumbing
   Repair", "Request Service"). The PLAIN .adv is the Water Safety Inspection
   ("Apply Now"). The frame below follows the client's own --primary class, so
   the phone door is the framed one. If the inspection should be the loud door,
   swap the class in the HTML — one word — do not swap it here. This is
   punch-list item #21 territory and is Chris's decision.
   Both headings are demoted EQUALLY so the frame, not the type, carries the
   distinction; demoting only the unframed one would shrink the offer's own
   door to promote the phone number. */
.adv h3{font-size:clamp(1.3rem,1.1rem + .6vw,1.6rem)}
.adv--primary{
  border:1px solid var(--hairline);
  border-radius:var(--radius-lg);
  /* floor kept low: at 375px the doors STACK (aw-base.css:548 collapses
     .adventure at 720px), and a 24px inset on one of two stacked cards costs
     ~50px of measure and opens a SECOND left edge against §11's one-edge rule.
     18.4px at 375px, ~33px at 1280px. */
  padding:clamp(1.15rem,.8rem + 1.6vw,2.1rem);
}
/* the framed door is also physically the wider one */
.adventure{grid-template-columns:1.12fr .88fr;column-gap:clamp(1.5rem,1rem + 1.8vw,2.6rem)}
/* ⛔ RESTATE THE STACK. aw-base.css:548 collapses .adventure at 720px and the
   rule above is later at equal specificity, so without this a phone would
   render two 1.12fr/.88fr columns. */
@media (max-width:720px){
  .adventure{grid-template-columns:1fr}
  /* ⛔ ONE LEFT EDGE. Stacked, the frame's inset put the primary door's text at
     40px and the plain door's at 20px — a 20px jog between two blocks sitting
     directly above each other, against §11's whole premise (it left-aligns six
     centred blocks at 640px precisely to establish a single left edge).
     Lowering the padding only shrank the jog from ~50px to 20px; the frame
     itself is the problem once the cards stack. So on a phone the door drops to
     the SAME 2px-rule mechanism the ranked .ocard uses: rank without inset. */
  .adv--primary{border:0;border-top:2px solid var(--hairline);border-radius:0;
    padding:1.5rem 0 0}
  /* and with no border, radius or clip left to host it, aw-base.css:300's 3px
     copper bar would render full-bleed — the same orphaned-cap failure already
     fixed for .ocard--paid above, and it would put rank back on hue. */
  .adv--primary::after{display:none}
}
/* a 50px tinted chip would be the only filled object on a de-boxed hero */
.adv__icon{background:none;border:0;border-radius:0;width:28px;height:28px;margin-bottom:1.1rem}
.adv__icon svg{width:28px;height:28px}

/* ---- PLATE · the Water Safety Inspection. The one container left. ----
   It was TWO .svc__body cards — the exact component the five chapters are
   built from. The container moves UP to the grid and the halves become
   COLUMNS OF ONE SLAB rather than two cards.

   ⛔ The divider is a border on the half, NOT the "welded seam" (gap:1px over
   a tinted wrapper) two judges suggested. Two refuters computed it
   independently: --hairline over #inspection's --charcoal ground composites to
   rgb(38,42,45) against a rgb(34,39,43) half — delta (4,3,2), INVISIBLE in
   dark. Over --card-top it is rgb(56,60,64), delta (22,21,21). The seam also
   requires the halves to carry the fill, and both halves are .reveal with the
   second on data-delay=1, so the plate would assemble itself in two visible
   pieces. Graft rejected on both counts; only its craft point survives — the
   gutter is sized so the seam sits centred.

   ⛔ FLAT --card-top, not the --card-top -> --card-bot gradient every card
   used. In dark, --card-bot IS --charcoal, the identical value to this
   section's own section--deep ground, so the old card dissolved into the floor
   at its own bottom edge.

   max-width:none, not the old 980px: that cap made each half 469px — SMALLER
   than a 594px service chapter card, so the offer was physically outranked by
   the thing teasing it. Uncapped it takes the full 1144px container against an
   820px .section-head: a 324px overhang that reads in both themes, which a
   black shadow on a dark ground never does. */
.svc--feature__grid{
  --plate-pad:clamp(1.5rem,1.1rem + 1.8vw,2.8rem);
  max-width:none;
  gap:var(--plate-pad) calc(var(--plate-pad) * 1.5);
  margin-top:clamp(2.6rem,2rem + 1.6vw,3.6rem);
  padding:var(--plate-pad);
  background:var(--card-top);
  border:1px solid var(--hairline);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);
  position:relative;
}
/* ⛔ NO overflow:hidden. Both halves are .reveal and aw-base.css:526 translates
   them on entry; clipping the wrapper would shear them mid-animation. The
   grain pseudo was the only thing needing the clip, so it inherits the radius
   instead. */
.svc--feature__grid::before{
  content:"";position:absolute;inset:0;border-radius:inherit;
  background-image:var(--grain);background-repeat:repeat;
  opacity:calc(var(--grain-o) * .4);pointer-events:none;
}
.svc--feature__grid > *{position:relative;z-index:1}
.svc--feature__grid > * + *{border-left:1px solid var(--hairline);padding-left:var(--plate-pad)}
@media (max-width:820px){                    /* the existing 1-col switch */
  .svc--feature__grid > * + *{border-left:0;padding-left:0;
    border-top:1px solid var(--hairline);padding-top:var(--plate-pad)}
}
/* the plate's h3 must beat the ranked .ocard's 1.5rem, or the offer's heading
   is smaller than the heading on the card that merely teases it. 27.2px at
   1280, 22.4px floor at 375. */
.svc--feature .svc__body h3{font-size:clamp(1.4rem,1.2rem + .8vw,1.7rem)}
/* ⛔ Three bordered, rounded, padded .outcome boxes NESTED inside the plate
   were the specific thing making the offer read as "a bullet list in a frame".
   They become rows. (.takeaway keeps its box — it is the one deliberately
   distinct component and is explicitly out of scope.) */
.svc--feature .outcome{border:0;border-radius:0;padding:0}
.svc--feature .outcomes{gap:1.15rem}

/* §9's print block lists .svc__body for break-inside:avoid but predates the
   plate, and the container is now .svc--feature__grid. Print already zeroes
   --grain-o and --shadow-card and sets --card-top:#fff, so nothing else here
   needs a print override. */
@media print{.svc--feature__grid{break-inside:avoid}}

/* ============================================================
   15. THE LADDER, CARRIED THROUGH THE FUNNEL — 16 Sep 2026
   Chris, after seeing §14 on the homepage: "did you upgrade the other three
   pages?" He had not, and the result was a funnel speaking two visual
   languages — a bare editorial homepage leading to /apply/ with three rounded
   boxes. §14 was scoped body:not(.funnel) as a SAFETY measure (those pages
   were verified block by block and signed off in an earlier session, and all
   three reviewers called an unscoped rule fatal). That was the right call
   about risk and the wrong end state. Chris's ruling: ONE PLATE PER PAGE.

   The rule is the same everywhere: the single thing that page exists for keeps
   its container; everything else goes quiet. Only the plate changes identity.

     /              plate = the Water Safety Inspection   (§14)
     /apply/        plate = the opt-in FORM               .formcard
     /apply/thank-you/  plate = the VIDEO FRAME           .vsl__frame
     /apply/book/   untouched — the calendar is already the only object on it,
                    and the audit calls that page finished.

   ⛔ .formcard and .vsl__frame ALREADY carry fill + border + radius + shadow,
   so no plate has to be built here. The whole job is removing the boxes around
   them. Nothing is added to make either plate loud.
   ⛔ NO NEW HUE, same as §14.
   ============================================================ */

/* ---- The three cards on each funnel page give up the box. ----
   /apply/ has 3 .ocard.objection ("Question"), /apply/thank-you/ has 3 .ocard
   ("Outcome 1-3", the third .ocard--paid). /apply/book/ has none, which is why
   it needs no rule and stays exactly as signed off. */
body.funnel .ocard{
  background:none;border:0;border-radius:0;box-shadow:none;padding:0;
  border-top:1px solid var(--hairline);padding-top:1.5rem;
}
/* the same orphaned copper cap as §14: inset against the padding box, so with
   padding and radius gone it renders full-bleed and puts rank back on hue. */
body.funnel .ocard--paid::after{display:none}
body.funnel .ocard--paid{border-top-width:2px}
body.funnel .ocard:hover{transform:none;box-shadow:none}
body.funnel .cardgrid{
  column-gap:clamp(1.75rem,1rem + 2.2vw,3rem);
  row-gap:clamp(2.25rem,1.5rem + 2vw,3.25rem);
  align-items:start;          /* .ocard__link is margin-top:auto — see §14 */
}
/* ⚠ §11 sets `body:not(.funnel) .ocard{padding-left/right:1.15rem}` at <=640px.
   That is scoped AWAY from these pages, so nothing fights this. Checked. */

/* ---- The video frame becomes a player, not a gap. ----
   Audit, /apply/thank-you/: "The video frame is a near-white rectangle on a
   near-white ground, so the most important element on the page is close to
   invisible before the film exists. Give the empty frame a darker surface so
   it reads as a player, not a gap." Confirmed by eye in the light theme.

   ⛔ LIGHT THEME ONLY. In dark the frame already reads correctly — its
   --card-top -> --card-bot gradient sits on a dark ground with a border, and
   the play mark is clearly visible. Only light is broken.

   ⛔ NO NEW HUE. --bone is an EXISTING token and in the light palette it is
   #1E2327, the dark gunmetal ink. Reusing it as a surface is on the permitted
   list; no value is changed and nothing new is defined. A dark rectangle is
   also what every video player on earth looks like before it plays, so this is
   a material decision rather than a brand one. It is covered the moment a real
   <iframe> or <video> mounts (both are z-index:2 over it), so this only ever
   shows while the film does not exist. */
:root[data-theme="light"] .vsl__frame{background:var(--bone)}
