/* ==========================================================================
   PRODUCT SECTION — gallery, bundle bars, subscription, accordions
   ========================================================================== */
.product{padding:16px 0 40px}
.product__grid{display:grid;gap:24px}
@media (min-width:990px){
  .product{padding:32px 0 64px}
  .product__grid{grid-template-columns:minmax(0,1fr) minmax(0,540px);gap:56px;align-items:start}
  /* The media column is a long scrolling stack; the buy box is the shorter
     of the two, so that is the one that sticks. */
  .product__info-col{position:sticky;top:85px;align-self:start}
}

/* -------- gallery -------- */
.gallery{position:relative}

/* ---------- stacked gallery (scrolls past the sticky buy box) ---------- */
.gallery--stack .gallery__stage{aspect-ratio:auto;overflow:visible;background:none;border-radius:0}
/* 6-column mosaic: full = 6, half = 3, third = 2 */
.gallery--stack .gallery__slides{
  display:grid;grid-template-columns:repeat(6,1fr);gap:12px;
  height:auto;transition:none;transform:none;
}
.gallery--stack .gallery__slide{flex:none;height:auto;grid-column:span 6}
.gallery--stack .gallery__slide--full{grid-column:span 6}
.gallery--stack .gallery__slide--half{grid-column:span 3}
.gallery--stack .gallery__slide--third{grid-column:span 2}
/* one column below the 2-col breakpoint — thirds are unreadable on a phone */
/* MOBILE: the mosaic must NOT simply collapse to one column — that stacked all
   seven squares vertically and pushed the headline 3.2 screens down and the buy
   box 5.3 screens down. Below 750px the gallery becomes a native scroll-snap
   carousel: one image per screen, swipe to advance, thumbnails underneath. */
@media (max-width:749px){
  /* min-width:0 is load-bearing. Grid and flex tracks default to min-width:auto,
     so seven slides at flex-basis:100% resolve to a max-content width and blow the
     column out to 552px inside a 375px viewport — scrolling the whole page
     sideways instead of scrolling the carousel. */
  .product__media-col,
  .gallery--stack .gallery__stage{min-width:0}
  .gallery--stack .gallery__slides{
    display:flex;
    grid-template-columns:none;
    min-width:0;
    width:100%;
    gap:0;
    overflow-x:auto;
    overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    -ms-overflow-style:none;
  }
  .gallery--stack .gallery__slides::-webkit-scrollbar{display:none}
  .gallery--stack .gallery__slide,
  .gallery--stack .gallery__slide--full,
  .gallery--stack .gallery__slide--half,
  .gallery--stack .gallery__slide--third{
    grid-column:auto;
    flex:0 0 100%;
    scroll-snap-align:center;
  }
}
/* DIRECT CHILD only. As a descendant selector this also styled images nested inside
   a slide (the stage-card thumbnails), stretching them to the slide height. */
.gallery--stack .gallery__slide > img,
.gallery--stack .gallery__slide > video{
  width:100%;height:auto;display:block;
  border-radius:var(--media-radius);background:var(--bg-2);
}
/* The nav row: prev arrow, thumbnail strip, next arrow, all on one line under the
   image. Nothing is overlaid on the photograph any more. Pointless on the desktop
   mosaic, where every image is already on screen, so the whole row is hidden
   there and the arrows go back to being static flex items here. */
/* MOBILE HERO HEIGHT CAP.
   On a phone the gallery is the entire first screen and the H1 sat at 606px, below
   the fold, so the first thing a visitor met was packaging rather than the argument.
   Capping the slide to ~36vh lifts the eyebrow, the H1 and the opening line into the
   first screen without shrinking the image to a thumbnail. object-fit keeps the jar
   and the pad centred rather than squashed. Desktop keeps the full mosaic. */
@media (max-width:749px){
  /* NO HEIGHT CAP ON THE GALLERY IMAGES. A 36vh cap with object-fit:cover was added
   to lift the H1 above the fold, and it was wrong: these slides are 1080 square
   creatives with headlines and body copy baked into them, so cropping them to a
   letterbox cut the top line off every one. The images have to be seen whole.
   If the H1 needs to come up again, take the height out of the thumbnail strip or
   the header, never out of the artwork. */
.gallery--stack .gallery__slide > img,
.gallery--stack .gallery__slide > video{height:auto;max-height:none;object-fit:contain}
}
.gallery--stack .gallery__nav{display:none}
@media (max-width:749px){
  .gallery--stack .gallery__nav{
    display:flex;align-items:center;gap:10px;margin-top:12px;
  }
  .gallery--stack .gallery__thumbs{flex:1 1 auto;min-width:0;margin-top:0}
  .gallery--stack .gallery__arrow{
    position:static;transform:none;display:grid;flex:0 0 34px;
    width:34px;height:34px;background:#fff;
    box-shadow:0 0 0 1px var(--line) inset;
  }
  .gallery--stack .gallery__arrow:active{background:var(--surface-quiet)}
  .gallery--stack .gallery__arrow svg{width:15px;height:15px;color:var(--heading)}
}
@media (min-width:990px){.gallery--stack .gallery__slides{gap:14px}}
.gallery__stage{position:relative;border-radius:var(--media-radius);overflow:hidden;background:var(--bg-2);aspect-ratio:1/1}
.gallery__slides{display:flex;height:100%;transition:transform var(--dur-long) cubic-bezier(.25,.8,.3,1)}
.gallery__slide{flex:0 0 100%;height:100%}
.gallery__slide > img,.gallery__slide > video{width:100%;height:100%;object-fit:cover;display:block}
.gallery__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;width:38px;height:38px;border-radius:50%;background:rgba(255,255,255,.85);display:grid;place-items:center;box-shadow:0 2px 10px rgba(18,18,18,.12)}
.gallery__arrow--prev{left:10px}
.gallery__arrow--next{right:10px}
.gallery__arrow svg{width:16px;height:16px}
.gallery__badge{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:2;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;background:#fff;border-radius:var(--pill-radius);padding:9px 16px;font-size:var(--fs-small);font-weight:600;color:var(--heading);box-shadow:0 4px 16px rgba(18,18,18,.12)}
.gallery__badge svg{width:16px;height:16px;color:var(--accent-1)}
.gallery__thumbs{display:flex;gap:8px;margin-top:10px;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
.gallery__thumbs::-webkit-scrollbar{display:none}
.gallery__thumb{flex:0 0 72px;height:72px;border-radius:8px;overflow:hidden;scroll-snap-align:start;box-shadow:0 0 0 1px rgba(18,18,18,.1) inset;transition:box-shadow var(--dur);background:var(--bg-2)}
.gallery__thumb img{width:100%;height:100%;object-fit:cover}
.gallery__thumb[aria-current="true"]{box-shadow:0 0 0 2px var(--accent-1) inset}
@media (min-width:750px){.gallery__thumb{flex:0 0 88px;height:88px}}

/* -------- rating row -------- */
.rating{display:flex;align-items:center;gap:8px;font-size:var(--fs-small);font-weight:600;color:var(--text)}
.rating .stars{color:var(--star);font-size:16px;letter-spacing:-1px}

/* -------- benefit bullets -------- */
.rating--tp{flex-direction:column;align-items:flex-start;gap:5px}
/* Stars sit to the LEFT of the score, on one row, at every width. It used to wrap:
   the row needed 110px of stars + 10px + 215px of text against a 276px column at 320w
   and a 327px one at 375w, so the stars took a line of their own and the score dropped
   under them, which is the one arrangement a rating must never have. "Based on 4,684
   Reviews" became "4,684 reviews" (-63px), the stars come down 2px on a phone, and the
   row is nowrap because it has been measured to fit from 320 up with room to spare. */
.tp-row{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
.tp-stars{height:23px;width:auto;display:block;flex:0 0 auto}
.tp-text{white-space:nowrap}
@media (max-width:749px){
  .tp-row .tp-stars{height:21px}
}
.tp-text{font-size:var(--fs-small);font-weight:400;color:var(--text);font-variant-numeric:tabular-nums}
.tp-text strong{font-weight:700}
.tp-sep{color:var(--text-60);margin:0 2px}
.rating__note{font-size:var(--fs-small);font-weight:400;color:var(--text-60)}
/* Replaces the star-rating block above the H1. Deliberately NOT styled as an
   eyebrow label (uppercase, tracked, accent colour): it is a sentence the reader
   is meant to read, not a category tag they skim past. Sits on --text-60 so it
   reads as an aside to the headline rather than competing with it. */
/* Labels the struck-through bundle price so it cannot be read as a former price.
   The comparison is to the single-jar price offered on this same page at this same
   moment, which is what makes it defensible under the FTC deceptive-pricing guides
   (16 CFR 233.1). An unlabelled strike reads as a "was" price, which it is not. */
.bundle__compare-note{display:block;font-size:12px;line-height:1.2;color:var(--ink-muted,#5B6169);margin-top:2px;white-space:nowrap}
/* Recurring-billing disclosure, rendered under the add-to-cart button by module 4. */
.payment-note{margin:12px 0 0;font-size:13px;color:var(--text-60);text-align:center}
/* Makes the whole subscribe panel a hit target for the checkbox. The switch track
   is 46x27 and it was the only way to opt into recurring billing: the single most
   consequential control in the buy box was also the smallest thing on the page. */
/* The clickable area is the TITLE only, not the whole panel. A full-panel invisible
   overlay swallowed every click in the box, including the terms link underneath. */
.subscribe__title{cursor:pointer;display:inline-block}
/* "Read them yourself. We would rather you did." under the FDA citation. */
.record__src-note{display:block;margin-top:2px;opacity:.85}
/* The subscription/one-time label in the sticky bar. It must stay legible: it is
   the only thing telling a shopper what the bar's price actually commits them to. */
.sticky-atc__mode{display:block;font-size:11px;font-weight:600;color:var(--text-60);letter-spacing:.2px}
/* The stage card slide was replaced 10 Sep 2026 by assets/img/slide-timeline.jpg,
   a rendered 1080 square in the same language as slide-compare. Its ~40 lines of
   .stagecard / .gallery__slide--card CSS went with it. */
/* ---- groomer testimonial: video-ready poster + quote ----
   .groomer__media is built to be swapped for a <video poster="..."> with no layout
   change. Keep the aspect-ratio on whatever replaces the img. */
.groomer{margin-top:26px;border:1px solid var(--line,#dbe6f2);border-radius:var(--media-radius,12px);background:#fff;overflow:hidden}
.groomer__media{position:relative;display:block;background:var(--bg-2)}
.groomer__media img,.groomer__media video{width:100%;display:block;aspect-ratio:1200/908;object-fit:cover}
.groomer__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:58px;height:58px;border-radius:50%;background:rgba(255,255,255,.94);color:var(--heading);display:flex;align-items:center;justify-content:center;padding-left:3px;box-shadow:0 6px 24px rgba(10,26,48,.34)}
.groomer__badge{position:absolute;left:12px;bottom:12px;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:#fff;background:rgba(10,26,48,.72);backdrop-filter:blur(4px);border-radius:40px;padding:6px 12px}
.groomer__body{padding:18px}
.groomer__quote{margin:0 0 14px;position:relative;padding-top:2px}
/* Set at 14.5/1.52. This block runs three paragraphs, and at 15px+ it read as a
   wall rather than a review card: the density of the type is what makes a
   testimonial feel like something a person wrote rather than page copy. */
/* One colour for the whole quotation. The :last-child rule here existed to zero the
   bottom margin and was also flipping the final paragraph from navy to body colour, so
   a three-paragraph quote rendered in two different colours and read as if the last
   part had been pasted in from somewhere else.
   The colour it settles on is --text, not --heading: the type system's rule is
   "headings navy, body never navy", and three paragraphs at 14.5px is running copy. */
.groomer__quote p{margin:0 0 10px;font-size:14.5px;line-height:1.52;color:var(--text)}
.groomer__quote p:last-child{margin-bottom:0}
.groomer__quote em{font-style:italic}
.groomer__who{display:flex;align-items:center;gap:11px;padding-top:14px;border-top:1px solid var(--line,#dbe6f2)}
/* Lead variant: attribution sits ABOVE the quote, so it carries no top rule and
   a larger avatar. The face is the credential here, not a footnote to it. */
.groomer__who--lead{padding-top:0;border-top:0}
.groomer__who--lead .groomer__avatar{flex:0 0 48px;width:48px;height:48px}
.groomer__who--lead .groomer__meta strong{font-size:15px}
.groomer__avatar{flex:0 0 44px;width:44px;height:44px;border-radius:50%;overflow:hidden;background:var(--bg-2)}
/* stacy-hollen.jpg is already cropped square on her face, so no object-position
   nudge. Re-add one only if the source image changes. */
.groomer__avatar img{width:100%;height:100%;object-fit:cover;display:block}
.groomer__meta{display:flex;flex-direction:column;gap:1px;min-width:0}
.groomer__meta strong{font-size:14px;color:var(--heading);line-height:1.2}
.groomer__meta span{font-size:11.5px;color:var(--text-60);line-height:1.34}
.groomer__rating{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin:11px 0 11px}
.groomer__rating .tp-stars{width:118px;height:auto}
.groomer__score{font-size:13.5px;color:var(--text-60)}
.groomer__score strong{color:var(--heading);font-size:15px}
/* Spec chips. Squared corners, white ground, a teal tick in a tinted disc. Pills on a
   tinted ground read as tags; these need to read as a checklist someone verified, which
   is the only job they have in this block. */
.vetcard__specs{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:7px}
.vetcard__specs li{
  display:inline-flex;align-items:center;gap:7px;
  font-size:12.5px;font-weight:600;letter-spacing:-.005em;color:var(--heading);
  background:#fff;border:1px solid var(--line,#dbe6f2);border-radius:9px;
  padding:7px 12px 7px 9px;box-shadow:0 1px 2px rgba(19,61,38,.055);
}
.vetcard__specs li::before{
  content:"";flex:none;width:16px;height:16px;border-radius:50%;
  background:var(--accent-2,#0C8480)
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round' d='M5 12.6l4.6 4.6L19 7.4'/%3E%3C/svg%3E")
    center/10px 10px no-repeat;
}
.atc-terms{margin:10px 0 0;font-size:13px;line-height:1.45;color:var(--text-60);max-width:var(--measure)}
/* Visible disclaimer under the Weese quote. Must not be hidden or shrunk away. */
.record__src--disclaim{margin-top:8px;font-style:italic}
.product__eyebrow{margin:0 0 10px;font-size:var(--fs-small);line-height:1.45;color:var(--text-60);max-width:var(--measure)}
.product__subhead{margin:10px 0 0;font-size:var(--fs-body);line-height:1.5;color:var(--text-60);max-width:var(--measure)}
.usp-list{margin:18px 0 22px;display:grid;gap:13px}
/* Centred, not top-aligned. Every one of these bullets wraps to two lines, and an
   icon pinned to the first line reads as hanging off the top of its own row rather
   than marking it. align-items:center puts the glyph on the optical middle of the
   whole bullet, which is where the eye expects a marker in front of a block of text. */
.usp-list li{display:flex;align-items:center;gap:13px;font-size:var(--fs-body);color:var(--text)}
/* The chip is gone and is not coming back: a row of boxed icons reads as a settings
   menu rather than a benefit list.

   The four glyphs are the fine-line set, rewritten 12 Sep 2026 to match the #i-q-*
   icons in the dark four-up slab, which is the set the brand wants the page to look
   like. Read the note above those symbols in index.html before touching them: they are
   drawn on a 48 grid at stroke 2.04 SPECIFICALLY so that at this 28px they render at
   1.19 real px, the same on-screen weight as the slab at 44px/1.3.
   (The size was 26px with stroke 2.2 when this was first built and was changed to 28
   on disk; the stroke was re-solved to 2.04 to keep the match. This is the pairing the
   next person will break.)

   Two consequences, both load-bearing:
   - No stroke-width here, and never add one. Each symbol sets its own, and a blanket
     value would undo the size-compensated weight that makes the two sets match.
   - The size below and the stroke in the symbols are ONE decision. Changing 26px
     without re-solving stroke = 1.19 x 48 / newSize breaks the match, and a fine-line
     glyph that drifts light on white is the exact failure this list already had once
     with hairline outlines. */
/* The bullet icons are generated PNGs now, not symbols: keyed off white, recoloured to
   navy in the alpha channel, and stored at 224px so they are 8x the 28px they render at.
   They are <img>, so `color` no longer reaches them - a different navy means
   regenerating the asset, not editing a CSS variable. That is the trade for the drawing
   quality, and it is why the rest of the page still uses the SVG sprite. */
.usp-list .ico{
  width:32px;height:32px;flex:0 0 32px;object-fit:contain;
}
/* margin-top is gone with the top alignment: it existed only to nudge a top-pinned
   glyph down onto the first line's cap height. With the row centred it would push
   every icon off-centre by exactly that much. */
/* Bold carries the claim, regular carries the qualifier — the eye lands on the
   bold half first, so the bullet reads even when it is skimmed. */
.usp-list strong{font-weight:700;color:var(--text)}
/* Second half of the H1 is the mechanism name: same size, lighter weight, so the
   outcome + timeframe reads first. */
.product__info-col h1 .h1-alt{font-weight:500}
/* Deliberate deviation from the 52px H1 token, and the desktop half of the same
   two-line rule the mobile clamp below enforces. The desktop column is a fixed 540px
   at every width from 990 up, so this needs no clamp, only the right number.
   "Tear Stains Don't Wash Off." costs 11.89px of width per px of font: 553px at 47px,
   which overflowed 540 and broke "Off." onto a line of its own. The ceiling is 45.4px;
   45 measures 535 and clears by 5px, which is under 1% and too tight to trust across
   font-rendering differences, so this sits at 44px / 523px, clearing by 17px.
   ⚠ 47px was correct for the PREVIOUS headline ("With The Wet-Lift System") and is
   wrong for this one. Re-solve on any headline rewrite: font = 540 / 11.89 x 0.97,
   then confirm with _tools/measure.html, which now runs the desktop widths too. */
@media (min-width:990px){
  .product__info-col h1{font-size:44px;line-height:1.07}
}
/* The H1 must be exactly TWO lines at every mobile width, one per half of the
   forced <br>. "Tear Stains Don’t Wash Off." is the long half: it needs 345px at
   29px, against a column measuring 276px at 320w, 320px at 375w and 357px at 412w,
   so a fixed 29px wrapped it to three lines on every phone narrower than ~412px.
   Sized off the column instead: the long half costs col/0.082 per px of font, so
   font = col x 0.082 fits with ~2% to spare, and the column runs ~viewport minus
   55px, which is where 8.2vw - 4.5px comes from. The 22px floor covers 320w; the
   29px ceiling holds the token from 412w up.
   Measured with _tools/measure.html — re-run it after any wording change. */
@media (max-width:749px){
  .product__info-col h1{font-size:clamp(22px,calc(8.2vw - 4.5px),29px);line-height:1.13}
}
.usp-note{background:var(--bg-2);border-radius:var(--media-radius);padding:14px 16px;font-size:var(--fs-small);color:var(--text);display:flex;gap:10px;align-items:flex-start;margin-bottom:22px}
.usp-note .ico{width:23px;height:23px;flex:0 0 23px;margin-top:0;color:var(--accent-1)}

/* ==========================================================================
   BUNDLE BARS — structural clone of the Kaching-style offer selector
   ========================================================================== */
.bundles{display:grid;gap:12px;margin-bottom:18px}
.bundle{position:relative}
.bundle__input{position:absolute;opacity:0;width:0;height:0}

/* Card. Unselected reads as a quiet option; selected takes a 2px navy edge and a
   white ground so the choice is unmistakable at a glance. */
/* Unselected tiers sit on a tinted ground rather than pure white, so they read as
   available options instead of disabled ones — and so the selected tier can go
   white and lift off the group. Inverting it this way means the chosen card is
   the brightest thing in the stack without needing a heavier border. */
.bundle__label{
  display:block;position:relative;cursor:pointer;overflow:hidden;
  border-radius:var(--bar-radius);background:var(--surface-quiet);
  box-shadow:0 0 0 1px var(--line) inset;
  transition:box-shadow var(--dur),background var(--dur);
}
.bundle__label:hover{box-shadow:0 0 0 1px var(--line-strong) inset}
.bundle__input:checked + .bundle__label{
  background:#fff;box-shadow:0 0 0 2px var(--heading) inset;
}
.bundle__input:focus-visible + .bundle__label{outline:2px solid var(--accent-1);outline-offset:2px}

/* ribbon sits on the top-right corner, not centred */
.bundle__ribbon{
  position:absolute;top:0;right:0;z-index:2;
  background:var(--heading);color:#fff;border-radius:0 var(--bar-radius) 0 8px;
  padding:6px 12px;font-size:12px;font-weight:700;letter-spacing:.02em;white-space:nowrap;
}
/* Tier 1's ribbon states a fact, it does not award the tier a badge, so it sits quiet:
   the same shape and position as the other two but on the tinted surface rather than
   filled navy. Navy here would give the cheapest tier the loudest chip on the stack. */
.bundle__ribbon--plain{
  background:var(--surface-quiet-2,#e6eef8);color:var(--heading);font-weight:700;
}

/* one row: radio, label stack, price stack. No thumbnail — the image was eating
   half the row and forcing every label to wrap three lines on a phone. */
.bundle__main{display:flex;align-items:center;gap:11px;padding:15px 16px 14px}
/* 46px keeps the jar count legible in silhouette while leaving the title and
   subtitle enough width to hold one line each at 375px. */
.bundle__image{flex:0 0 46px;width:46px;height:46px;border-radius:7px;object-fit:cover;background:#fff}
/* The ribbon is absolutely placed top-right and the price stack is also right
   aligned, so without this the ribbon lands on top of the price. */
.bundle--has-ribbon .bundle__main{padding-top:40px}
.bundle__radio{
  flex:0 0 21px;width:21px;height:21px;border-radius:50%;background:#fff;
  box-shadow:0 0 0 1.5px var(--line-strong) inset;transition:box-shadow var(--dur);
}
.bundle__input:checked + .bundle__label .bundle__radio{box-shadow:0 0 0 6.5px var(--heading) inset}
.bundle__left{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.bundle__title{font-size:19px;font-weight:800;color:var(--heading);line-height:1.2;letter-spacing:-.015em}
.bundle__subtitle{font-size:13.5px;color:var(--text-60);line-height:1.3;margin-top:3px}
.bundle__pricing{flex:0 0 auto;text-align:right;display:flex;flex-direction:column;align-items:flex-end}
.bundle__price{font-size:21px;font-weight:800;color:var(--heading);line-height:1.1;font-variant-numeric:tabular-nums}
.bundle__compare{font-size:13.5px;color:var(--text-60);margin-top:2px;font-variant-numeric:tabular-nums}

/* perk bars run full width under the row and escalate tier by tier */
.bundle__perks{display:block}
/* Unselected perks sit greyed back so the chosen tier's navy bars are the only
   thing lit up — the contrast is what communicates "this is what you unlock". */
.bundle__perk{
  display:flex;align-items:center;gap:9px;
  padding:9px 16px;background:var(--surface-quiet-2);
  border-top:1px solid rgba(255,255,255,.85);
  font-size:13.5px;font-weight:700;color:var(--ink-muted);
  transition:background var(--dur),color var(--dur);
}
.bundle__perk .ico{width:17px;height:17px;flex:0 0 17px;color:var(--ink-faint);transition:color var(--dur)}
.bundle__perk-txt{flex:1 1 auto;min-width:0}
.bundle__perk s{flex:0 0 auto;font-weight:400;color:var(--ink-faint);font-variant-numeric:tabular-nums}
/* the selected tier's perks fill in, so the value you unlock is the loudest thing */
.bundle__input:checked + .bundle__label .bundle__perk{
  background:var(--heading);color:#fff;border-top-color:rgba(255,255,255,.22);
}
.bundle__input:checked + .bundle__label .bundle__perk .ico{color:#fff}
.bundle__input:checked + .bundle__label .bundle__perk s{color:rgba(255,255,255,.72)}

/* ==========================================================================
   SUBSCRIPTION TOGGLE
   ========================================================================== */
/* On is a solid navy panel. Subscription is the highest-value choice in the box,
   so when it is active it should be the one filled block below the tiers, in the
   same navy that marks the selected tier. Off, it recedes to a quiet card. */
.subscribe{border-radius:var(--bar-radius);box-shadow:0 0 0 1px var(--line) inset;padding:14px;display:flex;align-items:center;gap:12px;margin-bottom:16px;background:var(--surface-quiet);transition:box-shadow var(--dur),background var(--dur)}
.subscribe.is-on{box-shadow:none;background:var(--heading)}
.subscribe__text{flex:1;min-width:0}
.subscribe__title{font-size:var(--fs-label);font-weight:600;color:var(--heading);transition:color var(--dur)}
.subscribe__sub{font-size:var(--fs-small);color:var(--text-60);margin-top:2px;transition:color var(--dur)}
.subscribe.is-on .subscribe__title{color:#fff}
.subscribe.is-on .subscribe__sub{color:var(--on-navy-70)}
/* The unchecked track needs to lift off navy, and the checked track uses sky,
   which is the one place sky is genuinely at its best: small, on a dark ground. */
.subscribe.is-on .switch__track{background:rgba(255,255,255,.26)}
.switch{position:relative;flex:0 0 46px;width:46px;height:27px}
.switch input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer;z-index:2}
.switch__track{position:absolute;inset:0;background:rgba(18,18,18,.2);border-radius:999px;transition:background var(--dur)}
.switch__thumb{position:absolute;top:3px;left:3px;width:21px;height:21px;background:#fff;border-radius:50%;transition:transform var(--dur);box-shadow:0 1px 3px rgba(0,0,0,.25)}
.switch input:checked ~ .switch__track{background:var(--accent-1)}
.switch input:checked ~ .switch__thumb{transform:translateX(19px)}

/* ==========================================================================
   STOCK BAR + FREE GIFT SUMMARY + ATC BLOCK
   ========================================================================== */
.stock{margin-bottom:16px}
.stock__row{display:flex;justify-content:space-between;font-size:var(--fs-small);font-weight:600;letter-spacing:var(--ls-label);margin-bottom:6px}
/* Amber, not red. Red is the UI convention for an error or a destructive action;
   on a scarcity cue it reads as something being wrong with the page rather than
   the stock. Amber carries urgency without the alarm, and it does not fight the
   teal add-to-cart sitting directly below it. */
.stock__label{color:#D98014;display:inline-flex;align-items:center;gap:8px}
.stock__dot{width:9px;height:9px;border-radius:50%;background:#F5A524;flex:0 0 9px;
  box-shadow:0 0 0 3px rgba(245,165,36,.22)}
.stock__meter{height:7px;border-radius:99px;background:rgba(18,18,18,.1);overflow:hidden}
.stock__fill{height:100%;border-radius:99px;background:linear-gradient(90deg,#FFC46B,#F5A524);width:0;transition:width 1.2s ease}
.gift-summary{border-radius:var(--bar-radius);background:var(--bg-2);margin-bottom:14px;overflow:hidden}
.gift-summary__head{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 15px;font-size:var(--fs-label);font-weight:600;color:var(--heading);text-align:left}
.gift-summary__count{color:var(--heading);font-size:var(--fs-small);font-weight:600}
.gift-summary__body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur-long)}
.gift-summary.is-open .gift-summary__body{grid-template-rows:1fr}
.gift-summary__inner{overflow:hidden}
.gift-summary__list{padding:0 15px 14px;display:grid;gap:9px}
.gift-summary__list li{display:flex;align-items:center;gap:9px;font-size:var(--fs-small);color:var(--text)}
.gift-summary__list .ico{width:16px;height:16px;flex:0 0 16px;color:var(--heading)}
.atc-meta{display:flex;flex-direction:column;gap:7px;align-items:center;margin-top:12px;font-size:var(--fs-small);color:var(--text-60)}
.atc-meta__row{display:inline-flex;align-items:center;gap:7px}
.atc-meta__row .ico{width:16px;height:16px;color:var(--accent-1)}
.atc-meta strong{color:var(--text)}
.payment-icons{display:flex;justify-content:center;gap:6px;margin-top:12px;flex-wrap:wrap}
/* Scale by width, never by a fixed height. A fixed height plus max-width:100%
   clamps the width on narrow screens while the height stays put, which squashes
   the strip horizontally. The 870x47 source keeps its ratio at any width. */
.payment-icons__img{width:100%;height:auto;max-width:430px;display:block}
.payment-icons span{height:24px;display:grid;place-items:center;padding:0 7px;border-radius:4px;background:#fff;box-shadow:0 0 0 1px rgba(18,18,18,.1) inset;font-size:10px;font-weight:600;letter-spacing:var(--ls-label);color:var(--text-60)}
.guarantee{border-radius:var(--text-boxes-radius);background:var(--bg-2);padding:22px 20px;margin-top:24px;text-align:center}
.guarantee__seal{width:56px;height:56px;margin:0 auto 12px;color:var(--accent-1)}
.guarantee h3{margin-bottom:8px}
.guarantee p{font-size:var(--fs-small);color:var(--text);margin:0 auto}

/* ==========================================================================
   ACCORDIONS
   ========================================================================== */
/* One accordion style everywhere on the site: a hairline rule, the label, and a
   plus that becomes a minus. No leading icons, no chevrons.
   The leading icons were five decorative glyphs sitting next to labels that
   already said exactly what they were ("Ingredients", "Payment & delivery"), so
   they added colour and ink without adding meaning, and they pulled the eye off
   the labels. The .ico rule is a hide rather than a markup deletion so the
   glyphs can come back if a future section genuinely needs them. */
.accordion{border-top:1px solid var(--line)}
.accordion:last-child{border-bottom:1px solid var(--line)}
.accordion__trigger{width:100%;display:flex;align-items:center;gap:12px;padding:20px 0;text-align:left;font-size:var(--fs-body);font-weight:500;color:var(--heading)}
.accordion__trigger .ico,
.accordion__trigger .chevron{display:none}
.accordion__trigger::after{
  content:"";margin-left:auto;flex:0 0 15px;width:15px;height:15px;
  background:
    linear-gradient(var(--heading),var(--heading)) center/15px 1.5px no-repeat,
    linear-gradient(var(--heading),var(--heading)) center/1.5px 15px no-repeat;
  transition:opacity var(--dur);
}
/* Open state drops the vertical bar, so the plus reads as a minus. */
.accordion.is-open .accordion__trigger::after{
  background:linear-gradient(var(--heading),var(--heading)) center/15px 1.5px no-repeat;
}
/* visibility:hidden takes the collapsed panel out of the accessibility tree as well
   as out of sight. Without it every trigger reported aria-expanded="false" over
   content a screen reader still announced, so the whole 15-question FAQ read out
   as one wall. visibility is transitionable, so the 0fr/1fr animation is intact. */
.accordion__panel{display:grid;grid-template-rows:0fr;visibility:hidden;transition:grid-template-rows var(--dur-long),visibility 0s linear var(--dur-long)}
.accordion.is-open .accordion__panel{grid-template-rows:1fr;visibility:visible;transition:grid-template-rows var(--dur-long),visibility 0s}
.accordion__inner{overflow:hidden}
.accordion__content{padding:0 0 20px;font-size:var(--fs-body);color:var(--text)}
.accordion__content p:last-child{margin-bottom:0}
.accordion__content ul{display:grid;gap:9px;margin:0 0 14px}
.accordion__content li{display:flex;gap:9px;align-items:flex-start}
.accordion__content ul:not(.check) li::before{content:"";flex:0 0 6px;width:6px;height:6px;border-radius:50%;background:var(--accent-1);margin-top:9px}

.faq .accordion__content{padding-bottom:22px;color:var(--text)}

/* ==========================================================================
   STICKY ADD-TO-CART BAR
   ========================================================================== */
.sticky-atc{position:fixed;left:0;right:0;bottom:0;z-index:70;background:#fff;box-shadow:0 -4px 20px rgba(18,18,18,.12);padding:8px var(--gutter-mobile);padding-bottom:calc(8px + env(safe-area-inset-bottom));transform:translateY(110%);transition:transform var(--dur-long) cubic-bezier(.25,.8,.3,1)}
.sticky-atc.is-visible{transform:translateY(0)}
.sticky-atc__inner{max-width:var(--page-width);margin:0 auto;display:flex;align-items:center;gap:12px}
.sticky-atc__img{flex:0 0 40px;width:40px;height:40px;border-radius:8px;object-fit:cover;background:#fff}
/* The text block only takes the width it needs. The button gets the rest, because on a
   phone the button is the reason this bar exists. */
.sticky-atc__text{flex:0 1 auto;min-width:0}
/* Both lines are single-line and truncate rather than wrap. The bar is 44px of
   button plus whatever is left, so anything that wraps pushes the bar taller and
   shunts the button off centre. */
.sticky-atc__title{font-size:13.5px;font-weight:700;color:var(--heading);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.2}
.sticky-atc__price{font-size:16px;font-weight:800;color:var(--heading);white-space:nowrap;margin-top:0;font-variant-numeric:tabular-nums;line-height:1.2}
.sticky-atc__rating .stars{color:var(--star);letter-spacing:-1px;flex:0 0 auto;font-size:12px}
/* Grows into whatever the thumbnail and price do not use, so the tap target is as wide
   as the bar allows. 48px keeps it above the minimum comfortable touch height. */
.sticky-atc .btn{width:auto;flex:1 1 auto;min-height:48px;padding:12px 16px;font-size:15px;font-weight:800;letter-spacing:.02em;white-space:nowrap}
/* 375px is the commonest phone width, so the thumbnail stays there for product
   recognition. Only genuinely narrow handsets drop it to buy the button more room. */
@media (max-width:359px){
  .sticky-atc{padding-left:12px;padding-right:12px}
  .sticky-atc__inner{gap:10px}
  .sticky-atc__img{display:none}
}
@media (min-width:750px){
  .sticky-atc{padding-left:var(--gutter-desktop);padding-right:var(--gutter-desktop)}
  .sticky-atc .btn{flex:0 1 auto;padding:12px 22px}
}

/* ==========================================================================
   PURCHASE BLOCK — sale header, countdown, assurances, vet recommendation
   Structure follows the reference funnel; colour comes entirely from our
   own tokens so it reads as this brand, not a pasted-in component.
   ========================================================================== */

/* sale label with rules either side */
.sale-head{display:flex;align-items:center;gap:14px;margin:4px 0 12px}
.sale-head__line{flex:1 1 auto;height:1px;background:rgba(18,18,18,.14)}
.sale-head__label{
  flex:0 0 auto;font-size:13px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--heading);
}

/* countdown. Runs to real local midnight — see the countdown module in funnel.js */
/* .deal-bar removed entirely. It began as a countdown, was demoted to a quiet
   "free shipping is included" strip, and then deleted: free shipping and the
   guarantee are already stated on every tier's perk bar and again in the
   assurances under the button, so the strip was a third telling of the same two
   facts sitting between the reader and the prices. */

/* shipping line above the button */
/* Two facts, one row: when it leaves and where it is going. The region is filled
   in from the visitor's own browser locale — no lookup, no request. */
.shiprow{
  display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  margin:18px 0 12px;padding:12px 16px;
  background:var(--bg-2);border-radius:var(--bar-radius);
}
.shiprow__item{
  display:inline-flex;align-items:center;gap:8px;
  font-size:var(--fs-small);color:var(--text-60);white-space:nowrap;
}
.shiprow__item strong{color:var(--heading);font-weight:700}
.shiprow__dot{
  width:9px;height:9px;border-radius:50%;background:#2FA84F;flex:0 0 9px;
  box-shadow:0 0 0 3px rgba(47,168,79,.2);
}
.shiprow__flag{width:22px;height:15px;flex:0 0 22px;display:block;border-radius:2px}
/* The two facts must sit on ONE line on a phone. At the 14px small token the pair
   needs 326px — dot 9 + flag 22 + two 8px icon gaps + 12px between the items, and
   267px of text — against an inner width of 244px at 320w, 295px at 375w and 325px at
   412w, so it wrapped to two rows on every phone under 430px.
   Reclaimed 22px of chrome (padding 16>12, item gap 12>8, icon gaps 8>6, flag 22>20)
   and scaled the type down with the viewport for the rest. Text costs ~19px of width
   per px of font, so 3.4vw keeps the row one line from ~355px up and reaches the full
   14px token by 412px. `flex-wrap` is deliberately left on: below ~355px it wraps
   rather than overflowing the card.
   Measured with _tools/measure.html — re-run it if either string changes. */
@media (max-width:749px){
  .shiprow{padding:12px;gap:8px}
  .shiprow__item{font-size:clamp(12px,3.4vw,14px);gap:6px}
  .shiprow__flag{width:20px;height:14px;flex:0 0 20px}
}

/* Payment marks. One row, centred, never wrapping: five marks at 34px plus 7px gaps is
   198px against 327px of column at 375w, so there is room to spare even at 320.
   The marks are full-bleed coloured cards of slightly different aspect (the brand's amex
   is 35x24, the rest are 750x471), so height is fixed and width runs auto - setting both
   would squash four of the five. */
.paymarks{
  list-style:none;margin:14px 0 0;padding:0;
  display:flex;justify-content:center;align-items:center;gap:7px;flex-wrap:nowrap;
}
/* flex-shrink MUST stay off. With seven marks the row is 292px against a 276px column
   at 320w, and the default shrink silently squeezed every card narrower to make it
   "fit" - which distorts a trademark rather than wrapping it. The narrow step below
   buys the room honestly instead. */
.paymarks li{flex:0 0 auto;display:block}
/* The hairline matters for PayPal specifically: its card is white, so without a border
   it reads as a gap in the row rather than a fifth tile. */
.paymarks img{height:24px;width:auto;display:block;border-radius:3px;border:1px solid rgba(19,61,38,.10)}
@media (max-width:379px){
  .paymarks{gap:5px}
  .paymarks img{height:21px}
}

.subscribe__terms{
  margin:-6px 0 16px;font-size:13px;line-height:1.45;color:var(--text-60);
}
.subscribe__terms a{color:var(--text-60);text-decoration:underline}

/* the add-to-cart itself — this is the thing the whole column exists for */
.btn--atc{
  width:100%;font-size:19px;font-weight:800;letter-spacing:.02em;
  padding:20px 22px;border-radius:var(--btn-radius);
}

.assurances{margin:16px 0 0;display:grid;gap:10px}
.assurances li{
  display:flex;align-items:center;gap:10px;
  font-size:var(--fs-small);font-weight:600;color:var(--text);
}
.assurances .ico{width:20px;height:20px;flex:0 0 20px;color:var(--accent-1)}

/* ---- the record ----
   Replaces the photo-led vet card. Three things were wrong with that block: the
   photograph was the single biggest space cost in the buy box, a stock shot of
   someone in scrubs beside a named male specialist did not survive one second of
   scrutiny, and a person's face is the weakest kind of proof available here
   anyway. Authority in this category comes from a dated citation a sceptic can
   go and check, so the block is now built like a record card, not a testimonial:
   a claim, the evidence, and where to verify it. Roughly half the height. */
.record{
  margin:24px 0 0;padding:0;overflow:hidden;
  background:var(--surface-quiet);
  box-shadow:0 0 0 1px var(--line) inset;
  border-radius:var(--bar-radius);
}
.record__inner{padding:16px 19px 16px}
.record__figure{margin:0;position:relative}
/* 1200/908 is the real file ratio, so the box matches the crop instead of cropping
   a crop. Everything that earns trust in this frame — her hands, the pad on the
   eye, the open jar — is already inside it. */
.record__photo{
  width:100%;display:block;aspect-ratio:1200/908;object-fit:cover;object-position:center;
}
/* A caption, not a testimonial: it describes the routine in the picture and makes
   no claim on her behalf, which is what keeps the cited quote below from being
   read as hers. Laid over the foot of the photo rather than given its own row,
   which buys back ~36px of buy-box height and reads as a press caption instead
   of a strip of UI. The gradient is navy-tinted so it belongs to the palette. */
.record__caption{
  position:absolute;left:0;right:0;bottom:0;
  padding:26px 19px 11px;
  background:linear-gradient(to top,rgba(11,25,48,.86),rgba(11,25,48,.55) 55%,rgba(11,25,48,0));
  font-size:12.5px;line-height:1.45;color:#fff;font-weight:500;
}
.record__badge{
  display:inline-flex;align-items:center;gap:5px;
  background:#fff;color:var(--heading);border-radius:var(--pill-radius);
  padding:4px 10px;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;white-space:nowrap;
  box-shadow:0 0 0 1px var(--line) inset;
}
.record__badge .ico{width:11px;height:11px;flex:0 0 11px;color:var(--accent-2)}
.record__head{
  margin:11px 0 0;font-size:17px;font-weight:800;color:var(--heading);
  letter-spacing:-.014em;line-height:1.25;
}
.record__body{margin:9px 0 0;font-size:14.5px;line-height:1.55;color:var(--text)}
.record__body--close{font-weight:700;color:var(--heading)}
/* Navy rule, not sky: this is the one quotation on the page that is somebody
   else's, so it gets the structural colour rather than a decorative one. */
.record__quote{
  margin:13px 0 0;padding:0 0 0 13px;border-left:3px solid var(--heading);
  font-size:16px;line-height:1.45;font-weight:600;color:var(--heading);
  letter-spacing:-.008em;
}
.record__quote cite{
  display:block;margin-top:7px;font-style:normal;font-weight:500;
  font-size:12.5px;line-height:1.4;color:var(--text-60);letter-spacing:0;
}
/* Spec chips. Six short, checkable statements about the formula do more for
   perceived rigour than one grand adjective, and unlike a certification badge
   every one of them is something you can actually stand behind. They also give
   the block a second visual beat so it does not read as one long paragraph. */
.record__specs{
  display:flex;flex-wrap:wrap;gap:6px;margin:13px 0 0;padding:0;list-style:none;
}
.record__specs li{
  display:inline-flex;align-items:center;
  background:#fff;color:var(--heading);
  box-shadow:0 0 0 1px var(--line) inset;
  border-radius:var(--pill-radius);
  padding:5px 11px;font-size:12px;font-weight:600;white-space:nowrap;
}
.record__specs li::before{
  content:"";flex:0 0 5px;width:5px;height:5px;margin-right:7px;
  border-radius:50%;background:var(--accent-2);
}
.record__src{
  margin:13px 0 0;padding-top:11px;border-top:1px solid var(--line);
  font-size:12px;line-height:1.5;color:var(--text-60);
}

/* ==========================================================================
   CHECKOUT BLOCK — reference funnel's structure, this brand's palette.

   The reference uses green benefit bars and a black selected card. Neither is in
   this palette, so bars take a navy tint and the selected card takes navy. Teal
   was tried and pulled: it reads as a second brand colour next to the navy, and
   this block is the one place on the page that must look like one system.

   ⚠ THE RIBBON IS A CORNER TAB, INSIDE THE CARD. .bundle__label carries
   overflow:hidden, so anything positioned outside its box is clipped. A ribbon
   floated above the top edge loses its top third. Keep it at top:0 right:0.

   ⚠ NO STRUCK-THROUGH SHIPPING PRICE ON THE BARS. Shipping is free on every
   tier, so a struck figure is a price nobody is ever charged (16 CFR 233.1).
   ========================================================================== */
.bundle{position:relative}
.bundle + .bundle{margin-top:12px}
.bundle__label{border-radius:11px}
.bundle__input:checked + .bundle__label{
  box-shadow:0 0 0 2px var(--heading) inset, 0 6px 20px -10px rgba(19,61,38,.35);
}

/* ribbon: corner tab, top-right, inside the clip */
.bundle__ribbon{
  position:absolute;top:0;right:0;z-index:2;
  background:var(--heading);color:#fff;
  border-radius:0 11px 0 9px;
  padding:6px 13px;font-size:11.5px;font-weight:700;letter-spacing:.01em;white-space:nowrap;
}
/* The ribbon gets its own band on the LABEL, so .bundle__main keeps symmetric padding
   and align-items:center actually centres on the row. Putting the clearance on the flex
   container instead (padding-top:34px) pushed the content box down inside the border
   box, so the radio and thumbnail centred 11px below the visible middle of the row. */
.bundle--has-ribbon .bundle__label{padding-top:30px}
.bundle--has-ribbon .bundle__main{padding-top:15px}

/* row: give the price column room so the compare note stops crowding the title */
/* Centred, not flex-start. flex-start pinned the radio and the thumbnail to the top of
   the row while the price block beside them is two lines tall, so the selector sat 6 to
   10px above the middle of its own row. The ribbon's extra top padding made it worse on
   whichever tiers carried one. */
.bundle__main{gap:13px;padding:15px 16px 13px;align-items:center}
.bundle__left{flex:1 1 auto;min-width:0;padding-right:6px}
.bundle__title{line-height:1.2}
.bundle__subtitle{font-size:12.5px;margin-top:4px;line-height:1.35}
.bundle__subtitle i{font-style:normal;color:var(--ink-faint,#9fb0c4);margin:0 4px}
.bundle__subtitle b{font-weight:700;color:var(--heading);white-space:nowrap}
.bundle__pricing{flex:0 0 auto;padding-left:4px}
.bundle__compare-note{margin-top:1px;line-height:1.25}

/* benefit bars: flush, stacked, navy tint */
.bundle__perks{display:flex;flex-direction:column;gap:1px;margin-top:11px}
.bundle__perk{
  display:flex;align-items:center;gap:9px;width:100%;
  padding:9px 16px;
  background:rgba(19,61,38,.055);color:var(--heading);
  font-size:12.5px;font-weight:700;letter-spacing:-.005em;
}
.bundle__perk .ico{width:16px;height:16px;flex:none;color:var(--accent-2)}
/* The base rule flips this text white for a navy bar. These bars are a light
   tint, so the colour has to be restated or the selected card's benefits vanish. */
.bundle__input:checked + .bundle__label .bundle__perk{background:rgba(19,61,38,.10);color:var(--heading)}
.bundle__input:checked + .bundle__label .bundle__perk .ico{color:var(--accent-2)}
.bundle__input:checked + .bundle__label .bundle__perk s{color:var(--ink-faint)}

/* subscribe: dashed opt-in box, and it reads as ON */
.subscribe{
  border:1.5px dashed var(--line-strong,#b9cbe0);background:transparent;
  border-radius:11px;padding:13px 10px;margin-top:14px;gap:8px;
}
/* The label must sit on ONE line. It wrapped at 375px, which split the consent
   sentence across two rows and made the box read as a paragraph rather than a
   choice. nowrap plus a vw-scaled size keeps it single-line from 320px up; the
   clamp ceiling is the old 14.5px so nothing changes on wider phones. If the
   copy or the switch width changes, re-check the fit at 320px. */
.subscribe .switch{flex:0 0 40px;width:40px}
/* Thumb travel is track width minus both 3px insets minus the 21px thumb, so a
   narrower track needs its own value or the thumb overshoots the edge. */
.subscribe .switch input:checked ~ .switch__thumb{transform:translateX(13px)}
.subscribe__title{font-size:clamp(10.5px,calc(11.5px + (100vw - 320px) * 0.0535),14.5px);white-space:nowrap}
.subscribe__sub{font-size:12.5px;line-height:1.45}

/* --------------------------------------------------------------------------
   THUMBNAIL STRIP. Was: an 8px radius, a pale-blue fill showing through as
   rounded corners on every photo, and a 2px sky ring on the current one. The
   fill and the ring were the "blue corners" - they sat on top of the artwork.
   Now: square, equal, hairline border, and the selected state is a navy ring
   on the outside of the image rather than an inset overlay.
   -------------------------------------------------------------------------- */
.gallery__thumb{
  border-radius:4px;background:transparent;
  box-shadow:none;border:1px solid var(--line);
  padding:0;overflow:hidden;
}
.gallery__thumb img{border-radius:0;display:block}
.gallery__thumb[aria-current="true"]{
  box-shadow:none;border:2px solid var(--heading);
}

/* Thumbnail strip sized so FIVE are visible on a 375px phone, not four. At 72px
   the fifth was always cut in half, which reads as a broken row rather than an
   invitation to swipe. 54px still shows what each slide is. */
/* Measured, not guessed: the mobile strip is 261px once the two arrows and the
   row gaps are taken out. Five thumbs plus four 5px gaps has to fit inside that,
   so 48px is the largest size that shows five. At 54 the fifth was clipped. */
.gallery__thumb{flex:0 0 48px;height:48px}
.gallery__thumbs{gap:5px}
@media (max-width:749px){
  .gallery--stack .gallery__arrow{flex:0 0 30px;width:30px;height:30px}
  .gallery--stack .gallery__nav{gap:7px}
}
@media (min-width:750px){.gallery__thumb{flex:0 0 84px;height:84px}}

/* ==========================================================================
   TIER SELECTION — the reference funnel's colour structure, our navy.
   Unselected: quiet card, benefit bars a pale tint of the brand colour.
   Selected:   the bars FILL solid navy with white text.
   Previously only the border changed, which is a 2px difference the eye has to
   hunt for. Filling the bars makes the chosen tier the only saturated object in
   the box, so the selection is readable at a glance and on a phone.
   ========================================================================== */
.bundle__perk .ico{display:none}
.bundle__perk::before{
  content:"";flex:none;width:19px;height:19px;border-radius:50%;
  background:var(--heading)
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round' d='M5 12.5l4.6 4.6L19 7.4'/%3E%3C/svg%3E")
    center/11px 11px no-repeat;
  opacity:.34;transition:opacity var(--dur),background-color var(--dur);
}
.bundle__perk{
  background:rgba(19,61,38,.06);
  color:var(--ink-muted,#5A7391);
  transition:background var(--dur),color var(--dur);
}
.bundle__input:checked + .bundle__label .bundle__perk{
  background:var(--heading);
  color:#fff;
}
.bundle__input:checked + .bundle__label .bundle__perk::before{
  opacity:1;
  background-color:#fff;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%2316305C' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round' d='M5 12.5l4.6 4.6L19 7.4'/%3E%3C/svg%3E");
}
.bundle__input:checked + .bundle__label .bundle__perk s{color:rgba(255,255,255,.7)}
/* the chosen card also lifts: white ground against the quiet unselected ones */
.bundle__input:checked + .bundle__label{background:#fff}

/* ==========================================================================
   DESKTOP GALLERY = CAROUSEL, not a stacked mosaic.
   The mosaic rendered all seven slides at 5152px against a 2131px buy box, so a
   desktop visitor scrolled past every photo before reaching the tiers. One slide
   at a time puts the image and the checkout on the same screen, which is what
   the reference funnel does and the only arrangement where a sticky buy box has
   anything to be sticky against.

   funnel.js needs no change: its isCarousel() test is scrollWidth > clientWidth,
   so the arrows and thumbnail sync switch on by themselves at every width.
   ========================================================================== */
.product__media-col,
.gallery--stack .gallery__stage{min-width:0}
.gallery--stack .gallery__slides{
  display:flex;grid-template-columns:none;
  min-width:0;width:100%;gap:0;
  overflow-x:auto;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none;
}
.gallery--stack .gallery__slides::-webkit-scrollbar{display:none}
.gallery--stack .gallery__slide,
.gallery--stack .gallery__slide--full,
.gallery--stack .gallery__slide--half,
.gallery--stack .gallery__slide--third{
  grid-column:auto;flex:0 0 100%;scroll-snap-align:center;
}
.gallery--stack .gallery__nav{
  display:flex;align-items:center;gap:10px;margin-top:12px;
}
.gallery--stack .gallery__thumbs{flex:1 1 auto;min-width:0;margin-top:0}
.gallery--stack .gallery__arrow{
  position:static;transform:none;display:grid;flex:0 0 34px;
  width:34px;height:34px;background:#fff;
  box-shadow:0 0 0 1px var(--line) inset;
}
.gallery--stack .gallery__arrow svg{width:15px;height:15px;color:var(--heading)}
@media (min-width:990px){
  /* the two columns are now comparable heights, so the buy box can simply sit
     beside the gallery rather than sticking past a five-screen image stack */
  .product__info-col{position:static}
  .gallery--stack .gallery__thumb{flex:0 0 72px;height:72px}
}

@media (min-width:990px){
  /* The columns have swapped roles. The gallery used to be a 5152px stack and the
     buy box the short one, so the buy box stuck. As a carousel the gallery is
     ~808px and the buy box is ~2131px, so the image is now the thing that should
     hold while the tiers, terms and accordions scroll past it. */
  .product__media-col{position:sticky;top:85px;align-self:start}
}

/* The uniform tick disc goes: the two perks say different things, so they get
   different marks. Truck for the shipping bar, gift for the comb. The icons stay
   in the same 19px optical box the tick occupied, and invert to white when the
   tier fills navy, so the row rhythm is unchanged. */
.bundle__perk::before{content:none}
.bundle__perk .ico{
  display:block;flex:none;width:20px;height:20px;
  color:var(--ink-faint,#8CA3BC);
  transition:color var(--dur);
}
.bundle__input:checked + .bundle__label .bundle__perk .ico{color:#fff}

/* 54px, and the source images are now cropped to the product bounding box. At
   46px against an uncropped 2048 square, object-fit:cover was showing a slice of
   the jar's midsection with the lid and base outside the crop, which read as a
   stretched, too-tall jar. */
.bundle__image{flex:0 0 54px;width:54px;height:54px;border-radius:8px;object-fit:cover}

/* ==========================================================================
   DESKTOP GALLERY: MOSAIC AGAIN (>=990px only)
   Mobile is untouched and stays the scroll-snap carousel.

   Rhythm is the reference's: one wide hero, then two, then two, then one wide.
   With six slides that is span-2 / 1 1 / 1 1 / span-2, which is why the spans are
   pinned to :first-child and :last-child rather than nth-of-type lists: add or
   remove a middle slide and the shape still holds.

   funnel.js needs no change. isCarousel() tests scrollWidth > clientWidth, and a
   grid with overflow visible reports them equal, so the arrows, the snap and the
   thumbnail sync all switch themselves off here.

   Both columns go static. The buy box was sticky because the gallery had shrunk to
   a single 808px slide; as a mosaic the media column is the tall one again, and a
   sticky buy box beside it would pin at the top and sit in dead space.
   ========================================================================== */
@media (min-width:990px){
  .product__media-col{position:static}
  .product__info-col{position:static}

  .gallery--stack .gallery__slides{
    display:grid;grid-template-columns:1fr 1fr;gap:14px;
    overflow:visible;scroll-snap-type:none;
  }
  .gallery--stack .gallery__slide,
  .gallery--stack .gallery__slide--full,
  .gallery--stack .gallery__slide--half,
  .gallery--stack .gallery__slide--third{
    flex:none;width:auto;grid-column:span 1;scroll-snap-align:none;
  }
  .gallery--stack .gallery__slide:first-child,
  .gallery--stack .gallery__slide:last-child{grid-column:span 2}
  /* With an ODD number of middle slides the last one would sit alone in a 2-column
     row as a half-width orphan. This catches exactly that case: the second-to-last
     slide, when it is an even-numbered child, is the one left over. Seven slides
     span 2 / 1 1 / 1 1 / 2 / 2; six slides do not match it and are unaffected. */
  .gallery--stack .gallery__slide:nth-child(even):nth-last-child(2){grid-column:span 2}

  .gallery--stack .gallery__slide img{
    width:100%;height:100%;object-fit:cover;border-radius:var(--media-radius);display:block;
  }
  /* Every slide is on screen at once, so the nav row has nothing left to do. */
  .gallery--stack .gallery__nav{display:none}
}

/* --------------------------------------------------------------------------
   BUY_BOX = 'app'  (funnel.js). A bundle app owns the offer.

   Set by the JS on <html>, not <body>, so it applies before first paint and the
   hand-built tier stack never flashes on screen and then disappears.

   Everything hidden here is wired to the tier radios: without them the price,
   the instalment maths, the recurring-billing terms and the sticky bar have
   nothing to read, so they go together or not at all. `display:none` rather
   than removal keeps the markup one word away from coming back.

   ⚠ The app's widget must then provide its own add-to-cart. This hides ours.
   -------------------------------------------------------------------------- */
.buybox-app [data-bundles],
.buybox-app [data-subscribe],
.buybox-app [data-atc-terms],
.buybox-app .btn--atc,
.buybox-app .sticky-atc{display:none !important}

/* ==========================================================================
   NATIVA BUY-BOX CONTROLS
   This funnel sells ONE product with a quantity and two opt-in add-ons, so it
   has no tier stack. These are the controls that replace it.
   ========================================================================== */

.product__lede{font-size:var(--fs-body);line-height:1.6;color:var(--text-60);
  margin:0 0 20px;max-width:var(--measure)}

/* ---------- quantity ---------- */
.supply{margin:0 0 18px;padding:14px 16px;border:1px solid var(--line);border-radius:12px;
  background:var(--surface-quiet)}
.supply__row{display:flex;align-items:center;justify-content:space-between;gap:14px}
.supply__label{font-size:var(--fs-label);font-weight:600;letter-spacing:var(--ls-label);
  text-transform:uppercase;color:var(--heading)}
.supply__note{margin:10px 0 0;font-size:var(--fs-small);color:var(--ink-muted)}
.supply__note strong{color:var(--heading);font-variant-numeric:tabular-nums}

.qty{display:flex;align-items:center;gap:0;border:1px solid var(--line-strong);
  border-radius:10px;overflow:hidden;background:#fff}
.qty__btn{width:40px;height:40px;border:0;background:#fff;color:var(--heading);
  font-size:20px;line-height:1;cursor:pointer;flex:0 0 40px}
.qty__btn:hover{background:var(--surface-quiet-2)}
.qty__btn:focus-visible{outline:2px solid var(--accent-1);outline-offset:-2px}
/* Tabular numerals and a fixed width, so stepping 9 -> 10 does not resize the
   control and shift the row it sits in. */
.qty__input{width:46px;height:40px;border:0;border-left:1px solid var(--line);
  border-right:1px solid var(--line);text-align:center;font:inherit;font-size:15px;
  font-weight:600;font-variant-numeric:tabular-nums;color:var(--heading);background:#fff;
  -moz-appearance:textfield}
.qty__input::-webkit-outer-spin-button,
.qty__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.qty__input:focus-visible{outline:2px solid var(--accent-1);outline-offset:-2px}

/* ---------- add-ons ----------
   ⚠ Styled so an UNCHECKED box is visibly unchecked at a glance. An add-on that
   looks selected when it is not, or vice versa, is how people end up paying for
   something they did not choose. The checked state changes border, ground AND
   the mark, so it does not rely on colour alone. */
.addons{border:0;padding:0;margin:0 0 16px;min-width:0}
.addons__legend{font-size:var(--fs-small);font-weight:600;color:var(--ink-muted);
  padding:0;margin:0 0 8px}
.addon{display:flex;align-items:flex-start;gap:11px;padding:12px 13px;margin-bottom:8px;
  border:1px solid var(--line);border-radius:10px;background:#fff;cursor:pointer;
  transition:border-color .15s,background .15s}
.addon:last-child{margin-bottom:0}
.addon:hover{border-color:var(--line-strong)}
.addon input{position:absolute;opacity:0;width:0;height:0}
.addon__box{flex:0 0 20px;width:20px;height:20px;margin-top:1px;border-radius:6px;
  border:2px solid var(--line-strong);background:#fff;position:relative;transition:all .15s}
.addon__box::after{content:"";position:absolute;left:5px;top:1px;width:5px;height:10px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg) scale(0);
  transition:transform .15s}
.addon input:checked ~ .addon__box{background:var(--accent-2);border-color:var(--accent-2)}
.addon input:checked ~ .addon__box::after{transform:rotate(45deg) scale(1)}
.addon input:focus-visible ~ .addon__box{outline:2px solid var(--accent-1);outline-offset:2px}
.addon:has(input:checked){border-color:var(--accent-2);background:var(--surface-quiet)}
.addon__text{min-width:0;display:flex;flex-direction:column;gap:2px}
.addon__title{font-size:14.5px;font-weight:600;color:var(--heading);line-height:1.3}
.addon__title b{font-weight:700;font-variant-numeric:tabular-nums}
.addon__sub{font-size:13px;line-height:1.45;color:var(--text-60)}

/* ---------- itemised terms under the button ---------- */
.atc-terms{margin:10px 0 0;font-size:13px;line-height:1.5;color:var(--ink-muted);
  text-align:center}
.atc-terms.is-error{color:#B4372B;font-weight:600}

.paymarks__txt{font-size:13px;font-weight:600;color:var(--ink-muted);
  display:flex;align-items:center}
.paymarks .ico{width:17px;height:17px;color:var(--ink-muted)}

/* A loud, ugly placeholder marker. It is meant to be impossible to ship by
   accident: anything wearing this class is unverified content. */
.flag-warn{background:#FFF6D6;border:1px dashed #B58900;border-radius:8px;
  padding:9px 11px;font-size:13px;color:#6B4E00;margin:0 0 12px}

/* The announcement ticker sits above the header and runs one short message, so
   it gets generous side padding: the marquee repeats its group until it exceeds
   the viewport, and a short item otherwise appears many times at once. */
.announce span{padding-inline:clamp(56px,20vw,280px)}

/* ==========================================================================
   BUNDLE TIERS
   Three radio tiers. Replaces the quantity + add-on controls.

   Selected tier goes WHITE on a tinted stack: the chosen card becomes the
   brightest thing in the group without needing a heavier border, and the
   unchosen ones read as available rather than disabled.
   ========================================================================== */
.tiers{display:grid;gap:10px;margin:0 0 16px}
.tier{position:relative}
.tier__input{position:absolute;opacity:0;width:0;height:0}
.tier__label{display:flex;align-items:center;gap:12px;padding:15px 14px;cursor:pointer;
  background:var(--surface-quiet);border:2px solid var(--line);border-radius:12px;
  transition:border-color .15s,background .15s}
.tier__label:hover{border-color:var(--line-strong)}
.tier__input:checked ~ .tier__label{background:#fff;border-color:var(--accent-2)}
.tier__input:focus-visible ~ .tier__label{outline:2px solid var(--accent-1);outline-offset:2px}

.tier__radio{flex:0 0 22px;width:22px;height:22px;border-radius:50%;
  border:2px solid var(--line-strong);background:#fff;position:relative}
.tier__input:checked ~ .tier__label .tier__radio{border-color:var(--accent-2)}
.tier__input:checked ~ .tier__label .tier__radio::after{content:"";position:absolute;
  inset:4px;border-radius:50%;background:var(--accent-2)}

.tier__main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:3px}
.tier__title{font-size:16px;font-weight:700;color:var(--heading);line-height:1.2}
.tier__sub{font-size:12.5px;color:var(--text-60);line-height:1.3}
.tier__price{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;
  font-variant-numeric:tabular-nums}
.tier__price b{font-size:18px;font-weight:800;color:var(--heading)}
.tier__price s{font-size:13px;color:var(--ink-faint)}

/* The perk bar is attached to the card, so it reads as part of the tier rather
   than as a floating claim. Green only on the selected one. */
.tier__perks{display:flex;flex-wrap:wrap;gap:0;margin:0;padding:0;list-style:none;
  border-radius:0 0 12px 12px;overflow:hidden;margin-top:-12px;position:relative;z-index:-1}
.tier__perks li{flex:1 1 auto;padding:9px 14px 8px;font-size:12px;font-weight:600;
  background:var(--surface-quiet-2);color:var(--ink-muted);text-align:center}
.tier__input:checked ~ .tier__perks li{background:var(--accent-2);color:#fff}

.tier__ribbon{position:absolute;top:-9px;right:12px;z-index:2;font-size:10.5px;
  font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#fff;
  background:var(--accent-2);border-radius:40px;padding:4px 10px}
.tier__ribbon--plain{background:var(--heading)}

/* ==========================================================================
   REFERENCE MATCH (23 Sep 2026) — gallery, tiers, ATC and ship row set to the
   tryalmape.com PDP the brand supplied.
   Gallery: arrows overlay the image at every width (dark translucent discs,
   hidden at either end). On phones the carousel runs edge to edge with square
   corners, the thumbnail strip goes and a dot row takes its place. Desktop
   keeps the thumbnail strip under the image.
   ========================================================================== */
.gallery--stack .gallery__stage{position:relative}
.gallery--stack .gallery__stage .gallery__arrow{
  position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:36px;height:36px;flex:none;display:grid;place-items:center;border-radius:50%;
  background:rgba(19,61,38,.55);box-shadow:none;transition:opacity var(--dur),background var(--dur);
}
.gallery--stack .gallery__stage .gallery__arrow:hover{background:rgba(19,61,38,.75)}
.gallery--stack .gallery__stage .gallery__arrow svg{width:15px;height:15px;color:#fff}
.gallery--stack .gallery__stage .gallery__arrow--prev{left:10px}
.gallery--stack .gallery__stage .gallery__arrow--next{right:10px}
.gallery--stack .gallery__stage .gallery__arrow:disabled{opacity:0;pointer-events:none}
.gallery__dots{display:none}
@media (max-width:749px){
  .gallery--stack{margin:0 calc(-1 * var(--gutter-mobile))}
  .gallery--stack .gallery__slide > img{border-radius:0}
  .gallery--stack .gallery__nav{display:none}
  .gallery__dots{display:flex;justify-content:center;align-items:center;gap:8px;margin-top:12px}
  .gallery__dot{width:7px;height:7px;border-radius:50%;background:rgba(19,61,38,.22);transition:background var(--dur),transform var(--dur)}
  .gallery__dot.is-active{background:var(--heading);transform:scale(1.15)}
}

/* Tiers: white cards with a pale-mint perk bar; the chosen tier turns mint with
   a solid green bar, as on the reference. */
.tier__label{background:#fff}
.tier__perks li{background:#DDF2DC;color:var(--heading)}
.tier__input:checked ~ .tier__label{background:#E7F6E6;border-color:var(--accent-2)}
.tier__input:checked ~ .tier__perks li{background:var(--accent-2);color:#fff}

/* Add to cart in brand green with the reference's 8px corners. White on
   #2F7E4B is 5.1:1. */
.btn--atc{background:var(--accent-2);border-radius:8px}
.btn--atc:hover{background:var(--accent-2-dark);filter:none}

/* Round flag on the ship row and on the other "Ships from the USA" lines. */
.shiprow__flag{width:22px;height:22px;flex:0 0 22px;border-radius:50%}
@media (max-width:749px){.shiprow__flag{width:20px;height:20px;flex:0 0 20px}}
/* Clipped round by CSS: a clipPath inside a <symbol> is not honoured through <use> in Chrome. */
.ico--flag,.shiprow__flag{border-radius:50%;overflow:hidden;clip-path:circle(50%)}

/* Product name line above the H1, the slot the reference uses for its title. */
.product__name{margin:0 0 8px;font-size:15px;font-weight:700;color:var(--heading);letter-spacing:.01em}
.product__name span{font-weight:500;color:var(--accent-2)}
/* Desktop is the two-column stacked grid (every image on screen, as on the
   reference), so there is nothing for the overlay arrows to do there. */
@media (min-width:990px){.gallery--stack .gallery__stage .gallery__arrow{display:none}}

/* ==========================================================================
   MOBILE HERO = REFERENCE (23 Sep 2026, second pass). Measured on
   tryalmape.com at 375px: image edge to edge; white 31px zoom disc top left;
   black 30px arrow discs 10px in from the edge; dots overlaid on the bottom of
   the image; then a trust row, a 17px mixed-weight product title, and plain
   14px bullets with open tracking.
   ========================================================================== */
.gallery__zoom{
  position:absolute;top:10px;left:10px;z-index:3;width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;background:#fff;color:#121212;box-shadow:0 1px 4px rgba(0,0,0,.12);
}
.gallery__zoom svg{width:17px;height:17px}
.gallery--stack .gallery__stage .gallery__arrow{width:30px;height:30px;background:rgba(18,18,18,.9)}
.gallery--stack .gallery__stage .gallery__arrow:hover{background:#121212}
.gallery--stack .gallery__stage .gallery__arrow svg{width:13px;height:13px;color:rgba(255,255,255,.9)}
@media (max-width:749px){
  .gallery__dots{position:absolute;left:0;right:0;bottom:10px;z-index:3;margin:0;gap:9px}
  .gallery__dot{width:8px;height:8px;background:rgba(18,18,18,.25)}
  .gallery__dot.is-active{background:#121212;transform:none}
}
@media (min-width:990px){.gallery__zoom{display:none}}

.gallery-lightbox{position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,.92);display:grid;place-items:center;padding:16px;cursor:zoom-out}
.gallery-lightbox[hidden]{display:none}
.gallery-lightbox img{max-width:100%;max-height:100%;object-fit:contain}

.product__trust{
  display:flex;align-items:center;flex-wrap:wrap;gap:4px 5px;margin:4px 0 12px;white-space:nowrap;
  font-size:15px;letter-spacing:.03em;color:var(--text);
}
.product__trust .ico{width:22px;height:22px;flex:0 0 22px;color:var(--accent-2)}
.product__trust strong{font-weight:700}
.product__trust span{color:var(--ink-faint);margin:0 2px}
.product__info-col h1.product__title{
  font-size:17px;line-height:1.3;font-weight:400;letter-spacing:.06em;color:#121212;margin:0 0 16px;
}
.product__title strong{font-weight:700}
@media (min-width:750px){.product__info-col h1.product__title{font-size:23px}}

.usp-list--plain{gap:14px;margin:0 0 22px;padding:0 8px}
.usp-list--plain li{display:block;font-size:14px;line-height:1.3;letter-spacing:.06em;color:#121212}
@media (min-width:750px){.usp-list--plain li{font-size:16px}}

/* A grid track defaults to min-width:auto, so one nowrap line in the buy box
   (the trust row) widened the whole column past a 375px screen. */
.product__info-col{min-width:0}

/* Reference bullet list (third pass): green fine-line icon on the left, 14px text
   with open tracking, tight 12px rhythm. Five rows, like the reference. */
.usp-list--ref{margin:0 0 18px;gap:12px}
.usp-list--ref li{display:flex;align-items:flex-start;gap:10px;font-size:14px;line-height:1.35;letter-spacing:.05em;color:#121212}
.usp-list--ref .ico{width:30px;height:30px;flex:0 0 30px;color:var(--heading);margin-top:0}
.usp-list--ref strong{font-weight:700;color:#121212}
@media (min-width:750px){.usp-list--ref li{font-size:16px}.usp-list--ref .ico{width:30px;height:30px;flex-basis:30px}}

/* Trust row in the reference's rating slot: a solid green badge plus one fact.
   No stars and no review count until real reviews exist. */
.product__trust{gap:8px;margin:2px 0 10px;font-size:13px;letter-spacing:.02em;flex-wrap:wrap}
.product__badge{display:inline-flex;align-items:center;gap:5px;background:var(--accent-2);color:#fff;
  font-weight:700;font-size:13px;padding:4px 10px 4px 7px;border-radius:4px;white-space:nowrap}
.product__trust .product__badge .ico{width:16px;height:16px;flex:0 0 16px;color:#fff}
.product__info-col h1.product__title{margin:0 0 12px}
@media (min-width:750px){.product__trust{font-size:15px}.product__badge{font-size:15px}}
/* The older `.product__trust span` rule (faint separator dot) outranked both of these. */
.product__trust .product__badge{color:#fff;margin:0}
.product__trust > span:not(.product__badge){color:#121212;margin:0}
.product__trust > span:not(.product__badge){display:inline-flex;align-items:center;gap:5px}
.product__trust .ico--flag{width:18px;height:18px;flex:0 0 18px}

/* SWIPE AFFORDANCE (phones). The next photo peeks in at the right edge, the dots
   sit under the image (not over the benefit cards baked into slide 1), and a
   "1 / 7" counter sits on the image. Three cues that this is a carousel. */
.gallery__count{display:none}
@media (max-width:749px){
  .gallery--stack .gallery__slides{gap:8px;padding:0 16px;scroll-padding:0 16px}
  .gallery--stack .gallery__slide,
  .gallery--stack .gallery__slide--full{flex:0 0 calc(100% - 44px);scroll-snap-align:center}
  .gallery--stack .gallery__slide > img{border-radius:12px}
  .gallery__dots{position:static;margin-top:12px}
  .gallery__count{
    display:block;position:absolute;top:12px;right:28px;z-index:3;
    background:rgba(18,18,18,.72);color:#fff;font-size:12px;font-weight:600;letter-spacing:.04em;
    padding:4px 9px;border-radius:40px;font-variant-numeric:tabular-nums;
  }
  .gallery__zoom{left:26px;top:12px}
  .gallery--stack .gallery__stage .gallery__arrow--prev{left:22px}
  .gallery--stack .gallery__stage .gallery__arrow--next{right:22px}
}

/* Ship row on ONE line on phones. Poppins sets ~7% wider than the old face, so the
   two facts wrapped at 375px. Tighter type, no tracking, and nowrap; the row is
   re-measured by the check in _tools (overflow must stay 0 at 360px). */
@media (max-width:749px){
  .shiprow{flex-wrap:nowrap;gap:6px;padding:11px 10px}
  .shiprow__item{font-size:clamp(11px,3.15vw,14px);letter-spacing:0;gap:5px}
  .shiprow__item strong{letter-spacing:0}
  .shiprow__dot{width:8px;height:8px;flex-basis:8px}
  .shiprow__flag{width:18px;height:18px;flex:0 0 18px}
}

/* ---- buy-box tail, reference layout: payment grid, two trust lines, card ---- */
.paygrid{list-style:none;margin:16px 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.paygrid li{display:grid;place-items:center;height:40px;border:1px solid rgba(18,18,18,.12);border-radius:6px;background:#fff}
.paygrid img{height:22px;width:auto;display:block}
@media (min-width:750px){.paygrid{grid-template-columns:repeat(8,1fr)}}
.buylines{list-style:none;margin:6px 0 16px;padding:0;display:grid;gap:10px}
.buylines li{display:flex;align-items:center;gap:12px;font-size:15px;letter-spacing:.05em;color:#121212}
.buylines__flag{width:28px;height:28px;flex:0 0 28px;border-radius:50%;overflow:hidden;clip-path:circle(50%)}
.buylines__shield{width:28px;height:28px;flex:0 0 28px;color:var(--accent-3)}
.revcard{margin:0 0 8px;padding:18px 18px 20px;border:1px solid rgba(19,61,38,.12);border-top:5px solid var(--accent-2);
  border-radius:16px;background:linear-gradient(#fff,#F6FAF5);box-shadow:0 6px 18px rgba(19,61,38,.06)}
.revcard__head{display:flex;align-items:center;gap:12px;margin-bottom:12px}
.revcard__avatar{width:56px;height:56px;border-radius:50%;object-fit:contain;padding:10px 6px;background:#FFF8E6;border:2px solid var(--accent-2)}
.revcard__name{margin:0;font-weight:700;font-size:17px;color:#121212;letter-spacing:-.01em}
.revcard__badge{margin:2px 0 0;display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--accent-2)}
.revcard__badge svg{width:16px;height:16px}
.revcard__title{margin:0 0 8px;font-weight:700;font-size:17px;line-height:1.3;color:#121212}
.revcard__body{margin:0;font-size:15px;line-height:1.55;letter-spacing:.04em;color:#5A5F5B}

/* Bullet icons in the product-photo card style: bold forest line icon on a cream
   rounded tile (matches the "Feel Lighter / Plant-Based / Risk-Free" cards). */
.usp-list--ref li{align-items:center}
.usp-list--ref .ico{width:44px;height:44px;flex:0 0 44px;padding:8px;margin:0;
  background:#F6F0E1;border-radius:11px;color:#133D26;box-shadow:0 1px 0 rgba(19,61,38,.06)}
@media (min-width:750px){.usp-list--ref .ico{width:48px;height:48px;flex-basis:48px;padding:9px}}
.usp-list--ref .ico{padding:5px}
@media (min-width:750px){.usp-list--ref .ico{padding:6px}}

/* Trustpilot TrustBox slots. Hidden until a real business-unit id is set. */
.tp-slot{margin:0 0 8px}
.tp-slot--voices{margin:0 auto 18px;max-width:700px}
.tp-slot[hidden]{display:none}
/* Generated line icons (assets/img/icons, GPT Image 2.5, matched to the hero-photo cards). */
.usp-list--ref img.ico{object-fit:contain;padding:7px}

/* Local mockup elements (see assets/js/mockup-local.js) */
.mock-tag{display:inline-block;margin-left:6px;font-size:9px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:#fff;background:#C0392B;border-radius:3px;padding:1px 4px;vertical-align:middle}
.mock-rating{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:2px 0 12px;font-size:16px;letter-spacing:.03em;color:#121212}
.voices .mock-rating{justify-content:center}
.mock-rating b{font-weight:700}
.mock-rating__stars{display:inline-flex;gap:2px}
.mock-rating__stars i{width:22px;height:22px;background:#00B67A;display:grid;place-items:center}
.mock-rating__stars svg{width:16px;height:16px}
.revcard__avatar--photo{object-fit:cover;padding:0}
.revcard__body--long p{margin:0 0 10px;font-size:15px;line-height:1.55;letter-spacing:.02em;color:#3E4540}
.revcard__body--long p:last-child{margin:0}
/* Payment strip image (assets/img/pay/payment-types.png, 870x47) */
.paystrip{display:block;width:100%;height:auto;margin:14px 0 4px}
.revcard__avatar--photo{object-position:50% 50%}
