/* ==========================================================================
   NADA ENERGY
   Base CSS renders a plain, readable, stacked document. `html.motion` (added
   by app.js only when motion is allowed and the viewport is big enough) opts
   into the pinned scenes and the 3D arc. Nothing below the fold depends on JS.
   ========================================================================== */

@font-face{
  font-family:"Archivo";src:url(fonts/archivo-roman.woff2) format("woff2");
  font-weight:100 900;font-stretch:62% 125%;font-style:normal;font-display:swap;
}
@font-face{
  font-family:"Archivo";src:url(fonts/archivo-italic.woff2) format("woff2");
  font-weight:100 900;font-stretch:62% 125%;font-style:italic;font-display:swap;
}

:root{
  /* Dark ground. The product photography is shot on black, so the page has to
     meet it there — a cream page under a black-lit bottle reads as a cutout
     pasted onto the wrong document. --ink is the page, --paper is the type. */
  --ink:#0B0C11;
  --ink-2:#14161D;
  --paper:#F2F5FA;
  --mute:#8C93A4;
  --accent:#3D9BFF;          /* JS overwrites per flavour */
  --flood:#0A1424;
  --edge:rgba(242,245,250,.14);
  --hud-h:62px;
}
*{box-sizing:border-box}
/* A decorative element past the viewport makes the document scroll sideways
   and slides the fixed header off. clip, not hidden, so sticky still works. */
html,body{overflow-x:clip}
html{scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;background:var(--ink);color:var(--paper);
  font-family:"Archivo",system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:17px;line-height:1.6;font-synthesis:none;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;height:auto;display:block}
a{color:inherit}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* fixed, NOT absolute. Absolute positions it against the initial containing
   block, so tabbing anywhere below the first screen parks it at the top of the
   DOCUMENT rather than the top of the viewport — off-screen, and the one user
   who needs it is the one who cannot see where it went. */
.skip{position:fixed;left:12px;top:-60px;z-index:200;background:var(--paper);color:var(--ink);
  padding:11px 18px;border-radius:2px;font-weight:700;text-decoration:none;transition:top .18s ease}
/* Both land in the same place. Only one can be focused at a time, so offsetting
   the second just parks it in from the edge with nothing beside it. */
.skip:focus{top:12px}
/* The skip targets take focus programmatically so the jump actually moves the
   keyboard position — a bare id on a <section> is not focusable, so without
   this the link scrolls and leaves focus behind in the header. They are
   regions rather than controls, so no ring is drawn on them. */
[tabindex="-1"]:focus{outline:none}
@media (prefers-reduced-motion:reduce){ .skip{transition:none} }
:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* ---------- display type ---------- */
.disp{
  font-style:italic;font-weight:900;font-stretch:125%;
  text-transform:uppercase;letter-spacing:-.025em;line-height:.86;
}

/* ==========================================================================
   HUD
   ========================================================================== */
.hud{
  position:fixed;top:0;left:0;right:0;height:var(--hud-h);z-index:90;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  padding:0 18px;gap:12px;
  /* No backdrop-filter here. The header sits over the product scenes, and a
     blurred backdrop turns the can tops into a smeared halo along the exact
     line where the filter region ends. A taller scrim does the same job. */
  background:linear-gradient(rgba(11,12,17,.97) 40%,rgba(11,12,17,.8) 70%,rgba(11,12,17,0));
  height:calc(var(--hud-h) + 26px);padding-bottom:26px;
}
.hud-read{
  margin:0;font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mute);font-variant-numeric:tabular-nums;
}
.hud-sep{opacity:.45;padding:0 .35em}
.hud-mark{
  justify-self:center;text-decoration:none;font-style:italic;font-weight:900;
  font-stretch:125%;font-size:19px;letter-spacing:-.02em;color:var(--paper);
}
.hud-nav{justify-self:end;display:flex;align-items:center;gap:10px}
.hud-menu,.hud-cta{
  font:inherit;font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  padding:9px 16px;min-height:36px;border-radius:100px;cursor:pointer;text-decoration:none;
  display:inline-flex;align-items:center;
}
.hud-menu{background:none;border:1px solid var(--edge);color:var(--paper)}
.hud-menu:hover{border-color:var(--paper)}
.hud-cta{background:var(--paper);color:var(--ink);border:1px solid var(--paper);
  transition:background .2s ease,color .2s ease}
.hud-cta:hover{background:var(--accent);border-color:var(--accent);color:var(--ink)}

.menu{
  position:fixed;top:var(--hud-h);right:14px;z-index:95;
  display:flex;flex-direction:column;min-width:210px;padding:8px;
  background:rgba(20,22,29,.98);border:1px solid var(--edge);border-radius:14px;
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  box-shadow:0 22px 48px rgba(0,0,0,.6);
}
.menu[hidden]{display:none}
.menu a{
  text-decoration:none;padding:12px 14px;border-radius:9px;font-size:14px;font-weight:600;
  min-height:44px;display:flex;align-items:center;
}
.menu a:hover{background:rgba(242,245,250,.07)}

/* ==========================================================================
   BASE (no-JS / reduced-motion / small screens) — a plain document
   ========================================================================== */
.scene{padding:calc(var(--hud-h) + 40px) 18px 60px}
.pin{max-width:1180px;margin:0 auto}
.void,.plinth,.ghost{display:none}

.stage-kicker{
  /* The launch line, not a caption. "This is a protein drink" over a bright
     blue sports bottle IS the advertisement — the contradiction does the work —
     so it is set loud enough to be read before the bottle is. */
  margin:0 0 22px;font-size:clamp(12px,1.5vw,15px);letter-spacing:.2em;
  text-transform:uppercase;color:var(--paper);font-weight:700;text-align:center;
}
.stage-kicker .hud-sep{color:var(--accent);opacity:.9}
.ring{display:none}

.grid{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:10px;
}
.grid a{
  display:flex;flex-direction:column;align-items:center;gap:12px;padding:22px 8px 18px;
  text-decoration:none;border:1px solid var(--edge);border-radius:16px;
  background:radial-gradient(110% 75% at 50% 34%,color-mix(in srgb,var(--accent) 16%,transparent),transparent 68%);
  transition:border-color .2s ease,background .2s ease,transform .2s ease;
}
.grid a:hover{border-color:var(--accent);transform:translateY(-3px)}
.grid img{height:190px;width:auto;filter:drop-shadow(0 18px 26px rgba(0,0,0,.75)) drop-shadow(0 0 26px color-mix(in srgb,var(--accent) 40%, transparent))}
.grid span{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--mute);text-align:center}

/* Controls that only work with scripting are hidden until `js` is present,
   and the content they reveal is served in full as static text instead. */
.scrub,.rail,.claim-one{display:none}
.js .scrub{display:block}
.js .rail{display:flex}
.js .claim-one{display:block}
.js .claim-all{display:none}
.claim-all{margin:0}
.claim-all dt{margin:20px 0 6px;font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent)}
.claim-all dt:first-child{margin-top:0}
.claim-all dd{margin:0;color:var(--mute);max-width:62ch}

/* the scrub bar */
.scrub{max-width:620px;margin:38px auto 40px;text-align:center}
input[type=range]{
  -webkit-appearance:none;appearance:none;width:100%;height:34px;background:none;cursor:grab;
}
input[type=range]:active{cursor:grabbing}
input[type=range]::-webkit-slider-runnable-track{
  height:3px;border-radius:2px;
  background:linear-gradient(90deg,#8b8f98,var(--accent) 55%,#ffffff);
}
input[type=range]::-moz-range-track{
  height:3px;border-radius:2px;
  background:linear-gradient(90deg,#8b8f98,var(--accent) 55%,#ffffff);
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:16px;height:16px;margin-top:-6.5px;
  border-radius:50%;background:#fff;border:0;
  box-shadow:0 0 0 5px rgba(242,245,250,.14),0 4px 12px rgba(0,0,0,.6);
}
input[type=range]::-moz-range-thumb{
  width:16px;height:16px;border-radius:50%;background:#fff;border:0;
  box-shadow:0 0 0 5px rgba(242,245,250,.14),0 4px 12px rgba(0,0,0,.6);
}
.scrub-now{margin:14px 0 0;font-size:13.5px;color:var(--mute);min-height:3.2em}
.scrub-now strong{
  display:block;font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:23px;letter-spacing:-.02em;color:var(--paper);margin-bottom:5px;
}

/* ---------- flavour detail ---------- */
.detail{display:grid;gap:30px}
.detail-eyebrow{margin:0 0 12px;font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--accent);
  font-variant-numeric:tabular-nums}
.detail-name{
  margin:0;font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:clamp(38px,10vw,92px);line-height:.86;letter-spacing:-.03em;
}
.detail-note{margin:16px 0 0;max-width:34ch;color:var(--mute)}
.claim{margin-top:32px;padding-top:26px;border-top:1px solid var(--edge);max-width:42ch;min-height:190px}
.claim-h{margin:0 0 10px;font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent)}
.claim-p{margin:0;color:var(--mute);line-height:1.72}
.detail-can{margin:0;text-align:center}
.detail-can img{height:min(52vh,430px);width:auto;margin:0 auto;
  filter:drop-shadow(0 40px 60px rgba(0,0,0,.75)) drop-shadow(0 0 60px color-mix(in srgb,var(--accent) 40%, transparent))}

.rail{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.rail button{
  font:inherit;font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  padding:11px 16px;min-height:44px;border-radius:100px;cursor:pointer;
  background:none;border:1px solid var(--edge);color:var(--mute);
  transition:border-color .2s ease,color .2s ease,background .2s ease;
}
.rail button:hover{color:var(--paper);border-color:var(--paper)}
.rail button[aria-selected=true]{background:var(--accent);border-color:var(--accent);color:var(--ink)}

/* ---------- line-up ---------- */
.scene-lineup{padding:80px 18px 90px;background:linear-gradient(var(--ink),#101219)}
.lineup-head{max-width:1180px;margin:0 auto 44px}
.lineup-head h2{
  margin:0;font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:clamp(40px,10vw,110px);line-height:.85;letter-spacing:-.035em;
}
.lineup-head h2 em{font-style:italic;color:var(--accent)}
.lineup-head p{margin:20px 0 0;max-width:46ch;color:var(--mute)}
.row{
  max-width:1180px;margin:0 auto;display:flex;justify-content:center;align-items:flex-end;
  gap:clamp(2px,1.4vw,14px);flex-wrap:wrap;
}
.row img{height:clamp(150px,26vw,300px);width:auto;filter:drop-shadow(0 24px 30px rgba(0,0,0,.75)) drop-shadow(0 0 30px color-mix(in srgb,var(--accent) 40%, transparent))}

/* ---------- faq ---------- */
.scene-faq{padding:90px 18px 100px;background:#101219}
.faq-h{
  max-width:1180px;margin:0 auto 44px;
  font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:clamp(38px,10vw,104px);line-height:.84;letter-spacing:-.035em;
}
.faq-h em{font-style:italic;-webkit-text-stroke:1px var(--paper);color:transparent}
.faq-list{max-width:820px;margin:0 auto;border-top:1px solid var(--edge)}
.faq-list details{border-bottom:1px solid var(--edge)}
.faq-list summary{
  cursor:pointer;padding:22px 44px 22px 0;position:relative;list-style:none;
  font-size:clamp(16px,2.4vw,19px);font-weight:600;
}
.faq-list summary::-webkit-details-marker{display:none}
.faq-list summary::after{
  content:"";position:absolute;right:8px;top:50%;width:13px;height:13px;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  transform:translateY(-70%) rotate(45deg);transition:transform .2s ease;
}
.faq-list details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq-list summary:hover{color:var(--accent)}
.faq-list p{margin:0 0 26px;max-width:62ch;color:var(--mute)}

/* ---------- footer ---------- */
/* The footer is the one block on the page that is symmetrical about the
   centre: the outline wordmark, three equal columns under it, and the legal
   note centred beneath those. Ragged-left columns under a centred 190px
   wordmark read as a layout that came apart. */
.foot{background:var(--ink);padding:70px 18px 40px;border-top:1px solid var(--edge)}
.foot-in{max-width:1180px;margin:0 auto;text-align:center}
.foot-mark{
  margin:0 0 34px;font-style:italic;font-weight:900;font-stretch:125%;
  font-size:clamp(56px,17vw,190px);line-height:.8;letter-spacing:-.04em;
  color:transparent;-webkit-text-stroke:1px rgba(242,245,250,.26);
}
.foot-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:28px}
.foot-cols h3{margin:0 0 8px;font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent)}
.foot-cols p{margin:0;font-size:14.5px;color:var(--mute);line-height:1.7}
/* auto margins, not just text-align: the 62ch measure has to sit in the middle
   of the 1180 container, otherwise centred text still hangs off the left. */
.foot-note{margin:44px auto 0;padding-top:22px;border-top:1px solid var(--edge);
  font-size:12.5px;color:var(--mute);max-width:62ch}   /* 5.26:1; #6f7580 was 4.32 */

/* ==========================================================================
   MOTION MODE — pinned scenes and the 3D arc
   ========================================================================== */
html.motion .scene{padding:0;position:relative}
/* One screen. In v1 this was 360vh because document scroll WAS the arc's
   position; here the arc has its own wheel surface, so the section is just a
   section and the page is ~2,000px shorter. */
html.motion .scene-range{height:100vh}
/* In motion mode the flavour copy lives in the click-opened viewer, so this
   section is only the plain-mode / no-JS home for the same words. */
html.motion .scene-flavour{display:none}
/* No negative margin. There is no sticky tail to cover any more: the range is
   exactly one viewport and the line-up simply follows it. */
html.motion .scene-lineup{position:relative;z-index:3;
  background:linear-gradient(180deg,var(--ink),#101219)}

/* No CSS scroll-snap. The arc is not a scroll container, so the browser has
   nothing to snap; settling on a can is done in JS after the wheel goes quiet. */
html.locked{overflow-y:hidden}
html.motion .pin{
  position:relative;height:100vh;max-width:none;
  display:flex;flex-direction:column;justify-content:center;overflow:hidden;
}
/* dvh, not vh, on anything that has to fit a phone screen. Mobile browsers
   report 100vh as the height WITHOUT their collapsing URL bar, so a 100vh pin
   is taller than what you can actually see and the bottom of the helix sits
   under the browser chrome until you scroll. dvh tracks the visible box. The
   100vh above stays as the fallback for anything that lacks dvh. */
@supports (height:100dvh){ html.motion .pin{height:100dvh} }

/* ---- no fold peek ------------------------------------------------------
   The range is one whole viewport again. v4 briefly ran it at 90dvh so the
   bottom edge sliced the top of "All eight", on the reasoning that a headline
   cut by the fold is the oldest way to say there is more below. It worked, and
   it is not what this section wants: the first screen is a product shot, and a
   second headline crowding into the bottom of it costs more than the cue is
   worth. The range reveals the cans and nothing else.

   WHAT THAT COSTS, so the next person does not rediscover it by accident. The
   range LOOPS, so it never ends and never hands the wheel back on its own; the
   way out is the gutters either side of the column (see .shaft). Those are a
   desktop affordance — under ~720px the column is wider than the screen, so
   there is no gutter, and with no peek either there is nothing on a phone
   saying a page exists below. The escape is real (a swipe below the cans
   scrolls the document, see drag.mode in app.js) but it is unadvertised. If
   phone bounce ever needs fixing, that is the thing to fix, and the cheapest
   honest fix is to put the peek back at this breakpoint only. */

/* ---- and that is exactly what this is ----------------------------------
   The peek, phones only. Desktop keeps the whole viewport for the cans
   because it does not need the cue: the gutters either side of the column are
   visibly page, and a wheel in one of them leaves the section immediately.
   Under 720px that column is wider than the screen, so there is no gutter to
   find, the range loops and never ends on its own, and nothing at all would
   say a page exists below. So the fold takes a tenth of the screen back and
   slices the top of "All eight" — enough to prove there is something under
   there and that it has been cut.

   720px is not a guess: it is the same threshold sizeArc() switches the helix
   geometry at, so the breakpoint where the cue appears is the breakpoint where
   the gutters disappear. Keep them in step.

   Both heights, not just the pin's — the section carries its own and the pin
   fills it, so shrinking one alone just leaves the difference as empty section
   and the fold lands in exactly the same place. The tenth comes out of the
   ring (slack: the cans are absolute at its midpoint, so a shorter box does
   not move them) and the air under the scrub. */
@media (max-width:719px){
  html.motion .scene-range{height:90vh}
  html.motion .scene-range .pin{height:90vh}
  html.motion .scene-range .ring{height:min(56vh,520px)}
  html.motion .scene-range .scrub{margin-bottom:26px}
  html.motion .scene-lineup{padding-top:7vh}
  @supports (height:100dvh){
    html.motion .scene-range{height:90dvh}
    html.motion .scene-range .pin{height:90dvh}
    html.motion .scene-lineup{padding-top:7dvh}
  }
}

html.motion .grid{display:none}

/* the studio void */
html.motion .void{
  display:block;position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(80% 55% at 50% 34%, color-mix(in srgb, var(--flood) 60%, var(--accent) 22%) 0%, transparent 70%),
    radial-gradient(120% 70% at 50% 108%, color-mix(in srgb, var(--accent) 34%, #000) 0%, transparent 62%),
    var(--flood);
  transition:background 300ms cubic-bezier(.4,0,.2,1);
}
html.motion .scene-range .stage-kicker{position:relative;z-index:3;margin-top:calc(var(--hud-h) + 6px)}

/* the arc */
html.motion .stage{
  position:relative;z-index:2;flex:1;min-height:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  perspective:1500px;perspective-origin:50% 46%;
}

/* ---- the shaft ---------------------------------------------------------
   v4. The scroll container, lit.

   app.js bounds the wheel and the mouse drag to a column around the helix
   rather than to the whole pinned viewport, and hands the width here as
   --surf-w. This is that same column made visible — not a border, which would
   be a diagram of the rule rather than the room, but a shaft of light that the
   range stands in and the gutters do not. The fall-off IS the edge: the eye
   reads the lit region as the space this thing lives in, and the panel either
   side as somewhere else.

   It has to stay this quiet. Loud enough to notice and you have drawn a box on
   a product shot; the cursor does the precise half of the job the moment
   anyone actually reaches for it. */
.shaft{display:none}
html.motion .shaft{
  display:block;position:absolute;top:0;bottom:0;left:50%;translate:-50% 0;
  width:var(--surf-w,62%);z-index:0;pointer-events:none;
  background:linear-gradient(90deg,
    transparent 0,
    color-mix(in srgb, var(--paper) 5%, transparent) 24%,
    color-mix(in srgb, var(--paper) 5%, transparent) 76%,
    transparent 100%);
  /* Same reasoning as the rail's mask: the column is a shaft, not a panel, so
     it must not end on a hard line at the top or bottom of the stage. */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 16%,#000 84%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 16%,#000 84%,transparent 100%);
}

/* ---- the rail ----------------------------------------------------------
   v4. The helix was invisible: eight cans placed on a curve, and the curve
   itself drawn nowhere. Which meant the section had no way of saying it was a
   TRACK — that the cans are beads on it, that it has a direction, and that it
   runs past what you can see. Every other cue (the counter, the scrub bar) is
   a label for that fact; this is the fact.

   Not in plain mode. There is no helix there to draw. */
.track{display:none}
html.motion .track{
  display:block;position:absolute;inset:0;
  /* Behind the cans. z-index:0 still makes a stacking context, and the ring
     below takes 1, so the painting order is stated rather than inferred from
     DOM order and a pair of `auto`s. */
  z-index:0;pointer-events:none;
  /* A line that STOPS inside the frame reads as a decoration. A line that
     dissolves off both edges reads as something that continues past them,
     which is the entire point — the eight cans are a window onto a run, not
     the whole of it. The fade also keeps the rail off the kicker above and the
     scrub below, so it never has to compete with type. */
     Graded rather than a plain fade in and out, because the top of the stage
     has the kicker line living in it — measured at 16 to 21% of the stage
     height across every breakpoint — and the rail passes straight through it.
     So the first stretch is held at a fraction of full strength: enough that
     the rail visibly arrives from somewhere above rather than starting at a
     hard edge, faint enough that it never competes with type it is crossing.
     Full strength only below the kicker, where the only thing to cross is
     panel.

     The first pass had this the wrong way round — opaque from 19% to 76%,
     which is roughly the band the CANS occupy. The rail was at its strongest
     exactly where a can was hiding it and at its weakest in the gaps where it
     could actually be seen. Nothing below the stage needs protecting: the
     scrub bar is a sibling, not a child, so the bottom is free to run out to
     the edge. */
  -webkit-mask-image:linear-gradient(180deg,
    transparent 0, rgba(0,0,0,.3) 8%, rgba(0,0,0,.3) 21%, #000 32%, #000 93%, transparent 100%);
  mask-image:linear-gradient(180deg,
    transparent 0, rgba(0,0,0,.3) 8%, rgba(0,0,0,.3) 21%, #000 32%, #000 93%, transparent 100%);
}
html.motion .scene-range .ring{z-index:1}

/* v3 made the WHOLE pinned scene the handle, because restricting it left a
   dead margin over most of the screen and a dead margin reads as the
   interaction being broken rather than bounded.

   v4 restricts it after all — but the thing that made that fail was never the
   bound, it was that the bound was invisible. So the column is lit (.shaft
   above) and, more to the point, the cursor now changes at its edge: `.hot` is
   toggled by app.js the moment the pointer crosses into the box. A boundary
   you can feel before you commit is a boundary, not a bug. Plain `auto`
   outside, so the gutters read as ordinary page — which is exactly what they
   now behave as. */
html.motion .scene-range .pin{
  cursor:auto;
  /* touch-action:none hands us every touch here instead of letting the browser
     start a page scroll and cancel the gesture mid-spin. It also means the page
     can no longer scroll from within this scene on its own, so app.js forwards
     anything past either end of the range to the document by hand. */
  touch-action:none;
  /* A drag across the scene would otherwise select the copy under it. */
  -webkit-user-select:none;user-select:none;
}
html.motion .scene-range .pin.hot{cursor:grab}
html.motion .scene-range .pin.hot:active{cursor:grabbing}
html.motion .stage,html.motion .can,html.motion .can-btn{cursor:inherit}
/* The scrub bar keeps its own cursor and its own gestures: it is a real slider,
   and app.js declines to start a drag from it for the same reason. */
html.motion .scene-range .scrub{cursor:auto}
html.motion .scene-range .scrub input{cursor:pointer;touch-action:none}

/* ---- the bar, taken out of the composition ------------------------------
   v4. The range loops now and the helix says where it is by moving; a track
   with a thumb parked a fifth of the way along was measuring a run that no
   longer has ends. So it goes — visually.

   It does NOT come out of the DOM, and it must not. In motion mode `.grid` is
   display:none, which leaves this slider as the ONLY keyboard route through
   the range: delete it and the carousel becomes mouse-and-finger-only, which
   is a straight WCAG 2.1.1 failure on a public page. Hidden with opacity
   rather than display or a clip rect so it stays focusable, and it fades back
   in on focus — the bar exists, for exactly the people who need it.

   Opacity also keeps its 34px in the flow. Collapsing it would have the whole
   composition jump the moment a keyboard user tabbed in, and reserved air
   under a floating helix reads as spacing rather than as a gap. */
html.motion .scene-range .scrub input{
  opacity:0;pointer-events:none;
  transition:opacity 320ms cubic-bezier(.4,0,.2,1);
}
html.motion .scene-range .scrub:focus-within input{opacity:1;pointer-events:auto}
@media (prefers-reduced-motion:reduce){
  html.motion .scene-range .scrub input{transition:none}
}
/* Chrome on Android paints a tap flash on the button under a spin. */
html.motion .can-btn{-webkit-tap-highlight-color:transparent}
html.motion .ring{
  display:block;position:relative;width:100%;height:min(62vh,560px);
  transform-style:preserve-3d;
  /* THE RING MUST NOT BE HIT-TESTABLE. preserve-3d puts its own box on the
     Z=0 plane of the 3D context, and every can sits at NEGATIVE z (behind it),
     so the ring wins every hit test while being completely invisible. Clicks on
     the cans silently did nothing. pointer-events inherits, so the cans have to
     opt back in below. */
  pointer-events:none;
}
html.motion .can{
  position:absolute;left:50%;top:50%;width:auto;
  /* `translate` composes BEFORE `transform`, so the JS transform can own the
     arc maths without having to know the can's rendered width. */
  translate:-50% -50%;
  will-change:transform,opacity;
  pointer-events:auto;          /* see the note on .ring above */
}
html.motion .can img{
  height:min(34vh,285px);width:auto;
  filter:drop-shadow(0 30px 40px rgba(0,0,0,.75)) drop-shadow(0 0 40px color-mix(in srgb,var(--accent) 40%, transparent));
}
/* absolute so the reflection does not add to the wrapper height, which would
   push the can itself off centre */
html.motion .can .refl{
  position:absolute;left:0;top:100%;margin-top:2px;
  height:min(42vh,340px);width:auto;transform:scaleY(-1);opacity:.11;
  -webkit-mask-image:linear-gradient(transparent 74%,#000);
  mask-image:linear-gradient(transparent 74%,#000);
  filter:none;
}
html.motion .can-btn{
  position:absolute;inset:0;z-index:2;background:none;border:0;padding:0;cursor:pointer;
}
html.motion .plinth{
  display:none;position:absolute;left:50%;bottom:8%;translate:-50% 0;
  width:min(30vw,300px);height:min(4vw,34px);border-radius:50%;z-index:1;pointer-events:none;
  background:radial-gradient(closest-side, color-mix(in srgb, var(--accent) 32%, transparent), transparent 70%);
  filter:blur(11px);opacity:.5;transition:background 300ms cubic-bezier(.4,0,.2,1);
}
html.motion .scrub{position:relative;z-index:3;margin:0 auto 42px;padding:0 18px;width:100%}

/* flavour scene */
html.motion .scene-flavour .pin{justify-content:center}
/* Sits behind the CAN on the right, not behind the copy on the left, and a
   left scrim keeps the paragraph off it entirely. Ghost type crossing body
   text is the fastest way to make a scene look busy and unreadable. */
html.motion .ghost{
  display:block;position:absolute;right:3%;top:50%;translate:0 -50%;z-index:1;
  margin:0;white-space:nowrap;pointer-events:none;user-select:none;
  font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:clamp(64px,12vw,180px);line-height:.8;letter-spacing:-.045em;
  color:transparent;-webkit-text-stroke:1px rgba(242,245,250,.12);
}
html.motion .scene-flavour .pin::after{
  content:"";position:absolute;inset:0 auto 0 0;width:min(62%,880px);z-index:1;
  pointer-events:none;
  background:linear-gradient(90deg, rgba(4,5,8,.88) 0%, rgba(4,5,8,.62) 45%, transparent 100%);
}
html.motion .scene-flavour{background:none}
html.motion .scene-flavour .pin{
  background:
    radial-gradient(70% 60% at 62% 46%, color-mix(in srgb, var(--flood) 62%, var(--accent) 20%), transparent 68%),
    linear-gradient(160deg, var(--flood), #07080C 78%);
  transition:background 300ms cubic-bezier(.4,0,.2,1);
}
html.motion .detail{
  position:relative;z-index:2;width:100%;max-width:1240px;margin:0 auto;
  padding:calc(var(--hud-h) + 20px) clamp(18px,5vw,70px) 40px;
  grid-template-columns:minmax(0,1fr) minmax(0,.85fr) auto;
  align-items:center;gap:clamp(20px,4vw,60px);
}
html.motion .detail-can img{height:min(66vh,620px)}
html.motion .rail{flex-direction:column;flex-wrap:nowrap;gap:10px}
html.motion .rail button{width:100%;justify-content:flex-start;text-align:left}

/* line-up gets real depth in motion mode */
html.motion .row{
  flex-wrap:nowrap;perspective:1100px;perspective-origin:50% 50%;
  transform-style:preserve-3d;justify-content:center;
}
html.motion .row img{
  height:clamp(170px,25vw,320px);flex:0 0 auto;
  transition:transform .36s cubic-bezier(.2,.7,.3,1);will-change:transform;
}

/* ==========================================================================
   THE VIEWER — the zoom-in state
   ========================================================================== */
.viewer{display:none}
.viewer[hidden]{display:none}
html.motion .viewer:not([hidden]){
  display:block;position:fixed;inset:0;z-index:120;
}
.viewer .rail,.viewer .rail button{cursor:pointer}
.viewer-close{cursor:pointer}
.viewer-bg{
  position:absolute;inset:0;
  background:
    radial-gradient(66% 58% at 62% 46%, color-mix(in srgb, var(--flood) 58%, var(--accent) 22%), transparent 68%),
    linear-gradient(160deg, var(--flood), #07080C 78%);
  opacity:0;transition:opacity .24s ease;
}
.viewer-bg::after{
  content:"";position:absolute;inset:0 auto 0 0;width:min(62%,880px);
  background:linear-gradient(90deg, rgba(4,5,8,.9) 0%, rgba(4,5,8,.64) 45%, transparent 100%);
}
.viewer.in .viewer-bg{opacity:1}

.viewer .ghost{
  display:block;position:absolute;right:3%;top:50%;translate:0 -50%;z-index:1;
  margin:0;white-space:nowrap;pointer-events:none;user-select:none;
  font-style:italic;font-weight:900;font-stretch:125%;text-transform:uppercase;
  font-size:clamp(64px,12vw,180px);line-height:.8;letter-spacing:-.045em;
  color:transparent;-webkit-text-stroke:1px rgba(242,245,250,.12);
  opacity:0;transition:opacity .27s ease .04s;
}
.viewer.in .ghost{opacity:1}

.viewer-close{
  position:absolute;top:calc(var(--hud-h) + 14px);right:20px;z-index:6;
  font:inherit;font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:11px 18px;
  border-radius:100px;cursor:pointer;color:var(--paper);
  background:rgba(242,245,250,.06);border:1px solid var(--edge);
  opacity:0;transition:opacity .22s ease .05s,background .17s ease,border-color .17s ease;
}
.viewer-close .x{font-size:17px;line-height:0}
.viewer-close:hover{background:rgba(242,245,250,.14);border-color:var(--paper)}
.viewer.in .viewer-close{opacity:1}

.viewer-in{
  position:relative;z-index:4;height:100%;width:100%;max-width:1240px;margin:0 auto;
  padding:calc(var(--hud-h) + 30px) clamp(18px,5vw,70px) 40px;
  display:grid;grid-template-columns:minmax(0,1.12fr) minmax(0,.82fr) auto;
  align-items:center;gap:clamp(20px,4vw,60px);
}
.viewer-copy{opacity:0;transform:translateY(14px);
  transition:opacity .23s ease .04s,transform .3s cubic-bezier(.2,.7,.3,1) .04s}
.viewer.in .viewer-copy{opacity:1;transform:none}
.viewer-can{margin:0;text-align:center}
/* The image that grows. It is NOT faded in: it takes over from the arc's can at
   the identical rect with the identical pixels, so it must be opaque from the
   first frame or the handover shows as a flicker. JS owns its transform. */
.viewer-can img{height:min(74vh,680px);width:auto;margin:0 auto;
  filter:drop-shadow(0 44px 62px rgba(0,0,0,.75)) drop-shadow(0 0 62px color-mix(in srgb,var(--accent) 40%, transparent));
  will-change:transform}
.viewer .rail{flex-direction:column;flex-wrap:nowrap;gap:10px;
  opacity:0;transition:opacity .23s ease .07s}
.viewer.in .rail{opacity:1}
.viewer .rail button{width:100%;justify-content:flex-start;text-align:left}

/* the arc ducks out of the way while the viewer is open */
html.motion .stage,html.motion .scrub,html.motion .stage-kicker{
  transition:opacity .21s ease,transform .28s cubic-bezier(.4,0,.2,1);
}
html.viewing .stage{opacity:0;pointer-events:none}
html.viewing .scrub,html.viewing .stage-kicker{opacity:0;pointer-events:none}

/* The affordance is the can itself lifting under the pointer, not a caption
   telling you to click. The JS owns .can's transform and filter every frame,
   so hover has to live on the image. */
html.motion .can-btn{cursor:pointer}
html.motion .can img{transition:filter .16s ease}
html.motion .can:hover img:not(.refl),
html.motion .can-btn:focus-visible ~ img{
  filter:drop-shadow(0 34px 48px rgba(0,0,0,.75)) drop-shadow(0 0 48px color-mix(in srgb,var(--accent) 40%, transparent)) saturate(1.06);
}

@media(max-width:900px){
  .viewer-in{grid-template-columns:1fr;gap:18px;align-content:center;
    padding-top:calc(var(--hud-h) + 56px)}
  .viewer-can{order:-1}
  .viewer-can img{height:min(38vh,330px)}
  .viewer .rail{flex-direction:row;flex-wrap:wrap}
  .viewer .rail button{width:auto}

  /* ---- the close button goes icon-only ----------------------------------
     It has to, and this is the block that causes it: `order:-1` above moves
     the can to the top of the stack, straight under a 208px pill pinned to the
     top right. On a phone they overlap by about 80x44px — the pill lies across
     the can's face, and because it is translucent both the label and the can
     are harder to read than either would be alone. Measured, not eyeballed;
     _v4_viewer.js asserts the intersection is zero.

     A round × is the one control that needs no words anywhere, so this costs
     nothing but the phrase. The phrase itself survives in .lbl for anyone
     listening rather than looking, which is why it is a separate element and
     why it is clipped rather than display:none — the × is aria-hidden, so
     hiding these words properly would leave a button with no name at all. */
  .viewer-close{
    top:calc(var(--hud-h) + 10px);right:14px;
    width:44px;min-width:44px;height:44px;min-height:44px;
    padding:0;gap:0;justify-content:center;border-radius:50%;
  }
  .viewer-close .x{font-size:21px}
  .viewer-close .lbl{
    position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
    overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
  }
}

/* loader */
/* Hidden unless motion mode asked for it, so a plain document never sees it.
   .gone is also set by a failsafe timer in the head, so a missing app.js
   cannot leave the loader covering the page. */
#loader{display:none}
html.motion #loader{
  position:fixed;inset:0;z-index:300;background:var(--ink);
  display:grid;place-items:center;transition:opacity .24s ease;
}
#loader.gone{display:none!important}
#loader.done{opacity:0;pointer-events:none}
.loader-in{text-align:center}
.loader-mark{
  display:block;font-style:italic;font-weight:900;font-stretch:125%;font-size:clamp(48px,12vw,120px);
  letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1px rgba(242,245,250,.30);
}
.loader-pct{
  display:block;margin-top:16px;font-size:13px;letter-spacing:.3em;color:var(--paper);
  font-variant-numeric:tabular-nums;
}
.loader-step{display:block;margin-top:7px;font-size:11px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--mute)}

/* ---------- responsive ---------- */
@media(max-width:900px){
  html.motion .detail{grid-template-columns:1fr;gap:22px;padding-top:calc(var(--hud-h) + 12px)}
  html.motion .detail-can{order:-1}
  html.motion .detail-can img{height:min(34vh,300px)}
  html.motion .rail{flex-direction:row;flex-wrap:wrap}
  html.motion .rail button{width:auto}
  html.motion .claim{min-height:150px;margin-top:20px;padding-top:18px}
}
/* ---- the helix on a phone ---------------------------------------------- */
@media(max-width:719px){
  /* Capped by vw as well as vh. A can is about three times taller than it is
     wide, so sizing it off height alone makes it tall AND wide enough that two
     neighbours collide across a 375px screen. */
  /* The vw term is a guard for short landscape screens, not the usual binding
     constraint — a can is roughly a third as wide as it is tall, so 32vw here
     was capping the HEIGHT at a third of the screen width and shrinking the can
     to about 40px across. Loose enough now that vh does the work. */
  html.motion .can img{height:min(25vh,46vw,200px)}
  /* Smaller drop shadow to match the smaller object; the desktop one reads as
     a smudge at this size. */
  html.motion .can img{filter:drop-shadow(0 18px 26px rgba(0,0,0,.75)) drop-shadow(0 0 26px color-mix(in srgb,var(--accent) 40%, transparent))}
  html.motion .ring{height:min(56vh,420px)}
  html.motion .scene-range .stage-kicker{font-size:10px;letter-spacing:.14em}
}

@media(max-width:620px){
  .hud{grid-template-columns:auto 1fr auto;padding:0 12px}
  .hud-read{display:none}
  .hud-mark{justify-self:start}
  .hud-cta{display:none}
  .grid img{height:150px}
  .foot-cols{gap:24px}
}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}

/* ==========================================================================
   THE CLAIM BAND — the argument, set once, in the brand's own voice.
   Sits between the flavour detail and the formats so the page states WHY
   before it starts enumerating WHAT.
   ========================================================================== */
.scene-claimband{
  padding:96px 18px 104px;background:var(--ink);
  border-top:1px solid var(--edge);
}
.band-in{max-width:820px;margin:0 auto}
.band-eyebrow{
  margin:0 0 18px;font-size:12px;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;color:var(--mute);
}
.band-h{
  margin:0;font-style:italic;font-weight:900;font-stretch:125%;
  text-transform:uppercase;letter-spacing:-.025em;line-height:.9;
  font-size:clamp(34px,6.2vw,72px);
}
.band-h em{font-style:italic;color:var(--accent)}
.band-lede{margin:26px 0 0;max-width:56ch;color:var(--mute);font-size:clamp(16px,1.5vw,19px)}
.band-facts{
  list-style:none;margin:44px 0 0;padding:0;display:grid;gap:18px;
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
}
.band-facts li{
  padding:22px 20px;border:1px solid var(--edge);border-radius:14px;
  background:color-mix(in srgb,var(--accent) 7%,transparent);
}
.band-facts strong{
  display:block;font-style:italic;font-weight:900;font-stretch:125%;
  font-size:clamp(30px,4.4vw,44px);line-height:1;letter-spacing:-.03em;
  color:var(--accent);
}
.band-facts span{display:block;margin-top:10px;font-size:14px;color:var(--mute)}
.band-fine{margin:26px 0 0;font-size:13px;color:var(--mute);opacity:.85;max-width:52ch}

/* ==========================================================================
   THREE FORMATS
   ========================================================================== */
.scene-formats{padding:90px 18px 96px;background:var(--ink);border-top:1px solid var(--edge)}
.formats-head{max-width:1180px;margin:0 auto 52px}
.formats-head h2{
  margin:0;font-style:italic;font-weight:900;font-stretch:125%;
  text-transform:uppercase;letter-spacing:-.025em;line-height:.88;
  font-size:clamp(38px,7vw,86px);
}
.formats-head h2 em{font-style:italic;color:var(--accent)}
.formats-head p{margin:20px 0 0;max-width:52ch;color:var(--mute)}
.formats-grid{
  max-width:1180px;margin:0 auto;display:grid;gap:26px;
  grid-template-columns:repeat(auto-fit,minmax(272px,1fr));
}
.fmt{
  padding:28px 26px 30px;border:1px solid var(--edge);border-radius:18px;
  background:linear-gradient(180deg,color-mix(in srgb,var(--paper) 4%,transparent),transparent);
}
.fmt img{
  height:200px;width:auto;margin:0 0 20px;
  filter:drop-shadow(0 20px 26px rgba(0,0,0,.75));
}
.fmt h3{
  margin:0;font-style:italic;font-weight:900;font-stretch:125%;
  text-transform:uppercase;letter-spacing:-.02em;font-size:clamp(24px,3vw,32px);line-height:1;
}
.fmt-sub{
  margin:10px 0 16px;font-size:12px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);
}
.fmt p:last-child{margin:0;color:var(--mute);font-size:15.5px}

@media (max-width:640px){
  .scene-claimband{padding:72px 18px 78px}
  .scene-formats{padding:70px 18px 76px}
  .fmt img{height:160px}
}

/* ==========================================================================
   STEPPING THE CLAIM
   The wheel inside the viewer moves one section at a time — macro, taste,
   format, cap — rather than scrolling a box of text. The swap is animated so
   the step is visible as a step; the rail says which of the four you are on,
   which is why there is no instruction line here to read.
   ========================================================================== */
.viewer .claim{min-height:210px}
.viewer .claim.step .claim-h{animation:claimStep .34s cubic-bezier(.2,.7,.3,1) both}
.viewer .claim.step .claim-p{animation:claimStep .38s cubic-bezier(.2,.7,.3,1) .04s both}
@keyframes claimStep{
  from{opacity:0;transform:translateY(15px)}
  to{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .viewer .claim.step .claim-h,.viewer .claim.step .claim-p{animation:none}
}

/* The viewer's column is narrower than the plain section's, and the range now
   carries names like STRAWBERRIES & CREAM rather than COCOA. At the shared
   92px the longest word ran under the bottle, so the viewer sets its own step
   down and is allowed to break a word only as a last resort. */
.viewer .detail-name{font-size:clamp(24px,3.05vw,44px);text-wrap:balance}
.viewer .detail-note{max-width:32ch}
