/* ============================================================
   shaded. v2
   palette: chocolate/espresso grounds, warm cream, golden light
   (gradient + hairline only), burnt caramel as the single accent
   display: Spectral Light. body/UI: Inter.
   ============================================================ */

/* vars + reset */
:root {
  --espresso: #241812;
  --chocolate: #38271C;
  --cream: #F4EBDD;
  --cream-soft: #FAF5EC;
  --gold: #E3A94F;
  --caramel: #B0602F;
  --caramel-deep: #96491C;
  --ink: #2A2622;
  --ink-soft: rgba(42, 38, 34, 0.72);
  --cream-soft-a: rgba(244, 235, 221, 0.78);
  --hairline-dark: rgba(42, 38, 34, 0.22);
  --hairline-light: rgba(244, 235, 221, 0.22);
  --ease-slow: cubic-bezier(0.22, 0.08, 0.14, 1);
  --pad-x: clamp(1.4rem, 5.5vw, 4.5rem);
  --measure: 33em;
}

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

html { -webkit-text-size-adjust: 100%; scroll-padding-top: 5rem; }

body {
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.75;
  color: var(--ink);
  background: var(--espresso);
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

a { color: inherit; }

/* type */
h1, h2, .serif {
  font-family: "Spectral", "Times New Roman", serif;
  font-weight: 300;
  line-height: 1.12;
  letter-spacing: -0.005em;
}

h1 em, h2 em {
  font-style: italic;
  font-weight: 300;
  color: var(--caramel);
}

h2 { font-size: clamp(1.95rem, 5.6vw, 3.5rem); }

.eyebrow {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  opacity: 0.75;
}

.body-copy {
  max-width: var(--measure);
  font-size: clamp(1rem, 0.95rem + 0.35vw, 1.13rem);
}

.micro {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* Unverified figures. They render clean in production; add ?debug to the
   URL to bracket them for internal review. The class itself is the launch
   gate: grep for class="ph" before spending on ads. */
.ph { white-space: nowrap; }
.debug .ph::before { content: "["; opacity: 0.4; }
.debug .ph::after { content: "]"; opacity: 0.4; }

/* skip link */
.skip {
  position: absolute;
  top: -4rem;
  left: 1rem;
  z-index: 60;
  padding: 0.6rem 1rem;
  background: var(--cream);
  color: var(--ink);
  font-size: 0.8rem;
  text-decoration: none;
}
.skip:focus { top: 1rem; }

/* buttons: no solid button exists above the reveal */
.btn {
  display: inline-block;
  padding: 0.95rem 2.4rem;
  font-family: "Inter", system-ui, sans-serif;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  border-radius: 2px;
  cursor: pointer;
  transition: background-color 0.45s var(--ease-slow), color 0.45s var(--ease-slow), border-color 0.45s var(--ease-slow);
}

.btn--ghost {
  border: 1px solid var(--cream-soft-a);
  background: transparent;
  color: var(--cream);
}
.btn--ghost:hover { background: var(--cream); color: var(--espresso); border-color: var(--cream); }

/* buttons are hairline-outlined, never filled blocks. a thin rule and
   letterspaced caps read more expensive than a slab of colour */
.btn--solid {
  border: 1px solid rgba(42, 38, 34, 0.45);
  background: transparent;
  color: var(--ink);
}
.btn--solid:hover { background: var(--espresso); border-color: var(--espresso); color: var(--cream-soft); }
.btn--solid[disabled] { opacity: 0.55; cursor: default; }

.on-dark .btn--solid,
.footer .btn--solid {
  border-color: rgba(244, 235, 221, 0.5);
  background: transparent;
  color: var(--cream);
}
.on-dark .btn--solid:hover,
.footer .btn--solid:hover { background: var(--cream); border-color: var(--cream); color: var(--espresso); }

:is(.btn, a, button, input, label):focus-visible {
  outline: 2px solid var(--caramel);
  outline-offset: 3px;
}

/* nav */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.05rem var(--pad-x);
  color: var(--cream);
  border-bottom: 1px solid transparent;
  transition: background-color 0.5s var(--ease-slow), border-color 0.5s var(--ease-slow);
}

/* No backdrop-filter. Blurring the backdrop of a fixed bar means iOS Safari
   re-blurs it every frame of the scroll, which was the single most expensive
   thing on the page. A slightly more opaque ground reads the same. */
.nav--scrolled {
  background: rgba(36, 24, 18, 0.94);
  border-bottom-color: var(--hairline-light);
}

.wordmark {
  font-family: "Spectral", serif;
  font-weight: 300;
  font-size: 1.3rem;
  line-height: 1;
  text-decoration: none;
}
.wordmark b { font-weight: 300; color: var(--caramel); }

.nav__cta {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid rgba(244, 235, 221, 0.45);
  transition: border-color 0.35s;
}
.nav__cta:hover { border-bottom-color: var(--cream); }

/* hero */
.hero {
  position: relative;
  /* var set once by app.js; the svh values are the no-JS fallback */
  min-height: 100vh;
  min-height: 100svh;
  min-height: var(--vh-lock, 100svh);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  color: var(--cream);
}

.hero__media { position: absolute; inset: 0; }
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 34%;
}

.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(36, 24, 18, 0.34), rgba(36, 24, 18, 0) 24%),
    linear-gradient(to top, rgba(36, 24, 18, 0.9), rgba(36, 24, 18, 0.5) 38%, rgba(36, 24, 18, 0.08) 66%);
}

.hero__content {
  position: relative;
  padding: 0 var(--pad-x) clamp(5.5rem, 12vw, 9rem);
  max-width: 40rem;
}

.hero h1 {
  font-size: clamp(1.95rem, 6.8vw, 3.9rem);
  margin-bottom: 2.2rem;
}
/* the hero emphasis is cream italic: the italic alone carries it */
.hero h1 em { color: inherit; }

/* sections: shared editorial pacing */
.sec {
  position: relative;
  padding: clamp(7rem, 12vw, 11rem) var(--pad-x);
  overflow: hidden;
}

.sec--cream { background: var(--cream); color: var(--ink); }
.sec--white { background: var(--cream-soft); color: var(--ink); }
.sec--chocolate { background: var(--chocolate); color: var(--cream); }
.sec--espresso { background: var(--espresso); color: var(--cream); }

.sec__inner { max-width: 72rem; margin: 0 auto; position: relative; }

/* 2. science + ladder.
   image leads and runs full-bleed on phones; one type voice throughout
   (Spectral for everything except the single small footnote) */
/* photograph runs the full width as a band, text sits centred beneath it */
.sec--science { padding: 0 0 clamp(7rem, 12vw, 11rem); text-align: center; }
.sec--science .science__fig { margin-bottom: clamp(3rem, 8vw, 5rem); }
.sec--science .science__fig img {
  width: 100%;
  aspect-ratio: 4 / 5;
  max-height: 34rem;
  object-fit: cover;
  /* the band is far wider than the photograph, so it crops hard vertically.
     anchor low: the crowns and the horizon, not the empty sky above them */
  object-position: center 72%;
}
.sec--science .science__text {
  max-width: 62rem;
  margin: 0 auto;
  padding: 0 var(--pad-x);
}

.sec--science h2 {
  margin: 0 auto clamp(2.4rem, 6vw, 3.6rem);
  max-width: 15em;
}

/* three columns side by side, so it reads as a comparison rather than a
   list. no rules anywhere: space alone separates them */
.ladder {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 5vw, 2.8rem);
  margin: 0 0 clamp(3rem, 7vw, 4.5rem);
  text-align: center;
}
.ladder dt,
.ladder dd { font-family: "Spectral", serif; }
.ladder dt {
  font-weight: 400;
  font-size: clamp(1.3rem, 1.1rem + 0.8vw, 1.75rem);
  line-height: 1.25;
}
/* regular weight, not light, and a much smaller drop in contrast: at 300
   and 72% ink this was the least readable copy on the page */
.ladder dd {
  font-weight: 400;
  font-size: clamp(1.02rem, 0.96rem + 0.3vw, 1.15rem);
  line-height: 1.6;
  color: rgba(42, 38, 34, 0.88);
  margin-top: 0.6rem;
  max-width: 22em;
  margin-inline: auto;
}
/* the bold words carry the argument at the two ends of the ladder: burning,
   spots, slackening / nothing, nothing, nothing. the middle column stays
   unbolded, since the caveats are the point and emphasis only cluttered them */
.ladder dd strong {
  font-weight: 600;
  color: var(--ink);
}
.ladder__row--ours dt { color: var(--caramel-deep); }
.ladder__row--ours dd strong { color: var(--caramel-deep); }

.science__close {
  font-family: "Spectral", serif;
  font-weight: 400;
  font-size: clamp(1.2rem, 1rem + 0.9vw, 1.75rem);
  line-height: 1.45;
  max-width: 22em;
  margin-inline: auto;
}

/* 3. triad. a quiet typographic breath on dark, centred, nothing else */
.sec--triad { text-align: center; }
.sec--triad .sec__inner { max-width: 30em; }
.sec--triad h2 { margin: 0 auto; }

/* 4. a silent full-bleed breath. no text, no scrim */
/* clips: on pointer devices the still drifts inside this frame */
.breath { display: block; line-height: 0; background: var(--espresso); overflow: hidden; }
.breath img {
  width: 100%;
  aspect-ratio: 3 / 4;
  max-height: 34rem;
  object-fit: cover;
  object-position: center 62%;
}

/* 4. the one thing */
/* no product visual yet, so this is a compact type statement rather than a
   full screen. tighter padding stops it reading as a missing image */
.sec--reveal {
  text-align: center;
  padding-top: clamp(4.5rem, 9vw, 7rem);
  padding-bottom: clamp(4.5rem, 9vw, 7rem);
}
.sec--reveal .sec__inner { max-width: 54rem; }
.sec--reveal h2 { margin-bottom: clamp(1.6rem, 4vw, 2.4rem); }

/* the product, in its three colourways. one row at every size; on phones
   it breaks out past the section padding so the images stay as large as
   the screen allows */
.colourways {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.3rem, 1.4vw, 0.9rem);
  margin: 0 calc(var(--pad-x) * -1) clamp(2rem, 5vw, 3rem);
}
.colourways__item { margin: 0; }
.colourways__item img { width: 100%; height: auto; }

@media (min-width: 760px) {
  .colourways { margin-inline: auto; }
}

.sec--reveal .body-copy { margin: 0 auto 1.5rem; color: var(--ink-soft); }

.scarcity {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 2.4rem;
}


/* 5. summer */
.sec--summer { padding-right: 0; }
.sec--summer .sec__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
  align-items: center;
  max-width: none;
}
.sec--summer .summer__text { padding-right: var(--pad-x); }
.sec--summer h2 {
  font-size: clamp(1.6rem, 4.4vw, 2.7rem);
  max-width: 14em;
}

.summer__fig img {
  width: 100%;
  /* height:auto is required, otherwise the html height attribute wins as a
     presentational hint and aspect-ratio never applies */
  height: auto;
  /* squarer on phones so it does not eat the whole screen; taller again
     once it sits beside the copy */
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center 42%;
}
@media (min-width: 760px) {
  .summer__fig img { aspect-ratio: 4 / 5; }
}

/* 7. pre-order. no card: open water, one line of type, one field.
   an invitation rather than a form */
.preorder {
  position: relative;
  min-height: 88svh;
  min-height: calc(var(--vh-lock, 88svh) * 0.88);
  display: flex;
  align-items: center;
  overflow: hidden;
  color: var(--cream);
  padding: clamp(5rem, 12vw, 9rem) var(--pad-x);
}
.preorder__media { position: absolute; inset: 0; }
.preorder__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.preorder__scrim {
  position: absolute;
  inset: 0;
  /* the glitter is what makes this frame and it is also what makes the type
     swim: a blown-out crest behind a line of copy drops local contrast to
     about 3.3:1. the ellipse takes the crests down over the content column
     only, so the water at the edges stays open and the bottom edge still
     lands on .72 for the footer to carry on from. */
  background:
    radial-gradient(38rem 62% at 50% 50%, rgba(16, 26, 34, 0.34), rgba(16, 26, 34, 0) 68%),
    linear-gradient(to bottom, rgba(20, 32, 40, 0.62), rgba(20, 30, 38, 0.72));
}
.preorder__inner {
  position: relative;
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
  text-align: center;
}
.preorder h2 {
  font-size: clamp(1.8rem, 5.4vw, 3rem);
  margin-bottom: clamp(2rem, 5vw, 2.8rem);
}
.preorder h2 em { color: var(--cream); }

/* the live places line: filled from the sheet by app.js, absent when unknown.
   [hidden] keeps it out of the layout until there is a real number, so the
   negative margin pulls it up into the gap the heading already leaves */
.places {
  margin: calc(clamp(2rem, 5vw, 2.8rem) * -0.55) 0 clamp(1.6rem, 4vw, 2.2rem);
  /* the count is the one live fact on the page, and it spent three rounds as
     nearly the smallest type on it because every bump was capped by the wrong
     string. the sold-out fallback ("more on the list than places in the
     drop.") is the long one, and holding it to a single line inside the 34rem
     column is what kept the size at 0.9rem. that is backwards: sold-out is a
     state this page reaches once, at the end, and it was rationing the line
     every visitor actually reads.

     so the cap is gone. the count sizes for itself, roughly 40% of the h2, a
     subhead rather than a caption, and the sold-out line is simply allowed to
     wrap to two. tracking still comes down as size goes up (0.22em/0.75rem,
     0.18em/0.8rem, 0.08em/0.9rem, now 0.05em) because it exists to open up
     small caps and large ones do not need it; at this size it reads as a
     tracked label, not a gappy one. line-height and balance are here for the
     wrap, not the count: they only ever apply to the sold-out sentence. */
  font-size: clamp(1.05rem, 2.1vw, 1.3rem);
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.45;
  text-wrap: balance;
  text-transform: uppercase;
  color: rgba(244, 235, 221, 0.85);
}

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

/* a single underlined baseline, submit sits inline on the same rule */
.line-field {
  display: flex;
  align-items: center;
  gap: 1rem;
  border-bottom: 1px solid rgba(244, 235, 221, 0.5);
  transition: border-color 0.4s var(--ease-slow);
}
.line-field:focus-within { border-bottom-color: var(--cream); }
.line-field input[type="email"] {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.85rem 0;
  font-family: "Spectral", serif;
  font-weight: 300;
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  color: var(--cream);
  background: transparent;
  border: 0;
  border-radius: 0;
}
.line-field input[type="email"]::placeholder { color: rgba(244, 235, 221, 0.5); }
.line-field input[type="email"]:focus { outline: none; }
.line-field button {
  flex: 0 0 auto;
  padding: 0.5rem 0;
  font-family: "Inter", system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--cream);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: opacity 0.35s;
}
.line-field button:hover { opacity: 0.65; }
.line-field button[disabled] { opacity: 0.45; cursor: default; }

.hp { position: absolute; left: -9999px; }

.field__error {
  margin-top: 0.7rem;
  font-size: 0.82rem;
  color: var(--gold);
  text-align: left;
}
.form__error { text-align: center; }
.form__error:empty, .field__error:empty { display: none; }
.line-field input[aria-invalid="true"] { color: var(--gold); }

.privacy {
  margin-top: 1.2rem;
  font-size: 0.78rem;
  color: rgba(244, 235, 221, 0.62);
  text-align: center;
}
.privacy a { color: inherit; text-underline-offset: 2px; }
.privacy a:hover { color: var(--cream); }

/* five sentences in one centred block is a wall, and the one sentence that
   answers "did it work?" was buried in it. the promise leads at full cream;
   the terms follow smaller and quieter, so the eye can take the first line
   and stop there. */
.confirm h2 { margin-bottom: 1.1rem; }
/* margin-inline, not the shorthand: `margin: 0 auto` here outranks the
   single-class .confirm__note below it and would zero out its top margin */
.confirm .body-copy { margin-inline: auto; }
/* the lead gets the full column so it lands on one line and is read in one go.
   pretty, not balance: balance would halve it and break after "Your", stranding
   the word from the "number" it belongs to on the widths where it does wrap. */
.confirm__lead {
  color: var(--cream);
  text-wrap: pretty;
}
/* two short lines, which is exactly what balance is for. 1rem is a floor, not
   a preference: this is body copy, and dropping it under 16px to buy contrast
   with the lead would undo the readability the split is here to win. the step
   is carried by colour and the gap instead. */
.confirm__note {
  margin-top: 1.9rem;
  font-size: 1rem;
  line-height: 1.7;
  color: rgba(244, 235, 221, 0.86);
  text-wrap: balance;
}

/* footer */
/* no seam: the water carries on past the pre-order screen and darkens, so
   there is no join to notice. the scrim starts at the alpha the pre-order
   scrim ends on (.72) and deepens. the image is uniform sparkle with no
   horizon, so the continuation reads as unbroken. */
.footer {
  background:
    linear-gradient(to bottom, rgba(20, 30, 38, 0.74), rgba(13, 20, 26, 0.95)),
    url("assets/ocean-glitter.jpg") center 78% / cover;
  color: var(--cream);
  padding: clamp(3.5rem, 7vw, 5.5rem) var(--pad-x) clamp(2.5rem, 5vw, 4rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.2rem;
  text-align: center;
}
.footer__line {
  max-width: 30em;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--cream-soft-a);
}
.footer__meta {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* full cream, not dimmed: the muted grey read as a disabled state */
  color: var(--cream);
}
.footer__meta a { text-decoration: none; }
.footer__meta a:hover { color: var(--cream); }
.footer__meta svg { display: block; width: 16px; height: 16px; fill: currentColor; }

/* the way back into the consent banner; injected by app.js only when a
   pixel ID is configured, so it never appears on a pixel-less deploy */
.consent-reopen {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}
.consent-reopen:hover { text-decoration: underline; text-underline-offset: 3px; }

/* cookie consent. Fixed to the bottom edge, espresso over whatever section
   is behind it, and deliberately quiet: two hairline buttons of identical
   weight, because pre-ticked emphasis on "allow" is the pattern regulators
   call out. Sits below the skip link (60) and above everything else. */
.consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 55;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.9rem 2rem;
  padding: 1rem var(--pad-x) calc(1rem + env(safe-area-inset-bottom));
  background: rgba(36, 24, 18, 0.96);
  color: var(--cream);
  border-top: 1px solid var(--hairline-light);
  font-size: 0.8rem;
  line-height: 1.55;
}
.consent p { margin: 0; max-width: 44em; color: var(--cream-soft-a); }
.consent a { color: var(--cream); text-underline-offset: 2px; }
.consent__actions { display: flex; gap: 0.7rem; }
.consent__actions button {
  appearance: none;
  cursor: pointer;
  background: none;
  border: 1px solid var(--cream-soft-a);
  color: var(--cream);
  font-family: "Inter", system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.65rem 1.4rem;
  transition: background-color 0.45s var(--ease-slow), color 0.45s var(--ease-slow);
}
.consent__actions button:hover { background: var(--cream); color: var(--espresso); }


/* film grain */
:root {
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}
/* A full-viewport fixed layer above every section has to be recomposited on
   every scroll frame, which is expensive on phones and buys almost nothing
   at 4% opacity. Kept on pointer devices, dropped on touch. */
.grain { display: none; }

/* Only promote the parallax stills to their own layer where the parallax
   actually runs. On phones these were permanent GPU layers doing nothing. */
@media (hover: hover) and (pointer: fine) {
  /* js writes --drift; each still spends it here, so the amount of movement
     and the way it is absorbed stay in the stylesheet */
  .breath img,
  .summer__fig img {
    will-change: transform;
    transform: translateY(var(--drift, 0px));
  }

  /* the breath still fills its frame exactly, so drifting it uncovered the
     espresso ground beneath, a dark seam sitting on top of the cream
     section below. oversized past the frame, which clips it, so the drift
     runs inside the photograph and no ground is ever exposed */
  .breath img { transform: translateY(var(--drift, 0px)) scale(1.08); }

  .grain {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background-image: var(--grain);
    opacity: 0.04;
    pointer-events: none;
  }
}

/* scroll reveals (js adds .is-in) */
.js .reveal { opacity: 0; }
.js .reveal.is-in { opacity: 1; }

/* motion: everything slower than expected */
@media (prefers-reduced-motion: no-preference) {
  /* Pointer devices only. An in-app browser repositions the scroll offset
     itself as its chrome collapses; with smooth scrolling on the root, that
     adjustment gets animated and fights the momentum already in flight,
     which is what makes the page oscillate rather than settle. */
  @media (hover: hover) and (pointer: fine) {
    html { scroll-behavior: smooth; }
  }

  .js .reveal { transform: translateY(14px); }
  .js .reveal.is-in {
    transform: translateY(0);
    /* was 1s: long enough that fast scrolling landed you on copy that was
       still fading, which read as content arriving late */
    transition: opacity 0.45s var(--ease-slow), transform 0.45s var(--ease-slow);
  }
  .js .reveal--slow.is-in { transition-duration: 0.6s; }
}

/* The hero drift runs for nine seconds from load, which is most of the time
   anyone spends scrolling the first screens. Continuously scaling a
   full-bleed image forces the compositor to re-rasterise that layer, and on
   an in-app webview that is enough to stutter the scroll underneath it.
   Pointer devices keep it; touch gets a still hero. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .hero__media img { animation: kenburns 9s var(--ease-slow) forwards; }
  @keyframes kenburns {
    from { transform: scale(1); }
    to { transform: scale(1.035); }
  }
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; }
}

/* ============ tablet+ ============ */
@media (min-width: 760px) {
  .sec--summer .sec__inner {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: 0;
  }
  .sec--summer .summer__text { padding-left: var(--pad-x); position: relative; z-index: 2; }

  .footer {
    flex-direction: row;
    justify-content: space-between;
    text-align: left;
    gap: 3rem;
  }
}

/* ============ desktop ============ */
@media (min-width: 1080px) {
  .hero__content { padding-bottom: clamp(6.5rem, 12vw, 11rem); }
  .sec--summer .sec__inner { grid-template-columns: 1fr minmax(0, 44%); }

  .ladder { grid-template-columns: repeat(3, 1fr); gap: clamp(2rem, 4vw, 3.5rem); }
  .ladder dd { max-width: 18em; }

}
