/* =============================================================
   Frost Bio — brand theme
   Loaded AFTER style.css. The base sheet is token-driven, so
   remapping its custom properties re-skins every shared page
   (cart, checkout, account, blog) in one shot. Below that are
   the components of a single-vial-first store.

   Ported from four.css (the Four Performance purple theme). The
   layout, grid and spacing are deliberately unchanged — this is a
   re-skin plus a merchandising restructure, not a redesign. Class
   names are kept byte-for-byte so the PHP keeps matching; only the
   custom-property VALUES move to the ice palette, and the new
   .fb-* components are added at the bottom.
   ============================================================= */

:root {
  /* ---- Brand palette — decided with the owner, do not drift ---- */
  --fb-ice:         #7FD4F5;   /* bright accent — announce bar, active states */
  --fb-deep:        #0B3B5C;   /* primary — buttons, headings, dark bands */
  --fb-glacier:     #EAF6FB;   /* pale section background */
  --fb-steel:       #0F1D26;   /* ink / body text */
  --fb-frost:       #C9E9F5;   /* soft fills, alternating headline lines */
  --fb-signal:      #3DE0C4;   /* savings / in-stock / verified accents */

  /* ---- Derived shades — all pulled out of the six above ----
     --fb-ice is a 0.58-luminance cyan: beautiful as a fill, invisible
     as text on white (1.4:1). --fb-ice-deep is the same hue darkened
     until it clears 4.5:1 on paper, and is what every ice-coloured
     LABEL uses. Filling with --fb-ice, lettering with --fb-ice-deep. */
  --fb-ice-deep:    #1273A6;
  --fb-ice-soft:    #A5E2F8;
  --fb-deep-2:      #062A43;   /* button hover / gradient floor */
  --fb-mist:        #F4F9FC;   /* neutral cool surface — image wells */
  --fb-edge:        #D3E7F0;   /* hairlines, dashed rules, control borders */
  --fb-slate:       #3A4C57;   /* long-form body copy on light */
  --fb-signal-deep: #0E9B80;   /* signal, darkened enough to be text */
  --fb-alert:       #D92D20;   /* sale flags — the one warm colour */

  /* ---- Remap the base design tokens ---- */
  --c-paper:       #FFFFFF;
  --c-ink:         var(--fb-steel);
  --c-ink-2:       var(--fb-deep);
  --c-navy:        var(--fb-deep);
  --c-teal:        var(--fb-deep);
  --c-teal-light:  var(--fb-ice-deep);
  --c-teal-bright: var(--fb-ice);
  --c-muted:       #566B78;
  --c-line:        rgba(15, 29, 38, 0.10);
  --c-line-strong: rgba(15, 29, 38, 0.18);

  --bg:           #FFFFFF;
  --surface:      #FFFFFF;
  --surface-2:    var(--fb-mist);
  --surface-soft: var(--fb-glacier);

  /* --c-cream is inherited from the Boreal markup — product.php,
     order-confirmation.php and affiliate-dashboard.php all set
     `background: var(--c-cream)` inline — but nothing has ever defined
     it, so those panels have been silently falling back to transparent.
     Defining it here is the cheapest fix and puts it with the tokens. */
  --c-cream:      var(--fb-mist);

  --font-sans:    "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-display: "Clash Display", "Public Sans", -apple-system, BlinkMacSystemFont, Helvetica, sans-serif;

  /* Radii inherited from Four unchanged — 4px controls, 8px cards.
     Moving these would shift every card's silhouette, and the brief is
     to keep component metrics identical. */
  --r-sm:   4px;
  --r-md:   8px;
  --r-lg:   12px;
  --r-xl:   16px;
  --r-pill: 999px;

  /* Shadows recast cold: a blue-grey tint, never the purple cast. */
  --shadow-sm: 0 1px 2px rgba(15, 29, 38, 0.06);
  --shadow-md: 0 8px 26px -10px rgba(11, 59, 92, 0.20), 0 2px 6px rgba(15, 29, 38, 0.04);
  --shadow-lg: 0 30px 60px -22px rgba(11, 59, 92, 0.30), 0 8px 20px -12px rgba(15, 29, 38, 0.08);

  --container: 1280px;

  /* ---- Legacy --fp-* aliases ----
     ~150 inline style="" attributes across index.php, kits.php, about.php
     and includes/quiz.php still name the Four variables. An UNDEFINED
     custom property makes the whole declaration fail silently — that is
     the bug that ate --gutter — so a stale var() would blank a quiz
     progress bar or an eyebrow with no console error to find it by.
     These aliases keep every one of those call sites rendering in frost
     colours whether or not the PHP is renamed. Write new markup against
     the --fb-* names; this block is a safety net, not an API. */
  --fp-purple:        var(--fb-deep);
  --fp-purple-deep:   var(--fb-deep-2);
  --fp-violet:        var(--fb-ice-deep);
  --fp-violet-soft:   var(--fb-ice-soft);
  --fp-lavender:      var(--fb-frost);
  --fp-lavender-pale: var(--fb-glacier);
  --fp-ink:           var(--fb-steel);
  --fp-grey:          var(--fb-glacier);
  --fp-grey-2:        var(--fb-edge);
  --fp-lime:          var(--fb-signal);
  --fp-green:         var(--fb-signal-deep);
  --fp-red:           var(--fb-alert);
}

/* -------------------------------------------------------------
   Type
   Clash Display stays on headings — swapping the face would move
   every cap-height and re-flow the cards. Only the colour changes.
   ------------------------------------------------------------- */
body {
  font-family: var(--font-sans);
  font-weight: 400;
  color: var(--fb-steel);
  background: #fff;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.display, .nav-wordmark-main {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1.02;
  color: var(--fb-deep);
}

.eyebrow {
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fb-ice-deep);
}

.muted { color: var(--c-muted); }

/* -------------------------------------------------------------
   Buttons — square-ish, Clash Display, 0.5px tracking
   ------------------------------------------------------------- */
.btn {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.5px;
  border-radius: var(--r-sm);
  padding: 11px 22px;
  font-size: 1rem;
  border: 1.5px solid transparent;
  transition: transform var(--t-fast), background var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
}
.btn-lg { padding: 15px 30px; font-size: 1.12rem; }
.btn-sm { padding: 8px 15px; font-size: 0.88rem; }

.btn-primary { background: var(--fb-deep); color: #fff; border-color: var(--fb-deep); }
.btn-primary:hover { background: var(--fb-deep-2); border-color: var(--fb-deep-2); transform: translateY(-1px); }

.btn-secondary { background: #fff; color: var(--fb-deep); border-color: var(--fb-deep); }
.btn-secondary:hover { background: var(--fb-deep); color: #fff; }

/* .btn-teal is the base sheet's accent button. On ice it takes a solid
   fill with deep ink rather than white — white on #7FD4F5 is 1.6:1. */
.btn-teal { background: var(--fb-ice); color: var(--fb-deep); border-color: var(--fb-ice); }
.btn-teal:hover { background: var(--fb-deep); color: #fff; border-color: var(--fb-deep); }

.btn-ghost { background: transparent; color: var(--fb-deep); border-color: var(--c-line-strong); }
.btn-ghost:hover { border-color: var(--fb-deep); background: var(--fb-glacier); }

/* Kept as .btn-lime because the markup says so; it is the signal colour now. */
.btn-lime { background: var(--fb-signal); color: var(--fb-steel); border-color: var(--fb-signal); }
.btn-lime:hover { filter: brightness(0.95); }

/* -------------------------------------------------------------
   Announcement bar
   Four ran white text on violet. Ice is far lighter, so the bar
   inverts: deep ink on the ice fill (7:1) instead of white (1.6:1).
   ------------------------------------------------------------- */
.fp-announce {
  background: var(--fb-ice);
  color: var(--fb-deep);
  text-align: center;
  font-size: 0.94rem;
  font-weight: 600;
  padding: 11px 18px;
  letter-spacing: 0.01em;
}
.fp-announce a { color: var(--fb-deep); text-decoration: underline; text-underline-offset: 3px; }

/* -------------------------------------------------------------
   Navigation — deep bar, near-white links
   ------------------------------------------------------------- */
.nav {
  background: var(--fb-deep);
  border-bottom: none;
  position: sticky;
  top: 0;
  z-index: 200;
  backdrop-filter: none;
}
.nav-inner { min-height: 74px; gap: 22px; }

.nav-brand { display: flex; align-items: center; gap: 10px; }
.fp-logo { height: 38px; width: auto; display: block; }

.nav-links { gap: 26px; }
.nav-link {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.98rem;
  color: #EAF6FB;
  letter-spacing: 0;
}
.nav-link:hover { color: var(--fb-frost); }
.nav-link.is-active { color: var(--fb-ice); }

.nav-actions { gap: 16px; color: #EAF6FB; }
.nav-actions .nav-link { color: #EAF6FB; }
.nav-cart { color: #EAF6FB; position: relative; }
.nav-cart:hover { color: var(--fb-frost); }
.nav-cart-badge {
  background: var(--fb-signal);
  color: var(--fb-steel);
  font-weight: 800;
  font-size: 0.68rem;
  min-width: 18px;
  height: 18px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  position: absolute;
  top: -6px;
  right: -8px;
  padding: 0 5px;
}
.nav-toggle { color: #EAF6FB; }

/* -------------------------------------------------------------
   Hero
   ------------------------------------------------------------- */
.fp-hero {
  background: var(--fb-glacier);
  padding: clamp(48px, 6vw, 92px) 0 clamp(52px, 6vw, 96px);
  overflow: hidden;
}
.fp-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.18fr) minmax(0, 0.82fr);
  gap: clamp(28px, 3.4vw, 54px);
  align-items: center;
}
/* Sized so the headline's longest line holds on one line in the text
   column — the multi-line stack is the whole point of the treatment. */
.fp-hero h1 {
  font-size: clamp(2.35rem, 4.25vw, 3.9rem);
  line-height: 1.03;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}
/* Four used pale lavender for .alt on a neutral grey band. --fb-frost on
   --fb-glacier is two pale blues an eyelash apart (1.2:1) — unreadable.
   The alternating line takes the mid ice tone instead: still visibly the
   secondary line, still legible. */
.fp-hero h1 .alt { color: var(--fb-ice-deep); display: block; }
.fp-hero h1 .base { color: var(--fb-deep); display: block; }
.fp-hero-sub {
  margin-top: 22px;
  font-size: clamp(1rem, 1.15vw, 1.16rem);
  line-height: 1.62;
  color: var(--fb-slate);
  max-width: 46ch;
  font-weight: 400;
}
.fp-hero-cta { margin-top: 30px; display: flex; gap: 12px; flex-wrap: wrap; }

/* Floating mini product cards, right of the headline */
/* Hero group shot. The .fp-hero-card rules below are kept because the same
   card shape is reused elsewhere, but the homepage hero now renders one image
   instead of three cards. Generated by tools/make-hero-vials.py. */
.fp-hero-art {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
.fp-hero-art img {
  width: 100%;
  max-width: 620px;
  height: auto;
  display: block;
  /* Presented as a panel, not a cut-out. The render carries the source photos'
     own studio grey; rounding and shadowing it makes that a deliberate product
     shot instead of a stray rectangle on the hero band.
     NO mask here — a radial-gradient mask on this <img> made Chrome drop the
     image completely, laid out at the right size and painting nothing. */
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-md);
}

.fp-hero-cards { display: grid; gap: 14px; }
.fp-hero-card {
  background: #fff;
  border-radius: var(--r-md);
  padding: 16px 18px;
  display: flex;
  align-items: center;
  gap: 16px;
  box-shadow: var(--shadow-md);
  text-decoration: none;
  color: inherit;
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}
.fp-hero-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.fp-hero-card img { width: 84px; height: 84px; object-fit: contain; flex: 0 0 84px; }
.fp-hero-card-name { font-family: var(--font-display); font-weight: 600; font-size: 1.06rem; color: var(--fb-deep); }
.fp-hero-card-desc { font-size: 0.85rem; color: var(--c-muted); margin-top: 3px; line-height: 1.45; }
.fp-hero-card-price { margin-top: 6px; font-weight: 700; font-size: 0.92rem; color: var(--fb-steel); }
.fp-hero-card-price .per { color: var(--fb-ice-deep); font-weight: 700; }

@media (max-width: 940px) {
  .fp-hero-grid { grid-template-columns: 1fr; }
  .fp-hero-cards { grid-template-columns: 1fr; }
  .fp-hero-art img { max-width: 460px; }
}

/* -------------------------------------------------------------
   Deep review band
   The frost gradient is two flat stops plus one radial — no image,
   no blur filter. Ad landing pages are scored on load time here.
   ------------------------------------------------------------- */
.fp-band {
  background:
    radial-gradient(circle at 78% 12%, rgba(127, 212, 245, 0.16), transparent 58%),
    linear-gradient(168deg, var(--fb-deep) 0%, var(--fb-deep-2) 100%);
  color: #fff;
  padding: clamp(34px, 4vw, 56px) 0;
  text-align: center;
}
.fp-band h2 { color: #fff; font-size: clamp(1.7rem, 3.1vw, 2.7rem); }
.fp-band p { color: var(--fb-frost); margin-top: 10px; font-size: 1.05rem; font-weight: 500; }
.fp-band-logos {
  margin-top: 26px;
  display: flex;
  gap: clamp(20px, 4vw, 54px);
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  opacity: 0.92;
}
.fp-band-logo { font-family: var(--font-display); font-weight: 600; font-size: 1.15rem; color: #fff; letter-spacing: 0.02em; }
.fp-band-logo span { display: block; font-family: var(--font-sans); font-size: 0.72rem; font-weight: 500; color: var(--fb-frost); letter-spacing: 0.06em; margin-top: 2px; }

/* -------------------------------------------------------------
   Section scaffolding
   ------------------------------------------------------------- */
.fp-section { padding: clamp(46px, 5.5vw, 84px) 0; }
.fp-section-grey { background: var(--fb-glacier); }
.fp-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: clamp(24px, 3vw, 40px);
}
.fp-section-head h2 { font-size: clamp(1.9rem, 3.4vw, 3rem); margin: 0; }
.fp-section-head p { color: var(--c-muted); margin-top: 10px; max-width: 58ch; line-height: 1.6; }

/* -------------------------------------------------------------
   Product cards
   .fp-kit is the generic card unit, not a kit-only unit — the name is
   inherited, the component is used for singles too. Kept verbatim so
   the PHP being edited in parallel keeps matching.
   ------------------------------------------------------------- */
.fp-kit-grid,
.fb-vial-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
  gap: clamp(14px, 1.7vw, 24px);
}
.fp-kit {
  position: relative;
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: transform var(--t-fast), box-shadow var(--t-fast), border-color var(--t-fast);
}
.fp-kit:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: rgba(11, 59, 92, 0.25); }

/* --fb-mist rather than --fb-glacier: on a glacier section band the well
   would otherwise vanish and the vial would float on nothing. */
.fp-kit-media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--fb-mist);
  display: grid;
  place-items: center;
  padding: 14px;
}
.fp-kit-media img { width: 100%; height: 100%; object-fit: contain; }

/* per-vial pill — only meaningful once kits exist, kept for that switch */
.fp-per-vial {
  position: absolute;
  right: 10px;
  bottom: 10px;
  background: var(--fb-signal);
  color: var(--fb-steel);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 5px 11px;
  border-radius: var(--r-sm);
  letter-spacing: 0.2px;
  box-shadow: 0 2px 8px rgba(15, 29, 38, 0.12);
}
.fp-save-flag {
  position: absolute;
  top: 10px;
  left: 10px;
  background: var(--fb-alert);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--r-sm);
}
.fp-sold-out {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.66);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--fb-steel);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fp-kit-body { padding: 16px 17px 18px; display: flex; flex-direction: column; flex: 1; }
.fp-kit-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.08rem;
  line-height: 1.22;
  color: var(--fb-deep);
}
.fp-kit-spec {
  margin-top: 5px;
  font-size: 0.83rem;
  color: var(--c-muted);
  letter-spacing: 0.01em;
}
.fp-kit-foot { margin-top: auto; padding-top: 14px; }
.fp-kit-price { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.fp-kit-price .now { font-family: var(--font-display); font-weight: 600; font-size: 1.34rem; color: var(--fb-steel); }
.fp-kit-price .was { font-size: 0.94rem; color: var(--c-muted); text-decoration: line-through; }
.fp-kit-cta { margin-top: 12px; width: 100%; justify-content: center; display: inline-flex; }

/* -------------------------------------------------------------
   Category tiles
   ------------------------------------------------------------- */
.fp-cats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 14px;
}
.fp-cat {
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: 26px 18px;
  text-align: center;
  text-decoration: none;
  color: var(--fb-steel);
  font-weight: 600;
  transition: transform var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.fp-cat:hover { transform: translateY(-3px); border-color: var(--fb-ice); background: var(--fb-glacier); }
.fp-cat-icon {
  width: 46px; height: 46px;
  margin: 0 auto 12px;
  border-radius: var(--r-sm);
  background: var(--fb-glacier);
  color: var(--fb-deep);
  display: grid; place-items: center;
}
.fp-cat-name { font-size: 0.98rem; line-height: 1.3; }
.fp-cat-count { display: block; font-size: 0.8rem; color: var(--c-muted); font-weight: 400; margin-top: 4px; }

/* -------------------------------------------------------------
   Value props
   ------------------------------------------------------------- */
.fp-values { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: clamp(14px, 2vw, 26px); }
.fp-value { text-align: left; }
.fp-value-icon {
  width: 52px; height: 52px;
  border-radius: var(--r-md);
  background: var(--fb-deep);
  color: #fff;
  display: grid; place-items: center;
  margin-bottom: 16px;
}
.fp-value h3 { font-size: 1.28rem; margin-bottom: 8px; }
.fp-value p { color: var(--c-muted); line-height: 1.62; font-size: 0.97rem; }

/* -------------------------------------------------------------
   Comparison strip
   ------------------------------------------------------------- */
.fp-compare {
  background:
    radial-gradient(circle at 88% 8%, rgba(127, 212, 245, 0.15), transparent 55%),
    linear-gradient(160deg, var(--fb-deep) 0%, var(--fb-deep-2) 100%);
  color: #fff;
  border-radius: var(--r-lg);
  padding: clamp(26px, 3.4vw, 44px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(22px, 3vw, 48px);
  align-items: center;
}
.fp-compare h2 { color: #fff; font-size: clamp(1.6rem, 2.8vw, 2.4rem); }
.fp-compare p { color: var(--fb-frost); margin-top: 12px; line-height: 1.6; max-width: 48ch; }
.fp-compare-figs { display: flex; gap: clamp(14px, 2vw, 30px); }
.fp-compare-fig { text-align: center; }
.fp-compare-fig .n { font-family: var(--font-display); font-weight: 600; font-size: clamp(1.9rem, 3.4vw, 2.9rem); color: var(--fb-signal); line-height: 1; }
.fp-compare-fig .l { font-size: 0.8rem; color: var(--fb-frost); margin-top: 7px; letter-spacing: 0.04em; }
@media (max-width: 760px) { .fp-compare { grid-template-columns: 1fr; } }

/* -------------------------------------------------------------
   Testimonials
   ------------------------------------------------------------- */
.fp-quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 16px; }
.fp-quote {
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: 22px;
  display: flex;
  flex-direction: column;
}
.fp-quote p { line-height: 1.62; font-size: 0.95rem; color: #24333D; }
.fp-quote-foot { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--c-line); display: flex; justify-content: space-between; align-items: center; }
.fp-quote-who { font-weight: 700; color: var(--fb-deep); font-size: 0.92rem; }
.fp-quote-src { font-size: 0.78rem; color: var(--c-muted); }
.fp-stars { color: #F5A623; letter-spacing: 1px; font-size: 0.9rem; margin-bottom: 10px; }

/* -------------------------------------------------------------
   FAQ accordion
   ------------------------------------------------------------- */
.fp-faq { border-top: 1px solid var(--c-line); }
.fp-faq details { border-bottom: 1px solid var(--c-line); }
.fp-faq summary {
  cursor: pointer;
  padding: 19px 40px 19px 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--fb-deep);
  list-style: none;
  position: relative;
}
.fp-faq summary::-webkit-details-marker { display: none; }
.fp-faq summary::after {
  content: "+";
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--fb-ice-deep);
  transition: transform var(--t-fast);
}
.fp-faq details[open] summary::after { content: "\2212"; }
.fp-faq details > div { padding: 0 40px 20px 0; color: var(--c-muted); line-height: 1.66; font-size: 0.96rem; }

/* -------------------------------------------------------------
   Footer
   ------------------------------------------------------------- */
.footer { background: var(--fb-steel); color: #B9CCD6; border-top: none; }
.footer a { color: #B9CCD6; }
.footer a:hover { color: var(--fb-frost); }
.footer h4, .footer-wordmark { color: #fff; font-family: var(--font-display); font-weight: 600; }
.footer-bottom { border-top: 1px solid rgba(255, 255, 255, 0.1); color: #7C919D; }

/* -------------------------------------------------------------
   Newsletter
   The base sheet paints this band with a dark gradient and sets
   color:#fff on the section, the h2 and the paragraph. Overriding
   only the background left white text on a pale panel — so keep it
   a dark band and just move it onto the brand deep, which also
   matches .fp-band and .fp-compare elsewhere on the page.
   ------------------------------------------------------------- */
.newsletter {
  background: linear-gradient(135deg, var(--fb-deep-2) 0%, var(--fb-deep) 55%, #12557F 120%);
  color: #fff;
  padding: clamp(58px, 6.5vw, 92px) 0;
}
.newsletter::before {
  background:
    radial-gradient(circle at 15% 20%, rgba(127, 212, 245, 0.30), transparent 52%),
    radial-gradient(circle at 85% 80%, rgba(201, 233, 245, 0.16), transparent 52%);
}
.newsletter h2 { color: #fff; }
.newsletter p  { color: var(--fb-frost); }
.newsletter .eyebrow { color: var(--fb-signal); }

.newsletter-form {
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.22);
}
.newsletter-form input { color: #fff; }
.newsletter-form input::placeholder { color: rgba(255, 255, 255, 0.58); }
.newsletter-form button {
  background: var(--fb-signal);
  color: var(--fb-steel);
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.5px;
}
.newsletter-form button:hover { filter: brightness(0.95); transform: translateY(-1px); }
.newsletter-msg { color: var(--fb-signal); }

/* -------------------------------------------------------------
   Misc shared-component touch-ups
   ------------------------------------------------------------- */
.badge-teal { background: var(--fb-glacier); color: var(--fb-deep); }
.product-card { border-radius: var(--r-md); }
.product-card-title { font-family: var(--font-display); font-weight: 600; color: var(--fb-deep); }
.product-card-price { font-family: var(--font-display); font-weight: 600; color: var(--fb-steel); }

/* -------------------------------------------------------------
   Product page — per-vial block (kit-era surface, kept for the switch)
   ------------------------------------------------------------- */
.fp-pdp-pervial {
  display: inline-flex;
  align-items: baseline;
  gap: 9px;
  background: var(--fb-signal);
  color: var(--fb-steel);
  border-radius: var(--r-sm);
  padding: 9px 15px;
  margin-bottom: 18px;
}
.fp-pdp-pervial .n {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.24rem;
  letter-spacing: -0.01em;
}
.fp-pdp-pervial .l { font-size: 0.87rem; font-weight: 600; opacity: 0.78; }

/* -------------------------------------------------------------
   Reveal-on-scroll, fail-safe
   The base sheet sets .reveal { opacity: 0 } unconditionally, so if JS
   never runs — or IntersectionObserver is missing — every revealed
   block (product cards included) stays permanently invisible. Here
   .reveal is visible by default and only hidden once the inline head
   script has confirmed the observer exists.

   NOTE for anyone injecting cards after load: main.js collects .reveal
   ONCE. A card added later under html.has-reveal never gets .in and is
   invisible forever. Omit the class on injected nodes.
   ------------------------------------------------------------- */
.reveal { opacity: 1; transform: none; }
html.has-reveal .reveal { opacity: 0; transform: translateY(24px); }
html.has-reveal .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.has-reveal .reveal { opacity: 1; transform: none; transition: none; }
}

.fp-trust {
  display: flex;
  gap: clamp(14px, 2.4vw, 38px);
  justify-content: center;
  flex-wrap: wrap;
  padding: 18px 0;
  border-bottom: 1px solid var(--c-line);
}
.fp-trust-item { display: flex; align-items: center; gap: 8px; font-size: 0.88rem; font-weight: 600; color: var(--fb-deep); }
.fp-trust-item svg { color: var(--fb-ice-deep); flex: 0 0 auto; }

@media (max-width: 860px) {
  /* The sticky bottom bar already carries Account and Cart, so the text
     "Sign in" link only competes with the logo and wraps onto two lines. */
  .nav-actions > .nav-link { display: none; }
  .nav-inner { min-height: 64px; gap: 12px; }
  .fp-logo { height: 32px; }
}

/* -------------------------------------------------------------
   Mobile menu panel
   The base sheet drops this panel in at rgba(255,255,255,.98) — fine
   when nav links were dark, unreadable now they're near-white for the
   deep bar. Carry the deep colour down into the panel instead of
   darkening the text, so it reads as one continuous surface with the nav.

   Also re-anchored: the base uses `position:fixed; top:60px`, which
   assumes a 60px nav pinned to the viewport top. With the announcement
   bar above it that lands in the wrong place, so this hangs the panel
   off the bottom of .nav (sticky = a positioned ancestor) instead.
   ------------------------------------------------------------- */
@media (max-width: 880px) {
  .nav-links.open {
    position: absolute;
    top: 100%;
    background: var(--fb-deep);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: 0 18px 40px -14px rgba(6, 42, 67, 0.55);
    padding: 10px 16px 18px;
  }
  .nav-links.open .nav-link {
    color: #EAF6FB;
    border-bottom: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 0;
  }
  .nav-links.open li:last-child .nav-link { border-bottom: 0; }
  .nav-links.open .nav-link:hover,
  .nav-links.open .nav-link:active { background: rgba(255, 255, 255, 0.09); color: #fff; }
  .nav-links.open .nav-link.is-active { color: var(--fb-ice); }
}

@media (max-width: 620px) {
  .fp-hero h1 { font-size: clamp(2.4rem, 11vw, 3.2rem); }
  .fp-kit-grid,
  .fb-vial-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
  .fp-kit-body { padding: 13px 13px 15px; }
  .fp-kit-name { font-size: 0.97rem; }
  .fp-kit-price .now { font-size: 1.16rem; }
  .fp-per-vial { font-size: 0.8rem; padding: 4px 8px; }
}

/* ── Nav dropdown ─────────────────────────────────────────────────────
   The header collapses to a burger at 880px, so this needs two modes:
   a hover/focus flyout on desktop, and a plain always-open sublist
   inside the mobile drawer (hover doesn't exist on touch).           */
.nav-has-menu { position: relative; }
.nav-caret { font-size: 0.62em; margin-left: 3px; opacity: 0.7; }

.nav-menu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 208px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: #fff;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-md, 8px);
  box-shadow: 0 14px 34px rgba(11, 59, 92, 0.16);
  /* Animate from hidden rather than display:none so it can be tabbed into. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 140ms ease, transform 140ms ease, visibility 140ms;
  z-index: 60;
}
.nav-has-menu:hover > .nav-menu,
.nav-has-menu:focus-within > .nav-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.nav-menu a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 6px;
  font-size: 0.93rem;
  font-weight: 600;
  color: var(--fb-steel);
  text-decoration: none;
  white-space: nowrap;
}
.nav-menu a span {
  font-size: 0.76rem;
  font-weight: 500;
  color: var(--fb-ice-deep);
  opacity: 0.85;
}
.nav-menu a:hover,
.nav-menu a:focus-visible { background: var(--fb-glacier); }

@media (max-width: 880px) {
  /* Inside the burger drawer: no flyout, just an indented sublist. The drawer
     is --fb-deep, so the desktop palette (dark ink on white) inverts here —
     without the colour overrides below the sublist renders near-black on deep. */
  .nav-menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    margin: 2px 0 6px 14px;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }
  .nav-menu a {
    padding: 8px 0;
    color: #EAF6FB;                     /* matches .nav-links.open .nav-link */
  }
  .nav-menu a span { color: var(--fb-frost); }
  .nav-menu a:hover,
  .nav-menu a:active,
  .nav-menu a:focus-visible { background: rgba(255, 255, 255, 0.09); color: #fff; }
  .nav-caret { display: none; }
}

/* ── Homepage singles band ────────────────────────────────────────── */
.fp-singles-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 26px;
  flex-wrap: wrap;
}
.fp-singles-all { flex: none; }

.fp-singles-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.fp-single {
  display: block;
  text-decoration: none;
  color: inherit;
  background: #fff;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-lg, 14px);
  overflow: hidden;
  transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
}
.fp-single:hover {
  transform: translateY(-3px);
  border-color: rgba(18, 115, 166, 0.45);
  box-shadow: 0 16px 34px -18px rgba(11, 59, 92, 0.45);
}
.fp-single-media { background: var(--fb-mist); aspect-ratio: 1 / 1; }
.fp-single-media img { width: 100%; height: 100%; object-fit: contain; display: block; }

.fp-single-body { padding: 14px 15px 16px; }
.fp-single-name { font-weight: 700; font-size: 0.95rem; line-height: 1.3; }
.fp-single-price { margin-top: 8px; display: flex; align-items: baseline; gap: 7px; }
.fp-single-price .now { font-size: 1.22rem; font-weight: 800; letter-spacing: -0.01em; }
.fp-single-price .unit { font-size: 0.76rem; color: var(--fb-steel); opacity: 0.55; }

.fp-single-vs {
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px dashed var(--fb-edge);
  font-size: 0.78rem;
  color: var(--fb-steel);
  opacity: 0.75;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.fp-single-vs strong {
  color: var(--fb-deep);
  background: var(--fb-glacier);
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 0.74rem;
  opacity: 1;
}

@media (max-width: 900px) { .fp-singles-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) {
  .fp-singles-grid { gap: 12px; }
  .fp-single-body { padding: 12px 12px 14px; }
  .fp-single-name { font-size: 0.88rem; }
  .fp-single-price .now { font-size: 1.1rem; }
  .fp-single-vs { font-size: 0.72rem; flex-wrap: wrap; }
}

/* ── Bundle & save picker (product page) ──────────────────────────── */
.fp-bundle {
  margin-top: 20px;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-lg, 12px);
  padding: 12px;
  background: #fff;
}
.fp-bundle-head {
  text-align: center;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-muted);
  margin-bottom: 10px;
}

.fp-bundle-opt {
  position: relative;
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) auto;
  grid-template-areas: "dot main price" "dot total price";
  align-items: center;
  column-gap: 12px;
  padding: 15px 16px;
  margin-bottom: 9px;
  border: 2px solid var(--fb-edge);
  border-radius: var(--r-md, 8px);
  background: #fff;
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.fp-bundle-opt:last-of-type { margin-bottom: 0; }
.fp-bundle-opt:hover { border-color: var(--fb-ice); }
.fp-bundle-opt.is-on { border-color: var(--fb-deep); background: #F7FBFD; }

/* The real radio stays in the DOM for keyboard + form semantics; the visible
   dot is drawn separately so it can be styled consistently cross-browser. */
.fp-bundle-opt input { position: absolute; opacity: 0; pointer-events: none; }
.fp-bundle-dot {
  grid-area: dot;
  width: 19px; height: 19px;
  border-radius: 50%;
  border: 2px solid var(--c-line-strong);
  display: block;
  position: relative;
}
.fp-bundle-opt.is-on .fp-bundle-dot { border-color: var(--fb-deep); }
.fp-bundle-opt.is-on .fp-bundle-dot::after {
  content: "";
  position: absolute; inset: 3px;
  border-radius: 50%;
  background: var(--fb-deep);
}
.fp-bundle-opt input:focus-visible ~ .fp-bundle-dot {
  outline: 2px solid var(--fb-ice-deep);
  outline-offset: 2px;
}

.fp-bundle-main  { grid-area: main; min-width: 0; }
.fp-bundle-title { font-weight: 700; font-size: 1.02rem; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fp-bundle-sub   { display: block; font-size: 0.8rem; color: var(--c-muted); margin-top: 3px; }
.fp-bundle-save {
  background: var(--fb-alert);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 800;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.fp-bundle-price { grid-area: price; text-align: right; white-space: nowrap; }
.fp-bundle-price .now { font-size: 1.16rem; font-weight: 800; display: block; }
.fp-bundle-price .now em { font-style: normal; font-size: 0.74rem; font-weight: 600; color: var(--c-muted); }
.fp-bundle-price .was { font-size: 0.82rem; color: var(--c-muted); text-decoration: line-through; }
.fp-bundle-total { grid-area: total; font-size: 0.78rem; color: var(--c-muted); margin-top: 2px; }

.fp-bundle-flag {
  position: absolute;
  top: -9px; right: 12px;
  background: var(--fb-deep);
  color: #fff;
  font-size: 0.63rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
}
.fp-bundle-flag.is-best { background: var(--fb-alert); }

.fp-bundle-foot {
  text-align: center;
  font-size: 0.76rem;
  color: var(--c-muted);
  margin-top: 11px;
}

@media (max-width: 420px) {
  .fp-bundle-opt { padding: 13px 12px; column-gap: 9px; }
  .fp-bundle-title { font-size: 0.94rem; }
  .fp-bundle-price .now { font-size: 1.04rem; }
}

/* ── Free-gift ladder (under the bundle picker) ───────────────────── */
.fp-gifts { margin-top: 16px; }
.fp-gifts-head {
  text-align: center;
  font-weight: 800;
  font-size: 1.02rem;
  color: var(--fb-deep);
  margin-bottom: 11px;
}
.fp-gifts-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.fp-gift {
  position: relative;
  border: 2px solid var(--fb-deep);
  border-radius: var(--r-md, 8px);
  padding: 22px 12px 14px;
  text-align: center;
  background: #fff;
  transition: border-color 160ms ease, background 160ms ease, opacity 160ms ease;
}
.fp-gift.is-locked {
  border-color: var(--fb-edge);
  border-style: dashed;
  background: var(--fb-mist);
  opacity: 0.72;
}
.fp-gift-flag {
  position: absolute;
  top: -11px; left: 50%;
  transform: translateX(-50%);
  background: var(--fb-alert);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.fp-gift-flag s { opacity: 0.75; }
.fp-gift.is-locked .fp-gift-flag { background: #7C919D; }
.fp-gift-ico { display: block; font-size: 1.9rem; line-height: 1.2; }
.fp-gift-label {
  display: block;
  margin-top: 6px;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--fb-steel);
}
.fp-gift.is-locked .fp-gift-label { color: var(--c-muted); font-weight: 600; text-transform: none; }
.fp-gift-hint { display: block; margin-top: 3px; font-size: 0.7rem; color: var(--c-muted); }
.fp-gift:not(.is-locked) .fp-gift-hint { visibility: hidden; }

@media (max-width: 380px) {
  .fp-gift { padding: 20px 8px 12px; }
  .fp-gift-label { font-size: 0.72rem; }
}

/* ── Hero: scannable claim + bullets (replaced a dense paragraph) ─── */
.fp-hero-claim {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.12rem, 1.5vw, 1.35rem);
  color: var(--fb-deep);
  margin-bottom: 12px;
}
.fp-hero-points { list-style: none; margin: 0; padding: 0; }
.fp-hero-points li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 9px;
  font-size: clamp(0.98rem, 1.1vw, 1.08rem);
  line-height: 1.5;
  color: var(--fb-slate);
}
.fp-hero-points li:last-child { margin-bottom: 0; }
/* A check rather than a bullet — reads as a benefit, not a list item. */
.fp-hero-points li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.42em;
  width: 15px; height: 8px;
  border-left: 2.5px solid var(--fb-deep);
  border-bottom: 2.5px solid var(--fb-deep);
  transform: rotate(-45deg);
}

/* ── Best sellers: horizontal scroller instead of a wrapping grid ─── */
.fp-kit-scroller {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(230px, 1fr);
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 4px 0 14px;
  scrollbar-width: thin;
  /* Without this, swiping past the last card hands the gesture to the page:
     the whole site slides sideways and the body colour shows behind it. */
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.fp-kit-scroller > * { scroll-snap-align: start; }
.fp-kit-scroller::-webkit-scrollbar { height: 6px; }
.fp-kit-scroller::-webkit-scrollbar-thumb { background: var(--fb-edge); border-radius: 999px; }
.fp-kit-scroller::-webkit-scrollbar-track { background: transparent; }

@media (max-width: 720px) {
  /* One product centred at a time. 78vw leaves the neighbours peeking, which
     is what tells the user there's more to swipe. */
  .fp-kit-scroller {
    grid-auto-columns: 78vw;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 11vw;
  }
  .fp-kit-scroller > * { scroll-snap-align: center; }
}

@media (min-width: 981px) {
  /* Four cards fit on desktop — no scrolling needed. */
  .fp-kit-scroller { overflow-x: visible; padding: 4px 0 6px; }
}

/* ── Checkout trust bar (under Add to cart) ───────────────────────── */
.fp-trustbar { margin-top: 14px; text-align: center; }
.fp-trustbar-proof {
  font-size: 0.84rem;
  color: var(--c-muted);
  margin-bottom: 9px;
}
.fp-trustbar-proof strong { color: var(--fb-steel); font-weight: 700; }
.fp-paylogos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}
.fp-paylogo {
  display: block;
  width: 46px; height: 29px;
  border: 1px solid var(--fb-edge);
  border-radius: 5px;
  background: #fff;
  padding: 1px;
}
.fp-paylogo svg { width: 100%; height: 100%; display: block; }

/* ── Gift icons: real artwork, and a locked/unlocked swap ─────────── */
.fp-gift-ico { display: block; height: 42px; }
.fp-gift-ico svg { width: 42px; height: 42px; display: block; margin: 0 auto; }
/* Only one of the two ever shows; toggled by .is-locked on the card. */
.fp-gift .fp-ico-locked   { display: none; }
.fp-gift .fp-ico-unlocked { display: block; }
.fp-gift.is-locked .fp-ico-locked   { display: block; }
.fp-gift.is-locked .fp-ico-unlocked { display: none; }

/* Official card artwork already carries its own plate + rounding — the wrapper
   border would double it up, so only the hand-drawn marks keep the chrome. */
.fp-paylogo:has(img) { border: 0; padding: 0; background: none; }
.fp-paylogo img { width: 100%; height: 100%; display: block; object-fit: contain; }

/* ── Global guard: nothing may scroll the page sideways ──────────────
   A single over-wide element used to drag the whole site left/right on
   mobile, exposing the body colour behind the content. Horizontal panning
   is never wanted here — real horizontal scrolling lives inside its own
   overflow container (.fp-kit-scroller), which is unaffected by this. */
html, body {
  max-width: 100%;
  overflow-x: hidden;
  overscroll-behavior-x: none;
  background: #fff;
}

/* ── Carousel arrows (mobile) ─────────────────────────────────────── */
.fp-scroll-wrap { position: relative; }
.fp-scroll-btn {
  position: absolute;
  top: 38%;
  z-index: 3;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid var(--fb-edge);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.96);
  color: var(--fb-deep);
  box-shadow: 0 4px 14px rgba(11, 59, 92, 0.18);
  cursor: pointer;
  padding: 0;
}
.fp-scroll-btn svg { width: 19px; height: 19px; }
.fp-scroll-btn.is-prev { left: 2px; }
.fp-scroll-btn.is-next { right: 2px; }
.fp-scroll-btn[hidden] { display: none; }
.fp-scroll-btn:active { transform: scale(0.94); }

@media (min-width: 981px) {
  /* All four cards fit — the row can't scroll, so the arrows are meaningless. */
  .fp-scroll-btn { display: none !important; }
}

/* ── Ads landing hero image (research-home) ───────────────────────── */
.fp-rh-hero-img { display: flex; align-items: center; justify-content: center; }
.fp-rh-hero-img img {
  width: 100%;
  height: auto;
  max-width: 520px;
  display: block;
  /* The source photo is on white; the hero band is --fb-glacier, so blend
     the edges rather than showing a lighter rectangle floating on it. */
  mix-blend-mode: multiply;
}
@media (max-width: 900px) {
  .fp-rh-hero-img { margin-top: 8px; }
  .fp-rh-hero-img img { max-width: 460px; margin: 0 auto; }
}

/* =============================================================
   FROST BIO COMPONENTS
   Everything above this line is the ported Four Performance
   theme, re-coloured. Everything below is new, and exists
   because Frost Bio sells SINGLE VIALS: one vial has to be the
   obvious, low-friction first purchase, and trust — not price —
   is what closes it.
   ============================================================= */

/* ── Single-vial card ─────────────────────────────────────────────────
   The counterpart to .fp-kit, deliberately lighter: no red save flag,
   no strike-through, no "per vial" arithmetic. One dose, one price,
   one button. It slots into .fp-kit-grid / .fb-vial-grid / .fp-kit-scroller
   unchanged, so the listing pages need no new layout.

   Note for anyone injecting these after page load: main.js collects
   .reveal elements ONCE, so an injected card carrying `reveal` stays at
   opacity:0 forever. Leave the class off dynamically added cards.       */
.fb-vial {
  position: relative;
  background: #fff;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: transform var(--t-fast), box-shadow var(--t-fast), border-color var(--t-fast);
}
.fb-vial:hover,
.fb-vial:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: rgba(18, 115, 166, 0.42);
}

.fb-vial-media {
  position: relative;
  aspect-ratio: 1 / 1;
  /* A single flat radial, not an image: the vial reads as lit from above
     without costing a request. Ad landing pages are scored on load time. */
  background:
    radial-gradient(circle at 50% 24%, #FFFFFF 0%, var(--fb-mist) 62%, var(--fb-glacier) 100%);
  display: grid;
  place-items: center;
  padding: 14px;
}
.fb-vial-media img { width: 100%; height: 100%; object-fit: contain; }

/* The dose pill is the loudest thing on the card — on a single-vial store
   "5mg" IS the product choice, the way "10 vials" was on the kit store.
   Inline by default; pinned when dropped straight into the media well. */
.fb-vial-dose {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1;
  letter-spacing: 0.2px;
  color: var(--fb-deep);
  background: var(--fb-frost);
  border: 1px solid rgba(11, 59, 92, 0.12);
  border-radius: var(--r-sm);
  padding: 6px 11px;
}
.fb-vial-dose .u { font-size: 0.76rem; font-weight: 600; opacity: 0.72; }
.fb-vial-media > .fb-vial-dose {
  position: absolute;
  top: 10px;
  left: 10px;
  box-shadow: 0 2px 8px rgba(11, 59, 92, 0.14);
}

.fb-vial-body { padding: 16px 17px 18px; display: flex; flex-direction: column; flex: 1; gap: 5px; }

/* Paired selectors throughout: new markup can use .fb-vial-name, and markup
   that reuses the card partial's existing .fp-kit-* children still lands
   on the right type. Neither branch is a rename, so nothing races. */
.fb-vial-name,
.fb-vial .fp-kit-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.08rem;
  line-height: 1.22;
  color: var(--fb-deep);
}
.fb-vial-spec,
.fb-vial .fp-kit-spec {
  font-size: 0.83rem;
  color: var(--c-muted);
  letter-spacing: 0.01em;
}

.fb-vial-foot { margin-top: auto; padding-top: 14px; }
.fb-vial-price,
.fb-vial .fp-kit-price { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.fb-vial-price .now,
.fb-vial .fp-kit-price .now {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.34rem;
  color: var(--fb-steel);
}
.fb-vial-price .unit { font-size: 0.78rem; color: var(--c-muted); font-weight: 500; }

/* In-stock dot. Static — a pulsing dot on every card in a grid is a
   repaint per card per frame for no information gain. */
.fb-vial-stock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--fb-signal-deep);
}
.fb-vial-stock::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--fb-signal);
  box-shadow: 0 0 0 3px rgba(61, 224, 196, 0.22);
  flex: 0 0 auto;
}
.fb-vial-stock.is-out { color: var(--c-muted); }
.fb-vial-stock.is-out::before { background: var(--c-muted); box-shadow: none; }

/* Overlay badges on the vial card's image well.
   .fb-vial-media is `display:grid; place-items:center`, so anything in it that
   is not absolutely positioned becomes another grid ROW and squashes the photo.
   Both of these are pinned for exactly that reason.

   .fb-save-flag only renders when compare_at_price_cents genuinely exceeds
   price_cents (kit_discount_pct() returns null otherwise). The single vials
   deliberately carry no compare-at price — see sql/seed_frost_catalog.sql — so
   this rule is dormant on the current catalogue and exists for a real, run
   promotion later.

   PINNED TOP-RIGHT, NOT TOP-LEFT. `.fb-vial-media > .fb-vial-dose` already
   owns top:10px/left:10px, and every vial carries a dose — so a left-pinned
   save flag would sit exactly on top of the dose pill (and win, having
   z-index:2) on every card the moment a promotion is run. The kit card avoids
   the same clash by putting .fp-per-vial bottom-right; this is the equivalent. */
.fb-save-flag {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  background: var(--fb-alert);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.03em;
  padding: 4px 9px;
  border-radius: var(--r-sm);
  line-height: 1.15;
}

.fb-sold-out {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  background: rgba(15, 29, 38, 0.82);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-align: center;
  padding: 7px 10px;
}

/* Struck former price. Paired with the .fp-kit variant so both card
   partials render an offered-before price identically. */
.fb-vial-price .was,
.fb-vial .fp-kit-price .was {
  font-size: 0.85rem;
  color: var(--c-muted);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.fb-vial-cta { margin-top: 12px; width: 100%; justify-content: center; display: inline-flex; }

@media (max-width: 620px) {
  .fb-vial-body { padding: 13px 13px 15px; }
  .fb-vial-name,
  .fb-vial .fp-kit-name { font-size: 0.97rem; }
  .fb-vial-price .now,
  .fb-vial .fp-kit-price .now { font-size: 1.16rem; }
  .fb-vial-dose { font-size: 0.84rem; padding: 5px 9px; }
}

/* ── Trust band ───────────────────────────────────────────────────────
   The homepage's load-bearing section: on a new store with no order
   history, this is the conversion lever. Given real presence — larger
   cards, an ice hairline along the top edge, generous padding — rather
   than the small icon row the kit store used (.fp-trust, still above).

   Copy discipline lives in the PHP, not here, but it is worth stating:
   these cards must describe what testing IS done and how COAs are
   published. No purity percentage the COA data cannot back.            */
.fb-trust-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
  gap: clamp(14px, 1.8vw, 22px);
}
.fb-trust-card {
  position: relative;
  background: #fff;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-lg);
  padding: clamp(20px, 2.2vw, 28px) clamp(18px, 2vw, 24px) clamp(22px, 2.2vw, 26px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform var(--t-fast), box-shadow var(--t-fast), border-color var(--t-fast);
}
/* 3px of ice across the top edge — the one piece of decoration in the
   band, and it is a gradient rather than an image. */
.fb-trust-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, var(--fb-ice) 0%, var(--fb-signal) 100%);
}
.fb-trust-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: rgba(18, 115, 166, 0.34);
}
.fb-trust-ico {
  width: 46px; height: 46px;
  border-radius: var(--r-md);
  background: var(--fb-glacier);
  color: var(--fb-deep);
  display: grid; place-items: center;
  margin-bottom: 15px;
  flex: 0 0 auto;
}
.fb-trust-ico svg { width: 23px; height: 23px; }
.fb-trust-card h3 {
  font-size: 1.14rem;
  line-height: 1.24;
  margin: 0 0 9px;
  color: var(--fb-deep);
}
.fb-trust-card p {
  color: var(--c-muted);
  font-size: 0.95rem;
  line-height: 1.62;
  margin: 0;
}
.fb-trust-card a {
  margin-top: 12px;
  align-self: flex-start;
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--fb-ice-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.fb-trust-card a:hover { color: var(--fb-deep); }

/* Honest fine print under the grid — e.g. that COAs go up per batch as
   they land, rather than claiming every vial is already documented. */
.fb-trust-note {
  margin-top: clamp(16px, 2vw, 22px);
  font-size: 0.84rem;
  line-height: 1.6;
  color: var(--c-muted);
  max-width: 74ch;
}

/* Placed on a dark band, the cards invert. Kept in one block so the band
   can be flipped by wrapping in .fp-band without touching the markup. */
.fp-band .fb-trust-card,
.fp-compare .fb-trust-card {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.16);
  text-align: left;
}
.fp-band .fb-trust-card h3,
.fp-compare .fb-trust-card h3 { color: #fff; }
.fp-band .fb-trust-card p,
.fp-compare .fb-trust-card p { color: var(--fb-frost); }
.fp-band .fb-trust-ico,
.fp-compare .fb-trust-ico { background: rgba(127, 212, 245, 0.16); color: var(--fb-ice); }
.fp-band .fb-trust-card a,
.fp-compare .fb-trust-card a { color: var(--fb-ice); }

/* ── COA / batch reassurance strip (product page) ─────────────────────
   Compact by design: it sits near Add to cart, so it must not push the
   button down the page. One line on desktop, wraps to two on mobile.   */
.fb-coa-strip {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.6vw, 20px);
  flex-wrap: wrap;
  background: var(--fb-glacier);
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-md);
  padding: 11px 14px;
  margin-top: 14px;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--fb-slate);
}
.fb-coa-item { display: flex; align-items: center; gap: 7px; min-width: 0; }
.fb-coa-item svg { width: 17px; height: 17px; color: var(--fb-ice-deep); flex: 0 0 auto; }
.fb-coa-item strong { color: var(--fb-deep); font-weight: 700; }

/* The batch number itself — tabular so a column of them lines up, and
   visually a "record", which is the whole point of showing it. */
.fb-coa-batch {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--fb-deep);
  background: #fff;
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-sm);
  padding: 3px 8px;
}
.fb-coa-verified { color: var(--fb-signal-deep); font-weight: 700; }
.fb-coa-verified::before {
  content: "";
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--fb-signal);
  margin-right: 6px;
  vertical-align: 1px;
}
.fb-coa-strip a {
  margin-left: auto;
  font-weight: 700;
  color: var(--fb-ice-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
}
.fb-coa-strip a:hover { color: var(--fb-deep); }
/* No COA published for this batch yet — say so plainly rather than
   dressing the strip up as verification it does not have. */
.fb-coa-strip.is-pending { background: var(--fb-mist); }
.fb-coa-strip.is-pending .fb-coa-verified { color: var(--c-muted); }
.fb-coa-strip.is-pending .fb-coa-verified::before { background: var(--c-muted); }

@media (max-width: 560px) {
  .fb-coa-strip { gap: 8px 14px; font-size: 0.82rem; }
  .fb-coa-strip a { margin-left: 0; }
}

/* ── Kit tease (gated) ────────────────────────────────────────────────
   Only rendered when FROST_KITS_ENABLED is true — the PHP gate is the
   switch, this is just its skin. Styled deliberately quiet: glacier, one
   ice rule, a ghost button. No red, no countdown, no savings flag. The
   brand's job right now is to earn trust on one vial; this block exists
   so the multi-vial upsell has somewhere to land later, not to push it.
   Any figure shown inside must come from bulk_discount_pct_for_qty(),
   never a number typed into the markup.                                */
.fb-kit-tease {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(16px, 2.4vw, 34px);
  background: var(--fb-glacier);
  border: 1px solid var(--fb-edge);
  border-left: 3px solid var(--fb-ice);
  border-radius: var(--r-lg);
  padding: clamp(18px, 2.4vw, 26px) clamp(18px, 2.4vw, 30px);
  margin-top: clamp(20px, 2.6vw, 30px);
}
.fb-kit-tease h3 {
  font-size: clamp(1.06rem, 1.5vw, 1.3rem);
  line-height: 1.28;
  margin: 0;
  color: var(--fb-deep);
}
.fb-kit-tease p {
  margin: 7px 0 0;
  color: var(--c-muted);
  font-size: 0.93rem;
  line-height: 1.6;
  max-width: 56ch;
}
.fb-kit-tease .fb-kit-tease-fig {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--fb-deep);
}
.fb-kit-tease .btn { flex: none; }
@media (max-width: 700px) {
  .fb-kit-tease { grid-template-columns: 1fr; }
  .fb-kit-tease .btn { width: 100%; justify-content: center; }
}

/* ── How it works / how to store it ───────────────────────────────────
   Three steps, numbered. Used for the ordering flow on the homepage and
   for handling + storage on the product page — the same component,
   because both are "here is what happens, in order", and repeating the
   shape is itself a trust signal.                                       */
.fb-steps {
  --fb-step-gap: clamp(16px, 2.4vw, 30px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--fb-step-gap);
  counter-reset: fb-step;
}
.fb-step {
  position: relative;
  counter-increment: fb-step;
  padding-top: 4px;
}
.fb-step h3 {
  font-size: 1.08rem;
  line-height: 1.26;
  margin: 0 0 7px;
  color: var(--fb-deep);
}
.fb-step p {
  margin: 0;
  color: var(--c-muted);
  font-size: 0.94rem;
  line-height: 1.62;
}
.fb-step::before {
  content: counter(fb-step);
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  margin-bottom: 14px;
  border-radius: 50%;
  background: var(--fb-deep);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  line-height: 1;
}
/* Hairline joining one step to the next. It stops inside the following
   gutter, so it can never reach the container edge and re-open the
   sideways-scroll bug — and it is dropped entirely once the steps stack. */
.fb-step::after {
  content: "";
  position: absolute;
  top: 23px;
  left: 48px;
  right: calc(-1 * var(--fb-step-gap) + 8px);
  height: 1px;
  background: linear-gradient(90deg, var(--fb-frost), rgba(201, 233, 245, 0));
}
.fb-step:last-child::after { display: none; }

@media (max-width: 719px) {
  /* Auto-fit has collapsed to one column by here; a horizontal connector
     between vertically stacked steps would point at nothing. */
  .fb-step::after { display: none; }
  .fb-steps { gap: 20px; }
  .fb-step::before { width: 34px; height: 34px; font-size: 0.95rem; margin-bottom: 11px; }
}

/* Variant: steps inside a bordered panel, for the product page's
   handling + storage block where they need to read as one unit. */
.fb-steps.is-panel {
  background: var(--fb-mist);
  border: 1px solid var(--fb-edge);
  border-radius: var(--r-lg);
  padding: clamp(18px, 2.2vw, 26px);
}
