/* Self-hosted, dependency-free — no CDN. Colors come from CSS custom properties set inline per
   request in lib/View.php, from the client's own branding, so this one stylesheet works for every
   storefront without ever being edited per client. */
:root{--sf-brand:#a855f7;--sf-brand-dark:#7c3aed;--sf-button:#a855f7;--sf-font:#1a1a1a;--sf-footer:#111827;--sf-bg:#f7f7f8;--sf-card:#ffffff;--sf-border:#e6e6ea;--sf-muted:#6b7280;--sf-danger:#e5484d;--sf-radius:10px;--sf-btn-radius:8px}
*{box-sizing:border-box}
html{height:100%;scroll-behavior:smooth}
body{margin:0;min-height:100%;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:var(--sf-font);background:#fff;line-height:1.5}
/* Sticky footer: .sf-main grows to fill any leftover space so the footer always sits at the
   bottom of the viewport on short-content pages instead of floating right under the content. */
.sf-main{flex:1 0 auto}
.sf-footer{flex-shrink:0}
a{color:var(--sf-brand);text-decoration:none}
img{max-width:100%;display:block}
.sf-container{max-width:1500px;margin:0 auto;padding:0 1.25rem}

.sf-header{background:var(--sf-card);border-bottom:1px solid var(--sf-border);position:sticky;top:0;z-index:10}
.sf-header-static{position:static}
/* No .sf-container here on purpose — the logo/nav are meant to sit close to the true edges of the
   bar at any screen size (like a normal site nav), not inside .sf-container's 1500px cap, which on
   a wide monitor left huge symmetric gutters on both sides that a laptop viewport never showed. */
.sf-header-inner{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;gap:1rem;position:relative}
.sf-brand{font-weight:700;font-size:1.15rem;color:var(--sf-font)}
.sf-nav{display:flex;gap:1.25rem;align-items:center}
.sf-nav a{color:var(--sf-font);font-weight:500;font-size:.95rem}
.sf-nav a:hover{color:var(--sf-accent,var(--sf-brand))}
.sf-nav a.sf-btn{color:#fff}
.sf-nav a.sf-btn:hover{color:#fff}
.sf-nav-toggle{display:none;background:none;border:none;padding:.35rem;margin:-.35rem;color:var(--sf-font);cursor:pointer;border-radius:6px}
.sf-nav-toggle:hover,.sf-nav-toggle-open{background:var(--sf-bg)}

/* Collapses the inline nav into a hamburger-triggered dropdown panel below the header on narrow
   viewports — .sf-header-inner needs position:relative (set above) so .sf-nav can anchor to it
   with position:absolute instead of a hardcoded top offset that would break if the header's own
   height ever changes (e.g. a taller logo). */
@media (max-width:760px){
.sf-nav-toggle{display:flex;align-items:center;justify-content:center}
.sf-nav{position:absolute;top:100%;left:0;right:0;flex-direction:column;align-items:stretch;gap:0;background:var(--sf-card);border-bottom:1px solid var(--sf-border);box-shadow:0 10px 20px rgba(0,0,0,.08);padding:.25rem 1.25rem;opacity:0;visibility:hidden;transform:translateY(-6px);transition:opacity .15s ease,transform .15s ease}
.sf-nav.sf-nav-open{opacity:1;visibility:visible;transform:translateY(0)}
.sf-nav a{padding:.85rem 0;border-bottom:1px solid var(--sf-border)}
.sf-nav a:last-child{border-bottom:none}
.sf-nav a.sf-btn{margin:.6rem 0;text-align:center}
}

/* Hero — same 120deg dark→light brand gradient, copy and CTA as the central landing page. A client
   can swap the gradient for their own image (.sf-hero-has-image, set only when one's uploaded) —
   background-size:cover means any aspect ratio they upload renders acceptably without needing to be
   pixel-perfect; the crop tool in the branding form is just a framing convenience on top of that. */
/* display:flex + align-items:center is harmless when no inline height is set (a client who's never
   touched the height slider) — with no fixed height to center within, this just behaves like the
   old block layout, sized purely by .sf-hero-inner's own padding. Once index.php sets an explicit
   height (0-100 mapped to 0-60vh), this is what actually centers the content within that taller box
   instead of it sitting pinned to the top. */
.sf-hero{position:relative;background:linear-gradient(120deg,var(--sf-brand-dark),var(--sf-brand));color:#fff;display:flex;align-items:center}
/* The gradient is kept as a second background-image layer, not dropped — if --sf-hero-img ever
   points at a URL that fails to load (a transient network hiccup, a host blocking outbound
   requests, anything), CSS just treats that one layer as empty and the gradient underneath still
   paints, instead of the whole hero going blank with white text stranded on a white page. */
.sf-hero-has-image{background-image:var(--sf-hero-img),linear-gradient(120deg,var(--sf-brand-dark),var(--sf-brand));background-size:cover;background-position:center}
.sf-hero-overlay{position:absolute;inset:0}
/* flex:0 0 auto + an explicit width (not just max-width) gives this a definite size flexbox can rely
   on, so the two .sf-hero-spacer siblings (see index.php) only ever divide up whatever's left over —
   margin used to be auto/auto for centering, but flexbox resolves auto-margins on an item BEFORE
   handing any remaining space to growable siblings, which would swallow all of it and leave both
   spacers stuck at their 10px floor regardless of the text-position slider. At the default 50/50
   spacer split this still renders exactly centered, so nothing changes for a client who's never
   touched that slider. */
.sf-hero-inner{position:relative;z-index:1;flex:0 0 auto;width:900px;max-width:calc(100% - 20px);padding-top:5rem;padding-bottom:5rem;margin-left:0;margin-right:0}
/* Divides whatever horizontal space .sf-hero-inner doesn't itself claim, in the ratio index.php sets
   via inline flex-grow (0-100 / 100-0) — min-width is the 10px floor that keeps the text block at
   least that far from either edge no matter how far the slider's pushed. */
.sf-hero-spacer{flex-shrink:0;min-width:10px}
.sf-hero h1{margin:0 0 .75rem;font-size:2.6rem;font-weight:800;line-height:1.15;letter-spacing:-.02em}
.sf-hero p{margin:0 0 1.5rem;opacity:.92;font-size:1.15rem;max-width:640px}
/* This is the hero's own CTA specifically (its only use in this package) — sitting over a colored
   gradient or, now, a client's own photo, so its text needs to stay reliably white rather than
   var(--sf-font) (a client's general body-text color, often dark — easy to lose against a dark
   image/overlay). The .sf-btn base rule further down happens to already set color:#fff for the same
   element, but that's incidental to base .sf-btn styling, not a guarantee for this specific button —
   pin it here explicitly instead of relying on cascade order between the two. */
.sf-btn-light{background:#fff;color:#fff}
.sf-btn-light:hover{color:#fff}
/* .sf-hero-spacer hidden — the text-position slider is desktop-only by design (explicitly requested
   not to affect mobile); with both spacers gone .sf-hero-inner is this row's only flex item again and
   just takes the full width, same as it always has on mobile. */
@media (max-width:760px){.sf-hero h1{font-size:1.9rem}.sf-hero-inner{padding-top:3rem;padding-bottom:3rem;width:auto}.sf-hero-spacer{display:none}}
/* Mobile hero image only takes over once the nav's own breakpoint kicks in — matches the header's
   existing 760px collapse point, not a separate one, so there's no in-between width using neither. */
@media (max-width:760px){.sf-hero-has-image{background-image:var(--sf-hero-img-mobile),linear-gradient(120deg,var(--sf-brand-dark),var(--sf-brand))}}

/* Feature trio — mirrors the landing page's "Clinician guided / Convenient care / Clear pricing" band. */
.sf-promo-banner{text-align:center;padding:.7rem 1rem;position:sticky;top:var(--sf-header-height,64px);z-index:9}
/* A builder-placed Promo Banner isn't necessarily right under the header (unlike the storefront's
   own hardcoded one, always the first thing on the homepage) — sticking it to --sf-header-height
   from wherever it happens to sit further down a page would look wrong, so this instance is static. */
.sf-b-promo-banner{position:static}
/* Marquee builder block — a repeated item list slides from 0 to one-set-width so the loop point is
   invisible (every repeated set is identical); overflow:hidden on the outer element (from its own
   Border/Size fields via styleFromGroups, or the browser default of visible clipped by
   width+no-wrap here) keeps only one row visible at a time. The baked HTML always ships exactly 2
   copies of the item set (see components.jsx's Marquee.render) — app.js clones extra copies at
   runtime and sets --sf-marquee-dist whenever 2 copies aren't wide enough to fill the container
   (a short item list on a wide section), which is also why the fallback below assumes 2 sets.
   Disabled entirely under prefers-reduced-motion. */
.sf-b-marquee{overflow:hidden;width:100%}
.sf-b-marquee-track{display:inline-flex;align-items:center;gap:2.5rem;white-space:nowrap;animation:sf-marquee-scroll linear infinite;padding-right:2.5rem}
.sf-b-marquee-item{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap}
.sf-b-marquee-icon{font-size:1.15em;line-height:1}
@keyframes sf-marquee-scroll{from{transform:translateX(0)}to{transform:translateX(calc(-1 * var(--sf-marquee-dist, 50%)))}}
@media (prefers-reduced-motion:reduce){.sf-b-marquee-track{animation:none}}
.sf-features{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;text-align:center;padding-top:1rem;padding-bottom:1rem}
.sf-features h2{margin:0 0 .35rem;font-size:1.1rem;font-weight:700}
.sf-features p{margin:0;color:var(--sf-muted)}
@media (max-width:760px){.sf-features{grid-template-columns:1fr}}

.sf-products{background:var(--sf-bg);padding:3rem 0}
/* Sticks the same way the category sidebar below already does (same --sf-sticky-offset, right under
   the header/promo banner) — the 20px top margin is desktop-only per spec, so mobile keeps its
   original flush spacing instead of extra gap above an already-cramped small screen. */
.sf-product-search{position:sticky;top:var(--sf-sticky-offset,84px);z-index:5;background:var(--sf-bg);padding:.75rem 0}
@media (min-width:761px){.sf-product-search{margin-top:20px}}
.sf-product-search-inner{position:relative;max-width:420px;margin:0 auto}
/* Shifts the search box right by half the category sidebar's own width (130px = 260px / 2) so it
   stays centered over the product grid instead of the full page — without this, centering against
   the whole .sf-container (which the sidebar eats into) looks visibly off relative to the grid
   below it. Only applies once the sidebar is actually showing beside the grid (desktop widths;
   below 761px it stacks above instead, where full-page centering is correct again — see the
   max-width:760px override further down). */
@media (min-width:761px){.sf-product-search--with-sidebar .sf-product-search-inner{margin-left:calc((100% - 420px) / 2 + 130px);margin-right:auto}}
.sf-product-search-inner svg{position:absolute;left:.9rem;top:50%;transform:translateY(-50%);color:var(--sf-muted);pointer-events:none}
.sf-product-search-inner input{width:100%;padding:.65rem 1rem .65rem 2.6rem;border:1px solid var(--sf-border);border-radius:999px;background:var(--sf-card);color:var(--sf-font);font:inherit;font-size:.95rem}
.sf-product-search-inner input:focus{outline:none;border-color:var(--sf-brand)}
.sf-products-intro{text-align:center;margin-bottom:2rem;scroll-margin-top:var(--sf-sticky-offset,84px)}
.sf-products-intro:not(:first-child){margin-top:3rem}
.sf-products-intro h2{margin:0 0 .35rem;font-size:1.9rem;font-weight:700}
.sf-products-intro p{margin:0;color:var(--sf-muted)}

/* Category sidebar — sits directly beside the product grid (deliberately outside .sf-container,
   which would otherwise leave empty space between the sidebar and the grid on wide screens),
   sticking just below the storefront's own sticky header (and promo banner, when one's enabled —
   see --sf-sticky-offset in View.php) once scrolled past its normal position, so it stays reachable
   no matter how far down a long product list the customer has scrolled. max-width+margin:auto here
   caps and centers the whole sidebar+grid row itself (260px sidebar + .sf-shop-categories' own
   1300px cap below) — without it, on a monitor much wider than that the row still anchored to the
   true left edge, dumping all the leftover space as dead air on the right instead of splitting it
   evenly like every other section of the page. */
.sf-shop-layout{display:flex;align-items:flex-start;max-width:1560px;margin:0 auto}
/* --sf-cat-sticky-offset (set in View.php, alongside --sf-sticky-offset) is --sf-sticky-offset PLUS
   the search bar's own rendered height — the search bar above is sticky at the plain offset, so the
   sidebar needs the extra room or the two would both land on the same fixed position once scrolled
   and the sidebar (later in the DOM, so painted on top) would cover the search bar entirely. */
.sf-cat-sidebar{flex:0 0 260px;position:sticky;top:var(--sf-cat-sticky-offset,var(--sf-sticky-offset,84px));max-height:calc(100vh - var(--sf-cat-sticky-offset,var(--sf-sticky-offset,84px)) - 20px);overflow-y:auto;padding:0 1rem 2rem 1.5rem}
.sf-cat-sidebar-heading{margin:0 0 .75rem;padding:0 .75rem;font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--sf-muted)}
.sf-cat-sidebar nav{display:flex;flex-direction:column;gap:.15rem}
.sf-cat-sidebar a{display:flex;align-items:center;justify-content:space-between;gap:.5rem;padding:.55rem .75rem;border-radius:8px;color:var(--sf-font);font-weight:600;font-size:.92rem}
.sf-cat-sidebar a:hover{background:var(--sf-card);color:var(--sf-brand)}
.sf-cat-count{color:var(--sf-muted);font-weight:600;font-size:.8rem;background:var(--sf-card);border-radius:999px;padding:.1rem .55rem}
.sf-shop-categories{flex:1;min-width:0;max-width:1300px;padding:0 1.25rem}
@media (min-width:900px){.sf-shop-categories .sf-grid{grid-template-columns:repeat(3,1fr)}}
/* A dropdown reads far better than a wrapped row of pill buttons once the sidebar drops below the
   product grid on narrow screens — a custom button+list (not a native <select>) so it stays fully
   styleable; an open native picker is positioned entirely by the OS/browser with no CSS control at
   all over where it lands. */
.sf-cat-toggle{display:none}
/* display:block (not flex-direction:column) deliberately — .sf-shop-layout's own align-items:
   flex-start above governs the vertical axis in the default row layout, but the same property
   would instead govern the HORIZONTAL axis once switched to a column flex direction, shrinking
   each child to its own content width instead of stretching full-width — which is exactly what
   was leaving the product grid narrower than the viewport with dead space beside it. Falling back
   to plain block stacking sidesteps that flex cross-axis behavior altogether. */
@media (max-width:760px){
.sf-product-search{position:static;margin-top:0}
.sf-product-search-inner{max-width:none}
.sf-shop-layout{display:block}
.sf-cat-sidebar{position:static;max-height:none;width:100%;padding:0 1.25rem;margin-bottom:1rem}
.sf-cat-toggle{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:.65rem .9rem;border:1px solid var(--sf-border);border-radius:8px;background:var(--sf-card);color:var(--sf-font);font:inherit;font-size:.95rem;cursor:pointer}
.sf-cat-chev{flex-shrink:0;transition:transform .15s ease}
.sf-cat-sidebar.sf-cat-open .sf-cat-chev{transform:rotate(180deg)}
.sf-cat-sidebar nav{display:none;flex-direction:column;gap:0;margin-top:.4rem;background:var(--sf-card);border:1px solid var(--sf-border);border-radius:8px;padding:.3rem}
.sf-cat-sidebar.sf-cat-open nav{display:flex}
.sf-shop-categories{padding:0 1.25rem}
}

/* auto-fit (not auto-fill) is what matters here — auto-fill reserves a track for every column that
   could theoretically fit the container width, even an empty one with nothing in it, which left a
   lone product card stranded on the left with dead space beside it instead of stretching to fill
   the row. auto-fit collapses those empty tracks so real items expand into the space instead. */
.sf-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem;margin-bottom:1rem}
/* Website builder: same .sf-card markup as .sf-grid above, just a horizontally-scrolling row
   instead of a wrapping grid — each card gets a fixed width so it doesn't stretch full-width. */
.sf-products-carousel{display:flex;gap:1.5rem;overflow-x:auto;padding-bottom:.5rem;margin-bottom:1rem;scroll-snap-type:x proximity}
.sf-products-carousel .sf-card{flex:0 0 260px;scroll-snap-align:start}
.sf-category-grid{display:grid;grid-template-columns:var(--sf-grid-columns,repeat(auto-fit,minmax(200px,1fr)));gap:1rem;margin-bottom:1rem}
.sf-b-search{margin-bottom:1.5rem}
.sf-b-search .sf-product-search-inner{margin-bottom:1.5rem}
/* All Products builder block — .sf-product-search's own background:var(--sf-bg) (a light grey,
   #f7f7f8) is right for the classic storefront homepage it was originally built for (whose page
   background IS that color), but this block can land inside any section — including one with its
   own dark/colored background (Section's own Background field) — where that hardcoded grey shows
   up as an obvious mismatched box instead of blending in. Also drops the sticky positioning: it's
   fine anchored to the classic homepage's own top offset, but has no correct offset to anchor to
   inside an arbitrary builder page. */
.sf-b-all-products .sf-product-search{background:transparent;position:static;margin-top:0;padding:0 0 1.25rem}
/* Website builder Animations group (Entrance/Exit/Duration/Delay/Hover — see builder-src/src/
   components.jsx's animationFields()) — see assets/app.js's own IntersectionObserver, which adds/
   removes .sf-anim-in/.sf-anim-out and sets each element's own transition-duration/-delay from its
   data-sf-duration/-delay attributes. transition-property is fixed here (opacity+transform); only
   the per-element TIMING is configurable, not which properties animate. */
[data-sf-enter],[data-sf-exit]{opacity:0;transition-property:opacity,transform;transition-timing-function:ease}
.sf-enter-fade-up{transform:translateY(30px)}
.sf-enter-fade-down{transform:translateY(-30px)}
.sf-enter-slide-left{transform:translateX(-50px)}
.sf-enter-slide-right{transform:translateX(50px)}
.sf-enter-zoom-in{transform:scale(.85)}
.sf-enter-bounce-in{transform:scale(.3)}
/* transform:none!important resets an entrance's own starting transform (scale/translate) once it's
   done — but !important always wins over a running CSS animation for that same property, no matter
   how specific the animation's own selector is, so this was silently freezing a loop animation
   (also driven by transform) solid on any element that had BOTH an entrance and a loop set. The
   opacity reset still applies to every element either way; the transform reset is skipped for one
   that's also looping, since its own keyframes need to keep driving transform instead. */
.sf-anim-in{opacity:1!important}
.sf-anim-in:not(.sf-loop-float):not(.sf-loop-grow):not(.sf-loop-pulse){transform:none!important}
.sf-anim-out{opacity:0!important}
.sf-exit-zoom-out.sf-anim-out{transform:scale(.85)!important}
.sf-exit-slide-out-left.sf-anim-out{transform:translateX(-50px)!important}
.sf-exit-slide-out-right.sf-anim-out{transform:translateX(50px)!important}
/* Hover effects — a plain CSS class, not tied to entrance/exit at all, so they work even on an
   element with no scroll animation set. */
.sf-hover-grow:hover{transform:scale(1.05);transition:transform .2s ease}
.sf-hover-shrink:hover{transform:scale(.95);transition:transform .2s ease}
.sf-hover-float:hover{transform:translateY(-6px);transition:transform .2s ease}
.sf-hover-pulse:hover{animation:sfHoverPulse .6s ease infinite}
@keyframes sfHoverPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
/* Loop animations — unlike entrance/exit (scroll-triggered, needs the IntersectionObserver in
   app.js) and hover (only while the pointer is over it), these run continuously from the moment the
   element is on the page, so they're plain always-on CSS classes with no JS involved at all. */
.sf-loop-float{animation:sfLoopFloat 3s ease-in-out infinite}
.sf-loop-grow{animation:sfLoopGrow 2s ease-in-out infinite}
.sf-loop-pulse{animation:sfLoopPulse 1.4s ease-in-out infinite}
@keyframes sfLoopFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-12px)}}
@keyframes sfLoopGrow{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}
@keyframes sfLoopPulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.04);opacity:.85}}
@media (prefers-reduced-motion:reduce){[data-sf-enter],[data-sf-exit]{opacity:1;transform:none;transition:none}.sf-hover-grow:hover,.sf-hover-shrink:hover,.sf-hover-float:hover{transform:none}.sf-hover-pulse:hover{animation:none}.sf-loop-float,.sf-loop-grow,.sf-loop-pulse{animation:none}}
.sf-category-tile{display:block;padding:1.25rem;background:var(--sf-card);border-radius:var(--sf-radius);box-shadow:0 2px 12px rgba(0,0,0,.06);text-decoration:none;color:var(--sf-font);transition:box-shadow .15s,transform .15s}
.sf-category-tile:hover{box-shadow:0 8px 24px rgba(0,0,0,.1);transform:translateY(-2px)}
.sf-category-tile-name{font-weight:700}
.sf-category-tile-count{color:var(--sf-muted);font-size:.85rem;margin-top:.25rem}
.sf-card{background:var(--sf-card);color:var(--sf-font);border:none;border-radius:var(--sf-radius);overflow:hidden;position:relative;box-shadow:0 2px 12px rgba(0,0,0,.06);transition:box-shadow .15s,transform .15s;display:flex;flex-direction:column}
.sf-card:hover{box-shadow:0 8px 24px rgba(0,0,0,.1);transform:translateY(-2px)}
/* Deliberately NOT .sf-card's own background/color (var(--sf-card) is a fixed #ffffff with no
   dark-theme variant anywhere in this stylesheet, and var(--sf-font) a fixed dark grey) — a category
   card sits directly on whatever background/text-color the page around it already has (a plain
   Section/Container with its own background, light or dark), the same way Heading/Text/every other
   element here does by default. Forcing a hardcoded white box behind it is exactly the "why does it
   have a white background I never added" bug this card style went through several rounds chasing
   symptoms of (letterboxed images, an empty text block still taking up space, a radius fight with
   .sf-card's own) before landing on the actual root cause: the background itself was never wanted at
   all, only the hover-lift motion was. transparent/inherit here means a client who DOES want a
   visible card background can still get one from the Category Grid's own Background field group
   (styleFromGroups(props), applied to the outer grid — or, once cards can be styled individually,
   from there) without this element forcing one whether they asked for it or not. Also drops the base
   (non-hover) box-shadow, which read as its own faint "boxed" edge around an otherwise-transparent
   card — the hover-only shadow is kept, since that's the actual "lift" effect being reused here. */
.sf-b-catgrid-card{background:transparent;color:inherit;border:none;transition:box-shadow .15s,transform .15s;display:flex;flex-direction:column;text-decoration:none}
.sf-b-catgrid-card:hover{box-shadow:0 8px 24px rgba(0,0,0,.1);transform:translateY(-2px)}
/* Bottle shots are contained (not cropped) on white, exactly like the landing page's cards. */
.sf-card img,.sf-card-noimg{width:100%;height:220px;object-fit:contain;padding:1rem;background:#fff;display:block;box-sizing:border-box}
.sf-card-img-btn{display:block;width:100%;padding:0;margin:0;border:none;background:none;cursor:pointer;text-align:inherit;font:inherit;color:inherit}
.sf-card-body{padding:0 1.25rem 1.25rem;display:flex;flex-direction:column;flex:1}
.sf-card-body h3{margin:0 0 .35rem;font-size:1.25rem;font-weight:700;text-align:center}
.sf-card-desc{color:var(--sf-muted);font-size:.92rem;margin:0 0 .5rem}
.sf-price-block{margin:auto 0 1rem;text-align:center}
.sf-price-block small{display:block;text-transform:uppercase;color:var(--sf-muted);font-size:.72rem;letter-spacing:.04em}
.sf-price-block strong{font-size:1.65rem;font-weight:700}
.sf-price-suffix{color:var(--sf-muted)}
.sf-price-original{display:inline-block;color:var(--sf-muted);text-decoration:line-through;font-size:.85em;font-weight:500;margin-right:.4em}
.sf-card .sf-btn,.sf-card form{margin-top:0}
.sf-price-label{display:block;text-transform:uppercase;font-size:.7rem;letter-spacing:.03em;font-weight:600;color:var(--sf-muted);margin-bottom:.15rem}
.sf-badge{position:absolute;top:.65rem;left:.65rem;background:var(--sf-danger);color:#fff;font-weight:700;font-size:.7rem;padding:.28rem .6rem;border-radius:999px;z-index:2;letter-spacing:.02em}
.sf-empty{color:var(--sf-muted);padding:3rem 0;text-align:center}
.w-100{width:100%}

.sf-back{display:block;max-width:1500px;margin:1.25rem auto 0;padding:0 1.25rem;color:var(--sf-muted);font-size:.9rem}
.sf-back:hover{color:var(--sf-brand)}

.sf-product{display:grid;grid-template-columns:1fr 1fr;gap:2.5rem;padding:1.5rem 1.25rem 2.5rem}
.sf-product-media{position:relative;background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);overflow:hidden}
.sf-product-media img,.sf-product-noimg{width:100%;border-radius:0;height:360px;object-fit:cover;background:var(--sf-card)}
.sf-product-info h1{margin-top:0;font-size:1.6rem}
.sf-product-info p{color:var(--sf-muted)}
.sf-price{font-size:1.3rem;font-weight:700;margin:1rem 0}

.sf-modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:100;padding:1rem}
.sf-modal-backdrop[hidden]{display:none}
/* Header/footer stay put, only .sf-modal-body scrolls — the dose-picker step (many option tiles)
   used to grow the whole modal, pushing "Continue to checkout" out of view until you scrolled all
   the way down. display:flex + overflow:hidden here, flex:1/overflow-y:auto on the body below, is
   what keeps the CTA reachable without scrolling regardless of how many options there are. */
.sf-modal{background:#fff;color:var(--sf-font);border-radius:var(--sf-radius);max-width:500px;width:100%;max-height:85vh;padding:1.5rem;display:flex;flex-direction:column;overflow:hidden}
@media (min-width:992px){.sf-modal{max-width:800px}}
.sf-modal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.1rem;flex-shrink:0}
.sf-modal-header h2{margin:0;font-size:1.15rem}
.sf-modal-close{background:none;border:none;font-size:1.6rem;line-height:1;cursor:pointer;color:var(--sf-muted);padding:0}
.sf-modal-close:hover{color:var(--sf-font)}
.sf-modal-body{overflow-y:auto;min-height:0;flex:1 1 auto}
.sf-modal-footer{margin-top:1.25rem;flex-shrink:0}

.pkg-header{display:flex;align-items:flex-start;gap:1.75rem;padding-bottom:1.25rem;margin-bottom:1.25rem;border-bottom:1px solid var(--sf-border)}
.pkg-header-img{width:150px;height:150px;object-fit:contain;border-radius:10px;background:var(--sf-bg);flex:none}
.pkg-header-placeholder{width:150px;height:150px;border-radius:10px;background:var(--sf-bg);display:flex;align-items:center;justify-content:center;color:var(--sf-muted);flex:none}
.pkg-header-placeholder[hidden]{display:none}
.pkg-header-body{display:flex;flex-direction:column;gap:.65rem;padding-top:.35rem;min-width:0;flex:1}
.pkg-header-name{font-weight:800;font-size:1.5rem;letter-spacing:-.01em}
.pkg-header-desc{color:var(--sf-muted);font-size:.95rem;line-height:1.6;margin:0}
.pkg-header-desc[hidden]{display:none}
/* .sf-form label{display:block} (below) would otherwise outrank the [hidden] attribute's own default
   display:none, same gotcha as pkg-header-desc/pkg-header-placeholder above. */
#sf-pkg-mode-row[hidden]{display:none}
/* The modal itself is only ~500px wide with padding on phones — the image plus the gap next to it
   would crowd out the name/description, so this stacks the image above the text and shrinks it
   slightly instead. */
@media (max-width:600px){.pkg-header{flex-direction:column;align-items:center;text-align:center}.pkg-header-img,.pkg-header-placeholder{width:130px;height:130px}.pkg-header-body{align-items:center}.pkg-header-desc{text-align:left}}

.pkg-badges{display:flex;gap:.5rem;margin-bottom:1.25rem;padding-bottom:1.25rem;border-bottom:1px solid var(--sf-border)}
.pkg-badge{flex:1;min-width:0;display:flex;align-items:center;gap:.6rem;padding:0 .6rem}
.pkg-badge:not(:last-child){border-right:1px solid var(--sf-border)}
.pkg-badge-icon{flex:none;width:44px;height:44px;border-radius:50%;background:color-mix(in srgb, var(--sf-brand) 15%, #ffffff);color:var(--sf-brand);display:flex;align-items:center;justify-content:center;font-size:1.1rem}
.pkg-badge-icon svg,.pkg-badge-icon i{color:var(--sf-brand)}
.pkg-badge-text{font-weight:700;color:#000;font-size:.82rem;line-height:1.25}
@media (max-width:600px){.pkg-badges{flex-direction:column;gap:.75rem}.pkg-badge{padding:0}.pkg-badge:not(:last-child){border-right:none;border-bottom:1px solid var(--sf-border);padding-bottom:.75rem}}

/* Landing page "What's Included" section — a pale tint of the client's own primary colour (not
   the hero's solid gradient), holding a white card of icon/title/subtext items divided by thin
   vertical rules, circular colored icon badges rather than the popup's bordered squares. */
.sf-included{background:color-mix(in srgb, var(--sf-brand) 8%, #ffffff);border-radius:20px;padding:2.5rem 2rem;margin:1rem 0 3rem}
.sf-included-title{display:flex;align-items:center;justify-content:center;gap:1.25rem;margin:0 0 1.75rem;font-size:1.4rem;font-weight:800;color:var(--sf-font)}
.sf-included-title::before,.sf-included-title::after{content:'';flex:1;max-width:110px;height:1px;background:color-mix(in srgb, var(--sf-brand) 35%, transparent)}
.sf-included-items{background:#fff;border-radius:16px;display:flex;padding:1.75rem 1.25rem;box-shadow:0 2px 16px rgba(0,0,0,.05)}
.sf-included-item{flex:1;display:flex;align-items:center;gap:1rem;padding:0 1.25rem}
.sf-included-item:not(:last-child){border-right:1px solid var(--sf-border)}
.sf-included-icon{flex:none;width:56px;height:56px;border-radius:50%;background:var(--sf-brand);color:#fff;display:flex;align-items:center;justify-content:center;font-size:1.4rem}
.sf-included-item-title{font-weight:800;color:var(--sf-font);font-size:1rem;margin-bottom:.15rem}
.sf-included-item-sub{margin:0;color:var(--sf-muted);font-size:.85rem;line-height:1.4}
@media (max-width:760px){.sf-included{padding:1.75rem 1rem}.sf-included-items{flex-direction:column;gap:1.25rem;padding:1.5rem 1.25rem}.sf-included-item{padding:0 0 1.25rem;border-right:none!important;border-bottom:1px solid var(--sf-border)}.sf-included-item:last-child{padding-bottom:0;border-bottom:none}.sf-included-title{gap:.65rem}.sf-included-title::before,.sf-included-title::after{max-width:40px}}

.sf-pkg-error{color:var(--sf-danger);font-size:.85rem;margin:.4rem 0}

.dose-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}
@media (max-width:576px){.dose-grid{grid-template-columns:repeat(2,1fr)}}
.dose-tile{border:2px solid var(--sf-border);border-radius:14px;padding:.9rem .5rem;text-align:center;cursor:pointer;background:#fff;transition:border-color .15s ease,background .15s ease,color .15s ease}
.dose-tile:hover{border-color:var(--sf-brand)}
.dose-tile.selected{background:var(--sf-brand);border-color:var(--sf-brand);color:#fff}
.dose-tile.selected .dose-tile-sub{color:rgba(255,255,255,.85)}
.dose-tile.selected .dose-tile-price-original{color:rgba(255,255,255,.75)}
.dose-tile-icon{margin-bottom:.35rem}
.dose-tile-title{font-weight:700;font-size:.92rem;line-height:1.25}
.dose-tile-sub{font-size:.76rem;color:var(--sf-muted);margin-top:.1rem}
.dose-tile-price{font-weight:700;margin-top:.35rem;font-size:.88rem}
.dose-tile-price-original{display:inline-block;color:var(--sf-muted);text-decoration:line-through;font-weight:500;font-size:.85em;margin-right:.35em}

.sf-btn{display:inline-block;background:var(--sf-button);color:#fff;border:none;border-radius:var(--sf-btn-radius);padding:.6rem 1.1rem;font-weight:600;cursor:pointer;font-size:.95rem;white-space:nowrap}
.sf-btn[hidden]{display:none}
.sf-btn:hover{filter:brightness(.92)}
.sf-btn-lg{padding:.85rem 1.4rem;font-size:1rem}
.sf-btn-outline{background:transparent;border:1px solid var(--sf-border);color:var(--sf-font)}
.sf-btn-link{background:none;border:none;color:var(--sf-brand);font-size:.85rem;cursor:pointer;padding:0}

.sf-cookie-banner{position:fixed;left:0;right:0;bottom:0;z-index:200;background:var(--sf-footer);color:#fff;padding:1rem;display:flex;gap:1rem;flex-wrap:wrap;align-items:center;justify-content:space-between;box-shadow:0 -4px 16px rgba(0,0,0,.15)}
.sf-cookie-banner[hidden]{display:none}
.sf-cookie-banner p{margin:0;font-size:.9rem;color:#fff}
.sf-cookie-banner-actions{display:flex;gap:.6rem;flex-shrink:0}
.sf-cookie-banner .sf-btn-outline{border-color:rgba(255,255,255,.4);color:#fff}

.sf-muted{color:var(--sf-muted)}

.sf-form label{display:block;font-weight:600;font-size:.88rem;margin-bottom:1rem}
.sf-required{color:var(--sf-danger);font-weight:700}
.sf-form input,.sf-form select,.sf-form textarea{display:block;width:100%;margin-top:.35rem;padding:.6rem;border:1px solid var(--sf-border);border-radius:8px;font-size:.95rem;font-family:inherit}
.sf-form textarea{resize:vertical}
/* ---- searchable state dropdown — a custom-styled, scrollable panel instead of a native <datalist>
   (whose suggestion UI is unstyled and wildly inconsistent between browsers). Wraps the same
   input[name=state]/[name=billing_state] fields already in use, so nothing else has to change. ---- */
.sf-select{margin-top:.35rem}
.sf-select input{margin-top:0}
/* position:fixed, not absolute — top/left/width are set inline by app.js from the input's own
   getBoundingClientRect() each time it opens. A merely-absolute panel still counts toward any
   scrolling ancestor's overflow (the "Choose your option" modal's own overflow-y:auto in
   particular), so it could force the modal to grow/scroll just to fit the list even while visually
   floating on top of everything. Fixed positioning removes it from that calculation — it's anchored
   to the viewport, never to a container's scrollable content area. */
.sf-select-panel{position:fixed;z-index:9999;background:var(--sf-card);border:1px solid var(--sf-border);border-radius:8px;box-shadow:0 10px 28px rgba(0,0,0,.14);max-height:230px;overflow-y:auto;padding:.3rem}
.sf-select-option{padding:.5rem .65rem;border-radius:6px;cursor:pointer;font-size:.9rem;font-weight:500}
.sf-select-option:hover,.sf-select-option.is-active{background:var(--sf-bg);color:var(--sf-brand-dark)}
.sf-select-option[hidden]{display:none}
.sf-select-empty{padding:.5rem .65rem;font-size:.88rem;color:var(--sf-muted)}
.sf-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:0 1.25rem}
.sf-form-row{display:grid;grid-template-columns:1fr 1fr;gap:0 1.25rem}
.sf-form-row-3{grid-template-columns:1fr 1fr 1fr}
.sf-form label.sf-check{display:flex;align-items:center;gap:.5rem;font-weight:500}
.sf-check input{width:auto;margin:0}
.sf-inline{display:flex;gap:.75rem;align-items:flex-end;flex-wrap:wrap}
.sf-inline label{margin-bottom:0}

.sf-error{background:#fdecea;color:#b3261e;padding:.85rem 1rem;border-radius:8px;margin-bottom:1.25rem}
.sf-order-summary{display:flex;align-items:center;background:#e7f6ec;color:#1e7e34;border-radius:var(--sf-radius);padding:1rem;margin-bottom:1.25rem;gap:1rem}
.sf-order-summary img{width:56px;height:56px;object-fit:contain;background:#fff;border-radius:8px;padding:.35rem;flex:none}
.sf-order-summary-info{display:flex;flex-direction:column;gap:.15rem;flex:1;min-width:0}
/* Truncates with an ellipsis instead of wrapping — the row's own image + "Change" button already
   leave this column narrow (worse on mobile), and a long product name or dose+price pairing was
   wrapping onto a second line each, instead of staying on their own single line. */
.sf-order-summary-info strong{font-size:.95rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sf-order-summary-info span{font-size:.88rem;opacity:.9;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sf-order-summary .sf-btn-outline{color:#1e7e34;border-color:#1e7e34;flex:none}
.sf-order-total{border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:.9rem 1rem;margin-bottom:1.25rem}
.sf-order-total-row{display:flex;justify-content:space-between;padding:.3rem 0;font-size:.92rem;color:var(--sf-muted)}
.sf-order-total-row.sf-order-total-final{border-top:1px solid var(--sf-border);margin-top:.25rem;padding-top:.65rem;font-weight:700;font-size:1.05rem;color:var(--sf-font)}
.sf-order-total-row.sf-order-total-recurring{margin-top:.25rem;font-size:.85rem}
.sf-order-total-note{font-size:.8rem;color:var(--sf-muted);text-align:right;margin-top:-.1rem}
.sf-success{background:#e7f6ec;color:#1e7e34;padding:.85rem 1rem;border-radius:8px}
.sf-coupon-result{margin:-.5rem 0 1rem;font-size:.85rem}
.sf-coupon-ok{color:#1e7e34}
.sf-coupon-bad{color:var(--sf-danger)}
.sf-checkout-note{color:var(--sf-muted);font-size:.82rem;text-align:center;margin:1rem 0 0}
.sf-payment-element{margin:0 0 1.25rem;min-height:220px}
#sf-payment-step .sf-btn-link{display:block;text-align:center;margin-top:.85rem}

.sf-checkout{padding:2.5rem 1.25rem;max-width:760px}
.sf-checkout-card{background:#fff;border:1px solid var(--sf-border);border-radius:var(--sf-radius);box-shadow:0 2px 12px rgba(0,0,0,.05);padding:2rem;margin-top:1rem}
.sf-checkout-card h1{margin-top:0;font-size:1.5rem}
/* .sf-checkout's own side padding plus .sf-checkout-card's padding stacked on top of it (20px + 32px
   per side) left very little room for the actual input fields on a phone-width screen. Cut both back
   on mobile instead of just one, so the card still has *some* breathing room from the screen edge
   without doubling up. */
@media (max-width:760px){.sf-checkout{padding:1.5rem .5rem}.sf-checkout-card{padding:1.25rem}}
.sf-cart,.sf-confirm,.sf-account{padding:2.5rem 1.25rem;max-width:720px}

/* ---- Post-checkout consultation wait/reveal (success.php) ---- */
.sf-consult{text-align:center;max-width:480px;margin:0 auto}
.sf-consult-stage{opacity:0;transform:translateY(6px)}
.sf-consult-stage:not([hidden]){animation:sfConsultIn .45s ease forwards}
.sf-consult-fade-out{animation:sfConsultOut .2s ease forwards!important}
@keyframes sfConsultIn{to{opacity:1;transform:translateY(0)}}
@keyframes sfConsultOut{to{opacity:0;transform:translateY(-6px)}}
.sf-consult h1{font-size:1.4rem;margin:0 0 .6rem}
.sf-consult-lead{color:var(--sf-font);font-size:1rem;margin:0 0 .5rem;opacity:.85}
.sf-consult-note{font-size:.85rem;color:var(--sf-muted);margin-top:1rem}
.sf-consult .sf-muted{color:var(--sf-muted);font-size:.88rem}
.sf-consult-spinner{width:56px;height:56px;margin:0 auto 1.5rem;position:relative}
.sf-consult-spinner span{position:absolute;inset:0;border-radius:50%;border:3px solid transparent;border-top-color:var(--sf-brand);animation:sfSpin 1.1s cubic-bezier(.5,0,.5,1) infinite}
.sf-consult-spinner span:nth-child(2){border-top-color:transparent;border-right-color:var(--sf-brand-dark);opacity:.6;animation-duration:1.6s;animation-direction:reverse}
.sf-consult-spinner span:nth-child(3){inset:12px;border-top-color:var(--sf-brand);opacity:.35;animation-duration:.85s}
@keyframes sfSpin{to{transform:rotate(360deg)}}
.sf-consult-icon{width:64px;height:64px;border-radius:50%;margin:0 auto 1.25rem;display:flex;align-items:center;justify-content:center;animation:sfPopIn .45s cubic-bezier(.34,1.56,.64,1)}
.sf-consult-icon-ready{background:linear-gradient(135deg,var(--sf-brand-dark),var(--sf-brand))}
.sf-consult-icon-later{background:var(--sf-bg);border:1px solid var(--sf-border)}
@keyframes sfPopIn{from{transform:scale(0)}to{transform:scale(1)}}
.sf-consult #sf-consult-btn{margin-top:.5rem}
.sf-cart-row{display:flex;gap:1.25rem;align-items:center;background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:1rem}
.sf-cart-row img{width:100px;height:100px;object-fit:cover;border-radius:8px}
.sf-cart-actions{display:flex;gap:.75rem;margin-top:1.25rem}

.sf-table{width:100%;border-collapse:collapse;margin-top:1.5rem}
.sf-table th,.sf-table td{text-align:left;padding:.65rem .5rem;border-bottom:1px solid var(--sf-border);font-size:.92rem}

/* ---- My Account: passwordless dashboard ---- */
.small{font-size:.85rem}
.mt-2{margin-top:.5rem}
.mb-0{margin-bottom:0}
.sf-account-narrow{max-width:400px;margin:2rem auto}
.sf-btn-sm{padding:.4rem .8rem;font-size:.85rem}
.sf-btn-link-danger{background:none;border:none;color:var(--sf-danger);font-size:.85rem;cursor:pointer;padding:0;text-decoration:underline}

/* Sidebar shell — sits inside .sf-container (already capped at 1500px), so only vertical padding
   is needed here; the sidebar is sticky so it stays reachable next to a long Orders/Payments list. */
.sf-account-shell{display:flex;align-items:flex-start;gap:2rem;padding:2.5rem 0 4rem}
.sf-account-sidebar{flex:0 0 250px;background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:1.5rem 1.15rem;position:sticky;top:100px}
.sf-account-user{display:flex;align-items:center;gap:.75rem;padding-bottom:1.15rem;margin-bottom:1rem;border-bottom:1px solid var(--sf-border)}
.sf-account-avatar{flex:none;width:42px;height:42px;border-radius:50%;background:linear-gradient(135deg,var(--sf-brand),var(--sf-brand-dark));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.95rem}
.sf-account-user-info{min-width:0;display:flex;flex-direction:column;gap:.05rem}
.sf-account-user-info strong{font-size:.92rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.sf-account-user-info span{font-size:.78rem;color:var(--sf-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.sf-account-nav{display:flex;flex-direction:column;gap:.15rem}
.sf-account-nav a{display:flex;align-items:center;gap:.7rem;padding:.6rem .7rem;border-radius:8px;color:var(--sf-font);font-weight:600;font-size:.88rem;transition:background .12s,color .12s}
.sf-account-nav a svg{flex:none;opacity:.6}
.sf-account-nav a:hover{background:var(--sf-bg)}
.sf-account-nav a.active{background:var(--sf-brand);color:#fff}
.sf-account-nav a.active svg{opacity:1}
.sf-account-nav-count{margin-left:auto;background:var(--sf-bg);color:var(--sf-muted);font-size:.72rem;font-weight:700;padding:.1rem .5rem;border-radius:999px}
.sf-account-nav a.active .sf-account-nav-count{background:rgba(255,255,255,.25);color:#fff}
.sf-account-signout{margin-top:1rem;padding-top:1rem;border-top:1px solid var(--sf-border)}
.sf-account-signout button{display:flex;align-items:center;gap:.7rem;width:100%;background:none;border:none;padding:.6rem .7rem;border-radius:8px;color:var(--sf-danger);font-weight:600;font-size:.88rem;cursor:pointer}
.sf-account-signout button:hover{background:#fdecea}

.sf-account-main{flex:1;min-width:0;padding:.25rem 0}
.sf-account-main h1{margin:0 0 .3rem;font-size:1.5rem}
.sf-account-sub{color:var(--sf-muted);margin:0 0 1.75rem}
.sf-account-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1rem;margin-bottom:2rem}
.sf-stat-card{background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:1.1rem 1.25rem}
.sf-stat-card span{display:block;color:var(--sf-muted);font-size:.76rem;text-transform:uppercase;letter-spacing:.03em;margin-bottom:.35rem}
.sf-stat-card strong{font-size:1.55rem;font-weight:700}
.sf-account-section-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}
.sf-account-section-head h2{margin:0;font-size:1.05rem}
.sf-address-card{background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:1.5rem;max-width:560px}
@media (max-width:860px){.sf-account-shell{flex-direction:column;padding-top:1.5rem}.sf-account-sidebar{position:static;width:100%;flex:none}.sf-account-nav{flex-direction:row;flex-wrap:wrap}.sf-account-nav a{flex:1 1 auto;justify-content:center}.sf-account-user{justify-content:center}}

.sf-orders{display:flex;flex-direction:column;gap:1rem;margin-top:1rem}
.sf-order-card{background:var(--sf-card);border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:1.25rem}
.sf-order-card-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;padding-bottom:.85rem;margin-bottom:.85rem;border-bottom:1px solid var(--sf-border)}
.sf-order-badge{flex:none;background:var(--sf-bg);color:var(--sf-font);font-weight:600;font-size:.78rem;padding:.3rem .7rem;border-radius:999px;white-space:nowrap}
.sf-order-badge-info{background:#e8f1ff;color:#0d47a1}
.sf-order-card-body{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.75rem 1.25rem}
.sf-order-fact{display:flex;flex-direction:column;gap:.15rem}
.sf-order-fact span{color:var(--sf-muted);font-size:.76rem;text-transform:uppercase;letter-spacing:.03em}
.sf-order-consult{display:flex;align-items:center;gap:.85rem;flex-wrap:wrap;margin-top:1rem;padding-top:1rem;border-top:1px solid var(--sf-border)}
.sf-order-cancel{margin-top:.85rem}
@media (max-width:600px){.sf-order-card-head{flex-direction:column}}

.sf-activate{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1.5rem;background:var(--sf-bg)}
.sf-activate-box{max-width:420px;width:100%;background:#fff;border:1px solid var(--sf-border);border-radius:var(--sf-radius);padding:2rem;text-align:center}
.sf-activate-box h1{margin-top:0;font-size:1.4rem}
.sf-activate-box .sf-form{text-align:left}
.sf-activate-logo{display:block;margin:0 auto 1.25rem;max-height:40px}
.sf-hint{color:var(--sf-muted);font-size:.85rem;margin-top:1rem}

.sf-footer{background:var(--sf-footer);color:#fff;margin-top:3rem}
/* A builder page provides its own bottom spacing via each section's own Spacing fields — the fixed
   3rem gap above was designed for the non-builder pages' own content, and on a builder page whose
   last section has a full-bleed dark background, it shows as a visible stray white strip (body's
   own background) between that section and the footer instead of just breathing room. */
body:has(.sf-builder-page) .sf-footer{margin-top:0}
.sf-footer-inner{display:flex;justify-content:space-between;flex-wrap:wrap;gap:.5rem;padding:1.5rem 1.25rem;font-size:.9rem}
.sf-footer a{color:#fff;opacity:.85}
.sf-footer-blurb{width:100%;opacity:.85}
/* Icons only ever appear for whichever social links a client actually filled in (see
   storefront/lib/View.php's footerBar()) — white/outline, not each platform's own brand color, to
   stay neutral against any theme color a client has picked. */
.sf-footer-social{display:flex;justify-content:center;flex-wrap:wrap;gap:.75rem;padding:0 1.25rem 1.25rem;border-top:1px solid rgba(255,255,255,.12);margin-top:.25rem;padding-top:1.25rem}
.sf-footer-social a{width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,.35);border-radius:50%;font-size:1rem;opacity:.85;transition:opacity .15s,border-color .15s}
.sf-footer-social a:hover{opacity:1;border-color:#fff}
.sf-footer-legal{text-align:center;padding:0 1.25rem 1.5rem;font-size:.85rem}
/* Stacked, centered, and reordered (email, then affiliate links, then copyright last) — the
   order property only reflows the visual/reading order, the underlying markup order (copyright
   first) is unchanged so nothing else needs to know about this. */
@media (max-width:760px){.sf-footer-inner{flex-direction:column;align-items:center;text-align:center}.sf-footer-email{order:1}.sf-footer-affiliate{order:2}.sf-footer-copy{order:3}}

@media (max-width:760px){.sf-product{grid-template-columns:1fr}.sf-grid-2{grid-template-columns:1fr}.sf-form-row,.sf-form-row-3{grid-template-columns:1fr}}
