/* ==========================================================================
   KG Goat Farm — home page (index.html)
   Dark cinematic layout: black ground, rounded section panels, lime accent.
   Design system: see DESIGN.md → "Night Theme" (tokens-only; literals live in
   the :root block below and nowhere else).
   ========================================================================== */

/* Every literal in this file lives here, and every value here is documented in
   DESIGN.md under "Night Theme". Rules below reference tokens only — that is
   what keeps the alpha steps from sprawling back into a dozen near-duplicates. */
:root{
  /* surfaces: black ground, then a four-step panel ramp */
  --black:#050604;
  --panel:#0e0f0a;
  --panel-1b:#111309;
  --panel-2:#15170e;
  --panel-3:#1b1d13;

  /* ink on panels */
  --ink:#ecebe0;
  --ink-2:#9d9e8d;
  --ink-3:#6b6d5e;
  --ink-4:#4a4c40;

  /* ink over photography — four steps, deliberately no more */
  --on-photo-strong:rgba(236,235,224,.94);
  --on-photo:rgba(236,235,224,.72);
  --on-photo-faint:rgba(236,235,224,.45);
  --line-photo:rgba(236,235,224,.16);

  --accent:#cbe45f;
  --accent-2:#a9bb52;
  --accent-3:#c6dd63;
  --accent-hi:#d8ee74;
  --ink-on-accent:#14170a;

  /* accent tints — three steps */
  --accent-line:rgba(203,228,95,.60);
  --accent-line-soft:rgba(203,228,95,.28);
  --accent-tint:rgba(203,228,95,.12);

  --line:rgba(236,235,224,.10);
  --line-2:rgba(236,235,224,.06);

  /* scenic + utility */
  --scrim-pill:rgba(7,9,4,.58);
  --scrim-soft:rgba(10,12,6,.28);
  --sun-core:rgba(255,206,132,.42);
  --sun-halo:rgba(255,184,98,.16);
  --logo-plate:#fff;
  --mask-solid:#000;
  --mask-mid:rgba(0,0,0,.45);
  --shadow-ink:rgba(0,0,0,.90);
  --shadow-float:0 30px 60px -30px rgba(0,0,0,.90);

  --display:'Archivo',system-ui,sans-serif;
  --body:'Source Sans 3',system-ui,sans-serif;

  /* type steps this theme adds on top of the shared ramp */
  --fs-micro:9.5px;
  --fs-label:11px;
  --fs-badge-num:clamp(21px,1.8vw,26px);
  --fs-stat:clamp(26px,2.5vw,36px);
  --fs-display-hero:clamp(88px,18.6vw,290px);
  --fs-display-hero-sm:clamp(74px,25vw,150px);
  --fs-display-morph:clamp(52px,10.4vw,158px);
  /* the shared step's floor is set by the desktop line length; on a phone
     "NATURALLY" at 52px is wider than the panel, so the small screen gets a
     step of its own rather than a clamp that has to serve both */
  --fs-display-morph-sm:clamp(34px,11.2vw,50px);
  --fs-display-morph-aside:clamp(22px,3.1vw,48px);
  --fs-display-section:clamp(30px,3.3vw,48px);
  --fs-quote:clamp(19px,2.3vw,33px);
  --fs-display-cta:clamp(38px,5.4vw,78px);
  /* the outline numeral behind each process step — display scale, but it is
     texture rather than reading matter, so it sits below --fs-display-section */
  --fs-step-ghost:clamp(46px,4.6vw,68px);

  --pad:10px;
  --radius:16px;
  --r-xs:8px;
  --r-sm:12px;
  --r-pill:999px;
  --gutter:clamp(22px,3.2vw,46px);

  /* the nav's resting height — each scroll state overrides it, and
     scroll-padding + the menu's offset both read whatever is current */
  --nav-h:84px;
  /* one duration and one curve for the whole navbar morph, so the bar, the
     mark and the two link wings all arrive together */
  --t-nav:.52s;
  --e-nav:cubic-bezier(.4,0,.2,1);
}

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

html{
  -webkit-text-size-adjust:100%;
  /* the fixed nav must not cover an anchored section */
  scroll-padding-top:calc(var(--nav-h) + 12px);
}

/* No `scroll-behavior:smooth` on the scroller Lenis owns. Lenis animates
   scrollTop itself, frame by frame; with native smoothing on, the browser then
   eases towards each of those frames in turn, so every wheel tick is smoothed
   twice and lands late. That is what made the page feel like it was refusing to
   move. kg-home.js sets `.js-smooth` only once Lenis is actually running, so
   every other path — no GSAP, no Lenis, reduced motion — still gets the
   browser's own smooth scrolling.

   The flag must NOT be called `.lenis-on`, or anything else containing the
   string "lenis". Lenis rewrites the root element's class list on every scroll
   and clears its own namespace first with

       className.replace(/lenis(-\w+)?/g, '')

   — a pattern that matches `lenis-on` in full. The flag was therefore deleted
   microseconds after it was set, this rule stayed live for the whole session,
   and the browser re-smoothed every frame Lenis wrote. The document crept
   forward a few pixels while Lenis's own position ran away to the target, then
   snapped back when Lenis resynced: the "scroll is stuck" bug. */
html:not(.js-smooth){scroll-behavior:smooth;}

/* Lenis's own contract, from its stylesheet. `.lenis` and `.lenis-smooth` are
   maintained by Lenis itself, so these hold even if the flag above is ever
   lost again — the belt to that braces. */
html.lenis,html.lenis body{height:auto;}
html.lenis-smooth{scroll-behavior:auto!important;}
html.lenis-stopped{overflow:hidden;}

/* `overflow-x` lives on the root, not on body, and is `clip` rather than
   `hidden`. `overflow:hidden` on body propagates to the viewport and turns body
   into a scroll container — which ScrollTrigger's pin-spacer then has to
   reserve space inside, and which GSAP's own docs warn against combining with
   pinning. `clip` clips without creating a scrollport, so the pin keeps
   measuring against the real document. Nothing here actually needs the clip
   anyway (every full-bleed layer is already inside a `.panel{overflow:hidden}`)
   — it stays as a guard against a stray wide child. */
html{overflow-x:clip;}

body{
  margin:0;
  background:var(--black);
  color:var(--ink);
  font-family:var(--body);
  font-size:15px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
}

img{max-width:100%;display:block;}
ul,ol{margin:0;padding:0;list-style:none;}
h1,h2,h3,p{margin:0;}
a{color:inherit;text-decoration:none;}
button{font:inherit;color:inherit;}

::selection{background:var(--accent);color:var(--ink-on-accent);}

:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--r-xs);}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

.skip{
  position:fixed;top:8px;left:8px;z-index:200;
  transform:translateY(-160%);
  background:var(--accent);color:var(--ink-on-accent);
  padding:10px 18px;border-radius:var(--r-pill);
  font-family:var(--display);font-weight:700;font-size:13px;
  transition:transform .25s ease;
}
.skip:focus{transform:none;}

/* ────────────────────────────────── page transition + curtains ────── */

/* Both the veil and the hero curtain cover the page before they animate off,
   which makes them the two things on the site that must never survive a
   failure. Three things protect against that, in order:

     1. They are `display:none` until the inline boot script in <head> sets
        `.js-boot`, so JS off means no cover at all.
     2. Both are opened by a CSS animation here — NOT by GSAP. GSAP arrives
        from a CDN, and a blocked or slow CDN would otherwise hold a black
        rectangle over the whole page for as long as the request takes to time
        out. Keyframes run as soon as the stylesheet does.
     3. kg-home.js then removes the elements outright, so neither remains as a
        full-screen composited layer for the rest of the session.

   `both` fill mode is what makes step 2 safe: the animation ends held at its
   final frame, so even if nothing ever removes the node, it stays open and
   invisible rather than snapping back to covering the page. */
.pageveil,.curtain{display:none;}
.no-motion .pageveil,.no-motion .curtain{display:none!important;}

/* "05 · smooth page transition" — one element, both directions.
   The `display` for the shown state lives on the `.js-boot` rule rather than on
   `.pageveil`, because `.js-boot .pageveil` is the more specific selector and
   would otherwise override the layout `display` set here — which is exactly
   what happened: it flattened the grid to block, un-blockified the inline
   span inside it, and left the 100%-sized image resolving against the
   full-screen veil instead of a 64px mark. */
.js-boot .pageveil{
  display:grid;
  animation:veilLift .62s cubic-bezier(.4,0,.2,1) .1s both;
}
.pageveil{
  position:fixed;inset:0;z-index:300;
  background:var(--black);
  place-items:center;
}
@keyframes veilLift{
  from{opacity:1;transform:scale(1);visibility:visible;}
  99% {opacity:0;transform:scale(1.04);visibility:visible;}
  to  {opacity:0;transform:scale(1.04);visibility:hidden;}
}
/* while JS is driving it back down over the page on the way out */
.pageveil.is-covering{animation:none;visibility:visible;}

.pageveil__mark{
  display:block;                 /* a bare <span> is inline, and would ignore both */
  width:64px;height:64px;border-radius:50%;overflow:hidden;
  background:var(--logo-plate);
  box-shadow:0 0 0 1px var(--line-photo);
}
.pageveil__mark img{width:100%;height:100%;object-fit:cover;}

/* "01 · curtain open (hero)" — two halves that part vertically. Fixed, so the
   parting edge runs the full height of the window rather than being cut off by
   the hero panel's own 16px radius. */
.js-boot .curtain{display:block;}
.curtain{
  position:fixed;inset:0;z-index:290;
  pointer-events:none;
}
.curtain__half{
  position:absolute;top:0;bottom:0;width:50.6%;
  background:linear-gradient(180deg,#0b0d07 0%,var(--black) 55%,#0b0d07 100%);
}
.curtain__half--l{left:0;animation:curtainL 1.15s cubic-bezier(.66,0,.34,1) .25s both;}
.curtain__half--r{right:0;animation:curtainR 1.15s cubic-bezier(.66,0,.34,1) .25s both;}
@keyframes curtainL{from{transform:translateX(0);}to{transform:translateX(-101%);}}
@keyframes curtainR{from{transform:translateX(0);}to{transform:translateX(101%);}}

/* the lit seam where the two halves meet, so the open reads as fabric parting
   rather than two rectangles sliding */
.curtain__seam{
  position:absolute;top:0;bottom:0;left:50%;width:2px;
  transform:translateX(-50%);
  background:linear-gradient(180deg,transparent,var(--accent-line) 45%,transparent);
  animation:curtainSeam .55s ease-in .2s both;
}
@keyframes curtainSeam{from{opacity:.5;}to{opacity:0;}}

/* Reduced motion gets neither — no cover, no reveal, just the page. This is a
   media query rather than the `.no-motion` class because it must hold from the
   first paint, before any script has had a chance to add a class. */
@media (prefers-reduced-motion:reduce){
  .js-boot .pageveil,.js-boot .curtain{display:none;}
}

/* The per-section curtains — wipe, up and diagonal. The covering element is
   built by kg-home.js and appended to `[data-curtain]`, so a section with no
   JS simply shows its content. */
.sectionCurtain{
  position:absolute;inset:0;z-index:20;
  background:linear-gradient(120deg,#0b0d07 0%,var(--black) 50%,#0a0c06 100%);
  pointer-events:none;
  transform-origin:left center;
}
/* the diagonal one leaves on a skew, so its edge crosses the panel at an angle;
   over-tall and over-wide so the skewed corners never expose the panel */
.sectionCurtain--diagonal{
  inset:-20% -10%;
  transform-origin:center center;
}
.sectionCurtain__edge{
  position:absolute;top:0;bottom:0;right:0;width:2px;
  background:linear-gradient(180deg,transparent,var(--accent-line) 50%,transparent);
  opacity:.45;
}

/* ───────────────────────────────────────────── shared bits ─────────── */

/* Block flow with margins, not a flex column with `gap`. ScrollTrigger reserves
   a pinned section's scroll distance by wrapping it in a spacer element and
   padding that spacer out to the pin's length — and a flex item does not hold
   that space, so the reservation silently did nothing. The hero pinned fine, but
   every panel below it kept its original position and scrolled up over the top
   of it, which is why the goat could be seen through the 10px gaps between
   panels most of the way down the page. Margins lay out identically here (no
   child relies on flex sizing) and let the pin reserve its space properly. */
.page{
  padding:var(--pad);
  display:block;
}
.page > *{margin-bottom:var(--pad);}
.page > *:last-child{margin-bottom:0;}

.panel{
  position:relative;
  border-radius:var(--radius);
  background:var(--panel);
  overflow:hidden;
  isolation:isolate;
}

/* "02 · ABOUT US" section markers, pinned to the panel's top-left corner */
.marker{
  position:absolute;
  top:clamp(18px,2.2vw,26px);
  left:clamp(20px,2.6vw,32px);
  z-index:6;
  display:flex;
  align-items:center;
  gap:14px;
  font-size:var(--fs-label);
  font-weight:600;
  letter-spacing:.19em;
  text-transform:uppercase;
}
.marker__num{color:var(--ink-3);font-variant-numeric:tabular-nums;}
.marker__label{color:var(--accent-2);}
.marker--over .marker__num{color:var(--on-photo);}

.eyebrow{
  font-size:var(--fs-label);font-weight:600;letter-spacing:.19em;
  text-transform:uppercase;line-height:1.7;color:var(--ink-2);
}
.eyebrow--accent{color:var(--accent-3);}

.rule{
  display:block;width:34px;height:1px;
  background:var(--accent-2);opacity:.55;
  margin:16px 0 20px;
}

.h-display{
  font-family:var(--display);
  font-weight:800;
  line-height:.95;
  letter-spacing:-.025em;
  text-transform:uppercase;
}

.accent{color:var(--accent);}

.btn{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--display);font-weight:700;font-size:12.5px;
  letter-spacing:.01em;
  padding:11px 21px;border-radius:var(--r-pill);
  border:1px solid transparent;
  transition:transform .28s cubic-bezier(.2,.7,.3,1),background-color .28s ease,box-shadow .28s ease;
  /* No `will-change:transform` here. It only moves on hover, and declaring it
     permanently gives every button on the page its own composited layer for the
     99% of the time it is holding still. */
}
.btn--accent{background:var(--accent);color:var(--ink-on-accent);}
.btn--accent:hover{background:var(--accent-hi);transform:translateY(-2px);box-shadow:0 10px 26px -10px var(--accent-line);}
.btn--accent:active{transform:translateY(0);}
/* The nav's outline pill — it has to sit over the hero photograph without
   competing with the closing section's filled CTA. Not `--ghost`: that name is
   already taken by the enquiry page's neutral secondary button, and since
   kg-enquire.css loads after this file it would win on that page and paint the
   nav's CTA in body ink. */
.btn--outline{border-color:var(--accent-line);color:var(--accent);background:transparent;}
.btn--outline:hover{background:var(--accent);border-color:var(--accent);color:var(--ink-on-accent);transform:translateY(-2px);}
.btn--outline:active{transform:translateY(0);}
.btn--lg{font-size:13.5px;padding:14px 26px;}
.btn svg{transition:transform .28s cubic-bezier(.2,.7,.3,1);}
.btn:hover svg{transform:translateX(3px);}

.arrowlink{
  display:inline-flex;align-items:center;gap:10px;
  color:var(--accent);
  font-family:var(--display);font-weight:700;font-size:13px;
}
.arrowlink svg{transition:transform .3s cubic-bezier(.2,.7,.3,1);}
.arrowlink:hover svg{transform:translateX(5px);}

.playlink{
  display:inline-flex;align-items:center;gap:13px;
  font-size:13px;font-weight:500;color:var(--ink);
}
/* No backdrop-filter on this one. It sits in the hero, over a plate that is
   being rescaled and a video that is playing, so the blur cannot be cached and
   is recomputed every frame. A slightly heavier flat scrim reads the same at
   38px across. */
.playlink__btn{
  width:38px;height:38px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  border:1px solid var(--on-photo-faint);
  background:var(--scrim-pill);
  transition:background-color .3s ease,border-color .3s ease,transform .3s ease;
}
.playlink:hover .playlink__btn{background:var(--accent);border-color:var(--accent);color:var(--ink-on-accent);transform:scale(1.08);}
/* sits over the lower third of the FARM wordmark, as in the comp */
.playlink--center{
  position:absolute;left:50%;bottom:6%;
  transform:translateX(-50%);z-index:5;
  padding:6px 16px 6px 6px;border-radius:var(--r-pill);
  background:var(--scrim-pill);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  white-space:nowrap;
}

.mouse{
  width:17px;height:26px;border-radius:var(--r-pill);
  border:1px solid var(--on-photo-faint);
  display:grid;justify-items:center;padding-top:5px;
}
.mouse__dot{
  width:2px;height:5px;border-radius:var(--r-pill);background:var(--on-photo-strong);
  animation:mouseDot 1.9s ease-in-out infinite;
}
@keyframes mouseDot{
  0%,100%{transform:translateY(0);opacity:1;}
  55%{transform:translateY(7px);opacity:.25;}
}

/* ─────────────────────────────────────────────────── nav ───────────── */

/* Centre-logo bar. Everything that moves between the four scroll states is
   driven off `[data-nav-state]` on `.nav`, and every one of those properties is
   transitioned here rather than tweened in JS — so the whole morph costs one
   class write per threshold crossed, not work on every scroll frame.
   See the comment above <header> in index.html for what the states mean. */

.nav{
  position:fixed;top:0;left:0;right:0;z-index:70;
  padding:var(--pad) var(--pad) 0;
  pointer-events:none;
}
.nav__inner{
  pointer-events:auto;
  position:relative;
  height:var(--nav-h);
  padding:0 clamp(14px,2vw,26px);
  display:grid;
  grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
  align-items:center;
  border-radius:var(--radius);
  background:transparent;
  box-shadow:0 0 0 0 transparent;
  transition:
    height var(--t-nav) var(--e-nav),
    background-color var(--t-nav) var(--e-nav),
    box-shadow var(--t-nav) var(--e-nav),
    backdrop-filter var(--t-nav) var(--e-nav);
}

/* the glass arrives at state 1 and stays for the rest of the page */
.nav[data-nav-state="1"] .nav__inner,
.nav[data-nav-state="2"] .nav__inner,
.nav[data-nav-state="3"] .nav__inner{
  background:rgba(8,9,5,.72);
  backdrop-filter:blur(14px) saturate(1.3);
  -webkit-backdrop-filter:blur(14px) saturate(1.3);
  box-shadow:0 12px 34px -22px var(--shadow-ink),inset 0 0 0 1px var(--line-2);
}

/* …except while the bar is sitting on the pinned hero. A backdrop-filter is
   only cheap when what is behind it holds still: the browser blurs the backdrop
   once and reuses it. Over the hero nothing holds still — the photograph is
   being rescaled, the wordmark scrubbed and the goat is a playing video — so the
   blur is recomputed from scratch every frame, and it was the single biggest
   remaining cost in the hero (about a threefold difference in dropped frames).
   Radius makes almost no difference to that; only the backdrop does.
   States 1-2 are exactly the two that overlap the pin, and the plate behind
   them there is already dark and graded, so a flat translucent fill is very
   close to identical. Past the hero the backdrop is ordinary scrolling content
   and the real glass comes back. Browsers without :has() simply keep the blur,
   which is the old behaviour, not a broken one. */
body:has(.hero) .nav[data-nav-state="1"] .nav__inner,
body:has(.hero) .nav[data-nav-state="2"] .nav__inner{
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
}

/* the bar tightens as you go */
.nav[data-nav-state="1"]{--nav-h:74px;}
.nav[data-nav-state="2"]{--nav-h:66px;}
.nav[data-nav-state="3"]{--nav-h:60px;}

/* ---------------------------------------------------- the two link wings */

.nav__side{display:flex;align-items:center;gap:clamp(16px,2.1vw,30px);min-width:0;}
.nav__side--right{justify-content:flex-end;}

.nav__link{
  position:relative;
  font-size:var(--fs-label);font-weight:600;letter-spacing:.15em;text-transform:uppercase;
  color:var(--on-photo);
  white-space:nowrap;
  transition:color .25s ease,opacity var(--t-nav) var(--e-nav);
}
.nav__link::after{
  content:"";position:absolute;left:0;right:100%;bottom:-6px;height:1px;
  background:var(--accent);transition:right .32s cubic-bezier(.2,.7,.3,1);
}
.nav__link:hover{color:var(--ink);}
.nav__link:hover::after,
.nav__link.is-active::after{right:0;}
.nav__link.is-active{color:var(--accent);}

/* State 3 folds the wings away and hands navigation to the burger. They are
   taken out of the tab order too — an invisible link you can still focus is
   worse than no link. */
.nav[data-nav-state="3"] .nav__link{
  opacity:0;pointer-events:none;visibility:hidden;
  transition:opacity .3s var(--e-nav),visibility 0s linear .3s;
}

/* ------------------------------------------------ the centre mark itself */

.nav__brand{
  display:grid;place-items:center;
  justify-self:center;
  position:relative;
}
.nav__mark{
  position:relative;
  width:88px;height:88px;
  border-radius:50%;
  display:grid;place-items:center;
  background:var(--logo-plate);
  box-shadow:0 0 0 1px var(--line-photo),0 10px 30px -14px var(--shadow-ink);
  transition:
    width var(--t-nav) var(--e-nav),
    height var(--t-nav) var(--e-nav),
    background-color var(--t-nav) var(--e-nav),
    box-shadow var(--t-nav) var(--e-nav);
}
.nav[data-nav-state="1"] .nav__mark{width:62px;height:62px;}
.nav[data-nav-state="2"] .nav__mark{width:50px;height:50px;}
.nav[data-nav-state="3"] .nav__mark{width:46px;height:46px;}

/* Past state 1 the white plate drops away and the mark becomes an outline, so
   the monogram and the goat sit in the same ring the full lockup drew. */
.nav[data-nav-state="2"] .nav__mark,
.nav[data-nav-state="3"] .nav__mark{
  background:var(--accent-tint);
  box-shadow:0 0 0 1px var(--accent-line),0 8px 22px -14px var(--shadow-ink);
}

/* the three mark layers are stacked and cross-faded, never re-laid-out */
.nav__markFull,.nav__markKg,.nav__markGoat{
  grid-area:1/1;
  transition:opacity var(--t-nav) var(--e-nav),transform var(--t-nav) var(--e-nav);
}
.nav__markFull{
  width:100%;height:100%;border-radius:50%;object-fit:cover;
}
.nav__markKg{
  font-family:var(--display);font-weight:800;
  font-size:calc(var(--nav-h) * .27);
  letter-spacing:.02em;line-height:1;
  color:var(--accent);
  opacity:0;transform:scale(.7);
}
.nav__markGoat{
  width:58%;height:58%;
  color:var(--accent);
  opacity:0;transform:scale(.7);
}
/* state 2 · the lockup resolves to the monogram */
.nav[data-nav-state="2"] .nav__markFull{opacity:0;transform:scale(1.25);}
.nav[data-nav-state="2"] .nav__markKg{opacity:1;transform:scale(1);}
/* state 3 · the monogram hands over to the goat */
.nav[data-nav-state="3"] .nav__markFull{opacity:0;transform:scale(1.25);}
.nav[data-nav-state="3"] .nav__markKg{opacity:0;transform:scale(1.5);}
.nav[data-nav-state="3"] .nav__markGoat{opacity:1;transform:scale(1);}

.nav__brand:hover .nav__mark{box-shadow:0 0 0 1px var(--accent-line),0 12px 30px -14px var(--shadow-ink);}

/* ------------------------------------------------------- CTA + call + burger */

.nav__cta{flex:none;}

.nav__call,.nav__burger{
  width:40px;height:40px;flex:none;padding:0;
  border:1px solid var(--line-photo);border-radius:50%;
  background:var(--scrim-soft);color:var(--on-photo-strong);
  cursor:pointer;
  display:grid;place-items:center;
  transition:background-color .3s ease,border-color .3s ease,color .3s ease,
             opacity var(--t-nav) var(--e-nav),width var(--t-nav) var(--e-nav),
             margin var(--t-nav) var(--e-nav);
}
.nav__call:hover,.nav__burger:hover{background:var(--accent);border-color:var(--accent);color:var(--ink-on-accent);}

/* Both only exist once the wings are gone. `width:0` rather than `display:none`
   keeps them in the grid so the flip is a transition, not a jump. */
.nav__call,.nav__burger{opacity:0;width:0;border-width:0;pointer-events:none;overflow:hidden;}
.nav[data-nav-state="3"] .nav__call,
.nav[data-nav-state="3"] .nav__burger{opacity:1;width:40px;border-width:1px;pointer-events:auto;}

.nav__burger{flex-direction:column;align-items:center;justify-content:center;gap:4px;}
.nav__burger span{width:14px;height:1.4px;background:currentColor;transition:transform .3s ease,opacity .2s ease;}
.nav__burger[aria-expanded="true"] span:nth-child(1){transform:translateY(5.4px) rotate(45deg);}
.nav__burger[aria-expanded="true"] span:nth-child(2){opacity:0;}
.nav__burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-5.4px) rotate(-45deg);}

/* ------------------------------------------------------------ the menu */

.menu{
  position:fixed;z-index:65;
  top:calc(var(--nav-h) + var(--pad) + 8px);
  left:var(--pad);right:var(--pad);
  margin-inline:auto;max-width:420px;
  background:rgba(8,9,5,.94);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  padding:14px;
  display:flex;flex-direction:column;gap:2px;
  box-shadow:var(--shadow-float);
}
.menu[hidden]{display:none;}
.menu a{
  padding:13px 10px;font-size:14px;font-weight:600;
  color:var(--ink-2);border-bottom:1px solid var(--line-2);
  transition:color .25s ease;
}
.menu a:hover{color:var(--ink);}
.menu a:last-of-type{border-bottom:0;}
.menu__tel{color:var(--ink)!important;}
.menu .btn{justify-content:center;margin-top:8px;border-bottom:0;color:var(--ink-on-accent);}

/* ───────────────────────────────────────────── 01 · hero ───────────── */

.hero{
  height:calc(100vh - var(--pad)*2);
  min-height:600px;
}
@supports (height:100svh){
  .hero{height:calc(100svh - var(--pad)*2);}
}

.hero__stage{position:absolute;inset:0;}

.hero__bg{position:absolute;inset:-7%;will-change:transform;}
.hero__bg img{width:100%;height:100%;object-fit:cover;}

/* No `mix-blend-mode:screen` here, deliberately. A blend mode forces the browser
   to read back everything painted underneath it before it can composite — and
   underneath it is the hero: a scaling photograph, a scrubbed wordmark and a
   playing video. That readback ran on every single frame and on its own held
   the hero to 30fps. Over a plate this dark, screen and normal source-over
   resolve to within a couple of levels of each other anyway (screen against a
   near-black backdrop ≈ straight alpha), so the light reads the same. */
.hero__sun{
  position:absolute;inset:0;
  background:radial-gradient(42% 48% at 32% 22%,var(--sun-core) 0%,var(--sun-halo) 36%,transparent 70%);
}
.hero__grade{
  position:absolute;inset:0;
  background:
    linear-gradient(180deg,rgba(5,7,3,.78) 0%,rgba(5,7,3,.18) 22%,rgba(5,7,3,.10) 46%,rgba(5,7,3,.86) 100%),
    linear-gradient(90deg,rgba(5,7,3,.66) 0%,rgba(5,7,3,.06) 30%,rgba(5,7,3,.06) 70%,rgba(5,7,3,.58) 100%),
    radial-gradient(126% 96% at 50% 44%,transparent 32%,rgba(4,6,2,.70) 100%);
}

.hero__word{
  position:absolute;inset:0;
  display:grid;place-items:center;
  /* lifts the wordmark into the upper band so the goat overlaps its middle
     rather than burying it, the way the comp reads */
  padding-bottom:clamp(120px,25vh,300px);
}
.hero__wordText{
  font-family:var(--display);
  font-weight:900;
  font-size:var(--fs-display-hero);
  line-height:.82;
  letter-spacing:-.035em;
  color:rgba(28,31,15,.74);
  user-select:none;
  will-change:transform;
}

.hero__goat{
  position:absolute;left:50%;bottom:0;
  transform:translateX(-50%);
  /* sized so the horns break into the GOAT letterforms */
  height:63%;
}
/* The entrance and the scrub both drive this box, so this is the layer that
   wants promoting — not the static wrapper above it.

   No mask here, deliberately, and no filter either. The loop is a 680x614 crop
   of a wider plate, so the goat's chest is sliced off square at the frame edge;
   at rest that edge sits on the hero's bottom where nothing sees it, but the
   scrub lifts the whole group and walks the straight line up into view. That
   used to be hidden with `mask-image:linear-gradient(...)` right here — and a
   mask on the one layer whose transform changes every frame is not the free
   "fixed gradient on an already-composited layer" it looks like. It stops the
   box being composited at all: the browser has to re-render its whole subtree
   into a texture and re-apply the mask on every frame of the scrub, and that
   subtree contains a playing VP9 video. Ablated on the pinned hero at 1440x900,
   scrolling: mask on 26fps / 18 dropped video frames, mask off 35fps / 11 —
   and removing the video *instead* scored the same 35fps, which is the tell
   that the two were one cost, not two.

   The same ramp is baked into the alpha channel of goat-loop.webm and its still
   by tools-make-goat-loop.sh, so the fade is identical and costs nothing. The
   element box and the video frame are the same height by construction (both
   layers are height:100% of this box), so the ramp lands on exactly the rows
   the gradient used to. If you re-crop the goat, re-run that script — do not
   put the mask back. */
.hero__goatInner{
  position:relative;height:100%;
  will-change:transform;
}

/* <picture> is inline by default, which would leave the img's height:100% with
   nothing to resolve against — give it the block box the img expects. */
.hero__goat picture,.cta__goat picture{display:block;height:100%;}

.hero__goat img{
  height:100%;width:auto;max-width:none;
}

/* The looping goat sits exactly on top of its own first frame, so it can fade
   in without anything shifting. It stays hidden until kg-home.js confirms the
   browser composites the WebM's alpha — see index.html. */
.hero__goatVid{
  position:absolute;left:0;top:0;
  height:100%;width:auto;max-width:none;
  opacity:0;transition:opacity .5s ease;
  pointer-events:none;
}
.hero__goat.is-live .hero__goatVid{opacity:1;}
/* once the video is carrying the frame, the still underneath is only weight —
   but it must stay laid out, because it is what sizes the box */
.hero__goat.is-live img{visibility:hidden;}

.hero__floor{
  position:absolute;left:0;right:0;bottom:0;height:26%;
  z-index:2;pointer-events:none;
  background:linear-gradient(180deg,transparent 0%,rgba(5,7,3,.30) 42%,rgba(5,7,3,.82) 100%);
}

.hero__copy{
  position:absolute;
  left:var(--gutter);
  top:41%;
  max-width:290px;
  z-index:4;
}
.hero__lede{
  font-family:var(--display);
  font-weight:600;
  font-size:clamp(14px,1.15vw,16px);
  line-height:1.6;
  color:var(--on-photo-strong);
  margin-bottom:26px;
}

.hero__badge{
  position:absolute;
  right:var(--gutter);
  top:57%;
  z-index:4;
  width:min(214px,32vw);
  padding:16px 18px 17px;
  border-radius:var(--r-sm);
  /* Same reasoning as .playlink__btn — this panel sits on the moving hero, so
     its backdrop is never cacheable. Opaque enough to hold the type without
     asking the compositor to re-blur the photograph behind it every frame. */
  background:rgba(9,11,6,.82);
  border:1px solid var(--line-photo);
}
.hero__badgeTop{
  display:flex;align-items:center;gap:11px;
  padding-bottom:12px;margin-bottom:11px;
  border-bottom:1px solid var(--line-photo);
}
.hero__badgeIcon{
  width:30px;height:30px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  border:1px solid var(--accent-line);
  color:var(--accent);
}
.hero__badgeNum{
  font-family:var(--display);font-weight:800;font-size:var(--fs-badge-num);line-height:1;
  letter-spacing:-.02em;
}
.hero__badgeList li{
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.17em;text-transform:uppercase;
  color:var(--on-photo);line-height:2.05;
}

.hero__scroll{
  position:absolute;left:50%;bottom:clamp(16px,2.4vw,26px);
  transform:translateX(-50%);
  z-index:4;
  display:grid;justify-items:center;gap:9px;
}
.hero__scrollLabel{
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.24em;text-transform:uppercase;
  color:var(--on-photo);
}
.hero__scroll:hover .hero__scrollLabel{color:var(--accent);}

/* drifting leaves */
.leaves{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:3;}

/* The drift is a CSS keyframe, not a tween.
   These were twelve elements each carrying an infinite GSAP tween, which meant
   twelve transforms written from the main thread on every single frame for the
   whole session. Measured on the finished page that one detail was the single
   largest cost on the site: removing the leaves took it from 35fps to 58fps.
   As a keyframed transform the animation is handed to the compositor instead
   and the main thread does nothing at all for it, which buys back the frames
   without losing the effect.
   kg-home.js seeds the per-leaf values into the custom properties below and
   decides how many there are; everything after that is the browser's job. */
.leaf{
  position:absolute;top:0;left:0;
  width:18px;height:18px;
  background:no-repeat center/contain;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23a8c25a' d='M21 3C10.5 3 4 7.6 4 14.2c0 2 .6 3.7 1.7 5C8.4 14.5 12 11.6 17 9.8c-4.4 2.5-7.5 5.8-9.6 10.4l2 .8c.5-1.1 1-2 1.6-2.9 1 .2 1.9.3 2.8.3 5.6 0 8.2-4.3 8.2-15.4Z'/%3E%3C/svg%3E");
  opacity:.55;
  animation:leafDrift var(--leaf-dur,14s) ease-in-out var(--leaf-delay,0s) infinite alternate;
}
@keyframes leafDrift{
  from{transform:translate3d(var(--leaf-x,0),var(--leaf-y,0),0) rotate(var(--leaf-r0,0deg));}
  to  {transform:translate3d(var(--leaf-x2,0),var(--leaf-y2,0),0) rotate(var(--leaf-r1,180deg));}
}
/* parked while the panel is nowhere near the viewport — a paused compositor
   animation costs nothing, and nobody can see what it is not doing */
.leaves.is-parked .leaf{animation-play-state:paused;}

/* ────────────────────────────────────── 02 · text transition ───────── */

.morph{
  min-height:clamp(420px,68vh,660px);
  display:flex;align-items:center;
  padding:clamp(72px,8vw,110px) var(--gutter) clamp(48px,6vw,80px);
  background:#0a0b06;
}
.morph__bg{position:absolute;inset:-8%;z-index:-3;will-change:transform;}
.morph__bg img{width:100%;height:100%;object-fit:cover;object-position:center 48%;}
/* The type is the composition, so the plate is graded almost to black and only
   kept as texture — anything lighter and the counters of NATURALLY fill in. */
.morph__grade{
  position:absolute;inset:0;z-index:-2;
  background:
    linear-gradient(180deg,rgba(5,7,3,.88) 0%,rgba(5,7,3,.58) 34%,rgba(5,7,3,.66) 66%,rgba(5,7,3,.92) 100%),
    radial-gradient(120% 90% at 50% 48%,rgba(5,7,3,.22) 0%,rgba(4,6,2,.82) 100%);
}

.morph__inner{position:relative;z-index:2;width:100%;}
.morph__eyebrow{margin-bottom:clamp(18px,2.4vw,30px);}

.morph__word{
  font-family:var(--display);
  font-weight:900;
  line-height:.86;
  letter-spacing:-.035em;
  text-transform:uppercase;
  display:grid;
  gap:clamp(2px,.4vw,8px);
}
.morph__row{display:flex;align-items:flex-start;gap:clamp(12px,1.6vw,28px);}

/* Each line rises from behind its own clip edge. The mask is the clipping box
   and the glyph run inside it is what moves, so the type is never itself the
   animated container — that is what keeps the reveal crisp instead of the whole
   line fading as one block. `padding-bottom` + the matching negative margin buy
   the descender room the clip would otherwise shave off. */
.morph__mask{
  display:block;overflow:hidden;
  padding-bottom:.12em;margin-bottom:-.12em;
}

.morph__big{
  display:block;
  font-size:var(--fs-display-morph);
  color:var(--on-photo-strong);
  /* No `will-change`. These are the largest glyph runs on the page, and
     promoting them permanently hands the compositor a texture the size of the
     panel for type that only moves once, on entrance. GSAP promotes them for
     the duration of that tween and releases them after. */
}
/* "NATURALLY" is two glyphs longer than "RAISED"; tracking it in slightly is
   what keeps both lines ending near the same optical edge, as in the comp. */
.morph__big--wide{letter-spacing:-.05em;}

/* the small accented "the way", set off the baseline of RAISED */
.morph__aside{
  display:grid;
  font-family:var(--display);
  font-weight:500;
  font-style:italic;
  font-size:var(--fs-display-morph-aside);
  line-height:.92;
  letter-spacing:-.02em;
  text-transform:lowercase;
  color:var(--accent);
  padding-top:.12em;
  white-space:nowrap;
}
.morph__aside span:last-child{padding-left:.5em;}

/* the board's supporting line, set against the right edge of the two big
   lines so the block reads as one composition rather than a stacked caption */
.morph__body{
  max-width:42ch;
  margin-top:clamp(22px,2.8vw,34px);
  margin-left:auto;
  font-size:clamp(13px,1.05vw,15px);
  line-height:1.75;
  color:var(--on-photo);
  text-align:right;
}
.morph__body .w{transition:color .1s linear;}

.leaves--morph{z-index:1;}

@media (max-width:1040px){
  .morph__body{margin-left:0;text-align:left;}
}

@media (max-width:760px){
  .morph{min-height:0;align-items:flex-start;}
  .morph__big{font-size:var(--fs-display-morph-sm);}
  .morph__row{flex-direction:column;gap:2px;}
  .morph__aside{padding-top:0;}
  .morph__aside span:last-child{padding-left:1.4em;}
  .morph__body{margin-top:22px;}
}

/* ──────────────────────────────────────────── 03 · about ───────────── */

.about{
  padding:clamp(62px,7vw,86px) var(--gutter) clamp(48px,5vw,72px);
  background:linear-gradient(180deg,#0d0e09 0%,var(--panel-1b) 100%);
  /* `clip`, not `hidden`. `overflow:hidden` establishes a scroll container, and
     a scroll container is what `position:sticky` resolves against — so the
     sticky portrait below would have stuck to a box that never scrolls, i.e.
     done nothing at all. `overflow:clip` clips to the same rounded box without
     establishing one, so the portrait sticks against the viewport as intended.
     Safari below 16 ignores `clip` and simply does not crop, which is a
     cosmetic loss on a panel whose children stay inside it anyway. */
  overflow:clip;
}
.about__grid{
  display:grid;
  grid-template-columns:minmax(0,.95fr) minmax(0,1.25fr);
  gap:clamp(24px,4vw,68px);
  align-items:start;
}

.about__title{
  font-size:var(--fs-display-section);
  margin-bottom:22px;
}
.about__body{
  font-size:13.5px;
  line-height:1.75;
  color:var(--ink-3);
  max-width:38ch;
  margin-bottom:24px;
}
.about__body .w{transition:color .1s linear;}

/* the column that scrolls past the pinned portrait — the gap is what gives the
   sticky travel something to travel through */
.about__flow{display:grid;gap:clamp(44px,6vw,88px);padding-top:clamp(0px,2vw,26px);}

/* "03 · sticky image scroll" */
.about__media{
  margin:0;
  position:sticky;
  top:calc(var(--nav-h) + var(--pad) + clamp(18px,3vw,40px));
}
.about__mediaBox{
  height:clamp(300px,38vw,460px);
  overflow:hidden;
  border-radius:var(--r-sm);
}
.about__media img{
  width:100%;height:100%;object-fit:cover;object-position:52% 40%;
  /* The portrait is shot on black, so fading its own edges is what makes it sit
     in the panel instead of reading as a pasted rectangle. `closest-side` is
     what guarantees the fade actually reaches zero at the box edge — a
     percentage ending-shape larger than 50% leaves a visible rectangle. */
  -webkit-mask-image:radial-gradient(closest-side,var(--mask-solid) 34%,var(--mask-mid) 72%,transparent 100%);
  mask-image:radial-gradient(closest-side,var(--mask-solid) 34%,var(--mask-mid) 72%,transparent 100%);
}
.about__mediaCap{
  display:flex;align-items:center;gap:10px;
  margin-top:16px;
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.17em;text-transform:uppercase;
  color:var(--ink-3);
}
.about__mediaDot{
  width:5px;height:5px;border-radius:50%;flex:none;
  background:var(--accent);
  box-shadow:0 0 0 3px var(--accent-tint);
}

/* Capped rather than filling the column. The rail is pinned to this box's right
   edge, so without a cap it drifted to the far side of a very wide column and
   read as an unrelated line down the panel instead of a gauge beside the list. */
.pillars{
  position:relative;padding-right:34px;
  display:grid;gap:clamp(18px,2vw,26px);
  max-width:540px;
}
.pillar{display:grid;grid-template-columns:32px minmax(0,1fr);gap:15px;align-items:start;}
.pillar__num{
  width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;
  border:1px solid var(--line);
  font-family:var(--display);font-weight:700;font-size:var(--fs-micro);
  color:var(--ink-3);
  transition:color .4s ease,border-color .4s ease,background-color .4s ease;
}
.pillar.is-on .pillar__num{color:var(--accent);border-color:var(--accent-line);background:var(--accent-tint);}
.pillar__title{
  font-family:var(--display);font-weight:700;font-size:12.5px;
  letter-spacing:.13em;text-transform:uppercase;
  color:var(--ink);margin-bottom:7px;
}
.pillar__title em{font-style:normal;color:var(--accent);}
.pillar__body{font-size:12.5px;line-height:1.65;color:var(--ink-3);max-width:38ch;}

.pillars__rail{
  position:absolute;right:6px;top:6px;bottom:6px;width:1px;
  background:var(--line);
  display:flex;flex-direction:column;justify-content:space-between;align-items:center;
}
.pillars__rail i{
  width:5px;height:5px;border-radius:50%;
  background:var(--ink-4);
  transition:background-color .4s ease,box-shadow .4s ease;
}
.pillars__rail i.is-on{background:var(--accent);box-shadow:0 0 0 3px var(--accent-tint);}

/* ────────────────────────────────────── 04 · mission (split) ───────── */

/* "03 · parallax split image". The two columns are given opposite speeds in the
   markup; all this has to do is leave the plate room to travel without showing
   its top or bottom edge — hence the over-tall `.mission__plate` inside a
   fixed-height frame. */
.mission{
  padding:clamp(62px,7vw,90px) var(--gutter) clamp(56px,6vw,84px);
  background:var(--panel-1b);
}
.mission__grid{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(28px,5vw,80px);
  align-items:center;
}

.mission__media{
  margin:0;position:relative;
  height:clamp(320px,40vw,500px);
  border-radius:var(--r-sm);
  overflow:hidden;
}
.mission__plate{
  position:absolute;
  /* the extra 14% top and bottom is the parallax travel budget */
  left:0;right:0;top:-14%;bottom:-14%;
}
.mission__plate img{width:100%;height:100%;object-fit:cover;object-position:50% 42%;}
/* a hairline inset frame, so the plate reads as a considered crop */
.mission__frame{
  position:absolute;inset:clamp(10px,1.2vw,16px);
  border:1px solid var(--line-photo);
  border-radius:var(--r-xs);
  pointer-events:none;
}

.mission__title{
  font-family:var(--display);
  font-weight:800;
  font-size:var(--fs-display-section);
  line-height:1.02;
  letter-spacing:-.025em;
  text-transform:uppercase;
  margin-bottom:20px;
}
.mission__body{
  font-size:13.5px;line-height:1.75;color:var(--ink-3);
  max-width:40ch;margin-bottom:26px;
}
.mission__body .w{transition:color .1s linear;}

.mission__list{display:grid;gap:12px;margin-bottom:28px;}
.mission__list li{
  display:flex;align-items:baseline;gap:14px;
  font-size:12.5px;letter-spacing:.02em;color:var(--ink-2);
  padding-bottom:12px;
  border-bottom:1px solid var(--line-2);
}
.mission__list li:last-child{border-bottom:0;padding-bottom:0;}
.mission__list span{
  font-family:var(--display);font-weight:700;font-size:var(--fs-micro);
  letter-spacing:.1em;color:var(--accent);flex:none;
}

@media (max-width:1040px){
  .mission__grid{grid-template-columns:1fr;gap:32px;}
  .mission__media{height:clamp(260px,52vw,380px);}
}

/* ────────────────────────────────────────── 05 · process ───────────── */

.process{padding:clamp(62px,7vw,86px) var(--gutter) clamp(30px,3.4vw,44px);}
.process__grid{
  display:grid;
  grid-template-columns:minmax(180px,.86fr) minmax(0,3.4fr);
  gap:clamp(24px,3vw,46px);
  align-items:start;
}
.process__intro{position:relative;min-height:190px;}
.process__title{
  font-family:var(--display);
  font-weight:600;
  font-size:clamp(17px,1.5vw,21px);
  line-height:1.45;
  letter-spacing:-.01em;
  color:var(--ink);
}
.process__ghost{
  position:absolute;left:-6px;bottom:-30px;
  width:clamp(120px,12vw,172px);height:auto;
  opacity:.13;
  pointer-events:none;
}

.steps{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(10px,1.1vw,16px);
  align-items:stretch;
}
/* Each card carries its own parallax transform from GSAP, so the hover lift is
   a nested element's job — not this box's. Putting both on the same element
   would mean the hover transition and the scroll-linked transform fighting over
   one `transform`, and the scrub wins sixty times a second. */
.step{
  position:relative;
  display:flex;flex-direction:column;
  padding:clamp(18px,1.7vw,24px) clamp(16px,1.5vw,20px) clamp(20px,1.9vw,26px);
  border-radius:var(--r-sm);
  background:var(--panel-2);
  border:1px solid var(--line-2);
  overflow:hidden;
  transition:border-color .45s ease,background-color .45s ease;
}
.step:hover{border-color:var(--accent-line-soft);background:var(--panel-3);}

/* the board's oversized outline numeral, sitting behind the icon */
.step__ghost{
  /* not a negative top — the card clips its overflow, so a numeral hung above
     the edge loses its cap rather than bleeding off it */
  position:absolute;top:4px;right:12px;
  font-family:var(--display);font-weight:900;
  font-size:var(--fs-step-ghost);
  line-height:1;letter-spacing:-.04em;
  color:transparent;
  -webkit-text-stroke:1px var(--line);
  pointer-events:none;
  transition:-webkit-text-stroke-color .45s ease;
}
.step:hover .step__ghost{-webkit-text-stroke-color:var(--accent-line-soft);}

.step__icon{
  width:clamp(42px,3.6vw,52px);height:clamp(42px,3.6vw,52px);
  flex:none;margin-bottom:clamp(16px,1.6vw,22px);
  border-radius:50%;
  display:grid;place-items:center;
  border:1px solid var(--accent-line-soft);
  background:var(--accent-tint);
  color:var(--accent);
  transition:background-color .45s ease,border-color .45s ease,transform .45s cubic-bezier(.2,.7,.3,1);
}
.step__icon svg{width:52%;height:52%;}
.step:hover .step__icon{transform:scale(1.07);border-color:var(--accent-line);}

.step__title{
  font-family:var(--display);font-weight:800;font-size:15px;
  letter-spacing:.1em;text-transform:uppercase;margin-bottom:9px;
}
.step__body{
  margin-top:auto;
  font-size:12px;line-height:1.6;color:var(--ink-3);max-width:22ch;
}
.step__arrow{display:none;}

/* the arrow columns only exist on wide screens, where there is room */
@media (min-width:1120px){
  .steps{grid-template-columns:1fr auto 1fr auto 1fr auto 1fr;gap:0 clamp(8px,.9vw,14px);}
  .step__arrow{
    display:grid;place-items:center;
    color:var(--ink-4);align-self:center;
  }
}

/* ───────────────────────────────────────────── 05 · farm ───────────── */

.farm{
  padding:clamp(54px,5.6vw,70px) clamp(14px,2.2vw,30px) clamp(26px,3vw,40px);
  background:#0b0c07;
}
.farm__word{position:relative;}
.farm__svg{display:block;width:100%;height:auto;}

/* ─────────────────────────────────────────── 07 · film ─────────────── */

/* "06 · parallax video section" — footage slower than the page, copy faster.
   The stage is a fixed-aspect window and the media inside it is over-tall by
   the same margin the parallax will move it, so no edge is ever exposed. */
.film{
  padding:clamp(54px,5.6vw,72px) clamp(14px,2.2vw,30px) clamp(26px,3vw,40px);
  background:#0a0b06;
}
.film__stage{
  position:relative;
  border-radius:var(--r-sm);
  overflow:hidden;
  aspect-ratio:16/8;
  min-height:300px;
  background:#080905;
}
.film__media{position:absolute;left:0;right:0;top:-12%;bottom:-12%;}
/* The clip is cropped off-centre to cut a watermark off its right-hand edge
   (see tools-make-farm-film.sh), so the framing is recentred here rather than
   in the encode — keeping the pixels and moving the window over them. */
.film__vid{
  width:100%;height:100%;object-fit:cover;
  object-position:56% 42%;
  display:block;
}
.film__grade{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(90deg,rgba(5,7,3,.86) 0%,rgba(5,7,3,.34) 44%,rgba(5,7,3,.12) 70%,rgba(5,7,3,.46) 100%),
    linear-gradient(180deg,rgba(5,7,3,.62) 0%,transparent 32%,rgba(5,7,3,.72) 100%);
}

.film__copy{
  position:absolute;
  left:clamp(20px,3.4vw,54px);
  top:50%;
  transform:translateY(-50%);
  max-width:min(360px,46%);
  z-index:3;
}
.film__title{
  font-family:var(--display);font-weight:800;
  font-size:var(--fs-display-section);
  line-height:1.02;letter-spacing:-.025em;text-transform:uppercase;
  color:var(--on-photo-strong);
  margin:14px 0 16px;
}
.film__body{
  font-size:13px;line-height:1.7;color:var(--on-photo);
  max-width:32ch;
}

.film__play{
  position:absolute;
  right:clamp(22px,4vw,64px);bottom:clamp(22px,3.4vw,48px);
  z-index:4;
  width:clamp(58px,5vw,74px);height:clamp(58px,5vw,74px);
  padding:0;border:0;border-radius:50%;
  display:grid;place-items:center;
  background:var(--scrim-pill);
  color:var(--on-photo-strong);
  cursor:pointer;
  transition:background-color .3s ease,color .3s ease,transform .3s cubic-bezier(.2,.7,.3,1);
}
.film__play:hover{background:var(--accent);color:var(--ink-on-accent);transform:scale(1.07);}
.film__playRing{
  position:absolute;inset:0;border-radius:50%;
  border:1px solid var(--on-photo-faint);
}
.film__play:hover .film__playRing{border-color:var(--accent);}
.film__playIcon{margin-left:3px;}
/* while it is playing the button becomes a pause target and gets out of the way */
.film__play[data-playing="true"]{background:var(--scrim-soft);opacity:.55;}
.film__play[data-playing="true"] .film__playIcon{display:none;}
.film__play[data-playing="true"]::after{
  content:"";width:14px;height:14px;
  border-left:3px solid currentColor;border-right:3px solid currentColor;
}

@media (max-width:760px){
  .film__stage{aspect-ratio:4/5;}
  .film__copy{
    top:auto;bottom:clamp(84px,18vw,120px);transform:none;
    max-width:none;right:clamp(20px,3.4vw,54px);
  }
  .film__grade{
    background:
      linear-gradient(180deg,rgba(5,7,3,.60) 0%,transparent 30%,rgba(5,7,3,.88) 78%,rgba(5,7,3,.94) 100%);
  }
  .film__play{left:clamp(20px,3.4vw,54px);right:auto;bottom:clamp(22px,4vw,34px);}
}

/* ─────────────────────────────────────────── 08 · impact ───────────── */

.impact{
  position:relative;
  padding:clamp(58px,6vw,74px) var(--gutter) clamp(24px,2.6vw,32px);
}
/* "04 · parallax stats" — the plate behind the numbers travels at its own
   speed. Over-tall by the travel budget, same as the film stage. */
.impact__bg{position:absolute;left:0;right:0;top:-14%;bottom:-14%;z-index:-3;}
.impact__bg img{width:100%;height:100%;object-fit:cover;object-position:center 55%;}
.impact__grade{
  position:absolute;inset:0;z-index:-2;
  background:
    linear-gradient(180deg,rgba(5,7,3,.90) 0%,rgba(5,7,3,.80) 50%,rgba(5,7,3,.93) 100%),
    radial-gradient(110% 90% at 50% 50%,rgba(5,7,3,.46) 0%,rgba(4,6,2,.90) 100%);
}
.stats{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(16px,2vw,30px);
}
.stat{display:flex;align-items:center;gap:clamp(10px,1.1vw,16px);}
.stat__icon{
  width:clamp(30px,2.6vw,38px);height:clamp(30px,2.6vw,38px);
  flex:none;color:var(--accent);
}
.stat__icon svg{width:100%;height:100%;}
.stat__num{
  font-family:var(--display);font-weight:800;
  font-size:var(--fs-stat);line-height:1;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;
}
.stat__label{
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.19em;text-transform:uppercase;
  color:var(--ink-3);margin-top:6px;
}
.stat__text{min-width:0;}

@media (min-width:1100px){
  .impact{
    display:grid;
    grid-template-columns:auto minmax(0,1fr);
    align-items:center;
    padding:clamp(30px,3.2vw,42px) var(--gutter);
    gap:clamp(26px,3vw,48px);
  }
  .impact .marker{position:static;}
  .stats{padding-left:clamp(10px,2vw,40px);}
}

/* ─────────────────────────────────────── 07 · testimonials ─────────── */

.voices{
  padding:clamp(58px,6vw,78px) clamp(14px,2vw,26px) clamp(24px,2.6vw,34px);
  background:#0a0b06;
}
.voices__bg{position:absolute;inset:0;z-index:-3;}
.voices__bg img{width:100%;height:100%;object-fit:cover;object-position:center 58%;}
.voices__grade{
  position:absolute;inset:0;z-index:-2;
  background:
    linear-gradient(180deg,rgba(5,7,3,.90) 0%,rgba(5,7,3,.74) 40%,rgba(5,7,3,.94) 100%),
    radial-gradient(100% 80% at 50% 50%,rgba(5,7,3,.52) 0%,rgba(4,6,2,.88) 100%);
}

.voices__stage{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;
  gap:clamp(8px,1.4vw,20px);
}

.voices__nav{
  width:40px;height:40px;flex:none;padding:0;
  border:1px solid var(--line-photo);border-radius:50%;
  background:var(--scrim-soft);color:var(--on-photo);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  display:grid;place-items:center;cursor:pointer;
  transition:background-color .3s ease,border-color .3s ease,color .3s ease,transform .3s ease,opacity .3s ease;
}
.voices__nav:hover{background:var(--accent);border-color:var(--accent);color:var(--ink-on-accent);transform:scale(1.08);}
.voices__nav:disabled{opacity:.3;cursor:default;transform:none;background:var(--scrim-soft);border-color:var(--line-photo);color:var(--on-photo);}

/* The rail is a real scroller with snap points, so a trackpad swipe, a touch
   drag and the arrow buttons all move the same thing — the pointer handler in
   kg-home.js only adds mouse-dragging on top of it. */
.voices__rail{
  display:flex;
  gap:clamp(14px,2vw,32px);
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  scroll-behavior:smooth;
  scrollbar-width:none;
  -ms-overflow-style:none;
  cursor:grab;
}
.voices__rail::-webkit-scrollbar{display:none;}
.voices__rail:focus-visible{outline:2px solid var(--accent);outline-offset:6px;border-radius:var(--r-sm);}
.voices__rail.is-dragging{cursor:grabbing;scroll-behavior:auto;scroll-snap-type:none;}
.voices__rail.is-dragging .voice{user-select:none;}

.voice{
  flex:0 0 100%;
  scroll-snap-align:center;
  display:grid;
  grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:
    "avatar quote"
    ".      by";
  align-items:start;
  gap:6px clamp(16px,2vw,26px);
  padding:clamp(20px,2.8vw,38px) clamp(6px,1.4vw,24px);
}
.voice__avatar{
  grid-area:avatar;
  width:clamp(44px,4vw,56px);height:clamp(44px,4vw,56px);
  border-radius:50%;
  display:grid;place-items:center;
  background:var(--accent-tint);
  border:1px solid var(--accent-line-soft);
  color:var(--accent);
  font-family:var(--display);font-weight:800;font-size:13px;letter-spacing:.06em;
}
.voice__quote{
  grid-area:quote;
  margin:0;
  position:relative;
  font-family:var(--display);
  font-weight:500;font-style:italic;
  font-size:var(--fs-quote);
  line-height:1.45;
  letter-spacing:-.015em;
  color:var(--on-photo-strong);
  text-wrap:balance;
}
/* the open-quote glyph hangs into the gutter so the first word of the
   sentence still starts on the text's own left edge */
.voice__mark{
  position:absolute;left:-.42em;top:-.05em;
  color:var(--accent);font-size:1.25em;line-height:1;
}
.voice__by{
  grid-area:by;
  margin-top:clamp(12px,1.4vw,18px);
  font-size:12.5px;font-weight:600;letter-spacing:.02em;
  color:var(--on-photo);
}
.voice__by span{
  display:block;margin-top:3px;
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.19em;text-transform:uppercase;
  color:var(--on-photo-faint);
}

.voices__dots{
  display:flex;justify-content:center;gap:8px;
  margin-top:clamp(14px,1.8vw,22px);
}
.voices__dot{
  width:6px;height:6px;padding:0;border:0;border-radius:50%;
  background:var(--on-photo-faint);cursor:pointer;
  transition:background-color .3s ease,transform .3s ease,box-shadow .3s ease;
}
.voices__dot:hover{background:var(--on-photo);}
.voices__dot.is-on{background:var(--accent);transform:scale(1.25);box-shadow:0 0 0 3px var(--accent-tint);}

@media (max-width:760px){
  .voices__stage{grid-template-columns:1fr;}
  /* the arrows fall away on touch, where the rail is swiped directly and two
     40px targets would only crowd the quote */
  .voices__nav{display:none;}
  .voice{
    grid-template-columns:1fr;
    grid-template-areas:"avatar" "quote" "by";
    gap:16px;
    padding:clamp(16px,4vw,26px) 4px;
  }
}

/* ──────────────────────────────────────────── 08 · cta ─────────────── */

.cta{
  min-height:clamp(400px,50vh,540px);
  display:flex;align-items:center;
  padding:clamp(66px,7vw,86px) var(--gutter) clamp(40px,4.4vw,58px);
  background:#0a0b06;
}
.cta__bg{position:absolute;inset:-5%;z-index:-3;will-change:transform;}
.cta__bg img{width:100%;height:100%;object-fit:cover;object-position:center 62%;}
.cta__grade{
  position:absolute;inset:0;z-index:-2;
  background:
    linear-gradient(90deg,rgba(5,7,3,.90) 0%,rgba(5,7,3,.55) 38%,rgba(5,7,3,.20) 62%,rgba(5,7,3,.62) 100%),
    linear-gradient(180deg,rgba(5,7,3,.60) 0%,transparent 34%,rgba(5,7,3,.72) 100%);
}
.cta__goat{
  position:absolute;left:56%;bottom:0;z-index:-1;
  transform:translateX(-50%);
  height:88%;
  will-change:transform;
}
/* same reasoning as the hero goat: this one is 1100px wide, parallaxed, and
   sitting behind a grade that already does most of the grounding */
.cta__goat img{
  height:100%;width:auto;max-width:none;
}
.cta__copy{position:relative;z-index:2;max-width:min(440px,52vw);}
.cta__title{
  font-size:var(--fs-display-cta);
  margin-bottom:clamp(20px,2.4vw,30px);
}

/* ───────────────────────────────────────────────── footer ──────────── */

.foot{
  padding:clamp(30px,3.6vw,46px) var(--gutter) clamp(20px,2.2vw,26px);
  background:#0c0d08;
}
.foot__ghost{
  position:absolute;right:-10px;bottom:-22px;
  width:clamp(130px,14vw,196px);height:auto;
  opacity:.12;pointer-events:none;
}
.foot__grid{
  display:grid;
  grid-template-columns:1.5fr 1fr 1.25fr 1fr;
  gap:clamp(24px,3vw,44px);
  padding-bottom:clamp(24px,3vw,38px);
}
.foot__mark{
  width:46px;height:46px;border-radius:50%;overflow:hidden;
  display:grid;place-items:center;background:var(--logo-plate);
  box-shadow:0 0 0 1px var(--line-photo);
  margin-bottom:14px;
}
.foot__mark img{width:100%;height:100%;object-fit:cover;}
.foot__name{font-family:var(--display);font-weight:800;font-size:15px;letter-spacing:.02em;margin-bottom:8px;}
.foot__tag{font-size:12.5px;line-height:1.6;color:var(--ink-3);}

.foot__head{
  font-size:var(--fs-micro);font-weight:600;letter-spacing:.19em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:16px;
}
.foot__col li{font-size:12.5px;line-height:2.05;color:var(--ink-2);}
.foot__col a{transition:color .25s ease;}
.foot__col a:hover{color:var(--accent);}

.foot__social{display:flex;gap:9px;}
.foot__social a{
  width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;
  border:1px solid var(--line);color:var(--ink-2);
  transition:color .3s ease,border-color .3s ease,transform .3s ease,background-color .3s ease;
}
.foot__social a:hover{color:var(--ink-on-accent);background:var(--accent);border-color:var(--accent);transform:translateY(-3px);}

.foot__base{
  border-top:1px solid var(--line-2);
  padding-top:18px;
  display:flex;flex-wrap:wrap;gap:10px 24px;justify-content:space-between;
  font-size:11.5px;color:var(--ink-4);
}

/* ─────────────────────────────────────────── entrance states ───────── */

/* Scoped to `.js-boot`, like the curtains and for the same reason: an entrance
   state is a promise that something will arrive and undo it. With JS off
   nothing ever does, and these rules alone left six elements invisible and two
   images permanently cropped in. Gating them on the boot flag means a reader
   with no JS gets the finished state directly, never the "before" of an
   animation that is not coming. */
.js-boot [data-reveal]{opacity:0;transform:translateY(26px);}
.no-motion [data-reveal]{opacity:1;transform:none;}

/* "01 · scroll triggered zoom in". The scale lives on the image inside the box,
   never on the box itself, so the crop stays put while the picture grows into
   it. Declared here rather than set from JS so there is no first-frame pop
   between paint and the scrub's first update. */
[data-zoom]{overflow:hidden;}
.js-boot [data-zoom] img{transform:scale(1.16);transform-origin:50% 50%;}
.no-motion [data-zoom] img{transform:none;}

/* "04 · hover tilt effect". The tilt itself is written by JS onto the custom
   properties below, which keeps the whole effect in one composited transform
   and lets the element's own parallax stay on a separate wrapper. The
   transition is what makes the pointer leaving feel like a settle rather than
   a snap; while the pointer is inside, JS clears it so tracking stays 1:1. */
[data-tilt]{
  --tilt-x:0deg;--tilt-y:0deg;--tilt-z:0;
  transform:perspective(900px) rotateX(var(--tilt-x)) rotateY(var(--tilt-y)) translateZ(var(--tilt-z));
  transition:transform .5s cubic-bezier(.2,.7,.3,1);
}
[data-tilt].is-tilting{transition:none;}
.no-motion [data-tilt]{transform:none;}

/* A parallaxed element must not also be a `transform`-transition target, or the
   two write the same property from different clocks. */
[data-para]{will-change:transform;}
.no-motion [data-para]{will-change:auto;transform:none!important;}

/* ────────────────────────────────────────────── responsive ─────────── */

@media (max-width:1180px){
  .nav__side{gap:16px;}
  .nav__link{letter-spacing:.11em;}
}

@media (max-width:1040px){
  /* Below this the two wings cannot flank a centred mark without crushing the
     labels, so the bar goes straight to its state-3 shape — burger left, mark
     centre, CTA right — and stays there for the whole page. */
  .nav__link{display:none;}
  .nav__burger{opacity:1;width:40px;border-width:1px;pointer-events:auto;}
  .nav__mark,
  .nav[data-nav-state="1"] .nav__mark{width:64px;height:64px;}
  .nav[data-nav-state="2"] .nav__mark,
  .nav[data-nav-state="3"] .nav__mark{width:48px;height:48px;}

  /* The sticky portrait needs a tall column beside it to travel against, and
     below this width there is no such column — so the section stacks and the
     portrait goes back to being an ordinary block. `position:static` is what
     switches the sticky off; leaving it sticky in one column would pin the
     image to the top of the viewport for the whole section. */
  .about__grid{grid-template-columns:1fr;row-gap:34px;}
  .about__media{position:static;}
  /* the height belongs to the picture box, not to the figure — the figure also
     holds the caption, and clamping it made the two overlap */
  .about__mediaBox{height:clamp(230px,42vw,330px);}
  .about__flow{gap:36px;padding-top:0;}
  .pillars{grid-template-columns:repeat(3,1fr);gap:24px;padding-right:0;max-width:none;}
  .pillars__rail{display:none;}
  .process__grid{grid-template-columns:1fr;}
  .process__intro{min-height:0;padding-bottom:8px;}
  .process__ghost{left:auto;right:0;bottom:auto;top:-16px;opacity:.05;}
  .steps{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;}
  .stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 20px;}
  .foot__grid{grid-template-columns:1fr 1fr;row-gap:32px;}
}

@media (max-width:760px){
  :root{--nav-h:72px;--gutter:20px;}
  .nav[data-nav-state="1"]{--nav-h:66px;}
  .nav[data-nav-state="2"]{--nav-h:62px;}
  .nav[data-nav-state="3"]{--nav-h:58px;}
  /* the call icon is the first thing to go — the CTA and the burger are the
     two targets that have to survive to the narrowest screen */
  .nav[data-nav-state="3"] .nav__call{opacity:0;width:0;border-width:0;pointer-events:none;}
  .nav__cta{font-size:11.5px;padding:10px 16px;}

  .hero{min-height:560px;}
  /* dropped further down the stage than on desktop so the wordmark and the
     goat's head read as one block instead of two things at opposite ends */
  .hero__word{place-items:start center;padding:calc(var(--nav-h) + 96px) 0 0;}
  .hero__wordText{font-size:var(--fs-display-hero-sm);}
  .hero__copy{
    position:absolute;top:calc(var(--nav-h) + 8px);left:var(--gutter);right:var(--gutter);
    max-width:none;
  }

  .hero__copy .rule,.hero__copy .hero__lede,.hero__copy .playlink{display:none;}
  /* Wider than the screen on purpose: the goat reads at a useful size and the
     stage clips the outer ear tips, which is cheaper than stranding it at the
     bottom of a portrait viewport. Lifted off the floor so the head clears the
     wordmark and the 100% badge lands on the chest rather than the muzzle. */
  .hero__goat{height:58%;bottom:9%;}
  .hero__badge{
    top:auto;bottom:72px;left:50%;right:auto;
    transform:translateX(-50%);
    width:min(186px,58vw);
    padding:12px 15px 13px;
  }
  .hero__badgeTop{padding-bottom:10px;margin-bottom:9px;}
  
  .hero__badgeList li{font-size:var(--fs-micro);line-height:1.95;}

  .about__mediaBox{height:clamp(240px,58vw,320px);}
  .pillars{grid-template-columns:1fr;gap:20px;}

  .steps{grid-template-columns:1fr;}
  .stats{grid-template-columns:1fr;gap:20px;}
  .stat{gap:14px;}

  .cta{min-height:440px;}
  .cta__copy{max-width:none;}
  .cta__goat{left:auto;right:-16%;transform:none;height:52%;opacity:.7;}
  .cta__grade{
    background:
      linear-gradient(90deg,rgba(5,7,3,.86) 0%,rgba(5,7,3,.52) 58%,rgba(5,7,3,.34) 100%),
      linear-gradient(180deg,rgba(5,7,3,.70) 0%,rgba(5,7,3,.30) 38%,rgba(5,7,3,.88) 100%);
  }

  .foot__grid{grid-template-columns:1fr;row-gap:28px;}
  .foot__base{font-size:var(--fs-label);}
}

/* ───────────────────────────────── mobile ergonomics ───────────────────
   Most of the people this farm sells to arrive on a phone, so the two things
   that only ever get tested on a desktop — how big the type actually is and
   whether a thumb can hit the controls — get their own block here rather than
   being folded into the layout rules above.

   Nothing in here changes the desktop composition: every rule is inside the
   phone breakpoint, and the hit-area work is done with pseudo-elements and
   min-heights so the drawn size of each control stays exactly as designed. */
@media (max-width:760px){

  /* 9.5px and 11px are legible on a monitor at arm's length and marginal on a
     phone held at reading distance. Both are all-caps and letter-spaced, which
     buys back some apparent size, so this is a nudge rather than a rebuild —
     enough to clear the ~11px floor where small caps stop being comfortable. */
  :root{--fs-micro:11px;--fs-label:12px;}

  /* --- the hero says what the farm sells again ------------------------ */
  /* The lede is the brand promise and it was being hidden on exactly the
     devices most buyers use. It comes back under the eyebrow, and the wordmark
     drops far enough to clear it. The playlink stays hidden: it points at a
     section further down the same page, the nav's Enquire Now is on screen the
     whole time as the real call to action, and the room it would take is room
     the goat needs. */
  .hero__copy .hero__lede{display:block;margin-bottom:0;}
  .hero__lede{font-size:13px;line-height:1.5;}
  .hero__word{padding-top:calc(var(--nav-h) + 168px);}
}

/* Short phones — a 320x568 or an SE-sized screen in a browser with its chrome
   showing. The hero has a fixed cast at the top (nav, eyebrow, lede) and a
   fixed one at the bottom (scroll cue), and between them the goat scales with
   the viewport; below about 640px of height the goat's muzzle arrives exactly
   where the badge is anchored and the badge lands across its face.

   The badge is what gives. It is the one element in the hero whose content
   appears again further down the page — "100% / natural feed" is repeated
   verbatim in the impact stats — so dropping it here costs the reader nothing,
   where dropping the lede would cost them what the farm actually sells. */
@media (max-width:760px) and (max-height:640px){
  .hero__badge{display:none;}
}

/* ───────────────────────────────── touch targets ───────────────────────
   Keyed off the pointer, not the viewport width. What makes a 20px-tall link
   hard to use is a fingertip, not a narrow screen — a tablet is 768px wide and
   still gets tapped, and the audit duly found "Talk to the farm" at 119x20 and
   the testimonial dots at 6x6 there too, after the phone breakpoint had
   already fixed them. `pointer:coarse` is the thing actually being described.

   Every rule below grows the *hit* area and leaves the drawn control alone, so
   none of this is visible until a thumb lands on it. 44px is the comfortable
   floor; WCAG 2.5.8 asks for 24x24, so these clear it with room to spare. */
@media (pointer:coarse){
  /* Padding cannot be used for the nav CTA: the ≤420px block below sets its
     own tighter padding to keep burger + mark + CTA on one line, and would
     win on order. A min-height is orthogonal to that, so both hold. */
  .nav__cta{min-height:44px;}
  .btn,.playlink,.arrowlink{min-height:44px;}

  /* Inline links in a stacked list — 12.5px text on a 2.05 line-height is a
     ~26px box. inline-flex is what lets a min-height apply to them at all. */
  .foot__col li a,.menu a{display:inline-flex;align-items:center;min-height:44px;}
  .foot__col li{line-height:1.5;}

  .foot__social a{width:44px;height:44px;}

  /* The dots are the interesting one. Growing them to 44px would turn four
     6px marks into four fat circles and wreck the rail, so the *drawn* dot
     only goes to 9px and an invisible ::after carries the real target. The
     28px width is the dot plus the gap exactly, so the four targets tile the
     row edge to edge without overlapping — an overlapping hit area is worse
     than a small one, because it sends the tap to the wrong slide. */
  .voices__dots{gap:19px;}
  .voices__dot{width:9px;height:9px;position:relative;}
  .voices__dot::after{
    content:'';position:absolute;top:50%;left:50%;
    width:28px;height:44px;transform:translate(-50%,-50%);
  }
}

@media (max-width:420px){
  /* burger + mark + CTA is the floor of this layout — below 420px the mark is
     what gives, because it is the one element that still reads at half size. */
  .nav__mark,
  .nav[data-nav-state="1"] .nav__mark{width:52px;height:52px;}
  .nav[data-nav-state="2"] .nav__mark,
  .nav[data-nav-state="3"] .nav__mark{width:44px;height:44px;}
  .nav__inner{padding:0 10px;}
  .nav__cta{font-size:11px;padding:9px 13px;}
}

/* ───────────────────────────────────────── reduced motion ──────────── */

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
  }
  [data-reveal]{opacity:1;transform:none;}
  .leaves{display:none;}
}
