/* Self-hosted so the page makes ZERO third-party requests. Subset to latin,
   width axis pinned at 100, weight axis 100-900 kept: 27 KB for every weight used. */
@font-face{
  font-family:'Archivo';
  src:url('fonts/archivo-subset.woff2') format('woff2');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}

/* ============================================================
   MOCKUP ONLY. The real build self-hosts Archivo via next/font
   and ships zero requests to fonts.googleapis.com.
   ============================================================ */

:root{
  --pill:#FFFFFF;
  --paper:#F8F8F8;
  --sunken:#EDEDEA;
  --ink:#001020;
  --ink-raised:#0A1A2C;

  --green:#80C800;        /* fill only on light. 1.94:1 as text on paper — never text */
  --green-hi:#22E022;     /* hover / focus only */
  --green-deep:#4A7300;   /* 5.48:1 — the only green allowed as TEXT on paper */
  --muted:#8EA0B4;        /* on ink only */
  --muted-ink:#47586A;    /* 6.88:1 on paper. Was #55677A — that measured only 4.05:1
                             for nav links against the translucent bar over the ink band. */

  --ease:cubic-bezier(0,0,.35,1);
  --ease-out:cubic-bezier(.19,1,.22,1);
  --nav-h:72px;
  --gutter:clamp(1rem,5vw,4rem);
  --measure:68ch;
}

*,*::before,*::after{box-sizing:border-box}
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth }
body{
  margin:0;
  overflow-x:clip;              /* clip, NOT hidden — hidden would kill position:sticky */
  background:var(--paper);
  color:var(--ink);
  font-family:Archivo,system-ui,"Segoe UI",Arial,sans-serif;
  font-weight:400;
  font-size:1.0625rem;
  line-height:1.6;
  font-variant-numeric:tabular-nums;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3{ font-weight:600; letter-spacing:-.015em; line-height:1.02; margin:0 }
h1{ font-size:clamp(2.5rem,6vw,4.5rem) }
h2{ font-size:clamp(1.75rem,3.5vw,2.75rem) }
h3{ font-size:1.25rem; line-height:1.25 }
p{ margin:0 }
a{ color:inherit }
img{ display:block; max-width:100% }

.wrap{ width:min(1180px,100%); margin-inline:auto; padding-inline:var(--gutter) }
section{ padding-block:clamp(4.5rem,10vw,8rem) }        /* 128px at desktop */
.s-sunken{ background:var(--sunken) }
.s-ink{ background:var(--ink); color:var(--paper) }
.s-ink h1,.s-ink h2,.s-ink h3{ color:var(--paper) }

.eyebrow{
  font-size:.8125rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--green-deep); display:flex; align-items:center; gap:.6rem; margin-bottom:1.25rem;
}
.eyebrow::before{ content:""; width:9px; height:9px; background:var(--green); border-radius:2px; flex:none }
.s-ink .eyebrow{ color:var(--green) }

.lede{ color:var(--muted-ink); font-size:1.125rem; max-width:var(--measure) }
.s-ink .lede{ color:var(--muted) }

/* ---------- buttons: fill wipe, no scale, no shadow bloom ---------- */
.btn{
  --wipe:var(--green-hi);
  position:relative; isolation:isolate; overflow:hidden;
  display:inline-flex; align-items:center; gap:.55rem;
  min-height:48px; padding:0 1.5rem;
  background:var(--green); color:var(--ink);
  font:inherit; font-weight:600; font-size:1rem;
  border:0; border-radius:999px; cursor:pointer; text-decoration:none;
  white-space:nowrap;                /* without this the nav pill wraps to 2 lines below 430px */
  transition:color 180ms var(--ease);
}
/* overflow:hidden (for the ::after wipe) zeroes the flex automatic minimum size,
   so nowrap alone would clip the label instead of wrapping it. */
.nav .btn{ flex:none }
.btn::after{
  content:""; position:absolute; inset:0; z-index:-1;
  background:var(--wipe); transform:scaleX(0); transform-origin:left;
  transition:transform 180ms var(--ease);
}
.btn:hover::after,.btn:focus-visible::after{ transform:scaleX(1) }
.btn:active{ transform:translateY(1px) }
.btn .arw{ transition:transform 180ms var(--ease) }
.btn:hover .arw{ transform:translateX(3px) }
.btn:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }
.s-ink .btn:focus-visible{ outline-color:var(--paper) }

.btn-ghost{
  background:transparent; color:inherit; border:1px solid var(--muted-ink);   /* .18 alpha measured 1.48:1 — fails SC 1.4.11 */
  min-height:44px; padding:0 1.1rem; border-radius:999px;
  display:inline-flex; align-items:center; font-weight:500; text-decoration:none;
  transition:border-color 180ms var(--ease), background-color 180ms var(--ease);
}
.btn-ghost:hover{ border-color:var(--ink); background:rgb(0 16 32 / .04) }

/* ---------- nav ---------- */
.nav{
  position:sticky; top:0; z-index:50; height:var(--nav-h);
  display:flex; align-items:center;
  background:rgb(248 248 248 / .82);
  border-bottom:1px solid rgb(0 16 32 / .07);
}
@supports (animation-timeline: scroll()){
  @media (min-width:768px){
    .nav{
      background:rgb(248 248 248 / 0); border-bottom-color:rgb(0 16 32 / 0);
      animation:nav-solid linear both;
      animation-timeline:scroll(root block);
      animation-range:0 120px;
    }
  }
}
@keyframes nav-solid{
  to{ background:rgb(248 248 248 / .86); backdrop-filter:blur(12px); border-bottom-color:rgb(0 16 32 / .09) }
}
.nav .wrap{ display:flex; align-items:center; gap:1.5rem; width:min(1180px,100%) }
.brand{ display:flex; align-items:center; gap:.7rem; text-decoration:none; margin-right:auto }
.brand img{ width:44px; height:44px; flex:none }
.brand b{ font-weight:600; font-size:1.0625rem; letter-spacing:-.01em }
.nav-links{ display:none; gap:1.5rem; align-items:center }
.nav-links a{ text-decoration:none; color:var(--muted-ink); font-weight:500; font-size:.9375rem; transition:color 180ms var(--ease) }
.nav-links a:hover{ color:var(--ink) }
@media (min-width:860px){ .nav-links{ display:flex } .nav-menu{ display:none } }
@media (max-width:429px){ .brand b{ display:none } }   /* mark alone carries the brand; wordmark wrapped to 3 lines at 320px */

/* Mobile nav — a zero-JS <details> disclosure. The panel is absolutely positioned
   so opening it never changes the 72px sticky bar height. */
/* static, so the panel anchors to .nav .wrap's right edge instead of the 44px
   hamburger — anchored to the button it hung 26px off the left of the screen. */
.nav .wrap{ position:relative }
.nav-menu{ position:static }
.nav-menu > summary{
  list-style:none; cursor:pointer; display:grid; place-items:center;
  width:44px; height:44px; border-radius:4px; transition:background-color 180ms var(--ease);
}
.nav-menu > summary::-webkit-details-marker{ display:none }
.nav-menu > summary:hover{ background:rgb(0 16 32 / .05) }
.nav-menu > summary:focus-visible{ outline:2px solid var(--ink); outline-offset:2px }
.nav-menu__bars,.nav-menu__bars::before,.nav-menu__bars::after{
  content:""; display:block; width:20px; height:2px; background:var(--ink); border-radius:1px;
}
.nav-menu__bars{ position:relative }
.nav-menu__bars::before{ position:absolute; top:-6px }
.nav-menu__bars::after{ position:absolute; top:6px }
.nav-menu__panel{
  position:absolute; top:calc(100% + .25rem); right:var(--gutter);
  display:grid; gap:.15rem; min-width:min(13rem, calc(100vw - 2 * var(--gutter)));
  padding:.5rem; background:var(--pill); border:1px solid rgb(0 16 32 / .12); border-radius:4px;
  box-shadow:0 8px 28px -10px rgb(0 16 32 / .35);
}
.nav-menu__panel a{
  text-decoration:none; color:var(--ink); font-weight:500; font-size:.9375rem;
  padding:.6rem .75rem; border-radius:3px; min-height:44px; display:flex; align-items:center;
}
.nav-menu__panel a:hover{ background:var(--sunken) }

/* ---------- hero ---------- */
.hero{ padding-block:clamp(3.5rem,9vw,7rem) clamp(3rem,7vw,5.5rem) }
.hero h1{ max-width:16ch }
.hl{ position:relative; display:inline-block; z-index:0; padding-inline:.12em }
/* Sized from top AND bottom, not by height: a fixed height left the ascenders poking
   out the top and the p/g descenders hanging below. This covers the whole word, which
   is also closer to the solid caption blocks in the founder's own videos. */
.hl::before{
  content:""; position:absolute; z-index:-1;
  left:0; right:0; top:-.07em; bottom:-.16em;
  background:var(--green); border-radius:3px;
  transform:scaleX(0); transform-origin:left;
  animation:hl-draw .45s var(--ease-out) .25s forwards;
}
@keyframes hl-draw{ to{ transform:scaleX(1) } }
.hero .lede{ margin-top:1.75rem; font-size:1.1875rem }
.hero-cta{ margin-top:2.25rem; display:flex; flex-wrap:wrap; gap:.75rem; align-items:center }
.hero-note{ color:var(--muted-ink); font-size:.875rem }

/* ---------- problem: the deliberately still section ---------- */
.problem{ padding-block:clamp(5rem,13vw,11.25rem) }   /* 180px — the rhythm break */
/* Opening line and body share ONE measure. At 40ch the intro wrapped to four short
   ragged lines directly above a 68ch block, which read as a mistake rather than as
   emphasis. The hierarchy now comes from size and colour, not from a different width. */
.problem p{ max-width:41rem; font-size:clamp(1.125rem,1.7vw,1.375rem); color:var(--ink); margin-top:1.5rem }
/* The opening statement keeps its narrow measure and its weight. The longer passage
   below runs at normal body size and a normal reading width, so the short line still
   lands first and the detail follows rather than competing with it. */
.problem__more{ margin-top:2.75rem; display:grid; gap:1.15rem; max-width:41rem }
.problem__more p{ font-size:1.0625rem; max-width:none; margin-top:0 }

/* ---------- ticker ---------- */
.tickwrap{ padding-block:0 clamp(3rem,7vw,5rem) }
.tickhead{ display:flex; align-items:baseline; justify-content:space-between; gap:1rem; margin-bottom:.9rem }
.ticklabel{ font-size:.8125rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--muted-ink) }
.ticker:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }
.ticker{
  --gap:2.5rem; overflow:hidden;
  border-block:1px solid rgb(0 16 32 / .09); padding-block:.9rem;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 5rem,#000 calc(100% - 5rem),transparent);
          mask-image:linear-gradient(90deg,transparent,#000 5rem,#000 calc(100% - 5rem),transparent);
}
.tick-track{ display:flex; width:max-content; animation:marquee 40s linear infinite }
.ticker:hover .tick-track,.ticker:focus-within .tick-track{ animation-play-state:paused }
.tick-set{
  display:flex; gap:var(--gap); padding-right:var(--gap);   /* gap on the SET, not the track — keeps -50% on the seam */
  margin:0; padding-left:0; list-style:none; align-items:center;
}
.tick-set li{ color:var(--muted-ink); font-size:.9375rem; white-space:nowrap; display:flex; align-items:center; gap:var(--gap) }
.tick-set li::after{ content:""; width:4px; height:4px; border-radius:50%; background:var(--green); flex:none }
@keyframes marquee{ from{ transform:translate3d(0,0,0) } to{ transform:translate3d(-50%,0,0) } }

/* ---------- editorial sticky two-column ---------- */
.editorial{ display:grid; gap:2.5rem }
/* The sticky MUST live inside the two-column query. Declared outside it, it also applies
   to the single-column mobile layout — where there is no second column to scroll past, so
   the heading pinned itself to the top of the viewport and every card ran underneath it. */
@media (min-width:900px){
  .editorial{ grid-template-columns:minmax(0,4fr) minmax(0,7fr); gap:4rem; align-items:start } /* start, NOT stretch */
  .editorial__aside{ position:sticky; top:calc(var(--nav-h) + 2rem); align-self:start }
}

/* ---------- white pill cards ---------- */
.pills{ display:grid; gap:1rem }
.pill{
  background:var(--pill); color:var(--ink);
  border-radius:20px; padding:1.75rem;
  box-shadow:0 1px 2px rgb(0 16 32 / .05), 0 8px 24px -12px rgb(0 16 32 / .18);
  display:grid; grid-template-columns:auto 1fr; gap:1.25rem; align-items:start;
  transition:box-shadow 200ms var(--ease);
}
.pill:hover{ box-shadow:0 1px 2px rgb(0 16 32 / .06), 0 14px 32px -14px rgb(0 16 32 / .26) }
.pill .n{
  font-size:2.25rem; font-weight:600; line-height:1; color:var(--green-deep);
  min-width:1.6ch; transition:color 200ms var(--ease);
}
.pill:hover .n{ color:var(--ink) }
.pill p{ color:var(--muted-ink); margin-top:.45rem }

/* ---------- accordion (grid 0fr -> 1fr), zero JS ---------- */
.aud{ display:grid; gap:1rem }
@media (min-width:860px){ .aud{ grid-template-columns:repeat(3,1fr) } }
.acc{
  background:var(--ink-raised); border:1px solid rgb(248 248 248 / .09);
  border-radius:4px; padding:1.5rem;
  transition:border-color 200ms var(--ease), background-color 200ms var(--ease);
}
.acc:hover,.acc:focus-within{ border-color:rgb(128 200 0 / .5); background:#0C2032 }
.acc h3 a{ text-decoration:none; color:var(--paper) }
.acc h3 a:focus-visible{ outline:2px solid var(--green); outline-offset:3px }
/* The card body is ALWAYS visible — hiding real copy behind hover costs leads.
   The accordion reveals the reel link, which ADDS something instead. */
.acc p{ color:var(--muted); padding-top:.9rem; margin:0 }
/* The row is reserved permanently and only opacity animates. Growing the row on hover
   pushed every section below down by 38px — motion that shoves the page is worse than none.
   opacity:0 (not visibility/display) keeps the strip focusable, so :focus-within still works. */
.acc__body{ display:grid; grid-template-rows:1fr; opacity:0; transition:opacity 260ms var(--ease) }
.acc:hover .acc__body,.acc:focus-within .acc__body{ opacity:1 }
.acc__body > div{ min-height:0; overflow:hidden }
.acc .more{ color:var(--green); font-size:.875rem; font-weight:600; display:inline-block; padding-top:.9rem }
@media (hover:none),(pointer:coarse){ .acc__body{ opacity:1; transition:none } }

/* Make the heading link cover the whole card so the revealed green cue is actually clickable.
   position:static defeats [data-pending]{position:relative}, which would otherwise collapse
   the stretched ::after back to the heading text. */
.acc{ position:relative; cursor:pointer }
.acc h3 a[data-pending]{ position:static }
.acc h3 a::after{ content:""; position:absolute; inset:0; border-radius:4px }

/* ---------- reel wall ---------- */
.reels{ display:grid; grid-template-columns:repeat(2,1fr); gap:.75rem; margin-top:2.5rem }
@media (min-width:720px){ .reels{ grid-template-columns:repeat(3,1fr) } }
@media (min-width:1080px){ .reels{ grid-template-columns:repeat(6,1fr); gap:1rem } }
.reel{
  position:relative; display:block; aspect-ratio:9/16; overflow:hidden;
  border-radius:4px; background:var(--ink-raised);
  border:1px solid rgb(248 248 248 / .09); text-decoration:none;
  transition:border-color 200ms var(--ease);
}
.reel:hover{ border-color:rgb(128 200 0 / .55) }
.reel:focus-visible{ outline:2px solid var(--green); outline-offset:3px }
/* width/height/object-fit are required now that this is a real <img>: inset:0 alone
   leaves a replaced element at its intrinsic size, so the poster overflowed the frame. */
.reel__inner{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  transition:transform 260ms var(--ease);      /* image moves, frame stays */
}
.reel:hover .reel__inner{ transform:scale(1.05) }
.reel__play{
  position:absolute; inset:0; margin:auto; width:42px; height:42px; border-radius:50%;
  background:rgb(248 248 248 / .92); display:grid; place-items:center;
  transition:background-color 180ms var(--ease);
}
.reel:hover .reel__play{ background:var(--green) }
.reel__play::after{
  content:""; width:0;height:0; margin-left:3px;
  border-left:13px solid var(--ink); border-top:8px solid transparent; border-bottom:8px solid transparent;
}
/* Scrim. The gradient alone left the caption sitting on whatever the frame happened to
   show; the last stretch is now solid ink so the text always has a flat ground under it. */
.reel::after{
  content:""; position:absolute; inset:auto 0 0 0; height:55%;
  background:linear-gradient(to bottom, rgb(0 16 32 / 0) 0%, rgb(0 16 32 / .72) 45%, rgb(0 16 32 / .97) 100%);
  pointer-events:none;
}
.reel__tag{
  position:absolute; z-index:1; left:.6rem; right:.6rem; bottom:.6rem;
  font-size:.8125rem; font-weight:600; color:#FFFFFF; line-height:1.35;
  letter-spacing:-.005em; text-wrap:balance;
}

/* ---------- pending markers (mockup honesty) ---------- */
[data-pending]{ position:relative }
.pending-note{
  font-size:.6875rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted-ink); border:1px dashed rgb(0 16 32 / .28); border-radius:3px;
  padding:.3rem .5rem; display:inline-block;
}
/* .foot is an ink surface too but does not carry .s-ink — without it the
   footer note lands at 3.29:1. Measured, not assumed. */
.s-ink .pending-note,.foot .pending-note{ color:var(--muted); border-color:rgb(248 248 248 / .28) }
.ph{
  background:
    repeating-linear-gradient(135deg, rgb(0 16 32 / .045) 0 9px, transparent 9px 18px);
  border:1px dashed rgb(0 16 32 / .2); border-radius:4px;
  display:grid; place-items:center; text-align:center; padding:1rem;
}
.s-ink .ph{
  background:repeating-linear-gradient(135deg, rgb(248 248 248 / .05) 0 9px, transparent 9px 18px);
  border-color:rgb(248 248 248 / .2);
}

/* ---------- case result ---------- */
.case-fig{
  font-size:clamp(2.75rem,9vw,7rem); font-weight:600; line-height:.9; letter-spacing:-.04em;
  font-variant-numeric:tabular-nums; margin:0; overflow-wrap:normal;
}
.case-fig .cur{ font-size:.42em; vertical-align:.5em; margin-right:.06em; color:var(--green-deep) }

/* ---------- reviews: rolling row ----------
   Same marquee mechanism as the ticker — gap on the SET (not the track), so the
   -50% translate lands exactly on the seam. Duplicate track is aria-hidden.
   Pausable by hover, by keyboard focus, and by an explicit button (SC 2.2.2). */
.revhead{ display:flex; align-items:flex-end; justify-content:space-between; gap:1.5rem; flex-wrap:wrap }
.revscore{ display:flex; align-items:baseline; gap:.6rem }
.revscore b{ font-size:clamp(2.25rem,5vw,3.25rem); font-weight:600; line-height:1; letter-spacing:-.03em; font-variant-numeric:tabular-nums }
.revscore span{ color:var(--muted-ink); font-size:.9375rem }

.revroll{
  --gap:1rem;
  overflow:hidden; margin-top:2.5rem; padding-block:.25rem;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 3rem,#000 calc(100% - 3rem),transparent);
          mask-image:linear-gradient(90deg,transparent,#000 3rem,#000 calc(100% - 3rem),transparent);
}
.revroll__track{ display:flex; width:max-content; animation:marquee 72s linear infinite }
/* No pause button any more. Each card carries a link to the Google review, so the row
   stops on hover for mouse users and on :focus-within for keyboard users. That link is
   the SC 2.2.2 mechanism, and it does more than a button did: it goes to the real review. */
.revroll:hover .revroll__track,
.revroll:focus-within .revroll__track{ animation-play-state:paused }
.revroll__set{
  display:flex; gap:var(--gap); padding-right:var(--gap);
  margin:0; padding-left:0; list-style:none; align-items:stretch;
}
.revroll__set > li{ width:clamp(255px,76vw,350px); flex:none; display:flex }

.rev{
  background:var(--pill); border-radius:4px; padding:1.5rem;
  border:1px solid rgb(0 16 32 / .1); display:flex; flex-direction:column; width:100%;
  transition:border-color 200ms var(--ease);
}
.revroll__set > li:hover .rev{ border-color:var(--muted-ink) }
.rev p{ color:var(--ink); margin:0 }
/* Initial on a disc, the way Google itself renders a reviewer with no photo.
   Not a stock face: these are real people and their likeness is not ours to publish. */
.rev__by{ display:flex; align-items:center; gap:.65rem; margin-top:auto; padding-top:1.25rem }
.rev__av{
  width:34px; height:34px; border-radius:50%; flex:none;
  background:var(--ink); color:var(--paper);
  display:grid; place-items:center; font-weight:600; font-size:.9375rem; line-height:1;
}
.rev cite{ font-style:normal; font-size:.875rem; color:var(--muted-ink) }
/* One link, stretched over the whole card, so the hit area matches what looks clickable. */
.rev{ position:relative; cursor:pointer }
.rev__link{ text-decoration:none; color:var(--muted-ink); font-weight:600 }
.rev__link::after{ content:""; position:absolute; inset:0; border-radius:4px }
.rev__link:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }
.revroll__set > li:hover .rev__link{ color:var(--ink) }
.stars{ color:var(--green-deep); font-size:.875rem; letter-spacing:.1em; margin-bottom:.75rem }

/* ---------- about ---------- */
.about-grid{ display:grid; gap:2.5rem }
@media (min-width:860px){ .about-grid{ grid-template-columns:5fr 7fr; gap:4rem; align-items:center } }
/* Uncapped, the 4:5 box hit 757x947 in the single-column band, taller than the viewport.
   The cap is 17rem rather than 26rem because the supplied photo is only 268px wide;
   displaying it larger would visibly soften it. Raise this when a bigger original lands. */
.portrait{ position:relative; max-width:17rem; margin-inline:auto }
.portrait .ph{ aspect-ratio:4/5; border-radius:4px }
.portrait__img{ width:100%; height:auto; aspect-ratio:4/5; object-fit:cover; border-radius:4px; display:block }
.about__body{ display:grid; gap:1.15rem; margin-top:1.5rem }
.about__body p{ color:var(--muted-ink); max-width:var(--measure) }

.tilt{
  position:absolute; right:-.75rem; bottom:-1.25rem; max-width:17rem;
  background:var(--pill); color:var(--ink); border-radius:20px; padding:1rem 1.25rem;
  box-shadow:0 2px 4px rgb(0 16 32 / .07), 0 18px 40px -18px rgb(0 16 32 / .35);
  font-weight:600; font-size:1.0625rem; line-height:1.25;
  transform:rotate(-1.2deg);          /* the one kept imperfection */
}

/* ---------- form ---------- */
.formstack{ display:grid }
.formstack > *{ grid-area:1/1 }        /* both states share one cell -> height never changes */
.formstack > [data-inactive]{ visibility:hidden; opacity:0; pointer-events:none }
.formstack > :not([data-inactive]){ opacity:1; transition:opacity 200ms var(--ease) }
.field{ display:grid; gap:.4rem; margin-bottom:1rem }
.field label{ font-size:.875rem; font-weight:500 }
.field input,.field textarea{
  font:inherit; font-size:1rem; color:var(--ink); background:var(--pill);
  border:1px solid var(--muted-ink);   /* .16 alpha composited to 1.42:1 — the fields read as invisible */
  border-radius:4px; padding:.7rem .85rem; width:100%;
  min-height:48px; transition:border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.field textarea{ min-height:120px; resize:vertical }
.field input:focus,.field textarea:focus{
  outline:0; border-color:var(--green-deep); box-shadow:0 0 0 3px rgb(128 200 0 / .28);
}
.row2{ display:grid; gap:1rem }
@media (min-width:640px){ .row2{ grid-template-columns:1fr 1fr } }
.hp{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap }
.status{ min-height:2lh; font-size:.875rem; color:var(--muted-ink); margin-top:.75rem }  /* the error wraps to 2 lines; 1.5lh shifted by 11px */
.field input[aria-invalid="true"],.field textarea[aria-invalid="true"]{ border-color:#A3231B }
.field .err{ font-size:.8125rem; color:#A3231B; min-height:0 }
.success{ display:grid; align-content:center; gap:.75rem; text-align:left }
.tick{
  width:46px;height:46px;border-radius:50%;background:var(--green);
  display:grid;place-items:center;color:var(--ink);font-weight:700;font-size:1.4rem;
}

/* ---------- map + footer ---------- */
/* Static image, not a live embed: zero third-party cookies, zero map JS,
   no billed key, and the aspect-ratio box means CLS stays at 0. */
.map{ position:relative; aspect-ratio:4/3; width:100%; overflow:hidden; background:var(--sunken) }
@media (min-width:768px){ .map{ aspect-ratio:3/1 } .map__pin{ left:55.2% } }
@media (min-width:1280px){ .map{ aspect-ratio:5/1 } .map__pin{ left:53.1% } }
.map > img{ width:100%; height:100%; object-fit:cover; display:block; filter:saturate(.72) contrast(1.02) }
/* The marker sits at image fraction 0.5312, but object-fit:cover crops the 5:1 image
   horizontally whenever the box is narrower than 5:1, so x = 50% + 15.6/aspect percent.
   Re-derive if map-static.jpg is re-exported at a different aspect. */
.map__pin{
  position:absolute; left:61.7%; top:50.2%; width:18px; height:18px; margin:-9px 0 0 -9px;
  border-radius:50%; background:var(--green); border:3px solid var(--ink);
  box-shadow:0 0 0 6px rgb(128 200 0 / .28);
}
.map__attr{
  position:absolute; right:0; bottom:0; z-index:500; font-size:.6875rem; line-height:1;
  background:var(--paper); color:var(--muted-ink); padding:.35rem .5rem;  /* .82 alpha let dark map pixels through at 3.60:1 */
}
.map__attr a{ color:var(--muted-ink) }

/* Click-to-load interactive map. The static image is the default: zero JS, zero
   third-party requests, no billed key. Leaflet and the OSM tiles load only when
   the visitor actually asks to move the map. */
.map__load{
  position:absolute; inset:0; z-index:400; display:grid; place-items:center;
  background:rgb(0 16 32 / .12); border:0; cursor:pointer; font:inherit;
  transition:background-color 180ms var(--ease);
}
.map__load:hover{ background:rgb(0 16 32 / .04) }
.map__load:focus-visible{ outline:2px solid var(--ink); outline-offset:-4px }
.map__load span{
  background:var(--pill); color:var(--ink); font-weight:600; font-size:.9375rem;
  padding:.65rem 1.1rem; border-radius:999px; min-height:44px;
  display:inline-flex; align-items:center; gap:.5rem;
  box-shadow:0 2px 4px rgb(0 16 32 / .1), 0 10px 28px -12px rgb(0 16 32 / .4);
}
/* The static image is NEVER removed. It stays underneath at z-index 1, so if the Google
   frame is blocked (a strict CSP, an extension, a tracker blocker) the visitor still sees
   a map instead of an empty box. A working frame simply covers it. */
.map--live .map__load,.map--live .map__pin{ display:none }
.map__canvas{ position:absolute; inset:0; z-index:300; width:100%; height:100%; border:0; display:block }
.map__fallback{
  position:absolute; left:0; right:0; bottom:0; z-index:450;
  background:var(--ink); color:var(--paper); font-size:.8125rem;
  padding:.6rem var(--gutter); display:none;
}
.map--blocked .map__fallback{ display:block }
.map--blocked .map__canvas{ display:none }
.foot{ background:var(--ink); color:var(--muted); padding-block:3.5rem 2.5rem; font-size:.9375rem }
.foot a{ color:var(--paper); text-decoration:none }
.foot a:hover{ color:var(--green) }
.foot-top{ display:grid; gap:2rem; margin-bottom:2.5rem }
@media (min-width:768px){ .foot-top{ grid-template-columns:2fr 1fr 1fr } }
.foot img{ width:40px;height:40px; opacity:.85; margin-bottom:.9rem }
.foot h3{ color:var(--paper); font-size:.8125rem; letter-spacing:.08em; text-transform:uppercase; margin:0 0 .85rem; font-weight:600 }
.foot ul{ list-style:none; margin:0; padding:0; display:grid; gap:.5rem }
.foot-bot{ border-top:1px solid rgb(248 248 248 / .1); padding-top:1.5rem; display:flex; flex-wrap:wrap; gap:1rem; justify-content:space-between; font-size:.8125rem }

/* ============================================================
   SCROLL-DRIVEN ANIMATIONS — progressive enhancement.
   Default state is ALWAYS the finished state. The @supports
   block re-animates it. Browsers without support (Firefox today)
   simply see the final composition — never a blank page.
   ============================================================ */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference) and (min-width:768px){

    /* Section headings are WIPED open left to right, not faded up. Same gesture as the
       hero highlight, so the page has one vocabulary. A fade-up here is the AI signature. */
    .s-sunken h2, .s-ink h2, .revhead h2{
      animation:wipe-in linear both; animation-timeline:view(); animation-range:entry 15% entry 70%;
    }
    @keyframes wipe-in{
      from{ clip-path:inset(0 100% 0 0) }
      to  { clip-path:inset(0 0 0 0) }
    }

    /* Steps slide in from the right — the column they live in. Direction follows layout,
       and the stagger comes from their real positions, not from artificial delays. */
    .pill{ animation:step-in linear both; animation-timeline:view(); animation-range:entry 10% entry 80% }
    @keyframes step-in{ from{ transform:translate3d(3.5rem,0,0) } to{ transform:translate3d(0,0,0) } }

    /* reel row drifts horizontally as you scroll vertically */
    .reels{ animation:reel-drift linear both; animation-timeline:view(); animation-range:cover 8% cover 95% }
    @keyframes reel-drift{ from{ transform:translate3d(7%,0,0) } to{ transform:translate3d(-7%,0,0) } }

    /* The wipe on the case-result figure is GONE, deliberately.
       Its left column is sticky, so the section stays on screen far longer than the
       animation range assumed, and the number sat half-clipped at normal reading
       positions. A figure that is sometimes unreadable is worse than a figure that
       never moves, and on a CPA page the number is the one thing that must be legible. */

    /* the pill drops into its kept imperfection */
    .tilt{ animation:pill-settle linear both; animation-timeline:view(); animation-range:entry 20% entry 95% }
    @keyframes pill-settle{
      from{ transform:rotate(-9deg) translate3d(0,-1.25rem,0) }
      to  { transform:rotate(-1.2deg) translate3d(0,0,0) }
    }
  }
}

/* ============================================================
   REDUCED MOTION — kills everything, including scroll-driven.
   animation-timeline:auto is the non-obvious line: scroll-driven
   animations ignore animation-duration entirely, so the 0.01ms
   reset below does nothing until they are put back on the
   document timeline.
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto !important }
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-delay:-.01ms !important;
    animation-iteration-count:1 !important;
    animation-timeline:auto !important;
    transition-duration:.01ms !important;
    transition-delay:0s !important;
    scroll-behavior:auto !important;
  }
  .hl::before{ transform:scaleX(1) }
}

.sr{ position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap }
.skip{ position:absolute; left:-9999px; top:0; background:var(--ink); color:var(--paper); padding:.75rem 1rem; z-index:100 }
.skip:focus{ left:0 }
/* Without this every anchor jump lands its target under the 72px sticky bar. */
[id]{ scroll-margin-top:calc(var(--nav-h) + 1rem) }

/* ============================================================
   Document pages — privacy, terms, 404.
   Same tokens, narrow measure, no motion.
   ============================================================ */
.doc{ padding-block:clamp(3rem,7vw,5rem) clamp(4rem,9vw,7rem) }
.doc .wrap{ width:min(760px,100%) }
.doc h1{ font-size:clamp(2rem,4.5vw,3rem) }
.doc h2{ font-size:1.375rem; margin-top:2.75rem }
.doc h3{ font-size:1.0625rem; margin-top:1.75rem }
.doc p,.doc li{ color:var(--muted-ink); margin-top:.9rem; max-width:64ch }
.doc strong{ color:var(--ink) }
.doc ul{ padding-left:1.1rem; margin:0 }
.doc li{ margin-top:.5rem }
.doc a{ color:var(--green-deep); font-weight:600 }
.doc .updated{ font-size:.875rem; color:var(--muted-ink); margin-top:1rem }
.doc .note{
  border-left:3px solid var(--green); background:var(--sunken);
  padding:1rem 1.25rem; margin-top:1.5rem; border-radius:0 4px 4px 0;
}
.doc .note p{ margin-top:.4rem }
.doc .note p:first-child{ margin-top:0 }
.doc dl{ margin:1rem 0 0 }
.doc dt{ font-weight:600; color:var(--ink); margin-top:1rem }
.doc dd{ margin:.25rem 0 0; color:var(--muted-ink) }

/* 404 */
.nf{ min-height:60vh; display:grid; place-items:center; text-align:center; padding-block:5rem }
.nf .code{
  font-size:clamp(4rem,14vw,9rem); font-weight:600; line-height:.9;
  letter-spacing:-.04em; font-variant-numeric:tabular-nums; color:var(--ink);
}
.nf h1{ font-size:clamp(1.5rem,3.5vw,2.25rem); margin-top:1rem }
.nf p{ color:var(--muted-ink); margin-top:1rem }
.nf .actions{ margin-top:2rem; display:flex; gap:.75rem; justify-content:center; flex-wrap:wrap }
