/* ==========================================================================
   MOJO soft-launch landing — production stylesheet
   Source of truth: design-reference/mocks/mojo_home_v12_mock2_final.html
   This is that stylesheet, productionised. Every deviation is marked [PROD].
   Dead rules for sections the final mock does not render (tagline, proof-grid,
   why-teaser, steps, belief, side cart, video grid, review cards) were dropped.
   ========================================================================== */

/* [PROD] self-hosted Inter — removes the render-blocking Google Fonts request
   and the two third-party preconnects the mock carried. */
@font-face{
  font-family:"Inter";
  src:url("../assets/fonts/inter-var-latin.woff2") format("woff2");
  font-weight:400 900;
  font-style:normal;
  font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root{
  --black:#000; --ink:#0A0A0A; --panel:#111113; --white:#fff; --grey:#F4F4F5;
  --line-dk:#232327; --line-lt:#E4E4E7;
  --muted-dk:#A1A1AA; --muted-lt:#52525B; --legal-dk:#8F8F95;
  --accent:#E66000; --accent-hover:#F97316; --accent-bright:#FB923C; --accent-on-light:#A34200; --brand:rgba(255,117,23,.9); --brand-glow:rgba(255,117,23,.6);
  --font-ui:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --fs-lg:clamp(1.15rem,1rem + 0.5vw,1.3rem);
  --fs-d2:clamp(1.9rem,1.4rem + 2.6vw,3rem);
  --fs-hero:clamp(2.9rem,1.9rem + 5.6vw,5rem);
  --ls-tight:-0.035em; --ls-snug:-0.02em; --ls-wide:0.18em;
  --band-pad:clamp(72px,10vw,128px); --wrap-pad:clamp(24px,5vw,64px); --wrap-max:1280px;
  --glow-accent:0 12px 48px -12px rgba(230,96,0,.55);
  --e-out:cubic-bezier(0.19,1,0.22,1); --e-spring:cubic-bezier(0.34,1.56,0.64,1);
  /* [PROD] focus ring is context-aware: light bands re-declare it below so the
     ring always clears 3:1 against what sits behind it (WCAG 1.4.11). */
  --focus-ring:#FB923C;
}
*{box-sizing:border-box;margin:0;padding:0}
/* [PROD] smooth scroll only when motion is welcome */
@media(prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}
body{background:var(--black);color:var(--white);font-family:var(--font-ui);line-height:1.55;-webkit-font-smoothing:antialiased;overflow-x:hidden}
a{color:inherit;text-decoration:none}
img,svg{display:block}
::selection{background:var(--accent);color:#0A0A0A}
.wrap{max-width:var(--wrap-max);margin:0 auto;padding-inline:var(--wrap-pad)}

/* [PROD] focus + skip link — the mock had neither, and stripped input outlines. */
:focus-visible{outline:3px solid var(--focus-ring);outline-offset:3px;border-radius:6px}
.band--white,.band--grey,.trustbar{--focus-ring:#A34200}
.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--accent);color:#0A0A0A;font-weight:800;padding:14px 22px;border-radius:0 0 12px 0}
.skip:focus{left:0}
.visually-hidden{position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
/* A break that only fires once there is room for the line it creates: it holds
   a phrase together on wide screens and disappears on narrow ones so the text
   wraps on its own. The markup keeps a space before it, which is what separates
   the words when the break is removed. */
.br-md{display:none}
@media(min-width:561px){.br-md{display:inline}}

.eyebrow{font-size:.8rem;font-weight:800;letter-spacing:var(--ls-wide);text-transform:uppercase;color:var(--accent)}
.band--white .eyebrow,.band--grey .eyebrow{color:var(--accent-on-light)}
h1,h2,h3{letter-spacing:var(--ls-tight);font-weight:800;line-height:1.04}

.btn{display:inline-flex;align-items:center;gap:.5em;font-weight:700;font-size:.95rem;padding:14px 24px;border-radius:12px;border:1.5px solid transparent;cursor:pointer;transition:transform .15s var(--e-out),background .2s,border-color .2s,box-shadow .2s}
.btn--lg{padding:16px 30px;font-size:1rem}
.btn--sm{padding:10px 18px;font-size:.85rem}
/* [PROD] CTA label is near-black, not white. White on this fill is 3.28:1 and
   fails AA for normal text; #0A0A0A is 6.03:1 — and CLAUDE.md locks
   "CTA = black label on orange fill; never white-on-orange". The text-shadow
   went with it (it existed to rescue the white label). */
.btn--accent{background:var(--brand);color:#0A0A0A;font-weight:800;border-radius:999px;box-shadow:0 0 25px 10px var(--brand-glow)}
.btn--accent:hover{background:var(--accent);transform:scale(1.04);box-shadow:0 0 32px 12px rgba(230,96,0,.6)}
/* [PROD] the mock fixed this at width:340px. A fixed width makes the grid
   item's min-content 340px too, so at 320px the button ran 44px past the
   viewport and the right end was clipped — a WCAG 1.4.10 reflow failure.
   Cap instead of fix: identical at every width above 340. */
.cta-main{flex-direction:column;align-items:center;justify-content:center;gap:2px;width:100%;max-width:340px;min-height:84px;padding:0;border-radius:999px;line-height:1.05;transition:transform .55s cubic-bezier(.22,.61,.36,1),background .55s cubic-bezier(.22,.61,.36,1),box-shadow .55s cubic-bezier(.22,.61,.36,1)}
.cta-l1{font-size:1.22rem;font-weight:800;letter-spacing:.01em}
/* [PROD] '16 fl oz · Ready To Use' is the most important product fact on the
   page. It used to be hover-only, i.e. invisible to every mouse user who did
   not happen to hover, and to every keyboard user. Now it is always shown. */
.cta-l2{font-size:.82rem;font-weight:600;letter-spacing:.04em;opacity:.92}
.cta-main:hover .cta-l2,.cta-main:focus-visible .cta-l2{opacity:1}
/* [PROD] '16 fl oz · Ready To Use' sits INSIDE the button as .cta-l2 on every
   breakpoint (two-line pill). The separate outside .cta-caption was removed
   with the mobile swap it existed for. */
.cta-sep{display:inline-block;width:3px;height:.9em;background:currentColor;opacity:.6;margin:0 .5em;vertical-align:-.03em;border-radius:2px}
.btn--accent.cta-main:hover{background:var(--accent);transform:scale(1.06);box-shadow:0 0 36px 13px rgba(230,96,0,.6)}
.arr{transition:transform .2s var(--e-out)}
.btn:hover .arr{transform:translateX(3px)}

/* ===== scroll reveals =================================================
   Gated on .js so a no-JS visitor never gets a blank page, and on
   prefers-reduced-motion so it is opt-out by default for anyone who asks.
   Opacity + translate only — no layout property animates, so CLS stays 0. */
@media(prefers-reduced-motion:no-preference){
  .js [data-reveal]{
    opacity:0;
    transform:translate3d(0,18px,0);
    transition:opacity .7s var(--e-out),transform .7s var(--e-out);
    transition-delay:var(--rv,0ms);
    will-change:opacity,transform;
  }
  .js [data-reveal].is-in{opacity:1;transform:none;will-change:auto}
}

/* [PROD] The closing CTA reveals the reassurance line ABOVE it (.sub) on hover
   or focus, so the closer stays clean until intent shows. .sub is a preceding
   sibling of .closer-cta, so the toggle is driven from the shared .wrap parent
   with :has(). data-reveal was removed from .sub in the markup so the scroll
   reveal cannot fight this. Only opacity animates; the reduced-motion block
   flattens the fade. Desktop only: below 861px the line is always visible. */
@media(min-width:861px){
  .closer .wrap .sub{opacity:0;transition:opacity .35s var(--e-out)}
  .closer .wrap:has(.cta-main:hover) .sub,
  .closer .wrap:has(.cta-main:focus-visible) .sub{opacity:1}
}
/* :has() is broadly supported, but if it is missing the line must not be stuck
   invisible — no-:has desktop gets it permanently, same as mobile. */
@supports not selector(:has(*)){
  @media(min-width:861px){.closer .wrap .sub{opacity:1}}
}

/* ghost wordmark — page-wide watermark. Brightened to .15 (from .10) so it also reads through the 85% white FAQ band; stays faint on the dark sections. */
.ghost{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.ghost svg{position:absolute;top:50%;left:50%;transform:translate(-50%,-49.5%);height:100%;width:auto;opacity:.15}

/* trustbar + nav */
.trustbar{position:relative;z-index:5;overflow:hidden;background:#fff;border-bottom:1px solid #e3e3e6;font-size:clamp(1.05rem,1.35vw,1.25rem);color:#111;font-weight:700;letter-spacing:.03em}
.trustbar .wrap{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;gap:12px;min-height:36px;padding-block:6px}
/* [PROD] the shine's light stop was #efe9dd — 1.21:1 on white, i.e. the offer
   line went almost invisible on every pass. Lightest stop is now #6B6B6B (5.0:1)
   so the sweep never drops the text below AA. */
/* [PROD] the shimmer was an infinite animation on a static fact — a permanent
   tax on attention for no information gain. Element and copy unchanged. */
.trustbar .wrap span{color:#141414}
.trustbar svg{width:24px;height:24px;flex:0 0 24px;fill:none;stroke:var(--accent);stroke-width:1.8}
/* [PROD] One arrival on load, then it parks. Not a loop and not a marquee: the
   offer is a static fact, so the motion earns a single glance and then stops
   competing with the page. Gated on .js so a no-JS visitor sees it parked, and
   on prefers-reduced-motion. Slowed 900ms -> 1500ms (2026-08-26): at 900ms the
   drive-in read as a flinch rather than an arrival. Still exactly one pass. */
@media(prefers-reduced-motion:no-preference){
  .js .trustbar svg{animation:truckin 1500ms cubic-bezier(.22,.61,.36,1) both}
  @keyframes truckin{
    from{transform:translateX(-42vw);opacity:0}
    60%{opacity:1}
    to{transform:translateX(0);opacity:1}
  }
}

/* [PROD] the mock's nav is rgba(0,0,0,.6). Sticky over the white FAQ band that
   composites to #666666, where the orange active link reads 2.54:1 — a fail.
   At .82 the bar is visually unchanged over the black bands (black on black)
   and the active link holds 6.0:1 over white. */
.nav{position:sticky;top:0;z-index:40;background:rgba(0,0,0,.82);backdrop-filter:blur(12px);border-bottom:1px solid rgba(255,255,255,.07)}
.nav .wrap{display:flex;align-items:center;justify-content:space-between;height:86px;gap:24px}
.brand{display:block}
.brand-logo{height:72px;width:auto;transform:translateY(3px)}
.nav-links{display:flex;gap:clamp(52px,6.8vw,96px);list-style:none;font-size:0.89rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}
/* [PROD] 44px min target height on the nav links */
.nav-links a{display:flex;align-items:center;min-height:44px;color:#fff;transition:color .2s var(--e-out)}
.nav-links a:hover{color:var(--accent-bright)}
/* [PROD] colour alone cannot carry the active-section state (1.4.1); the inset
   rule adds a second cue without reflow or clashing with the focus outline. */
.nav-links a.is-active{color:var(--accent);box-shadow:inset 0 -2px 0 currentColor}
.nav-actions{display:flex;align-items:center;gap:14px}
/* hide the whole landmark, not just the list: an empty <nav> is still a flex
   item and its 24px gap pushed the header past 320px */
@media(max-width:820px){.nav-desktop{display:none}}

/* hero */
main{position:relative;z-index:2}
.hero{position:relative;color:#fff;padding:clamp(36px,5vw,64px) 0 clamp(24px,4vw,48px)}
.hero .wrap{display:grid;grid-template-columns:1.25fr .75fr;gap:40px;align-items:center}
.hero-copy{min-width:0}
.hero h1{font-size:var(--fs-hero);font-weight:900}
.hero h1 em{font-style:normal;color:var(--accent)}
.hero-h2{margin-top:20px;font-size:clamp(1.1rem,1rem + .75vw,1.5rem);font-weight:700;color:#F3F1EC;letter-spacing:-.01em;line-height:1.3}
.hero-h3{margin-top:16px;font-size:clamp(1.1rem,1rem + .55vw,1.35rem);font-weight:500;color:var(--muted-dk);line-height:1.55}
.hero-h3 b{color:#fff;font-weight:700}
@media(max-width:860px){.hero-h2,.hero-h3{margin-left:auto;margin-right:auto}}
.hero-cta{margin-top:32px;display:flex;gap:16px;flex-wrap:wrap;align-items:center}
/* [PROD] the mock's rule is `transform:translateX(30px)` — the "bottle nudged
   right" change in the handoff changelog. It never rendered: `.stage` also
   carried data-reveal, and the later `[data-reveal]{transform:none}` reset
   (equal specificity) cancelled it. Matching the mock AS APPROVED ON SCREEN,
   so the nudge stays off. Restore by putting the translate back here. */
.stage{position:relative;display:flex;justify-content:center;align-items:flex-end;min-height:60vh}
.stage picture{position:relative;z-index:2}
/* the reflection's <picture> wrapper must not become a flex item of its own */
.stage .shot{position:relative;z-index:2}
/* [PROD] The third term keeps the bottle base above the fold on short desktop
   windows (laptops ~768-960px tall), where 78vh alone pushed the base below
   the viewport. 250px reserves the trust bar + nav + hero top padding
   (~212px) plus a small bottom margin. Tall monitors are governed by the
   820px cap as before, so the large render is unchanged there. Mobile is
   untouched (the <=860px rules override this height). */
.stage .shot{height:min(78vh,820px,calc(100vh - 250px));width:auto;filter:drop-shadow(0 40px 60px rgba(0,0,0,.65))}
/* [PROD] The mirrored reflection was replaced by a neutral floor glow: the
   flip duplicated the label upside down and read as a second bottle at small
   sizes. This grounds the render without repeating it. */
.stage .floor{position:absolute;z-index:1;bottom:0;left:50%;transform:translateX(-50%);width:min(42%,340px);height:90px;pointer-events:none;background:radial-gradient(ellipse at center,rgba(255,255,255,.16) 0%,rgba(255,255,255,.07) 42%,rgba(255,255,255,0) 72%);filter:blur(7px)}
/* [PROD] Mobile hero, tuned so the buy button clears the fold on a 390x844
   phone — it was landing 168px below it. The bottle came down to 34vh, but the
   real cost was the h1: at 2.9rem "With Standards." no longer fits 342px and
   broke to a third line (163px tall). 2.5rem puts it back on two lines. The
   rest is margin discipline. Measured: CTA bottom 1012px -> inside the fold. */
@media(max-width:860px){
  .hero .wrap{grid-template-columns:1fr;text-align:center;gap:24px}
  .hero{padding-top:24px}
  .stage{order:-1;min-height:auto;transform:none}
  .stage .shot{height:46vh}
  .hero h1{font-size:clamp(2.5rem,1.6rem + 4.6vw,3.4rem)}
  .hero-h2{margin-top:14px}
  .hero-h3{margin-top:12px}
  .hero-cta{justify-content:center;margin-top:22px}
  .hero-cta .cta-main{min-height:76px}
  /* [PROD] the desktop glow is too heavy at phone size, where the button is
     a much larger share of the screen. Desktop and hover are untouched. */
  .btn--accent.cta-main{box-shadow:0 0 18px 5px rgba(230,96,0,.38)}
}

/* [PROD] anchor targets must clear the 86px sticky header — the mock had no
   scroll-margin, so #why / #faq landed underneath the nav. */
main > section[id],footer[id]{scroll-margin-top:100px}
@media(max-width:640px){main > section[id]{scroll-margin-top:78px}}

/* [PROD] Short viewports (older/smaller phones, and any phone in landscape).
   The bottle is proportional so it shrinks with the screen, but the type stack
   does not — so on a 667px-tall screen the CTA slid back under the fold. Keyed
   on height, so tall modern phones keep the larger hero. */
@media(max-width:860px) and (max-height:780px){
  .hero{padding-top:16px;padding-bottom:16px}
  .hero .wrap{gap:16px}
  .stage .shot{height:34vh}
  .hero h1{font-size:2.15rem}
  .hero-h2{margin-top:10px;font-size:1rem}
  .hero-h3{margin-top:8px;font-size:.98rem}
  .hero-cta{margin-top:16px}
  .hero-cta .cta-main{min-height:68px}
}

/* bands */
.band{position:relative;padding:var(--band-pad) 0;z-index:2}
.band--white{background:var(--white);color:var(--ink)}
.band--black{background:transparent}
.band--white .sub{color:var(--muted-lt)}
h2{font-size:var(--fs-d2)}
.section-head{max-width:1120px}
.section-head h2{font-size:clamp(1.7rem,2.9vw,2.5rem);font-weight:900;letter-spacing:var(--ls-tight);line-height:1.08}
.section-head--center{margin-inline:auto;text-align:center}

/* explore / versatility carousel */
/* [PROD] The seam between the carousel and Why MOJO read as dead space: 72px of
   explore padding met 128px of band padding, 218px of nothing at 1440. Both
   halves are halved, which closes it to roughly 110px without touching the
   rhythm of any other band. */
.explore{position:relative;z-index:2;background:transparent;padding:clamp(20px,3vw,36px) 0 clamp(22px,3vw,36px)}
.band.why{padding-top:clamp(36px,5vw,64px)}
.explore-head{text-align:center;padding:0 20px}
.explore-h{font-size:clamp(2rem,3.8vw,3rem);font-weight:900;letter-spacing:var(--ls-tight);line-height:1.05;margin:0;color:#fff}
.explore-h em{font-style:normal;color:var(--accent)}
.carousel{position:relative;margin-top:clamp(28px,4vw,44px)}
/* [PROD] progressive enhancement: with no JS the track cannot be moved, so the
   viewport is a native horizontal scroller and all seven surfaces stay
   reachable. Once the script takes over it adds .js-carousel and the scripted
   track behaviour applies instead. */
.viewport{overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.viewport::-webkit-scrollbar{display:none}
.js-carousel .viewport{overflow:hidden}
.carousel-nav{display:none}
.js-carousel .carousel-nav{display:flex}
.track{display:flex;gap:56px;transition:transform .375s cubic-bezier(.4,0,.2,1);will-change:transform}
.slide{flex:0 0 calc((100% - 56px)/2);position:relative;aspect-ratio:3/2;overflow:hidden;border-radius:14px;background:#0e0e0f}
/* [PROD] the slides were CSS background-images inlined as base64. They are real
   <img> now: lazy-loaded, responsive, and out of the critical path. */
.slide .shot{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .6s var(--e-out)}
@media(hover:hover){.slide:hover .shot{transform:scale(1.05)}}
/* [PROD] scrim reaches full depth earlier so the caption clears AA over any
   frame of any photo (worst case = a blown-out highlight behind the text). */
.slide .scrim{position:absolute;inset:0;background:linear-gradient(180deg,transparent 0%,rgba(0,0,0,.14) 30%,rgba(0,0,0,.80) 58%,rgba(0,0,0,.94) 100%)}
.slide .cat{position:absolute;z-index:3;left:clamp(18px,2.4vw,30px);right:clamp(18px,2.4vw,30px);bottom:clamp(16px,2.2vw,26px);font-size:clamp(1.2rem,2.2vw,1.9rem);font-weight:900;letter-spacing:var(--ls-tight);color:#fff;line-height:1}
/* [PROD] small orange accent rule under each carousel category name (name stays white); same accent-bar language as the Why MOJO cards. */
.slide .cat-name{display:block;position:relative;padding-bottom:11px}
.slide .cat-name::after{content:"";position:absolute;left:0;bottom:0;width:30px;height:3px;background:var(--accent);border-radius:2px}
/* [PROD] descriptions are no longer hover-only. They carry the surface
   qualifiers ("sealed", "non-porous") that keep the versatility claim honest
   (02 §2), so they must be readable without a pointer. */
.slide .cat-desc{display:block;font-size:.5em;font-weight:600;letter-spacing:0;line-height:1.42;color:#EDEDEF;max-width:38ch;margin-top:11px}
/* [PROD] eyebrow uses accent-bright: over a photo scrim the burnt accent can
   fall under 4.5:1 at this size; #FB923C holds 5.6:1 worst case. */
.slide .cat small{display:block;font-size:.4em;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--accent-bright);margin-bottom:8px}
.carousel-nav{gap:8px;justify-content:center;align-items:center;margin-top:18px}
/* [PROD] 9px dots were 9px tap targets. The button is 44px; the dot is drawn inside. */
.dots{display:flex;gap:2px;justify-content:center}
.dots button{width:44px;height:44px;border:0;background:none;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center}
.dots button::before{content:"";width:9px;height:9px;border-radius:50%;background:#3a3a3e;transition:background .2s,transform .2s}
.dots button[aria-current="true"]::before{background:var(--accent);transform:scale(1.3)}
.car-btn{width:44px;height:44px;display:flex;align-items:center;justify-content:center;border:1px solid var(--line-dk);background:transparent;border-radius:50%;color:#fff;cursor:pointer;transition:border-color .2s,color .2s,background .2s}
.car-btn:hover{border-color:var(--accent);color:var(--accent-bright)}
.car-btn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
/* [PROD] Mobile: hand the track to the browser as a scroll-snap container so the
   carousel is finger-swipeable — no library, no touch handlers. The JS switches
   to scrollTo/scroll-read in the same breakpoint. `transform:none !important`
   matters: a transform left over from desktop would shift the scroll container's
   contents and fight the native scroll. */
@media(max-width:700px){
  .slide{flex:0 0 100%;scroll-snap-align:center}
  .track{
    gap:0;
    overflow-x:auto;
    overflow-y:hidden;
    scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain;
    scrollbar-width:none;
    -ms-overflow-style:none;
    transform:none!important;
    transition:none;
    will-change:auto;
  }
  .track::-webkit-scrollbar{display:none;width:0;height:0}
  .viewport{overflow:visible}
}
/* [PROD] with 44px dot targets the control row overflows a 390px screen, so the
   dots drop to their own line rather than pushing the pause button off-screen. */
@media(max-width:640px){.carousel-nav{flex-wrap:wrap}.dots{order:3;width:100%;margin-top:2px}}
/* [PROD] Under 640 the sub ran wider than both headline lines and stranded a
   word. Both properties are required: text-wrap:balance removes the orphan,
   and the 30ch cap forces the wrap at 430 where balance alone leaves one
   long line. */
@media (max-width:640px){
  .closer .sub{ max-width:30ch; margin-inline:auto; text-wrap:balance; }
}


/* ===== where it works, by space ==============================
   Moved off the landing onto surface-guide.html (2026-08-26): the homepage now
   argues versatility with the carousel scenes, and the detailed list lives on
   its own page. Still a judging layout, not a final one, so every item is
   marked pending and carries a dotted underline that keeps the review state
   visible on the page rather than only in the markup. */
.by-space{position:relative;z-index:2;padding-block:clamp(28px,4vw,52px) clamp(40px,6vw,72px)}
.bs-legend{margin-top:12px;color:var(--legal-dk);font-size:.8rem;display:flex;align-items:center;gap:9px}
.bs-key{display:inline-block;width:26px;height:0;border-bottom:1px dotted var(--accent-bright);flex:0 0 26px}
.bs-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,2.6vw,40px);max-width:980px;margin-inline:auto}
.bs-group h3{font-size:.78rem;font-weight:800;letter-spacing:var(--ls-wide);text-transform:uppercase;
  color:var(--accent);margin-bottom:12px}
.bs-group ul{list-style:none;display:grid;gap:7px}
.bs-group li{color:#C4C2BD;font-size:.95rem;line-height:1.45}
/* A verified-but-limited result. The surface name stays in the normal list
   colour because the claim holds; the limit follows in muted grey. Reusable
   for any future Partial: never drop the qualifier to make a line tidier. */
.bs-group .sg-qual{color:var(--muted-dk)}
/* the pending marker is visible, not just semantic */
[data-pending-surface]{border-bottom:1px dotted rgba(251,146,60,.55);padding-bottom:1px}
@media(max-width:860px){.bs-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.bs-grid{grid-template-columns:1fr;max-width:420px}}

/* ===== surface guide page ===================================
   Same vocabulary as /about: black ground, burnt-orange eyebrow, left-aligned
   at the wrap edge with the measure capped per element. The list spans the full
   wrap here rather than the landing's centred 980px column, so the six groups
   line up with the heading above them. */
.sg-hero{padding:clamp(56px,8vw,104px) 0 clamp(28px,4vw,44px)}
.sg-hero .eyebrow{margin-bottom:18px}
.sg-hero h1{font-size:clamp(2.4rem,1.6rem + 4vw,4rem);font-weight:900;line-height:1.04;max-width:14ch}
.sg-hero h1 em{font-style:normal;color:var(--accent)}
.sg-sub{margin-top:26px;max-width:64ch;font-size:var(--fs-lg);color:#D4D4D8;line-height:1.6}
.surface-guide .by-space{padding-block:0 clamp(48px,7vw,88px)}
.sg-bs-head{margin-bottom:clamp(22px,3vw,36px)}
.sg-bs-head h2{font-size:clamp(1.5rem,1.2rem + 1.2vw,2.1rem);font-weight:900;color:#FBFAF7}
.sg-bs-head .bs-legend{margin-top:14px}
.surface-guide .bs-grid{max-width:none;margin-inline:0;
  gap:clamp(26px,3vw,48px) clamp(20px,2.6vw,40px)}
.surface-guide .bs-group h3{padding-bottom:12px;margin-bottom:14px;border-bottom:1px solid var(--line-dk)}

.sg-note{padding:clamp(40px,6vw,72px) 0;border-block:1px solid var(--line-dk);background:#050505}
.sg-note h2{font-size:clamp(1.5rem,1.2rem + 1.2vw,2.1rem);font-weight:900;color:#FBFAF7;
  margin-bottom:clamp(24px,3vw,38px)}
.sg-note-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(24px,3vw,44px)}
.sg-item h3{font-size:1rem;font-weight:800;letter-spacing:var(--ls-snug);color:#FBFAF7;margin-bottom:10px}
.sg-item p{max-width:62ch;color:#C4C2BD;font-size:clamp(.98rem,.94rem + .2vw,1.04rem);line-height:1.68}
.sg-legal{margin-top:clamp(28px,3.5vw,44px);padding-top:22px;border-top:1px solid var(--line-dk);
  max-width:78ch;color:var(--legal-dk);font-size:.85rem;line-height:1.6}
@media(max-width:760px){.sg-note-grid{grid-template-columns:1fr}}

/* ===== /the-bottle =========================================
   Same vocabulary as /about: black ground, orange eyebrow, .wrap for the
   reading columns. The only thing that leaves .wrap is the strip, which is
   full bleed because the horizontal scroll is the point of the page. */
.tb-head{padding:clamp(48px,7vw,92px) 0 clamp(22px,3vw,34px)}
.tb-head-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  gap:clamp(24px,4vw,64px);align-items:end}
.tb-head .eyebrow{margin-bottom:16px}
.tb-head h1{font-size:clamp(2.3rem,1.5rem + 3.8vw,3.8rem);font-weight:900;
  letter-spacing:var(--ls-tight);line-height:1.04}
.tb-head h1 em{font-style:normal;color:var(--accent)}
.tb-standfirst{color:#C4C2BD;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.66;
  max-width:46ch;padding-bottom:6px}

/* the rail: a real readout, driven by the strip's scroll position */
.tb-rail{margin-top:clamp(26px,3.4vw,42px);display:flex;align-items:center;gap:16px}
.tb-rail-label,.tb-count{font-size:.68rem;font-weight:800;letter-spacing:var(--ls-wide);
  text-transform:uppercase;color:var(--legal-dk);flex:0 0 auto}
.tb-count{font-variant-numeric:tabular-nums}
.tb-track{position:relative;flex:1 1 auto;height:2px;background:var(--line-dk);border-radius:2px}
.tb-fill{position:absolute;inset:0 auto 0 0;width:25%;background:var(--accent);border-radius:2px;
  transition:width .18s linear}

/* the strip. padding-inline reproduces the wrap gutter at desktop and collapses
   to the viewport edge on narrow screens, which is the intended bleed. */
.tb-strip-wrap{position:relative;z-index:2}
.tb-strip{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding-inline:max(0px,calc((100vw - 1200px) / 2));
  scroll-padding-inline:max(0px,calc((100vw - 1200px) / 2));
  scrollbar-width:none;-ms-overflow-style:none;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 42px,#000 calc(100% - 42px),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 42px,#000 calc(100% - 42px),transparent 100%)}
.tb-strip::-webkit-scrollbar{display:none;width:0;height:0}
.tb-strip{cursor:grab}
/* snap is suspended only while a drag is in flight, then restored on release */
.tb-strip.is-dragging{cursor:grabbing;scroll-snap-type:none}
.tb-tile{flex:0 0 auto;scroll-snap-align:start;margin:0}
.tb-tile img{-webkit-user-drag:none;user-select:none;-webkit-user-select:none}
.tb-tile img{display:block;height:520px;width:auto;border-radius:2px}
.tb-tile figcaption{margin-top:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--legal-dk)}
.tb-tile .tb-n{color:var(--accent);font-weight:700}

.tb-facts{padding:clamp(34px,4.5vw,60px) 0 clamp(48px,7vw,88px)}
.tb-facts-grid{display:flex;flex-wrap:wrap;gap:clamp(24px,3vw,48px);
  align-items:center;justify-content:space-between}
.tb-facts-list{display:flex;flex-wrap:wrap;gap:clamp(22px,3vw,52px)}
.tb-facts-list dt{font-size:.68rem;font-weight:800;letter-spacing:var(--ls-wide);
  text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.tb-facts-list dd{color:#EDEDED;font-size:1rem;line-height:1.4;white-space:nowrap}
/* The CTA sits in the same flex row as the facts list, so it was shrinking to
   its content and crushing to 165px. A fixed basis plus a floor keeps it a
   button rather than a sliver. */
.tb-cta .cta-main{flex:0 0 auto;min-width:280px}
.tb-legal{margin-top:clamp(28px,3.6vw,44px);padding-top:22px;border-top:1px solid var(--line-dk);
  max-width:78ch;color:var(--legal-dk);font-size:.83rem;line-height:1.6}

/* 360 view. The spin viewer is its own document in an iframe, so its global
   rules never touch this page and vice versa. An iframe never sizes itself to
   its content, so the height is derived here. Inside, viewer.css sizes the
   4:5 stage as min(100%, (100svh - 210px) * .8): 100svh is the frame height,
   so a frame of width W needs 1.25 * (W - 16) + 210 for the stage to fill the
   16px-padded width, and that is 1.25 * W + 190. W is the wrap column capped
   at 520px, which min(100vw - 2 gutters, 520px) reproduces without JS. The
   measured chrome (heading 32, controls 56, help 33, message 43) is 164px,
   so about 46px of black is left under the help line by the viewer's own
   210px budget. The second height caps the frame to the viewport on short
   desktops, where the viewer then shrinks its own stage to fit, so stage and
   controls stay on screen together; 640px is the floor (a 344px stage). The
   first height is the fallback where svh is unsupported. The frame is lifted
   above the page-wide ghost wordmark, like the strip, so the validated black
   stage stays black. */
.tb-spin{padding:clamp(48px,7vw,84px) 0 0}
.tb-spin-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,520px);
  gap:clamp(24px,4vw,64px);align-items:center}
.tb-spin .eyebrow{margin-bottom:16px}
.tb-spin h2{font-size:clamp(2rem,1.3rem + 2.8vw,3.2rem);font-weight:900;
  letter-spacing:var(--ls-tight);line-height:1.04}
.tb-spin h2 em{font-style:normal;color:var(--accent)}
.tb-spin-sub{margin-top:18px;color:#C4C2BD;font-size:clamp(1rem,.96rem + .2vw,1.08rem);
  line-height:1.66;max-width:38ch}
.tb-spin-frame{display:block;position:relative;z-index:2;width:100%;max-width:520px;
  border:0;background:#000;justify-self:end;
  height:calc(min(100vw - 2 * var(--wrap-pad),520px) * 1.25 + 190px);
  height:min(calc(min(100vw - 2 * var(--wrap-pad),520px) * 1.25 + 190px),max(calc(100svh - 90px),640px))}
@media(max-width:1000px){
  .tb-spin-grid{grid-template-columns:1fr;gap:28px}
  .tb-spin-frame{justify-self:start}
}

/* Features. Same padding, eyebrow, heading scale and gap as .tb-spin above, so the
   two sections read as one system. Each row alternates image and copy; the media
   box carries the aspect ratio so it reserves its space before the picture loads
   and CLS stays at 0. The media is lifted above the page-wide ghost wordmark, the
   same way the strip and the spin frame are, so the black plate stays black. */
.tb-features{padding:clamp(48px,7vw,84px) 0 0}
.tb-features .eyebrow{margin-bottom:16px}
.tb-features h2{font-size:clamp(2rem,1.3rem + 2.8vw,3.2rem);font-weight:900;
  letter-spacing:var(--ls-tight);line-height:1.04}
.tb-features h2 em{font-style:normal;color:var(--accent)}
.tb-feature-list{list-style:none;margin:clamp(34px,4.5vw,60px) 0 0;padding:0;
  display:grid;gap:clamp(40px,6vw,76px)}
.tb-feature{display:grid;grid-template-columns:minmax(0,520px) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);align-items:center}
.tb-feature:nth-child(even){grid-template-columns:minmax(0,1fr) minmax(0,520px)}
.tb-feature:nth-child(even) .tb-feature-media{order:2}
.tb-feature:nth-child(even) .tb-feature-copy{order:1;justify-self:end}
.tb-feature-media{display:block;position:relative;z-index:2;margin:0;
  width:100%;max-width:520px;aspect-ratio:4/5;background:#000;overflow:hidden;border-radius:2px}
.tb-feature-media--wide{aspect-ratio:880/700}
.tb-feature-media img{width:100%;height:100%;object-fit:contain;display:block}
.tb-feature-copy{max-width:38ch}
.tb-feature-copy .tb-n{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:10.5px;letter-spacing:.14em;color:var(--accent);font-weight:700;margin-bottom:12px}
.tb-feature-copy h3{font-size:clamp(1.4rem,1.1rem + 1.2vw,2rem);font-weight:900;
  letter-spacing:var(--ls-tight);line-height:1.1}
.tb-feature-copy p{margin-top:14px;color:#C4C2BD;
  font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.66}
@media(max-width:1000px){
  .tb-feature,.tb-feature:nth-child(even){grid-template-columns:1fr;gap:24px}
  .tb-feature:nth-child(even) .tb-feature-media{order:0}
  .tb-feature:nth-child(even) .tb-feature-copy{order:0;justify-self:start}
}

@media(max-width:900px){
  .tb-head-grid{grid-template-columns:1fr;gap:20px;align-items:start}
  .tb-standfirst{padding-bottom:0}
  .tb-facts-grid{justify-content:flex-start}
}
/* Stays horizontal on purpose. The scroll IS the page, so it never becomes a
   column; the tiles just get shorter. */
@media(max-width:640px){
  .tb-tile img{height:380px}
  /* The gutter is 0 at this width, so a 42px edge fade was eating the start of
     the first caption. Shorten the fade rather than add a gutter, which would
     cost the edge-to-edge bleed the strip exists for. */
  /* Both halves are needed: a 20px fade alone still starts the first caption
     at x=0 inside it, so the leading '0' stayed dim. The matching 20px
     gutter puts the caption exactly where the fade ends. scroll-padding
     mirrors it so the resting snap position is still the tile edge. */
  .tb-strip{gap:10px;padding-inline:20px;scroll-padding-inline:20px;
    -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 20px,#000 calc(100% - 20px),transparent 100%);
    mask-image:linear-gradient(90deg,transparent 0,#000 20px,#000 calc(100% - 20px),transparent 100%)}
  .tb-facts-list{gap:20px 26px}
  .tb-cta{width:100%}
}

/* why mojo (2x2 editorial cards) */
.why-head{text-align:left;max-width:980px;margin:0 auto clamp(18px,3vw,32px)}
.why-title{font-size:clamp(2rem,3.8vw,3rem);font-weight:900;letter-spacing:var(--ls-tight);line-height:1.06;color:#fff;margin:0}
.why-title em{font-style:normal;color:var(--accent)}
.why-sub{margin-top:14px;color:var(--muted-dk);font-size:var(--fs-lg)}
.why-grid{display:grid;grid-template-columns:1fr 1fr;grid-auto-rows:1fr;gap:clamp(28px,4vw,52px);max-width:980px;margin:0 auto}
.wm-card{position:relative;background:#141416;border:1px solid var(--line-dk);border-radius:18px;padding:clamp(26px,3vw,40px);display:flex;flex-direction:column;align-items:center;text-align:center;overflow:hidden;transition:transform .5s var(--e-out),box-shadow .5s var(--e-out),border-color .5s var(--e-out)}
.wm-card::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);width:34px;height:3px;background:var(--accent);border-radius:0 0 3px 3px;transition:width .5s var(--e-out)}
.wm-card:hover{transform:translateY(-5px);box-shadow:0 30px 60px -24px rgba(0,0,0,.6);border-color:#3a2a1e}
.wm-card:hover::before{width:64px}
/* icon sits above the heading, under the card's orange tick */
.wm-icon{display:block;width:34px;height:34px;margin-bottom:16px}
.wm-icon svg{width:100%;height:100%;display:block;overflow:visible}
.wm-card h3{font-size:clamp(1.2rem,1.1rem + .5vw,1.5rem);color:#FBFAF7;letter-spacing:var(--ls-snug);margin-bottom:12px;line-height:1.15}
.wm-card h3 em{font-style:normal;color:var(--accent)}
.wm-card p{color:#C4C2BD;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.6}
@media(max-width:720px){.why-grid{grid-template-columns:1fr;grid-auto-rows:auto;max-width:460px}.why-head{max-width:460px}}

/* faq */
.faq{max-width:760px;margin-inline:auto}
.faq details{border-bottom:1px solid var(--line-lt);padding:6px 0}
.faq summary{display:flex;justify-content:space-between;gap:16px;align-items:center;cursor:pointer;list-style:none;padding:18px 0;min-height:44px;font-weight:700;font-size:1.08rem}
.faq summary::-webkit-details-marker{display:none}
.faq .chev{width:22px;height:22px;flex:0 0 22px;fill:none;stroke:var(--accent);stroke-width:2.4;transition:transform .25s var(--e-out)}
.faq details[open] .chev{transform:rotate(180deg)}
.faq details>div{padding:0 0 18px;color:var(--muted-lt);max-width:64ch;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.6}

/* why mojo (2x2 editorial cards) */
.why-head{text-align:left;max-width:980px;margin:0 auto clamp(18px,3vw,32px)}
.why-title{font-size:clamp(2rem,3.8vw,3rem);font-weight:900;letter-spacing:var(--ls-tight);line-height:1.06;color:#fff;margin:0}
.why-title em{font-style:normal;color:var(--accent)}
.why-sub{margin-top:14px;color:var(--muted-dk);font-size:var(--fs-lg)}
.why-grid{display:grid;grid-template-columns:1fr 1fr;grid-auto-rows:1fr;gap:clamp(28px,4vw,52px);max-width:980px;margin:0 auto}
.wm-card{position:relative;background:#141416;border:1px solid var(--line-dk);border-radius:18px;padding:clamp(26px,3vw,40px);display:flex;flex-direction:column;align-items:center;text-align:center;overflow:hidden;transition:transform .5s var(--e-out),box-shadow .5s var(--e-out),border-color .5s var(--e-out)}
.wm-card::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);width:34px;height:3px;background:var(--accent);border-radius:0 0 3px 3px;transition:width .5s var(--e-out)}
.wm-card:hover{transform:translateY(-5px);box-shadow:0 30px 60px -24px rgba(0,0,0,.6);border-color:#3a2a1e}
.wm-card:hover::before{width:64px}
/* icon sits above the heading, under the card's orange tick */
.wm-icon{display:block;width:34px;height:34px;margin-bottom:16px}
.wm-icon svg{width:100%;height:100%;display:block;overflow:visible}
.wm-card h3{font-size:clamp(1.2rem,1.1rem + .5vw,1.5rem);color:#FBFAF7;letter-spacing:var(--ls-snug);margin-bottom:12px;line-height:1.15}
.wm-card h3 em{font-style:normal;color:var(--accent)}
.wm-card p{color:#C4C2BD;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.6}
@media(max-width:720px){.why-grid{grid-template-columns:1fr;grid-auto-rows:auto;max-width:460px}.why-head{max-width:460px}}

/* faq */
.faq{max-width:760px;margin-inline:auto}
.faq details{border-bottom:1px solid var(--line-lt);padding:6px 0}
.faq summary{display:flex;justify-content:space-between;gap:16px;align-items:center;cursor:pointer;list-style:none;padding:18px 0;min-height:44px;font-weight:700;font-size:1.08rem}
.faq summary::-webkit-details-marker{display:none}
.faq .chev{width:22px;height:22px;flex:0 0 22px;fill:none;stroke:var(--accent);stroke-width:2.4;transition:transform .25s var(--e-out)}
.faq details[open] .chev{transform:rotate(180deg)}
.faq details>div{padding:0 0 18px;color:var(--muted-lt);max-width:64ch;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.6}

/* ===== FAQ + Your Turn — one white band, 60/40 =====
   The review block sits on the ghost wordmark with the orange trace, reusing the
   footer sign-off's #tgrad and #ctaGlow (SVG ids are document-global, so it does
   not matter that they are declared further down the page). */
.fr-grid{display:grid;grid-template-columns:55% 45%;gap:clamp(28px,4vw,56px);align-items:center}
.fr-faq .section-head{margin-bottom:clamp(20px,2.5vw,32px)}
.fr-faq .faq{max-width:none;margin-inline:0}
.fr-review{position:relative;display:flex;align-items:center;justify-content:center;text-align:center;
  min-height:clamp(300px,34vw,420px);padding:clamp(24px,3vw,40px) clamp(16px,2vw,28px)}
.fr-review-inner{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;gap:14px}
/* [PROD] FAQ band drops to 85% white so the page-spanning ghost wordmark (brightened to .15) reads through the background. On the resulting ~#D9D9D9 the muted answer text at #52525B holds 5.5:1 (AA ok), so it is left unchanged. Dividers are re-scoped to #A34200 (--line-lt) to read on the tint. The "Your Turn" accent is kept bright #E66000 (2.5:1 here, under AA large-text) by founder choice; near-black --ink text stays 14:1. */
#faq{background:rgba(255,255,255,.85);--line-lt:#A34200}
/* Share Your Review — the brief's #E66000 fill and glow. Label is near-black,
   not white: white on #E66000 measures 3.47:1 and fails AA at this size, and
   CLAUDE.md locks "black label on orange fill, never white-on-orange". #0A0A0A
   gives 6.04:1 and matches every other orange CTA on the page. */
.btn--review{background:#E66000;color:#0A0A0A;font-weight:800;font-size:1.15rem;padding:20px 44px;border-radius:999px;
  box-shadow:0 12px 36px -6px rgba(230,96,0,.55),0 0 0 1px rgba(230,96,0,.18)}
.btn--review:hover{background:#F97316;transform:translateY(-2px);
  box-shadow:0 16px 44px -6px rgba(230,96,0,.62),0 0 0 1px rgba(230,96,0,.26)}
@media(max-width:860px){
  .fr-grid{grid-template-columns:1fr;gap:clamp(32px,6vw,48px)}
  .fr-review{min-height:auto;padding-top:clamp(32px,7vw,56px)}
}

/* reviews */
.reviews-title{font-size:clamp(2.1rem,3.6vw,3rem);font-weight:900;letter-spacing:var(--ls-tight);line-height:1.06;color:var(--ink)}
.reviews-title em{font-style:normal;color:var(--accent)}
.reviews-sub{color:var(--muted-lt);font-size:var(--fs-lg);max-width:34ch}

/* closer */
.closer{position:relative;text-align:center;overflow:hidden;padding-top:clamp(24px,3.5vw,48px)}
.closer .wrap{position:relative;z-index:2}
/* 18ch was sized for "Buy 1 to try MOJO." at 18 characters. The line is now
   "Order 1 to try MOJO." at 20, which wraps at the old cap. */
/* [PROD] --ls-tight (-0.035em) also tightens the spaces, which collapsed the word
   gaps around the digits (measured 0.165em; "Order 1 to" read as "Order1to").
   word-spacing restores a normal ~0.25em gap while the letterforms keep their
   display tracking. Spaces only, so nothing else moves. */
.closer h2{font-size:clamp(2rem,3.8vw,3rem);font-weight:900;letter-spacing:var(--ls-tight);word-spacing:.08em;line-height:1.17;max-width:21ch;margin-inline:auto}
.closer .sub{margin:24px auto 0;color:#D4D4D8;font-size:clamp(.94rem,.9rem + .16vw,.97rem);line-height:1.6}
.closer-cta{margin-top:28px;display:flex;justify-content:center}
#faq,#buy{padding-block:clamp(40px,6vw,72px)}

/* ===== /about — Our Story =========================================
   Same vocabulary as the landing: black ground, Inter, burnt-orange eyebrow and
   accents, generous vertical rhythm, and a measure capped for reading. Broken
   into numbered chapters so it scans rather than reading as a wall of text. */
.about-hero{padding:clamp(56px,8vw,104px) 0 clamp(32px,5vw,56px)}
.about-hero .eyebrow{margin-bottom:18px}
.about-hero h1{font-size:clamp(2.4rem,1.6rem + 4vw,4rem);font-weight:900;line-height:1.04;max-width:16ch}
.about-hero h1 em{font-style:normal;color:var(--accent)}
.about-sub{margin-top:26px;max-width:60ch;font-size:var(--fs-lg);color:#D4D4D8;line-height:1.6}

.about-story{padding:clamp(8px,1.5vw,20px) 0 clamp(48px,7vw,88px)}
.story{display:grid;grid-template-columns:auto 1fr;gap:clamp(20px,3vw,44px);
  padding:clamp(28px,4vw,44px) 0;border-top:1px solid var(--line-dk)}
.story:first-child{border-top:0}
/* Beats are icons now, not numerals. Same column the numeral occupied, so the
   grid and the mobile stack are unchanged. */
.story-icon{display:block;width:40px;height:40px;flex:0 0 40px}
.story-icon svg{width:100%;height:100%;display:block;overflow:visible}
.story-body h2{font-size:clamp(1.35rem,1.1rem + .9vw,1.9rem);font-weight:800;
  letter-spacing:var(--ls-snug);color:#FBFAF7;margin-bottom:12px}
.story-body p{max-width:62ch;color:#C4C2BD;font-size:clamp(1rem,.96rem + .2vw,1.08rem);line-height:1.68}
@media(max-width:560px){
  .story{grid-template-columns:1fr;gap:12px}
  .story-icon{width:34px;height:34px;flex-basis:34px}
}

.about-quote{padding:clamp(40px,6vw,80px) 0;border-block:1px solid var(--line-dk);background:#050505}
/* max-width in ch on the figure resolved against the inherited 1rem, not the
   display-size blockquote — it clamped the quote to ~250px and broke it to
   one word a line. Constrain in px here; the <br> controls the break. */
.about-quote figure{max-width:min(92%,880px);margin-inline:auto;text-align:center}
.about-quote blockquote{font-size:clamp(1.6rem,1.1rem + 2.4vw,3rem);font-weight:900;
  letter-spacing:var(--ls-tight);line-height:1.12;color:#fff}
.about-quote blockquote em{font-style:normal;color:var(--accent)}
.about-quote figcaption{margin-top:22px;font-size:.95rem;font-weight:600;letter-spacing:.02em;
  color:var(--muted-dk);max-width:none}

.about-cta{padding:clamp(48px,7vw,88px) 0 clamp(56px,8vw,96px)}
.about-cta .wrap{display:flex;justify-content:center}

@media(max-width:820px){
    }

/* footer */
footer{position:relative;z-index:2;background:#000;border-top:1px solid var(--line-dk);padding:56px 0 40px}
footer .wrap{display:flex;flex-direction:column;align-items:center;gap:28px;text-align:center}
/* The final mark's viewBox carries ~70u of bloom margin, so the letters occupy
   744.8/884.8 of the box. 822px = 1.5x the previous 548px, giving letters of
   ~692px — a full-width sign-off on desktop. The percentage keeps it inside the
   wrap on narrower screens, where there is no room for the multiplier. */
.footer-mark{width:min(822px,88%);margin:0 auto 4px}
.footer-mark svg{width:100%;height:auto;overflow:visible}
/* Footer sign-off mark — final, per design-reference/logo-final/FOOTER_MARK_SPEC.md.
   Two traced paths: .trace--1 is the wordmark's OUTER contour only, so the light
   runs continuously instead of diving into an O's counter (the counters still
   render in the faint fill); .trace--2 is the flourish over the J, offset half a
   cycle so the light rounds the whole mark. The glow is the GET MOJO CTA glow
   rebuilt as an SVG filter, because a stroke cannot take box-shadow spread. */
.mark-fill path{fill:#fff;opacity:.08}
.trace{fill:none;stroke:url(#tgrad);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:160 840;filter:url(#ctaGlow);animation:trace-run 8.5s linear infinite}
.trace--2{animation-delay:-4.25s}
@keyframes trace-run{to{stroke-dashoffset:-1000}}
@media(prefers-reduced-motion:reduce){.trace{animation:none;stroke-dasharray:none;opacity:.6}}
/* Copyright stays optically centred; the socials sit hard right on the same row. */
.foot-bottom{width:100%;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px}
.foot-legal{grid-column:2;font-size:.82rem;letter-spacing:.05em;color:var(--legal-dk);font-weight:600}
.social{grid-column:3;justify-self:end;display:flex;align-items:center;gap:6px}
.social-icon{display:flex;align-items:center;justify-content:center;width:44px;height:44px;color:#D4D4D8;transition:color .2s var(--e-out)}
.social-icon:hover{color:#fff}
.social-icon svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
@media(max-width:560px){
  .foot-bottom{grid-template-columns:1fr auto;gap:8px}
  .foot-legal{grid-column:1;justify-self:start}
  .social{grid-column:2}
}
.footer-cols{width:100%;display:flex;gap:40px;flex-wrap:wrap;justify-content:space-between;text-align:left}
.footer-cols h2{font-size:.78rem;letter-spacing:var(--ls-wide);text-transform:uppercase;color:var(--legal-dk);font-weight:800;margin-bottom:8px}
/* [PROD] gap 10px -> 2px: the columns read too airy. The 44px min-height on
   each link (below) is what guarantees the tap target, so tightening the gap
   closes the rhythm without shrinking anything touchable. */
.footer-cols ul{list-style:none;display:grid;gap:2px;font-size:.95rem;color:#D4D4D8}
/* [PROD] The 44px min-height was what made these columns read airy — it is a
   TOUCH requirement, so it now applies only where the pointer is coarse. Fine
   pointers get the tighter rhythm the brief asked for; touch keeps its target. */
.footer-cols a,.footer-cols button{display:inline-flex;align-items:center;min-height:32px;color:inherit;background:none;border:0;font:inherit;text-align:left;cursor:pointer;transition:color .2s}
@media(pointer:coarse){.footer-cols a,.footer-cols button{min-height:44px}}
.footer-cols a:hover,.footer-cols button:hover{color:#fff}
.foot-rule{width:100%;height:1px;background:var(--line-dk)}
@media(max-width:560px){.footer-cols{display:grid;grid-template-columns:1fr 1fr;gap:24px;justify-content:initial}}

/* mobile nav */
.nav-toggle{display:none;background:transparent;border:0;cursor:pointer;width:44px;height:44px;flex-direction:column;justify-content:center;align-items:center;gap:5px;padding:0}
.nav-toggle span{display:block;width:26px;height:2.5px;background:#fff;border-radius:2px;transition:transform .3s var(--e-out),opacity .2s var(--e-out)}
.nav-toggle.is-open span:nth-child(1){transform:translateY(7.5px) rotate(45deg)}
.nav-toggle.is-open span:nth-child(2){opacity:0}
.nav-toggle.is-open span:nth-child(3){transform:translateY(-7.5px) rotate(-45deg)}
/* [PROD] the mock transitioned `visibility` over .35s. Discrete properties flip
   at the halfway point, so for the first ~175ms after opening, the overlay is
   still computed `visibility:hidden` — and a hidden element refuses focus().
   The result was that opening the menu stranded keyboard focus on <body>.
   Visibility now flips instantly on open and is delayed only on close, so the
   fade-out still reads. */
.mobile-menu{position:fixed;inset:0;z-index:39;background:rgba(6,6,8,.985);backdrop-filter:blur(8px);display:flex;flex-direction:column;justify-content:center;align-items:center;opacity:0;visibility:hidden;transition:opacity .35s var(--e-out),visibility 0s linear .35s;padding:86px 24px 48px}
.mobile-menu.is-open{opacity:1;visibility:visible;transition:opacity .35s var(--e-out),visibility 0s linear 0s}
.mm-nav{display:flex;flex-direction:column;align-items:center;gap:2px;width:100%}
.mm-nav a{font-size:clamp(1.9rem,7.5vw,2.6rem);font-weight:900;letter-spacing:var(--ls-tight);color:#fff;padding:14px;transition:color .2s var(--e-out)}
.mm-nav a:active,.mm-nav a:hover{color:var(--accent-bright)}
.mm-cta{margin-top:30px;min-height:62px;padding:0 44px;font-size:1.05rem;border-radius:999px}
@media(max-width:820px){.nav-toggle{display:flex}}
@media(min-width:821px){.mobile-menu{display:none!important}}
@media(max-width:640px){.nav .wrap{height:66px}.brand-logo{height:50px}.trustbar{font-size:.88rem}}

/* forms + modals */
.field{margin-bottom:14px}
.field label{display:block;font-size:.82rem;color:#D4D4D8;margin-bottom:7px;font-weight:600}
.field input,.field textarea{width:100%;background:#0f0f11;border:1px solid var(--line-dk);border-radius:12px;color:#fff;font:inherit;font-size:.98rem;transition:border-color .2s,box-shadow .2s}
.field input{height:50px;padding:0 16px}
.field textarea{padding:12px 16px;resize:vertical}
.field input::placeholder,.field textarea::placeholder{color:#6a6a72}
/* [PROD] the mock removed the outline on focus with no replacement. Keep the
   accent glow AND keep a real focus ring. */
.field input:focus-visible,.field textarea:focus-visible{border-color:var(--accent);box-shadow:0 0 0 3px rgba(230,96,0,.28)}
.field-row{display:flex;gap:12px}
.field-row .field{flex:1}
@media(max-width:520px){.field-row{flex-direction:column;gap:0}}
/* [PROD] rating groups are <fieldset>s for grouping semantics; strip the UA
   chrome so they match the other .field rows visually. */
.field fieldset,fieldset.field{border:0;padding:0;margin:0 0 14px;min-width:0}
.field legend,fieldset.field legend{display:block;padding:0;font-size:.82rem;color:#D4D4D8;margin-bottom:7px;font-weight:600}
.ast{color:var(--accent-bright);font-weight:700;margin-left:2px}
.field .hint{display:block;font-size:.76rem;color:var(--legal-dk);font-weight:500;margin-top:6px}
/* [PROD] inline validation states */
.field .err{display:none;font-size:.8rem;color:#FFB4A2;font-weight:600;margin-top:7px}
.field.is-bad input,.field.is-bad textarea{border-color:#E5734F}
.field.is-bad .err{display:block}
/* [PROD] star inputs are a real radio group: keyboard-operable, labelled, and
   with no ★ glyph in the text layer (the character reads as a rating claim to
   the claims linter, 02 §3.9). */
.stars{display:flex;gap:2px;margin-top:2px}
.stars input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.stars label{display:flex;align-items:center;justify-content:center;width:44px;height:44px;cursor:pointer;color:#3a3a40;transition:color .15s,transform .15s var(--e-out)}
.stars label svg{width:26px;height:26px;fill:currentColor}
.stars label:hover{transform:scale(1.08)}
.stars.is-set label{color:#3a3a40}
.stars label.on{color:var(--accent-bright)}
.stars input:focus-visible + label{outline:3px solid var(--focus-ring);outline-offset:2px;border-radius:8px}
.form-submit{width:100%;min-height:52px;margin-top:10px;font-size:1rem;justify-content:center}
.form-note{text-align:center;color:var(--legal-dk);font-size:.76rem;line-height:1.5;margin-top:16px}
.form-status{margin-top:14px;padding:14px 16px;border-radius:12px;font-size:.92rem;line-height:1.5;display:none}
.form-status.is-on{display:block}
.form-status.ok{background:rgba(230,96,0,.12);border:1px solid var(--accent);color:#FFD9BC}
.form-status.bad{background:rgba(229,115,79,.1);border:1px solid #E5734F;color:#FFC9B8}
.modal{position:fixed;inset:0;z-index:95;display:none;align-items:flex-start;justify-content:center;padding:5vh 18px;overflow-y:auto;background:rgba(4,4,6,.72);backdrop-filter:blur(6px)}
.modal.is-open{display:flex}
.modal-box{position:relative;width:100%;max-width:600px;background:#0b0b0d;border:1px solid var(--line-dk);border-radius:22px;padding:clamp(24px,3.5vw,40px);margin:auto}
.modal-head{text-align:center;margin-bottom:22px}
.modal-head h2{font-size:clamp(1.6rem,2.6vw,2.1rem);letter-spacing:var(--ls-tight);font-weight:900}
.modal-head h2 em{font-style:normal;color:var(--accent)}
.modal-head p{color:var(--muted-dk);margin-top:10px;font-size:.95rem;line-height:1.5}
.modal-close{position:absolute;top:12px;right:12px;width:44px;height:44px;display:flex;align-items:center;justify-content:center;border:0;background:#17171a;color:#fff;border-radius:50%;font-size:1.3rem;cursor:pointer;line-height:1}
.modal-close:hover{background:var(--accent);color:#0A0A0A}

/* [PROD] one global reduced-motion contract. The mock guarded 2 of its 33
   animated properties; everything else kept moving. */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
  .track{transition:none!important}
  .wm-card:hover,.btn--accent:hover,.btn--accent.cta-main:hover,.vid-slide:hover{transform:none!important}
  .slide:hover .shot{transform:none!important}
}
