  /* ============================================================
     DESIGN TOKENS
     A small, systematic scale for color and spacing — same idea
     as Tailwind's config: name the values once, reference them
     everywhere, never hardcode a raw hex or rem in a component.
     ============================================================ */
  :root{
    /* ---- Brand base colors ---- */
    --color-ember-500:#F36B21;
    --color-ember-400: color-mix(in srgb, var(--color-ember-500) 85%, white);
    --color-ember-600: color-mix(in srgb, var(--color-ember-500) 85%, black);
    --color-charcoal-500:#292929;
    --color-charcoal-600:#3a3937;   /* warm charcoal — the atmosphere/haze tone */
    --color-air-white-500:#F5F3EE;
    --color-near-black-500:#151515;
    --color-black-900:#0B0B0B;      /* deeper than the page bg — vignette/depth only */
    --color-white:#ffffff;          /* pure white — reserved for the placeholder texture only */

    /* ---- Semantic aliases: what a component actually asks for ---- */
    --color-bg: var(--color-near-black-500);
    --color-bg-elevated: var(--color-charcoal-500);
    /* Footer base — a hair of charcoal so it reads as a plinth under the CTA. */
    --color-bg-plinth: color-mix(in srgb, var(--color-charcoal-500) 40%, var(--color-near-black-500));
    /* Full-bleed section band — breaks the page out of one flat near-black column. */
    --color-bg-band: color-mix(in srgb, var(--color-charcoal-500) 55%, var(--color-near-black-500));
    --color-bg-surface: var(--color-air-white-500);
    --color-bg-card: var(--color-white);
    --color-text: var(--color-air-white-500);        /* default text on dark */
    --color-text-inverse: var(--color-near-black-500); /* default text on light */
    --color-accent: var(--color-ember-500);
    --color-accent-hover: var(--color-ember-400);
    --color-star: #FFC53D; /* rating stars only — distinct from the ember accent */

    /* ---- Alpha ramps, generated from the two text colors ----
       Every "text at X% opacity" value in the design reduces to
       one of these — same pattern as Tailwind's text-white/60 etc. */
    --text-on-dark-85: color-mix(in srgb, var(--color-air-white-500) 85%, transparent);
    --text-on-dark-78: color-mix(in srgb, var(--color-air-white-500) 78%, transparent);
    --text-on-dark-75: color-mix(in srgb, var(--color-air-white-500) 75%, transparent);
    --text-on-dark-70: color-mix(in srgb, var(--color-air-white-500) 70%, transparent);
    --text-on-dark-60: color-mix(in srgb, var(--color-air-white-500) 60%, transparent);
    --text-on-dark-55: color-mix(in srgb, var(--color-air-white-500) 55%, transparent);
    --text-on-dark-50: color-mix(in srgb, var(--color-air-white-500) 50%, transparent);
    --text-on-dark-40: color-mix(in srgb, var(--color-air-white-500) 40%, transparent);
    --text-on-dark-30: color-mix(in srgb, var(--color-air-white-500) 30%, transparent);

    --text-on-light-75: color-mix(in srgb, var(--color-near-black-500) 75%, transparent);
    --text-on-light-65: color-mix(in srgb, var(--color-near-black-500) 65%, transparent);
    --text-on-light-55: color-mix(in srgb, var(--color-near-black-500) 55%, transparent);
    --text-on-light-50: color-mix(in srgb, var(--color-near-black-500) 50%, transparent);
    --text-on-light-20: color-mix(in srgb, var(--color-near-black-500) 20%, transparent);
    --text-on-light-10: color-mix(in srgb, var(--color-near-black-500) 10%, transparent);
    --text-on-light-08: color-mix(in srgb, var(--color-near-black-500) 8%, transparent);

    --border-on-dark-08: color-mix(in srgb, var(--color-white) 8%, transparent);
    --border-on-dark-25: color-mix(in srgb, var(--color-white) 25%, transparent);
    --border-on-light-08: color-mix(in srgb, var(--color-near-black-500) 8%, transparent);
    --border-on-light-10: color-mix(in srgb, var(--color-near-black-500) 10%, transparent);
    --border-on-light-20: color-mix(in srgb, var(--color-near-black-500) 20%, transparent);

    --accent-alpha-12: color-mix(in srgb, var(--color-accent) 12%, transparent);
    --accent-alpha-15: color-mix(in srgb, var(--color-accent) 15%, transparent);
    --accent-alpha-22: color-mix(in srgb, var(--color-accent) 22%, transparent);
    --accent-alpha-40: color-mix(in srgb, var(--color-accent) 40%, transparent);
    --accent-alpha-50: color-mix(in srgb, var(--color-accent) 50%, transparent);
    --accent-alpha-60: color-mix(in srgb, var(--color-accent) 60%, transparent);
    --accent-alpha-70: color-mix(in srgb, var(--color-accent) 70%, transparent);

    /* Placeholder texture only — the one remaining white-based tint. */
    --overlay-smoke-1: color-mix(in srgb, var(--color-white) 5%, transparent);

    /* Atmosphere: warm charcoal haze. Replaces the old white-based smoke
       so the hero lifts toward charcoal instead of going cool-grey, which
       is what split it into a grey half and an orange half. */
    --overlay-charcoal-1: color-mix(in srgb, var(--color-charcoal-600) 70%, transparent);
    --overlay-charcoal-2: color-mix(in srgb, var(--color-charcoal-600) 45%, transparent);
    --overlay-vignette:   color-mix(in srgb, var(--color-black-900) 75%, transparent);

    /* ---- Spacing scale (4px base, same increments as Tailwind) ---- */
    --space-0: 0;
    --space-1: 0.25rem;
    --space-1_5: 0.375rem;
    --space-2: 0.5rem;
    --space-2_5: 0.625rem;
    --space-3: 0.75rem;
    --space-3_5: 0.875rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-7: 1.75rem;
    --space-8: 2rem;
    --space-9: 2.25rem;
    --space-10: 2.5rem;
    --space-12: 3rem;
    --space-14: 3.5rem;
    --space-16: 4rem;
    --space-20: 5rem;
    --space-22: 5.5rem;   /* project extension — headline-block breathing room */
    --space-24: 6rem;
    --space-28: 7rem;
    --space-32: 8rem;

    /* Fluid horizontal page gutter — used on every full-width section */
    --space-container: clamp(1.25rem, 4vw, 3.5rem);

    /* ---- Radius scale ---- */
    --radius-none: 0;
    --radius-sm: 2px;
    --radius-md: 3px;
    --radius-lg: 4px;
    --radius-xl: 6px;
    --radius-2xl: 14px;
    --radius-full: 9999px;

    /* ---- Type (unchanged from v1 — not in scope of this pass) ---- */
    --font-display:'Space Grotesk', sans-serif;
    --font-body:'Inter', sans-serif;

    /* ---- Motion ----
       One custom curve. The house `ease` is symmetric, which is right for
       hover state changes but wrong for entrances — a decelerating curve is
       what makes a reveal read as "settling" rather than "starting slow". */
    --ease-out-soft: cubic-bezier(.22,.61,.36,1);
    --dur-micro: .2s;      /* nav icons, link colors */
    --dur-btn: .25s;       /* buttons */
    --dur-surface: .3s;    /* cards, header */
    --dur-reveal: .55s;    /* scroll entrances */
    --flip-cycle: 9s;                   /* lifestyle cards + heading swap */
    --reveal-shift: var(--space-3_5);   /* 14px rise */
    --reveal-step: 60ms;                /* stagger between grid children */
    --focus-ring-on-accent: var(--color-near-black-500);
    --scroll-offset: var(--space-24);   /* announce bar + header height */
  }

  *{box-sizing:border-box; margin:0; padding:0;}
  html{scroll-behavior:smooth;}
  body{
    font-family:var(--font-body);
    background:var(--color-bg);
    color:var(--color-text);
    overflow-x:hidden;
    -webkit-font-smoothing:antialiased;
  }
  a{color:inherit; text-decoration:none;}
  img{max-width:100%; display:block;}
  /* Anchor targets clear the sticky header. Without this, every nav link
     scrolls its section to a position hidden behind .site-top. */
  #shop, #ingredients, #ritual, #reviews{scroll-margin-top:var(--scroll-offset);}
  .eyebrow{
    font-family:var(--font-display);
    font-size:0.72rem;
    letter-spacing:0.22em;
    text-transform:uppercase;
    color:var(--color-accent);
    font-weight:600;
  }
  .btn{
    display:inline-flex;
    align-items:center;
    gap:var(--space-2);
    font-family:var(--font-display);
    font-weight:600;
    font-size:0.85rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    padding:var(--space-4) var(--space-8);
    border-radius:var(--radius-full);
    cursor:pointer;
    border:1px solid transparent;
    transition:transform var(--dur-btn) var(--ease-out-soft),
               background var(--dur-btn) ease,
               border-color var(--dur-btn) ease;
  }
  /* Guarded: on touch, a tap leaves the lift stuck until you tap elsewhere,
     which reads as a rendering bug. */
  @media (hover:hover){ .btn:hover{transform:translateY(-2px);} }
  /* Must follow :hover to win the cascade while a pressed button is hovered. */
  .btn:active{transform:translateY(0) scale(.985); transition-duration:.08s;}
  .btn-primary{background:var(--color-accent); color:var(--color-near-black-500);}
  .btn-primary:hover{background:var(--color-accent-hover);}
  .btn-ghost{border-color:currentColor; color:inherit; background:transparent;}
  .btn-ghost:hover{border-color:var(--color-accent); color:var(--color-accent);}

  /* ---------- Focus ----------
     Nothing authored a focus style before this, so keyboard users got the
     UA default only. :where() keeps specificity at 0 so components can
     override the ring colour without an escalation war. */
  :where(a, button, input, [tabindex]):focus-visible{
    outline:2px solid var(--color-accent);
    outline-offset:3px;
    border-radius:var(--radius-sm);
  }
  /* An ember ring on the ember-filled button would be invisible. */
  .btn-primary:focus-visible{outline-color:var(--focus-ring-on-accent);}

  /* ---------- Brand mark (logo) ---------- */
  /* Width-based sizing everywhere: height:auto means the aspect
     ratio can never break, even if a parent column gets squeezed
     on mobile — this is what caused the earlier footer stretch bug. */
  /* Scales rather than changing height, so only padding-block drives layout
     and backdrop-filter isn't asked to re-blur a resizing box every frame. */
  .brand-mark{
    display:block; width:auto; height:1.875rem;
    transform-origin:left center;
    transition:transform var(--dur-surface) var(--ease-out-soft);
  }
  header.condensed .brand-mark{transform:scale(.84);}
  .brand-mark--footer{display:block; width:min(220px, 100%); height:auto; margin:0 auto var(--space-1);}

  /* ---------- Photo placeholder system ---------- */
  .photo-slot{
    position:relative;
    aspect-ratio: var(--slot-ratio, 4/3);
    display:flex;
    align-items:center;
    justify-content:center;
    background:
      repeating-linear-gradient(135deg, var(--overlay-smoke-1) 0 2px, transparent 2px 14px);
    border:1px dashed var(--border-on-dark-25);
    color:var(--text-on-dark-55);
    text-align:center;
    overflow:hidden;
    border-radius:var(--radius-lg);
  }
  /* Any slot holding a real photo fills edge-to-edge — no border,
     no dashed placeholder texture, and the image is pinned to all
     four sides so there's no room for a stray gap underneath it. */
  .photo-slot:has(img){border:none; background:none;}
  .photo-slot > img{
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover;
    display:block;
  }
  .photo-slot .slot-label{
    font-family:var(--font-display);
    font-size:0.68rem;
    letter-spacing:0.14em;
    text-transform:uppercase;
    padding:0 var(--space-6);
    line-height:1.6;
  }
  .photo-slot .slot-tag{
    position:absolute;
    top:var(--space-3); left:var(--space-3);
    font-family:var(--font-display);
    font-size:0.6rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    background:var(--color-accent);
    color:var(--color-near-black-500);
    padding:var(--space-1) var(--space-2);
    border-radius:var(--radius-sm);
    font-weight:700;
  }
  /* Source photo is landscape (1536x1024). At a strict 4:5, cover can only
     ever show ~53% of the width — no object-position fixes that, it just
     trades left crop for right crop. Easing to 9:10 shows meaningfully
     more of both sides (~60% of width) while still reading as portrait. */
  .hero-image .photo-slot{ --slot-ratio: 9/10; border-radius:var(--radius-xl); }
  .hero-image .photo-slot > img{object-position:32% center;}
  /* Exactly matches routine-photo (1080x1350 = 4/5). object-fit:cover only
     crops when the slot and the source disagree — at parity nothing is
     trimmed, so the wordmark at the top of the graphic stays intact. */
  .proof-grid .photo-slot{ --slot-ratio: 4/5; border-radius:var(--radius-2xl); }
  /* Ember hairline, same token as .purchase-box — the one other accent-bordered
     surface on the page, so the two read as the same treatment. */
  .proof-grid .proof-photo{ border:2px solid var(--accent-alpha-50); }
  /* .lifestyle-grid no longer uses .photo-slot — its cards are .flip-card,
     which sets its own 1/1 ratio and puts the radius on .flip-face. */

  /* ---------- Announcement bar ---------- */
  .announce-bar{
    /* Solid ember on near-black text — the one bright band on the page, so
       it reads as a banner instead of dissolving into the dark background. */
    background:var(--color-accent);
    color:var(--color-near-black-500);
    overflow:hidden;
    padding:var(--space-2_5) 0;
    font-family:var(--font-display);
    font-size:0.72rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    font-weight:700;
    position:relative;
    z-index:101;
  }
  /* Same seamless-loop technique as the two photo carousels: the message
     set is emitted exactly twice, animated 0 -> -50%, so the loop point is
     invisible. Slow and continuous, not a scroll-triggered marquee — this
     is a thin persistent strip, not content someone reads start-to-finish. */
  .announce-track{
    display:flex;
    align-items:center;
    gap:var(--space-8);
    width:max-content;
    padding-right:var(--space-8);
    animation:announce-scroll 26s linear infinite;
  }
  .announce-bar:hover .announce-track{animation-play-state:paused;}
  @keyframes announce-scroll{
    from{ transform:translateX(0); }
    to{ transform:translateX(-50%); }
  }
  .announce-track span[aria-hidden]{opacity:0.6;}

  .site-top{
    position:sticky;
    top:0;
    z-index:100;
  }
  /* ---------- Nav ---------- */
  header{
    position:relative;
    display:flex; align-items:center; justify-content:space-between;
    /* Split from the `padding` shorthand so padding-block alone can animate. */
    padding-block:var(--space-4);
    padding-inline:var(--space-container);
    background:linear-gradient(to bottom, color-mix(in srgb, var(--color-near-black-500) 95%, transparent), color-mix(in srgb, var(--color-near-black-500) 75%, transparent));
    transition:background var(--dur-surface) ease,
               padding-block var(--dur-surface) var(--ease-out-soft);
  }
  header.scrolled{background:color-mix(in srgb, var(--color-near-black-500) 92%, transparent); backdrop-filter:blur(8px);}
  header.condensed{padding-block:var(--space-2_5);}
  nav ul{list-style:none; display:none; gap:var(--space-10);}
  nav a{
    font-family:var(--font-display);
    font-size:0.78rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    opacity:0.85;
    transition:opacity var(--dur-micro) ease, color var(--dur-micro) ease;
  }
  nav a:hover{opacity:1; color:var(--color-accent);}
  .nav-icons{display:flex; align-items:center; gap:var(--space-6);}
  .nav-icon-btn{
    display:flex; align-items:center; justify-content:center;
    background:none; border:none; cursor:pointer;
    color:var(--color-text);
    opacity:0.9;
    transition:opacity var(--dur-micro) ease, color var(--dur-micro) ease;
  }
  .nav-icon-btn:hover{opacity:1; color:var(--color-accent);}
  .nav-icon-btn svg{width:20px; height:20px;}
  .cart-badge{position:relative;}
  .cart-count{
    position:absolute; top:calc(-1 * var(--space-1_5)); right:calc(-1 * var(--space-2));
    background:var(--color-accent); color:var(--color-near-black-500);
    font-family:var(--font-display);
    font-size:0.6rem; font-weight:700;
    width:16px; height:16px; border-radius:var(--radius-full);
    display:flex; align-items:center; justify-content:center;
    line-height:1;
  }
  @media(min-width:821px){ nav ul{display:flex;} }

  /* ---------- Hero ---------- */
  .hero{
    min-height:100vh;
    display:grid;
    grid-template-columns:1fr;
    align-items:center;
    /* Mobile: zero top padding — the photo leads now, so it should sit
       flush against the sticky header with nothing between them. Desktop
       is untouched below (still text-first, needs the clearance). */
    padding:0 var(--space-container) var(--space-12);
    /* Mobile stacks photo-over-copy, so this is the gap between them —
       48px was the biggest space in the section. Desktop restores it,
       where the same value is the horizontal column gutter instead. */
    gap:var(--space-6);
    position:relative;
    overflow:hidden;
    isolation:isolate;
  }
  /* Mobile: photo before copy — the product is the first thing you see,
     text follows. Desktop reverts to source order (copy | image) once
     it's a genuine side-by-side two-column layout. */
  .hero-image{
    order:1;
    /* Bleeds past .hero's own horizontal padding to the screen edges, so
       the photo shows more of its actual frame instead of being cropped
       narrower by the section gutter. */
    margin-inline:calc(-1 * var(--space-container));
  }
  .hero-copy{order:2; text-align:center;}
  .hero p.sub{margin-inline:auto;}
  .hero-ctas{justify-content:center;}
  .hero-proof{justify-content:center;}
  @media(min-width:901px){
    .hero{grid-template-columns:1.1fr 0.9fr; gap:var(--space-12); padding-top:var(--space-32);}
    .hero-image, .hero-copy{order:initial;}
    .hero-image{margin-inline:0;}
    .hero-image .photo-slot{border-radius:var(--radius-2xl);}
    .hero-copy{text-align:left;}
    .hero p.sub{margin-inline:0;}
    .hero-ctas{justify-content:flex-start;}
    .hero-proof{justify-content:flex-start;}
  }
  .hero::before{
    /* Charcoal atmosphere across the WHOLE hero, plus a vignette that
       drops the edges below the page bg. Full-bleed on purpose: the old
       version only covered the left 70%, which is what made the hero read
       as two stitched-together halves. */
    content:'';
    position:absolute;
    inset:-10% -10% 0 -10%;
    background:
      radial-gradient(ellipse 70% 60% at 28% 22%, var(--overlay-charcoal-2), transparent 65%),
      radial-gradient(ellipse 60% 55% at 65% 75%, var(--overlay-charcoal-1), transparent 60%),
      linear-gradient(180deg, transparent 55%, var(--overlay-vignette) 100%);
    /* Forces every atmosphere layer to zero at the bottom edge, so the hero
       ends on the exact page background and meets the next section with no
       seam. The vignette still reads as depth just above the fade. */
    -webkit-mask-image:linear-gradient(180deg, black 86%, transparent 100%);
    mask-image:linear-gradient(180deg, black 86%, transparent 100%);
    z-index:0;
    pointer-events:none;
  }
  .hero::after{
    /* One ember light source, anchored on the product itself. Two stops
       share a center so it reads as a single glow rather than two blooms.
       Mobile: product sits below the copy, so the glow sits low. */
    content:'';
    position:absolute;
    inset:0;
    background:
      radial-gradient(circle at 50% 78%, var(--accent-alpha-22), transparent 55%),
      radial-gradient(circle at 50% 65%, var(--accent-alpha-12), transparent 45%);
    z-index:0;
    pointer-events:none;
  }
  @media(min-width:901px){
    /* Two-column layout — the glow follows the product to the right. */
    .hero::after{
      background:
        radial-gradient(circle at 76% 46%, var(--accent-alpha-22), transparent 55%),
        radial-gradient(circle at 70% 62%, var(--accent-alpha-12), transparent 45%);
    }
  }
  .hero > *{position:relative; z-index:1;}
  .ember-specks{
    /* Specks drift through the whole scene and fade radially around the
       same light source as .hero::after — no hard vertical cutoff. */
    position:absolute;
    inset:0;
    z-index:0;
    pointer-events:none;
    opacity:0.7;
    background-image:
      radial-gradient(1.5px 1.5px at 42% 34%, var(--color-accent), transparent),
      radial-gradient(1px 1px at 55% 62%, var(--color-accent), transparent),
      radial-gradient(2px 2px at 72% 24%, var(--accent-alpha-70), transparent),
      radial-gradient(1px 1px at 88% 72%, var(--color-accent), transparent),
      radial-gradient(1.5px 1.5px at 64% 84%, var(--accent-alpha-60), transparent),
      radial-gradient(1px 1px at 34% 78%, var(--color-accent), transparent),
      radial-gradient(1.5px 1.5px at 92% 44%, var(--accent-alpha-50), transparent),
      radial-gradient(1px 1px at 24% 56%, var(--accent-alpha-40), transparent);
    background-repeat:no-repeat;
    -webkit-mask-image:radial-gradient(ellipse 55% 60% at 50% 72%, black 0%, transparent 78%);
    mask-image:radial-gradient(ellipse 55% 60% at 50% 72%, black 0%, transparent 78%);
  }
  @media(min-width:901px){
    .ember-specks{
      -webkit-mask-image:radial-gradient(ellipse 48% 58% at 76% 48%, black 0%, transparent 78%);
      mask-image:radial-gradient(ellipse 48% 58% at 76% 48%, black 0%, transparent 78%);
    }
  }
  .hero-copy .eyebrow{margin-bottom:var(--space-4); display:block;}
  .hero h1{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(2.9rem, 7.2vw, 5.6rem);
    line-height:0.98;
    letter-spacing:-0.015em;
    margin-bottom:var(--space-5);
    text-transform:uppercase;
  }
  .hero h1 .accent{color:var(--color-accent);}
  .hero p.sub{
    font-family:var(--font-body);
    font-size:1.15rem;
    line-height:1.55;
    color:var(--text-on-dark-78);
    max-width:34ch;
    margin-bottom:var(--space-7);
  }
  .hero p.sub .sub-accent{color:var(--color-text); font-weight:600;}
  /* Last element in .hero-copy now that the proof strip moved above the h1 —
     a trailing margin here would just pad the bottom of the hero. */
  .hero-ctas{display:flex; gap:var(--space-4); flex-wrap:wrap;}

  /* Shared micro credibility strip. Separators are hairline rules, not
     middots — item text like "Non-GMO · Vegan Friendly" already owns the dot.
     Two users with different wrapping needs, so sizing and wrap live on the
     context class rather than here. */
  .proof-strip{
    display:flex;
    align-items:center;
    gap:var(--space-2);
    font-family:var(--font-display);
    letter-spacing:0.04em;
    color:var(--text-on-dark-60);
  }
  .proof-strip span{display:inline-flex; align-items:center; gap:var(--space-2); white-space:nowrap;}
  .proof-strip span + span::before{
    content:'';
    flex:0 0 auto;
    width:1px; height:0.95em;
    background:var(--border-on-dark-25);
  }
  .proof-strip strong{color:var(--color-star); font-weight:600; letter-spacing:0;}

  /* Hero: sits above the h1 where the eyebrow used to. Strictly one line at
     every width — nowrap plus a font-size that scales with the viewport,
     floored low enough to survive a 320px screen. */
  /* Three items totalling ~60 characters. One line at every width would
     need ~7px type on a phone, so instead the items stay unbreakable
     (white-space on .proof-strip span) while the GROUP is allowed to wrap
     to a second centred row on mobile. Desktop has the room for one line. */
  .hero-proof{
    flex-wrap:nowrap;
    /* One line at every width. Getting there costs characters, not just
       CSS: gaps are down to --space-1 and the copy was cut ~20 chars,
       because the previous wording needed ~7px type to fit a 375px phone. */
    gap:var(--space-1);
    margin-bottom:var(--space-4);
    font-size:clamp(0.56rem, 2.6vw, 0.72rem);
    white-space:nowrap;
  }

  /* Same wrapping contract as .hero-proof: items never break internally,
     but the group wraps to a second centred row on mobile rather than
     shrinking the type past legibility. One line from 901px up. */
  .lifestyle-proof{
    flex-wrap:wrap;
    justify-content:center;
    gap:var(--space-1_5) var(--space-2);
    margin-top:var(--space-4);
    font-size:clamp(0.62rem, 2.6vw, 0.72rem);
  }
  @media(min-width:901px){
    .lifestyle-proof{flex-wrap:nowrap;}
  }

  .stat-bar{
    display:grid;
    grid-template-columns:1fr 1fr;
    /* Sits mid-page now, so it's a self-contained rule-off band rather than
       the gradient bridge it used to be directly under the hero. */
    border-block:1px solid var(--border-on-dark-08);
    background:var(--color-bg);
    position:relative;
    z-index:2;
  }
  .stat-item{
    display:flex;
    align-items:flex-start;
    gap:var(--space-3_5);
    padding:var(--space-7) clamp(var(--space-4), 2.5vw, var(--space-8));
    border-right:1px solid var(--border-on-dark-08);
    border-bottom:1px solid var(--border-on-dark-08);
  }
  .stat-item:last-child{border-right:none;}
  @media(min-width:821px){
    .stat-bar{grid-template-columns:repeat(4,1fr);}
    .stat-item{border-bottom:none;}
  }
  .stat-item svg{width:26px; height:26px; stroke:var(--color-accent); flex-shrink:0; margin-top:0.15rem;}
  .stat-item .stat-title{
    font-family:var(--font-display);
    font-size:0.82rem;
    font-weight:600;
    letter-spacing:0.02em;
    text-transform:uppercase;
    line-height:1.3;
    margin-bottom:var(--space-1);
  }
  .stat-item .stat-sub{
    font-size:0.82rem;
    color:var(--text-on-dark-55);
    line-height:1.4;
  }

  /* ---------- Tension / insecurity+persuasion section ---------- */
  /* Full-bleed section — the copy holds its own 900px measure inside, so a
     background (band, or the hero bridge below) can paint edge to edge. */
  .tension{
    padding:var(--space-16) var(--space-container);
    text-align:center;
  }
  .tension > *{max-width:900px; margin-inline:auto;}
  /* Tightens the gap when the stat bar follows — a full space-24 below the
     copy left the two reading as unrelated blocks. */
  .tension:has(+ .stat-bar){padding-bottom:var(--space-8);}
  .tension--band{
    background:var(--color-bg-band);
    border-block:1px solid var(--border-on-dark-08);
  }
  .tension .eyebrow{justify-content:center; display:block; margin-bottom:var(--space-5);}
  .tension h2{
    font-family:var(--font-body);
    font-weight:500;
    font-size:clamp(1.6rem, 3.4vw, 2.5rem);
    line-height:1.35;
    color:var(--color-text);
  }
  .tension h2 .hot{color:var(--color-accent); font-style:normal; font-family:var(--font-display); font-weight:700;}
  /* Body copy inside a .tension block. Distinct from .fine, which is an
     uppercase display tagline and unreadable at paragraph length. Narrower
     than the 900px .tension > * cap so a full paragraph keeps a sane
     measure instead of running the width of the band. */
  .tension .detail{
    margin-top:var(--space-6);
    max-width:640px;
    font-size:1rem;
    line-height:1.6;
    color:var(--text-on-dark-70);
  }
  /* Uppercase micro-type is fine for a few words and punishing at sentence
     length, so once this runs past one line it needs a measure and looser
     leading — 900px of 0.75rem all-caps is unreadable. */
  .tension .fine{
    margin-top:var(--space-7);
    max-width:620px;
    font-family:var(--font-display);
    font-size:0.75rem;
    line-height:1.8;
    letter-spacing:0.06em;
    color:var(--text-on-dark-55);
    text-transform:uppercase;
    text-wrap:balance;
  }
  /* Citation, not a certification stamp — deliberately an icon rather than
     an agency logo. Naming EMA/NCCIH is a fair citation of published
     recognition for the herb; their actual insignia here would read as an
     endorsement of AfterSmoke itself, which neither body has given. */
  .citation-badge{
    display:flex;
    align-items:flex-start;
    justify-content:center;
    gap:var(--space-3);
    max-width:480px;
    margin:var(--space-6) auto 0;
    font-size:0.75rem;
    line-height:1.5;
    color:var(--text-on-dark-50);
    text-align:left;
    text-transform:none;
    letter-spacing:normal;
  }
  .citation-badge svg{width:18px; height:18px; flex:0 0 auto; stroke:var(--text-on-dark-50);}

  /* ---------- Content wrapper (formerly a scroll-color transition —
     removed in favor of one consistent brand theme site-wide) ---------- */
  #transition-wrap{
    position:relative;
    background:var(--color-bg);
  }

  .habit-heading{
    text-align:center;
    margin-top:var(--space-12);
    padding:0 var(--space-container);
  }
  .habit-heading .eyebrow{display:block;}
  .habit-row{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:1px;
    background:var(--border-on-dark-08);
    margin:var(--space-5) var(--space-container) 0;
    border-radius:var(--radius-lg);
    overflow:hidden;
  }
  @media(min-width:701px){ .habit-row{grid-template-columns:repeat(4,1fr);} }
  .habit-card{
    /* Top-lit charcoal so the tile reads as an object, not a flat swatch. */
    background:linear-gradient(160deg, var(--color-charcoal-600), var(--color-charcoal-500));
    padding:var(--space-8) var(--space-5);
    text-align:center;
    transition:background .3s ease;
  }
  .habit-card:hover{
    background:linear-gradient(160deg, var(--color-charcoal-600), var(--color-charcoal-600));
  }
  /* The icon sits in an ember well so each tile has a focal anchor
     instead of a small stroke floating in dead space. */
  .habit-card svg{
    width:54px; height:54px;
    padding:var(--space-3_5);
    margin:0 auto var(--space-4);
    stroke:var(--color-accent);
    background:var(--accent-alpha-12);
    border:1px solid var(--accent-alpha-22);
    border-radius:var(--radius-full);
    display:block;
    transition:background .3s ease, border-color .3s ease, transform .3s ease;
  }
  @media (hover:hover){
    .habit-card:hover svg{
      background:var(--accent-alpha-22);
      border-color:var(--accent-alpha-40);
      transform:translateY(-2px);
    }
  }
  .habit-card .label{
    font-family:var(--font-display);
    font-size:0.72rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    color:var(--text-on-dark-85);
    transition:color .3s ease;
  }
  .habit-card:hover .label{color:var(--color-text);}

  .headline-block{
    text-align:center;
    /* A card mid-rotation projects wider than its own box. Clipping here
       guarantees it can never paint over the section edges. */
    overflow:hidden;
    padding:var(--space-14) var(--space-container) var(--space-8);
  }
  /* Every neighbouring block announces itself with an eyebrow before it
     speaks. Without one this block started mid-thought and read as an
     interstitial rather than a section of its own. */
  .headline-block .eyebrow{display:block; margin-bottom:var(--space-4);}
  .headline-block h2{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.8rem, 4vw, 3rem);
    line-height:1.15;
    max-width:23ch;
    margin:0 auto;
    /* Evens out the line lengths instead of filling greedily — without it
       the second sentence strands "be too." alone on a fourth line. */
    text-wrap:balance;
  }
  /* Concession, then pivot. These are two different jobs, so they get two
     different weights: the setup recedes, the turn carries the ember. Each
     is display:block so the pair breaks cleanly and balances independently
     — a hard <br> would fix the break point at one viewport width only. */
  /* Full white, deliberately. Dimming this line was tried and reverted: a
     display heading rendered half-white/half-grey reads as two elements, or
     as something disabled, rather than as one sentence with a turn in it.
     The ember phrase below carries the emphasis on its own. */
  .headline-block h2 .headline-setup{display:block;}
  .headline-block h2 .headline-turn{
    display:block;
    margin-top:var(--space-5);
  }
  .headline-block h2 .ember-word{color:var(--color-accent);}
  /* Fixed box, every width: 560px max, 4:3 -> 420px tall on desktop, and
     the same ratio scaled down on mobile via width:100%. .headline-photo
     also carries .flip-card, whose shared rule supplies overflow:hidden —
     a hard clip at THIS exact box, at every rotation angle, regardless of
     perspective distance, guaranteeing the photo can't escape on desktop.
     No border here deliberately: it lives on .flip-face below instead, so
     the frame rotates WITH the card. A border on this static outer box
     would sit still while only the photo underneath turned — a static
     frame over swapping content, not one card flipping, which is exactly
     what looked wrong on desktop's flatter, more visible rotation. */
  /* Reuses .proof-strip (the same star/pipe component from the hero and
     lifestyle sections) rather than a one-off — centered here since the
     whole block is centered, unlike the hero's left-aligned desktop use. */
  .headline-proof{
    justify-content:center;
    margin-top:var(--space-3);
  }
  .headline-block .headline-photo{
    width:min(560px, 100%);
    aspect-ratio:4/3;
    margin:var(--space-10) auto 0;
  }
  /* Ember hairline on each rotating face — matches .proof-grid .proof-photo
     — so the whole card, frame included, appears to turn as one piece,
     the same read the lifestyle grid cards already have (they carry no
     competing outer border to begin with). */
  .headline-flip .flip-face{border:2px solid var(--accent-alpha-50);}
  /* Perspective distortion scales with how large the element is relative to
     the vanishing distance: fine on a phone (~350px wide, ratio ~2.9) but
     this card reaches its full 560px on desktop, dropping the ratio to 1.8
     and swinging the rotating edge out further than at small sizes. A
     longer vanishing distance keeps the turn looking gentle rather than a
     lurch — and the .flip-card overflow:hidden clip means even if this
     number is ever wrong again, nothing can render outside the box.
     Specificity note: (0,2,0) here deliberately beats the unconditional
     .flip-card{perspective:1000px} rule regardless of where either sits in
     the file — a bare .headline-flip{} tied with .flip-card on specificity
     and silently lost once before. */
  @media(min-width:901px){
    .headline-block .headline-flip{perspective:2400px;}
  }
  /* The page's emotional turn dead-ended into an ingredient list. This is the
     highest-intent moment outside the hero, so it gets a real exit. */
  .headline-block .headline-cta{margin-top:var(--space-10);}

  /* ---------- Ingredient / proof section ---------- */
  .section{
    padding:var(--space-14) var(--space-container);
  }
  /* Single-photo testimonial slot — same sizing/border language as the
     other one-photo moments on the page (.headline-photo, .proof-photo):
     4/5 matches the source art exactly (1120x1400), so nothing is cropped. */
  /* Highlighter-marker reveal on "not ours." — text is always fully
     visible/legible by default (this base rule has no opacity or motion in
     it), so nothing depends on JS. Under .js-motion the mark starts unswept
     and the text starts hidden; hl-reveal below fades the text in first,
     then lets the highlight visibly catch up and sweep under it — reads as
     "marking over already-visible text," not a bounce or a wipe. */
  /* Underline draw, not a highlight block. Text itself never fades — only
     a thin ember rule under it grows left-to-right on scroll-in. Base rule
     (no .js-motion) draws it fully by default, so nothing depends on JS.
     ::after rather than border-bottom/text-decoration so the line's own
     radius and thickness are controllable and it can be transform-animated
     (scaleX, GPU-composited) instead of animating width (layout-triggering). */
  .hl-mark{
    position:relative;
    padding-bottom:0.1em;
  }
  /* Base line. box-shadow starts included (not animated in via keyframe)
     so the no-JS / reduced-motion default is a fully-formed line with its
     glow already there — nothing missing when motion is off. */
  .hl-mark::after{
    content:'';
    position:absolute;
    left:0; right:0; bottom:0;
    height:2px;
    background:var(--color-accent);
    border-radius:var(--radius-full);
    box-shadow:0 0 8px var(--accent-alpha-60);
    transform:scaleX(1);
    transform-origin:left;
  }
  /* One-time glint — a short bright streak that travels the length of the
     line once, timed to start right as the draw finishes. Off-screen at
     rest (opacity:0, no motion needed to hide it), so it costs nothing
     when .js-motion is absent. */
  .hl-mark::before{
    content:'';
    position:absolute;
    left:0; bottom:-1px;
    width:28px; height:4px;
    background:linear-gradient(90deg, transparent, #fff, transparent);
    filter:blur(1px);
    opacity:0;
    pointer-events:none;
  }
  /* .hl-mark appended to every selector below so specificity is
     UNAMBIGUOUSLY higher than the generic ".js-motion [data-reveal]" rules
     elsewhere in this file, rather than tied with them — a tie was a real
     bug earlier (equal specificity means the LATER file rule wins outright
     for the whole property, and the generic reveal-rise rule sits far
     below this block). Opacity is pinned back to 1 here specifically to
     cancel that generic rule's opacity:0 base — this mark never fades,
     only the line draws. */
  .js-motion [data-reveal="highlight"].hl-mark{opacity:1;}
  .js-motion [data-reveal="highlight"].hl-mark::after{
    transform:scaleX(0);
    box-shadow:0 0 0 transparent;
  }
  .js-motion [data-reveal="highlight"].hl-mark.is-visible::after{
    animation:hl-underline 0.6s var(--ease-out-soft) 0.15s both;
  }
  /* Glint starts at 0.7s — 0.15s initial delay + 0.6s draw, so it chases
     the line just as it finishes rather than racing ahead of it or
     lagging noticeably behind. */
  .js-motion [data-reveal="highlight"].hl-mark.is-visible::before{
    animation:hl-glint 0.7s ease-out 0.7s both;
  }
  @keyframes hl-underline{
    from{transform:scaleX(0); box-shadow:0 0 0 transparent;}
    to{transform:scaleX(1); box-shadow:0 0 8px var(--accent-alpha-60);}
  }
  @keyframes hl-glint{
    0%   {left:0%;   opacity:0;}
    15%  {opacity:1;}
    85%  {opacity:1;}
    100% {left:calc(100% - 28px); opacity:0;}
  }
  .home-testimonial-photo{
    --slot-ratio:4/5;
    width:min(480px, 100%);
    margin:var(--space-10) auto 0;
    border:2px solid var(--accent-alpha-50);
    border-radius:var(--radius-2xl);
  }
  /* Trust ticker between the testimonial and product sections. Same
     seamless-loop technique as .announce-track / .carousel-track (message
     set emitted exactly twice, animated 0 -> -50%), but quieter than the
     bright ember top banner — this sits mid-page on the dark background,
     so it's text-on-dark rather than a solid ember band. The hairline
     borders do double duty as the section divider. */
  .trust-ticker{
    overflow:hidden;
    padding:var(--space-6) 0;
    border-block:1px solid var(--border-on-dark-08);
  }
  .trust-ticker-track{
    display:flex;
    align-items:center;
    gap:var(--space-8);
    width:max-content;
    padding-right:var(--space-8);
    font-family:var(--font-display);
    font-size:0.78rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    color:var(--text-on-dark-60);
    /* Slower than the top banner's 26s — this one is ambient background
       texture, not a lead promo, so it shouldn't compete for attention. */
    animation:trust-ticker-scroll 42s linear infinite;
  }
  .trust-ticker:hover .trust-ticker-track{animation-play-state:paused;}
  .trust-ticker-track span[aria-hidden]{color:var(--color-accent); opacity:0.7;}
  @keyframes trust-ticker-scroll{
    from{ transform:translateX(0); }
    to{ transform:translateX(-50%); }
  }
  .section--band{
    background:var(--color-bg-band);
    border-block:1px solid var(--border-on-dark-08);
  }
  .proof-grid{
    display:grid;
    grid-template-columns:1fr;
    gap:var(--space-14);
    align-items:center;
    max-width:1200px;
    margin:0 auto;
  }
  /* Mobile: heading reads first, photo sits below it — so this section
     doesn't stack directly on top of the headline-block photo above it
     with nothing but a photo-to-photo seam between them. Desktop reverts
     to source order (photo | text) once it's a genuine side-by-side. */
  /* Mobile: the photo sits *inside* the reading order — after the heading,
     before the ingredient list — so the section opens with words, not a
     second photo. `display:contents` dissolves .proof-text's box so its
     children become grid items alongside .proof-photo and can be ordered
     against it; `order` alone can't reorder across nesting levels. Row gap
     is zeroed here because each element already carries its own top margin.
     Desktop restores the real two-column box. */
  .proof-grid{row-gap:0;}
  .proof-grid .proof-text{display:contents;}
  .proof-grid .proof-text > .eyebrow{order:1; text-align:center;}
  .proof-grid .proof-text > h2{order:2; text-align:center; text-wrap:balance;}
  .proof-grid .proof-text > .label-caption{order:3; text-align:center;}
  .proof-grid .proof-photo{order:4; margin-top:var(--space-10);}
  .proof-grid .proof-text > .ingredient-list{order:5;}
  @media(min-width:901px){
    .proof-grid{grid-template-columns:0.9fr 1.1fr; row-gap:var(--space-14);}
    .proof-grid .proof-text{display:block;}
    .proof-grid .proof-photo{order:initial; margin-top:0;}
    .proof-grid .proof-text > .eyebrow,
    .proof-grid .proof-text > h2,
    .proof-grid .proof-text > .label-caption,
    .proof-grid .proof-text > .ingredient-list{order:initial;}
    .proof-grid .proof-text > .eyebrow,
    .proof-grid .proof-text > h2,
    .proof-grid .proof-text > .label-caption{text-align:left;}
  }
  .label-caption{
    margin-top:var(--space-3);
    font-family:var(--font-display);
    font-size:0.78rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    color:var(--text-on-dark-55);
  }
  .ingredient-list{display:flex; flex-direction:column; gap:var(--space-6); margin-top:var(--space-8);}
  .ingredient-item{
    display:grid;
    grid-template-columns:auto 1fr;
    gap:var(--space-4);
    padding-bottom:var(--space-6);
    border-bottom:1px solid var(--border-on-dark-08);
  }
  .ingredient-item .num{font-family:var(--font-display); font-weight:700; color:var(--color-accent); font-size:0.85rem;}
  .ingredient-item h4{font-family:var(--font-display); font-weight:600; font-size:0.95rem; margin-bottom:var(--space-1);}
  .ingredient-item p{font-size:0.92rem; line-height:1.5; color:var(--text-on-dark-60);}

  /* ---------- How to use ---------- */
  .ritual{
    max-width:1100px; margin:0 auto;
    text-align:center;
  }
  .ritual .ritual-aside{
    margin:var(--space-5) auto 0;
    max-width:54ch;
    font-size:1rem;
    line-height:1.55;
    color:var(--text-on-dark-60);
  }
  .ritual .ritual-aside .hot{color:var(--color-accent); font-weight:600;}
  .ritual-steps{
    display:grid;
    grid-template-columns:1fr;
    gap:var(--space-10);
    margin-top:var(--space-12);
    text-align:center;
  }
  .ritual-step{text-align:center;}
  /* Four steps: 2x2 on tablet, one row of four on desktop. A repeat(3) tier
     would strand step 04 alone on its own line. */
  @media(min-width:561px){ .ritual-steps{grid-template-columns:repeat(2,1fr);} }
  @media(min-width:901px){ .ritual-steps{grid-template-columns:repeat(4,1fr);} }
  @media(min-width:901px){ .ritual-step{text-align:left;} }
  .ritual-step .step-num{
    /* Outlined ember numerals. Previously stroked in near-black on a
       near-black background with a transparent fill — i.e. invisible. */
    font-family:var(--font-display);
    font-size:2.4rem;
    font-weight:700;
    -webkit-text-stroke:1.5px var(--color-accent);
    -webkit-text-fill-color:transparent;
    color:var(--color-accent);
    margin-bottom:var(--space-3);
    display:block;
  }
  .ritual-step h4{font-family:var(--font-display); font-weight:600; font-size:1.05rem; margin-bottom:var(--space-2);}
  .ritual-step p{font-size:0.95rem; line-height:1.55; color:var(--text-on-dark-60);}

  /* ---------- Lifestyle grid ---------- */
  .lifestyle-grid{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:var(--space-4);
    max-width:1300px;
    margin:var(--space-12) auto 0;
  }

  /* ---------- Lifestyle flip cards ----------
     Front = the product where it lives. Back = the person who put it there.
     One shared 9s cycle drives the cards and the heading, so the copy swaps
     at the exact moment the cards are edge-on and showing nothing.

     Timing (see @keyframes below):
       0–42%   front, heading A
       42–50%  flip out          <- 46% is edge-on, the text swap point
       50–92%  back, heading B
       92–100% flip back         <- 96% is edge-on, text returns
     ------------------------------------------------------------------ */
  /* overflow:hidden here is spec-safe: it forces transform-style:flat only
     on the element that itself declares preserve-3d, which is .flip-inner,
     not .flip-card. Clipping at this level — the card's own box — means a
     rotating face can never visually bulge past its true bounds, at any
     angle, regardless of perspective distance. */
  /* No overflow:hidden here. It clips the card at its exact box, which
     slices the projecting edge mid-rotation into a hard straight cut
     instead of a smooth turn. Containment comes from the perspective
     distance instead (see .headline-flip), plus the section-level clip
     on .headline-block. */
  .flip-card{
    position:relative;
    perspective:1000px;
  }
  .lifestyle-grid .flip-card{aspect-ratio:1/1;}
  .flip-inner{
    position:absolute;
    inset:0;
    transform-style:preserve-3d;
    animation:card-flip var(--flip-cycle) ease-in-out infinite;
  }
  /* Small ripple across the row so it reads as depth rather than four
     shutters snapping at once — under a tenth of a second apart, so the
     group still lands as one event against the heading. */
  /* The stagger lives on the CARD as a custom property, not on .flip-inner
     directly, so every animation inside that card reads the same value.
     Setting it per-element is what broke it: the rotation was staggered
     but the front-face crossfade was not, so on cards 2-4 the image swap
     fired while that card's rotation sat .09-.27s behind. The swap window
     is only ~4% of the cycle, so a .27s offset pushes the tail of the fade
     into the visible period — the image visibly changes on a face that is
     still pointed at you. Custom properties inherit; animation-delay does
     not. This makes drift structurally impossible. */
  .lifestyle-grid .flip-card{--flip-delay:0s;}
  .lifestyle-grid .flip-card:nth-child(2){--flip-delay:.09s;}
  .lifestyle-grid .flip-card:nth-child(3){--flip-delay:.18s;}
  .lifestyle-grid .flip-card:nth-child(4){--flip-delay:.27s;}
  .flip-face{
    position:absolute;
    inset:0;
    backface-visibility:hidden;
    -webkit-backface-visibility:hidden;
    border-radius:var(--radius-2xl);
    overflow:hidden;
  }
  .flip-face img{width:100%; height:100%; object-fit:cover; display:block;}
  .flip-back{transform:rotateY(180deg);}
  @keyframes card-flip{
    0%, 42%   {transform:rotateY(0deg);}
    50%, 92%  {transform:rotateY(180deg);}
    100%      {transform:rotateY(360deg);}
  }

  /* All three headings occupy the same grid cell so the block is sized by
     the tallest one and nothing reflows when they trade places. */
  .heading-swap{display:grid;}
  .heading-swap > span{grid-area:1 / 1;}
  .lifestyle-h2{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.6rem, 3vw, 2.2rem);
    margin-top:0.8rem;
    text-wrap:balance;
  }
  /* Delay matches the middle of the card ripple so the swap reads as one
     synchronised beat with the row rather than leading it. */
  .heading-a, .heading-b{animation:var(--flip-cycle) ease-in-out infinite; animation-delay:.13s;}
  .heading-a{animation-name:heading-out;}
  .heading-b{opacity:0; animation-name:heading-in;}
  @keyframes heading-out{
    0%, 40%    {opacity:1; transform:translateY(0);}
    46%, 90%   {opacity:0; transform:translateY(calc(-1 * var(--space-2)));}
    96%, 100%  {opacity:1; transform:translateY(0);}
  }
  @keyframes heading-in{
    0%, 40%    {opacity:0; transform:translateY(var(--space-2));}
    46%, 90%   {opacity:1; transform:translateY(0);}
    96%, 100%  {opacity:0; transform:translateY(var(--space-2));}
  }
  @media(min-width:901px){ .lifestyle-grid{grid-template-columns:repeat(4,1fr);} }
  .lifestyle-cta{
    text-align:center;
    margin-top:var(--space-12);
  }
  .lifestyle-cta-note{
    margin-top:var(--space-4);
    font-family:var(--font-display);
    font-size:0.72rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    color:var(--text-on-dark-50);
  }
  /* ---------- Cost comparison chart ---------- */
  .cost-compare-inner{max-width:640px; margin:0 auto;}
  .cost-sub{
    font-family:var(--font-body);
    font-size:0.92rem;
    line-height:1.5;
    color:var(--text-on-dark-60);
    text-align:center;
    max-width:460px;
    margin:var(--space-3) auto 0;
  }
  /* Lifts to full white rather than ember — the accent is already carrying
     the price in .cost-callout, and a second orange phrase this close would
     split the emphasis instead of concentrating it. */
  .cost-sub strong{color:var(--color-text); font-weight:600;}

  .cost-chart{
    list-style:none;
    margin:var(--space-10) 0 0;
    padding:0;
    display:flex;
    flex-direction:column;
    gap:var(--space-6);
  }
  .cost-row-head{
    display:flex;
    align-items:baseline;
    justify-content:space-between;
    gap:var(--space-3);
    margin-bottom:var(--space-2);
    flex-wrap:wrap;
  }
  .cost-name{font-family:var(--font-display); font-weight:600; font-size:0.92rem; color:var(--color-text);}
  .cost-note{font-size:0.76rem; color:var(--text-on-dark-50);}
  .cost-row-body{display:flex; align-items:center; gap:var(--space-4);}
  .cost-track{
    position:relative;
    flex:1;
    height:20px;
    background:var(--border-on-dark-08);
    border-radius:var(--radius-lg);
    overflow:hidden;
  }
  .cost-fill{
    position:absolute;
    left:0; top:0;
    height:100%;
    background:var(--text-on-dark-30);
    border-radius:0 var(--radius-lg) var(--radius-lg) 0;
  }
  .cost-row--accent .cost-fill{background:var(--color-accent);}
  .cost-value{
    flex:0 0 auto;
    min-width:64px;
    text-align:right;
    font-variant-numeric:tabular-nums;
    font-family:var(--font-display);
    font-weight:700;
    font-size:0.92rem;
    color:var(--color-text);
  }
  .cost-value .cost-unit{font-weight:500; font-size:0.68rem; color:var(--text-on-dark-50); margin-left:1px;}
  .cost-callout{
    margin-top:var(--space-8);
    text-align:center;
    font-family:var(--font-display);
    font-weight:600;
    font-size:1rem;
    line-height:1.5;
    color:var(--color-text);
  }
  .cost-callout strong{color:var(--color-accent);}
  .cost-footnote{
    margin-top:var(--space-3);
    text-align:center;
    font-size:0.7rem;
    line-height:1.5;
    color:var(--text-on-dark-40);
  }

  /* ---------- Real-customer photo carousel (auto-scrolling, infinite loop) ---------- */
  .carousel-heading{
    text-align:center;
    max-width:620px;
    margin:var(--space-6) auto 0;
    padding:0 var(--space-container);
  }
  .carousel-heading .eyebrow{display:block; margin-bottom:var(--space-3);}
  .carousel-heading h2{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.5rem, 3.2vw, 2.1rem);
    line-height:1.3;
  }
  .carousel-heading h2 .ember-word{color:var(--color-accent);}
  .carousel-heading .carousel-subtext{
    margin-top:var(--space-3);
    font-family:var(--font-display);
    font-size:0.78rem;
    letter-spacing:0.04em;
    color:var(--text-on-dark-55);
  }
  .carousel-wrap{
    max-width:100%;
    /* Bottom was 0 — the only gap under a carousel came from whatever block
       happened to follow it, so the strip sat tight against the next
       section. space-10 gives it room of its own. */
    margin:var(--space-6) auto var(--space-10);
    position:relative;
    overflow:hidden;
    -webkit-mask-image:linear-gradient(to right, transparent 0, black var(--space-8), black calc(100% - var(--space-8)), transparent 100%);
    mask-image:linear-gradient(to right, transparent 0, black var(--space-8), black calc(100% - var(--space-8)), transparent 100%);
  }
  .carousel-track{
    display:flex;
    gap:var(--space-3);
    width:max-content;
    animation:carousel-scroll 34s linear infinite;
  }
  .carousel-wrap:hover .carousel-track{animation-play-state:paused;}
  /* Second marquee runs the other way so the two don't read as one long
     conveyor. Starting at -50% and ending at 0 is the same distance, just
     reversed — the halves still line up, so the loop stays seamless. */
  .carousel-heading--lifestyle{margin-top:var(--space-14);}
  .carousel-wrap--reverse .carousel-track{animation-name:carousel-scroll-rev;}
  @keyframes carousel-scroll-rev{
    from{ transform:translateX(-50%); }
    to{ transform:translateX(0); }
  }
  @keyframes carousel-scroll{
    from{ transform:translateX(0); }
    to{ transform:translateX(-50%); }
  }
  .carousel-card{
    flex:0 0 auto;
    width:min(160px, 42vw);
    border-radius:var(--radius-lg);
    overflow:hidden;
    aspect-ratio:4/5;
    position:relative;
    background:var(--color-bg-elevated);
  }
  .carousel-card img{width:100%; height:100%; object-fit:cover; display:block;}

  /* ---------- Text review fader ----------
     No card chrome — the quote sits straight on the page like the photos.
     All items are stacked in one grid cell so the block sizes itself to the
     tallest quote, then each crossfades in turn. 10 reviews x 4s = 40s cycle. */
  .review-heading{text-align:center; margin-top:var(--space-12); padding:0 var(--space-container);}

  /* ---------- Customer reviews (vertical list, ecom-style) ----------
     Replaces the old single-quote fading carousel. Cards are rendered by
     JS from window.AFTERSMOKE_REVIEWS (js/reviews-data.js) — 8 at a time,
     "Show More" appends the next batch. Static base markup (heading,
     summary, empty list/photo containers) always renders; only the cards
     themselves depend on JS, same no-JS-safety posture as the rest of the
     page's dynamic bits (cart, gallery). */
  .reviews-section{
    max-width:720px;
    margin:var(--space-8) auto 0;
    /* This is the last thing in #transition-wrap — footer starts right
       after it with only its own top padding for breathing room. Without
       a bottom pad here, "Show More Reviews" sits almost flush against
       the footer logo, reading as one run-on block instead of two
       sections. Matches the space-16 close other full sections (e.g.
       .final-cta) use before handing off to the footer. */
    padding:0 var(--space-container) var(--space-16);
  }
  .reviews-summary{
    display:flex;
    flex-wrap:wrap;
    align-items:baseline;
    justify-content:center;
    gap:var(--space-2) var(--space-3);
    text-align:center;
  }
  .reviews-summary-stars{color:var(--color-star); font-size:1.1rem; letter-spacing:0.14em;}
  .reviews-summary-score{font-family:var(--font-display); font-weight:700; font-size:1rem; color:var(--color-text);}
  .reviews-summary-count{font-size:0.85rem; color:var(--text-on-dark-50);}

  /* Star-rating filter pills — "All" plus one per rating present in the
     data, built by JS so the counts can never drift out of sync. */
  .reviews-filter{
    display:flex;
    justify-content:center;
    flex-wrap:wrap;
    gap:var(--space-2);
    margin-top:var(--space-5);
  }
  .reviews-filter-btn{
    padding:var(--space-1_5) var(--space-3);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-full);
    background:none;
    font-family:var(--font-body);
    font-size:0.8rem;
    color:var(--text-on-dark-60);
    cursor:pointer;
    transition:border-color var(--dur-micro) ease, color var(--dur-micro) ease, background var(--dur-micro) ease;
  }
  .reviews-filter-btn:hover{border-color:var(--border-on-dark-25); color:var(--text-on-dark-75);}
  .reviews-filter-btn.is-active{
    background:var(--accent-alpha-12);
    border-color:var(--accent-alpha-40);
    color:var(--color-accent);
  }

  /* Photo strip — Amazon-style "photos from reviews" preview row. Each
     thumbnail opens the lightbox dialog with that review's full text. */
  .reviews-photos{
    display:flex;
    justify-content:center;
    flex-wrap:wrap;
    gap:var(--space-3);
    margin-top:var(--space-6);
  }
  .reviews-photo-thumb{
    aspect-ratio:1/1;
    width:64px;
    padding:0;
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-md);
    overflow:hidden;
    cursor:pointer;
    background:none;
    transition:border-color var(--dur-micro) ease;
  }
  .reviews-photo-thumb:hover{border-color:var(--accent-alpha-50);}
  .reviews-photo-thumb img{display:block; width:100%; height:100%; object-fit:cover;}

  .reviews-list{
    display:flex;
    flex-direction:column;
    margin-top:var(--space-10);
  }
  .review-card{padding:var(--space-6) 0; border-bottom:1px solid var(--border-on-dark-08);}
  .review-card:first-child{padding-top:0;}
  .review-card-stars{color:var(--color-star); font-size:0.95rem; letter-spacing:0.14em;}
  .review-card-stars .is-empty{color:var(--border-on-dark-25);}
  .review-card-title{
    margin-top:var(--space-2);
    font-family:var(--font-display);
    font-weight:700;
    font-size:1rem;
    color:var(--color-text);
  }
  .review-card-body{
    margin-top:var(--space-2);
    font-size:0.92rem;
    line-height:1.65;
    color:var(--text-on-dark-70);
  }
  /* Inline photo on the ~10% of reviews that have one — same lightbox as
     the strip at the top of the section, opened from either place. */
  .review-card-photo{
    display:block;
    width:96px;
    aspect-ratio:1/1;
    margin-top:var(--space-3);
    padding:0;
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-md);
    overflow:hidden;
    cursor:pointer;
    background:none;
    transition:border-color var(--dur-micro) ease;
  }
  .review-card-photo:hover{border-color:var(--accent-alpha-50);}
  .review-card-photo img{display:block; width:100%; height:100%; object-fit:cover;}
  .review-card-foot{
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap:var(--space-2) var(--space-3);
    margin-top:var(--space-4);
    font-size:0.8rem;
    color:var(--text-on-dark-50);
  }
  .review-card-name{font-family:var(--font-display); font-weight:600; color:var(--text-on-dark-75);}
  .review-card-verified{color:var(--color-accent);}
  .review-helpful{
    display:inline-flex;
    align-items:center;
    gap:var(--space-1_5);
    margin-left:auto;
    padding:var(--space-1) var(--space-2_5);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-full);
    background:none;
    font-family:var(--font-body);
    font-size:0.78rem;
    color:var(--text-on-dark-50);
    cursor:pointer;
    transition:border-color var(--dur-micro) ease, color var(--dur-micro) ease;
  }
  .review-helpful svg{width:14px; height:14px; stroke:currentColor; fill:none;}
  .review-helpful:hover{color:var(--text-on-dark-75); border-color:var(--border-on-dark-25);}
  .review-helpful.is-active{color:var(--color-accent); border-color:var(--accent-alpha-40);}
  .review-helpful.is-active svg{fill:var(--color-accent);}

  .reviews-showmore{display:flex; margin:var(--space-8) auto 0; justify-content:center;}
  .reviews-showmore[hidden]{display:none;}

  /* Photo review lightbox — same centering technique as the other two
     dialogs (explicit inset+margin rather than the UA default). */
  dialog.review-photo-dialog{
    inset:0;
    margin:auto;
    border:none;
    padding:0;
    border-radius:var(--radius-2xl);
    background:transparent;
    width:calc(100vw - var(--space-8));
    max-width:420px;
    max-height:94vh;
  }
  dialog.review-photo-dialog::backdrop{
    background:color-mix(in srgb, var(--color-near-black-500) 70%, transparent);
    backdrop-filter:blur(4px);
  }
  .review-photo-card{
    position:relative;
    overflow:hidden;
    max-height:94vh;
    overflow-y:auto;
    border-radius:var(--radius-2xl);
    border:1px solid var(--border-on-dark-08);
    background:var(--color-bg-elevated);
  }
  .review-photo-card img{display:block; width:100%; aspect-ratio:1/1; object-fit:cover;}
  .review-photo-close{
    position:absolute;
    top:var(--space-3); right:var(--space-3);
    width:28px; height:28px;
    display:flex; align-items:center; justify-content:center;
    background:color-mix(in srgb, var(--color-near-black-500) 55%, transparent);
    border:none; border-radius:var(--radius-full);
    font-size:1.3rem; line-height:1;
    color:var(--color-text);
    cursor:pointer;
  }
  .review-photo-body{padding:var(--space-5) var(--space-6) var(--space-6);}
  .review-photo-body h4{
    margin-top:var(--space-2);
    font-family:var(--font-display);
    font-weight:700;
    font-size:1.05rem;
    color:var(--color-text);
  }
  .review-photo-body p{margin-top:var(--space-2); font-size:0.9rem; line-height:1.6; color:var(--text-on-dark-70);}
  .review-photo-meta{
    display:flex;
    gap:var(--space-2);
    margin-top:var(--space-4);
    font-size:0.8rem;
    color:var(--text-on-dark-50);
  }
  .review-photo-meta span:first-child{font-weight:600; color:var(--text-on-dark-75);}
  /* Reduced-motion handling for the whole page now lives in one block at the
     bottom of this file — see "Reduced motion". */

  /* ---------- Final CTA ---------- */
  .final-cta{
    background:var(--color-near-black-500);
    color:var(--color-text);
    text-align:center;
    padding:var(--space-16) var(--space-container);
    position:relative;
    overflow:hidden;
    isolation:isolate;
  }
  .final-cta::before{
    /* Bookends the hero: same single ember source, rising behind the CTA. */
    content:'';
    position:absolute;
    inset:0;
    background:
      radial-gradient(ellipse 70% 60% at 50% 92%, var(--accent-alpha-22), transparent 62%),
      radial-gradient(ellipse 55% 48% at 50% 74%, var(--accent-alpha-12), transparent 55%);
    z-index:0;
    pointer-events:none;
  }
  .final-cta > *{position:relative; z-index:1;}
  .final-cta h2{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.9rem, 4vw, 3.2rem);
    margin-bottom:var(--space-5);
  }
  /* Scoped to the intro line by class, NOT `.final-cta p`. That descendant
     selector is (0,1,1) and was reaching every paragraph nested inside the
     section — seven in the accordion, plus .cost-footnote, .directions-note
     and .product-tagline — overriding each one's font-size, max-width and
     margins with the intro's. */
  .final-cta-intro{
    font-family:var(--font-body);
    font-size:1.05rem;
    color:var(--text-on-dark-70);
    max-width:40ch;
    margin:0 auto var(--space-8);
  }
  .final-cta-intro .accent-word{color:var(--color-accent); font-weight:600;}

  /* ---------- Product photo gallery ----------
     One large main photo with a clickable thumbnail strip beneath — swaps
     via JS (main.js), degrades to just showing the first photo without it. */
  .product-gallery{margin:var(--space-8) 0;}
  .product-gallery-main{
    max-width:420px;
    margin:0 auto;
    position:relative;
  }
  .product-gallery-mainslot{--slot-ratio:4/5; border-radius:var(--radius-2xl);}
  /* Sits on .product-gallery-main, NOT inside #galleryMain — the thumbnail
     handler wipes that element's innerHTML on every swap, which would take
     the badge with it. Same pill treatment as .purchase-box-badge. */
  .product-badge{
    position:absolute;
    top:var(--space-4);
    left:var(--space-4);
    z-index:2;
    background:var(--color-accent);
    color:var(--color-near-black-500);
    font-family:var(--font-display);
    font-weight:700;
    font-size:0.66rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    padding:3px var(--space-3);
    border-radius:var(--radius-full);
  }
  .product-gallery-thumbs{
    display:flex;
    justify-content:center;
    flex-wrap:wrap;
    gap:var(--space-2);
    max-width:420px;
    margin:var(--space-3) auto 0;
  }
  .product-gallery-thumb{
    display:block;
    flex:0 0 auto;
    width:56px;
    padding:0;
    background:none;
    border:2px solid transparent;
    border-radius:var(--radius-md);
    overflow:hidden;
    cursor:pointer;
    opacity:0.55;
    transition:opacity var(--dur-micro) ease, border-color var(--dur-micro) ease;
  }
  .product-gallery-thumb-slot{--slot-ratio:4/5; pointer-events:none;}
  .product-gallery-thumb:hover{opacity:0.85;}
  .product-gallery-thumb.is-active{opacity:1; border-color:var(--color-accent);}

  /* ---------- Product title block ---------- */
  .product-rating{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:var(--space-2);
    margin:var(--space-8) 0 var(--space-3);
  }
  .product-rating .stars{color:var(--color-star); letter-spacing:0.15em; font-size:1rem;}
  .product-rating .rating-count{font-size:0.85rem; color:var(--text-on-dark-60);}
  .product-title{
    font-family:var(--font-display);
    font-weight:800;
    font-size:clamp(1.5rem, 3vw, 2.1rem);
    color:var(--color-accent);
    margin-bottom:var(--space-2);
  }
  /* Held to one line at every width. nowrap alone would overflow a narrow
     phone, so the size scales with the viewport and only caps at 0.95rem
     once there's room for the full string. */
  .product-tagline{
    font-size:clamp(0.7rem, 3.2vw, 0.95rem);
    font-style:italic;
    color:var(--text-on-dark-70);
    margin-bottom:var(--space-8);
    white-space:nowrap;
  }

  /* ---------- Product benefits checklist ---------- */
  .product-benefits{
    list-style:none;
    display:flex;
    flex-direction:column;
    gap:var(--space-3);
    text-align:left;
    max-width:420px;
    margin:0 auto var(--space-8);
  }
  .product-benefits li{
    display:flex;
    align-items:flex-start;
    gap:var(--space-3);
    font-size:0.95rem;
    color:var(--text-on-dark-85);
  }
  .product-benefits li::before{
    content:'✓';
    flex:0 0 auto;
    color:var(--color-accent);
    font-weight:700;
  }

  /* ---------- Purchase box ---------- */
  /* Two selectable plans. The radio is a real <input> with appearance:none
     rather than a decorative span, so selection state, keyboard arrow-key
     navigation and screen-reader announcement all come from the platform —
     only the CTA label needs JS. */
  .purchase-options{
    display:flex;
    flex-direction:column;
    /* space-5, not -4: .purchase-box-badge is translateY(-50%) off the top
       edge, so the gap has to clear the badge overhang of the card below. */
    gap:var(--space-5);
    max-width:420px;
    margin:var(--space-6) auto 0;
  }
  .purchase-box{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:var(--space-4);
    padding:var(--space-5);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-lg);
    background:transparent;
    text-align:left;
    position:relative;
    cursor:pointer;
    transition:border-color var(--dur-surface) ease,
               background var(--dur-surface) ease;
  }
  .purchase-box:has(input:checked){
    border-color:var(--accent-alpha-40);
    background:var(--accent-alpha-12);
  }
  .purchase-box input[type="radio"]{
    appearance:none;
    -webkit-appearance:none;
    flex:0 0 auto;
    width:20px; height:20px;
    margin:0;
    border-radius:var(--radius-full);
    border:2px solid var(--color-accent);
    background:none;
    position:relative;
    cursor:pointer;
  }
  .purchase-box input[type="radio"]::after{
    content:'';
    position:absolute; inset:3px;
    border-radius:var(--radius-full);
    background:var(--color-accent);
    opacity:0;
    transition:opacity var(--dur-micro) ease;
  }
  .purchase-box input[type="radio"]:checked::after{opacity:1;}
  .purchase-box-badge{
    position:absolute;
    top:0;
    left:var(--space-5);
    transform:translateY(-50%);
    background:var(--color-accent);
    color:var(--color-near-black-500);
    font-family:var(--font-display);
    font-weight:700;
    font-size:0.66rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    padding:3px var(--space-3);
    border-radius:var(--radius-full);
  }
  /* Product thumb inside an option row. Reuses .photo-slot, so while it's
     empty it renders the same dashed placeholder frame as every other
     unfilled slot on the page, and once an <img> is dropped in the
     :has(img) rule strips the border automatically — no extra CSS. */
  .purchase-box .purchase-box-thumb{
    --slot-ratio:1/1;
    flex:0 0 auto;
    width:var(--space-12);
    border-radius:var(--radius-md);
  }

  /* These are <span>s inside a <label> — label only accepts phrasing
     content, so they can't be divs and need display:block to stack. */
  .purchase-box-info{flex:1;}
  .purchase-box-name{display:block; font-family:var(--font-display); font-weight:700; font-size:0.95rem; color:var(--color-text);}
  .purchase-box-sub{display:block; font-size:0.8rem; color:var(--text-on-dark-55); margin-top:2px;}
  .purchase-box-price{flex:0 0 auto; text-align:right;}
  .purchase-box-amount{display:block; font-family:var(--font-display); font-weight:700; font-size:1.15rem; color:var(--color-text);}
  .purchase-box-perday{display:block; font-size:0.75rem; color:var(--text-on-dark-50);}

  /* Quiet captions, not boxed callouts — a pill here competed with the buy
     button right above it for attention it doesn't need. The block is
     centred but each line is left-aligned, so the icons form one clean
     column instead of drifting with each line's length. */
  .final-cta .trust-lines{
    list-style:none;
    display:flex;
    flex-direction:column;
    gap:var(--space-3);
    width:max-content;
    max-width:100%;
    margin:var(--space-8) auto 0;
    text-align:left;
  }
  .final-cta .trust-lines li{
    display:flex;
    align-items:flex-start;
    gap:var(--space-2);
    font-size:0.75rem;
    line-height:1.5;
    color:var(--text-on-dark-40);
  }
  /* 18px icon against an 18px line box (0.75rem x 1.5) — they align exactly
     at flex-start, so any nudge here is what knocks the icon off. */
  .final-cta .trust-lines svg{width:18px; height:18px; flex:0 0 auto; stroke:var(--text-on-dark-40);}
  .final-cta .trust-lines strong{color:var(--text-on-dark-60); font-weight:600;}

  /* ---------- Product accordion ----------
     Native <details>/<summary> — no JS required to expand/collapse. */
  .product-accordion{
    max-width:560px;
    margin:var(--space-10) auto 0;
    text-align:left;
    border-top:1px solid var(--border-on-dark-08);
  }
  .product-accordion details{border-bottom:1px solid var(--border-on-dark-08);}
  .product-accordion summary{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:var(--space-4);
    padding:var(--space-5) var(--space-1);
    font-family:var(--font-display);
    font-weight:600;
    font-size:0.95rem;
    color:var(--color-text);
    cursor:pointer;
    list-style:none;
  }
  .product-accordion summary::-webkit-details-marker{display:none;}
  .product-accordion summary::after{
    content:'+';
    flex:0 0 auto;
    font-size:1.2rem;
    color:var(--color-accent);
    transition:transform var(--dur-surface) var(--ease-out-soft);
  }
  /* Rotating the same glyph 45° turns + into × — no character swap needed,
     so it animates smoothly instead of popping between two glyphs. */
  .product-accordion details[open] summary::after{transform:rotate(45deg);}
  .product-accordion .acc-body{
    padding:0 var(--space-1) var(--space-6);
    font-size:0.92rem;
    line-height:1.6;
    color:var(--text-on-dark-60);
  }
  /* The global reset zeroes every margin, so stacked paragraphs inside a
     panel would run together into one block without this. */
  .product-accordion .acc-body p + p{margin-top:var(--space-4);}
  .product-accordion .acc-body ul{margin-top:var(--space-2); padding-left:var(--space-5);}
  .product-accordion .acc-body li{margin-bottom:var(--space-1);}
  /* The cost chart is reused verbatim inside an accordion panel. The two
     rules above are (0,2,1)/(0,2,1) and would out-specify .cost-chart's own
     padding/margin resets, indenting the bars and double-spacing the rows
     on top of the flex gap. These put it back. */
  .product-accordion .acc-body .cost-chart{margin-top:var(--space-6); padding-left:0;}
  .product-accordion .acc-body .cost-chart li{margin-bottom:0;}
  .product-accordion .acc-body strong{color:var(--color-text); font-weight:600;}

  /* ---------- Icon list (accordion) ----------
     Ember-ringed icon badges beside a title and a line of detail. Shared by
     the Directions steps and the Priced For You options — <ol> where order
     matters, <ul> where it doesn't. Scoped past .acc-body's list rules,
     which are (0,2,1) and would otherwise indent it and stack extra margin
     on top of the flex gap. */
  .product-accordion .acc-body .icon-list{
    list-style:none;
    display:flex;
    flex-direction:column;
    gap:var(--space-5);
    margin-top:var(--space-4);
    padding-left:0;
  }
  .product-accordion .acc-body .icon-list li{
    display:grid;
    grid-template-columns:auto 1fr;
    gap:var(--space-4);
    align-items:start;
    margin-bottom:0;
  }
  .icon-list-badge{
    display:grid;
    place-items:center;
    width:var(--space-10); height:var(--space-10);
    border:1px solid var(--accent-alpha-40);
    border-radius:var(--radius-full);
  }
  .icon-list-badge svg{width:var(--space-5); height:var(--space-5); stroke:var(--color-accent);}
  .icon-list-title{
    display:block;
    margin-bottom:var(--space-1);
    font-family:var(--font-display);
    font-weight:700;
    font-size:0.9rem;
    letter-spacing:0.02em;
    color:var(--color-text);
  }
  .directions-note{
    margin-top:var(--space-8);
    padding-top:var(--space-5);
    border-top:1px solid var(--border-on-dark-08);
    font-size:0.85rem;
    line-height:1.7;
    color:var(--text-on-dark-50);
  }

  /* ---------- Static content pages (FAQ / Shipping / Returns) ----------
     Same 560px column .product-accordion already uses, so an FAQ page
     built from that component and a prose page like Shipping sit at
     identical width — one shared "reading column" rather than a second
     magic number. */
  .static-page{
    max-width:560px;
    margin:0 auto;
    padding:var(--space-20) var(--space-container) var(--space-24);
  }
  .static-page > .eyebrow{display:block; text-align:center; margin-bottom:var(--space-4);}
  .static-page > h1{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.8rem, 4vw, 2.6rem);
    line-height:1.15;
    text-align:center;
  }
  .static-page > .static-intro{
    margin-top:var(--space-5);
    font-size:1rem;
    line-height:1.7;
    color:var(--text-on-dark-75);
    text-align:center;
  }
  .static-page h2{
    font-family:var(--font-display);
    font-weight:700;
    font-size:1.15rem;
    color:var(--color-text);
    margin-top:var(--space-14);
    margin-bottom:var(--space-3);
  }
  .static-page p{
    font-size:0.92rem;
    line-height:1.75;
    color:var(--text-on-dark-60);
  }
  .static-page p + p{margin-top:var(--space-4);}
  .static-page ul{margin-top:var(--space-3); padding-left:var(--space-5); font-size:0.92rem; line-height:1.75; color:var(--text-on-dark-60);}
  .static-page li{margin-bottom:var(--space-2);}
  .static-page strong{color:var(--color-text); font-weight:600;}
  /* Same treatment as the other scoped accent spans on the page (.hero
     h1 .accent, .ritual-aside .hot, .promo-title .accent) — ember colour
     for the one key phrase per paragraph worth the emphasis, not the
     whole sentence. */
  .static-page .accent{color:var(--color-accent); font-weight:600;}
  /* :not(.btn) — otherwise this wins over .btn-primary's own
     color:near-black (higher specificity: class+tag beats a single
     class, and this rule also sits later in the file), turning any
     button placed inside .static-page into ember text on an ember
     background. Real bug, not hypothetical: it's exactly what happened
     to .about-cta. */
  .static-page a:not(.btn){color:var(--color-accent);}
  .static-page a:not(.btn):hover{color:var(--color-accent-hover);}
  .static-page .product-accordion{margin-top:var(--space-10);}
  /* .btn is inline-flex (inline-level) by default, so auto margins alone
     wouldn't center it here — flex (block-level) plus a fit-content
     width is what lets margin-inline:auto actually apply. */
  .about-cta{display:flex; width:fit-content; margin:var(--space-8) auto 0; justify-content:center;}

  .supplement-facts-trigger{
    display:inline-flex;
    align-items:center;
    margin-top:var(--space-3);
    font-family:var(--font-display);
    font-size:0.78rem;
    font-weight:600;
    letter-spacing:0.04em;
    text-transform:uppercase;
    color:var(--color-accent);
    background:none;
    border:none;
    border-bottom:1px solid currentColor;
    padding:0 0 2px;
    cursor:pointer;
    transition:color var(--dur-micro) ease;
  }
  .supplement-facts-trigger:hover{color:var(--color-accent-hover);}
  /* The product-page trigger sits right after .product-tagline, which
     already carries its own margin-bottom:space-8 for the gap down to
     the benefits list below. Margins here don't collapse (this is
     inline-flex, not a block box), so the base margin-top:space-3 above
     was stacking on top of that space-8, pushing the button far lower
     than intended. Zero the redundant top gap and move the real spacing
     to margin-bottom instead, so the button sits close under the
     tagline and the benefits list still gets proper breathing room
     below it. */
  .product-tagline:has(+ .supplement-facts-trigger){margin-bottom:var(--space-2);}
  .product-tagline + .supplement-facts-trigger{margin-top:0; margin-bottom:var(--space-6);}

  /* ---------- Supplement Facts dialog ----------
     One continuous on-brand panel — tag, title, headline stat, ingredient
     pills, then the facts table, all on the same charcoal surface. Real
     data (serving size, blend, amounts) comes straight off the physical
     label; the presentation is the site's own card treatment, not a
     photocopy of a printed panel. */
  dialog.nutrition-dialog{
    border:none;
    padding:0;
    border-radius:var(--radius-lg);
    background:transparent;
    max-width:min(420px, 92vw);
    width:100%;
  }
  dialog.nutrition-dialog::backdrop{
    background:color-mix(in srgb, var(--color-near-black-500) 70%, transparent);
    backdrop-filter:blur(4px);
  }

  /* ---------- First-order promo popup ---------- */
  dialog.promo-dialog{
    /* inset:0 + margin:auto explicitly, rather than trusting the browser's
       default modal-centering margin — a gap on only ONE side (not a
       symmetric squeeze) means the box was being anchored to an edge
       rather than centered, not just sized too small. This pairing is the
       standard way to force-center a box with an explicit width smaller
       than its containing block regardless of UA default behavior. width
       is a direct viewport-minus-gutter calc rather than a vw percentage,
       so the gutter is an exact, predictable 16px each side. */
    inset:0;
    margin:auto;
    border:none;
    padding:0;
    border-radius:var(--radius-2xl);
    background:transparent;
    width:calc(100vw - var(--space-8));
    max-width:760px;
    max-height:94vh;
  }
  dialog.promo-dialog::backdrop{
    background:color-mix(in srgb, var(--color-near-black-500) 70%, transparent);
    backdrop-filter:blur(4px);
  }
  .promo-card{
    position:relative;
    overflow:hidden;
    display:flex;
    flex-direction:column;
    /* space-between, not center. Centering a shorter-than-container block
       always leaves equal empty space above AND below no matter how
       generous the internal gaps get — that's structural, not a spacing
       problem. This distributes the actual content (logo down through the
       decline link) across the full height instead, so it reads as filling
       the card top to bottom rather than floating in the middle of it. */
    justify-content:space-between;
    /* Deliberately tall, not just content-sized — reaches toward the edges
       of the screen rather than shrink-wrapping the text. Pure vh, no px
       fallback: a min(620px, 82vh) here was the bug — on any phone with a
       logical viewport over ~756px tall (most of them), 82vh EXCEEDS
       620px, so min() was locking to the flat 620px and leaving a visible
       gap under the card instead of scaling with the screen. The parent
       dialog's own max-height:94vh is the real ceiling; this just needs to
       get close to it. */
    min-height:88vh;
    padding:var(--space-12) var(--space-10);
    border-radius:var(--radius-2xl);
    border:1px solid var(--accent-alpha-40);
    background:var(--color-bg-elevated);
    text-align:center;
  }
  /* Ambient bokeh — soft ember orbs drifting behind the card content.
     overflow:hidden on .promo-card clips them to the border radius; z-index
     on the real content lifts it above the orb layer without needing a
     wrapper around everything else. */
  .promo-bokeh{
    position:absolute;
    inset:0;
    z-index:0;
    overflow:hidden;
    pointer-events:none;
  }
  .promo-card > :not(.promo-bokeh){position:relative; z-index:1;}
  .bokeh-orb{
    position:absolute;
    border-radius:var(--radius-full);
    filter:blur(28px);
    opacity:0.55;
    animation-timing-function:ease-in-out;
    animation-iteration-count:infinite;
  }
  .bokeh-1{
    width:180px; height:180px;
    left:-40px; top:-50px;
    background:radial-gradient(circle, var(--accent-alpha-70), transparent 70%);
    animation-name:bokeh-drift-1;
    animation-duration:9s;
  }
  .bokeh-2{
    width:190px; height:190px;
    right:-5%; bottom:-60px;
    background:radial-gradient(circle, var(--accent-alpha-50), transparent 70%);
    animation-name:bokeh-drift-2;
    animation-duration:11s;
    animation-delay:-3s;
  }
  .bokeh-3{
    width:120px; height:120px;
    left:45%; top:35%;
    background:radial-gradient(circle, var(--accent-alpha-40), transparent 70%);
    animation-name:bokeh-drift-3;
    animation-duration:13s;
    animation-delay:-6s;
  }
  .bokeh-4{
    width:150px; height:150px;
    right:-3%; top:-30px;
    background:radial-gradient(circle, var(--accent-alpha-60), transparent 70%);
    animation-name:bokeh-drift-2;
    animation-duration:10s;
    animation-delay:-1.5s;
  }
  .bokeh-5{
    width:220px; height:220px;
    left:-60px; bottom:-90px;
    background:radial-gradient(circle, var(--accent-alpha-22), transparent 70%);
    animation-name:bokeh-drift-1;
    animation-duration:15s;
    animation-delay:-7s;
  }
  /* Right-center — the wider card left this whole stretch bare with only
     corner orbs. right/top expressed as % rather than px so it stays
     proportionally in place as the card's max-width scales with viewport. */
  .bokeh-6{
    width:200px; height:200px;
    right:-4%; top:40%;
    background:radial-gradient(circle, var(--accent-alpha-50), transparent 70%);
    animation-name:bokeh-drift-3;
    animation-duration:12s;
    animation-delay:-4s;
  }
  @keyframes bokeh-drift-1{
    0%, 100%  {transform:translate(0, 0) scale(1);}
    50%       {transform:translate(24px, 18px) scale(1.15);}
  }
  @keyframes bokeh-drift-2{
    0%, 100%  {transform:translate(0, 0) scale(1);}
    50%       {transform:translate(-20px, -22px) scale(1.1);}
  }
  @keyframes bokeh-drift-3{
    0%, 100%  {transform:translate(0, 0) scale(1);}
    50%       {transform:translate(16px, -14px) scale(1.2);}
  }
  /* .promo-message, .promo-offer, .promo-actions are the three direct flex
     children .promo-card's space-between distributes across the full card
     height. Grouping eyebrow+title+body (and code+extra, and the logo)
     together — rather than leaving every line as its own flex item —
     matters: plain space-between on individual siblings would space the
     logo, the eyebrow, and the headline apart exactly as far as every
     other gap, which breaks the tight lockup those three want and the
     kicker-hugs-its-heading pattern used everywhere else on the page.
     Margins inside each group stay small/tight on purpose; the big gaps
     come from space-between itself, not from these. The logo lives INSIDE
     .promo-message specifically (not as its own sibling) so its gap to the
     eyebrow is this small fixed margin, not a share of that macro gap. */
  .promo-logo{
    display:block;
    width:min(320px, 68%);
    height:auto;
    margin:0 auto var(--space-3);
  }
  .promo-card .eyebrow{display:block; text-align:center; margin-bottom:var(--space-4);}
  .promo-close{
    position:absolute;
    top:var(--space-1); right:var(--space-1);
    width:28px; height:28px;
    display:flex; align-items:center; justify-content:center;
    background:none; border:none;
    font-size:1.3rem; line-height:1;
    color:var(--text-on-dark-60);
    cursor:pointer;
  }
  .promo-title{
    font-family:var(--font-display);
    font-weight:700;
    font-size:clamp(1.7rem, 5.5vw, 2.3rem);
    line-height:1.2;
    color:var(--color-text);
  }
  .promo-title .accent{color:var(--color-accent);}
  .promo-body{
    margin-top:var(--space-5);
    max-width:38ch;
    margin-inline:auto;
    font-size:1rem;
    line-height:1.6;
    color:var(--text-on-dark-70);
  }
  /* Dashed border echoes the site's own placeholder-slot styling, so the
     code reads as "fill this in at checkout" rather than a random pill. */
  .promo-code{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:var(--space-3);
    max-width:420px;
    margin:0 auto;
    padding:var(--space-4) var(--space-6);
    border:1px dashed var(--border-on-dark-25);
    border-radius:var(--radius-lg);
  }
  .promo-code-label{
    font-family:var(--font-display);
    font-size:0.68rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    color:var(--text-on-dark-50);
  }
  .promo-code-value{
    font-family:var(--font-display);
    font-weight:700;
    font-size:1rem;
    letter-spacing:0.04em;
    color:var(--color-accent);
  }
  .promo-extra{
    margin-top:var(--space-3);
    font-size:0.8rem;
    color:var(--text-on-dark-60);
  }
  /* Both capped to match .promo-code's 420px column — on the card's full
     760px width, a truly full-width button/link stretched edge to edge
     rather than reading as a deliberate column. */
  .promo-cta{max-width:420px; width:100%; margin-inline:auto; justify-content:center;}
  .promo-decline{
    display:block;
    max-width:420px;
    width:100%;
    margin:var(--space-6) auto 0;
    padding:var(--space-2);
    background:none;
    border:none;
    font-family:var(--font-body);
    font-size:0.82rem;
    color:var(--text-on-dark-50);
    cursor:pointer;
    text-decoration:underline;
    text-underline-offset:3px;
  }
  .promo-decline:hover{color:var(--text-on-dark-70);}

  /* ---------- Cart drawer ----------
     Right-anchored, full-height panel that opens the instant "Add to
     Cart" is clicked, pre-filled with the selected plan. A native
     <dialog> gets us focus trap / ESC / top-layer for free, same as the
     other two dialogs — the only new thing here is the slide transform.
     The UA stylesheet gives an open dialog `position:fixed; inset:0;
     margin:auto`, which is what centers the other two; overriding inset
     to `0 0 0 auto` (top/right/bottom pinned, left auto) anchors it to
     the right edge full-height instead, same trick as the promo dialog's
     centering override just aimed at an edge instead of the middle. */
  dialog.cart-drawer{
    inset:0 0 0 auto;
    margin:0;
    border:none;
    padding:0;
    width:min(420px, 100vw);
    height:100%;
    max-height:100vh;
    background:transparent;
    /* Starts off-screen right; JS adds .is-open one frame after showModal()
       so the transition has a starting value to animate from — a dialog
       has no equivalent to @starting-style support old enough to rely on
       here, so this is the same double-rAF pattern used for other
       JS-driven reveals on the page. */
    transform:translateX(100%);
    transition:transform var(--dur-surface) var(--ease-out-soft);
  }
  dialog.cart-drawer.is-open{transform:translateX(0);}
  dialog.cart-drawer::backdrop{
    background:color-mix(in srgb, var(--color-near-black-500) 70%, transparent);
    backdrop-filter:blur(4px);
    opacity:0;
    transition:opacity var(--dur-surface) ease;
  }
  dialog.cart-drawer.is-open::backdrop{opacity:1;}
  .cart-drawer-card{
    display:flex;
    flex-direction:column;
    height:100%;
    background:var(--color-bg-elevated);
    border-left:1px solid var(--border-on-dark-08);
  }
  .cart-drawer-header{
    display:flex;
    align-items:center;
    justify-content:space-between;
    padding:var(--space-5) var(--space-6);
    border-bottom:1px solid var(--border-on-dark-08);
  }
  .cart-drawer-header h3{
    font-family:var(--font-display);
    font-weight:700;
    font-size:1.1rem;
    color:var(--color-text);
  }
  .cart-drawer-close{
    width:28px; height:28px;
    display:flex; align-items:center; justify-content:center;
    background:none; border:none;
    font-size:1.3rem; line-height:1;
    color:var(--text-on-dark-60);
    cursor:pointer;
  }
  .cart-drawer-close:hover{color:var(--color-text);}
  .cart-drawer-body{
    flex:1;
    overflow-y:auto;
    padding:var(--space-5) var(--space-6);
  }
  /* Name/sub/price layout matches .purchase-box-name/-sub/-amount exactly
     — this is the same line item the customer just picked, just rendered
     in the drawer instead of the purchase card. */
  .cart-line{display:flex; align-items:flex-start; gap:var(--space-4);}
  /* Same treatment as .purchase-box-thumb — the one other small square
     product thumbnail on the page — so the two read as the same object. */
  .cart-line-thumb{--slot-ratio:1/1; flex:0 0 auto; width:var(--space-14); border-radius:var(--radius-md);}
  .cart-line-info{flex:1; display:flex; flex-direction:column;}
  .cart-line-product{font-size:0.72rem; letter-spacing:0.02em; color:var(--text-on-dark-50);}
  .cart-line-name{font-family:var(--font-display); font-weight:700; font-size:0.95rem; color:var(--color-text); margin-top:2px;}
  .cart-line-sub{font-size:0.8rem; color:var(--text-on-dark-55); margin-top:2px;}
  /* Savings math for the two discounted plans (Subscribe & Save's 20%,
     the 3-Pack's flat vs.-three-singles amount). Hidden entirely for the
     One Bottle plan, which has nothing to discount against. */
  .cart-line-savings{display:block; margin-top:var(--space-1_5); font-size:0.75rem; font-weight:600; color:var(--color-accent);}
  .cart-line-savings[hidden]{display:none;}
  .cart-line-price{
    flex:0 0 auto;
    display:flex;
    flex-direction:column;
    align-items:flex-end;
    font-family:var(--font-display);
    font-weight:700;
    font-size:1.05rem;
    color:var(--color-text);
  }
  .cart-line-price-strike{
    font-family:var(--font-body);
    font-weight:400;
    font-size:0.78rem;
    color:var(--text-on-dark-40);
    text-decoration:line-through;
  }
  .cart-drawer-footer{
    padding:var(--space-5) var(--space-6) var(--space-6);
    border-top:1px solid var(--border-on-dark-08);
  }
  .cart-drawer-discount{
    display:flex;
    justify-content:space-between;
    font-size:0.85rem;
    font-weight:600;
    color:var(--color-accent);
    margin-bottom:var(--space-2);
  }
  .cart-drawer-discount[hidden]{display:none;}
  .cart-drawer-subtotal{
    display:flex;
    justify-content:space-between;
    font-family:var(--font-display);
    font-weight:700;
    font-size:1rem;
    color:var(--color-text);
    margin-bottom:var(--space-4);
  }
  .cart-drawer-checkout{display:flex; width:100%; justify-content:center;}
  .cart-drawer-continue{
    display:block;
    width:100%;
    margin-top:var(--space-3);
    padding:var(--space-2);
    background:none;
    border:none;
    font-family:var(--font-body);
    font-size:0.82rem;
    color:var(--text-on-dark-50);
    cursor:pointer;
    text-decoration:underline;
    text-underline-offset:3px;
  }
  .cart-drawer-continue:hover{color:var(--text-on-dark-70);}
  .cart-drawer-trust{
    list-style:none;
    margin-top:var(--space-5);
    display:flex;
    flex-direction:column;
    gap:var(--space-2);
    font-size:0.75rem;
    color:var(--text-on-dark-50);
  }

  /* ---------- Support chat widget ----------
     Floating launcher + a non-modal panel. Plain positioned elements, not
     a <dialog> — this should stay open alongside normal page scrolling
     and interaction, unlike the site's three modal dialogs, so none of
     that top-layer/backdrop/focus-trap machinery applies here. z-index
     is set above the sticky header's (101) so it can never end up
     underneath it on a short viewport. */
  .chat-widget{
    position:fixed;
    right:var(--space-container);
    bottom:var(--space-container);
    z-index:200;
  }
  .chat-launcher{
    width:56px; height:56px;
    display:flex; align-items:center; justify-content:center;
    border-radius:var(--radius-full);
    border:none;
    background:var(--color-accent);
    color:var(--color-near-black-500);
    cursor:pointer;
    box-shadow:0 4px 16px var(--overlay-vignette);
    transition:background var(--dur-btn) ease;
  }
  .chat-launcher:hover{background:var(--color-accent-hover);}
  .chat-launcher svg{width:24px; height:24px;}
  .chat-launcher-icon-close{display:none;}
  .chat-widget.is-open .chat-launcher-icon-open{display:none;}
  .chat-widget.is-open .chat-launcher-icon-close{display:block;}

  /* Anchored above the launcher, not centered on the viewport — a plain
     display:none/flex toggle (no [hidden] attribute involved) sidesteps
     the earlier [hidden]-vs-authored-display bug documented on the cart
     drawer discount row: nothing here ever sets `display` outside this
     one is-open toggle, so there's no authored rule left to conflict
     with a UA default. Height uses dvh, not vh, so a mobile on-screen
     keyboard resizing the visual viewport doesn't leave the input row
     pinned off-screen the way a fixed vh figure would. */
  .chat-panel{
    display:none;
    flex-direction:column;
    position:fixed;
    right:var(--space-container);
    bottom:calc(56px + var(--space-container) + var(--space-3));
    width:min(380px, calc(100vw - 2 * var(--space-container)));
    height:min(560px, calc(100dvh - 56px - 3 * var(--space-container)));
    background:var(--color-bg-elevated);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-2xl);
    overflow:hidden;
    box-shadow:0 12px 40px var(--overlay-vignette);
  }
  .chat-panel.is-open{display:flex;}
  .chat-panel-header{
    display:flex;
    align-items:center;
    gap:var(--space-3);
    padding:var(--space-4) var(--space-5);
    border-bottom:1px solid var(--border-on-dark-08);
    background:linear-gradient(180deg, var(--color-charcoal-500), var(--color-charcoal-600));
  }
  .chat-panel-logo{width:40px; height:40px; object-fit:contain; flex:0 0 auto;}
  .chat-panel-heading{display:flex; flex-direction:column; flex:1; min-width:0;}
  .chat-panel-name{font-family:var(--font-display); font-weight:700; font-size:0.9rem; color:var(--color-text);}
  .chat-panel-status{display:flex; align-items:center; gap:var(--space-1_5); font-size:0.7rem; color:var(--text-on-dark-50);}
  /* Ember, not green — the palette is deliberately one accent colour
     throughout (see README "Current theme"); a status dot is not worth
     breaking that for. */
  .chat-status-dot{width:6px; height:6px; border-radius:var(--radius-full); background:var(--color-accent);}
  .chat-panel-close{
    width:28px; height:28px;
    display:flex; align-items:center; justify-content:center;
    background:none; border:none;
    font-size:1.3rem; line-height:1;
    color:var(--text-on-dark-60);
    cursor:pointer;
  }
  .chat-panel-close:hover{color:var(--color-text);}
  .chat-messages{
    flex:1;
    overflow-y:auto;
    padding:var(--space-4) var(--space-5);
    display:flex;
    flex-direction:column;
    gap:var(--space-4);
  }
  .chat-bubble{display:flex; gap:var(--space-2); max-width:88%;}
  .chat-bubble-avatar{width:22px; height:22px; object-fit:contain; flex:0 0 auto; margin-top:2px;}
  .chat-bubble p{
    padding:var(--space-3) var(--space-4);
    border-radius:var(--radius-xl);
    font-size:0.85rem;
    line-height:1.55;
  }
  .chat-bubble-bot p{background:var(--border-on-dark-08); color:var(--text-on-dark-85);}
  .chat-bubble-user{align-self:flex-end; flex-direction:row-reverse;}
  .chat-bubble-user p{background:var(--color-accent); color:var(--color-near-black-500);}
  /* The support email in bot replies (agent handoff, guarantee, fallback)
     is a real mailto link, not just text — built via safe DOM node
     insertion in JS, not innerHTML, since only fixed bot copy goes
     through that path, never what a visitor typed. */
  .chat-bubble-bot p a{color:var(--color-accent); text-decoration:underline; text-underline-offset:2px;}
  .chat-bubble-bot p a:hover{color:var(--color-accent-hover);}

  /* Preset quick-reply chips — tappable shortcuts into the same
     keyword-matched reply logic as typing, pinned above the input so
     they're always available, not just on first open. */
  .chat-quick-replies{
    display:flex;
    flex-wrap:wrap;
    gap:var(--space-2);
    padding:0 var(--space-5) var(--space-3);
  }
  .chat-quick-btn{
    padding:var(--space-1_5) var(--space-3);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-full);
    background:none;
    font-family:var(--font-body);
    font-size:0.76rem;
    color:var(--text-on-dark-70);
    cursor:pointer;
    transition:border-color var(--dur-micro) ease, color var(--dur-micro) ease;
  }
  .chat-quick-btn:hover{border-color:var(--accent-alpha-40); color:var(--color-accent);}
  .chat-input-row{
    display:flex;
    align-items:center;
    gap:var(--space-2);
    padding:var(--space-3) var(--space-4);
    border-top:1px solid var(--border-on-dark-08);
  }
  .chat-input{
    flex:1;
    background:none;
    border:none;
    font-family:var(--font-body);
    font-size:0.88rem;
    color:var(--color-text);
    padding:var(--space-2) 0;
  }
  .chat-input::placeholder{color:var(--text-on-dark-40);}
  .chat-send{
    width:36px; height:36px;
    display:flex; align-items:center; justify-content:center;
    border-radius:var(--radius-full);
    border:none;
    background:var(--color-accent);
    color:var(--color-near-black-500);
    cursor:pointer;
    flex:0 0 auto;
    transition:background var(--dur-btn) ease;
  }
  .chat-send:hover{background:var(--color-accent-hover);}
  .chat-send svg{width:16px; height:16px;}
  /* Below ~440px wide, a fixed 380px-minus-gutter panel plus the 56px
     launcher can crowd the corner — drop the right gutter to the same
     inline padding the rest of the page uses at that width instead of
     the larger --space-container value. */
  @media(max-width:440px){
    .chat-widget{right:var(--space-4); bottom:var(--space-4);}
    .chat-panel{right:var(--space-4);}
  }

  .nutrition-label{
    background:linear-gradient(160deg, var(--color-charcoal-600), var(--color-charcoal-500));
    color:var(--color-text);
    font-family:var(--font-body);
    padding:var(--space-6) var(--space-5) var(--space-5);
    border:1px solid var(--border-on-dark-08);
    border-radius:var(--radius-lg);
    position:relative;
  }
  .nutrition-label-close{
    position:absolute;
    top:var(--space-3); right:var(--space-3);
    width:28px; height:28px;
    display:flex; align-items:center; justify-content:center;
    background:none; border:none;
    font-size:1.3rem; line-height:1;
    color:var(--text-on-dark-60);
    cursor:pointer;
  }
  .nutrition-label-close:hover{color:var(--color-text);}

  .nutrition-label .nl-tag{
    display:block;
    font-family:var(--font-display);
    font-weight:700;
    font-size:0.72rem;
    letter-spacing:0.12em;
    text-transform:uppercase;
    color:var(--color-accent);
    margin-bottom:var(--space-2);
  }
  .nutrition-label .nl-brand{
    font-family:var(--font-display);
    font-weight:800;
    font-size:2rem;
    color:var(--color-text);
    margin-bottom:var(--space-4);
  }
  .nutrition-label .nl-serving{
    font-size:0.85rem;
    line-height:1.7;
    color:var(--text-on-dark-85);
    padding-bottom:var(--space-4);
    border-bottom:1px solid var(--border-on-dark-08);
  }
  .nutrition-label .nl-serving strong{color:var(--color-text);}

  /* The equivalent of "9g of Net Carbs" — one honest, on-brand stat rather
     than a fabricated nutrition breakdown that doesn't apply to a tincture. */
  .nutrition-label .nl-callout{
    display:flex;
    align-items:baseline;
    gap:var(--space-2);
    margin-top:var(--space-4);
  }
  .nutrition-label .nl-callout-num{
    font-family:var(--font-display);
    font-weight:800;
    font-size:2rem;
    color:var(--color-accent);
  }
  .nutrition-label .nl-callout-label{
    font-family:var(--font-display);
    font-size:0.85rem;
    color:var(--text-on-dark-70);
  }

  .nutrition-label .nl-pill-row{
    display:flex;
    flex-wrap:wrap;
    gap:var(--space-2);
    margin-top:var(--space-4);
  }
  .nutrition-label .nl-pill{
    font-family:var(--font-display);
    font-size:0.7rem;
    font-weight:600;
    letter-spacing:0.02em;
    color:var(--color-text);
    background:var(--accent-alpha-12);
    border:1px solid var(--accent-alpha-40);
    border-radius:var(--radius-full);
    padding:var(--space-1_5) var(--space-3);
  }

  .nutrition-label .nl-divider{
    height:1px;
    background:var(--border-on-dark-08);
    margin:var(--space-5) 0;
  }
  .nutrition-label .nl-facts-title{
    font-family:var(--font-display);
    font-weight:700;
    font-size:1.1rem;
    color:var(--color-text);
    margin-bottom:var(--space-3);
  }
  .nutrition-label .nl-amount-head{
    display:flex; justify-content:space-between; align-items:baseline;
    font-size:0.75rem; font-weight:700;
    color:var(--text-on-dark-55);
    padding-bottom:var(--space-2);
    border-bottom:1px solid var(--border-on-dark-08);
  }
  .nutrition-label .nl-row{
    display:flex; justify-content:space-between; align-items:baseline;
    padding:var(--space-3) 0;
    border-bottom:1px solid var(--border-on-dark-08);
    font-weight:700;
    font-size:0.9rem;
    color:var(--color-text);
  }
  .nutrition-label .nl-blend-list{
    font-size:0.78rem;
    font-weight:400;
    color:var(--text-on-dark-60);
    padding:var(--space-3) 0;
    border-bottom:1px solid var(--border-on-dark-08);
    line-height:1.6;
  }
  .nutrition-label .nl-footnote{
    font-size:0.72rem;
    color:var(--text-on-dark-50);
    margin-top:var(--space-3);
    line-height:1.5;
  }
  .nutrition-label .nl-other{
    font-size:0.78rem;
    color:var(--text-on-dark-85);
    margin-top:var(--space-2);
    font-weight:600;
  }

  /* ---------- Footer ---------- */
  footer{
    background:linear-gradient(180deg, var(--color-near-black-500), var(--color-bg-plinth) 100%);
    padding:var(--space-14) var(--space-container) var(--space-8);
    border-top:1px solid var(--border-on-dark-08);
  }
  .footer-grid{
    display:grid;
    grid-template-columns:1fr;
    gap:var(--space-8);
    max-width:1300px;
    margin:0 auto var(--space-12);
    text-align:center;
  }
  .footer-grid p{margin:0 auto;}
  .footer-grid h5{
    font-family:var(--font-display);
    font-size:0.72rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    color:var(--text-on-dark-50);
    margin-bottom:var(--space-4);
  }
  .footer-grid ul{list-style:none; display:flex; flex-direction:column; gap:var(--space-2_5);}
  .footer-grid a{font-size:0.88rem; color:var(--text-on-dark-75); transition:color var(--dur-micro) ease;}
  .footer-grid a:hover{color:var(--color-accent);}
  .footer-bottom a{transition:color var(--dur-micro) ease;}
  .footer-bottom a:hover{color:var(--color-accent);}
  .footer-bottom{
    max-width:1300px; margin:0 auto;
    display:flex; justify-content:space-between;
    flex-direction:column; align-items:center;
    text-align:center;
    padding-top:var(--space-8); border-top:1px solid var(--border-on-dark-08);
    font-size:0.75rem; line-height:1.6; color:var(--text-on-dark-40);
    flex-wrap:wrap; gap:var(--space-3);
  }
  .social-links{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:var(--space-5);
    width:100%;
  }
  .social-icon{color:var(--text-on-dark-75); display:flex; transition:color var(--dur-micro) ease;}
  .social-icon:hover{color:var(--color-accent);}
  .social-icon svg{width:18px; height:18px;}
  .footer-legal-links{
    display:flex;
    justify-content:center;
    gap:var(--space-2);
    margin-top:var(--space-6);
    font-size:0.75rem;
    color:var(--text-on-dark-40);
  }
  .footer-legal-links a{color:inherit; transition:color var(--dur-micro) ease;}
  .footer-legal-links a:hover{color:var(--color-accent);}
  .legal-note{
    max-width:1300px; margin:var(--space-4) auto 0;
    font-size:0.7rem; color:var(--text-on-dark-30); line-height:1.6;
  }

  @media(min-width:561px){
    .footer-grid{grid-template-columns:1fr 1fr; gap:var(--space-8) var(--space-6); text-align:left;}
    .footer-grid p{margin:0;}
    .brand-mark--footer{margin:0 0 var(--space-1);}
    .footer-bottom{flex-direction:row; align-items:center;}
    .social-links{width:auto; justify-content:flex-start;}
  }
  @media(min-width:821px){
    .footer-grid{grid-template-columns:1.4fr 1fr 1fr 1.2fr; gap:var(--space-10);}
  }

  /* ---------- Scroll reveal ----------
     The hidden state is gated behind .js-motion on <html>, which only the
     inline head script can add. No JS (or a thrown error, or a 404 on
     main.js) means the class is never set / gets removed, and every element
     renders normally. Content is never left hidden by a script failure.

     These use `animation`, not `transition`, on purpose: the stagger rule
     `.js-motion [data-reveal-stagger] > *` has specificity (0,2,0) and a
     `transition` shorthand there would out-specify `.habit-card` (0,1,0),
     silently wiping its hover transition. Animations can't collide that way. */
  .js-motion [data-reveal],
  .js-motion [data-reveal-stagger] > *{opacity:0;}

  .js-motion [data-reveal].is-visible{
    animation:reveal-rise var(--dur-reveal) var(--ease-out-soft) both;
  }
  .js-motion [data-reveal-stagger].is-visible > *{
    animation:reveal-rise var(--dur-reveal) var(--ease-out-soft)
              calc(var(--i,0) * var(--reveal-step)) both;
  }
  /* Fade-only. Used where children share hairline borders or a 1px-gap
     divider background (.stat-bar, .habit-row) — translating those tears
     the grid lines mid-animation — and on .carousel-wrap, which is masked
     and hosts the marquee, so it must not take a transform of its own. */
  .js-motion [data-reveal="fade"].is-visible,
  .js-motion [data-reveal-stagger="fade"].is-visible > *{
    animation-name:reveal-fade;
  }
  @keyframes reveal-rise{
    from{opacity:0; transform:translateY(var(--reveal-shift));}
    to{opacity:1; transform:none;}
  }
  @keyframes reveal-fade{
    from{opacity:0;}
    to{opacity:1;}
  }

  /* ---------- Cart badge (presentational) ---------- */
  .cart-count.is-bumped{animation:cart-bump .34s var(--ease-out-soft);}
  @keyframes cart-bump{
    0%{transform:scale(1);}
    40%{transform:scale(1.28);}
    100%{transform:scale(1);}
  }

  /* ---------- Reduced motion ----------
     One block for the whole page. Previously this covered only the review
     fader, leaving the 34s photo marquee — the most motion-heavy element
     here — plus smooth scrolling and the hover transforms running at full
     motion for someone who explicitly asked the OS to cut it. */
  @media(prefers-reduced-motion:reduce){
    html{scroll-behavior:auto;}

    /* The photo marquee. */
    .carousel-track{animation:none;}
    .announce-track{animation:none;}
    .trust-ticker-track{animation:none;}
    .bokeh-orb{animation:none;}

    /* Flip cards settle on the product side and the heading holds its
       original line — the UGC and the golf/third state stay reachable via
       the review carousel. */
    .flip-inner{animation:none;}
        .heading-a{animation:none; opacity:1;}
    .heading-b{animation:none; opacity:0;}

    /* Reveals: show everything immediately, no rise, no stagger. */
    .js-motion [data-reveal],
    .js-motion [data-reveal-stagger] > *{opacity:1; animation:none;}

    /* Movement-based feedback drops out; colour feedback stays. */
    .btn:hover, .btn:active, .habit-card:hover svg{transform:none;}
    .cart-count.is-bumped{animation:none;}
    .cart-drawer{transition:none;}
    .cart-drawer::backdrop{transition:none;}
  }
