/* ============================================================================
   Cadbury — "A glass and a half, poured, set & wrapped"
   Hyperion Studio capability concept · handcrafted static CSS (no framework).
   Brand tokens verified against the real C Club / & More creatives.
   ============================================================================ */

:root{
  /* Cadbury purple — Pantone 2685 C is the trademarked field. Brighter web tone is digital. */
  --purple:#330072;        /* Pantone 2685 C — verify exact production value at sign-off */
  --purple-web:#4e008e;    /* brighter digital purple */
  --purple-lift:#6a2a9e;   /* spotlight lift */
  --purple-deep:#1d0040;
  --night:#0e0020;

  /* Gold script wordmark gradient — PMS 7502 C -> 465 C */
  --gold-1:#f4e6b8; --gold-2:#dec28b; --gold-3:#b18d58;
  --gold-grad:linear-gradient(100deg,var(--gold-3),var(--gold-1) 45%,var(--gold-2) 70%,var(--gold-3));

  --cream:#f7efe2; --white:#ffffff;

  /* Milk chocolate render tones */
  --c-hi:#9a6a3e; --c-mid:#5e3d23; --c-lo:#3a2113; --c-deep:#23130a;

  /* Machinery (Factory hero) */
  --steel-1:#43464f; --steel-2:#22242b; --steel-3:#14151a;

  --rim:rgba(222,194,139,.55);   /* gold rim-light on machinery */
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
/* Lenis smooth-scroll support (initLenis in main.js). Lenis sets these classes on <html>
   while active; the overrides keep native anchored/smooth scroll out of its interpolation. */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}
body{font-family:"Hanken Grotesk",sans-serif;background:var(--night);color:var(--cream);
  overflow-x:hidden;-webkit-font-smoothing:antialiased;line-height:1.6}
.disp{font-family:"Fraunces",serif}
img{max-width:100%;display:block}
a{color:inherit}
.wrap{max-width:1160px;margin:0 auto;padding-inline:28px}
main{position:relative;z-index:2}
.gold-text{background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;color:transparent}

/* film grain — NOTE: no mix-blend-mode. An `overlay`/`soft-light` blend on this
   fixed full-page layer seams against the sticky .show-bg compositing layer
   (a hard horizontal band in the showcase). Plain low-opacity noise avoids it. */
.grain{position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.05;transform:translateZ(0);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* ---- nav ---- */
nav{position:fixed;top:0;left:0;right:0;z-index:50;display:flex;align-items:center;justify-content:space-between;
  padding-block:16px;padding-inline:34px;background:linear-gradient(rgba(14,0,32,.92),transparent);
  transition:background .4s ease,padding .4s ease}
nav.solid{background:rgba(14,0,32,.92);padding-block:11px;box-shadow:0 6px 24px -10px rgba(0,0,0,.7);backdrop-filter:blur(8px)}
.brandlink{display:inline-flex;text-decoration:none}
.brand{height:30px;filter:brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(640%) hue-rotate(2deg) brightness(95%)}
.brand-fallback{font-family:"Fraunces";font-weight:600;font-size:24px;color:var(--gold-2)}
.navlinks{display:flex;gap:28px;align-items:center;font-weight:600;font-size:13px;letter-spacing:.06em;text-transform:uppercase}
.navlinks a{color:var(--cream);text-decoration:none;opacity:.78;transition:.25s}
.navlinks a:hover{opacity:1;color:var(--gold-1)}
.navpill{background:var(--gold-grad);color:var(--purple-deep)!important;opacity:1!important;font-weight:800;
  padding:9px 18px;border-radius:100px;letter-spacing:.03em}
.navpill:hover{filter:brightness(1.06)}
@media(max-width:820px){.navlinks a:not(.navpill){display:none}.navpill{padding:8px 15px;font-size:12px}}

/* Rolling: default visible; the .js gate hides until the scrubber places each element. */
/* No permanent will-change: 120+ reveals were each forced into their own GPU layer
   (≈100 composited layers at rest → heavy on weak/shared GPUs). They fade once on entry
   then sit static, so a layer buys nothing. The scrubber still animates them; settled
   text renders with default subpixel AA. */
.reveal{opacity:1}
.js .reveal{opacity:0}

/* ====================== SCROLL-SCRUB VIDEO HERO (active) ====================== */
.heroscrub{position:relative;height:300vh}
.heroscrub-stage{position:sticky;top:0;height:100vh;width:100%;overflow:clip;background:#0a0014}
.heroseq,.heroscrub-poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.heroseq{z-index:2;opacity:0}     /* hidden until the morph crossfades it in */
.heroscrub-poster{z-index:1;transition:opacity .4s ease}
.heroscrub-cue{position:absolute;left:0;right:0;bottom:7%;z-index:8;display:flex;flex-direction:column;align-items:center;gap:12px;
  font-size:12px;font-weight:700;letter-spacing:.34em;text-transform:uppercase;color:var(--gold-1);text-shadow:0 2px 10px rgba(0,0,0,.45);pointer-events:none}
.heroscrub-cue .rule{width:48px;height:1px;background:linear-gradient(90deg,transparent,var(--gold-2),transparent)}
.heroscrub-cue .chev{font-size:17px;animation:bob 2.2s ease-in-out infinite}
.rm .heroscrub-cue .chev{animation:none}

/* bottom blend — feather the video's lower edge so the dark hero dissolves into
   the brand purple of the showcase below instead of ending on a hard seam.
   Variants (.blend-*) are swappable live in _scratch/transition-lab.html. */
.heroscrub-stage::after{content:"";position:absolute;left:0;right:0;bottom:0;height:34vh;z-index:6;pointer-events:none;
  background:linear-gradient(to top,var(--purple-deep) 0%,rgba(29,0,64,0) 100%)}
.heroscrub.blend-deep .heroscrub-stage::after{height:50vh;
  background:linear-gradient(to top,var(--night) 0%,rgba(14,0,32,0) 100%)}
.heroscrub.blend-gold .heroscrub-stage::before{content:"";position:absolute;left:0;right:0;bottom:32vh;height:2px;z-index:7;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(222,194,139,.55),transparent);filter:blur(.4px)}
.heroscrub.blend-none .heroscrub-stage::after{display:none}

/* top blend — the hero above is purple; feather the interlude's black scene in
   from purple-deep at the very top so the cut from foil → shatter reads as one
   continuous scene rather than a hard seam. Subtle; sits below the text + cue. */
.heroscrub-topblend{position:absolute;left:0;right:0;top:0;height:22vh;z-index:6;pointer-events:none;
  background:linear-gradient(to bottom,var(--purple-deep) 0%,rgba(29,0,64,.35) 42%,rgba(29,0,64,0) 100%)}

/* Option C end-of-shatter line — light Fraunces + gold italic script accent.
   Driven by the scrubber: fades up once the shatter holds on the black frame. */
.scrub-text{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);z-index:7;
  text-align:center;padding:0 6vw;opacity:0;will-change:opacity,transform;pointer-events:none}
.scrub-text .eyebrow{margin-bottom:20px}
.scrub-line{font-family:"Fraunces";font-weight:300;line-height:1.08;color:var(--white);
  font-size:clamp(34px,5.6vw,82px);letter-spacing:-.005em}
.scrub-line .gen{font-style:italic;font-weight:500;font-size:1.06em}

/* ===== story copy track — Heritage lines, fade + rise, centred, one→next ===== */
.story{position:absolute;inset:0;z-index:7;pointer-events:none}
.s-line{position:absolute;left:50%;top:50%;width:min(56vw,760px);text-align:center;opacity:0;will-change:opacity,transform}
.s-line .eye{display:block;font:700 12px/1 "Hanken Grotesk";letter-spacing:.42em;text-transform:uppercase;color:var(--gold-2);margin-bottom:18px}
/* drop-shadow (NOT text-shadow) so it layers correctly under the gradient-clipped gold */
.s-line .ln{display:block;font-family:"Fraunces";font-weight:300;color:var(--white);line-height:1.1;
  font-size:clamp(34px,4.8vw,76px);letter-spacing:-.005em;
  filter:drop-shadow(0 2px 16px rgba(8,0,20,.72)) drop-shadow(0 1px 5px rgba(8,0,20,.85))}
/* vertical metallic gold — even sheen on any word (the old horizontal grad went dull on short words) */
.s-line .g,.s-line .gi{background:linear-gradient(180deg,#f8edc8 0%,#e8c578 50%,#cb9c4f 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.s-line .gi{font-style:italic;font-weight:500}
@media(max-width:900px){.s-line{width:min(86vw,440px)}.s-line .ln{font-size:clamp(30px,8vw,46px)}}

/* travelling scrim behind the copy while the bright bar fills the screen */
.story-scrim{position:absolute;inset:0;z-index:6;pointer-events:none;opacity:0;
  background:radial-gradient(56vw 42vh at 50% 50%,rgba(8,0,20,.82),rgba(8,0,20,.3) 58%,rgba(8,0,20,0) 80%)}

/* constant keep-scrolling cue — pinned near the TOP, with a soft dark halo so it POPS over the bright bar */
.scroll-cue{position:absolute;left:0;right:0;top:84px;z-index:8;display:flex;flex-direction:column;align-items:center;gap:10px;pointer-events:none;opacity:0;
  font:800 11.5px/1 "Hanken Grotesk";letter-spacing:.38em;text-transform:uppercase;color:var(--gold-1);
  text-shadow:0 1px 3px rgba(8,0,20,.95),0 2px 16px rgba(8,0,20,.78)}
/* soft dark halo behind the cue — lifts it off whatever bright frame is behind it without a hard box */
.scroll-cue::before{content:"";position:absolute;left:50%;top:48%;transform:translate(-50%,-50%);width:240px;height:150px;z-index:-1;pointer-events:none;
  background:radial-gradient(closest-side,rgba(8,0,20,.68),rgba(8,0,20,0) 78%)}
@media(max-width:820px){.scroll-cue{top:72px}.scroll-cue::before{width:200px}}
.scroll-cue .rule{width:2px;height:30px;border-radius:2px;background:linear-gradient(var(--gold-1),rgba(244,230,184,0));box-shadow:0 0 8px rgba(244,230,184,.5)}
.scroll-cue .ch{font-size:16px;text-shadow:0 1px 3px rgba(8,0,20,.95),0 0 12px rgba(244,230,184,.4);animation:bob 2.1s ease-in-out infinite}
.rm .scroll-cue .ch{animation:none}

/* mobile: same full-bleed cover as desktop (object-fit:cover centre-crops the
   landscape footage) — kept consistent across breakpoints for now. A 90° rotation
   to fit more of the bar in portrait was trialled and parked (see handoff). */
@media(max-width:900px){
  .heroscrub{height:230vh}
  .heroscrub-stage::after{height:26vh}
}

/* ============================ THE ACT — unwrap → morph → shatter (one stage) ============================ */
.hero-wrap{position:relative;height:450vh}   /* desktop: bar (first frame) → morph → shatter → line */
.hero-stage{position:sticky;top:0;height:100vh;overflow:hidden;background:#0a0014;contain:layout paint}

/* ── DESKTOP vs MOBILE hero variants ──────────────────────────────────────────────
   Desktop = bar-as-first-frame (no wrapper). Mobile = the original foil-unwrap intro.
   The foil elements live in the DOM always; they're hidden on desktop and the bar-first
   ambient is hidden on mobile. The mobile act needs extra scroll room for the unwrap. */
.foil,.uw-dust,.uw-seam{display:none}                 /* desktop: no foil */
@media(max-width:900px){
  .hero-wrap{height:480vh}                            /* room for unwrap + morph + shatter */
  .amb-layer{display:none}                            /* mobile uses the foil's own dust, not the bar ambient */
  .foil{display:block}
  .uw-dust,.uw-seam{display:block}
}
/* purple stage backdrop — fades to the near-black stage bg as the bar morphs into the shatter */
.uw-bg{position:absolute;inset:0;z-index:0;
  background:radial-gradient(68vw 70vh at 50% 38%,var(--purple-lift),var(--purple) 50%,var(--purple-deep) 100%)}

/* ambient first-frame motion behind the bar — drifting gold dust + breathing aura glows */
.amb-layer{position:absolute;inset:0;z-index:1;pointer-events:none;overflow:hidden;will-change:opacity;contain:layout paint}
/* NO filter blur: a filter:blur() forces the drifting layer to re-rasterize the blur every
   frame (profiled — blur(70px) = ~760ms/s LoAF / 47fps in the hero; blur(24px) barely better;
   filter:none = ~340ms/s / 59fps). The glow is already a soft radial-gradient, so the blur was
   near-redundant — we recover its diffuseness by fading the gradient all the way to the edge and
   enlarging ~17% (centres unchanged). will-change:transform keeps the slow drift compositor-only. */
.amb-aura{position:absolute;border-radius:50%;will-change:transform}
.amb-aura.b1{left:20%;top:26%;width:56vw;height:56vh;background:radial-gradient(closest-side,rgba(168,96,224,.42),transparent);animation:ambDrift1 19s ease-in-out infinite}
.amb-aura.b2{right:14%;top:40%;width:50vw;height:50vh;background:radial-gradient(closest-side,rgba(120,60,180,.38),transparent);animation:ambDrift2 24s ease-in-out infinite}
.amb-aura.b3{left:38%;top:16%;width:42vw;height:44vh;background:radial-gradient(closest-side,rgba(244,230,184,.12),transparent);animation:ambDrift3 16s ease-in-out infinite}
@keyframes ambDrift1{0%,100%{transform:translate(-8%,-4%) scale(1)}50%{transform:translate(10%,7%) scale(1.16)}}
@keyframes ambDrift2{0%,100%{transform:translate(6%,4%) scale(1.05)}50%{transform:translate(-9%,-6%) scale(.9)}}
@keyframes ambDrift3{0%,100%{transform:translate(0,0) scale(1);opacity:.8}50%{transform:translate(4%,-5%) scale(1.2);opacity:1}}
.amb-mote{position:absolute;border-radius:50%;background:radial-gradient(circle,#fff7df,#dec28b);box-shadow:0 0 8px #f4e6b8;opacity:0;animation:ambMote linear infinite}
@keyframes ambMote{0%{transform:translateY(30px) scale(.7);opacity:0}14%{opacity:.85}80%{opacity:.5}100%{transform:translateY(-140px) scale(1);opacity:0}}
/* freeze ambient drift while actively scrolling (class toggled in main.js) so the GPU isn't
   re-blending these full-viewport layers every frame on top of the scroll — the dominant
   fill-rate cost on wide windows / integrated GPUs. Resumes the instant scrolling stops;
   imperceptible in motion (everything is moving anyway). */
html.scrolling .amb-aura,html.scrolling .amb-mote{animation-play-state:paused}
.rm .amb-layer{display:none}   /* reduce-motion: no ambient loop */
/* bottom blend — feathers the dark shatter scene into the showcase purple below
   (JS fades it in as the background darkens, so it only shows once we're in the dark scene) */
.act-blend{position:absolute;left:0;right:0;bottom:0;height:34vh;z-index:6;pointer-events:none;opacity:0;
  background:linear-gradient(to top,var(--purple-deep) 0%,rgba(29,0,64,0) 100%)}
/* promoted to its own compositor layer so the 230px inset blur rasterizes ONCE
   instead of repainting every frame while it rides the sticky stage (pixel-identical) */
.vignette{position:absolute;inset:0;pointer-events:none;box-shadow:inset 0 0 230px 80px rgba(8,0,20,.72);z-index:9;transform:translateZ(0)}

/* the scene revealed behind the foil */
.uw-scene{position:absolute;inset:0;z-index:1;display:grid;place-items:center}
.uw-glow{position:absolute;left:50%;top:42%;transform:translate(-50%,-50%);width:min(54vw,560px);height:min(54vw,560px);pointer-events:none;
  background:radial-gradient(closest-side,rgba(255,238,205,.22),rgba(160,80,200,.12) 52%,transparent 74%)}
/* the revealed chocolate — real Cadbury block, foil peeled, isolated on transparent
   so it floats on the stage with a soft shadow; same id #uwBar the scrubber animates.
   Capped by BOTH axes so it can never exceed the stage on any viewport. */
.uw-choc{position:relative;height:min(62vh,600px);max-width:86vw;opacity:0;will-change:transform;
  filter:drop-shadow(0 34px 52px rgba(0,0,0,.5)) drop-shadow(0 8px 16px rgba(0,0,0,.38))}
/* per-frame colour grade lives here (saturate/sepia/brightness, NO blur) so the
   figure's cached drop-shadow above is only composite-transformed, never re-blurred */
.uw-choc img{display:block;height:100%;width:auto;max-width:86vw;object-fit:contain;will-change:filter}
.uw-head{position:absolute;bottom:9%;left:0;right:0;text-align:center;padding-inline:24px;pointer-events:none;opacity:0;z-index:2}
.uw-head .cta{pointer-events:auto}

/* purple foil halves — exactly 50% each so they meet cleanly at the seam with
   no overlap (the centred logo + cue reconstruct as one image) */
.foil{position:absolute;top:0;bottom:0;width:50%;z-index:3;overflow:hidden;will-change:transform;
  /* recognizable Cadbury Dairy Milk purple — bright digital 2685 C, near-uniform
     field with the etched tone-on-tone wrapper pattern + a soft satin lift up top
     (printed flow-wrap, not crinkled foil) */
  background:
    url("assets/pattern/wrapper-pattern.svg") 0 0 / 360px 360px repeat,
    radial-gradient(120% 78% at 50% 26%,rgba(150,72,205,.28),transparent 68%),
    linear-gradient(180deg,#5412a0 0%,#4e008e 32%,#46007e 68%,#3a0068 100%)}
.foil.l{left:0;box-shadow:inset -22px 0 50px -34px rgba(0,0,0,.55)}
.foil.r{right:0;box-shadow:inset 22px 0 50px -34px rgba(0,0,0,.55)}
/* smooth satin wrapper sheen — a single broad gloss sweep + soft top light;
   no repeating crinkle (Dairy Milk packs read as smooth printed plastic) */
.foil-sheen{position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(116deg,transparent 41%,rgba(255,245,225,.10) 48%,rgba(255,255,255,.16) 51%,rgba(255,245,225,.09) 54%,transparent 62%),
    radial-gradient(70% 50% at 50% 16%,rgba(255,244,214,.12),transparent 60%)}

/* the centred label, printed across the seam: each half holds a copy whose box
   is 200% of the (50%-wide) foil = 100% of the stage, anchored to the seam edge,
   so BOTH copies centre their content on the exact same physical pixel (the
   seam). Using % — not vw — keeps it consistent with the %-sized foils, so the
   scrollbar doesn't offset the two copies (that mismatch cut the seam glyph). */
.foil-label{position:absolute;top:0;height:100%;width:200%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:min(2.4vh,26px);pointer-events:none}
.foil.l .foil-label{left:0}
.foil.r .foil-label{right:0}

/* The Cadbury Dairy Milk lockup — built from the REAL brand artwork: gold Cadbury
   script (SVG) + the actual white DAIRY MILK wordmark (lifted off-pack) + the white
   glass-and-a-half. Sized as ONE unit off --lw, which is capped by the SHORTER
   viewport axis (vh) so the lockup can never clip, overflow, or blow up on a
   wide/short window — the failure that broke the previous build. */
.dm-lockup{--lw:min(42vw,47vh,500px);display:flex;flex-direction:column;align-items:center;width:var(--lw)}
.dm-cad{width:66%;height:auto;
  filter:brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(640%) hue-rotate(2deg) brightness(95%) drop-shadow(0 8px 20px rgba(0,0,0,.45))}
.dm-wm{width:97%;height:auto;margin-top:calc(var(--lw)*.02);filter:drop-shadow(0 8px 22px rgba(0,0,0,.34))}
.dm-glass{width:26%;height:auto;margin-top:calc(var(--lw)*.045);filter:drop-shadow(0 6px 14px rgba(0,0,0,.32))}
.dm-sub{margin-top:calc(var(--lw)*.035);font-family:"Hanken Grotesk";font-weight:800;text-transform:uppercase;
  letter-spacing:.34em;font-size:calc(var(--lw)*.044);color:#fff;opacity:.94;padding-left:.34em}

.uw-cue{display:flex;flex-direction:column;align-items:center;gap:12px;font-size:12px;font-weight:700;letter-spacing:.34em;text-transform:uppercase;color:var(--gold-1);text-shadow:0 2px 10px rgba(0,0,0,.4)}
.uw-cue .rule{width:48px;height:1px;background:linear-gradient(90deg,transparent,var(--gold-2),transparent)}
.uw-cue .chev{font-size:17px;animation:bob 2.2s ease-in-out infinite}

/* idle gold dust drifting up the closed wrapper (the only idle motion kept) */
.uw-dust{position:absolute;inset:0;z-index:4;pointer-events:none}
.uw-dust i{position:absolute;width:4px;height:4px;border-radius:50%;background:radial-gradient(circle,#fff7df,#dec28b);box-shadow:0 0 8px #f4e6b8;opacity:.5;animation:uwDrift linear infinite}
@keyframes uwDrift{0%{transform:translateY(10px);opacity:0}15%{opacity:.6}100%{transform:translateY(-60px);opacity:0}}

/* centre seam glint */
.uw-seam{position:absolute;top:0;bottom:0;left:50%;width:3px;transform:translateX(-50%);z-index:5;pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(255,250,225,.85),transparent);box-shadow:0 0 28px 8px rgba(244,230,184,.55)}

/* generic copy (used by .uw-head) */
.script{font-family:"Fraunces";font-style:italic;font-size:clamp(20px,2.4vw,30px);margin-bottom:8px}
.uw-head h1{font-family:"Fraunces";font-weight:600;font-size:clamp(32px,5vw,64px);line-height:1.0;color:#fff}
.uw-head h1 em{font-style:italic;color:var(--gold-1)}
.uw-head .cta{display:inline-block;margin-top:20px;background:var(--gold-grad);color:var(--purple-deep);font-weight:800;font-size:14px;letter-spacing:.04em;padding:14px 30px;border-radius:100px;text-decoration:none;box-shadow:0 10px 24px -8px rgba(0,0,0,.5)}
@keyframes bob{50%{transform:translateY(7px)}}

/* ============================ RIBBON ============================ */
.ribbon{border-top:1px solid rgba(222,194,139,.25);border-bottom:1px solid rgba(222,194,139,.25);padding-block:20px;overflow:hidden;white-space:nowrap;background:var(--purple-deep);position:relative;z-index:2}
.ribbon span{display:inline-block;font-family:"Fraunces";font-style:italic;font-size:25px;padding-right:46px;animation:slide 28s linear infinite}
@keyframes slide{to{transform:translateX(-100%)}}

/* ============================ SECTIONS ============================ */
section.s{padding-block:120px;position:relative;z-index:2}
.eyebrow{font-weight:700;font-size:12px;letter-spacing:.3em;text-transform:uppercase;margin-bottom:16px}
h2{font-family:"Fraunces";font-weight:600;font-size:clamp(34px,5.2vw,68px);line-height:1.02;letter-spacing:-.01em}
h2 em{font-style:italic}
.lede{font-size:18px;color:rgba(247,239,226,.78);max-width:54ch;margin-top:18px}
.steps{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-top:48px}
@media(max-width:880px){.steps{grid-template-columns:1fr 1fr}}
.step{border:1px solid rgba(222,194,139,.22);border-radius:16px;padding:22px 18px;background:linear-gradient(160deg,rgba(78,0,142,.4),rgba(29,0,64,.5))}
.step .n{font-family:"Fraunces";font-size:30px;font-weight:600}
.step h4{font-size:15px;margin-top:8px;text-transform:uppercase;letter-spacing:.04em}
.step p{font-size:12.5px;color:rgba(247,239,226,.62);margin-top:5px}

/* ============================ SPOTLIGHT REVEALS ============================ */
.showcase{position:relative;z-index:2}
/* fixed full-viewport morph layer — always covers the viewport (no sticky-edge
   gap/band). The scrubber fades it in only while the showcase is on screen, so
   it never bleeds over the hero or the sections below. */
.show-bg{position:fixed;inset:0;z-index:0;opacity:0;transition:opacity .35s ease;
  background:radial-gradient(80vw 80vh at 60% 30%,var(--purple-lift),var(--purple) 50%,var(--purple-deep))}
/* stacked gradient layers — the JS cross-fades the incoming section colour over the outgoing */
.show-bg .mbg{position:absolute;inset:0;opacity:0;transition:opacity .7s ease}
.show-tex{position:absolute;inset:0;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

.srail{position:fixed;top:50%;right:24px;transform:translateY(-50%);z-index:40;display:flex;flex-direction:column;gap:14px;align-items:flex-end;opacity:0;transition:opacity .4s ease;pointer-events:none}
.srail.show{opacity:1;pointer-events:auto}
@media(max-width:900px){.srail{display:none}}
.srail a{display:flex;align-items:center;gap:10px;text-decoration:none;color:rgba(247,239,226,.5);font-size:12px;font-weight:700;letter-spacing:.02em;transition:.3s}
.srail a .dash{width:18px;height:2px;background:currentColor;transition:.3s}
.srail a.on{color:var(--gold-1)}.srail a.on .dash{width:40px;height:3px}
.srail a .nm{opacity:0;transform:translateX(6px);transition:.3s}
.srail a.on .nm,.srail a:hover .nm{opacity:1;transform:none}

.show-intro{position:relative;z-index:3;min-height:78vh;display:grid;place-content:center;text-align:center;padding-inline:24px}
.show-intro .k{font-weight:700;letter-spacing:.3em;text-transform:uppercase;font-size:12px;margin-bottom:16px}
.show-intro h2{font-size:clamp(40px,7vw,96px);line-height:.96}
.show-intro p{margin:18px auto 0;color:rgba(247,239,226,.82);max-width:54ch;font-size:17px}

/* overflow-x:clip (NOT hidden) contains the bleeding .bigword without turning
   .moment into a scroll container — so the sticky .visual still sticks to the viewport */
.moment{position:relative;z-index:3;min-height:140vh;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:40px;padding-inline:7vw;overflow-x:clip}
/* desktop: the sequence moment keeps the same scroll length as a normal moment
   (the floating cut-out is unchanged); mobile overrides this into a pinned
   full-viewport background below. */
.moment.tall{min-height:140vh}
.moment.flip{direction:rtl}.moment.flip .copy,.moment.flip .visual{direction:ltr}
@media(max-width:900px){
  /* mobile hero: trimmed from 300vh so the unwrap takes fewer swipes, but kept long
     enough that the scroll-position scrubber stays smooth (too short → big per-tick
     jumps during momentum scroll read as low-fps). ~2 swipes, smooth. */
  .hero-wrap{height:380vh}
  .act-blend{height:26vh}
  .moment{grid-template-columns:1fr;text-align:center;min-height:auto;padding-block:7vh;gap:22px}
  .moment.tall{min-height:auto}
  /* stack the (now large) product above the copy instead of pinning it, so big
     shots never sit under the text; the scroll-parallax transform still fires */
  .visual{position:static;height:auto;min-height:58vh}}
/* will-change toggled in JS only while the moment is on-screen (see update()) — not
   permanently, so off-screen moments don't hold live GPU layers. */
.visual{position:sticky;top:0;height:100vh;display:grid;place-items:center;perspective:1400px}
.bigword{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-family:"Fraunces";font-weight:600;font-size:clamp(80px,17vw,280px);line-height:.8;white-space:nowrap;opacity:.12;z-index:0;pointer-events:none;letter-spacing:-.03em}
.prod{position:relative;z-index:2;width:min(30vw,300px);aspect-ratio:.62;border-radius:14px;display:grid;grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(5,1fr);gap:5px;padding:8px;transform-style:preserve-3d;
  background:linear-gradient(160deg,var(--c-hi),var(--c-lo));box-shadow:0 60px 90px -30px rgba(0,0,0,.75)}
.prod i{border-radius:5px;box-shadow:inset 2px 2px 3px rgba(255,214,160,.3),inset -2px -3px 5px rgba(0,0,0,.55)}
.prod .sheen{position:absolute;inset:0;border-radius:14px;pointer-events:none;background:linear-gradient(116deg,transparent 34%,rgba(255,240,222,.32) 47%,rgba(255,255,255,.55) 50%,transparent 64%);background-size:260% 260%;background-position:0% 50%}
.prod.real{background:none;box-shadow:none;display:block;width:auto;aspect-ratio:auto;grid-template-columns:none;grid-template-rows:none}
.prod.real img{width:var(--imgw,min(40vw,440px));max-height:84vh;object-fit:contain;border-radius:18px;box-shadow:0 50px 80px -26px rgba(0,0,0,.6)}
.prod.real .sheen{display:none}
.prod.real .ph-flag{display:none}
/* transparent cut-out pack-shots: product floats with a grounded drop shadow,
   no card, no white box — sits naturally on the coloured scene */
.prod.whiteshot{filter:drop-shadow(0 40px 42px rgba(0,0,0,.5)) drop-shadow(0 6px 14px rgba(0,0,0,.35))}
.prod.whiteshot img{width:var(--imgw,min(34vw,420px));max-height:84vh;object-fit:contain;border-radius:0;box-shadow:none}
/* scroll-scrubbed caramel: a <canvas> drawing a transparent frame sequence, so it
   floats with the same grounded drop-shadow as the cut-out pack-shots */
.prod.whiteshot canvas{width:var(--imgw,min(38vw,460px));max-height:74vh;object-fit:contain;display:block}
.prod .wrap{position:absolute;inset:0;border-radius:14px;display:grid;place-items:center;overflow:hidden}
.prod .wrap img{width:62%;filter:brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(640%) hue-rotate(2deg) brightness(95%)}
/* banner moment (real photography) */
.prod.banner{background:none;box-shadow:none;display:block;width:min(40vw,460px);aspect-ratio:auto}
.prod.banner img{width:100%;border-radius:20px;box-shadow:0 50px 90px -28px rgba(0,0,0,.6)}
/* mobile: product shots go much larger (vw-based defaults shrink too hard on phones) */
@media(max-width:900px){
  .prod.real img,.prod.whiteshot img,.prod.whiteshot canvas{width:min(86vw,520px);max-height:52vh;object-fit:contain}
  /* Freddo (the only --imgw product) is wide/landscape — let it run wider on mobile */
  .prod.whiteshot img[style*="--imgw"]{width:min(96vw,600px);max-height:46vh}
  .prod.banner{width:min(92vw,560px)}

  /* ===== Caramello on mobile: a TRUE full-viewport pinned background =====
     The moment gets real scroll length and its .visual pins to the whole screen.
     The mobile frame set is padded to the phone aspect, so object-fit:cover fills
     the viewport AND the chocolate's sliced sides land exactly on the screen edges
     (no visible cut). The copy overlays on top and scrolls up over the caramel. */
  .moment.tall{min-height:200vh;padding:0;display:block;text-align:left}
  .moment.tall .visual{position:sticky;top:0;left:0;width:100vw;height:100vh;min-height:100vh;
    z-index:0;overflow:hidden;perspective:none}
  /* the canvas wrapper + canvas cover the whole pinned stage; kill the scrubber's
     parallax transform/drop-shadow so the full-bleed sides stay rock-steady */
  .moment.tall .visual .prod{position:absolute;inset:0;width:100%;height:100%;
    filter:none;transform:none!important;border-radius:0}
  .moment.tall .prod.whiteshot canvas{position:absolute;inset:0;
    width:100%!important;height:100%!important;max-width:none!important;max-height:none!important;
    object-fit:cover;border-radius:0}
  /* hide the oversized backdrop word + floating bits behind the full-screen choc */
  .moment.tall .bigword,.moment.tall .bit{display:none}
  /* copy overlays the pinned background. NO scrim band on the visual (it left an
     intrusive dark gradient + hard edge as the visual un-pinned) — instead the text
     carries its own shadow, so nothing is painted onto the pinned chocolate. */
  .moment.tall .copy{position:relative;z-index:3;margin-top:-100vh;min-height:100vh;
    display:flex;flex-direction:column;justify-content:flex-end;
    padding:0 7vw 13vh;text-align:left}
  .moment.tall .copy h3,.moment.tall .copy p,.moment.tall .copy .num{
    text-shadow:0 2px 12px rgba(14,0,32,.92),0 1px 4px rgba(14,0,32,.95)}
  .moment.tall .copy p{margin-inline:0;max-width:34ch}
  .moment.tall.flip .copy p{margin-inline:0}
}
/* placeholder flag chip on render tiles */
.prod .ph-flag{position:absolute;left:50%;bottom:-30px;transform:translateX(-50%);white-space:nowrap;font-size:10px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--purple-deep);background:var(--gold-2);padding:4px 10px;border-radius:100px;z-index:5}
.bit{position:absolute;border-radius:50%;z-index:1;filter:blur(.3px)}
.copy{position:relative;z-index:3;padding-block:40px}
.copy .num{font-family:"Fraunces";font-size:17px;letter-spacing:.2em;opacity:.85}
.copy h3{font-family:"Fraunces";font-weight:600;font-size:clamp(40px,5.8vw,84px);line-height:.96;margin:8px 0 16px}
.copy p{font-size:18px;color:rgba(247,239,226,.88);max-width:42ch}
.moment.flip .copy p{margin-left:auto}
@media(max-width:900px){.moment.flip .copy p,.copy p{margin-inline:auto}}
.copy .cta{display:inline-block;margin-top:22px;font-size:13px;font-weight:800;letter-spacing:.04em;color:var(--purple-deep);background:var(--gold-grad);padding:13px 26px;border-radius:100px;text-decoration:none}
.realchip{display:inline-block;font-size:11px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--purple-deep);background:var(--gold-2);padding:5px 12px;border-radius:100px;margin-bottom:16px}

/* ============================ & MORE BAND ============================ */
#more{position:relative;z-index:2;padding-block:40px 10px}
.realband{margin-inline:24px;border-radius:30px;overflow:hidden;border:1px solid rgba(222,194,139,.3);display:grid;grid-template-columns:1.1fr .9fr;align-items:stretch;background:var(--purple-deep)}
@media(max-width:880px){.realband{grid-template-columns:1fr}}
.realband .copy{padding:60px 48px;display:flex;flex-direction:column;justify-content:center}
.realband .shot{min-height:440px;background-size:cover;background-position:center}

/* ============================ CLOSING ============================ */
.closing{position:relative;z-index:2;padding-block:150px;text-align:center;
  background:radial-gradient(70vw 50vh at 50% 30%,var(--purple-lift),var(--purple) 45%,var(--purple-deep))}
.closing-inner{max-width:760px;margin:0 auto;padding-inline:24px}
.closing h2{font-size:clamp(40px,6vw,84px);line-height:1.02}
.closing .lede{margin-inline:auto}
.closing .cta{display:inline-block;margin-top:30px;font-size:14px;font-weight:800;letter-spacing:.04em;color:var(--purple-deep);background:var(--gold-grad);padding:16px 36px;border-radius:100px;text-decoration:none;box-shadow:0 12px 30px -10px rgba(0,0,0,.6)}

/* ============================ FOOTER ============================ */
footer{padding-block:80px 48px;border-top:1px solid rgba(222,194,139,.2);text-align:center;position:relative;z-index:2;background:var(--night)}
.foot-logo{height:30px;margin:0 auto 22px;filter:brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(640%) hue-rotate(2deg) brightness(95%)}
.sig{font-family:"Fraunces";font-style:italic;font-size:20px}
.disc{margin:14px auto 0;font-size:12px;color:rgba(247,239,226,.5);max-width:62ch}
.flagnote{margin:14px auto 0;font-size:12px;color:var(--gold-2);font-style:italic;max-width:66ch;opacity:.85}

/* reduced state: kill all looping/decorative animation, show all reveals */
.rm .reveal{opacity:1!important;transform:none!important}
.rm .uw-cue .chev,.rm .prod .sheen,.rm .uw-dust i{animation:none}
.rm .uw-dust{display:none}
.rm .scrollcue{opacity:0}
