/* ==========================================================================
   QUADRA BIOTECH
   The page is a film. It opens on black, scrubs a 90-frame sequence as you
   scroll, then hands off to four lit compositions — one per compound.
   Nothing here uses a runtime blur, a blend mode or a full-viewport mask:
   the earlier layered build ran at 8fps, this one holds 60.
   ========================================================================== */

:root {
  transition: --scene-accent .45s linear, --scene-rim .45s linear;

  /* Brand — fixed, never tweened */
  --brand-blue:      #0F53A6;
  --brand-blue-mid:  #4770AE;
  --brand-blue-pale: #93B6D4;
  --chrome-hi:       #FDFDFE;
  --chrome-mid:      #C7CAD1;
  --chrome-lo:       #7A828C;
  --chrome-shadow:   #4A525B;

  /* Lab (hero) — fixed */
  --lab-bg:          #FBFCFD;
  --lab-ink:         #14181C;
  --lab-rule:        #E4E8EC;

  /* Scene — every one of these is tweened per section */
  --scene-bg:        #0A1F1A;
  --scene-fog:       #16332B;
  --scene-accent:    #C87A4A;
  --scene-rim:       #4FBFA0;
  --scene-ink:       #F2F6F4;
  --scene-ink-dim:   #9FB3AC;

  --chrome-grad: linear-gradient(168deg,
    #FDFDFE 0%, #C7CAD1 28%, #7A828C 46%,
    #EFF1F4 58%, #9BA3AC 74%, #4A525B 100%);

  --font-display: 'Archivo', system-ui, sans-serif;
  --font-body:    'Inter Tight', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace;

  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --hdr-h: 76px;

  --page: min(1320px, 100vw - 11rem);

  /* Measured from the research-use banner at runtime; everything pinned to the
     top of the viewport offsets by it. Hardcoding this broke on mobile, where
     the banner wraps to two lines. */
  --ruo-h: 0px;

  /* Scene art. Swapped in one place so the whole world changes with one edit.

     The compounds used to stand on a photographic plinth of tree roots and
     granite, and briefly on a sphere. They now stand on still water, lit the
     way the opening sequence is lit — the only material in this world that was
     ever native to it. The roots were a second world borrowed to hold up the
     first, and the sphere held the vial at a tangent, which is not a place
     anything stands.

     `--water-size` is the width of the whole PLATE, not of the visible rings:
     the plate is a wide field whose ripples fade to black well before its own
     edges, so it is always set considerably wider than the ripples want to be. */
  --water:      url('assets/layers/water-plinth.webp');
  --water-ar:   2400 / 865;  /* the plate's own aspect, for reserving its box */
  /* Sized in vw, not vh, because the constraint is horizontal and it is a tight
     one: the vial stands a quarter of the way in from one edge, and the rings
     have to die out before they reach the frame on that side and before they
     reach the copy on the other. Measured off the plate, the outermost visible
     ring is 0.713 of its width, so 56vw keeps the rings inside roughly the
     middle third — clear of both — at every desktop width, because the whole
     layout is proportional too. */
  --water-size: 56vw;
  /* The rings are not centred in their own plate — the camera is looking across
     the water, so the centre sits low, 0.606 of the way down. This is that
     point measured from the plate's BOTTOM edge, and it is what gets parked on
     the waterline. Centring the box instead floated the vial above the rings. */
  --water-focus: 39.4%;
  /* The waterline: where the surface sits, and therefore where the vial's base
     sits — the two are the same number by definition, which is the whole point
     of a flat plinth over a round one. */
  --water-line: 27%;

  /* Vials are sized by HEIGHT, not width. Every render is the same physical
     vial photographed at the same distance, but they crop to different widths —
     628px through 705px against a constant 1300px. Sizing on width therefore
     made the narrow ones tall: GHK-Cu stood 45px higher in the frame than
     TB-500 for no reason anybody looking at the two could name. One height, and
     each vial's own aspect supplies the width. */
  --vial-h: clamp(300px, 47vh, 560px);
  --vial-ar: 660 / 1300;
}

@media (max-width: 900px) { :root { --page: calc(100vw - 2.5rem); --hdr-h: 64px; } }

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


body {
  margin: 0;
  background: #000;
  color: var(--lab-ink);
  font-family: var(--font-body);
  font-size: clamp(1rem, 1.15vw, 1.125rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}



img, svg, canvas, video { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }

::selection { background: var(--brand-blue); color: #fff; }

:focus-visible {
  outline: 2px solid var(--scene-rim);
  outline-offset: 2px;
  border-radius: 2px;
}
.is-lab-focus :focus-visible { outline-color: var(--brand-blue-pale); }

/* --- Shared type roles ---------------------------------------------------- */

.chrome {
  background: var(--chrome-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .chrome { color: var(--chrome-mid); background: none; }
}

.eyebrow {
  margin: 0;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.eyebrow sup { font-size: .7em; letter-spacing: 0; }

/* ==========================================================================
   Research-use-only banner
   ========================================================================== */

/* The notice is a label, not an alarm. It reads the way the line at the foot
   of a spec sheet does: a status in the same mono the site uses for data, a
   rule, and one plain sentence. No badge, no glow — nothing on it is trying to
   be looked at, which is the point of a disclaimer that is always on screen. */
.ruo {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 120;
  display: flex;
  align-items: center;
  min-height: 32px;
  padding: .45rem 3rem .45rem max(1.25rem, calc((100vw - var(--page)) / 2));
  background: #05080C;
  border-bottom: 1px solid rgba(255,255,255,.07);
  color: rgba(214,224,234,.62);
  transform: translateY(0);
  transition: transform .38s var(--ease-out);
}
.ruo[data-dismissed] { transform: translateY(-101%); }
.ruo__text {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: .9rem;
  font-size: .76rem;
  line-height: 1.35;
}
.ruo__tag {
  flex: none;
  padding-right: .9rem;
  border-right: 1px solid rgba(255,255,255,.16);
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #E3EAF1;
}
.ruo__short { display: none; }
@media (max-width: 640px) {
  .ruo { padding: .4rem 2.4rem .4rem 1rem; }
  .ruo__long { display: none; }
  .ruo__short { display: inline; }
  .ruo__text { gap: .65rem; font-size: .7rem; white-space: nowrap; }
  .ruo__tag { padding-right: .65rem; letter-spacing: .12em; }
  .ruo__close { right: .45rem; }
}
.ruo__close {
  position: absolute;
  right: max(.75rem, calc((100vw - var(--page)) / 2 - .5rem)); top: 50%;
  translate: 0 -50%;
  display: grid; place-items: center;
  width: 26px; height: 26px;
  color: #C9D6E3;
  opacity: .55;
  transition: opacity .2s, background-color .2s;
}
.ruo__close:hover { opacity: 1; }
.ruo__close svg { width: 9px; height: 9px; stroke: currentColor; stroke-width: 1.6; }


/* ==========================================================================
   Header
   ========================================================================== */

.hdr {
  position: fixed;
  top: var(--ruo-h); left: 0; right: 0;
  z-index: 90;
  color: #E7EDF4;
  height: var(--hdr-h);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 2rem;
  padding-inline: max(1.25rem, calc((100vw - var(--page)) / 2));
  transition: top .38s var(--ease-out), background-color .5s linear,
              border-color .5s linear;
  border-bottom: 1px solid transparent;
}

.hdr__logo {
  display: flex;
  align-items: center;
  gap: .6rem;
  text-decoration: none;
}
.hdr__mark { height: 38px; width: auto; flex: none; }
.hdr__word { height: 24px; width: auto; flex: none; }
/* The supplied artwork is chrome rendered for white. Against the dark scenes
   it needs a little lift so the silver still reads as metal. */
.hdr__mark, .hdr__word { filter: brightness(1.12) contrast(1.08) drop-shadow(0 1px 2px rgba(0,0,0,.6)); }

.hdr__nav {
  justify-self: center;
  display: flex;
  gap: 2.2rem;
}
.hdr__nav a {
  position: relative;
  font-size: .9rem;
  text-decoration: none;
  color: #E7EDF4;
  padding-block: .35rem;
  transition: color .5s linear;
}
.hdr__nav a::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--brand-blue-pale);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .26s var(--ease-out), background-color .5s linear;
}
.hdr__nav a:hover::after, .hdr__nav a:focus-visible::after { transform: scaleX(1); }
.hdr.is-scene .hdr__nav a { color: var(--scene-ink); }
.hdr.is-scene .hdr__nav a::after { background: var(--scene-accent); }

.cartbtn {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .55rem .95rem;
  border: 1px solid color-mix(in srgb, currentColor 26%, transparent);
  border-radius: 2px;
  transition: color .5s linear, border-color .28s, background-color .28s;
}
.cartbtn:hover { background: color-mix(in srgb, currentColor 8%, transparent); }
.cartbtn__icon {
  width: 13px; height: 13px;
  flex: none;
  margin-right: .5em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.hdr.is-scene .cartbtn { color: var(--scene-ink); }
.cartbtn__n { display: inline-block; transition: color .35s linear; }
.cartbtn__n.has-items { color: var(--cart-accent, var(--scene-accent)); }
.hdr.is-lab .cartbtn__n.has-items { color: var(--cart-accent, var(--brand-blue-pale)); }

/* Header states */
.hdr.is-lab    { background: linear-gradient(to bottom, rgba(0,0,0,.55), transparent); }
.hdr.is-descent{ background: rgba(4,6,10,.55); }
.hdr.is-scene  {
  background: rgba(4,6,10,.62);
  border-bottom-color: color-mix(in srgb, var(--scene-accent) 22%, transparent);
}
.hdr.is-descent .hdr__nav a, .hdr.is-descent .cartbtn { color: #fff; }

/* The catalogue and compound pages are not the film; the bar is solid from the
   first pixel rather than fading up out of a scene. */
.hdr.is-page {
  background: rgba(5, 8, 11, .82);
  backdrop-filter: blur(16px);
  border-bottom-color: rgba(255,255,255,.08);
}
.hdr__nav a[aria-current="page"] { color: var(--scene-accent); }
.hdr__nav a[aria-current="page"]::after { transform: scaleX(1); background: var(--scene-accent); }

.hdr__actions { display: flex; align-items: center; gap: .6rem; }

/* The phone menu button. Two bars that cross when the panel is open. */
.navbtn {
  display: none;
  width: 38px; height: 38px;
  place-items: center;
  border: 1px solid color-mix(in srgb, currentColor 26%, transparent);
  border-radius: 2px;
  position: relative;
}
.navbtn span {
  position: absolute;
  left: 50%; top: 50%;
  width: 16px; height: 1.4px;
  background: currentColor;
  translate: -50% -50%;
  transition: transform .28s var(--ease-out), opacity .2s;
}
.navbtn span:first-child { transform: translateY(-4px); }
.navbtn span:last-child  { transform: translateY(4px); }
.nav-open .navbtn span:first-child { transform: rotate(45deg); }
.nav-open .navbtn span:last-child  { transform: rotate(-45deg); }

@media (max-width: 900px) {
  /* `.hdr__nav { display: none }` left the cart sitting in the 1fr column the
     nav had vacated, which parked it against the logo in the middle of the bar
     instead of at the end of it. The actions now name their own column. */
  .hdr { grid-template-columns: auto 1fr auto; }
  .hdr__actions { grid-column: 3; justify-self: end; }
  .navbtn { display: grid; }
  .cartbtn__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .cartbtn { padding: .5rem .7rem; }

  /* The nav becomes a panel under the bar rather than disappearing. A phone
     had no route to the catalogue at all while these were simply hidden. */
  /* Positioned against the header, not the viewport. An out-of-flow child of a
     grid container is laid out in its GRID AREA — so `left: 0; right: 0` gave
     it the width of the middle column, 128px of it, floating in the centre of
     the screen. Spanning every column first is what makes those two zeroes mean
     the header, and the negative margin then carries it past the header's own
     side padding to the edges of the screen. */
  .hdr__nav {
    position: absolute;
    grid-column: 1 / -1;
    grid-row: 1;
    justify-self: stretch;
    top: 100%;
    left: 0; right: 0;
    display: grid;
    gap: 0;
    margin-inline: calc(-1 * max(1.25rem, (100vw - var(--page)) / 2));
    padding: .5rem max(1.25rem, calc((100vw - var(--page)) / 2)) 1.1rem;
    /* Opaque, and no blur of its own. The header above it already carries a
       backdrop-filter, and a nested one composites against a backdrop that has
       itself been filtered — which is both slower and, on the scenes, visibly
       different from the bar it hangs off. */
    background: #080B0F;
    border-bottom: 1px solid color-mix(in srgb, var(--scene-accent) 20%, transparent);
    transform-origin: top;
    transition: opacity .24s var(--ease-out), transform .28s var(--ease-out), visibility .28s;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
  }
  .nav-open .hdr__nav { opacity: 1; visibility: visible; transform: none; }
  .hdr__nav a {
    padding-block: .85rem;
    font-size: 1rem;
    border-bottom: 1px solid rgba(255,255,255,.07);
  }
  .hdr__nav a:last-child { border-bottom: 0; }
  .hdr__nav a::after { display: none; }
}

/* ==========================================================================
   Compound rail
   ========================================================================== */

.rail {
  position: fixed;
  z-index: 80;
  right: max(1rem, calc((100vw - var(--page)) / 2 - 2.75rem));
  top: 50%;
  translate: 0 -50%;
  display: grid;
  padding-right: 14px;          /* room for the track, so dashes clear it */
  opacity: 0;
  pointer-events: none;
  transition: opacity .45s;
}
.rail.is-on { opacity: 1; pointer-events: auto; }

/* The track and its progress fill sit on a fixed x, which is what makes every
   dash line up — previously the dash preceded a variable-width label in a
   right-aligned row, so each one landed at a different position. */
.rail__track {
  position: absolute;
  right: 0; top: .45rem; bottom: .45rem;
  width: 1px;
  background: color-mix(in srgb, var(--scene-ink-dim) 16%, transparent);
}
.rail__fill {
  position: absolute;
  inset: 0 0 auto 0;
  width: 1px;
  height: 100%;
  background: var(--scene-accent);
  opacity: .7;
  transform-origin: top;
  transform: scaleY(var(--rail-p, 0));
  transition: transform .25s linear, background-color .45s linear;
}

.rail__item {
  display: grid;
  grid-template-columns: 1fr 34px;   /* fixed dash column = perfect alignment */
  align-items: center;
  gap: .85rem;
  padding: .62rem 0;
  text-decoration: none;
  color: var(--scene-ink-dim);
  border-radius: 3px;
  transition: color .35s;
}
.rail__item:focus-visible { outline-offset: 4px; }

.rail__label {
  justify-self: end;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: .4;
  transition: opacity .3s, letter-spacing .35s var(--ease-out);
}

/* Full-width dash scaled from its right edge: the animation is a transform, so
   it stays composited and the right edge never moves out of alignment. */
.rail__dash {
  justify-self: end;
  width: 34px;
  height: 1px;
  background: currentColor;
  opacity: .32;
  transform: scaleX(.38);
  transform-origin: right;
  transition: transform .38s var(--ease-out), opacity .3s;
}

.rail__item:hover .rail__label { opacity: .8; }
.rail__item:hover .rail__dash { transform: scaleX(.68); opacity: .6; }

.rail__item.is-active { color: var(--scene-accent); }
.rail__item.is-active .rail__label { opacity: 1; letter-spacing: .2em; }
.rail__item.is-active .rail__dash { transform: scaleX(1); opacity: 1; }

@media (max-width: 1100px) { .rail__label { display: none; } .rail__item { grid-template-columns: 34px; } }
@media (max-width: 900px)  { .rail { display: none; } }

/* ==========================================================================
   §A  Hero — the opening frame
   ========================================================================== */

/* The opening is one scroll container holding one backdrop. Its height is the
   hero beat plus the reveal beat; the stage sticks across all of it and lets
   go exactly as the sequence finishes. */
.opening { position: relative; background: #000; }

.opening__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: #000;
  z-index: 0;
}

/* Poster for the canvas: the same first frame as a plain background image, so
   the opening paints before the sequence engine has run. The canvas fades over
   it once frame 1 is decoded, at the same framing, so the swap is invisible. */
.opening__flight, .opening__frame {
  position: absolute;
  inset: 0;
  will-change: transform;
}
/* So the frame can close into a circle on the way out rather than staying a
   shrinking rectangle. */
.opening__flight { overflow: hidden; }
.opening__plate {
  position: absolute;
  inset: 0;
  background: url('assets/seq/frame_001.webp') center / cover no-repeat, #000;
}
.opening__canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  display: block;
  opacity: 0;
  transition: opacity .3s linear;
}
.opening__canvas.is-ready { opacity: 1; }

/* Two scrims over one backdrop: the hero's side gradient carries the opening
   copy, the vignette carries the reveal lines. They cross-fade on the handoff
   rather than each belonging to its own section. */
.opening__scrim, .opening__vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.opening__scrim {
  background:
    linear-gradient(100deg, rgba(0,0,0,.92) 0%, rgba(0,0,0,.72) 42%, rgba(0,0,0,.25) 78%),
    linear-gradient(to bottom, rgba(0,0,0,.7) 0%, transparent 30%, rgba(0,0,0,.85) 100%);
}
/* What the collapsing frame becomes. Fixed, not absolute: the stage is scrolling
   away underneath during the whole departure, and the star has to be able to
   hold the centre of the *screen* rather than travel with it. */
/* Sits 18% of the screen above centre, not at it. The frame collapses to the
   middle of the *stage*, and by the moment of the swap the stage has already
   scrolled that far up — a star parked at the middle of the *viewport* appears
   below the point the droplet just closed into. This is where the collapse
   actually lands. */
.opening__star {
  position: fixed;
  left: 50%; top: 32%;
  width: 16px; height: 16px;
  margin: -8px 0 0 -8px;
  z-index: 85;             /* over the rising scene, under the header (90) */
  opacity: 0;
  pointer-events: none;
}
.opening__star::before,
.opening__star::after { content: ''; position: absolute; }
.opening__star::before {
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #DCEEFF 32%, rgba(130,195,255,.55) 58%, transparent 74%);
  box-shadow: 0 0 26px 7px rgba(140,200,255,.5);
}
/* The tail trails back along the path, and only exists while there is a path to
   trail along — it is faded in with the break to the right, so the star has none
   while it is holding still. */
.opening__star::after {
  left: 50%; top: 50%;
  width: 200px; height: 2px;
  transform-origin: 0 50%;
  transform: rotate(201deg);   /* back up the right-and-down path it is on */
  background: linear-gradient(to right, rgba(190,225,255,.8), transparent);
  filter: blur(1px);
  opacity: var(--tail, 0);
}

.opening__vignette {
  opacity: 0;
  background:
    linear-gradient(to bottom, #000 0%, transparent 18%),
    linear-gradient(to top, #000 0%, transparent 22%),
    radial-gradient(125% 95% at 50% 50%, transparent 34%, rgba(0,0,0,.72) 100%);
}

/* Pulled back over the sticky stage — the stage owns the first viewport of
   flow, the hero copy sits on top of it rather than after it. */
.hero {
  position: relative;
  z-index: 2;
  margin-top: -100svh;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: calc(var(--hdr-h) + 5rem) 6rem;
  color: #EEF3F8;
  pointer-events: none;
}
.hero a, .hero button { pointer-events: auto; }

.hero__inner {
  position: relative;
  z-index: 3;
  width: var(--page);
  margin-inline: auto;
}

.hero__eyebrow {
  margin: 0 0 clamp(1.4rem, 2.6vw, 2.2rem);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  color: var(--brand-blue-pale);
}

.hero__h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.9rem, 7.4vw, 6.6rem);
  line-height: .95;
  letter-spacing: -.035em;
  max-width: 16ch;
}
.line { display: block; overflow: hidden; padding-bottom: .06em; }
.line__in {
  display: block;
  will-change: transform;
  background: var(--chrome-grad);
  background-size: 100% 360%;
  background-position: 0 calc(var(--i, 0) * 50%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .line__in { color: var(--chrome-mid); background: none; }
}

.hero__sub {
  margin: clamp(1.6rem, 3vw, 2.4rem) 0 0;
  max-width: 46ch;
  color: rgba(238, 243, 248, .72);
}

.hero__cta {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding: .95rem 1.5rem;
  border: 1px solid rgba(238, 243, 248, .26);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .82rem;
  letter-spacing: .14em;
  text-decoration: none;
  color: #EEF3F8;
  transition: border-color .26s, background-color .26s;
}
.hero__cta:hover { border-color: var(--brand-blue-pale); background: rgba(147, 182, 212, .1); }
.hero__chev { width: 12px; height: 17px; fill: none; stroke: var(--brand-blue-pale); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

.hero__meta {
  position: absolute;
  z-index: 3;
  left: max(1.25rem, calc((100vw - var(--page)) / 2));
  bottom: 2rem;
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .2em;
  color: rgba(238, 243, 248, .34);
}
@media (max-width: 700px) { .hero__meta { display: none; } }

/* ==========================================================================
   §B  The Reveal — scroll-scrubbed frame sequence
   ========================================================================== */

/* Pure scroll distance for the sequence — the stage above paints all of it. */
.reveal { height: 320vh; }

.reveal__copy {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding-inline: 1.5rem;
  pointer-events: none;
}
.reveal__line {
  grid-area: 1 / 1;
  margin: 0;
  max-width: 17ch;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.75rem, 4.1vw, 3.5rem);
  line-height: 1.1;
  letter-spacing: -.03em;
  color: #F4F8FF;
  text-shadow: 0 2px 60px rgba(0,0,0,.8);
  opacity: 0;
}

@media (max-width: 900px) { .reveal { height: 280vh; } }
/* The phone intro plays on a clock, so it needs no scroll distance at all. */
.auto-intro .reveal { height: 0; }


/* --- Per-compound palettes ------------------------------------------------
   Scoped to the scene, never to :root, so a scene's colour is fixed for its
   whole life on screen. Scrolling back up cannot recolour it. */
[data-scene="ghk"]  .scene { --scene-bg:#030605; --scene-fog:#0D2019; --scene-accent:#D98A55; --scene-rim:#5FE0BC; --scene-ink:#F2F6F4; --scene-ink-dim:#9FB3AC; }
[data-scene="bpc"]  .scene { --scene-bg:#060302; --scene-fog:#250B07; --scene-accent:#F04A38; --scene-rim:#FFB765; --scene-ink:#FBF2EE; --scene-ink-dim:#C7A198; }
[data-scene="tb"]   .scene { --scene-bg:#02030A; --scene-fog:#0A1533; --scene-accent:#4E88FF; --scene-rim:#7CE8FF; --scene-ink:#EEF4FF; --scene-ink-dim:#93A8CC; }
[data-scene="reta"] .scene { --scene-bg:#060402; --scene-fog:#241906; --scene-accent:#F0B647; --scene-rim:#FFEEC4; --scene-ink:#FFF8EA; --scene-ink-dim:#C4AC7E; }

/* ==========================================================================
   §C–§F  Scenes
   ========================================================================== */

/* Height is the chapter's scroll budget. The scene is pinned for (height − 100vh)
   of it and then takes a fixed 100vh to travel out, so the taller it is, the
   larger the share you spend looking at the compound rather than moving between
   compounds. */
.chapter { position: relative; height: 200vh; }

.scene {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
  background: var(--scene-bg);
}

.scene > * { position: absolute; inset: 0; }

/* z0 — the void. Near-black everywhere; the compound's colour arrives as light
   on the bubble and as bloom behind the vial, never as a wash over the frame. */
.scene__sky {
  background:
    radial-gradient(58% 40% at 50% 76%, color-mix(in srgb, var(--scene-fog) 85%, transparent) 0%, transparent 72%),
    var(--scene-bg);
}


/* z1 — starfield. Two seamless 512px tiles drifting at different speeds, which
   reads as depth. The loop translates by exactly one tile so it never seams,
   and because it is a pure transform the compositor owns it: no per-frame
   paint, unlike the canvas particle field this replaces. */
.scene__stars {
  overflow: hidden;
  pointer-events: none;
  display: none;
}
.chapter.stars-on .scene__stars { display: block; }
.scene__stars i {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: calc(100% + 512px);
  background-repeat: repeat;
  background-size: 512px 512px;
  will-change: transform;
}
.scene__stars i {
  background-image: url('assets/layers/stars.webp');
  animation: starDrift 150s linear infinite;
  opacity: .62;
}
@keyframes starDrift {
  from { transform: translate3d(0, -512px, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .scene__stars i { animation: none; }
}

/* z5.5 — THE BLOOM. A pool of the compound's own light behind the vial. This
   is what the whole scene is built around: the silhouette reads against it. */
.scene__halo {
  top: auto;
  left: var(--halo-x, 50%);
  bottom: 8%;
  width: min(58vw, 780px);
  height: min(58vw, 780px);
  inset-inline: auto;
  translate: -50% 0;
  background:
    radial-gradient(closest-side,
      color-mix(in srgb, var(--scene-rim) 62%, transparent) 0%,
      color-mix(in srgb, var(--scene-accent) 30%, transparent) 38%,
      transparent 72%);
  opacity: 0;
  pointer-events: none;
}

/* z7 — the water the compound stands on.

   It was a slab of tree roots, then briefly a sphere; a vial balanced on top of
   a ball reads as a trick rather than a display, which is what sent it back.
   Still water is the honest version of the same idea: a plinth with no edges,
   made of the one substance a peptide vial actually belongs to, and it holds
   the vial at a real waterline instead of at a tangent point.

   There is no cutout and no alpha, and that is the whole trick. The plate was
   rendered against true black and is composited with `screen`, under which
   black is the identity: every pixel that should not be there contributes
   exactly nothing, and only the ripple crests, the contact caustic and the
   motes survive. A matted plate would have carried a halo along every soft
   edge, and on water almost every edge is soft.

   `isolation` plus `mix-blend-mode` on the same element is deliberate: the
   element screens onto the scene as a whole, while its own two layers blend
   with each other privately inside it. That is what lets the tint below
   multiply the water without ever touching the void around it — multiplied
   black is still black, and black screens to nothing. */
.scene__ground {
  top: auto; bottom: 0;
  height: 100%;
  isolation: isolate;
  mix-blend-mode: screen;
  will-change: transform;
  pointer-events: none;
}
.scene__ground::before,
.scene__ground::after {
  content: '';
  position: absolute;
  left: var(--water-x, 50%);
  bottom: var(--water-line);
  /* Bottom edge parked on the waterline, then pushed back down by the height of
     the ring centre above that edge — which lands the ring centre exactly on
     the line. The vial's base is on the same line, so the innermost ripple
     closes around the glass rather than near it. */
  translate: -50% var(--water-focus);
  width: var(--water-size);
  aspect-ratio: var(--water-ar);
}
/* The plate's own ripples reach its edges, so at any size where the rings are
   big enough to matter they were also running off the side of the frame and
   ending on a cut. An elliptical fade centred on the ring centre takes them out
   the way water does — by running out of energy — and it follows the same
   flattened ellipse the rings do, because `closest-side` on a 2.77:1 box is
   that ellipse. It also kills the faint haze the generator left along the left
   edge, which was reading as a horizon line. */
.scene__ground::before,
.scene__ground::after {
  -webkit-mask-image: radial-gradient(closest-side at 50% 60.6%,
    #000 40%, rgba(0,0,0,.5) 66%, transparent 90%);
  mask-image: radial-gradient(closest-side at 50% 60.6%,
    #000 40%, rgba(0,0,0,.5) 66%, transparent 90%);
}
.scene__ground::before {
  background: var(--water) center / contain no-repeat;
  /* Water is never quite still. A slow, tiny swell — a few percent, nine
     seconds out and back — is the difference between a surface and a decal.
     It rides on the `scale` property rather than on `transform`, which GSAP is
     already using for the parallax; the two compose instead of overwriting. */
  animation: waterSwell 9s ease-in-out infinite alternate;
}
@keyframes waterSwell {
  from { scale: 1 1; }
  to   { scale: 1.035 1.05; }
}
/* The scene's own light, pooled where the vial meets the surface and falling
   off across the rings. Multiply rather than screen: the crests are already the
   brightest thing in the frame and adding to them only washed them out. Taking
   colour out of white light is how water is tinted. */
.scene__ground::after {
  background: radial-gradient(38% 62% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 92%, white) 0%,
    color-mix(in srgb, var(--scene-accent) 58%, white) 44%,
    transparent 82%);
  mix-blend-mode: multiply;
  opacity: .85;
}

.scene__stage {
  top: auto;
  bottom: 0;
  height: 100%;
  perspective: 1400px;
  pointer-events: none;
}

/* Contact. On the root plinth this was a shadow — the vial occluded the light
   and the granite went dark under it. Water does not take light away, it
   gathers it, so the same job is now a bright pool of caustic spreading from
   the waterline. A dark ellipse painted on lit water read as a hole in it.

   It is wider than the vial and heavily blurred, because on a flat surface the
   contact light spreads outward along the plane. It is also the element that
   ties the vial to the plate: the plate's own rings are generated art and land
   wherever they land, while this is drawn at the vial's exact x. */
.scene__shadow {
  position: absolute;
  left: 50%;
  bottom: var(--water-line);
  width: calc(var(--vial-h) * 0.56);
  height: clamp(14px, 1.7vw, 28px);
  translate: -50% 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 62%, transparent) 0%,
    color-mix(in srgb, var(--scene-rim) 22%, transparent) 46%,
    transparent 78%);
  mix-blend-mode: screen;
  filter: blur(7px);
  opacity: 0;
}

.scene__rise  { position: absolute; inset: 0; transform-style: preserve-3d; }
.scene__tilt  { position: absolute; inset: 0; transform-style: preserve-3d; }
.scene__float {
  position: absolute;
  left: 50%; bottom: var(--water-line);
  translate: -50% 0;
  height: var(--vial-h);
  width: auto;
  aspect-ratio: var(--vial-ar);
}

.scene__float picture { display: block; height: 100%; }
.scene__product { width: 100%; height: 100%; object-fit: contain; filter: brightness(.94) contrast(1.02); }

/* The reflection. Nothing says "standing on water" like the thing standing on
   it appearing underneath, and no amount of ripple detail substitutes for it.

   It hangs off the bottom of the float wrapper, so it inherits the idle bob,
   the mouse tilt and the launch transform along with the vial and can never
   drift out of register with it. The mask lives on the wrapper and the flip on
   the image inside, because a mask and a flip on the same element would be
   applied in the same coordinate space and the fade would run upwards. */
.scene__mirror {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  aspect-ratio: var(--vial-ar);
  overflow: hidden;
  /* Faint and short. A crisp mirror image is the one thing that reads as glass
     rather than as water — at the first pass the label was legible upside down,
     which turns the reflection into a second copy of the product competing with
     the real one. It only has to say "there is something underneath". */
  opacity: .2;
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.8) 0%, transparent 30%);
  mask-image: linear-gradient(to bottom, rgba(0,0,0,.8) 0%, transparent 30%);
  pointer-events: none;
}
.scene__mirror img {
  display: block;
  width: 100%;
  height: auto;
  /* Squashed as well as flipped: the camera is looking across the surface, so
     the reflection is foreshortened the same way the ripple rings are. */
  transform: scaleY(-.62);
  transform-origin: top center;
  /* Water is not a mirror. It scatters, so the reflection loses its edges and
     most of its colour long before it loses its shape. */
  filter: blur(5px) saturate(.4) brightness(.8);
}

/* z13 — copy */
.scene__copy {
  display: grid;
  align-content: center;
  width: var(--page);
  inset: 0 auto 0 50%;
  translate: -50% 0;
  pointer-events: none;
}
.scene__copy-in {
  width: min(46ch, 42%);
  pointer-events: auto;
}
@media (min-width: 901px) {
  .scene__copy { padding-right: 9.5rem; }
}
@media (min-width: 901px) and (max-width: 1100px) {
  .scene__copy { padding-right: 4.5rem; }
}
[data-side="left"] .scene__copy-in { justify-self: start; }
[data-side="right"] .scene__copy-in { justify-self: end; }
/* The vial sits opposite the copy so neither ever covers the other. */
[data-side="left"]  .scene__float { left: 72%; }
[data-side="right"] .scene__float { left: 28%; }
[data-side="left"]  .scene__shadow { left: 72%; }
[data-side="right"] .scene__shadow { left: 28%; }
/* The water is centred on the vial rather than pushed to the far edge. The
   ripples spread from the point the vial touches the surface, so that point is
   not a composition choice — it is wherever the vial is. */
[data-side="left"]  .scene { --halo-x: 72%; --water-x: 72%; }
[data-side="right"] .scene { --halo-x: 28%; --water-x: 28%; }

.pname {
  margin: .5rem 0 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.4rem, 5.5vw, 4.75rem);
  line-height: .96;
  letter-spacing: -.02em;
  font-stretch: 108%;
}
/* Eleven letters with an M and an O in them do not fit the copy column at the
   display size, and the dose was the thing that fell off: it wrapped onto a
   line of its own under the name. Long names step down one size instead. */
.pname--long { font-size: clamp(2.2rem, 4.4vw, 3.9rem); }
.pname__dose {
  white-space: nowrap;
  font-size: .3em;
  font-weight: 400;
  letter-spacing: .08em;
  vertical-align: .9em;
  margin-left: .3em;
}

.pdata {
  margin: .9rem 0 0;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  color: var(--scene-ink-dim);
  position: relative;
  padding-bottom: .7rem;
}
.pdata::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: color-mix(in srgb, var(--scene-accent) 55%, transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .5s var(--ease-out);
}
.scene__copy-in:hover .pdata::after,
.scene__copy-in:focus-within .pdata::after { transform: scaleX(1); }

.pbody {
  margin: 1.35rem 0 0;
  max-width: 46ch;
  color: var(--scene-ink);
  text-shadow: 0 1px 22px color-mix(in srgb, var(--scene-bg) 92%, transparent);
}

.evidence {
  display: inline-block;
  margin: 1.5rem 0 0;
  padding: 4px 10px;
  border: 1px solid color-mix(in srgb, var(--scene-accent) 40%, transparent);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .2em;
  color: var(--scene-accent);
}

.btns { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.9rem; }

.btn {
  position: relative;
  overflow: hidden;
  padding: .95rem 1.45rem;
  border-radius: 2px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .82rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform .22s var(--ease-out), filter .22s, border-color .22s, opacity .22s;
}
.btn--ghost {
  border: 1px solid color-mix(in srgb, var(--scene-ink) 30%, transparent);
  color: var(--scene-ink);
}
.btn--ghost::before {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--scene-accent) 12%, transparent);
  clip-path: inset(0 100% 0 0);
  transition: clip-path .24s var(--ease-out);
}
.btn--ghost:hover { border-color: color-mix(in srgb, var(--scene-accent) 70%, transparent); }
.btn--ghost:hover::before { clip-path: inset(0 0 0 0); }
.btn--fill {
  background: var(--scene-accent);
  color: #0B0D0C;
  border: 1px solid var(--scene-accent);
}
.btn--fill:hover { filter: brightness(1.12); transform: translateY(-1px); }
.btn--fill[disabled] { opacity: .45; cursor: not-allowed; filter: none; transform: none; }
.btn--block { width: 100%; }
.btn > span, .btn__label { position: relative; }

/* While the compounds hold the input, the page is not a scroll, and the two
   things the browser does at the ends of a scroll — rubber-band on a trackpad,
   swipe-to-go-back on a phone — are both triggered by gestures we are
   deliberately swallowing. Neither should fire behind a page that is not
   moving. Set by stepper() in main.js. */
.is-stepping, .is-stepping body { overscroll-behavior: none; }

@media (max-width: 900px) {
  /* The opening plate is the LCP element; a phone gets the 640px version. */
  .opening__plate { background-image: url('assets/seq/frame_001@sm.webp'); }
  .chapter { height: 180vh; }
  /* `[data-side]` so this actually wins. The side rules that place the vial
     left or right are attribute-plus-class and outrank a bare `.scene`, media
     query or no — a phone has one column and neither the water nor the bloom
     has anywhere to go but the middle of it. */
  [data-side] .scene {
    --halo-x: 50%;
    --water-x: 50%;
    /* Wider than the viewport, deliberately. The rings have to run off both
       edges or the waterline stops looking like a surface and starts looking
       like a puddle with a rim — and a phone is too narrow for the outer rings
       to fade out inside the frame. */
    --water-size: 128vw;
    --water-line: 56%;
  }
  /* Vial and water own the top half, copy the bottom — same scene, restacked. */
  .scene__copy { align-content: end; padding-right: 0; padding-bottom: 5vh; }
  .scene__copy-in { width: 100%; justify-self: stretch !important; }
  /* Height, not width, for the same reason as on desktop — and it has to be.
     This rule used to pin the width at 96px while the desktop rule was already
     setting a height, so the box came out 96px wide and a third of a screen
     tall. The vial filled its width and sat at the TOP of that box, so its base
     hung 70-odd pixels above the waterline and the ripples spread from empty
     water under it. */
  .scene__float { left: 50% !important; }
  :root { --vial-h: clamp(190px, 29svh, 270px); }
  .scene__shadow { left: 50% !important; height: 14px; }
  .scene__halo { bottom: 34%; width: 116vw; height: 116vw; }
  /* Nothing to fade out any more: the plate already ends in black, and black is
     the edge. The mask that used to hide the plinth's cut-off bottom would now
     eat the near half of the water. */
  .scene__fore { height: 40%; bottom: -14%; }
  .scene__far { bottom: 46%; height: 34%; }
  .scene__mid { bottom: 42%; height: 70%; }
  .scene__vignette { background: radial-gradient(110% 62% at 50% 34%, transparent 0%, transparent 34%, #000 100%); }
  .pname { font-size: clamp(2.1rem, 10vw, 3rem); }
  .pbody { text-shadow: 0 1px 26px var(--scene-bg), 0 1px 4px var(--scene-bg); }
  .btns { margin-top: 1.4rem; }
  .evidence { margin-top: 1.1rem; }
}

/* ==========================================================================
   §G  Ascent / Research note
   ========================================================================== */

.ascent {
  position: relative;
  background: #05070A;
  color: #E7EDF4;
  padding: clamp(7rem, 14vh, 11rem) 0 clamp(5rem, 9vh, 8rem);
  overflow: hidden;
}
/* The void settling as the film ends. */
.ascent__rise {
  position: absolute;
  inset: 0 0 auto 0;
  height: 40vh;
  background: linear-gradient(to bottom, #000 0%, #05070A 100%);
}

.ascent__inner { position: relative; width: var(--page); margin-inline: auto; }

.ascent__h2 {
  margin: 0 0 clamp(2.5rem, 5vw, 4rem);
  max-width: 18ch;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 4.4vw, 3.6rem);
  line-height: 1.02;
  letter-spacing: -.025em;
}

.note {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.8rem, 4vw, 3.4rem);
  padding-top: 2.2rem;
  border-top: 1px solid rgba(255,255,255,.1);
}
.note__h3 {
  margin: 0 0 .9rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--brand-blue-pale);
}
.note p { margin: 0; font-size: .95rem; color: rgba(231,237,244,.74); }
.note em { font-style: italic; }

.ledger {
  list-style: none;
  margin: clamp(3rem, 6vw, 4.5rem) 0 0;
  padding: 0;
  border-top: 1px solid rgba(255,255,255,.1);
}
.ledger li { border-bottom: 1px solid rgba(255,255,255,.1); }
.ledger li > * {
  display: grid;
  grid-template-columns: 12rem 1fr 4rem;
  align-items: center;
  gap: 1.5rem;
  padding: 1.05rem 0;
  text-decoration: none;
  transition: padding-left .28s var(--ease-out);
}
.ledger li a:hover { padding-left: .6rem; }
.ledger li a:hover .ledger__k { color: var(--scene-accent); }
.ledger__k { transition: color .22s; }
.ledger__k {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -.01em;
}
.ledger__v {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(231,237,244,.56);
}
/* Three ticks: how far the evidence actually goes. */
.ledger__b {
  --n: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3px;
  height: 3px;
}
.ledger__b::before, .ledger__b::after, .ledger__b { }
.ledger__b { position: relative; background: none; }
.ledger__b::before {
  content: '';
  grid-column: 1 / 4;
  height: 3px;
  background:
    linear-gradient(to right, var(--brand-blue-pale) 0 calc(var(--n) / 3 * 100%), rgba(255,255,255,.14) calc(var(--n) / 3 * 100%) 100%);
}
.ledger__b--1 { --n: 1; }
.ledger__b--2 { --n: 2; }
.ledger__b--3 { --n: 3; }

.ascent__fine {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  max-width: 72ch;
  font-size: .84rem;
  color: rgba(231,237,244,.5);
}

@media (max-width: 900px) {
  .note { grid-template-columns: 1fr; }
  .ledger li { grid-template-columns: 1fr; gap: .35rem; }
  .ledger__b { max-width: 4rem; }
}

/* ==========================================================================
   Footer
   ========================================================================== */

.ftr {
  background: #0B0E11;
  color: #C9CFD6;
  padding: clamp(3.5rem, 7vw, 5.5rem) 0 1.5rem;
}
.ftr__top {
  width: var(--page);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: clamp(1.8rem, 4vw, 3rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
.ftr__mark { width: auto; height: 82px; margin-bottom: 1.4rem; filter: brightness(1.28); }
.ftr__tag {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.1rem;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: #EDF1F5;
}
.ftr h4 {
  margin: 0 0 1.1rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .64rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--brand-blue-pale);
}
.ftr__nav { display: grid; gap: .55rem; align-content: start; }
.ftr__nav a {
  font-size: .89rem;
  text-decoration: none;
  color: #A7B0BA;
  width: fit-content;
  transition: color .2s;
}
.ftr__nav a:hover { color: #fff; }
.ftr__legal p { margin: 0; font-size: .84rem; color: #949DA6; line-height: 1.7; }

.ftr__bar {
  width: var(--page);
  margin-inline: auto;
  padding-top: 1.4rem;
  border-top: 1px solid rgba(255,255,255,.09);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .6rem 2rem;
}
.ftr__bar p {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: #949DA6;
}
.ftr__bar a { text-decoration: none; }
.ftr__bar a:hover { color: #fff; }

@media (max-width: 900px) { .ftr__top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .ftr__top { grid-template-columns: 1fr; } }

/* ==========================================================================
   Drawers, scrim, gate
   ========================================================================== */

.drawer[hidden], .scrim[hidden] { display: none; }

.scrim {
  position: fixed;
  touch-action: none;
  inset: 0;
  z-index: 100;
  background: rgba(0,0,0,.6);
  opacity: 0;
}

.drawer {
  position: fixed;
  z-index: 110;
  top: var(--ruo-h); right: 0;
  height: calc(100dvh - var(--ruo-h));
  display: flex;
  flex-direction: column;
  background: color-mix(in srgb, #070B0A 82%, transparent);
  backdrop-filter: blur(20px);
  border-left: 1px solid color-mix(in srgb, var(--scene-accent) 24%, transparent);
  color: var(--scene-ink);
}
.drawer--learn { width: min(620px, 100vw); }
.drawer--cart  { width: min(420px, 100vw); }

.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem clamp(1.4rem, 3vw, 2.6rem);
  border-bottom: 1px solid rgba(255,255,255,.09);
  flex: none;
}
/* Scoped past `.drawer p`, which would otherwise win on specificity and give
   the sequence a body font-size and a 1rem bottom margin — the margin sits in
   the flex alignment, tipping it off-centre against the close button. */
.drawer .drawer__seq, .drawer .drawer__close {
  font-family: var(--font-mono);
  font-size: .68rem;
  line-height: 1.2;
  letter-spacing: .2em;
  text-transform: uppercase;
  margin: 0;
}
.drawer__seq { color: var(--scene-accent); }
.drawer__close { color: var(--scene-ink-dim); transition: color .2s; }
.drawer__close:hover { color: var(--scene-ink); }

.drawer__body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(1.2rem, 2.2vw, 1.7rem) clamp(1.4rem, 3vw, 2.6rem) 3rem;
}

.drawer__title {
  margin: 0 0 .5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 4.5vw, 3rem);
  line-height: 1;
  letter-spacing: -.02em;
}
.drawer__data {
  margin: 0 0 2.2rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  color: var(--scene-ink-dim);
}
.drawer h3 {
  margin: 2.2rem 0 .8rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .66rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.drawer h3:first-of-type { margin-top: 0; }
.drawer p { margin: 0 0 1rem; font-size: .95rem; color: color-mix(in srgb, var(--scene-ink) 84%, transparent); }
.drawer ol, .drawer ul { margin: 0; padding-left: 1.1rem; }
.drawer li { margin-bottom: .6rem; font-size: .88rem; color: color-mix(in srgb, var(--scene-ink) 76%, transparent); }
.drawer a { color: var(--scene-rim); text-underline-offset: 3px; }
.drawer .evidence { margin-top: 0; margin-bottom: 2rem; }
.drawer__ruo {
  margin-top: 2.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid rgba(255,255,255,.09);
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}

/* Cart */
.cart__list { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.cart__item {
  display: grid;
  grid-template-columns: 46px 1fr auto;
  gap: 1rem;
  align-items: center;
  padding: 1rem 0;
  border-bottom: 1px solid rgba(255,255,255,.09);
}
.cart__thumb {
  width: 46px; height: 62px;
  object-fit: contain;
  background: rgba(255,255,255,.04);
  border-radius: 2px;
}
.cart__name { font-size: .92rem; margin: 0; }
.cart__sku { margin: .15rem 0 0; font-family: var(--font-mono); font-size: .6rem; letter-spacing: .14em; color: var(--scene-ink-dim); }
.cart__qty { display: flex; align-items: center; gap: .55rem; margin-top: .5rem; }
.cart__qty button {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1;
  transition: border-color .2s, background-color .2s;
}
.cart__qty button:hover { border-color: var(--scene-accent); background: color-mix(in srgb, var(--scene-accent) 14%, transparent); }
.cart__qty span { font-family: var(--font-mono); font-size: .78rem; min-width: 1.4em; text-align: center; }
.cart__price { font-family: var(--font-mono); font-size: .82rem; align-self: start; }
.cart__rm {
  display: block;
  margin-top: .5rem;
  font-family: var(--font-mono);
  font-size: .58rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
  transition: color .2s;
}
.cart__rm:hover { color: var(--scene-accent); }
.cart__empty { font-size: .9rem; color: var(--scene-ink-dim); }
.cart__foot { margin-top: 2rem; }
.cart__sum {
  display: flex;
  justify-content: space-between;
  padding-bottom: 1.2rem;
  font-family: var(--font-mono);
  font-size: .82rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.cart__note { margin: 1rem 0 0; font-size: .74rem; color: var(--scene-ink-dim); }

/* Age gate */
html.qb-verified .gate { display: none; }

.gate {
  position: fixed;
  inset: 0;
  z-index: 140;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: rgba(6, 10, 14, .93);
}
.gate__card {
  width: min(480px, 100%);
  padding: clamp(2rem, 5vw, 3rem);
  background: var(--lab-bg);
  border-radius: 3px;
  box-shadow: 0 32px 90px -20px rgba(10, 20, 32, .55);
  text-align: left;
}
.gate__mark { width: auto; height: 76px; margin-bottom: 1.8rem; }
.gate__title {
  margin: 0 0 1rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 3.4vw, 2rem);
  line-height: 1.08;
  letter-spacing: -.02em;
}
.gate__body { margin: 0 0 2rem; font-size: .95rem; color: color-mix(in srgb, var(--lab-ink) 72%, transparent); }
.gate__btns { display: flex; flex-wrap: wrap; gap: .75rem; }
.gate .btn--fill { background: var(--brand-blue); border-color: var(--brand-blue); color: #fff; }
.gate .btn--ghost { border-color: var(--lab-rule); color: color-mix(in srgb, var(--lab-ink) 62%, transparent); }
.gate .btn--ghost::before { background: color-mix(in srgb, var(--brand-blue) 8%, transparent); }

/* ==========================================================================
   Reduced motion — the settled state of every scene, as a normal page
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .chapter { height: auto; }
  .scene { position: relative; height: auto; min-height: 100svh; padding-block: 6rem; }
  .scene > * { position: absolute; }
  .scene__copy { position: relative; inset: auto; translate: 0; margin-inline: auto; }
  .scene__stage { position: absolute; }
  .descent { height: auto; }
  .descent__stage { position: relative; height: 48vh; }
  .descent__drain { --drain: 60%; }
  .scene__fog { animation: none; }
  .hero__chev { animation: none; }
  * { scroll-behavior: auto !important; }
}

/* ==========================================================================
   Flat pages — the catalogue index and the compound pages

   These are not the film. There is no scroll engine, no pinning and no scrubbed
   sequence; what carries over is the world the film is lit in — a near-black
   void, one colour per compound arriving as light rather than as a wash, mono
   for anything a laboratory would call data, and Archivo for anything it would
   call a name.
   ========================================================================== */

body.is-page {
  background:
    radial-gradient(120% 70% at 50% -10%, color-mix(in srgb, var(--scene-fog) 55%, transparent) 0%, transparent 62%),
    #05070A;
  color: var(--scene-ink, #E7EDF4);
  min-height: 100dvh;
}
body.is-page .page {
  padding-top: calc(var(--ruo-h) + var(--hdr-h));
  /* The water plate is deliberately wider than a phone. `overflow-x: clip` on
     <body> does not stop a mobile browser widening its layout viewport to fit
     it — it zoomed the whole page out and pushed the header off the right edge
     — so the clip lives on the page itself, which is full width anyway. */
  overflow-x: clip;
}

/* The drawer animates on GSAP inside the film and on a class everywhere else.
   Both land in the same place; only these pages need the CSS half. */
body.is-page .drawer { transform: translateX(100%); transition: transform .42s var(--ease-out); }
body.is-page .drawer.is-on { transform: none; }
body.is-page .scrim { transition: opacity .3s linear; }
body.is-page .scrim.is-on { opacity: 1; }

.btn--sm { padding: .68rem 1.05rem; font-size: .72rem; letter-spacing: .12em; }

/* --- Breadcrumb ----------------------------------------------------------- */

.crumb {
  margin: 0 0 1.6rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}
.crumb a { text-decoration: none; transition: color .2s; }
.crumb a:hover { color: var(--scene-accent); }
.crumb span { opacity: .4; margin-inline: .45em; }

/* --- Masthead ------------------------------------------------------------- */

.mast { padding: clamp(3rem, 8vh, 6rem) 0 clamp(2rem, 4vh, 3.4rem); }
.mast__in { width: var(--page); margin-inline: auto; }

.mast__h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.6rem, 7vw, 5.4rem);
  line-height: .95;
  letter-spacing: -.025em;
  font-stretch: 108%;
}
.mast__sub {
  margin: 1.4rem 0 0;
  max-width: 62ch;
  font-size: clamp(1rem, 1.3vw, 1.12rem);
  color: color-mix(in srgb, var(--scene-ink) 76%, transparent);
}
.mast__cta { margin-top: 2rem; }

/* --- Filters -------------------------------------------------------------- */

.filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 2.4rem; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .55rem .95rem;
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--scene-ink) 70%, transparent);
  transition: border-color .22s, color .22s, background-color .22s;
}
.chip:hover:not([disabled]) { border-color: rgba(255,255,255,.34); color: var(--scene-ink); }
.chip.is-on {
  border-color: var(--brand-blue-pale);
  background: color-mix(in srgb, var(--brand-blue-pale) 12%, transparent);
  color: #fff;
}
.chip[disabled] { opacity: .3; cursor: not-allowed; }
.chip__n { font-size: .92em; opacity: .55; }

/* --- Grid ----------------------------------------------------------------- */

.grid-wrap { padding-bottom: clamp(3rem, 8vh, 6rem); }
.grid {
  width: var(--page);
  margin-inline: auto;
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(276px, 1fr));
  gap: clamp(1rem, 1.8vw, 1.6rem);
}
.grid__none {
  width: var(--page);
  margin: 2rem auto 0;
  font-family: var(--font-mono);
  font-size: .8rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}
.card[hidden] { display: none; }

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(255,255,255,.09);
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 40%), #06090C;
  overflow: hidden;
  transition: border-color .3s, transform .3s var(--ease-out);
}
.card:hover {
  border-color: color-mix(in srgb, var(--scene-accent) 46%, transparent);
  transform: translateY(-3px);
}

/* The card's art is the scene in miniature: the compound's bloom behind the
   vial, and its light pooled on the surface underneath. Nothing here is a
   photograph of a set — it is the same three layers the film uses. */
/* Absolutely positioned, not a grid item. A percentage height on a grid item
   resolves against an area the browser is still deciding the size of, and it
   silently fell back to the image's intrinsic height — a 650px vial in a 236px
   box. Against a box with a definite aspect ratio it always resolves. */
.card__art {
  position: relative;
  display: block;
  aspect-ratio: 5 / 4;
  background:
    radial-gradient(90% 70% at 50% 108%, color-mix(in srgb, var(--scene-fog) 80%, transparent) 0%, transparent 70%),
    #040608;
  overflow: hidden;
}
.card__halo {
  position: absolute;
  left: 50%; bottom: 6%;
  width: 78%; aspect-ratio: 1;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 26%, transparent) 0%,
    color-mix(in srgb, var(--scene-accent) 10%, transparent) 42%,
    transparent 72%);
  opacity: .9;
  transition: opacity .4s, scale .5s var(--ease-out);
}
.card:hover .card__halo { opacity: 1; scale: 1.06; }
.card__pool {
  position: absolute;
  left: 50%; bottom: 13%;
  width: 56%; height: 10px;
  translate: -50% 50%;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 62%, transparent) 0%,
    transparent 74%);
  filter: blur(5px);
}
.card__art img {
  position: absolute;
  left: 50%; bottom: 13%;
  height: 74%;
  width: auto;
  translate: -50% 0;
  filter: brightness(.96) contrast(1.02);
  transition: transform .5s var(--ease-out);
}
.card:hover .card__art img { transform: translateY(-5px); }

.card__body { display: flex; flex-direction: column; flex: 1; padding: 1.35rem 1.35rem 1.2rem; }
.card__seq {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  color: var(--scene-accent);
  /* Sequences are long and must not wrap a card into a different height. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card__name {
  margin: .5rem 0 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.6rem;
  line-height: 1.05;
  letter-spacing: -.015em;
}
.card__name a { text-decoration: none; }
/* The whole card is the target; the name carries the accessible link. */
.card__name a::after { content: ''; position: absolute; inset: 0; }
.card { position: relative; }
.card__dose { font-size: .58em; font-weight: 400; color: var(--scene-ink-dim); letter-spacing: .04em; }
.card__tag {
  margin: .6rem 0 0;
  font-size: .9rem;
  line-height: 1.5;
  color: color-mix(in srgb, var(--scene-ink) 68%, transparent);
}

.card__tier {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 1rem 0 0;
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}

/* Three ticks: how far the evidence actually goes. Same scale as the ledger on
   the home page, because it is the same claim. */
.card__ticks {
  flex: none;
  width: 34px;   /* 3 segments of 10px, 2 gutters of 2px */
  height: 4px;
  background: linear-gradient(to right,
    var(--scene-accent) 0 calc(var(--n) / 3 * 100%),
    rgba(255,255,255,.15) calc(var(--n) / 3 * 100%) 100%);
  /* The gutters are cut out of both halves at once, so a partly-lit scale never
     shows a lit sliver bleeding into the gap after it. */
  -webkit-mask-image: repeating-linear-gradient(to right, #000 0 10px, transparent 10px 12px);
  mask-image: repeating-linear-gradient(to right, #000 0 10px, transparent 10px 12px);
}
.card__ticks--1 { --n: 1; }
.card__ticks--2 { --n: 2; }
.card__ticks--3 { --n: 3; }

.card__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-top: auto;
  padding-top: 1.3rem;
}
.card__price { font-family: var(--font-mono); font-size: 1.05rem; letter-spacing: .04em; }
/* Above the card's own full-bleed link, so both buttons are actually clickable. */
.card__btns { display: flex; gap: .5rem; position: relative; z-index: 1; }

/* --- Tier definitions ----------------------------------------------------- */

.pagenote {
  border-top: 1px solid rgba(255,255,255,.08);
  padding: clamp(2.6rem, 6vh, 4.5rem) 0 clamp(3rem, 7vh, 5rem);
}
.pagenote__in { width: var(--page); margin-inline: auto; }
.pagenote h2 {
  margin: 0 0 1.8rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--brand-blue-pale);
}
.tierdefs { display: grid; gap: 1.1rem; margin: 0; max-width: 78ch; }
.tierdefs > div { display: grid; grid-template-columns: 11rem 1fr; gap: 1.4rem; align-items: baseline; }
.tierdefs dt {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #fff;
}
.tierdefs dd { margin: 0; font-size: .92rem; color: rgba(231,237,244,.7); }
.pagenote__fine {
  margin: 2.6rem 0 0;
  max-width: 78ch;
  font-size: .78rem;
  line-height: 1.7;
  color: rgba(231,237,244,.44);
}
@media (max-width: 640px) {
  .tierdefs > div { grid-template-columns: 1fr; gap: .3rem; }
}

/* ==========================================================================
   Compound page
   ========================================================================== */

/* --- The composition, held still ------------------------------------------ */

.phero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 46%) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
  width: var(--page);
  margin-inline: auto;
  padding: clamp(2rem, 5vh, 4rem) 0 clamp(2.5rem, 6vh, 4.5rem);
}

.phero__art {
  position: relative;
  aspect-ratio: 4 / 5;
  max-height: 72vh;
  margin-inline: auto;
  width: 100%;
}
/* The void, not a panel. The first pass painted an opaque rectangle behind the
   vial and it read as exactly that — a framed picture dropped onto the page,
   with three hard edges that lined up with nothing. Everything here now fades
   to transparent well inside its own box, so the composition has no border and
   the page's own background is the only thing behind it. */
.phero__sky {
  position: absolute;
  inset: -12% -16% -8%;
  background:
    radial-gradient(58% 46% at 50% 76%, color-mix(in srgb, var(--scene-fog) 88%, transparent) 0%, transparent 72%),
    radial-gradient(76% 62% at 50% 56%, rgba(0,0,0,.72) 0%, transparent 76%);
}
.phero__halo {
  position: absolute;
  left: 50%; bottom: 17%;
  width: 74%; aspect-ratio: 1;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 30%, transparent) 0%,
    color-mix(in srgb, var(--scene-accent) 12%, transparent) 40%,
    transparent 70%);
}
/* Contact. On water the vial does not cast a shadow, it gathers light — the
   same call the film makes, for the same reason. */
.phero__pool {
  position: absolute;
  left: 50%; bottom: 25%;
  width: 46%; height: 16px;
  translate: -50% 50%;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 66%, transparent) 0%,
    color-mix(in srgb, var(--scene-rim) 20%, transparent) 46%,
    transparent 78%);
  filter: blur(7px);
}
.phero__vial {
  position: absolute;
  left: 50%; bottom: 25%;
  height: 68%;
  width: auto;
  translate: -50% 0;
  filter: brightness(.96) contrast(1.02);
  animation: vial-float 4.2s ease-in-out infinite alternate;
}
@keyframes vial-float { to { transform: translateY(-10px); } }

.phero__mirror {
  position: absolute;
  left: 50%; bottom: 25%;
  width: auto; height: 68%;
  translate: -50% 0;
  opacity: .16;
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.85) 0%, transparent 42%);
  mask-image: linear-gradient(to bottom, rgba(0,0,0,.85) 0%, transparent 42%);
  transform: scaleY(-.5);
  transform-origin: bottom center;
  pointer-events: none;
}
.phero__mirror img { height: 100%; width: auto; filter: blur(4px) saturate(.4) brightness(.8); }

@media (prefers-reduced-motion: reduce) { .phero__vial { animation: none; } }

.phero__copy { min-width: 0; }
.phero .pname { margin-top: .4rem; font-size: clamp(2.4rem, 5vw, 4.2rem); }
.pdata--static::after { transform: scaleX(1); }
.phero .pbody { text-shadow: none; }

/* --- Buy ------------------------------------------------------------------ */

.buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.2rem;
  margin-top: 2.2rem;
  padding: 1.3rem 0 0;
  border-top: 1px solid rgba(255,255,255,.1);
}
.buy__price { display: grid; gap: .25rem; }
.buy__amt {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2rem;
  line-height: 1;
  letter-spacing: -.01em;
}
.buy__unit {
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}
.buy__btns { display: flex; flex-wrap: wrap; gap: .7rem; }

.assure {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}
.assure li { display: flex; align-items: center; gap: .5em; }
.assure li::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--scene-accent);
  flex: none;
}

/* --- Body ----------------------------------------------------------------- */

.prod__body {
  width: var(--page);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
  padding-block: clamp(2.5rem, 6vh, 4.5rem);
  border-top: 1px solid rgba(255,255,255,.08);
}

.jump {
  position: sticky;
  top: calc(var(--ruo-h) + var(--hdr-h) + 2rem);
  align-self: start;
  display: grid;
  gap: .2rem;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.jump a {
  padding: .5rem 0 .5rem .9rem;
  border-left: 1px solid rgba(255,255,255,.12);
  color: var(--scene-ink-dim);
  text-decoration: none;
  transition: color .22s, border-color .22s;
}
.jump a:hover { color: var(--scene-ink); border-left-color: var(--scene-accent); }

.prose { min-width: 0; max-width: 72ch; }
.prose section + section { margin-top: clamp(2.4rem, 5vh, 3.6rem); }
.prose section { scroll-margin-top: calc(var(--ruo-h) + var(--hdr-h) + 1.5rem); }
.prose h2 {
  margin: 0 0 1.1rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.prose h3 {
  margin: 2.4rem 0 .9rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--scene-ink) 70%, transparent);
}
.prose p {
  margin: 0 0 1.05rem;
  font-size: 1rem;
  line-height: 1.68;
  color: color-mix(in srgb, var(--scene-ink) 80%, transparent);
}
.prose p:last-child { margin-bottom: 0; }
.prose__ruo {
  margin-top: 1.6rem !important;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(255,255,255,.09);
  font-family: var(--font-mono);
  font-size: .62rem !important;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--scene-ink-dim) !important;
  line-height: 1.75 !important;
}

.tiercard {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-bottom: 1.3rem;
  padding: .85rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--scene-accent) 34%, transparent);
  border-radius: 2px;
  background: color-mix(in srgb, var(--scene-accent) 7%, transparent);
}
.tiercard__label {
  margin: 0 !important;
  font-family: var(--font-mono);
  font-size: .68rem !important;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--scene-accent) !important;
}

/* --- Specification -------------------------------------------------------- */

.spec { margin: 0; display: grid; }
.spec__row {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 1.4rem;
  padding: .78rem 0;
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.spec__row:first-child { border-top: 1px solid rgba(255,255,255,.08); }
.spec dt {
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--scene-ink-dim);
}
.spec dd { margin: 0; font-size: .94rem; color: var(--scene-ink); overflow-wrap: anywhere; }

.spec__note { font-size: .86rem !important; color: var(--scene-ink-dim) !important; }

.tablewrap { overflow-x: auto; }
.assay { width: 100%; border-collapse: collapse; font-size: .86rem; min-width: 30rem; }
.assay th, .assay td { text-align: left; padding: .7rem .9rem .7rem 0; border-bottom: 1px solid rgba(255,255,255,.08); }
.assay thead th {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .6rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.assay tbody th { font-weight: 400; color: var(--scene-ink); }
.assay td { color: color-mix(in srgb, var(--scene-ink) 70%, transparent); }

/* --- References ----------------------------------------------------------- */

.refs { margin: 0; padding-left: 1.3rem; display: grid; gap: .85rem; }
.refs li { font-size: .9rem; line-height: 1.55; color: color-mix(in srgb, var(--scene-ink) 72%, transparent); }
.refs a { color: var(--scene-rim); text-decoration: none; border-bottom: 1px solid color-mix(in srgb, var(--scene-rim) 34%, transparent); transition: border-color .2s; }
.refs a:hover { border-bottom-color: var(--scene-rim); }
.extl { display: inline-block; width: 9px; height: 9px; margin-left: .35em; fill: none; stroke: currentColor; stroke-width: 1.4; vertical-align: baseline; }

/* --- Feedback ------------------------------------------------------------- */

.revs { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.2rem; }
.rev-item { padding: 1.1rem 0; border-bottom: 1px solid rgba(255,255,255,.08); }
.rev-item__head {
  display: flex; flex-wrap: wrap; gap: .8rem;
  margin: 0 0 .5rem !important;
  font-family: var(--font-mono);
  font-size: .62rem !important;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.rev-item__lab { color: var(--scene-accent); }
.rev-item__role, .rev-item time { color: var(--scene-ink-dim); }
.revs__empty {
  padding: 1.3rem 1.4rem;
  border: 1px dashed rgba(255,255,255,.16);
  border-radius: 2px;
  font-size: .9rem !important;
  color: var(--scene-ink-dim) !important;
  margin: 0 !important;
}

/* --- Related -------------------------------------------------------------- */

.rel { border-top: 1px solid rgba(255,255,255,.08); padding-block: clamp(2.6rem, 6vh, 4.2rem); }
.rel__in { width: var(--page); margin-inline: auto; }
.rel__h2 {
  margin: 0 0 1.8rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--brand-blue-pale);
}
.rel__list {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1rem;
}
.rel__item a {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 1rem;
  align-items: center;
  padding: 1rem;
  border: 1px solid rgba(255,255,255,.09);
  border-radius: 3px;
  text-decoration: none;
  transition: border-color .25s, background-color .25s;
}
.rel__item a:hover {
  border-color: color-mix(in srgb, var(--scene-accent) 50%, transparent);
  background: color-mix(in srgb, var(--scene-accent) 5%, transparent);
}
.rel__item img { grid-row: 1 / 3; height: 62px; width: auto; }
.rel__name { font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; align-self: end; }
.rel__dose { font-size: .72em; font-weight: 400; color: rgba(231,237,244,.55); }
.rel__tier {
  align-self: start;
  margin-top: .25rem;
  font-family: var(--font-mono);
  font-size: .56rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.rel__all { margin: 1.8rem 0 0; }

/* --- Sticky buy bar ------------------------------------------------------- */

.buybar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 80;
  background: rgba(5, 8, 11, .9);
  backdrop-filter: blur(18px);
  border-top: 1px solid color-mix(in srgb, var(--scene-accent) 24%, transparent);
  transform: translateY(101%);
  transition: transform .34s var(--ease-out);
}
.buybar.is-on { transform: none; }
.buybar__in {
  width: var(--page);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .7rem 0;
}
.buybar__thumb { width: 34px; height: 46px; object-fit: contain; flex: none; }
.buybar__id { min-width: 0; flex: 1; }
.buybar__name { margin: 0; font-size: .95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buybar__name span { color: var(--scene-ink-dim); font-size: .85em; }
.buybar__tier {
  margin: .1rem 0 0;
  font-family: var(--font-mono);
  font-size: .56rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--scene-accent);
}
.buybar__price { font-family: var(--font-mono); font-size: .95rem; flex: none; }

/* --- Narrow --------------------------------------------------------------- */

@media (max-width: 980px) {
  .prod__body { grid-template-columns: 1fr; }
  /* A rail of anchors is a sidebar; laid flat under the heading it is a row of
     tabs that scrolls, which is the same job in the space a phone has. */
  .jump {
    position: static;
    grid-auto-flow: column;
    grid-template-columns: none;
    justify-content: start;
    gap: .4rem;
    overflow-x: auto;
    padding-bottom: .6rem;
    scrollbar-width: none;
  }
  .jump::-webkit-scrollbar { display: none; }
  .jump a {
    border-left: 0;
    border-bottom: 1px solid rgba(255,255,255,.12);
    padding: .5rem .2rem;
    white-space: nowrap;
  }
  .jump a:hover { border-left: 0; border-bottom-color: var(--scene-accent); }
}

@media (max-width: 860px) {
  .phero { grid-template-columns: 1fr; gap: 1.5rem; padding-top: 1.5rem; }
  .phero__art { aspect-ratio: 1 / 1; max-height: 46vh; order: -1; }
  .phero .pname { font-size: clamp(2.1rem, 9vw, 3rem); }
  .buy { flex-direction: column; align-items: stretch; }
  .buy__btns .btn { flex: 1; }
  .spec__row { grid-template-columns: 1fr; gap: .25rem; }
  .buybar__thumb, .buybar__tier { display: none; }
}


/* --- A compound whose render has not landed yet --------------------------- */

.no-art { position: relative; }
.no-art::after {
  content: 'RENDER PENDING';
  position: absolute;
  left: 50%; top: 50%;
  translate: -50% -50%;
  padding: .5em .8em;
  border: 1px dashed rgba(255,255,255,.22);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: .56rem;
  letter-spacing: .18em;
  color: var(--scene-ink-dim);
  white-space: nowrap;
  pointer-events: none;
}
.rel__item a.no-art, .buybar__in.no-art { position: relative; }
.rel__item a.no-art::after, .buybar__in.no-art::after { display: none; }
.rel__item a.no-art { grid-template-columns: minmax(0, 1fr); }


/* --- The compound page is lit like the film -------------------------------

   The hero is the scene held still, so it gets the scene's two missing
   ingredients: the drifting starfield behind everything, and the water the vial
   stands on. Both are the film's own assets and the film's own compositing —
   stars as a slow compositor-only drift, water as a black-backed plate screened
   onto the dark and tinted by multiply — so the two never look like cousins. */

.phero { isolation: isolate; }
.phero__stars {
  position: absolute;
  z-index: -1;
  left: 50%;
  width: 100vw;
  translate: -50% 0;
  top: calc(-1 * (var(--ruo-h) + var(--hdr-h)));
  bottom: 0;
  overflow: hidden;
  pointer-events: none;
  /* Fades out before the copy below the fold, so the page body is not starry. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%);
}
.phero__stars i {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: calc(100% + 512px);
  background: url('assets/layers/stars.webp') repeat;
  background-size: 512px 512px;
  opacity: .62;
  animation: starDrift 150s linear infinite;
  will-change: transform;
}

/* The ring centre lands on the vial's base line, exactly as in the scenes. */
.phero__water {
  position: absolute;
  left: 50%;
  bottom: 25%;
  width: 168%;
  aspect-ratio: var(--water-ar);
  translate: -50% var(--water-focus);
  isolation: isolate;
  mix-blend-mode: screen;
  pointer-events: none;
}
.phero__water::before,
.phero__water::after {
  content: '';
  position: absolute;
  inset: 0;
  -webkit-mask-image: radial-gradient(closest-side at 50% 60.6%,
    #000 40%, rgba(0,0,0,.5) 66%, transparent 90%);
  mask-image: radial-gradient(closest-side at 50% 60.6%,
    #000 40%, rgba(0,0,0,.5) 66%, transparent 90%);
}
.phero__water::before {
  background: var(--water) center / contain no-repeat;
  animation: waterSwell 9s ease-in-out infinite alternate;
}
.phero__water::after {
  background: radial-gradient(38% 62% at 50% 50%,
    color-mix(in srgb, var(--scene-rim) 92%, white) 0%,
    color-mix(in srgb, var(--scene-accent) 58%, white) 44%,
    transparent 82%);
  mix-blend-mode: multiply;
  opacity: .85;
}
/* The drawn contact pool now sits on real water; it only needs to be a glint. */
.phero__pool { opacity: .7; }
/* The art box no longer needs a void painted behind it: the page is the void. */
.phero__sky {
  background: radial-gradient(58% 46% at 50% 76%,
    color-mix(in srgb, var(--scene-fog) 88%, transparent) 0%, transparent 72%);
}

@media (max-width: 860px) {
  .phero__water { width: 150%; }
}
@media (prefers-reduced-motion: reduce) {
  .phero__stars i, .phero__water::before { animation: none; }
}

/* ==========================================================================
   Add-to-cart flight
   ========================================================================== */

.fly {
  position: fixed;
  z-index: 95;               /* above the header, below drawers */
  width: 0; height: 0;
  pointer-events: none;
}
.fly__in {
  position: absolute;
  left: 0; top: 0;
  width: 44px; height: 88px;
  display: grid;
  place-items: center;
  filter: drop-shadow(0 6px 14px color-mix(in srgb, var(--fly-accent, #93B6D4) 45%, transparent));
  will-change: transform, opacity;
}
.fly__in img { width: 100%; height: 100%; object-fit: contain; }
.fly__in.no-art::after {
  content: '';
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--fly-accent, #93B6D4);
}
