/* ==========================================================================
   MishBio Luxe — atmosphere & conversion layer

   Loaded on the front page and product pages only. The base design system
   lives in style.css; this adds the dimensional background, scroll-driven
   motion, and the product-page merchandising blocks.

   Everything here degrades: no JS means a static gradient instead of a live
   field; no scroll-timeline support means IntersectionObserver reveals; no
   support for either means content simply visible.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Atmosphere — the dimensional background
   -------------------------------------------------------------------------- */

/* The hero owns the atmosphere. It used to be position:fixed across the whole
   document, so the graphic followed you down the page and competed with every
   section. Contained to the hero, it is a single opening moment and then it is
   gone — which is also what lets the sections below carry their own graphics.

   The 3D moment itself is no longer here: it is the vitrine in §1a, inside the
   hero figure. This layer is now only the gradient and the receding grid. */
.hero-shell {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.atmosphere {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  perspective: 1200px;
  perspective-origin: 50% 40%;
  background:
    radial-gradient(90% 60% at 78% 22%, rgba(18, 165, 222, 0.14), transparent 62%),
    radial-gradient(70% 55% at 12% 6%, rgba(11, 32, 50, 0.07), transparent 60%),
    linear-gradient(168deg, #F6FAFD 0%, var(--glass) 46%, #E9E4DA 100%);
}

/* Only used if JavaScript never runs at all. */
.atmosphere:not([data-atmosphere]) {
  background:
    radial-gradient(58% 46% at 76% 26%, rgba(18, 165, 222, 0.20), transparent 64%),
    radial-gradient(50% 40% at 14% 8%, rgba(11, 32, 50, 0.10), transparent 62%),
    linear-gradient(168deg, #F6FAFD 0%, var(--glass) 46%, #E9E4DA 100%);
}

/* The layered planes. transform-style preserve-3d is what makes the
   translateZ on children read as depth rather than as scale. */
.atmosphere__stage {
  position: absolute;
  inset: -10%;
  transform-style: preserve-3d;
  will-change: transform;
}

.atmosphere__plane {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  will-change: transform;
  transition: transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Fine hairline grid — the "laboratory record" motif, receding in space.
   Carries the background alone now, so it is kept quiet: the vitrine is the
   thing meant to hold the eye. */
.atmosphere__grid {
  position: absolute;
  inset: -20%;
  background-image:
    linear-gradient(to right, rgba(11, 32, 50, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(11, 32, 50, 0.05) 1px, transparent 1px);
  background-size: 5.5rem 5.5rem;
  mask-image: radial-gradient(70% 60% at 50% 35%, #000 0%, transparent 78%);
  transform: rotateX(58deg) translateZ(-220px) scale(2.1);
  transform-origin: 50% 100%;
}

/* Glass panes. Disabled: at large viewport sizes they drifted to the edges and
   read as stray white rectangles rather than depth. The receding grid and the
   vitrine carries the dimensionality on its own. Kept for reference — set
   `display:block` to reinstate. */
.atmosphere__pane { display: none; }

.atmosphere__pane-disabled {
  position: absolute;
  border-radius: 3px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: linear-gradient(
    140deg,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.06) 42%,
    rgba(18, 165, 222, 0.05) 100%
  );
  backdrop-filter: blur(2px);
  box-shadow:
    0 30px 90px -40px rgba(11, 32, 50, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.7);
}

.atmosphere__pane--a {
  inset-inline-start: 6%;
  inset-block-start: 14%;
  width: min(34vw, 30rem);
  aspect-ratio: 3 / 4;
  transform: rotateY(16deg) rotateZ(-4deg) translateZ(60px);
}

.atmosphere__pane--b {
  inset-inline-end: 4%;
  inset-block-start: 34%;
  width: min(26vw, 22rem);
  aspect-ratio: 1 / 1.3;
  transform: rotateY(-20deg) rotateZ(5deg) translateZ(-40px);
}

@media (max-width: 60rem) {
  /* Panes crowd a narrow viewport and cost fill rate for little payoff. */
  .atmosphere__pane { display: none; }
}

/* Everything above the atmosphere needs a stacking context. */
.site-header,
.site-main,
.site-footer,
.sticky-atc { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   1a. The vitrine — the hero's one 3D moment

   Replaces the DNA helix. The helix was a decorative object floating beside
   the content, and every position tried for it looked placed rather than
   belonging; the logo carries that motif already. This puts the product inside
   a rendered display case instead — brief §4.2 — so the 3D holds the thing
   being sold rather than an abstraction of the industry.

   The case is drawn on the canvas (see assets/js/atmosphere.js). Everything
   here is the frame around it, plus the states for when the canvas does not
   run: narrow viewports, no JS, no canvas. In each of those the photograph
   still renders on a clean gradient, which is the brief's rule that mobile
   gets a static image rather than a live scene.
   -------------------------------------------------------------------------- */

.vitrine {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* Set from the sampled photograph at runtime, so the element behind the
     canvas is the same tone as the case and no seam shows at the edge. */
  background: var(--vitrine-tone, linear-gradient(168deg, var(--paper) 0%, var(--cleanroom) 62%, #E3EBF1 100%));
  border: 1px solid var(--trace);
}

.vitrine__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  /* Not blurred and not faded. Unlike the helix this is architecture, not
     atmosphere — softening it would just make the corner lines mud. */
}

/* The subject: the real pack shot, inset so the case reads around it. Sized so
   the product stands on the rendered floor with the case visible on all four
   sides — at full bleed the photo covered the canvas and the 3D was invisible,
   which is the mistake that made the previous graphic pointless. */
.vitrine__subject {
  position: absolute;
  z-index: 1;
  inset-inline-start: 50%;
  inset-block-end: 9%;
  width: 66%;
  margin-inline-start: -33%;
  transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

/* Scoped through .vitrine so it beats `.hero__figure img { object-fit: cover }`
   in style.css on specificity rather than on load order. */
.vitrine .vitrine__subject img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  /* The pack shot's own sweep and the rendered interior are the same colour,
     so only the corners need easing to hide the rectangle entirely. */
  -webkit-mask-image: radial-gradient(104% 90% at 50% 50%, #000 54%, transparent 98%);
  mask-image: radial-gradient(104% 90% at 50% 50%, #000 54%, transparent 98%);
}

/* The museum label. Names what is actually on the plinth and links to it —
   real data, and the vitrine metaphor finished properly. */
.vitrine__plate {
  position: absolute;
  z-index: 2;
  inset-inline: 0;
  inset-block-end: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35em 0.75em;
  padding: var(--space-s) var(--space-m);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  background: linear-gradient(to top, rgba(11, 32, 50, 0.42), transparent);
}

.vitrine__plate-label {
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--azure-lift);
}

.vitrine__plate a {
  color: #fff;
  text-decoration: none;
  border-block-end: 1px solid rgba(255, 255, 255, 0.45);
}

.vitrine__plate a:hover { border-block-end-color: var(--azure-lift); }

/* Below the hero's two-column breakpoint the canvas never initialises, so the
   figure falls back to its gradient and the photo sits plainly on it. */
@media (max-width: 61.999rem) {
  .vitrine__canvas { display: none; }
  /* Let the photograph set the height. `.hero__figure` reserves 4:5, which is
     right when the case is rendering behind a cropped size, but here it just
     clips the bottom off any image whose ratio differs. */
  .vitrine { aspect-ratio: auto; }
  .vitrine__subject {
    position: static;
    width: auto;
    margin-inline-start: 0;
    transform: none;
  }
  .vitrine .vitrine__subject img { -webkit-mask-image: none; mask-image: none; }
  .vitrine__plate { position: static; background: none; padding-inline: 0; }
  .vitrine__plate a { color: var(--ink); border-block-end-color: var(--trace); }
}

@media (prefers-reduced-motion: reduce) {
  .vitrine__subject { transition: none; }
}

/* --------------------------------------------------------------------------
   2. Scroll-driven motion
   Uses native scroll timelines where supported — these run off the main
   thread, so they stay smooth under load. IntersectionObserver is the
   fallback, already handled by [data-reveal] in style.css.
   -------------------------------------------------------------------------- */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] {
      opacity: 1;
      transform: none;
      animation: luxe-rise linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 26%;
    }

    /* The hero settles and recedes slightly as you leave it. */
    .hero[data-scroll-fade] {
      animation: luxe-hero-exit linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
  }
}

@keyframes luxe-rise {
  from { opacity: 0; transform: translate3d(0, 2.5rem, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes luxe-hero-exit {
  to { opacity: 0.25; transform: translate3d(0, -3rem, 0) scale(0.985); }
}

/* Section rules that draw themselves in as they enter. */
.rule-draw {
  height: 1px;
  background: var(--trace);
  transform-origin: left center;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rule-draw {
      animation: luxe-draw linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 22%;
    }
  }
}

@keyframes luxe-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* --------------------------------------------------------------------------
   3. Hero
   -------------------------------------------------------------------------- */

.hero--luxe {
  min-height: min(92vh, 54rem);
  align-content: center;
  padding-block: var(--space-3xl) var(--space-2xl);
}

.hero__title--luxe {
  font-size: clamp(3rem, 2rem + 5.2vw, 6.5rem);
  letter-spacing: -0.045em;
  line-height: 0.93;
}

/* Each word rises on load. The delay is set inline per word by the template. */
.hero__word {
  display: inline-block;
  animation: luxe-rise 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--d, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  .hero__word { animation: none; }
}

.hero__figure--luxe {
  border-radius: 3px;
  box-shadow:
    0 60px 120px -50px rgba(11, 32, 50, 0.45),
    0 2px 0 rgba(255, 255, 255, 0.6) inset;
  transform: perspective(1400px) rotateY(-6deg) rotateX(2deg);
  transition: transform 900ms var(--ease);
}
.hero__figure--luxe:hover { transform: perspective(1400px) rotateY(-2deg) rotateX(0deg); }

/* Scroll cue */
.scroll-cue {
  display: inline-flex; align-items: center; gap: 0.6em;
  margin-block-start: var(--space-xl);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--mineral);
}
.scroll-cue::before {
  content: ""; width: 2.5rem; height: 1px; background: var(--meniscus);
  transform-origin: left; animation: cue 2.4s var(--ease) infinite;
}
@keyframes cue { 0%,100% { transform: scaleX(0.3); opacity: .4 } 50% { transform: scaleX(1); opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .scroll-cue::before { animation: none; transform: none } }

/* --------------------------------------------------------------------------
   4. Honest urgency
   Every element here is backed by real data. There is no element that
   fabricates scarcity, and there is deliberately no "resets on reload"
   countdown — see inc/urgency.php.
   -------------------------------------------------------------------------- */

.urgency {
  display: grid;
  gap: var(--space-2xs);
  margin-block: var(--space-m);
  padding: var(--space-s) var(--space-m);
  border: 1px solid var(--trace);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--paper) 70%, transparent);
  backdrop-filter: blur(8px);
}

.urgency__row {
  display: flex; align-items: center; gap: var(--space-2xs);
  font-family: var(--font-mono); font-size: var(--step--1);
  letter-spacing: 0.03em;
}

.urgency__dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--meniscus); flex: none;
  animation: pulse 2.6s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1) } 50% { opacity: .45; transform: scale(.8) } }
@media (prefers-reduced-motion: reduce) { .urgency__dot { animation: none } }

.urgency__time { font-variant-numeric: tabular-nums; color: var(--meniscus); font-weight: 500; }

/* Real stock level, rendered as a meter. */
.stock-meter { display: grid; gap: var(--space-3xs); }
.stock-meter__track {
  height: 3px; background: var(--trace); border-radius: 999px; overflow: hidden;
}
.stock-meter__fill {
  height: 100%; background: var(--meniscus);
  transform-origin: left; transition: transform 600ms var(--ease);
}
.stock-meter--low .stock-meter__fill { background: #b4552f; }
.stock-meter__label {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--mineral);
}

/* --------------------------------------------------------------------------
   5. Upsell blocks
   -------------------------------------------------------------------------- */

/* Quantity breaks — real saving, computed from the real price. */
.tiers { display: grid; gap: var(--space-2xs); margin-block: var(--space-m); }

.tier {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-s);
  align-items: center;
  padding: var(--space-s) var(--space-m);
  border: 1px solid var(--trace);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--paper) 60%, transparent);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.tier:hover { border-color: var(--mineral); }
.tier:has(input:checked) {
  border-color: var(--meniscus);
  background: var(--meniscus-10);
}

.tier input { accent-color: var(--meniscus); width: 1rem; height: 1rem; }
.tier__label { font-weight: 500; }
.tier__note { display: block; font-size: var(--step--1); color: var(--mineral); }
.tier__price { font-family: var(--font-mono); text-align: end; }
.tier__save {
  display: block; font-size: var(--step--2); color: var(--meniscus);
  letter-spacing: 0.04em; text-transform: uppercase;
}

.tier__badge {
  position: absolute; inset-block-start: -0.7em; inset-inline-end: var(--space-m);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--ink); color: var(--glass);
  padding: 0.25em 0.7em; border-radius: 999px;
}
.tier { position: relative; }

/* Frequently bought together */
.bundle {
  border: 1px solid var(--trace);
  border-radius: var(--radius);
  padding: var(--space-m);
  background: color-mix(in srgb, var(--paper) 70%, transparent);
}

.bundle__items {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-s); margin-block-end: var(--space-m);
}

.bundle__item {
  display: grid; gap: var(--space-2xs); justify-items: center;
  width: 6.5rem; text-align: center;
}
.bundle__item img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius); }
.bundle__item label {
  font-size: var(--step--2); line-height: 1.3;
  display: flex; gap: 0.35em; align-items: start;
}
.bundle__plus { font-family: var(--font-mono); color: var(--mineral); font-size: var(--step-1); }

.bundle__total {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-s);
  padding-block-start: var(--space-m);
  border-block-start: 1px solid var(--trace);
}
.bundle__total-price { font-family: var(--font-mono); font-size: var(--step-2); }
.bundle__total-save { font-family: var(--font-mono); font-size: var(--step--1); color: var(--meniscus); }

/* --------------------------------------------------------------------------
   6. Trust row
   -------------------------------------------------------------------------- */

.trust-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-m);
  padding-block: var(--space-l);
  border-block: 1px solid var(--trace);
  margin-block: var(--space-2xl);
}

.trust-item { display: grid; gap: var(--space-3xs); text-align: center; }
.trust-item__key {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--meniscus);
}
.trust-item__val { font-size: var(--step--1); color: var(--mineral); }

/* --------------------------------------------------------------------------
   7. Marquee — the range, stated plainly
   -------------------------------------------------------------------------- */

/* Runs as a DARK band, not a hairline-ruled strip.
   It previously had no background at all: mineral type on the page's own
   cleanroom ground, between a warm sand band above and a cleanroom section
   below. Three near-identical luminances stacked on top of each other, so the
   strip read as a smudge rather than a divider and the text barely cleared the
   background. Inverting it to ink gives the page a hard horizontal beat
   between the hero and the range, and reuses the dark world already in the
   token set rather than introducing a fourth tone. */
.marquee {
  overflow: hidden;
  background: var(--ink);
  color: var(--cleanroom);
  border-block: 0;
  padding-block: var(--space-m);
  margin-block: var(--space-2xl);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.marquee__track {
  display: flex; gap: var(--space-xl); width: max-content;
  animation: marquee 46s linear infinite;
  font-family: var(--font-mono); font-size: var(--step--1);
  /* Was --step--1 at mineral on near-white: about 1.9:1. Cleanroom on ink is
     roughly 15:1, so the claims are actually legible — they are trust copy,
     not decoration. */
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--cleanroom);
}
.marquee:hover .marquee__track { animation-play-state: paused; }

@keyframes marquee { to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .marquee { mask-image: none; }
}

.marquee__item { display: flex; align-items: center; gap: var(--space-s); white-space: nowrap; }
.marquee__item::after { content: "\00B7"; color: var(--meniscus); }

/* --------------------------------------------------------------------------
   8. Editorial split — brand story with depth
   -------------------------------------------------------------------------- */

.split {
  display: grid; gap: var(--space-xl);
  align-items: center;
}
@media (min-width: 62rem) {
  .split { grid-template-columns: 1fr 1fr; gap: var(--space-3xl); }
  .split--reverse > :first-child { order: 2; }
}

.split__figure {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 3px;
  box-shadow: 0 50px 100px -60px rgba(11, 32, 50, 0.5);
}
.split__figure img { width: 100%; height: 100%; object-fit: cover; }

/* --------------------------------------------------------------------------
   9. Stacked product blocks
   Mirrors the reference store's block structure — rating row, benefit
   bullets, assurances, payment badges — in the MishBio palette.
   -------------------------------------------------------------------------- */

/* Rating + reviewer avatars. Renders only with real reviews. */
.rating-row {
  display: flex; align-items: center; gap: var(--space-s);
  flex-wrap: wrap; margin-block: var(--space-s);
}
.rating-row__avatars { display: flex; }
.rating-row__avatar {
  width: 2.125rem; height: 2.125rem; border-radius: 50%;
  border: 2px solid var(--paper); object-fit: cover;
  margin-inline-start: -0.625rem;
}
.rating-row__avatar:first-child { margin-inline-start: 0; }
.rating-row__count {
  display: block; font-family: var(--font-mono);
  font-size: var(--step--2); letter-spacing: 0.06em;
  color: var(--mineral); text-decoration: none;
}
.rating-row__count:hover { color: var(--meniscus); }

/* Benefit bullets — the reference uses emoji; inline SVG renders
   identically across platforms and takes the brand colour. */
.benefits { list-style: none; margin: var(--space-m) 0; padding: 0; display: grid; gap: var(--space-xs); }
.benefit { display: grid; grid-template-columns: 1.5rem 1fr; gap: var(--space-2xs); align-items: start; }
.benefit__icon { width: 1.25rem; height: 1.25rem; color: var(--meniscus); margin-block-start: 0.15em; }
.benefit span { line-height: 1.5; }

/* Real recent-sales line. No timed popups. */
.social-proof {
  display: flex; align-items: center; gap: var(--space-2xs);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--mineral); margin-block: var(--space-2xs);
}
.social-proof__dot {
  width: 0.45rem; height: 0.45rem; border-radius: 50%;
  background: var(--meniscus); flex: none;
  animation: pulse 2.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .social-proof__dot { animation: none; } }

/* Assurance rows */
.assurances {
  list-style: none; margin: var(--space-m) 0 0; padding: var(--space-m) 0 0;
  border-block-start: 1px solid var(--trace);
  display: grid; gap: var(--space-s);
}
.assurance { display: grid; grid-template-columns: 1.75rem 1fr; gap: var(--space-2xs); align-items: start; }
.assurance .benefit__icon { width: 1.35rem; height: 1.35rem; }
.assurance strong { display: block; font-size: var(--step--1); }
.assurance span span { display: block; font-size: var(--step--1); color: var(--mineral); }

/* --------------------------------------------------------------------------
   10. Tonal contrast
   The first build was one pale field top to bottom, which read as flat. These
   give the page a rhythm: light, deep, light.
   -------------------------------------------------------------------------- */

.band {
  position: relative;
  margin-block: var(--space-3xl);
  padding-block: var(--space-3xl);
}

/* Deep navy band, full-bleed, with an azure bloom. */
.band--deep {
  background:
    radial-gradient(80% 120% at 15% 0%, rgba(18, 165, 222, 0.28), transparent 58%),
    radial-gradient(70% 100% at 95% 100%, rgba(94, 200, 240, 0.16), transparent 60%),
    linear-gradient(160deg, #123049 0%, var(--navy-deep) 60%, #04101B 100%);
  color: #E6EFF6;

  /* Full-bleed. The negative margins alone were not enough: this element also
     carries .wrap, whose max-width capped it at 82rem, so it shifted left
     instead of spanning the viewport. Releasing max-width is the actual fix. */
  max-width: none;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  padding-inline: var(--gutter);
}
.band--deep h2, .band--deep h3 { color: #fff; }
.band--deep .eyebrow { color: var(--azure-lift); }
.band--deep .eyebrow::before { background: var(--azure-lift); }
.band--deep p { color: #8CA3B5; }
.band--deep .btn {
  background: var(--azure-lift); border-color: var(--azure-lift); color: var(--navy-deep);
}
.band--deep .btn:hover { background: #fff; border-color: #fff; }
.band--deep .link-rule { color: #fff; border-block-end-color: rgba(255,255,255,.25); }
.band--deep .link-rule:hover { border-block-end-color: var(--azure-lift); }

.band--deep__inner { max-width: var(--wrap); margin-inline: auto; }

/* Stat row for the deep band */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--space-l); }
.stat__num {
  font-family: var(--font-display); font-size: var(--step-5);
  line-height: 1; color: #fff; letter-spacing: -0.03em;
}
.stat__label {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--azure-lift);
  margin-block-start: var(--space-2xs);
}

/* Gradient text accent, used sparingly on one heading */
.grad {
  background: linear-gradient(96deg, var(--meniscus), var(--azure-lift) 60%, #9AD9F5);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* --------------------------------------------------------------------------
   10a. Section graphics — what carries the page below the hero

   The vitrine is a hero-only moment. Below it the sections need their own
   visual identity, but WebGL is the wrong tool for background texture: it
   costs a canvas, a render loop and GPU time for something that never moves.
   These are pure CSS, composite-only, and cost nothing.
   -------------------------------------------------------------------------- */

/* MOLECULAR LATTICE — the deep band.
   Node points on a triangular pitch, echoing the molecule in the logo. Two
   offset dot layers read as depth without a second element. */
.band--deep {
  position: relative;
  isolation: isolate;
}

.band--deep::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(circle at center, rgba(94, 200, 240, 0.30) 1.4px, transparent 1.6px),
    radial-gradient(circle at center, rgba(255, 255, 255, 0.10) 1px, transparent 1.2px);
  background-size: 4.5rem 4.5rem, 4.5rem 4.5rem;
  background-position: 0 0, 2.25rem 2.25rem;
  /* Fades from the corner so the copy column stays clean. */
  mask-image: radial-gradient(120% 90% at 88% 12%, #000 0%, transparent 70%);
  -webkit-mask-image: radial-gradient(120% 90% at 88% 12%, #000 0%, transparent 70%);
  pointer-events: none;
}

/* CHROMATOGRAPHY BAND — separates light sections without a hard edge.
   Vertical bands of varying width, like a developed TLC plate. */
.chroma {
  height: 3px;
  border: 0;
  margin: 0;
  background: repeating-linear-gradient(
    90deg,
    var(--meniscus) 0 2px,
    transparent 2px 9px,
    var(--kraft) 9px 10px,
    transparent 10px 22px,
    var(--ink) 22px 23px,
    transparent 23px 41px
  );
  opacity: 0.42;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

/* CONTOUR FIELD — warm sand banding for alternate light sections.
   Concentric hairlines, like a topographic plate. */
.section--contour {
  position: relative;
  isolation: isolate;
  background: var(--sage-tint);
}

.section--contour::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: repeating-radial-gradient(
    circle at 12% 50%,
    transparent 0 38px,
    rgba(11, 32, 50, 0.05) 38px 39px
  );
  mask-image: linear-gradient(90deg, #000 0%, transparent 62%);
  -webkit-mask-image: linear-gradient(90deg, #000 0%, transparent 62%);
  pointer-events: none;
}

/* Full-bleed helper, so a banded section can span the viewport. */
.bleed {
  max-width: none;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  padding-inline: var(--gutter);
}

@media (prefers-reduced-motion: reduce) {
  .band--deep::before,
  .section--contour::before { opacity: 0.6; }
}

/* --------------------------------------------------------------------------
   10b. Photography strip
   An editorial mosaic rather than a uniform grid — two tall cells break the
   rhythm so it reads as art direction rather than a product list.
   -------------------------------------------------------------------------- */

.shot-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2xs);
}
@media (min-width: 48rem) {
  .shot-grid { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 12rem; }
  .shot--0 { grid-column: span 2; grid-row: span 2; }
  .shot--3 { grid-row: span 2; }
}

.shot {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--paper);
  aspect-ratio: 1;
  text-decoration: none;
  box-shadow: 0 20px 50px -38px rgba(11, 32, 50, 0.5);
}
@media (min-width: 48rem) {
  .shot { aspect-ratio: auto; height: 100%; }
}

.shot img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 900ms var(--ease), filter var(--dur) var(--ease);
}
.shot:hover img { transform: scale(1.05); }

.shot__label {
  position: absolute; inset-inline: 0; inset-block-end: 0;
  padding: var(--space-m) var(--space-s) var(--space-s);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: #fff;
  background: linear-gradient(to top, rgba(6, 21, 35, 0.85), transparent);
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.shot:hover .shot__label,
.shot:focus-visible .shot__label { opacity: 1; transform: none; }

/* Touch devices have no hover, so the label is always readable there. */
@media (hover: none) {
  .shot__label { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   11. Product detail tabs
   -------------------------------------------------------------------------- */

/* The tabs band. Full-bleed, banded off the page ground so the detail section
   reads as its own chapter rather than a column adrift in whitespace. */
.pdp-tabs {
  background: var(--sage-tint);
  border-block: 1px solid var(--trace);
  padding-block: var(--space-xl);
  margin-block: var(--space-2xl);
}

.tabs { margin-block: 0; }

/* Prose stays at measure even though the band is full width. Widening the band
   is the fix for the boxed-in look; widening the LINE LENGTH would just trade
   one readability problem for another. */
.tabs__panel .prose,
.tabs__panel p,
.tabs__panel li { max-width: var(--measure); }

.tabs__list {
  display: flex; flex-wrap: wrap; gap: 0;
  list-style: none; margin: 0 0 var(--space-l); padding: 0;
  border-block-end: 1px solid var(--trace);
}

.tabs__btn {
  appearance: none; background: none; border: 0;
  border-block-end: 2px solid transparent;
  padding: var(--space-s) var(--space-l);
  margin-block-end: -1px;
  cursor: pointer;
  font-family: var(--font-mono); font-size: var(--step--1);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--mineral);
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  white-space: nowrap;
}
.tabs__btn:hover { color: var(--ink); }
.tabs__btn[aria-selected="true"] { color: var(--ink); border-block-end-color: var(--meniscus); }

.tabs__panel[hidden] { display: none; }
.tabs__panel { animation: luxe-rise 420ms var(--ease) both; }

@media (max-width: 40rem) {
  .tabs__list { overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; }
  .tabs__list::-webkit-scrollbar { display: none; }
}

/* Shipping table inside a tab */
.ship-table { width: 100%; border-collapse: collapse; }
.ship-table th, .ship-table td {
  text-align: start; padding: var(--space-s) var(--space-s) var(--space-s) 0;
  border-block-end: 1px solid var(--trace); vertical-align: top;
}
.ship-table th {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mineral);
  width: 12rem;
}

/* --------------------------------------------------------------------------
   12. DSHEA notice (supplements only)
   Required adjacent to structure/function claims, not tucked into the footer.
   Never set below --step--1.
   -------------------------------------------------------------------------- */

.dshea {
  margin-block-start: var(--space-m);
  padding: var(--space-m);
  border: 1px solid var(--trace);
  border-inline-start: 3px solid var(--meniscus);
  border-radius: var(--radius);
  background: var(--paper);
}
.dshea p { font-size: var(--step--1); line-height: 1.55; margin: 0; max-width: none; }
.dshea__statement { font-weight: 500; color: var(--ink); }
.dshea__advice { margin-block-start: var(--space-2xs) !important; color: var(--mineral); }

/* Payment badges — only for gateways actually enabled */
.pay-badges {
  list-style: none; margin: var(--space-m) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2xs);
}
.pay-badge {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.4em 0.75em; border: 1px solid var(--trace);
  border-radius: var(--radius); color: var(--mineral);
  background: var(--paper);
}
