/** Shopify CDN: Minification failed

Line 2741:20 Unexpected "*"
Line 2745:80 Unterminated string token
Line 2747:81 Unterminated string token

**/
/* ============================================================================
   sparko-custom.css
   All Sparko custom CSS lives here. This file is loaded in layout/theme.liquid
   AFTER the theme's own bundles, so its rules win over base.bundle.css.

   Do NOT append custom CSS to base.bundle.css or any *.bundle.* file — those are
   build artifacts replaced wholesale on Shapes version updates.

   Sections:
     1. Brand fonts (repoint theme font tokens to Adobe Fonts / Typekit)
     2. Qstomizer button styling
     3. Judge.me review styling overrides
   ============================================================================ */


/* ----------------------------------------------------------------------------
   1. Brand fonts
   Ported verbatim from v3.0.5 assets/custom-font.css. Repoints the theme's own
   font custom properties to the Typekit families (loaded via the <link> in
   theme.liquid). All six property names verified to still exist in v4.4.
   Display: Filson Pro 900. Body: Ingra 500.
   ---------------------------------------------------------------------------- */
:root {
  --main-font-stack: "ingra", sans-serif !important;
  --main-font-weight: 500 !important;
  --main-font-style: normal !important;

  --heading-font-stack: "filson-pro", sans-serif !important;
  --heading-font-weight: 900 !important;
  --heading-font-style: normal !important;
}


/* ----------------------------------------------------------------------------
   2. Qstomizer button styling
   Ported from v3.0.5 base.bundle.css. Styles the app-injected button
   (#qstomizer-product-button) and the theme-rendered custom-product button
   (#qstomizer-product-button-custom, see snippets/sparko-qstomizer-button.liquid).
   Both are built entirely from the theme's own button custom properties; all 12
   referenced properties verified to still exist in v4.4. The -custom variant
   adds full width and a bottom margin.
   ---------------------------------------------------------------------------- */
#qstomizer-product-button {
  display: inline-block;
  cursor: pointer;
  border-radius: var(--button-border-radius);
  padding: .75rem 1rem;
  text-align: center;
  font-size: var(--font-size-base);
  line-height: var(--base-line-height);
  text-transform: var(--button-text-transform);
  background: rgb(var(--color-button-background));
  color: rgb(var(--color-button-text));
  box-shadow: inset 0 0 0 var(--button-border-width) rgb(var(--color-button-border));
  box-sizing: border-box;
  transition: transform .1s cubic-bezier(.215, .61, .355, 1);
  font-family: var(--button-font-stack);
  font-weight: var(--button-font-weight);
  font-style: var(--button-font-style);
  letter-spacing: var(--button-letter-spacing);
}

#qstomizer-product-button-custom {
  display: inline-block;
  cursor: pointer;
  border-radius: var(--button-border-radius);
  padding: .75rem 1rem;
  text-align: center;
  font-size: var(--font-size-base);
  line-height: var(--base-line-height);
  text-transform: var(--button-text-transform);
  background: rgb(var(--color-button-background));
  color: rgb(var(--color-button-text));
  box-shadow: inset 0 0 0 var(--button-border-width) rgb(var(--color-button-border));
  box-sizing: border-box;
  transition: transform .1s cubic-bezier(.215, .61, .355, 1);
  font-family: var(--button-font-stack);
  font-weight: var(--button-font-weight);
  font-style: var(--button-font-style);
  letter-spacing: var(--button-letter-spacing);
  width: 100%;
  margin-bottom: 15px;
}


/* ----------------------------------------------------------------------------
   3. Judge.me review styling overrides
   Ported from the inline <style> block in v3.0.5 theme.liquid. Targets specific
   Judge.me text/arrow/star elements only, never the star glyph font. Forces the
   brand fonts and colors: Ingra on review text, Filson Pro on titles/authors,
   California Gold (#EFB037) stars, Electric Pink (#DA2B6B) carousel arrows.

   NOTE: v3 used `var(--standard-heading-size)` for the widget title size. That
   token still exists in v4.4, but per the migration plan its value is hardcoded
   here (v3 resolved: 2rem mobile / 2.66968rem >=990px) and marked for the
   redesign, so Judge.me title sizing is decoupled from the evolving type scale.
   ---------------------------------------------------------------------------- */

/* --- CAROUSEL: Review card text --- */
.jdgm-carousel .jdgm-rev__body,
.jdgm-carousel .jdgm-rev__author,
.jdgm-carousel .jdgm-rev__timestamp,
.jdgm-carousel .jdgm-rev__product,
.jdgm-carousel .jdgm-rev__title {
  font-family: "ingra", sans-serif !important;
  font-weight: 500 !important;
  font-style: normal !important;
}

/* --- CAROUSEL: Widget title (e.g. "TRUSTED & LOVED") --- */
.jdgm-carousel .jdgm-carousel-wrapper__title,
.jdgm-widget .jdgm-widget__title,
.jdgm-widget .jdgm-title,
.jdgm-widget h2.jdgm-title,
h2.jdgm-title {
  font-family: "filson-pro", sans-serif !important;
  font-weight: 900 !important;
  font-style: normal !important;
  text-transform: var(--heading-capitalize) !important;
  letter-spacing: var(--heading-letterspacing) !important;
  font-size: 2rem !important; /* REDESIGN-TODO: was var(--standard-heading-size); v3 mobile value (--font-size-3xl = 2 * 1rem) */
  font-synthesis: none !important;
  color: #262666 !important;
}

@media (min-width: 990px) {
  .jdgm-carousel .jdgm-carousel-wrapper__title,
  .jdgm-widget .jdgm-widget__title,
  .jdgm-widget .jdgm-title,
  .jdgm-widget h2.jdgm-title,
  h2.jdgm-title {
    font-size: 2.66968rem !important; /* REDESIGN-TODO: v3 desktop value (--font-size-4xl = 2.66968 * 1rem) */
  }
}

/* --- CAROUSEL: Author names --- */
.jdgm-carousel .jdgm-rev__author-name {
  font-family: "filson-pro", sans-serif !important;
  font-weight: 700 !important;
}

/* --- LIGHTBOX: Text elements only --- */
#jdgm-carousel-lightbox-root .jdgm-rev__body,
#jdgm-carousel-lightbox-root .jdgm-rev__author,
#jdgm-carousel-lightbox-root .jdgm-rev__timestamp,
#jdgm-carousel-lightbox-root .jdgm-rev__product,
#jdgm-carousel-lightbox-root .jdgm-rev__title {
  font-family: "ingra", sans-serif !important;
  font-weight: 500 !important;
  font-style: normal !important;
}

/* --- PRODUCT PAGE: Review widget text --- */
.jdgm-rev-widg .jdgm-rev__body,
.jdgm-rev-widg .jdgm-rev__author,
.jdgm-rev-widg .jdgm-rev__timestamp,
.jdgm-rev-widg .jdgm-rev__product,
.jdgm-rev-widg .jdgm-rev__title,
.jdgm-rev-widg .jdgm-header-info,
.jdgm-rev-widg .jdgm-summary-text,
.jdgm-rev-widg .jdgm-write-rev-link,
.jdgm-rev-widg .jdgm-all-reviews-text {
  font-family: "ingra", sans-serif !important;
  font-weight: 500 !important;
  font-style: normal !important;
}

/* --- PRODUCT PAGE: Review count badge text (e.g. "4 reviews") --- */
.jdgm-prev-badge__text,
.jdgm-preview-badge .jdgm-prev-badge__text,
span.jdgm-prev-badge__text {
  font-family: "ingra", sans-serif !important;
  font-weight: 500 !important;
  font-style: normal !important;
}

/* --- ALL STARS EVERYWHERE: Only set color, never touch font --- */
.jdgm-star {
  color: #EFB037 !important;
}

/* --- ARROWS: Main carousel (inline widget) --- */
.jdgm-carousel__left-arrow,
.jdgm-carousel__right-arrow,
.jdgm-carousel__btn,
.jdgm-carousel__btn::before,
.jdgm-carousel__btn svg,
.jdgm-carousel__btn path,
.jdgm-prev-btn,
.jdgm-next-btn {
  color: #DA2B6B !important;
  fill: #DA2B6B !important;
  stroke: #DA2B6B !important;
  border-color: #DA2B6B !important;
  opacity: 1 !important;
}

/* --- ARROWS: Lightbox carousel --- */
#jdgm-carousel-lightbox-root .jdgm-carousel__left,
#jdgm-carousel-lightbox-root .jdgm-carousel__right,
#jdgm-carousel-lightbox-root .jdgm-carousel__btn,
#jdgm-carousel-lightbox-root .jdgm-carousel__btn::before,
#jdgm-carousel-lightbox-root .jdgm-carousel__btn svg,
#jdgm-carousel-lightbox-root .jdgm-carousel__btn path {
  color: #DA2B6B !important;
  fill: #DA2B6B !important;
  stroke: #DA2B6B !important;
  border-color: #DA2B6B !important;
}


/* ----------------------------------------------------------------------------
   4. Announcement bar (section: sparko-announcement-bar)
   Colors come from section settings via the --sa-* custom properties.
   ---------------------------------------------------------------------------- */
.sparko-announcement {
  width: 100%;
  background: var(--sa-bg, #EFB037);
  color: var(--sa-fg, #262666);
}

.sparko-announcement__inner {
  /* Full-width chrome: matches the header (no cap, fixed 2rem gutter). */
  padding: 0.5rem 2rem;
  text-align: center;
}

.sparko-announcement__text {
  display: block;
  color: var(--sa-fg, #262666);
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: 0.8125rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  /* single line: never wrap; trim with ellipsis on narrow screens */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

a.sparko-announcement__text {
  text-decoration: none;
}

a.sparko-announcement__text:hover {
  text-decoration: underline;
}


/* ----------------------------------------------------------------------------
   5. Header (section: sparko-header)
   Colors come from section settings via the --sh-* custom properties.
   Desktop: [left menu] [centered wordmark] [right menu + icons far right].
   Mobile: [hamburger] [centered wordmark] [cart], with an Alpine drawer.
   ---------------------------------------------------------------------------- */
.sparko-header {
  width: 100%;
  background: var(--sh-bg, #262666);
  color: var(--sh-fg, #ffffff);
  position: relative;
  /* The bar's height, in ONE place. The bar and the inline search bar are
     siblings that swap on open, so a number that lives in two rules drifts and
     the page jumps when search opens. It did: the search bar kept a hardcoded
     62px, written when the bar was also 62px, and stayed there when the bar was
     retuned to match the live header. The jump measured +11px at 1440 and +3px
     at 390. */
  --sparko-header-h: 51px;
}

.sparko-header__bar {
  display: grid;
  /* minmax(0, 1fr) keeps the side columns from blowing out to fit a wide menu,
     so the wordmark stays truly centered regardless of menu length. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: 1.5rem;
  /* Full-width chrome: no max-width cap, so the nav and icons sit near the
     viewport edges on wide screens. The horizontal padding reads --sparko-gutter
     rather than a fixed 2rem, so the first nav item lands on the same left edge
     as page content in .sparko-wrap. It was 2rem against a 48px page gutter, and
     when the gutter moved to 40px the two ended up 8px apart, which read as a
     near-miss rather than as two systems.

     This is the only horizontal-padding declaration for the bar; the phone rule
     below reads the same token, so the two edges stay locked at every width.

     HEIGHT is matched to the live Shapes header, measured rather than eyeballed:
     51px at 1440 there against 62px here, so the bar was 11px taller than the
     site it is replacing. `min-height` carries the number so it is stated rather
     than emerging from padding plus whatever the logo happens to measure — the
     logo is a merchant-set image whose height follows its own aspect ratio, so
     padding alone would drift the moment it changed. The padding is set below
     that height so the min-height is what governs. */
  padding: 0.5rem var(--sparko-gutter);
  min-height: var(--sparko-header-h);
}

.sparko-header__left {
  justify-self: start;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.sparko-header__right {
  justify-self: end;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.sparko-header__nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.sparko-header__link {
  color: var(--sh-fg, #ffffff);
  /* Filson Pro 900, the wordmark's family, not Ingra. The nav previously read as
     a lighter, wider family sitting next to the mark.

     Tracking: the wordmark is a raster PNG, so it has no computed
     letter-spacing to copy. It was measured optically instead -- median
     inter-letter gap over cap height = 0.0465 on the 400px logo. Filson Pro 900
     rendered to canvas gives 0.0411 at -0.02em and 0.0548 at -0.01em, so the
     mark sits between the two. -0.01em is the nearer safe end and is also the
     brand's own display tracking, the value .sparko-section-title uses. The old
     0.08em was positive, i.e. looser than the mark rather than matching it. */
  font-family: var(--heading-font-stack, sans-serif);
  /* 700 (Bold). The Typekit kit (ruu0tch) ships only three Filson Pro faces,
     400 / 700 / 900, so the 600 that was asked for resolves to 700 anyway --
     both measure 354.91px at 60px, against 358.63px for 900. The value is
     written as 700 so it names the face that is actually loaded rather than one
     that is not. Real step down from Black; the drawer stays 900. */
  font-weight: 700;
  /* 13.8px. Written in rem so it still tracks the root size; 0.8625 x 16 = 13.8. */
  font-size: 0.8625rem;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
}

/* Hover and current-page state are a color change only: California Gold, with no
   underline and no transition. Underline is not part of the v2 system. This
   covers both the left and right split menus, which share this class.

   Gold, not Electric Pink. Pink was the original choice here and the intent was
   right, but #DA2B6B on the navy bar measures 2.93:1 -- under the 4.5:1 AA floor
   for text this size. It also made the current-page link look SMALLER than its
   white neighbours, which is what sent us looking: the glyphs are identical
   (measured 2026-09-11 at 1440px -- same 13.8px, 700, -0.01em, same 10.25px cap
   height and advance), but white sits at 13.54:1 and blooms into its antialiased
   edges at 13.8px where the low-contrast pink does not. Gold is 7.05:1 on the
   same bar, clears AA and AAA, and is already in the palette -- no fourth pink
   invented for one state. Chosen 2026-09-11; see CLAUDE.md, Component
   conventions. */
.sparko-header__link:hover,
.sparko-header__link.is-active {
  color: var(--sparko-gold, #EFB037);
}

.sparko-header__wordmark {
  justify-self: center;
  color: var(--sh-mark, #DA2B6B);
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  letter-spacing: 0.02em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

/* Image logo (replaces the text wordmark when a logo is uploaded) */
.sparko-header__wordmark--image {
  display: inline-flex;
  align-items: center;
  line-height: 0;
}

.sparko-header__logo-img {
  display: block;
  width: var(--sh-logo-width, 200px);
  max-width: 100%;
  height: auto;
}

@media (max-width: 989px) {
  .sparko-header__logo-img {
    /* Scale the logo down on small screens so the centered one-line image clears
       the hamburger and the three icons (never above the chosen width).

       38.5vw, not 32vw: at 390 that is 150px, which is what the live Shapes
       header renders. 32vw gave 125px, a logo a sixth smaller than the site
       this replaces, which is most of why our header read as emptier at the
       same bar height.

       A single vw figure is the closest honest fit, not a transcription. Live's
       logo is sized by its flex layout rather than by a rule, so it measures
       132px at 320, 150 at 390, 181 at 560 and 200 from 768 up — a curve no
       single vw or linear formula reproduces. This matches at 390, the width
       this theme is checked at, and stays within a few px at 320. */
    width: min(var(--sh-logo-width, 200px), 38.5vw);
  }
}

.sparko-header__icons {
  display: flex;
  align-items: center;
  gap: 1.1rem;
}

.sparko-header__icon {
  color: var(--sh-fg, #ffffff);
  display: inline-flex;
  align-items: center;
  position: relative;
  text-decoration: none;
}

/* 1.75rem = 28px, the size the live header uses. Ours were 1.4rem / 22.4px,
   noticeably lighter beside the same wordmark. Live measures 28px at 390 and at
   1440 alike, so this is the base rule rather than a phone-only one, and the
   account icon on desktop takes the same size for the same reason. */
.sparko-header__icon .theme-icon {
  width: 1.75rem;
  height: 1.75rem;
}

.sparko-header__cart-count {
  position: absolute;
  top: -0.5rem;
  right: -0.6rem;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: #EFB037;
  color: #262666;
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 700;
  font-size: 0.7rem;
  line-height: 1.1rem;
  text-align: center;
}

.sparko-header__cart-count[hidden] {
  display: none;
}

.sparko-header__burger {
  display: none;
  background: none;
  border: 0;
  padding: 0;
  color: var(--sh-fg, #ffffff);
  cursor: pointer;
}

/* 28px, the same as the search and cart icons beside it and the same as live's
   burger. It was 1.6rem / 25.6px, which read as a near-miss against 28 rather
   than as a deliberate difference once the other two grew. */
.sparko-header__burger .theme-icon {
  width: 1.75rem;
  height: 1.75rem;
}

.sparko-header__drawer {
  display: none;
}

/* Drawer chrome — always defined; only visible when the compact media query below
   sets the drawer to display:block. */
.sparko-header__scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
}
/* Warm cream panel with navy type, matching the live site's drawer. It was navy
   on navy with white links, which inverted the site's own drawer treatment. The
   panel sets its own fg/bg rather than inheriting --sh-bg / --sh-fg, because
   those are the HEADER BAR's colours and the bar stays navy. */
/* Width follows Switch's own left-drawer rather than a fixed cap: it is
   `w-11/12 md:w-7/12 lg:w-5/12` in snippets/left-drawer.liquid, so the panel is
   nearly full-bleed on a phone and settles to a column on a tablet. The old
   min(80vw, 20rem) held 320px at every width, which read as a narrow strip once
   the drawer started appearing at the 1400px collapse breakpoint.

   The percentages are written out rather than borrowed as Tailwind classes,
   because that bundle is purged and these are OUR element's styles. */
.sparko-header__panel {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 91.6667%;
  background: var(--sparko-cream, #FEFBF5);
  color: var(--sparko-navy, #262666);
  /* No right border. Switch's drawer carries one, and ours previously matched it
     with the 2px Night Sky Blue of the card and button convention, but that
     convention is for closed shapes — a card or a button, ringed on all four
     sides. On a panel pinned to three edges of the viewport it is a single naked
     stripe down one side, which reads as an artifact rather than as an edge
     (2026-09-09, at the client's direction). The cream panel already separates
     itself from the page by sitting on the scrim. */
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  overflow-y: auto;
}
@media (min-width: 768px) {
  .sparko-header__panel { width: 58.3333%; }
}
@media (min-width: 1024px) {
  .sparko-header__panel { width: 41.6667%; }
}

/* Slide-in, driven by the x-transition class hooks on the panel. Transform only,
   so it composites and never reflows the list behind it. */
.sparko-header__panel--anim { transition: transform 300ms ease; }
.sparko-header__panel--off { transform: translateX(-100%); }
.sparko-header__panel--on { transform: translateX(0); }
.sparko-header__panel-close {
  align-self: flex-end;
  background: none;
  border: 0;
  padding: 0;
  color: var(--sparko-navy, #262666);
  cursor: pointer;
}
.sparko-header__panel-close .theme-icon {
  width: 1.5rem;
  height: 1.5rem;
}
/* Row separation is PADDING on each row, not gap between rows.

   A gap is dead space: it separates the labels but is not tappable, so widening
   it makes a menu look easier to hit while leaving the target the same size. The
   rows were a 26px target with 16px of untappable space around them. Padding
   grows the target itself, and because the rows are stretch-sized in this flex
   column they already span the full panel width, so the whole strip is live.

   Gap is kept at a hair rather than zero so adjacent targets read as separate
   rows; the visible separation now comes mostly from the padding inside them. */
.sparko-header__drawer-nav {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
/* Filson Pro Heavy, matching the desktop nav and the wordmark. Same -0.01em
   tracking, measured off the wordmark; see .sparko-header__link. */
.sparko-header__drawer-nav a {
  color: var(--sparko-navy, #262666);
  text-decoration: none;
  font-family: var(--heading-font-stack, sans-serif);
  /* See .sparko-header__link: 800 is not in the kit and resolves to 900. */
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  font-size: 1.5rem;
  line-height: 1.1;
  /* 26.4px of text + 2x8.8px = 44px, the Apple HIG / WCAG 2.5.5 target. The
     sublinks inherit this and land at 38px, which is smaller only because their
     type is, and still well past the 24px WCAG 2.5.8 minimum. */
  padding: 0.55rem 0;
}
/* Same color-only hover as the desktop nav links.

   Guarded on (hover: hover). Unguarded, this fires on touch and LATCHES: tapping
   a row to open its group leaves that row pink until something else is tapped, so
   the drawer appears to be marking a page the shopper is not on. The drawer has
   no current-page state by design (see CLAUDE.md), which is exactly why the stuck
   hover was misread as one. Drawer scope only; the file-wide guard is a known gap
   and is not fixed here. */
@media (hover: hover) {
  .sparko-header__drawer-nav a:hover {
    color: var(--sparko-pink, #DA2B6B);
  }
}
/* Account links stacked above a search field, matching the live drawer. Was a
   row of two bare icons, which is the desktop bar's treatment. */
.sparko-header__drawer-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.6rem;
  padding-top: 1.25rem;
  /* Navy hairline, not the white one: the panel is cream now. */
  border-top: 1px solid rgba(38, 38, 102, 0.2);
  color: var(--sparko-navy, #262666);
}
/* Body font, sentence case: these are secondary to the Filson caps above, and
   the live site sets them the same way. */
.sparko-header__drawer-link {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: 1rem;
  color: var(--sparko-navy, #262666);
  text-decoration: none;
}
@media (hover: hover) {
  .sparko-header__drawer-link:hover { color: var(--sparko-pink, #DA2B6B); }
}

/* ----------------------------------------------------------------------------
   Header — <shopify-account>

   The account entry points in sparko-header.liquid are Shopify's
   <shopify-account> custom element, not anchors. The sheet it opens is styled
   entirely through --shopify-account-* custom properties, which are set inline
   on the element from snippets/sparko-account-style.liquid; nothing in here can
   reach inside the sheet, and it should not try to. These rules only make the
   element itself sit in our header the way the anchors it replaced did.

   An undefined custom element is display: inline with no cursor, so both
   instances need at least a box and a pointer. The desktop one takes the rest
   from .sparko-header__icon, and the .theme-icon sizing rule above still hits
   the slotted <svg> because slotted content stays a light-DOM descendant.
   ---------------------------------------------------------------------------- */
.sparko-header__icon--account,
.sparko-header__drawer-link--account {
  cursor: pointer;
}

/* <shopify-account> injects a headless <shopify-store> element as a SIBLING, and
   it lands inside .sparko-header__icons. It measures 0x0, so it looks harmless,
   but the row is a flex container with `gap`, and a zero-width flex item still
   takes a gap on both sides. That doubled the space on one side only: search to
   account measured 35.2px against account to cart at 17.6px, which is the uneven
   icon spacing this caused. display:none takes it out of flex layout; it stays in
   the DOM and its script still runs, which is all it needs since it renders
   nothing. Scoped to the header so an instance injected elsewhere is unaffected. */
.sparko-header__icons shopify-store {
  display: none;
}

/* Slotted content does NOT inherit our type. The component drops the slot inside
   its own <button> in the shadow tree, and a button does not inherit font-family
   or font-size from the page, so the label came out 13.33px Arial 400 — visibly
   smaller than every other drawer row and in the wrong family. Setting it on the
   slotted element works because slotted content stays in the light DOM, so this
   is our own markup being styled, not a reach into the shadow tree.

   1rem matches Shapes 5.0.1, which puts `text-base` on this span, and matches
   .sparko-header__drawer-link beside it. */
.sparko-header__drawer-link--account [slot='signed-out-avatar'] {
  font-family: var(--main-font-stack, 'ingra', sans-serif);
  font-size: 1rem;
  font-weight: var(--main-font-weight, 500);
  line-height: 1.4;
  color: inherit;
}

/* Signed-in state, desktop. 5.0.1 draws a plain 1.75rem block in the theme's
   accent; ours is a circle in Electric Pink, which is the avatar-placeholder
   use, not a decorative one. Same 1.75rem as the signed-out icon beside it so
   the bar does not reflow when a customer signs in. */
.sparko-header__account-avatar {
  display: inline-block;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--sparko-pink, #DA2B6B);
}

/* The drawer instance is a flex item in .sparko-header__drawer-actions, which
   the anchors it replaced were too. block, not inline-flex: the anchors were
   full-width rows and the label must keep sitting on the left edge. */
.sparko-header__drawer-link--account {
  display: block;
}

.sparko-header__drawer-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.6rem 0.9rem 0.6rem 1.1rem;
  border: 2px solid var(--sparko-navy, #262666);
  border-radius: 999px;
  background: #ffffff;
}
.sparko-header__drawer-search input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  padding: 0;
  font-family: var(--main-font-stack, sans-serif);
  font-size: 1rem;
  color: var(--sparko-navy, #262666);
}
.sparko-header__drawer-search input::placeholder { color: rgba(38, 38, 102, 0.6); }
.sparko-header__drawer-search input:focus { outline: none; }
/* Same treatment as the header bar: heavier border, no glow. */
.sparko-header__drawer-search:focus-within {
  border-width: 3px;
  padding: calc(0.6rem - 1px) calc(0.9rem - 1px) calc(0.6rem - 1px) calc(1.1rem - 1px);
}
.sparko-header__drawer-search button {
  flex: 0 0 auto;
  display: flex;
  border: 0;
  background: none;
  padding: 0;
  color: var(--sparko-navy, #262666);
  cursor: pointer;
}
.sparko-header__drawer-search button .theme-icon,
.sparko-header__drawer-search button svg { width: 1.25rem; height: 1.25rem; }

/* Compact mode: a FIXED breakpoint swaps the inline split nav for the hamburger.
   Above 1400px the inline split nav shows; at 1400px and below the header
   collapses to the hamburger + centered logo + icons, with Main menu in the
   drawer. This is a pure CSS media query (no JS measurement), so it is
   deterministic and cannot silently fail. The inline nav's true fit point is
   ~1388px, so 1400 collapses ~12px early on purpose: overlapping text is worse
   than collapsing a touch early. */
@media (max-width: 1400px) {
  .sparko-header__nav { display: none; }
  .sparko-header__burger { display: inline-flex; }
  .sparko-header__drawer { display: block; position: fixed; inset: 0; z-index: 100; }
}

/* Phone-only tightening (the logo also scales via the rule higher up).
   Vertical padding drops; horizontal keeps reading --sparko-gutter, which is
   itself 1.5rem below 980px. Hardcoding 2rem here would have re-opened the same
   8px gap at the bottom of the range that the desktop rule just closed, in the
   other direction: 32px of header against a 24px page gutter. */
@media (max-width: 989px) {
  /* 59px on a phone, the live header's height. Note this GROWS ours by 9px:
     measured, the phone bar was 50px against the live site's 59px, so it was
     already the shorter of the two even though the desktop bar was taller. The
     two ends were off in opposite directions, which is why matching means
     shrinking one and growing the other. */
  /* 0.9375rem, down from 1rem, so the 59px min-height keeps governing. The
     icons went from 22.4px to 28px and 28 + 2 x 16 comes to 60, one pixel over
     the height matched to live. At 15px the content is 58 and the min-height is
     what sets the bar again. */
  .sparko-header { --sparko-header-h: 59px; }
  .sparko-header__bar { padding: 0.9375rem var(--sparko-gutter); }
  /* No account icon in the bar on a phone, matching the live header, which
     carries search and cart there and keeps account for desktop.

     It is hidden, not removed: the drawer carries its own <shopify-account>,
     whose sheet covers log in, create account, account and log out alike, so
     nothing becomes unreachable — the icon was a second route to the same sheet.
     Dropping it also gives the wordmark room between the burger and the two
     remaining icons at 320px. */
  .sparko-header__icon--account { display: none; }
  .sparko-header__icons { gap: 0.6rem; }
}

[x-cloak] {
  display: none !important;
}


/* ----------------------------------------------------------------------------
   6. Footer (section: sparko-footer)
   Colors come from section settings via the --sf-* custom properties.
   ---------------------------------------------------------------------------- */
.sparko-footer {
  width: 100%;
  background: var(--sf-bg, #262666);
  color: var(--sf-fg, #ffffff);
}

.sparko-footer__inner {
  /* Full-width chrome: matches the header (no cap, fixed 2rem gutter). */
  padding: 3rem 2rem 2rem;
}

.sparko-footer__top {
  display: grid;
  /* Anchored to the design reference's .sp-footer-grid, which is
     "1.4fr 1fr 1fr 1fr" with a 48px gap. The brand block takes the wider
     explicit track; each menu column flows into an implicit 1fr track, so the
     1.4:1:1:1 ratio holds for whatever number of menu_column blocks the theme
     editor has. The gap is the reference's --sp-7, the same 48px token as the
     container gutter, so the footer shares the site's horizontal rhythm.
     Columns of uneven length are left alone, as both the reference and Switch
     leave them: default stretch, content flowing from the top of each cell. */
  grid-template-columns: 1.4fr;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 3rem;
}

.sparko-footer__wordmark {
  display: inline-block;
  color: var(--sf-fg, #ffffff);
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: clamp(1.5rem, 3vw, 2rem);
  letter-spacing: 0.02em;
  text-decoration: none;
}

.sparko-footer__brandline {
  margin-top: 0.75rem;
  max-width: 22rem;
  color: var(--sf-fg, #ffffff);
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: 0.95rem;
  line-height: 1.5;
}

.sparko-footer__columns {
  /* Lifts the menu columns into .sparko-footer__top's grid so each one is a
     sibling of the brand block rather than sharing a single nested track. This
     wrapper becomes a grid again at mobile, below. */
  display: contents;
}

.sparko-footer__col-head {
  color: var(--sf-head, #EFB037);
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.9rem;
  margin: 0 0 0.9rem;
}

.sparko-footer__col-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.sparko-footer__col-links a {
  color: var(--sf-fg, #ffffff);
  text-decoration: none;
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: 0.9rem;
}

.sparko-footer__col-links a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Footer stacking order on a phone.

   The footer is Switch's stock section, whose grid is one column below 990px
   and twelve above it. Stacked, the source order put the newsletter beneath
   three menus totalling twenty-two links, which is past the point anyone
   scrolls; side by side it is the right-hand column, which is where it belongs
   and is left alone.

   So this is a MOBILE-ONLY reorder: engagement first (tagline, socials, then
   the signup), navigation second, with the copyright bar the section renders
   after both. `order` works here because the parent is a grid and these are its
   direct children. The hooks come from footer.liquid and exist only on the
   three-block footer. */
/* Footer menus, two across on a phone.

   Stacked in one column the three menus ran twenty-two links and three headings
   before the copyright, which is most of the footer's height. Two across roughly
   halves it. Three across is what this replaced and is not an option: the labels
   wrap onto two lines at that width.

   `.sparko-fmenus > .sparko-fmenu` is two class selectors so it beats Tailwind's
   own `.w-full` on the same element without needing !important; the width is
   half the row less half the column gap. Above 990px none of this applies and
   the columns size to their own content, as they already did. */
@media (max-width: 989px) {
  .sparko-fmenus { gap: 2rem 1rem; }
  .sparko-fmenus > .sparko-fmenu { width: calc(50% - 0.5rem); }
}

@media (max-width: 989px) {
  .sparko-fblock--tagline_and_social_links { order: 1; }
  .sparko-fblock--newsletter { order: 2; }
  .sparko-fblock--menus { order: 3; }
}

.sparko-footer__divider {
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  margin: 2.5rem 0 1.25rem;
}

.sparko-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.sparko-footer__copyright {
  margin: 0;
  color: var(--sf-fg, #ffffff);
  font-family: var(--main-font-stack, sans-serif);
  font-size: 0.8rem;
}

.sparko-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.sparko-footer__legal a {
  color: var(--sf-fg, #ffffff);
  text-decoration: none;
  font-family: var(--main-font-stack, sans-serif);
  font-size: 0.8rem;
}

.sparko-footer__legal a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

@media (max-width: 749px) {
  .sparko-footer__top {
    grid-auto-flow: row;
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  /* Re-formed into its own grid so the brand block stacks above a two-up set of
     menu columns, which is the pre-existing mobile layout. */
  .sparko-footer__columns {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.5rem;
  }
}

/* ============================================================================
   Image placeholders (snippet: sparko-image-placeholder)
   Shown when a theme-editor image setting is empty. Deliberately plain and
   captioned so it reads as missing content rather than as a design element,
   and sized to fill its slot so an empty section keeps its real layout.
   ============================================================================ */
.sparko-ph {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  background: var(--sparko-ph-fill, rgba(38, 38, 102, 0.05));
  overflow: hidden;
}
/* Dark sections: the navy tints are invisible against Night Sky Blue, so invert
   them to light. Pass tone: 'dark' from the call site. */
.sparko-ph--dark {
  --sparko-ph-fill: rgba(255, 255, 255, 0.10);
  --sparko-ph-glyph: rgba(255, 255, 255, 0.40);
}
/* Background layers (the hero art) rather than in-flow slots. */
.sparko-ph--fill {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
}
.sparko-ph__art { position: absolute; inset: 0; display: block; }
/* In the fill variant the box is a whole section's background, so a centred
   glyph lands on the copy once the section is narrow. Pin it to the top-right
   at a fixed size instead: clear of the left-aligned text column at any width,
   and clear of the caption pill in the opposite corner. */
.sparko-ph--fill .sparko-ph__art {
  inset: 0.75rem 0.75rem auto auto;
  width: 3rem;
  height: 3rem;
}
.sparko-ph__svg {
  width: 100%;
  height: 100%;
  display: block;
  fill: var(--sparko-ph-glyph, rgba(38, 38, 102, 0.14));
  background: transparent;
}
/* Top-left, on an opaque cream pill, so the caption stays legible over the
   hero's shade gradient as well as over a plain card slot. */
.sparko-ph__cap {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 1;
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 700;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sparko-navy);
  background: rgba(254, 251, 245, 0.94);
  border: 1px solid rgba(38, 38, 102, 0.35);
  border-radius: 999px;
  padding: 0.25rem 0.6rem;
  white-space: nowrap;
  pointer-events: none;
}


/* ============================================================================
   HOMEPAGE — shared foundation (brand tokens, layout wrap, pill buttons)
   Authored for the Sparko homepage redesign; brand hexes per CLAUDE.md.
   Buttons: bubbly pills, 2px Night Sky Blue border, hard offset shadow.
   ============================================================================ */
:root {
  --sparko-navy: #262666;
  --sparko-pink: #DA2B6B;
  --sparko-gold: #EFB037;
  --sparko-cream: #FEFBF5;
  --sparko-pink-hover: #c0245d;
  --sparko-navy-hover: #1e1e54;
  --sparko-gold-hover: #e0a52d;
  /* Text selection. Switch already ships a ::selection rule in
     snippets/css-bridge.liquid, driven by the selected_text_background_color
     setting, but every option it offers (text / accent_1 / accent_2) resolves
     against the current color scheme. That would make the highlight change
     colour section by section, since the homepage runs scheme1, 3 and 4 while
     the footer runs scheme7. These hold one fixed brand value instead. */
  --sparko-select-bg: #DA2B6B;
  --sparko-select-fg: #ffffff;
  /* Layout tokens. Body content caps at --sparko-container; prose lines cap at
     --sparko-measure (~70 characters) for readability inside the wider container.
     --sparko-bleed-pad is the left padding a full-bleed row uses to line its
     first item up with the container's content edge (partials run off the right
     edge). It uses 100% (the full-bleed parent's width), so it stays correct at
     any viewport without a 100vw scrollbar overflow. */
  /* Container: 1820px / 40px, matching Switch's own `max-w-site` + `px-section`
     so our sections and the stock ones share a left content edge.

     This deliberately diverges from the design reference, whose .sp-wrap is
     1320px / 48px (hifi/hifi-styles.css). The reference has no stock Shapes
     surfaces to sit beside; this theme does, and a cart or search page next to a
     Sparko page was stepping 8px horizontally and re-centring at a different
     width. Alignment with the surrounding theme won over matching the comp.

     Caveat worth knowing: stock Shapes is not one container. `max-w-site`
     (1820px) is what the stock product section uses, but the cart's main section
     is `max-w-5xl` (1024px) and the search results section has no cap at all.
     Below a 1820px viewport every px-section surface starts 40px in and this
     matches all of them; above it, the uncapped ones keep hugging the viewport
     while we centre. That is inherent to Switch, not something we can fix here.

     Third change of this value: 1320 -> 1680 in 668f4f6, reverted to 1320, now
     1820 with the reason above. See the Layout container section in CLAUDE.md. */
  --sparko-container: 1820px;
  --sparko-gutter: 40px;
  --sparko-measure: 38.75rem;
  /* Section rhythm, taken from the process section and shared from there. Any
     homepage section following the heading-then-content pattern uses these
     rather than deciding its own; see the section-rhythm block below. */
  --sparko-section-pad: 3.5rem;
  --sparko-heading-gap: 1.5rem;
  --sparko-content-gap: 2.5rem;
  --sparko-bleed-pad: max(var(--sparko-gutter), calc((100% - var(--sparko-container)) / 2 + var(--sparko-gutter)));
}

/* ----------------------------------------------------------------------------
   DISPLAY TYPE — the mobile ramp
   ----------------------------------------------------------------------------
   Every display heading is a three-part clamp. Read them as:

     clamp( floor , calc(intercept + slope) , ceiling )

   The middle term is the fluid one and it is written as calc() ON PURPOSE. The
   old form was a bare `Nvw`, which looks fluid but is not: a bare vw term small
   enough to keep a headline sane at 1820px is far below the floor at 390px, so
   the floor won at EVERY phone and tablet width. Measured before this change,
   all 33 clamps in this file resolved to their floor at 390px. Mobile type was
   never designed; it inherited whatever floor had been picked as a desktop
   safety net. The collection hero read 52px on a 342px column, about six
   characters a line.

   calc(intercept + slope) restores a real slope through the phone range. Each
   line is fitted through two points:

     390px viewport  ->  the mobile size chosen for a 342px content column
     the SAME width at which the old rule reached its ceiling  ->  that ceiling

   So desktop is unchanged, pixel for pixel, and so is the width where each
   heading stops growing. Only the small end moved. Floors are the value the
   line reaches at 320px, so the clamp binds below the narrowest real phone and
   the type stays fluid from 320px up rather than stepping.

   The mobile ramp at 390px, and what uses it:

     36px  primary hero      sparko-hero, collection-hero, page-hero, page-banner
     32px  secondary hero    page-hero--split, page-hero--compact, article
     30px  product title     pdp-buy
     28px  section title     sparko-section-title (shared, most sections)
     26px  sub-heading       honey, pdp-brand, blog-featured, checklist, occ

   Sized for uppercase Filson Pro 900 on a 342px column, which is a 390px
   viewport less two 24px gutters. Body-scale clamps (floors under 28px) were
   already landing at 16-19px on a phone and were left alone.

   The hero carries TWO font-size lines, a vw one then a cqi one. The cqi line
   is the one that renders; the vw line is the fallback for engines without
   container query units. Its slope is fitted against the CONTAINER width
   (viewport less the gutters), not the viewport, so the two numbers differ on
   purpose. See the note at .sparko-hero__title.

   Changing a mobile size means refitting that line, not just editing the floor:
   edit the floor alone and the slope no longer meets it, which puts a step in
   the ramp at 320px. */

/* Text selection highlight, Electric Pink site-wide.
   Overrides Switch's own ::selection (snippets/css-bridge.liquid:135), which
   resolves to the current scheme's accent_1. On the homepage that is scheme1's
   #5aff24, hence the green.

   The `html` prefix is load-bearing. This file is a <link> at head index 4,
   while css-bridge renders an inline <style> at index 7, so a bare ::selection
   here loses on document order despite equal specificity. Verified by selecting
   text and looking, not assumed. `html ::selection` scores one higher and wins
   regardless of order, which beats reaching for !important.

   Not a stock-section override: ::selection is a global pseudo element, not
   markup we do not control.
   White on Electric Pink measures 4.63:1, clear of the 4.5:1 threshold. */
html ::selection {
  background-color: var(--sparko-select-bg);
  color: var(--sparko-select-fg);
}


.sparko-wrap {
  max-width: var(--sparko-container);
  margin: 0 auto;
  padding-inline: var(--sparko-gutter);
}
/* The reference narrows its gutter on small screens rather than keeping 48px,
   which would eat a third of a 390px viewport. Same breakpoint.

   20px, not the reference's 1.5rem, because the LIVE theme uses 20px and this
   is the number a shopper compares against. Measured at 390 on the live PDP,
   45 content blocks sit at a 20px left edge; ours sat at 24. The visible
   symptom was the PDP's hero image, which is the gutter twice over: 390 - 48
   gave a 342px frame against live's 350. It is a 4px change to one token and
   every mobile surface follows it, which is the point. */
@media (max-width: 980px) {
  :root { --sparko-gutter: 20px; }
}

.sparko-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: 1rem;
  text-transform: uppercase;
  /* -0.8px at 16px, which is what the live theme's .push-btn__surface sets.
     Ours was +0.04em, so every label was 1.44px per character looser than the
     site it replaces; on a long CTA that is most of the width difference. */
  letter-spacing: -0.05em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  /* Geometry copied from the live theme's .push-btn__surface, measured at 390:
     46px tall, 16px of side padding, a full pill radius and a 2px navy ring.

     min-height rather than vertical padding, because the ring differs. Shapes
     draws its 2px as an INSET box-shadow, which paints inside the box and adds
     nothing to it; ours is a real border, which does. Matching their padding
     would therefore have made ours 4px taller than theirs. A min-height with
     border-box pins the outside of the pill at 46 whichever way the ring is
     drawn, and inline-flex centring keeps the label centred inside it.

     The ring stays a border rather than becoming an inset shadow: the component
     conventions call for a 2px Night Sky Blue border and no shadow, and this
     reproduces their geometry without adopting their mechanism.

     Side padding was 2rem, double the live theme's 1rem. That is the "sides"
     part of the report; it made every button wider than its Shapes counterpart
     for the same label. */
  box-sizing: border-box;
  min-height: 46px;
  padding: 0 1rem;
  border-radius: 999px;
  border: 2px solid var(--sparko-navy);
  transition: background-color 0.15s ease;
}
.sparko-btn--pink { background: var(--sparko-pink); color: #ffffff; }
.sparko-btn--pink:hover { background: var(--sparko-pink-hover); }
.sparko-btn--gold { background: var(--sparko-gold); color: var(--sparko-navy); }
.sparko-btn--gold:hover { background: var(--sparko-gold-hover); }
.sparko-btn--navy { background: var(--sparko-navy); color: #ffffff; }
.sparko-btn--navy:hover { background: var(--sparko-navy-hover); }
/* The small variant keeps its own proportions, and needs its own min-height
   or the base 46px would flatten the difference between them. */
.sparko-btn--sm { min-height: 38px; padding: 0 0.875rem; font-size: 0.85rem; }
/* The quiet sibling: white fill, navy label, same pill and same 2px navy border
   as every other button. For a second action standing next to a pink primary,
   so the pair does not read as two primaries competing. */
.sparko-btn--outline { background: #ffffff; color: var(--sparko-navy); }
.sparko-btn--outline:hover { background: rgba(38, 38, 102, 0.06); color: var(--sparko-navy); }

/* Single guard: nothing in the Sparko system carries a hard offset shadow.
   Buttons keep the pill + 2px Night Sky Blue border; form controls keep their
   border. The !important here means no individual button or form element can
   reintroduce a shadow. Supersedes the brand guidelines' hard-shadow treatment.
   (The Qstomizer inset box-shadow that renders that button's border is a border,
   not an offset shadow, so it is intentionally not matched here.) */
.sparko-btn,
.sparko-card__cta,
.sparko-honey__badge,
.sparko-best__arrow,
.sparko-email__input {
  box-shadow: none !important;
}

/* ============================================================================
   HOMEPAGE — Hero (section: sparko-hero)
   ============================================================================ */
.sparko-hero {
  position: relative;
  /* The header art is a gradient, not a photograph (2026-08-08, client's
     direction). It replaces the illustrated hero rather than sitting over it:
     there is no scrim and no fade anywhere in this section.

     Night Sky Blue throughout, deepened at the top left and lifted at the bottom
     right. Electric Pink is reserved for three uses and a decorative background
     is not one of them, and California Gold would drop the white copy under the
     contrast threshold, so the ramp stays inside the one brand colour that can
     carry white type at every stop.

     Worst case is the lightest stop, #3A3A8F, which is 8.9:1 against white. The
     photo it replaces measured 1.05:1 behind the headline.

     A photo can still be uploaded; the art layer renders over this when one is
     set, and the gradient becomes the fallback again if it is removed. */
  background: linear-gradient(155deg, #1A1A45 0%, var(--sparko-navy) 52%, #3A3A8F 100%);
  color: #ffffff;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  /* Height follows live's, and live changes SHAPE at 1024 rather than scaling one
     band. Below that it stacks a 2:3 portrait image over a copy block, so its
     height is the image plus that block: measured 755 at 320, 831 at 390, 1064
     at 560, 1454 at 768. From 1024 up it is a single full-bleed 16:9 image, a
     constant 0.5625 of the viewport: 574 at 1024, 717 at 1280, 807 at 1440, 942
     at 1680.

     THREE terms, each fixing something different. Take any one out and a real
     case breaks.

       150vw            live's IMAGE ratio, which is what a phone should match.
                        Live's copy sits in a block BELOW its picture while ours
                        sits inside the gradient, so the section ends where
                        live's picture ends: 480 at 320, 585 at 390.

       100svh - 4rem    never taller than the screen. Without it the copy is
                        pinned to the bottom of a band 1.5x the viewport WIDTH,
                        so on a 930px-wide window the hero was 1395px tall with
                        the headline at y=1232 and the whole screen was bare
                        gradient. svh rather than vh so a phone's collapsing
                        toolbar does not change it mid-scroll.

       44rem            never taller than a sensible band once past phone
                        widths. This is what stops the step at the breakpoint
                        being a cliff.

     This deliberately stops matching live above about 470px, where the 44rem
     cap takes over from 150vw. Live keeps growing because it has a picture
     filling the space; we would just be adding empty gradient. */
  min-height: min(150vw, 100svh - 4rem, 44rem);
}
@media (min-width: 750px) {
  /* 750, not live's 1024. Live stacks a portrait image until 1024 and can
     afford to, because the image fills it. Ours has nothing in that space, so
     the phone ratio applied at tablet widths produced a 1534px hero at 1023px
     and a 512px one at 1024px: a 1022px swing across one pixel of width. Moving
     the band down to 750 removes it.

     50vw is a clean 2:1, slightly shorter than live's 16:9 at the client's
     direction: 720 at 1440 against live's 807. The 32rem floor stops it
     collapsing to 375px at the breakpoint itself.

     Uncapped at the top, so a wide monitor grows it rather than stranding the
     copy at the bottom of a fixed band. */
  .sparko-hero { min-height: max(50vw, 32rem); }
}
.sparko-hero__art { position: absolute; inset: 0; z-index: 0; }
/* <picture> is inline by default, so the img's height: 100% would resolve
   against an auto-height box and collapse the cover crop. */
.sparko-hero__art picture { display: block; width: 100%; height: 100%; }
.sparko-hero__img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Declares a containment context so the headline below can size in cqi. Only
   container-type is needed; there are no @container rules. Safe here because
   nothing inside this wrapper is absolutely positioned (the hero's art layer
   and shade are siblings, not descendants). */
.sparko-hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-block: 7rem 4.5rem;
  container-type: inline-size;
}
.sparko-hero__title {
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  /* Sized against its own column rather than the viewport, so it stops growing
     once the container caps at --sparko-container instead of tracking a 2560px
     monitor. The vw line is the fallback for engines without container query
     units.

     This deliberately undercuts the design reference. .sp-hero-h1 in
     hifi/hifi-styles.css is clamp(56px, 7vw, 112px), and this used to mirror
     that ceiling at 7rem, which rendered 85.7px and broke the headline over
     three lines. Shrunk twice on direction from newer Claude Design passes, so
     the banner reads as a story rather than a wall of type: first to a 4rem
     ceiling (63.6px), then to 3.25rem (52px). The headline still sets on two
     lines; measured, the two-to-three line break sits between 68px and 72px at
     the 960px title column, so there is plenty of headroom. Revisit together
     with the reference if that file is updated.

     Alignment is left ON DESKTOP and centred on phones (2026-09-09, at the
     client's direction). The H1 still opts out of the shared centring rule by
     not using .sparko-section-title, so there is no text-align at this rule; the
     phone centring is an explicit override in the max-width: 749px block. Do not
     add a text-align here, which would centre the desktop hero too. */
  font-size: clamp(2.1876rem, calc(1.9023rem + 1.43vw), 3.25rem);
  font-size: clamp(2.1706rem, calc(1.862rem + 1.82cqi), 3.25rem);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: #ffffff;
  margin: 0 0 1.25rem;
  max-width: 60rem;
}
.sparko-hero__title strong { color: var(--sparko-gold); font-weight: inherit; }
.sparko-hero__title em { color: var(--sparko-pink); font-style: normal; }
.sparko-hero__sub {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.6vw, 1.4rem);
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.92);
  margin: 0 0 1.5rem;
  max-width: var(--sparko-measure);
}
.sparko-hero__trust {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: 0.95rem;
  color: rgba(255, 255, 255, 0.8);
  margin: 0 0 1.5rem;
}
.sparko-hero__ctas { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }

@media (max-width: 749px) {
  /* Mobile hero proportions, matched to the Shapes 3.0 homepage (2026-09-05).
     Measured on the live site, not read off a screenshot: its artwork container
     is exactly 2:3 at every width, 360x540, 390x585, 430x645, 749x1124. It is a
     RATIO, not a fixed height, which is why the 32rem this replaces could not
     match it. A flat 512px was 0.762 at 390px and drifted further everywhere
     else.

     The hero is full-bleed here, so width is the viewport and 2:3 means a
     height of 1.5x it. The `min()` holds that ratio up to the point where it
     reaches 40rem and then stops: 640 / 1.5 = 426.67px. Below the cap the
     proportions are v3's to the pixel, which covers the whole portrait-phone
     range; above it the hero would only get taller than the screen it is on,
     and v3 going to 1124px at 749px is not worth reproducing.

     40rem is the cap because that is what desktop already uses, so the mobile
     band ends on exactly the height the desktop rule begins with and there is
     no step at the 749/750 boundary.

     `min-height` rather than `aspect-ratio` on purpose. This is a flex
     container, and a flex container takes no automatic minimum from its
     contents, so `aspect-ratio` would let a long headline overflow at a narrow
     width instead of growing the box. `min-height` reserves the box and still
     yields when the copy needs more room.

     The artwork is still pending. `.sparko-hero__art` is inset:0 with
     object-fit: cover, so whatever is uploaded fills this box and lands in the
     v3 proportions; until then the reserved space carries the gradient.

     Mobile only, across the range this breakpoint already covered. Desktop
     keeps its own 40rem and is untouched. */
  /* Hero height now lives on the base rule and a min-width: 1024px override,
     which is where live's own breakpoint is. Nothing needed here. */
  .sparko-hero__inner { padding-block: 5rem 3rem; }
  /* Centred on phones only (2026-09-09, at the client's direction). This
     REVERSES the note at .sparko-hero__title, which said the hero H1 opts out of
     the shared centring rule and not to add a text-align; that note is updated
     rather than left contradicting this. Desktop keeps the left alignment the
     note was written about, so the reversal is scoped to this breakpoint.

     The sub also drops its measure cap here. Capped and centred, a paragraph
     narrower than its column reads as an indented block rather than a centred
     one, which is the same thing the split page hero needed. */
  .sparko-hero__title,
  .sparko-hero__sub { text-align: center; }
  .sparko-hero__sub { max-width: none; margin-inline: auto; }
  .sparko-hero__ctas { flex-direction: column; align-items: stretch; }
  .sparko-hero__ctas .sparko-btn { width: 100%; }
}

/* ============================================================================
   HOMEPAGE — Hero circle (section: sparko-hero-circle)
   Port of the Claude Design "cutout" hero (hifi/hero-cutout.css, lollipop
   shape). Sizes, spacing and the circle's geometry are the design's; fonts are
   mapped to the theme's own: the design's display face (Big Shoulders, a stand-in
   for Amplitude Condensed) is Filson Pro 900 here, its body face is Ingra, and
   its UI face was already Filson Pro.

   Container: the design's .sp-wrap is 1320px / 48px. This keeps the theme's
   shell and gutter (see Layout container in CLAUDE.md) and caps the module at
   the design's 1224px content width instead, so it lines up with every other
   section on the page.

   The circle's pink offset shadow and the pink arc text are APPROVED exceptions
   to the no-offset-shadow rule and the Electric Pink reservation (client,
   2026-10-11; recorded in CLAUDE.md, Component conventions). Do not revert.
   The pills keep the no-shadow rule.
   ============================================================================ */
.sparko-hc {
  position: relative;
  overflow: hidden;
  background: var(--sparko-navy);
  color: #ffffff;
}
.sparko-hc__bg { position: absolute; inset: 0; z-index: 0; }
.sparko-hc__bg picture { display: block; width: 100%; height: 100%; }
.sparko-hc__bg-img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 750px) {
  .sparko-hc__bg-img--mobile-only { display: none; }
}
.sparko-hc__inner {
  position: relative;
  z-index: 2;
  box-sizing: border-box;
  max-width: calc(1224px + 2 * var(--sparko-gutter));
  margin-inline: auto;
  padding-inline: var(--sparko-gutter);
  display: grid;
  /* The design's right column is a flat 530px. Filson is much wider than the
     design's condensed face, so the column also gives way to 44% of the row,
     which keeps both pills side by side down to the 981px stacking point. At
     1440 the 44% is 538px, so the circle is the design's 530 there. */
  grid-template-columns: minmax(0, 1fr) minmax(0, min(530px, 44%));
  gap: 48px;
  align-items: center;
  min-height: 680px;
}
.sparko-hc__copy { align-self: center; position: relative; z-index: 2; min-width: 0; }
.sparko-hc__title {
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  text-transform: uppercase;
  font-size: clamp(56px, 7.4vw, 116px);
  line-height: 0.9;
  letter-spacing: -0.01em;
  color: var(--sparko-hc-heading, #ffffff);
  margin: 0 0 24px;
  text-wrap: balance;
}
.sparko-hc__title-line { display: block; }
.sparko-hc__title strong { color: var(--sparko-hc-accent, var(--sparko-gold)); font-weight: inherit; }
.sparko-hc__title em { font-style: normal; }
.sparko-hc__sub {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 500;
  font-size: clamp(18px, 1.4vw, 22px);
  line-height: 1.35;
  max-width: 460px;
  margin: 0;
  color: var(--sparko-hc-sub, #ffffff);
  text-wrap: pretty;
}
.sparko-hc__ctas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  max-width: 500px;
  margin-top: 32px;
}
.sparko-hc__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  height: 56px;
  padding: 0 24px;
  /* The theme's standard 2px Night Sky ring (CLAUDE.md, Component
     conventions). With border-box and a fixed height the ring sits inside the
     pill's box, so the pill's OUTER edge is the column edge and lines up with
     the subheading's left edge. */
  border: 2px solid var(--sparko-navy);
  border-radius: 999px;
  font-family: var(--heading-font-stack, sans-serif);
  /* 900, the weight of every other button on the site (.sparko-btn and the
     card CTAs; client, 2026-10-12). The design's 700 read lighter. */
  font-weight: 900;
  font-size: 17px;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: none;
  transition: background-color 0.15s ease;
}
.sparko-hc__cta--pink { background: var(--sparko-pink); color: #ffffff; }
.sparko-hc__cta--gold { background: var(--sparko-gold); color: var(--sparko-navy); }
@media (hover: hover) {
  .sparko-hc__cta--pink:hover { background: var(--sparko-pink-hover); color: #ffffff; }
  .sparko-hc__cta--gold:hover { background: var(--sparko-gold-hover); color: var(--sparko-navy); }
}

/* The circle. Every measurement inside it is in the SVGs' 100x100 viewBox, so
   it scales with the circle: rim r=48, arc r=39.5, shadow offset (2.2, 2.6). */
.sparko-hc__col {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-block: 48px;
  min-width: 0;
}
.sparko-hc__shape { position: relative; width: 100%; aspect-ratio: 1 / 1; z-index: 2; }
.sparko-hc__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sparko-hc__shadow,
.sparko-hc__rim {
  stroke: var(--sparko-navy);
  stroke-width: 3px;
  vector-effect: non-scaling-stroke;
}
.sparko-hc__shadow { fill: var(--sparko-pink); }
.sparko-hc__rim { fill: none; }
/* Rim and the shadow's navy outline: 3px on desktop, 2px on phones
   (client, 2026-10-12). The shadow's offset and fill are unchanged. */
@media (max-width: 749px) {
  .sparko-hc__shadow,
  .sparko-hc__rim { stroke-width: 2px; }
}
.sparko-hc__float { position: absolute; inset: 0; z-index: 1; transform-origin: 50% 50%; }
.sparko-hc__photo {
  position: absolute;
  inset: 0;
  z-index: 1;
  clip-path: circle(48% at 50% 50%);
  background: var(--sparko-cream);
  overflow: hidden;
}
.sparko-hc__photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-hc__svg--top { z-index: 3; pointer-events: none; }
/* The rim and arc paint above the photo at every width: both layers are
   z-indexed inside .sparko-hc__float, whose transform makes it the stacking
   context, so nothing outside it can slot between them. */
.sparko-hc__arc {
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: 4.2px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  fill: var(--sparko-pink);
}
.sparko-hc__arc--glow {
  fill: var(--sparko-cream);
  stroke: var(--sparko-cream);
  stroke-width: 1.3px;
  stroke-linejoin: round;
  opacity: 0.6;
}

/* Float: transform only, on the photo + rim + arc layer. The shadow sits
   outside it and stays still. 5px rise + 102% on desktop. Single column
   (979px and below) is scale-only from the rim's top: 102% to 749px, the
   design's gentler 101.2% on phones. */
.sparko-hc--float .sparko-hc__float {
  animation: sparko-hc-float 6s ease-in-out infinite;
  will-change: transform;
}
@keyframes sparko-hc-float {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(var(--sparko-hc-float-y, -5px)) scale(var(--sparko-hc-float-s, 1.02)); }
}
@media (prefers-reduced-motion: reduce) {
  .sparko-hc--float .sparko-hc__float { animation: none; }
}

/* Single column (979px and below): the phone arrangement at every width, per
   the client (2026-10-11), not the desktop order stacked. Centred headline on
   one line, sized by the section's script to 92% of the content width (max
   84px); then the circle, capped at 480px and overlapping the bottom of the
   headline; then both pills side by side at the circle's width. No
   subheading. The design stacked at 860; this stacks below 980, the
   theme's own gutter breakpoint, because Filson's wider headline needs the
   room before the design's condensed face did. */
@media (max-width: 979px) {
  .sparko-hc__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    min-height: 0;
    padding-block: 32px 48px;
    text-align: center;
  }
  .sparko-hc__copy { display: contents; }
  /* Pulls the circle's rim about 7.5% of the cap height up into the letters
     at rest, so it just meets the bottom of them, circle in front (client,
     2026-10-12; was 17%). Measured in Filson Pro 900: the line box ends
     0.12em below the baseline and the rim sits 2% of the circle's width
     inside its box, so the pull is those two plus the overlap (0.05em).
     min(2%, 9.6px) is that 2% of the circle, the column capped at 480px.
     The single-column float scales from the rim's top, so this holds through
     the whole animation. */
  .sparko-hc__title {
    order: 1;
    position: relative;
    z-index: 1;
    font-size: 40px;
    margin: 0 0 calc(-0.175em - min(2%, 9.6px));
    white-space: nowrap;
  }
  .sparko-hc__title-line { display: inline-block; white-space: nowrap; }
  /* Desktop side-by-side only (client, 2026-10-11): hidden at every
     single-column width so the circle can overlap the headline. */
  .sparko-hc__sub { display: none; }
  .sparko-hc__col { order: 3; padding: 0; position: relative; z-index: 2; }
  .sparko-hc__shape { width: min(100%, 480px); }
  /* Scale only, no rise, and scaled from the rim's top point (2% down the
     box), so the circle grows down and outward and its top never moves: the
     headline overlap holds at its rest value through the whole loop
     (client, 2026-10-12). Desktop keeps rise + scale from the centre. */
  .sparko-hc__float { --sparko-hc-float-y: 0px; transform-origin: 50% 2%; }
  .sparko-hc__ctas {
    order: 4;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px;
    width: min(100%, 480px);
    max-width: none;
    margin: 16px auto 0;
  }
}

/* Phone: 24px side margins, the design's gentler float, 52px pills and 2px
   circle lines (set beside the rim rule above). */
@media (max-width: 749px) {
  .sparko-hc__inner { padding: 24px 24px 48px; }
  .sparko-hc__float { --sparko-hc-float-s: 1.012; }
  /* The button row spans the full width at 16px side margins (the +16px
     reaches 8px past each side of the 24px content padding), capped at the
     circle's 480px and centred, so from about 530px up it lines up with the
     circle (client, 2026-10-12). Two equal pills with a 10px gap. */
  .sparko-hc__ctas {
    width: min(100% + 16px, 480px);
    /* Centred by an explicit offset, half the difference: auto margins stop
       centring once the row is wider than its column, which it is (by 16px)
       below the cap. */
    margin: 16px 0 0 calc((100% - min(100% + 16px, 480px)) / 2);
    justify-self: start;
    gap: 10px;
  }
  .sparko-hc__cta {
    height: 52px;
    padding: 0 4px;
    /* 14px on both pills (900 comes from the base rule). Tracking stays
       normal: .sparko-btn's -0.05em ran SHOP and COLLECTION together at
       this size. */
    font-size: 14px;
    letter-spacing: 0;
    min-width: 0;
  }
}
/* Narrow phones: -0.03em (under half a pixel a letter) keeps SHOP COLLECTION
   at least 16px from the pill's outer edge at 360. Both pills. */
@media (max-width: 389px) {
  .sparko-hc__cta { letter-spacing: -0.03em; }
}

/* ----------------------------------------------------------------------------
   Hero effects: snow (snippet: sparko-hero-fx-snow)
   Shared layer contract for every hero effect: .sparko-fx fills the section
   behind the content (z-index 1, under .sparko-hc__inner at 2), takes no
   clicks and no space. A new preset adds its own block below this one.
   ---------------------------------------------------------------------------- */
.sparko-fx { position: absolute; inset: 0; z-index: 1; overflow: hidden; pointer-events: none; }
.sparko-fx-snow i {
  position: absolute;
  top: 0;
  left: var(--x);
  width: var(--s);
  height: 100%;
  transform: translate3d(0, -10px, 0);
  animation: sparko-snow-fall var(--d) linear var(--dl) infinite;
}
.sparko-fx-snow i::before {
  content: "";
  position: absolute;
  top: calc(var(--s) * -1);
  left: 0;
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  background: #ffffff;
  opacity: var(--o);
  filter: blur(0.5px);
  animation: sparko-snow-sway 4s ease-in-out var(--dl) infinite alternate;
}
@keyframes sparko-snow-fall {
  from { transform: translate3d(0, -10px, 0); }
  to { transform: translate3d(var(--dx), 100%, 0); }
}
@keyframes sparko-snow-sway {
  from { transform: translateX(-4px); }
  to { transform: translateX(4px); }
}
@media (max-width: 749px) {
  .sparko-fx-snow i:nth-child(even) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sparko-fx-snow i { animation: none; transform: translate3d(0, var(--y), 0); }
  .sparko-fx-snow i::before { animation: none; }
}

/* ============================================================================
   HOMEPAGE — Credibility marquee (section: sparko-credibility)
   ============================================================================ */
/* Asymmetric on purpose: the label needs less room above it than the strip
   needs below, and the cream section that follows supplies its own top padding,
   so the two read as one gap. */
/* Symmetric again now the label is gone, so the logo row sits centred in the band. */
.sparko-cred { background: var(--sparko-cream); padding-block: 2.5rem; overflow: hidden; }
/* A strip that carries a lead already has that label's own line and its 0.75rem
   of space doing the work the top padding does on a strip without one, so the
   top padding halves. Scoped with :has() rather than to the B2B pages, because
   the condition really is "does this strip have a label", and the homepage strip
   has none and is deliberately unchanged at 2.5rem.

   This is the last of three cuts to the cream between the hero's CTA and the
   logos, which measured 126px against the live theme's 48. The hero's bottom
   padding went 56 to 32, the button lost 5px of its own height, and this takes
   the remaining 16. It does not reach 48 and cannot: the live strip has no label
   in that position, so ~30px of the difference is an element live does not
   render. */
.sparko-cred:has(.sparko-cred__lead) { padding-top: 1.5rem; }
/* The row stacks at every width: the lead sits ABOVE the logos, centred, and the
   marquee runs the full viewport below it (2026-09-08, at the client's
   direction). It used to be a flex row with the lead as a side label at the
   container's content edge and the track running off the right viewport edge,
   which is why the label was left-aligned; it now labels the row from above
   rather than beside it.

   The track stays edge to edge either way, so logos still enter and exit at the
   viewport bounds rather than from under a static element. */
.sparko-cred__row { display: block; }
/* Champagne band, the B2B client-proof strip. These pages open on a cream hero
   and the strip has to read as proof rather than as more of the hero, so the
   comps tint it. Navy type either way, so nothing else changes. */
.sparko-cred--champagne { background: color-mix(in srgb, var(--sparko-gold) 22%, var(--sparko-cream)); }
/* The lead is deliberately quieter than the names it introduces: eyebrow size,
   muted, letterspaced. It labels the row, it is not part of the roster.

   Centred on its own line above the logos, at every width. It no longer uses
   --sparko-bleed-pad: that token exists to line a full-bleed row's first item up
   with the container's content edge, which was the right answer while this was a
   side label and is the wrong one for a centred heading. */
.sparko-cred__lead {
  display: block;
  padding: 0 var(--sparko-gutter) 0.75rem;
  text-align: center;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700;
  font-size: 0.8rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--sparko-navy);
}
/* The scroll itself is Switch's <scrolling-items> component, including its
   pause-on-hover and reduced-motion handling. All we own here is the row's
   layout and spacing. */
.sparko-cred__marquee { flex: 1 1 auto; min-width: 0; overflow: hidden; }
.sparko-cred__track {
  display: flex;
  align-items: center;
  width: max-content;
  gap: 3rem;
  padding-inline-end: 3rem;
}
.sparko-cred__item { flex: 0 0 auto; display: inline-flex; align-items: center; }
.sparko-cred__name {
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: 1.2rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sparko-navy);
  white-space: nowrap;
}
/* Single-colour logos. The asset supplies only its alpha channel as a mask; the
   visible colour is this background, so full-colour, black and white sources all
   render as Night Sky Blue and the row reads as one row. Width comes from the
   inline aspect-ratio, so each logo keeps its own proportions at a shared height.
   Requires an asset with real transparency; a flattened JPEG would mask to a
   solid block. */
.sparko-cred__logo {
  /* 1.75rem is the shared baseline; --sparko-cred-scale is the per-logo optical
     correction the section sets from each block. Drawing every mark to one
     height is what makes the correction necessary: it equalises the BOX, not
     the letterforms, and a wordmark's cap height, ascenders and width all vary.
     Measured at 28px, "Google" puts only 13px of letterform in the box where
     DIOR puts 22. */
  height: calc(1.75rem * var(--sparko-cred-scale, 1));
  display: block;
  background-color: var(--sparko-navy);
  -webkit-mask-image: var(--sparko-cred-logo);
          mask-image: var(--sparko-cred-logo);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
}
/* A client whose project has an Our Work page renders its mark as a link. The
   mark itself is unchanged, so a linked logo and an unlinked one (Google and
   AbbVie, which have no project page) sit at the same weight in the row; only
   the pointer and the hover tell them apart. No underline, per the rule against
   underlined text links in Component conventions. */
.sparko-cred__item--link { color: inherit; text-decoration: none; cursor: pointer; }
/* The mask's background-color is the logo's visible colour, so the hover fades
   the mark rather than its box. The name variant has no mask and fades itself.
   Hovering also pauses the marquee (Switch's own
   motion-safe:hover:[animation-play-state:paused]), which is what makes a moving
   logo clickable at all: the row stops before the cursor reaches the mark. */
.sparko-cred__item--link .sparko-cred__logo { transition: opacity 0.2s ease; }
.sparko-cred__item--link.sparko-cred__name { transition: opacity 0.2s ease; }
.sparko-cred__item--link:hover .sparko-cred__logo,
.sparko-cred__item--link:hover.sparko-cred__name { opacity: 0.6; }
@media (prefers-reduced-motion: reduce) {
  .sparko-cred__item--link .sparko-cred__logo,
  .sparko-cred__item--link.sparko-cred__name { transition: none; }
}
/* The roster below is where those same links are reachable by keyboard, and it is
   visually hidden, so a sighted keyboard user would otherwise Tab into nothing.
   On :focus-within it drops the clip and TAKES THE MARQUEE'S PLACE: the scrolling
   logos go out of flow and the names lay out where they were, centred, under the
   lead if the strip has one.

   Swapping one for the other is what keeps this width-proof. Tucking the names
   under the logos instead fitted on a desktop and wrapped to two lines at 390px,
   where the band's bottom padding is 40px and `overflow: hidden` clipped the
   second line; overlaying them needed the lead's rendered height as a magic
   number. This needs neither, because the flow does the arithmetic.

   The band does change height while focus is inside it, because a text row is not
   a logo row: measured at -4.7px at 1440, where the names fit one line, and
   +18.8px at 390, where they wrap to two. It happens only while a keyboard user is
   tabbing through the strip, it restores exactly on blur, and it is the cost of
   not clipping the reveal on a phone.

   Scoped to this list rather than to .sparko-visually-hidden, which is a shared
   utility used by the header and the collection grid. Two classes beat the
   one-class utility on specificity, so no !important. */
.sparko-cred:has(.sparko-cred__roster:focus-within) .sparko-cred__marquee { display: none; }
.sparko-cred__roster:focus-within {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.35rem 1.25rem;
  padding: 0.45rem var(--sparko-gutter);
  list-style: none;
}
/* The type treatment goes on the list item, not on the link, or the two clients
   with no project page would sit in the revealed row at body size and mixed case
   beside four uppercase links. Same weight for all six, exactly as in the strip
   above: whether a client has a page is not a difference worth drawing here. */
.sparko-cred__roster:focus-within li {
  font-family: var(--main-font-stack, sans-serif);
  font-size: 0.8rem;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sparko-navy);
}
.sparko-cred__roster-link { color: inherit; text-decoration: none; }
.sparko-cred__roster-link:hover { opacity: 0.6; }
.sparko-cred__roster-link:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 3px; border-radius: 2px; }
/* Visually hidden but announced. Carries the client roster once, since the
   marquee is aria-hidden (its content is cloned to fill the width). */
.sparko-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   HOMEPAGE — shared section title + Intent Router + cards
   ============================================================================ */
/* Shared heading for every full-width homepage section. */
.sparko-section-title {
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: clamp(1.6346rem, calc(1.1071rem + 2.64vw), 3.25rem);
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  /* Navy by default. Sections with a dark background set the variable instead
     of overriding this rule, so the heading stays legible on any band. */
  color: var(--sparko-section-title-color, var(--sparko-navy));
  margin: 0 0 var(--sparko-heading-gap);
}

/* ----------------------------------------------------------------------------
   SHARED SECTION HEADING ALIGNMENT — the one rule to point new sections at.

   Full-width section headings and their supporting lines are centered. A new
   full-width section inherits this simply by using these three classes; it
   needs no alignment rule of its own:

     .sparko-section-eyebrow   small label above the heading
     .sparko-section-title     the section heading
     .sparko-section-sub       the supporting line under it

   margin-inline is centered too, so a supporting line capped at --sparko-measure
   centers on the container rather than hugging the left edge.

   Headlines anchored inside a composition deliberately do NOT use these classes
   and keep their own alignment: the hero H1 (.sparko-hero__title), the honey
   band (.sparko-honey__heading), the occasions tile (.sparko-occ__heading) and
   the email row (.sparko-email__h). Opting out is just not using the class.
   ---------------------------------------------------------------------------- */
.sparko-section-eyebrow,
.sparko-section-title,
.sparko-section-sub {
  text-align: center;
  margin-inline: auto;
}

/* ----------------------------------------------------------------------------
   EYEBROWS ARE OFF THEME-WIDE. Every section keeps its eyebrow setting and its
   markup; this one rule hides all of them, so the decision lives in one place
   instead of being an empty string repeated across every template.

   Consequence worth knowing: typing an eyebrow in the theme editor will appear
   to do nothing while this rule stands. To bring eyebrows back, delete this
   rule — do not fight it with an inline style or an !important in a section.
   ---------------------------------------------------------------------------- */
.sparko-section-eyebrow:not(.sparko-section-eyebrow--on),
/* The cross-sell card's kicker is an eyebrow by another name, so it follows the
   same rule. Kept in this one place so "eyebrows are off" means all of them and
   a future section cannot reintroduce one under a new class by accident. */
.sparko-pdp-cross__kicker { display: none; }

/* The one documented opt-out, added 2026-08-06 at the user's direction: a
   section may show a single eyebrow by adding --on to the class. Amending the
   rule here rather than overriding it from a section, which is what the note
   above asks for. Two sections opt in: sparko-pdp-honey-buy, and wholesale-hero
   for the signed-in buyer's company name, which is content rather than decoration.

   Navy, not the eyebrow default: this one sits on cream directly above a navy
   title, and pink there would read as a second accent competing with the pink
   Add to Cart further down the column. */
.sparko-section-eyebrow--on {
  /* The shared alignment rule centres eyebrows with the section headings it sits
     beside. In a left-aligned buy column that read as a stray centred line above
     a left-aligned title, so this one opts out of the centring too. */
  text-align: left;
  margin-inline: 0;
  /* Type treatment, never exercised while every eyebrow was display:none. */
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 700;
  font-size: 0.875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  /* Navy rather than the accent pink: this sits on cream directly above a navy
     title, and pink here would compete with the pink Add to Cart below it. */
  color: var(--sparko-navy);
}

/* ----------------------------------------------------------------------------
   SHARED SECTION RHYTHM — the spacing counterpart to the alignment rule above.

   Values are the process section's, promoted here so the rest of the homepage
   matches it rather than each section picking its own:

     --sparko-section-pad    3.5rem   top and bottom padding
     --sparko-heading-gap    1.5rem   heading down to the supporting line
     --sparko-content-gap    2.5rem   last text element down to the content

   A new full-width section gets the rhythm by adding .sparko-section to its
   root and .sparko-section__content to the block below the heading. The
   heading gap comes from .sparko-section-title's own margin, so it applies
   wherever that class is used.

   Full-bleed bands and internal compositions deliberately opt out by not using
   these classes: the hero sizes itself from min-height with no section padding,
   and honey and occasions run their own internal spacing.
   ---------------------------------------------------------------------------- */
.sparko-section {
  padding-block: var(--sparko-section-pad);
}
.sparko-section__content {
  margin-top: var(--sparko-content-gap);
}

.sparko-router { background: var(--sparko-cream); padding-block: 3.5rem; }
.sparko-router__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }

.sparko-card {
  display: flex;
  flex-direction: column;
  background: #ffffff;
  border: 2px solid var(--sparko-navy);
  border-radius: 1.25rem;
  overflow: hidden;
  text-decoration: none;
  color: var(--sparko-navy);
}
/* Card borders stay 2px Night Sky Blue in every state, including hover.
   Electric Pink is reserved for primary CTAs and the Occasions month scroller,
   and is never a decorative accent on individual cards. */
.sparko-card__img {
  display: block;
  aspect-ratio: 3 / 2;
  background: var(--sparko-cream);
  overflow: hidden;
  border-bottom: 2px solid var(--sparko-navy);
}
.sparko-card__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Title, subtext and pill all centre in the card (2026-09-08, at the client's
   direction). align-items does the pill and the two text blocks alike, since
   all three are flex children of this column; text-align handles the wrapped
   lines inside a title or subtext that runs to two lines.

   Safe to change on .sparko-card itself rather than scoping to .sparko-router:
   sparko-intent-router is the only section in the theme that renders this card. */
.sparko-card__body { display: flex; flex-direction: column; gap: 0.5rem; padding: 1.5rem; flex: 1 1 auto; align-items: center; text-align: center; }
.sparko-card__title { display: block; font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.4rem; line-height: 1.1; }
.sparko-card__line { display: block; font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1rem; line-height: 1.4; color: rgba(38, 38, 102, 0.72); flex: 1 1 auto; }
.sparko-card__cta {
  margin-top: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--heading-font-stack, sans-serif);
  font-weight: 900;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #ffffff;
  background: var(--sparko-pink);
  border: 2px solid var(--sparko-navy);
  border-radius: 999px;
  padding: 0.6rem 1.1rem;
}
.sparko-card:hover .sparko-card__cta { background: var(--sparko-pink-hover); }
/* Four across only once four across actually fits. Measured on the real cards:
   at 1200px they are 262px wide and every title sets on one line; at 1180 and
   below a title starts wrapping and the descriptions run to three and four
   lines. The old switch at 980px left a 220px band, 981 to 1199, of cramped
   four-up. 1199 is the last width that is not comfortable, so it is the last
   width that gets two columns. Wide desktop is untouched. */
@media (max-width: 1199px) { .sparko-router__grid { grid-template-columns: repeat(2, 1fr); } }
/* Phone: the four route cards stay a 2x2 grid instead of becoming one tall
   column. They are navigation, not merchandising, and a shopper choosing
   between four destinations needs to SEE the four. Stacked full-width they ran
   1526px at 320px and 1691px at 390px, so the fourth card sat two full screens
   below the third.

   Everything else here is what makes two-up fit. A card is about 130px wide at
   320px, so the desktop proportions do not survive the halving: 24px of padding
   would leave 78px of text column, and a 22.4px title in that space sets three
   or four words a line.

   Titles WRAP rather than shrink further or truncate. `overflow-wrap` is for a
   single long word rather than for normal phrases; without it one such word
   would push past the card edge instead of breaking.

   The description keeps a readable 14px. It is the line that tells a shopper
   which of the four they want, so it is the last thing to cut, not the first.

   The CTA pill grows to 44px on a coarse pointer even though the whole card is
   one anchor and is therefore already an enormous target. The pill is the
   visible affordance, and a 41px pill that LOOKS like the button reads as the
   thing to hit. It is in the pointer query so a desktop mouse keeps the tighter
   pill. */
@media (max-width: 560px) {
  .sparko-router__grid { grid-template-columns: repeat(2, 1fr); gap: 0.75rem; }

  /* Square art. A 16:9 strip at this card width was a 71px letterbox that read
     as a header bar rather than a picture; 1:1 gives the image something to be.
     The panel underneath stays a panel: the title and the pill sit BELOW the
     image, never over it. No overlay, no scrim, nothing set on the photo. */
  .sparko-card__img { aspect-ratio: 1 / 1; }

  /* Descriptions go. Two-up at 320px leaves a 102px text column, where the
     description ran four lines and pushed the pill off the first screen. The
     title carries the meaning at this size and the pill carries the action. */
  .sparko-card__line { display: none; }

  .sparko-card__body { padding: 0.75rem; gap: 0.5rem; }
  /* Titles stay FULL and wrap. Truncating the one line that says where the card
     goes would be the wrong economy. */
  .sparko-card__title { font-size: 1.0625rem; overflow-wrap: break-word; }
  .sparko-card__cta {
    font-size: 0.75rem;
    /* 44px on every pointer here, not just coarse. A 560px viewport is a phone
       in all but the rarest case, and the previous pointer-scoped rule left a
       40px pill on the exceptions. `min-height` rather than padding so the
       number is the guarantee rather than the result of one. */
    min-height: 44px;
    padding-block: 0;
    padding-inline: 0.85rem;
    justify-content: center;
    /* The description used to be the flex child that grew, so with it hidden
       the pill needs its own push to keep the row's CTAs on one line. */
    margin-top: auto;
  }
}

/* ============================================================================
   HOMEPAGE — Bestsellers carousel (section: sparko-bestsellers)
   ============================================================================ */
.sparko-best { background: var(--sparko-cream); }
/* The heading block spans the whole row so its centered text centers on the
   container, not on a flex child sitting beside the arrows. The arrows share
   that same grid cell and pin to the right, keeping the carousel affordance
   where it was. */
.sparko-best__head { display: grid; align-items: end; }
.sparko-best__head > :first-child { grid-area: 1 / 1; }
.sparko-best__sub { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1.05rem; color: rgba(38, 38, 102, 0.7); margin: 0.5rem auto 0; max-width: var(--sparko-measure); }
.sparko-best__arrows { grid-area: 1 / 1; justify-self: end; align-self: end; display: flex; gap: 0.75rem; flex: none; }
.sparko-best__arrow {
  width: 3rem; height: 3rem; border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; font-size: 1.1rem;
  background: var(--sparko-pink); color: #ffffff; border: 2px solid var(--sparko-navy); cursor: pointer;
  transition: background-color 0.15s ease;
}
.sparko-best__arrow:hover { background: var(--sparko-pink-hover); }
/* Sized to match the text glyphs these replaced. Color comes from the button's
   own `color` via currentColor in the theme icon, so it needs nothing here. */
.sparko-best__arrow .theme-icon { width: 1.25rem; height: 1.25rem; display: block; }
/* Full bleed: viewport spans the whole section width; the first product lines up
   with the container gutter, later products run past the right viewport edge
   (partial peek). scroll-padding keeps arrow-scroll and snapping aligned. */
.sparko-best__viewport { overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity; scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 0.5rem; padding-inline-start: var(--sparko-bleed-pad); padding-inline-end: var(--sparko-gutter); scroll-padding-inline-start: var(--sparko-bleed-pad); }
.sparko-best__viewport::-webkit-scrollbar { display: none; }
.sparko-best__track { display: flex; gap: 1.5rem; width: max-content; }
.sparko-prod { flex: 0 0 clamp(200px, 22vw, 260px); scroll-snap-align: start; display: flex; flex-direction: column; gap: 0.75rem; text-decoration: none; color: var(--sparko-navy); }
.sparko-prod__img { display: block; aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden; border: 2px solid var(--sparko-navy); background: #ffffff; transition: border-color 0.15s ease; }
.sparko-prod__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-prod:hover .sparko-prod__img { border-color: var(--sparko-pink); }

/* Shaped card frame, used by the collection grids only (the card takes
   `frame_shape` so the bestsellers rail, predictive search and the PDP related
   row keep the plain rounded frame).

   The clip replaces the radius AND the CSS border: a clip cuts a border off, so
   the 2px navy edge is drawn by an SVG outline sitting over the clipped box on
   the same path. Image sizing, typography and spacing are untouched; only the
   corner geometry changes. No shadow is introduced. */
/* Pager under the collection grid. Same spacing the blog gives its own. */
.sparko-collection-grid__pager { margin-top: 2.5rem; }

.sparko-prod__frame { position: relative; display: block; }
.sparko-prod__img--shaped { border: 0; border-radius: 0; }
.sparko-prod__outline {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none;
  fill: none; stroke: var(--sparko-navy); stroke-width: 2px;
  /* `stroke-width` is in USER units, and this SVG maps a 200x200 viewBox onto
     whatever box the card happens to be, so the painted edge scaled with the
     card instead of staying 2px: measured 3.22px on a 322px desktop card,
     1.67px on a 167px phone card, and a sawtooth in between as the grid drops
     from four columns to three to two and the cards get wider again. It was
     never actually 2px. `non-scaling-stroke` paints the declared width
     regardless of the viewBox scale, so every card edge is 2px at every width
     and matches the 2px the rest of the theme uses. Added 2026-09-10. */
  vector-effect: non-scaling-stroke;
}
/* The outline stays Night Sky Blue in every state, hover included (client
   direction, 2026-09-06). The unshaped card still turns its CSS border pink on
   hover; that rule keys off .sparko-prod__img and cannot reach the SVG, so
   nothing here has to undo it. Keyboard focus is handled below and is a ring on
   the card, not a change to this stroke, so focus stays distinguishable from
   hover rather than both being "the frame looks different". */
.sparko-prod__row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; }
.sparko-prod__name { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.05rem; line-height: 1.2; }
.sparko-prod__price { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.95rem; color: rgba(38, 38, 102, 0.7); flex: none; }
/* Narrow: the arrows are hidden outright. The rail is a touch scroller with
   snapping, so a thumb already does everything they do, and on a phone they
   were a second control for a gesture the shopper will use anyway.

   `display: none` and not `visibility: hidden` or an off-screen shift: they
   have to leave the accessibility tree and the tab order, not just the screen.
   A hidden-but-focusable button sends a keyboard user to a control they cannot
   see.

   Nothing reserves space for them once they are gone. `.sparko-best__head` is a
   grid whose only remaining item is the heading block in cell 1/1, so no second
   row is generated and its row-gap never applies. That reclaims 64px: the 48px
   arrow row plus the 16px gap.

   The rail keeps everything: overflow-x, scroll-snap, the inline script's
   initial peek offset, and one focus stop per product card. Keyboard users page
   the rail by tabbing the cards, which the browser scrolls into view; that path
   never went through the arrows.

   Desktop keeps its arrows. */
@media (max-width: 560px) {
  .sparko-best__arrows { display: none; }

  /* Snapping off on touch, and this is the whole reason the rail felt dead.
     Snap points sit one card pitch apart (200px card + 24px gap = 224px) with
     `scroll-snap-align: start`, so a gesture that does not carry past the 112px
     halfway mark gets pulled back to exactly where it started. Not "moves a
     little and settles" — measured at 390px, a 30px, 60px and 100px drag each
     left scrollLeft on 224, unchanged. On a phone where the card is 200px wide,
     that is most of the swipes a thumb actually makes, so the rail read as
     frozen and the products past the second one were unreachable once the
     arrows were hidden.

     `proximity` was already in force; it is not strict enough a word for what
     Chrome does here, which is snap back from 60px away. The same rule is
     harmless on desktop, where the arrows do the paging and nobody drags the
     rail, so snapping stays there and keeps the tidy card alignment.

     Verified with real touch events rather than a CSS check or an assignment to
     scrollLeft: neither of those goes through hit testing or snapping, and both
     passed on a rail a thumb could not move. */
  .sparko-best__viewport { scroll-snap-type: none; }
}

/* ============================================================================
   HOMEPAGE — Case study / custom projects (section: sparko-case-study)
   ============================================================================ */
/* Dark band: the shared section heading would be navy-on-navy, so this section
   sets the variable to California Gold. Scoped here, so the shared rule and
   every other section's heading are untouched. Gold on navy is permitted; the
   contrast rule in CLAUDE.md bars gold text on Warm Cream only. */
.sparko-case { background: var(--sparko-navy); color: #ffffff; --sparko-section-title-color: var(--sparko-gold); }
.sparko-case__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
/* text-align rather than align-items: the children are flex items, so centring
   the ITEMS would shrink each one to its content width and take the image down
   with it. Leaving them stretched and centring the inherited text keeps the
   image full-bleed and centres the name and the line inside it. */
.sparko-case__item { display: flex; flex-direction: column; gap: 0.75rem; text-decoration: none; color: #ffffff; text-align: center; }
.sparko-case__img {
  display: block;
  aspect-ratio: 1 / 1;
  border-radius: 1.25rem;
  overflow: hidden;
  /* California Gold, matching the band's heading and the SEE OUR WORK pill.
     The image frame is the only gold element here; the client name, title and
     caption below it stay white. */
  border: 2px solid var(--sparko-gold);
  background: rgba(255, 255, 255, 0.06);
}
.sparko-case__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-case__client { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.5rem; transition: color 0.15s ease; }
/* Title and caption mirror the occasions value item (.sparko-occ__value-title
   and .sparko-occ__value-line), same font, weight and size. Occasions sits on
   Warm Cream and uses navy ink; this band is navy, so both are white. */
.sparko-case__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; margin: 0; color: #ffffff; }
.sparko-case__line { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1rem; line-height: 1.45; color: #ffffff; margin: 0; }
/* The card heading is .sparko-case__title now that projects lead with a name
   rather than a held client_name, so the hover affordance has to reach it too.
   Both are listed because either field can carry the name. */
a.sparko-case__item:hover .sparko-case__client,
a.sparko-case__item:hover .sparko-case__title { color: var(--sparko-pink); }
.sparko-case__foot { display: flex; justify-content: center; margin-top: 2.5rem; }
@media (max-width: 900px) { .sparko-case__grid { grid-template-columns: 1fr; } }

/* ============================================================================
   HOMEPAGE — Process / How custom works (section: sparko-process)
   ============================================================================ */
/* No text-align declared, matching collections, honey and occasions, which all
   declare none and inherit the default left. The step cards re-center their own
   content below, and the footer CTA centers itself. */
.sparko-process { background: var(--sparko-cream); }
.sparko-process__sub { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1.05rem; color: rgba(38, 38, 102, 0.7); margin: 0.5rem auto 0; max-width: var(--sparko-measure); }
.sparko-process__steps { list-style: none; margin-block-end: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
/* Step card content stays centered; this is deliberate, and no longer inherited
   now that the section itself aligns left. */
.sparko-process__step { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; text-align: center; }
/* The 4:3 illustration fills its grid column, matching .sp-step-media in the
   design reference (hifi-styles.css). No max-width cap: capping it left the
   image centered in a much wider column, which read as the steps being flung
   apart on wide viewports. Equal columns keep the three slots aligned. */
.sparko-process__media { position: relative; width: 100%; margin-bottom: 0.5rem; }
.sparko-process__img { display: block; width: 100%; aspect-ratio: 4 / 3; border-radius: 1.25rem; overflow: hidden; border: 2px solid var(--sparko-navy); background: #ffffff; }
.sparko-process__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-process__num {
  position: absolute; top: -0.75rem; left: -0.75rem;
  width: 2.25rem; height: 2.25rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--sparko-pink); color: #ffffff; border: 2px solid var(--sparko-navy);
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1rem;
}
.sparko-process__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.4rem; margin: 0; color: var(--sparko-navy); }
.sparko-process__line { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.7); margin: 0; max-width: 20rem; }
/* Stays centered, as it was, now that text-align no longer does it. */
.sparko-process__cta { margin: 2.5rem auto 0; display: flex; width: fit-content; }
/* Narrow: the homepage's three steps condense to one row of numbered labels.
   The photos and the descriptions go; the number, the title, the section
   heading, the subtitle and the CTA stay. Stacked full width the section ran
   1356px at 320px and 1465px at 390px for what is a three-word summary of a
   process, and the CTA underneath it is the thing the section is actually for.

   `:has(.sparko-process__media)` isolates the homepage without inventing a
   modifier class. This section is shared with four page templates, and every
   one of them sets `hide_media`, so the homepage is the only instance that
   renders a media span at all. Those four keep the single stacked column they
   have always had, descriptions included, via the `:not()` below. If a page
   ever turns images back on it opts into this treatment, which is the right
   default. In a browser without `:has()` the whole pair is dropped and mobile
   stays as it was, which is a safe way to lose.

   The photo is hidden, NOT the media span. The step number lives inside that
   span and is absolutely positioned over the photo, so hiding the span would
   take the number with it and leave unnumbered steps. Instead the span stops
   being a positioning context and the number becomes the step's own centred
   marker.

   Titles wrap. Three columns at 320px is about 83px each, and "We make it"
   needs two lines there; forcing one line would mean shrinking the type past
   readable or clipping a word. `overflow-wrap` is for safety on a longer label
   a merchant might type, not for these three. */
@media (max-width: 760px) {
  .sparko-process__steps:not(:has(.sparko-process__media)) { grid-template-columns: 1fr; }

  .sparko-process__steps:has(.sparko-process__media) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    /* No gap. The dividers sit ON the column edges and the breathing room comes
       from each step's own padding, which is how the PDP's How to customize
       block does it. A gap would put a channel of empty space either side of
       every rule and read as three separate cards. */
    gap: 0;
    align-items: stretch;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__img { display: none; }

  /* Divider colour and weight lifted verbatim from .sparko-pdp-howto__step, so
     the two "three numbered steps" blocks in the theme match:
     1px solid rgba(38, 38, 102, 0.16). Only BETWEEN the steps, via the adjacent
     sibling, so there is no rule outside the first or last column and nothing
     here draws a card. `align-items: stretch` above is what lets the rules run
     the full height of the row rather than stopping at the shortest step. */
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__step {
    padding-inline: 0.75rem;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__step:first-child {
    padding-inline-start: 0;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__step:last-child {
    padding-inline-end: 0;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__step + .sparko-process__step {
    border-left: 1px solid rgba(38, 38, 102, 0.16);
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__line {
    font-size: 0.8125rem; line-height: 1.35; max-width: none; overflow-wrap: break-word;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__media {
    position: static; width: auto; margin-bottom: 0;
    display: flex; justify-content: center;
  }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__num { position: static; }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__step { gap: 0.35rem; }
  .sparko-process__steps:has(.sparko-process__media) .sparko-process__title {
    font-size: 0.9375rem; line-height: 1.2; overflow-wrap: break-word;
  }
}

/* ============================================================================
   HOMEPAGE — Collections grid (section: sparko-collections)
   ============================================================================ */
.sparko-collections { background: var(--sparko-cream); }
.sparko-collections__grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1.5rem; }
/* Columns follow the tile count, so a row of two, three or four fills the width
   instead of leaving empty cells on the right of a fixed five-column track.
   Five and above keep the default. */
.sparko-collections__grid[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sparko-collections__grid[data-count="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sparko-collections__grid[data-count="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Six tiles are a 3x2 block, not a row of five with one orphan underneath, and
   not a carousel. Columns only: the grid fills the shared page container and
   lines up with every other section on the page, so there is no max-width and
   no margin-inline here. Tiles get whatever width the container gives them. */
.sparko-collections__grid[data-count="6"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* A reserved slot is not clickable, so it must not offer the hover the real
   tiles do. Its label sits at the same weight; the placeholder art is what says
   it is unfilled. */
.sparko-tile--reserved { cursor: default; }
.sparko-tile--reserved:hover .sparko-tile__img { border-color: var(--sparko-navy); }
.sparko-tile { display: flex; flex-direction: column; gap: 0.75rem; text-decoration: none; color: var(--sparko-navy); }
.sparko-tile__img { aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden; border: 2px solid var(--sparko-navy); background: #ffffff; transition: border-color 0.15s ease; }
.sparko-tile__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-tile:hover .sparko-tile__img { border-color: var(--sparko-pink); }
/* Centred under the tile. text-align as well as justify-content, because the row
   centres the name box while text-align centres a name that wraps to two lines
   inside it, and "All Shape Lollipops" already wraps at the narrow breakpoints. */
.sparko-tile__row { display: flex; align-items: center; justify-content: center; gap: 0.5rem; text-align: center; }
.sparko-tile__name { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.05rem; line-height: 1.2; }
@media (max-width: 980px) {
  .sparko-collections__grid { grid-template-columns: repeat(3, 1fr); }
  /* The count rules above outrank a bare class, so each one is restated here or
     a four-tile row would stay four across on a tablet. Four goes to a 2x2 rather
     than three-then-one. */
  .sparko-collections__grid[data-count="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sparko-collections__grid[data-count="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Restated for the same reason as the two above: the base [data-count="6"]
     rule is (0,2,0) and outranks the bare class here regardless of source
     order, so without this line six tiles would keep their desktop track. It
     happens to be the same three columns, and it is written out so that stays
     true if either value is ever changed. */
  .sparko-collections__grid[data-count="6"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .sparko-collections__grid,
  .sparko-collections__grid[data-count="3"],
  .sparko-collections__grid[data-count="4"],
  .sparko-collections__grid[data-count="6"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ============================================================================
   HOMEPAGE — Reviews (section: sparko-reviews). Judge.me widget styling is in
   the parity Judge.me block above; this only styles the section chrome.
   ============================================================================ */
/* No text-align declared, matching every other homepage section. */
.sparko-reviews { background: var(--sparko-cream); }
.sparko-reviews__stars { color: var(--sparko-gold); font-size: 1.6rem; letter-spacing: 0.35rem; line-height: 1; margin-bottom: 0.75rem; text-align: center; }
.sparko-reviews__widget { }

/* ============================================================================
   HOMEPAGE — Honey line (section: sparko-honey)
   ============================================================================ */
.sparko-honey { background: var(--sparko-gold); color: var(--sparko-navy); padding-block: 3.5rem; }
.sparko-honey__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; align-items: center; }
.sparko-honey__img { border-radius: 1.25rem; overflow: hidden; border: 2px solid var(--sparko-navy); }
.sparko-honey__img img { width: 100%; height: 100%; object-fit: cover; display: block; aspect-ratio: 4 / 3; }
.sparko-honey__eyebrow { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.14em; color: var(--sparko-navy); margin: 0 0 0.75rem; }
.sparko-honey__heading { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: clamp(1.5269rem, calc(1.0786rem + 2.24vw), 3rem); line-height: 1; text-transform: uppercase; color: var(--sparko-navy); margin: 0 0 1rem; }
/* Two-color headline: the editor-chosen word goes white against the gold band. */
.sparko-honey__heading-hl { color: #ffffff; }
.sparko-honey__body { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1.1rem; line-height: 1.5; color: var(--sparko-navy); margin: 0 0 1.5rem; max-width: 28rem; }
.sparko-honey__badges { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.sparko-honey__badge {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border: 2px solid var(--sparko-navy); border-radius: 999px; padding: 0.55rem 1.1rem;
  color: var(--sparko-navy); white-space: nowrap;
}
.sparko-honey__cta { margin-top: 1.5rem; }
/* Stacked: the text column centres. Left-aligned copy is right beside a photo
   and wrong beneath one, where there is no column edge for it to hang off and
   the ragged right just reads as a mistake.

   The paragraph keeps its 28rem cap and gets `margin-inline: auto` to sit in
   the middle of it. Capping without centring would pin a narrow measure to the
   left of a full-width column, which is the thing this is fixing.

   `justify-content: center` on the badge row rather than `text-align`, because
   the badges are flex items: text-align would centre the glyphs inside each
   pill and leave the pills themselves packed left. It also centres the SECOND
   row on its own once they wrap, which they do at 320px, instead of leaving a
   short row hanging under a full one.

   Image sizing is untouched: the 4/3 ratio, the border and the object-fit all
   live on .sparko-honey__img and none of them are width-dependent. */
@media (max-width: 760px) {
  .sparko-honey__grid { grid-template-columns: 1fr; }
  .sparko-honey__text { text-align: center; }
  .sparko-honey__body { margin-inline: auto; }
  .sparko-honey__badges {
    justify-content: center;
    /* One row, always. The base rule wraps, which dropped "Made in LA" onto its
       own line at 390px and put all three on separate lines at 320px. */
    flex-wrap: nowrap;
    gap: 0.375rem;
    align-items: stretch;
  }
  .sparko-honey__badge {
    /* `auto` basis, not `0`. Equal WIDTHS force every pill to the width of the
       narrowest useful one, and at 320px that left about 70px of text per pill,
       which broke "No Artificial Colors" onto three lines. Sizing from content
       and then sharing the shortfall proportionally gives the long label the
       room it needs and the short one less, and all three land on two lines.
       Equal HEIGHT, which is what was actually asked for, comes from
       `align-items: stretch` on the row rather than from equal widths.

       `min-width: 0` is required either way: a flex item's automatic minimum is
       its content, so without it the longest label refuses to shrink at all and
       pushes the row past the viewport. The inner flex centres a shorter label
       against a taller neighbour. */
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    /* The base rule is `white-space: nowrap`. Wrapping is the whole point here:
       the wording is fixed, so the labels have to break rather than the row. */
    white-space: normal;
    text-align: center;
    font-size: 0.75rem;
    letter-spacing: 0.01em;
    line-height: 1.15;
    padding: 0.4rem 0.4rem;
  }
  .sparko-honey__cta { display: inline-flex; }
}

/* ============================================================================
   HOMEPAGE — Our Story (section: sparko-our-story)
   ============================================================================
   The same grid as sparko-honey: media left, copy right, both vertically
   centred, one centred column below 760px. Warm Cream ground, Night Sky Blue
   type, no shadow anywhere.

   The media slot is a three-slide strip rather than a single image. Layout
   stability is the thing to protect: the frame owns a fixed 4/3 ratio and every
   slide fills it, so the box is the same height on slide one and slide three and
   nothing reflows mid-swipe. That is also why the ratio lives on the SLIDE and
   not on the image, which would let a portrait upload change the frame. */
.sparko-story { background: var(--sparko-cream); padding-block: 3.5rem; }
.sparko-story__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; align-items: center; }

/* The frame: Honey's proportions, radius and border, carried verbatim so the two
   image-and-text bands on this page read as the same component. */
.sparko-story__viewport {
  border-radius: 1.25rem;
  border: 2px solid var(--sparko-navy);
  overflow-x: auto;
  overflow-y: hidden;
  display: flex;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  background: #ffffff;
  /* A flex item's automatic minimum is its content, and the content here is
     three full-width slides. Without this the strip refuses to shrink and blows
     the grid column open. */
  min-width: 0;
}
.sparko-story__viewport::-webkit-scrollbar { display: none; }
.sparko-story__slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  aspect-ratio: 4 / 3;
  min-width: 0;
}
.sparko-story__slide img,
.sparko-story__slide .sparko-ph {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* Dots on every screen size, not just touch. 44px targets on a coarse pointer
   via the shared rule at the end of this file; the visible dot stays 9px. */
.sparko-story__dots { display: flex; justify-content: center; gap: 0.5rem; margin-top: 1rem; }
.sparko-story__dot {
  width: 28px; height: 28px; padding: 0; border: none; background: none;
  display: grid; place-items: center; cursor: pointer;
}
.sparko-story__dot::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  border: 2px solid var(--sparko-navy); background: transparent;
}
.sparko-story__dot[aria-selected="true"]::before { background: var(--sparko-navy); }

.sparko-story__text { display: flex; flex-direction: column; align-items: flex-start; }
.sparko-story__eyebrow {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--sparko-navy); margin: 0 0 0.75rem;
}
.sparko-story__heading {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.5269rem, calc(1.0786rem + 2.24vw), 3rem);
  line-height: 1; text-transform: uppercase; color: var(--sparko-navy); margin: 0 0 1rem;
}
.sparko-story__body {
  font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1.1rem;
  line-height: 1.5; color: var(--sparko-navy); margin: 0 0 1.5rem; max-width: 28rem;
}
.sparko-story__cta { align-self: flex-start; }

@media (max-width: 760px) {
  /* Stacked: slideshow above, copy and button centred below. */
  .sparko-story__grid { grid-template-columns: 1fr; }
  .sparko-story__text { align-items: center; text-align: center; }
  .sparko-story__body { margin-inline: auto; }
  .sparko-story__cta { align-self: center; }
}

/* ============================================================================
   HOMEPAGE — Occasions hub + values (section: sparko-occasions)
   ============================================================================ */
.sparko-occ { background: var(--sparko-cream); padding-block: 3.5rem; }
.sparko-occ__tile {
  position: relative; display: block; overflow: hidden;
  border-radius: 1.25rem; border: 2px solid var(--sparko-navy);
  background: var(--sparko-navy); text-decoration: none;
}
/* The band holds a banner ratio of its own and the image cover-crops into it.

   It used to run at the image's own ratio (height: auto), which quietly made the
   band's shape a property of whichever file someone uploaded: a square photo
   turned this into a full-width square, metres tall on a desktop. 21:9 is the
   shape the empty-slot placeholder already stands in for, so the band now keeps
   that shape whether the slot is filled or not.

   Taller below 700px, because 21:9 on a phone is a letterbox roughly 170px high
   and the label has a heading and a button to fit inside it. Not verified at a
   real mobile viewport. */
.sparko-occ__tile { aspect-ratio: 16 / 9; }
@media (min-width: 701px) {
  .sparko-occ__tile { aspect-ratio: 21 / 9; }
}
.sparko-occ__tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Heading and button centre as one group near the bottom of the banner, at
   every width. `left: 0; right: 0` rather than a left offset so the flex box
   spans the tile and `align-items: center` can centre both children on the same
   axis; padding-inline keeps them off the rounded corners at narrow widths.
   Image proportions and the absence of any overlay are untouched. */
.sparko-occ__label {
  position: absolute; left: 0; right: 0; bottom: 2rem;
  display: flex; flex-direction: column; gap: 0.75rem;
  align-items: center; text-align: center;
  padding-inline: 1.5rem;
}
/* Night Sky Blue, not white. Read against the banner image directly: there is
   no scrim, fade or gradient behind this label and none is being added, so the
   colour is the whole readability mechanism. Worth knowing that the schema
   still offers an "Overlay opacity" setting which nothing consumes; it renders
   no element and never has. */
.sparko-occ__heading { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: clamp(1.5519rem, calc(1.2175rem + 1.67vw), 2.75rem); text-transform: uppercase; color: var(--sparko-navy); line-height: 1; }
.sparko-occ__values { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; margin-top: 2.5rem; }
/* A single callout is a closing statement, not a column. Left in the
   three-column track it would sit in the left third under a full-width banner.
   `:only-child` scopes this to exactly the one-block case, so a three-value row
   anywhere else is untouched and no markup or data-count attribute is needed.

   Spacing tightens at both ends: this is a sign-off under the banner rather
   than a band of its own, and the section's own padding already supplies the
   air beneath it. The paragraph caps so the line does not run the full
   container width, which at 1440 would be a single 1360px sentence. */
.sparko-occ__values:has(> .sparko-occ__value:only-child) { margin-top: 1.75rem; margin-bottom: 0.25rem; }
.sparko-occ__value:only-child { grid-column: 1 / -1; }
.sparko-occ__value:only-child .sparko-occ__value-line { max-width: 34rem; margin-inline: auto; }

/* Centred, and with no marker above the title. The navy dot that used to sit
   there was the item's only ornament; it read as a bullet on a list that is not
   a list, and it anchored the column to a left edge the rest of the homepage
   does not use. Its markup and its dot_color setting are both gone, not just
   hidden, so nothing dangles in the theme editor. */
.sparko-occ__value { position: relative; display: flex; flex-direction: column; gap: 0.5rem; align-items: center; text-align: center; }
/* Short navy rule in the gap before each item after the first.

   A pseudo-element rather than a border-left, because a border would run the
   full height of the tallest column and read as a table rule. This one is a
   fixed 3rem, centred on the item's own height, so it separates without
   dividing. It sits at half the grid's 2rem gap, less 1px for its own width, so
   it lands on the centre line between two columns.

   Only while the grid is multi-column: below 980px the columns stack, and a
   vertical rule between stacked items would point the wrong way. */
@media (min-width: 981px) {
  .sparko-occ__value + .sparko-occ__value::before {
    content: "";
    position: absolute;
    left: calc(-1rem - 1px);
    top: 50%;
    transform: translateY(-50%);
    width: 2px;
    height: 3rem;
    background: var(--sparko-navy);
  }
}
.sparko-occ__value-title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; margin: 0; color: var(--sparko-navy); }
.sparko-occ__value-line { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.72); margin: 0; }
@media (max-width: 760px) {
  .sparko-occ__values { grid-template-columns: 1fr; }
}

/* ============================================================================
   HOMEPAGE — Email signup (section: sparko-email)
   ============================================================================ */
.sparko-email { background: var(--sparko-pink); color: #ffffff; padding-block: 3.5rem; }
.sparko-email__inner { display: flex; align-items: center; gap: 3rem; }
.sparko-email__copy { flex: 1 1 auto; }
.sparko-email__h { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: clamp(1.4rem, 2.2vw, 2rem); color: #ffffff; margin: 0 0 0.5rem; line-height: 1.1; }
.sparko-email__sub { font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 1.05rem; color: rgba(255, 255, 255, 0.9); margin: 0; max-width: var(--sparko-measure); }
.sparko-email__form-wrap { flex: 0 0 auto; }
.sparko-email__form { display: flex; gap: 0.75rem; align-items: center; }
.sparko-email__input {
  font-family: var(--main-font-stack, sans-serif); font-size: 1rem;
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 999px;
  padding: 0 1.5rem; height: 3.25rem; width: 18rem; color: var(--sparko-navy);
}
.sparko-email__input::placeholder { color: rgba(38, 38, 102, 0.5); }
.sparko-email__msg { margin: 0.65rem 0 0; font-family: var(--main-font-stack, sans-serif); font-size: 0.9rem; color: #ffffff; }
@media (max-width: 760px) {
  .sparko-email__inner { flex-direction: column; align-items: stretch; }
  .sparko-email__form { flex-direction: column; }
  .sparko-email__input { width: 100%; box-sizing: border-box; }
  .sparko-email__form .sparko-btn { width: 100%; }
}


/* ============================================================================
   PDP — Custom Image Lollipops (sections: sparko-pdp-*)
   Rebuilt from the v2 design "Sparko PDP - Custom Image Lollipops.html" and its
   custom/custom-styles.css + pdp/pdp-styles.css. Rebuilt, not copied: the design
   ships .sp-*/.pdp-* classes and --ss-*/--sp-* tokens, and this file composes on
   our own .sparko-* primitives and brand tokens instead, the same way the
   homepage sections were built.

   The design's comments describe "hard directional navy shadows". Those are not
   ported: CLAUDE.md supersedes the brand guidelines and bars hard offset shadows
   system-wide. The design's own CSS already has the shadow declarations stripped
   for the same reason, so this matches what it actually renders.
   ============================================================================ */
.sparko-pdp { background: var(--sparko-cream); }
.sparko-pdp-hero { padding-block: 3.5rem 5rem; }
/* 50/50 with a 40px gutter, which is exactly what the live PDP does. Measured
   on /products/honey-dipper-lollipops: it is a 12-column grid with a constant
   40px gap and the media and content blocks each spanning 6, so the media column
   is 525px at a 1170 viewport and 660px at 1440.

   Ours was 1.02fr / 0.98fr with a 4rem gap, which made the gutter 24px wider
   than live's at every width and the two columns unequal. The image size falls
   out of the column, so this is one change and not two: at 1170 the frame goes
   523 -> 525 and at 1440 it stays 660, both matching live.

   The 40px is deliberately not var(--sparko-gutter): that token is 40px on
   desktop and narrows to 24px under 980px, and this gutter should not follow
   it, since the grid is a single column by then anyway. */
.sparko-pdp-hero__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 40px; align-items: start;
}

/* ---- gallery ---- */
.sparko-pdp-gallery { display: flex; flex-direction: column; gap: 1rem; }
/* position: relative on every wrapper that can host a fill placeholder.
   sparko-image-placeholder with fill:true renders .sparko-ph--fill, which is
   position: absolute, so without a positioned ancestor its label escapes to
   the section corner instead of sitting in the card. */
/* The frame takes the MEDIA's aspect ratio, not a fixed square. --media-ratio
   is server-rendered onto this element from the first image and swapped by the
   gallery script as the selection changes, so a portrait photo gets a portrait
   frame instead of being cropped to a square one.

   This matches the live Shapes gallery, which forces no ratio at all: its
   `crop` setting defaults to blank, and snippets/media-image.liquid only adds
   an `aspect-w-* aspect-h-*` wrapper when crop is set. Measured at 390px on the
   red-heart Twinkle product, live renders its square photos in 350x350 boxes
   and its portrait one in 350x622.

   The 1 fallback keeps the old square if a media somehow reports no ratio. */
.sparko-pdp-gallery__main {
  position: relative;
  aspect-ratio: var(--media-ratio, 1); border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-pdp-gallery__main img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-gallery__strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
.sparko-pdp-thumb {
  aspect-ratio: 1 / 1; width: 100%; border-radius: 0.75rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
  cursor: pointer; padding: 0; opacity: 0.55;
  transition: opacity 0.15s ease;
}
.sparko-pdp-thumb:hover { opacity: 1; }
/* Selection is the opacity going to 1, and that is all it has ever been in
   practice. This carried `box-shadow: inset 0 0 0 3px var(--sparko-navy)` as
   well, which never painted: an inset shadow sits in the element's background
   layer, before its children, so the `object-fit: cover` image covered it
   completely. Measured at 1440, a selected thumbnail's left edge read
   38,38,102 | 38,38,102 | 255,255,255 — two pixels of border, then the photo.
   Removing it changes nothing on screen and leaves one border per thumbnail,
   which is the whole design now. */
.sparko-pdp-thumb[aria-current="true"] { opacity: 1; }
.sparko-pdp-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-gallery__thumbs { display: none; }

/* ---- buy column ---- */
.sparko-pdp-buy { display: flex; flex-direction: column; gap: 1rem; align-self: start; }
.sparko-pdp-buy__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  /* Cap 3rem, not 4rem. Measured on the live site, a PDP title renders at
     47.95px at 1440; ours ran to 64px, a third larger, and on a long name like
     "Clam Shell Lollipops - Baby Blue, Pink, Purple (24 Pieces)" that filled
     four lines before the price. The floor and the slope are untouched, so
     phones are unaffected: ours is 30.02px at 390 against the live site's 32px,
     already the smaller of the two.

     This lowers one cell of the approved type ramp on purpose, at the client's
     direction, and type-baseline.json is updated to match. It is not drift. */
  font-size: clamp(1.7264rem, calc(1.0473rem + 3.40vw), 3rem); line-height: 0.95;
  letter-spacing: -0.01em; text-transform: uppercase; color: var(--sparko-navy); margin: 0;
}
.sparko-pdp-buy__rating { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.sparko-pdp-buy__stars { color: var(--sparko-gold); font-size: 1.3rem; letter-spacing: 3px; line-height: 1; }
.sparko-pdp-buy__rating-count {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.95rem;
  color: var(--sparko-navy); text-decoration: underline; text-underline-offset: 3px;
}
.sparko-pdp-buy__price { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.3rem; line-height: 1; color: var(--sparko-navy); }
.sparko-pdp-buy__desc { font-family: var(--main-font-stack, sans-serif); font-size: 1.15rem; line-height: 1.45; color: var(--sparko-navy); margin: 0; }
.sparko-pdp-field-label {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: rgba(38, 38, 102, 0.72);
  /* A label has to sit closer to its own control than to the field above it,
     or it reads as belonging to either one. It was 0px to its control and 8px
     to the previous field, which is not enough of a difference to group them. */
  margin-top: 0.875rem;
  margin-bottom: 0.375rem;
}
/* The first label opens the form, so the how-to block above owns that gap.
   :first-of-type, not :first-child — Shopify's {% form %} injects hidden inputs
   ahead of it, so :first-child never matched and it kept the group margin. */
.sparko-pdp-form .sparko-pdp-field-label:first-of-type { margin-top: 0; }
/* Every control takes the SAME gap to the next field's label: 0.875rem, set on
   the label above. There used to be an exception here giving the label after the
   pack tiles 1.5rem, on the reasoning that a tile grid is a heavier block than a
   select and wants the wider gap. Measured across the five buy sections, that
   exception was the only inconsistency in the form's rhythm, and it showed up
   twice on one page: the Galaxy and Custom Image PDPs both run tiles then a
   select, so the same boundary rendered 24px once and 14px again four fields
   later. The label still groups with its own control, which sits 0.375rem below
   it, so the 8px difference that rule was protecting is still there. */

/* ---- how to customize ---- */
.sparko-pdp-howto {
  display: flex; flex-direction: column; gap: 0.75rem;
  /* The rules are a divider, so the space outside them has to match on both
     sides or the block looks like it belongs to whatever is above it. This
     margin owns that gap on both sides; the first form label zeroes its own
     top margin so nothing stacks underneath. */
  margin-block: 0.75rem; padding-block: 1.25rem;
  border-top: 1px solid rgba(38, 38, 102, 0.16);
  border-bottom: 1px solid rgba(38, 38, 102, 0.16);
}
.sparko-pdp-howto__title {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: rgba(38, 38, 102, 0.72);
}
.sparko-pdp-howto__grid { display: grid; grid-template-columns: repeat(3, 1fr); align-items: stretch; }
.sparko-pdp-howto__step { display: flex; flex-direction: column; gap: 4px; padding-inline: 1rem; }
.sparko-pdp-howto__step:first-child { padding-left: 0; }
.sparko-pdp-howto__step + .sparko-pdp-howto__step { border-left: 1px solid rgba(38, 38, 102, 0.16); }
/* The step art was removed on 2026-09-07: three 34px line drawings above the
   numbered headings, and the 2px that separated them from the heading below.
   `min-height` stays — it is not icon spacing, it holds the three headings on a
   common baseline so a one-line and a two-line title do not stagger the rows. */
.sparko-pdp-howto__step-title {
  display: flex; align-items: flex-start; gap: 7px; min-height: 2.2em;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1rem;
  line-height: 1.1; color: var(--sparko-navy);
}
.sparko-pdp-howto__num {
  flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--sparko-gold); color: var(--sparko-navy);
  border: 2px solid var(--sparko-navy);
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.7rem;
}
.sparko-pdp-howto__line { font-family: var(--main-font-stack, sans-serif); font-size: 0.9rem; line-height: 1.4; color: rgba(38, 38, 102, 0.72); margin: 0; }

/* ---- pack selector (one tile per variant) ---- */
.sparko-pdp-packs { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
/* Column count follows the number of packs, so three never leaves one stranded
   on a second row. Across the 11 products on this template the pack option
   carries at most 3 values, so there is no 4-up case to design for; anything
   larger falls back to the 2-up default and wraps. */
.sparko-pdp-packs[data-count="3"] { grid-template-columns: repeat(3, 1fr); }
/* Three abreast is a narrower tile, so ease the padding and the icon rather
   than let "10 Pops Gift Pack" push the card taller than its neighbours. */
.sparko-pdp-packs[data-count="3"] .sparko-pdp-pack { padding: 0.85rem; gap: 0.5rem; }
/* The selected tile trades 1px of padding for the 1px its border gains, so its
   contents sit where its neighbours' do instead of shifting in. The 2-up rule
   has carried this companion since it shipped; the 3-up rule never did, so the
   Galaxy tiles were 1px roomier inside than the tile beside them at every width.
   (0,4,0) here against (0,3,0) above, which is also why the generic
   `.sparko-pdp-pack[aria-checked]` rule at (0,2,0) never reached these.) */
.sparko-pdp-packs[data-count="3"] .sparko-pdp-pack[aria-checked="true"] { padding: calc(0.85rem - 1px); }
.sparko-pdp-packs[data-count="3"] .sparko-pdp-pack svg { width: 42px; height: 38px; }
.sparko-pdp-packs[data-count="3"] .sparko-pdp-pack__head { font-size: 0.875rem; }
.sparko-pdp-packs[data-count="3"] .sparko-pdp-pack__price { font-size: 1.1rem; margin-top: 8px; }
.sparko-pdp-pack {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.75rem; text-align: left;
  border: 2px solid var(--sparko-navy); border-radius: 0.75rem;
  background: #ffffff; color: var(--sparko-navy); cursor: pointer; padding: 1rem;
  transition: background-color 0.16s ease;
}
.sparko-pdp-pack:hover { background: rgba(38, 38, 102, 0.05); }
/* Selected reads by colour and by weight: gold border one step thicker than the
   unselected navy, padding trimmed by the extra pixel so tiles stay aligned. */
.sparko-pdp-pack[aria-checked="true"] { border: 3px solid var(--sparko-gold); padding: calc(1rem - 1px); }
.sparko-pdp-pack svg { flex: 0 0 auto; display: block; color: var(--sparko-navy); width: 50px; height: 46px; }
.sparko-pdp-pack__label { width: 100%; display: flex; flex-direction: column; }
.sparko-pdp-pack__head { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.95rem; line-height: 1.2; }
.sparko-pdp-pack__price { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.2rem; line-height: 1; margin-top: 10px; }
.sparko-pdp-pack__sold { font-family: var(--main-font-stack, sans-serif); font-size: 0.75rem; color: rgba(38, 38, 102, 0.6); margin-top: 4px; }

/* ---- actions ---- */
/* margin-top separates the actions from the last option select; gap is the
   space between Customize and Add to Cart. Both are edge-to-edge only because
   the Qstomizer button's own 15px bottom margin is zeroed further down. */
.sparko-pdp-actions { display: flex; flex-direction: column; gap: 1.25rem; margin-top: 1.5rem; }
/* PDP action buttons take the live Shapes proportions: a narrower pill, same
   999px ends. Measured there, the pill is 46px tall on a 16px label with 12px
   of padding above and below; ours was 54px on a phone and 56px on desktop from
   a 17.6px label and 16px padding, which read as chunkier at the same width.

   13px of padding rather than live's 12px because our pill carries a 2px border
   that theirs does not: 13 + 13 + 16 + 4 = 46, the same height by a different
   route. No shadow, which is what ours already did — the live button has an
   offset one and that is the part not being copied. */
.sparko-pdp-actions .sparko-btn { width: 100%; }
/* Both wrappers: the custom-image template stacks its buttons in
   `.sparko-pdp-actions`, while shaped, twinkle, galaxy and honey put Add to Cart
   beside the quantity stepper with a `.sparko-pdp-atc` class and no actions
   wrapper. Sizing only — `width: 100%` stays on the stacked variant, because the
   inline one shares its row with the stepper and must not fill it. */
.sparko-pdp-actions .sparko-btn,
.sparko-pdp-atc {
  font-size: 1rem;
  padding-block: 0.8125rem;
}
.sparko-pdp-atc-group { display: flex; flex-direction: column; gap: 6px; }
.sparko-pdp-atc {
  background: transparent; color: var(--sparko-navy);
  border: 2px solid var(--sparko-navy);
}
.sparko-pdp-atc:hover { background: rgba(38, 38, 102, 0.08); }
.sparko-pdp-atc[disabled] { opacity: 0.5; cursor: default; }
.sparko-pdp-helper { font-family: var(--main-font-stack, sans-serif); font-size: 0.9rem; color: rgba(38, 38, 102, 0.72); margin: 0; }

/* ---- trust badges ---- */
.sparko-pdp-badges { display: flex; flex-wrap: nowrap; justify-content: flex-start; align-items: flex-start; gap: 1rem; margin: 0.5rem 0 0; }
/* Phones: the row SHRINKS instead of wrapping, and never wraps at any width.

   This reverses the earlier call recorded here, at the client's direction
   (2026-09-10). That note chose wrapping over shrinking to protect the 11.04px
   label, and it was right about the type: the label is STILL 11.04px and is not
   touched by this. What changed is the judgement about the second row.

   The arithmetic that forces a compromise: the buy column is 335px at 375, and
   the widest label, "Gluten Free", needs 71px to sit on one line. Five of those
   is 355px before any gap, so five labels each on one line is impossible at this
   type size. Measured alternatives, all rejected:

     10px type   "Gluten Free" STILL wraps, so it buys nothing and costs a pixel
     9.5px type  fits on one line, but a 14% type cut to save one line break
     36px disc   changes no line count; the disc is not the binding constraint
     overflow-x  fits, but puts the fifth trust badge off-screen

   So the box shrinks and "Gluten Free" takes two lines. One row carrying one
   two-line label is still shorter than the two rows it replaces, and honey's
   four badges come out strictly better: one row at a 79.3px box, wider than the
   78px they had, with their line counts unchanged. They only wrapped before
   because 4 x 78 + 3 x 8 = 336 against 335, missing by a single pixel.

   Gap drops to 6px only where width is scarce, which buys 40px across five
   badges. Above 560px the row has room and keeps its 1rem. */
@media (max-width: 560px) {
  .sparko-pdp-badges { gap: 6px; }
}
.sparko-pdp-badge { flex: 0 1 78px; width: auto; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 7px; text-align: center; }
/* The disc tracks its box. Fixed at 44px it was the hard floor on how narrow a
   badge could get: six badges in the 280px column at 320px gives a 41.7px box,
   and a 44px disc then overflowed it. width plus max-width plus aspect-ratio
   lets it sit at 44px wherever there is room and shrink below that where there
   is not, staying circular either way. The icon inside is capped the same way. */
.sparko-pdp-badge__disc {
  flex: 0 1 auto; width: 44px; max-width: 100%; aspect-ratio: 1; height: auto; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--sparko-gold) 35%, #ffffff);
  color: var(--sparko-navy);
}
/* min() rather than a max-% cap: at the normal 44px disc this is exactly 30px,
   because 70% of 44 is 30.8, so desktop is untouched to the pixel. A flat 68%
   cap looked equivalent and was not: it computed 29.92px and shrank every icon
   on the site by 0.09px. It only binds once the disc itself shrinks. */
.sparko-pdp-badge__disc svg { width: min(30px, 70%); height: min(30px, 70%); }
.sparko-pdp-badge__text {
  max-width: 100%; font-family: var(--main-font-stack, sans-serif); font-weight: 800; font-size: 0.69rem;
  text-transform: uppercase; letter-spacing: 0.02em; line-height: 1.15; color: var(--sparko-navy);
  word-break: keep-all; hyphens: none; text-wrap: balance;
}

/* ---- accordions (buy column + FAQ) ---- */
.sparko-pdp-acc { display: flex; flex-direction: column; gap: 0.75rem; }
.sparko-pdp-acc__item { border: 2px solid var(--sparko-navy); border-radius: 0.75rem; background: #ffffff; overflow: hidden; }
.sparko-pdp-acc__btn {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  width: 100%; background: none; border: none; cursor: pointer; text-align: left;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 1rem;
  color: var(--sparko-navy); padding: 16px 20px; line-height: 1.2;
}
.sparko-pdp-acc__btn svg { flex: 0 0 auto; transition: transform 0.15s ease; }
.sparko-pdp-acc__item[open] .sparko-pdp-acc__btn svg { transform: rotate(180deg); }
.sparko-pdp-acc__body { padding: 0 20px 18px; }
.sparko-pdp-acc__body p { font-family: var(--main-font-stack, sans-serif); font-size: 1.03rem; line-height: 1.5; color: var(--sparko-navy); margin: 0 0 0.5rem; }
.sparko-pdp-acc__body p:last-child { margin-bottom: 0; }

/* ============ Featured projects (navy band, gold-bordered white cards) ============ */
.sparko-pdp-featured {
  background: var(--sparko-navy); color: #ffffff;
  /* Same mechanism as .sparko-case: the shared heading is navy, which is
     invisible on a navy band, so the band retargets the variable. */
  --sparko-section-title-color: #ffffff;
}
.sparko-pdp-featured .sparko-section-eyebrow { color: var(--sparko-gold); }
/* Centred head. The two heads used to carry inline text-align:left on the title
   and eyebrow, which beat the shared .sparko-section-title centring; those
   inline styles are gone from the Liquid, so the shared rule applies again and
   only the wrapper and note need centring here. */
.sparko-pdp-featured__head { margin: 0 auto 2.5rem; max-width: 45rem; text-align: center; }
.sparko-pdp-featured__note { font-family: var(--main-font-stack, sans-serif); font-size: 1.1rem; line-height: 1.5; color: rgba(255, 255, 255, 0.82); margin: 1rem auto 0; }
.sparko-pdp-featured__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
.sparko-pdp-feat {
  background: #ffffff; border: 2px solid var(--sparko-gold); border-radius: 1.25rem;
  padding: 1.5rem; display: flex; flex-direction: column; gap: 0.75rem;
  text-decoration: none; transition: transform 0.15s ease;
  /* Centres the title, the line and the button label in one declaration. The
     image span is unaffected: it is a block that fills the card width, so there
     is no inline box for this to move. */
  text-align: center;
}
.sparko-pdp-feat:hover { transform: translate(-2px, -2px); }
.sparko-pdp-feat__img {
  display: block; position: relative;
  aspect-ratio: 1 / 1; overflow: hidden; margin: -1.5rem -1.5rem 0;
  border-bottom: 2px solid var(--sparko-gold);
  border-radius: calc(1.25rem - 2px) calc(1.25rem - 2px) 0 0;
}
.sparko-pdp-feat__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-feat__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.25rem; line-height: 1.1; color: var(--sparko-navy); }
.sparko-pdp-feat__line { font-family: var(--main-font-stack, sans-serif); font-size: 0.97rem; line-height: 1.45; color: rgba(38, 38, 102, 0.72); }
/* Pink pill closing each project card, matching .sparko-pdp-opt__cta on the
   same page and .sparko-btn--pink everywhere else: navy border, 999px radius,
   white uppercase heading type.

   Two differences from the option-card version, both deliberate.
   `align-self: center` rather than `stretch`, because "Check It Out" is short
   and a full-width bar reads as a banner rather than a button; the option cards
   stretch only because their longer labels overflowed a 4-up column, which this
   one cannot at any width. And `margin-top: auto` pushes it to the bottom of
   the card, so the buttons line up across a row however tall the copy above
   them runs. */
.sparko-pdp-feat__cta {
  align-self: center; margin-top: auto;
  padding: 0.7rem 1.4rem; border-radius: 999px; line-height: 1.25;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-pink); color: #ffffff;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.02em;
  text-decoration: none; white-space: nowrap;
  transition: background-color 0.15s ease;
}
.sparko-pdp-feat:hover .sparko-pdp-feat__cta { background: var(--sparko-pink-hover); }
/* Gold pill, centred under the grid. Was an underlined gold text link, which is
   not a shape the brand uses anywhere else; every other CTA on the site is a
   pill. Matches .sparko-btn--gold rather than reusing it, because this one sits
   on the navy band and needs the navy border to read as an outline. */
.sparko-pdp-featured__more {
  width: fit-content; margin: 2.5rem auto 0;
  /* Same pill as .sparko-btn, which copies the live theme: 46px via min-height,
     16px sides, a 1rem/900 label at -0.05em. flex rather than block, because
     min-height only centres a label if the box is centring its content.

     This is DUPLICATION and it is why this button was missed when .sparko-btn
     was retuned: three CTAs in the theme draw their own pill instead of
     rendering that class. Anything that looks like a button should use
     .sparko-btn; if one of these is touched again, move it over. */
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; min-height: 46px; padding: 0 1rem;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1rem; text-transform: uppercase; letter-spacing: -0.05em;
  line-height: 1; border-radius: 999px;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-gold); color: var(--sparko-navy);
  text-decoration: none; text-align: center;
}
.sparko-pdp-featured__more:hover { background: var(--sparko-gold-hover); color: var(--sparko-navy); }

/* ============ Other custom options (cream band) ============ */
.sparko-pdp-other { background: var(--sparko-cream); }
.sparko-pdp-other__head { margin: 0 auto 2.5rem; max-width: 39rem; text-align: center; }
.sparko-pdp-other__note { font-family: var(--main-font-stack, sans-serif); font-size: 1.1rem; color: rgba(38, 38, 102, 0.72); margin: 1rem auto 0; }
.sparko-pdp-other__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
/* Centred, and the gap tightened between the name and the price so the two
   read as one caption under the image rather than as two stacked lines. The
   0.75rem gap still separates the image from that caption, via a margin on the
   name (2026-09-08, at the client's direction, to match "You May Also Like"). */
.sparko-pdp-opt { display: flex; flex-direction: column; gap: 0.35rem; text-decoration: none; align-items: center; text-align: center; }
.sparko-pdp-opt__name { margin-top: 0.4rem; }
.sparko-pdp-opt__img {
  display: block; position: relative;
  aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden; background: #ffffff;
  border: 2px solid var(--sparko-navy); transition: transform 0.15s ease;
}
.sparko-pdp-opt:hover .sparko-pdp-opt__img { transform: translate(-2px, -2px); }
.sparko-pdp-opt__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Sized and weighted to match .sparko-prod__name / .sparko-prod__price, the
   card used by "You May Also Like", rather than to the display ramp this tile
   used to carry. The old name was a clamp up to 1.45rem in uppercase, which
   read as a section sub-heading with a caption under it; these are a product
   listing.

   The tile keeps its OWN markup rather than rendering sparko-product-card. That
   snippet's own note explains why: this tile lifts its image on hover and can
   carry a pill CTA, neither of which the shared card does, so folding it in
   would trade one visual mismatch for two behavioural ones. Only the type and
   alignment are being matched here, which is what was asked. */
.sparko-pdp-opt__name {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.05rem;
  line-height: 1.2; letter-spacing: normal; color: var(--sparko-navy);
}
/* Full Night Sky Blue, not a tint. Same call .sparko-best and .sparko-pdp-related
   made: centred on its own line, a muted price reads as disabled. */
.sparko-pdp-opt__price { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.95rem; color: var(--sparko-navy); }
/* .sparko-pdp-opt__cta lives with the other PDP button rules at the end of the
   file, so the two CTA treatments on this page stay side by side. */

/* ============ FAQ (cream band, two-column split) ============ */
.sparko-pdp-faq { background: var(--sparko-cream); }
.sparko-pdp-faq__grid { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 4rem; align-items: start; }
/* The FAQ head is a column in a split layout, so centring the title alone
   would leave the contact line hanging off to one side. Centre the whole
   head so the column reads as one centred block. */
.sparko-pdp-faq__head { text-align: center; }
.sparko-pdp-faq__contact { font-family: var(--main-font-stack, sans-serif); font-size: 1.05rem; line-height: 1.5; color: rgba(38, 38, 102, 0.72); margin: 1rem auto 0; max-width: 34ch; }

/* ============ For brands and events (gold band) ============ */
.sparko-pdp-brand { background: var(--sparko-gold); padding-block: 5rem; }
.sparko-pdp-brand__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4rem; align-items: center; }
.sparko-pdp-brand__media {
  position: relative;
  aspect-ratio: 4 / 3; border-radius: 1.25rem; overflow: hidden; background: #ffffff;
  border: 2px solid var(--sparko-navy);
}
.sparko-pdp-brand__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A single-product cutout is mostly white space with the pop at the top and the
   stick running to the bottom, so cover in a 4:3 frame crops both ends off. This
   fits the whole photo instead. The frame's own white background fills the sides,
   which is why it does not need a letterbox colour of its own. */
.sparko-pdp-brand__media--contain img { object-fit: contain; }
.sparko-pdp-brand__text { display: flex; flex-direction: column; gap: 1rem; align-items: flex-start; }
/* Centred variant, driven by the section's `align` setting. Used by the Twinkle
   PDP's "The Favor They Keep" band (2026-09-08, at the client's direction);
   every other band in the theme keeps the left default, so this is opt-in.
   align-items centres the heading, the body and the pink CTA alike, since all
   three are flex children of this column. text-align handles the wrapped lines
   inside the body's 46ch measure. */
.sparko-pdp-brand__text--center { align-items: center; text-align: center; }
.sparko-pdp-brand__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.5308rem, calc(1.1002rem + 2.15vw), 3rem); line-height: 0.98;
  text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy); margin: 0;
}
.sparko-pdp-brand__body { font-family: var(--main-font-stack, sans-serif); font-size: 1.1rem; line-height: 1.55; color: var(--sparko-navy); margin: 0; max-width: 46ch; }
/* The body is richtext, so it can hold several paragraphs, but its <p> children
   were inheriting margin: 0 from the reset. Two paragraphs therefore rendered as
   one unbroken wall of text: on the Honey PDP's Harvest band that ran the
   [PLACEHOLDER] confirmation note straight on from the customer copy with no
   break, so it read as part of the sentence before it.

   Same shape as the rule sparko-pdp-acc__body p already carries, sized up for
   this band's larger 1.1rem body. */
.sparko-pdp-brand__body p { margin: 0 0 0.75rem; }
.sparko-pdp-brand__body p:last-child { margin-bottom: 0; }

/* ============ responsive ============ */
@media (max-width: 980px) {
  /* 2rem above the gallery on a phone, down from 3.5rem. Measured against the
     live site, which leaves 32px between the header and the product image at
     390 and 64px at 1440. Ours was a flat 56px: already tighter than live on
     desktop, so that end is left alone, and 24px too generous on a phone, where
     the image is the whole first screen. The bottom padding is unchanged. */
  .sparko-pdp-hero { padding-block: 2rem 5rem; }
  .sparko-pdp-hero__grid { grid-template-columns: minmax(0, 1fr); gap: 2.5rem; }
  .sparko-pdp-gallery__main { display: none; }
  /* Two automatic minimums, both of which had to be pinned, or the carousel
     overflows its column. Measured at 390px: the gallery came out 380.2px wide
     inside a 342px column, keeping its 24px gutter on the left and running
     14px off the right edge, so the first photo was clipped on every mobile PDP
     and every slide snapped off-centre.

     1. The TRACK. `1fr` is shorthand for `minmax(auto, 1fr)`, and that `auto`
        minimum is min-content, so a track holding five product photos refuses
        to be narrower than they are. `minmax(0, 1fr)` is the one above.
     2. The ITEM. A grid item's default `min-width: auto` refuses in the same
        way, so fixing the track alone still leaves the item overflowing it.

     Fixing only one of the two changes nothing measurable, which is why this
     looks over-specified and is not. The strip below needs no such rule: it is
     a block child that already sizes to its parent. */
  .sparko-pdp-gallery { min-width: 0; }
  /* No `scroll-behavior` here on purpose. The strip is scrolled two ways:
     smoothly when a thumbnail is tapped, and instantly when a scroll has to be
     corrected or cancelled mid-flight. A blanket `scroll-behavior: smooth`
     would apply to both and make the instant path impossible, so the script
     passes `behavior` per call instead.

     `scroll-snap-type` is likewise turned off and back on by the script for the
     duration of a tap-driven slide: mandatory snapping re-targets a programmatic
     smooth scroll and can drop it outright, which is what used to leave the main
     image on the previous photo. It is declared here because it is the resting
     state, and the script always restores it. */
  .sparko-pdp-gallery__strip {
    grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 100%;
    /* 40px between slides, matching the live Shapes gallery, which gets the same
       separation by giving each full-width slide `padding: 0 20px` and framing
       the media inside it. Ours frames the slide itself, so the same 40px comes
       from a gap instead.

       It was 0, and with a frame on every slide that meant two 2px navy borders
       touching mid-swipe, plus cream showing through the two 20px corner
       radii — which read as a seam between two cramped cards rather than as one
       photo moving aside for the next.

       THE SCRIPT DEPENDS ON THIS VALUE. `sparko-pdp-gallery.liquid` reads the
       computed column-gap to work out where slide i starts; a gap set here and
       not accounted for there puts every tap one slide short of its target. */
    gap: 2.5rem; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    /* Slides keep their own height instead of being stretched to the tallest.
       A grid row is as tall as its tallest item, so one portrait photo would
       otherwise stretch every square photo in the product to match it. The
       script pins the strip's own height to the SELECTED slide, so the space a
       tall slide needs is not left empty under a short one either. */
    align-items: start;
    /* Explicit, not inherited. overflow-x on its own forces overflow-y to
       compute to auto rather than visible, which would let a slide taller than
       the pinned height become a second, vertical scroll axis inside the
       carousel. Clipping is the intent; the script keeps the height matched to
       the scroll position so there is nothing to clip in normal use.

       No height transition here on purpose. The script interpolates the height
       against scroll position on every scroll event, so a CSS transition would
       be a second animation chasing the first and would lag the swipe. */
    overflow-y: hidden;
  }
  .sparko-pdp-gallery__strip::-webkit-scrollbar { display: none; }
  /* Below 980px the strip IS the main image, so a slide is framed to its own
     media rather than to the square the desktop thumbnail grid wants. The base
     rule's literal `1 / 1` still applies above this breakpoint, which is why
     --media-ratio can be set on every slide unconditionally. */
  .sparko-pdp-thumb { scroll-snap-align: center; opacity: 1; border-radius: 1.25rem; aspect-ratio: var(--media-ratio, 1); }
  .sparko-pdp-thumb[aria-current="true"] { box-shadow: none; }
  /* Thumbnail grid, replacing the dots. EVERY thumbnail is visible at once,
     wrapping onto as many rows as it takes, which is what the live Shapes
     gallery does — a four-column grid there, and four per row here too at 390
     because 4 x 80 + 3 x 8 = 344 inside a 350px row.

     It was a single row that scrolled, chosen so a second row could not push the
     buy block down. That is reversed at the client's direction: a photo you
     cannot see is a photo you will not look at, and a nine-image product hid six
     of them behind a sideways scroll nobody is told about. The buy block moving
     down is the price of showing them, and it is the right trade on a page whose
     job is to sell the thing in the photographs.

     80px squares as of 2026-09-07 — 52px originally, then 72px, now 80px. The
     whole button is the target, so it clears the 44px minimum on both axes
     several times over without needing a transparent hit area around a smaller
     mark, which is what the dots it replaced needed.

     80 + 8px gap = 88px a thumbnail, against a row content box of 272px at a
     320px viewport and 342px at 390px. Measured: three fit at 320 with 12px of
     a fourth showing, and four fit at 390 with NO peek — 4 x 80 + 3 x 8 is
     344px, which fills the row within 2px, so the fifth begins past the edge.

     That is the accepted consequence of fixing both the size and the spacing:
     the row overflows rather than letting the gap or the thumbnails absorb the
     difference. It does mean 390px has nothing part-shown to advertise that the
     row scrolls, which the 4px gap it briefly carried was there to provide.

     Selection is a 2px navy ring drawn with box-shadow rather than a border, so
     the thumbnail does not change size when it becomes selected and the row
     never reflows mid-swipe. Focus is a separate outline so a keyboard user can
     tell "focused" from "selected" when they are different thumbnails. */
  .sparko-pdp-gallery__thumbs {
    /* A FLUID four-column grid, which is what the live Shapes gallery uses, and
       the reason the thumbnails now scale instead of sitting at a fixed size.

       They were pinned at 80px everywhere below 980px. That matched live at 390,
       where its grid also lands on 80px, and diverged badly above it: live
       measures 123px at 560, 175px at 768 and 208px at 900 as its columns grow
       with the container, while ours stayed 80px and simply fitted more per row
       — five at 560, nine at 900. On a tablet or a narrow desktop window the
       thumbnails were a third the size of the site being replaced.

       Four columns and a 10px gap are live's own values. This supersedes the
       fixed 80px: the size is now the column width, tracking live rather than
       holding a number. */
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    /* No padding, and none needed. It existed because the row used to scroll,
       and a scroll container clips on BOTH axes, which sheared the focus ring
       off the edge thumbnails. Wrapping means `overflow` is visible, so nothing
       can be clipped and the ring needs no reserved space.

       Removing it is also what buys the fourth column. The row is 350px at a
       390px viewport, and four thumbnails plus their gaps come to 4 x 80 + 3 x 8
       = 344px. With 4px of padding each side the usable width was 342px, two
       pixels short, and the fourth thumbnail dropped to the next line — three
       across where the live gallery shows four. */
  }
  /* ONE 2px border per thumbnail, muted when unselected and full Night Sky Blue
     when selected — the same reading the desktop strip gives. No second ring on
     either layout.

     It has to be a real `border` and not an inset box-shadow. `overflow: hidden`
     clips the image to the PADDING box, which excludes the border area, so a
     border can never be painted over by the photo. An inset shadow lives in the
     element's background layer and paints BEFORE its children, so a
     `width:100%; height:100%; object-fit:cover` image covers it exactly — which
     is what used to happen here, and still happened on the desktop strip until
     its dead ring was removed above.

     The muted colour is `rgba(38, 38, 102, 0.55)`, not a hardcoded grey-blue,
     because desktop gets its muted border by drawing a navy one through
     `opacity: 0.55`. Same alpha, same result, and it follows the token if navy
     ever moves.

     `background-clip: padding-box` is what makes the two match exactly. The
     white background would otherwise extend under the border and the
     translucent navy would composite over WHITE, giving 136,136,171; clipped to
     the padding box it composites over the page instead, giving 135,133,166,
     which is what the desktop strip measures. The white still covers the whole
     image area, so a letterboxed photo is unaffected.

     `box-sizing: border-box` keeps the button 72x72 with the border inside it,
     rather than growing it to 76px. It is stated rather than inherited because
     this file sets it per-component, not globally. */
  .sparko-pdp-mthumb {
    box-sizing: border-box;
    /* Sized by its grid column now, not by a fixed basis, and kept square by
       the ratio rather than by a pair of matching pixel values. The old
       `flex: 0 0 80px` existed to stop nine thumbnails squeezing themselves down
       in a nowrap row; a grid with four fixed columns cannot do that, so the
       guard is no longer needed. */
    width: auto; height: auto;
    aspect-ratio: 1 / 1;
    padding: 0; background: #ffffff; background-clip: padding-box;
    border: 2px solid rgba(38, 38, 102, 0.55);
    border-radius: 0.75rem; overflow: hidden; cursor: pointer;
    transition: border-color 0.15s ease;
  }
  .sparko-pdp-mthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .sparko-pdp-mthumb[aria-current="true"] { border-color: var(--sparko-navy); }
  .sparko-pdp-mthumb:focus-visible {
    outline: 2px solid var(--sparko-navy);
    outline-offset: 2px;
  }
  .sparko-pdp-featured__grid, .sparko-pdp-other__grid { grid-template-columns: 1fr 1fr; }
  .sparko-pdp-brand__grid, .sparko-pdp-faq__grid { grid-template-columns: 1fr; gap: 2rem; }
}

/* Reduced motion. The script already asks for instant scrolls when this is set,
   which covers the gallery sliding; this covers the selection ring, which would
   otherwise still fade in behind an instant slide and arrive after it. */
@media (max-width: 980px) and (prefers-reduced-motion: reduce) {
  .sparko-pdp-mthumb { transition: none; }
}
@media (max-width: 560px) {
  /* `.sparko-pdp-packs[data-count="3"]` above is (0,2,0) and this rule was
     (0,1,0), so the three-tile ladder was the one pack count that ignored this
     breakpoint. It stayed three across on a phone AND overflowed: its tracks
     measured 110.9 + 121.4 + 123.9 plus 24px of gap = 380.2 inside a 342px
     column, running 14px off the right edge, because `1fr` is `minmax(auto,
     1fr)` and each track refused to go below the min-content width of its own
     price line. Two-tile ladders collapsed correctly the whole time, which is
     what made it look deliberate.

     The attribute selector is repeated here to match that specificity rather
     than raised past it with !important. `minmax(0, 1fr)` rather than `1fr` so
     a single track cannot blow out the same way on a long unbroken price. */
  /* Everything collapses to one column by default, INCLUDING the pack ladder;
     `[data-count="2"]` below is (0,2,0) and opts just that count back out. The
     default has to stay the collapse, not the two-up: Honey ships a one-tile
     ladder, and any rule shaped as "two columns unless three" leaves that tile
     in half a row with an empty column beside it. */
  .sparko-pdp-featured__grid, .sparko-pdp-other__grid, .sparko-pdp-packs {
    grid-template-columns: minmax(0, 1fr);
  }
  /* TWO tiles stay side by side. They were collapsed along with the three-tile
     ladder, but only the three-tile one had a reason to be: three tracks wanted
     380.2px inside a 342px column. Two do not — the widest thing in a tile is
     its price, and two tiles plus the gap clear the column at 320px, which is
     the narrowest this site is checked at.

     A pack ladder is a comparison. Stacked, the second price is off the bottom
     of the screen while the first is being read, which is the one thing the
     control exists to make easy.

     `minmax(0, 1fr)` rather than `1fr` for the same reason the rule above uses
     it: `1fr` is `minmax(auto, 1fr)`, and that auto floor is min-content, so a
     long unbroken price would push a track wider than its share instead of
     wrapping inside it. */
  .sparko-pdp-packs[data-count="2"] { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* Two-up at 320px is a 130px tile, and at the full type the widest price,
     "$2,625.00", wanted 101px inside a 94px box and was CLIPPED — which is
     worse than the stacking this replaces. So the tiles take the compact
     treatment this file already gives the three-up ladder, rather than a new
     set of numbers invented for the occasion: tighter padding, smaller icon,
     smaller head and price.

     Scoped to `[data-count="2"]` exactly. Only the count that actually goes
     side by side gets either rule; one-tile and three-tile ladders keep the
     full-width collapse above. The selected tile's padding is restated with the
     same 1px trim, or it would jump back to the wide value and shift the row
     when a pack is chosen. */
  .sparko-pdp-packs[data-count="2"] .sparko-pdp-pack { padding: 0.85rem; gap: 0.5rem; }
  .sparko-pdp-packs[data-count="2"] .sparko-pdp-pack[aria-checked="true"] { padding: calc(0.85rem - 1px); }
  .sparko-pdp-packs[data-count="2"] .sparko-pdp-pack svg { width: 42px; height: 38px; }
  .sparko-pdp-packs[data-count="2"] .sparko-pdp-pack__head { font-size: 0.875rem; }
  .sparko-pdp-packs[data-count="2"] .sparko-pdp-pack__price { font-size: 1.05rem; margin-top: 8px; }
}

/* Option selects beneath the pack tiles. The design has no colour or flavour
   control, but Add to Cart cannot post a variant without them. */
.sparko-pdp-select {
  font-family: var(--main-font-stack, sans-serif); font-size: 1rem; color: var(--sparko-navy);
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 0.75rem;
  padding: 0.7rem 0.9rem; width: 100%;
}

/* ---- PDP: Customize button + option CTAs as brand pink pills ----
   The Qstomizer snippet renders #qstomizer-product-button-custom with Switch's
   own button classes, which resolve to the active colour scheme's accent. On
   scheme1 that is #5aff24, so the primary CTA rendered bright green. Restyled
   here rather than in the snippet, because the snippet is shared with the stock
   product page and that page should keep the theme's own button treatment.

   Scoped to .sparko-pdp-actions so only this page is affected. */
.sparko-pdp-actions #qstomizer-product-button-custom,
.sparko-pdp-actions #qstomizer-product-button-custom:hover {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; box-sizing: border-box;
  /* Same pill as Add to Cart below it: 13px of padding on a 16px label gives
     46px with the 2px border. It kept the old 1rem/1.1rem and stood 61px tall
     against a 46px Add to Cart directly beneath, which is the one place on any
     PDP where two of these sit stacked and the mismatch is unmissable. This
     button is styled here rather than by `.sparko-btn` because it is Qstomizer's
     markup, so it does not inherit the sizing applied to our own buttons. */
  /* Geometry tracks .sparko-btn, which now copies the live theme's pill: 46px
     tall via min-height, 16px of side padding, -0.05em tracking. It cannot just
     use that class, because this is Qstomizer's markup. */
  min-height: 46px; padding: 0 1rem; border-radius: 999px;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-pink); color: #ffffff;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1rem; text-transform: uppercase; letter-spacing: -0.05em;
  /* `line-height: 1` is the last 6px. Without it the label inherits ~1.4 and
     the pill lands at 52px rather than 46: 13 + 13 + 22.4 + 4. Our own buttons
     get this from `.sparko-btn`; Qstomizer's markup does not use that class, so
     every part of the pill has to be stated here. */
  line-height: 1;
  box-shadow: none; cursor: pointer;
  /* The button ships with a 15px bottom margin, which stacked on top of the
     flex gap and made the space below it nearly 3x the space above. Zero it so
     .sparko-pdp-actions' gap is the only thing setting that distance. */
  margin: 0;
}
.sparko-pdp-actions #qstomizer-product-button-custom:hover { background: var(--sparko-pink-hover); }
/* The snippet wraps its button in the theme's .w-full div; strip its spacing so
   the pair stacks on .sparko-pdp-actions' own gap rather than two stacked gaps. */
.sparko-pdp-actions .w-full { margin: 0; }
/* Qstomizer also emits an empty container between the two buttons. It is a flex
   item with no height, so it still claims a gap and the Customize/Add to Cart
   pair sat 24px apart instead of 12px. :empty rather than a blanket
   display:none, so it comes back the moment the app puts anything in it. */
.sparko-pdp-actions > div:empty { display: none; }

/* Option cards that start a request get a real pink pill, not a text link, so
   they read as the same affordance as every other CTA on the site. */
.sparko-pdp-opt__cta {
  /* Stretch rather than shrink-to-fit: the labels are long enough that an
     intrinsically sized pill overflowed the 4-up grid column. Filling the card
     keeps the two CTAs the same width as each other too. */
  align-self: stretch; text-align: center; margin-top: auto;
  padding: 0.7rem 1rem; border-radius: 999px; line-height: 1.25;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-pink); color: #ffffff;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.02em;
  text-decoration: none;
}
.sparko-pdp-opt:hover .sparko-pdp-opt__cta { background: var(--sparko-pink-hover); }

/* ============================================================================
   SHAPED LOLLIPOPS PDP
   Built from the v2 design "Sparko PDP - Shaped Lollipops.html". Reuses the
   custom-image PDP's gallery, badge, accordion and select styling rather than
   restating it; only what the shaped page adds is below.
   ============================================================================ */

/* ---- buy column: price sub-line, quantity stepper, made-to-order note ---- */
.sparko-pdp-buy__pricesub {
  font-family: var(--main-font-stack, sans-serif); font-weight: 600; font-size: 0.85rem;
  letter-spacing: 0.01em; color: rgba(38, 38, 102, 0.72); margin: 0.3rem 0 0;
}
.sparko-pdp-cart-row { display: flex; gap: 0.75rem; align-items: stretch; margin-top: 0.375rem; }
.sparko-pdp-qty {
  display: flex; align-items: center; flex: 0 0 auto;
  border: 2px solid var(--sparko-navy); border-radius: 999px; background: #ffffff;
}
/* 42px, so the stepper comes to 46px with its 2px borders and the Add to Cart
   beside it stops being stretched to 56px. The row is `align-items: stretch`, so
   the TALLEST item sets the height: the button was already 46px on its own, and
   at 390 — where the row wraps and it sits on its own line — it measured exactly
   that. On desktop the stepper was inflating it.

   Tap target: the minus and plus become 46 x 42, which is 2px under the 44px
   guideline on the vertical axis. That is a deliberate trade for the narrower
   pill and it is still substantially larger than the live site's own stepper,
   which measures 48 x 38. Worth revisiting if the pill is ever allowed to be
   taller again. */
.sparko-pdp-qty button {
  width: 46px; height: 42px; background: none; border: none; cursor: pointer;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 1.4rem;
  color: var(--sparko-navy); line-height: 1; border-radius: 999px;
}
.sparko-pdp-qty button:hover { color: var(--sparko-pink); }
.sparko-pdp-qty button:disabled { color: rgba(38, 38, 102, 0.3); cursor: default; }
/* The count is a real number input so the form can post it and screen readers
   can read a value. Its spinner is hidden because the -/+ buttons are the
   affordance; the field itself stays focusable and typable. */
.sparko-pdp-qty__num {
  width: 3ch; min-width: 3ch; text-align: center; border: none; background: none;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 1.05rem;
  color: var(--sparko-navy); padding: 0; -moz-appearance: textfield;
}
.sparko-pdp-qty__num::-webkit-outer-spin-button,
.sparko-pdp-qty__num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.sparko-pdp-qty__num:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 2px; border-radius: 4px; }
/* Font size lives with the other PDP button sizing further up, not here: this
   rule sat later in the file and its 1.1rem was quietly winning, leaving the
   inline Add to Cart 2px taller than the stacked one at 48px against 46px. Only
   the flex behaviour belongs to this rule. */
.sparko-pdp-atc { flex: 1 1 auto; }
.sparko-pdp-fresh-note { margin: 0.75rem 0 0; }
/* The richtext supplies its own <p>, so the type rules target that. */
.sparko-pdp-fresh-note p {
  font-family: var(--main-font-stack, sans-serif); font-size: 1rem;
  color: rgba(38, 38, 102, 0.72); margin: 0;
}
.sparko-pdp-fresh-note strong { color: var(--sparko-navy); }

/* ---- more colours in this shape ---- */
.sparko-pdp-colors__head { margin-bottom: 2.5rem; }
.sparko-pdp-colors__grid {
  display: grid; grid-template-columns: repeat(var(--sparko-color-cols, 6), 1fr); gap: 1.5rem;
}
.sparko-pdp-color { display: flex; flex-direction: column; gap: 0.6rem; text-decoration: none; color: var(--sparko-navy); }
.sparko-pdp-color__img {
  display: block; position: relative; aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  background: #ffffff; border: 2px solid var(--sparko-navy); transition: filter 0.15s ease;
}
.sparko-pdp-color:hover .sparko-pdp-color__img { filter: brightness(0.9); }
.sparko-pdp-color__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-color__name {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1rem;
  line-height: 1.15; color: var(--sparko-navy);
}
.sparko-pdp-color__price { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem; color: var(--sparko-navy); }

/* ---- more shapes (navy band) ---- */
.sparko-pdp-shapes { background: var(--sparko-navy); --sparko-section-title-color: #ffffff; }
.sparko-pdp-shapes__head { margin: 0 auto 3rem; max-width: 45rem; text-align: center; }
.sparko-pdp-shapes__note {
  font-family: var(--main-font-stack, sans-serif); font-size: 1.1rem; line-height: 1.5;
  color: rgba(255, 255, 255, 0.82); margin: 1rem auto 0;
}
.sparko-pdp-shapes__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2rem 1.5rem; }
.sparko-pdp-shape { display: flex; flex-direction: column; gap: 0.75rem; text-decoration: none; }
.sparko-pdp-shape__img {
  display: block; position: relative; aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  background: #ffffff; border: 2px solid var(--sparko-gold); transition: filter 0.15s ease;
}
.sparko-pdp-shape:hover .sparko-pdp-shape__img { filter: brightness(0.9); }
.sparko-pdp-shape__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-shape__name {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1rem, 1.4vw, 1.3rem); line-height: 1;
  text-transform: uppercase; letter-spacing: -0.01em; color: #ffffff; text-align: center;
}
.sparko-pdp-shapes__all {
  width: fit-content; margin: 3rem auto 0;
  /* Same pill as .sparko-btn, which copies the live theme: 46px via min-height,
     16px sides, a 1rem/900 label at -0.05em. flex rather than block, because
     min-height only centres a label if the box is centring its content.

     This is DUPLICATION and it is why this button was missed when .sparko-btn
     was retuned: three CTAs in the theme draw their own pill instead of
     rendering that class. Anything that looks like a button should use
     .sparko-btn; if one of these is touched again, move it over. */
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; min-height: 46px; padding: 0 1rem;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1rem; text-transform: uppercase; letter-spacing: -0.05em;
  line-height: 1; border-radius: 999px;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-gold); color: var(--sparko-navy);
  text-decoration: none; text-align: center;
}
.sparko-pdp-shapes__all:hover { background: var(--sparko-gold-hover); color: var(--sparko-navy); }

/* ---- made for the occasion ---- */
.sparko-pdp-occ__head { margin: 0 auto 3rem; max-width: 45rem; text-align: center; }
.sparko-pdp-occ__lead {
  font-family: var(--main-font-stack, sans-serif); font-size: 1.15rem; line-height: 1.5;
  color: rgba(38, 38, 102, 0.72); margin: 1rem auto 0;
}
.sparko-pdp-occ__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
.sparko-pdp-occ__card {
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  padding: 1.5rem; display: flex; flex-direction: column; gap: 0.75rem;
}
.sparko-pdp-occ__num {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; line-height: 1;
  color: var(--sparko-gold); -webkit-text-stroke: 1.2px var(--sparko-navy);
}
.sparko-pdp-occ__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem;
  line-height: 1.1; margin: 0; color: var(--sparko-navy);
}
.sparko-pdp-occ__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.5; color: var(--sparko-navy); margin: 0; }
.sparko-pdp-occ__link {
  margin-top: auto; align-self: flex-start; padding-top: 0.5rem;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--sparko-pink); text-decoration: none;
  border-bottom: 2px solid var(--sparko-pink); padding-bottom: 1px;
}
.sparko-pdp-occ__link:hover { opacity: 0.78; }

/* ---- cross-sell (gold band) ---- */
.sparko-pdp-cross { background: var(--sparko-gold); }
.sparko-pdp-cross__head { margin: 0 auto 3rem; max-width: 45rem; text-align: center; }
.sparko-pdp-cross__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
.sparko-pdp-cross__card {
  background: var(--sparko-cream); border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  padding: 1.5rem; display: flex; flex-direction: column; gap: 0.75rem;
  text-decoration: none; color: var(--sparko-navy); transition: transform 0.15s ease;
  /* Card content is centred: title, line and pill. The image is exempt, it is a
     full-bleed edge-to-edge block and centring does nothing to it. */
  text-align: center; align-items: center;
}
/* align-items: center would shrink the full-bleed image to its content width,
   so it opts back out. */
.sparko-pdp-cross__card > .sparko-pdp-cross__img { align-self: stretch; }
.sparko-pdp-cross__card:hover { transform: translate(-2px, -2px); }
.sparko-pdp-cross__img {
  display: block; position: relative; aspect-ratio: 1 / 1; overflow: hidden;
  /* Bottom margin, not just the card's 12px flex gap: that left only 12px above
     the title against 24px of padding below the button, so the content sat high
     in the card. 12 + the 12px gap = 24, matching the padding. */
  margin: -1.5rem -1.5rem 0.75rem;
  border-bottom: 2px solid var(--sparko-navy);
  border-radius: calc(1.25rem - 2px) calc(1.25rem - 2px) 0 0;
}
.sparko-pdp-cross__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-pdp-cross__kicker {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.78rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--sparko-pink);
}
.sparko-pdp-cross__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; line-height: 1.1; margin: 0; }
.sparko-pdp-cross__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.4; color: rgba(38, 38, 102, 0.72); margin: 0; flex: 1 1 auto; }
.sparko-pdp-cross__cta { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.95rem; color: var(--sparko-pink); }

/* ---- responsive ---- */
@media (max-width: 980px) {
  .sparko-pdp-colors__grid { grid-template-columns: repeat(3, 1fr); }
  .sparko-pdp-shapes__grid { grid-template-columns: repeat(3, 1fr); }
  .sparko-pdp-occ__grid { grid-template-columns: 1fr 1fr; }
  .sparko-pdp-cross__grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .sparko-pdp-colors__grid { grid-template-columns: repeat(2, 1fr); }
  .sparko-pdp-shapes__grid { grid-template-columns: repeat(2, 1fr); }
  /* The occasion cards stay TWO across below 560px rather than collapsing to
     one, so the four read as a 2x2 block instead of a column four cards tall.
     `minmax(0, 1fr)` keeps a long word from pushing a track wider than its half.

     The card tightens with it. At two across a 390px screen gives each card
     159px, and at the full 1.5rem padding and 1rem body that left about 110px of
     text column — four words a line, and a card 361px tall to hold eight lines
     of a two-line sentence. 1rem of padding and a 0.9rem body give the text
     ~127px instead, which is most of the way back. The title and the number are
     untouched: they are the two things that have to stay legible at a glance. */
  .sparko-pdp-occ__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.75rem; }
  .sparko-pdp-occ__card { padding: 1rem; gap: 0.5rem; }
  .sparko-pdp-occ__line { font-size: 0.9rem; line-height: 1.45; }
  .sparko-pdp-cart-row { flex-wrap: wrap; }
  .sparko-pdp-atc { width: 100%; flex: 1 1 100%; }
}

/* ---- PDP hero: locked vertical rhythm ----
   Measured at 1440px on both Sparko templates: the title's top edge and the
   gallery's top edge already sit at the same y (151px on each). That alignment
   comes from .sparko-pdp-hero__grid's align-items: start, not from any height,
   and no min-height inside the buy column can change it -- both zones are at the
   grid's start edge, so a floor only moves where the column ENDS.

   So this floor is what a min-height can honestly lock: the buy column never
   bottoms out above its own gallery, which keeps the hero reading as two
   columns rather than one tall and one short.

   Value derived from the taller of the two galleries: 897px on custom-image,
   746px on shaped -> 900px. Deliberately NOT the taller buy column (1446px on
   custom-image vs 938px on shaped): that would have padded the shaped page with
   ~508px of empty space between the accordions and the section edge.

   Desktop only. Below 980px the grid is a single column, where a floor on the
   buy block would be dead space under the Add to Cart. */
@media (min-width: 981px) {
  .sparko-pdp-hero__grid > .sparko-pdp-buy { min-height: 900px; }
}

/* Shaped PDP: separate the trust badges from the buy controls.
   The badges sat 16px above the QUANTITY label while the cart row had 28px
   beneath it, so the cluster read as part of the buy block rather than as the
   end of the product summary.

   Scoped by adjacency rather than a new class: only the shaped buy column puts
   the badges immediately before the form. The custom-image column orders it
   form, badges, accordions, so this selector cannot match there. */
/* 1rem, not 2: the buy column's own flex gap already contributes 16px, so
   this lands the badges-to-QUANTITY gap at 32px against the cart row's 28px
   below. 2rem stacked to 48px, which over-separated it. */
.sparko-pdp-badges + .sparko-pdp-form { margin-top: 1rem; }

/* Cross-sell CTA as a pink pill, matching the option cards on the custom-image
   PDP and every other CTA on the site. It was a pink text link with a trailing
   arrow, the one affordance shape the brand does not use.

   Still a <span>, not an <a>: the whole card is already the link, so a nested
   anchor would be invalid and would give the card two tab stops. */
.sparko-pdp-cross__cta {
  align-self: center; margin-top: 0.35rem;
  padding: 0.7rem 1.4rem; border-radius: 999px;
  border: 2px solid var(--sparko-navy);
  background: var(--sparko-pink); color: #ffffff;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.02em;
  text-decoration: none; text-align: center;
}
.sparko-pdp-cross__card:hover .sparko-pdp-cross__cta { background: var(--sparko-pink-hover); }

/* Shaped PDP: Add to Cart is the primary action, so it is pink.
   The base .sparko-pdp-atc is the custom-image treatment, where ATC is the
   SECONDARY button sitting under the pink "Customize Your Pop" and is
   deliberately a navy outline. The shaped page has no Customize, so an outline
   ATC left that column with no primary button at all.
   Scoped by the row it sits in: .sparko-pdp-cart-row is the shaped layout,
   .sparko-pdp-atc-group is the custom-image one, so this cannot reach it. */
.sparko-pdp-cart-row .sparko-pdp-atc {
  background: var(--sparko-pink); color: #ffffff; border: 2px solid var(--sparko-navy);
}
.sparko-pdp-cart-row .sparko-pdp-atc:hover { background: var(--sparko-pink-hover); }

/* Page base is warm cream, per the design system's `.sp { background: cream }`.
   The white cards -- accordions, occasion cards, pack tiles -- were white on a
   white page, so they read as flat blocks rather than as cards. Applied to the
   PDP's neutral bands only; the navy and gold bands set their own. */
.sparko-pdp-hero,
.sparko-pdp-colors,
.sparko-pdp-occ,
.sparko-reviews { background: var(--sparko-cream); }

/* The hamburger alone is thickened, to 2.3. Its own snippet draws at 2, and two
   bars carry less ink than three, so it needs the extra weight to hold the
   header on its own at mobile widths.

   Everything else is left at its native weight, which is 1.7 for the search,
   account and cart icons and for the drawer close and search button. Note those
   are 1.7, NOT the 2 that icon-menu uses: stroke width is not consistent across
   the stock icon set. An earlier pass pushed all of them to 2.3 and read as
   heavy.

   Set in CSS because the stock snippets carry stroke-width="2" as a
   presentation attribute, which CSS outranks, so no stock file is edited. The
   icons use vector-effect: non-scaling-stroke, so the value is in screen units
   and does not scale with the viewBox. */
.sparko-header__burger svg [stroke] { stroke-width: 2.3; }

/* ---- header inline search bar ----
   Drops below the header when the search icon is clicked. The field is a rounded
   navy rectangle on cream; the browser's dotted focus ring is replaced with a
   pink glow on the container, so focus is still visible without the dashes. */
/* Inline: the search REPLACES the header bar rather than dropping below it, so
   the chrome keeps its height and the page does not shift. The bar is
   x-show="!searchOpen"; this sits in its place inside the same navy strip, so it
   inherits the header background and needs none of its own. Height is matched to
   the bar's so the swap does not jump. */
.sparko-header__searchbar {
  background: transparent;
  /* Same token as the bar, so opening search cannot nudge the page. Vertical
     padding is zero and the pill is sized off the token instead: padding here
     plus a pill with its own intrinsic height is two numbers that have to agree,
     which is exactly how this drifted the first time. */
  padding: 0 2rem;
  min-height: var(--sparko-header-h);
  display: flex;
  align-items: center;
}
.sparko-header__searchbar-form {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  max-width: 78rem;
  margin: 0 auto;
  /* Height from the bar's token, less a 10px inset so the pill sits inside the
     bar rather than filling it edge to edge. Vertical padding is zero because
     the height is fixed; the icon, field and close button centre themselves. */
  height: calc(var(--sparko-header-h) - 10px);
  padding: 0 1.1rem;
  border: 2px solid var(--sparko-navy, #262666);
  border-radius: 999px;
  background: #ffffff;
  width: 100%;
}
/* No pink halo. Focus is still visible, as a heavier navy border rather than a
   glow, so keyboard users keep an indicator without the pink fade. The border
   grows inward via a matching padding reduction, so the pill does not shift. */
.sparko-header__searchbar-form:focus-within {
  border-width: 3px;
  /* Horizontal only now. The extra 1px of border top and bottom is absorbed by
     the fixed height, so the pill still does not shift on focus. */
  padding-inline: calc(1.1rem - 1px);
}
.sparko-header__searchbar-icon { display: flex; flex: 0 0 auto; color: var(--sparko-navy, #262666); }
.sparko-header__searchbar-icon .theme-icon,
.sparko-header__searchbar-icon svg { width: 1.25rem; height: 1.25rem; }
.sparko-header__searchbar input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  padding: 0;
  font-family: var(--main-font-stack, sans-serif);
  font-size: 1rem;
  color: var(--sparko-navy, #262666);
}
.sparko-header__searchbar input::placeholder { color: rgba(38, 38, 102, 0.6); }
/* No dotted ring: the container's focus-within glow carries the state. */
.sparko-header__searchbar input:focus,
.sparko-header__searchbar input:focus-visible { outline: none; }
.sparko-header__searchbar input::-webkit-search-cancel-button { -webkit-appearance: none; }
.sparko-header__searchbar-close {
  flex: 0 0 auto;
  display: flex;
  border: 0;
  background: none;
  padding: 0;
  color: var(--sparko-navy, #262666);
  cursor: pointer;
}
.sparko-header__searchbar-close .theme-icon,
.sparko-header__searchbar-close svg { width: 1.25rem; height: 1.25rem; }

/* ---- theme cart drawer, brand colours ----
   Handled by the `drawer_color_scheme` theme setting (scheme8), not by CSS.
   There was a [data-modal-label] block here; it was removed because that
   attribute is not the cart drawer's. Nine stock surfaces carry it, including
   the collection filters and sort drawers, the video modal and the age gate,
   so the rule painted all of them cream. It also could not reach the checkout
   button, which is an <input class="push-btn__surface"> coloured from the
   drawer scheme's accent_1 rather than from `color`. Setting the scheme fixes
   the panel, the type and the button together, and keeps us off Switch's
   markup. See CLAUDE.md, running list of modified core files. */


/* ----------------------------------------------------------------------------
   12. Galaxy PDP (template: product.galaxy)
   Built from the v2 design "Sparko PDP - Galaxy Lollipops.html". Almost every
   zone reuses styles already defined above; what follows is only the delta.

   Nothing here is a second copy of an existing rule. The pack tiles, gallery,
   badges, accordions, quantity stepper, Add to Cart, product cards and section
   type are all the versions defined earlier in this file.
   ---------------------------------------------------------------------------- */

/* ---- band + column variants on two shared sections ----
   These make sparko-pdp-brand and sparko-pdp-shapes composable rather than
   forked. Each base rule above stays the default, so the custom-image and
   shaped PDPs render exactly as before. */

/* Brand band, Night Sky Blue. Used by the Galaxy "Made for the Moment" band.
   The eyebrow rule below is inert today: eyebrows are off theme-wide (see the
   EYEBROWS ARE OFF rule earlier in this file). It is here so that turning them
   back on does not leave a pink eyebrow on a navy band, where it fails contrast.
   Gold clears it. Do not read this rule as a reason to override the global one. */
.sparko-pdp-brand--navy { background: var(--sparko-navy); }
.sparko-pdp-brand--navy .sparko-pdp-brand__title { color: #ffffff; }
.sparko-pdp-brand--navy .sparko-pdp-brand__body { color: rgba(255, 255, 255, 0.86); }
.sparko-pdp-brand--navy .sparko-section-eyebrow { color: var(--sparko-gold); }
/* A navy border would vanish against a navy band, so the media frame takes gold. */
.sparko-pdp-brand--navy .sparko-pdp-brand__media { border-color: var(--sparko-gold); background: var(--sparko-navy); }

/* Media on the right. Desktop only: below 980px the grid is one column and the
   band stacks image first, which is what the base responsive rule already does. */
@media (min-width: 981px) {
  .sparko-pdp-brand__grid--media-right .sparko-pdp-brand__media { order: 2; }
}

/* Shapes grid, Warm Cream. Used by the Galaxy "The Designs" grid. The card
   border and the name both flip to navy, since the navy-band versions of both
   are tuned to sit on navy. */
.sparko-pdp-shapes--cream { background: var(--sparko-cream); --sparko-section-title-color: var(--sparko-navy); }
.sparko-pdp-shapes--cream .sparko-pdp-shapes__note { color: rgba(38, 38, 102, 0.72); }
.sparko-pdp-shapes--cream .sparko-pdp-shape__img { border-color: var(--sparko-navy); }
.sparko-pdp-shapes--cream .sparko-pdp-shape__name { color: var(--sparko-navy); }

/* Three up. Qualified at every width, not just desktop: an attribute selector
   outranks the bare-class rules in the media queries above whatever the order,
   so the narrow cases have to be restated here or the grid would stay three
   across on a phone. */
.sparko-pdp-shapes__grid[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 980px) {
  .sparko-pdp-shapes__grid[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 560px) {
  .sparko-pdp-shapes__grid[data-cols="3"] { grid-template-columns: repeat(2, 1fr); }
}

/* ---- pack tiles: quiet per-pop ----
   The design is explicit that per-pop is supporting text, never a discount
   badge. The shared tile prints it in caps; on this page it is sentence case so
   it reads as a note rather than a label. Colour and weight are unchanged. */

/* ---- you may also like ---- */
.sparko-pdp-related__head { margin: 0 0 3rem; }
.sparko-pdp-related__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
/* .sparko-prod carries a fixed flex-basis for the homepage carousel track. In
   this grid the card is the grid item and .sparko-prod is a flex CHILD of it, so
   that basis would become a fixed column height. Reset it here rather than
   weakening the carousel rule. */
.sparko-pdp-related__card { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; }
.sparko-pdp-related__card .sparko-prod { flex: 1 1 auto; width: 100%; }

/* Name centred, price centred on its own line beneath it, matching the live
   theme's related row (2026-09-08, at the client's direction). This is the same
   stack-and-centre override .sparko-best and .sparko-collection-grid__grid
   already carry; see the note at .sparko-best for why the shared card defaults
   to a space-between row instead of this.

   Like the collection grid and unlike the carousel, no price pinning is needed:
   each card is its own grid cell, so a two-line name moves only its own price
   rather than stepping the prices along a shared track. */
.sparko-pdp-related .sparko-prod { text-align: center; }
.sparko-pdp-related .sparko-prod__row {
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.35rem;
  text-align: center;
}
/* Full Night Sky Blue rather than the shared card's 70% tint, the same call
   .sparko-best made: centred on its own line the muted price read as disabled
   rather than as secondary. */
.sparko-pdp-related .sparko-prod__price { color: var(--sparko-navy); }

/* The quick-add / choose-options / sold-out button and its .sparko-pdp-related__form
   wrapper were removed here on 2026-09-08 at the client's direction. The card is
   the only control now. See the section file's comment for what that gave up. */

@media (max-width: 980px) {
  .sparko-pdp-related__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .sparko-pdp-related__grid { grid-template-columns: 1fr; }
}


/* ----------------------------------------------------------------------------
   13. Header mega menu + drawer groups
   Built from the v2 design's SpNavPanel and DRAWER_GROUPS (hifi/hifi-top.jsx,
   hifi-styles.css). Both are driven by Shopify menu children, so a dropdown
   exists when a menu item has child links and not otherwise.
   ---------------------------------------------------------------------------- */

/* ---- desktop mega panel ---- */
.sparko-header__item { position: relative; display: flex; align-items: center; }
/* The parent link keeps the nav's own type; the chevron is a size-matched hint. */
.sparko-header__item > .sparko-header__link { display: inline-flex; align-items: center; gap: 0.3rem; }
.sparko-header__item > .sparko-header__link svg { width: 0.85em; height: 0.85em; transition: transform 0.16s ease; }
.sparko-header__item:hover > .sparko-header__link svg,
.sparko-header__item:focus-within > .sparko-header__link svg { transform: rotate(180deg); }

.sparko-header__mega {
  position: absolute; top: 100%; left: -14px; z-index: 60;
  display: grid; grid-template-columns: minmax(190px, 1fr) 260px; gap: 2rem;
  margin-top: 12px; padding: 1.5rem;
  background: var(--sparko-cream); border: 2px solid var(--sparko-navy);
  border-radius: 20px;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
}
/* Hover AND focus-within, so the panel is reachable by keyboard without a
   toggle button. The parent link stays a plain link to its own page. */
.sparko-header__item:hover .sparko-header__mega,
.sparko-header__item:focus-within .sparko-header__mega {
  opacity: 1; visibility: visible; transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .sparko-header__mega { transition: none; transform: none; }
}
.sparko-header__mega-links { display: flex; flex-direction: column; gap: 2px; }
.sparko-header__mega-link {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9375rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--sparko-navy); text-decoration: none;
  padding: 0.5rem 0.875rem; border-radius: 999px; white-space: nowrap;
}
.sparko-header__mega-link:hover,
.sparko-header__mega-link:focus-visible,
.sparko-header__mega-link.is-active { color: var(--sparko-pink); background: rgba(38, 38, 102, 0.06); }
.sparko-header__mega-link:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 2px; }

/* Preview column: every frame stays mounted and stacked, so swapping is a class
   change rather than a re-render and the images do not reload on each hover. */
.sparko-header__mega-preview {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  border: 2px solid var(--sparko-navy); border-radius: 14px; overflow: hidden; background: #ffffff;
}
.sparko-header__mega-frame { position: absolute; inset: 0; display: none; }
.sparko-header__mega-frame.is-on { display: block; }
.sparko-header__mega-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Below the collapse breakpoint the whole desktop nav is hidden, so the panel
   goes with it. Nothing to undo here; this note exists so a future reader does
   not add a redundant mobile override. */

/* ---- drawer groups ---- */
.sparko-header__drawer-group { border: 0; }
/* Size and leading MUST track `.sparko-header__drawer-nav a` above, not the
   theme's 1.35rem card-title size. A top-level item with children renders as a
   <summary> rather than an <a>, so it never matches that anchor rule and has to
   restate it. It was 1.35rem with no line-height, which put SHOP / SHAPES /
   COLORS 10% smaller than CUSTOMIZE / OUR WORK / OCCASIONS beside them and on a
   looser rhythm. Same row, same level, so they take the same type.

   The 1.0625rem second-level override lives further down under --sub and is
   unaffected; it is a different level of the ramp, deliberately. */
.sparko-header__drawer-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  cursor: pointer; list-style: none;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.5rem;
  line-height: 1.1;
  text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy);
  /* Restated for the same reason as the size above: a summary is not an <a>, so
     it misses the padding on `.sparko-header__drawer-nav a`. Without this the
     three expandable rows would be the only under-sized targets in the list. */
  padding: 0.55rem 0;
}
.sparko-header__drawer-summary::-webkit-details-marker { display: none; }
@media (hover: hover) {
  .sparko-header__drawer-summary:hover { color: var(--sparko-pink); }
}
.sparko-header__drawer-summary:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 3px; border-radius: 4px; }
.sparko-header__drawer-summary svg { flex: none; width: 1.25rem; height: 1.25rem; transition: transform 0.2s ease; }
.sparko-header__drawer-group[open] .sparko-header__drawer-summary svg { transform: rotate(180deg); }
/* Same trade as the nav above: the rows carry their own padding now, so the gap
   drops to a hair and the top margin goes with it. The 0.75rem left margin is
   the indent and stays. */
.sparko-header__drawer-sub { display: flex; flex-direction: column; gap: 0.25rem; margin: 0.25rem 0 0 0.75rem; }
/* Qualified with the nav, because `.sparko-header__drawer-nav a` sets Filson 900
   at the parent's display size on EVERY anchor in the drawer and outranks a bare
   class. Unqualified, the children rendered identically to their parents and the
   group read as one flat list.

   Subordinate treatment matches the design's own drawer (hifi-styles.css
   .sp-drawer-sublink against .sp-drawer-item): the body face at 700 rather than
   the display face at 900, and roughly two thirds the size. Still uppercase, so
   it reads as navigation rather than prose. */
.sparko-header__drawer-nav .sparko-header__drawer-sublink {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 700;
  font-size: 1.0625rem;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sparko-navy);
  text-decoration: none;
}
@media (hover: hover) {
  .sparko-header__drawer-nav .sparko-header__drawer-sublink:hover { color: var(--sparko-pink); }
}

/* ---- drawer groups: animated collapse ----
   Switch's sidebar-nav opens its branches with Alpine's x-collapse. This drawer
   is <details>, kept for the no-script / keyboard / find-in-page reasons noted
   in the section, so the same feel comes from ::details-content instead. That
   pseudo-element is the only handle on a disclosure's own box, and
   interpolate-size is what makes the 0 -> auto height interpolation legal.

   It is scoped to the drawer rather than :root deliberately: interpolate-size
   inherits, and switching it on globally would quietly change how every other
   auto-sized transition on the site behaves.

   A browser without ::details-content skips both rules and keeps the instant
   open/close this drawer already shipped, so there is no fallback to write. */
.sparko-header__drawer { interpolate-size: allow-keywords; }
.sparko-header__drawer-group::details-content {
  block-size: 0;
  overflow: hidden;
  opacity: 0;
  transition: block-size 300ms ease, opacity 200ms ease, content-visibility 300ms;
  transition-behavior: allow-discrete;
}
.sparko-header__drawer-group[open]::details-content {
  block-size: auto;
  opacity: 1;
}

/* Second-level group. Same control as the top level one step down the ramp, so
   a branch reads as subordinate to its parent while still reading as a control
   rather than a link. Matches the sublink face it sits among; the chevron
   shrinks with it. Both selectors tie the top-level rules on specificity and win
   on source order, which is why they live below rather than above. */
.sparko-header__drawer-summary--sub {
  font-family: var(--main-font-stack, sans-serif);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: 0.04em;
}
.sparko-header__drawer-summary--sub svg { width: 1rem; height: 1rem; }
.sparko-header__drawer-sub--deep { margin: 0.25rem 0 0.25rem 1rem; gap: 0.25rem; }
.sparko-header__drawer-sub--deep .sparko-header__drawer-sublink {
  font-size: 0.9375rem;
  letter-spacing: 0.03em;
}

/* Staggered reveal on open.

   Switch's sidebar-nav-list-item.liquid sets --first-delay-tap /
   --second-delay-tap / --third-delay-tap inline on every row for exactly this,
   and gates it behind a sidebar-nav--enable-transitions class. NOTHING in this
   theme consumes any of them: grep base.bundle.css for `delay-tap` or
   `sidebar-nav` and there are no hits, because the rules were purged from the
   precompiled build. Stock Shapes ships the hooks with the animation dead.

   So this is our implementation of the effect that markup was reaching for, not
   a port of working stock CSS. Index comes from --sparko-drawer-i, set inline
   per row the same way Switch sets its own counters. */
.sparko-header__drawer-group[open] > .sparko-header__drawer-sub > * {
  animation: sparko-drawer-row-in 260ms ease both;
  animation-delay: calc(var(--sparko-drawer-i, 0) * 28ms);
}
@keyframes sparko-drawer-row-in {
  from { opacity: 0; transform: translateX(-6px); }
  to { opacity: 1; transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .sparko-header__panel--anim,
  .sparko-header__drawer-group::details-content,
  .sparko-header__drawer-summary svg { transition: none; }
  .sparko-header__drawer-group[open] > .sparko-header__drawer-sub > * { animation: none; }
}


/* ----------------------------------------------------------------------------
   14. Collection page (template: collection.honey, reusable by any collection)
   Built from the v2 design "Sparko Collection - Honey Lollipops.html".
   The product card itself is section 4's .sparko-prod* rules, shared with the
   bestsellers carousel and the PDP related grid; only the additions the Honey
   card needs are defined here.
   ---------------------------------------------------------------------------- */

/* ---- shared card additions (hover image, badge, stars, kicker, line, cta) ----
   These extend .sparko-prod rather than forking it, so the three surfaces that
   render sparko-product-card stay one implementation. Every one is inert unless
   the caller passes the matching parameter. */
.sparko-prod__img { position: relative; }
.sparko-prod__alt {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: var(--sparko-cream); transition: opacity 0.18s ease;
}
.sparko-prod__alt img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-prod:hover .sparko-prod__alt,
.sparko-prod:focus-visible .sparko-prod__alt { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .sparko-prod__alt { transition: none; }
}
.sparko-prod__badge {
  position: absolute; top: 0.75rem; left: 0.75rem; z-index: 2;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  background: var(--sparko-gold); color: var(--sparko-navy);
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  padding: 5px 11px; white-space: nowrap;
}
/* Judge.me mounts into this; it is empty until the widget hydrates, so it must
   not reserve space or the card rows would sit unevenly before load. */
.sparko-prod__stars { display: block; line-height: 1; }
.sparko-prod__stars:empty { display: none; }
.sparko-prod__kicker {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.75rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sparko-pink);
}
.sparko-prod__line { font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem; line-height: 1.4; color: rgba(38, 38, 102, 0.72); }
.sparko-prod__cta { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9rem; color: var(--sparko-pink); }

/* ---- collection hero ----
   A horizontal banner with the title and one short line of live text over the
   image, following the Shapes 3.0 reference for its proportions (measured live:
   a 1440x445 banner, ratio 3.2, grid immediately below).

   CENTRED 2026-09-07, at the client's direction: the text is centred and so is
   the box holding it, on desktop and on a phone. It was left-aligned on the
   container gutter until then, which is what the comments below used to
   describe. Alignment is the ONLY thing that changed — the banner ratios, the
   type scale, the spacing and the width caps are all untouched, so line lengths
   are exactly what the reference gave them.

   ONE copy block serves both layouts. Absolutely positioned over the banner
   from 761px up; static underneath it on a phone, on Warm Cream. That is why
   there is no duplicate markup and nothing to keep in sync.

   NO scrim, gradient or shade anywhere in here, per the no-fade rule in
   CLAUDE.md. Legibility comes from the focal point moving the crop and from the
   title colour, both per-collection settings. */
.sparko-collection-hero { position: relative; background: var(--sparko-cream); }

/* Shallow on purpose: the reference runs 16/9 on a phone and 3.2/1 on desktop,
   which is what keeps the first row of products near the top of the screen. */
.sparko-collection-hero__frame { aspect-ratio: 16 / 9; overflow: hidden; }
.sparko-collection-hero__img {
  width: 100%; height: 100%; display: block; object-fit: cover;
  object-position: var(--sparko-hero-focal, center);
}

/* One declaration centres the text in BOTH layouts, the absolutely positioned
   desktop one and the static phone one, because both inherit from here. It also
   reaches the text-only header, which has no media to position against. */
.sparko-collection-hero__copy { padding-block: 1.25rem 1.5rem; text-align: center; }
.sparko-collection-hero__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.9259rem, calc(0.4444rem + 7.41vw), 6rem); line-height: 0.92;
  letter-spacing: -0.01em; text-transform: uppercase;
  color: var(--sparko-navy); margin: 0;
}
.sparko-collection-hero__desc {
  font-family: var(--main-font-stack, sans-serif); font-weight: 500;
  font-size: 1.05rem; line-height: 1.45; color: var(--sparko-navy);
  /* `auto` inline margins, not `0`: text-align centres the lines INSIDE the
     box, this centres the capped box itself. The 40rem cap is unchanged, and it
     stays inert below 640px, so no phone sees a width change from it. */
  margin: 0.6rem auto 0; max-width: 40rem;
}
.sparko-collection-hero__desc p { margin: 0; }
.sparko-collection-hero__desc p + p { margin-top: 0.4rem; }

/* Text-only header, for a collection with no artwork. Compact by design: it is
   a label on the page, not a hero. */
.sparko-collection-hero--textonly { padding-block: 1.75rem 1.25rem; }
.sparko-collection-hero--textonly .sparko-collection-hero__copy { padding-block: 0; }

@media (min-width: 761px) {
  .sparko-collection-hero__frame { aspect-ratio: 3.2 / 1; }
  /* Over the image. `inset: 0` plus flex centring puts the block on the
     vertical middle of the banner; .sparko-wrap inside it supplies the same
     container and gutter every other section uses, so the centred copy shares
     its axis with the grid below rather than with the raw viewport.
     pointer-events stay off the box so it never sits between a cursor and the
     image. */
  .sparko-collection-hero:not(.sparko-collection-hero--textonly) .sparko-collection-hero__copy {
    position: absolute; inset: 0;
    display: flex; align-items: center;
    padding-block: 0;
    pointer-events: none;
    /* Left on desktop, centred on phones (client direction, 2026-09-10). This
       reverses the desktop half of 2a1482c, which centred both layouts on
       2026-09-07, also at the client's direction; the phone half of that commit
       stands, and the base rule above still centres it. Scoped to the BANNER
       layout: a text-only collection header has no artwork to sit against and
       stays centred. */
    text-align: left;
  }
  /* .sparko-wrap carries `margin: 0 auto`, which inside a flex row centres it
     instead of spanning the banner, so the copy started a third of the way
     across rather than on the container gutter. Width 100% makes the wrap fill
     the row again and the auto margins become inert. It still earns its place
     now that the copy is centred: a shrink-wrapped wrap would look centred too,
     but it would stop being the shared container, and the gutter that keeps the
     copy off the edge of a narrow screen would go with it. */
  .sparko-collection-hero:not(.sparko-collection-hero--textonly) .sparko-collection-hero__copy > .sparko-wrap {
    width: 100%;
  }
  /* The 34rem cap is kept EXACTLY as it was, so wrapping and line length are
     untouched; what changed is that the capped box now sits on the middle of
     the banner instead of against the left gutter. Its original reason — break
     the line before it runs into the subject of the photo — has expired, since
     the type is now in the middle where the subject usually is. The cap stays
     anyway, because a measure cap is worth having on its own, and legibility
     now rests on the focal point keeping the CENTRE of the photo quiet. */
  .sparko-collection-hero:not(.sparko-collection-hero--textonly) .sparko-collection-hero__title,
  .sparko-collection-hero:not(.sparko-collection-hero--textonly) .sparko-collection-hero__desc {
    /* `margin-inline: 0`, not `auto`: text-align moves the lines inside the box,
       this puts the capped box itself back on the container gutter. Both are
       needed, which is the same pair 2a1482c used in the other direction. The
       34rem cap is untouched, so wrapping and line length do not move. */
    max-width: 34rem; margin-inline: 0;
  }
  .sparko-collection-hero--textonly { padding-block: 2.25rem 1.5rem; }
}

/* Title colour is the only legibility lever; the description follows it. */
.sparko-collection-hero--cream .sparko-collection-hero__title,
.sparko-collection-hero--cream .sparko-collection-hero__desc { color: var(--sparko-cream); }

@media (max-width: 760px) {
  /* Under the image, on Warm Cream, tight. Products should appear early. */
  .sparko-collection-hero--cream .sparko-collection-hero__title,
  .sparko-collection-hero--cream .sparko-collection-hero__desc { color: var(--sparko-navy); }
  .sparko-collection-hero__desc { font-size: 0.95rem; }
}

/* ---- filter bar ---- */
.sparko-collection-bar {
  background: color-mix(in srgb, var(--sparko-gold) 12%, var(--sparko-cream));
  border-top: 2px solid var(--sparko-navy); border-bottom: 2px solid var(--sparko-navy);
  padding: 0.75rem 0; z-index: 30;
}
.sparko-collection-bar--sticky { position: sticky; top: 0; }
.sparko-collection-bar__row { display: flex; align-items: center; gap: 0.5rem; overflow-x: auto; scrollbar-width: none; }
.sparko-collection-bar__row::-webkit-scrollbar { display: none; }
.sparko-collection-bar__label {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: rgba(38, 38, 102, 0.72);
  margin-right: 0.5rem; flex: none;
}
.sparko-facet { flex: none; position: relative; }
.sparko-facet__btn {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer; list-style: none;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  background: #ffffff; color: var(--sparko-navy);
  padding: 10px 18px; line-height: 1; white-space: nowrap;
  transition: background-color 0.15s ease;
}
.sparko-facet__btn::-webkit-details-marker { display: none; }
.sparko-facet__btn:hover { background: color-mix(in srgb, var(--sparko-gold) 20%, #ffffff); }
.sparko-facet__btn:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 2px; }
.sparko-facet--active .sparko-facet__btn { background: var(--sparko-gold); }
.sparko-facet__btn svg { width: 1rem; height: 1rem; transition: transform 0.15s ease; }
.sparko-facet[open] .sparko-facet__btn svg { transform: rotate(180deg); }
.sparko-facet__count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; border-radius: 999px;
  background: var(--sparko-navy); color: #ffffff; font-size: 0.75rem; padding: 0 5px;
}
/* The chip tray floats over the grid rather than pushing it down, so opening a
   facet never moves the products the shopper is looking at. */
.sparko-facet__chips {
  position: absolute; top: calc(100% + 0.6rem); left: 0; z-index: 40;
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  min-width: 16rem; max-width: min(28rem, 90vw); padding: 0.9rem;
  background: var(--sparko-cream); border: 2px solid var(--sparko-navy); border-radius: 1rem;
}
.sparko-fchip {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.84rem;
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  background: #ffffff; color: var(--sparko-navy); text-decoration: none;
  padding: 8px 15px; line-height: 1; white-space: nowrap;
  transition: background-color 0.15s ease;
}
.sparko-fchip:hover { background: color-mix(in srgb, var(--sparko-gold) 20%, #ffffff); }
.sparko-fchip--on { background: var(--sparko-gold); }
.sparko-fchip[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }
.sparko-collection-bar__clear {
  flex: none; font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px;
  padding: 10px 6px; white-space: nowrap;
}

/* ---- grid ----
   Warm Cream behind the whole grid section, 2026-09-07. Every collection page
   used to sit on the browser's white `body` here: the hero painted its own
   cream, the grid painted nothing, and the join between them was visible.

   ONE declaration covers both the grid and the pagination because the pager is
   inside this section — `.sparko-collection-grid__body` holds the count, the
   grid and `.sparko-collection-grid__pager`. Painting the section rather than
   the inner wrap also means the colour runs edge to edge instead of stopping at
   the container gutter.

   Deliberately NOT painted, each for its own reason:
   - `.sparko-prod__img` stays white. Product cutouts are shot on white and a
     cream tile behind a white-matted photo shows the seam.
   - `.sparko-collection-bar` keeps its gold-tinted cream. It is the filter bar,
     it is meant to read as a distinct strip, and it is a child of this section
     so it would otherwise have been flattened by this rule.
   - The banner artwork is untouched; the hero paints cream behind the photo,
     not over it.
   - The sections BELOW the grid (`sparko-pdp-brand`, `sparko-cta-band`,
     `sparko-reviews`, `sparko-pdp-faq`) are shared with the product templates,
     so colouring them here would repaint every PDP too. They are out of scope
     for a collection-scoped change. */
.sparko-collection-grid { background: var(--sparko-cream); }
.sparko-collection-grid__body { padding-block: 2.5rem 3.5rem; }
.sparko-collection-grid__count { font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; color: rgba(38, 38, 102, 0.72); margin: 0 0 1.5rem; }
.sparko-collection-grid__empty { font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; color: rgba(38, 38, 102, 0.72); margin: 0; }
.sparko-collection-grid__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem 1rem; }
/* .sparko-prod carries a fixed flex-basis for the bestsellers carousel track.
   In this grid the card is the grid item, so that basis has to be reset or every
   column would lock to the carousel's card width. Same reset the PDP related
   grid needs, kept here rather than weakening the carousel rule. */
.sparko-collection-grid__grid .sparko-prod { flex: 1 1 auto; width: 100%; }

/* Every collection centres its card type and stacks the price under the name,
   replacing the shared card's name-left / price-right row. Scoped to this
   section, which is the grid on all five collection templates, so all 44
   collections pick it up and no other surface using the shared card changes.

   The whole card centres rather than just the two rows, so anything that joins
   it later lands centred too. Today the only other child is the Judge.me badge,
   and that is invisible on every Sparko card regardless: the app injects
   `.jdgm-preview-badge[data-template="index"] { display: none !important }` and
   this card hardcodes `data-template="index"`. The review counts are in the DOM
   and have never rendered. That is a Judge.me setting, not a theme rule, so it
   is left alone here rather than fought with a competing !important.

   This is the same stack-and-centre override .sparko-best already carries; see
   the note there for why the shared card defaults to a row instead. Unlike the
   carousel this grid needs no price pinning, because rows sit in independent
   grid cells rather than along one track, so a two-line name only moves its own
   price. */
.sparko-collection-grid__grid .sparko-prod { text-align: center; }
.sparko-collection-grid__grid .sparko-prod__row {
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.35rem;
  text-align: center;
}

@media (min-width: 700px) {
  .sparko-collection-grid__grid { grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
}
@media (min-width: 1020px) {
  .sparko-collection-grid__grid { grid-template-columns: repeat(4, 1fr); }
  .sparko-collection-grid__body { padding-block: 3.5rem 5rem; }
}


/* ----------------------------------------------------------------------------
   15. Honey Dipper PDP (template: product.honey)
   Built from the v2 design "Sparko PDP - Honey Dipper.html". The hero, badges,
   pack tiles, accordions, gold band, cross-sell and related grid are all the
   versions already defined above; only the delta is here.
   ---------------------------------------------------------------------------- */

/* ---- brand band: cream variant + fact pills ----
   Cream is the third band. It carries no background of its own beyond the page
   colour, so the media frame keeps the navy border it has on gold. */
.sparko-pdp-brand--cream { background: var(--sparko-cream); }

.sparko-pdp-brand__facts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; }
.sparko-pdp-brand__fact {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.84rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  padding: 8px 16px; color: var(--sparko-navy); white-space: nowrap;
  background: rgba(254, 251, 245, 0.6);
}
/* On the navy band a navy-on-translucent-cream pill would fight the ground, so
   the pill inverts to a light outline. */
.sparko-pdp-brand--navy .sparko-pdp-brand__fact { border-color: rgba(255, 255, 255, 0.5); color: #ffffff; background: transparent; }

/* ---- taste notes ---- */
.sparko-pdp-notes__mod {
  border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  background: #ffffff; padding: 3rem;
}
.sparko-pdp-notes__head { margin-bottom: 2rem; text-align: center; }
.sparko-pdp-notes__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.625rem; margin: 0; color: var(--sparko-navy); }
.sparko-pdp-notes__row { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
.sparko-pdp-notes__col { display: flex; flex-direction: column; gap: 8px; }
/* Gold numeral with a navy stroke, the same treatment the FAQ and process
   numerals use, so the module reads as part of the system. */
.sparko-pdp-notes__num {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.375rem; line-height: 1;
  color: var(--sparko-gold); -webkit-text-stroke: 1.2px var(--sparko-navy);
}
.sparko-pdp-notes__when {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--sparko-navy);
}
.sparko-pdp-notes__line { font-family: var(--main-font-stack, sans-serif); font-size: 1.09rem; line-height: 1.45; color: var(--sparko-navy); margin: 0; }

@media (min-width: 981px) {
  /* Columns follow the block count rather than a fixed three, so a two-note or
     four-note module still fills the panel evenly. */
  .sparko-pdp-notes__row { grid-template-columns: repeat(3, 1fr); gap: 3rem; }
  .sparko-pdp-notes__row[data-count="2"] { grid-template-columns: repeat(2, 1fr); }
  .sparko-pdp-notes__row[data-count="4"] { grid-template-columns: repeat(4, 1fr); }
  .sparko-pdp-notes__col + .sparko-pdp-notes__col { border-left: 2px solid rgba(38, 38, 102, 0.18); padding-left: 3rem; }
}
@media (max-width: 980px) {
  .sparko-pdp-notes__mod { padding: 1.75rem; }
  .sparko-pdp-notes__col + .sparko-pdp-notes__col { border-top: 2px solid rgba(38, 38, 102, 0.18); padding-top: 1.5rem; }
}

/* ---- brand band: centre the prose in its column ----
   The text column is a grid fraction, so it is always wider than the prose
   inside it. Left as-is that leftover pools on one side, and which side depends
   on where the media sits: with the media LEFT it pools at the page edge, with
   the media RIGHT it lands between the prose and the picture. On this PDP that
   read as a 64px gutter on the gold band against 153px on the cream one.

   Shrinking the block to its content and centring it splits the leftover evenly,
   so the prose sits in the middle of its half whichever side the media is on and
   the two bands balance against each other.

   Worth knowing: this centres the BLOCK, not the text. Lines stay left aligned
   and ragged right, so the heading and body keep one shared left edge.

   Desktop only. Below 980px the grid is one column, the block already fills it,
   and centring would do nothing but indent the copy. */
@media (min-width: 981px) {
  .sparko-pdp-brand__text {
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
  }
  /* The centred variant measures against the whole grid cell rather than
     shrink-wrapping. With width: fit-content the column collapses to its widest
     child, which is the body's 46ch measure, and everything would centre over
     that box rather than over the cell. Visually close, but it moves whenever
     the copy changes length. */
  .sparko-pdp-brand__text--center { width: 100%; }
}


/* ----------------------------------------------------------------------------
   16. Star Twinkle Pops PDP (template: product.twinkle)
   Built from the v2 design "Sparko PDP - Star Twinkle Pops.html". The gallery,
   badges, pack tiles, accordions, navy and gold bands, shapes grid, related grid
   and section type are all the versions already defined above; only the delta is
   here, and the delta is almost entirely the colour swatch selector.
   ---------------------------------------------------------------------------- */

/* ---- colour swatches ----
   Shared with any PDP that passes a swatch option to sparko-pdp-options, not
   Twinkle-only, which is why the classes are sparko-pdp-* rather than a Twinkle
   prefix. Only this template uses one today. */
.sparko-pdp-swatches { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
.sparko-pdp-swatch {
  flex: 0 0 auto; width: 42px; height: 42px; border-radius: 50%; padding: 0;
  border: 2px solid var(--sparko-navy); cursor: pointer;
  /* The border sits on top of the fill rather than outside it, so a swatch whose
     colour is close to navy still reads as a ring rather than a smudge. */
  background-clip: padding-box;
  transition: box-shadow 0.15s ease;
}
.sparko-pdp-swatch:hover { filter: brightness(0.88); }
/* Selected state is a gold ring floated off the swatch by a cream gap, which is
   the same gold the selected pack tile uses. A border change would have moved
   the swatch by a pixel and shifted the whole row. */
.sparko-pdp-swatch[aria-checked="true"] {
  box-shadow: 0 0 0 3px var(--sparko-cream), 0 0 0 6px var(--sparko-gold);
}
.sparko-pdp-swatch:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .sparko-pdp-swatch { transition: none; }
}
/* Fallback for an option value with no colour configured. Auto width and a pill
   radius, so it reads as a labelled chip rather than a broken circle. */
.sparko-pdp-swatch--text {
  width: auto; height: auto; border-radius: 999px; padding: 10px 18px;
  background: #ffffff; color: var(--sparko-navy);
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  line-height: 1; white-space: nowrap;
}
.sparko-pdp-swatch-name {
  font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.4;
  color: var(--sparko-navy); margin: 0.5rem 0 0;
}
.sparko-pdp-swatch-name strong { font-weight: 800; }

/* ----------------------------------------------------------------------------
   17. Bestsellers card: stacked, centred name and price
   The shared card puts the name and price on one baseline row with the price
   pushed right, which is what the collection grid and the PDP related grid want.
   The homepage carousel wants them stacked and centred instead, so the override
   is scoped to .sparko-best rather than applied to .sparko-prod, which would
   have moved all three surfaces.
   ---------------------------------------------------------------------------- */
.sparko-best .sparko-prod__row {
  /* Was a flex row with space-between. Column + centre stacks the price under
     the name and centres both, without touching the shared rule. */
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.35rem;
  text-align: center;
}
/* Full Night Sky Blue, not the shared card's 70% tint. At this size, centred
   under the name, the muted price read as disabled rather than secondary. */
.sparko-best .sparko-prod__price { color: var(--sparko-navy); }

/* Prices sit on one line across the whole carousel.
   Stacking the price under the name meant a two-line name pushed its price a row
   lower than a one-line name's, so the prices stepped up and down along the
   track. The track sets no align-items, so its cards already stretch to the
   tallest; the row takes that leftover height and the price is pinned to the
   bottom of it. Any extra space lands between the name and the price instead.

   Deliberately not a min-height on the name: that only holds while no name wraps
   past the line count it was set to, and these are real product titles. This
   measures whatever the tallest card actually is, so a three-line title keeps
   the row aligned rather than breaking it. */
.sparko-best .sparko-prod__row { flex: 1 1 auto; }
.sparko-best .sparko-prod__price { margin-top: auto; }


/* ----------------------------------------------------------------------------
   18. Our Story page (template: page.our-story)
   Built from the v2 design "Sparko Our Story.html". Three of the six sections
   are shared: the two colour bands are sparko-pdp-brand, and the headings and
   section rhythm are the site-wide ones. Only the delta is here.

   Headings use .sparko-section-title, so they centre with every other heading on
   the site. The comp draws them left, the same way it draws eyebrows the theme
   hides; the theme's decision wins. Prose stays left aligned inside its column,
   because a centred paragraph is harder to read across several lines.
   ---------------------------------------------------------------------------- */

/* Copy-only band: one column, and the prose capped rather than left to run the
   full 1820px shell. Without this the grid keeps its two columns and the copy
   sits in the right half with an empty left half beside it. The centring rule
   the brand band already carries then puts the block in the middle. */
.sparko-pdp-brand__grid--no-media { grid-template-columns: 1fr; }
.sparko-pdp-brand__grid--no-media .sparko-pdp-brand__body { max-width: 46rem; }

/* ---- page hero ---- */
/* Symmetric at the same 32/64 the first-section rule sets on top. The bottom
   was 56px, which put 96px of cream between the hero's CTA and the client
   strip's first line once that section's own 40px top padding was added. */
.sparko-page-hero { background: var(--sparko-cream); padding-block: 2rem; }
/* The centring moved off __inner and onto __copy when the split layout arrived.
   __inner is now only the one-or-two column shell, so the centred variant is
   still a single full-width flex column and renders exactly as it did before. */
.sparko-page-hero__inner { display: block; }
.sparko-page-hero__copy { display: flex; flex-direction: column; align-items: center; text-align: center; }
.sparko-page-hero__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(2.006rem, calc(0.8904rem + 5.58vw), 5.75rem); line-height: 0.95;
  letter-spacing: -0.01em; text-transform: uppercase;
  color: var(--sparko-navy); margin: 0 0 1.25rem;
  /* Capped in characters, not pixels, so the headline breaks into the same
     shape whatever the display size resolves to at this viewport. */
  max-width: 16ch;
}
/* The title's bottom margin exists to separate it from the sub-paragraph. With no
   sub it is the last child, and that margin was pushing the band 20px taller
   below the headline than above it. */
.sparko-page-hero__title:last-child { margin-bottom: 0; }
.sparko-page-hero__sub {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.06rem, 1.7vw, 1.35rem); line-height: 1.55;
  color: var(--sparko-navy); margin: 0; max-width: var(--sparko-measure);
}
.sparko-page-hero__sub p { margin: 0 0 0.75rem; }
.sparko-page-hero__sub p:last-child { margin-bottom: 0; }
.sparko-page-hero__cta { margin-top: 1.75rem; }

/* Split layout, the B2B page opening. Photo first while stacked, beside the copy
   from 1020px up, which is the breakpoint and the order all three comps use. */
.sparko-page-hero--split .sparko-page-hero__inner { display: grid; grid-template-columns: 1fr; gap: 2.5rem; align-items: center; }
.sparko-page-hero--split .sparko-page-hero__copy { align-items: flex-start; text-align: left; }
/* The 16ch cap exists to shape a headline that would otherwise run the full
   1820px shell. In the split the column already does that job, so the cap comes
   off. The type also steps down: the centred ramp is sized against the whole
   shell, and at 6.6vw a single word filled the column, which put "Custom
   Lollipops for Brand Activations and Productions" on six lines. 5vw is the
   comp's own proportion, and it lands that headline on four. */
.sparko-page-hero--split .sparko-page-hero__title {
  max-width: none; font-size: clamp(1.8296rem, calc(1.0509rem + 3.89vw), 4.75rem);
}
.sparko-page-hero--split .sparko-page-hero__sub { margin-inline: 0; max-width: 35rem; }
/* Centred split hero, used by the three B2B pages (2026-09-08, at the client's
   direction). This is a REVERSAL of the left alignment recorded in CLAUDE.md,
   which was itself set at the client's direction on 2026-08-08; that note has
   been updated rather than left to contradict this.

   Only the split variant reads it. The centred layout centres already, from the
   base .sparko-page-hero__copy rule that split overrides here.

   The sub needs its own line: split sets margin-inline: 0 to pin the paragraph
   to the left edge of the column, and text-align alone would leave a 35rem
   measure sitting left inside a wider column with its lines centred inside it. */
.sparko-page-hero--split.sparko-page-hero--align-center .sparko-page-hero__copy {
  align-items: center;
  text-align: center;
}
.sparko-page-hero--split.sparko-page-hero--align-center .sparko-page-hero__sub { margin-inline: auto; }
.sparko-page-hero--split .sparko-page-hero__media {
  order: -1;
  aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-page-hero--split .sparko-page-hero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 1020px) {
  .sparko-page-hero--split .sparko-page-hero__inner { grid-template-columns: 1.05fr 1fr; gap: 4rem; }
  .sparko-page-hero--split .sparko-page-hero__media { order: 0; }
}
@media (max-width: 700px) {
  .sparko-page-hero--split .sparko-page-hero__cta .sparko-btn { width: 100%; }
}

/* ---- wholesale hero ---- */
/* sections/wholesale-hero.liquid wears the split page hero above; these rules
   cover only what it adds. Two pills side by side (pink primary, outline
   secondary), wrapping to a stack on narrow columns, and full width under 700px
   through the page-hero rule above. */
.sparko-wholesale-hero__ctas { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem; align-self: stretch; }
/* The applicant state's contact line: quieter than the sub-paragraph. */
.sparko-wholesale-hero__note {
  margin-top: 1.25rem; max-width: 35rem;
  font-family: var(--main-font-stack, sans-serif);
  font-size: 0.95rem; line-height: 1.5; color: var(--sparko-navy);
}
.sparko-wholesale-hero__note p { margin: 0; }
.sparko-wholesale-hero__note a { color: inherit; text-decoration: underline; text-underline-offset: 0.2em; }
/* The company-name eyebrow (an --on opt-in) sits in a centred column, so it
   centres with the headline instead of taking --on's left alignment. */
.sparko-wholesale-hero .sparko-wholesale-hero__company { text-align: center; margin: 0 0 1rem; }
/* The Apply buttons jump to the Shopify Forms section, whose id comes from the
   apps section's anchor_id setting (our id, not Switch markup). The sticky header
   is 59px on phones and 51px on desktop; without this the form's title lands
   under it on a phone. 59px clears both. */
#wholesale-inquiry-form { scroll-margin-top: 59px; }
/* sparko-app-section sits on the page's cream like every other Sparko band. */
.sparko-app-section { background: var(--sparko-cream); }
/* Shopify Forms on the wholesale page, matched to the old sparko-brief-form
   (still on page.contact), which is the reference for fields and buttons.

   The block renders inside <shopify-forms-embed>'s OPEN shadow root: no iframe,
   no ::part() hooks, and no selector from here reaches its elements. Two routes
   in, and this page uses both:

   1. TOKENS (this rule). The app defines every token its inner rules read in
      ONE `:host { ... }` rule (52 of them on 2026-10-12). A page rule on the
      host outranks a component's own :host rule, so overriding them here
      restyles fields, text and colours without touching the app's markup. Every
      token below is one an inner rule reads; the rest are layout, popup or
      discount-code tokens with nothing to map.
   2. INJECTION. What no token reaches (the submit button's border, case,
      tracking and font; the select's 46px max-height) is styled by a stylesheet
      that sections/sparko-app-section.liquid adopts INTO the shadow root. No
      button tokens are set here on purpose: if injection fails, the button is
      the app's default rather than a half-styled pill.

   The form's title and intro are NOT the app's: sparko-app-section renders them
   as an ordinary .sparko-section-title and intro, so the app's own title and
   description are meant to be cleared in the Forms app. The heading token is
   still set so the app's title matches the font if it is ever re-enabled.

   Scoped by #wholesale-inquiry-form, the anchor_id on this template's form
   section, so any other Forms block keeps the app's own styling.

   Reference -> token:
     field ring 2px navy                    --form-field-border (a box-shadow, drawn
                                            OUTSIDE: the textarea's floating-label
                                            backdrop is a white ::before across its
                                            top edge and painted over an inset ring)
     field corners 0.75rem                  --form-field-border-radius
     focus (fallback only, see injection)   --form-field-border-focused
     field text 16px Ingra, navy            --forms-body-font, --forms-base-font-size,
                                            --form-text-color, --form-field-padding
     label / placeholder muted navy         --form-placeholder-color (the labels float
                                            inside the field, so they ARE the placeholder)
     links and errors pink                  --link-text-color, --forms-accent-color,
                                            --form-error-color

   Still different from the reference, and not reachable either way short of
   rebuilding the app's markup:
     - labels. The app floats each label inside its field; the reference sets a
       navy label above the field.
     - field corners. One radius covers every field. The reference's own text
       inputs render as full pills (a theme input setting outranks its 0.75rem)
       while its select and textarea are 0.75rem; 0.75rem is used for all here.
   These token names are the app's internals, not a published API: if Shopify
   renames them this silently falls back to the app's own styling. */
#wholesale-inquiry-form shopify-forms-embed {
  /* Type */
  --forms-base-font-size: 1rem;
  --forms-body-font: normal 500 1rem var(--main-font-stack, sans-serif);
  --forms-heading-font: normal 900 var(--forms-heading-font-size) var(--heading-font-stack, sans-serif);
  /* Colour */
  --form-text-color: #262666;
  --body-text-color: #262666;
  --heading-text-color: #262666;
  --form-placeholder-color: rgba(38, 38, 102, 0.78);
  --form-background-color: #ffffff;
  --link-text-color: #DA2B6B;
  --forms-accent-color: #DA2B6B;
  --forms-accent-color-hovered-modifier: #DA2B6B1a;
  --form-error-color: #DA2B6B;
  /* Fields */
  --form-field-border: 0 0 0 2px #262666;
  /* Fallback focus only: the real focus state (navy ring + the theme's 2px pink
     outline) is injected by sparko-app-section, which also makes room for it.
     Without that, the ring turns Electric Pink and nothing is drawn outside it,
     because the app's overflow:hidden containers clip anything that is. */
  --form-field-border-focused: 0 0 0 2px #DA2B6B;
  --form-field-border-radius: 0.75rem;
  --form-field-padding: 12.5px;
}

/* ---- founders ---- */
.sparko-story-founders { background: var(--sparko-cream); }
.sparko-story-founders__row { display: grid; grid-template-columns: 1fr; gap: 2rem; align-items: center; }
.sparko-story-founders__text { display: flex; flex-direction: column; gap: 1.25rem; align-items: flex-start; }
.sparko-story-founders__body {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.06rem, 1.5vw, 1.19rem); line-height: 1.6;
  color: var(--sparko-navy); margin: 0; max-width: var(--sparko-measure);
}
.sparko-story-founders__body p { margin: 0 0 0.75rem; }
.sparko-story-founders__body p:last-child { margin-bottom: 0; }
/* The caption names who is in the portrait, so it is a list rather than prose.
   The first name is the emphasis; the rest step back, matching the comp. */
.sparko-story-founders__cap { list-style: none; margin: 0; padding: 0; font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.5; color: var(--sparko-navy); }
.sparko-story-founders__cap li + li { color: rgba(38, 38, 102, 0.72); }
.sparko-story-founders__media {
  /* position:relative is load-bearing, not decoration. sparko-image-placeholder
     with fill:true is absolutely positioned, so without a positioned parent it
     escapes this frame and fills the whole section instead. Same reason
     .sparko-pdp-brand__media carries it. */
  position: relative;
  aspect-ratio: 4 / 3; border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-story-founders__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Quiet by design: this is the lowest-priority action on the page, below the
   headings and well below the closing buttons, so it is an underlined text link
   rather than anything that could read as a button. */
/* Also an outline pill rather than an underlined link, for the same reason. */
.sparko-story-founders__link {
  display: inline-block; margin-top: 1.5rem;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 0.85rem 1.75rem; border-radius: 999px;
  border: 2px solid var(--sparko-navy); background: #ffffff; color: var(--sparko-navy);
  text-decoration: none; transition: background-color 0.15s ease;
}
.sparko-story-founders__link:hover { background: rgba(38, 38, 102, 0.06); color: var(--sparko-navy); }

/* ---- link rows ---- */
.sparko-link-rows { background: var(--sparko-cream); }
.sparko-link-rows__list { display: flex; flex-direction: column; gap: 0.75rem; max-width: 55rem; margin-inline: auto; }
/* space-between existed to push an arrow to the right edge. With the arrow gone
   there is one child, so the row just fills its own width. */
.sparko-link-row {
  display: flex; align-items: center; gap: 1rem;
  text-decoration: none; color: var(--sparko-navy); background: #ffffff;
  border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  padding: 1.15rem 1.5rem; transition: border-color 0.15s ease;
}
.sparko-link-row:hover { border-color: var(--sparko-pink); }
.sparko-link-row__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.sparko-link-row__name { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; line-height: 1.1; }
.sparko-link-row__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; color: rgba(38, 38, 102, 0.72); }

/* ---- closing CTA band ---- */
.sparko-cta-band { background: var(--sparko-cream); }
.sparko-cta-band__inner { display: flex; flex-direction: column; align-items: center; text-align: center; }
.sparko-cta-band__body {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.13rem, 1.7vw, 1.44rem); line-height: 1.55;
  color: var(--sparko-navy); margin: 0; max-width: 45rem;
}
.sparko-cta-band__body p { margin: 0 0 0.75rem; }
.sparko-cta-band__body p:last-child { margin-bottom: 0; }
/* An inline link in the band's prose (the wholesale page's routing line) has to
   read as a link: the theme base strips underlines. Underlined prose links are
   allowed; it is a link acting as a BUTTON that has to be a pill instead. */
.sparko-cta-band__body a { color: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 2px; }
.sparko-cta-band__ctas { display: flex; flex-wrap: wrap; justify-content: center; gap: 1rem; margin-top: 2rem; }

@media (min-width: 981px) {
  /* Symmetric, so the headline sits centred in the band. */
  .sparko-page-hero { padding-block: 4rem; }
  /* Copy and portrait side by side, the portrait narrower and squared off, which
     is the comp's desktop pair. It only exists when a Person block does, so the
     copy-only variant keeps the single column below. */
  .sparko-story-founders__row { grid-template-columns: 1fr 0.7fr; gap: 4rem; }
  .sparko-story-founders__row--copy-only { grid-template-columns: 1fr; }
  .sparko-story-founders__media { aspect-ratio: 1 / 1; justify-self: end; width: 100%; max-width: 21rem; }
}
@media (max-width: 560px) {
  .sparko-link-row { padding: 1rem 1.15rem; }
  .sparko-cta-band__ctas .sparko-btn { width: 100%; }
}


/* ----------------------------------------------------------------------------
   19. Our Work page (template: page.our-work)
   Built from the v2 design "Sparko Our Work.html". The closing band is the
   shared sparko-cta-band; only the banner, the filter bar and the grid are here.
   ---------------------------------------------------------------------------- */

/* ---- full-bleed banner ---- */
.sparko-page-banner { background: var(--sparko-cream); }
/* 10/3 is 16/6 with the height cut 20 percent: 6 x 0.8 = 4.8, and 16/4.8 reduces
   to 10/3. Written reduced so the ratio reads cleanly. */
.sparko-page-banner__frame { position: relative; width: 100%; aspect-ratio: 10 / 3; overflow: hidden; }
.sparko-page-banner__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-page-banner__title {
  position: absolute; z-index: 1; margin: 0;
  left: clamp(1.25rem, 5vw, 4.5rem); bottom: clamp(1.25rem, 4vw, 3.5rem);
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(2.0041rem, calc(0.8802rem + 5.62vw), 6.5rem); line-height: 0.95;
  letter-spacing: -0.01em; text-transform: uppercase; color: var(--sparko-cream);
}
/* Title colour follows the photo, set per page. Navy also drags the subtitle with
   it, since a cream subtitle under a navy title would read as two systems. */
.sparko-page-banner__content--navy .sparko-page-banner__title { color: var(--sparko-navy); }
.sparko-page-banner__content--navy .sparko-page-banner__sub { color: var(--sparko-navy); }
/* 16:6 is a letterbox on a phone. Taller there so the title has somewhere to sit
   and the photo is still legible. Not verified at a real mobile viewport. */
@media (max-width: 700px) {
  /* Same 20 percent off the phone ratio: 4/3 becomes 5/3. */
  .sparko-page-banner__frame { aspect-ratio: 5 / 3; }
}

/* ---- filter bar ----
   Same chrome as the collection page's decision bar, deliberately: they are the
   same control doing the same job on two different surfaces. */
.sparko-work__bar {
  background: color-mix(in srgb, var(--sparko-gold) 22%, var(--sparko-cream));
  border-top: 2px solid var(--sparko-navy); border-bottom: 2px solid var(--sparko-navy);
  padding: 0.75rem 0; z-index: 30;
}
.sparko-work__bar--sticky { position: sticky; top: 0; }
.sparko-work__bar-row { display: flex; align-items: center; gap: 0.5rem; overflow-x: auto; scrollbar-width: none; }
.sparko-work__bar-row::-webkit-scrollbar { display: none; }
.sparko-work__bar-label {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: rgba(38, 38, 102, 0.72);
  margin-right: 0.5rem; flex: none;
}
.sparko-work__facet {
  display: inline-flex; align-items: center; flex: none; cursor: pointer;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  background: #ffffff; color: var(--sparko-navy);
  padding: 10px 18px; line-height: 1; white-space: nowrap;
  transition: background-color 0.15s ease;
}
.sparko-work__facet:hover { background: color-mix(in srgb, var(--sparko-gold) 20%, #ffffff); }
.sparko-work__facet:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 2px; }
.sparko-work__facet--on { background: var(--sparko-gold); }
.sparko-work__facet--on:hover { background: var(--sparko-gold); }

/* ---- project grid ---- */
.sparko-work__body { background: var(--sparko-cream); }
.sparko-work__count,
.sparko-work__empty { font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; color: rgba(38, 38, 102, 0.72); margin: 0 0 1.5rem; }
.sparko-work__empty { margin: 0; }
.sparko-work__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2.5rem 2rem; }
/* text-align rather than align-items, for the reason recorded on the case-study
   card: the children are flex items, so centring the ITEMS would shrink each to
   its content width and take the square photo down with it. Stretched children
   plus centred inherited text moves the title and the line and leaves the photo
   filling the card. */
.sparko-work__card { display: flex; flex-direction: column; gap: 0.75rem; text-decoration: none; color: var(--sparko-navy); text-align: center; }
.sparko-work__img {
  position: relative; display: block; aspect-ratio: 1 / 1;
  border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
  transition: border-color 0.15s ease;
}
.sparko-work__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-work__card:hover .sparko-work__img { border-color: var(--sparko-pink); }
.sparko-work__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1.35rem; line-height: 1.1; color: var(--sparko-navy);
  transition: color 0.15s ease;
}
.sparko-work__card:hover .sparko-work__title { color: var(--sparko-pink); }
.sparko-work__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.72); }

@media (max-width: 1020px) { .sparko-work__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .sparko-work__grid { grid-template-columns: 1fr; } }

/* ---- CTA band colour variants ----
   The base band is cream. On navy the heading and body invert, the primary stays
   pink, and the outlined secondary takes a cream fill: a white-outline button on
   navy reads as disabled rather than as a second action. */
.sparko-cta-band--cream { background: var(--sparko-cream); }
.sparko-cta-band--gold { background: var(--sparko-gold); }
.sparko-cta-band--navy { background: var(--sparko-navy); --sparko-section-title-color: var(--sparko-cream); }
.sparko-cta-band--navy .sparko-cta-band__body { color: rgba(254, 251, 245, 0.9); }
.sparko-cta-band--navy .sparko-btn--outline { background: var(--sparko-cream); color: var(--sparko-navy); }
.sparko-cta-band--navy .sparko-btn--outline:hover { background: #ffffff; color: var(--sparko-navy); }


/* ----------------------------------------------------------------------------
   20. Case study template (template: page.case-study)
   Built from the v2 design "Sparko Case Study - Dior Toile de Jouy.html". Half the
   page is shared: the banner is sparko-page-banner, the numbered steps are the
   homepage's sparko-process, the More Work row is sparko-work-grid and the closing
   band is sparko-cta-band. Only the four new sections are styled here.
   ---------------------------------------------------------------------------- */

/* ---- banner additions: back link, subtitle ---- */
/* Centred both ways. */
.sparko-page-banner__content {
  position: absolute; z-index: 1; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding-inline: clamp(1.25rem, 5vw, 4.5rem);
}
/* The title is positioned by the wrapper now, so it drops its own offsets. */
.sparko-page-banner__content .sparko-page-banner__title { position: static; left: auto; bottom: auto; }
.sparko-page-banner__content .sparko-page-banner__sub { margin-inline: auto; }
.sparko-page-banner__sub {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1rem, 1.5vw, 1.25rem); line-height: 1.5;
  color: rgba(254, 251, 245, 0.92); margin: 0.75rem 0 0; max-width: 40rem;
}

/* ---- prose ---- */
.sparko-prose--cream { background: var(--sparko-cream); }
.sparko-prose--white { background: #ffffff; }
.sparko-prose__inner { display: flex; flex-direction: column; align-items: center; }
/* The heading is capped to the same measure as the body beneath it. Left to the
   1820px shell it ran nearly four times the width of its own text, which reads
   as a banner sitting on an unrelated column rather than as the title of it.
   The case-study template is the only user of this section, and there the
   heading is the page title over a single column of prose. */
.sparko-prose__inner > .sparko-section-title { max-width: 44rem; }
/* The only section on the site that is nothing but running text, so the measure
   cap is doing real work rather than being a formality. */
.sparko-prose__body {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.06rem, 1.5vw, 1.19rem); line-height: 1.65;
  color: var(--sparko-navy); max-width: 44rem; margin: 0;
}
.sparko-prose__body p { margin: 0 0 1rem; }
.sparko-prose__body p:last-child { margin-bottom: 0; }

/* Everything below is for prose written in SHOPIFY ADMIN rather than typed into
   a richtext setting. A `richtext` setting can only hold p, br, strong, em, a
   and lists, so the settings path never produced a heading, an image or a
   blockquote and none of them had styles. `page.content` is a full rich text
   editor, and the live case studies use it: the Weeknd page runs five h2s and
   three photographs inside its body. Unstyled, those arrive as browser-default
   Times headings and full-bleed images.

   Scoped to .sparko-prose__body, so this cannot reach any other rich text on
   the site. */
.sparko-prose__body h1,
.sparko-prose__body h2,
.sparko-prose__body h3,
.sparko-prose__body h4 {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  text-transform: uppercase; letter-spacing: -0.01em; line-height: 1.05;
  color: var(--sparko-navy);
  /* Generous above, tight below: a heading belongs to the text that follows it,
     and equal margins would leave it floating between two blocks. */
  margin: 2.5rem 0 0.75rem;
}
.sparko-prose__body > :first-child { margin-top: 0; }
.sparko-prose__body h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); }
.sparko-prose__body h3 { font-size: clamp(1.2rem, 1.9vw, 1.45rem); }
.sparko-prose__body h4 { font-size: 1.1rem; text-transform: none; letter-spacing: 0; }
/* Photographs in the body run to the measure like the text. They carry the same
   frame the rest of the site gives a photo, so a picture dropped into admin
   does not arrive as a bare rectangle. */
.sparko-prose__body img {
  display: block; width: 100%; height: auto;
  margin: 2rem 0; border-radius: 1.25rem;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-prose__body ul,
.sparko-prose__body ol { margin: 0 0 1rem; padding-left: 1.25rem; }
.sparko-prose__body li { margin-bottom: 0.4rem; }
.sparko-prose__body li:last-child { margin-bottom: 0; }
.sparko-prose__body a {
  color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px;
}
.sparko-prose__body a:hover { color: var(--sparko-pink-hover); }
.sparko-prose__body strong { font-weight: 800; }
.sparko-prose__body blockquote {
  margin: 2rem 0; padding-left: 1.25rem;
  border-left: 3px solid var(--sparko-gold);
  font-style: italic; color: rgba(38, 38, 102, 0.82);
}
/* An admin editor emits tables for spec lists now and again; this stops one
   overflowing the measure on a phone. */
.sparko-prose__body table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; }
.sparko-prose__body td, .sparko-prose__body th { border: 1px solid rgba(38, 38, 102, 0.16); padding: 0.5rem 0.75rem; text-align: left; }

/* ---- info cards ---- */
.sparko-info-cards { background: var(--sparko-cream); }
.sparko-info-cards__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
.sparko-info-cards__grid[data-count="2"] { grid-template-columns: repeat(2, 1fr); }
.sparko-info-cards__grid[data-count="4"] { grid-template-columns: repeat(4, 1fr); }
/* Five is the only count that does not divide into a tidy row. A sixth-based
   track lets three sit on top and the remaining two centre under them, instead
   of leaving an empty cell on the right that reads as a missing card. Six falls
   through to the default three and simply wraps to two full rows. */
.sparko-info-cards__grid[data-count="5"] { grid-template-columns: repeat(6, 1fr); }
.sparko-info-cards__grid[data-count="5"] > * { grid-column: span 2; }
.sparko-info-cards__grid[data-count="5"] > *:nth-child(4) { grid-column: 2 / span 2; }
.sparko-info-cards__grid[data-count="5"] > *:nth-child(5) { grid-column: 4 / span 2; }
.sparko-info-card {
  display: flex; flex-direction: column; gap: 0.75rem;
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  padding: 1.75rem;
}
.sparko-info-card__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; line-height: 1.1; text-transform: uppercase; color: var(--sparko-navy); margin: 0; }
.sparko-info-card__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.5; color: rgba(38, 38, 102, 0.78); margin: 0; }
/* Intro paragraph. Centred and capped at the prose measure, because the heading
   above it is centred and a full-width line under a centred heading reads as a
   different section. */
/* sparko-app-section's intro shares this rule, so the wholesale form's heading
   and intro read exactly like the "Why Retailers Stock" pair. */
.sparko-info-cards__intro,
.sparko-app-section__intro {
  margin: var(--sparko-heading-gap) auto 0; max-width: 46rem; text-align: center;
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.06rem, 1.6vw, 1.19rem); line-height: 1.55;
  color: rgba(38, 38, 102, 0.78);
}
.sparko-info-cards__intro p, .sparko-app-section__intro p { margin: 0 0 0.75rem; }
.sparko-info-cards__intro p:last-child, .sparko-app-section__intro p:last-child { margin-bottom: 0; }

/* ---- checklist ---- */
.sparko-checklist { background: var(--sparko-cream); }
.sparko-checklist__grid { display: grid; grid-template-columns: 1fr; gap: 2rem; align-items: center; }
.sparko-checklist__media {
  /* Square, matching every other image frame in the theme: the work cards, the
     collection tiles and the gallery are all 1/1. This was the only 4:3 frame on
     the site, which read as a different system sitting next to them. */
  position: relative; aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-checklist__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-checklist__copy { display: flex; flex-direction: column; gap: 1.25rem; }
.sparko-checklist__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.5379rem, calc(1.1397rem + 1.99vw), 2.75rem); line-height: 0.98;
  text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy); margin: 0;
}
.sparko-checklist__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.9rem; }
.sparko-checklist__item { display: flex; gap: 0.75rem; align-items: flex-start; font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; line-height: 1.5; color: var(--sparko-navy); }
/* Gold tick on cream. This is a graphic mark rather than text, so it does not hit
   the "California Gold is never text on Warm Cream" rule, and the navy stroke
   weight keeps it legible at 20px. */
.sparko-checklist__check { flex: none; margin-top: 0.15rem; color: var(--sparko-gold); }
/* Copy-only variant is centred: no photo to sit beside, so the heading and the
   list centre on the page like every other headed section.

   The LIST is centred as a block rather than having its text centred. Each item
   is a tick plus a line, so centring the text would leave the ticks in a ragged
   column and the lines starting at different x. width:fit-content sizes the block
   to its longest item and margin-inline:auto puts that block in the middle, so
   the ticks stay in one column and the whole thing still reads as centred. */
.sparko-checklist__grid--no-media { grid-template-columns: 1fr; }
.sparko-checklist__grid--no-media .sparko-checklist__copy { align-items: center; }
.sparko-checklist__grid--no-media .sparko-checklist__title { text-align: center; }
.sparko-checklist__grid--no-media .sparko-checklist__list {
  max-width: 52rem; width: fit-content; margin-inline: auto;
}
/* Navy band. The tick stays gold, which is a graphic mark on navy rather than
   text on cream, so the contrast rule is not in play either way. Only the
   list-only variant is styled: a photo frame on navy would need its own border
   and background treatment, and no design asks for one. */
.sparko-checklist--navy { background: var(--sparko-navy); }
.sparko-checklist--navy .sparko-checklist__title { color: var(--sparko-cream); }
.sparko-checklist--navy .sparko-checklist__item { color: var(--sparko-cream); }

/* ---- gallery ---- */
.sparko-gallery { background: var(--sparko-cream); }
.sparko-gallery__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
.sparko-gallery__grid[data-count="2"] { grid-template-columns: repeat(2, 1fr); }
.sparko-gallery__grid[data-count="4"] { grid-template-columns: repeat(4, 1fr); }
.sparko-gallery__item { margin: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.sparko-gallery__frame {
  position: relative; display: block; aspect-ratio: 1 / 1;
  border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-gallery__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-gallery__caption { font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem; line-height: 1.4; color: rgba(38, 38, 102, 0.72); text-align: center; }

/* ---- process: numbered steps with no image ---- */
/* The number normally sits on the step's photo. With the photo gone it becomes
   the step's own marker, so it takes the gold-on-navy disc treatment instead. */
.sparko-process__num--bare {
  /* position:static is the load-bearing line. The base rule pins the number
     absolutely to the top-left of the step's photo; with no photo it escaped to
     the nearest positioned ancestor and all four stacked at the page edge. */
  position: static; top: auto; left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; border-radius: 50%;
  background: var(--sparko-gold); color: var(--sparko-navy);
  border: 2px solid var(--sparko-navy);
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.25rem;
  line-height: 1; margin-bottom: 0.25rem;
}

/* The steps grid is fixed at three. A four-step process left one step alone on a
   second row, so the column count follows the block count the same way the info
   cards and gallery do. */
.sparko-process__steps[data-count="4"] { grid-template-columns: repeat(4, 1fr); }
.sparko-process__steps[data-count="2"] { grid-template-columns: repeat(2, 1fr); }

/* ---- work grid: see-all link ---- */
/* An outline pill, not an underlined text link: underlined links are off brand.
   Same treatment as .sparko-btn--outline, scoped here so the anchor does not have
   to carry button classes from a section setting. */
.sparko-work__all {
  /* block + fit-content + auto margins, so the pill centres under the grid
     without the parent having to set text-align and catch everything else. */
  width: fit-content; margin: 2rem auto 0;
  /* Same pill as .sparko-btn, which copies the live theme: 46px via min-height,
     16px sides, a 1rem/900 label at -0.05em. flex rather than block, because
     min-height only centres a label if the box is centring its content.

     This is DUPLICATION and it is why this button was missed when .sparko-btn
     was retuned: three CTAs in the theme draw their own pill instead of
     rendering that class. Anything that looks like a button should use
     .sparko-btn; if one of these is touched again, move it over. */
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box; min-height: 46px; padding: 0 1rem;
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1rem; text-transform: uppercase; letter-spacing: -0.05em;
  line-height: 1; border-radius: 999px;
  border: 2px solid var(--sparko-navy); background: #ffffff; color: var(--sparko-navy);
  text-decoration: none; transition: background-color 0.15s ease;
}
.sparko-work__all:hover { background: rgba(38, 38, 102, 0.06); color: var(--sparko-navy); }

@media (min-width: 981px) {
  .sparko-checklist__grid { grid-template-columns: 1fr 1fr; gap: 4rem; }
  .sparko-checklist__grid--media-right .sparko-checklist__media { order: 2; }
  .sparko-checklist__grid--no-media { grid-template-columns: 1fr; }
}
@media (max-width: 1240px) {
  /* Five across is too narrow to read before the shell is near its full width,
     so the pair on the second row goes full width and the row above stays three. */
  .sparko-info-cards__grid[data-count="5"] > *:nth-child(4) { grid-column: 1 / span 3; }
  .sparko-info-cards__grid[data-count="5"] > *:nth-child(5) { grid-column: 4 / span 3; }
}
@media (max-width: 900px) {
  .sparko-process__steps[data-count="4"] { grid-template-columns: repeat(2, 1fr); }
  .sparko-info-cards__grid,
  .sparko-info-cards__grid[data-count="5"] { grid-template-columns: 1fr; }
  /* FOUR cards stay a grid on phones, 2x2 rather than a column of four
     (2026-09-08, at the client's direction). Scoped to the four-card count on
     purpose: this section is shared by five rows across the B2B pages, at 3, 4,
     5 and 6 cards, and only the four-card one divides evenly into two. */
  .sparko-info-cards__grid[data-count="4"] { grid-template-columns: repeat(2, 1fr); }
  .sparko-info-cards__grid[data-count="5"] > *,
  .sparko-info-cards__grid[data-count="5"] > *:nth-child(4),
  .sparko-info-cards__grid[data-count="5"] > *:nth-child(5) { grid-column: auto; }
}
/* A 2x2 card is about 171px wide at 390, so the desktop padding and type would
   leave a two-line sentence running to six. Same compact treatment the pack
   tiles and the occasion grid already use at this width. */
@media (max-width: 560px) {
  .sparko-info-cards__grid[data-count="4"] { gap: 0.75rem; }
  .sparko-info-cards__grid[data-count="4"] .sparko-info-card { padding: 1rem; gap: 0.4rem; }
  .sparko-info-cards__grid[data-count="4"] .sparko-info-card__title { font-size: 1.05rem; }
  .sparko-info-cards__grid[data-count="4"] .sparko-info-card__line { font-size: 0.85rem; line-height: 1.4; }
}

@media (max-width: 700px) {
  .sparko-gallery__grid,
  .sparko-gallery__grid[data-count="4"] { grid-template-columns: 1fr; }
}


/* ----------------------------------------------------------------------------
   21. Insights blog index (template: blog)
   Built from the v2 design "Sparko Insights.html". The page hero is the shared
   sparko-page-hero; only the featured lead, the tag bar and the article grid are
   here. The card and the bar reuse the Our Work treatments deliberately, since
   they are the same controls doing the same job on a different list.
   ---------------------------------------------------------------------------- */

/* ---- shared tag chip ---- */
.sparko-blog__tag {
  align-self: flex-start;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.1em; color: var(--sparko-pink);
}

/* ---- featured lead ---- */
/* Top padding equals the compact hero's top padding, so the title is evenly spaced. */
.sparko-blog-featured { background: var(--sparko-cream); padding-block: 2.25rem 1rem; }
.sparko-blog-featured__card { display: grid; grid-template-columns: 1fr; gap: 1.5rem; align-items: center; text-decoration: none; color: var(--sparko-navy); }
.sparko-blog-featured__media {
  position: relative; aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff; transition: border-color 0.15s ease;
}
.sparko-blog-featured__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-blog-featured__card:hover .sparko-blog-featured__media { border-color: var(--sparko-pink); }
.sparko-blog-featured__body { display: flex; flex-direction: column; gap: 0.75rem; align-items: flex-start; }
.sparko-blog-featured__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.5308rem, calc(1.1002rem + 2.15vw), 3rem); line-height: 0.98;
  text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy);
  transition: color 0.15s ease;
}
.sparko-blog-featured__card:hover .sparko-blog-featured__title { color: var(--sparko-pink); }
.sparko-blog-featured__excerpt {
  font-family: var(--main-font-stack, sans-serif); font-size: 1.1rem; line-height: 1.55;
  color: rgba(38, 38, 102, 0.78); max-width: var(--sparko-measure);
}
.sparko-blog-featured__date,
.sparko-blog-card__date { font-family: var(--main-font-stack, sans-serif); font-size: 0.875rem; color: rgba(38, 38, 102, 0.6); }
/* The read link is the outlined pill, not underlined text. Same rule as the
   see-all control: underlined links are off brand. */
.sparko-blog-featured__link {
  display: inline-block; margin-top: 0.5rem;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 0.85rem 1.75rem; border-radius: 999px;
  border: 2px solid var(--sparko-navy); background: #ffffff; color: var(--sparko-navy);
  transition: background-color 0.15s ease;
}
.sparko-blog-featured__card:hover .sparko-blog-featured__link { background: rgba(38, 38, 102, 0.06); }

/* ---- tag bar: the collection and Our Work decision bar, again ---- */
.sparko-blog-grid__bar {
  background: color-mix(in srgb, var(--sparko-gold) 22%, var(--sparko-cream));
  border-top: 2px solid var(--sparko-navy); border-bottom: 2px solid var(--sparko-navy);
  padding: 0.75rem 0; z-index: 30;
}
.sparko-blog-grid__bar--sticky { position: sticky; top: 0; }
.sparko-blog-grid__bar-row { display: flex; align-items: center; gap: 0.5rem; overflow-x: auto; scrollbar-width: none; }
.sparko-blog-grid__bar-row::-webkit-scrollbar { display: none; }
.sparko-blog-grid__bar-label {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: rgba(38, 38, 102, 0.72);
  margin-right: 0.5rem; flex: none;
}
.sparko-blog-grid__facet {
  display: inline-flex; align-items: center; flex: none; text-decoration: none;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.875rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border: 2px solid var(--sparko-navy); border-radius: 999px;
  background: #ffffff; color: var(--sparko-navy);
  padding: 10px 18px; line-height: 1; white-space: nowrap;
  transition: background-color 0.15s ease;
}
.sparko-blog-grid__facet:hover { background: color-mix(in srgb, var(--sparko-gold) 20%, #ffffff); color: var(--sparko-navy); }
.sparko-blog-grid__facet--on { background: var(--sparko-gold); }
.sparko-blog-grid__facet--on:hover { background: var(--sparko-gold); }

/* ---- article grid ---- */
.sparko-blog-grid__body { background: var(--sparko-cream); }
/* Flex-wrap and centred rather than a 3-column grid. Page one always holds one
   card fewer than the rest, because the featured lead above is showing the newest
   article, so a grid left a hole in the bottom-right. Centring the overflow makes
   a partial row read as deliberate instead of broken, at any article count. */
.sparko-blog-grid__grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 2.5rem 2rem; }
.sparko-blog-card { flex: 0 1 calc((100% - 4rem) / 3); }
.sparko-blog-card { display: flex; flex-direction: column; gap: 0.6rem; text-decoration: none; color: var(--sparko-navy); text-align: center; }
.sparko-blog-card .sparko-blog__tag { align-self: center; }
.sparko-blog-card__img {
  position: relative; display: block; aspect-ratio: 1 / 1;
  border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
  transition: border-color 0.15s ease; margin-bottom: 0.15rem;
}
.sparko-blog-card__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-blog-card:hover .sparko-blog-card__img { border-color: var(--sparko-pink); }
.sparko-blog-card__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: 1.35rem; line-height: 1.1; color: var(--sparko-navy);
  transition: color 0.15s ease;
}
.sparko-blog-card:hover .sparko-blog-card__title { color: var(--sparko-pink); }
.sparko-blog-card__excerpt { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.72); }
.sparko-blog-grid__empty { font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; color: rgba(38, 38, 102, 0.72); margin: 0; }
.sparko-blog-grid__pager { display: flex; justify-content: center; margin-top: 3rem; }

@media (min-width: 981px) {
  .sparko-blog-featured { padding-block: 3rem 1.5rem; }
  .sparko-blog-featured__card { grid-template-columns: 1.05fr 0.95fr; gap: 3.5rem; }
}
@media (max-width: 1020px) { .sparko-blog-card { flex-basis: calc((100% - 2rem) / 2); } }
@media (max-width: 640px) { .sparko-blog-card { flex-basis: 100%; } }

/* ---- page hero sizes ----
   Large is the Our Story headline scale, which a full sentence needs. Compact is
   for a one-word title like Insights, where that scale and its padding read as a
   splash screen rather than a page heading. */
/* Bottom padding is zero on purpose. The section below this one carries its own
   top padding, and the two were stacking: 48px above the title against 88px
   below it. The next section owns the gap now, so the title sits evenly. */
.sparko-page-hero--compact { padding-block: 2.25rem 0; }
.sparko-page-hero--compact .sparko-page-hero__title { font-size: clamp(1.896rem, calc(1.4208rem + 2.38vw), 3.5rem); margin-bottom: 0; max-width: none; }
@media (min-width: 981px) {
  .sparko-page-hero--compact { padding-block: 3rem 0; }
}

/* ---- pager ----
   Current page is a gold pill, not an underline: the underline read as a stray
   mark under one number rather than as a selected state. */
.sparko-pager { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 0.5rem; }
.sparko-pager__list { display: flex; align-items: center; gap: 0.25rem; list-style: none; margin: 0; padding: 0; }
.sparko-pager__page,
.sparko-pager__step {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9rem;
  color: var(--sparko-navy); text-decoration: none; border-radius: 999px;
  transition: background-color 0.15s ease;
}
.sparko-pager__page { min-width: 2.5rem; height: 2.5rem; padding: 0 0.6rem; }
a.sparko-pager__page:hover { background: rgba(38, 38, 102, 0.08); color: var(--sparko-navy); }
.sparko-pager__page--on { background: var(--sparko-gold); color: var(--sparko-navy); }
.sparko-pager__gap { display: inline-flex; align-items: center; justify-content: center; min-width: 1.5rem; height: 2.5rem; color: rgba(38, 38, 102, 0.5); }
/* Previous and Next are words, not arrows. */
.sparko-pager__step {
  height: 2.5rem; padding: 0 1.25rem;
  text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.8rem;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-pager__step:hover { background: rgba(38, 38, 102, 0.06); color: var(--sparko-navy); }


/* ----------------------------------------------------------------------------
   22. Insights article (template: article)
   Built from the v2 design "Sparko Insights Article.html". The comp builds its
   body from React components; here the body is article.content out of the Shopify
   editor, so the same treatments are CSS rules on whatever HTML the author wrote.
   ---------------------------------------------------------------------------- */

.sparko-article { background: var(--sparko-cream); }
/* The reading column. Everything in the article sits in this width except the
   cover and anything the author deliberately breaks out. */
.sparko-article__col { width: min(44rem, calc(100% - 2 * var(--sparko-gutter))); margin-inline: auto; }
.sparko-article__mast { padding-block: 2.5rem 1.5rem; }
.sparko-article__title {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.8811rem, calc(1.3373rem + 2.72vw), 3.5rem); line-height: 1.02;
  text-transform: uppercase; letter-spacing: -0.01em;
  color: var(--sparko-navy); margin: 0.5rem 0 0.75rem;
}
.sparko-article__date { font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem; color: rgba(38, 38, 102, 0.6); margin: 0; }
.sparko-article__author::before { content: " · "; }

/* Square, matching every other image frame on the site. It is also capped near
   the reading column rather than breaking out to the comp's full width: a square
   at 70rem would stand over 1100px tall and push the article off the first
   screen, which a 3:2 at that width did not. */
.sparko-article__cover { margin: 0 0 2.5rem; }
.sparko-article__cover-frame {
  width: min(40rem, calc(100% - 2 * var(--sparko-gutter))); margin-inline: auto;
  aspect-ratio: 1 / 1; border-radius: 1.25rem; overflow: hidden;
  border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-article__cover-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Summary panel */
.sparko-article__tldr { border: 2px solid var(--sparko-navy); border-radius: 1.25rem; background: #ffffff; padding: 1.5rem 1.75rem; margin-bottom: 2.5rem; }
.sparko-article__tldr-label { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.75rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--sparko-pink); margin-bottom: 0.6rem; }
.sparko-article__tldr-body { font-family: var(--main-font-stack, sans-serif); font-size: 1.02rem; line-height: 1.55; color: var(--sparko-navy); }
.sparko-article__tldr-body p { margin: 0 0 0.5rem; }
.sparko-article__tldr-body p:last-child { margin-bottom: 0; }
.sparko-article__tldr-body ul { margin: 0; padding-left: 1.1rem; }

/* ---- the body ----
   These rules target whatever the Shopify editor produced, so a post gets the
   design by being written normally. */
.sparko-article__body { padding-bottom: 3.5rem; }
.sparko-article__body p,
.sparko-article__body li {
  font-family: var(--main-font-stack, sans-serif);
  font-size: 1.13rem; line-height: 1.7; color: var(--sparko-navy);
}
.sparko-article__body p { margin: 0 0 1.25rem; }
.sparko-article__body h2,
.sparko-article__body h3 {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy);
  margin: 2.5rem 0 0.9rem;
}
.sparko-article__body h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); line-height: 1.05; }
.sparko-article__body h3 { font-size: clamp(1.2rem, 2vw, 1.5rem); line-height: 1.1; }
.sparko-article__body h4 { font-family: var(--main-font-stack, sans-serif); font-weight: 800; font-size: 1.1rem; color: var(--sparko-navy); margin: 2rem 0 0.5rem; }
.sparko-article__body ul,
.sparko-article__body ol { margin: 0 0 1.25rem; padding-left: 1.25rem; }
.sparko-article__body li { margin-bottom: 0.4rem; }
.sparko-article__body a { color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px; }
.sparko-article__body a:hover { color: var(--sparko-navy); }
/* Any image the author places gets the bordered frame the rest of the site uses. */
.sparko-article__body img {
  display: block; width: 100%; height: auto; margin: 2rem 0;
  border-radius: 1.25rem; border: 2px solid var(--sparko-navy); background: #ffffff;
}
.sparko-article__body figure { margin: 2rem 0; }
.sparko-article__body figure img { margin: 0; }
.sparko-article__body figcaption { font-family: var(--main-font-stack, sans-serif); font-size: 0.9rem; line-height: 1.4; color: rgba(38, 38, 102, 0.6); margin-top: 0.6rem; text-align: center; }
/* The comp's pull quote, applied to whatever the author marks as a blockquote. */
.sparko-article__body blockquote {
  margin: 2.5rem 0; padding: 0 0 0 1.5rem;
  border-left: 3px solid var(--sparko-gold);
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(1.35rem, 2.4vw, 1.75rem); line-height: 1.25;
  color: var(--sparko-navy);
}
.sparko-article__body blockquote p { font-family: inherit; font-size: inherit; line-height: inherit; margin: 0; }
.sparko-article__body hr { border: 0; border-top: 2px solid rgba(38, 38, 102, 0.18); margin: 2.5rem 0; }
.sparko-article__body table { width: 100%; border-collapse: collapse; margin: 2rem 0; font-family: var(--main-font-stack, sans-serif); font-size: 1rem; }
.sparko-article__body th,
.sparko-article__body td { border: 2px solid var(--sparko-navy); padding: 0.6rem 0.75rem; text-align: left; color: var(--sparko-navy); }
.sparko-article__body th { background: color-mix(in srgb, var(--sparko-gold) 20%, #ffffff); font-weight: 800; }

.sparko-article-related { background: var(--sparko-cream); }
.sparko-article-related .sparko-work__all { width: fit-content; margin: 2.5rem auto 0; }

@media (min-width: 981px) {
  .sparko-article__mast { padding-block: 3.5rem 2rem; }
}

/* Citations close the article. The list is numbered by CSS rather than by the
   author typing numbers, so renumbering is not a manual edit. */
.sparko-article__sources { border-top: 2px solid rgba(38, 38, 102, 0.18); padding-top: 1.75rem; margin-bottom: 3.5rem; }
.sparko-article__sources-h { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.25rem; text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy); margin: 0 0 0.9rem; }
.sparko-article__sources-body { font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem; line-height: 1.6; color: rgba(38, 38, 102, 0.78); }
.sparko-article__sources-body ol { margin: 0; padding-left: 1.35rem; }
.sparko-article__sources-body li { margin-bottom: 0.5rem; }
.sparko-article__sources-body a { color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px; }
/* The summary sits above the cover now, so it carries the gap to it. */
.sparko-article__tldr { margin-bottom: 2.5rem; }


/* ----------------------------------------------------------------------------
   23. Arcade page (template: page.arcade)
   Built from the v2 design "Sparko Arcade.html". The hero is sparko-page-hero and
   the closing cross-sell band is sparko-pdp-brand, so only the marquee and the
   game grid are here.
   ---------------------------------------------------------------------------- */

/* ---- text marquee ---- */
/* No top margin. Margin here sits OUTSIDE the cream hero above it, so it showed
   the page background as a white bar between the two. The hero's own bottom
   padding carries the gap, and being inside the hero it is cream. */
.sparko-marquee { background: var(--sparko-navy); border-block: 2px solid var(--sparko-navy); overflow: hidden; }
.sparko-marquee__row { display: flex; overflow: hidden; }
/* The track holds the list twice and travels exactly half its own width, so the
   second copy lands where the first began and the loop has no seam. */
.sparko-marquee__track { display: flex; flex: none; animation: sparko-marquee-scroll var(--sparko-marquee-speed, 30s) linear infinite; }
.sparko-marquee__set { display: flex; align-items: center; flex: none; }
.sparko-marquee__item,
.sparko-marquee__star {
  font-family: var(--heading-font-stack, sans-serif); font-weight: 900;
  font-size: clamp(0.95rem, 1.6vw, 1.25rem); line-height: 1;
  text-transform: uppercase; letter-spacing: 0.02em;
  padding: 0.9rem 0; white-space: nowrap;
}
.sparko-marquee__item { color: var(--sparko-cream); }
.sparko-marquee__star { color: var(--sparko-gold); padding-inline: 1.25rem; }
@keyframes sparko-marquee-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* Motion is decoration here, so it stops entirely rather than slowing down. */
@media (prefers-reduced-motion: reduce) {
  .sparko-marquee__track { animation: none; }
}

/* ---- game grid ---- */
.sparko-arcade { background: var(--sparko-cream); }
.sparko-arcade__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }
.sparko-arcade__card {
  display: flex; flex-direction: column;
  border: 2px solid var(--sparko-navy); border-radius: 1.25rem; overflow: hidden;
  background: #ffffff;
}
.sparko-arcade__img { position: relative; display: block; aspect-ratio: 1 / 1; overflow: hidden; background: var(--sparko-cream); }
.sparko-arcade__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The body grows so every card's button sits on the same line, whatever the
   description length. */
.sparko-arcade__body { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.5rem; padding: 1.5rem; flex: 1 1 auto; }
.sparko-arcade__genre { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--sparko-pink); }
.sparko-arcade__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.35rem; line-height: 1.1; text-transform: uppercase; color: var(--sparko-navy); }
/* A little air before the button. Given as bottom margin on the description
   rather than top margin on the button: the button uses margin-top:auto to sit at
   the bottom of the card, and auto collapses to zero on the tallest card, so a
   margin there would not hold. */
.sparko-arcade__line { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.72); margin: 0 0 0.6rem; }
.sparko-arcade__players { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; color: rgba(38, 38, 102, 0.6); }
/* margin only. A padding-top here was overriding the button's own vertical
   padding and squashing it to 39px against the standard 51px. */
.sparko-arcade__cta { margin-top: auto; }

@media (max-width: 1020px) { .sparko-arcade__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .sparko-arcade__grid { grid-template-columns: 1fr; } }

/* Band image shape. Landscape is the default so every PDP band and Our Story
   stay as approved; square matches the rest of the site's frames and is what the
   Arcade cross-sell uses. */
.sparko-pdp-brand__media--square { aspect-ratio: 1 / 1; }


/* ----------------------------------------------------------------------------
   24. Brand Activations page (template: page.brand-activations)
   Built from the v2 design "Sparko Brand Activations.html". Ten of its eleven
   sections are ones this theme already has, so only the brief form is here.
   ---------------------------------------------------------------------------- */
/* Tighter than the standard section rhythm. The sub is a subtitle belonging to
   the heading rather than a separate beat, so it overrides the 2.5rem that
   .sparko-section__content would otherwise give it. */
.sparko-brief { background: var(--sparko-cream); padding-block: 4rem 2.5rem; }
.sparko-brief__sub {
  font-family: var(--main-font-stack, sans-serif);
  font-size: clamp(1.06rem, 1.6vw, 1.19rem); line-height: 1.55;
  color: rgba(38, 38, 102, 0.78); max-width: 46rem; margin-inline: auto; text-align: center;
  margin-top: 0.5rem;
}
.sparko-brief__sub p { margin: 0; }
.sparko-brief__panel {
  max-width: 52rem; margin: 1.75rem auto 0;
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 1.25rem;
  padding: 2rem;
}
.sparko-brief__form { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin: 0; }
.sparko-brief__field { display: flex; flex-direction: column; gap: 0.4rem; }
.sparko-brief__field--full { grid-column: 1 / -1; }
/* Sentence case, not caps, and not bold. Both at the client's direction
   (2026-09-08), and both match the live contact form, whose labels are weight
   500 at about 14px with no transform.

   The tracking goes with the caps rather than surviving them: 0.08em exists to
   open up uppercase, and left on sentence case it reads as a spacing bug. Size
   steps 0.8rem -> 0.9rem for the same reason, since 12.8px was sized for a
   short uppercase label and reads small as a sentence. */
.sparko-brief__label {
  font-family: var(--main-font-stack, sans-serif); font-weight: 500; font-size: 0.9rem;
  letter-spacing: normal; text-transform: none; color: var(--sparko-navy);
}
.sparko-brief__input,
.sparko-brief__textarea {
  font-family: var(--main-font-stack, sans-serif); font-size: 1rem; color: var(--sparko-navy);
  background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 0.75rem;
  padding: 0.75rem 0.9rem; width: 100%;
}
/* The fields were drawing FOUR pixels of ring, not two. Our 2px navy border is
   only half of it: Switch's base bundle puts an `inset 0 0 0 2px` black shadow
   on every field, and the two stacked.

   SPECIFICITY IS THE WHOLE TRICK HERE, and getting it wrong is why this took two
   passes. The stock rule is written as `input[type="text"], input[type="email"]`
   and so on, which scores 0-1-1. A single class scores 0-1-0 and LOSES to it, so
   `box-shadow: none` on .sparko-brief__input silently did nothing to the text,
   email and tel fields. It did work on the select, the date and the textarea,
   because those element types are not in the stock selector list, which is
   exactly what made the failure look partial rather than total. Two classes
   score 0-2-0 and win.

   Killing the shadow rather than our border keeps the ring Night Sky Blue. The
   stock one is black, which is not a brand colour and would have been the result
   of matching live by dropping the border instead. */
.sparko-brief__field .sparko-brief__input,
.sparko-brief__field .sparko-brief__textarea {
  box-shadow: none;
}
.sparko-brief__textarea { resize: vertical; min-height: 8rem; }
.sparko-brief__input:focus-visible,
.sparko-brief__textarea:focus-visible { outline: 2px solid var(--sparko-pink); outline-offset: 2px; }
/* Full width, matching the live contact form's SEND button, which spans the
   form rather than sitting centred at its label width. The button is a pill with
   inline-flex centring, so width alone puts the label in the middle; nothing
   else is needed. */
.sparko-brief__actions { grid-column: 1 / -1; display: flex; justify-content: center; margin-top: 0.5rem; }
.sparko-brief__actions .sparko-btn { width: 100%; }
.sparko-brief__note { grid-column: 1 / -1; margin: 0; font-family: var(--main-font-stack, sans-serif); font-size: 1rem; border-radius: 0.75rem; padding: 0.9rem 1rem; }
.sparko-brief__note--ok { background: color-mix(in srgb, var(--sparko-gold) 22%, #ffffff); color: var(--sparko-navy); border: 2px solid var(--sparko-navy); }
.sparko-brief__note--err { background: color-mix(in srgb, var(--sparko-pink) 12%, #ffffff); color: var(--sparko-navy); border: 2px solid var(--sparko-pink); }
@media (max-width: 700px) { .sparko-brief__form { grid-template-columns: 1fr; } .sparko-brief__panel { padding: 1.5rem; } }
/* Native select, styled to match the text inputs. appearance:none removes the OS
   chrome so the 2px navy border reads the same as the fields beside it.

   Removing that chrome also removed the disclosure arrow, which left the field
   looking like a text input that happened to say "Select...". The arrow is drawn
   back as a background SVG in Night Sky Blue (2026-09-08, at the client's
   direction). Inline data URI rather than an asset, so it needs no extra request
   and cannot 404; the # in the stroke colour is escaped as %23, which is the one
   character that silently breaks a data URI in CSS.

   padding-inline-end clears the arrow so a long option cannot run underneath it.
   The value is the arrow's own inset plus its width plus a little air. */
.sparko-brief__select {
  appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23262666' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 1.1rem 1.1rem;
  padding-inline-end: 2.6rem;
}
/* An unanswered select was rendering its prompt in full-strength navy, so "Select
   a range" read as a chosen value while the text placeholders beside it were
   grey. :has() lets the prompt match them without a class toggled by script, and
   the colour returns to navy the moment a real option is checked. */
.sparko-brief__select:has(option[value=""]:checked) { color: rgba(38, 38, 102, 0.45); }
.sparko-brief__footer { margin-top: 1.5rem; text-align: center; font-family: var(--main-font-stack, sans-serif); font-size: 1rem; color: rgba(38, 38, 102, 0.78); }
.sparko-brief__footer p { margin: 0; }
/* The footer carries two lines now, the response-time promise and the email
   route, so consecutive paragraphs need separating. p:only-child stays flush. */
.sparko-brief__footer p + p { margin-top: 0.75rem; }
.sparko-brief__footer a { color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px; }
/* Links inside the intro line. Without this the routing links read as plain
   prose, which is the one place on a contact form you cannot afford to hide a
   route to a different form. */
.sparko-brief__sub a { color: var(--sparko-pink); text-decoration: underline; text-underline-offset: 3px; font-weight: 700; }
.sparko-brief__sub a:hover { color: var(--sparko-navy); }
/* FAQ, heading centred above the questions instead of beside them. A setting
   rather than a change, so the PDP and collection FAQs keep their split layout.
   The list caps and centres, since a full-width accordion at 1820px is a very
   long click target for a one-line question. */
/* Row gap 0.5rem, not the 2rem the side-by-side layout uses. Stacked, the
   heading sits directly above the questions rather than beside them, and the
   two gaps compound: the section title carries its own 24px bottom margin, so a
   32px row gap put 56px between "FAQ" and the first accordion. 0.5rem brings
   that to 32. The column gap is irrelevant here, the grid being one column, so
   only the row gap moves. */
.sparko-pdp-faq__grid--stacked { grid-template-columns: 1fr; column-gap: 2rem; row-gap: 0.5rem; }
.sparko-pdp-faq__grid--stacked .sparko-pdp-faq__head { text-align: center; }
.sparko-pdp-faq__grid--stacked > *:last-child { width: 100%; max-width: 55rem; margin-inline: auto; }

/* ----------------------------------------------------------------------------
   25. Holidays & Occasions (template: page.holidays-occasions)
   Built from the v2 design "Sparko Holidays & Occasions.html". Every "shop by"
   grid is sparko-collections, and the closing band is sparko-cta-band, so only
   the month rail is styled here.
   ---------------------------------------------------------------------------- */
.sparko-months { background: var(--sparko-cream); padding-block: 3.5rem; }
.sparko-months__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.sparko-months__title { text-align: left; }
.sparko-months__intro {
  font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem; line-height: 1.5;
  color: rgba(38, 38, 102, 0.78); margin: 0.5rem 0 0;
}
.sparko-months__tag {
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.8rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--sparko-navy);
  background: color-mix(in srgb, var(--sparko-gold) 30%, var(--sparko-cream));
  border: 2px solid var(--sparko-navy); border-radius: 999px; padding: 0.5rem 1rem; white-space: nowrap;
}
/* Full-bleed rail. The left edge lines up with the container's content edge via
   the shared bleed token; the right edge runs off the viewport so the next card
   always peeks and the row reads as scrollable. Same treatment as bestsellers. */
.sparko-months__track {
  display: flex; gap: 1.5rem; margin-top: 2.5rem;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  padding-inline: var(--sparko-bleed-pad) var(--sparko-gutter);
  scroll-padding-inline-start: var(--sparko-bleed-pad);
  scrollbar-width: none; -ms-overflow-style: none;
}
.sparko-months__track::-webkit-scrollbar { display: none; }
.sparko-months__card {
  flex: 0 0 clamp(11rem, 16vw, 15rem); scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 0.75rem;
  text-decoration: none; color: var(--sparko-navy);
}
.sparko-months__media {
  position: relative; display: block; aspect-ratio: 1 / 1;
  border: 2px solid var(--sparko-navy); border-radius: 1.25rem; overflow: hidden;
  background: #ffffff; transition: border-color 160ms ease;
}
.sparko-months__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sparko-months__card:hover .sparko-months__media { border-color: var(--sparko-pink); }
/* Electric Pink on the current month, California Gold on the next. CLAUDE.md
   names this rail as one of the three sanctioned pink uses. Gold on navy type is
   fine here: the badge is a filled chip, not gold text on cream. */
.sparko-months__badge {
  position: absolute; left: 0.6rem; top: 0.6rem;
  font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.7rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--sparko-pink); color: #ffffff;
  border: 2px solid var(--sparko-navy); border-radius: 999px; padding: 0.3rem 0.7rem;
}
.sparko-months__badge--next { background: var(--sparko-gold); color: var(--sparko-navy); }
.sparko-months__meta { display: flex; flex-direction: column; gap: 0.15rem; text-align: center; }
.sparko-months__month { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.05rem; line-height: 1.2; }
.sparko-months__occ { font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem; color: rgba(38, 38, 102, 0.72); }
/* Descriptor line under a collection tile. Blank on the homepage, so that row is
   unchanged; the Shop By Style row uses it. */
.sparko-tile__line {
  display: block; font-family: var(--main-font-stack, sans-serif); font-size: 0.95rem;
  line-height: 1.45; color: rgba(38, 38, 102, 0.72); text-align: center; margin-top: 0.25rem;
}
@media (max-width: 700px) {
  .sparko-months__card { flex-basis: 60vw; }
  .sparko-months__head { flex-direction: column; align-items: flex-start; }
}

/* ----------------------------------------------------------------------------
   26. Predictive search panel (snippet: sparko-predictive-search)
   Our fork of Switch's suggestions section, so every selector here targets our
   own markup. Nothing reaches into stock. See CLAUDE.md's running list.

   The surface stays Night Sky Blue for now: the panel is an overlay dropped from
   a navy header, so navy may be correct rather than a mismatch. Reviewing that
   separately, which is why the card and type colours below are written as
   on-navy overrides rather than baked into the card snippet.
   ---------------------------------------------------------------------------- */
/* The panel is an OVERLAY, not a full-height takeover: it hangs off the bar,
   caps its height and scrolls internally, so the page stays visible under it.
   The wrapper does the positioning and the container math; .sparko-psearch is
   the card itself. */
.sparko-header__search-results {
  position: absolute; top: calc(100% + 0.5rem); left: 0; right: 0; z-index: 60;
  display: flex; justify-content: center;
  padding-inline: var(--sparko-gutter);
}
/* The x-ref node the component writes markup into sits between the two and must
   not constrain either. */
.sparko-header__search-results > [x-ref='results'] { width: 100%; max-width: calc(var(--sparko-container) - 2 * var(--sparko-gutter)); }
.sparko-psearch {
  width: 100%;
  /* SAFETY CAP, not the normal case. Five results are one row on desktop and the
     panel sizes to its content well under this. It exists for the narrow widths
     where the grid drops to three, two or one column and five results become up
     to five rows: without it the panel would run past the fold and the view-all
     button would sit off screen with the page scroll locked. */
  max-height: 70vh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--sparko-navy);
  border: 2px solid rgba(254, 251, 245, 0.35);
  border-radius: 1.25rem;
  padding: 1.75rem 1.75rem 0;
}
/* Aligned to the shell, not to the viewport. The grid and the foot both carry
   .sparko-wrap, so the container cap and gutter come from the tokens and the
   results line up with every other row on the page. */
/* The side rail and its grid are gone with the collections and pages columns, so
   the products list is the panel's only content and takes the full width. */
.sparko-psearch__products.is-loading { opacity: 0.35; }

.sparko-psearch__products { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1.5rem; }
@media (max-width: 1020px) { .sparko-psearch__products { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .sparko-psearch__products { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The card is the shared sparko-product-card. Only the parts that sit ON the
   navy rather than inside the white image frame need a colour: the name and
   price print navy by default and would vanish here. */
/* The shared card is sized for the bestsellers CAROUSEL (flex-basis clamp), so
   in a grid cell it refuses to fill. Same override the related-products grid and
   the collection grid already carry. */
.sparko-psearch .sparko-prod { flex: 1 1 auto; width: 100%; }
/* And its row is a space-between line, name left and price hard right, which at
   this width read as two unrelated columns. Stacked and centred, matching the
   decision already made for bestsellers. */
.sparko-psearch .sparko-prod__row {
  flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 0.3rem; text-align: center;
}
.sparko-psearch .sparko-prod__name,
.sparko-psearch .sparko-prod__price { color: var(--sparko-cream); }
.sparko-psearch .sparko-prod__img { border-color: rgba(254, 251, 245, 0.55); }
.sparko-psearch .sparko-prod:hover .sparko-prod__img,
.sparko-psearch .predictive-search__option[aria-selected="true"] .sparko-prod__img { border-color: var(--sparko-pink); }

/* Sticky again now the panel can scroll at narrow widths. It costs nothing when
   there is no overflow, and when there is, it keeps the one control that reaches
   the full result set on screen instead of below the fold. */
.sparko-psearch__foot {
  position: sticky; bottom: 0; z-index: 1;
  margin-top: 2rem; padding-block: 1.25rem 1.75rem;
  display: flex; justify-content: center;
  background: var(--sparko-navy);
}
.sparko-psearch__all { display: flex; justify-content: center; }
.sparko-psearch__empty {
  font-family: var(--main-font-stack, sans-serif); font-size: 1.06rem;
  color: rgba(254, 251, 245, 0.8); margin: 0; text-align: center;
}
/* The keyboard-selected view-all gets the same gold ring the rows use, so the
   arrow keys have a visible target on the button too. */
.sparko-psearch__all[aria-selected="true"] .sparko-btn { box-shadow: 0 0 0 3px var(--sparko-gold); }

.sparko-psearch__loading { display: flex; justify-content: center; padding: 3rem 0; }
.sparko-psearch__spinner {
  width: 1.5rem; height: 1.5rem; border-radius: 50%;
  border: 3px solid rgba(254, 251, 245, 0.35); border-top-color: var(--sparko-cream);
  animation: sparko-psearch-spin 0.7s linear infinite;
}
@keyframes sparko-psearch-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .sparko-psearch__spinner { animation: none; } }

/* Wiring predictive search put a <data-island> between the searchbar flex row
   and the form. It is display:block with no basis, so as a flex child it shrank
   to its content and the form's width:100% then resolved against 280px, which is
   why the pill stopped spanning the bar. The island has to be told to grow.

   min-width:0 as well: a flex child will not shrink below its content otherwise,
   and the results grid inside it is wide. */
.sparko-header__search-island { flex: 1 1 auto; min-width: 0; }
/* position:relative so the absolutely positioned results overlay hangs off the
   bar rather than off the page. */
.sparko-header__searchbar { position: relative; }
/* The pill was capped at 78rem and centred itself, so it agreed with neither the
   bar nor the results below it. It carries .sparko-wrap's own math now, written
   out rather than by adding the class, because the class would also apply to the
   results panel in the same island and gutter it twice. */
.sparko-header__searchbar { padding-inline: 0; }
.sparko-header__searchbar-form {
  max-width: var(--sparko-container);
  margin-inline: auto;
  width: calc(100% - 2 * var(--sparko-gutter));
}

/* ----------------------------------------------------------------------------
   27b. Focus rings are for keyboard users only

   base.bundle.css sets `*:focus { outline: <input-border-width> dashed }` as well as the
   `*:focus-visible` equivalent. The bare `:focus` half fires on ANY focus, including focus
   moved by script, so Switch's own drawers draw a dashed ring on the close button the moment
   they open under a mouse tap: the cart drawer traps focus and sends it to that button. The
   rule is byte-identical in 4.4.0 and 5.0.1, so this is long-standing Switch behaviour rather
   than anything the rebase introduced.

   This turns the mouse case off and leaves the keyboard case alone. It is deliberately global
   and selector-agnostic rather than a rule aimed at Switch's drawer markup, so it does not
   reach into a stock section and does not break the hard rule. `*:focus:not(:focus-visible)`
   outranks the bundle's `*:focus` on specificity and sparko-custom.css loads after it, so the
   keyboard ring from `*:focus-visible` still wins where it should.
   Added 2026-09-09. */
*:focus:not(:focus-visible) { outline: none; }

/* ---------------------------------------------------------------------------
   28. Header focus rings
   The header chrome had no focus rule, so it fell back to the browser's dashed
   ring: near-invisible on Night Sky Blue and off-system where it did show.

   :focus-visible only, so a mouse click never draws a ring but Tab always does.
   The bare :focus reset beside it kills the UA ring on click for the elements
   that still paint one; it is safe because every rule here has a
   :focus-visible partner, so nothing ends up with no focus state.

   TWO COLOURS, one per surface, because the header has two. The bar is navy, so
   the ring is California Gold. The mega panel and the mobile drawer are cream,
   so there the ring is Night Sky Blue: gold on cream is barred as text and reads
   weakly as a ring. Focus and hover are both gold on the bar as of 2026-09-11,
   when the nav hover/active state moved off Electric Pink for contrast; they stay
   telling apart because focus draws a ring and hover recolours the glyphs.
   ---------------------------------------------------------------------------- */
.sparko-header__icon:focus,
.sparko-header__link:focus,
.sparko-header__burger:focus,
.sparko-header__wordmark:focus,
.sparko-header__logo-img:focus,
.sparko-header__searchbar-close:focus,
.sparko-header__mega-link:focus,
.sparko-header__panel-close:focus,
.sparko-header__drawer-link:focus,
.sparko-header__drawer-sublink:focus,
.sparko-header__drawer-summary:focus { outline: none; }

/* On the navy bar */
.sparko-header__icon:focus-visible,
.sparko-header__link:focus-visible,
.sparko-header__burger:focus-visible,
.sparko-header__wordmark:focus-visible,
.sparko-header__logo-img:focus-visible,
.sparko-header__searchbar-close:focus-visible {
  outline: 2px solid var(--sparko-gold);
  outline-offset: 3px;
  border-radius: 6px;
}
/* On the cream surfaces inside the header */
.sparko-header__mega-link:focus-visible,
.sparko-header__panel-close:focus-visible,
.sparko-header__drawer-link:focus-visible,
.sparko-header__drawer-sublink:focus-visible,
.sparko-header__drawer-summary:focus-visible {
  outline: 2px solid var(--sparko-navy);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ============================================================================
   TOUCH TARGETS
   ============================================================================
   Controls that are comfortable with a mouse and too small with a thumb. The
   query is `pointer: coarse`, NOT a width breakpoint, because this is a
   property of the input device rather than the viewport: a tablet in landscape
   at 1100px has the same thumb as a phone at 390px, and a width query would
   miss it. It is the only pointer query in this file; every other responsive
   rule here is width-based and should stay that way.

   Nothing below changes how a control LOOKS on a desktop pointer. The targets
   grow to 44px, Apple's minimum, only where a finger is doing the tapping.

   The PDP gallery dots are handled at their own rule instead, inside the
   max-width: 980px block, because there the fix is structural: the button had
   to become a wrapper around a pseudo-element dot rather than being the dot.

   Already clearing 44px and deliberately not listed: the quantity stepper
   (46x52), the bestsellers arrows (48px), the primary .sparko-btn (~51px), and
   the mobile drawer rows, which were rebuilt to 44px in their own pass. */
@media (pointer: coarse) {
  /* Collection filter bar. 10px of padding on 14px type gives a 38px control;
     14px gives 46px. The chips inside the tray are worse, 33px, and they are
     the ones a shopper taps repeatedly while narrowing a collection. */
  .sparko-facet__btn { padding: 14px 18px; }
  .sparko-fchip { padding: 14px 16px; }

  /* "Clear" sits in the same scrolling row as the facets, so it has to grow
     with them or it becomes the one thing in the row that is hard to hit. */
  .sparko-collection-bar__clear { padding: 14px 10px; }

  /* The small pill. Used for secondary actions in card footers and section
     headers, where it is often the only control in reach. */
  /* Vertical padding grows for the tap target and is the point of this rule;
     the sides follow the pill's new 0.875rem so it does not read as a wider
     button than the base one. Height is what the 44px minimum needs. */
  .sparko-btn--sm { padding: 0.95rem 0.875rem; }

  /* Pagination. 40px square, and the numbers sit 4px apart, so a miss lands on
     the neighbouring page rather than on nothing.

     Previous and Next are listed too. They were missed when this block was
     written, because the blog pager was the only surface using it and the
     numbers were what got measured; the collection grid put the same control on
     a page with fifty products under it, where the steps are the ones a thumb
     reaches for. Measured 76.8x40 before this line. */
  .sparko-pager__page { min-width: 2.75rem; height: 2.75rem; }
  .sparko-pager__step { min-height: 2.75rem; display: inline-flex; align-items: center; }

  /* Colour swatches are 42px, which is two pixels short. Cheap to correct and
     it keeps the ring geometry identical. */
  .sparko-pdp-swatch { width: 44px; height: 44px; }
}


/* ----------------------------------------------------------------------------
   The gap under the header
   The FIRST section on a page sits directly under the menu bar, so its top
   padding IS that gap. Measured against the live theme on /pages/wholesale at
   the same header height (59px on a phone, 51px on desktop): live's first
   section pads 32px then 64px, ours padded 56px then 72px, so every one of
   these pages opened lower than the site it replaces.

   Scoped to the first section, deliberately. The number that produced 56px is
   --sparko-section-pad, the rhythm BETWEEN every section on every page; live
   simply runs a tighter rhythm throughout. Retuning that token would have
   restyled the whole site off a note about one gap, so it is untouched and only
   the section that touches the header is trimmed.

   Three section types can be first and were over the baseline: the page hero
   (six pages, plus the blog's compact variant), the prose block that opens a
   case study, and the brief form that opens Contact. Everything else that can
   open a page already sits at or below it: the homepage hero, the Our Work
   banner, an article and a collection hero all pad 0 and are full-bleed by
   design, and the PDP hero is already 32px. None of them are in this selector.
   ---------------------------------------------------------------------------- */
#MainContent > .shopify-section:first-child > .sparko-page-hero,
#MainContent > .shopify-section:first-child > .sparko-prose,
#MainContent > .shopify-section:first-child > .sparko-brief {
  padding-top: 2rem;
}
@media (min-width: 981px) {
  #MainContent > .shopify-section:first-child > .sparko-page-hero,
  #MainContent > .shopify-section:first-child > .sparko-prose,
  #MainContent > .shopify-section:first-child > .sparko-brief {
    padding-top: 4rem;
  }
}

/* Sparko customizer app block: its own full-width row under the PDP listing (sections/sparko-pdp-buy.liquid,
   2026-10-15); Design Yours scrolls to it, clear of the sticky header. Below 700px the customizer shows nothing
   in this row (its designer is a full-screen sheet opened by Design Yours), so the row takes no space. */
.sparko-pdp-app { margin-top: 3.5rem; scroll-margin-top: 5rem; }
@media (max-width: 989px) { .sparko-pdp-app { margin-top: 2.5rem; } }
@media (max-width: 699px) { .sparko-pdp-app { margin-top: 0; } }

/* Shopify Inbox chat launcher (assets/sparko-chat-launcher.js, 2026-10-14): hidden while the cart drawer or the
   customizer's phone sheet (.spk-lock) is open, and while the customizer is at the bottom of the screen. */
html.sparko-chat-off--cart shopify-chat,
html.sparko-chat-off--customizer shopify-chat,
html.spk-lock shopify-chat { display: none !important; }

/* Nutrition Facts panel from the product's metafield (snippets/sparko-pdp-accordions.liquid, 2026-10-14). */
.sparko-pdp-acc__facts { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem; }

/* Custom quote form (snippets/sparko-quote-form.liquid, 2026-10-15): the old theme's Custom Shape quote form in the
   redesign's card, input and button styles. Placeholder and empty-choice text stay muted until filled. */
.sparko-quote { margin-top: 2rem; padding: 1.75rem; border: 2px solid var(--sparko-navy); border-radius: 20px; background: #ffffff; color: var(--sparko-navy); scroll-margin-top: 5rem; }
.sparko-quote__head { margin-bottom: 1.25rem; }
.sparko-quote__title { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; font-size: 1.5rem; line-height: 1.15; text-transform: uppercase; letter-spacing: -0.02em; margin: 0 0 0.4rem; }
.sparko-quote__intro { font-family: var(--main-font-stack, sans-serif); font-size: 1rem; line-height: 1.45; color: rgba(38, 38, 102, 0.75); margin: 0; }
.sparko-quote__form { display: flex; flex-direction: column; gap: 1rem; }
.sparko-quote__row { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 750px) { .sparko-quote__row { grid-template-columns: 1fr 1fr; } }
.sparko-quote__field { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.sparko-quote__field label { font-family: var(--main-font-stack, sans-serif); font-weight: 700; font-size: 0.9rem; }
.sparko-quote__req { color: var(--sparko-pink); }
.sparko-quote__opt { font-weight: 400; color: rgba(38, 38, 102, 0.6); }
.sparko-quote__input { box-sizing: border-box; width: 100%; min-width: 0; font-family: var(--main-font-stack, sans-serif); font-size: 1rem; color: var(--sparko-navy); background: #ffffff; border: 2px solid var(--sparko-navy); border-radius: 0.75rem; padding: 0.7rem 0.9rem; }
.sparko-quote__input::placeholder { color: rgba(38, 38, 102, 0.45); opacity: 1; }
.sparko-quote__input:focus { outline: none; border-color: var(--sparko-navy); box-shadow: 0 0 0 3px rgba(239, 176, 55, 0.55); }
.sparko-quote__select { -webkit-appearance: none; appearance: none; padding-right: 2.5rem; cursor: pointer;
  background-image: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2012%2012%22%3E%3Cpath%20fill%3D%22%23262666%22%20d%3D%22M6%208L1%203h10z%22%2F%3E%3C%2Fsvg%3E');
  background-repeat: no-repeat; background-position: right 1rem center; }
.sparko-quote__select:invalid, .sparko-quote__select:has(option[value=""]:checked) { color: rgba(38, 38, 102, 0.45); }
.sparko-quote__select option { color: var(--sparko-navy); }
.sparko-quote__date { -webkit-appearance: none; appearance: none; min-height: 3rem; display: block; text-align: left; }
.sparko-quote__submit { width: 100%; margin-top: 0.25rem; font-size: 1rem; padding-block: 0.8125rem; }
.sparko-quote__msg { padding: 1rem 1.1rem; border-radius: 12px; font-family: var(--main-font-stack, sans-serif); }
.sparko-quote__msg p { margin: 0; }
.sparko-quote__msg-t { font-weight: 800; margin-bottom: 0.3rem !important; }
.sparko-quote__msg--ok { background: #E6F4EC; border: 2px solid #00994B; color: #0B5A2E; }
.sparko-quote__msg--err { background: #FDE8EE; border: 2px solid #E11548; color: #8A0E2E; }
.sparko-quote__msg--err ul { margin: 0.3rem 0 0; padding-left: 1.2rem; }
@media (max-width: 749px) { .sparko-quote { padding: 1.25rem; } }
/* The theme's global text-input rule (pill radius, inset ring) outranks the class above; match the selects. */
.sparko-quote .sparko-quote__form input.sparko-quote__input,
.sparko-quote .sparko-quote__form textarea.sparko-quote__input,
.sparko-quote .sparko-quote__form select.sparko-quote__input { border: 2px solid var(--sparko-navy); border-radius: 0.75rem; box-shadow: none; padding: 0.7rem 0.9rem; min-height: 0; height: auto; }
.sparko-quote .sparko-quote__form input.sparko-quote__input:focus,
.sparko-quote .sparko-quote__form textarea.sparko-quote__input:focus,
.sparko-quote .sparko-quote__form select.sparko-quote__input:focus { box-shadow: 0 0 0 3px rgba(239, 176, 55, 0.55); }
.sparko-quote .sparko-quote__form select.sparko-quote__input { padding-right: 2.5rem; outline: none; }

/* /collections (sections/sparko-list-collections.liquid, 2026-10-15): each collection is a heading, its intro and a
   row of the collection cards, spaced like the redesigned collection pages. */
.sparko-list-collections__item + .sparko-list-collections__item { margin-top: 4rem; }
.sparko-list-collections__desc { font-family: var(--main-font-stack, sans-serif); font-size: 1.05rem; line-height: 1.45; color: var(--sparko-navy); max-width: 40rem; margin-bottom: 2rem; }
.sparko-list-collections__desc p { margin: 0; }
.sparko-list-collections__desc p + p { margin-top: 0.4rem; }
.sparko-list-collections__title + .sparko-list-collections__grid { margin-top: 1.5rem; }
.sparko-list-collections__more { display: flex; justify-content: center; margin-top: 2rem; }
@media (max-width: 699px) { .sparko-list-collections__item + .sparko-list-collections__item { margin-top: 3rem; } }

/* Search results (sections/main-search.liquid, 2026-10-15): cream page, the redesign heading, and the collection
   card centred with its price under the name, as on the collection pages. */
.sparko-search { background: var(--sparko-cream) !important; color: var(--sparko-navy); }
.sparko-search h1 { font-family: var(--heading-font-stack, sans-serif); font-weight: 900; text-transform: uppercase; letter-spacing: -0.01em; color: var(--sparko-navy); text-shadow: none; }
.sparko-search .sparko-prod { flex: 1 1 auto; width: 100%; text-align: center; }
.sparko-search .sparko-prod__row { flex-direction: column; align-items: center; justify-content: flex-start; gap: 0.35rem; text-align: center; }
