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

html, body { height: 100%; background: var(--paper); overflow: hidden; }
body {
  font-family: "Geist", -apple-system, BlinkMacSystemFont, sans-serif;
  color: var(--ink);
  position: relative;
  /* whole composition fades in together on load */
  opacity: 0;
  transition: opacity var(--duration-fade) ease;
}
body.ready { opacity: 1; }

/* ---- keyboard focus: one shared, on-brand ring on every interactive
   element. Previously only the reserve field styled focus; the nav CTA,
   language links, logo and social icons fell back to the browser's default
   outline — visible but inconsistent and off-brand. :focus-visible shows it
   only for keyboard/programmatic focus, never on mouse click, so it never
   intrudes on pointer users. :where() keeps specificity at 0 so it never
   fights a component's own rules. */
:where(a, button, input, [tabindex]):focus-visible {
  outline: 2px solid var(--text-primary);
  outline-offset: 3px;
  border-radius: 3px;
}
/* the email field + its submit button already signal focus via the
   .reserve container's own focus-within ring (css/components/cta-form.css)
   — suppress the shared outline on just those two so it isn't doubled. */
.reserve-email:focus-visible, .reserve-btn:focus-visible { outline: none; }

/* ============================================================
   EDITORIAL SCROLL MODEL
   One natural scroller. Sections flow in normal document order at
   their own heights — no forced 100dvh panels, no paginated snapping,
   no wheel/touch hijack, no sticky/pinned sections. The only fixed
   (viewport-anchored) elements on the page are the top announcement bar,
   the header and the mobile CTA dock — all position:fixed siblings of
   .scroll-stage.
   ============================================================ */
.scroll-stage {
  height: 100svh;
  height: 100dvh;
  overflow-y: auto;
  /* No horizontal scrolling — dragging a text selection toward the edge
     must never jog the page sideways. `overflow-x: clip` can't help here
     (paired with an `auto` y-axis it computes back to `hidden`, which is
     still programmatically scrollable), so the real guarantee is upstream:
     every element that deliberately bleeds past a screen edge (the
     transparency back-label, the membership pouch, the carousel's side
     cards) is clipped by its OWN wrapper's overflow:hidden, so the stage's
     scrollWidth never exceeds its clientWidth and there is simply no
     horizontal overflow for a selection-drag to scroll into. */
  overflow-x: hidden;
  /* clears the fixed top-bar (css/components/nav.css .top-bar), which is
     opaque and always visible — unlike the nav below it (transparent
     over the hero until scrolled), content genuinely needs to start
     below this one, not just visually assume it's there. */
  padding-top: var(--topbar-h);
  /* NOT -webkit-overflow-scrolling:touch — that legacy iOS momentum-scroll
     property is known to cause `position:fixed` + `backdrop-filter`
     children (our header) to blank out / flash white mid-scroll on a
     non-body scroll container. Momentum scrolling is native/default in
     current iOS Safari without it, so this only removes the bug, not
     the behaviour. */
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  .scroll-stage { scroll-behavior: auto; }
  /* skip the whole-page opacity fade-in on load for motion-sensitive users
     (the body rule above defines this transition, so overriding it here in
     the same file wins the cascade cleanly). */
  body { transition: none; }
}

/* shared centred content column — same width as the nav bar (--container),
   so copy, product figures and cards all line up on one grid instead of
   drifting to the true viewport edge on wide screens. `width` (not
   max-width) because --container already resolves the shrink-or-cap
   itself via min()/calc() — see the token definitions in tokens.css. */
.wrap {
  width: var(--container);
  margin-inline: auto;
}

/* ---- editorial section — content-height, top-anchored, with a uniform
   vertical rhythm between every section.
   The gap a reader sees between two sections is padding-bottom(N) +
   padding-top(N+1). Keeping BOTH of those the same on every section makes
   every inter-section gap identical (~142px desktop): a small, consistent
   bottom (--section-pad-bottom) plus the fixed nav-clearance top.
   Sections are NOT forced to a full-viewport band anymore (that centred
   short content in a tall box and blew the gaps out to ~360px); the hero
   opts back into 100svh for the opening screen, everything else is the
   height of its own content. */
.panel {
  --band: 0;
  /* the between-section breathing gap (this section's bottom + the next's
     top). Bumped up for a calmer, more Apple-like rhythm — every section
     references this one token (simplicity/transparency/products/membership
     all use var(--section-pad-bottom)), so raising it here widens every
     inter-section seam uniformly without touching any section's own
     carefully-tuned top padding (which controls headline alignment). */
  --section-pad-bottom: clamp(32px, 5svh, 60px);
  position: relative;
  width: 100%;
  min-height: var(--band);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  /* vertical rhythm only — every section's inner content sits in a .wrap,
     whose own width:var(--container) is already the single source of
     horizontal inset (see the long note this replaced re: double-counting
     the gutter if padding were set on both). */
  padding-bottom: var(--section-pad-bottom);
  /* top padding must never fall below the fixed chrome's real height
     (--topbar-h 28px + .site-nav 64px = 92px) or a section's own heading
     renders partially UNDER the frosted nav once it's scrolled (nav is
     position:fixed, not in flow). 108px = 92px + air; it's also the
     larger half of the ~142px inter-section gap. */
  padding-top: max(108px, clamp(64px, 12svh, 140px));
}
/* first section sits under the (initially invisible) fixed nav, full
   viewport height as the opening screen. padding-top:0 (not the shared
   nav-clear) because the hero is bottom-anchored and its bottle height is
   computed off the full (100svh - header) space. */
.panel-hero { --band: 100svh; padding-top: 0; }
/* first section sits under the (initially invisible) fixed nav, so it
   doesn't need the top clearance the rest do */
.panel-hero { padding-top: 0; }

/* ---- scroll-reveal: content settles softly into view as it enters
   the viewport (js/reveal.js toggles .in). Sections overlap because
   each reveal fires a little before the previous band has fully left.
   Deliberately simple: opacity + one small translateY, nothing else —
   this is the only motion any section (including Hero) uses now that
   the scroll-driven hero->simplicity pin/crossfade has been removed. */
[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 600ms var(--ease-standard), transform 600ms var(--ease-standard);
  will-change: opacity, transform;
}
[data-reveal].in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   MOBILE — natural editorial scroll, not a slideshow.
   Sections are already content-driven (`.panel` sets min-height,
   never height, and never clips), so the fix isn't the section
   shell — it's that every product image on mobile was sized off
   *height* (svh), which on a narrow, tall viewport starves the
   width and produces a small, cramped bottle. Every product
   figure switches to *width*-based (vw) sizing instead (see
   css/components/product-figure.css) so bottles read as large,
   premium objects and sections grow well past one screen — exactly
   as intended. Desktop is untouched throughout this block.
   ============================================================ */
@media (max-width: 767px) {
  .panel {
    /* mobile chrome is 28px topbar + 72px nav = 100px — the max() floor
       below guarantees this never dips under full clearance regardless
       of svh, unchanged from before. The clamp's ceiling (and
       --section-pad-bottom just below) were trimmed a touch per a
       pre-launch audit note: the combined section-to-section gap on a
       phone (e.g. transparency -> story) measured ~190-200px, noticeably
       more air than the same transition needs — consistent with the
       site's calm pacing elsewhere, just a little generous. This is also
       the (larger) half of the uniform inter-section gap on mobile — same
       model as desktop: small shared bottom + nav-clear top, so every
       gap is padding-bottom + this. */
    padding-top: max(100px, clamp(88px, 13svh, 124px));
    --section-pad-bottom: clamp(28px, 4svh, 48px);
    padding-bottom: var(--section-pad-bottom);
  }

  /* real body copy (not the tracked uppercase eyebrow/caption labels,
     which already sit correctly at --t-label/--t-desc's small end).
     .hero-headline's and .story-title's mobile overrides live in their
     own section files, NOT here — both have their own unconditional
     (desktop) rule in a file that loads *after* this one, so an override
     here would lose the cascade to that later, equally-specific rule
     despite this media query matching. */
  /* .card-text and .story-statement p used to share this mobile clamp but
     now sit at the Body tier (--t-body) via their own rules — only the
     hero sub keeps this larger mobile size. */
  .hero-sub {
    font-size: clamp(18px, 4.8vw, 22px);
    line-height: 1.45;
  }
}

/* content/lines.mjs's br() wraps a nested-array "line group" (a full
   sentence within a multi-sentence headline) in this class so a component's
   own CSS can put real spacing between two sentences via `.line-group +
   .line-group`, instead of just another same-size line-height gap — see
   .hero-headline in hero.css for the one current consumer. Structural only;
   the spacing value itself is each component's own decision. */
.line-group { display: block; }
