/* ============================================================
   KWT MOTION — presentation for the animation layer (kwt-motion.js).

   Loaded LAST on every page, after kwt3d.css, so it can settle the few
   fights it needs to win. Everything in here is one of four things:

     1. Off-switches: when GSAP owns the reveals, the CSS reveal must not
        also run, or every element animates twice.
     2. Ground colours: the page is a story told in three grounds — ink for
        the shop, paper for the brands, green for the customer's truck. The
        body tweens between them and the nav follows.
     3. New furniture: the tire-track stroke under the hero truck, the green
        "see it on your ride" chapter, the stacking step cards, the ghost
        step numbers, the phone thumb bar.
     4. Cross-document view transitions, which are one rule.

   Nothing here animates on its own except the ground tween and the nav
   hide. Every scroll-driven motion is driven from JS, on transform and
   opacity only, and every one of them fails OPEN: with JS off or a CDN down
   this sheet leaves the page fully visible and static.
   ============================================================ */

/* ── 4. Page swaps that morph (Chrome + Safari; no-op elsewhere) ── */
@view-transition { navigation: auto; }
.nav .brand img { view-transition-name: kwt-brand; }
.nav .phone-pill { view-transition-name: kwt-phone; }
::view-transition-old(root) { animation-duration: .22s; }
::view-transition-new(root) { animation-duration: .32s; }

/* ── Lenis (desktop weighted scroll) ──
   The four rules from lenis.css that matter, inlined so there is no extra
   stylesheet request. The scroll-behavior override is the load-bearing one:
   the base sheet asks for native smooth scrolling, and with Lenis writing
   the scroll position every frame the two would fight. (lenis.css also
   disables pointer events on iframes; left out so the map stays draggable.) */
html.lenis, html.lenis body { height: auto; }
html.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }

/* ── 1. Reveal ownership ──
   kwt-motion.js adds html.has-motion the moment GSAP is confirmed loaded,
   then animates every .reveal itself. Until that class lands the base
   stylesheet's IntersectionObserver reveal is the one that runs. */
html.has-motion .reveal,
html.has-motion .reveal--type { opacity: 1; transform: none; clip-path: none; transition: none; }

/* The ticker and brand marquee are driven by GSAP under has-motion so their
   speed can follow scroll velocity. The CSS keyframe must let go first or
   the two fight over the same transform. */
html.has-motion .topbar-track,
html.has-motion #brandWall { animation: none; }

/* Hover rotations move to the individual `rotate`/`scale` properties so
   they compose with the transform GSAP writes for scroll, instead of
   being overwritten by it. */
html.has-motion .finish:hover .finish-art { transform: none; rotate: 28deg; }
html.has-motion .finish-art { transition: rotate .6s cubic-bezier(.16,1,.3,1); }
html.has-motion .teaser-grid:hover .teaser-wheel { transform: none; }
html.has-motion .shot img,
html.has-motion .shot .hero-video { transition: scale .7s cubic-bezier(.16,1,.3,1); }
html.has-motion .shot:hover img,
html.has-motion .shot:hover .hero-video { transform: none; scale: 1.035; }

/* ── 2. Ground ──
   One element tweens (body), so the flip is essentially free. The manifesto
   and its neighbours are transparent so the ground shows through; sections
   that carry their own opaque colour (stats, the green chapter, reviews)
   are unaffected, which is what gives the page hard chapter edges. */
body { transition: background-color .85s cubic-bezier(.4,0,.2,1), color .85s cubic-bezier(.4,0,.2,1); }
body.ground-paper { background: var(--paper); color: var(--on-paper); }
body.ground-paper .manifesto-line { color: var(--on-paper); }
body.ground-paper .manifesto-line .serif { color: var(--brand-dim-p); }
body.ground-paper .scroll-progress { background: var(--brand-dark); }
body.ground-paper .grain { opacity: .05; }

/* The nav follows the ground. Specificity note: kwt.css re-darkens
   .nav.on-paper for the ink hero; body.ground-paper .nav outranks it. */
header.nav { position: sticky; top: 0; z-index: 100;
  transition: background .35s ease, border-color .35s ease, color .35s ease,
              transform .45s cubic-bezier(.16,1,.3,1); }
header.nav.is-hidden { transform: translateY(-101%); }
body.ground-paper .nav { background: rgba(243,243,238,.9); border-bottom-color: rgba(0,0,0,.09);
  color: var(--on-paper); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); }
body.ground-paper .nav .nav-links a { color: var(--on-paper-2); }
body.ground-paper .nav .nav-links a:hover,
body.ground-paper .nav .nav-links a.active { color: var(--on-paper); }
body.ground-paper .nav .brand { color: var(--on-paper); }
body.ground-paper .nav .brand small { color: var(--brand-dark); }
body.ground-paper .nav .phone-pill { background: var(--on-paper); color: var(--paper); }
body.ground-paper .nav .menu-btn span,
body.ground-paper .nav .menu-btn span::before,
body.ground-paper .nav .menu-btn span::after { background: var(--on-paper); }

/* ── 3a. Hero scroll cue ──
   (The drawn tire-track stroke that used to live here is gone: on the page
   it read as a stray green line under the truck, not as a road.) */
.hero-cue { position: absolute; z-index: 2; right: clamp(24px, 4vw, 64px); bottom: clamp(18px, 3vw, 40px);
  display: inline-flex; align-items: center; gap: 10px; pointer-events: none;
  font-family: var(--font-ui); font-weight: 700; font-size: 10.5px; letter-spacing: .28em;
  text-transform: uppercase; color: var(--text-secondary); opacity: 0; }
.hero-cue i { width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid var(--brand);
  display: inline-flex; align-items: center; justify-content: center; color: var(--brand); }
.hero-cue svg { width: 10px; height: 10px; }
@media (max-width: 720px) { .hero-cue { display: none; } }

/* ── 3b. Stats sweep ── a single light pass across the strip on entry */
.stats { position: relative; overflow: hidden; }
.stats .sweep { position: absolute; top: 0; bottom: 0; left: -30%; width: 22%; pointer-events: none;
  background: linear-gradient(105deg, transparent, rgba(16,198,3,.16), transparent);
  transform: skewX(-18deg) translateX(-120%); }

/* ── 3c. The green chapter: SEE IT ON YOUR RIDE ──
   Full-bleed brand green with ink type. It is the loudest colour on the
   page because it is the section no competitor has. Three drawn wheels sit
   on a road line and roll along it as the page scrolls. */
.band--green { background: var(--brand); color: #04140A; position: relative; overflow: hidden; }
.band--green::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse at 20% 0%, rgba(255,255,255,.22), transparent 55%),
              radial-gradient(ellipse at 90% 100%, rgba(4,20,10,.28), transparent 55%); }
.band--green .section { position: relative; }
.band--green .section-eyebrow { color: #04140A; }
.band--green .section-eyebrow::before { background: #04140A; }
.band--green .section-title { color: #04140A; }
.band--green .section-title .accent { color: var(--paper); text-shadow: 0 2px 0 rgba(4,20,10,.18); }
.band--green .section-lede { color: rgba(4,20,10,.78); }
.band--green .ride-ghost { position: absolute; left: 50%; top: 42%; transform: translate(-50%,-50%);
  font-family: var(--font-display); font-weight: 900; font-stretch: 100%;
  font-size: clamp(100px, 19vw, 280px); line-height: 1; letter-spacing: -.04em; white-space: nowrap;
  color: rgba(4,20,10,.07); pointer-events: none; user-select: none; }
.band--green .teaser-grid { background: rgba(4,20,10,.07); border-color: rgba(4,20,10,.22);
  border-left: 3px solid #04140A; grid-template-columns: 1fr; gap: 28px; padding: 0 0 32px; }
/* No overflow:hidden on the frame: the leftmost wheel's roll used to carry it
   past the frame edge, where it was clipped on every viewport narrower than
   the roll allowed for. The band itself still clips at the viewport. */
.band--green .teaser-wheels { position: relative; justify-content: center; gap: clamp(28px, 6vw, 96px);
  padding: 40px 0 0; border-bottom: 3px solid rgba(4,20,10,.7); min-height: 190px; }
.band--green .teaser-wheels::after { content: ""; position: absolute; left: 0; right: 0; bottom: -14px;
  height: 0; border-top: 2px dashed rgba(4,20,10,.32); }
.band--green .teaser-wheel { width: clamp(96px, 11vw, 150px); height: auto; margin-bottom: -3px;
  filter: drop-shadow(0 22px 22px rgba(4,20,10,.42)); transition: none; }
.band--green .teaser-cta { flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 12px; padding: 0 24px; }
.band--green .btn-primary { background: #04140A; border-color: #04140A; color: var(--brand); }
.band--green .btn-primary:hover { background: #0E120F; border-color: #0E120F; box-shadow: 0 12px 34px rgba(4,20,10,.4); }
.band--green .btn-ghost { border-color: rgba(4,20,10,.45); color: #04140A; }
.band--green .btn-ghost:hover { border-color: #04140A; color: #04140A; background: rgba(4,20,10,.08); }
.band--green .ride-note { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 18px;
  font-family: var(--font-ui); font-weight: 700; font-size: 11px; letter-spacing: .24em;
  text-transform: uppercase; color: rgba(4,20,10,.72); }
.band--green .ride-note b { color: #04140A; }
/* Real wheels rolling. The manufacturer's shot already carries the wheel's
   own lip and barrel, so it rolls as-is on the road line - no drawn tyre
   around it (that read as a black ring on the green). The whole image
   rotates; the caption hangs below the road like a sign and stays put. */
.band--green .teaser-wheels.is-real { align-items: flex-end; margin-bottom: 64px; padding-top: 44px; }
.band--green .rw { position: relative; display: flex; flex-direction: column; align-items: center; }
.band--green .rw-roll { position: relative; width: clamp(130px, 14vw, 210px); height: auto;
  aspect-ratio: 1; margin-bottom: -4px; filter: none; }
/* No shadow: the image is what rotates, so any shadow on it would swing
   round the wheel with it instead of staying on the road. */
.band--green .rw-roll img { display: block; width: 100%; height: 100%; object-fit: contain; filter: none; }
.band--green .rw-cap { position: absolute; top: calc(100% + 24px); left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 3px; white-space: nowrap;
  font-family: var(--font-ui); font-weight: 600; font-size: 10.5px; letter-spacing: .2em;
  text-transform: uppercase; color: rgba(4,20,10,.72); }
.band--green .rw-cap b { font-weight: 800; font-size: 11.5px; color: #04140A; }
.band--green .teaser-wheels.is-real::after { bottom: -9px; }

/* The wheel wall with real product photos, and the tire row under it. */
.finish-wall.is-real { grid-template-columns: repeat(auto-fill, minmax(214px, 1fr)); margin-top: 14px; }
.finish-wall.is-real .finish-art { width: min(156px, 66%); height: auto; border-radius: 50%; filter: none; }
/* Tire shots are upright tread-and-sidewall studio photos, so no circle clip. */
.finish-wall.is-tires .finish-art { border-radius: 0; width: min(176px, 74%); }
.wall-head { display: flex; align-items: baseline; gap: 14px; margin-top: clamp(28px, 4vw, 52px);
  font-family: var(--font-ui); font-weight: 800; font-size: 12px; letter-spacing: .3em;
  text-transform: uppercase; color: var(--brand); }
.wall-head::before { content: ""; width: 22px; height: 2px; background: var(--brand); align-self: center; }
.wall-head small { font-size: 10px; letter-spacing: .22em; color: var(--text-muted); font-weight: 700; }

@media (max-width: 820px) {
  .band--green .teaser-wheels { padding-top: 28px; min-height: 130px; }
  .band--green .teaser-wheels.is-real { margin-bottom: 58px; gap: clamp(14px, 4vw, 40px); }
  /* 24vw, not 26: the difference is the side clearance the roll needs to
     stay inside the frame on a 390px screen. */
  .band--green .rw-roll { width: clamp(84px, 24vw, 118px); }
  .band--green .rw-cap { font-size: 9px; letter-spacing: .14em; top: calc(100% + 20px); }
  .band--green .rw-cap b { font-size: 10px; }
  .band--green .ride-ghost { font-size: 28vw; top: 36%; }
}

/* ── 3d. Steps: ghost numbers + desktop stacking ──
   The number is the backdrop, the copy sits in front. On desktop the four
   cards stack as you scroll (each sticks, then the next slides over it);
   on phones they keep the grid and simply stagger in. */
.step { position: relative; overflow: hidden; }
.step-ghost { position: absolute; right: 14px; top: -22px; z-index: 0;
  font-family: var(--font-display); font-weight: 900; font-stretch: 100%;
  font-size: clamp(120px, 15vw, 230px); line-height: 1; letter-spacing: -.05em;
  color: rgba(255,255,255,.045); pointer-events: none; user-select: none; }
.step > :not(.step-ghost) { position: relative; z-index: 1; }
@media (min-width: 821px) {
  html.has-motion .steps { display: block; margin-top: 52px; }
  html.has-motion .step { position: sticky; top: 88px;
    margin-bottom: 28px; min-height: min(46vh, 380px);
    display: flex; flex-direction: column; justify-content: flex-end;
    padding: 34px 40px; background: var(--ink-2);
    border: 1px solid var(--border-strong); border-top: 3px solid var(--brand);
    box-shadow: 0 -18px 50px rgba(0,0,0,.45); transform-origin: 50% 0%; }
  html.has-motion .step:last-child { margin-bottom: 0; }
  html.has-motion .step h3 { font-size: clamp(28px, 3vw, 44px); }
  html.has-motion .step p { max-width: 52ch; font-size: 17px; }
  html.has-motion .step-ghost { font-size: clamp(180px, 20vw, 300px); top: -30px; right: 24px;
    color: rgba(255,255,255,.05); }
}

/* ── 3e. Gallery depth ── the figure moves, the image settles inside it */
html.has-motion .shot { will-change: transform; }

/* ── 3f. Phone thumb bar: Call · Text · Directions ──
   Bottom-anchored, 56px targets, slides in once the hero has scrolled
   away so the hero's own buttons are not doubled. Desktop never sees it. */
.thumbbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 120; display: none; }
@media (max-width: 820px) {
  .thumbbar { display: grid; grid-template-columns: 1.35fr 1fr 1fr; gap: 1px;
    background: var(--border-strong); border-top: 1px solid var(--border-strong);
    padding-bottom: env(safe-area-inset-bottom);
    transform: translateY(110%); transition: transform .4s cubic-bezier(.16,1,.3,1);
    box-shadow: 0 -12px 40px rgba(0,0,0,.5); }
  .thumbbar.is-on { transform: none; }
  .thumbbar a { display: flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 56px; background: #0B0E0A; color: var(--text);
    font-family: var(--font-ui); font-weight: 800; font-size: 11.5px; letter-spacing: .16em;
    text-transform: uppercase; }
  .thumbbar a.call { background: var(--brand); color: #04140A; }
  .thumbbar svg { width: 16px; height: 16px; flex: none; }
  /* Room for the bar over the very last thing on the page. */
  footer .footer-bottom { padding-bottom: 60px; }
}

/* ── Sharper text, solid cards ──
   Two things made copy look washed out. kwt3d.css turns the card surface
   tokens translucent so the 3D badge can ghost THROUGH cards - behind the
   text of steps, services, reviews and the quote form. And the secondary
   text tone sat too close to the ground. This sheet loads last, so it gets
   the final word: card surfaces go back to solid ink (the badge still
   lives in the hero and the open gaps between sections, where nothing has
   to be read over it), and the grey text steps up a level. */
:root {
  --surface-1: #151A16;
  --surface-2: #1B221C;
  --surface-3: #242D25;
  --text-secondary: #B5C0B3;
  --text-muted: #8B978A;
}
.review .text { color: #D9E0D6; }
.review { background: #10140F; }
.quote-card { background: var(--surface-1); }

/* ── Hours card: phones only ──
   On a phone it sits in the page flow under the hero and earns its place.
   On desktop the hero centres its column, so the corner it was pinned to
   never has clear room at any normal window size - it either overlapped
   the buttons or bled the badge through its translucent back. The callbar
   ("OPEN NOW - CLOSES 7PM") and the contact section carry the hours there. */
.nextcard { background: var(--ink-2); border-color: var(--border-strong); }
@media (min-width: 721px) { .nextcard { display: none; } }
/* The brand lockup is a name; it never wraps. */
.nav .brand span { white-space: nowrap; }

/* ── Site credit ── */
.footer-bottom .made-by { display: block; margin-top: 8px; color: var(--text-muted); }
.footer-bottom .made-by a { color: var(--text-secondary); transition: color .2s; }
.footer-bottom .made-by a:hover { color: var(--brand); }

/* ── Reduced motion: the finished state of everything, instantly ── */
@media (prefers-reduced-motion: reduce) {
  body { transition: none; }
  .hero-cue { display: none; }
  header.nav { transition: none; }
  header.nav.is-hidden { transform: none; }
  .thumbbar { transition: none; }
}
