/* ============================================================
   COCA-COLA — CONCEPT SITE
   Independent, unofficial design study.

   00  TOKENS
   01  RESET & BASE
   02  TYPOGRAPHY PRIMITIVES
   03  UTILITIES
   04  NAVIGATION
   05  MENU OVERLAY
   06  STAGE / PRODUCT
   07  SCENE 01 — HERO
   08  SCENE 02 — THE CLASSIC
   09  RESPONSIVE
   10  REDUCED MOTION
   ============================================================ */


/* ===== 00  TOKENS ========================================== */

/* Registered so the browser interpolates them as real types
   instead of as strings — needed for the scroll-driven colour
   and width-axis transitions. */
@property --bg   { syntax: '<color>';  inherits: true; initial-value: #E31E24; }
@property --fg   { syntax: '<color>';  inherits: true; initial-value: #FFFFFF; }
@property --wdth { syntax: '<number>'; inherits: true; initial-value: 125; }

:root {
  /* Colour — warm palette. Nostalgia is warm; no cool greys. */
  --coke-red:      #E31E24;
  --coke-red-dark: #8E1116;
  --coke-red-deep: #4A0A0E;
  --white:         #FFFFFF;
  --cream:         #F4EDE4;
  --black:         #0B0708;
  --gray:          #8A8078;
  --ice:           #DCE6E8;   /* reserved for SCENE 05 only */
  --mega-tint:     #F1C8C1;   /* --coke-red at 18% over --cream, flattened */
  /* Cherry — a deeper, bluer red than --coke-red, so the variant reads as
     a different fruit rather than as the same red dimmed. */
  --cherry:        #7C0B22;
  --cherry-deep:   #45060F;
  --cherry-lit:    #A81232;

  /* Live scene tokens — tweened by the scroll timeline. */
  --bg:   var(--coke-red);
  --fg:   var(--white);
  --wdth: 125;

  /* Type scale */
  --fs-display: clamp(4rem, 16vw, 18rem);
  --fs-mega:    clamp(7rem, 45.5vw, 50rem);
  --fs-happy-back:  clamp(3.5rem, 21vw, 22rem);
  --fs-happy-front: clamp(3rem, 16vw, 18rem);
  --fs-flav:        clamp(2.75rem, 15vw, 17rem);
  --fs-ice:         clamp(3.5rem, 21vw, 24rem);
  --fs-magic:       clamp(4rem, 27vw, 32rem);
  --fs-mo:          clamp(3rem, 17vw, 20rem);
  --fs-choose:      clamp(3.5rem, 18vw, 20rem);
  --fs-choose-open: clamp(3rem, 15vw, 15rem);
  --fs-the:     clamp(2.75rem, 9vw, 10rem);
  --fs-h2:      clamp(2.5rem, 7vw, 7rem);
  --fs-body:    clamp(1rem, 0.6vw + 0.85rem, 1.375rem);
  --fs-meta:    clamp(0.6875rem, 0.25vw + 0.6rem, 0.8125rem);

  /* Rhythm */
  --gutter: clamp(20px, 4vw, 64px);

  /* Product — the two knobs that resize the hero object.
     --product-ar must match the artwork's intrinsic ratio; it is the
     only thing that changes when the artwork is swapped. */
  --product-h:  74vh;
  --product-ar: 530 / 1800;   /* coke-bottle.webp, alpha-trimmed */

  /* Motion language — see CREATIVE-DIRECTION.md §5 */
  --ease-pour: cubic-bezier(0.16, 1, 0.3, 1);   /* expo.out  */
  --ease-snap: cubic-bezier(0.22, 1, 0.36, 1);  /* power3.out */
  --dur-touch: 0.28s;
}


/* ===== 01  RESET & BASE ==================================== */

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

html {
  background: var(--bg);
  scroll-behavior: auto;          /* Lenis owns scrolling */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--fs-body);
  line-height: 1.45;
  font-variation-settings: 'wdth' 100, 'wght' 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior-y: none;
}

/* Fine, static film grain. One fixed layer, never animated. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 400;
  pointer-events: none;
  opacity: .05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

a { color: inherit; text-decoration: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

::selection { background: var(--black); color: var(--cream); }

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 500;
  padding: .75em 1.25em;
  background: var(--black);
  color: var(--cream);
  font-size: var(--fs-meta);
  letter-spacing: .16em;
  text-transform: uppercase;
  transform: translateY(-200%);
  transition: transform var(--dur-touch) var(--ease-snap);
}
.skip-link:focus-visible { transform: none; }


/* ===== 02  TYPOGRAPHY PRIMITIVES =========================== */

/* The display voice. Width axis is live (--wdth) so headlines can
   physically narrow as they scroll away. */
.display,
.hero__title .hl__text,
.mega,
.scene__word,
.menu__link {
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
}

/* The editorial voice. Used for single words only. */
.serif,
.hero__the,
.classic__lead em,
.menu__link em {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  text-transform: none;
  letter-spacing: -0.01em;
}

/* The meta voice. */
.label,
.nav,
.hero__meta,
.menu__meta {
  font-size: var(--fs-meta);
  font-variation-settings: 'wdth' 92, 'wght' 500;
  text-transform: uppercase;
  letter-spacing: .18em;
  line-height: 1.6;
}

.label { margin: 0; opacity: .62; }


/* ===== 03  UTILITIES ======================================= */

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

/* Pre-hide only when JS is present; see the inline head script. */
.js [data-anim] { opacity: 0; }


/* ===== 04  NAVIGATION ====================================== */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  padding: clamp(18px, 2.6vh, 34px) var(--gutter);
  color: var(--fg);
  mix-blend-mode: normal;
  will-change: transform;
}

.nav__logo {
  display: flex;
  align-items: center;
  gap: .7em;
}
.nav__mark {
  width: auto;
  height: 1.9em;
  fill: currentColor;
  transition: transform var(--dur-touch) var(--ease-snap);
}
.nav__logo:hover .nav__mark { transform: rotate(-8deg) translateY(-2px); }
.nav__word {
  font-variation-settings: 'wdth' 112, 'wght' 700;
  letter-spacing: .2em;
}

.nav__links { display: flex; gap: clamp(20px, 2.4vw, 44px); }

/* Microinteraction: the label lifts, an underline wipes in from the left. */
.nav__link { position: relative; overflow: hidden; padding-bottom: .35em; }
.nav__link span {
  display: inline-block;
  transition: transform var(--dur-touch) var(--ease-snap);
}
.nav__link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-touch) var(--ease-snap);
}
.nav__link:hover span { transform: translateY(-2px); }
.nav__link:hover::after { transform: scaleX(1); }

/* Links to scenes that do not exist yet — visibly pending, not broken. */
.nav__link.is-upcoming,
.menu__link.is-upcoming {
  opacity: .38;
  cursor: default;
}
.nav__link.is-upcoming:hover span { transform: none; }
.nav__link.is-upcoming::after { display: none; }
.menu__inner .menu__link.is-upcoming:hover { opacity: .38; transform: none; }

.nav__menu { display: flex; align-items: center; gap: .8em; letter-spacing: .18em; }
.nav__menu-bars {
  display: grid;
  gap: 4px;
  width: 22px;
}
.nav__menu-bars i {
  display: block;
  height: 1px;
  background: currentColor;
  transition: transform var(--dur-touch) var(--ease-snap);
}
.nav__menu:hover .nav__menu-bars i:first-child { transform: translateX(-4px); }
.nav__menu:hover .nav__menu-bars i:last-child  { transform: translateX(4px); }

/* While the overlay is open the nav sits on the dark panel, not on the
   scene, so it must leave the --fg token behind (black on dark red). */
.nav.is-open { color: var(--cream); }
.nav.is-open .nav__menu-bars i:first-child { transform: translateY(2.5px) rotate(9deg); }
.nav.is-open .nav__menu-bars i:last-child  { transform: translateY(-2.5px) rotate(-9deg); }


/* ===== 05  MENU OVERLAY ==================================== */

.menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2rem;
  padding: 22vh var(--gutter) var(--gutter);
  background: var(--coke-red-deep);
  color: var(--cream);
  clip-path: inset(0 0 100% 0);
}
.menu[hidden] { display: none; }

.menu__inner { display: grid; }

.menu__link {
  display: flex;
  align-items: baseline;
  gap: .5em;
  padding: .12em 0;
  font-size: clamp(2.5rem, 11vw, 8rem);
  font-variation-settings: 'wdth' 118, 'wght' 900;
  transition: opacity var(--dur-touch) var(--ease-snap),
              transform var(--dur-touch) var(--ease-snap);
}
.menu__link em {
  font-size: var(--fs-meta);
  letter-spacing: .2em;
  opacity: .5;
}
.menu__inner:hover .menu__link { opacity: .38; }
.menu__inner .menu__link:hover { opacity: 1; transform: translateX(clamp(8px, 1.4vw, 22px)); }

.menu__meta { margin: 0; opacity: .5; }


/* ===== 06  STAGE / PRODUCT ================================= */

/* One product for the whole site. Fixed, so scenes scroll past it
   rather than it being handed from section to section. */
.stage {
  position: fixed;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.stage__product {
  position: relative;
  height: var(--product-h);
  aspect-ratio: var(--product-ar);
  /* The stage is a grid, so this is a grid item: without min-width:0 its
     automatic minimum size would let the wide can stretch the box and
     break the aspect ratio every scene depends on. The can is meant to
     overflow the box, not resize it. */
  min-width: 0;
  min-height: 0;
  will-change: transform;
}

.product__inner {
  width: 100%;
  height: 100%;
  will-change: transform;
  /* grid stacking for the flavour arts — see .product__art below */
}

/* The three products share one grid cell. Grid rather than absolute
   positioning because an absolutely positioned image with `left:0;right:0`
   takes the full box width and then letterboxes itself — every product
   would collapse to the narrow bottle width. Grid also avoids transforms,
   which matters: GSAP owns `transform` here for the idle float.

   Aligned to the bottom of the cell, so all three stand on one ground
   line and the contact shadow fits whichever is currently wiped in.

   Each art keeps its own height, so the sizes stay honest — the can is
   genuinely shorter and wider than the bottle. */
.product__inner {
  display: grid;
  place-items: end center;
}

.product__art {
  --art-k: 1;   /* height as a multiple of --product-h */

  grid-area: 1 / 1;
  /* Derived from --product-h rather than a percentage: a percentage height
     inside an auto-sized grid row does not resolve, and the images fall
     back to their intrinsic pixel size. */
  height: calc(var(--product-h) * var(--art-k));
  width: auto;
  max-width: none;
  object-fit: contain;
  object-position: bottom center;
}

.product__art[data-flavour='original'] { --art-k: .56; }
.product__art[data-flavour='zero']     { --art-k: 1.04; }

/* Hidden until scene 04 wipes them in, using the same clip line the
   flavour typography uses. */
.product__art--swap { clip-path: inset(100% 0 0 0); }

/* Contact shadow — a soft radial gradient rather than a drop-shadow or
   blur filter, both of which would re-rasterise while the product scales. */
.product__shadow {
  position: absolute;
  left: 50%;
  bottom: -4%;
  /* Wide enough to sit under the can as well as the bottle — all three
     products stand on the same ground line. */
  width: 92%;
  aspect-ratio: 3 / 1;
  translate: -50% 0;
  background: radial-gradient(closest-side, rgba(0,0,0,.3), rgba(0,0,0,.12) 46%, rgba(0,0,0,0) 74%);
}


/* ===== 07  SCENE 01 — HERO ================================= */

/* No transform / filter / will-change on .hero: it must NOT create a
   stacking context, otherwise its z-indexed children could not
   straddle the fixed .stage layer above and below. */
.hero {
  position: relative;
  min-height: 100svh;
  overflow: clip;
}

.hero__title { margin: 0; }

/* Headline words — depth layer 1, BEHIND the product. */
.hl {
  position: absolute;
  z-index: 1;
  font-size: var(--fs-display);
  white-space: nowrap;
  will-change: transform;
}
.hl--taste   { top: 13vh;    left: calc(var(--gutter) * -0.35); }
.hl--feeling { bottom: 8vh;  right: calc(var(--gutter) * -0.5); }

/* Mask for the reveal. Padding keeps the cap-height from being
   shaved by the clip; the negative margin cancels the layout shift. */
.hl__mask {
  display: block;
  overflow: hidden;
  padding: .08em .04em .16em;
  margin: -.08em -.04em -.16em;
}
.hl__text { display: block; }
.hl__text .char { display: inline-block; will-change: transform; }

/* "the" — depth layer 3, IN FRONT of the product. The editorial
   counterpoint that keeps the hero from reading as pure brutalism.
   Placed with top/left only: GSAP owns `transform` on this element and
   clears the CSS `translate`/`rotate` longhands when it takes over, so
   any placement expressed through those would be silently dropped. */
.hero__the {
  position: absolute;
  z-index: 3;
  top: 37%;
  left: 34%;   /* far enough right to overlap the bottle: the overlap IS the depth cue */
  font-size: var(--fs-the);
  line-height: .8;
  color: var(--cream);
  will-change: transform;
}

/* Ribbon — connective thread, depth layer 1. */
.hero__ribbon {
  position: absolute;
  z-index: 1;
  top: 42%;
  left: -8%;
  width: 116%;
  height: 44vh;
  opacity: .16;
  vector-effect: non-scaling-stroke;
  will-change: transform;
}

.hero__meta {
  position: absolute;
  z-index: 3;
  margin: 0;
}
.hero__meta--scroll {
  left: var(--gutter);
  bottom: clamp(20px, 3.5vh, 40px);
  display: flex;
  align-items: center;
  gap: .9em;
}
.hero__cue-line {
  display: block;
  width: clamp(40px, 5vw, 78px);
  height: 1px;
  background: currentColor;
  transform-origin: left;
  animation: cue 2.6s var(--ease-pour) infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleX(.35); opacity: .5; }
  45%      { transform: scaleX(1);   opacity: 1;  }
}
.hero__meta--note {
  right: var(--gutter);
  bottom: clamp(20px, 3.5vh, 40px);
  text-align: right;
  opacity: .55;
}


/* ===== 08  SCENE 02 — THE CLASSIC ========================== */

.scene { position: relative; }

/* Scroll budget: 140vh of sticky travel after the hero handover. */
.scene--classic { height: 240vh; }

/* Two sticky layers with the fixed stage (z2) sandwiched between them.
   Sticky rather than a GSAP pin, because a pinned element creates its
   own stacking context and both layers would end up on the same side
   of the product. */
.scene__layer {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  align-content: center;
  padding: 0 var(--gutter);
}
.scene__layer--back {
  z-index: 1;
  overflow: clip;      /* contains the numeral once it is scaled up */
  place-content: center;
  padding: 0;
}
.scene__layer--front {
  z-index: 3;
  margin-top: -100svh; /* stack both layers on the same viewport */
  overflow: clip;
  pointer-events: none;
}
.scene__layer--front > * { pointer-events: auto; }

/* --- the numeral ------------------------------------------------
   Rendered twice, identically, once per depth layer. Solid tint
   rather than transparent red: the front copy has to stay legible
   where it crosses the dark bottle, and an alpha low enough to feel
   quiet on cream disappears completely over the glass. The tint is
   the exact colour --coke-red at 18% over --cream resolves to, so the
   numeral looks unchanged on paper and now also paints on the product. */
.mega {
  position: absolute;
  top: 29vh;
  /* Bleeds off both edges — a field, not a word. The exact offset is
     tuned so the closing 6 clips only the right edge of the bottle:
     enough to prove the depth, not enough to bury the label. */
  left: -12%;
  font-size: var(--fs-mega);
  color: var(--mega-tint);
  white-space: nowrap;
  transform-origin: 20% 50%;   /* grows rightwards, left digits stay anchored */
  will-change: transform;
}
/* Reserves the exact width of "188" so the 6 of the front copy lands
   pixel-identically on the 6 of the back copy, at any viewport. */
.mega__ghost {
  visibility: hidden;
  font-style: normal;
}

/* --- editorial composition --------------------------------------
   Absolute placement on a deliberate diagonal — label, SINCE, numeral,
   lead, caption — so the scene never resolves into two columns. */
.classic__label {
  position: absolute;
  top: 17vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}
.classic__rule,
.rule {
  display: block;
  width: clamp(36px, 6vw, 110px);
  height: 1px;
  background: currentColor;
  opacity: .45;
}

.classic__title {
  position: absolute;
  top: 24vh;
  left: 11%;
  margin: 0;
  font-size: clamp(2.5rem, 8.5vw, 8.5rem);
}

.classic__lead {
  position: absolute;
  top: 65vh;
  left: 24%;
  margin: 0;
  max-width: 19ch;
  font-size: clamp(1.05rem, 1.9vw, 1.9rem);
  line-height: 1.24;
}
.classic__lead em { font-size: 1.06em; }

/* Caption as a vertical margin note. The bottle occupies the full height
   of the right half, so any horizontal caption there collides with it at
   some scroll position; the outer edge is the only clear column. */
.classic__fig {
  position: absolute;
  top: 30vh;
  right: calc(var(--gutter) * 0.34);
  margin: 0;
  writing-mode: vertical-rl;
  opacity: .5;
}

/* Quiet spacer until scenes 03–08 exist. */
.scene--todo {
  min-height: 46svh;
  display: grid;
  place-items: center;
  color: var(--gray);
}


/* ===== 08b  SCENE 03 — OPEN HAPPINESS ======================
   Same two-sticky-layer skeleton as scene 02, different depth device:
   there a single numeral was split around the product, here it is the
   carbonation that sits in front of and behind it. Reusing the same
   trick twice would make the scenes rhyme instead of contrast. */

.scene--happiness { height: 260vh; }

/* --- the two words ----------------------------------------------
   OPEN is solid and near; HAPPINESS is an outline and far. The stroke
   is what puts it behind the product optically as well as in z-order —
   and it lets the bubbles read straight through the letterforms. */
.happy {
  position: absolute;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  will-change: transform;
}

.happy--back {
  /* Moved up from 45vh and capped a touch smaller (see --fs-happy-back)
     so HAPPINESS always has clear headroom below it before the sticky
     layer's overflow:clip boundary — full word height stays visible on
     every tested viewport, including short landscape phones. */
  top: 38vh;
  left: -9%;
  font-size: var(--fs-happy-back);
  color: transparent;
  -webkit-text-stroke: clamp(1px, 0.16vw, 3.5px) var(--fg);
}

/* Base positions sit low enough that the upward parallax below never
   drives them under the fixed navigation. */
.happy--front {
  top: 28vh;
  left: var(--gutter);
  font-size: var(--fs-happy-front);
  color: var(--fg);
}

.happy__label {
  position: absolute;
  top: 22vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}

/* --- carbonation -------------------------------------------------
   Bubbles are built in js/modules/bubbles.js. Only their data —
   position, size, depth — comes from JS, as custom properties; every
   rule that decides how a bubble LOOKS lives here.

   Rising happens on the bubble, scroll parallax on .bubbles: two
   translate owners on one element would fight, the same way the
   reveal and parallax do in scene 02. */
.bubbles {
  position: absolute;
  inset: -14% -8%;
  pointer-events: none;
  will-change: transform;
}

.bubble {
  --size: 20px;
  --rim: .3;
  --core: .34;
  --alpha: .3;
  --blur: 0px;

  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, var(--rim));
  /* Off-centre highlight — reads as a gas bubble rather than a dot. */
  background: radial-gradient(circle at 34% 27%,
              rgba(255, 255, 255, var(--core)),
              rgba(255, 255, 255, .04) 52%,
              rgba(255, 255, 255, 0) 72%);
  opacity: var(--alpha);
  filter: blur(var(--blur));
}


/* ===== 08c  SCENE 04 — FLAVOURS ============================
   One rule holds the scene together: product, flavour name and note all
   wipe along the same rising clip line. A flavour change reads as a
   level rising, not as a slide swapping. */

.scene--flavours { height: 400vh; }

/* --- the three names ---------------------------------------------
   Each sits somewhere different. Three identically placed words would
   turn the scene into a carousel; moving them keeps it a scene. */
.flav__name {
  position: absolute;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  font-size: var(--fs-flav);
  color: var(--fg);
  clip-path: inset(100% 0 0 0);   /* JS wipes them in */
  will-change: transform, clip-path;
}

.flav__name--original { top: 56vh; left: -4%; }
.flav__name--zero     { top: 13vh; right: -3%; text-align: right; }
.flav__name--cherry   { top: 33vh; left: 0; right: 0; text-align: center; }

.flav__note {
  position: absolute;
  bottom: 13vh;
  left: var(--gutter);
  margin: 0;
  max-width: 21ch;
  font-size: clamp(1rem, 1.5vw, 1.5rem);
  line-height: 1.3;
  color: var(--fg);
  clip-path: inset(100% 0 0 0);
  will-change: clip-path;
}
.flav__note em {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-size: 1.12em;
}

.flav__label {
  position: absolute;
  top: 20vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}

/* --- cherries -----------------------------------------------------
   Silhouettes, not illustrations. Built in js/modules/cherries.js from
   the #cherry symbol; as with the bubbles, JS supplies only position,
   size and depth — everything visual is decided here.

   They do not drift on their own: fruit is heavy, and stillness is what
   separates them from the carbonation two scenes earlier. All their
   movement is parallax. */
.cherries {
  position: absolute;
  inset: -12% -8%;
  pointer-events: none;
  opacity: 0;                /* faded in during the zero → cherry step */
  will-change: transform;
}

.cherry {
  --size: 120px;
  --alpha: .5;
  --blur: 0px;

  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--size);
  color: var(--cherry-deep);
  opacity: var(--alpha);
  filter: blur(var(--blur));
  will-change: transform;
}
.cherry svg { width: 100%; height: auto; }

/* The near field catches more light, which is what separates the planes
   once both are blurred. */
[data-cherries='near'] .cherry { color: var(--cherry-lit); }


/* ===== 08d  SCENE 05 — ICE COLD ============================
   The material scene. Two focal planes of real photographed ice around
   the product: far is small, sharp and quiet; near is large, out of
   focus and cropped by the frame. That difference is the depth — not
   a particle system.

   Every element is placed by hand. Nothing here is tiled, repeated or
   randomised, because that is the difference between a composition and
   a collage. */

.scene--ice { height: 380vh; }

/* A cold glow rather than a condensation tile: the supplied frost panel
   is a rectangle by nature and would show its edges. */
.chill {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(115% 78% at 50% 42%, rgba(220, 230, 232, .12), rgba(220, 230, 232, 0) 62%),
    radial-gradient(70% 50% at 82% 88%, rgba(160, 196, 208, .09), rgba(160, 196, 208, 0) 70%);
  pointer-events: none;
}

.ice-title {
  position: absolute;
  left: 0;
  right: 0;
  top: 22vh;
  text-align: center;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  font-size: var(--fs-ice);
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  color: var(--fg);
  will-change: transform;
}

/* Above the title, not beside it: the two-line ICE COLD block is tall
   enough that any label placed level with it lands inside the letters. */
.ice__label {
  position: absolute;
  top: 16vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}

.ice-field {
  position: absolute;
  inset: 0;
  pointer-events: none;
  will-change: transform;
}

.ice {
  position: absolute;
  height: auto;
  max-width: none;
  /* Feathered edges. The extracted mattes are clean but not perfect, and a
     faint residual edge that is invisible at 1:1 becomes a soft rectangle
     once an element is scaled to half the viewport and blurred. Fading the
     outer band guarantees no straight edge can ever show, whatever the
     matte does. */
  -webkit-mask-image: radial-gradient(closest-side, #000 68%, transparent 99%);
  mask-image: radial-gradient(closest-side, #000 68%, transparent 99%);
}

/* --- far plane: small, sharp, quiet --------------------------------- */
.ice--far-a        { left: 5%;  top: 11%; width: 13vw; opacity: .55; }
.ice--far-b        { left: 79%; top: 23%; width: 11vw; opacity: .48; }
.ice--far-c        { left: 17%; top: 73%; width: 36vw; opacity: .38; }
.ice--splash-back  { left: 25%; top: 37%; width: 54vw; opacity: .40; }

/* --- near plane: large, out of focus, cropped -----------------------
   Blur scales with the viewport. A fixed 9px against an element that is
   32vw wide is a soft focus at 1440 and an unreadable smudge at 400 —
   the radius has to stay in proportion to the object. */
.ice--near-a       { left: -7%;  top: 57%;  width: 28vw; opacity: .85; filter: blur(clamp(2px, 0.45vw, 7px)); }
.ice--near-b       { left: 70%;  top: -11%; width: 32vw; opacity: .78; filter: blur(clamp(3px, 0.62vw, 10px)); }
.ice--near-c       { left: 58%;  top: 71%;  width: 22vw; opacity: .66; filter: blur(clamp(1.5px, 0.3vw, 5px)); }
.ice--splash-front { left: -11%; top: 25%;  width: 42vw; opacity: .48; filter: blur(clamp(2px, 0.36vw, 6px)); }


/* ===== 08e  SCENE 06 — REAL MAGIC ==========================
   The warm counter-scene. Carried by typography and light only — no
   imagery, no added asset weight.

   All light is built from soft radial ellipses that fade to fully
   transparent well inside their own box, so nothing can present a
   straight edge. The global film grain doubles as dithering, which is
   what keeps these large low-contrast gradients from banding. */

.scene--magic { height: 380vh; }

.glow {
  position: absolute;
  inset: -20%;
  pointer-events: none;
}
.glow span {
  position: absolute;
  display: block;
  border-radius: 50%;
  will-change: transform, opacity;
}

/* Placed with inset rather than a centring translate: GSAP owns
   `transform` on these and would clear a CSS translate. */
.glow__ember {
  inset: 8% -18% -22% -18%;
  background: radial-gradient(closest-side,
    rgba(90, 11, 11, .95), rgba(74, 10, 14, .48) 44%, rgba(74, 10, 14, 0) 74%);
}
.glow__core {
  inset: 20% 16% 18% 16%;
  background: radial-gradient(closest-side,
    rgba(227, 30, 36, .55), rgba(180, 18, 24, .22) 40%, rgba(180, 18, 24, 0) 72%);
}
.glow__spark {
  inset: 26% 56% 46% 20%;
  background: radial-gradient(closest-side,
    rgba(255, 138, 62, .42), rgba(255, 110, 40, .14) 38%, rgba(255, 110, 40, 0) 70%);
}

/* --- the two words -------------------------------------------------
   REAL sits behind the product and arrives out of depth; MAGIC sits in
   front and drifts the other way. The product ends up inside the type. */
.magic__word {
  position: absolute;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  font-size: var(--fs-magic);
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  color: var(--fg);
  will-change: transform, opacity;
}
.magic__word--real  { top: 16vh; left: -6%; }
.magic__word--magic { top: 48vh; right: -8%; text-align: right; }

/* --- the magic moment ----------------------------------------------
   A single soft bloom near the product, not a particle system. It peaks
   once in the middle of the scene and settles again. */
.bloom {
  position: absolute;
  inset: 24% 28% 28% 28%;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(255, 244, 232, .85), rgba(255, 158, 96, .34) 34%, rgba(244, 0, 9, 0) 70%);
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Two slow highlights crossing the frame — a camera catching the light,
   not a UI effect. Rotation is set from JS so it composes with the x
   travel instead of being cleared by it. */
.streak {
  position: absolute;
  width: 58vw;
  height: 16vh;
  border-radius: 50%;
  background: linear-gradient(100deg,
    rgba(255, 190, 150, 0), rgba(255, 205, 170, .20) 48%, rgba(255, 190, 150, 0));
  filter: blur(clamp(12px, 2vw, 34px));
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.streak--a { top: 30%; left: -30%; }
.streak--b { top: 62%; left: -20%; }

.magic__label {
  position: absolute;
  top: 14vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}

.magic__line {
  position: absolute;
  bottom: 12vh;
  left: var(--gutter);
  margin: 0;
  max-width: 20ch;
  font-size: clamp(1.05rem, 1.7vw, 1.75rem);
  line-height: 1.3;
  color: var(--fg);
  will-change: transform, opacity;
}
.magic__line em {
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-size: 1.12em;
}


/* ===== 08f  SCENE 07 — BRAND MOMENTS =======================
   Five photographic frames drifting through one space. A single sticky
   stage with an explicit z-index ladder, so typography interleaves with
   photography instead of sitting on top of it.

   z-index 2 on the stage itself: during the handover the first frame has
   to appear BEHIND scene 06's MAGIC (which is z3), as if it had been
   there all along. */

.scene--moments { height: 460vh; }

.moments__stage {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 100svh;
  overflow: clip;          /* frames leave the frame, not the document */
}

/* The colour field. Two soft radials; the red one takes over at the end
   as the party frame arrives. Opacity is driven from JS. */
.mo-light {
  position: absolute;
  inset: -15%;
  pointer-events: none;
  background:
    radial-gradient(60% 46% at 28% 30%, rgba(255, 168, 92, .16), rgba(255, 168, 92, 0) 70%),
    radial-gradient(70% 52% at 74% 78%, rgba(244, 0, 9, .20), rgba(244, 0, 9, 0) 72%);
  will-change: opacity;
}

/* --- the frames -----------------------------------------------------
   Every frame is a fixed aspect window with object-fit: cover, so each
   photograph can be cropped to the role it plays without shipping a
   second file. */
.mo-frame {
  position: absolute;
  margin: 0;
  overflow: hidden;
  will-change: transform, opacity, clip-path;
}
.mo-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* hero frame — 56vw stays under the file's native 910px at 1440 */
.mo-frame--roof   { z-index: 4; left: 7%;  top: 17%; width: 56vw; aspect-ratio: 910 / 533; }
/* back frame, deeper in the room, quiet */
.mo-frame--dinner { z-index: 2; left: 60%; top: 40%; width: 34vw; aspect-ratio: 623 / 533; }
/* vertical side frame — cropped to portrait by the container, not by a crop file */
.mo-frame--city   { z-index: 5; left: 2%;  top: 44%; width: 16vw; aspect-ratio: 3 / 4; }
.mo-frame--city img { object-position: 58% 50%; }
/* close-up punch */
.mo-frame--toast  { z-index: 7; left: 45%; top: 50%; width: 26vw; aspect-ratio: 1; }
/* final frame */
.mo-frame--party  { z-index: 8; left: 29%; top: 20%; width: 46vw; aspect-ratio: 517 / 489; }

/* --- typography ------------------------------------------------------
   Free-standing in the space: no boxes, no bars, no backgrounds. */
.mo-word {
  position: absolute;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  font-size: var(--fs-mo);
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  color: var(--fg);
  will-change: transform, opacity;
}
/* Low enough that the fixed navigation is never crossed, even before the
   upward drift starts. */
.mo-word--taste  { z-index: 3; left: -3%; top: 16%; }
.mo-word--the    { z-index: 6; left: 58%; top: 66%; font-family: 'Instrument Serif', Georgia, serif;
                   font-style: italic; font-weight: 400; text-transform: none;
                   letter-spacing: -0.01em; font-size: calc(var(--fs-mo) * 0.62); }
.mo-word--moment { z-index: 9; left: 3%;  top: 34%; }

.mo-label {
  position: absolute;
  z-index: 10;
  top: 14vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}


/* ===== 08g  SCENE 08 — CHOOSE YOUR ICON =====================
   The finale. One shared rhythm for all three variants — see
   scenes/final.js `step()` — so this is one visual system, not three.
   The background word sits at z1 (behind the global product, z2); OPEN
   in the finale sits at z3 (in front of it), matching the established
   OPEN/HAPPINESS grammar from scene 03. */

.scene--choose { height: 420vh; }

.choose__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
}

.choose-light {
  position: absolute;
  inset: -15%;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(62% 48% at 50% 46%, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 72%);
  will-change: opacity;
}

.choose-word {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  font-size: var(--fs-choose);
  color: var(--fg);
  opacity: .16;
  clip-path: inset(100% 0% 0% 0%);   /* wiped in by JS, one at a time */
  will-change: transform, opacity, clip-path;
}
/* HAPPINESS keeps the scene-03 grammar: outline instead of fill, so the
   finale reads as the same idea returning rather than a fourth product. */
.choose-word--happiness {
  color: transparent;
  opacity: 1;
  -webkit-text-stroke: clamp(1px, 0.14vw, 3px) var(--fg);
  /* Same defensive headroom as scene 03's fix: capped size, positioned so
     the full word height always clears the stage's overflow:clip edge. */
  top: 62%;
}

.choose-open {
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  top: 20vh;
  margin: 0;
  white-space: nowrap;
  font-family: 'Archivo', sans-serif;
  font-variation-settings: 'wdth' var(--wdth), 'wght' 900;
  font-weight: 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.03em;
  font-synthesis: none;
  font-size: var(--fs-choose-open);
  color: var(--fg);
  opacity: 0;
  will-change: transform, opacity;
}

.choose__note {
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: 12vh;
  translate: -50% 0;
  margin: 0;
  font-size: var(--fs-meta);
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--fg);
  opacity: 0;
  will-change: opacity, transform;
}

.choose__label {
  position: absolute;
  z-index: 3;
  top: 12vh;
  left: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1em;
}


/* ===== 08h  LEGAL & CREDITS ================================
   Quiet, but never faint: this is legal text and attribution, so
   contrast stays well above the minimum even at small sizes. It sits
   above the fixed stage (z3), which is what hides the product behind
   it as the footer scrolls up. */

.footer {
  position: relative;
  z-index: 3;
  background: var(--coke-red-deep);
  color: var(--cream);
  padding: clamp(56px, 12vh, 130px) var(--gutter) clamp(28px, 5vh, 54px);
  border-top: 1px solid rgba(244, 237, 228, .18);
}

.footer__eyebrow {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--fs-meta);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--cream);
}
.footer__meta-line {
  grid-column: 1 / -1;
  margin: .5em 0 0;
  font-size: var(--fs-meta);
  letter-spacing: .04em;
  color: rgba(244, 237, 228, .58);
}
.footer__meta-line--ai { margin-bottom: clamp(20px, 4vh, 40px); }

.footer__inner {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(28px, 4vh, 56px) var(--gutter);
  align-items: start;
}

.footer__mark {
  grid-column: 1 / -1;
  margin: 0 0 clamp(16px, 4vh, 44px);
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
  font-size: clamp(2rem, 6vw, 4.5rem);
  line-height: 1;
  color: var(--cream);
  opacity: .28;
}

.footer__block { grid-column: span 6; }

.footer__h {
  margin: 0 0 1.4em;
  opacity: 1;
  color: var(--cream);
}

.footer__text {
  max-width: 56ch;
  margin: 0 0 1em;
  /* Deliberately larger than the meta type: it has to be read, not noticed. */
  font-size: clamp(0.8125rem, 0.35vw + 0.72rem, 0.9375rem);
  line-height: 1.65;
  color: rgba(244, 237, 228, .82);
}
.footer__text strong {
  color: var(--cream);
  font-variation-settings: 'wdth' 100, 'wght' 700;
}

.credits { margin: 0; padding: 0; list-style: none; }
.credits__item {
  display: grid;
  gap: .15em;
  padding: .9em 0;
  border-top: 1px solid rgba(244, 237, 228, .16);
  font-size: clamp(0.8125rem, 0.3vw + 0.73rem, 0.9375rem);
  line-height: 1.5;
}
.credits__item:last-child { border-bottom: 1px solid rgba(244, 237, 228, .16); }

.credits__file {
  font-variation-settings: 'wdth' 92, 'wght' 600;
  letter-spacing: .04em;
  color: var(--cream);
}
.credits__by { color: rgba(244, 237, 228, .82); }
.credits__use {
  font-size: var(--fs-meta);
  text-transform: uppercase;
  letter-spacing: .16em;
  color: rgba(244, 237, 228, .5);
}

.credits a {
  color: var(--cream);
  text-decoration: underline;
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
  transition: opacity var(--dur-touch) var(--ease-snap);
}
.credits a:hover { opacity: .65; }

.footer__base-group { display: flex; flex-wrap: wrap; gap: .6em 2em; }

/* Studio signature — quiet, no CTA styling, just a slightly heavier name. */
.footer__signature {
  font-variation-settings: 'wdth' 100, 'wght' 500;
  color: rgba(244, 237, 228, .7);
}
.footer__signature strong {
  color: var(--cream);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  letter-spacing: .02em;
}

.footer__base {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .6em 2em;
  margin: clamp(20px, 4vh, 44px) 0 0;
  padding-top: clamp(16px, 2.5vh, 28px);
  border-top: 1px solid rgba(244, 237, 228, .16);
  font-size: var(--fs-meta);
  text-transform: uppercase;
  letter-spacing: .18em;
  color: rgba(244, 237, 228, .55);
}


/* ===== 09  RESPONSIVE ====================================== */

/* --- Tablet: 768–1199px ---------------------------------- */
@media (max-width: 1199px) {
  :root {
    --product-h: 60vh;
    --fs-display: clamp(3.5rem, 17vw, 12rem);
  }
  .hl--taste   { top: 15vh; }
  .hl--feeling { bottom: 10vh; }
  .hero__the   { top: 38%; left: 36%; }
  .nav__links  { gap: 22px; }

  /* Scene 02: the product is proportionally smaller here, so the numeral
     has to travel further left for its closing 6 to still cross the
     bottle — the sandwich only exists where the two actually meet. */
  :root            { --fs-mega: clamp(6rem, 47vw, 40rem); }
  .mega            { top: 31vh; left: -15%; }
  .classic__title  { top: 23vh; left: 8%; }
  .classic__lead   { top: 66vh; left: 16%; max-width: 22ch; }
}

/* --- Mobile: < 768px --------------------------------------
   A deliberately different composition, not a shrunk desktop:
   the product sits in a clear vertical corridor between the two
   headline words, and the width axis narrows so FEELING still
   holds the line. --------------------------------------------- */
@media (max-width: 767px) {
  :root {
    --wdth: 100;
    --fs-display: clamp(3.25rem, 19vw, 6rem);
    --fs-the:     clamp(2.25rem, 13vw, 4.5rem);
    --fs-mega:    clamp(5rem, 46vw, 16rem);
    --product-h:  46vh;
  }

  .hl--taste   { top: 13vh;    left: var(--gutter); }
  .hl--feeling { bottom: 13vh; right: var(--gutter); }

  /* Offset, not centred: centred it lands flat on the label band and
     the word reads as part of the artwork instead of in front of it. */
  .hero__the {
    top: 40%;
    left: 24%;
  }

  .hero__ribbon { height: 30vh; opacity: .12; }

  .nav__links { display: none; }        /* the overlay is the nav here */
  .nav__word  { font-size: .9em; }
  .nav__menu-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

  .hero__meta--note { display: none; }  /* keep the cue alone at the foot */

  /* --- Scene 02 on mobile: its own vertical composition.
     Label and SINCE ride high, the numeral crosses the middle behind
     the bottle, lead and caption sit low. Nothing is a shrunk desktop. */
  .scene--classic  { height: 210vh; }
  .mega            { top: 38vh; left: -22%; }
  .classic__label  { top: 14vh; }
  .classic__title  { top: 19vh; left: var(--gutter); }
  /* Sits in the clear band below the bottle — see PRODUCT_KEYS.classicEnd. */
  .classic__lead   { top: 74vh; left: var(--gutter); right: var(--gutter); max-width: 26ch; }
  /* Back to horizontal here: the mobile bottle is short enough to leave
     the bottom edge clear, and a vertical spine at 390px is cramped. */
  .classic__fig    { top: auto; bottom: 8vh; right: var(--gutter); writing-mode: horizontal-tb; }

  /* --- Scene 03 on mobile.
     The outline word bleeds off the right only: cutting it on both sides
     at this width leaves too few whole letterforms to read as a word. */
  .scene--happiness { height: 230vh; }
  :root {
    --fs-happy-back:  clamp(3rem, 27vw, 9rem);
    --fs-happy-front: clamp(2.5rem, 22vw, 7rem);
  }
  /* Base positions allow for the upward parallax without the label
     riding into the navigation when the user scrolls back up. */
  .happy--back    { top: 52vh; left: var(--gutter); }
  .happy--front   { top: 30vh; }   /* far enough down to still clip the bottle */
  .happy__label   { top: 22vh; }

  /* --- Scene 04 on mobile.
     At 15vw the flavour names read as subheads. They have to stay display
     type here too, which means accepting a harder bleed. */
  .scene--flavours { height: 340vh; }
  :root { --fs-flav: clamp(2.5rem, 22vw, 8rem); }

  .flav__label          { top: 13vh; }
  .flav__name--original { top: 52vh; left: -4%; }
  .flav__name--zero     { top: 18vh; right: -4%; }
  .flav__name--cherry   { top: 30vh; }
  .flav__note           { bottom: 11vh; max-width: 24ch; }

  /* --- Scene 05 on mobile.
     Fewer, larger elements. Eight pieces of ice that each read at 1440
     become eight small smudges at 400 — the composition survives thinning,
     the atmosphere does not survive clutter. */
  .scene--ice { height: 330vh; }
  :root { --fs-ice: clamp(3rem, 26vw, 9rem); }

  .ice--far-b, .ice--near-c { display: none; }

  .ice--far-a        { left: 3%;   top: 9%;   width: 26vw; }
  .ice--far-c        { left: 6%;   top: 76%;  width: 74vw; opacity: .3; }
  .ice--splash-back  { left: 6%;   top: 36%;  width: 92vw; opacity: .36; }
  .ice--near-a       { left: -18%; top: 62%;  width: 58vw; }
  .ice--near-b       { left: 58%;  top: -8%;  width: 62vw; }
  .ice--splash-front { left: -22%; top: 24%;  width: 78vw; }

  /* --- Scene 06 on mobile.
     Fewer depth layers and softer light, per the brief. The type is meant
     to be hard-cropped here — that is the mobile composition, not a
     shrunken desktop one. */
  .scene--magic { height: 320vh; }
  :root { --fs-magic: clamp(3.5rem, 34vw, 12rem); }

  .glow__spark, .streak--b { display: none; }   /* one light source fewer */
  .glow__core  { inset: 26% 6% 24% 6%; }
  .bloom       { inset: 32% 14% 36% 14%; }
  .streak--a   { height: 12vh; filter: blur(clamp(10px, 3vw, 18px)); }

  .magic__word--real  { top: 20vh; left: -10%; }
  .magic__word--magic { top: 46vh; right: -12%; }
  .magic__label       { top: 16vh; }
  .magic__line        { bottom: 14vh; max-width: 24ch; }

  /* --- Scene 07 on mobile: its own art direction, not a shrunk desktop.
     Never more than two frames at once, no miniatures, and the close-up
     goes nearly full bleed. The dinner frame is dropped entirely — its
     role is "deep in the room", which is exactly the role that stops
     working at this size. */
  .scene--moments { height: 400vh; }
  :root { --fs-mo: clamp(2.75rem, 26vw, 9rem); }

  .mo-frame--dinner { display: none; }

  .mo-frame--roof  { left: 6%;  top: 20%; width: 88vw; }
  .mo-frame--city  { left: 46%; top: 40%; width: 46vw; }
  .mo-frame--toast { left: 4%;  top: 26%; width: 92vw; }
  .mo-frame--party { left: 4%;  top: 22%; width: 92vw; }

  .mo-word--taste  { left: -6%; top: 16%; }
  .mo-word--the    { left: 8%;  top: 70%; font-size: calc(var(--fs-mo) * 0.7); }
  .mo-word--moment { left: -8%; top: 40%; }
  .mo-label        { top: 12vh; }

  /* --- Scene 08 on mobile.
     One dominant product, no rotation-heavy handovers, HAPPINESS given
     extra clearance so it stays fully readable at every step. */
  .scene--choose { height: 360vh; }
  :root {
    --fs-choose:      clamp(3rem, 24vw, 8rem);
    --fs-choose-open: clamp(2.75rem, 20vw, 6.5rem);
  }
  .choose-word--happiness { top: 56%; }
  .choose-open  { top: 16vh; }
  .choose__label { top: 10vh; }
  .choose__note  { bottom: 9vh; }

  .footer__block   { grid-column: 1 / -1; }
  .footer__base    { flex-direction: column; }

  .menu { padding: 18vh var(--gutter) var(--gutter); }
}

/* --- Very narrow: 390px and below -------------------------- */
@media (max-width: 400px) {
  :root { --fs-display: 18vw; --product-h: 42vh; }
  .hl--taste   { top: 14vh; }
  .hl--feeling { bottom: 15vh; }
  .hero__the   { left: 28%; }   /* keep the overlap with the bottle readable */
  .mega        { left: -26%; }
}

/* --- Short landscape phones -------------------------------- */
@media (max-height: 560px) and (orientation: landscape) {
  :root { --product-h: 74vh; --fs-display: clamp(2.5rem, 9vw, 6rem); }
  .hl--taste   { top: 9vh; }
  .hl--feeling { bottom: 7vh; }
}

/* Coarse pointers get no hover-only affordances — and no full-viewport
   blend layer, which the compositor would otherwise re-blend every frame. */
@media (hover: none) {
  .nav__link::after { display: none; }
  .menu__inner:hover .menu__link { opacity: 1; }
  body::after { display: none; }
}


/* ===== 10  REDUCED MOTION ================================== */

@media (prefers-reduced-motion: reduce) {
  .hero__cue-line { animation: none; transform: scaleX(1); }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }

  /* Nothing should be pre-hidden if we are not going to animate it in. */
  .js [data-anim] { opacity: 1; }
}
