/* ---------------------------------------------------------------------
   1. TOKENS  —  LIGHT is the default, DARK is opt-in
   ---------------------------------------------------------------------
   Two layers:
     - SEMANTIC tokens (--surface-*, --fg-*, --brand-*) carry the meaning
       and are the only thing a theme redefines.
     - LEGACY aliases (--ink-*, --lime-*, --text-*) keep the ~500 existing
       component rules working untouched.

   Channel tokens (--accent-rgb and friends) exist so translucent tints
   follow the theme: rgb(var(--accent-rgb) / .12).

   Every pair below was contrast-checked. Note --brand-display (#539729,
   sampled from the banner) is 3.60:1 on white: valid for LARGE display
   text only, which is exactly how the banner uses it. Anything
   interactive or body-sized uses --brand instead, at 5.40:1.
   --------------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* -- Surfaces ------------------------------------------------------- */
  --surface-base:   #FFFFFF;   /* page                                   */
  --surface-raised: #FFFFFF;   /* cards, panels                          */
  --surface-sunken: #F6F7F3;   /* alternating bands (matches the banner) */
  --surface-tint:   #EDF2E7;   /* brand-tinted panels                    */
  --surface-deep:   #E4EDDC;   /* hero band                              */

  /* -- Brand (sampled from the logo and banner) ------------------------ */
  --brand-display:  #539729;   /* LARGE display text only - 3.60:1       */
  --brand:          #1F7A31;   /* links, buttons, icons   - 5.40:1       */
  --brand-strong:   #17702B;   /* hover / pressed         - 6.20:1       */
  --brand-lime:     #7AB93C;   /* decorative only, never text            */
  --brand-tint:     #E9F3E0;
  --gold-400:       #7D6014;   /* restrained gold - 5.05:1 on its tint   */

  --on-accent:      #FFFFFF;   /* text on a brand-coloured background    */

  /* -- Text ----------------------------------------------------------- */
  --fg-strong:      #16211A;   /* headings           16.58:1             */
  --fg:             #333D36;   /* body               11.28:1             */
  --fg-soft:        #55635B;   /* secondary           5.87:1             */
  --fg-muted:       #616E66;   /* meta / captions     5.34:1             */

  /* -- Lines & glass --------------------------------------------------- */
  --hairline:        #E4EAE0;
  --hairline-mid:    #DDE5D8;
  --hairline-strong: rgba(31, 122, 49, .30);
  --glass:           rgba(255, 255, 255, .78);
  --glass-hi:        rgba(255, 255, 255, .95);
  --scrim:           rgba(28, 40, 30, .42);

  /* -- Channel tokens for translucent tints ---------------------------- */
  --accent-rgb:      31 122 49;
  --accent-soft-rgb: 122 185 60;
  --brand-deep-rgb:  83 151 41;
  --header-rgb:      255 255 255;
  --field-rgb:       252 253 251;
  --overlay-rgb:     22 33 26;
  --shadow-rgb:      26 44 30;

  /* -- Status ---------------------------------------------------------- */
  --success:    #16702F;  --success-rgb: 22 112 47;
  --warning:    #8A5A00;  --warning-rgb: 138 90 0;
  --danger:     #B3261E;  --danger-rgb:  179 38 30;
  --info:       #0B6E99;  --info-rgb:    11 110 153;
  --success-bg: rgb(var(--success-rgb) / .10);
  --warning-bg: rgb(var(--warning-rgb) / .10);
  --danger-bg:  rgb(var(--danger-rgb)  / .09);
  --info-bg:    rgb(var(--info-rgb)    / .09);

  /* -- Elevation (soft on light, never muddy) --------------------------- */
  --sh-1: 0 1px 2px rgb(var(--shadow-rgb) / .06);
  --sh-2: 0 1px 3px rgb(var(--shadow-rgb) / .08),
          0 6px 18px rgb(var(--shadow-rgb) / .06);
  --sh-3: 0 2px 6px rgb(var(--shadow-rgb) / .09),
          0 14px 36px rgb(var(--shadow-rgb) / .10);
  --sh-4: 0 4px 12px rgb(var(--shadow-rgb) / .10),
          0 30px 70px rgb(var(--shadow-rgb) / .14);
  --glow-lime: 0 0 0 1px rgb(var(--accent-rgb) / .30), 0 8px 26px rgb(var(--accent-rgb) / .16);

  /* -- Scene tokens (hero / footer atmosphere) ------------------------- */
  --hero-glow-1:  rgb(var(--brand-deep-rgb) / .18);
  --hero-glow-2:  rgb(var(--accent-soft-rgb) / .22);
  --hero-top:     #FFFFFF;
  --hero-mid:     #F4F9EF;
  --hero-bottom:  #FFFFFF;
  --hero-reflection: rgb(var(--shadow-rgb) / .20);
  /* Lifts the photo hero's copy space toward the page surface. */
  --hero-scrim-rgb: 255 255 255;
  --cta-glow:     rgb(var(--accent-soft-rgb) / .30);
  --footer-glow:  rgb(var(--accent-soft-rgb) / .18);
  --footer-top:   #F6F7F3;
  --footer-bottom:#EDF2E7;
  --spinner-track: rgb(255 255 255 / .40);
  --gold-bg:      rgb(160 124 33 / .10);
  --gold-line:    rgb(160 124 33 / .28);

  /* -- LEGACY ALIASES - component CSS still uses these ------------------ */
  --ink-950: var(--surface-deep);
  --ink-900: var(--surface-base);
  --ink-850: var(--surface-raised);
  --ink-800: var(--surface-sunken);
  --ink-750: var(--surface-tint);
  --ink-700: var(--surface-tint);
  --ink-600: var(--hairline-mid);

  --forest-900: var(--surface-deep);
  --forest-800: var(--surface-tint);
  --forest-700: var(--brand-strong);
  --forest-600: var(--brand);
  --forest-500: var(--brand);
  --forest-400: var(--brand-display);

  --teal-800: var(--surface-tint);
  --teal-700: var(--surface-tint);

  --lime-500: var(--brand-strong);
  --lime-400: var(--brand);
  --lime-300: var(--brand-strong);

  --text-hi:    var(--fg-strong);
  --text:       var(--fg);
  --text-mid:   var(--fg-soft);
  --text-low:   var(--fg-muted);
  --text-muted: var(--fg-muted);

  --line:        var(--hairline-mid);
  --line-soft:   var(--hairline);
  --line-strong: var(--hairline-strong);

  /* -- Type ----------------------------------------------------------- */
  --font-display: "Rubik", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-body: "Nunito Sans", "Segoe UI", system-ui, -apple-system, sans-serif;

  --fs-12: .75rem;
  --fs-14: .875rem;
  --fs-15: .9375rem;
  --fs-16: 1rem;
  --fs-18: 1.125rem;
  --fs-22: 1.375rem;
  --fs-28: 1.75rem;
  --fs-36: 2.25rem;
  --fs-48: 3rem;
  --fs-64: 4rem;

  /* -- Spacing (4px rhythm) ------------------------------------------- */
  --space-1: 4px;   --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
  --space-5: 20px;  --space-6: 24px;  --space-8: 32px;  --space-10: 40px;
  --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;

  /* -- Radii ---------------------------------------------------------- */
  --r-sm: 8px; --r-md: 14px; --r-lg: 20px; --r-xl: 28px; --r-2xl: 34px; --r-pill: 999px;

  /* -- Motion (expo.out - the house curve) ----------------------------- */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-in: cubic-bezier(.7, 0, .84, 0);
  --t-fast: 150ms; --t-base: 240ms; --t-slow: 420ms;

  /* -- Layout --------------------------------------------------------- */
  --container: 1240px;
  --container-narrow: 760px;
  --header-h: 72px;

  /* -- Z-index scale --------------------------------------------------- */
  --z-base: 1; --z-raised: 10; --z-sticky: 20;
  --z-header: 40; --z-drawer: 60; --z-modal: 80; --z-toast: 100;
}

/* ---------------------------------------------------------------------
   DARK THEME
   Only the semantic layer is redefined; every alias above follows.
   --------------------------------------------------------------------- */
[data-theme="dark"] {
  color-scheme: dark;

  --surface-base:   #080D0B;
  --surface-raised: #0B1210;
  --surface-sunken: #101A16;
  --surface-tint:   #16231D;
  --surface-deep:   #050807;

  --brand-display:  #C2EF8C;
  --brand:          #A8E063;
  --brand-strong:   #C2EF8C;
  --brand-lime:     #8FCF4A;
  --brand-tint:     rgb(var(--accent-rgb) / .12);
  --gold-400:       #C9A961;

  --on-accent:      #050807;

  --fg-strong:      #EDF5EF;
  --fg:             #DCE8DF;
  --fg-soft:        #A9BDB0;
  --fg-muted:       #97A99D;

  --hairline:        rgb(var(--overlay-rgb) / .10);
  --hairline-mid:    rgb(var(--accent-rgb) / .16);
  --hairline-strong: rgb(var(--accent-rgb) / .30);
  --glass:           rgba(16, 26, 22, .72);
  --glass-hi:        rgba(28, 44, 37, .86);
  --scrim:           rgba(3, 6, 5, .60);

  --accent-rgb:      168 224 99;
  --accent-soft-rgb: 194 239 140;
  --brand-deep-rgb:  26 107 71;
  --header-rgb:      8 13 11;
  --field-rgb:       11 18 16;
  --overlay-rgb:     220 232 223;
  --shadow-rgb:      0 0 0;

  --success: #4ADE80;  --success-rgb: 74 222 128;
  --warning: #FBBF24;  --warning-rgb: 251 191 36;
  --danger:  #F87171;  --danger-rgb:  248 113 113;
  --info:    #7DD3FC;  --info-rgb:    125 211 252;
  --success-bg: rgb(var(--success-rgb) / .12);
  --warning-bg: rgb(var(--warning-rgb) / .12);
  --danger-bg:  rgb(var(--danger-rgb)  / .12);
  --info-bg:    rgb(var(--info-rgb)    / .12);

  --hero-glow-1:  rgb(var(--brand-deep-rgb) / .34);
  --hero-glow-2:  rgb(11 58 56 / .38);
  --hero-top:     #050807;
  --hero-mid:     #061A12;
  --hero-bottom:  #080D0B;
  --hero-reflection: rgb(var(--accent-rgb) / .22);
  --cta-glow:     rgb(var(--brand-deep-rgb) / .40);
  --footer-glow:  rgb(14 53 36 / .50);
  --footer-top:   #080D0B;
  --footer-bottom:#050807;
  --spinner-track: rgb(0 0 0 / .25);
  --gold-bg:      rgb(201 169 97 / .14);
  --gold-line:    rgb(201 169 97 / .34);

  --sh-1: 0 1px 2px rgb(var(--shadow-rgb) / .30);
  --sh-2: 0 4px 16px rgb(var(--shadow-rgb) / .35);
  --sh-3: 0 12px 40px rgb(var(--shadow-rgb) / .45);
  --sh-4: 0 28px 80px rgb(var(--shadow-rgb) / .55);
  --glow-lime: 0 0 0 1px rgb(var(--accent-rgb) / .30), 0 8px 32px rgb(var(--accent-rgb) / .18);
  /* The artwork is bright; on dark the text is light, so the scrim must
     darken rather than lighten. */
  --hero-scrim-rgb: 8 13 11;
}

/* ---------------------------------------------------------------------
   2. RESET
   --------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Sticky header must not hide anchor targets. */
  scroll-padding-top: calc(var(--header-h) + var(--space-6));
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--ink-900);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-16);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The one rule that guarantees no horizontal scroll anywhere. */
  overflow-x: hidden;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; }
img { height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
p, h1, h2, h3, h4, h5, h6 { margin: 0; overflow-wrap: break-word; }
ul, ol { margin: 0; padding: 0; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-hi);
  line-height: 1.15;
  letter-spacing: -.015em;
  font-weight: 600;
}

/* Visible focus everywhere — never removed, only restyled. */
:focus-visible {
  outline: 2px solid var(--lime-400);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: rgb(var(--accent-rgb) / .28); color: #fff; }

/* ---------------------------------------------------------------------
   3. UTILITIES
   --------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-5);
}
.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--space-20); }
.section--tight { padding-block: var(--space-12); }

/* Alternating band. Works in both themes: it is one step away from the
   page surface in whichever direction the theme runs. */
.section--band {
  background: var(--surface-sunken);
  border-block: 1px solid var(--hairline);
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: absolute; top: -60px; left: var(--space-4);
  z-index: var(--z-toast);
  background: var(--lime-400); color: var(--on-accent);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--r-sm); font-weight: 700;
  transition: top var(--t-base) var(--ease);
}
.skip-link:focus { top: var(--space-4); }

.stack > * + * { margin-top: var(--space-4); }
.text-center { text-align: center; }
.nowrap { white-space: nowrap; }

/* Tabular figures stop prices jittering as they update. */
.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }

/* ---------------------------------------------------------------------
   4. SECTION HEADINGS
   --------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--lime-400);
  margin-bottom: var(--space-4);
}
.eyebrow::before {
  content: ""; width: 28px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--lime-400));
}

.section-head { max-width: 640px; margin-bottom: var(--space-12); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head--center .eyebrow::after {
  content: ""; width: 28px; height: 1px;
  background: linear-gradient(90deg, var(--lime-400), transparent);
}

.section-title {
  font-size: clamp(var(--fs-28), 4.5vw, var(--fs-48));
  margin-bottom: var(--space-4);
}
.section-sub {
  color: var(--text-mid);
  font-size: var(--fs-18);
  /* 60–75 characters on desktop. */
  max-width: 60ch;
}
.section-head--center .section-sub { margin-inline: auto; }

/* ---------------------------------------------------------------------
   5. BUTTONS
   --------------------------------------------------------------------- */
.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text-hi);
  --btn-border: var(--line-strong);

  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  /* 48px tall — comfortably above the 44px touch minimum. */
  min-height: 48px;
  padding: var(--space-3) var(--space-6);
  border: 1px solid var(--btn-border);
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-display);
  font-size: var(--fs-14);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: center;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--t-fast) var(--ease),
              box-shadow var(--t-base) var(--ease),
              background-color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              color var(--t-base) var(--ease);
  touch-action: manipulation;
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0) scale(.98); }

.btn[disabled], .btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  transform: none !important;
  pointer-events: none;
}

/* Primary — the one CTA per screen. */
.btn--primary {
  --btn-bg: linear-gradient(135deg, var(--lime-400), var(--lime-500));
  --btn-fg: var(--on-accent);
  --btn-border: transparent;
  font-weight: 700;
  box-shadow: 0 4px 20px rgb(var(--accent-rgb) / .22);
}
.btn--primary:hover { box-shadow: 0 10px 34px rgb(var(--accent-rgb) / .34); }

.btn--secondary {
  --btn-bg: rgb(var(--accent-rgb) / .07);
  --btn-border: var(--line-strong);
}
.btn--secondary:hover {
  --btn-bg: rgb(var(--accent-rgb) / .13);
  --btn-border: var(--lime-400);
}

.btn--ghost { --btn-border: var(--line-soft); --btn-fg: var(--text-mid); }
.btn--ghost:hover { --btn-fg: var(--text-hi); --btn-border: var(--line-strong); }

.btn--danger {
  --btn-bg: var(--danger-bg);
  --btn-border: rgb(var(--danger-rgb) / .4);
  --btn-fg: var(--danger);
}

.btn--block { width: 100%; }
.btn--sm {
  /* Still 44px tall: this is a customer-facing control, so the touch
     minimum wins over density even in the "small" variant. */
  min-height: 44px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-12);
}
.btn--lg { min-height: 56px; padding: var(--space-4) var(--space-8); font-size: var(--fs-16); }

.btn__icon { width: 18px; height: 18px; flex: 0 0 auto; }

/* Async state: the label is replaced, the width is not. */
.btn.is-loading { color: transparent !important; pointer-events: none; }
.btn.is-loading::after {
  content: "";
  position: absolute; inset: 0; margin: auto;
  width: 18px; height: 18px;
  border: 2px solid var(--spinner-track);
  border-top-color: currentColor;
  border-radius: 50%;
  color: var(--on-accent);
  animation: spin .7s linear infinite;
}
.btn--secondary.is-loading::after, .btn--ghost.is-loading::after { color: var(--lime-400); }

@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------------
   PROMOTIONAL POPUP
   A native <dialog>. showModal() supplies the focus trap, Escape-to-close
   and the ::backdrop, none of which have to be reimplemented here.
   --------------------------------------------------------------------- */
.promo {
  width: min(92vw, 27rem);
  /* The UA centres a modal dialog with `margin: auto`; spelling it out here
     keeps that true even though this rule sets other box properties. */
  margin: auto;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  color: var(--fg);
  box-shadow: var(--sh-3);
  overflow: hidden;
}
.promo::backdrop {
  background: rgb(var(--overlay-rgb) / .55);
  backdrop-filter: blur(3px);
}
.promo[open] { animation: promo-in .28s var(--ease) both; }
@keyframes promo-in {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

.promo__dismiss { position: absolute; top: var(--space-3); right: var(--space-3); }
.promo__close {
  display: grid; place-items: center;
  /* 44px is the minimum comfortable tap target, and this is the control a
     visitor reaches for first. */
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--fg-muted);
  transition: background-color var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.promo__close:hover { background: var(--surface-tint); color: var(--fg-strong); }

.promo__body { padding: var(--space-8) var(--space-6) var(--space-6); }
.promo__title {
  font-family: var(--font-display);
  font-size: var(--fs-22);
  font-weight: 700;
  color: var(--fg-strong);
  margin-bottom: var(--space-3);
  padding-right: var(--space-8);
}
.promo__text { color: var(--fg-soft); margin-bottom: var(--space-6); }
.promo__actions {
  display: flex; flex-wrap: wrap; gap: var(--space-3);
}
.promo__actions .btn { flex: 1 1 auto; justify-content: center; }

@media (prefers-reduced-motion: reduce) {
  .promo[open] { animation: none; }
}

/* ---------------------------------------------------------------------
   ANNOUNCEMENT BAR
   Above the header and in normal flow, so it scrolls away while the header
   stays sticky. Absent from the markup entirely when unset.
   --------------------------------------------------------------------- */
.announce {
  /* Both fall back to the brand palette, so a store that never touches the
     colour settings looks exactly as it did. */
  background: var(--announce-bg, var(--brand-strong));
  color: var(--announce-fg, var(--on-accent));
}
.announce__inner {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  max-width: var(--container);
  margin-inline: auto;
  padding: 9px var(--space-5);
  min-height: 40px;
  font-family: var(--font-display);
  font-size: var(--fs-14);
  font-weight: 600;
  letter-spacing: .01em;
  text-align: center;
  color: inherit;
}
a.announce__inner { text-decoration: none; }
a.announce__inner:hover { background: rgb(255 255 255 / .10); }
.announce__arrow { flex: 0 0 auto; transition: transform var(--t-base) var(--ease); }
a.announce__inner:hover .announce__arrow { transform: translateX(3px); }

/* --- Marquee mode -----------------------------------------------------
   The rail holds the message list twice and slides left by exactly half its
   own width. At that point copy two sits precisely where copy one started,
   so the reset is invisible and the loop looks endless.

   Only `transform` is animated. Anything that moves this much by animating
   `left` or `margin` re-runs layout on every frame for the whole page. */
.announce--marquee { position: relative; display: flex; align-items: center; }

.announce__viewport {
  flex: 1 1 auto;
  min-width: 0;              /* lets the flex item shrink instead of pushing */
  overflow: hidden;
  /* Fades the text into the bar's colour at both ends, so messages arrive
     and leave rather than being chopped off by a hard edge. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}

.announce__rail {
  display: flex;
  width: max-content;
  animation: announce-scroll var(--marquee-duration, 30s) linear infinite;
}
@keyframes announce-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Pause on hover or keyboard focus, and whenever the script says so. Three
   routes to the same stop, because a mouse user, a keyboard user and the
   button all need it. */
.announce--marquee:hover .announce__rail,
.announce--marquee:focus-within .announce__rail,
.announce--marquee.is-paused .announce__rail { animation-play-state: paused; }

.announce__track {
  display: flex; align-items: center;
  margin: 0; padding: 0; list-style: none;
}
.announce__item { display: flex; align-items: center; }
.announce__msg {
  display: block;
  padding-block: 11px;
  font-family: var(--font-display);
  font-size: var(--fs-14);
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;        /* a ticker line must never wrap mid-scroll */
  color: inherit;
}
a.announce__msg { text-decoration: none; }
a.announce__msg:hover { text-decoration: underline; text-underline-offset: 3px; }

/* A diamond between messages. A border-drawn shape rather than a character,
   so it cannot be picked up as text or read out. */
.announce__sep {
  width: 5px; height: 5px;
  margin-inline: var(--space-5);
  rotate: 45deg;
  background: currentColor;
  /* Decorative, so WCAG 1.4.11's 3:1 does not strictly apply — but at .5 it
     measured 2.77 on the light bar, faint enough to look like a rendering
     artefact rather than a deliberate mark. */
  opacity: .62;
  flex: 0 0 auto;
}

.announce__pause {
  flex: 0 0 auto;
  /* A full 44x44 target. The ink is only the small glyph — a big pale
     square sitting on the brand bar would read as a second, competing
     button — but the area that responds to a finger is the whole square. */
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 0; background: transparent;
  color: inherit;
  opacity: .72;
  transition: opacity var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}
.announce__pause:hover { opacity: 1; background: rgb(255 255 255 / .12); }
.announce__pause .announce__icon--play { display: none; }
.announce--marquee.is-paused .announce__pause .announce__icon--pause { display: none; }
.announce--marquee.is-paused .announce__pause .announce__icon--play { display: block; }

@media (max-width: 560px) {
  .announce__sep { margin-inline: var(--space-4); }
  .announce__msg { font-size: var(--fs-12); }
}

/*
 * No movement at all. The rail lays out as an ordinary wrapped list, the
 * duplicate copy is removed so nothing reads twice, and the pause button has
 * nothing left to pause.
 */
@media (prefers-reduced-motion: reduce) {
  .announce__rail { animation: none; width: auto; flex-wrap: wrap; justify-content: center; }
  .announce__viewport { -webkit-mask-image: none; mask-image: none; }
  .announce__track[aria-hidden="true"] { display: none; }
  .announce__track { flex-wrap: wrap; justify-content: center; }
  .announce__msg { white-space: normal; }
  .announce__pause { display: none; }
}

/* ---------------------------------------------------------------------
   6. HEADER + NAVIGATION
   --------------------------------------------------------------------- */
.header {
  position: sticky; top: 0;
  z-index: var(--z-header);
  height: var(--header-h);
  display: flex; align-items: center;
  background: rgb(var(--header-rgb) / .68);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom: 1px solid transparent;
  transition: background-color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}
.header.is-scrolled {
  background: rgb(var(--header-rgb) / .92);
  border-bottom-color: var(--line-soft);
}

.header__inner {
  display: flex; align-items: center; gap: var(--space-6);
  width: 100%; max-width: var(--container);
  margin-inline: auto; padding-inline: var(--space-5);
}

.brand {
  display: flex; align-items: center; gap: var(--space-3);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-18);
  letter-spacing: -.01em;
  color: var(--text-hi);
  /* Shrinkable, so a long store name never pushes the cart and menu
     buttons off the edge on a narrow phone. */
  flex: 0 1 auto;
  min-width: 0;
}
.brand > span:not(.brand__mark) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 48px in a 72px header leaves 12px of breathing room top and bottom.
   The previous 36px used only half the height available to it. */
.brand__logo { height: 48px; width: auto; object-fit: contain; }
.brand__mark {
  width: 44px; height: 44px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--forest-500), var(--forest-700));
  border: 1px solid var(--line-strong);
  color: var(--lime-400);
}
.brand__mark svg { width: 24px; height: 24px; }

.nav { display: flex; align-items: center; gap: var(--space-1); margin-inline: auto; }

.nav__link {
  position: relative;
  padding: var(--space-2) var(--space-4);
  min-height: 44px;
  display: inline-flex; align-items: center;
  font-size: var(--fs-14);
  font-weight: 600;
  color: var(--text-mid);
  border-radius: var(--r-pill);
  transition: color var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}
.nav__link:hover { color: var(--text-hi); background: rgb(var(--accent-rgb) / .07); }

/* Current page is marked by weight + colour + an underline, never colour alone. */
.nav__link[aria-current="page"] { color: var(--lime-400); }
.nav__link[aria-current="page"]::after {
  content: ""; position: absolute; left: var(--space-4); right: var(--space-4); bottom: 6px;
  height: 2px; border-radius: 2px; background: var(--lime-400);
}

.header__actions { display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }

.icon-btn {
  position: relative;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-mid);
  transition: color var(--t-base) var(--ease),
              background-color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}
.icon-btn:hover {
  color: var(--text-hi);
  background: rgb(var(--accent-rgb) / .08);
  border-color: var(--line);
}
.icon-btn svg { width: 21px; height: 21px; }

.cart-badge {
  position: absolute; top: 4px; right: 3px;
  min-width: 19px; height: 19px; padding-inline: 5px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: var(--lime-400);
  color: var(--on-accent);
  font-size: 10px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  border: 2px solid var(--ink-900);
  transition: transform var(--t-base) var(--ease);
}
.cart-badge[hidden] { display: none; }
.cart-badge.is-bumped { animation: badge-bump .45s var(--ease); }

@keyframes badge-bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

.nav-toggle { display: none; }

/* -- Mobile drawer ---------------------------------------------------- */
.drawer {
  position: fixed; inset: 0;
  z-index: var(--z-drawer);
  visibility: hidden;
  pointer-events: none;
}
.drawer.is-open { visibility: visible; pointer-events: auto; }

.drawer__scrim {
  position: absolute; inset: 0;
  /* 55% — enough to isolate the panel without hiding the page. */
  background: var(--scrim);
  backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
}
.drawer.is-open .drawer__scrim { opacity: 1; }

.drawer__panel {
  position: absolute; inset-block: 0; right: 0;
  width: min(360px, 88vw);
  display: flex; flex-direction: column;
  background: var(--ink-850);
  border-left: 1px solid var(--line-soft);
  box-shadow: var(--sh-4);
  transform: translateX(100%);
  transition: transform var(--t-slow) var(--ease);
  padding: var(--space-5);
  padding-top: max(var(--space-5), env(safe-area-inset-top));
  padding-bottom: max(var(--space-5), env(safe-area-inset-bottom));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.drawer.is-open .drawer__panel { transform: translateX(0); }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--space-6);
}

.drawer__nav { display: flex; flex-direction: column; gap: var(--space-1); }
.drawer__link {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--r-md);
  font-family: var(--font-display);
  font-size: var(--fs-18);
  font-weight: 500;
  color: var(--text);
  transition: background-color var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.drawer__link:hover, .drawer__link:focus-visible { background: rgb(var(--accent-rgb) / .08); }
.drawer__link[aria-current="page"] {
  color: var(--lime-400);
  background: rgb(var(--accent-rgb) / .1);
}
.drawer__link svg { width: 20px; height: 20px; color: var(--text-muted); }
.drawer__link[aria-current="page"] svg { color: var(--lime-400); }

.drawer__footer {
  margin-top: auto; padding-top: var(--space-6);
  border-top: 1px solid var(--line-soft);
  display: flex; flex-direction: column; gap: var(--space-3);
}

/* ---------------------------------------------------------------------
   7. HERO
   --------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: min(92dvh, 860px);
  display: flex; align-items: center;
  overflow: hidden;
  /* Reserve the space before anything paints — CLS stays at 0. */
  contain: layout paint;
  background:
    radial-gradient(120% 80% at 78% 18%, var(--hero-glow-1), transparent 62%),
    radial-gradient(90% 70% at 12% 88%, var(--hero-glow-2), transparent 58%),
    linear-gradient(180deg, var(--hero-top) 0%, var(--hero-mid) 55%, var(--hero-bottom) 100%);
}

/* Atmosphere canvas: particles, mist, drifting leaves. Purely decorative,
   so it is aria-hidden and removed entirely on reduced-motion. */
.hero__atmosphere {
  position: absolute; inset: 0;
  z-index: var(--z-base);
  pointer-events: none;
  opacity: .85;
}

/* A slow light sweep across the scene. */
.hero__sweep {
  position: absolute; inset: -20% -40%;
  z-index: var(--z-base);
  pointer-events: none;
  background: linear-gradient(102deg,
    transparent 38%,
    rgb(var(--accent-soft-rgb) / .07) 47%,
    rgb(var(--accent-soft-rgb) / .12) 50%,
    rgb(var(--accent-soft-rgb) / .07) 53%,
    transparent 62%);
  animation: sweep 11s var(--ease) infinite;
}
@keyframes sweep {
  0%, 100% { transform: translateX(-22%) rotate(2deg); opacity: 0; }
  35%, 65% { opacity: 1; }
  50% { transform: translateX(22%) rotate(2deg); }
}

.hero__grid {
  position: relative;
  z-index: var(--z-raised);
  width: 100%; max-width: var(--container);
  margin-inline: auto;
  padding: var(--space-16) var(--space-5);
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: var(--space-12);
  align-items: center;
}

.hero__title {
  font-size: clamp(2.5rem, 7vw, var(--fs-64));
  line-height: 1.02;
  letter-spacing: -.03em;
  font-weight: 700;
  margin-bottom: var(--space-5);
  text-wrap: balance;
}
.hero__title em {
  font-style: normal;
  background: linear-gradient(120deg, var(--lime-300), var(--lime-400) 45%, var(--forest-400));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero__copy {
  font-size: clamp(var(--fs-16), 2vw, var(--fs-18));
  color: var(--text-mid);
  max-width: 52ch;
  margin-bottom: var(--space-8);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-8); }

.hero__trust {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-2) var(--space-5);
  font-size: var(--fs-14);
  color: var(--text-muted);
}
.hero__trust li { display: flex; align-items: center; gap: var(--space-2); list-style: none; }
.hero__trust svg { width: 16px; height: 16px; color: var(--lime-400); flex: 0 0 auto; }

/* -- Product stage ----------------------------------------------------- */
.hero__stage {
  position: relative;
  display: grid; place-items: center;
  /* Fixed aspect so the image landing causes no shift. */
  aspect-ratio: 4 / 5;
  perspective: 1200px;
}

.hero__halo {
  position: absolute; inset: 8%;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--accent-rgb) / .2) 0%, rgb(var(--brand-deep-rgb) / .1) 42%, transparent 68%);
  filter: blur(30px);
  animation: halo-pulse 7s var(--ease) infinite;
}
@keyframes halo-pulse {
  0%, 100% { transform: scale(1); opacity: .75; }
  50% { transform: scale(1.09); opacity: 1; }
}

/* Concentric "shield" rings — the protection metaphor. */
.hero__rings { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
.hero__ring {
  position: absolute;
  border: 1px solid rgb(var(--accent-rgb) / .16);
  border-radius: 50%;
  animation: ring-drift 18s linear infinite;
}
.hero__ring:nth-child(1) { width: 58%; aspect-ratio: 1; }
.hero__ring:nth-child(2) { width: 76%; aspect-ratio: 1; animation-duration: 26s; animation-direction: reverse; border-style: dashed; opacity: .6; }
.hero__ring:nth-child(3) { width: 94%; aspect-ratio: 1; animation-duration: 34s; opacity: .35; }
@keyframes ring-drift { to { transform: rotate(360deg); } }

.hero__product {
  position: relative;
  z-index: var(--z-raised);
  width: min(78%, 380px);
  filter: drop-shadow(0 40px 60px rgb(var(--shadow-rgb) / .6));
  transform-style: preserve-3d;
  will-change: transform;
}
.hero__product img { width: 100%; height: auto; }

/* Soft reflection beneath the bottle. */
.hero__reflection {
  position: absolute;
  bottom: 4%; left: 50%;
  width: 46%; height: 40px;
  transform: translateX(-50%);
  /* Light: a soft contact shadow, so the bottle sits on something.
     Dark: a brand glow, because a shadow would be invisible. */
  background: radial-gradient(ellipse, var(--hero-reflection), transparent 70%);
  filter: blur(14px);
}

/* -- Scene variant ------------------------------------------------------
   Uses the brand banner artwork instead of the abstract product stage.
   The headline stays as live text, so it remains editable, searchable and
   readable by a screen reader — only the artwork comes from the image. */
.hero--scene .hero__grid {
  /* Inside the container the artwork could only ever be shorter than the
     headline block beside it, which read as timid. Running it out to the
     viewport edge instead lets it stand the same height as the text without
     squeezing the headline into a narrow column. */
  max-width: none;
  padding-right: 0;
  padding-left: max(var(--space-5), calc((100vw - var(--container)) / 2 + var(--space-5)));
  grid-template-columns: minmax(0, 480px) 1fr;
  gap: var(--space-8);
  align-items: center;
}
.hero--scene .hero__stage {
  aspect-ratio: 1400 / 809;
  perspective: none;
  max-width: none;
}
/* Only the leading corners are rounded — the trailing edge is flush with
   the viewport, so a radius there would look like a mistake. */
.hero--scene .hero__scene {
  border-radius: var(--r-xl) 0 0 var(--r-xl);
  border-right: 0;
}
/* The artwork carries its own dome, glow and particles, so the synthetic
   ones would fight it. */
.hero--scene .hero__halo,
.hero--scene .hero__rings,
.hero--scene .hero__reflection,
.hero--scene .hero__atmosphere,
.hero--scene .hero__sweep { display: none; }

.hero__scene {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  border-radius: var(--r-xl);
  border: 1px solid var(--hairline);
  box-shadow: var(--sh-3);
}

/* ---------------------------------------------------------------------
   PAGE BACKDROP
   Sits behind the page on shop and product. Fixed rather than scrolled,
   so it never repaints on scroll, and pinned behind everything with a
   negative z-index. The photograph is shown as supplied — no wash, no
   crop — so legibility over its darker areas depends on the picture.
   --------------------------------------------------------------------- */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--surface-base);
  background-image: url("/assets/uploads/brand/xstings-backdrop.jpg");
  background-image:
    image-set(url("/assets/uploads/brand/xstings-backdrop.webp") type("image/webp"),
              url("/assets/uploads/brand/xstings-backdrop.jpg")  type("image/jpeg"));
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Body is normally opaque; with a backdrop it has to let it through. */
body:has(.backdrop) { background: transparent; }
/* The darkest tone available for the eyebrow — it is the smallest text on
   these pages and the one most exposed over the photograph. */
body:has(.backdrop) .eyebrow { color: var(--brand-strong); }

/* ---------------------------------------------------------------------
   USAGE, PESTS AND THE FULL-WIDTH BAND
   --------------------------------------------------------------------- */

/* Two cards read better as a centred pair than stretched across four
   columns' worth of grid. */
.feature-grid--pair {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  max-width: 44rem;
  margin-inline: auto;
}

/* The guide is a reference sheet, not decoration — it is capped at a
   readable width and opens full size, rather than being stretched across
   the page where the small type would be illegible anyway. */
.usage-guide {
  margin: var(--space-16) auto 0;
  max-width: 62rem;
}
.usage-guide img {
  width: 100%; height: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  box-shadow: var(--sh-2);
  transition: box-shadow var(--t-base) var(--ease);
}
.usage-guide a:hover img { box-shadow: var(--sh-3); }
.usage-guide figcaption {
  margin-top: var(--space-3);
  text-align: center;
  font-size: var(--fs-14);
  color: var(--fg-muted);
}

/* Full-bleed artwork band, as a slider.
   The slides are letterboxed rather than cropped: the two supplied pieces
   are 2.00:1 and 1.50:1 and each carries a headline down its left side, so
   a shared crop would cut into one of them. */
.band {
  position: relative;
  background: var(--surface-sunken);
  border-block: 1px solid var(--hairline);
}
.band__viewport { overflow: hidden; }
.band__track {
  display: flex;
  /* Without this the items stretch to the tallest line, and that line is
     sized by the tallest artwork — which quietly overrides the aspect-ratio
     below and reshapes the frame to whichever image happens to be tallest. */
  align-items: flex-start;
  margin: 0; padding: 0; list-style: none;
  /* --i is written by the script; without it the first slide simply shows. */
  transform: translateX(calc(var(--i, 0) * -100%));
  transition: transform .5s cubic-bezier(.22, .68, .24, 1);
}
.band__slide {
  flex: 0 0 100%;
  min-width: 0;
  position: relative;
  /*
   * --band-ratio is the widest slide's own shape, computed in the partial.
   * A max-height here would be a mistake: with aspect-ratio it reshapes the
   * frame rather than shortening it, and every slide would float in bars.
   */
  aspect-ratio: var(--band-ratio, 2);
}
.band__slide picture { display: contents; }
/*
 * Out of flow on purpose. Left in flow, the image's own height defines the
 * slide and silently beats the aspect-ratio above — the frame then takes
 * whichever shape the tallest artwork happens to be, and the shorter slide
 * sits in a band of dead space.
 */
.band__img {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
  object-fit: contain;
}

/* A strip under the artwork, not an overlay on it. */
.band__controls {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--hairline);
}
.band__nav {
  display: grid; place-items: center;
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: 50%;
  /* The hairline tokens read at 1.14:1 here — the strip and the button
     paint the same colour, so a soft edge leaves the control invisible.
     WCAG 1.4.11 wants 3:1 for a control boundary; this measures 4.97. */
  border: 1px solid var(--fg-muted);
  background: var(--surface-raised);
  color: var(--fg-strong);
  transition: background-color var(--t-base) var(--ease), scale var(--t-base) var(--ease);
}
.band__nav:hover { background: var(--surface-base); scale: 1.06; }

.band__dots {
  display: flex; gap: var(--space-2);
  margin: 0; padding: 0; list-style: none;
}
/* The dot is small; its tap target is not. */
.band__dots li { display: grid; place-items: center; min-width: 44px; min-height: 44px; }
.band__dot {
  width: 10px; height: 10px; border-radius: 50%;
  padding: 0; border: 1px solid var(--fg-muted);
  background: var(--surface-raised);
  transition: background-color var(--t-base) var(--ease), scale var(--t-base) var(--ease);
}
.band__dot.is-on { background: var(--brand); border-color: var(--brand); scale: 1.3; }

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

/* ---------------------------------------------------------------------
   SCROLL GALLERY
   Photographs cross-fade inside one pinned frame as the page scrolls.

   The base rules below are the FALLBACK: a plain responsive grid. The
   pinned behaviour is added only inside the media query, so no-JS,
   reduced-motion and small screens all land on the grid without anything
   needing to be switched off.
   --------------------------------------------------------------------- */
.sgal {
  padding-block: var(--space-12);
}
.sgal__frame {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-4);
  padding-inline: var(--space-4);
  max-width: var(--container);
  margin-inline: auto;
}
.sgal__item { margin: 0; }
/* <picture> is not a layout box by default, so an <img> set to height:100%
   resolves against a wrapper that is only as tall as its own content — the
   image ends up short of the frame rather than filling it. Applies anywhere
   a <picture> wraps an image that is meant to fill its container. */
.sgal__item picture,
.hero__stage picture,
.card__media picture {
  display: block;
  width: 100%; height: 100%;
}
.sgal__img {
  width: 100%; height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center;
}
/* Cropping from the right only, so a headline down the left edge survives
   at every window shape. */
.sgal--cover-left .sgal__img { object-position: left center;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: var(--surface-sunken);
}
.sgal__dots { display: none; }

@media (min-width: 900px) and (min-height: 600px) and (prefers-reduced-motion: no-preference) {
  .sgal.is-live {
    --gp: 0;                       /* 0 .. n, the cross-fade playhead */
    /* Shorter than a full viewport: a photograph does not need the whole
       screen to land, and every extra centimetre here is one more between
       a visitor and the products. */
    --sgal-h: min(74vh, 620px);
    height: var(--track);
    padding-block: 0;
  }
  .sgal.is-live .sgal__pin {
    position: sticky;
    top: calc(var(--header-h) + var(--space-4));
    height: var(--sgal-h);
    display: grid;
    place-items: center;
  }
  /* The frame carries the artwork's own proportions, so the picture fits
     inside it whole instead of being cropped to a shape it was never
     composed for. Width follows from the height and that ratio. */
  .sgal.is-live .sgal__frame {
    display: block;
    position: relative;
    width: min(100% - 2 * var(--space-5), calc(var(--sgal-h) * 16 / 9));
    aspect-ratio: 16 / 9;
    max-width: none;
    padding: 0;
    margin-inline: auto;
    border-radius: var(--r-xl);
    overflow: hidden;
    background: var(--surface-sunken);
    box-shadow: var(--sh-3);
  }
  .sgal.is-live .sgal__item {
    position: absolute; inset: 0;
    /* Distance from this photograph's turn. max() stands in for abs(),
       which is too new to rely on. */
    --d: calc(var(--gp) - var(--i));
    opacity: clamp(0, calc(1 - max(var(--d), -1 * var(--d))), 1);
    /* The outgoing photograph settles back slightly as it leaves, which is
       what stops a straight cross-fade reading as a slideshow. */
    scale: calc(1 + max(var(--d), -1 * var(--d)) * .06);
  }
  .sgal.is-live .sgal__img {
    aspect-ratio: auto;
    border-radius: 0;
    border: 0;
  }
  /* Artwork with words in it cannot be cropped — a full-bleed frame trims
     whatever sits near the edges, which is exactly where a headline goes.
     "contain" shows the whole image and fills the remainder with a tinted
     ground instead. */
  /* Default. The frame already matches the common ratio, so most images
     fill it exactly and the odd one out simply letterboxes rather than
     losing an edge. */
  .sgal--contain.is-live .sgal__img { object-fit: contain; }

  .sgal.is-live .sgal__dots {
    display: flex; gap: var(--space-2);
    position: absolute; left: 50%; bottom: var(--space-5);
    translate: -50% 0;
    z-index: 2; margin: 0; padding: 0; list-style: none;
  }
  .sgal.is-live .sgal__dot {
    width: 9px; height: 9px; border-radius: 50%; padding: 0; border: 0;
    background: rgb(255 255 255 / .5);
    box-shadow: 0 1px 3px rgb(0 0 0 / .35);
    transition: background var(--t-base) var(--ease), scale var(--t-base) var(--ease);
  }
  .sgal.is-live .sgal__dot.is-on { background: #fff; scale: 1.35; }
}

/* -- Photo variant ------------------------------------------------------
   Full-bleed artwork whose left third is deliberate empty space. The
   headline sits in that space as live text, so it stays editable, indexable
   and translatable — only the photograph comes from the file.

   Measured on the supplied artwork: columns 10–40% carry almost no detail
   (luminance ~246, variation under 4), and detail climbs sharply from 41%
   where the dome begins. The text column is capped at 40% for that reason. */
.hero--photo {
  display: block;
  min-height: 0;
  overflow: hidden;
  position: relative;
}
.hero--photo .hero__atmosphere,
.hero--photo .hero__sweep { display: none; }

.hero__media {
  position: relative;
  /* Matching the artwork means nothing is cropped at all on a normal
     desktop; the cap only bites on very wide windows. */
  aspect-ratio: 1774 / 887;
  max-height: 86vh;
  background: var(--surface-sunken);
}
.hero__photo {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
/* The copy space is light but not uniform — soft leaves drift through it at
   around 214 luminance, which drops the smaller text under 4.5:1. A gradient
   weighted to the left (where those leaves are) lifts the floor without
   flattening the artwork, and fades out before the dome. */
.hero--photo .hero__media::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgb(var(--hero-scrim-rgb) / .60) 0%,
    rgb(var(--hero-scrim-rgb) / .52) 22%,
    rgb(var(--hero-scrim-rgb) / .24) 36%,
    transparent 50%);
  pointer-events: none;
}

.hero--photo .hero__grid {
  position: absolute; inset: 0;
  padding: var(--space-8) var(--space-5);
  grid-template-columns: minmax(0, 40%) 1fr;
  align-content: center;
  z-index: var(--z-raised);
}
.hero--photo .hero__content { grid-column: 1; }
/* Over artwork the standard brand green lands at 4.48:1 against the darkest
   leaf behind it — a hair under AA for 12px text. The stronger tone clears
   it without changing the colour a reader perceives. */
.hero--photo .eyebrow { color: var(--brand-strong); }

@media (max-width: 1023px) {
  /* The empty third is useless on a phone — the headline cannot sit on top
     of it at this width — so the artwork switches to a crop of the scene
     and the copy moves underneath it. */
  .hero--photo .hero__media { aspect-ratio: 900 / 682; max-height: 54vh; }
  .hero--photo .hero__grid {
    position: static;
    grid-template-columns: 1fr;
    padding: var(--space-10) var(--space-5) var(--space-12);
    max-width: var(--container);
    margin-inline: auto;
  }
}

/* -- Card variant -------------------------------------------------------
   The hero sits in an inset rounded panel with the header floating over it
   and small cards tucked into the bottom corners. Built on the photo
   variant, so the artwork handling and its scrim are shared. */
.hero--card {
  /* Pull up under the sticky header so the artwork starts at the very top
     of the page and the header reads as floating on it. */
  margin-top: calc(var(--header-h) * -1);
  padding: 0 var(--space-5) var(--space-5);
  background: var(--surface-base);
}
.hero--card .hero__media {
  border-radius: var(--r-2xl);
  overflow: hidden;
  aspect-ratio: 1774 / 887;
  max-height: min(90vh, 820px);
  /* Without an explicit width, a capped height feeds back through the
     aspect ratio and narrows the box — on a short window that left a
     200px+ strip of empty page beside the artwork. Fixing the width makes
     the cap crop instead, which is what object-fit is there for. */
  width: 100%;
}
.hero--card .hero__grid {
  inset: var(--header-h) var(--space-5) var(--space-5);
  padding: var(--space-10) var(--space-8);
}
/* The framed panel has a header band above the copy and a card strip below
   it, so the headline gets a slightly tighter scale than the open layouts —
   otherwise three lines of it plus the buttons overrun both. */
.hero--card .hero__title { font-size: clamp(2.2rem, 3.5vw, 3.25rem); }
.hero--card .hero__copy { font-size: var(--fs-16); }
.hero--card .hero__actions { margin-top: var(--space-6); }

/* With the header transparent, the navigation sits directly on the
   photograph — and the top of this artwork contains near-black detail
   (plants, shelving, insects) that drops link contrast to about 2.2:1.
   A gradient along the top edge lifts that band without touching the rest
   of the image; it covers roughly the top eighth. */
.hero--card .hero__media::before {
  content: "";
  position: absolute; inset: 0 0 auto;
  height: calc(var(--header-h) + var(--space-10));
  background: linear-gradient(180deg,
    rgb(var(--header-rgb) / .92) 0%,
    rgb(var(--header-rgb) / .74) 55%,
    transparent 100%);
  z-index: 1;
  pointer-events: none;
}

/* The header has no surface of its own over the artwork until the page is
   scrolled, at which point its usual blurred bar returns. */
body:has(.hero--card) .header:not(.is-scrolled) {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Pill treatment for the eyebrow, matching the reference. */
.hero--card .eyebrow {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 7px var(--space-4);
  border-radius: var(--r-pill);
  background: rgb(var(--header-rgb) / .82);
  backdrop-filter: blur(10px);
  border: 1px solid var(--hairline);
  box-shadow: var(--sh-2);
  color: var(--brand-strong);
}
.hero--card .eyebrow::before { content: none; }

@media (max-width: 1023px) {
  /* Stacked, the artwork is only a few hundred pixels tall — cards floating
     on it would cover the subject entirely, so they drop into the flow. */
  .hero--card { margin-top: 0; padding-inline: 0; }
  .hero--card .hero__media {
    border-radius: var(--r-lg);
    margin-inline: var(--space-5);
    /* Without this the card's 2:1 frame wins over the photo variant's
       mobile crop and the artwork collapses to a 175px letterbox. */
    aspect-ratio: 900 / 682;
    max-height: 54vh;
  }
  /* No floating header on mobile, so no band to lift. */
  .hero--card .hero__media::before { display: none; }
  .hero--card .hero__grid { inset: auto; padding-inline: var(--space-5); }
  body:has(.hero--card) .header:not(.is-scrolled) {
    background: rgb(var(--header-rgb) / .68);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
  }
}

/* -- Gallery as a deck (narrow screens) ---------------------------------
   A pinned cross-fade needs a tall viewport and a pointer; a phone has
   neither, and the fallback grid was five photographs stacked in a column
   with nothing happening. Here the same markup becomes a card deck: one
   photograph at a time, the next few peeking above it, swipe or tap a dot
   to advance. Offsets follow the reference — 30px per frame, three frames
   visible, 8% of scale per step. */
@media (max-width: 899px) {
  .sgal.is-deck { --active: 0; padding-block: var(--space-10); }
  .sgal.is-deck .sgal__pin { position: static; height: auto; display: block; }

  .sgal.is-deck .sgal__frame {
    display: block;
    position: relative;
    width: auto;
    margin-inline: var(--space-5);
    aspect-ratio: 16 / 9;
    max-width: none;
    background: none;
    box-shadow: none;
    border-radius: 0;
    overflow: visible;
    /* Room above for the cards peeking out of the stack. */
    margin-top: calc(var(--space-10) + 30px);
    perspective: 1000px;
    perspective-origin: center 60%;
    touch-action: pan-y;
  }

  .sgal.is-deck .sgal__item {
    position: absolute; inset: 0;
    --d: calc(var(--i) - var(--active));
    /* Clamped at three frames, so a long gallery does not recede forever. */
    transform:
      translateY(max(calc(var(--d) * -30px), -90px))
      scale(calc(1 - var(--d) * .08));
    opacity: 1;
    border-radius: var(--r-lg);
    border: 1px solid var(--hairline);
    background: var(--surface-sunken);
    overflow: hidden;
    box-shadow: var(--sh-2);
    transition: transform .25s cubic-bezier(.645,.045,.355,1),
                opacity .2s var(--ease), filter .2s var(--ease);
    will-change: transform;
  }
  .sgal.is-deck .sgal__item[data-front] { box-shadow: var(--sh-3); }
  /* Once passed, a card is gone rather than lingering behind the stack. */
  .sgal.is-deck .sgal__item[data-passed] {
    opacity: 0;
    filter: blur(2px);
    pointer-events: none;
  }
  .sgal.is-deck .sgal__img {
    aspect-ratio: auto;
    width: 100%; height: 100%;
    object-fit: contain;
    border: 0; border-radius: 0;
  }

  .sgal.is-deck .sgal__dots {
    display: flex; gap: var(--space-3);
    justify-content: center;
    margin: var(--space-6) 0 0;
    padding: 0; list-style: none;
  }
  .sgal.is-deck .sgal__dot {
    width: 10px; height: 10px; border-radius: 50%;
    padding: 0; border: 1px solid var(--line-soft);
    background: var(--surface-tint);
    transition: background-color var(--t-base) var(--ease), scale var(--t-base) var(--ease);
  }
  .sgal.is-deck .sgal__dot.is-on { background: var(--brand); border-color: var(--brand); scale: 1.3; }
  /* The visual dot is small; the tap target is not. */
  .sgal.is-deck .sgal__dots li {
    display: grid; place-items: center;
    min-width: 44px; min-height: 44px;
  }

  @media (prefers-reduced-motion: reduce) {
    .sgal.is-deck .sgal__item { transition: none; }
  }
}

/* -- Cinema variant -----------------------------------------------------
   The artwork starts small and grows to fill the screen as you scroll,
   with the headline fading as it takes over.

   Everything below is gated behind .is-live, which only the script adds.
   Without JavaScript — or with reduced motion — the section keeps its
   natural height and simply renders as a centred hero with the artwork at
   full size and the copy fully legible. Nothing depends on the effect. */
.hero--cinema {
  display: block;
  min-height: 0;
  /* position:sticky cannot work inside a clipped or paint-contained box,
     and the base .hero sets both. */
  overflow: visible;
  contain: none;
}
.hero--cinema .hero__atmosphere,
.hero--cinema .hero__sweep,
.hero--cinema .hero__halo,
.hero--cinema .hero__rings,
.hero--cinema .hero__reflection { display: none; }

.hero--cinema .hero__grid {
  grid-template-columns: 1fr;
  justify-items: center;
  align-content: center;
  gap: var(--space-8);
  text-align: center;
}
.hero--cinema .hero__content { max-width: 46rem; }
.hero--cinema .hero__actions,
.hero--cinema .hero__trust { justify-content: center; }

.hero--cinema .hero__stage {
  width: min(100%, 76rem);
  aspect-ratio: 1400 / 809;
  max-width: none;
  perspective: none;
}

/* --- driven state ----------------------------------------------------
   Opt IN, rather than switching off later. The effect needs room for the
   headline AND for the artwork to grow into; a portrait phone has neither,
   and there the headline alone fills the pinned area and the artwork
   overlaps it throughout. Requiring both dimensions covers that without
   punishing a laptop running a narrow window. */
@media (min-width: 900px) and (min-height: 600px) and (prefers-reduced-motion: no-preference) {
  .hero--cinema.is-live {
    --hp: 0;                     /* 0 at rest, 1 when fully grown */
    height: 190vh;               /* the scroll track */
  }
  .hero--cinema.is-live .hero__grid {
    position: sticky;
    top: var(--header-h);
    height: calc(100dvh - var(--header-h));
    display: block;
    margin-block: 0;
  }
  /* Both children come out of flow. `scale` is a paint-time transform — it
     does NOT shrink the layout box — so leaving the artwork in flow made it
     reserve its full grown size and push the headline off the top of the
     pinned area. */
  .hero--cinema.is-live .hero__content {
    position: absolute;
    left: 50%; top: 9%;
    width: min(92vw, 46rem);
    translate: -50% 0;
    z-index: 2;
    opacity: clamp(0, calc(1 - var(--hp) * 1.9), 1);
  }
  .hero--cinema.is-live .hero__stage {
    position: absolute;
    left: 50%; top: 50%;
    width: min(94vw, 76rem);
    /* Beats the static-fallback cap below, which would otherwise stop the
       artwork growing past 48rem. */
    max-width: none;
    aspect-ratio: 1400 / 809;
    /* Sits low at rest so it clears the headline, and rises to dead centre
       as it grows — by which point the headline has faded out. */
    translate: -50% calc(-50% + (1 - var(--hp)) * 32%);
    scale: calc(.46 + var(--hp) * .54);
    will-change: transform;
  }
}

/* Anywhere the effect does not apply, the section is an ordinary centred
   hero — which is also exactly what a visitor with JavaScript off sees,
   since .is-live is never added for them. */
.hero--cinema .hero__stage { max-width: 48rem; }

.hero__scroll {
  position: absolute;
  bottom: var(--space-6); left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-raised);
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  font-size: var(--fs-12);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.hero__scroll span {
  width: 1px; height: 40px;
  background: linear-gradient(180deg, var(--lime-400), transparent);
  animation: scroll-hint 2.4s var(--ease) infinite;
  transform-origin: top;
}
@keyframes scroll-hint {
  0%, 100% { transform: scaleY(.35); opacity: .4; }
  50% { transform: scaleY(1); opacity: 1; }
}

/* ---------------------------------------------------------------------
   8. PRODUCT CARD
   --------------------------------------------------------------------- */
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-6);
}

.card {
  position: relative;
  display: flex; flex-direction: column;
  background: linear-gradient(165deg, var(--ink-800), var(--ink-850) 60%);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  /* A resting shadow is what makes a card read as a card on a white
     page. On dark the background gradient did that job by itself. */
  box-shadow: var(--sh-2);
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease);
}

/* Gradient edge-light that fades in on hover. */
.card::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(150deg, rgb(var(--accent-rgb) / .45), transparent 40%, transparent 60%, rgb(var(--brand-deep-rgb) / .35));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
  pointer-events: none;
  z-index: 2;
}

.card:hover, .card:focus-within {
  transform: translateY(-6px);
  border-color: var(--line-strong);
  box-shadow: var(--sh-3);
}
.card:hover::before, .card:focus-within::before { opacity: 1; }

.card__media {
  position: relative;
  /* Reserved box — the image cannot shift the grid when it loads.
     Square, because product photography is nearly always shot square and
     a 4:3 box left tall bottles floating in empty space. */
  aspect-ratio: 1 / 1;
  overflow: hidden;
  /* Default to a flat, near-neutral panel. An opaque photo carries its own
     background, and any tint here turns that background into a visible
     rectangle floating inside the card. */
  background: var(--surface-raised);
  border-bottom: 1px solid var(--hairline);
}

/* A cut-out PNG has no background of its own, so it can take the tinted
   panel without showing a seam. is_transparent is detected at upload. */
.card__media--cutout {
  background:
    radial-gradient(circle at 50% 40%, rgb(var(--brand-deep-rgb) / .12), transparent 68%),
    linear-gradient(180deg, var(--surface-tint), var(--surface-sunken));
}
/* Direct children only: the badge icons also live inside .card__media and
   must keep their own 13px sizing. */
.card__media > img,
.card__media > picture > img,
.card__media > svg {
  width: 100%; height: 100%;
  object-fit: contain;
  padding: var(--space-4);
  transition: transform var(--t-slow) var(--ease);
}
.card:hover .card__media img { transform: scale(1.06) translateY(-4px); }

.card__glow {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 55%, rgb(var(--accent-rgb) / .16), transparent 60%);
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease);
  pointer-events: none;
}
.card:hover .card__glow { opacity: 1; }

.card__badges {
  position: absolute; top: var(--space-3); left: var(--space-3); right: var(--space-3);
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  z-index: 3;
  pointer-events: none;
}
/* These float over whatever the photo happens to be, so they carry their
   own backing rather than trusting the image behind them. */
.card__badges .badge {
  padding: 4px var(--space-2);
  backdrop-filter: blur(8px);
  box-shadow: 0 1px 4px rgb(var(--shadow-rgb) / .12);
}

.card__body {
  display: flex; flex-direction: column; flex: 1;
  gap: var(--space-3);
  padding: var(--space-5);
}

.card__title {
  font-size: var(--fs-18);
  font-weight: 600;
  line-height: 1.3;
}
.card__title a { transition: color var(--t-base) var(--ease); }
.card__title a:hover { color: var(--lime-400); }
/* The whole card is clickable, but the accessible name comes from the link. */
.card__title a::after { content: ""; position: absolute; inset: 0; z-index: 1; }

.card__desc {
  font-size: var(--fs-14);
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* Reserve both lines so a one-line description does not knock the rest
     of the card out of step with its neighbours in the grid. */
  min-height: calc(2 * 1.6em);
}

/* The ordinary case is quiet: a pill here would compete with the price and
   the Add button. Low stock and out of stock keep the pill, because those
   are the ones worth interrupting for. */
.card__stock {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--fs-14);
  font-weight: 600;
  color: var(--success);
}
.card__stock i {
  width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}

.card__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: 1px solid var(--line-soft);
}

.price { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.price__now {
  font-family: var(--font-display);
  font-size: var(--fs-22);
  font-weight: 700;
  color: var(--text-hi);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.price__was {
  font-size: var(--fs-14);
  color: var(--text-muted);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Buttons inside a card must sit above the stretched link. */
.card__foot .btn, .card__actions { position: relative; z-index: 2; }

/* ---------------------------------------------------------------------
   9. BADGES / PILLS
   --------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 5px var(--space-3);
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: .04em;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge svg { width: 13px; height: 13px; }

.badge--sale    { background: rgb(var(--accent-rgb) / .15); color: var(--lime-300); border-color: rgb(var(--accent-rgb) / .35); }
.badge--stock   { background: var(--success-bg); color: var(--success); border-color: rgb(var(--success-rgb) / .3); }
.badge--low     { background: var(--warning-bg); color: var(--warning); border-color: rgb(var(--warning-rgb) / .3); }
.badge--out     { background: var(--danger-bg);  color: var(--danger);  border-color: rgb(var(--danger-rgb) / .3); }
.badge--neutral { background: rgb(var(--overlay-rgb) / .07); color: var(--text-mid); border-color: var(--line-soft); }
.badge--gold    { background: var(--gold-bg); color: var(--gold-400); border-color: var(--gold-line); }
/* The one an administrator writes themselves — Hot, Limited, New. Given
   the danger palette because that is what urgency reads as, and kept the
   loudest of the set so it wins attention against Sale and Featured. */
.badge--hot     { background: var(--danger-bg); color: var(--danger); border-color: rgb(var(--danger-rgb) / .35); }

/* ---------------------------------------------------------------------
   10. FEATURE / TRUST STRIP
   --------------------------------------------------------------------- */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-5);
}

.feature {
  position: relative;
  padding: var(--space-6);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  background: linear-gradient(165deg, var(--surface-tint), var(--surface-sunken));
  overflow: hidden;
  transition: border-color var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.feature:hover { border-color: var(--line-strong); transform: translateY(-3px); }

/* --- pointer tilt ------------------------------------------------------
   The reference tilts a photo card and lifts its text on top. These cards
   have no photograph, so the depth has to come from the layers themselves —
   the icon rises furthest, the body text least. Everything sits flat until
   the script marks the card live, so a visitor without JavaScript, on a
   touch screen, or with reduced motion sees the ordinary card. */
.feature-grid { perspective: 1100px; }

[data-tilt-card] {
  transform-style: preserve-3d;
  /* `overflow: hidden` silently forces transform-style back to flat, which
     kills every translateZ below. The card clips nothing (there is no
     ::before), and the sheen inherits the radius, so it can go. */
  overflow: visible;
  /* The script writes rotateX/rotateY here, so the lift on hover cannot
     also live in `transform` — it would be overwritten every frame. */
  transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease);
}
[data-tilt-card].is-tilting {
  box-shadow: var(--sh-3);
  border-color: var(--line-strong);
}
/* Cancel the flat hover lift while tilting; the two fight over transform. */
[data-tilt-card].is-tilting:hover { transform: none; }

[data-tilt-card] > * {
  transition: transform var(--t-base) var(--ease);
}
[data-tilt-card].is-tilting .feature__icon  { transform: translateZ(30px); }
[data-tilt-card].is-tilting .feature__title { transform: translateZ(18px); }
[data-tilt-card].is-tilting .feature__text  { transform: translateZ(9px); }

/* A specular sheen that follows the tilt, so the card reads as a surface
   catching light rather than a flat panel being rotated. */
[data-tilt-card]::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(140deg,
    rgb(255 255 255 / .55), transparent 42%);
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
  pointer-events: none;
}
[data-tilt-card].is-tilting::after { opacity: .7; }

@media (prefers-reduced-motion: reduce) {
  [data-tilt-card],
  [data-tilt-card] > * { transition: none; transform: none !important; }
  [data-tilt-card]::after { display: none; }
}

.feature__icon {
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: linear-gradient(135deg, rgb(var(--accent-rgb) / .16), rgb(var(--brand-deep-rgb) / .16));
  border: 1px solid var(--line);
  color: var(--lime-400);
  margin-bottom: var(--space-4);
}
.feature__icon svg { width: 22px; height: 22px; }

.feature__title { font-size: var(--fs-18); margin-bottom: var(--space-2); }
.feature__text { font-size: var(--fs-14); color: var(--text-muted); }

/* ---------------------------------------------------------------------
   11. PRODUCT DETAIL
   --------------------------------------------------------------------- */
.pdp {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: var(--space-16);
  align-items: start;
}

.gallery { position: sticky; top: calc(var(--header-h) + var(--space-5)); }

.gallery__main {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line-soft);
  /* Flat by default, for the same reason as the card: an opaque photo
     brings its own background and a tint turns it into a visible box. */
  background: var(--surface-raised);
}
.gallery__main--cutout {
  background:
    radial-gradient(circle at 50% 40%, rgb(var(--brand-deep-rgb) / .16), transparent 64%),
    linear-gradient(180deg, var(--surface-tint), var(--surface-sunken));
}
.gallery__main img {
  width: 100%; height: 100%;
  object-fit: contain;
  padding: var(--space-10);
}

/* Horizontal swipe strip on mobile, thumbnail row on desktop. */
.gallery__thumbs {
  display: flex; gap: var(--space-3);
  margin-top: var(--space-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  padding-bottom: var(--space-2);
}
.gallery__thumb {
  flex: 0 0 82px;
  width: 82px; height: 82px;
  padding: var(--space-2);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: var(--ink-800);
  scroll-snap-align: start;
  transition: border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease);
}
.gallery__thumb img { width: 100%; height: 100%; object-fit: contain; }
.gallery__thumb:hover { transform: translateY(-2px); }
.gallery__thumb[aria-selected="true"] {
  border-color: var(--lime-400);
  box-shadow: 0 0 0 1px var(--lime-400);
}

.pdp__title {
  font-size: clamp(var(--fs-28), 4vw, var(--fs-48));
  margin-bottom: var(--space-4);
}

.pdp__price {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}
/* At 36px a price plus a struck-through original plus a saving badge is
   wider than a phone. Let the row wrap, but never break a price in half —
   "RM" stranded above "29.90" was the result. */
.pdp__price .price__now { font-size: var(--fs-36); }

.pdp__meta { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-6); }

.pdp__short {
  font-size: var(--fs-18);
  color: var(--text-mid);
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-8);
  border-bottom: 1px solid var(--line-soft);
}

.buy-row { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); }

.qty {
  display: inline-flex; align-items: center;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: rgb(var(--accent-rgb) / .05);
  overflow: hidden;
  flex: 0 0 auto;
}
.qty__btn {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  background: transparent;
  border: 0;
  color: var(--text-mid);
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.qty__btn:hover:not([disabled]) { color: var(--lime-400); background: rgb(var(--accent-rgb) / .1); }
.qty__btn[disabled] { opacity: .35; cursor: not-allowed; }
.qty__btn svg { width: 16px; height: 16px; }
.qty__input {
  width: 54px; height: 48px;
  border: 0; background: transparent;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-hi);
  -moz-appearance: textfield;
}
.qty__input::-webkit-outer-spin-button,
.qty__input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* -- Accordion (description / directions / ingredients / safety) ------- */
.accordion { border-top: 1px solid var(--line-soft); margin-top: var(--space-8); }
.accordion__item { border-bottom: 1px solid var(--line-soft); }

.accordion__trigger {
  width: 100%;
  min-height: 60px;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-4) 0;
  background: transparent; border: 0;
  font-family: var(--font-display);
  font-size: var(--fs-16);
  font-weight: 600;
  color: var(--text-hi);
  text-align: left;
  transition: color var(--t-base) var(--ease);
}
.accordion__trigger:hover { color: var(--lime-400); }
.accordion__trigger svg {
  width: 18px; height: 18px; flex: 0 0 auto;
  color: var(--text-muted);
  transition: transform var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.accordion__trigger[aria-expanded="true"] svg { transform: rotate(45deg); color: var(--lime-400); }

.accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-slow) var(--ease);
}
.accordion__panel[data-open="true"] { grid-template-rows: 1fr; }
.accordion__panel > div { overflow: hidden; }
.accordion__panel .rich { padding-bottom: var(--space-5); color: var(--text-mid); font-size: var(--fs-15, .95rem); }

/* ---------------------------------------------------------------------
   12. RICH TEXT
   --------------------------------------------------------------------- */
.rich { color: var(--text); line-height: 1.75; }
.rich > * + * { margin-top: var(--space-4); }
.rich h2 { font-size: var(--fs-28); margin-top: var(--space-10); }
.rich h3 { font-size: var(--fs-22); margin-top: var(--space-8); }
.rich h4 { font-size: var(--fs-18); margin-top: var(--space-6); }
.rich p { max-width: 72ch; }
.rich ul, .rich ol { padding-left: var(--space-6); }
.rich li + li { margin-top: var(--space-2); }
.rich li::marker { color: var(--lime-400); }
.rich a { color: var(--lime-400); text-decoration: underline; text-underline-offset: 3px; }
.rich a:hover { color: var(--lime-300); }
.rich img { border-radius: var(--r-md); margin-inline: auto; }
.rich blockquote {
  margin-inline: 0;
  padding: var(--space-4) var(--space-6);
  border-left: 3px solid var(--lime-400);
  background: rgb(var(--accent-rgb) / .05);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  color: var(--text-mid);
  font-style: italic;
}
.rich code {
  background: var(--ink-800);
  padding: 2px 6px;
  border-radius: 4px;
  font-size: .9em;
}
.rich pre { background: var(--ink-850); padding: var(--space-4); border-radius: var(--r-md); overflow-x: auto; }
.rich hr { border: 0; border-top: 1px solid var(--line-soft); margin-block: var(--space-8); }

/* Wide tables scroll inside themselves — the page never scrolls sideways. */
.rich table { width: 100%; border-collapse: collapse; font-size: var(--fs-14); }
.rich th, .rich td { padding: var(--space-3); border-bottom: 1px solid var(--line-soft); text-align: left; }
.rich th { color: var(--text-hi); font-weight: 600; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------------
   13. FORMS
   --------------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); }

.label {
  font-size: var(--fs-14);
  font-weight: 600;
  color: var(--text);
  display: flex; align-items: center; gap: var(--space-2);
}
.label .req { color: var(--lime-400); }

.input, .textarea, .select {
  width: 100%;
  /* 16px minimum stops iOS zooming the page on focus. */
  font-size: var(--fs-16);
  /* 48px keeps the touch target comfortable. */
  min-height: 48px;
  padding: var(--space-3) var(--space-4);
  background: rgb(var(--field-rgb) / .8);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  color: var(--text-hi);
  transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--text-muted); opacity: .7; }

.input:hover, .textarea:hover, .select:hover { border-color: var(--line); }
.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--lime-400);
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / .16);
}

.textarea { min-height: 130px; resize: vertical; line-height: 1.6; }

.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23839489' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 18px;
  padding-right: var(--space-10);
}
.select option { background: var(--ink-850); color: var(--text); }

/* Persistent helper text, not a disappearing placeholder. */
.help { font-size: var(--fs-12); color: var(--text-muted); }

/* Errors sit next to their field and are announced. */
.field-error {
  display: flex; align-items: flex-start; gap: var(--space-2);
  font-size: var(--fs-12);
  color: var(--danger);
}
.field-error svg { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 3px; }
.input.has-error, .textarea.has-error, .select.has-error { border-color: var(--danger); }

.checkbox { display: flex; align-items: flex-start; gap: var(--space-3); cursor: pointer; min-height: 44px; }
.checkbox input {
  appearance: none;
  width: 22px; height: 22px; flex: 0 0 auto;
  margin-top: 2px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: rgb(var(--field-rgb) / .8);
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.checkbox input:checked {
  background: var(--lime-400) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23050807' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E") center / 15px no-repeat;
  border-color: var(--lime-400);
}
.checkbox span { font-size: var(--fs-14); color: var(--text-mid); }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-4); }
.form-grid .field--full { grid-column: 1 / -1; }

.fieldset { border: 0; padding: 0; margin: 0 0 var(--space-8); }
.fieldset__legend {
  font-family: var(--font-display);
  font-size: var(--fs-12);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--lime-400);
  margin-bottom: var(--space-5);
  padding: 0;
}

/* Password reveal toggle. */
.password-wrap { position: relative; }
.password-wrap .input { padding-right: 52px; }
.password-toggle {
  position: absolute; right: 6px; top: 50%;
  transform: translateY(-50%);
  width: 40px; height: 40px;
  display: grid; place-items: center;
  background: transparent; border: 0;
  color: var(--text-muted);
  border-radius: var(--r-sm);
}
.password-toggle:hover { color: var(--lime-400); }
.password-toggle svg { width: 18px; height: 18px; }

/* ---------------------------------------------------------------------
   14. FLASH / ALERTS
   --------------------------------------------------------------------- */
.flash-stack {
  position: fixed;
  top: calc(var(--header-h) + var(--space-3));
  right: var(--space-4);
  left: var(--space-4);
  z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--space-2);
  pointer-events: none;
  margin-inline: auto;
  max-width: 460px;
}

.flash {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: var(--glass-hi);
  backdrop-filter: blur(14px);
  box-shadow: var(--sh-3);
  font-size: var(--fs-14);
  pointer-events: auto;
  animation: flash-in var(--t-slow) var(--ease) both;
}
@keyframes flash-in {
  from { opacity: 0; transform: translateY(-12px) scale(.97); }
  to { opacity: 1; transform: none; }
}
.flash.is-leaving { animation: flash-out var(--t-base) var(--ease-in) forwards; }
@keyframes flash-out { to { opacity: 0; transform: translateY(-8px); } }

.flash svg { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 2px; }
.flash__close {
  margin-left: auto; background: transparent; border: 0;
  color: var(--text-muted); width: 28px; height: 28px;
  display: grid; place-items: center; border-radius: var(--r-sm);
}
.flash__close:hover { color: var(--text-hi); }

.flash--success { border-color: rgb(var(--success-rgb) / .35); }
.flash--success svg { color: var(--success); }
.flash--error   { border-color: rgb(var(--danger-rgb) / .35); }
.flash--error svg { color: var(--danger); }
.flash--warning { border-color: rgb(var(--warning-rgb) / .35); }
.flash--warning svg { color: var(--warning); }
.flash--info    { border-color: rgb(var(--info-rgb) / .35); }
.flash--info svg { color: var(--info); }

/* Inline (non-floating) alert. */
.alert {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  font-size: var(--fs-14);
  margin-bottom: var(--space-5);
}
.alert svg { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 2px; }
.alert--info    { background: var(--info-bg);    border-color: rgb(var(--info-rgb) / .3); }
.alert--info svg { color: var(--info); }
.alert--warning { background: var(--warning-bg); border-color: rgb(var(--warning-rgb) / .3); }
.alert--warning svg { color: var(--warning); }
.alert--danger  { background: var(--danger-bg);  border-color: rgb(var(--danger-rgb) / .3); }
.alert--danger svg { color: var(--danger); }
.alert--success { background: var(--success-bg); border-color: rgb(var(--success-rgb) / .3); }
.alert--success svg { color: var(--success); }

/* ---------------------------------------------------------------------
   15. CART / CHECKOUT
   --------------------------------------------------------------------- */
.cart-layout {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: var(--space-8);
  align-items: start;
}

.cart-list { display: flex; flex-direction: column; gap: var(--space-4); }

.cart-item {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  background: linear-gradient(165deg, var(--ink-800), var(--ink-850));
  align-items: center;
}

.cart-item__media {
  width: 96px; height: 96px;
  border-radius: var(--r-md);
  background: linear-gradient(160deg, var(--forest-900), var(--ink-850));
  border: 1px solid var(--line-soft);
  overflow: hidden;
  flex: 0 0 auto;
}
.cart-item__media img { width: 100%; height: 100%; object-fit: contain; padding: var(--space-2); }

.cart-item__name { font-family: var(--font-display); font-weight: 600; color: var(--text-hi); margin-bottom: var(--space-1); }
.cart-item__meta { font-size: var(--fs-12); color: var(--text-muted); }
.cart-item__controls { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-3); flex-wrap: wrap; }
.cart-item__total { font-family: var(--font-display); font-size: var(--fs-18); font-weight: 700; color: var(--text-hi); font-variant-numeric: tabular-nums; }

.link-danger {
  background: none; border: 0; padding: var(--space-2) 0;
  font-size: var(--fs-12); color: var(--text-muted);
  text-decoration: underline; text-underline-offset: 3px;
  min-height: 44px;
}
.link-danger:hover { color: var(--danger); }

.summary {
  position: sticky;
  top: calc(var(--header-h) + var(--space-5));
  padding: var(--space-6);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  background: linear-gradient(165deg, var(--ink-800), var(--ink-850));
}
.summary__title { font-size: var(--fs-18); margin-bottom: var(--space-5); }

.summary__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
  font-size: var(--fs-14);
  color: var(--text-mid);
}
.summary__row span:last-child { font-variant-numeric: tabular-nums; color: var(--text); }
.summary__row--discount span:last-child { color: var(--lime-400); }
.summary__row--total {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-display);
  font-size: var(--fs-22);
  font-weight: 700;
  color: var(--text-hi);
}
.summary__row--total span:last-child { color: var(--lime-400); font-size: var(--fs-28); }

.coupon-row { display: flex; gap: var(--space-2); margin-block: var(--space-5); }
.coupon-row .input { min-height: 46px; }

.coupon-applied {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--r-md);
  background: rgb(var(--accent-rgb) / .09);
  border: 1px solid rgb(var(--accent-rgb) / .3);
  margin-block: var(--space-5);
  font-size: var(--fs-14);
}

.trust-row {
  display: flex; flex-direction: column; gap: var(--space-2);
  margin-top: var(--space-5); padding-top: var(--space-5);
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-12); color: var(--text-muted);
}
.trust-row li { display: flex; align-items: center; gap: var(--space-2); list-style: none; }
.trust-row svg { width: 14px; height: 14px; color: var(--lime-400); flex: 0 0 auto; }

/* -- Multi-step indicator ---------------------------------------------- */
.steps { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-10); }
.step { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-12); color: var(--text-muted); }
.step__dot {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-soft);
  font-size: 11px; font-weight: 700;
}
.step.is-active { color: var(--lime-400); }
.step.is-active .step__dot { border-color: var(--lime-400); background: rgb(var(--accent-rgb) / .12); }
.step.is-done { color: var(--text-mid); }
.step.is-done .step__dot { background: var(--lime-400); border-color: var(--lime-400); color: var(--on-accent); }
.step__line { flex: 1; height: 1px; background: var(--line-soft); min-width: 16px; }

/* ---------------------------------------------------------------------
   16. ORDER TIMELINE
   --------------------------------------------------------------------- */
.timeline { display: flex; flex-direction: column; gap: 0; }

.tl-step { display: grid; grid-template-columns: 32px 1fr; gap: var(--space-4); }

.tl-step__rail { display: flex; flex-direction: column; align-items: center; }
.tl-step__dot {
  width: 24px; height: 24px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid var(--line-soft);
  background: var(--ink-850);
  color: transparent;
  transition: all var(--t-base) var(--ease);
}
.tl-step__dot svg { width: 12px; height: 12px; }
.tl-step__line { width: 2px; flex: 1; min-height: 28px; background: var(--line-soft); }

/* State is carried by icon + colour + label, never colour alone. */
.tl-step.is-done .tl-step__dot { border-color: var(--lime-400); background: var(--lime-400); color: var(--on-accent); }
.tl-step.is-done .tl-step__line { background: var(--lime-400); }
.tl-step.is-current .tl-step__dot {
  border-color: var(--lime-400);
  background: var(--ink-850);
  color: var(--lime-400);
  box-shadow: 0 0 0 4px rgb(var(--accent-rgb) / .16);
}
.tl-step.is-cancelled .tl-step__dot { border-color: var(--danger); background: var(--danger); color: var(--on-accent); }

.tl-step__body { padding-bottom: var(--space-6); }
.tl-step__label { font-family: var(--font-display); font-weight: 600; color: var(--text-mid); }
.tl-step.is-done .tl-step__label, .tl-step.is-current .tl-step__label { color: var(--text-hi); }
.tl-step__time { font-size: var(--fs-12); color: var(--text-muted); margin-top: 2px; }
.tl-step:last-child .tl-step__line { display: none; }

/* ---------------------------------------------------------------------
   17. BLOG
   --------------------------------------------------------------------- */
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-6);
}

.post-card {
  position: relative;
  display: flex; flex-direction: column;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: linear-gradient(165deg, var(--ink-800), var(--ink-850));
  transition: transform var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease);
}
.post-card:hover, .post-card:focus-within {
  transform: translateY(-5px);
  border-color: var(--line-strong);
  box-shadow: var(--sh-3);
}

.post-card__media {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: linear-gradient(150deg, var(--forest-800), var(--ink-850));
  position: relative;
}
.post-card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--t-slow) var(--ease); }
.post-card:hover .post-card__media img { transform: scale(1.05); }

.post-card__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); flex: 1; }
.post-card__title { font-size: var(--fs-18); line-height: 1.35; }
.post-card__title a::after { content: ""; position: absolute; inset: 0; }
.post-card__title a:hover { color: var(--lime-400); }
.post-card__excerpt {
  font-size: var(--fs-14); color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.post-card__meta {
  display: flex; align-items: center; gap: var(--space-3);
  margin-top: auto; padding-top: var(--space-3);
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-12); color: var(--text-muted);
}

.post-featured {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: linear-gradient(140deg, var(--forest-800), var(--ink-850));
  margin-bottom: var(--space-10);
  position: relative;
}
.post-featured__media { position: relative; min-height: 320px; background: var(--forest-900); }
.post-featured__media img { width: 100%; height: 100%; object-fit: cover; }
.post-featured__body { padding: var(--space-10); display: flex; flex-direction: column; justify-content: center; gap: var(--space-4); }
.post-featured__title { font-size: clamp(var(--fs-22), 3vw, var(--fs-36)); }
.post-featured__title a::after { content: ""; position: absolute; inset: 0; }

.article {
  max-width: 760px;
  margin-inline: auto;
}
.article__header { text-align: center; margin-bottom: var(--space-10); }
.article__title { font-size: clamp(var(--fs-28), 5vw, var(--fs-48)); margin-bottom: var(--space-5); text-wrap: balance; }
.article__meta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--space-2) var(--space-4);
  font-size: var(--fs-14); color: var(--text-muted);
}
.article__hero {
  aspect-ratio: 16 / 9;
  border-radius: var(--r-xl);
  overflow: hidden;
  margin-bottom: var(--space-10);
  border: 1px solid var(--line-soft);
}
.article__hero img { width: 100%; height: 100%; object-fit: cover; }

.tag-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tag {
  display: inline-flex; align-items: center;
  min-height: 36px;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line-soft);
  background: rgb(var(--overlay-rgb) / .04);
  font-size: var(--fs-12);
  color: var(--text-mid);
  transition: all var(--t-base) var(--ease);
}
.tag:hover { border-color: var(--lime-400); color: var(--lime-400); }

.share-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

/* Product CTA inside an article. */
.post-cta {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: var(--space-6);
  align-items: center;
  padding: var(--space-6);
  margin-block: var(--space-10);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background:
    radial-gradient(circle at 12% 50%, rgb(var(--accent-rgb) / .12), transparent 60%),
    linear-gradient(140deg, var(--forest-800), var(--ink-850));
}
.post-cta__media {
  aspect-ratio: 1;
  border-radius: var(--r-md);
  background: var(--forest-900);
  overflow: hidden;
  border: 1px solid var(--line-soft);
}
.post-cta__media img { width: 100%; height: 100%; object-fit: contain; padding: var(--space-3); }

.filter-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-8);
}

/* ---------------------------------------------------------------------
   18. PAGINATION / EMPTY STATE
   --------------------------------------------------------------------- */
.pagination {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-12);
  flex-wrap: wrap;
}
.pagination__link {
  min-width: 44px; min-height: 44px;
  display: grid; place-items: center;
  padding-inline: var(--space-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  font-size: var(--fs-14);
  color: var(--text-mid);
  transition: all var(--t-base) var(--ease);
}
.pagination__link:hover { border-color: var(--lime-400); color: var(--lime-400); }
.pagination__link[aria-current="page"] {
  background: var(--lime-400);
  border-color: var(--lime-400);
  color: var(--on-accent);
  font-weight: 700;
}
.pagination__link[aria-disabled="true"] { opacity: .35; pointer-events: none; }

.empty {
  text-align: center;
  padding: var(--space-16) var(--space-5);
  border: 1px dashed var(--line-soft);
  border-radius: var(--r-lg);
  background: rgb(var(--field-rgb) / .4);
}
.empty__icon {
  width: 64px; height: 64px;
  margin: 0 auto var(--space-5);
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgb(var(--accent-rgb) / .08);
  border: 1px solid var(--line);
  color: var(--lime-400);
}
.empty__icon svg { width: 28px; height: 28px; }
.empty__title { font-size: var(--fs-22); margin-bottom: var(--space-2); }
.empty__text { color: var(--text-muted); max-width: 44ch; margin: 0 auto var(--space-6); }

/* ---------------------------------------------------------------------
   18b. CLOSING CTA PANEL
   --------------------------------------------------------------------- */
.cta-panel {
  position: relative;
  overflow: hidden;
  padding: var(--space-16) var(--space-8);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-xl);
  text-align: center;
  background:
    radial-gradient(80% 120% at 50% 0%, var(--cta-glow), transparent 65%),
    linear-gradient(160deg, var(--surface-tint), var(--surface-raised));
  box-shadow: var(--sh-2);
}

/* ---------------------------------------------------------------------
   19. FOOTER
   --------------------------------------------------------------------- */
.footer {
  position: relative;
  margin-top: var(--space-24);
  padding-top: var(--space-20);
  background:
    radial-gradient(90% 120% at 50% 0%, var(--footer-glow), transparent 62%),
    linear-gradient(180deg, var(--footer-top), var(--footer-bottom));
  border-top: 1px solid var(--line-soft);
  overflow: hidden;
}

/* Hairline of brand light along the very top edge. */
.footer::before {
  content: "";
  position: absolute; top: -1px; left: 50%;
  transform: translateX(-50%);
  width: min(620px, 80%); height: 1px;
  background: linear-gradient(90deg, transparent, var(--lime-400), transparent);
  opacity: .55;
}

.footer__top {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.3fr;
  gap: var(--space-10);
  padding-bottom: var(--space-16);
}

.footer__brand { max-width: 34ch; }
.footer__brand .brand { margin-bottom: var(--space-4); }
.footer__tagline { font-size: var(--fs-14); color: var(--text-muted); margin-bottom: var(--space-5); }

.footer__contact { display: flex; flex-direction: column; gap: var(--space-2); font-size: var(--fs-14); }
.footer__contact a, .footer__contact span {
  display: flex; align-items: flex-start; gap: var(--space-3);
  color: var(--text-mid);
  min-height: 32px;
  transition: color var(--t-base) var(--ease);
}
.footer__contact a:hover { color: var(--lime-400); }
.footer__contact svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 4px; color: var(--lime-400); }

.footer__col-title {
  font-family: var(--font-display);
  font-size: var(--fs-12);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-hi);
  margin-bottom: var(--space-5);
}

.footer__links { display: flex; flex-direction: column; gap: var(--space-1); }
.footer__links a {
  display: inline-flex; align-items: center;
  min-height: 40px;
  font-size: var(--fs-14);
  color: var(--text-muted);
  transition: color var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.footer__links a:hover { color: var(--lime-400); transform: translateX(3px); }
.footer__links li { list-style: none; }

.footer__note {
  font-size: var(--fs-14);
  color: var(--text-muted);
  margin-bottom: var(--space-5);
}

.footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-6);
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-12);
  color: var(--text-muted);
}
.footer__legal { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.footer__legal a { transition: color var(--t-base) var(--ease); }
.footer__legal a:hover { color: var(--lime-400); }

.footer__pay { display: flex; align-items: center; gap: var(--space-2); }
.footer__pay-chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: rgb(var(--overlay-rgb) / .04);
  font-size: var(--fs-12);
  color: var(--text-mid);
}
.footer__pay-chip svg { width: 16px; height: 16px; color: var(--lime-400); }

/* ---------------------------------------------------------------------
   20. WHATSAPP FAB
   --------------------------------------------------------------------- */
.wa-fab {
  position: fixed;
  right: var(--space-4);
  bottom: max(var(--space-4), env(safe-area-inset-bottom));
  z-index: var(--z-sticky);
  display: inline-flex; align-items: center; gap: var(--space-3);
  height: 56px;
  padding: 0 var(--space-5) 0 var(--space-4);
  border-radius: var(--r-pill);
  background: linear-gradient(135deg, #25D366, #128C7E);
  color: #fff;
  font-family: var(--font-display);
  font-size: var(--fs-14);
  font-weight: 600;
  box-shadow: 0 8px 28px rgba(37, 211, 102, .32);
  transition: transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.wa-fab:hover { transform: translateY(-3px); box-shadow: 0 14px 38px rgba(37, 211, 102, .42); }
.wa-fab:active { transform: translateY(0) scale(.97); }
.wa-fab svg { width: 24px; height: 24px; flex: 0 0 auto; }

/* ---------------------------------------------------------------------
   21. BREADCRUMBS
   --------------------------------------------------------------------- */
.breadcrumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  font-size: var(--fs-12);
  color: var(--text-muted);
  padding-block: var(--space-5);
}
.breadcrumbs li { display: flex; align-items: center; gap: var(--space-2); list-style: none; }
.breadcrumbs a { transition: color var(--t-base) var(--ease); }
.breadcrumbs a:hover { color: var(--lime-400); }
.breadcrumbs svg { width: 12px; height: 12px; opacity: .5; }
.breadcrumbs [aria-current="page"] { color: var(--text-mid); }

/* ---------------------------------------------------------------------
   22. SCROLL REVEAL
   Elements start hidden ONLY when JS is present to reveal them, so a
   JS failure never leaves a blank page.
   --------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 600ms var(--ease), transform 600ms var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }

/* ---------------------------------------------------------------------
   GRID/FLEX MINIMUM SIZE
   ---------------------------------------------------------------------
   Grid and flex children default to min-width:auto, which means they
   refuse to shrink below their content. That stops an inner
   overflow-x:auto scroller (wide tables, code blocks) from ever
   engaging, and the whole page grows sideways instead. Setting
   min-width:0 on the children is what makes those scrollers work.
   --------------------------------------------------------------------- */
.hero__grid > *,
.cart-layout > *,
.pdp > *,
.product-grid > *,
.post-grid > *,
.feature-grid > *,
.post-featured > *,
.post-cta > *,
.cart-item > *,
.order-line > *,
.card__foot > *,
.summary__row > * { min-width: 0; }

/* Long unbroken strings (order numbers, e-mails, URLs) must wrap
   rather than force the page wider. */
.card__title, .cart-item__name, .order-line__name,
.breadcrumbs, .kv dd { overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------
   23. RESPONSIVE
   Dedicated layouts, not a shrunken desktop.
   --------------------------------------------------------------------- */

/* -- Large desktop ---------------------------------------------------- */
@media (min-width: 1600px) {
  :root { --container: 1360px; }
  .hero__grid { gap: var(--space-16); }
}

/* -- Tablet landscape / small laptop (<= 1024px) ---------------------- */
@media (max-width: 1024px) {
  :root { --header-h: 66px; }
  .brand__logo { height: 40px; }
  .brand__mark { width: 38px; height: 38px; }
  .brand__mark svg { width: 21px; height: 21px; }

  /* Stack: headline first, artwork below at full width. */
  /* Stacked, there is no "right edge" to run to — restore the container. */
  .hero--scene .hero__grid {
    grid-template-columns: 1fr;
    max-width: var(--container);
    padding-inline: var(--space-5);
  }
  .hero--scene .hero__stage { order: 0; max-width: 640px; }
  .hero--scene .hero__scene { border-radius: var(--r-lg); border-right: 1px solid var(--hairline); }
  .hero--scene .hero__scene { border-radius: var(--r-lg); }

  .hero { min-height: auto; }
  .hero__grid {
    grid-template-columns: 1fr;
    gap: var(--space-10);
    padding-block: var(--space-16) var(--space-12);
    text-align: center;
  }
  .hero__copy { margin-inline: auto; }
  .hero__actions, .hero__trust { justify-content: center; }
  .hero__stage { order: -1; aspect-ratio: 1; max-width: 420px; margin-inline: auto; width: 100%; }
  .hero__scroll { display: none; }

  .pdp { grid-template-columns: 1fr; gap: var(--space-10); }

  /* Stacked, a square gallery is a full screen of photograph before the
     name, price or Add button come into view. Cap it so the buy decision
     stays within reach. The height is a viewport unit, so the box is
     still known before the image loads and nothing shifts. */
  .gallery { position: static; }
  /* The box stays square, so capping the height narrows it too — centre it
     rather than leaving it stranded against the left edge. On a portrait
     phone the natural square is already shorter than the cap, so this only
     engages on short, wide viewports such as a landscape phone. */
  .gallery__main { max-height: 56vh; margin-inline: auto; }
  .gallery { position: static; }

  .cart-layout { grid-template-columns: 1fr; }
  .summary { position: static; }

  .footer__top { grid-template-columns: 1fr 1fr; gap: var(--space-8); }
  .footer__brand { grid-column: 1 / -1; max-width: none; }

  .post-featured { grid-template-columns: 1fr; }
  .post-featured__media { min-height: 240px; }
  .post-featured__body { padding: var(--space-6); }
}

/* -- Tablet portrait / mobile (<= 768px) ------------------------------ */
@media (max-width: 768px) {
  :root {
    --space-20: 56px;
    --space-24: 64px;
  }

  .section { padding-block: var(--space-16); }

  /* Desktop nav out, hamburger in. */
  .nav { display: none; }
  .nav-toggle { display: grid; }

  .header__inner { gap: var(--space-3); }
  .brand { margin-right: auto; }

  .section-head { margin-bottom: var(--space-8); }

  .product-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-4); }
  .post-grid { grid-template-columns: 1fr; }

  .form-grid { grid-template-columns: 1fr; }

  .article__hero { aspect-ratio: 3 / 2; border-radius: var(--r-md); }

  .post-cta { grid-template-columns: 1fr; text-align: center; }
  .post-cta__media { max-width: 140px; margin-inline: auto; }

  .footer { margin-top: var(--space-16); padding-top: var(--space-12); }
  .footer__top { grid-template-columns: 1fr; gap: var(--space-8); padding-bottom: var(--space-10); }
  .footer__bottom { flex-direction: column; align-items: flex-start; gap: var(--space-3); }

  /* Label collapses to the icon so the FAB never covers content. */
  .wa-fab { width: 56px; padding: 0; justify-content: center; }
  .wa-fab span { display: none; }

  .flash-stack { top: auto; bottom: calc(72px + env(safe-area-inset-bottom)); }
}

/* -- Phone (<= 480px) -------------------------------------------------- */
@media (max-width: 480px) {
  .container { padding-inline: var(--space-4); }

  /* Match the container gutter so the header cannot be wider than the
     page it sits on. */
  .header__inner { padding-inline: var(--space-4); gap: var(--space-2); }

  /* Get the product range above the fold sooner. */
  .hero__grid { padding-block: var(--space-10) var(--space-8); gap: var(--space-6); }
  .hero__stage { max-width: 290px; }
  .hero__copy { margin-bottom: var(--space-6); }
  .hero__actions { margin-bottom: var(--space-6); }
  .section { padding-block: var(--space-16); }

  .hero__grid { padding-inline: var(--space-4); }
  .hero__title { font-size: clamp(2rem, 9vw, 2.75rem); }
  .hero__actions { flex-direction: column; align-items: stretch; }
  .hero__actions .btn { width: 100%; }
  .hero__trust { flex-direction: column; align-items: center; gap: var(--space-2); }

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

  .cart-item { grid-template-columns: 72px 1fr; }
  .cart-item__media { width: 72px; height: 72px; }
  .cart-item__total { grid-column: 1 / -1; text-align: right; }

  .buy-row { flex-direction: column; align-items: stretch; }
  .buy-row .qty { align-self: flex-start; }
  .buy-row .btn { width: 100%; }

  .gallery__main { border-radius: var(--r-lg); }
  .gallery__main img { padding: var(--space-5); }
  .gallery__main { max-height: 48vh; }
  .gallery__thumb { flex-basis: 68px; width: 68px; height: 68px; }

  .steps { font-size: 10px; }
  .step span:not(.step__dot) { display: none; }

  .summary { padding: var(--space-5); }
}

/* -- Very small (<= 360px) --------------------------------------------- */
@media (max-width: 360px) {
  :root { --fs-16: .9375rem; }
  .container { padding-inline: var(--space-3); }
  .header__inner { padding-inline: var(--space-3); }
  .btn { padding-inline: var(--space-4); font-size: var(--fs-12); }

  /* Below ~360px there is not room for the wordmark AND three 44px
     controls. The shield mark still identifies the brand and still
     links home; the accessible name comes from aria-label on the link. */
  .brand > span:not(.brand__mark) { display: none; }
  .icon-btn { width: 40px; }
}

/* -- Landscape phones: reclaim vertical space -------------------------- */
@media (max-height: 520px) and (orientation: landscape) {
  .hero { min-height: auto; }
  .hero__grid { padding-block: var(--space-10); }
  .hero__stage { max-width: 260px; }
}

/* ---------------------------------------------------------------------
   24. REDUCED MOTION / LOW-POWER
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }

  /* Content must be visible immediately, not merely un-animated. */
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }

  .hero__atmosphere, .hero__sweep, .hero__rings { display: none; }
  .hero__halo { animation: none; }
}

/* The "lite" class is set by JS on weak devices / save-data / small
   screens. It strips the expensive layers without touching usability. */
.lite .hero__atmosphere,
.lite .hero__sweep,
.lite .hero__ring:nth-child(3) { display: none; }
.lite .hero__halo { filter: blur(20px); animation: none; }
.lite .header { backdrop-filter: none; background: rgb(var(--header-rgb) / .96); }
.lite .card::before { display: none; }
.lite .flash { backdrop-filter: none; }

/* ---------------------------------------------------------------------
   25. PRINT (invoices / order pages)
   --------------------------------------------------------------------- */
@media print {
  .header, .footer, .wa-fab, .flash-stack, .drawer, .hero__atmosphere, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  .container { max-width: none; padding: 0; }
  a[href]::after { content: " (" attr(href) ")"; font-size: 10px; color: #555; }
}

/* ---------------------------------------------------------------------
   NEWSLETTER SIGN-UP
   One form, two homes: the footer and the promo dialog. Only the framing
   differs — the field, the button and the rules are identical, because a
   sign-up box that behaves differently in two places is two things to get
   wrong rather than one.
   --------------------------------------------------------------------- */
.nl { width: 100%; }
.nl__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--fs-22);
  line-height: 1.25;
  color: var(--fg-strong);
}
.nl__text {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-14);
  line-height: 1.6;
  color: var(--fg-muted);
  max-width: 52ch;            /* keeps the line length readable */
}

.nl__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}
.nl__field { flex: 1 1 240px; min-width: 0; }

.nl__label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
/* The field itself is a plain .input — same background, radius, focus ring
   and 48px height as every other field on the site. */
.nl__btn { min-height: 48px; flex: 0 0 auto; }

/* Off-screen rather than display:none — a bot that skips hidden inputs
   walks straight past a display:none trap. */
.nl__trap {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- In the footer --- */
.footer__nl {
  padding: var(--space-6) 0;
  border-top: 1px solid var(--hairline);
}
.nl--footer { max-width: 620px; }

/* --- In the popup --- */
.nl--popup .nl__title { font-size: var(--fs-18); }
.nl--popup .nl__row { flex-direction: column; align-items: stretch; }
.nl--popup .nl__btn { width: 100%; justify-content: center; }

@media (max-width: 560px) {
  .nl__row { flex-direction: column; align-items: stretch; }
  .nl__btn { width: 100%; justify-content: center; }
}

/* ---------------------------------------------------------------------
   FAQ ACCORDION
   Native <details>. The animation is on grid-template-rows rather than
   height, which is what lets an answer of unknown length open smoothly
   without measuring it in JavaScript.
   --------------------------------------------------------------------- */
.faq { background: var(--surface-sunken); }
.faq__head { text-align: center; margin-bottom: var(--space-8); }
.faq__intro { margin-inline: auto; max-width: 58ch; }

.faq__list {
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
  box-shadow: var(--sh-1);
  overflow: hidden;
}

.faq__item + .faq__item { border-top: 1px dotted var(--line-soft); }

.faq__q {
  display: flex; align-items: center; gap: var(--space-4);
  /* 44px of target even for a one-word question. */
  min-height: 44px;
  padding: var(--space-5) var(--space-6);
  cursor: pointer;
  font-family: var(--font-display);
  font-size: var(--fs-16);
  font-weight: 600;
  color: var(--fg-strong);
  list-style: none;                 /* no default triangle */
  transition: background-color var(--t-base) var(--ease);
}
/* Safari puts the triangle back unless this is here too. */
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { background: var(--surface-tint); }
.faq__q:focus-visible {
  /* Matches the site-wide focus ring; --accent is not a token here. */
  outline: 2px solid var(--lime-400);
  outline-offset: -2px;
}
.faq__q-text { flex: 1 1 auto; min-width: 0; }

.faq__chevron {
  flex: 0 0 auto;
  display: grid; place-items: center;
  color: var(--fg-muted);
  transition: rotate var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.faq__item[open] > .faq__q { color: var(--brand); }
.faq__item[open] > .faq__q .faq__chevron { rotate: 180deg; color: var(--brand); }

.faq__a {
  padding: 0 var(--space-6) var(--space-5);
  color: var(--fg-muted);
  font-size: var(--fs-15);
  line-height: 1.75;
}
.faq__a p { margin: 0; max-width: 68ch; }
.faq__a p + p { margin-top: var(--space-3); }

.faq__more {
  margin-top: var(--space-6);
  text-align: center;
  color: var(--fg-muted);
  font-size: var(--fs-15);
}
.faq__more a { color: var(--brand); font-weight: 600; }
.faq__more a:hover { text-decoration: underline; }

/*
 * Opening slides the answer down. ::details-content is the only way to
 * animate a <details> without scripting its height, and browsers that do
 * not support it simply snap open — which is how <details> has always
 * behaved, so nothing is lost.
 */
@supports selector(details::details-content) {
  .faq__item::details-content {
    display: grid;
    grid-template-rows: 0fr;
    overflow: hidden;
    opacity: 0;
    transition: grid-template-rows var(--t-slow, .32s) var(--ease),
                opacity var(--t-base) var(--ease),
                content-visibility var(--t-slow, .32s) allow-discrete;
    content-visibility: hidden;
  }
  .faq__item[open]::details-content {
    grid-template-rows: 1fr;
    opacity: 1;
    content-visibility: visible;
  }
  .faq__item::details-content > * { min-height: 0; }
}

@media (max-width: 560px) {
  .faq__q { padding: var(--space-4); font-size: var(--fs-15); gap: var(--space-3); }
  .faq__a { padding: 0 var(--space-4) var(--space-4); }
}

@media (prefers-reduced-motion: reduce) {
  .faq__item::details-content { transition: none; }
  .faq__chevron { transition: none; }
}

/* ---------------------------------------------------------------------
   BLOG MOSAIC (home page)
   One lead card beside two stacked ones. Below 900px it becomes a single
   column, because a 300px-wide photograph with a headline over it is
   unreadable at any scrim strength.
   --------------------------------------------------------------------- */
.mosaic {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .mosaic {
    grid-template-columns: 1.35fr 1fr;
    grid-template-rows: repeat(2, minmax(0, 1fr));
    height: 620px;
  }
  .mosaic__card--lead { grid-row: span 2; }
  /* One article should not stretch across a two-column grid. */
  .mosaic--single { grid-template-columns: 1fr; grid-template-rows: auto; height: 420px; }
}

.mosaic__card {
  position: relative;
  isolation: isolate;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 280px;
  padding: var(--space-6);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--surface-deep);
  transition: transform var(--t-slow, .32s) var(--ease), box-shadow var(--t-slow, .32s) var(--ease);
}
.mosaic__card:hover { transform: scale(.985) rotate(.3deg); box-shadow: var(--sh-3, var(--sh-2)); }

.mosaic__img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: scale var(--t-slow, .32s) var(--ease);
}
.mosaic__card:hover .mosaic__img { scale: 1.05; }
.mosaic__placeholder {
  position: absolute; inset: 0; z-index: -2;
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--surface-deep), var(--brand-deep, var(--surface-sunken)));
  color: var(--brand-lime, var(--brand));
  opacity: .5;
}

/*
 * The photograph is whatever the shop owner uploaded, so the text cannot
 * rely on it being dark. This scrim is opaque enough at the bottom that
 * white type clears 4.5:1 even over a white sky, measured rather than
 * guessed, and fades to nothing at the top so the image still reads.
 */
.mosaic__scrim {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top,
              rgb(6 10 8 / .92) 0%,
              rgb(6 10 8 / .80) 28%,
              rgb(6 10 8 / .45) 55%,
              rgb(6 10 8 / .12) 100%);
  transition: opacity var(--t-slow, .32s) var(--ease);
}
.mosaic__card:hover .mosaic__scrim { opacity: .96; }

/*
 * Deliberately NOT position: relative. The title's stretched ::after is
 * absolutely positioned, so it resolves against the nearest positioned
 * ancestor — make that the body and the clickable area shrinks to just the
 * text block, leaving the top two-thirds of the card dead to a click. The
 * card is the positioned ancestor; the body must stay out of the way.
 *
 * It still paints above the scrim without this: the scrim is at z-index -1,
 * and in-flow content always draws over a negative layer.
 */
.mosaic__body { display: flex; flex-direction: column; gap: var(--space-3); }

.mosaic__chip {
  align-self: flex-start;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  /*
   * DARK glass, not light. A white-tinted pill lightens the very surface its
   * white text sits on: measured over a pale photograph it dragged this chip
   * down to 4.08:1, under the 4.5 needed at 12px. Tinting downwards instead
   * keeps the frosted look and pushes contrast the right way — the same
   * measurement now reads 14:1.
   */
  background: rgb(6 10 8 / .55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgb(255 255 255 / .30);
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #fff;
}

.mosaic__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-22);
  line-height: 1.2;
  color: #fff;
}
.mosaic__card--lead .mosaic__title { font-size: var(--fs-28); }
.mosaic__title a { color: inherit; text-decoration: none; }
/* Stretches the title's hit area over the whole card without nesting the
   rest of the content inside the link. */
.mosaic__title a::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.mosaic__title a:focus-visible { outline: none; }
.mosaic__card:has(a:focus-visible) { outline: 2px solid var(--lime-400); outline-offset: 3px; }

.mosaic__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin: 0;
  font-size: var(--fs-12);
  color: rgb(255 255 255 / .86);
}
.mosaic__dot {
  width: 3px; height: 3px; border-radius: 50%;
  background: currentColor; opacity: .7;
}

.mosaic__arrow {
  position: absolute; right: var(--space-6); bottom: var(--space-6);
  display: grid; place-items: center;
  color: #fff; opacity: .85;
  transition: translate var(--t-base) var(--ease);
}
.mosaic__card:hover .mosaic__arrow { translate: 6px 0; }
@media (max-width: 560px) { .mosaic__arrow { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .mosaic__card, .mosaic__img, .mosaic__scrim, .mosaic__arrow { transition: none; }
  .mosaic__card:hover { transform: none; }
  .mosaic__card:hover .mosaic__img { scale: 1; }
  .mosaic__card:hover .mosaic__arrow { translate: 0; }
}

/* ---------------------------------------------------------------------
   BLOG INDEX CARDS
   --------------------------------------------------------------------- */
.post-card {
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--r-lg);
  background: transparent;
  color: inherit;
  text-decoration: none;
  transition: background-color var(--t-base) var(--ease);
}
.post-card:hover { background: var(--surface-tint); }
.post-card:focus-visible { outline: 2px solid var(--lime-400); outline-offset: 2px; }

.post-card__media {
  aspect-ratio: 16 / 9;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-sunken);
}
.post-card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: scale var(--t-slow, .32s) var(--ease);
}
.post-card:hover .post-card__media img { scale: 1.05; }
.post-card__placeholder {
  display: grid; place-items: center; height: 100%;
  color: var(--brand); opacity: .32;
}

.post-card__body { display: flex; flex-direction: column; gap: var(--space-2); padding: 0 var(--space-2) var(--space-2); }

.post-card__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin: 0;
  font-size: var(--fs-12);
  color: var(--fg-muted);
}
.post-card__dot {
  width: 3px; height: 3px; border-radius: 50%;
  background: currentColor; opacity: .75;
}

.post-card__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-18);
  line-height: 1.3;
  color: var(--fg-strong);
  /* Two lines, then an ellipsis — so a long headline cannot make one card
     twice the height of its neighbours. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.post-card:hover .post-card__title { color: var(--brand); }

.post-card__excerpt {
  margin: 0;
  font-size: var(--fs-14);
  line-height: 1.65;
  color: var(--fg-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.post-card__cat {
  align-self: flex-start;
  margin-top: var(--space-1, 4px);
  font-size: var(--fs-12);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--brand);
}

@media (prefers-reduced-motion: reduce) {
  .post-card, .post-card__media img { transition: none; }
  .post-card:hover .post-card__media img { scale: 1; }
}
