/** Shopify CDN: Minification failed

Line 1909:15 Expected identifier but found whitespace
Line 1909:17 Unexpected "{"
Line 1909:26 Expected ":"
Line 1909:51 Expected ":"

**/
/* SHOPIFY_STYLESHEETS_VERSION: 1.0 */


/* CSS from section stylesheet tags */
/* START_SECTION:blend-focus (INDEX:2) */
/* Half the viewport, matching the statement above it — the two read as a pair
     of equal beats rather than one section outweighing the other. min-height,
     not height: the ingredient list expands in place when it's revealed, and
     that has to be free to push the section taller. */
  .blend-focus {
    display: flex;
    align-items: center;
    min-height: 50vh;
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-2xl), 6vh, var(--space-4xl)) 0;
  }

  /* The flex parent above would otherwise shrink-to-fit the content column. */
  .blend-focus > * {
    width: 100%;
  }

  /* Doubled selector so the max-width survives the theme-wide
     `.page-width { max-width: none }` full-bleed rule. */
  /* Widened for the curve's sake, which needs length to make its comparison.
     Safe for the copy because every text element inside carries its own cap —
     the claim at 42rem, the list at 52rem — so this only ever governs the
     diagram. */
  .blend-focus .blend-focus__inner {
    max-width: 96rem;
    margin-inline: auto;
    text-align: center;
  }

  .blend-focus__eyebrow {
    margin: 0 0 var(--space-m);
    font-size: var(--text-caption);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-focus__feature + .blend-focus__feature {
    margin-top: var(--space-xl);
    padding-top: var(--space-xl);
    border-top: 0.1rem solid var(--hairline);
  }

  .blend-focus__feature-name {
    margin: 0 0 var(--space-s);
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
  }

  /* Sized by the setting rather than by the file's own dimensions, so swapping
     in a differently-exported logo doesn't resize the section. */
  .blend-focus__feature-name--logo {
    margin-bottom: var(--space-m);
  }

  .blend-focus__logo {
    display: block;
    margin: 0 auto;
    width: var(--logo-width, 32rem);
    max-width: 100%;
    height: auto;
  }

  /* currentColor, so the mark follows whatever the section's scheme resolves
     its foreground to — white on the dark schemes, ink on the light ones — with
     nothing to keep in sync by hand. */
  .blend-focus__logo--mask {
    aspect-ratio: var(--logo-ratio, 4);
    height: auto;
    background-color: currentColor;
    -webkit-mask-image: var(--logo-src);
    mask-image: var(--logo-src);
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
  }

  /* `pretty` rather than `balance`: at four lines balance evens every line and
     loses the shape, where pretty only prevents the last one stranding a word
     on its own — which is the actual fault here. Ignored by browsers that
     don't support it, and the paragraph is merely less tidy, not broken. */
  .blend-focus__feature-claim {
    margin: 0 auto;
    max-width: 42rem;
    text-wrap: pretty;
    font-size: var(--text-lead);
    line-height: 1.45;
    color: rgba(var(--color-foreground), var(--ink));
  }

  /* ---- The curve ---------------------------------------------------------
     Wider than the copy above it. The copy is a measure, capped for reading;
     the curve is a diagram, and its argument is the difference between two
     shapes, which needs length to be legible. */
  .blend-focus__curve {
    margin: var(--space-2xl) auto 0;
    max-width: 88rem;
    width: 100%;
  }

  .blend-focus__curve-svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
  }

  /* Quiet enough to stay furniture — they frame the drawing, they aren't part
     of it. The y label sits above the curve rather than rotated beside it:
     rotated text costs a column of width the chart needs, and reads worse at
     caption size than it does in a dense report. */
  .blend-focus__axis-label {
    margin: 0;
    font-size: var(--text-caption);
    letter-spacing: 0.06em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-focus__axis-label--y {
    margin-bottom: var(--space-xs);
    text-align: left;
  }

  .blend-focus__axis-label--x {
    margin-top: var(--space-xs);
    text-align: right;
  }

  .blend-focus__axis {
    stroke: rgba(var(--color-foreground), 0.18);
    stroke-width: 1;
  }

  /* Round caps and joins so the curves read as drawn strokes rather than
     charted output — this is an illustration, and it should look like one. */
  .blend-focus__line {
    fill: none;
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  /* The three singles share one muted tone and separate by pattern. Tone would
     have had to split four ways otherwise, and the quietest of them would have
     dropped below what's legible on a mid-grey background. */
  .blend-focus__line--spike,
  .blend-focus__line--plateau,
  .blend-focus__line--build {
    stroke: rgba(var(--color-foreground), 0.42);
  }

  .blend-focus__line--spike {
    stroke-dasharray: 5 6;
  }

  .blend-focus__line--plateau {
    stroke-dasharray: 1 7;
  }

  .blend-focus__line--build {
    stroke-dasharray: 14 6 2 6;
  }

  /* The only solid line, and the only one at full strength — the eye should
     find it without being told which one it is. */
  .blend-focus__line--blend {
    stroke: rgb(var(--color-foreground));
    stroke-width: 3.5;
  }

  .blend-focus__curve-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs) var(--space-m);
    margin: var(--space-s) 0 0;
    font-size: var(--text-caption);
  }

  /* The swatch repeats the line's own treatment — dashed for the one that
     spikes, solid for the one that holds — so the key is read off the drawing
     rather than off a colour. */
  .blend-focus__key {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    color: rgba(var(--color-foreground), var(--ink));
  }

  .blend-focus__key::before {
    content: "";
    width: 2.4rem;
    height: 0;
    border-top-width: 0.25rem;
    border-top-style: solid;
  }

  .blend-focus__key--spike::before,
  .blend-focus__key--plateau::before,
  .blend-focus__key--build::before {
    border-top-color: rgba(var(--color-foreground), 0.42);
  }

  .blend-focus__key--spike::before {
    border-top-style: dashed;
  }

  .blend-focus__key--plateau::before {
    border-top-style: dotted;
  }

  /* No CSS border style matches the dash-dot the line uses, so the swatch is
     drawn as a gradient instead — the pattern is what identifies the line, so
     it has to be the pattern and not an approximation of it. */
  .blend-focus__key--build::before {
    border-top-color: transparent;
    height: 0.25rem;
    border-top-width: 0;
    background-image: repeating-linear-gradient(
      to right,
      rgba(var(--color-foreground), 0.42) 0 0.7rem,
      transparent 0.7rem 1rem,
      rgba(var(--color-foreground), 0.42) 1rem 1.1rem,
      transparent 1.1rem 1.4rem
    );
  }

  .blend-focus__key--blend {
    font-weight: 700;
  }

  .blend-focus__key--blend::before {
    border-top-color: rgb(var(--color-foreground));
    border-top-width: 0.35rem;
  }

  .blend-focus__curve-note {
    flex-basis: 100%;
    text-align: center;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-statement] .blend-focus__inner > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-statement].is-visible .blend-focus__inner > * {
      opacity: 1;
      transform: none;
    }

    /* The curve draws itself in left to right, which is the direction it's
       read — the lines separate as they go, so the wipe lands the comparison
       in the order the argument is made.

       A clip wipe rather than a dash-offset draw: the spiking line is already
       dashed, and animating stroke-dashoffset on top of a dash pattern
       animates the pattern instead of revealing the path. Clipping the whole
       drawing also keeps both lines on one timeline. */
    [data-statement] .blend-focus__curve-svg {
      clip-path: inset(0 100% 0 0);
      /* Longer than --motion-slow, which is the page's token for an element
         arriving — a fade or a short rise, where 0.8s is already generous.
         This is a line being drawn across 880px, and the same duration reads as
         a flick: the eye is meant to follow the two shapes diverging, and it
         can't if they're both finished before it starts tracking. Off-scale on
         purpose, and the only value in the theme that is.

         Eased out, not in-out, so it opens at full speed and settles — the
         drawing leads the eye rather than making it wait for an accelerating
         start. */
      transition: clip-path 2.2s cubic-bezier(0.22, 1, 0.36, 1);
      transition-delay: var(--motion-base);
    }
    [data-statement].is-visible .blend-focus__curve-svg {
      clip-path: inset(0 -2% 0 0);
    }
  }
/* END_SECTION:blend-focus */

/* START_SECTION:blend-ingredients (INDEX:3) */
.blend-ingredients__more {
    display: flex;
    justify-content: center;
    margin-top: var(--space-xl);
  }
  .blend-ingredients__more .cart-add-more {
    padding: 0 3rem;
    font-size: 1.5rem;
  }

  .blend-ingredients {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-5xl), 12vh, var(--space-7xl)) 0;
    /* The photo bleeds past the true right edge of the page on purpose (see
       .blend-ingredients__image below), and the scroll-tilt below can swing
       its rotated bounding box taller than the row itself — clipped on both
       axes here so neither adds scroll to the page. (overflow-x alone would
       do it for x, but per the CSS spec, setting only one axis to non-visible
       computes the other to auto, not visible — that auto is what would let
       the section pick up a scrollbar of its own as the tilt increases.) */
    overflow: hidden;
  }

  /* Doubled selector so the max-width survives the theme-wide
     `.page-width { max-width: none }` full-bleed rule. Wider than before —
     this now holds a three-column row (intro / photo / text) rather than a
     single centred block. */
  .blend-ingredients .blend-ingredients__inner {
    max-width: 128rem;
    margin-inline: auto;
  }

  .blend-ingredients__eyebrow {
    margin: 0 0 var(--space-m);
    font-size: var(--text-caption);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-ingredients__heading {
    margin: 0 0 var(--space-xl);
    max-width: 20ch;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  /* Mobile: scrolls rather than wraps, same reasoning as the strength
     picker's own chip row — a wrapped row reflows into a different number of
     lines at every width, and stops reading as one object. From tablet up,
     a plain numbered list instead — hairline-divided rows rather than pills,
     echoing the 01/05 counter already used on the text column. */
  .blend-ingredients__tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
  }

  @media screen and (max-width: 749px) {
    .blend-ingredients__tabs {
      flex-wrap: nowrap;
      justify-content: flex-start;
      overflow-x: auto;
      scroll-snap-type: x proximity;
      scrollbar-width: none;
      margin-inline: calc(var(--diip-gutter, 2.4rem) * -1);
      padding-inline: var(--diip-gutter, 2.4rem);
    }
    .blend-ingredients__tabs::-webkit-scrollbar {
      display: none;
    }
    .blend-ingredients__tab {
      scroll-snap-align: center;
    }
  }

  @media screen and (min-width: 750px) {
    .blend-ingredients__tabs {
      flex-direction: column;
      align-items: stretch;
      gap: 0;
    }
  }

  /* No border/fill chrome — a plain row of index + name. Hairlines between
     rows (not around them) from tablet up, where they stack vertically; on
     mobile the scroll-snap row keeps a faint border instead, since there's
     no "between" to divide. The chosen row goes full-strength/bold, the rest
     stay muted — the only signal of selection. */
  .blend-ingredients__tab {
    display: flex;
    align-items: baseline;
    flex: 0 0 auto;
    gap: var(--space-xs);
    border: 0;
    border-radius: 0;
    background: none;
    color: rgba(var(--color-foreground), var(--ink-muted));
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: var(--space-xs) var(--space-m);
    cursor: pointer;
    transition: color var(--motion-base) var(--diip-ease);
  }

  @media screen and (max-width: 749px) {
    .blend-ingredients__tab {
      border: 0.1rem solid rgba(var(--color-foreground), 0.25);
      border-radius: var(--radius-pill);
    }
  }

  @media screen and (min-width: 750px) {
    .blend-ingredients__tab {
      padding: var(--space-xs) 0;
      border-bottom: 0.1rem solid var(--hairline);
    }
    .blend-ingredients__tab:last-child {
      border-bottom: 0;
    }
  }

  .blend-ingredients__tab-index {
    color: rgba(var(--color-foreground), var(--ink-faint));
    font-size: 1.1rem;
    font-variant-numeric: tabular-nums;
  }

  .blend-ingredients__tab:hover {
    color: rgb(var(--color-foreground));
  }

  .blend-ingredients__tab[aria-selected='true'] {
    color: rgb(var(--color-foreground));
    font-weight: 700;
  }

  .blend-ingredients__tab[aria-selected='true'] .blend-ingredients__tab-index {
    color: rgb(var(--color-foreground));
  }

  .blend-ingredients__tab:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  /* Stacked on a phone — intro (eyebrow/heading/pills), then photo, then
     counter/name/note, top to bottom. align-items: stretch, not centre — the
     intro's pill row scrolls full-bleed via a negative-margin trick (see
     .blend-ingredients__tabs below) that only works when its container is a
     definite, full width; a shrink-to-fit flex item sized to the pills' own
     unwrapped width pushed the whole intro (heading included) off-screen.
     Centred looks are still text-align: center on each piece, not on the
     column itself. From tablet up, three columns: intro on the left, the
     photo in the middle, the text on the right, all vertically centred
     against the row's own height. The outer two columns share the space left
     over from the (content-sized) photo column evenly, so the row fills the
     section rather than clumping in the middle. */
  .blend-ingredients__row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    gap: var(--space-l);
  }

  @media screen and (min-width: 750px) {
    .blend-ingredients__row {
      display: grid;
      grid-template-columns: 4fr 4fr 2fr;
      align-items: center;
      gap: clamp(var(--space-xl), 5vw, var(--space-4xl));
    }
  }

  /* Left column: eyebrow, heading and the vertical pill list, left-aligned
     (the row's own text-align: center above is for the mobile, stacked
     layout only). The hairline divides it from the centre column; padding on
     this side of it, rather than splitting the row's own gap in two, so it
     doesn't depend on the gap's size to stay clear of the text either side. */
  @media screen and (min-width: 750px) {
    .blend-ingredients__intro {
      text-align: left;
      padding-right: clamp(var(--space-xl), 5vw, var(--space-4xl));
      border-right: 0.1rem solid var(--hairline);
    }
  }

  /* One grid cell, every ingredient's counter/name/note stacked in it, so
     switching can't move the photo or resize the section — the column is
     always as tall as its longest piece. Inactive pieces stay in the layout
     and are hidden from view rather than removed, which is what reserves
     that height. */
  .blend-ingredients__texts {
    display: grid;
    justify-items: center;
  }

  @media screen and (min-width: 750px) {
    .blend-ingredients__texts {
      justify-items: start;
      text-align: left;
    }
  }

  /* The product shot: one photo with a soft radial wash behind it for some
     presence against a plain background. Not tied to which ingredient is
     selected — see the comment at the top of the file. Narrow on purpose —
     this column is a fifth of the row (see .blend-ingredients__row above),
     the smallest of the three, with the intro and the ingredient's text
     doing the talking instead. */
  .blend-ingredients__media {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .blend-ingredients__glow {
    position: absolute;
    inset: -20%;
    z-index: 0;
    border-radius: 50%;
    background: radial-gradient(
      circle,
      rgba(var(--color-foreground), 0.06) 0%,
      rgba(var(--color-foreground), 0.06) 35%,
      transparent 72%
    );
  }

  .blend-ingredients__image {
    position: relative;
    z-index: 1;
    display: block;
    width: 100%;
    max-width: 32rem;
    height: auto;
    max-height: min(56rem, 60vh);
    object-fit: contain;
  }

  /* Scroll-linked tilt (see the javascript block below): the script writes
     --scroll-rotate as the section passes through the viewport. Its own
     rule, not folded into the base/desktop transforms above, so it composes
     with the desktop translate() rather than replacing it. */
  @media (prefers-reduced-motion: no-preference) {
    .blend-ingredients__image {
      transform: rotate(var(--scroll-rotate, 0deg));
    }
  }

  /* Desktop only: the photo breaks out of its column and the page, pinned
     so its own centre sits exactly on the page's true right edge — half of
     it on the page, half off. right: -gutter reaches .blend-ingredients__inner's
     own edge, which is that true edge below the 128rem cap (the same
     assumption the rest of the theme's full-bleed elements make); translate
     then shifts it right by exactly half its own (now free, unconstrained)
     width, which is what centres it on that edge rather than sitting flush
     against it. The glow moves with it, on the same anchor point, sized big
     enough to reach past the image on every side. */
  @media screen and (min-width: 750px) {
    .blend-ingredients__glow {
      inset: auto;
      top: 50%;
      right: calc(-1 * var(--diip-gutter));
      width: 40rem;
      height: 40rem;
      transform: translate(50%, -50%);
    }

    .blend-ingredients__image {
      position: absolute;
      top: 50%;
      right: calc(-1 * var(--diip-gutter));
      /* Overrides the base rule's width: 100% — for an absolutely positioned
         element with only `right` set (not `left`), a percentage width
         resolves against the containing block (.blend-ingredients__media,
         which is narrow — it's sized by the grid column) rather than growing
         to fill max-width. width: auto lets the image's own intrinsic size,
         capped by max-width, decide instead. */
      width: auto;
      max-width: 56rem;
      transform: translate(50%, -50%);
    }

    @media (prefers-reduced-motion: no-preference) {
      .blend-ingredients__image {
        transform: translate(50%, -50%) rotate(var(--scroll-rotate, 0deg));
      }
    }
  }

  .blend-ingredients__panel {
    grid-area: 1 / 1;
  }
  .blend-ingredients__panel[hidden] {
    display: block;
    visibility: hidden;
  }

  @media (prefers-reduced-motion: no-preference) {
    .blend-ingredients__panel {
      opacity: 0;
      transition: opacity var(--motion-base) var(--diip-ease);
    }
    .blend-ingredients__panel.is-active {
      opacity: 1;
    }
  }

  /* No script: every ingredient's name and note shown at once, each pair
     stacked back into flow together, and the tabs (which would have nothing
     left to do) are hidden. */
  .blend-ingredients:not([data-enhanced]) .blend-ingredients__row {
    display: block;
  }
  .blend-ingredients:not([data-enhanced]) .blend-ingredients__media {
    margin-bottom: var(--space-xl);
  }
  .blend-ingredients:not([data-enhanced]) .blend-ingredients__texts {
    display: block;
  }
  .blend-ingredients:not([data-enhanced]) .blend-ingredients__panel {
    grid-area: auto;
    padding-bottom: var(--space-m);
  }
  .blend-ingredients:not([data-enhanced]) .blend-ingredients__tabs {
    display: none;
  }

  .blend-ingredients__name {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-lead);
    line-height: 1.2;
    letter-spacing: -0.01em;
    font-weight: 700;
    text-wrap: balance;
  }

  .blend-ingredients__panel-text {
    max-width: 36ch;
  }

  .blend-ingredients__counter {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-caption);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.08em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-ingredients__claim {
    margin: 0;
    font-size: var(--text-body);
    line-height: 1.6;
    color: rgba(var(--color-foreground), var(--ink));
    text-wrap: pretty;
  }

  /* Source / Role: a small label-and-value row each, a hairline between them,
     matching the reference's data rows under the note. <dl>/<dt>/<dd> since
     each pair really is a term and its value; margin reset since a <dl>
     carries Dawn/browser defaults meant for a denser, unstyled list. */
  .blend-ingredients__data {
    margin: var(--space-m) 0 0;
    width: 100%;
    max-width: 36ch;
  }

  .blend-ingredients__data-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-m);
    padding: var(--space-xs) 0;
    border-top: 0.1rem solid var(--hairline);
  }
  .blend-ingredients__data-row:last-child {
    border-bottom: 0.1rem solid var(--hairline);
  }

  .blend-ingredients__data-row dt {
    margin: 0;
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-ingredients__data-row dd {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 700;
    text-align: right;
  }

  .blend-ingredients__footnote {
    margin: var(--space-2xl) auto 0;
    max-width: 64rem;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .blend-ingredients__inner > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .blend-ingredients__inner > * {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .blend-ingredients__row { transition-delay: var(--motion-stagger); }
  }
/* END_SECTION:blend-ingredients */

/* START_SECTION:compare-slider (INDEX:13) */
.compare-slider {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-3xl), 12vh, var(--space-6xl)) 0;
  }

  /* Doubled selector so the width cap survives the theme-wide full-bleed
     .page-width rule, which loads later. */
  .compare-slider .compare-slider__inner {
    max-width: 144rem;
    margin-inline: auto;
  }

  .compare-slider__eyebrow {
    margin: 0 0 var(--space-m);
    text-align: center;
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .compare-slider__heading {
    margin: 0 auto var(--space-2xl);
    max-width: 24ch;
    text-align: center;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  /* ---- The stage --------------------------------------------------------
     Two layers stacked in one square. The second is clipped from the handle to
     the right edge, so the handle is exactly where one picture ends and the other
     begins. --split is the handle's position; it is 50% until the script moves
     it. */
  .compare-slider__stage {
    --split: 50%;
    position: relative;
    width: min(100%, var(--compare-slider-stage, 44rem));
    aspect-ratio: 1 / 1;
    margin-inline: auto;
    overflow: hidden;
    background-color: rgba(var(--color-foreground), 0.06);
    user-select: none;
  }

  .compare-slider__layer {
    position: absolute;
    inset: 0;
  }

  .compare-slider__layer--b {
    clip-path: inset(0 0 0 var(--split));
  }

  .compare-slider__photo {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
  }

  /* A block with no picture yet: a plain tile with the number on it. The first
     is light and the second dark, so the split still reads as lighter and
     stronger. */
  .compare-slider__layer--tile {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #e9ecef;
    color: #17181c;
  }

  .compare-slider__layer--tile.compare-slider__layer--b {
    background-color: #17181c;
    color: #ffffff;
  }

  .compare-slider__tile-number {
    font-size: clamp(9.6rem, 24vw, 22.4rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.04em;
  }

  /* The real control: a range input laid over the whole stage, invisible, so a
     drag anywhere on the picture moves the handle and the arrow keys work. Pan-y
     only, so a vertical swipe still scrolls the page on a phone. */
  .compare-slider__range {
    position: absolute;
    inset: 0;
    z-index: 3;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    opacity: 0;
    cursor: ew-resize;
    touch-action: pan-y;
    appearance: none;
    -webkit-appearance: none;
  }

  .compare-slider__grip {
    position: absolute;
    inset: 0 auto 0 var(--split);
    z-index: 2;
    width: 0;
    pointer-events: none;
  }

  .compare-slider__grip::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: -0.1rem;
    width: 0.2rem;
    background-color: #ffffff;
    box-shadow: 0 0 0 0.1rem rgba(0, 0, 0, 0.25);
  }

  .compare-slider__knob {
    position: absolute;
    top: 50%;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target);
    height: var(--tap-target);
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background-color: #ffffff;
    color: #17181c;
    box-shadow: 0 0.2rem 0.8rem rgba(0, 0, 0, 0.3);
  }

  .compare-slider__range:focus-visible ~ .compare-slider__grip .compare-slider__knob {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  /* Without the script there is nothing to drag, so no handle and no hint. */
  .compare-slider__grip {
    display: none;
  }

  .compare-slider__range {
    pointer-events: none;
  }

  [data-enhanced] .compare-slider__grip {
    display: block;
  }

  [data-enhanced] .compare-slider__range {
    pointer-events: auto;
  }

  .compare-slider__hint {
    display: none;
    margin: var(--space-s) 0 0;
    text-align: center;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  [data-enhanced] .compare-slider__hint {
    display: block;
  }

  /* ---- The words --------------------------------------------------------
     Without the script, stacked, both showing. With it, the panels share one
     grid cell so the section is as tall as the taller of the two and nothing
     jumps as the handle moves; the one in view is opaque, the other is inert (not
     focusable, not announced) and transparent. */
  .compare-slider__panels {
    display: grid;
    gap: var(--space-xl);
    margin-top: var(--space-xl);
  }

  .compare-slider__panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
  }

  [data-enhanced] .compare-slider__panels {
    gap: 0;
  }

  [data-enhanced] .compare-slider__panel {
    grid-area: 1 / 1;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--motion-fast) var(--diip-ease), visibility 0s linear var(--motion-fast);
  }

  [data-enhanced] .compare-slider__panel[data-active] {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--motion-fast) var(--diip-ease), visibility 0s;
  }

  @media (prefers-reduced-motion: reduce) {
    [data-enhanced] .compare-slider__panel,
    [data-enhanced] .compare-slider__panel[data-active] {
      transition: none;
    }
  }

  .compare-slider__title {
    margin: 0 0 var(--space-s);
    font-weight: 700;
  }

  .compare-slider__number {
    display: block;
    font-size: var(--text-display);
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
  }

  .compare-slider__label {
    display: block;
    margin-top: var(--space-xs);
    font-size: var(--text-lead);
    line-height: 1.2;
    letter-spacing: -0.01em;
  }

  .compare-slider__audience {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-body);
    font-weight: 700;
  }

  .compare-slider__text {
    margin: 0;
    max-width: 36ch;
    font-size: var(--text-body);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
    text-wrap: pretty;
  }

  .compare-slider__shop {
    margin-top: var(--space-m);
  }
/* END_SECTION:compare-slider */

/* START_SECTION:design-system (INDEX:16) */
.ds {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: var(--space-5xl) var(--diip-gutter, var(--space-m));
    max-width: 108rem;
    margin-inline: auto;
  }

  .ds__head { margin-bottom: var(--space-6xl); }
  .ds__eyebrow {
    margin: 0 0 var(--space-s);
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .ds__title {
    margin: 0 0 var(--space-m);
    font-size: var(--text-display);
    line-height: 1.05;
    letter-spacing: -0.025em;
    font-weight: 700;
  }
  .ds__lead {
    margin: 0;
    max-width: 60ch;
    font-size: var(--text-lead);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .ds__block {
    padding-top: var(--space-4xl);
    margin-top: var(--space-4xl);
    border-top: 0.1rem solid var(--hairline);
  }
  .ds__h {
    margin: 0 0 var(--space-s);
    font-size: var(--text-title);
    line-height: 1.2;
    letter-spacing: -0.01em;
    font-weight: 700;
  }
  .ds__note {
    margin: 0 0 var(--space-xl);
    max-width: 68ch;
    font-size: var(--text-body);
    line-height: 1.55;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .ds__rows { display: flex; flex-direction: column; gap: var(--space-xl); }
  .ds__row {
    display: grid;
    gap: var(--space-s);
    padding-bottom: var(--space-xl);
    border-bottom: 0.1rem solid var(--hairline);
  }
  .ds__row:last-child { border-bottom: 0; padding-bottom: 0; }

  .ds__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-s); }
  .ds__token {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink));
  }
  .ds__measure {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-faint));
  }
  .ds__usage {
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* Specimens use the tokens directly — never a copied value. */
  .ds__spec { margin: 0; }
  .ds__spec--hero    { font-size: var(--text-hero);    line-height: 1;    letter-spacing: -0.03em;  font-weight: 700; }
  .ds__spec--display { font-size: var(--text-display); line-height: 1.05; letter-spacing: -0.025em; font-weight: 700; }
  .ds__spec--heading { font-size: var(--text-heading); line-height: 1.08; letter-spacing: -0.02em;  font-weight: 700; }
  .ds__spec--title   { font-size: var(--text-title);   line-height: 1.2;  letter-spacing: -0.01em;  font-weight: 700; }
  .ds__spec--lead    { font-size: var(--text-lead);    line-height: 1.4;  font-weight: 400; }
  .ds__spec--body    { font-size: var(--text-body);    line-height: 1.55; font-weight: 400; }
  .ds__spec--sm      { font-size: var(--text-sm);      line-height: 1.45; font-weight: 400; }
  .ds__spec--caption { font-size: var(--text-caption); line-height: 1.4;  font-weight: 400; }

  .ds__ink { margin: 0; font-size: var(--text-lead); line-height: 1.4; }
  .ds__ink--strong { color: rgba(var(--color-foreground), var(--ink-strong)); }
  .ds__ink--base   { color: rgba(var(--color-foreground), var(--ink)); }
  .ds__ink--muted  { color: rgba(var(--color-foreground), var(--ink-muted)); }
  .ds__ink--faint  { color: rgba(var(--color-foreground), var(--ink-faint)); }

  .ds__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
    gap: var(--space-m);
  }
  .ds__card {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-m);
    border: 0.1rem solid var(--hairline);
    border-radius: var(--radius-s);
  }
  .ds__card--muted { opacity: 0.6; }
  .ds__weight { margin: 0; font-size: var(--text-title); line-height: 1.2; }

  .ds__swatches {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: var(--space-m);
    margin-bottom: var(--space-m);
  }
  .ds__swatch {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-l) var(--space-m);
    border: 0.1rem solid var(--hairline);
    border-radius: var(--radius-s);
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
  }
  .ds__swatch-name { font-size: var(--text-body); font-weight: 700; }

  .ds__chip {
    display: block;
    width: 100%;
    height: 4.8rem;
    border-radius: var(--radius-s);
  }
  .ds__chip--scrim { background: var(--scrim); }
  .ds__chip--hairline { background: var(--hairline); }

  .ds__bars { display: flex; flex-direction: column; gap: var(--space-s); }
  .ds__bar-row {
    display: grid;
    grid-template-columns: 12rem 1fr auto;
    align-items: center;
    gap: var(--space-s);
  }
  .ds__bar {
    display: block;
    height: 1.6rem;
    background-color: var(--diip-accent);
    border-radius: var(--radius-none);
  }

  .ds__radius {
    display: block;
    width: 100%;
    height: 6.4rem;
    background-color: rgba(var(--color-foreground), 0.08);
    border: 0.1rem solid var(--hairline);
  }

  /* Motion demo: the dot travels for exactly its token's duration. */
  .ds__motion { cursor: pointer; }
  .ds__dot {
    display: block;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: var(--radius-pill);
    background-color: var(--diip-accent);
    transform: translateX(0);
  }
  .ds__motion--fast .ds__dot { transition: transform var(--motion-fast) var(--diip-ease); }
  .ds__motion--base .ds__dot { transition: transform var(--motion-base) var(--diip-ease); }
  .ds__motion--slow .ds__dot { transition: transform var(--motion-slow) var(--diip-ease); }
  .ds__motion:hover .ds__dot { transform: translateX(calc(100% * 8)); }

  .ds__buttons { display: flex; flex-wrap: wrap; gap: var(--space-s); }
  .ds__btn {
    display: inline-flex;
    align-items: center;
    padding: var(--space-s) var(--space-m);
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease),
      color var(--motion-fast) var(--diip-ease),
      opacity var(--motion-fast) var(--diip-ease);
  }
  .ds__btn--filled {
    border: 0;
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
  }
  .ds__btn--outline {
    border: 0.1rem solid var(--hairline);
    background: transparent;
    color: inherit;
  }
  .ds__btn[disabled] { opacity: 0.45; cursor: not-allowed; }

  @media screen and (max-width: 749px) {
    .ds__bar-row { grid-template-columns: 1fr; }
  }
/* END_SECTION:design-system */

/* START_SECTION:faq (INDEX:19) */
.faq {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    /* Same vertical rhythm as the other large sections. */
    padding: clamp(var(--space-4xl), 10vh, var(--space-6xl)) 0;
    /* A hairline closing the section, between the last question and the footer. */
    border-bottom: 0.1rem solid var(--hairline);
  }

  /* Doubled selector so the max-width survives the theme-wide
     .page-width { max-width: none } full-bleed rule. */
  .faq .faq__inner {
    max-width: 120rem;
    margin-inline: auto;
  }

  /* One column on a phone (list, then the answer); from tablet up the list on
     the left and the answer on the right, vertically centred on each other. */
  .faq__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2xl);
  }

  @media screen and (min-width: 750px) {
    .faq__row {
      /* Two equal columns with no gap, the space either side of the divider
         done as padding, so the divider sits exactly on the section's centre. */
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      align-items: center;
      gap: 0;
    }
    .faq__intro {
      padding-right: clamp(var(--space-xl), 5vw, var(--space-4xl));
      border-right: 0.1rem solid var(--hairline);
    }
    .faq__answers {
      padding-left: clamp(var(--space-xl), 5vw, var(--space-4xl));
    }
  }

  .faq__eyebrow {
    margin: 0 0 var(--space-m);
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .faq__title {
    margin: 0;
    max-width: 24ch;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  .faq__subtitle {
    margin: var(--space-m) 0 0;
    max-width: 36rem;
    font-size: var(--text-body);
    line-height: 1.55;
    color: rgba(var(--color-foreground), var(--ink));
  }

  /* The question list. Hairlines between rows, no chrome; the chosen one goes
     full-strength and bold, the rest stay muted. Hidden until the script is
     running, since without it the answers are all on the page already. */
  .faq__tabs {
    display: none;
    margin-top: var(--space-xl);
    border-top: 0.1rem solid var(--hairline);
  }
  .faq.is-ready .faq__tabs {
    display: flex;
    flex-direction: column;
  }

  /* Pages of questions: the list fades between them. The off-page questions are
     taken out of the layout; the script holds the list at the tallest page's
     height so the pager and button below never jump. */
  .faq__tabs {
    transition: opacity var(--motion-base) var(--diip-ease);
  }
  .faq__tabs.is-fading {
    opacity: 0;
  }
  .faq__tab.is-off-page {
    display: none;
  }

  .faq__pager {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    margin-top: var(--space-m);
  }
  .faq__pager[hidden] {
    display: none;
  }
  .faq__pager-count {
    min-width: 5rem;
    text-align: center;
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .faq__pager-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    padding: 0;
    border: 0.1rem solid rgba(var(--color-foreground), 0.25);
    border-radius: 50%;
    background: none;
    color: rgb(var(--color-foreground));
    cursor: pointer;
    transition: border-color var(--motion-base) var(--diip-ease), background-color var(--motion-base) var(--diip-ease), color var(--motion-base) var(--diip-ease), opacity var(--motion-base) var(--diip-ease);
  }
  .faq__pager-button svg {
    width: 1.4rem;
    height: 1.4rem;
  }
  .faq__pager-button--prev svg {
    transform: rotate(90deg);
  }
  .faq__pager-button--next svg {
    transform: rotate(-90deg);
  }
  .faq__pager-button:hover:not(:disabled) {
    background-color: rgb(var(--color-foreground));
    border-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
  }
  .faq__pager-button:disabled {
    opacity: 0.35;
    cursor: default;
  }
  .faq__pager-button:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }

  .faq__tab {
    display: flex;
    align-items: baseline;
    gap: var(--space-s);
    width: 100%;
    padding: var(--space-s) 0;
    border: 0;
    border-bottom: 0.1rem solid var(--hairline);
    border-radius: 0;
    background: none;
    color: rgba(var(--color-foreground), var(--ink-muted));
    font: inherit;
    font-size: 1.8rem;
    line-height: 1.3;
    font-weight: 600;
    letter-spacing: -0.01em;
    text-align: left;
    cursor: pointer;
    transition: color var(--motion-base) var(--diip-ease);
  }
  .faq__tab:hover,
  .faq__tab[aria-selected='true'] {
    color: rgb(var(--color-foreground));
  }
  .faq__tab[aria-selected='true'] {
    font-weight: 700;
  }
  .faq__tab:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .faq__tab-index {
    flex: 0 0 auto;
    color: rgba(var(--color-foreground), var(--ink-faint));
    font-size: 1.1rem;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
  }
  .faq__tab[aria-selected='true'] .faq__tab-index {
    color: rgb(var(--color-foreground));
  }

  /* The answers share one grid cell so the column is always as tall as the
     longest answer and nothing moves when you switch. Inactive ones stay in the
     layout, invisible. Without the script they all just stack. */
  .faq__answers {
    display: grid;
    gap: var(--space-xl);
  }
  .faq.is-ready .faq__answers {
    gap: 0;
  }
  .faq.is-ready .faq__panel {
    grid-area: 1 / 1;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--motion-slow) var(--diip-ease), visibility 0s linear var(--motion-slow);
  }
  .faq.is-ready .faq__panel.is-active {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--motion-slow) var(--diip-ease) 0.1s, visibility 0s;
  }

  .faq__panel-number {
    margin: 0 0 var(--space-s);
    font-size: var(--text-caption);
    letter-spacing: 0.14em;
    font-variant-numeric: tabular-nums;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .faq__panel-question {
    margin: 0 0 var(--space-m);
    font-size: var(--text-title);
    line-height: 1.15;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  .faq__answer {
    max-width: 52rem;
    font-size: var(--text-body);
    line-height: 1.6;
    color: rgba(var(--color-foreground), var(--ink));
  }
  .faq__answer > *:first-child { margin-top: 0; }
  .faq__answer > *:last-child { margin-bottom: 0; }

  /* Arrows left, contact button right, on one row under the list. */
  .faq__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-m);
    margin-top: var(--space-xl);
  }
  .faq__footer .faq__pager {
    margin-top: 0;
  }
  .faq__footer .faq__button {
    margin: 0 0 0 auto;
  }
  /* The contact button keeps its label on one line; on a phone the row is tight, so
     the gap and the button's side padding come in a little. */
  .faq__footer .faq__button {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  @media screen and (max-width: 480px) {
    .faq__footer {
      gap: var(--space-s);
    }
    .faq__footer .faq__button {
      padding: 0 var(--space-m);
    }
  }

  /* Same pill language as the tabs and the other section buttons: a filled pill
     in the section's ink, arrow nudging forward on hover. */
  .faq__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    margin-top: var(--space-xl);
    min-height: var(--tap-target);
    padding: 0 var(--space-l);
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    transition: opacity var(--motion-base) var(--diip-ease);
  }
  .faq__button:hover {
    opacity: 0.85;
  }
  .faq__button:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.3rem;
  }
  .faq__button-arrow {
    display: inline-block;
    transition: transform var(--motion-base) var(--diip-ease);
  }
  .faq__button:hover .faq__button-arrow {
    transform: translateX(0.3rem);
  }

  /* The contact form: stacked in the answers' grid cell like another panel, so
     the column stays as tall as its tallest content and nothing jumps when you
     switch. Not shown at all until the script has run. */
  .faq__contact {
    display: none;
  }
  .faq.is-ready .faq__contact {
    display: block;
    grid-area: 1 / 1;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--motion-slow) var(--diip-ease), visibility 0s linear var(--motion-slow);
  }
  .faq.is-ready .faq__contact.is-active {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--motion-slow) var(--diip-ease) 0.1s, visibility 0s;
  }
  .faq__form {
    display: grid;
    gap: var(--space-m);
    max-width: 52rem;
  }
  .faq__form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--space-m);
  }
  .faq__field {
    display: grid;
    gap: var(--space-xs);
  }
  .faq__label {
    font-size: var(--text-caption);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* Same outlined, rounded language as the pills elsewhere; the full-strength
     outline marks the field you are in. */
  .faq__input {
    width: 100%;
    min-height: var(--tap-target);
    padding: 1.2rem 2rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: transparent;
    color: rgb(var(--color-foreground));
    font: inherit;
    font-size: var(--text-body);
    transition: border-color var(--motion-fast) var(--diip-ease);
  }
  .faq__input--area {
    min-height: 14rem;
    border-radius: 2rem;
    resize: vertical;
  }
  .faq__input:hover {
    border-color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .faq__input:focus {
    outline: none;
    border-color: rgb(var(--color-foreground));
  }
  .faq__input[aria-invalid='true'] {
    border-color: rgb(var(--color-foreground));
  }
  .faq__form-status {
    margin: 0;
    font-size: var(--text-body);
    line-height: 1.5;
  }
  .faq__form .faq__button--submit {
    justify-self: start;
    margin-top: 0;
    border: 0;
    cursor: pointer;
    font-family: inherit;
  }

  /* ---- Phone: a standard accordion ------------------------------------------
     Under 750px each answer opens directly under its question (the script moves
     the panel there) and the rows get a chevron that turns when open. The
     questions stay paged, with the arrows underneath, so a long list does not
     become a long scroll. The contact form opens right under the button, in the
     same way. */
  @media screen and (max-width: 749px) {
    .faq--accordion .faq__tab {
      align-items: center;
      padding: var(--space-m) 0;
      border-bottom: 0;
    }
    .faq--accordion .faq__tab::after {
      content: '';
      flex: 0 0 auto;
      width: 0.9rem;
      height: 0.9rem;
      margin: -0.3rem 0.4rem 0 auto;
      border-right: 0.18rem solid currentColor;
      border-bottom: 0.18rem solid currentColor;
      transform: rotate(45deg);
      transition: transform var(--motion-base) var(--diip-ease);
    }
    .faq--accordion .faq__tab.is-active::after {
      margin-top: 0.3rem;
      transform: rotate(-135deg);
    }
    /* The row is the question, so the panel is just the answer, under it. */
    .faq--accordion .faq__panel {
      display: none;
      padding: 0 0 var(--space-m);
      opacity: 1;
      visibility: visible;
      border-bottom: 0.1rem solid var(--hairline);
    }
    .faq--accordion .faq__panel.is-active {
      display: block;
      animation: faq-accordion-open var(--motion-base) var(--diip-ease);
    }
    .faq--accordion .faq__tab.is-active {
      border-bottom: 0;
    }
    .faq--accordion .faq__tab:not(.is-active) {
      border-bottom: 0.1rem solid var(--hairline);
    }
    .faq--accordion .faq__panel .faq__panel-number,
    .faq--accordion .faq__panel .faq__panel-question {
      display: none;
    }
    .faq--accordion .faq__answer {
      font-size: var(--text-body);
    }
    /* The contact form: under the button, not in a column of its own. */
    .faq.faq--accordion .faq__contact {
      display: none;
      margin-top: var(--space-xl);
      opacity: 1;
      visibility: visible;
    }
    .faq.faq--accordion .faq__contact.is-active {
      display: block;
      animation: faq-accordion-open var(--motion-base) var(--diip-ease);
    }
    @keyframes faq-accordion-open {
      from {
        opacity: 0;
        transform: translateY(-0.6rem);
      }
      to {
        opacity: 1;
        transform: none;
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .faq.is-ready .faq__panel,
    .faq.is-ready .faq__panel.is-active,
    .faq.is-ready .faq__contact,
    .faq.is-ready .faq__contact.is-active {
      transition: none;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    /* Scroll reveal, matching the neighbouring sections. */
    [data-reveal] .faq__row > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .faq__row > * {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .faq__answers { transition-delay: var(--motion-stagger); }
  }
/* END_SECTION:faq */

/* START_SECTION:fine-print (INDEX:23) */
.fine-print {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-xl), 7vh, var(--space-4xl)) 0;
  }

  .fine-print .fine-print__inner {
    max-width: 72rem;
    margin-inline: auto;
  }

  .fine-print__heading {
    margin: 0 0 var(--space-s);
    font-size: var(--text-caption);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .fine-print__content {
    font-size: var(--text-caption);
    line-height: 1.6;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .fine-print__content p { margin: 0 0 var(--space-xs); }
  .fine-print__content p:last-child { margin-bottom: 0; }
  .fine-print__content strong { color: rgba(var(--color-foreground), var(--ink)); font-weight: 700; }
/* END_SECTION:fine-print */

/* START_SECTION:flavor-guide (INDEX:24) */
.flavor-guide {
    padding: var(--space-5xl) var(--diip-gutter, 2.4rem);
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
  }
  .flavor-guide__inner {
    max-width: 120rem;
    margin: 0 auto;
  }
  .flavor-guide__header {
    max-width: 72rem;
    margin: 0 0 var(--space-3xl);
  }
  .flavor-guide__heading {
    margin: 0;
    font-size: var(--text-heading);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: rgb(var(--color-foreground));
  }
  .flavor-guide__heading--small {
    font-size: var(--text-title);
    letter-spacing: -0.01em;
  }
  .flavor-guide__text {
    margin: var(--space-s) 0 0;
    font-size: var(--text-lead);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
  }

  /* A phone: less air above and below. */
  @media screen and (max-width: 749px) {
    .flavor-guide {
      padding-block: var(--space-3xl);
    }
    .flavor-guide__header {
      margin-bottom: var(--space-xl);
    }
    .flavor-guide__strengths {
      margin-top: var(--space-3xl);
    }
    .flavor-guide__strength-value {
      min-width: 4.8rem;
      font-size: var(--text-display);
    }
    .flavor-guide__strength {
      gap: var(--space-s);
    }
  }
  @media screen and (min-width: 750px) and (max-width: 989px) {
    .flavor-guide {
      padding-block: var(--space-4xl);
    }
    .flavor-guide__strengths {
      margin-top: var(--space-4xl);
    }
  }

  .flavor-guide__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-l) var(--space-s);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  /* Four across from a tablet up: seven flavors fill four and three, where three
     across would leave one alone on the last row. */
  @media screen and (min-width: 750px) {
    .flavor-guide__grid {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }
  .flavor-guide__card {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
  }
  .flavor-guide__media {
    display: block;
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--radius-m);
    background: rgba(var(--color-foreground), 0.05);
  }
  .flavor-guide__media img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: var(--space-s);
  }
  .flavor-guide__name {
    margin: var(--space-xs) 0 0;
    font-size: var(--text-lead);
    font-weight: 700;
    line-height: 1.2;
  }
  .flavor-guide__link {
    color: inherit;
    text-decoration: none;
  }
  /* The name is a link, shown on hover or focus by a small arrow fading in after
     it (the same as the flavor name elsewhere); always there, quietly, on touch. */
  .flavor-guide__link::after {
    content: '';
    display: inline-block;
    width: 0.75em;
    height: 0.75em;
    margin-left: 0.4em;
    vertical-align: -0.02em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: 0;
    transform: translateX(-0.4em);
    transition: opacity var(--motion-base) var(--diip-ease), transform var(--motion-base) var(--diip-ease);
  }
  .flavor-guide__link:hover::after,
  .flavor-guide__link:focus-visible::after {
    opacity: 1;
    transform: none;
  }
  .flavor-guide__link:focus-visible {
    outline: 0.2rem solid currentColor;
    outline-offset: 0.3rem;
  }
  @media (hover: none) {
    .flavor-guide__link::after {
      opacity: 0.55;
      transform: none;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .flavor-guide__link::after {
      transition: none;
      transform: none;
    }
  }
  .flavor-guide__note {
    margin: 0;
    font-size: var(--text-body);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
  }
  .flavor-guide__badge {
    align-self: flex-start;
    margin: 0;
    padding: 0.3rem 1rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    font-size: var(--text-caption);
    font-weight: 600;
    color: rgba(var(--color-foreground), var(--ink));
  }

  .flavor-guide__strengths {
    margin-top: var(--space-5xl);
    padding-top: var(--space-xl);
    border-top: 0.1rem solid var(--hairline);
  }
  .flavor-guide__strength-list {
    display: grid;
    gap: var(--space-m);
    margin: var(--space-m) 0 0;
    padding: 0;
    list-style: none;
  }
  @media screen and (min-width: 750px) {
    .flavor-guide__strength-list {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-xl);
    }
  }
  .flavor-guide__strength {
    display: flex;
    gap: var(--space-m);
    align-items: baseline;
  }
  .flavor-guide__strength-value {
    flex: none;
    min-width: 6rem;
    font-size: var(--text-hero);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
  }
  .flavor-guide__strength-text {
    font-size: var(--text-body);
    line-height: 1.55;
    color: rgba(var(--color-foreground), var(--ink));
  }
/* END_SECTION:flavor-guide */

/* START_SECTION:footer (INDEX:25) */
footer.footer {
    /* The footer's own grey, set here so the colour scheme (and the other things
       that use it) is left alone. */
    background-color: #404040;
    color: rgb(var(--color-foreground));
    margin-top: {{ section.settings.margin_top }}px;
    /* No padding of its own: the containers run the full height of the footer. */
    padding: 0;
  }

  /* ---- Containers ---------------------------------------------------------
     The footer is a grid of containers divided by hairlines, the way the product
     panel is: the logo on the left half; on the right half the social links, the
     policies and the payment logos, one under another; and the 21+ notice in a
     container across the foot, all inside one bordered frame. */
  .footer__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    --footer-line: rgba(var(--color-foreground), 0.28);
    --footer-gutter: 4rem;
    border-top: 0.1rem solid var(--footer-line);
  }

  .footer__cell--logo {
    display: flex;
    align-items: center;
    padding: var(--space-xl) var(--space-xl) var(--space-xl) var(--footer-gutter);
    border-right: 0.1rem solid var(--footer-line);
  }

  .footer__cell--info {
    display: flex;
    flex-direction: column;
  }

  .footer__row {
    padding: var(--space-l) var(--footer-gutter) var(--space-l) var(--space-xl);
  }
  /* The social row takes the leftover height, so the rows below sit at the foot
     of the container, level with the foot of the logo's. */
  /* Copyright on the left, the card logos on the right, one line. */
  .footer__row--payment {
    border-top: 0.1rem solid var(--footer-line);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s) var(--space-m);
  }
  /* The policies take the leftover height, so the copyright, the social icons and
     the card logos sit at the foot of the container, level with the foot of the logo. */
  /* The account links get a container of their own above the policies. */
  .footer__row--learn {
    border-top: 0.1rem solid var(--footer-line);
  }
  .footer__row--policies {
    flex: 1 1 auto;
    border-top: 0.1rem solid var(--footer-line);
  }
  .footer__row-start {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-s) var(--space-m);
  }
  .footer__row-start .footer__copyright {
    margin: 0;
  }

  .footer__cell--notice {
    grid-column: 1 / -1;
    padding: var(--space-l) var(--footer-gutter);
    border-top: 0.1rem solid var(--footer-line);
  }

  @media screen and (max-width: 749px) {
    .footer__grid {
      grid-template-columns: minmax(0, 1fr);
    }
    .footer__cell--logo {
      padding: var(--space-l) 1.5rem;
      border-right: 0;
      border-bottom: 0.1rem solid var(--footer-line);
    }
    .footer__row,
    .footer__cell--notice {
      padding-left: 1.5rem;
      padding-right: 1.5rem;
    }
  }

  /* ---- Brand column ------------------------------------------------------ */
  .footer__brand {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-m);
  }

  .footer__logo {
    display: block;
    width: 100%;
    /* The scheme's body colour is 75% ink; the logo is full ink. */
    color: rgb(var(--color-foreground));
    opacity: 1;
    text-decoration: none;
  }
  /* The header sets the mark's height; here its width is what's set. */
  .footer__logo .header__logo-svg svg,
  .footer__logo svg,
  .footer__logo img {
    display: block;
    width: 100%;
    height: auto;
    max-width: none;
  }
  .footer__logo .header__logo-svg,
  .footer__logo .header__heading-logo-wrapper {
    display: block;
    width: 100%;
    color: rgb(var(--color-foreground));
    opacity: 1;
  }
  .footer__logo .header__logo-svg svg {
    fill: rgb(var(--color-foreground));
  }

  .footer__tagline {
    margin: 0;
    max-width: 32ch;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .footer__social {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 1.2rem;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  /* The icons are 20px; the tap target reaches past them. */
  .footer__social .list-social__link {
    position: relative;
  }
  .footer__social .list-social__link::after {
    content: '';
    position: absolute;
    inset: -0.8rem;
  }
  .footer__social .list-social__link {
    display: flex;
    color: rgba(var(--color-foreground), var(--ink-muted));
    transition: color var(--motion-base) var(--diip-ease);
  }
  .footer__social .list-social__link:hover {
    color: rgb(var(--color-foreground));
  }
  .footer__social .list-social__link,
  .footer__social .svg-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    /* The height of the card logos beside them. */
    width: 2rem;
    height: 2rem;
  }
  .footer__social .svg-wrapper svg {
    width: 100%;
    height: 100%;
  }
  /* With the icons lifted out, an empty brand column shouldn't leave a gap. */
  .footer__brand:not(:has(.footer__tagline, .footer__follow-on-shop)) {
    display: contents;
  }

  /* ---- Nav columns --------------------------------------------------------
     A plain multi-column list, not boxed or bordered — the hairline under
     the whole __top row is the only divider this area needs. */
  .footer__nav {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-xl);
  }

  @media screen and (min-width: 480px) {
    .footer__nav {
      grid-template-columns: repeat(3, 1fr);
    }
  }

  .footer__nav-heading {
    margin: 0 0 var(--space-s);
    font-size: var(--text-caption);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* The Account and Policies titles: plain sentence case, close to their links. */
  .footer__account-heading {
    margin: 0 0 0.8rem;
    font-size: 1.6rem;
    line-height: 1.3;
    text-transform: none;
    letter-spacing: 0;
    color: rgb(var(--color-foreground));
  }

  .footer__nav-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-s);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .footer__nav-link {
    color: rgba(var(--color-foreground), var(--ink));
    text-decoration: none;
    font-size: var(--text-sm);
    transition: color var(--motion-base) var(--diip-ease);
  }
  .footer__nav-link:hover {
    color: rgb(var(--color-foreground));
    text-decoration: underline;
  }

  /* ---- Newsletter ---------------------------------------------------------
     A single-line field with the submit action as an inline arrow, matching
     the site's other minimal form fields rather than Dawn's boxed default. */
  .footer__newsletter-form {
    max-width: 34rem;
  }

  .footer__newsletter-field {
    display: flex;
    align-items: center;
    border-bottom: 0.1rem solid rgba(var(--color-foreground), 0.35);
    transition: border-color var(--motion-base) var(--diip-ease);
  }
  .footer__newsletter-field:focus-within {
    border-color: rgb(var(--color-foreground));
  }

  .footer__newsletter-input {
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    background: none;
    padding: var(--space-s) 0;
    font-family: inherit;
    font-size: var(--text-body);
    color: rgb(var(--color-foreground));
  }
  .footer__newsletter-input::placeholder {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .footer__newsletter-input:focus {
    outline: none;
  }

  .footer__newsletter-button {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.2rem;
    height: 3.2rem;
    border: 0;
    background: none;
    color: rgb(var(--color-foreground));
    cursor: pointer;
  }
  .footer__newsletter-button:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }
  .footer__newsletter-button .svg-wrapper svg {
    width: 1.8rem;
    height: 1.8rem;
  }

  .footer__newsletter-message {
    margin: var(--space-xs) 0 0;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* ---- Bottom row ---------------------------------------------------------
     Localization, payment icons and legal links share one row on desktop,
     wrapping to their own lines on a phone in that same order. */
  .footer__bottom {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-m);
    padding-top: var(--space-xl);
  }

  @media screen and (min-width: 750px) {
    .footer__bottom {
      flex-direction: row;
      align-items: center;
      justify-content: space-between;
    }
  }

  /* The 21+ notice: small print under the policy row. */
  .footer__age-notice {
    margin: 0;
    width: 100%;
    font-size: 1.1rem;
    line-height: 1.6;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .footer__localization .localization-form__select,
  .footer__localization .disclosure__button {
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .footer__payment {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-s);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .footer__payment-icon {
    display: block;
    height: 2rem;
    width: auto;
    border-radius: 0.3rem;
  }

  .footer__legal {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
  }

  .footer__copyright {
    margin: 0;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .footer__copyright a {
    color: inherit;
  }


  .footer__policies {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-m);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* The privacy choice is a switch, so it can't be mistaken for a page link. */
  .footer__privacy-control {
    margin-top: var(--space-m);
  }
  .footer__privacy-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-m);
  }
  /* "Learn more" opens the data sharing opt-out page. */
  .footer__privacy-more {
    display: inline-block;
    padding-block: 0.4rem;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
    text-decoration: underline;
    text-underline-offset: 0.3rem;
  }
  .footer__privacy-more:hover {
    color: rgb(var(--color-foreground));
  }
  .footer__privacy-question {
    margin: 0 0 var(--space-s);
    font-size: var(--text-caption);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .footer__choices {
    display: inline-flex;
    gap: 0.8rem;
  }
  /* Yes and No: two clearly labelled buttons; the chosen one is filled. */
  .footer__choice {
    min-width: 6.4rem;
    height: 3.4rem;
    padding: 0 1.8rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.6);
    border-radius: 999px;
    background: none;
    color: rgb(var(--color-foreground));
    font: inherit;
    font-size: var(--text-caption);
    font-weight: 700;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease), color var(--motion-fast) var(--diip-ease), border-color var(--motion-fast) var(--diip-ease);
  }
  .footer__choice:hover {
    border-color: rgb(var(--color-foreground));
  }
  .footer__choice[aria-checked='true'] {
    border-color: rgb(var(--color-foreground));
    background-color: rgb(var(--color-foreground));
    color: #404040;
  }
  .footer__choice:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.3rem;
  }
  /* Title row: "Your privacy choices" with a "Saved" status beside it. */
  .footer__privacy-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-s);
    margin-bottom: 0.8rem;
  }
  .footer__privacy-head .footer__privacy-title {
    margin: 0;
  }
  .footer__privacy-status {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: var(--text-caption);
    color: rgb(var(--color-foreground));
    opacity: 0;
    transition: opacity 0.5s ease;
  }
  .footer__privacy-status.is-visible {
    opacity: 1;
    transition-duration: 0.15s;
  }
  .footer__privacy-check {
    display: inline-flex;
    align-items: center;
  }
  /* The tick is the height of the lettering, centred on it (the same sizing as the
     check on the buy button). */
  .footer__privacy-check svg {
    width: auto;
    height: 0.88em;
    transform: translateY(-0.035em);
  }
  /* The x beside "Couldn't save"; the tick shows for "Saved". */
  .footer__privacy-x {
    display: none;
    align-items: center;
  }
  .footer__privacy-x svg {
    width: auto;
    height: 0.88em;
  }
  .footer__privacy-status.is-error .footer__privacy-check {
    display: none;
  }
  .footer__privacy-status.is-error .footer__privacy-x {
    display: inline-flex;
  }
  @media (prefers-reduced-motion: reduce) {
    .footer__privacy-status {
      transition: none;
    }
  }

  /* Padded to a 24px-tall target (the lettering stays the same size). */
  .footer__policy-link {
    display: inline-block;
    padding-block: 0.4rem;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
    text-decoration: none;
  }
  .footer__policy-link:hover {
    color: rgb(var(--color-foreground));
    text-decoration: underline;
  }

  /* Footer uncovered by the page scrolling away. */
  .footer-reveal.is-pinned {
    position: relative;
    height: var(--footer-height);
    clip-path: inset(0);
  }
  .footer-reveal.is-pinned > .footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
  }
  /* Scrolling is the reveal, so the footer's own entrance animation is off. */
  .footer-reveal.is-pinned .footer .footer__top > * {
    opacity: 1;
    transform: none;
    transition: none;
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .footer__top > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .footer__top > * {
      opacity: 1;
      transform: none;
    }
  }
/* END_SECTION:footer */

/* START_SECTION:header (INDEX:26) */
.header {
    position: relative;
  }
/* END_SECTION:header */

/* START_SECTION:how-it-works (INDEX:27) */
.how-it-works {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: calc(clamp(var(--space-3xl), 12vh, var(--space-6xl)) + var(--space-xl) * 0.8) 0;
  }

  /* This section only appears directly below the product carousel on the
     Nixodine collection page. Every card there carries 24px of padding
     below the buy button, so the button doesn't touch the carousel's own
     bottom divider line (see main-collection-product-grid.liquid) — that
     24px stacks on top of this section's own padding-top, making the gap
     above "Simple enough..." read 24px taller than the gap below the last
     step. Trimmed off padding-top here rather than off the card, since the
     card needs that space regardless of which one ends up last in the row. */
  .how-it-works {
    padding-top: calc(clamp(var(--space-3xl), 12vh, var(--space-6xl)) + var(--space-xl) * 0.8 - var(--space-m));
  }

  /* Doubled selector so the width cap survives the theme-wide full-bleed
     .page-width rule, which loads later. */
  .how-it-works .how-it-works__inner {
    max-width: 144rem;
    margin-inline: auto;
  }

  .how-it-works__eyebrow {
    margin: 0 0 var(--space-m);
    text-align: center;
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .how-it-works__heading {
    margin: 0 auto var(--space-3xl);
    max-width: 24ch;
    text-align: center;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  /* One column on a phone, a row from tablet up. A rule above each step rather
     than a box round it: it sets the steps apart without adding a frame. */
  .how-it-works__steps {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-xl) var(--space-l);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* On a phone the steps are a row you swipe sideways, not a tall stack, and each
     is a good deal narrower than the screen (so its picture is smaller, and the
     next step shows at the edge as a hint to swipe). The row bleeds out to the
     screen's edges and snaps step by step. */
  @media screen and (max-width: 749px) {
    .how-it-works__steps {
      display: flex;
      gap: var(--space-m);
      margin-inline: calc(var(--diip-gutter, 2.4rem) * -1);
      padding-inline: var(--diip-gutter, 2.4rem);
      overflow-x: auto;
      overscroll-behavior-x: contain;
      scroll-snap-type: x mandatory;
      scroll-padding-inline: var(--diip-gutter, 2.4rem);
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
    }
    .how-it-works__steps::-webkit-scrollbar {
      display: none;
    }
    .how-it-works__step {
      flex: 0 0 min(62%, 24rem);
      scroll-snap-align: start;
    }
  }

  /* Wide gutters rather than wide columns: the steps are short, and the white
     space between them is what makes the row read as three separate moments. The
     gap grows with the screen (10vw, from 40px up to 128px).

     The same value is the section's left and right padding, so the space is
     even all the way across: edge, column, gap, column, gap, column, edge. With
     a wider gap between the columns than beside them the row looks off-centre
     even when it is not. Phones keep the page's own gutter; the steps stack
     there and there is no gap to match. */
  @media screen and (min-width: 750px) {
    .how-it-works {
      --how-it-works-gap: clamp(var(--space-xl), 10vw, var(--space-7xl));
    }

    .how-it-works .how-it-works__inner {
      padding-inline: var(--how-it-works-gap);
    }

    .how-it-works__steps {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      column-gap: var(--how-it-works-gap);
    }
  }

  .how-it-works__step {
    padding-top: var(--space-m);
    border-top: 0.1rem solid var(--hairline);
  }

  /* With a picture, the picture leads and the hairline goes: a rule above an
     image would only frame it. The gap below it is the same one that separates
     the numeral from the title. */
  .how-it-works__step--media {
    padding-top: 0;
    border-top: 0;
  }

  .how-it-works__media {
    margin-bottom: var(--space-m);
    aspect-ratio: var(--how-it-works-ratio, 1 / 1);
    overflow: hidden;
    background-color: rgba(var(--color-foreground), 0.06);
  }

  .how-it-works__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* The numeral is the visual anchor; muted so it leads the eye without
     out-shouting the step's title. */
  .how-it-works__number {
    display: block;
    margin-bottom: var(--space-m);
    font-size: var(--text-display);
    line-height: 1;
    letter-spacing: -0.03em;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: rgba(var(--color-foreground), var(--ink-faint));
  }

  .how-it-works__title {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-lead);
    line-height: 1.2;
    letter-spacing: -0.01em;
    font-weight: 700;
  }

  .how-it-works__text {
    margin: 0;
    max-width: 36ch;
    font-size: var(--text-body);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
    text-wrap: pretty;
  }
/* END_SECTION:how-it-works */

/* START_SECTION:image-banner (INDEX:28) */
/* Cursor motion (an option on the section): the photo is held a little larger
     than its frame so it can drift toward the pointer without showing an edge.
     The script sets --cm-x and --cm-y; without it, or on touch, nothing moves. */
  .banner[data-cursor-motion].is-cursor-ready .banner__media > img,
  .banner[data-cursor-motion].is-cursor-ready .banner__media > video {
    transform: translate3d(var(--cm-x, 0px), var(--cm-y, 0px), 0) scale(1.08);
    will-change: transform;
  }
/* END_SECTION:image-banner */

/* START_SECTION:line-chooser (INDEX:30) */
/* Registered so it can be animated. A plain custom property is a string as
     far as transitions are concerned — it flips from one value to the next with
     no interpolation — which is why the clip radius used to snap while the fill
     eased. Declared as a length, it interpolates, and the clip that reads it
     eases with it.

     This is what lets the radius animate while the circle's CENTRE does not:
     the centre comes from --cta-x/--cta-y, which stay unregistered and so keep
     jumping straight to the cursor. Transitioning clip-path as a whole would
     have eased both and made the inversion lag the pointer. */
  @property --cta-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  /* Palette comes from the section's color scheme (like every other section),
     not hardcoded here, so the splash retunes with the rest of the site. */
  .line-chooser {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
  }

  .line-chooser__brand {
    margin: 0;
  }

  .line-chooser__panels {
    display: flex;
    width: 100%;
    height: 100vh;
    height: 100dvh;
  }

  .line-chooser__panel {
    position: relative;
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-xl) var(--space-l);
    color: inherit;
    text-decoration: none;
    overflow: hidden;
    transition: flex-grow var(--motion-base) var(--diip-ease),
      background-color var(--motion-base) var(--diip-ease),
      opacity var(--motion-base) var(--diip-ease);
  }

  .line-chooser__panel + .line-chooser__panel {
    border-left: 0.1rem solid var(--hairline);
  }

  .line-chooser__panel.line-chooser__panel--nolink {
    cursor: default;
  }

  /* Hover: grow the hovered panel, recede + dim the others. */
  @media (hover: hover) {
    .line-chooser__panels:hover .line-chooser__panel {
      flex-grow: 0.82;
    }
    .line-chooser__panels:hover .line-chooser__panel:hover {
      flex-grow: 1.5;
      background-color: rgba(var(--color-foreground), 0.05);
    }
  }

  .line-chooser__inner {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-m);
    text-align: center;
    transition: transform var(--motion-base) var(--diip-ease);
  }

  /* Hover media (video or image): fills the panel behind the content, fades in
     on hover, with a scrim so the (now white) logo and text stay readable. */
  .line-chooser__media {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0;
    transition: opacity var(--motion-base) var(--diip-ease);
  }
  .line-chooser__media video,
  .line-chooser__media img,
  .line-chooser__media svg {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  /* Placeholder reveal (no real photo yet): the same illustration the hero
     banners use, treated exactly like a real photo — filled to the panel and
     sitting under the same scrim. Swaps out once a hover image/video is set. */
  .line-chooser__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background-color: var(--scrim);
  }
  @media (hover: hover) {
    .line-chooser__panel--has-media:hover .line-chooser__media {
      opacity: 1;
    }
    .line-chooser__panel--has-media:hover {
      color: var(--ink-on-media);
    }
  }
  /* Keyboard: the same reveal on focus, so keyboard users get the image + white
     text, not just mouse users. */
  .line-chooser__panel--has-media:focus-within .line-chooser__media {
    opacity: 1;
  }
  .line-chooser__panel--has-media:focus-within {
    color: var(--ink-on-media);
  }

  @media (hover: hover) {
    .line-chooser__panel:hover .line-chooser__inner {
      transform: scale(1.06);
    }
  }

  .line-chooser__logo {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* Both logos share one height so the content below them lines up on both
     panels; width is automatic (they have different aspect ratios). max-width
     is a safety so the wide Nootropic wordmark can't overflow a panel. */
  .line-chooser__logo svg {
    height: clamp(6rem, 8vw, 9rem);
    width: auto;
    max-width: 40vw;
    display: block;
  }

  /* The line name reads as a small title (our established .t-title style),
     not an uppercase label. */
  .line-chooser__title {
    margin: 0;
    font-size: var(--text-title);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.2;
    color: inherit;
  }

  .line-chooser__desc {
    /* Pull the phrase up toward the title (the stack otherwise sits on the
       full inner gap). calc() so the custom property actually negates. */
    margin: calc(var(--space-s) * -1) 0 0;
    max-width: 32rem;
    font-size: var(--text-body);
    line-height: 1.6;
    letter-spacing: -0.01em;
    color: inherit;
  }

  /* Ink is defined as a pair so the button can invert wholesale. At rest the
     panel is pale, so the button is dark on nothing; once the hover image is
     up the panel carries a 50% scrim, so the backdrop is reliably dark and the
     button flips to light. That's what makes it read correctly over any
     photograph without measuring the image itself. */
  .line-chooser__cta {
    --cta-ink: rgb(var(--color-foreground));
    --cta-ink-inv: rgb(var(--color-background));
    /* Circle geometry, driven from JS. One diameter feeds both the painted
       circle and the clip on the inverted label, so they cannot disagree. */
    --cta-x: 50%;
    --cta-y: 50%;
    --cta-d: 0px;

    /* The circle is painted into the button's own background rather than being
       a transformed child. A child element cannot be clipped to a rounded
       parent without a seam: it rasterises on its own layer, the parent's
       radius clips the composite, and the two antialiased edges disagree —
       a hairline arc down the left and right curves. A background gradient has
       no layer of its own, so there is one edge and one antialiasing pass.
       The 99% stop keeps the circle's own edge smooth; a stop at exactly 100%
       stair-steps. */
    background-image: radial-gradient(
      circle calc(var(--cta-d) / 2) at var(--cta-x) var(--cta-y),
      var(--cta-ink) 0 99%,
      transparent 100%
    );

    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    margin-top: var(--space-xs);
    padding: var(--space-xs) var(--space-m);
    min-height: var(--tap-target);
    border: 0.1rem solid var(--cta-ink);
    border-radius: var(--radius-pill);
    color: var(--cta-ink);
    font-size: var(--text-sm);
    letter-spacing: -0.01em;
    font-weight: 700;
    opacity: 0;
    /* --cta-d is animated here rather than on the clipped layer, because it's
       the element JS writes it to and the one both the fill and the clip
       inherit it from — animate it once at the source and the two can't
       disagree. */
    transition: opacity var(--motion-base) var(--diip-ease),
      --cta-d var(--motion-base) var(--diip-ease);
  }

  .line-chooser__panel--has-media:hover .line-chooser__cta,
  .line-chooser__panel--has-media:focus-within .line-chooser__cta {
    --cta-ink: var(--ink-on-media);
    --cta-ink-inv: #1c1c1c;
  }

  /* The circle. Sized and positioned entirely by the variables above, so JS
     only ever writes three numbers and never touches layout. */
  /* Fixed box, scaled — it used to animate width and height. Transform is
     compositor-driven, so growing the circle no longer runs layout on every
     frame of a hover; width/height animation does, and this fires on mousemove.

     The box is the resting diameter. A click grows the circle past the pill's
     far corner, which is simply a scale above 1 — nothing needs to resize. */

  .line-chooser__cta-text {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    white-space: nowrap;
  }

  /* The long arrow replaces the → character. A glyph would have been simpler,
     but → is drawn by whichever font is resolved and its weight and length vary
     with that — this one is a fixed drawing that matches the Light icons in the
     header.

     Sized by height against the label's type, with width following the aspect
     ratio, so the arrow lengthens or shortens with the text rather than being
     pinned to a px measurement. Height is set below cap height deliberately: an
     arrow matched to cap height reads heavier than the letters beside it,
     because it's a solid horizontal bar where they're mostly vertical strokes.

     The viewBox is cropped to the ink, so the shaft touches both edges — there
     is no built-in padding, and the gap on .line-chooser__cta-text is the only
     space between the label and the arrow. */
  .line-chooser__arrow {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
  }

  .line-chooser__arrow svg {
    height: 0.6em;
    width: calc(0.6em * 1.788);
  }

  /* The inverted copy, clipped to exactly the circle.

     It has to span the whole button rather than sit where the label sits:
     clip-path resolves against the clipped element's OWN box, so an offset
     layer would shift the clip by that same offset and the inversion would
     drift out of the circle. Spanning the button gives it the identical
     coordinate space the fill is positioned in, so the two stay locked
     together. Padding matches the button's so the duplicate text lands exactly
     over the real one. */
  .line-chooser__cta-text--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-m);
    color: var(--cta-ink-inv);
    /* No transition on clip-path itself, deliberately. Transitioning it eases
       the WHOLE shape, centre included, so on mousemove the inverted region
       drifted toward the pointer while the fill jumped there instantly — the
       colour boundary visibly lagged the circle.

       Instead --cta-d is animated (registered below, so it can be), and the
       clip reads it. The radius eases; the centre, which comes from separate
       untransitioned properties, tracks the cursor immediately — which is what
       the fill does too. */
    clip-path: circle(calc(var(--cta-d) / 2) at var(--cta-x) var(--cta-y));
  }

  /* No cursor to track, and no reason to animate for someone who asked not to:
     the button stays a plain outline. */
  @media (hover: none), (prefers-reduced-motion: reduce) {
    .line-chooser__cta {
      background-image: none;
    }
    .line-chooser__cta-text--over {
      display: none;
    }
  }

  @media (hover: hover) {
    .line-chooser__panel:hover .line-chooser__cta {
      opacity: 1;
    }
  }
  .line-chooser__panel:focus-within .line-chooser__cta {
    opacity: 1;
  }
  @media (hover: none) {
    .line-chooser__cta {
      opacity: 1;
    }
  }

  /* Load: logos ease in. */
  @media (prefers-reduced-motion: no-preference) {
    .line-chooser__inner {
      animation: line-chooser-in var(--motion-slow) var(--diip-ease) both;
    }
    .line-chooser__panel:nth-child(2) .line-chooser__inner {
      animation-delay: calc(var(--motion-stagger) * 1.5);
    }
    @keyframes line-chooser-in {
      from {
        opacity: 0;
        transform: translateY(1.6rem);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }
  }

  @media screen and (max-width: 749px) {
    .line-chooser__panels {
      flex-direction: column;
      height: auto;
    }
    .line-chooser__panel {
      min-height: 50vh;
      min-height: 50dvh;
    }
    .line-chooser__panel + .line-chooser__panel {
      border-left: 0;
      border-top: 0.1rem solid var(--hairline);
    }
    .line-chooser__cta {
      opacity: 1;
    }
    /* No hover on touch: show the image as a static background, white text on. */
    .line-chooser__panel--has-media .line-chooser__media {
      opacity: 1;
    }
    .line-chooser__panel--has-media {
      color: var(--ink-on-media);
    }
    /* The photo is up behind the text here, so the button has to be light too: at
       rest its ink is the dark foreground colour, which vanished on the photo. */
    .line-chooser__panel--has-media .line-chooser__cta {
      --cta-ink: var(--ink-on-media);
      --cta-ink-inv: #1c1c1c;
    }
  }
/* END_SECTION:line-chooser */

/* START_SECTION:logo-marquee (INDEX:31) */
/* Bottom hairline only, closing off the strip before whatever comes next.
     No top border to match: the product grid above it (in the carousel
     layout) already draws its own bottom frame line, and a second one here
     would sit right against it and read as one thick, doubled rule. */
  .logo-marquee.logo-marquee {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    overflow: hidden;
    padding: var(--space-xl) 0;
    border-bottom: 0.1rem solid var(--hairline);
  }

  .logo-marquee__heading {
    margin: 0 0 var(--space-l);
    text-align: center;
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .logo-marquee__track {
    display: flex;
    width: max-content;
    animation: logo-marquee-scroll var(--marquee-speed, 30s) linear infinite;
  }

  .logo-marquee__group {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .logo-marquee__item {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    padding-inline: var(--space-2xl);
  }

  .logo-marquee__link {
    display: block;
    line-height: 0;
  }

  .logo-marquee__logo {
    display: block;
    width: auto;
    height: 3.2rem;
    max-width: 14rem;
    object-fit: contain;
    filter: grayscale(1);
    opacity: 0.5;
    transition: filter var(--motion-base) var(--diip-ease), opacity var(--motion-base) var(--diip-ease);
  }

  .logo-marquee__item:hover .logo-marquee__logo,
  .logo-marquee__link:focus-visible .logo-marquee__logo {
    filter: grayscale(0);
    opacity: 1;
  }

  /* Placeholder for a block with no logo uploaded yet — keeps the row's
     rhythm intact in the editor instead of leaving a gap. */
  .logo-marquee__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 3.2rem;
    padding-inline: var(--space-m);
    border: 0.1rem dashed rgba(var(--color-foreground), 0.25);
    border-radius: var(--radius-s);
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
    white-space: nowrap;
  }

  .logo-marquee:hover .logo-marquee__track {
    animation-play-state: paused;
  }

  @media (prefers-reduced-motion: reduce) {
    .logo-marquee__track {
      animation: none;
      justify-content: center;
      flex-wrap: wrap;
      width: 100%;
    }
    .logo-marquee__group:not(:first-child) {
      display: none;
    }
  }

  @keyframes logo-marquee-scroll {
    from {
      transform: translateX(0);
    }
    to {
      transform: translateX(-25%);
    }
  }
/* END_SECTION:logo-marquee */

/* START_SECTION:made-in-usa (INDEX:32) */
.made-in-usa {
    position: relative;
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-xl), 5vh, var(--space-3xl)) 0;
  }

  .made-in-usa .made-in-usa__inner {
    display: grid;
    grid-template-columns: 1fr;
    align-items: center;
    gap: var(--space-l) var(--space-2xl);
  }

  /* The flag-filled lettering. Bold, large and tightly set: the flag only reads
     through thick strokes, so weight and size are doing real work here. */
  .made-in-usa__flag-text {
    margin: 0;
    font-family: var(--font-heading-family);
    font-size: clamp(4.8rem, 8.5vw, 10rem);
    /* Narrow enough that it breaks as "MADE IN / THE USA"; the flag needs the
       height of two lines to show its stripes. */
    max-width: 5.6em;
    font-weight: 700;
    line-height: 0.92;
    letter-spacing: -0.035em;
    text-transform: uppercase;
    text-wrap: balance;
    background-image: var(--flag-image);
    background-size: cover;
    /* The photo's blue field is its top-left; the stripes are its lower half.
       Sitting low in the frame puts more of the red and white behind both
       lines. (Scaling the photo smaller than the lettering is not an option:
       it would leave the edges of the letters with no fill.) */
    background-position: center 82%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    /* Tuned for a light background, where the photo's white stripes would
       otherwise fade into the page: a slightly deeper photo. On a dark
       background a brightness lift of ~1.3 reads better. */
    filter: brightness(0.88) contrast(1.12) saturate(1.1);
  }

  @media (forced-colors: active) {
    .made-in-usa__flag-text {
      background: none;
      color: CanvasText;
      -webkit-text-fill-color: currentColor;
    }
  }

  .made-in-usa__copy {
    max-width: 44rem;
  }

  .made-in-usa__heading {
    margin: 0 0 var(--space-s);
    font-size: var(--text-heading);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  .made-in-usa__body {
    font-size: var(--text-body);
    line-height: 1.55;
    /* Full-strength ink, not the dimmed body ink: on a mid-tone background the
       dimmed value drops below the 4.5:1 minimum for small text. */
    color: rgb(var(--color-foreground));
  }
  .made-in-usa__body > *:first-child { margin-top: 0; }
  .made-in-usa__body > *:last-child { margin-bottom: 0; }

  /* Side by side from tablet up, with a hairline between the two. */
  @media screen and (min-width: 750px) {
    .made-in-usa .made-in-usa__inner {
      grid-template-columns: auto auto;
      justify-content: center;
    }

    .made-in-usa__copy {
      padding-left: var(--space-2xl);
      border-left: 0.1rem solid rgba(var(--color-foreground), 0.2);
    }
  }

  /* Tablet: the desktop banner with the desktop spacing (the gap before the
     divider and after it are the same as on a desktop), only the copy is held a bit
     narrower, so the lettering, the divider and the copy together are narrower than
     the content and sit in the middle of it. */
  @media screen and (min-width: 750px) and (max-width: 989px) {
    .made-in-usa__copy {
      max-width: 30rem;
    }
  }

  /* Phone only (under 750px): the lettering is scaled until its wider line
     is exactly as wide as the content, edge to edge between the page's side
     padding (the script at the end of this file sets the size), as two lines,
     "MADE IN" over "THE USA", with the heading and the line stacked under it.
     A tablet and a desktop keep the banner as it was: the lettering beside the copy. */
  @media screen and (max-width: 749px) {
    .made-in-usa .made-in-usa__inner {
      grid-template-columns: 1fr;
      justify-content: stretch;
    }
    .made-in-usa__flag-text {
      font-size: 7vw;
      width: 100%;
      max-width: none;
    }
    .made-in-usa__flag-line {
      display: block;
      width: max-content;
    }
    .made-in-usa__copy {
      padding-left: 0;
      border-left: 0;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .made-in-usa__inner > *,
    [data-reveal] .made-in-usa__copy > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    /* The copy block fades as one; only its children are staggered. */
    [data-reveal] .made-in-usa__copy {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .made-in-usa__inner > *,
    [data-reveal].is-visible .made-in-usa__copy > * {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .made-in-usa__heading { transition-delay: var(--motion-stagger); }
    [data-reveal].is-visible .made-in-usa__body { transition-delay: calc(var(--motion-stagger) * 2); }
  }
/* END_SECTION:made-in-usa */

/* START_SECTION:main-cart-footer (INDEX:39) */
#main-cart-footer .page-width {
    max-width: 78rem;
  }

  /* One column, the width of the lines above it: the total sits label-left,
     amount-right, and the buttons run the full width. */
  #main-cart-footer .cart__footer > * {
    width: 100%;
  }
  #main-cart-footer .totals {
    justify-content: space-between;
  }
  #main-cart-footer .tax-note {
    margin: 1.2rem 0 2.4rem;
    text-align: left;
  }
  #main-cart-footer .cart__checkout-button {
    max-width: none;
  }

  #checkout[hidden],
  #CartPage-CheckZip[hidden] {
    display: none !important;
  }
  /* The ZIP steps sit in a block that is the width of the lines above it, with
     the same space under it as between cards. */
  #main-cart-footer .cart-drawer-zip {
    margin: 0 0 1.6rem;
  }
/* END_SECTION:main-cart-footer */

/* START_SECTION:main-cart-items (INDEX:40) */
/* The cart page is one centred column, the width of a mini cart's contents
     given room to breathe. */
  .cart-page .page-width {
    max-width: 78rem;
  }

  /* "Add more": a button, not a text link: an outlined pill like the other secondary
     buttons, 48px tall, a plus before the words. */
  .cart-add-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.8rem;
    min-height: var(--tap-target);
    padding: 0 2rem;
    box-sizing: border-box;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    color: rgb(var(--color-foreground));
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
  }
  /* The same cursor-following circle as the product cards' secondary buttons
     (card-buy.liquid): transparent at rest; on hover a circle of the foreground
     colour follows the pointer, painted into the button's own background, with an
     inverted copy of the label clipped to exactly that circle. */
  @property --cam-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }
  .cart-add-more {
    position: relative;
    background-image: radial-gradient(
      circle calc(var(--cam-d) / 2) at var(--cam-x) var(--cam-y),
      rgb(var(--color-foreground)) 0 99%,
      transparent 100%
    );
    --cam-x: 50%;
    --cam-y: 50%;
    --cam-d: 0px;
    transition: --cam-d var(--motion-base) var(--diip-ease), border-color var(--motion-fast) var(--diip-ease);
  }
  .cart-add-more:hover {
    border-color: rgba(var(--color-foreground), 0.5);
    text-decoration: none;
  }
  .cart-add-more:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }
  .cart-add-more__label {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 0.8rem;
  }
  .cart-add-more__label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-background));
    clip-path: circle(calc(var(--cam-d) / 2) at var(--cam-x) var(--cam-y));
    pointer-events: none;
  }
  /* The empty cart: the message and the two shop buttons sit in the middle of the
     section, both ways. The section fills the screen below the header (the page is a whole
     screen tall, assets/brand.css), so this centres them in what is visible. */
  cart-items.cart-page.is-empty {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: calc(100vh - var(--header-height, 6.4rem));
    min-height: calc(100svh - var(--header-height, 6.4rem));
    box-sizing: border-box;
  }
  cart-items.cart-page.is-empty .page-width {
    width: 100%;
  }
  cart-items.cart-page.is-empty .cart__warnings {
    padding: 0;
    margin: 0;
    text-align: center;
  }
  .cart-empty-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.2rem;
  }
  .cart-empty-actions .cart-add-more {
    padding: 0 3rem;
    font-size: 1.5rem;
  }
  /* In the cart page header on a phone the two buttons are a row of their own under
     the title, a half each, instead of stacking one above the other. */
  /* Everywhere on a phone (the empty cart page and the empty drawer too) the pair is
     two equal halves of the width there is, never wider than that. */
  @media screen and (max-width: 749px) {
    .cart-empty-actions {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 0.8rem;
      width: 100%;
      max-width: 34rem;
      margin-inline: auto;
    }
    .cart-empty-actions .cart-add-more {
      width: 100%;
      padding: 0 1.2rem;
    }
  }
  @media screen and (max-width: 749px) {
    .title-wrapper-with-link .cart-empty-actions {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 0.8rem;
      width: 100%;
      margin-top: 1.6rem;
    }
    .title-wrapper-with-link .cart-empty-actions .cart-add-more {
      width: 100%;
      padding: 0 1.2rem;
    }
  }
  .cart-add-more__icon {
    display: inline-flex;
  }
  .cart-add-more__icon svg {
    display: block;
    width: 1.2rem;
    height: 1.2rem;
  }
  .cart-item__unavailable {
    display: inline-flex;
    align-self: flex-start;
    margin: 0;
    padding: 0.2rem 0.9rem;
    border-radius: 999px;
    background: #fdd8d4;
    color: #7a1b13;
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1.4;
  }
/* END_SECTION:main-cart-items */

/* START_SECTION:main-collection-product-grid (INDEX:42) */
/* No fading of the cards themselves in the carousel: the edges of the row do
     it (see .product-carousel__viewport below). The grid as a whole still fades
     in on load. What the theme adds to a revealed card is switched off here:
     its 0.8s opacity transition (brand.css) and Dawn's fade-in animation, which
     restarts whenever the loop moves a card from one end of the row to the
     other, and its hidden-until-revealed opacity, so a card sliding in from the
     side is never waiting on that. */
  .product-grid.product-grid--carousel > .grid__item.scroll-trigger {
    opacity: 1;
    transition: none;
    animation: none;
  }

  /* One row that scrolls sideways. The mechanics — arrows, end states, resize —
     come from Dawn's slider-component; only the sizing and the arrows' look are
     ours. */
  .product-carousel {
    display: block;
    position: relative;
  }

  .product-carousel__viewport {
    position: relative;
    overflow-x: auto;
    /* Hidden, not auto: the cards slide up into place on reveal, which pushes
       their bottom edge past this box, and an auto axis would turn that into a
       second, vertical scroll area trapping the wheel. */
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;

    /* Runs out to the true edges of the page, with the page's side margin put
       back as padding, so at rest the cards sit exactly where they always did.
       The margin is where the row fades: the mask is clear across the cards and
       fades to nothing over the margin at each end, so a card sliding out (or
       in) fades through the empty margin at the screen edge, while cards at
       rest are never touched. A mask, not an overlay, so it needs no colour to
       match the section behind it. Same --diip-gutter as the frame lines, so
       it follows the phone and desktop widths on its own. */
    margin-inline: calc(-1 * var(--diip-gutter));
    padding-inline: var(--diip-gutter);
    scroll-padding-inline: var(--diip-gutter);
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--diip-gutter), #000 calc(100% - var(--diip-gutter)), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 var(--diip-gutter), #000 calc(100% - var(--diip-gutter)), transparent 100%);
  }
  .product-carousel__viewport::-webkit-scrollbar {
    display: none;
  }

  /* Frames the row: a hairline right above the first card and another right
     below the last one, so the vertical lines between the cards (which
     already run the full height of the row) meet both of them square rather
     than stopping short in open space. Full-bleed, to true page edges, to
     match the marquee and the filter bar's own divider above it.

     Neither line is drawn on .product-carousel__viewport, even though that's
     where the row visually starts and ends: it has overflow-x: auto (it's the
     thing that scrolls), and a browser clips an element's OWN pseudo-elements
     to its OWN box the same as it clips real content — an absolutely
     positioned line extending past that box's edges via a negative inset gets
     silently cut back to it, no matter what left/right compute to. Tried that
     first; the lines came out the same width as the (gutter-width) cards, not
     full-bleed, because of exactly this. Drawn instead on .product-carousel
     itself, which scrolls/clips nothing: top: 0 lands exactly where the
     viewport (and so the cards, and the dividers between them) begins, once
     the count/arrows below are pulled out of this element's normal flow (see
     next); bottom: 0 already lined up with the viewport's own bottom, since
     the viewport is the last thing left in flow. pointer-events: none on
     both, out of the way of dragging the carousel. */
  .product-carousel {
    position: relative;
  }

  .product-carousel::before,
  .product-carousel::after {
    content: '';
    position: absolute;
    left: calc(-1 * var(--diip-gutter));
    right: calc(-1 * var(--diip-gutter));
    border-top: 0.1rem solid var(--hairline);
    pointer-events: none;
  }

  .product-carousel::before {
    top: 0;
  }

  .product-carousel::after {
    bottom: 0;
  }

  /* Nixodine only, desktop only. Pulls the count and arrows out of their own
     row and up onto the filter bar's, right-aligned against the same edge the
     chips stop short of. A CSS-only move rather than an actual markup change:
     the filter chips live in a block the filter script patches in place on a
     click (so your scroll position and focus survive it), and the count/
     arrows live in a block that gets rebuilt wholesale on every filter change
     along with the product cards — merging them for real would mean untangling
     that, which is a bigger, riskier change than this page needed today.

     The cost of doing it this way: the top value below is measured against
     the current distance from .product-carousel's own top edge up to the
     chips (not calculated from it — CSS has no way to ask a sibling how tall
     it rendered), so it drifts whenever that distance changes for an
     unrelated reason. It already has once: removing the filter bar's own
     divider line (see facets.liquid) closed a 24px gap that used to sit
     between the filter bar and this element, which pulled .product-carousel's
     own top edge — and so this element's whole positioning context — 24px
     closer to the chips than when this was first measured, throwing the
     alignment off by exactly that much. If a future flavour or strength
     pushes the chips onto a second line, or anything else changes the
     vertical space between the filter bar and here, expect to retune this
     again. */
  @media screen and (min-width: 750px) {
    #MainContent[data-template-suffix='nixodine'] .product-carousel__controls {
      position: absolute;
      top: -7.2rem;
      right: 0;
      left: auto;
      margin-bottom: 0;
    }

    /* The "N products" text next to the arrows — redundant once the arrows
       sit on the filter bar's own row, since the bar has no count of its own
       to confuse it with. The persistent, visually hidden count in the filter
       bar (facets.liquid) is unrelated and still announces changes to screen
       readers either way — this one was always aria-hidden, decorative only. */
    #MainContent[data-template-suffix='nixodine'] .product-carousel__count {
      display: none;
    }
  }

  /* The gap between cards matches the row's own left/right padding
     (var(--diip-gutter)) rather than the space scale, so the row reads as
     evenly spaced all the way across — edge, card, gap, card, gap, card, edge
     — instead of a narrower gap between cards than beside them. diip-gutter
     is already responsive on its own (2.4rem below 990px, 4rem from 990px
     up), so this needs no breakpoints of its own; --cols still does. */
  .product-grid.product-grid--carousel {
    --carousel-gap: var(--diip-gutter);
    --cols: var(--cols-mobile);
    display: flex;
    flex-wrap: nowrap;
    column-gap: var(--carousel-gap);
    margin: 0;
    padding: 0;
  }

  @media screen and (min-width: 750px) {
    .product-grid.product-grid--carousel {
      --cols: var(--cols-tablet);
    }
  }

  @media screen and (min-width: 990px) {
    .product-grid.product-grid--carousel {
      --cols: var(--cols-desktop);
    }
  }

  /* Each card is exactly one Nth of the visible row, gaps included, so N fit
     with none clipped and the next one starts at the edge. Specificity is
     chosen to beat Dawn's per-breakpoint .grid--N-col rules, which set width and
     max-width on the same element. */
  .product-grid.product-grid--carousel > .grid__item {
    flex: 0 0 calc((100% - (var(--cols) - 1) * var(--carousel-gap)) / var(--cols));
    width: calc((100% - (var(--cols) - 1) * var(--carousel-gap)) / var(--cols));
    max-width: none;
    scroll-snap-align: start;
    /* Room above the photo and below the buy button, now that the viewport
       draws a hairline right at the card's own top and bottom edge — without
       this the line sat flush against the photo and the button. The vertical
       dividers between cards still reach both lines exactly, since they run
       the full height of this (now taller) box, not just the content inside
       it. */
    padding-block: var(--space-m);
  }

  /* A hairline between neighbouring products, centred in the gap so it sits the
     same distance from both. Drawn from the item's own edge into the gap, so it
     takes no room and moves nothing; the item is as tall as the row, so the line
     runs the full height. None before the first item or after the last. */
  .product-grid.product-grid--carousel > .grid__item {
    position: relative;
  }

  .product-grid.product-grid--carousel > .grid__item + .grid__item::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(var(--carousel-gap) / -2);
    border-left: 0.1rem solid var(--hairline);
    pointer-events: none;
  }

  /* Count on the left, arrows on the right, one row. The row keeps its height
     even when the arrows go, so the count never jumps. */
  .product-carousel__controls {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--space-m);
    min-height: var(--tap-target);
    /* --space-m (24px), matching the padding on the other side of the top
       line (below it, before the photo) and the gap below the row at the
       bottom line — was --space-s (16px), uneven next to those. */
    margin-bottom: var(--space-m);
  }

  /* Set as a title, not as small print: it heads the row of products, so it
     takes the same treatment as the flavour names — lead size, bold, full ink,
     tight tracking — rather than the muted caption the count used to be. */
  .product-carousel__count {
    margin: 0;
    font-size: var(--text-lead);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: rgb(var(--color-foreground));
  }

  /* Mobile shows its own count beside the Filter button. */
  @media screen and (max-width: 749px) {
    .product-carousel__count {
      display: none;
    }
  }

  /* Straight after the count, not pushed to the far edge. On a phone the count
     is hidden, so there they go back to the right, where a lone pair of arrows
     belongs. */
  .product-carousel__buttons {
    display: flex;
    gap: var(--space-xs);
  }

  @media screen and (max-width: 749px) {
    .product-carousel__buttons {
      margin-left: auto;
    }
  }

  /* When every product already fits, both arrows are disabled and there is
     nothing to press. Only the arrows go — removed rather than left as two dead
     buttons — the row and the count stay. */
  .product-carousel:not([data-autoplay]):has(button[name='previous'][disabled]):has(button[name='next'][disabled]) .product-carousel__buttons {
    display: none;
  }

  /* A carousel that goes round has no ends, so its arrows are never dimmed or
     hidden, whatever state Dawn's slider briefly leaves them in as the row
     wraps. */
  .product-carousel[data-autoplay] .product-carousel__button[disabled] {
    opacity: 1;
    cursor: pointer;
  }

  .product-carousel__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target);
    height: var(--tap-target);
    padding: 0;
    border: 0.1rem solid rgba(var(--color-foreground), 0.25);
    border-radius: 50%;
    background: none;
    color: rgb(var(--color-foreground));
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease),
      color var(--motion-fast) var(--diip-ease),
      border-color var(--motion-fast) var(--diip-ease);
  }

  .product-carousel__button .svg-wrapper {
    display: inline-flex;
    width: 2rem;
    height: 2rem;
  }

  .product-carousel__button svg {
    width: 100%;
    height: 100%;
  }

  /* One glyph, mirrored, so the pair can't drift apart. */
  .product-carousel__button--prev svg {
    transform: scaleX(-1);
  }

  .product-carousel__button:hover:not([disabled]) {
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    border-color: rgb(var(--color-foreground));
  }

  .product-carousel__button[disabled] {
    opacity: 0.35;
    cursor: default;
  }
/* END_SECTION:main-collection-product-grid */

/* START_SECTION:main-product (INDEX:49) */
.product-disclaimer {
    margin-top: var(--space-m);
    padding-top: var(--space-s);
    border-top: 0.1rem solid var(--hairline);
    font-size: var(--text-caption);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .product-disclaimer p {
    margin: 0 0 0.8rem;
  }

  .product-disclaimer p:last-child {
    margin-bottom: 0;
  }

  .product-disclaimer strong {
    font-weight: 600;
  }
/* END_SECTION:main-product */

/* START_SECTION:maintenance (INDEX:53) */
.maintenance {
    flex: 1 0 auto;
    display: flex;
    min-height: 100vh;
    min-height: 100svh;
    padding: var(--space-xl) var(--diip-gutter, 2.4rem);
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
  }
  .maintenance__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xl);
    width: 100%;
    max-width: 56rem;
    margin: 0 auto;
    text-align: center;
  }
  .maintenance__logo-img {
    display: block;
    width: 14rem;
    height: auto;
  }
  @media screen and (min-width: 750px) {
    .maintenance__logo-img {
      width: 18rem;
    }
  }
  .maintenance__logo-text {
    font-size: var(--text-title);
    font-weight: 700;
    color: rgb(var(--color-foreground));
  }
  .maintenance__body {
    width: 100%;
  }
  .maintenance__eyebrow {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-sm);
    font-weight: 600;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .maintenance__heading {
    margin: 0;
    font-size: var(--text-hero);
    font-weight: 700;
    line-height: 1.04;
    letter-spacing: -0.03em;
    color: rgb(var(--color-foreground));
    text-wrap: balance;
  }
  .maintenance__text {
    max-width: 44rem;
    margin: var(--space-m) auto 0;
    font-size: var(--text-lead);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
    text-wrap: balance;
  }

  .maintenance__form {
    max-width: 44rem;
    margin: var(--space-xl) auto 0;
  }
  .maintenance__field,
  .maintenance__password-row {
    display: flex;
    gap: var(--space-xs);
  }
  .maintenance__input {
    flex: 1 1 auto;
    min-width: 0;
    height: 4.8rem;
    padding: 0 var(--space-m);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: transparent;
    font: inherit;
    font-size: var(--text-body);
    color: rgb(var(--color-foreground));
  }
  .maintenance__input::placeholder {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .maintenance__input:focus {
    outline: none;
    border-color: rgb(var(--color-foreground));
  }
  .maintenance__input:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .maintenance__button {
    flex: none;
    height: 4.8rem;
    padding: 0 var(--space-l);
    border: 0;
    border-radius: var(--radius-pill);
    background: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    font: inherit;
    font-size: var(--text-body);
    font-weight: 600;
    cursor: pointer;
  }
  .maintenance__button:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .maintenance__button--quiet {
    background: transparent;
    color: rgb(var(--color-foreground));
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
  }
  .maintenance__thanks {
    margin: 0;
    font-size: var(--text-lead);
    font-weight: 600;
    color: rgb(var(--color-foreground));
  }
  .maintenance__error {
    margin: var(--space-xs) 0 0;
    font-size: var(--text-sm);
    color: rgb(var(--color-foreground));
  }

  .maintenance__foot {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-m);
    width: 100%;
  }
  .maintenance__social {
    display: flex;
    gap: var(--space-m);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .maintenance__social-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4.4rem;
    height: 4.4rem;
    color: rgba(var(--color-foreground), var(--ink-muted));
    transition: color var(--motion-base) var(--diip-ease);
  }
  .maintenance__social-link:hover,
  .maintenance__social-link:focus-visible {
    color: rgb(var(--color-foreground));
  }
  .maintenance__social-link .svg-wrapper,
  .maintenance__social-link svg {
    width: 2rem;
    height: 2rem;
  }
  .maintenance__password {
    width: 100%;
    max-width: 32rem;
  }
  .maintenance__summary {
    display: inline-block;
    padding: var(--space-xs) var(--space-s);
    font-size: var(--text-sm);
    color: rgba(var(--color-foreground), var(--ink-muted));
    cursor: pointer;
    list-style: none;
  }
  .maintenance__summary::-webkit-details-marker {
    display: none;
  }
  .maintenance__summary:hover,
  .maintenance__summary:focus-visible {
    color: rgb(var(--color-foreground));
  }
  .maintenance__details[open] .maintenance__summary {
    margin-bottom: var(--space-xs);
  }

  @media screen and (max-width: 749px) {
    .maintenance__field {
      flex-direction: column;
    }
    .maintenance__button {
      width: 100%;
    }
  }
/* END_SECTION:maintenance */

/* START_SECTION:marquee (INDEX:54) */
/* Doubled class: Dawn sets every colour scheme's text to 75% opacity, from a
     rule that loads after this one, so a single class got the section's own
     full-strength colour overridden and the text read as grey. */
  .marquee.marquee {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    overflow: hidden;
    padding: var(--space-s) 0;
    border-block: 0.1rem solid var(--hairline);
  }

  .marquee__track {
    display: flex;
    width: max-content;
    animation: marquee-scroll var(--marquee-speed, var(--motion-slow)) linear infinite;
  }

  .marquee__group {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* The gap on the phrase's side of the divider and the padding on the far side
     of it (this item's plus the next item's) add up to the same 32px, so the line
     sits exactly halfway between two phrases. */
  .marquee__item {
    display: flex;
    align-items: center;
    gap: var(--space-l);
    padding-inline: var(--space-s);
  }

  /* Body size: the band is a line of small print-scale statements, not a
     headline, so it sits quietly above the grid instead of competing with it. */
  .marquee__text {
    font-size: var(--text-body);
    font-weight: 700;
    letter-spacing: -0.01em;
    text-transform: none;
    white-space: nowrap;
  }

  /* A vertical hairline between phrases. Faint enough to separate without
     competing with the text; the block is only a line, with no glyph in it. */
  .marquee__divider {
    display: block;
    flex: 0 0 auto;
    width: 0;
    height: var(--space-s);
    border-left: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
  }

  .marquee:hover .marquee__track {
    animation-play-state: paused;
  }

  @media (prefers-reduced-motion: reduce) {
    .marquee__track {
      animation: none;
      justify-content: center;
    }
    .marquee__group:not(:first-child) {
      display: none;
    }
  }

  @keyframes marquee-scroll {
    from {
      transform: translateX(0);
    }
    to {
      transform: translateX(-25%);
    }
  }
/* END_SECTION:marquee */

/* START_SECTION:product-showcase (INDEX:63) */
/* Registered so it can be animated. An unregistered custom property is a
     string to the transition machinery — it flips between values with no
     interpolation — so the clip radius would snap while the fill eased.
     Declared as a length it interpolates, and the clip that reads it eases too.

     This is also what keeps the radius and the centre on different timings:
     --cta-x/--cta-y stay unregistered, so they jump straight to the cursor. */
  @property --cta-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  @property --sub-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  /* Stacking panels: the section wrapper pins to the top of the viewport and
     whatever follows scrolls up over it, clipping this panel from the bottom —
     the product and the spec rail get masked mid-element as the next one
     arrives. Duplicate the section per flavour and they stack in sequence.
     The wrapper carries the sticky (via the schema `class`) because the inner
     element's containing block is only as tall as the section itself. */
  /* No viewport min-height here. The pinned rule below sets its own 100vh; in
     flow the section should be the height of its content, otherwise it is
     padded out to a full screen and the surplus collects as dead space under
     the buy note. */
  /* Plain text in a panel inherits the colour scheme's 0.75-alpha body ink, which
     is under 4.5:1 on the mid-tone panels (Nootropic's blue). Doubled class so it
     beats the scheme rule wherever the stylesheets land in the cascade. */
  .product-showcase.product-showcase {
    color: rgba(var(--color-foreground), 0.92);
  }

  /* On a product page with no hero image the panel opens the page, up under the navbar. Stacked (a
     phone or tablet, or a short screen), what leads the panel is the flavor bar,
     which would sit behind the logo, so the panel starts below the bar there.
     Wide and tall, the photo is centred and the bar floats over the panel's own
     colour, as on the line pages. */
  @media screen and (max-width: 1199px), screen and (max-height: 759px) {
    body.has-opening-panel .product-showcase[data-product-page] {
      padding-top: var(--header-height, 6.4rem);
    }
  }
  .product-showcase {
    /* The panels are coloured, mid-tone ones included (Nootropic's blue), so the
       secondary text stays near full strength to hold 4.5:1 on any of them. */
    --ink-muted: 0.88;
    position: relative;
    display: flex;
    flex-direction: column;
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: 0;
    overflow: hidden;
  }

  /* ---- Flavour name ----------------------------------------------------
     Sits at the head of the rail's copy, above the description.

     Was accent-coloured, back when panels each carried their own hue. Now
     that a panel's background can be any colour a merchant picks — including
     ones close to the accent itself — a fixed accent could no longer promise
     to stay legible against it. Full-strength foreground ink does: it's the
     same colour already guaranteed to read against this exact background (see
     the auto-contrast derivation above), so the name is readable on every
     slide, and differentiates one flavour from another by name and weight
     rather than by hue.

     Lead size and bold: large enough to title the rail, small enough that the
     buy button is still the loudest thing in the column. */
  .product-showcase__flavour {
    margin: 0;
    color: rgb(var(--color-foreground));
    font-size: var(--text-lead);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
    /* Sentence case, so it takes whatever capitalisation the label is given
       rather than forcing it — the theme's convention elsewhere too. */
    text-transform: none;
  }

  /* A link, shown by a small arrow that fades in and slides a little way out
     from the name on hover or keyboard focus (no underline). The arrow's room is
     kept so the name never shifts. On a touch screen, with no hover, it is
     always there, quietly. */
  .product-showcase__flavour-link {
    color: inherit;
    text-decoration: none;
  }
  .product-showcase__flavour-link::after {
    content: '';
    display: inline-block;
    width: 0.75em;
    height: 0.75em;
    margin-left: 0.4em;
    vertical-align: -0.02em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: 0;
    transform: translateX(-0.4em);
    transition: opacity var(--motion-base) var(--diip-ease), transform var(--motion-base) var(--diip-ease);
  }
  .product-showcase__flavour-link:hover::after,
  .product-showcase__flavour-link:focus-visible::after {
    opacity: 1;
    transform: none;
  }
  @media (hover: none) {
    .product-showcase__flavour-link::after {
      opacity: 0.55;
      transform: none;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__flavour-link::after {
      transition: none;
      transform: none;
    }
  }
  .product-showcase__flavour-link:focus-visible {
    outline: 0.2rem solid currentColor;
    outline-offset: 0.3rem;
  }

  .product-showcase__grid {
    display: grid;
    grid-template-columns: 1fr;
    flex: 1;
  }

  /* Even inset on all four sides, both columns. The value is the gutter rather
     than a spacing step because the horizontal figure isn't free: it is the panel-wide
     gutter the heading, the seam that used to sit above and every other inset in
     this section resolve to, so pulling it in here alone would knock the column
     out of line with the rest. Equalising therefore means bringing the vertical
     sides up to the gutter, not pulling the horizontal ones in. */
  .product-showcase__main {
    display: flex;
    flex-direction: column;
    padding: var(--diip-gutter, var(--space-m));
  }

  /* Line breaks come from the setting's own newlines, not from wrapping, so the
     heading lays out identically on every panel. Width-based wrapping shifted
     the break as the copy changed, which made the type jump during a reveal. */
  .product-showcase__heading {
    margin: 0;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    /* Not nowrap: the heading is one line by content now, so let it wrap where
       the panel genuinely can't hold it (narrow screens) instead of
       overflowing. */
    text-wrap: balance;
  }

  /* No colour rule left: the per-panel accent this word used to carry is gone
     (see the flavour name, above, for why), so it now just inherits the
     heading's own ink. The setting stays — a merchant can still call out one
     word by wording it that way — but nothing on the page renders it
     differently from the rest of the line any more. The class is kept as a
     hook rather than deleted, in case a future non-colour treatment (weight,
     style) gives it a reason to exist again. */

  /* The image is the flexible element in the column: the heading takes what it
     needs and the image absorbs whatever height is left, so it's never the
     thing that pushes the panel past the fold.

     Centred on both axes in that leftover space. Previously it sat on the
     bottom edge and bled past the column, which read as a product resting on
     the seam; centred it reads as a product being presented, which is what the
     panel is for. */
  .product-showcase__media {
    /* Full width stacked — there's no "left area" to sit inside when the panel
       is one column, and holding the product back from the edges there just
       makes it small on a phone. The inset applies beside the rail only, set in
       the two-column block below. */
    --media-width: 100%;

    /* No padding here. align-items centres within the CONTENT box, so any
       asymmetric padding offsets the image by half of it — a top pad of 32
       parked the product 16px below true centre, which is exactly the kind of
       near-miss that reads as sloppy rather than intentional. The heading's own
       spacing already separates the two. */
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* The product is the hero of the panel — as large as fits. Capped on both
     axes with auto sizing on both, so it stays proportional and never grows the
     panel past the viewport (the panel is a fixed 100vh window; an image taller
     than that pushes the buy action off the clipped bottom edge). */
  /* max-height:100% rather than a vh figure — 70vh ignored the heading, the
     padding and the navbar above it, so the column always totalled more than
     the panel. Bounded by its flex parent, the image scales to the space that
     actually remains. object-fit keeps it undistorted as it does. */
  /* Width is driven, height follows. object-fit does the rest: where the two
     constraints disagree — a tall image at 75% width in a short panel — the
     box clamps and the drawing letterboxes inside it rather than stretching, so
     the product is never distorted and stays centred in whatever box it gets. */
  .product-showcase__media img,
  .product-showcase__placeholder {
    display: block;
    width: var(--media-width);
    height: auto;
    max-width: min(100%, 108rem);
    /* In flow the column has no definite height, so a percentage cap would be
       ignored and the image would render at full size — taller than the rail,
       leaving its leftover height as a lopsided gap under the buy note. A vh
       cap keeps the two columns close so the rail's own padding frames it
       evenly top and bottom. Overridden to 100% when pinned, where the flex
       parent does have a definite height to resolve against. */
    max-height: 60vh;
    object-fit: contain;
  }

  /* Right rail */
  /* In flow the product column is usually taller than the rail (the image is
     the tall thing), and the rail stretches to match it. Centre the rail's
     content in that leftover rather than top-aligning it, otherwise the whole
     surplus pools underneath the buy note and reads as dead space. Pinned
     panels override this to bottom-align. */
  /* Same even inset as the image column — see there for why it's the gutter. */
  .product-showcase__rail {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-m);
    padding: var(--diip-gutter, var(--space-m));
    border-top: 0.1rem solid var(--hairline);
  }


  /* The rail content, grouped and pushed to the foot of the rail.
     24px rhythm to match the gap between the spec groups. */
  /* Top-aligned by default, so the flavour name starts level with the heading
     opposite it and the space above it is just the rail padding — one token,
     on the 8px scale. (Bottom-alignment is a pinned-panel behaviour and is
     applied there instead: in flow the leftover height landed above the label
     as an arbitrary off-scale gap.) */
  .product-showcase__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
  }

  /* Baseline-aligned: the star's own bottom edge sits on the text's baseline,
     the same way a second line of text would, and its height is set to the
     text's own cap-height-to-baseline span (see the svg rule below) so its top
     lands level with the top of the digits too. Top and bottom both match, not
     just the middle.

     This was tried once before and abandoned — with the star at its old size
     (half again the digits' height) baseline alignment put its top well above
     the digits, which read as the star hanging off the text rather than
     sitting with it. That problem was the star's size, not the alignment
     method; now that it's sized to the text, baseline is the more literal fix
     and centring is no longer needed. */
  .product-showcase__rating {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
    font-size: var(--text-caption);
  }

  /* The count stays at caption size. It's a footnote to the stars, and at 12px
     centred it happens to land dead level with them — 14px measures 0.5px out,
     so making it bigger would cost alignment as well as emphasis. */
  .product-showcase__rating-count {
    line-height: 1.4;
  }
  /* One star, drawn rather than the ★ character, so its viewBox is cropped to
     the ink and the box IS the shape — the star has no ascender/descender
     padding the way a font glyph would, so its box can be lined up directly
     against the text's own cap-height and baseline (see the svg rule below).

     Was the sitewide gold (--color-star), which is exactly the kind of fixed
     hue a per-panel background can now defeat — Butterbrew's yellow makes a
     gold star disappear into it. Matched to the score beside it instead
     (same --ink-strong tier as .product-showcase__rating-score below), so the
     star and the number read as one mark in whatever ink this panel is
     already using, rather than a second colour that has to keep working
     against whatever background comes next. */
  .product-showcase__stars {
    display: inline-flex;
    color: rgba(var(--color-foreground), var(--ink-strong));
  }

  /* Outline star before any reviews. Muted rather than faint: the outline is
     thin, and at 0.32 a hairline star reads as a smudge. */
  .product-showcase__stars--empty {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* Sized to the text's cap-height, not its font-size box: measured (canvas,
     against the actual loaded webfont rather than a fallback, confirmed
     loaded first) at 9px from baseline to cap-height for both the score and
     the count at this weight and size — the icon's previous 14px was visibly
     taller than either. 0.9rem is 9px in this theme's scale.

     With the row now baseline-aligned (above), a box this height sitting on
     the baseline puts its top exactly level with the top of the digits too —
     top and bottom both matched, not inferred from a centre point. */
  .product-showcase__stars svg {
    flex: 0 0 auto;
    width: 0.9rem;
    height: 0.9rem;
  }

  /* The score carries the weight now that it, not the row of stars, is the
     rating. Full-strength ink against the muted count beside it.

     line-height matches the count's below for the same reason the count
     needed it: left at the ambient 1.8, the score sat in a 21.6px box around
     12px bold type, and centring that tall box in the row put the glyph's own
     optical centre above the row's true centre — the box was centred, the
     digits weren't. Both text elements now share one box height, so both
     centre exactly where the star does. */
  .product-showcase__rating-score {
    font-weight: 700;
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-strong));
  }

  .product-showcase__rating-count {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* Only ever the struck original on a sale now that the amount charged lives
     on the button. Set at body size rather than the old lead: it's a reference
     point, and at display size it would read as the price being asked. */
  .product-showcase__price {
    margin: 0;
    font-size: var(--text-body);
  }

  .product-showcase__price-was {
    opacity: 0.5;
    font-weight: 400;
  }

  /* The paragraph is the row; the badge inside it is the shape. Splitting the
     two lets the row take a full line while the pill still hugs its own text
     rather than stretching the rail.

     No margin: the rail is a flex column with its own 24px gap, and a margin
     here stacked on top of it for 48 — double every other step in the list. The
     gap also handles the note being absent on its own, since gaps only apply
     between children that exist, which is what the margin was there for. */
  /* Held at the top of the rail. flex-shrink: 0 so it can't be compressed when
     the rail runs short — it would be the first thing squeezed otherwise, being
     the only item above the auto margin. */
  .product-showcase__note {
    flex: 0 0 auto;
    margin: 0;
    line-height: 1.4;
  }


  /* Shaped, so it reads as a deliberate shipping status rather than fine print.

     Was accent-tinted; now built from the panel's own foreground instead, at
     the same 8% wash the selected-variant chip uses elsewhere in this section
     — one consistent "quiet chip" treatment rather than two. This is the part
     that actually matters now that the background itself is the thing
     changing per panel: foreground-on-background is the one pairing already
     guaranteed to read on whatever colour a merchant picks, because it's the
     exact pair the auto-contrast derivation above solves for. An accent hue
     had no such guarantee — it was corrected against the background at the
     time, but nothing recomputes it if the background changes again later,
     and a mid-tone accent can still land badly on a mid-tone background even
     after correction. */
  .product-showcase__note-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-s);
    border-radius: var(--radius-pill);
    background-color: rgba(var(--color-foreground), 0.08);
    font-size: var(--text-caption);
    /* Matches .product-showcase__variants-label's own caption-size treatment
       below, so this reads as the same tier of secondary rail text rather than
       a differently-cased one-off — whatever the merchant types in. */
    text-transform: lowercase;
    color: rgb(var(--color-foreground));
  }

  /* The badge row: "New" and the status badge side by side. */
  .product-showcase__note {
    align-self: flex-start;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
  }
  .product-showcase__note-badge[hidden],
  .product-showcase__note[hidden] {
    display: none;
  }
  /* "New": a filled badge like the status one, with a stronger wash and bolder
     type so it reads as the louder of the two. Filled, not outlined: an outline
     makes it look like a button (the strength pills are outlined). Built from
     the foreground colour, the pair already guaranteed to read on any flavor. */
  /* "# left" (low stock) is styled exactly like New. */
  .product-showcase__note-badge--new,
  .product-showcase__note-badge--low {
    background-color: rgba(var(--color-foreground), 0.18);
    font-weight: 700;
  }
  /* "# left" flashes softly when it appears: it fades almost out and back five times, then
     stays on (4.5 seconds in all, inside the 5 seconds WCAG 2.2.2 allows without a pause
     control), about one flash a second (the limit is three). It runs again each
     time it is shown, for example after a different strength is chosen. Off for
     visitors who ask for less motion. */
  @keyframes product-showcase-low-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.2; }
  }
  .product-showcase__note-badge--low:not([hidden]) {
    animation: product-showcase-low-pulse 0.9s ease-in-out 5;
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__note-badge--low:not([hidden]) {
      animation: none;
    }
  }

  /* Body leading (1.55), matching .t-body. The paragraph rule is needed because
     this block carries Dawn's `rte` class, whose `.rte p { line-height: 1.7 }`
     otherwise wins over the container and left the description visibly looser
     than the spec values beside it. */
  .product-showcase__desc,
  .product-showcase__desc.rte p {
    font-size: var(--text-body);
    line-height: 1.55;
  }
  .product-showcase__desc > *:first-child { margin-top: 0; }
  .product-showcase__desc > *:last-child { margin-bottom: 0; }

  /* Two columns: the spec groups (flavor, ingredients) sit side by side, each a
     labelled list. auto-fit with a 14rem minimum keeps two across on a normal rail
     and drops to one stacked column on a rail too narrow to fit both. */
  .product-showcase__specs {
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--space-m);
  }

  .product-showcase__spec {
    /* No divider between groups — the gap alone separates them. */
  }

  /* 0.7 rather than 0.55: still clearly secondary to the values, but the labels
     were failing AA (~3.5:1) against the lighter panel backgrounds. */
  .product-showcase__spec-label {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-caption);
    /* Caption leading (1.4) — it was inheriting body leading at 1.8. */
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* One step below body. These are scannable lists rather than prose, so they
     don't need body size, and dropping a step buys real height in a panel
     that's fighting for it. (Matches the reference: gethapply runs its
     equivalent groups smaller than its description too.) */
  .product-showcase__spec-values {
    margin: 0;
    font-size: var(--text-sm);
    line-height: 1.55;
  }
  .product-showcase__spec-values span {
    display: block;
  }

  /* Strength / variant selector */
  /* No bottom margin: this sits beside the buy button in a flex row, and the
     margin would lift it off the shared baseline. */
  .product-showcase__variants {
    border: 0;
    margin: 0;
    padding: 0;
  }
  .product-showcase__variants-label {
    padding: 0;
    margin: 0 0 var(--space-xs);
    font-size: var(--text-caption);
    text-transform: lowercase;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .product-showcase__variant-options {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
  }
  .product-showcase__variant {
    position: relative;
    cursor: pointer;
  }
  /* `inset: 0` alone doesn't stretch a form control — an input has an intrinsic
     size that beats `auto` dimensions, so it sat at 40x45 inside a 48x48
     control. The label still took the click across its whole area, but the
     input is given explicit dimensions so the element you inspect matches the
     one you see, and so nothing depends on label-forwarding for the hit area. */
  .product-showcase__variant input {
    position: absolute;
    opacity: 0;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
  }
  .product-showcase__variant span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Hit area, not just a look: these were 39x44 and missed the 44px
       guideline on the short axis. */
    min-width: var(--tap-target);
    min-height: var(--tap-target);
    padding: var(--space-xs) var(--space-s);
    /* An interactive boundary, not a divider. --hairline (0.14) is tuned for
       rules between blocks and is too faint to read as a control here — the
       unselected strength looked like bare text beside the outlined selected
       one and the solid buy button, which is what made the set look mismatched
       despite all three being exactly 48px. */
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    font-weight: 700;
    transition: border-color var(--motion-fast) var(--diip-ease), background-color var(--motion-fast) var(--diip-ease);
  }
  .product-showcase__variant input:checked + span {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.08);
  }
  .product-showcase__variant input:focus-visible + span {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }
  /* Sold-out strength: struck through and dimmed, still shown for context. */
  .product-showcase__variant--soldout span {
    opacity: 0.4;
    text-decoration: line-through;
  }

  /* Actions */
  /* No auto top margin — the rail is bottom-aligned, so pushing the actions
     down would only open a gap above them. */
  /* Bottom-aligned, not centred. The strength group is taller than the button
     because it carries its own label above the pills, so centring the two
     boxes left the pills sitting below the button's middle. Aligning to the
     foot puts pills and button on one baseline, which is what the eye reads. */
  /* Row and column gaps set separately: strength and quantity are two distinct
     choices and need real air between them, but that shouldn't also push the
     buy button further from the controls it belongs to. */
  /* Row and column gaps are set separately because they separate different
     things. The rows are distinct steps — choose a strength, then choose an
     amount and buy — so they take the rail's own 24px rhythm and read as part
     of the same list as the specs and description above. The column gap stays
     tighter: the quantity and the button are one action split across two
     controls, and the same 24 between them would read as two unrelated ones. */
  .product-showcase__actions {
    /* A two-column grid with every control placed explicitly: strength and
       quantity on the first row, buy and subscribe side by side on the second.
       (Flex wrapping couldn't hold that shape; with five items from three
       different elements, any width that let two share a line let them all.) */
    display: grid;
    /* A third and two thirds: the stepper and the buy button share the last row
       that way (the strength pills span the whole row above). */
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    align-items: end;
    row-gap: var(--space-m);
    column-gap: var(--space-s);
    /* Its own block at the foot of the column, set the same way as the flavor
       picker on the left (.product-showcase__flavor-bar): a hairline rule across
       the column edge to edge, bleeding through the column's padding, with the
       same padding inside. */
    margin: 0 calc(var(--diip-gutter, 2.4rem) * -1) calc(var(--diip-gutter, 2.4rem) * -1);
    padding: 2rem var(--diip-gutter, 2.4rem) var(--diip-gutter, 2.4rem);
    border-top: 0.1rem solid var(--hairline);
  }

  /* The flex has to go on the inner <form> that Liquid's form tag renders —
     <product-form> only wraps it, so flexing the wrapper left the quantity and
     the button stacked as blocks inside. */
  /* Both wrappers are display:contents so the strength pills, the quantity and
     the buy button all become direct children of the actions row. They sit in
     three different elements in the markup — the fieldset outside the form,
     the other two inside it — and only one flex context can line them up.
     Left as boxes, the form measured its full content width and wrapped as a
     unit, which forced the pills onto their own row. */
  .product-showcase__form {
    margin: 0;
    display: contents;
  }

  /* Errors take the full width above the controls rather than squeezing in
     beside them. */
  .product-showcase__form-error {
    grid-column: 1 / -1;
    grid-row: 4;
  }

  /* display:contents so the form's children join the actions row directly.
     The quantity has to live inside the form to post, but the strength pills
     sit outside it — without this they're in separate flex contexts and can
     never share a line, which forced a three-row stack that cost 120px of
     panel height and broke the masking fit. The form still submits normally;
     only its box is removed. */
  .product-showcase__buy {
    display: contents;
  }

  /* Three explicit lines. `order` rather than DOM sequence does the arranging,
     because these five items come from three different elements in the markup —
     the fieldset outside the form, the quantity and button inside it — and the
     display:contents wrappers above flatten them into one row in whatever order
     the markup happens to fall. Ordering them here keeps the layout readable in
     one place instead of depending on where each element had to be nested to
     work. Order values are spaced so a future item can slot between two without
     renumbering the rest.

       1  strength   own line
       2  quantity   shares a line, hugs its content
       3  buy        same line, takes whatever is left
       4  note       own line at the foot

     The buy button takes the remainder rather than a fixed share, so it grows
     with the rail instead of leaving the quantity a half-width box. */
  /* Rows now: strength + quantity share the first line (strength takes what
     the quantity leaves, the quantity hugs its content at the right), the buy
     button and the subscribe button share the next line, half each. */
  .product-showcase__variants {
    order: 1;
    grid-column: 1 / -1;
    grid-row: 1;
    min-width: 0;
  }

  /* Purchase picker: its own full-width row between the strength/quantity row
     and the buy button. */
  .product-showcase__purchase {
    grid-column: 1 / -1;
    grid-row: 2;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
  }
  .product-showcase__purchase-option {
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: 1.6rem;
    transition: border-color var(--motion-fast) var(--diip-ease), background-color var(--motion-fast) var(--diip-ease);
  }
  .product-showcase__purchase-option.is-active {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.06);
  }
  .product-showcase__purchase-row {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    min-height: var(--tap-target);
    padding: 0 var(--space-s);
    cursor: pointer;
  }
  /* The subscribe row's vertical padding is set so the VISIBLE gap from the
     option's top border to the lettering, and from the lettering to the divider
     below, are both 20px (the 25px line box has about 8px of empty space above
     the 10px capitals and 7px below them, hence the uneven numbers). */
  [data-purchase-subscribe] .product-showcase__purchase-row {
    min-height: 0;
    padding-top: 1.11rem;
    padding-bottom: 1.29rem;
  }
  .product-showcase__purchase-row input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }
  .product-showcase__purchase-radio {
    flex: 0 0 auto;
    width: 1.8rem;
    height: 1.8rem;
    border: 0.15rem solid rgba(var(--color-foreground), 0.6);
    border-radius: 50%;
    box-sizing: border-box;
  }
  .product-showcase__purchase-row input:checked + .product-showcase__purchase-radio {
    border-color: rgb(var(--color-foreground));
    background: radial-gradient(circle, rgb(var(--color-foreground)) 0 45%, transparent 50%);
  }
  .product-showcase__purchase-row input:focus-visible + .product-showcase__purchase-radio {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .product-showcase__purchase-title {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: var(--space-xs);
    white-space: nowrap;
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
  }
  /* The subscribe row's right side: the first-order price, the same as the
     one-time row. The "Save 30%" badge sits right after the title instead. */
  .product-showcase__prices {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--space-xs);
  }
  .product-showcase__prices .product-showcase__purchase-price {
    white-space: nowrap;
  }
  /* Same quiet chip as the "made for california" badge (an 8% wash of the
     panel's own ink, a pill), smaller. */
  .product-showcase__price-badge {
    display: inline-flex;
    align-items: center;
    /* 0.17rem above and 0.03rem below (0.2rem in all, as before): this tilts the
       lettering about 0.7px down inside the pill, which is where it measured
       high against the prices and titles beside it. */
    padding: 0.17rem var(--space-xs) 0.03rem;
    /* The pill is centred on the price's line box, but the price's digits sit a
       little lower in that box than its middle (measured: the pill's centre was
       0.2 to 0.4px above the digits'), which read as the digits being low in the
       pill. Nudged so the pill is centred on the digits themselves. */
    transform: translateY(0.3px);
    border-radius: var(--radius-pill);
    background-color: rgba(var(--color-foreground), 0.08);
    color: rgb(var(--color-foreground));
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    text-transform: lowercase;
  }
  .product-showcase__price-badge[hidden] {
    display: none;
  }

  /* Right of the "Frequency" label: "Renews every month at $33.99" with its
     saving as a badge. */
  .product-showcase__recurring {
    display: flex;
    flex: 0 1 auto;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-xs);
    margin: 0;
    /* The same type as the prices in the row above (.product-showcase__purchase-price):
       the same size, weight and colour. */
    font-size: var(--text-sm);
    font-weight: 700;
    line-height: 1.4;
  }
  .product-showcase__recurring[hidden] {
    display: none;
  }

  /* The age line is a shipping-note look-alike (same class), sitting above it. */
  .product-showcase__age-line + .product-showcase__shipping-note {
    margin-top: -1.9rem;
  }

  /* "Free shipping on orders over $60", quiet and centred under the buy button. */
  .product-showcase__shipping-note {
    /* Pulled up toward the button: the rail's own 24px gap is too loose for a
       note that belongs to it. */
    align-self: stretch;
    /* The actions block is a two-column grid; span both so the note is centred
       under the whole button. */
    grid-column: 1 / -1;
    margin: -1.2rem 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    text-align: center;
    font-size: var(--text-caption);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* The icon's drawn shape is as tall as the lettering (about 0.714em of digit
     and capital height) and sits on its centre. */
  .product-showcase__shipping-icon {
    display: inline-flex;
    flex: 0 0 auto;
    height: 0.714em;
    transform: translateY(-0.074em);
  }
  .product-showcase__shipping-icon svg {
    display: block;
    width: auto;
    height: 100%;
  }

  .product-showcase__purchase-price {
    flex: 0 0 auto;
    font-size: var(--text-sm);
    font-weight: 700;
  }
  .product-showcase__purchase[disabled] {
    opacity: 0.5;
  }

  /* A hairline under the subscribe title row separates today's deal (above)
     from how it repeats (below). */
  .product-showcase__frequency {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-s);
    /* Same left inset as the row above, so this lines up with the radio button.
       The top is shorter than the sides: the row above gets its breathing room
       from a 44px minimum height centred on the text (12px above the text), so
       the same 12px (11px + the 1px rule) sits above this group's first line.
       Below the chips it is the VISIBLE gap that has to match: in the row above,
       the 12px box gap plus the empty space inside the 25px line box above the
       10px capitals is about 19px from the border to the lettering, so the pill
       edge of the chips sits 19px (18px + the option's 1px border) from the
       bottom border. */
    padding: 1.1rem var(--space-s) 1.9rem;
    border-top: 0.1rem solid rgba(var(--color-foreground), 0.2);
  }
  .product-showcase__frequency[hidden] {
    display: none;
  }
  /* "Frequency" on the left, the renewal line on the right, one line above the
     chips. */
  .product-showcase__frequency-head {
    display: flex;
    flex: 1 1 100%;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs) var(--space-s);
  }
  /* Styled as the "Subscribe" title above it (.product-showcase__purchase-title):
     the same size, weight, spacing and colour. */
  .product-showcase__frequency-title {
    flex: 0 0 auto;
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
  }
  .product-showcase__frequency-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
  }
  .product-showcase__frequency-option {
    min-height: 3.2rem;
    padding: 0 1.2rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--text-caption);
    font-weight: 700;
    cursor: pointer;
  }
  .product-showcase__frequency-option.is-active {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.12);
  }
  /* Always shown, so the choices are discoverable; quieter while one-time is
     selected, and pressing one switches to subscribing. */
  .product-showcase__purchase[data-mode="onetime"] .product-showcase__frequency {
    opacity: 0.55;
  }
  .product-showcase__purchase[data-mode="onetime"] .product-showcase__frequency-option.is-active {
    border-color: rgba(var(--color-foreground), var(--ink-faint));
    background-color: transparent;
  }

  /* The stepper (a third) and the buy button (two thirds) share the last row, the
     stepper at the left. */
  .product-showcase__qty {
    order: 2;
    grid-column: 1;
    grid-row: 3;
    justify-self: stretch;
  }

  /* Basis 0 rather than auto, with min-width cleared: on auto the button asks
     for its whole label first and, with the price in it, that plus the stepper
     is wider than the rail — so it wrapped to its own line instead of sharing
     one. From 0 it takes the space that's left and the pair stays on one line
     at every rail width. */
  /* Height is set, not inherited from the content: the icon is taller than the
     text line it replaced, and left to padding the button grew to 53px — off
     the 48px tap target the rest of the controls are built on. Fixing the
     height and centring inside it means the icon can be sized for legibility
     without moving the button. */
  .product-showcase__actions .product-showcase__cta {
    order: 3;
    grid-column: 2;
    grid-row: 3;
    min-width: 0;
    min-height: var(--tap-target);
    padding-block: 0;
    justify-content: center;
    align-items: center;
  }

  /* Icon and price as one centred pair. The gap is the only thing between them
     now that the bullet is gone, so it does the separating the punctuation used
     to — space rather than a mark, which is why the icon needs to sit optically
     level with the digits rather than on the text baseline. */
  .product-showcase__cta-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    /* Above the fill. Positioned rather than just z-indexed, because z-index
       does nothing on a static element and the label would sit under the
       circle. */
    position: relative;
    z-index: 1;
  }

  /* "| 2 in cart" after the label: how many of this flavour are already in the
     cart, across every strength and both one-time and subscription lines. Quieter
     than the label so the action still reads first. */
  .product-showcase__cta-count {
    display: inline-flex;
    align-items: center;
    /* Equal space either side of the divider. The label's own gap already puts
       var(--space-xs) before this, so the margin tops that up to the same
       var(--space-s) used after the divider. */
    gap: var(--space-s);
    margin-left: calc(var(--space-s) - var(--space-xs));
    font-weight: 400;
    line-height: 1;
    opacity: 0.75;
  }
  /* A thin vertical divider between the label and the count, not a bullet. */
  .product-showcase__cta-count::before {
    content: "";
    flex: 0 0 auto;
    width: 0.1rem;
    height: 1.6rem;
    background-color: currentColor;
    opacity: 0.6;
  }
  .product-showcase__cta-count[hidden] {
    display: none;
  }

  /* The label is one row: the wording, the divider and the "N in cart" count.
     Any change to any part of it (Add to cart / Add 2 to cart / Added, the count
     appearing, changing or going) fades the whole row out, swaps what changed
     and fades the whole row back in, so the pieces never change on their own. */
  .product-showcase__cta-row {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    transition: opacity var(--motion-base) var(--diip-ease);
  }
  /* The check beside "N added": only there while that wording is. */
  .product-showcase__cta-check {
    display: inline-flex;
    align-items: center;
  }
  .product-showcase__cta-check[hidden] {
    display: none;
  }
  /* Sized so the tick itself (about 80% of the icon box) is the height of the
     lettering, and nudged up half a pixel so their centres line up. */
  .product-showcase__cta-check svg {
    width: auto;
    height: 0.88em;
    transform: translateY(-0.035em);
  }
  .product-showcase__cta-row.is-swapping {
    opacity: 0;
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__cta-row {
      transition: none;
    }
  }

  /* No spinner on the buy buttons. The add is quick, and a spinner replacing the
     label made the wording blink out and back before the real feedback ("N
     added") arrived. The button still reports busy to assistive tech through
     product-form's aria-disabled; the label just stays put until it changes. */
  .product-showcase__cta .loading__spinner,
  .product-showcase__subscribe .loading__spinner {
    display: none !important;
  }

  /* A solid bag rather than the header's outline cart. Not an inconsistency for
     its own sake: the header icon sits larger and on a light background, where
     an outline holds. Here it is 20px reversed out of a dark fill, and Dawn's
     glyph is a line about one unit wide in a 40-unit viewBox — roughly half a
     pixel at this size, which no display renders as a solid line. It dithered
     to grey and disappeared. A filled shape has no hairline to lose, so it
     survives the size instead of needing to be propped up at it.

     Sized in em against the label's own font, so the icon tracks the price if
     the type scale moves rather than needing a second number kept in step. */
  .product-showcase__cta-icon {
    display: inline-flex;
    flex: 0 0 auto;
  }

  /* Nudged up because the glyph is bottom-heavy, not because it was drawn off
     centre. Rasterised and weighted, this one's centre of mass sits 2.87% below
     the middle of its box — the bag body is solid, the handle above it is a thin
     arc. Centring the boxes therefore centres the wrong thing and reads as
     sitting low however exactly it's done, so the offset aligns mass instead.

     The figure is specific to the artwork: the hand-drawn bag this replaced
     needed 7%. Remeasure rather than carry it over if the icon is ever swapped.

     Percentage, not em: em would resolve against the inherited label font-size
     rather than the icon's own size, so it would drift out of step the moment
     the icon is resized. As a percentage of the glyph's height it holds. */
  .product-showcase__cta-icon svg {
    width: 1em;
    height: 1em;
    transform: translateY(-2.9%);
  }

  /* Name left, rating right, on one line. Baseline rather than centre: the two
     are different sizes — 20px bold against 12px — so centring their boxes
     would leave the type sitting at visibly different heights. On a baseline
     they read as one line, which is the point of putting them on one.

     Wraps, so a name long enough to crowd the rating sends it to the next line
     instead of squashing it. */
  .product-showcase__title-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-xs) var(--space-s);
    /* Tall enough for the rating pill, so a flavor without reviews doesn't sit
       a few pixels shorter and shift everything under it when switching. */
    min-height: 3rem;
  }

  /* "40+ bought this month": quiet text under the flavor name, in the same muted ink as
     the shipping note. */
  .product-showcase__bought {
    /* Pulled up under the name: the rail's own gap and the name row's minimum height
       (tall enough for the rating pill) would otherwise leave it floating well below. */
    margin: -2.4rem 0 0;
    font-size: var(--text-caption);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .product-showcase__bought[hidden] {
    display: none;
  }

  .product-showcase__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
  }

  /* Column, so the label sits above the field the way the strength legend does.
     Without it the label is an inline span next to an inline-flex control and
     the two share a line. */
  .product-showcase__qty {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }

  .product-showcase__qty-control {
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-sizing: border-box;
    width: 100%;
    height: var(--tap-target);
    /* Same height and border language as the strength pills, so the row reads
       as one family of controls. */
    min-height: var(--tap-target);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    overflow: hidden;
  }

  .product-showcase__qty-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Full tap target each, which is the reason for a stepper over the number
       input's own spinners. */
    /* The full tap target where there is room; on a phone the stepper is a third
       of the row, so the buttons give a little (to 4rem) and the number field
       keeps enough room for a two-digit count. */
    flex: 0 1 var(--tap-target);
    min-width: 4rem;
    min-height: 0;
    height: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: var(--text-body);
    line-height: 1;
    cursor: pointer;
  }
  .product-showcase__qty-step:disabled {
    opacity: 0.35;
    cursor: not-allowed;
  }

  .product-showcase__qty-input {
    align-self: stretch;
    flex: 1 1 0;
    min-width: 2.4rem;
    width: 3.2rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
    /* Native spinners removed — the steppers replace them, and they'd sit
       awkwardly inside a pill. */
    appearance: textfield;
    -moz-appearance: textfield;
  }
  .product-showcase__qty-input::-webkit-outer-spin-button,
  .product-showcase__qty-input::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }

  /* ---- Flavour switcher (collection mode) --------------------------------
     Single-product panels wrap their photo and rail content in these elements
     purely so both modes share one template; they're transparent there
     (display: contents), so the layout is exactly what it always was. */
  .product-showcase__media-panel,
  .product-showcase__flavors,
  .product-showcase__flavor {
    display: contents;
  }

  /* Collection mode: every flavour's photo, and every flavour's rail content,
     stacked in one cell each. Only the active one shows, but all of them are
     laid out, so the panel reserves the tallest one's height and switching
     can't move the buy button. Definite tracks so the photo's max-height:100%
     has a real box to resolve against. */
  .product-showcase__media--stack {
    display: grid;
    grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  }

  .product-showcase__media--stack > .product-showcase__media-panel {
    display: grid;
    grid-template: minmax(0, 1fr) / minmax(0, 1fr);
    place-items: center;
    grid-area: 1 / 1;
    min-width: 0;
    min-height: 0;
    transition: opacity var(--motion-base) var(--diip-ease), transform var(--motion-base) var(--diip-ease);
  }

  .product-showcase__flavors--stack {
    display: grid;
  }

  .product-showcase__flavors--stack > .product-showcase__flavor {
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
    grid-area: 1 / 1;
    /* Every flavor shares one cell, as tall as the tallest of them. Anchored to the
       foot of that cell, a shorter flavor ends level with the others (the buy button
       and the shipping note sit in one place whichever flavor shows) instead of
       leaving a gap under it. */
    align-self: end;
    transition: opacity var(--motion-base) var(--diip-ease), transform var(--motion-base) var(--diip-ease);
  }

  .product-showcase__flavors--stack > .product-showcase__flavor[hidden] {
    display: flex;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease, visibility 0s 0.3s;
  }
  .product-showcase__flavors--stack > .product-showcase__flavor {
    transition: opacity 0.3s ease 0.1s, visibility 0s;
  }

  /* The tin rolls: flavours before the chosen one wait off-screen left, the
     rest off-screen right; picking one rolls the old tin out and the new one
     in along the same line. Plain state transitions, so clicking through
     quickly just redirects the roll from wherever each tin is. */
  .product-showcase__media--stack > .product-showcase__media-panel {
    transition: transform 0.7s cubic-bezier(0.22, 0.8, 0.3, 1), opacity 0.5s ease;
    will-change: transform;
  }
  .product-showcase__media--stack > .product-showcase__media-panel[data-pos="left"] {
    transform: translateX(-120%) rotate(-540deg);
    opacity: 0;
    pointer-events: none;
  }
  .product-showcase__media--stack > .product-showcase__media-panel[data-pos="right"] {
    transform: translateX(120%) rotate(540deg);
    opacity: 0;
    pointer-events: none;
  }

  .product-showcase--flavors {
    transition: background-color 0.7s ease;
  }
  .product-showcase--flavors .product-showcase__main {
    overflow-x: clip;
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__media--stack > .product-showcase__media-panel,
    .product-showcase--flavors {
      transition: none;
    }
  }

  /* Peek image: sits in the tin's own grid cell, behind it, invisible until the
     tin is hovered, then slides out to the right (and tilts a touch) so a piece
     of it shows past the tin's edge. The left column clips horizontally, so it
     is cut off at the seam rather than running into the rail. */
  .product-showcase__peek {
    grid-area: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    min-height: 0;
    z-index: 0;
    pointer-events: none;
    transform: translateX(0) rotate(0deg);
    transition: transform 0.7s cubic-bezier(0.22, 0.8, 0.3, 1);
  }
  /* The open-can photo is cropped tight (its can fills ~98% of the frame) while
     the tin shots leave margin around the can (~61%), so at equal box sizes the
     open can looks far bigger. Scaled by the ratio so the two cans read as the
     same size; the setting exists in case a different image is chosen. */
  .product-showcase__peek img {
    transform: scale(var(--peek-scale, 0.62));
  }

  /* Strength photos: all in one cell, the chosen one on top. Picking another
     strength swaps them instantly. No transition on purpose: the two photos
     differ only in the strength badge, so an animation had nothing to show
     that read as intentional (tried a wipe, a shuffle and a flip). */
  .product-showcase__media-panel > img[data-pos] {
    grid-area: 1 / 1;
  }
  .product-showcase__media-panel > img[data-pos="front"] {
    z-index: 2;
  }
  .product-showcase__media-panel > img[data-pos="back"] {
    z-index: 1;
  }

  /* It lives behind the tin at rest, so while the tins roll (which clears the
     centre) it has to go too, or it shows through where the tin was. Back the
     moment the roll has settled. */
  .product-showcase--flavors.is-rolling .product-showcase__peek {
    visibility: hidden;
  }
  .product-showcase__media--stack > .product-showcase__media-panel {
    position: relative;
    z-index: 1;
  }
  /* With a mouse: hovering the tin slides the open can out. On a touch screen
     there is no hover (a tap leaves one "stuck" on, with no way to undo it), so
     there the tin toggles the open can: tap to show it, tap again to put it back
     (the .is-peeking class, set by the script at the end of this file). */
  @media (hover: hover) {
    .product-showcase--flavors:not(.is-rolling) .product-showcase__media:has(.product-showcase__media-panel[data-pos="active"] img:hover) .product-showcase__peek {
      transform: translateX(16%) rotate(4deg);
    }
  }
  .product-showcase--flavors:not(.is-rolling) .product-showcase__media.is-peeking .product-showcase__peek {
    transform: translateX(16%) rotate(4deg);
  }
  /* No open can behind the Variety pack (its photo is five flavors already). */
  .product-showcase__media:has(.product-showcase__media-panel[data-pos="active"][data-no-peek]) .product-showcase__peek {
    display: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__peek {
      transition: none;
    }
    .product-showcase--flavors:not(.is-rolling) .product-showcase__media:has(.product-showcase__media-panel[data-pos="active"] img:hover) .product-showcase__peek,
    .product-showcase--flavors:not(.is-rolling) .product-showcase__media.is-peeking .product-showcase__peek {
      transform: translateX(16%);
    }
  }

  /* Same pill language as the strength picker below it, in a single row that
     scrolls sideways rather than wrapping: pinned, this panel is a fixed
     height, and every extra row of pills is height the buy button loses. */
  .product-showcase__flavor-pills {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 0.8rem;
  }

  /* The flavour control sits at the foot of the left pane, full width, under
     the tin: it changes the whole panel, and down here it is in the eye's path
     from the product to the buy stack. Bleeds through the column's padding so
     its rule spans the pane edge to edge. */
  .product-showcase__flavor-bar {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1.2rem;
    margin: var(--space-m) calc(var(--diip-gutter, 2.4rem) * -1) calc(var(--diip-gutter, 2.4rem) * -1);
    padding: 2rem var(--diip-gutter, 2.4rem) var(--diip-gutter, 2.4rem);
    border-top: 0.1rem solid var(--hairline);
  }

  /* Stacked (a phone, a tablet, or a short window: everything but the two-column
     panel below): "Choose your flavor" sits above the product photo instead of
     under it, with its rule underneath, and the pills are one row that scrolls
     sideways rather than wrapping onto several lines. */
  @media screen and (max-width: 1199px), screen and (max-height: 759px) {
    .product-showcase__flavor-bar {
      order: -1;
      margin: calc(var(--diip-gutter, 2.4rem) * -1) calc(var(--diip-gutter, 2.4rem) * -1) var(--space-m);
      padding: 2rem 0 var(--space-m) var(--diip-gutter, 2.4rem);
      border-top: 0;
      border-bottom: 0.1rem solid var(--hairline);
      /* The pills run to the screen edge, so the row reads as scrollable. */
      align-items: stretch;
    }
    /* Without min-width: 0 the row's full length (all the pills) becomes the
       column's minimum width, and the whole panel, photo included, grows wider than
       the screen. */
    .product-showcase__main,
    .product-showcase__flavor-bar {
      min-width: 0;
    }
    .product-showcase__flavor-pills {
      min-width: 0;
      flex-wrap: nowrap;
      overflow-x: auto;
      overscroll-behavior-x: contain;
      scroll-snap-type: x proximity;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
      /* Space after the last pill, so it can scroll clear of the screen edge. */
      padding-right: var(--diip-gutter, 2.4rem);
    }
    .product-showcase__flavor-pills::-webkit-scrollbar {
      display: none;
    }
    .product-showcase__flavor-pill {
      scroll-snap-align: center;
    }
  }

  /* The title with the guide link at its end: one row where there is room, the link
     under the title where there is not (a phone). */
  .product-showcase__flavor-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-xs) var(--space-m);
    width: 100%;
  }
  .product-showcase__guide-link {
    font-size: var(--text-sm);
    font-weight: 600;
    color: rgba(var(--color-foreground), var(--ink-muted));
    text-decoration: none;
    white-space: nowrap;
  }
  .product-showcase__guide-link span {
    display: inline-block;
    transition: transform var(--motion-base) var(--diip-ease);
  }
  .product-showcase__guide-link:hover,
  .product-showcase__guide-link:focus-visible {
    color: rgb(var(--color-foreground));
  }
  .product-showcase__guide-link:hover span,
  .product-showcase__guide-link:focus-visible span {
    transform: translateX(0.3rem);
  }
  .product-showcase__guide-link:focus-visible {
    outline: 0.2rem solid currentColor;
    outline-offset: 0.3rem;
  }
  @media (prefers-reduced-motion: reduce) {
    .product-showcase__guide-link span {
      transition: none;
    }
  }

  .product-showcase__flavor-title {
    margin: 0;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
  }

  .product-showcase__flavor-pill {
    flex: 0 0 auto;
    min-height: 4.2rem;
    padding: 0 1.8rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: none;
    color: inherit;
    font-family: inherit;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
    transition: border-color var(--motion-fast) var(--diip-ease), background-color var(--motion-fast) var(--diip-ease);
  }
  .product-showcase__flavor-pill.is-active {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.08);
  }
  .product-showcase__flavor-pill:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .product-showcase__cta,
  .product-showcase__secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 42px tall before — under the 44px guideline. */
    min-height: var(--tap-target);
    gap: var(--space-xs);
    padding: var(--space-s) var(--space-m);
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--motion-fast) var(--diip-ease),
      color var(--motion-fast) var(--diip-ease),
      opacity var(--motion-fast) var(--diip-ease);
  }

  .product-showcase__cta {
    border: 0;
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));

    /* The circle is painted INTO the button's own background rather than being
       a transformed child element.

       An element can't be clipped to a rounded parent without a seam: the child
       rasterises on its own layer, the parent's radius clips the composite, and
       the two antialiased edges don't agree — which showed as a hairline arc
       down the left and right curves. isolation: isolate didn't help, because
       the separate layer IS the problem, not the stacking order.

       A background gradient has no layer of its own. It's painted by the same
       element that owns the radius, so there's one edge and one antialiasing
       pass. The hard-ish stop at 99% is what keeps the circle's own edge smooth
       — a stop at exactly 100% aliases into a stair-step. */
    background-image: radial-gradient(
      circle calc(var(--cta-d) / 2) at var(--cta-x) var(--cta-y),
      rgb(var(--color-background)) 0 99%,
      transparent 100%
    );
    /* Containing block for the inverted label layer. */
    position: relative;
    /* Resting values, so the circle has somewhere to grow from before the
       pointer has been anywhere near it. One diameter drives both the painted
       circle and the clip on the inverted label, so they cannot disagree. */
    --cta-x: 50%;
    --cta-y: 50%;
    --cta-d: 0px;
    /* Animated here because this is the element JS writes to and both the fill
       and the clipped copy inherit from — eased once at the source, so the
       circle and the colour boundary can't disagree. */
    transition: --cta-d var(--motion-base) var(--diip-ease);
  }

  /* Both CTA types now fill the growing circle with the panel's own
     background colour — not an accent. That used to differ: the "add to
     cart" button pressed in accent, the "link" button pressed in background,
     and the label had to invert only for the latter (its own label started
     light, so a light circle would have erased it). Now that neither button
     presses in accent, both need the same inverted copy underneath, so it's
     no longer a per-variant override — see below. */

  /* The inverted copy, clipped to exactly the circle. Spans the whole button
     rather than sitting where the label sits: clip-path resolves against the
     clipped element's own box, so an offset layer would shift the clip by that
     offset and the inversion would drift out of the circle.

     No transition on clip-path itself — that eases the whole shape, centre
     included, and the inverted region would trail the pointer while the fill
     jumped to it. The radius eases because --cta-d is registered and animated;
     the centre comes from untransitioned properties and tracks immediately. */
  .product-showcase__cta-label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-foreground));
    clip-path: circle(calc(var(--cta-d) / 2) at var(--cta-x) var(--cta-y));
    pointer-events: none;
  }

  .product-showcase__cta[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
  }

  /* Own full-width row beneath the buy button — same reasoning as the buy
     button taking the remainder of its own line: there's nowhere left beside
     the strength/quantity/buy row for a fifth control to share. */
  .product-showcase__actions .product-showcase__subscribe {
    order: 4;
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
    min-height: var(--tap-target);
    padding-block: 0;
    justify-content: center;
    align-items: center;
  }

  /* Outline, not filled — secondary to the buy button above it, same relationship
     as the card grid's own subscribe button. Same cursor-tracked hover-fill
     device as .product-showcase__cta, but filling with the foreground colour
     from a transparent resting state rather than the reverse, since it starts
     outlined rather than solid. */
  .product-showcase__subscribe {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative;
    min-height: var(--tap-target);
    padding: var(--space-s) var(--space-m);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background-color: transparent;
    color: rgba(var(--color-foreground), var(--ink-muted));
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;

    background-image: radial-gradient(
      circle calc(var(--sub-d) / 2) at var(--sub-x) var(--sub-y),
      rgb(var(--color-foreground)) 0 99%,
      transparent 100%
    );
    --sub-x: 50%;
    --sub-y: 50%;
    --sub-d: 0px;
    transition: --sub-d var(--motion-base) var(--diip-ease), border-color var(--motion-fast) var(--diip-ease);
  }

  .product-showcase__subscribe:hover {
    border-color: rgba(var(--color-foreground), 0.5);
  }

  .product-showcase__subscribe[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .product-showcase__subscribe-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    position: relative;
    z-index: 1;
  }

  .product-showcase__subscribe-label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-background));
    clip-path: circle(calc(var(--sub-d) / 2) at var(--sub-x) var(--sub-y));
    pointer-events: none;
  }

  .product-showcase__subscribe-icon {
    display: inline-flex;
    flex: 0 0 auto;
  }
  .product-showcase__subscribe-icon svg {
    width: 0.8em;
    height: 0.8em;
  }

  .product-showcase__secondary {
    border: 0.1rem solid var(--hairline);
    color: inherit;
  }


  /* ---- Desktop and laptop only ---------------------------------------
     One breakpoint decides everything about this section, so it has exactly
     two states and no in-between:

       >= 1200px wide AND >= 760px tall  ->  two columns, pinned, fluid scale
       anything smaller                  ->  one column, normal flow, static

     Pinned, the panel is fixed to the viewport and the section acts as a window
     over it: scrolling grows the window rather than moving the panel, so the
     product and rail are progressively uncovered and then covered again by the
     next panel — a reveal, not a slide. clip-path on the wrapper does two jobs:
     it makes the wrapper a containing block for the fixed child, binding the
     panel to this section rather than the viewport, and it clips the panel to
     the section box.

     Why these numbers:
       width 1200 sits above landscape tablets (1024) and below every laptop, so
       tablets and phones fall to the flow layout as intended;
       height 760 is where the panel demonstrably fits. It is a real limit, not
       a preference — pinned, anything taller than the viewport is clipped with
       no way to scroll to it, and a clipped buy button is a broken storefront.

     Both are a function of the RAIL S CONTENT, so revisit them when it changes:
     at 1280x660 the panel currently needs 682px, which is why the shortest
     laptop screens (1366x768, about 660px of viewport) stay in flow.

     Everything that makes this layout desktop — the two columns, the bleeding
     product image, the viewport-driven scale — lives in here with the pinning,
     rather than in separate breakpoints that could disagree with it. */
  @media screen and (min-width: 1200px) and (min-height: 760px) {
    /* The section is taller than the 100vh panel by --diip-showcase-hold. While
       you scroll that extra distance the panel stays fully pinned and visible —
       a "hold" where the whole panel (including the buy button at the foot of
       the rail) is readable — before the next section's window starts to reveal
       over it. Without the hold the full panel showed at exactly one scroll
       position, so the buy button got clipped a pixel either side. */
    .product-showcase-section {
      height: calc(100vh + var(--diip-showcase-hold, 33vh));
      clip-path: inset(0);
    }

    .product-showcase {
      position: fixed;
      inset: 0;
      height: 100vh;
      min-height: 0;
    }

    /* The panel is pinned to the viewport top, so its content would sit under
       the fixed navbar. Drop the whole grid to the navbar's bottom edge and
       draw a divider there: the content begins below the line, and the rail's
       vertical divider now starts at that line instead of running up through
       the nav. */
    .product-showcase__grid {
      /* The seam used to clear the navbar and carry this offset; with it gone
         the grid clears the navbar itself. */
      margin-top: var(--header-height, var(--space-4xl));

      /* And draws the line the seam's hairline used to. Pinned, the panel runs
         under a transparent navbar, so without this the content simply starts
         in mid-air with nothing marking where the bar ends. On the grid rather
         than on the header because it belongs to the panel: it scrolls away
         with the panel it belongs to instead of being a permanent rule under a
         bar that is meant to be transparent. */
      border-top: 0.1rem solid var(--hairline);

      /* A definite height is what lets the column's flex children shrink —
         without it the row is sized by its content and the image can't give
         any space back. The panel minus the navbar strip; the seam's 38px is
         no longer subtracted, which is the height this change gives back. */
      height: calc(100vh - var(--header-height, 6.5rem));
    }


    .product-showcase__main,
    .product-showcase__rail {
      min-height: 0;
    }

    /* Pinned only: the rail sits at the foot of the panel, so the buy action
       lands near the bottom edge alongside the product. */
    .product-showcase__body {
      margin-top: auto;
    }

    /* Pinned: the flex parent has a definite height, so the image can resolve
       against it and shrink to whatever space the heading leaves. */
    .product-showcase__media img,
    .product-showcase__placeholder {
      max-height: 100%;
    }

    /* Two columns, with the rail taking a third of the panel and the product
       the other two. Proportional rather than a fixed width so the rail gains
       room on wide screens. */
    .product-showcase__grid {
      grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    }

    .product-showcase__rail {
      border-top: 0;
      border-left: 0.1rem solid var(--hairline);
    }

    /* Beside the rail, the product takes three quarters of its column and
       centres in the rest. One number is the whole knob: 75% gives it real
       presence while leaving the panel air to be premium in; 50% reads more
       restrained and catalogue-like.

       No bleed any more. The product used to run toward the panel edges, but an
       image centred inside a column and simultaneously pulled off that column's
       centre by uneven margins reads as misaligned rather than deliberate — the
       two ideas contradict each other. Centred wins, so the margins go and the
       column's own gutters frame it evenly. */
    .product-showcase__media {
      --media-width: 75%;
    }

    /* ---- Fluid panel scale ------------------------------------------
       The panel is a fixed window here, so anything taller than the viewport is
       clipped rather than scrolled to. Instead of stepping at breakpoints, the
       panel's own spacing and type scale with the viewport height, so it
       shrinks to fit rather than overflowing.

       Tuned so the vh term equals the normal token at ~900px tall: at or above
       that the panel is pixel-identical to the 8px scale, and only below does
       the rhythm compress. Each clamp floors on a real 8px step, so the tight
       end lands back on the scale. Only needed while pinned — in flow the
       section simply grows. */
    .product-showcase-section,
    .product-showcase {
      --space-xs: clamp(0.4rem, 0.9vh, 0.8rem);
      --space-s: clamp(0.8rem, 1.78vh, 1.6rem);
      --space-m: clamp(1.6rem, 2.67vh, 2.4rem);
      --space-l: clamp(1.6rem, 3.56vh, 3.2rem);
      --space-xl: clamp(2.4rem, 4.44vh, 4rem);
      --space-4xl: clamp(2.4rem, 7.11vh, 6.4rem);
      --space-5xl: clamp(3.2rem, 8.89vh, 8rem);

      /* --text-heading is deliberately NOT overridden. Every other section
         titles at clamp(2.8rem, 4vw, 4.4rem), and a height-aware version here
         made this one heading shrink on short screens while the statement and
         blend focus below it stayed put — the same rank of title at two
         different sizes on one page. It also floored 4px lower than the rest.

         The height it used to save comes out of the image instead, which is the
         flexible element in that column and the right thing to give way. */
      --text-title: clamp(1.8rem, 2.67vh, 2.4rem);
      --text-lead: clamp(1.6rem, 2.22vh, 2rem);
      --text-body: clamp(1.4rem, 1.78vh, 1.6rem);
      --text-sm: clamp(1.2rem, 1.56vh, 1.4rem);
      --text-caption: clamp(1.1rem, 1.33vh, 1.2rem);
    }
  }


  /* The rating as a button: a fully rounded outline pill like the site's other
     buttons and chips, in the panel's own ink, filling faintly on hover. */
  button.product-showcase__rating {
    appearance: none;
    margin: 0;
    padding: 0.5rem 1.2rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.4);
    border-radius: 999px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--text-caption);
    text-align: left;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease;
  }
  /* A hairline between the score and the count. */
  .product-showcase__rating-divider {
    align-self: stretch;
    flex: 0 0 auto;
    width: 0.1rem;
    background: rgba(var(--color-foreground), 0.3);
  }
  /* The arrow after the count: its drawn shape as tall as the lettering
     (about 0.714em of digit height), the shaft and head filling the box's
     width. */
  .product-showcase__rating-arrow {
    display: inline-flex;
    align-self: center;
    flex: 0 0 auto;
    color: rgba(var(--color-foreground), var(--ink-muted));
    transform: translateY(-0.075em);
  }
  .product-showcase__rating-arrow svg {
    display: block;
    width: auto;
    height: 0.82em;
  }
  .product-showcase__rating--link:hover {
    border-color: rgba(var(--color-foreground), 0.75);
    background: rgba(var(--color-foreground), 0.08);
  }
  .product-showcase__rating--link:focus-visible {
    outline: 0.2rem solid currentColor;
    outline-offset: 0.2rem;
  }

  /* The reviews drawer: slides in from the right over a dimmed page. Colours
     are set here rather than inherited, so a flavor panel's own scheme can't
     leak into it. */
  .reviews-drawer {
    position: fixed;
    inset: 0 0 0 auto;
    width: min(52rem, 100vw);
    max-width: 100vw;
    height: 100dvh;
    max-height: 100dvh;
    margin: 0;
    padding: 0;
    border: 0;
    background: #fff;
    color: #17181c;
    flex-direction: column;
    overflow: hidden;
    box-shadow: -1.6rem 0 4.8rem rgba(0, 0, 0, 0.18);
    transform: translateX(100%);
    transition: transform 0.35s ease, overlay 0.35s ease allow-discrete, display 0.35s ease allow-discrete;
  }
  .reviews-drawer[open] {
    display: flex;
    transform: translateX(0);
  }
  @starting-style {
    .reviews-drawer[open] {
      transform: translateX(100%);
    }
  }
  .reviews-drawer::backdrop {
    background: rgba(0, 0, 0, 0.45);
    opacity: 0;
    transition: opacity 0.35s ease, overlay 0.35s ease allow-discrete, display 0.35s ease allow-discrete;
  }
  .reviews-drawer[open]::backdrop {
    opacity: 1;
  }
  @starting-style {
    .reviews-drawer[open]::backdrop {
      opacity: 0;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .reviews-drawer,
    .reviews-drawer::backdrop {
      transition: none;
    }
  }
  html.reviews-drawer-open {
    overflow: hidden;
  }
  .reviews-drawer__header {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
    padding: var(--space-s) var(--space-m);
    border-bottom: 0.1rem solid rgba(23, 24, 28, 0.12);
  }
  .reviews-drawer__title {
    margin: 0;
    font-size: var(--text-title);
    font-weight: 700;
    line-height: 1.2;
  }
  .reviews-drawer__close {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 4.4rem;
    height: 4.4rem;
    margin: 0 -1.2rem 0 0;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    color: inherit;
    cursor: pointer;
  }
  .reviews-drawer__close:hover {
    background: rgba(23, 24, 28, 0.06);
  }
  .reviews-drawer__close svg {
    width: 1.6rem;
    height: 1.6rem;
  }
  .reviews-drawer__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-m);
    overscroll-behavior: contain;
  }
  /* "Loading reviews…" until Junip's widget has rendered into the span. */
  .reviews-drawer__body::before {
    content: attr(data-loading-text);
    display: block;
    color: rgba(23, 24, 28, 0.6);
    font-size: var(--text-caption);
  }
  .reviews-drawer__body:has(.junip-product-review-rendered)::before {
    display: none;
  }
  /* No "Write a review" button in the drawer: reviews written there aren't tied
     to an order, so new reviews come only from Junip's post-purchase emails and
     stay verified. */
  .reviews-drawer .junip-write-review-cta {
    display: none;
  }
  /* "Verified buyer" as a badge: a neutral pill in the same shape as the
     age-verification badge, with the seal drawn as tall as the lettering. */
  /* The order inside each review: the stars with the date at their right, the
     message, then one row with the reviewer (avatar, name, Verified badge) on the
     left and the flavor and strength bought at its right. Junip's markup puts the reviewer
     first, so the list item and the stars row are dissolved (display: contents)
     and their parts placed on one grid. */
  /* One review = one message bubble, set out like a conversation: the customer's
     review is a warm off-white bubble on the right at 90% of the width, and diip's
     reply a light bubble on the left at 90%. The review bubble holds the stars (with the
     date), the message and the reviewer row (avatar, name, Verified badge, flavor
     and strength); it is drawn as a background layer (the ::before below) behind
     the first rows of the review's grid, so the reply, on the last row, sits
     outside it. The grid's columns are: a 10% spacer, the bubble's left padding,
     the content, the right-hand items (date, flavor) and the bubble's right
     padding, so the bubble starts at 10%. Junip's markup puts the reviewer first, so
     the list item and the stars row are dissolved (display: contents) and their
     parts placed on the grid. No divider lines between reviews, just space. */
  .reviews-drawer .junip-reviews-container {
    display: flex;
    flex-direction: column;
    gap: var(--space-xl);
    padding: var(--space-m) 0 0;
  }
  .reviews-drawer .junip-reviews-container > .junip-separator {
    display: none;
  }
  .reviews-drawer .junip-review-list-item-container {
    position: relative;
    isolation: isolate;
    display: grid;
    grid-template-columns: 10% var(--space-m) minmax(0, 1fr) auto var(--space-m);
    align-items: center;
    column-gap: 0;
    row-gap: var(--space-s);
    padding: var(--space-s) 0 0;
    color: #17181c;
  }
  .reviews-drawer .junip-review-list-item-container::before {
    content: '';
    grid-area: 1 / 2 / 4 / 6;
    /* The grid centres its items, which would leave this empty layer zero tall. */
    align-self: stretch;
    z-index: -1;
    margin: calc(var(--space-s) * -1) 0;
    /* The squared corner (the message tail) is on the side the bubble sits on. */
    border-radius: 1.8rem 1.8rem 0.4rem 1.8rem;
    background: #f4f3f0;
  }
  .reviews-drawer .junip-review-list-item,
  .reviews-drawer .junip-flex-wrapper {
    display: contents;
  }
  .reviews-drawer .junip-star-ratings-container {
    grid-column: 3;
    grid-row: 1;
  }
  .reviews-drawer .junip-review-content-container {
    grid-column: 3 / 5;
    grid-row: 2;
  }
  .reviews-drawer .junip-review-content-container > div {
    flex: 1 1 auto;
    min-width: 0;
  }
  .reviews-drawer .junip-review-content-container .junip-review-title,
  .reviews-drawer .junip-review-content-container .junip-review-body {
    color: inherit;
  }
  .reviews-drawer .junip-review-content-container .junip-review-body {
    font-size: 1.5rem;
    line-height: 1.5;
  }
  .reviews-drawer .junip-review-customer {
    grid-column: 3;
    grid-row: 3;
  }
  /* A smaller avatar. */
  .reviews-drawer .junip-avatar {
    width: 3.2rem;
    min-width: 3.2rem;
    height: 3.2rem;
    min-height: 3.2rem;
  }
  .reviews-drawer .junip-avatar-image {
    width: 100%;
    height: 100%;
  }
  .reviews-drawer .junip-flex-wrapper > .junip-d-flex {
    grid-column: 4;
    grid-row: 1;
    justify-self: end;
    white-space: nowrap;
    color: rgba(23, 24, 28, 0.6);
  }
  .reviews-drawer .junip-review-product {
    grid-column: 4;
    grid-row: 3;
    justify-self: end;
    margin-top: 0;
    margin-left: var(--space-s);
    white-space: nowrap;
  }
  /* diip's reply, set like a text message and pushed to the left: one soft rounded
     bubble with a squared corner at the bottom left, 90% wide, just under the
     review bubble (it sits on the last row, outside the review bubble's background
     layer). The message, then diip's avatar and name in a row under it, at the
     left. */
  .reviews-drawer .junip-review-response-container {
    grid-column: 1 / -1;
    grid-row: 4;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.8rem;
    margin: 0.8rem 10% 0 0;
    padding: 1.2rem 1.6rem;
    border: 0;
    border-radius: 1.8rem 1.8rem 1.8rem 0.4rem;
    /* White with an outline, so it stays distinct from the off-white review bubble. */
    background: #fff;
    box-shadow: inset 0 0 0 0.1rem rgba(23, 24, 28, 0.15);
    color: #17181c;
  }
  .reviews-drawer .junip-review-response-content {
    order: 1;
    color: #17181c;
    font-size: 1.4rem;
    line-height: 1.5;
  }
  /* "Response from diip" becomes diip's own reviewer row, like the customers':
     the avatar (a 32px circle with the logo) and then the name, at the left.
     The original text is kept for screen readers but shrunk to nothing; the
     visible "diip" is generated (its empty alternative text stops it being read
     twice). */
  .reviews-drawer .junip-review-response-container .junip-review-respondent {
    /* Under the message, not above it: Junip's markup has it first. */
    order: 2;
    align-self: flex-start;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.8rem;
    margin: 0;
    font-size: 0;
    line-height: 0;
    color: #17181c;
  }
  .reviews-drawer .junip-review-response-container .junip-review-respondent::before {
    content: '';
    flex: 0 0 auto;
    width: 3.2rem;
    height: 3.2rem;
    border-radius: 50%;
    background: #17181c var(--reviews-reply-logo) center / 72% auto no-repeat;
  }
  .reviews-drawer .junip-review-response-container .junip-review-respondent::after {
    content: 'diip';
    content: 'diip' / '';
    font-size: 1.6rem;
    font-weight: 400;
    line-height: 1.4;
  }

  /* Review photos: a horizontal strip inside the bubble, under the message, that
     scrolls sideways and snaps photo by photo (swipe on a phone, trackpad or
     shift-wheel on a desktop; the thin scrollbar shows there is more). A review
     with photos gets an extra row for the strip, which pushes the reviewer row,
     the bubble's background and the reply down one. */
  .reviews-drawer .junip-review-media-container {
    grid-column: 3 / 5;
    grid-row: 3;
    display: flex;
    flex-wrap: nowrap;
    gap: 0.8rem;
    margin: 0;
    padding-bottom: 0.4rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
    min-width: 0;
  }
  .reviews-drawer .junip-review-media-container[hidden] {
    display: none;
  }
  /* The long selector outranks Junip's own sizing rule for narrow widgets
     (".junip-container-xs ... .junip-review-image-wrapper", 64px square), which
     is the one that applies in the drawer. */
  .reviews-drawer .junip-product-review-container .junip-reviews-container .junip-review-list-item-container .junip-review-list-item .junip-review-media-container .junip-review-image-wrapper {
    flex: 0 0 auto;
    width: auto;
    height: 11rem;
    overflow: hidden;
    border-radius: 1.2rem;
    cursor: zoom-in;
    scroll-snap-align: start;
  }
  .reviews-drawer .junip-review-image-wrapper[hidden] {
    display: none;
  }
  .reviews-drawer .junip-review-media-container .junip-review-image-wrapper img {
    display: block;
    width: auto;
    height: 100%;
    max-width: none;
    object-fit: cover;
  }
  .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden])) .junip-review-customer,
  .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden])) .junip-review-product {
    grid-row: 4;
  }
  .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden]))::before {
    grid-area: 1 / 2 / 5 / 6;
  }
  .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden])) .junip-review-response-container {
    grid-row: 5;
  }

  /* The enlarged photo, inside the drawer: a panel that slides in over the list,
     with the drawer's own header and the photo centred in the rest at its own size
     (down to fit if need be, never up: a review's file can be small). */
  .reviews-drawer__photo {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    background: #fff;
    visibility: hidden;
    transform: translateX(100%);
    transition: transform 0.35s ease, visibility 0.35s;
  }
  .reviews-drawer__photo.is-open {
    visibility: visible;
    transform: translateX(0);
  }
  @media (prefers-reduced-motion: reduce) {
    .reviews-drawer__photo {
      transition: none;
    }
  }
  .reviews-drawer__photo-body {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    padding: var(--space-m);
  }
  /* Centred at a modest size, not stretched to fill the drawer: the reviews app
     only hands the page a small copy (150 x 200), and blowing that up to the
     drawer's width made it a blur. 30rem is double its size, about as far as it
     holds up; narrower drawers shrink it to fit. */
  .reviews-drawer__photo-image {
    display: block;
    width: 30rem;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--radius-s, 0.8rem);
  }

  /* Too narrow for the reviewer and the flavor line side by side (a phone):
     the flavor line drops to its own line under the name row, inside the
     bubble, and the reply moves down a row. */
  @media screen and (max-width: 560px) {
    .reviews-drawer .junip-review-list-item-container::before {
      grid-area: 1 / 2 / 5 / 6;
    }
    .reviews-drawer .junip-review-product {
      grid-column: 3 / 5;
      grid-row: 4;
      justify-self: start;
      margin-left: 0;
    }
    .reviews-drawer .junip-review-response-container {
      grid-row: 5;
    }
    /* With a photo strip, one row further down again. */
    .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden])) .junip-review-product {
      grid-row: 5;
    }
    .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden]))::before {
      grid-area: 1 / 2 / 6 / 6;
    }
    .reviews-drawer .junip-review-list-item-container:has(.junip-review-media-container:not([hidden])) .junip-review-response-container {
      grid-row: 6;
    }
  }
  /* The strength after the flavor, "Butterbrew | 4": plain text in the same type,
     set off by a thin vertical divider. */
  .reviews-drawer .reviews-drawer__strength {
    display: inline-block;
    margin-left: 0.4rem;
    padding-left: 0.76rem;
    border-left: 0.1rem solid rgba(23, 24, 28, 0.3);
    color: inherit;
    font: inherit;
    line-height: 1;
    vertical-align: baseline;
  }
  /* The badge sits to the right of the reviewer's name, on the same line (it
     wraps underneath only if the name is too long for both). */
  .reviews-drawer .junip-customer-details {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.8rem;
  }
  /* The badge is a label, not a control: Junip wraps it as a tooltip (pointer
     cursor, a hover popup). No pointer, no popup. */
  .reviews-drawer .junip-tooltip,
  .reviews-drawer .junip-verified-container,
  .reviews-drawer .junip-verified,
  .reviews-drawer .junip-verified * {
    cursor: default;
  }
  .reviews-drawer .junip-verified-container {
    pointer-events: none;
  }
  .reviews-drawer .junip-verified {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    margin-top: 0;
    padding: 0.2rem 0.9rem 0.2rem 0.7rem;
    border-radius: 999px;
    background: rgba(23, 24, 28, 0.08);
    color: #17181c;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1.4;
    white-space: nowrap;
  }
  .reviews-drawer .junip-verified .junip-verified-badge {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    /* The seal fills about 93% of its box, so the box is a little taller than the
       capitals for the drawn shape to match them, then nudged onto their centre. */
    height: 0.765em;
    /* Junip fixes this box at 14px wide, wider than the seal drawn in it, which
       left a gap before the word; it is as wide as the seal instead. */
    width: auto;
    transform: translateY(-0.075em);
  }
  .reviews-drawer .junip-verified .junip-verified-badge svg {
    width: auto;
    height: 100%;
  }
  .reviews-drawer .junip-verified .junip-ml-1 {
    margin-left: 0.4rem;
    line-height: inherit;
  }
  /* No "Customer reviews" heading above the rating summary: the drawer's own
     header gives the count. (The big average with its stars and count beside the
     bars stays.) */
  .reviews-drawer .junip-product-review-title {
    display: none;
  }
  /* No underline on the rating number when hovering a bar (Junip's own hover
     style). A bar whose filter is selected keeps its underline, which is how it
     shows which filter is on. */
  .reviews-drawer .junip-product-review-bar-wrapper:not(.junip-no-hover):not(.junip-selected):hover .junip-product-review-bar-rating {
    text-decoration: none;
  }
  /* No Filter button or its dropdown, nor the line above them; the list is always
     newest first (the widget is built with sort order "mostRecent"). The rating
     bars are filters too (clicking one narrows the list), and with no Filter
     panel there'd be no way to clear that, so they are display only. */
  .reviews-drawer .junip-filters,
  .reviews-drawer .junip-product-review-container > .junip-separator {
    display: none;
  }
  /* A thin vertical line between the overall rating and the bars: the two sit in
     one row, stretched to the same height, with the line on the bars' left edge. */
  /* The summary (overall rating and bars) in a card: the same outlined, rounded
     shape as the purchase options. */
  .reviews-drawer .junip-product-review-summary-flex-wrapper {
    align-items: stretch;
    box-sizing: border-box;
    padding: var(--space-m);
    border: 0.1rem solid rgba(23, 24, 28, 0.12);
    border-radius: 1.6rem;
  }
  /* Junip's own space under the summary goes, so the gap from the card to the first
     review is the same 40px as between reviews. */
  .reviews-drawer .junip-product-review-summary-container {
    margin-bottom: 0;
  }
  .reviews-drawer .junip-product-review-bars-container {
    flex: 1 1 auto;
    min-width: 0;
    padding-left: var(--space-s);
    border-left: 0.1rem solid rgba(23, 24, 28, 0.12);
  }
  /* The rating bars: the rating number, a rounded bar filled in the rating gold, and the
     review count ("2 reviews") after it. The count is added by the script. */
  .reviews-drawer .junip-product-review-bar-wrapper {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    height: auto;
    margin: 0 0 0.8rem;
  }
  .reviews-drawer .junip-product-review-bar-rating {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    /* Both number columns (this and the count) are fixed widths with centred
       digits, so the figures line up down each column instead of staggering. */
    width: 2rem;
    margin: 0;
    text-align: center;
    color: #17181c;
    font-size: 1.4rem;
    font-weight: 600;
    line-height: 1;
  }
  .reviews-drawer .junip-product-review-bar {
    flex: 1 1 auto;
    height: 0.8rem;
    overflow: hidden;
    border-radius: 999px;
    background: rgba(23, 24, 28, 0.08);
  }
  .reviews-drawer .junip-product-review-bar-filled {
    height: 100%;
    border-radius: 999px;
    /* Inline style sets the colour, so it takes !important to override. */
    background-color: var(--junipStarColor, #fdb600) !important;
  }
  .reviews-drawer .reviews-drawer__bar-count {
    flex: 0 0 auto;
    width: 2rem;
    color: rgba(23, 24, 28, 0.6);
    font-size: 1.3rem;
    line-height: 1;
    text-align: center;
    white-space: nowrap;
  }
  /* No padding of Junip's own around the widget (it adds 32px above and below and
     16px at the sides); the drawer body's own padding is the only inset. */
  .reviews-drawer .junip-product-review-container {
    padding: 0;
  }
  /* And no "Reviewed on Junip" footer under the list, and no Helpful up / down
     vote row under each review (the whole row, so its top margin goes too). */
  .reviews-drawer .junip-powered-by-footer,
  .reviews-drawer .junip-d-flex:has(> .junip-review-vote-container) {
    display: none;
  }
/* END_SECTION:product-showcase */

/* START_SECTION:receptor-study (INDEX:65) */
.receptor-study {
    position: relative;
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-4xl), 10vh, var(--space-6xl)) 0;
    /* The brain bleeds off the left edge on purpose, and its scroll tilt can swing
       the rotated box past the section; clipped on both axes so neither adds
       scroll to the page. */
    overflow: hidden;
  }

  .receptor-study .receptor-study__inner {
    position: relative;
    z-index: 1;
    max-width: 120rem;
    margin-inline: auto;
  }

  /* The brain: an anchor point on the page's left edge at the section's mid
     height; the image and its glow are centred on it, so half sits off-screen. */
  /* --brain-hidden: how much of the image's own width sits off the left edge
     (50% would be centred on the edge; lower shows more of it). */
  .receptor-study__brain {
    --brain-hidden: 30%;
    display: none;
    position: absolute;
    top: 50%;
    left: 0;
    width: 0;
    height: 0;
    z-index: 0;
    pointer-events: none;
    /* The slide lives on this anchor, not on the image: the image's own transform
       is rewritten on every scroll frame by the tilt, and a transition there would
       smear it. */
    transition: transform 0.6s var(--diip-ease);
  }

  @media screen and (min-width: 750px) {
    .receptor-study__brain {
      display: block;
    }
  }

  .receptor-study__brain-glow {
    position: absolute;
    top: 0;
    left: 0;
    width: min(80rem, 47vw);
    aspect-ratio: 1;
    transform: translate(calc(var(--brain-hidden, 30%) * -1), -50%);
    border-radius: 50%;
    background: radial-gradient(
      circle,
      rgba(var(--color-foreground), 0.06) 0%,
      rgba(var(--color-foreground), 0.06) 35%,
      transparent 72%
    );
  }

  .receptor-study__brain-img {
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    width: min(64rem, 36vw);
    height: auto;
    /* scaleX(-1) mirrors the image; it is last so the tilt and the offset still
       act in screen terms. */
    transform: translate(calc(var(--brain-hidden, 30%) * -1), -50%) rotate(var(--scroll-rotate, 0deg)) scaleX(-1);
  }

  /* Slides off to the left, fully out of view, while the Stats tab is showing,
     and back in on Summary. The distance is the image's own width plus a margin
     (the image sits partly off the edge already), so it always clears the screen. */
  .receptor-study.is-stats-view .receptor-study__brain {
    transform: translateX(calc(min(64rem, 36vw) * -1.1));
  }

  @media (prefers-reduced-motion: reduce) {
    .receptor-study__brain {
      transition: none;
    }
  }

  .receptor-study__eyebrow {
    margin: 0 0 var(--space-m);
    text-align: center;
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .receptor-study__eyebrow--logo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
  }
  .receptor-study__eyebrow-logo {
    display: block;
    height: var(--logo-height, 2.4rem);
    aspect-ratio: var(--logo-ratio, 4);
    background-color: rgb(var(--color-foreground));
    -webkit-mask: var(--logo-src) center / contain no-repeat;
    mask: var(--logo-src) center / contain no-repeat;
  }

  .receptor-study__heading {
    margin: 0 auto var(--space-xl);
    max-width: 24ch;
    text-align: center;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  /* The plain-English summary — what everyone reads. Same measure as body
     copy elsewhere, not the wider chart grid below it, since it's prose. */
  .receptor-study__plain {
    max-width: 60rem;
    margin: 0 auto var(--space-xl);
    text-align: center;
    font-size: var(--text-body);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
  }
  .receptor-study__plain > *:first-child { margin-top: 0; }
  .receptor-study__plain > *:last-child { margin-bottom: 0; }

  /* Carousel: two slides stacked in one spot, crossfading. The viewport's height
     follows the active slide (they differ a lot) and is clipped, so the section
     resizes smoothly rather than jumping. The stacking and fading only apply once
     the script has run (.is-ready); without it both slides just sit one above the
     other, so the charts are never hidden from anyone. */
  .receptor-study__carousel {
    text-align: center;
  }

  .receptor-study__viewport {
    transition: height 0.6s var(--diip-ease);
  }

  .receptor-study__carousel.is-ready .receptor-study__viewport {
    overflow: hidden;
  }

  .receptor-study__carousel.is-ready .receptor-study__track {
    display: grid;
  }

  .receptor-study__slide {
    min-width: 0;
  }

  .receptor-study__carousel.is-ready .receptor-study__slide {
    grid-area: 1 / 1;
    align-self: start;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.5s var(--diip-ease), visibility 0s linear 0.5s;
  }

  .receptor-study__carousel.is-ready:not(.is-stats) .receptor-study__slide[data-receptor-slide="intro"],
  .receptor-study__carousel.is-ready.is-stats .receptor-study__slide[data-receptor-slide="stats"] {
    opacity: 1;
    visibility: visible;
    /* The incoming slide waits a beat for the outgoing one to clear. */
    transition: opacity 0.5s var(--diip-ease) 0.2s, visibility 0s;
  }

  /* The curve in the Stats tab. When the script is running it draws in left to
     right each time the tab opens, the way the standalone version does. */
  .receptor-study__curve {
    margin: 0 auto;
  }
  @media (prefers-reduced-motion: no-preference) {
    .receptor-study__carousel.is-ready .receptor-study__curve .blend-curve__svg {
      clip-path: inset(0 100% 0 0);
    }
    .receptor-study__carousel.is-ready.is-stats .receptor-study__curve .blend-curve__svg {
      clip-path: inset(0 -2% 0 0);
      transition: clip-path 2.2s cubic-bezier(0.22, 1, 0.36, 1) 0.3s;
    }
  }

  /* The Stats charts draw in left to right as each one comes into view, the way
     the Nootropic blend curve does: a clip wipe over the whole drawing (axes and
     all), one slow ease-out. The script adds .is-draw-ready to the section only
     when it is running, so without it the charts simply show. */
  @media (prefers-reduced-motion: no-preference) {
    .receptor-study.is-draw-ready .receptor-study__svg {
      clip-path: inset(0 100% 0 0);
    }
    .receptor-study.is-draw-ready .receptor-study__figure.is-drawn .receptor-study__svg {
      clip-path: inset(0 -2% 0 0);
      transition: clip-path 2.2s cubic-bezier(0.22, 1, 0.36, 1);
    }
  }

  /* The "what it leaves out" tiles: four across on desktop, two on a tablet or
     phone. Outlined cards in the same language as the pills and option rows,
     an icon in a small circle, a bold label, and its plain-language meaning. */
  .receptor-study__points {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-xl) 0;
    max-width: 96rem;
    margin: var(--space-xl) auto 0;
    padding: 0;
    list-style: none;
  }

  @media screen and (min-width: 990px) {
    .receptor-study__points {
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 0;
    }
  }

  .receptor-study__point {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-m);
    text-align: center;
  }

  /* Hairline dividers between tiles instead of card borders: a line on the
     left of every tile that isn't first in its row (2 across, then 4 across). */
  .receptor-study__point:nth-child(even) {
    border-left: 0.1rem solid rgba(var(--color-foreground), 0.18);
  }
  @media screen and (min-width: 990px) {
    .receptor-study__point:nth-child(even) {
      border-left: 0;
    }
    .receptor-study__point:not(:first-child) {
      border-left: 0.1rem solid rgba(var(--color-foreground), 0.18);
    }
  }

  .receptor-study__point-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 5.2rem;
    height: 5.2rem;
    margin-bottom: var(--space-xs);
    border-radius: 50%;
    background-color: rgba(var(--color-foreground), 0.06);
  }
  .receptor-study__point-icon svg {
    width: 2.4rem;
    height: 2.4rem;
  }

  .receptor-study__point-label {
    font-size: 2rem;
    line-height: 1.15;
    letter-spacing: -0.01em;
    font-weight: 700;
    white-space: nowrap;
  }

  .receptor-study__point-meaning {
    font-size: var(--text-sm);
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink));
  }

  /* Tabs: a small centred pill switch. The selected tab is filled in the
     section's ink (the same treatment as the selected flavor and strength pills),
     the other is outlined text. Hidden until the script is running, since
     without it there is nothing to switch. */
  .receptor-study__tabs {
    position: relative;
    display: none;
    margin: 0 auto var(--space-xl);
    padding: 0.3rem;
    width: fit-content;
    border: 0.1rem solid rgba(var(--color-foreground), 0.25);
    border-radius: var(--radius-pill);
  }

  .receptor-study__carousel.is-ready .receptor-study__tabs {
    display: flex;
    gap: 0.2rem;
  }

  /* The filled pill behind the selected tab. It is one element that slides
     between the tabs (position and width set by the script), rather than each
     tab filling in place. */
  .receptor-study__tab-indicator {
    position: absolute;
    top: 0.3rem;
    bottom: 0.3rem;
    left: 0;
    width: 0;
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
    pointer-events: none;
  }
  .receptor-study__tabs.is-animated .receptor-study__tab-indicator {
    transition: transform 0.4s var(--diip-ease), width 0.4s var(--diip-ease);
  }

  .receptor-study__tab {
    position: relative;
    z-index: 1;
    min-width: 11rem;
    min-height: 4rem;
    padding: 0 var(--space-m);
    border: 0;
    border-radius: var(--radius-pill);
    background: none;
    color: rgba(var(--color-foreground), var(--ink-muted));
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: background-color var(--motion-base) var(--diip-ease), color var(--motion-base) var(--diip-ease);
  }
  .receptor-study__tab:hover {
    color: rgb(var(--color-foreground));
  }
  .receptor-study__tab.is-active {
    color: rgb(var(--color-background));
  }
  .receptor-study__tab:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }

  @media (prefers-reduced-motion: reduce) {
    .receptor-study__tabs.is-animated .receptor-study__tab-indicator,
    .receptor-study__viewport,
    .receptor-study__carousel.is-ready .receptor-study__slide,
    .receptor-study__carousel.is-ready:not(.is-stats) .receptor-study__slide[data-receptor-slide="intro"],
    .receptor-study__carousel.is-ready.is-stats .receptor-study__slide[data-receptor-slide="stats"] {
      transition: none;
    }
  }

  /* All three at once, not behind tabs. Each chart tells a different story on
     the same axes — one stays below the reference, one crosses it, one ends
     above it — and the honest reading is all three side by side. Hiding two of
     them behind a selector would leave the reader with whichever one was open. */
  .receptor-study__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-2xl) var(--space-l);
    margin-top: var(--space-xl);
  }

  /* Under 990px (a phone or a tablet) the three charts are a row you swipe
     sideways, one card at a time, with the next card showing at the edge, instead
     of three tall cards stacked. All three are still there to be reached; the
     honest reading is still all three on the same axes. */
  @media screen and (max-width: 989px) {
    .receptor-study__grid {
      display: flex;
      gap: var(--space-m);
      overflow-x: auto;
      overscroll-behavior-x: contain;
      scroll-snap-type: x mandatory;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
    }
    .receptor-study__grid::-webkit-scrollbar {
      display: none;
    }
    /* Each chart is a bit narrower than the row, so the next one shows at the
       edge: the cue that there is more to swipe to. */
    .receptor-study__card {
      /* 80% of the row on a phone; on a tablet that was far too big a chart, so it is
         capped at 32rem (two charts across, the third peeking in). */
      flex: 0 0 min(80%, 32rem);
      min-width: 0;
      scroll-snap-align: start;
    }
  }

  @media screen and (min-width: 990px) {
    .receptor-study__grid {
      grid-template-columns: repeat(3, 1fr);
      /* Wider than the mobile column-gap above — with the divider added,
         the tighter gap read as the charts crowding the hairline rather
         than sitting in their own column. One value, reused below, so the
         divider stays centred in it whatever it's set to. */
      --receptor-grid-gap: clamp(var(--space-2xl), 6vw, var(--space-4xl));
      column-gap: var(--receptor-grid-gap);
    }

    /* A hairline centred in the column gap, not on a card edge — the card
       itself keeps no border, so the divider doesn't shift if the gap size
       ever changes. Only between columns, so the first card gets none. */
    .receptor-study__card {
      position: relative;
    }
    .receptor-study__card:not(:first-child)::before {
      content: "";
      position: absolute;
      top: 0;
      bottom: 0;
      left: calc(var(--receptor-grid-gap) / -2);
      width: 0.1rem;
      background-color: var(--hairline);
    }
  }

  /* --text-heading (up to 4.4rem) was sized for a page-level heading, not a
     card label — on a single, full-width column (anything under 990px) a
     name with slashes in it ("α6/3/β2β3") wrapped across three lines at that
     size. --text-title still reads as a heading in the card without doing
     that. */
  .receptor-study__name {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-title);
    line-height: 1.15;
    letter-spacing: -0.02em;
    font-weight: 400;
  }

  /* Reserved height so the three charts start on one line whatever the
     description length; the longest wraps to three lines at this width. */
  .receptor-study__desc {
    margin: 0 0 var(--space-m);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
    text-wrap: pretty;
  }

  @media screen and (min-width: 990px) {
    .receptor-study__desc {
      min-height: 6em;
    }
  }

  .receptor-study__figure {
    margin: 0;
  }

  .receptor-study__axis-title {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .receptor-study__axis-title--x {
    margin: var(--space-xs) 0 0;
    text-align: center;
  }

  .receptor-study__svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
  }

  .receptor-study__axis,
  .receptor-study__tick {
    fill: none;
    stroke: rgba(var(--color-foreground), var(--ink-muted));
    stroke-width: 1;
    stroke-linecap: square;
  }

  .receptor-study__tick-label {
    fill: rgba(var(--color-foreground), var(--ink-muted));
    font-family: inherit;
    font-size: 11px;
  }

  .receptor-study__line {
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  /* Solid against dotted, as in the source figures — separable without colour
     and at low contrast. */
  .receptor-study__line--series {
    stroke: rgb(var(--color-foreground));
    stroke-width: 2.5;
  }

  .receptor-study__line--reference {
    stroke: rgba(var(--color-foreground), var(--ink-muted));
    stroke-width: 2;
    stroke-dasharray: 1 6;
  }

  .receptor-study__legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-xs) var(--space-m);
    margin: var(--space-s) 0 0;
    font-size: var(--text-caption);
  }

  .receptor-study__key {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
  }

  .receptor-study__key::before {
    content: "";
    width: 2.4rem;
    height: 0;
    border-top: 0.25rem solid rgb(var(--color-foreground));
  }

  .receptor-study__key--reference {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .receptor-study__key--reference::before {
    border-top-style: dotted;
    border-top-color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .receptor-study__footnote {
    margin: var(--space-xl) auto 0;
    max-width: 72rem;
    text-align: center;
    font-size: var(--text-caption);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .receptor-study__inner > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .receptor-study__inner > * {
      opacity: 1;
      transform: none;
    }
  }
/* END_SECTION:receptor-study */

/* START_SECTION:timeline (INDEX:69) */
.timeline {
    padding: var(--space-5xl) var(--diip-gutter, 2.4rem);
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
  }
  .timeline__inner {
    max-width: 120rem;
    margin: 0 auto;
  }
  .timeline__header {
    max-width: 72rem;
    margin: 0 0 var(--space-3xl);
  }
  .timeline__eyebrow {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-sm);
    font-weight: 600;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .timeline__heading {
    margin: 0;
    font-size: var(--text-heading);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: rgb(var(--color-foreground));
  }
  .timeline__text {
    margin: var(--space-s) 0 0;
    font-size: var(--text-lead);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink));
  }

  /* A vertical line with a dot per period on a phone. */
  .timeline__steps {
    position: relative;
    display: grid;
    gap: var(--space-xl);
    margin: 0;
    padding: 0 0 0 var(--space-l);
    list-style: none;
  }
  .timeline__steps::before {
    content: '';
    position: absolute;
    top: 0.6rem;
    bottom: 0.6rem;
    left: 0.5rem;
    width: 0.1rem;
    background: rgba(var(--color-foreground), 0.25);
  }
  .timeline__step {
    position: relative;
  }
  .timeline__step::before {
    content: '';
    position: absolute;
    top: 0.5rem;
    left: calc(var(--space-l) * -1);
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    background: rgb(var(--color-foreground));
    box-shadow: 0 0 0 0.5rem rgb(var(--color-background));
  }
  .timeline__period {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: 0.02em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .timeline__title {
    margin: 0 0 var(--space-xs);
    font-size: var(--text-title);
    font-weight: 700;
    line-height: 1.2;
    color: rgb(var(--color-foreground));
  }
  .timeline__note {
    margin: 0;
    font-size: var(--text-body);
    line-height: 1.55;
    color: rgba(var(--color-foreground), var(--ink));
  }
  .timeline__disclaimer {
    max-width: 72rem;
    margin: var(--space-3xl) 0 0;
    font-size: var(--text-caption);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  /* A phone: less air above and below, the header closer to the periods. */
  @media screen and (max-width: 749px) {
    .timeline {
      padding-block: var(--space-3xl);
    }
    .timeline__header {
      margin-bottom: var(--space-xl);
    }
    .timeline__disclaimer {
      margin-top: var(--space-xl);
    }
  }

  /* A tablet: two columns of periods, each under its own line with a dot on it,
     instead of one thin column down the left of a wide screen. */
  @media screen and (min-width: 750px) and (max-width: 989px) {
    .timeline {
      padding-block: var(--space-4xl);
    }
    .timeline__steps {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-xl) var(--space-xl);
      padding: 0;
    }
    .timeline__steps::before {
      display: none;
    }
    .timeline__step {
      padding-top: var(--space-m);
      border-top: 0.1rem solid rgba(var(--color-foreground), 0.25);
    }
    .timeline__step::before {
      top: -0.6rem;
      left: 0;
    }
  }

  /* Side by side along a horizontal line wherever there is room. */
  @media screen and (min-width: 990px) {
    .timeline__steps {
      grid-template-columns: repeat(var(--timeline-count), minmax(0, 1fr));
      gap: var(--space-l);
      padding: var(--space-l) 0 0;
    }
    .timeline__steps::before {
      top: 0.5rem;
      bottom: auto;
      left: 0;
      right: 0;
      width: auto;
      height: 0.1rem;
    }
    .timeline__step::before {
      top: calc(var(--space-l) * -1 - 0.05rem);
      left: 0;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    .timeline[data-timeline-reveal] .timeline__header,
    .timeline[data-timeline-reveal] .timeline__step,
    .timeline[data-timeline-reveal] .timeline__disclaimer {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    .timeline[data-timeline-reveal].is-visible .timeline__header,
    .timeline[data-timeline-reveal].is-visible .timeline__step,
    .timeline[data-timeline-reveal].is-visible .timeline__disclaimer {
      opacity: 1;
      transform: none;
    }
    .timeline[data-timeline-reveal].is-visible .timeline__step:nth-child(2) { transition-delay: 0.08s; }
    .timeline[data-timeline-reveal].is-visible .timeline__step:nth-child(3) { transition-delay: 0.16s; }
    .timeline[data-timeline-reveal].is-visible .timeline__step:nth-child(4) { transition-delay: 0.24s; }
    .timeline[data-timeline-reveal].is-visible .timeline__step:nth-child(5) { transition-delay: 0.32s; }
  }
/* END_SECTION:timeline */

/* START_SECTION:video-showcase (INDEX:70) */
/* An app's widget (or pasted embed) under the heading, full width.

     Scaled up from the centre (--embed-scale, a section setting): the app lays
     its clips out at a size of its own with no setting for it, and at that size
     the text burned into the videos (a creator's handle, a caption) is too small
     to read. A transform scales only the rendering, so the app's own layout
     maths is untouched; the script below adds back the vertical room the scaled
     widget takes, and the section clips what spills past the page edges. Desktop
     and tablet only: on a phone the clip already fills the screen. */
  .video-showcase__embed {
    /* --embed-extra is the room the scaled widget takes (set by the script);
       the top margin adds it to the normal gap under the heading. The active
       clip in a coverflow also stands taller than the widget's own box, hence
       the larger base gap. */
    margin-top: calc(var(--space-2xl) + var(--embed-extra, 0px));
    margin-bottom: var(--embed-extra, 0px);
  }

  /* Spark's carousel is a 3D coverflow: a large centre clip with smaller, angled
     clips either side, each positioned by inline transform, scale, depth and
     opacity. Flattened here to the same look as the section's own clip row: equal
     tall cards side by side. !important because the app writes these as inline
     styles on every slide as it moves. */
  .video-showcase__embed .swiper-slide {
    transform: none !important;
    z-index: auto !important;
    opacity: 1 !important;
    filter: none !important;
  }
  .video-showcase__embed .swiper {
    perspective: none !important;
  }

  @media screen and (min-width: 750px) {
    .video-showcase {
      overflow-x: clip;
    }

    /* On a wrapper inside the embed, not on the embed itself: the section's
       fade-in rules set transform on every direct child of the inner container
       and would override a scale put there. */
    .video-showcase__embed-scale {
      transform: scale(var(--embed-scale, 1));
      transform-origin: center;
    }
  }

  .video-showcase {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-3xl), 8vh, var(--space-6xl)) 0;
  }

  .video-showcase__inner {
    text-align: center;
  }

  .video-showcase__eyebrow {
    margin: 0 0 var(--space-m);
    font-size: var(--text-caption);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .video-showcase__heading {
    margin: 0 auto var(--space-2xl);
    max-width: 32ch;
    font-size: var(--text-heading);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  /* Scroll-snap row, full-bleed past the page's own gutter so the first and
     last card aren't flush against the padding — same construction as the
     ingredient tabs' mobile row. */
  .video-showcase__row {
    display: flex;
    gap: var(--space-m);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    margin-inline: calc(var(--diip-gutter, 2.4rem) * -1);
    padding-inline: var(--diip-gutter, 2.4rem);
  }
  .video-showcase__row::-webkit-scrollbar {
    display: none;
  }

  .video-showcase__card {
    flex: 0 0 auto;
    width: min(26rem, 72vw);
    scroll-snap-align: center;
    text-align: left;
  }

  .video-showcase__frame {
    position: relative;
    aspect-ratio: 9 / 16;
    overflow: hidden;
    border-radius: var(--radius-m);
    background-color: rgba(var(--color-foreground), 0.05);
  }

  .video-showcase__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  .video-showcase__frame.placeholder .video-showcase__video {
    object-fit: contain;
    padding: var(--space-xl);
    opacity: 0.4;
  }

  .video-showcase__sound {
    position: absolute;
    right: var(--space-s);
    bottom: var(--space-s);
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.6rem;
    height: 3.6rem;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    cursor: pointer;
  }
  .video-showcase__sound svg {
    width: 1.8rem;
    height: 1.8rem;
  }
  .video-showcase__sound svg + svg {
    display: none;
  }
  .video-showcase__sound[aria-pressed='true'] svg:first-child {
    display: none;
  }
  .video-showcase__sound[aria-pressed='true'] svg + svg {
    display: block;
  }
  /* The pause button sits left of the sound one. */
  .video-showcase__pause {
    right: calc(var(--space-s) + 4.4rem);
  }
  .video-showcase__sound:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .video-showcase__caption {
    margin: var(--space-s) 0 0;
    font-size: var(--text-sm);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .video-showcase__inner > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .video-showcase__inner > * {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .video-showcase__heading { transition-delay: var(--motion-stagger); }
    [data-reveal].is-visible .video-showcase__row { transition-delay: calc(var(--motion-stagger) * 2); }
  }
/* END_SECTION:video-showcase */

/* START_SECTION:why-pink (INDEX:72) */
.why-pink {
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    padding: clamp(var(--space-4xl), 10vh, var(--space-6xl)) 0;
  }

  /* Doubled selector so the max-width survives the theme-wide
     .page-width { max-width: none } full-bleed rule. */
  .why-pink .why-pink__inner {
    max-width: 120rem;
    margin-inline: auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
    gap: var(--space-2xl);
  }

  .why-pink__media {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .why-pink__image {
    display: block;
    width: auto;
    max-width: min(100%, var(--photo-width, 22rem));
    height: auto;
    max-height: 36rem;
    object-fit: contain;
  }

  .why-pink__placeholder {
    background-color: rgba(var(--color-foreground), 0.06);
  }

  .why-pink__eyebrow {
    margin: 0 0 var(--space-m);
    font-size: var(--text-caption);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .why-pink__heading {
    margin: 0 0 var(--space-m);
    max-width: 18ch;
    font-size: var(--text-heading);
    line-height: 1.08;
    letter-spacing: -0.02em;
    font-weight: 700;
    text-wrap: balance;
  }

  .why-pink__body {
    max-width: 48rem;
    font-size: var(--text-body);
    line-height: 1.6;
    color: rgba(var(--color-foreground), var(--ink));
  }
  .why-pink__body > *:first-child { margin-top: 0; }
  .why-pink__body > *:last-child { margin-bottom: 0; }

  /* Photo left, copy right from tablet up, with a hairline between them,
     centred on the section like the other two-column sections. */
  @media screen and (min-width: 750px) {
    .why-pink .why-pink__inner {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      gap: 0;
    }
    .why-pink__media {
      padding-right: clamp(var(--space-xl), 5vw, var(--space-4xl));
      border-right: 0.1rem solid var(--hairline);
    }
    .why-pink__copy {
      padding-left: clamp(var(--space-xl), 5vw, var(--space-4xl));
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-reveal] .why-pink__inner > * {
      opacity: 0;
      transform: translateY(2rem);
      transition: opacity var(--motion-slow) var(--diip-ease), transform var(--motion-slow) var(--diip-ease);
    }
    [data-reveal].is-visible .why-pink__inner > * {
      opacity: 1;
      transform: none;
    }
    [data-reveal].is-visible .why-pink__copy { transition-delay: var(--motion-stagger); }
  }
/* END_SECTION:why-pink */

/* CSS from snippet stylesheet tags */
/* START_SNIPPET:age-badge (INDEX:73) */
.age-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.2rem 0.9rem 0.2rem 0.7rem;
    border-radius: 999px;
    background-color: #ffe9a8;
    color: #5a3b00;
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: 0;
    white-space: nowrap;
  }
  .age-badge__icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
  }
  /* The drawn triangle fills about 94% of its box's height, so the box is sized
     (in em of the badge's own type) for the triangle to be the height of the
     capitals (0.714em) it sits beside, then nudged onto their centre. Measured. */
  .age-badge__icon svg {
    width: auto;
    height: 0.762em;
    fill: currentColor;
    transform: translateY(-0.03em);
  }
/* END_SNIPPET:age-badge */

/* START_SNIPPET:blend-curve (INDEX:75) */
/* ---- The curve ---------------------------------------------------------
     Wider than the copy above it. The copy is a measure, capped for reading;
     the curve is a diagram, and its argument is the difference between two
     shapes, which needs length to be legible. */
  .blend-curve {
    margin: var(--space-2xl) auto 0;
    max-width: 88rem;
    width: 100%;
  }

  .blend-curve__svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
  }

  /* Quiet enough to stay furniture — they frame the drawing, they aren't part
     of it. The y label sits above the curve rather than rotated beside it:
     rotated text costs a column of width the chart needs, and reads worse at
     caption size than it does in a dense report. */
  .blend-curve__axis-label {
    margin: 0;
    font-size: var(--text-caption);
    letter-spacing: 0.06em;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .blend-curve__axis-label--y {
    margin-bottom: var(--space-xs);
    text-align: left;
  }

  .blend-curve__axis-label--x {
    margin-top: var(--space-xs);
    text-align: right;
  }

  .blend-curve__axis {
    stroke: rgba(var(--color-foreground), 0.18);
    stroke-width: 1;
  }

  /* Round caps and joins so the curves read as drawn strokes rather than
     charted output — this is an illustration, and it should look like one. */
  .blend-curve__line {
    fill: none;
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  /* The three singles share one muted tone and separate by pattern. Tone would
     have had to split four ways otherwise, and the quietest of them would have
     dropped below what's legible on a mid-grey background. */
  .blend-curve__line--spike,
  .blend-curve__line--plateau,
  .blend-curve__line--build {
    stroke: rgba(var(--color-foreground), 0.42);
  }

  .blend-curve__line--spike {
    stroke-dasharray: 5 6;
  }

  .blend-curve__line--plateau {
    stroke-dasharray: 1 7;
  }

  .blend-curve__line--build {
    stroke-dasharray: 14 6 2 6;
  }

  /* The only solid line, and the only one at full strength — the eye should
     find it without being told which one it is. */
  .blend-curve__line--blend {
    stroke: rgb(var(--color-foreground));
    stroke-width: 3.5;
  }

  .blend-curve__legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs) var(--space-m);
    margin: var(--space-s) 0 0;
    font-size: var(--text-caption);
  }

  /* The swatch repeats the line's own treatment — dashed for the one that
     spikes, solid for the one that holds — so the key is read off the drawing
     rather than off a colour. */
  .blend-curve__key {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    color: rgba(var(--color-foreground), var(--ink));
  }

  .blend-curve__key::before {
    content: "";
    width: 2.4rem;
    height: 0;
    border-top-width: 0.25rem;
    border-top-style: solid;
  }

  .blend-curve__key--spike::before,
  .blend-curve__key--plateau::before,
  .blend-curve__key--build::before {
    border-top-color: rgba(var(--color-foreground), 0.42);
  }

  .blend-curve__key--spike::before {
    border-top-style: dashed;
  }

  .blend-curve__key--plateau::before {
    border-top-style: dotted;
  }

  /* No CSS border style matches the dash-dot the line uses, so the swatch is
     drawn as a gradient instead — the pattern is what identifies the line, so
     it has to be the pattern and not an approximation of it. */
  .blend-curve__key--build::before {
    border-top-color: transparent;
    height: 0.25rem;
    border-top-width: 0;
    background-image: repeating-linear-gradient(
      to right,
      rgba(var(--color-foreground), 0.42) 0 0.7rem,
      transparent 0.7rem 1rem,
      rgba(var(--color-foreground), 0.42) 1rem 1.1rem,
      transparent 1.1rem 1.4rem
    );
  }

  .blend-curve__key--blend {
    font-weight: 700;
  }

  .blend-curve__key--blend::before {
    border-top-color: rgb(var(--color-foreground));
    border-top-width: 0.35rem;
  }

  .blend-curve__note {
    flex-basis: 100%;
    text-align: center;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
/* END_SNIPPET:blend-curve */

/* START_SNIPPET:buy-buttons (INDEX:77) */
.product-form__pre-order-note {
    margin: var(--space-s) 0 0;
    font-size: var(--text-caption);
    line-height: 1.4;
    text-align: center;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
/* END_SNIPPET:buy-buttons */

/* START_SNIPPET:card-buy (INDEX:78) */
/* Registered so the hover fill can be animated; an unregistered custom
     property is a string to the transition machinery. Own names, so this doesn't
     collide with the showcase button's. */
  @property --buy-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  /* In the card's last grid row, above the title link's whole-card click area
     (Dawn stretches that link over the card, so anything that has to be pressed
     has to sit above it). */
  .card-buy {
    position: relative;
    z-index: 2;
    grid-row-start: 4;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    row-gap: var(--space-s);
    column-gap: var(--space-xs);
    margin-top: var(--space-m);
  }

  /* Dawn pads the bottom of the text block by 17px, which would stack on this
     margin for an off-scale 33px between the rating and the strength. With the
     controls below it, that padding has nothing to do, so the margin above is the
     whole gap. */
  .card__content:has(> .card-buy) > .card__information {
    padding-bottom: 0;
  }

  /* Wrappers that only exist to hold a form and its parts: removed from the
     layout so the pills, the stepper and the button are one flex row's items,
     though the fieldset sits outside the form and the other two inside. */
  .card-buy__form,
  .card-buy__buy {
    display: contents;
  }

  .card-buy__error {
    flex: 1 0 100%;
    order: 0;
  }

  /* ---- Strength ---- */
  .card-buy__variants {
    order: 1;
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
  }

  .card-buy__variants-label {
    padding: 0;
    margin: 0 0 var(--space-xs);
    font-size: var(--text-caption);
    text-transform: lowercase;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .card-buy__variant-options {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
  }

  .card-buy__variant {
    position: relative;
    cursor: pointer;
  }

  .card-buy__variant input {
    position: absolute;
    opacity: 0;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
  }

  .card-buy__variant span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap-target);
    min-height: var(--tap-target);
    padding: var(--space-xs) var(--space-s);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    font-weight: 700;
    transition: border-color var(--motion-fast) var(--diip-ease),
      background-color var(--motion-fast) var(--diip-ease);
  }

  .card-buy__variant input:checked + span {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.08);
  }

  .card-buy__variant input:focus-visible + span {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .card-buy__variant--soldout span {
    opacity: 0.4;
    text-decoration: line-through;
  }

  /* ---- Quantity ---- */
  .card-buy__qty {
    order: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .card-buy__qty-control {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-target);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    overflow: hidden;
  }

  .card-buy__qty-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target);
    min-height: var(--tap-target);
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: var(--text-body);
    line-height: 1;
    cursor: pointer;
  }

  .card-buy__qty-step:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: -0.2rem;
    border-radius: var(--radius-pill);
  }

  .card-buy__qty-step:disabled {
    opacity: 0.35;
    cursor: not-allowed;
  }

  .card-buy__qty-input {
    width: 3.2rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
    appearance: textfield;
    -moz-appearance: textfield;
  }

  .card-buy__qty-input::-webkit-outer-spin-button,
  .card-buy__qty-input::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }

  /* ---- Buy button ---- */
  /* Its own full-width line: with the price and the icon in it, it doesn't fit
     beside the stepper at a card's width. */
  .card-buy__cta {
    order: 3;
    flex: 1 0 100%;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap-target);
    padding: 0 var(--space-m);
    border: 0;
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
    text-decoration: none;

    /* The hover circle is painted into the button's own background, not a child
       element, so there is one edge and one antialiasing pass (a child clipped
       to a rounded parent leaves a seam). */
    background-image: radial-gradient(
      circle calc(var(--buy-d) / 2) at var(--buy-x) var(--buy-y),
      rgb(var(--color-background)) 0 99%,
      transparent 100%
    );
    --buy-x: 50%;
    --buy-y: 50%;
    --buy-d: 0px;
    transition: --buy-d var(--motion-base) var(--diip-ease);
  }

  .card-buy__cta:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .card-buy__cta[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .card-buy__cta-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    position: relative;
    z-index: 1;
  }

  /* The inverted copy, clipped to exactly the circle, so the label stays
     readable wherever the fill covers it. */
  .card-buy__cta-label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-foreground));
    clip-path: circle(calc(var(--buy-d) / 2) at var(--buy-x) var(--buy-y));
    pointer-events: none;
  }

  .card-buy__cta .loading__spinner {
    position: relative;
    z-index: 3;
  }

  .card-buy__cta-icon {
    display: inline-flex;
    flex: 0 0 auto;
  }

  /* A solid bag: the outline cart's line is under a pixel at this size and
     disappears against the dark fill. Nudged up because the glyph is
     bottom-heavy; the figure is specific to this artwork. */
  .card-buy__cta-icon svg {
    width: 1em;
    height: 1em;
    transform: translateY(-2.9%);
  }

  /* Outline, not filled — secondary to the buy button above it by design (one
     clear primary action per card), not because it's inactive: it's a real
     submit button, wired to Recharge's own selling plan. No font-family
     override, deliberately — it matches whatever .card-buy__cta above it
     renders as (the browser's own button font), rather than picking its own
     and drifting from it. */
  @property --sub-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  .card-buy__subscribe {
    order: 4;
    flex: 1 0 100%;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap-target);
    padding: 0 var(--space-m);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background-color: transparent;
    color: rgba(var(--color-foreground), var(--ink-muted));
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;

    /* Same construction as the buy button's hover fill: painted into the
       button's own background rather than a child element, so there's one
       edge and one antialiasing pass. Fills with the foreground colour here
       (the button starts transparent, not foreground-filled), so the label
       needs to invert to the background colour inside the circle instead. */
    background-image: radial-gradient(
      circle calc(var(--sub-d) / 2) at var(--sub-x) var(--sub-y),
      rgb(var(--color-foreground)) 0 99%,
      transparent 100%
    );
    --sub-x: 50%;
    --sub-y: 50%;
    --sub-d: 0px;
    transition: --sub-d var(--motion-base) var(--diip-ease), border-color var(--motion-fast) var(--diip-ease);
  }

  .card-buy__subscribe:hover {
    border-color: rgba(var(--color-foreground), 0.5);
  }

  .card-buy__subscribe:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .card-buy__subscribe[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .card-buy__subscribe-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    position: relative;
    z-index: 1;
  }

  /* The inverted copy, clipped to exactly the circle, so the label stays
     readable wherever the fill covers it — background colour on the
     foreground-coloured fill, the reverse of the button's resting state. */
  .card-buy__subscribe-label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-background));
    clip-path: circle(calc(var(--sub-d) / 2) at var(--sub-x) var(--sub-y));
    pointer-events: none;
  }

  .card-buy__subscribe-icon {
    display: inline-flex;
    flex: 0 0 auto;
  }
  /* The bag icon's own artwork sits well inside its viewBox (room for the
     handle), where arrows-rotate's fills edge to edge — the same 1em box
     around both left this one reading visibly bigger. Sized down to match
     how large the two actually look next to each other, not their boxes. */
  .card-buy__subscribe-icon svg {
    width: 0.8em;
    height: 0.8em;
  }
/* END_SNIPPET:card-buy */

/* START_SNIPPET:card-product (INDEX:80) */
/* "New", switched on by giving the product the tag "new" in the admin (remove
     the tag to switch it off). The same quiet pill as the product showcase's
     note: the card's own text colour at an 8% wash, a dot, lowercase. Sits at the
     right end of the title and rating, centred on the pair. Only a card that has
     the badge becomes a two-column grid, so cards without it are untouched, and
     the badge is shorter than the pair so a card's height never changes. */
  .card__information:has(.card-launch-badge) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-s);
  }

  .card__information:has(.card-launch-badge) > .card__heading,
  .card__information:has(.card-launch-badge) > .card-information {
    grid-column: 1;
  }

  .card-launch-badge {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-s);
    border-radius: var(--radius-pill);
    background-color: rgba(var(--color-foreground), 0.08);
    font-size: var(--text-caption);
    line-height: 1.4;
    text-transform: lowercase;
    color: rgb(var(--color-foreground));
  }

  .card-launch-badge__dot {
    flex: 0 0 auto;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
  }

  /* The star row: one star, the score, the count, on a shared baseline. The star
     is drawn, not the ★ character (that glyph falls back to another font and sits
     low), and sized to the cap height of the text beside it so its top and bottom
     both land level with the digits. Ink follows the card's own text colour. */
  .card-rating {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
    font-size: var(--text-caption);
  }

  .card-rating__star {
    display: inline-flex;
    color: rgba(var(--color-foreground), var(--ink-strong));
  }

  .card-rating__star--empty {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .card-rating__star svg {
    flex: 0 0 auto;
    width: 0.9rem;
    height: 0.9rem;
  }

  .card-rating__score {
    font-weight: 700;
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-strong));
  }

  .card-rating__count {
    line-height: 1.4;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .card-price-was {
    margin: var(--space-xs) 0 0;
    font-size: var(--text-body);
    opacity: 0.5;
  }
/* END_SNIPPET:card-product */

/* START_SNIPPET:card-subscribe-drawer (INDEX:81) */
.options-drawer {
    position: fixed;
    z-index: 1000;
    inset: 0;
    display: flex;
    justify-content: flex-end;
    background-color: rgba(var(--color-foreground), 0.5);
    visibility: hidden;
    opacity: 0;
    transition: visibility var(--motion-base) var(--diip-ease), opacity var(--motion-base) var(--diip-ease);
  }

  .options-drawer[open] {
    visibility: visible;
    opacity: 1;
  }

  .options-drawer__dialog {
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 40rem;
    max-width: calc(100vw - 3rem);
    padding: var(--space-xl) var(--diip-gutter, 2.4rem);
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform var(--motion-base) var(--diip-ease);
  }

  .options-drawer[open] .options-drawer__dialog {
    transform: translateX(0);
  }

  @media (prefers-reduced-motion: reduce) {
    .options-drawer,
    .options-drawer__dialog {
      transition: none;
    }
  }

  .options-drawer__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-m);
    margin-bottom: var(--space-xl);
  }

  .options-drawer__title {
    margin: 0;
    font-size: var(--text-title);
    font-weight: 700;
    letter-spacing: -0.01em;
  }

  .options-drawer__close {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.6rem;
    height: 3.6rem;
    border: 0;
    background: none;
    color: rgb(var(--color-foreground));
    cursor: pointer;
  }
  .options-drawer__close svg {
    width: 1.8rem;
    height: 1.8rem;
  }
  .options-drawer__close:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .options-drawer__frequency-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-s);
    margin-bottom: var(--space-xl);
  }

  .options-drawer__frequency-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-m);
    padding: var(--space-m);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-m);
    background: none;
    color: rgb(var(--color-foreground));
    font-family: inherit;
    font-size: var(--text-body);
    font-weight: 700;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--motion-fast) var(--diip-ease), background-color var(--motion-fast) var(--diip-ease);
  }

  .options-drawer__frequency-option.is-active {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.08);
  }

  .options-drawer__frequency-option:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .options-drawer__frequency-option-price {
    font-variant-numeric: tabular-nums;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }

  .options-drawer__subscribe {
    margin-top: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    min-height: var(--tap-target);
    padding: 0 var(--space-m);
    border: 0;
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
  }
  .options-drawer__subscribe:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }
/* END_SNIPPET:card-subscribe-drawer */

/* START_SNIPPET:cart-drawer (INDEX:84) */
/* The quantity stepper and the remove button, the same as the product panel's:
     a pill with the faint border, full tap-target buttons either side of a bold
     number, and a round remove button to match. */
  :is(.cart-drawer, .cart-page) .quantity {
    display: inline-flex;
    align-items: center;
    width: auto;
    min-height: var(--tap-target);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    overflow: hidden;
  }
  :is(.cart-drawer, .cart-page) .quantity::before,
  :is(.cart-drawer, .cart-page) .quantity::after {
    display: none;
  }
  :is(.cart-drawer, .cart-page) .quantity__button {
    width: var(--tap-target);
    min-height: var(--tap-target);
    margin: 0;
  }
  :is(.cart-drawer, .cart-page) .quantity__button:first-child,
  :is(.cart-drawer, .cart-page) .quantity__button:last-child {
    margin: 0;
  }
  :is(.cart-drawer, .cart-page) .quantity__input {
    flex: 0 0 auto;
    width: 3.2rem;
    padding: 0;
    font-size: var(--text-sm);
    font-weight: 700;
    opacity: 1;
    font-variant-numeric: tabular-nums;
  }
  :is(.cart-drawer, .cart-page) .cart-item cart-remove-button {
    align-items: center;
  }
  :is(.cart-drawer, .cart-page) cart-remove-button .button {
    width: var(--tap-target);
    height: var(--tap-target);
    min-width: var(--tap-target);
    min-height: var(--tap-target);
    margin: 0;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: 50%;
    transition: background-color var(--motion-fast) var(--diip-ease),
      border-color var(--motion-fast) var(--diip-ease);
  }
  :is(.cart-drawer, .cart-page) cart-remove-button .button:hover {
    border-color: rgb(var(--color-foreground));
  }

  /* At the top of the drawer, a little air under the heading. */
  /* Buttons and form controls fall back to the browser's own font (Arial) unless
     told otherwise. Everything in the cart, drawer and page, takes the site's. */
  :is(.cart-drawer, .cart-page) :is(button, input, textarea, select) {
    font-family: inherit;
  }

  /* No underline when hovering a line's name (the theme's own rule underlines
     anything with the name's class, so even the plain-text name in the drawer). */
  :is(.cart-drawer, .cart-page) .cart-item__name:hover {
    text-decoration: none;
  }
  /* A line's name is a link to its product page, shown on hover or focus by a
     small arrow fading in after it (the same as the flavor name on the line
     pages); always there, quietly, with no hover (touch). */
  :is(.cart-drawer, .cart-page) a.cart-item__name::after {
    content: '';
    display: inline-block;
    width: 0.75em;
    height: 0.75em;
    margin-left: 0.4em;
    vertical-align: -0.02em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 8h10.5M8.5 3.5L13 8l-4.5 4.5'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: 0;
    transform: translateX(-0.4em);
    transition: opacity var(--motion-base) var(--diip-ease), transform var(--motion-base) var(--diip-ease);
  }
  :is(.cart-drawer, .cart-page) a.cart-item__name:hover::after,
  :is(.cart-drawer, .cart-page) a.cart-item__name:focus-visible::after {
    opacity: 1;
    transform: none;
  }
  @media (hover: none) {
    :is(.cart-drawer, .cart-page) a.cart-item__name::after {
      opacity: 0.55;
      transform: none;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    :is(.cart-drawer, .cart-page) a.cart-item__name::after {
      transition: none;
      transform: none;
    }
  }

  /* The header set like the reviews drawer's: a bar across the full width with a
     hairline under it, the title at the theme's title size, and a round close
     button. The drawer's side padding is the same 24px as the reviews drawer's,
     so the title, the cards and the footer share one left edge. */
  .cart-drawer .drawer__inner {
    padding-left: var(--space-m);
    padding-right: var(--space-m);
  }
  .cart-drawer .drawer__header {
    margin: 0 calc(var(--space-m) * -1);
    padding: var(--space-s) var(--space-m);
    border-bottom: 0.1rem solid rgba(23, 24, 28, 0.12);
    /* No margin under it: the gap lives inside the scrolling list instead, so lines
       scroll right up to the header's line rather than being clipped 24px short. */
    margin-bottom: 0;
  }
  .cart-drawer cart-drawer-items {
    padding-top: var(--space-m);
  }
  .cart-drawer .drawer__heading {
    margin: 0;
    font-size: var(--text-title);
    font-weight: 700;
    line-height: 1.2;
  }
  .cart-drawer .drawer__close {
    /* The theme positions it absolutely; here it is an ordinary item in the
       header row, like the reviews drawer's. */
    position: static;
    inset: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4.4rem;
    height: 4.4rem;
    margin: 0 -1.2rem 0 0;
    padding: 0;
    border-radius: 50%;
  }
  /* The empty cart has no header bar, so there the close button goes back to the
     top right corner of the drawer. */
  .cart-drawer .drawer__inner-empty {
    position: relative;
  }
  .cart-drawer .drawer__inner-empty .drawer__close {
    position: absolute;
    top: var(--space-s);
    right: var(--space-m);
    margin: 0;
  }
  .cart-drawer .drawer__close:hover {
    background: rgba(23, 24, 28, 0.06);
  }
  .cart-drawer .drawer__close svg {
    width: 1.6rem;
    height: 1.6rem;
  }

  /* The free-shipping progress in a card, the same outlined, rounded shape as the
     cart lines below it. */
  :is(.cart-drawer, .cart-page) .cart-shipping {
    box-sizing: border-box;
    padding: 1.6rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.15);
    border-radius: 1.6rem;
    /* The same 1rem as between the cart lines. */
    margin-bottom: 1rem;
  }

  /* The ZIP check (in the cart drawer and on the cart page): a caption, a pill field, and short messages, above the
     buttons. The check button and the checkout button share one slot (the script
     shows one at a time). */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip {
    display: grid;
    /* One column that can shrink: without minmax(0, ...) the grid sizes it to the
       widest content (the row of suggestion cards, which scrolls), and on a phone
       the whole footer ran past the right edge of the drawer. */
    grid-template-columns: minmax(0, 1fr);
    gap: 0.8rem;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__label,
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip .cart-drawer-zip__gate,
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip .cart-drawer-zip__estimate {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 1.2rem 1.4rem;
    border-radius: 1.2rem;
    background: #fff1c7;
    color: #5a3b00;
    font-size: 1.3rem;
    font-weight: 600;
    line-height: 1.4;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip .cart-drawer-zip__gate {
    background: #fde2e0;
    color: #8a1c14;
  }
  /* What can ship instead: one card holding the title and a plain list of
     products, one row each, with a hairline between rows. No sideways scroll (the
     Add button of one product sat right beside the next product's photo, which
     read as the two belonging together), and each row is small enough for a
     phone: photo, name over "option | price", Add. */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alts[hidden] {
    display: none;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alts {
    padding: 1rem 1.2rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: 1.2rem;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alts-title {
    margin: 0 0 0.4rem;
    font-size: 1.3rem;
    font-weight: 600;
    line-height: 1.4;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alts-track {
    display: block;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt {
    display: grid;
    grid-template-columns: 4.4rem minmax(0, 1fr) auto;
    align-items: center;
    gap: 1.2rem;
    padding: 1rem 0;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt + .cart-drawer-zip__alt {
    border-top: 0.1rem solid var(--hairline);
  }
  /* The same photo treatment as the cart lines: 4.4rem, the whole pouch shown,
     no tile behind it. */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-img {
    display: block;
    width: 4.4rem;
    height: 4.4rem;
    max-width: 100%;
    object-fit: contain;
  }
  /* The name, and under it "option | price". */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-info {
    display: grid;
    gap: 0.2rem;
    min-width: 0;
    font-size: 1.3rem;
    line-height: 1.35;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-name {
    font-weight: 600;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-divider {
    width: 0.1rem;
    height: 1.2em;
    margin: 0 0.8rem;
    background: currentColor;
    opacity: 0.4;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-price {
    white-space: nowrap;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 3.6rem;
    padding: 0 1.6rem;
    border: 0;
    border-radius: var(--radius-pill);
    background: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    font: inherit;
    font-size: 1.3rem;
    font-weight: 600;
    cursor: pointer;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__alt-add:disabled {
    opacity: 0.5;
    cursor: default;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip .cart-drawer-zip__estimate {
    background: #dff3e1;
    color: #1d5a2a;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__icon--check {
    height: 0.72em;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip:has(:is(.cart-drawer-zip__gate, .cart-drawer-zip__estimate):not([hidden])) .cart-drawer-zip__label {
    display: none;
  }
  /* The triangle's drawn shape as tall as the lettering (about 0.714em of capital
     height, the glyph filling 94% of its box), centred on the card's height. */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__icon {
    display: inline-flex;
    flex: 0 0 auto;
    height: 0.82em;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__icon svg {
    display: block;
    width: auto;
    height: 100%;
    fill: currentColor;
  }
  /* The field and the check button always split the row 50/50 (the button stays
     after the ZIP passes, to check another one). */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.8rem;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__row .cart__checkout-button {
    width: 100%;
    min-width: 0;
    padding: 0 1.2rem;
    white-space: nowrap;
  }
  /* A phone gives each half of the row about 144px: "View cart | $39.99" needs a
     little less type, padding and divider space to fit without touching the edges. */
  @media screen and (max-width: 480px) {
    :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__row .cart__checkout-button {
      padding: 0 0.8rem;
      font-size: 1.4rem;
    }
    .cart-drawer .cart-drawer-zip__row .cart__checkout-divider {
      margin: 0 0.8rem;
    }
  }
  /* Once the ZIP has passed, View cart is the one primary action: the recheck
     button steps down to an outlined one (the field's own border), so there are
     never two filled buttons at once. */
  :is(.cart-drawer .cart-drawer__footer, .cart-zip-scope)[data-zip-gate="clear"] :is(#CartDrawer-CheckZip, #CartPage-CheckZip) {
    --color-button: var(--color-foreground);
    --alpha-button-background: 0;
    background-color: transparent;
    color: rgb(var(--color-foreground));
    box-shadow: none;
  }
  :is(.cart-drawer .cart-drawer__footer, .cart-zip-scope)[data-zip-gate="clear"] :is(#CartDrawer-CheckZip, #CartPage-CheckZip)::before {
    display: none;
  }
  :is(.cart-drawer .cart-drawer__footer, .cart-zip-scope)[data-zip-gate="clear"] :is(#CartDrawer-CheckZip, #CartPage-CheckZip)::after {
    /* The theme insets this layer 1px; the filled button beside it has no such
       inset, so the outline looked 2px smaller. Draw it at the full 48px. */
    inset: 0;
    width: auto;
    height: auto;
    box-sizing: border-box;
    box-shadow: none;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
  }
  /* A clear button inside the field, at its right, while there is something to clear. */
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__field {
    position: relative;
    min-width: 0;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__field .cart-drawer-zip__input {
    padding-right: 4.4rem;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__clear {
    position: absolute;
    top: 50%;
    right: 1.2rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(var(--color-foreground), 0.08);
    color: rgb(var(--color-foreground));
    cursor: pointer;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__clear[hidden] {
    display: none;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__clear svg {
    display: block;
    width: 1.1rem;
    height: 1.1rem;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__input {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    min-height: var(--tap-target);
    padding: 0 2rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: transparent;
    color: rgb(var(--color-foreground));
    font: inherit;
    font-size: var(--text-body);
    box-sizing: border-box;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip__input:is(:focus, :focus-visible) {
    outline: none;
    box-shadow: none;
    border-color: rgb(var(--color-foreground));
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip :is(.cart-drawer-zip__error, .cart-drawer-zip__estimate, .cart-drawer-zip__gate) {
    margin: 0;
    font-size: 1.3rem;
    line-height: 1.4;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart-drawer-zip :is(.cart-drawer-zip__error, .cart-drawer-zip__estimate, .cart-drawer-zip__gate)[hidden] {
    display: none;
  }
  /* Step two (the ZIP passed): the field is gone, the row is the recheck button
     and View cart, 50/50. */
  :is(.cart-drawer .cart-drawer__footer, .cart-zip-scope)[data-zip-gate="clear"] .cart-drawer-zip__field {
    display: none;
  }
  :is(.cart-drawer, .cart-zip-scope) .cart__checkout-button[hidden] {
    display: none;
  }
  /* The list of lines scrolls, but without a visible scrollbar. */
  .cart-drawer cart-drawer-items {
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .cart-drawer cart-drawer-items::-webkit-scrollbar {
    display: none;
  }
  /* A line that can't ship to the entered ZIP is a red card (the alert's red). */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item.is-unavailable {
    border-color: #e8a7a1;
    background-color: #fff3f2;
  }
  /* The "can't ship" badge is the first thing in the card: its own row above the
     photo and name row, which (with the rows after it) move down one. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item .cart-item__unavailable {
    grid-column: 1 / 4;
    grid-row: 1;
    justify-self: start;
    margin: 0;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item:has(> .cart-item__unavailable) :is(.cart-item__media, .cart-item__title, .cart-item__totals) {
    grid-row: 2;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item:has(> .cart-item__unavailable) .cart-item__frequency {
    grid-row: 3;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item:has(> .cart-item__unavailable) .cart-item__quantity {
    grid-row: 3;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item:has(> .cart-item__unavailable):has(.cart-item__frequency) .cart-item__quantity {
    grid-row: 4;
  }

  /* The footer is the button and the line under it. The subtotal sits on the
     button after a thin divider (no bullets or middots as separators); the tax
     note under it is set like the free-shipping note under Add to cart on the
     product panels: small, muted, centred. */
  /* The footer bar runs the full width of the drawer, like the header: its
     hairline edge to edge, with the same 24px sides inside. */
  .cart-drawer .drawer__footer {
    margin: 0 calc(var(--space-m) * -1);
    padding: var(--space-s) var(--space-m);
    border-top: 0.1rem solid rgba(23, 24, 28, 0.12);
  }
  .cart-drawer .cart-drawer__footer {
    display: flex;
    flex-direction: column;
    gap: 1.2rem;
  }
  .cart-drawer .cart__checkout-button {
    gap: 0;
  }
  .cart-drawer .cart__checkout-divider {
    flex: 0 0 auto;
    width: 0.1rem;
    height: 1.4em;
    margin: 0 1.2rem;
    background: currentColor;
    opacity: 0.4;
  }
  /* One class more than the theme's cart stylesheet's own rules for these (which
     left-align the note and add space above every child of the footer block). */
  .cart-drawer .cart-drawer__footer > * + * {
    margin-top: 0;
  }
  /* The one button is the full width of the drawer. */
  .cart-drawer .cart__ctas .cart__checkout-button {
    width: 100%;
    max-width: none;
  }

  /* Was-price and now-price on one line, struck price first. */
  .cart-drawer .cart-item__totals .cart-item__price-wrapper .cart-item__discounted-prices,
  .cart-page .cart-item__totals .cart-item__price-wrapper .cart-item__discounted-prices {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: baseline;
    justify-content: flex-end;
    gap: 0.8rem;
    white-space: nowrap;
  }

  /* "Then $29.99 per delivery" under the line total, right-aligned with it. The
     icon is the lettering's height, centred on it (measured: the arrows fill
     their whole box, so 0.714em of the text size). */
  .cart-drawer .cart-item__recurring,
  .cart-page .cart-item__recurring {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.4rem;
    margin: 0.4rem 0 0;
    font-size: 1.2rem;
    line-height: 1.3;
    text-align: right;
    opacity: 0.85;
  }
  .cart-item__recurring-icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
  }
  .cart-item__recurring-icon svg {
    width: auto;
    height: 0.714em;
    fill: currentColor;
    transform: translateY(-0.007em);
  }

  /* No spinner on the line items. It only flashed while a quantity or frequency
     change was in flight; the line is still locked against double-clicks during
     that time (cart__items--disabled), and the totals and the free-shipping bar
     visibly update when the change lands. */
  :is(cart-drawer cart-drawer-items, cart-items) .loading__spinner {
    display: none !important;
  }
  /* The theme hid everything after the spinner (the price, mostly) while it was
     showing, and dimmed the price too, so the price blinked out during a change.
     Without the spinner there is nothing for it to make room for: the price
     stays put, fully visible, until the new total arrives. */
  :is(cart-drawer, cart-items) .cart-item .loading__spinner:not(.hidden) ~ * {
    visibility: visible;
  }
  :is(cart-drawer, cart-items) .loading__spinner:not(.hidden) + .cart-item__price-wrapper {
    opacity: 1;
  }

  /* Free-shipping progress at the top of the drawer's contents. */
  .cart-shipping {
    padding: 0 0 1.4rem;
  }
  .cart-shipping__text {
    margin: 0 0 0.8rem;
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.3;
  }
  .cart-shipping__track {
    height: 0.6rem;
    border-radius: 0.3rem;
    background-color: rgba(var(--color-foreground), 0.12);
    overflow: hidden;
  }
  .cart-shipping__fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background-color: rgb(var(--color-foreground));
    transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  }
  @media (prefers-reduced-motion: reduce) {
    .cart-shipping__fill {
      transition: none;
    }
  }

  .cart-item__savings {
    margin: 0;
    font-size: 1.2rem;
    line-height: 1.4;
    opacity: 0.85;
  }

  .cart-drawer .cart-item__title,
  .cart-page .cart-item__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.8rem;
  }
  .cart-item__option-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.4rem;
    height: 2.4rem;
    padding: 0 0.8rem;
    box-sizing: border-box;
    border: 0.1rem solid rgba(var(--color-foreground), 0.35);
    border-radius: 999px;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1;
  }
  /* The options no longer render as a list; hide the list when nothing else
     (line item properties) is in it. */
  .cart-drawer .cart-item__details dl:not(:has(*)),
  .cart-page .cart-item__details dl:not(:has(*)) {
    display: none;
  }

  /* Item columns: a fixed photo column, a flexible details column and the line
     total, instead of four equal columns. The details column is where the
     delivery-frequency pills live, and four equal columns left it too narrow
     for the three of them to share a row. */
  .cart-drawer .cart-items .cart-item,
  .cart-page .cart-items .cart-item {
    grid-template-columns: 10rem minmax(0, 1fr) auto;
  }
  .cart-drawer .cart-items .cart-item__details,
  .cart-page .cart-items .cart-item__details {
    grid-column: 2;
  }
  .cart-drawer .cart-items .cart-item__totals,
  .cart-page .cart-items .cart-item__totals {
    grid-column: 3;
  }
  .cart-drawer .cart-items .cart-item__quantity,
  .cart-page .cart-items .cart-item__quantity {
    grid-column: 2 / 4;
  }
  /* Dawn caps every child of the details column at 30rem; the three frequency
     pills need slightly more than that to share a row. */
  .cart-drawer .cart-items .cart-item__details .cart-item__frequency,
  .cart-page .cart-items .cart-item__details .cart-item__frequency {
    max-width: none;
  }

  /* The cart drawer and the cart page lay their lines out the same way, as a small grid: a small
     photo, the name with its strength badge, and the price all on one row; the
     frequency pills across the full width under them; the stepper last. The
     savings sentence and the "how often" label are left to the cart page. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item {
    grid-template-columns: 4.4rem minmax(0, 1fr) auto;
    column-gap: 0.8rem;
    row-gap: 0.8rem;
    align-items: center;
    /* Each line is a card: an outlined, rounded box (the same shape as the
       purchase options on the product panels) with the space between cards in
       place of the old run-together rows. */
    box-sizing: border-box;
    padding: 1.6rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.15);
    border-radius: 1.6rem;
    margin-bottom: 1rem;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__media {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    padding-top: 0;
    width: 4.4rem;
    min-width: 0;
  }
  /* In the drawer the strength is no badge: "Black Cherry | 4", plain text after
     a thin vertical divider. */
  :is(.cart-drawer, .cart-page) .cart-item__option-badge {
    display: inline-block;
    min-width: 0;
    height: auto;
    margin-left: 0;
    padding: 0 0 0 0.8rem;
    border: 0;
    border-left: 0.1rem solid rgba(var(--color-foreground), 0.3);
    border-radius: 0;
    font-size: 1.6rem;
    font-weight: 400;
    line-height: 1.2;
    vertical-align: baseline;
    /* Measured: its baseline sat 0.7px above the name's and the price's. */
    position: relative;
    top: 0.07rem;
  }
  /* The price: level with the photo and the name, and at the same right edge as
     the stepper and delete button below it. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__totals {
    padding: 0;
    margin: 0;
    justify-self: end;
    text-align: right;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__price-wrapper {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-height: 0;
    margin: 0;
    padding: 0;
  }
  /* A small photo: it fills its 4.4rem column and no more. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__image {
    display: block;
    width: 4.4rem;
    height: 4.4rem;
    max-width: 100%;
    object-fit: contain;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__details {
    display: contents;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__title {
    grid-column: 2;
    grid-row: 1;
    align-self: center;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__totals {
    grid-column: 3;
    grid-row: 1;
    align-self: center;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__frequency {
    grid-column: 1 / 4;
    grid-row: 2;
    margin-top: 0;
  }
  /* One more class than the theme's cart stylesheet's own rule for the same cell
     (which puts it in columns 2 to 5 and adds a fourth, empty column that pushed
     the price 12px in from the edge); it spans the card, on the second row, or
     the third when frequency pills take the second. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item .cart-item__quantity {
    grid-column: 1 / 4;
    grid-row: 2;
    padding: 0;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item:has(.cart-item__frequency) .cart-item__quantity {
    grid-row: 3;
  }
  /* The stepper at the left of the card, the delete button at the right. */
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__quantity-wrapper {
    justify-content: space-between;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__quantity-wrapper .quantity-popover-container {
    flex: 0 0 auto;
  }
  :is(.cart-drawer, .cart-page) .cart-items .cart-item__details .discounts:not(:has(li)) {
    display: none;
  }
  :is(.cart-drawer, .cart-page) .cart-item__savings {
    display: none;
  }
  :is(.cart-drawer, .cart-page) .cart-item__frequency-options {
    flex-wrap: nowrap;
    gap: 0.6rem;
  }
  :is(.cart-drawer, .cart-page) .cart-item__frequency-option {
    flex: 1 1 auto;
    min-height: 3.2rem;
    padding: 0 0.6rem;
    font-size: 1.2rem;
    white-space: nowrap;
  }

  /* Delivery frequency on a subscription line, the same as the product panel's
     subscribe option: a hairline above, the label and the renewal price (with
     its saving as a badge) on one line, then the schedule pills. */
  .cart-item__frequency {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-top: 0.8rem;
    padding-top: 1.2rem;
    border-top: 0.1rem solid rgba(var(--color-foreground), 0.2);
  }
  .cart-item__frequency-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem 1.2rem;
  }
  .cart-item__frequency-title {
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
  }
  .cart-item__recurring-line {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 700;
    line-height: 1.4;
  }
  .cart-item__price-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.17rem 0.8rem 0.03rem;
    border-radius: var(--radius-pill);
    background-color: rgba(var(--color-foreground), 0.08);
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    text-transform: lowercase;
  }
  .cart-item__frequency-options { display: flex; flex-wrap: wrap; gap: 0.6rem; }
  .cart-item__frequency-option {
    min-height: 3.2rem;
    padding: 0 1.2rem;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: none;
    color: inherit;
    font: inherit;
    font-size: 1.2rem;
    font-weight: 700;
    cursor: pointer;
    transition: border-color 0.2s ease, background-color 0.2s ease;
  }
  .cart-item__frequency-option:hover { border-color: rgba(var(--color-foreground), 0.6); }
  .cart-item__frequency-option.is-active {
    border-color: rgb(var(--color-foreground));
    background-color: rgba(var(--color-foreground), 0.12);
  }
  .cart-item__frequency-option[disabled] { opacity: 0.5; cursor: progress; }
/* END_SNIPPET:cart-drawer */

/* START_SNIPPET:facets (INDEX:89) */
/* ---- Filter chips ------------------------------------------------------
     The horizontal bar's list filters as toggle chips. The chip look is the
     same pill used by the ingredient selector and the strength buttons, so
     the page has one kind of pressable pill. */
  .facets__form .facets__wrapper {
    column-gap: var(--space-m);
    row-gap: var(--space-xs);
  }

  /* A hairline under the whole row — chips, sort and count — so the controls
     read as one band, separate from the products below. Drawn on the form, which
     sits inside the page-width aside, so it runs gutter to gutter and lines up
     with the row of products it divides from. */
  /* With the count hidden the third column is empty, and its gap would still be
     drawn. */
  .facets__form:has(> .product-count.visually-hidden) {
    grid-template-columns: 1fr max-content;
  }

  /* Same for the sort column when sorting is off: otherwise the filters stop a
     column-gap short of the right edge, and "Remove all" with them. */
  .facets__form:has(> .product-count.visually-hidden):not(:has(> .sorting)) {
    grid-template-columns: 1fr;
  }

  .facets__form.facets__form {
    padding-bottom: var(--space-m);
    margin-bottom: var(--space-m);
    border-bottom: 0.1rem solid var(--hairline);
  }

  /* Label above its chips, so each group reads as a small labelled set and
     the row stays compact whichever way the groups wrap. */
  .facets__chips {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-xs);
    margin: 0;
  }

  .facets__chips-label {
    color: rgba(var(--color-foreground), var(--ink-muted, 0.65));
  }

  .facets__chips .facets__chips-set {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
  }

  .facets__chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin: 0;
    padding: 0;
  }

  .facets__chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap-target);
    min-height: var(--tap-target);
    padding: var(--space-xs) var(--space-s);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-pill);
    background: none;
    color: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    transition: border-color var(--motion-fast) var(--diip-ease),
      background-color var(--motion-fast) var(--diip-ease);
  }

  /* The real checkbox stays in place, visually hidden, so it keeps its native
     keyboard and screen-reader behaviour and stays the thing the form submits. */
  .facets__chip input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: inherit;
  }

  /* On: a full-strength outline and a soft grey fill, the same as the strength
     pills on the product cards and the ones in the strength guide, so every
     choice on the page looks the same. Not a solid black fill, which reads as an
     action button rather than a choice. No hover change, as on those pills. */
  .facets__chip:has(input:checked) {
    background-color: rgba(var(--color-foreground), 0.08);
    border-color: rgb(var(--color-foreground));
  }

  .facets__chip:has(input:focus-visible) {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .facets__chip.disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }

  /* A selected chip is filled in, so the row of removable pills that Dawn draws
     underneath repeats what is on screen. Hidden, but left in the markup:
     facets.js re-renders that row and expects it. What stays is the reset
     button, which sits in the chips' own row, straight after the last group
     (the markup puts it inside the row, see above), so it is beside the options
     it clears rather than out at the far end where the carousel's arrows are on
     the Nixodine page. Dawn already hides it until something is selected. */
  .facets__form .active-facets-desktop {
    align-self: flex-end;
    width: auto;
    margin: 0;
    /* Level with the chips' own row, not the labels above them. */
    min-height: var(--tap-target);
    align-items: center;
  }

  .facets__form .active-facets-desktop .active-facets__button {
    display: none;
  }

  .facets__form .active-facets-desktop .active-facets__button-wrapper {
    padding-top: 0;
  }

  /* A normal secondary button (same as Choose options). Dawn sizes everything in
     its wrapper at 1.4rem, which would leave this one text size below the rest;
     hand the size back to the button. */
  .facets__form .active-facets-desktop .active-facets__button-remove,
  .facets__form .active-facets-desktop .active-facets__button-remove span {
    font-size: 1.5rem;
  }

  /* The reset arrow to the left of the word. */
  .facets__form .active-facets-desktop .active-facets__button-remove {
    gap: var(--space-xs);
  }

  /* The same black pill and cursor-following circle as the buy buttons on the
     product cards (card-buy.liquid): black at rest, and on hover a circle of the
     background colour follows the pointer, with an inverted copy of the label
     clipped to exactly that circle so it stays readable wherever the fill lands.
     The circle is painted into the button's own background so there is one edge.
     Own property names, so the two don't share state. Dawn's ring around a
     button (its ::before and ::after) is switched off. */
  @property --reset-d {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
  }

  .facets__form .active-facets-desktop .active-facets__button-remove {
    position: relative;
    border: 0;
    border-radius: var(--radius-pill);
    background-color: rgb(var(--color-foreground));
    background-image: radial-gradient(
      circle calc(var(--reset-d) / 2) at var(--reset-x) var(--reset-y),
      rgb(var(--color-background)) 0 99%,
      transparent 100%
    );
    color: rgb(var(--color-background));
    box-shadow: none;
    --reset-x: 50%;
    --reset-y: 50%;
    --reset-d: 0px;
    transition: --reset-d var(--motion-base) var(--diip-ease);
  }

  .facets__form .active-facets-desktop .active-facets__button-remove::before,
  .facets__form .active-facets-desktop .active-facets__button-remove::after {
    display: none;
  }

  .facets__form .active-facets-desktop .reset-label {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    color: rgb(var(--color-background));
  }

  .facets__form .active-facets-desktop .reset-label--over {
    position: absolute;
    inset: 0;
    z-index: 2;
    justify-content: center;
    color: rgb(var(--color-foreground));
    clip-path: circle(calc(var(--reset-d) / 2) at var(--reset-x) var(--reset-y));
    pointer-events: none;
  }

  .facets__form .active-facets-desktop .active-facets__button-remove:focus-visible {
    outline: 0.2rem solid var(--diip-accent);
    outline-offset: 0.2rem;
  }

  .facets__form .active-facets-desktop .active-facets__button-remove .svg-wrapper {
    display: inline-flex;
    width: 1.6rem;
    height: 1.6rem;
  }

  .facets__form .active-facets-desktop .active-facets__button-remove .svg-wrapper svg {
    width: 100%;
    height: 100%;
  }

  /* The sort control and the count sit level with the chips, not the labels.
     Their default is the top of the row, which was right when the filters were
     one line tall. */
  /* Doubled class: Dawn sets align-self on the count from a stylesheet that
     loads after this one, and a single class loses to it. */
  .facets__form.facets__form > .sorting,
  .facets__form.facets__form > .product-count:not(.visually-hidden) {
    align-self: end;
    min-height: var(--tap-target);
    display: flex;
    align-items: center;
  }

  /* Linked to by the strength guide ("Shop 4", "Shop 8"). Without this the page
     lands with the filter bar's top edge under the sticky header, and the labels
     above the chips are hidden. A literal value on purpose: with the --space-5xl
     token here the browser's first scroll to the link overshot the bar by
     hundreds of pixels, and only a plain length landed it in the right place. */
  #FacetFiltersForm {
    scroll-margin-top: 8rem;
  }

  /* Nixodine only. The filter bar's own top and bottom padding — 24px
     (--space-m) each, above the chips and below them before the divider —
     set once, on the form, which is also where the divider itself is drawn.

     Getting there means zeroing two OTHER paddings that used to add to the
     same visual gap above the chips: this section's own top-padding setting
     (set to 0 in the template — it has no other job on this page, since the
     filters are the first thing in the section) and .facets-container's own
     built-in 10px (Dawn's, zeroed just below). Without that, the form's own
     24px would stack on top of theirs instead of replacing them. Below the
     divider, before "8 products", is untouched — Dawn's own default there is
     already --space-m, the same 24px.

     Full-bleed too, to match the marquee bar above it: the aside this form
     sits in has no max-width (this theme strips it from .page-width
     site-wide), so it is already true document width; only the aside's own
     gutter keeps the form narrower than that. Pushing the form out by the
     gutter and pulling the content back in by the same amount reaches the
     real edges without a 100vw/-50vw trick, which would overflow by the
     scrollbar's width.

     No border-bottom of its own, though — the shared default draws one — now
     that the product count and arrows sit up on this same row: the carousel's
     own top frame line (main-collection-product-grid.liquid) sits right where
     the cards start, and the two read as one divider doubled rather than two.
     That line is the one worth keeping: it is also what the vertical lines
     between the cards touch.

     The shared default's margin-bottom (also --space-m) went with the border:
     it and this rule's own padding-bottom were two 24px gaps stacked either
     side of that border — the padding between the chips and where the border
     used to be, the margin between the border and whatever came next. With
     the border gone, both were still there, leaving 48px of empty space
     between the chips and the one line that's left instead of a plain 24px
     matching the rest of the page. */
  #MainContent[data-template-suffix='nixodine'] .facets-container {
    padding-top: 0;
  }

  #MainContent[data-template-suffix='nixodine'] .facets__form.facets__form {
    margin-inline: calc(-1 * var(--diip-gutter));
    padding-inline: var(--diip-gutter);
    padding-top: var(--space-m);
    border-bottom: 0;
    margin-bottom: 0;
  }
/* END_SNIPPET:facets */

/* START_SNIPPET:hcaptcha-notice (INDEX:91) */
.hcaptcha-notice {
    margin: 0.8rem 0 0;
    font-size: 1.1rem;
    line-height: 1.4;
    opacity: 0.7;
  }
  .hcaptcha-notice a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 0.2rem;
  }
/* END_SNIPPET:hcaptcha-notice */

/* START_SNIPPET:hero-video (INDEX:99) */
.hero-video {
    object-fit: cover;
    object-position: center;
  }
  /* Pause control: bottom right, clear of the title (which sits bottom left). */
  .hero-video__pause {
    position: absolute;
    right: var(--space-m);
    bottom: var(--space-m);
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4.4rem;
    height: 4.4rem;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    cursor: pointer;
  }
  .hero-video__pause svg {
    width: 2rem;
    height: 2rem;
  }
  .hero-video__pause svg + svg {
    display: none;
  }
  .hero-video__pause[aria-pressed='true'] svg:first-child {
    display: none;
  }
  .hero-video__pause[aria-pressed='true'] svg + svg {
    display: block;
  }
  .hero-video__pause:focus-visible {
    outline: 0.2rem solid #fff;
    outline-offset: 0.2rem;
  }
/* END_SNIPPET:hero-video */

/* START_SNIPPET:review-card (INDEX:125) */
/* Colours come from the surrounding scheme (--color-foreground), so the card
     reads on whichever panel it is in. */
  .review-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-s);
    padding: var(--space-m);
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: var(--radius-m);
    background-color: rgba(var(--color-foreground), 0.05);
    text-align: left;
  }
  /* The star filter in the reviews panel hides cards with the hidden attribute; the
     display above would otherwise win over it. */
  .review-card[hidden] {
    display: none;
  }
  /* Stars on the left, what they bought (the strength, "4") on the right of the same line. */
  .review-card__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
  }
  .review-card__stars {
    display: flex;
    gap: 0.3rem;
  }
  .review-card__star {
    display: inline-flex;
    width: 1.6rem;
    height: 1.6rem;
  }
  .review-card__star svg {
    width: 100%;
    height: 100%;
    fill: currentColor;
  }
  .review-card__star.is-empty {
    opacity: 0.22;
  }
  /* The theme's base styles give every blockquote a left rule, an indent and italic,
     muted text; the review should read as plain text, like the rest of the card. */
  .review-card__quote {
    margin: 0;
    padding: 0;
    border: 0;
    font-style: normal;
    color: inherit;
    font-size: var(--text-body);
    line-height: 1.5;
  }
  /* The reviewer's name, with the "verified buyer" badge just to its right. */
  .review-card__reviewer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem var(--space-xs);
    margin-top: auto;
    font-size: var(--text-sm);
  }
  /* The store's reply, under the review: set apart by its label, no rule or indent. */
  .review-card__reply {
    margin-top: var(--space-xs);
  }
  .review-card__reply-label {
    margin: 0 0 0.4rem;
    font-size: var(--text-caption);
    font-weight: 700;
  }
  .review-card__reply-text {
    margin: 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .review-card__name {
    font-weight: 700;
  }
  .review-card__meta {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-size: var(--text-caption);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* "verified buyer": the same small pill as the "30% off first order" badge on the
     product panel (a wash of the ink colour, lowercase). */
  .review-card__badge {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.5rem;
    /* Even top and bottom: the lowercase words sit centred in the pill (the old
       lopsided padding was borrowed from a badge with capitals and digits, and
       pushed this text low). */
    padding: 0.3rem var(--space-xs) 0.3rem 0.7rem;
    border-radius: var(--radius-pill, 999px);
    background-color: rgba(var(--color-foreground), 0.12);
    color: rgb(var(--color-foreground));
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    text-transform: lowercase;
  }
  /* What they bought: the flavor as quiet text, then the variant pill. */
  .review-card__bought {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-width: 0;
  }
  .review-card__flavor {
    font-size: var(--text-caption);
    line-height: 1.2;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* The variant: an outlined pill like the option badge in the cart
     (thin border, no fill, bold, in the text's own case), so it reads as different
     from the filled "verified buyer" pill. */
  .review-card__badge--plain {
    box-sizing: border-box;
    justify-content: center;
    min-height: 2.4rem;
    padding: 0 0.8rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.35);
    background-color: transparent;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1;
    text-transform: none;
  }
  .review-card__check {
    display: inline-flex;
    width: 1rem;
    height: 1rem;
  }
  .review-card__check svg {
    width: 100%;
    height: 100%;
  }
/* END_SNIPPET:review-card */

/* START_SNIPPET:reviews-panel (INDEX:127) */
/* The panel: fixed to the right edge, full height, sliding in from off-screen.
     Reset first: a <dialog> arrives with its own margin, border and sizing. */
  .reviews-panel {
    position: fixed;
    inset: 0 0 0 auto;
    width: min(60rem, 100vw);
    max-width: 100vw;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    background-color: rgb(var(--color-background));
    color: rgb(var(--color-foreground));
    box-shadow: -1.2rem 0 4rem rgba(0, 0, 0, 0.25);
    /* Gentle: a long, soft ease-out, so it settles rather than snaps. */
    transform: translateX(100%);
    transition: transform 0.55s cubic-bezier(0.22, 0.8, 0.3, 1);
    overflow: hidden;
  }
  .reviews-panel.is-open {
    transform: none;
  }
  .reviews-panel::backdrop {
    background-color: rgba(0, 0, 0, 0.45);
    opacity: 0;
    transition: opacity 0.55s ease;
  }
  .reviews-panel.is-open::backdrop {
    opacity: 1;
  }

  .reviews-panel__sheet {
    position: relative;
    height: 100%;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-m);
    /* Scrolls, but never shows a scrollbar. */
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .reviews-panel__sheet::-webkit-scrollbar {
    display: none;
  }
  /* Outside the scrolling sheet, so it stays put while the reviews scroll. */
  .reviews-panel__close {
    position: absolute;
    top: var(--space-m);
    right: var(--space-m);
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4.4rem;
    height: 4.4rem;
    padding: 0;
    border: 0.1rem solid rgba(var(--color-foreground), var(--ink-faint));
    border-radius: 50%;
    background-color: rgb(var(--color-background));
    color: inherit;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease);
  }
  .reviews-panel__close:hover {
    background-color: rgba(var(--color-foreground), 0.12);
  }
  .reviews-panel__close:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .reviews-panel__close .svg-wrapper {
    display: inline-flex;
    width: 1.4rem;
    height: 1.4rem;
  }
  .reviews-panel__close svg {
    width: 100%;
    height: 100%;
  }

  .reviews-panel__pane[hidden] {
    display: none;
  }
  .reviews-panel__title {
    margin: 0 5.6rem var(--space-s) 0;
    font-size: var(--text-heading);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 700;
  }
  .reviews-panel__summary {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin: 0 0 var(--space-m);
    font-size: var(--text-sm);
  }
  .reviews-panel__summary-star {
    display: inline-flex;
    width: 1.4rem;
    height: 1.4rem;
  }
  .reviews-panel__summary-star svg {
    width: 100%;
    height: 100%;
    fill: currentColor;
  }
  .reviews-panel__summary-score {
    font-weight: 700;
  }
  .reviews-panel__summary-count {
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  /* The star breakdown: one row per level, each a button that filters the list. */
  /* One grid for the whole breakdown, so every row shares the same three
     columns: the star label, the bar (takes what is left) and the count, which
     is only as wide as the longest count ("10 reviews"), right-aligned to the
     edge. The words therefore sit right at the end of the bar with no spare
     room, and every bar is the same length. Each row is a subgrid of it. */
  .reviews-panel__breakdown {
    display: grid;
    grid-template-columns: 4rem minmax(0, 1fr) auto;
    column-gap: var(--space-xs);
    row-gap: 0.2rem;
    margin: 0 0 var(--space-m);
  }
  .reviews-panel__bar-row {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
    width: 100%;
    margin: 0;
    padding: 0.7rem 0.8rem;
    border: 0;
    border-radius: 0.8rem;
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--text-sm);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease);
  }
  .reviews-panel__bar-row:hover {
    background-color: rgba(var(--color-foreground), 0.08);
  }
  .reviews-panel__bar-row:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.1rem;
  }
  .reviews-panel__bar-row.is-active {
    background-color: rgba(var(--color-foreground), 0.14);
  }
  .reviews-panel__bar-label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 700;
  }
  .reviews-panel__bar-star {
    display: inline-flex;
    width: 1.2rem;
    height: 1.2rem;
  }
  .reviews-panel__bar-star svg {
    width: 100%;
    height: 100%;
    fill: currentColor;
  }
  .reviews-panel__bar-track {
    display: block;
    height: 0.8rem;
    border-radius: 999px;
    background-color: rgba(var(--color-foreground), 0.16);
    overflow: hidden;
  }
  .reviews-panel__bar-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background-color: rgb(var(--color-foreground));
  }
  .reviews-panel__bar-count {
    text-align: right;
    white-space: nowrap;
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .reviews-panel__status {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
    margin: 0 0 var(--space-s);
    font-size: var(--text-sm);
    color: rgba(var(--color-foreground), var(--ink-muted));
  }
  .reviews-panel__status[hidden] {
    display: none;
  }
  .reviews-panel__show-all {
    padding: 0;
    border: 0;
    background: none;
    color: rgb(var(--color-foreground));
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 0.25rem;
    cursor: pointer;
  }
  /* "Show more reviews": the list shows ten at a time. */
  .reviews-panel__more {
    display: block;
    width: 100%;
    margin: var(--space-s) 0 0;
    padding: 1.2rem 1.6rem;
    border: 0.1rem solid rgba(var(--color-foreground), 0.35);
    border-radius: var(--radius-pill, 999px);
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease);
  }
  .reviews-panel__more:hover {
    background-color: rgba(var(--color-foreground), 0.08);
  }
  .reviews-panel__more:focus-visible {
    outline: 0.2rem solid rgb(var(--color-foreground));
    outline-offset: 0.2rem;
  }
  .reviews-panel__more[hidden] {
    display: none;
  }
  .reviews-panel__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-s);
  }

  @media (prefers-reduced-motion: reduce) {
    .reviews-panel,
    .reviews-panel::backdrop {
      transition: none;
    }
  }
/* END_SNIPPET:reviews-panel */

/* START_SNIPPET:signup-tab (INDEX:129) */
/* The anchor: a zero-height strip just under the divider line at the top of
     the panel, so nothing moves; the card is attached to it and hangs below. */
  .signup-tab {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    z-index: 5;
    height: 0;
  }

  /* Closed, the card is a small tab hanging from the divider line, at its left
     end; open, it slides out down and to the right into the full card. One
     element does both: the full card is always laid out, and a clip-path shows
     either all of it or just its top-left corner (the tab's size, measured by
     the script into --tab-w / --tab-h). Animating the clip-path is what makes
     the slide. */
  .signup-tab__card {
    position: absolute;
    left: var(--diip-gutter, 2.4rem);
    top: 0;
    width: min(43rem, calc(100% - var(--diip-gutter, 2.4rem) * 2));
    /* A filter, not a box-shadow on the clipped element: the clip would cut a
       shadow off. */
    filter: drop-shadow(0 0.4rem 2.4rem rgba(0, 0, 0, 0.28));
    /* Clipped at the line: the card hangs from the divider, so its shadow shows
       below and at the sides, never spilling up over the navbar. (The clip runs
       after the filter, so it trims the shadow too.) */
    clip-path: inset(0 -6rem -6rem -6rem);
  }
  .signup-tab__clip {
    position: relative;
    background-color: #ffffff;
    color: #17181c;
    clip-path: inset(0 calc(100% - var(--tab-w, 26rem)) calc(100% - var(--tab-h, 4.4rem)) 0 round 0 0 1.2rem 1.2rem);
  }
  /* Nothing is drawn until the script has measured the tab (--tab-w / --tab-h):
     before that the clip window is only a guess, and a wrong guess shows a strip
     of the card beside the tab. The slide is switched on only then too, so the
     measured size is taken instantly rather than animated into. */
  .signup-tab:not(.is-ready) .signup-tab__card {
    visibility: hidden;
  }
  .signup-tab.is-ready .signup-tab__clip {
    transition: clip-path 0.55s cubic-bezier(0.22, 0.8, 0.3, 1);
  }
  [data-signup-tab].is-open .signup-tab__clip {
    clip-path: inset(0 0 0 0 round 0 0 1.2rem 1.2rem);
  }
  [data-signup-tab].is-open .signup-tab__panel {
    visibility: visible;
    transition: visibility 0s;
  }

  /* Closed, the form is not drawn at all (the clip would otherwise show the
     corner of it around the tab). It stays drawn while the card slides shut, and
     is there the moment it starts to open. */
  .signup-tab__panel {
    visibility: hidden;
    transition: visibility 0s 0.55s;
    display: grid;
    grid-template-columns: 11.6rem minmax(0, 1fr);
    align-items: stretch;
    padding: 1.2rem;
    gap: 1.6rem;
  }

  /* The closed face: the offer in one line, top left of the card, over the
     panel (which is inert and invisible to everything while closed). */
  .signup-tab__tab {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    height: 4.4rem;
    padding: 0 2rem;
    border: 0;
    border-radius: 0 0 1.2rem 1.2rem;
    background-color: #ffffff;
    color: inherit;
    font: inherit;
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    white-space: nowrap;
    cursor: pointer;
    /* Back in only after the card has slid shut; out quickly when it opens. */
    transition: opacity 0.25s ease 0.3s, background-color var(--motion-fast) var(--diip-ease);
  }
  .signup-tab__tab:hover {
    background-color: #f1f3f5;
  }
  .signup-tab__tab:focus-visible {
    outline: 0.2rem solid #17181c;
    outline-offset: -0.4rem;
  }
  [data-signup-tab].is-open .signup-tab__tab {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.2s ease, visibility 0s 0.2s;
  }

  .signup-tab__close {
    position: absolute;
    top: 0.8rem;
    right: 0.8rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: rgba(23, 24, 28, 0.08);
    color: inherit;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--diip-ease);
  }
  .signup-tab__close:hover {
    background-color: rgba(23, 24, 28, 0.16);
  }
  .signup-tab__close .svg-wrapper {
    display: inline-flex;
    width: 1.2rem;
    height: 1.2rem;
  }
  .signup-tab__close svg {
    width: 100%;
    height: 100%;
  }

  /* The offer, in type: a big number with its unit under it. */
  .signup-tab__offer {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.4rem;
    border-radius: 0.8rem;
    background-color: #f1f3f5;
    padding: 1rem;
  }
  .signup-tab__percent {
    font-size: 4.2rem;
    font-weight: 700;
    line-height: 0.95;
    letter-spacing: -0.04em;
  }
  .signup-tab__off {
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: -0.01em;
  }

  .signup-tab__body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    padding-right: 2.8rem;
  }
  .signup-tab__eyebrow {
    margin: 0 0 0.4rem;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(23, 24, 28, 0.6);
  }
  .signup-tab__title {
    margin: 0;
    font-size: 1.7rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
  }
  .signup-tab__text {
    margin: 0.4rem 0 0;
    font-size: 1.15rem;
    line-height: 1.4;
    color: rgba(23, 24, 28, 0.7);
  }
  .signup-tab__form {
    display: flex;
    flex-direction: column;
  }
  .signup-tab__row {
    display: flex;
    gap: 0.8rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 0.1rem solid rgba(23, 24, 28, 0.14);
  }
  .signup-tab__input {
    flex: 1 1 auto;
    min-width: 0;
    height: 3.6rem;
    padding: 0 1.2rem;
    border: 0.1rem solid rgba(23, 24, 28, 0.3);
    border-radius: 0.8rem;
    background: #fff;
    /* White field, so dark text and cursor: inheriting the panel's ink put white
       text on it. */
    color: #17181c;
    caret-color: #17181c;
    font: inherit;
    font-size: 1.3rem;
  }
  .signup-tab__input:focus-visible {
    outline: 0.2rem solid #17181c;
    outline-offset: 0.1rem;
  }
  .signup-tab__submit {
    flex: 0 0 auto;
    height: 3.6rem;
    padding: 0 1.4rem;
    border: 0;
    border-radius: 0.8rem;
    background-color: #17181c;
    color: #fff;
    font: inherit;
    font-size: 1.3rem;
    font-weight: 700;
    cursor: pointer;
    transition: opacity var(--motion-fast) var(--diip-ease);
  }
  .signup-tab__submit:hover {
    opacity: 0.85;
  }
  .signup-tab__captcha {
    margin: 0.8rem 0 0;
    font-size: 1rem;
    line-height: 1.3;
    color: rgba(23, 24, 28, 0.55);
  }
  .signup-tab__captcha a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 0.2rem;
  }
  /* Shopify's hCaptcha badge is replaced by the notice inside the card. */
  body:has(.signup-tab) #shop-hcaptcha-badge-container {
    display: none !important;
  }
  .signup-tab__error {
    margin: 0.8rem 0 0;
    font-size: 1.2rem;
    color: #b3261e;
  }
  .signup-tab__code-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 0.1rem solid rgba(23, 24, 28, 0.14);
  }
  .signup-tab__code {
    flex: 1 1 auto;
    padding: 0.8rem 1.2rem;
    border: 0.1rem dashed rgba(23, 24, 28, 0.5);
    border-radius: 0.8rem;
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-align: center;
  }
  .signup-tab__copy {
    flex: 0 0 auto;
    height: 3.6rem;
    padding: 0 1.4rem;
    border: 0;
    border-radius: 0.8rem;
    background-color: #17181c;
    color: #fff;
    font: inherit;
    font-size: 1.4rem;
    font-weight: 700;
    cursor: pointer;
  }

  @media (prefers-reduced-motion: reduce) {
    .signup-tab.is-ready .signup-tab__clip,
    .signup-tab__panel,
    .signup-tab__tab {
      transition: none;
    }
  }

  /* On a phone: the same tab; opened, it grows downward to a card the width of
     the pane with just the heading and the signup row. */
  @media screen and (max-width: 749px) {
    .signup-tab__panel {
      grid-template-columns: minmax(0, 1fr);
      padding: 1.2rem;
      gap: 0;
    }
    .signup-tab__offer,
    .signup-tab__text,
    .signup-tab__eyebrow {
      display: none;
    }
    .signup-tab__body {
      padding-right: 3rem;
    }
    .signup-tab__row {
      margin-top: 0.8rem;
      padding-top: 0.8rem;
    }
    .signup-tab__captcha {
      margin-top: 0.6rem;
    }
    .signup-tab__close {
      top: 0.8rem;
      right: 0.8rem;
    }
  }
/* END_SNIPPET:signup-tab */