/* ==========================================================================
   PLAYNEST TOYS — STYLESHEET
   Brand Colors: Navy #1B2A5E | Coral-Red #E63950 | Warm Yellow #FFC93C
   Background: #FAFAF7 | Sand/Cream #F0EDE4 | Ink #2D2D2D
   Typography: Fredoka (Headings) + Inter / Plus Jakarta Sans (Body)
   ========================================================================== */

/* ==========================================================================
   DESIGN TOKENS

   Two layers, on purpose:

   1. BRAND layer (--color-*) — the fixed Playnest palette. These identity
      colors are the SAME in light and dark mode so the site still reads as
      Playnest, not a generic dark theme. Dark mode nudges only the two
      accents down in saturation/up in lightness (see the dark block below)
      so they don't vibrate against a dark ground.

   2. SEMANTIC layer (--surface-*, --text-*, --border-*, --hero-*) — what a
      color is FOR, not what it is. Every rule in this stylesheet consumes
      the semantic layer, never a raw hex. That makes dark mode a pure token
      swap: only the ~35 declarations in the dark block below change.

   THEME RESOLUTION
   ----------------
   :root                              → light values (the base, always defined)
   @media (prefers-color-scheme: dark)
     :root:not([data-theme="light"])  → system dark, unless manually overridden
   :root[data-theme="dark"]           → manual dark, wins in both directions

   The inline bootstrap script in index.html stamps data-theme before first
   paint, so there is never a flash of the wrong theme.
   ========================================================================== */
:root {
  /* --- BRAND (identity — stable across themes) --- */
  --color-navy: #1B2A5E;
  --color-navy-dark: #101B3E;
  --color-navy-light: #2A3E7E;
  --color-coral: #E63950;
  --color-coral-hover: #D1253C;
  --color-coral-light: #FFF0F2;
  --color-yellow: #FFC93C;
  --color-yellow-hover: #F0B820;
  --color-yellow-light: #FFF8E7;
  --color-offwhite: #FAFAF7;
  --color-sand: #F0EDE4;
  --color-sand-dark: #E2DDD0;
  --color-sand-light: #F7F5EF;
  --color-ink: #2D2D2D;
  --color-ink-muted: #5E636E;
  --color-white: #FFFFFF;
  --color-whatsapp: #25D366;   /* brand green — display/icon use only */
  --color-whatsapp-dark: #1EBE5D;

  /* --- SEMANTIC: action fills (white label must clear 4.5:1) ---
     White on brand coral is 4.15:1 and white on brand WhatsApp green is a
     dismal 1.98:1 — both fail AA for button labels. These deeper tints keep the
     colours unmistakably on-brand while passing: 5.20:1 and 5.23:1. */
  --fill-action: #D1253C;
  --fill-action-hover: #B81E33;
  --text-accent: #D1253C;   /* coral used as TEXT on a surface */
  --fill-wa: #0E7A6C;
  --fill-wa-hover: #0A6459;

  /* --- SEMANTIC: surfaces --- */
  --surface-page: var(--color-offwhite);   /* body / section canvas          */
  --surface-card: var(--color-white);      /* product cards, drawer, modal   */
  --surface-sunken: var(--color-sand);     /* card media wells, toolbar      */
  --surface-sunken-soft: var(--color-sand-light);
  --surface-media: var(--color-sand);   /* product image well */
  --surface-raised: var(--color-white);    /* icon chips floating on sunken  */
  --surface-header: rgba(250, 250, 247, 0.94);
  --surface-header-scrolled: rgba(250, 250, 247, 0.98);
  --surface-footer: var(--color-navy-dark);
  --surface-inset: rgba(27, 42, 94, 0.06); /* counter tag, subtle fills      */
  --surface-scrim: rgba(16, 27, 62, 0.6);  /* drawer / modal backdrop        */
  --surface-scrim-strong: rgba(16, 27, 62, 0.7);
  --surface-glass: rgba(255, 255, 255, 0.9); /* quick-view pill on media     */

  /* --- SEMANTIC: text --- */
  --text-heading: var(--color-navy);       /* titles, card names, nav        */
  --text-body: var(--color-ink);           /* long-form copy                 */
  --text-muted: var(--color-ink-muted);    /* specs, captions, placeholders  */
  --text-footer: #D5DAE8;
  --text-footer-muted: #B5BDD6;
  --text-footer-faint: #8C96BA;

  /* --- SEMANTIC: borders --- */
  --border-subtle: rgba(27, 42, 94, 0.08);
  --border-default: rgba(27, 42, 94, 0.12);
  --border-strong: rgba(27, 42, 94, 0.15);

  /* Theme switch. The border is what makes the control's boundary visible
     (3.9:1 on the header), because a track fill light enough to read as "off"
     can never carry that contrast on its own. */
  --toggle-track-bg: #D2CCBA;
  --toggle-track-border: #767D93;
  --toggle-track-icon: #5F6678;
  --toggle-thumb-ring: rgba(27, 42, 94, 0.35);

  /* "% OFF" tag. Green so a saving never competes with the coral price or the
  red Add to Cart. 6.5:1. */
  --discount-bg: #E3F5EF;
  --discount-text: #0B6156;
  --border-footer: rgba(255, 255, 255, 0.1);

  /* --- SEMANTIC: out-of-stock / disabled --- */
  --disabled-bg: #E5E7EB;
  --disabled-text: #9CA3AF;
  --disabled-border: #D1D5DB;
  --badge-muted-bg: #6B7280;
  --badge-muted-text: #FFFFFF;

  /* --- SEMANTIC: stock status pills --- */
  --status-in-bg: #ECFDF5;
  --status-in-text: #065F46;
  --status-in-border: #A7F3D0;
  --status-in-dot: #10B981;
  --status-out-bg: #FEF2F2;
  --status-out-text: #991B1B;
  --status-out-border: #FECACA;
  --status-out-dot: #EF4444;

  /* --- SEMANTIC: hero stage + scrim ---
     The hero subject (child + jeep) is a transparent WebP sequence, so the
     backdrop is entirely CSS and re-themes for free. The radial glow gives the
     glossy BLACK jeep a lighter pool to read against — without it the vehicle
     silhouette dissolves into the page colour in dark mode. */
  /* --- SEMANTIC: category photo tiles --- */
  --cat-scrim-strong: rgba(12, 16, 32, 0.86);
  --cat-scrim-soft: rgba(12, 16, 32, 0.42);
  --cat-label: #FFFFFF;
  --cat-label-muted: rgba(255, 255, 255, 0.82);

  --hero-stage-glow: #FFFFFF;          /* centre of the radial stage       */
  --hero-stage-base: #E8E2D4;          /* outer edge of the stage          */
  --hero-ground: rgba(27, 42, 94, 0.16); /* contact shadow under the tyres */

  /* Copy sits on the stage, not on raw video, so the scrim is far lighter
     than the previous photographic hero needed. */
  --hero-scrim-top: rgba(27, 42, 94, 0.30);
  --hero-scrim-bottom: rgba(27, 42, 94, 0.34);
  --hero-text-strong: var(--color-navy);
  --hero-text-body: var(--color-ink);
  --hero-text-muted: var(--color-ink-muted);

  /* --- SEMANTIC: tagline emblem --- */
  --tagline-ink: var(--hero-text-strong);
  --tagline-accent-pop: var(--color-coral);
  --tagline-accent-warm: var(--color-yellow);

  /* --- Typography --- */
  --font-display: 'Fredoka', cursive, system-ui, -apple-system, sans-serif;
  --font-script: 'Caveat', cursive, system-ui, -apple-system, sans-serif;
  /* Figtree: humanist geometric sans with open apertures and softly rounded
     terminals — echoes Fredoka's roundness without competing with it, and stays
     legible at spec-chip sizes. Replaces Inter, which reads as a default. */
  --font-body: 'Figtree', 'Segoe UI', system-ui, -apple-system, sans-serif;

  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 22px;
  --radius-xl: 32px;
  --radius-full: 9999px;

  --shadow-sm: 0 2px 8px rgba(27, 42, 94, 0.06);
  --shadow-md: 0 8px 24px rgba(27, 42, 94, 0.08);
  --shadow-lg: 0 16px 36px rgba(27, 42, 94, 0.12);
  --shadow-floating: 0 20px 40px -10px rgba(27, 42, 94, 0.14), 0 0 1px rgba(27, 42, 94, 0.2);
  --shadow-glow-coral: 0 8px 25px rgba(230, 57, 80, 0.35);
  --shadow-action: 0 6px 20px rgba(230, 57, 80, 0.30);
  --shadow-wa: 0 4px 14px rgba(14, 122, 108, 0.30);
  --shadow-glow-yellow: 0 8px 25px rgba(255, 201, 60, 0.4);
  --shadow-drawer: -10px 0 40px rgba(27, 42, 94, 0.2);

  --transition-fast: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-normal: 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-spring: 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);

  --header-height: 74px;

  /* Height reserved at the bottom of the hero so the CTA never collides with
     the fixed Cart/Chat pills. Derived from the pill height + its offsets. */
  --floating-bar-clearance: 96px;

  color-scheme: light;
}

/* --------------------------------------------------------------------------
   DARK THEME TOKENS
   Only the semantic layer moves. Base is a deep navy-black (#12141C family)
   rather than a neutral gray, keeping the brand's navy character. Surfaces
   step UP in lightness as they come forward, so product cards still read as
   floating objects. Text is off-white (#E7E9F0), never pure #FFF.
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Accents: same hues, eased back so they don't glare on a dark ground */
    --fill-action: #D1253C;
    --fill-action-hover: #E0384F;
    --text-accent: #FF7A88;
    --fill-wa: #0E7A6C;
    --fill-wa-hover: #12907F;
    --color-coral: #F25266;
    --color-coral-hover: #FF6B7D;
    --color-coral-light: #33202A;
    --color-yellow: #F5C860;
    --color-yellow-hover: #FFD97A;
    --color-yellow-light: #2E2716;

    --surface-page: #12141C;
    --surface-card: #1B1E29;
    --surface-sunken: #171A24;
    --surface-sunken-soft: #1E2130;
    --surface-media: #262B3A;
    --surface-raised: #262A38;
    --surface-header: rgba(18, 20, 28, 0.90);
    --surface-header-scrolled: rgba(18, 20, 28, 0.97);
    --surface-footer: #0D0F16;
    --surface-inset: rgba(255, 255, 255, 0.07);
    --surface-scrim: rgba(6, 7, 11, 0.72);
    --surface-scrim-strong: rgba(6, 7, 11, 0.82);
    --surface-glass: rgba(38, 42, 56, 0.92);

    --text-heading: #E7E9F0;
    --text-body: #D7DAE4;
    --text-muted: #9AA1B4;
    --text-footer: #C9CEDE;
    --text-footer-muted: #99A1B8;
    --text-footer-faint: #767E95;

    --border-subtle: rgba(255, 255, 255, 0.08);
    --border-default: rgba(255, 255, 255, 0.13);
  --border-strong: rgba(255, 255, 255, 0.20);
  
    /* Theme switch — same reasoning, inverted. */
    --toggle-track-bg: #2A3358;
  --toggle-track-border: #7C89B8;
  --toggle-track-icon: #9AA6C9;
  --toggle-thumb-ring: rgba(0, 0, 0, 0.45);

  /* "% OFF" tag. 8.3:1. */
  --discount-bg: #17352F;
  --discount-text: #6FE0C8;
    --border-footer: rgba(255, 255, 255, 0.09);

    --disabled-bg: #262A38;
    --disabled-text: #6E7689;
    --disabled-border: #333849;
    --badge-muted-bg: #4A5164;
    --badge-muted-text: #E7E9F0;

    --status-in-bg: #12291F;
    --status-in-text: #6EE7B7;
    --status-in-border: #1E4635;
    --status-in-dot: #34D399;
    --status-out-bg: #2E1618;
    --status-out-text: #FCA5A5;
    --status-out-border: #55262A;
    --status-out-dot: #F87171;

    /* Dark mode leans the scrim heavier: less glare from a bright video
       against an otherwise dark page, and a moodier hero. */
    --cat-scrim-strong: rgba(6, 8, 16, 0.90);
    --cat-scrim-soft: rgba(6, 8, 16, 0.50);
    --hero-stage-glow: #262E4A;
    --hero-stage-base: #0F111A;
    --hero-ground: rgba(0, 0, 0, 0.55);
    --hero-scrim-top: rgba(10, 12, 18, 0.34);
    --hero-scrim-bottom: rgba(10, 12, 18, 0.38);
    --hero-text-strong: #F2F4FA;
    --hero-text-body: #E2E5EF;
    --hero-text-muted: #A9B0C4;

  
    /* Shadows read as depth pools, not gray smudges, on a dark ground */
    /* Neutral elevation on dark: a coloured halo here is AI-UI slop. */
    --shadow-glow-coral: 0 10px 28px rgba(0, 0, 0, 0.55);
    --shadow-action: 0 6px 20px rgba(0, 0, 0, 0.50);
    --shadow-wa: 0 4px 14px rgba(0, 0, 0, 0.50);
    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.40);
    --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.48);
    --shadow-lg: 0 16px 36px rgba(0, 0, 0, 0.58);
    --shadow-floating: 0 20px 40px -10px rgba(0, 0, 0, 0.62), 0 0 1px rgba(255, 255, 255, 0.10);
    --shadow-drawer: -10px 0 40px rgba(0, 0, 0, 0.62);

    color-scheme: dark;
  }
}

/* Manual override — wins in both directions, including "force dark on a
   light system". Values are kept identical to the media-query block above. */
:root[data-theme="dark"] {
  --fill-action: #D1253C;
  --fill-action-hover: #E0384F;
  --text-accent: #FF7A88;
  --fill-wa: #0E7A6C;
  --fill-wa-hover: #12907F;
  --color-coral: #F25266;
  --color-coral-hover: #FF6B7D;
  --color-coral-light: #33202A;
  --color-yellow: #F5C860;
  --color-yellow-hover: #FFD97A;
  --color-yellow-light: #2E2716;

  --surface-page: #12141C;
  --surface-card: #1B1E29;
  --surface-sunken: #171A24;
  --surface-sunken-soft: #1E2130;
  --surface-media: #262B3A;
  --surface-raised: #262A38;
  --surface-header: rgba(18, 20, 28, 0.90);
  --surface-header-scrolled: rgba(18, 20, 28, 0.97);
  --surface-footer: #0D0F16;
  --surface-inset: rgba(255, 255, 255, 0.07);
  --surface-scrim: rgba(6, 7, 11, 0.72);
  --surface-scrim-strong: rgba(6, 7, 11, 0.82);
  --surface-glass: rgba(38, 42, 56, 0.92);

  --text-heading: #E7E9F0;
  --text-body: #D7DAE4;
  --text-muted: #9AA1B4;
  --text-footer: #C9CEDE;
  --text-footer-muted: #99A1B8;
  --text-footer-faint: #767E95;

  --border-subtle: rgba(255, 255, 255, 0.08);
  --border-default: rgba(255, 255, 255, 0.13);
  --border-strong: rgba(255, 255, 255, 0.20);
  
  /* Theme switch — same reasoning, inverted. */
  --toggle-track-bg: #2A3358;
  --toggle-track-border: #7C89B8;
  --toggle-track-icon: #9AA6C9;
  --toggle-thumb-ring: rgba(0, 0, 0, 0.45);

  /* "% OFF" tag. 8.3:1. */
  --discount-bg: #17352F;
  --discount-text: #6FE0C8;
  --border-footer: rgba(255, 255, 255, 0.09);

  --disabled-bg: #262A38;
  --disabled-text: #6E7689;
  --disabled-border: #333849;
  --badge-muted-bg: #4A5164;
  --badge-muted-text: #E7E9F0;

  --status-in-bg: #12291F;
  --status-in-text: #6EE7B7;
  --status-in-border: #1E4635;
  --status-in-dot: #34D399;
  --status-out-bg: #2E1618;
  --status-out-text: #FCA5A5;
  --status-out-border: #55262A;
  --status-out-dot: #F87171;

  /* Dark mode leans the scrim heavier: less glare from a bright video
     against an otherwise dark page, and a moodier hero. */
  --cat-scrim-strong: rgba(6, 8, 16, 0.90);
  --cat-scrim-soft: rgba(6, 8, 16, 0.50);
  --hero-stage-glow: #262E4A;
  --hero-stage-base: #0F111A;
  --hero-ground: rgba(0, 0, 0, 0.55);
  --hero-scrim-top: rgba(10, 12, 18, 0.34);
  --hero-scrim-bottom: rgba(10, 12, 18, 0.38);
  --hero-text-strong: #F2F4FA;
  --hero-text-body: #E2E5EF;
  --hero-text-muted: #A9B0C4;


  /* Neutral elevation on dark: a coloured halo here is AI-UI slop. */
  --shadow-glow-coral: 0 10px 28px rgba(0, 0, 0, 0.55);
  --shadow-action: 0 6px 20px rgba(0, 0, 0, 0.50);
  --shadow-wa: 0 4px 14px rgba(0, 0, 0, 0.50);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.40);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.48);
  --shadow-lg: 0 16px 36px rgba(0, 0, 0, 0.58);
  --shadow-floating: 0 20px 40px -10px rgba(0, 0, 0, 0.62), 0 0 1px rgba(255, 255, 255, 0.10);
  --shadow-drawer: -10px 0 40px rgba(0, 0, 0, 0.62);

  color-scheme: dark;
}

/* --- Base & Reset --- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  background-color: var(--surface-page);
  color: var(--text-body);
  line-height: 1.5;
  font-size: 16px;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg {
  display: block;
  max-width: 100%;
  height: auto;
}

button, input, select {
  font-family: inherit;
  font-size: inherit;
}

a {
  color: inherit;
  text-decoration: none;
}

/* Focus states for high accessibility */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 3px solid var(--color-coral);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Anchor targets must clear the sticky header, otherwise every in-page jump
   lands with the section heading hidden underneath it. */
:target,
section[id],
#footer {
  scroll-margin-top: calc(var(--header-height) + 16px);
}

/* Utility Container */
.container {
  width: 100%;
  max-width: 1240px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 20px;
  padding-right: 20px;
}

/* Typography elements */
.font-display {
  font-family: var(--font-display);
}

/* ==========================================================================
   NAVIGATION BAR
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--header-height);
  background: var(--surface-header);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border-subtle);
  transition: box-shadow var(--transition-fast), background var(--transition-fast);
}

.site-header.scrolled {
  box-shadow: var(--shadow-sm);
  background: var(--surface-header-scrolled);
}

.nav-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-height);
}

.brand-logo-link {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
}

.brand-logo-img {
  height: 48px;
  width: auto;
  object-fit: contain;
  border-radius: var(--radius-sm);
}

.nav-menu {
  display: none;
  align-items: center;
  gap: 28px;
  list-style: none;
}

@media (min-width: 860px) {
  .nav-menu {
    display: flex;
  }
}

.nav-link {
  font-weight: 500;
  color: var(--text-heading);
  font-size: 0.95rem;
  padding: 8px 4px;
  position: relative;
  transition: color var(--transition-fast);
}

.nav-link:hover {
  color: var(--text-accent);
}

.nav-link::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background-color: var(--color-coral);
  /* scaleX, not width: width relayouts on every frame. */
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--transition-fast);
  border-radius: 2px;
}

.nav-link:hover::after {
  transform: scaleX(1);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Header Cart Button */
.header-cart-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background-color: var(--surface-sunken);
  color: var(--text-heading);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 9px 16px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-default);
  cursor: pointer;
  position: relative;
  transition: transform var(--transition-fast), background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}

.header-cart-btn:hover {
  background-color: var(--surface-raised);
  border-color: var(--text-accent);
  color: var(--text-accent);
  transform: translateY(-1px);
}

.header-cart-btn:active {
  transform: scale(0.96);
  transition-duration: 100ms;
}

.cart-icon-svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cart-badge {
  background-color: var(--fill-action);
  color: var(--color-white);
  font-size: 0.75rem;
  font-weight: 700;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  transition: transform var(--transition-spring);
}

.cart-badge.bump {
  animation: badge-bump 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

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

.header-wa-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background-color: var(--fill-wa);
  color: var(--color-white);
  font-weight: 600;
  font-size: 0.88rem;
  padding: 9px 16px;
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-wa);
  transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast);
}

.header-wa-btn:hover {
  background-color: var(--fill-wa-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-wa);
}

.header-wa-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* ==========================================================================
   CINEMATIC SCROLL-DRIVEN HERO SECTION

   A 22-frame still sequence from videos/hero-source.mp4, drawn to a <canvas>
   and stepped by scroll position. Frames are WebP (~442 KB for the whole
   sequence) with a JPEG fallback; see js/app.js -> initScrollHero.

   4-beat scroll choreography:
     Beat 0  0.00–0.05  wide shot, tagline reads
     Beat 1  0.05–0.30  camera pushes in
     Beat 2  0.30–0.65  mid sequence
     Beat 3  0.65–1.00  close-up, CTA resolves
   ========================================================================== */
.hero-scroll-container {
  position: relative;
  width: 100%;
  height: 320vh;
  background: var(--hero-stage-base);
}

.hero-sticky-viewport {
  /* Where the scroll-scrubbed subject sits. Read by drawFrame() in js/app.js.
     --hero-subject-width may exceed 1 so the plate's empty edges bleed off
     screen and the vehicle itself reads larger. */
  --hero-subject-width: 0.86;
  --hero-subject-max-h: 0.46;
  --hero-subject-bottom: 0.21;

  position: sticky;
  /* Sits directly below the sticky header rather than behind it, so the
     content lane maths (and the CTA / floating-pill clearance) stay honest. */
  top: var(--header-height);
  width: 100%;
  height: calc(100vh - var(--header-height));
  height: calc(100dvh - var(--header-height));
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--hero-stage-base);
}

/* --- Frame canvas -------------------------------------------------------- */
.hero-frame-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  display: block;
  opacity: 0;
  transition: opacity 0.45s ease-out;
}

.hero-frame-canvas.ready {
  opacity: 1;
}

/* --- Loading indicator --------------------------------------------------- */
.hero-loader {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
  transition: opacity 0.35s ease-out;
}

.hero-loader.hidden {
  opacity: 0;
  pointer-events: none;
}

.hero-loader-spinner {
  width: 34px;
  height: 34px;
  border: 3px solid rgba(255, 255, 255, 0.22);
  border-top-color: var(--color-coral);
  border-radius: 50%;
  animation: hero-spin 0.8s linear infinite;
}

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

/* --------------------------------------------------------------------------
   HERO STAGE

   The subject is a transparent WebP sequence, so everything behind it is CSS.
   A radial glow sits under the vehicle: in light mode it reads as a soft studio
   sweep, and in dark mode it is what stops a glossy BLACK jeep from dissolving
   into a near-black page. The ellipse beneath adds ground contact so the
   vehicle sits on something instead of floating.
   -------------------------------------------------------------------------- */
.hero-stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse 62% 58% at 50% 62%,
      var(--hero-stage-glow) 0%,
      var(--hero-stage-base) 78%);
}

.hero-stage::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 20%;
  width: min(56vw, 620px);
  height: 42px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: var(--hero-ground);
  filter: blur(26px);
}

/* --------------------------------------------------------------------------
   READABILITY SCRIM

   Much lighter than the previous photographic hero required: the backdrop is
   now a controlled brand colour rather than unpredictable video luminance, so
   the scrim only has to separate the copy from the stage, not fight blown
   highlights. Sits above the subject so the vehicle reads behind the text.
   -------------------------------------------------------------------------- */
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    var(--hero-scrim-top) 0%,
    transparent 34%,
    transparent 62%,
    var(--hero-scrim-bottom) 100%
  );
}

/* --- Content ------------------------------------------------------------- */
.hero-content-wrapper {
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: 1100px;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  /* Bottom padding reserves a lane for the fixed Cart/Chat pills so the
     "Browse Collection" CTA can never sit underneath them. */
  padding: 30px 20px calc(24px + var(--floating-bar-clearance));
  text-align: center;
  pointer-events: none;
}

.hero-content-wrapper a,
.hero-content-wrapper button {
  pointer-events: auto;
}

.hero-text-zone {
  margin-top: 6px;
  transition: transform 0.2s ease-out, opacity 0.2s ease-out;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* --- Script tagline emblem (inline SVG) ---------------------------------- */
.hero-tagline-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 4px;
  max-width: 100%;
}

.hero-tagline {
  width: min(92vw, 620px);
  height: auto;
  display: block;
  overflow: visible;
  user-select: none;
  /* Lifts the wordmark off the busiest frames without a hard outline. */
  filter: drop-shadow(0 2px 8px var(--hero-scrim-top));
}

.hero-tagline-text {
  font-family: var(--font-script);
  font-size: 78px;
  font-weight: 700;
  letter-spacing: 0.5px;
}

@media (max-width: 600px) {
  .hero-tagline { width: min(94vw, 440px); }
}

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

/* Hero copy always sits on the dark scrim, so it uses light-on-dark tokens in
   BOTH themes rather than the page's normal text tokens. */
.hero-subtitle {
  font-size: clamp(0.92rem, 1.8vw, 1.12rem);
  color: var(--hero-text-body);
  max-width: 600px;
  margin: 0 auto 6px;
  font-weight: 500;
  text-shadow: 0 1px 10px var(--hero-scrim-bottom);
}

.hero-warm-note {
  font-size: 0.84rem;
  color: var(--hero-text-muted);
  font-weight: 500;
  font-style: italic;
  text-shadow: 0 1px 10px var(--hero-scrim-bottom);
}

/* Beat 3 Action Box */
.hero-action-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  z-index: 10;
  transition: opacity 0.25s ease-out, transform 0.25s ease-out;
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background-color: var(--fill-action);
  color: #FFFFFF;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1.02rem;
  padding: 13px 30px;
  border-radius: var(--radius-full);
  border: none;
  cursor: pointer;
  box-shadow: var(--shadow-action);
  transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast);
}

.btn-primary:hover {
  background-color: var(--fill-action-hover);
  transform: translateY(-2px) scale(1.02);
  box-shadow: var(--shadow-glow-coral);
}

.btn-primary:active {
  transform: scale(0.97);
  transition-duration: 100ms;
}

/* Compact variant (empty-state "Reset Filters") */
.btn-primary--sm {
  padding: 8px 20px;
  font-size: 0.88rem;
}

/* WhatsApp variant (footer "Chat on WhatsApp") */
.btn-primary--wa {
  padding: 10px 20px;
  font-size: 0.9rem;
  background-color: var(--fill-wa);
  box-shadow: var(--shadow-wa);
}

.btn-primary--wa:hover {
  background-color: var(--fill-wa-hover);
  box-shadow: var(--shadow-wa);
}

.hero-scroll-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--hero-text-muted);
  text-shadow: 0 1px 10px var(--hero-scrim-bottom);
}

.scroll-mouse-icon {
  width: 18px;
  height: 26px;
  flex-shrink: 0;
  border: 2px solid var(--hero-text-muted);
  border-radius: 12px;
  position: relative;
}

.scroll-mouse-dot {
  width: 4px;
  height: 6px;
  background-color: var(--color-coral);
  border-radius: 2px;
  position: absolute;
  top: 4px;
  left: 50%;
  transform: translateX(-50%);
  animation: mouse-wheel 1.8s infinite;
}

@keyframes mouse-wheel {
  0% { transform: translate(-50%, 0); opacity: 1; }
  100% { transform: translate(-50%, 10px); opacity: 0; }
}

.hero-beat-indicators {
  position: absolute;
  right: 24px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 20;
}

.beat-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--hero-text-muted);
  opacity: 0.45;
  /* transform, not height: animating height relayouts on every frame. */
  transform-origin: center;
  transition: transform var(--transition-normal), background-color var(--transition-normal), border-radius var(--transition-normal);
}

.beat-dot.active {
  transform: scaleY(2.85);
  border-radius: 4px;
  background: var(--color-coral);
}

/* ==========================================================================
   CATEGORY STRIP (CUSTOM SVG LINE ICONS)
   ========================================================================== */
.category-section {
  padding: 60px 0 30px;
  position: relative;
  background-color: var(--surface-page);
  z-index: 10;
}

.section-header {
  text-align: center;
  max-width: 680px;
  margin: 0 auto 36px;
}

.section-eyebrow {
  font-size: 0.85rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-coral);
  margin-bottom: 6px;
}

.section-title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.15;
  margin-bottom: 10px;
}

.section-desc {
  font-size: 1rem;
  color: var(--text-muted);
}

.category-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

@media (min-width: 768px) {
  .category-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
  }
}

.category-card {
  position: relative;
  overflow: hidden;
  background-color: var(--surface-sunken);
  border-radius: var(--radius-lg);
  padding: 20px;
  cursor: pointer;
  border: 2px solid transparent;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-normal), box-shadow var(--transition-normal), border-color var(--transition-normal), background-color var(--transition-normal);
  display: flex;
  align-items: flex-end;
  min-height: 156px;
}

.category-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  background-color: var(--surface-sunken-soft);
  border-color: var(--text-accent);
}

.category-card:active {
  transform: translateY(-1px) scale(0.98);
  transition-duration: 100ms;
}

.category-card.active {
  border-color: var(--color-coral);
  background-color: var(--surface-raised);
  box-shadow: var(--shadow-md);
}

/* --------------------------------------------------------------------------
   CATEGORY PHOTO

   Real product photography rather than line icons, so the category strip reads
   like the rest of the site. The image is the category's flagship product,
   chosen at runtime from the CSV (see initCategoryCounts).

   The source photos are square supplier plates with the product NAME set large
   across the top and a spec strip along the bottom. Both would fight the
   category label, so object-position pushes the frame down onto the vehicle
   itself and the tile crops the rest away.
   -------------------------------------------------------------------------- */
.category-photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
}

.category-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Frame the vehicle, not the supplier's title band. */
  object-position: center 56%;
  transform: scale(1.04);
  transform-origin: center 56%;
  transition: transform var(--transition-spring);
}

.category-card:hover .category-photo img,
.category-card.active .category-photo img {
  transform: scale(1.1);
}

/* Legibility scrim: the label sits over photography, so it needs a controlled
   ground rather than whatever the photo happens to be behind it. */
.category-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    var(--cat-scrim-strong) 0%,
    var(--cat-scrim-soft) 46%,
    transparent 78%
  );
}

.category-label {
  position: relative;
  z-index: 1;
}

.category-name {
  font-family: var(--font-display);
  font-size: 1.12rem;
  font-weight: 600;
  color: var(--cat-label);
  margin-bottom: 2px;
  text-shadow: 0 1px 6px var(--cat-scrim-strong);
}

.category-count {
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--cat-label-muted);
  text-shadow: 0 1px 6px var(--cat-scrim-strong);
}

/* A category with no products yet keeps its tile but says so plainly, instead
   of showing an empty photo frame. */
.category-card--empty .category-photo img { display: none; }

/* An empty category that DOES have stock art reads like a normal tile again,
   but keeps its 'coming soon' count so it never implies stock. */
.category-card--empty.category-card--stock-art {
  border-style: solid;
  border-color: transparent;
  background: var(--surface-sunken);
}
.category-card--empty.category-card--stock-art .category-photo img { display: block; }
.category-card--empty.category-card--stock-art .category-photo::after { display: block; }
.category-card--empty.category-card--stock-art .category-name {
  color: var(--cat-label);
  text-shadow: 0 1px 6px var(--cat-scrim-strong);
}
.category-card--empty.category-card--stock-art .category-count {
  color: var(--cat-label-muted);
  text-shadow: 0 1px 6px var(--cat-scrim-strong);
}
.category-card--empty .category-photo::after { display: none; }
.category-card--empty .category-name { color: var(--text-heading); text-shadow: none; }
.category-card--empty .category-count { color: var(--text-muted); text-shadow: none; }

.category-card--empty {
  background: var(--surface-sunken);
  border-style: dashed;
  border-color: var(--border-default);
}

.category-card--empty .category-count::after {
  content: ' · coming soon';
  opacity: 0.75;
}



/* ==========================================================================
   PRODUCT CATALOG SECTION (FILTERS, SEARCH, GRID)
   ========================================================================== */
.catalog-section {
  padding: 40px 0 80px;
  background-color: var(--surface-page);
}

.catalog-toolbar {
  background: var(--surface-sunken);
  border-radius: var(--radius-lg);
  padding: 16px 20px;
  margin-bottom: 30px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  box-shadow: var(--shadow-sm);
}

@media (min-width: 768px) {
  .catalog-toolbar {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.search-box {
  position: relative;
  flex: 1;
  max-width: 360px;
}

.search-input {
  width: 100%;
  padding: 10px 14px 10px 38px;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  font-size: 0.92rem;
  color: var(--text-body);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.search-input:focus {
  border-color: var(--color-coral);
  box-shadow: 0 0 0 3px rgba(230, 57, 80, 0.15);
  outline: none;
}

.search-icon {
  position: absolute;
  left: 13px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--text-muted);
  pointer-events: none;
}

.toolbar-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.sort-select {
  padding: 9px 16px;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--text-heading);
  cursor: pointer;
  outline: none;
}

.catalog-counter-tag {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--surface-inset);
  padding: 6px 12px;
  border-radius: var(--radius-full);
}

.filter-pills-row {
  display: flex;
  align-items: center;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 6px;
  scrollbar-width: none;
}

.filter-pills-row::-webkit-scrollbar {
  display: none;
}

.filter-pill-btn {
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  color: var(--text-heading);
  font-size: 0.88rem;
  font-weight: 600;
  padding: 7px 16px;
  border-radius: var(--radius-full);
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--transition-fast), background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.filter-pill-btn:hover {
  border-color: var(--text-accent);
  color: var(--text-accent);
}

.filter-pill-btn:active {
  transform: scale(0.96);
  transition-duration: 100ms;
}

.filter-pill-btn.active {
  background-color: var(--color-navy);
  color: #FFFFFF;
  border-color: var(--color-navy);
}

/* Product Grid (2 col mobile, 3-4 col desktop) */
.product-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

@media (min-width: 768px) {
  .product-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 22px;
  }
}

@media (min-width: 1080px) {
  .product-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
  }
}

/* Product Card — Floating on Sand Effect */
.product-card {
  background: var(--surface-card);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  position: relative;
  transition: transform var(--transition-normal), box-shadow var(--transition-normal), border-color var(--transition-fast);
}

.product-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-floating);
  border-color: rgba(27, 42, 94, 0.15);
}

.card-media {
  position: relative;
  background-color: var(--surface-media);
  padding: 16px 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 170px;
  cursor: pointer;
}

@media (min-width: 600px) {
  .card-media {
    min-height: 200px;
    padding: 20px 16px;
  }
}

.card-img {
  width: 100%;
  height: 140px;
  object-fit: contain;
  transition: transform var(--transition-spring);
}

.product-card:hover .card-img {
  transform: scale(1.06);
}

/* A product can carry more than one badge, so they stack down the corner
   rather than overlapping. The stack owns the positioning; each badge inside
   it is a plain tag. */
.card-badge-stack {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.card-badge {
  background: var(--color-navy);
  color: var(--color-white);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
}

.badge-out-of-stock {
  position: absolute;
  top: 10px;
  left: 10px;
  background: var(--badge-muted-bg);
  color: var(--badge-muted-text);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  z-index: 2;
}

.quick-view-trigger {
  position: absolute;
  bottom: 8px;
  right: 8px;
  background: var(--surface-glass);
  color: var(--text-heading);
  border: none;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  opacity: 0.9;
  transition: opacity var(--transition-fast), background var(--transition-fast);
}

.quick-view-trigger:hover {
  background: var(--surface-raised);
  color: var(--text-accent);
}

.card-body {
  padding: 14px 14px 16px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

@media (min-width: 600px) {
  .card-body {
    padding: 16px 18px 18px;
  }
}

.card-title {
  font-family: var(--font-body);
  font-size: 0.98rem;
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.3;
  margin-bottom: 8px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  height: 2.6em;
}

.card-spec-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 12px;
}

.spec-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--surface-sunken);
  color: var(--text-heading);
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
}

.spec-chip-icon {
  width: 12px;
  height: 12px;
  fill: currentColor;
}

.card-price-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: auto;
  margin-bottom: 12px;
}

.card-price {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--color-coral);
}

.card-mrp {
  font-size: 0.8rem;
  color: var(--text-muted);
  text-decoration: line-through;
}

/* Discount pricing. Both of these only exist in the markup when the sheet
   carries an OriginalPrice above the selling price, so an undiscounted card is
   byte-for-byte what it was before. */
.card-price-was {
  font-size: 0.85rem;
  color: var(--text-muted);
  /* <s> already strikes the text; this keeps the line the same weight as the
     glyphs rather than the browser default hairline. */
  text-decoration-thickness: 1px;
}

.card-discount {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  background: var(--discount-bg);
  color: var(--discount-text);
  white-space: nowrap;
}

/* Add to Cart Button */
.btn-add-cart {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background-color: var(--fill-action);
  color: var(--color-white);
  font-size: 0.9rem;
  font-weight: 600;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: none;
  cursor: pointer;
  transition: background-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
}

.btn-add-cart:hover {
  background-color: var(--fill-action-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-action);
}

.btn-add-cart:active {
  transform: scale(0.96);
  transition-duration: 100ms;
}

.btn-out-of-stock {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background-color: var(--disabled-bg);
  color: var(--disabled-text);
  font-size: 0.88rem;
  font-weight: 600;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--disabled-border);
  cursor: not-allowed;
}

.catalog-empty-state {
  grid-column: 1 / -1;
  text-align: center;
  padding: 60px 20px;
  background: var(--surface-sunken);
  border-radius: var(--radius-lg);
}

.empty-icon {
  width: 48px;
  height: 48px;
  color: var(--text-heading);
  margin: 0 auto 12px;
  opacity: 0.5;
}

/* ==========================================================================
   CART DRAWER (LIGHTWEIGHT WHATSAPP-BASED)
   ========================================================================== */
.cart-backdrop {
  position: fixed;
  inset: 0;
  background: var(--surface-scrim);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 1050;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast), visibility var(--transition-fast);
}

.cart-backdrop.open {
  opacity: 1;
  visibility: visible;
}

.cart-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  max-width: 420px;
  background: var(--surface-card);
  box-shadow: var(--shadow-drawer);
  z-index: 1100;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform var(--transition-spring);
}

.cart-backdrop.open .cart-drawer {
  transform: translateX(0);
}

.cart-header {
  padding: 20px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--surface-page);
}

.cart-title {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--text-heading);
  display: flex;
  align-items: center;
  gap: 8px;
}

.cart-close-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text-heading);
  padding: 6px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-fast);
}

.cart-close-btn:hover {
  background: var(--surface-sunken);
  color: var(--text-accent);
}

.cart-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.cart-item-card {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--surface-sunken-soft);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 12px;
}

.cart-item-img {
  width: 68px;
  height: 54px;
  object-fit: contain;
  background: var(--surface-media);
  border-radius: var(--radius-sm);
  padding: 4px;
  flex-shrink: 0;
}

.cart-item-details {
  flex: 1;
  min-width: 0;
}

.cart-item-title {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text-heading);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 4px;
}

.cart-item-price {
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--color-coral);
}

.cart-item-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
}

.qty-control {
  display: inline-flex;
  align-items: center;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  overflow: hidden;
}

.qty-btn {
  background: none;
  border: none;
  padding: 3px 9px;
  font-weight: bold;
  font-size: 0.9rem;
  color: var(--text-heading);
  cursor: pointer;
  transition: background var(--transition-fast);
}

.qty-btn:hover {
  background: var(--surface-sunken);
  color: var(--text-accent);
}

.qty-number {
  font-size: 0.84rem;
  font-weight: 700;
  padding: 0 6px;
  min-width: 24px;
  text-align: center;
}

.cart-item-remove {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px;
  font-size: 0.8rem;
  transition: color var(--transition-fast);
}

.cart-item-remove:hover {
  color: var(--text-accent);
}

.cart-empty-message {
  text-align: center;
  padding: 60px 10px;
  color: var(--text-muted);
}

.cart-empty-icon {
  width: 54px;
  height: 54px;
  color: var(--text-heading);
  opacity: 0.35;
  margin: 0 auto 12px;
}

/* Cart Footer */
.cart-footer {
  padding: 20px 24px;
  background: var(--surface-page);
  border-top: 1px solid var(--border-subtle);
}

.cart-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 14px;
}

.cart-total-label {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-heading);
}

.cart-total-value {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--color-coral);
}

.btn-checkout-wa {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background-color: var(--fill-wa);
  color: var(--color-white);
  font-size: 1rem;
  font-weight: 600;
  padding: 13px 20px;
  border-radius: var(--radius-full);
  border: none;
  cursor: pointer;
  text-decoration: none;
  box-shadow: var(--shadow-wa);
  transition: background-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
}

.btn-checkout-wa:hover {
  background-color: var(--fill-wa-hover);
  transform: translateY(-2px);
  box-shadow: var(--shadow-wa);
}

.btn-checkout-wa.disabled {
  opacity: 0.5;
  pointer-events: none;
  box-shadow: none;
}

/* Payment Terms Note */
.cart-terms-note {
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--text-muted);
  text-align: center;
  margin-top: 12px;
  padding: 8px 12px;
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong);
}

/* ==========================================================================
   TRUST & SPECS STRIP
   ========================================================================== */
.trust-section {
  padding: 50px 0;
  background-color: var(--surface-sunken);
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}

.trust-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

@media (min-width: 900px) {
  .trust-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
  }
}

.trust-item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

.trust-icon-box {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  background: var(--surface-raised);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-coral);
  box-shadow: var(--shadow-sm);
}

.trust-icon-svg {
  width: 26px;
  height: 26px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.trust-text-box h3 {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-heading);
  margin-bottom: 2px;
}

.trust-text-box p {
  font-size: 0.84rem;
  color: var(--text-muted);
  line-height: 1.4;
}

/* ==========================================================================
   QUICK VIEW / PRODUCT DETAIL MODAL
   ========================================================================== */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--surface-scrim-strong);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast), visibility var(--transition-fast);
}

.modal-backdrop.open {
  opacity: 1;
  visibility: visible;
}

.modal-card {
  background: var(--surface-card);
  border-radius: var(--radius-xl);
  max-width: 740px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  position: relative;
  box-shadow: var(--shadow-lg);
  transform: scale(0.95) translateY(10px);
  transition: transform var(--transition-spring);
}

.modal-backdrop.open .modal-card {
  transform: scale(1) translateY(0);
}

.modal-close-btn {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--surface-raised);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-heading);
  z-index: 10;
  transition: background var(--transition-fast), transform var(--transition-fast);
}

.modal-close-btn:hover {
  background: var(--color-coral);
  color: var(--color-white);
  transform: rotate(90deg);
}

.modal-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  padding: 0 0 4px;
}

@media (min-width: 720px) {
  .modal-body {
    grid-template-columns: 1fr 1.2fr;
    gap: 28px;
  }
}

.modal-media-col {
  background: var(--surface-media);
  padding: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
}

.modal-product-img {
  max-height: 260px;
  width: 100%;
  object-fit: contain;
}

.modal-info-col {
  padding: 24px;
  display: flex;
  flex-direction: column;
}

.modal-category-tag {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--color-coral);
  margin-bottom: 4px;
}

.modal-title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-heading);
  line-height: 1.2;
  margin-bottom: 10px;
}

.modal-price-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 16px;
}

.modal-price {
  font-family: var(--font-display);
  font-size: 1.8rem;
  font-weight: 700;
  color: var(--color-coral);
}

.modal-mrp {
  font-size: 0.95rem;
  color: var(--text-muted);
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}

.modal-discount {
  font-size: 0.78rem;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: var(--radius-sm);
  background: var(--discount-bg);
  color: var(--discount-text);
}

.modal-description {
  font-size: 0.92rem;
  color: var(--text-body);
  line-height: 1.5;
  margin-bottom: 18px;
}

.modal-specs-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 18px;
  font-size: 0.86rem;
}

.modal-specs-table tr {
  border-bottom: 1px solid var(--border-subtle);
}

.modal-specs-table td {
  padding: 6px 0;
}

.modal-specs-table td:first-child {
  font-weight: 600;
  color: var(--text-heading);
  width: 40%;
}

.modal-specs-table td:last-child {
  color: var(--text-muted);
}

.modal-features-list {
  list-style: none;
  margin-bottom: 22px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.modal-feature-item {
  font-size: 0.82rem;
  color: var(--text-heading);
  display: flex;
  align-items: center;
  gap: 6px;
}

.feature-check {
  color: var(--color-whatsapp);
  font-weight: bold;
}

/* Modal Footer & Action Button */
.modal-footer {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}

.modal-stock-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: var(--radius-full);
}

.modal-stock-badge .stock-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
}

.modal-stock-badge.in-stock {
  background-color: var(--status-in-bg);
  color: var(--status-in-text);
  border: 1px solid var(--status-in-border);
}

.modal-stock-badge.in-stock .stock-dot {
  background-color: var(--status-in-dot);
}

.modal-stock-badge.out-of-stock {
  background-color: var(--status-out-bg);
  color: var(--status-out-text);
  border: 1px solid var(--status-out-border);
}

.modal-stock-badge.out-of-stock .stock-dot {
  background-color: var(--status-out-dot);
}

.modal-action-wrapper {
  width: 100%;
}

.modal-primary-btn {
  width: 100%;
  min-height: 48px;
  padding: 13px 24px;
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-size: 0.98rem;
  font-weight: 600;
  border: none;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-align: center;
  transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast);
}

.modal-primary-btn:active {
  transform: scale(0.97);
  transition-duration: 100ms;
}

.modal-btn-icon {
  flex-shrink: 0;
}

.modal-primary-btn.btn-in-stock {
  background-color: var(--fill-action);
  color: var(--color-white);
  box-shadow: var(--shadow-action);
}

.modal-primary-btn.btn-in-stock:hover {
  background-color: var(--fill-action-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-glow-coral);
}

.modal-primary-btn.btn-wa-inquire {
  background-color: var(--fill-wa);
  color: var(--color-white);
  box-shadow: var(--shadow-wa);
}

.modal-primary-btn.btn-wa-inquire:hover {
  background-color: var(--fill-wa-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-wa);
}

.modal-secondary-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 0.84rem;
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 500;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast);
}

.modal-secondary-link:hover {
  color: #128C7E;
}

.modal-secondary-link svg {
  color: #25D366;
  flex-shrink: 0;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer {
  background-color: var(--surface-footer);
  color: var(--text-footer);
  padding: 60px 0 30px;
  position: relative;
}

.footer-top {
  display: grid;
  grid-template-columns: 1fr;
  gap: 36px;
  margin-bottom: 40px;
}

@media (min-width: 768px) {
  .footer-top {
    grid-template-columns: 1.5fr 1fr 1fr;
  }
}

.footer-brand {
  max-width: 360px;
}

.footer-logo {
  height: 44px;
  width: auto;
  border-radius: var(--radius-sm);
  background: #FFFFFF;
  padding: 4px;
  margin-bottom: 14px;
}

.footer-tagline {
  font-size: 0.95rem;
  color: var(--text-footer-muted);
  margin-bottom: 12px;
}

.footer-warm-quote {
  font-size: 0.85rem;
  color: var(--color-yellow);
  font-style: italic;
}

.footer-heading {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text-footer);
  margin-bottom: 16px;
}

.footer-links {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.footer-links a {
  font-size: 0.9rem;
  color: var(--text-footer-muted);
  transition: color var(--transition-fast);
}

.footer-links a:hover {
  color: var(--color-yellow);
}

.footer-bottom {
  border-top: 1px solid var(--border-footer);
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  font-size: 0.84rem;
  color: var(--text-footer-faint);
  text-align: center;
}

@media (min-width: 600px) {
  .footer-bottom {
    flex-direction: row;
    text-align: left;
  }
}

/* ==========================================================================
   FLOATING CART / WHATSAPP PILL
   ========================================================================== */
.floating-actions-bar {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 10px;
}

.floating-cart-btn {
  background-color: var(--color-navy);
  color: var(--color-white);
  font-weight: 600;
  font-size: 0.92rem;
  padding: 12px 18px;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  gap: 8px;
  border: none;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition: transform var(--transition-spring), box-shadow var(--transition-fast);
}

.floating-cart-btn:hover {
  transform: translateY(-3px) scale(1.03);
  box-shadow: var(--shadow-lg);
}

.floating-wa-btn {
  background-color: var(--fill-wa);
  color: var(--color-white);
  font-weight: 600;
  font-size: 0.92rem;
  padding: 12px 18px;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: var(--shadow-wa);
  transition: transform var(--transition-spring), box-shadow var(--transition-fast), background-color var(--transition-fast);
}

.floating-wa-btn:hover {
  background-color: var(--fill-wa-hover);
  transform: translateY(-3px) scale(1.03);
  box-shadow: var(--shadow-lg);
}

@media (max-width: 540px) {
  .floating-wa-text, .floating-cart-text {
    display: none;
  }
  .floating-cart-btn, .floating-wa-btn {
    padding: 14px;
    border-radius: 50%;
  }
}

/* ==========================================================================
   DARK MODE TOGGLE (HEADER)
   A pill-shaped switch. The thumb shows the mode that is CURRENTLY ACTIVE
   (sun while light, moon while dark) and the track carries both options dim
   behind it, so the thumb's position and its icon always tell the same story.
   An earlier version showed the destination instead, which read ambiguously:
   a moon on a light page could equally mean "you are in dark mode".

   The travel below deliberately subtracts the border as well as the padding.
   Omitting it parked the thumb 4px from the left edge but only 2px from the
   right, which is small enough to look like a rendering bug rather than a
   design.
   ========================================================================== */
.theme-toggle {
  --toggle-w: 60px;
  --toggle-h: 32px;
  --toggle-pad: 3px;
  --toggle-border: 1px;
  --thumb: calc(var(--toggle-h) - var(--toggle-border) * 2 - var(--toggle-pad) * 2);
  /* Distance the thumb travels so its gap is identical at both ends. */
  --thumb-travel: calc(
    var(--toggle-w) - var(--toggle-border) * 2 - var(--toggle-pad) * 2 - var(--thumb)
  );

  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  line-height: 0;
  border-radius: var(--radius-full);
}

.theme-toggle-track {
  position: relative;
  display: block;
  width: var(--toggle-w);
  height: var(--toggle-h);
  border-radius: var(--radius-full);
  /* The old track was --surface-sunken on the header's own near-white: 1.12:1,
     which left a white thumb apparently floating on nothing. These two carry
     the switch's outline instead, and both clear the 3:1 that WCAG 1.4.11 asks
     of a control's boundary. */
  background: var(--toggle-track-bg);
  border: var(--toggle-border) solid var(--toggle-track-border);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.10);
  transition: background-color var(--transition-normal), border-color var(--transition-normal);
}

/* The two destinations, dim, sitting under the thumb. */
.theme-track-icon {
  position: absolute;
  top: 50%;
  width: 13px;
  height: 13px;
  margin-top: -6.5px;
  color: var(--toggle-track-icon);
  transition: color var(--transition-normal);
  pointer-events: none;
}
.theme-track-icon--sun  { left: 6px; }
.theme-track-icon--moon { right: 6px; }

.theme-toggle:hover .theme-toggle-track {
  border-color: var(--color-coral);
}

.theme-toggle-thumb {
  position: absolute;
  z-index: 1;
  top: var(--toggle-pad);
  left: var(--toggle-pad);
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
  background: var(--surface-raised);
  color: var(--color-navy);
  /* The hairline ring is what separates the knob from the track; the drop
     shadow alone washes out against a pale track. */
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18), 0 0 0 1px var(--toggle-thumb-ring);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--transition-spring), background-color var(--transition-normal), color var(--transition-normal);
}

.theme-toggle:active .theme-toggle-thumb {
  transform: scale(0.92);
  transition-duration: 100ms;
}

.theme-icon {
  position: absolute;
  width: 15px;
  height: 15px;
  transition: opacity var(--transition-normal), transform var(--transition-normal);
}

/* Light mode: thumb parked left over the sun, sun showing on the thumb. */
.theme-icon--sun  { opacity: 1; transform: rotate(0deg) scale(1); }
.theme-icon--moon { opacity: 0; transform: rotate(90deg) scale(0.5); }

/* Dark mode: thumb slides right over the moon, moon showing on the thumb. */
:root[data-theme="dark"] .theme-toggle-thumb {
  transform: translateX(var(--thumb-travel));
  background: var(--color-yellow);
  color: #12141C;
}
:root[data-theme="dark"] .theme-toggle:active .theme-toggle-thumb {
  transform: translateX(var(--thumb-travel)) scale(0.92);
}
:root[data-theme="dark"] .theme-icon--sun  { opacity: 0; transform: rotate(-90deg) scale(0.5); }
:root[data-theme="dark"] .theme-icon--moon { opacity: 1; transform: rotate(0deg) scale(1); }

/* Keep the toggle usable on small screens where the nav menu is hidden. */
@media (max-width: 400px) {
  .theme-toggle { --toggle-w: 52px; --toggle-h: 29px; }
}

/* ==========================================================================
   EMPTY STATES (rendered from js/app.js)
   ========================================================================== */
.empty-state-title {
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--text-heading);
  margin-bottom: 6px;
}

.empty-state-text {
  color: var(--text-muted);
  font-size: 0.92rem;
  margin-bottom: 16px;
}

.cart-empty-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-heading);
  margin-bottom: 4px;
}

.cart-empty-text {
  font-size: 0.86rem;
  color: var(--text-muted);
}

/* Out-of-stock product thumbnails read as "greyed out" in both themes. */
.card-img--dimmed {
  opacity: 0.5;
  filter: grayscale(0.35);
}

/* ==========================================================================
   FOOTER TEXT HELPERS
   ========================================================================== */
.footer-note {
  font-size: 0.88rem;
  line-height: 1.6;
  margin-bottom: 14px;
  color: var(--text-footer-muted);
}

.footer-bottom-aside {
  opacity: 0.7;
}

/* ==========================================================================
   PREFERS REDUCED MOTION
   Collapses the scroll-driven hero into a single static composition. Colors
   are untouched, so a theme swap under reduced motion is still a clean cut
   with no half-transitioned states.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Collapse the 320vh scroll track to a single screen: no scrubbing, but the
     composition (and therefore all the spacing that keeps the CTA clear of
     the floating pills) is identical to the scrubbed version. A definite height is required here — `height: auto` would stop the
     content wrapper's `height: 100%` from resolving and collapse the layout. */
  .hero-scroll-container {
    height: calc(100vh - var(--header-height)) !important;
    min-height: 560px;
  }

  .hero-sticky-viewport {
    position: relative !important;
    top: auto !important;
    height: 100% !important;
  }

  /* The canvas still paints — it just holds one chosen frame and never
     scrubs (js/app.js draws REDUCED_MOTION_FRAME and attaches no scroll
     listener). Fade it in without the transition, so there is no flash. */
  .hero-frame-canvas {
    opacity: 1 !important;
    transition: none !important;
  }

  .hero-loader-spinner {
    animation: none !important;
    border-top-color: rgba(255, 255, 255, 0.22) !important;
  }

  .hero-beat-indicators {
    display: none !important;
  }

  .scroll-mouse-dot {
    animation: none !important;
  }
}

/* ==========================================================================
   THEME TRANSITION
   A short, explicit cross-fade on the properties that actually change when
   the theme flips. Scoped to a class that js/app.js adds for the duration of
   the swap only — so it never slows down ordinary hover/press feedback, and
   never fights the scroll-driven hero transforms mid-scrub.
   ========================================================================== */
.theme-transition,
.theme-transition *,
.theme-transition *::before,
.theme-transition *::after {
  transition: background-color 220ms ease, border-color 220ms ease,
              color 220ms ease, fill 220ms ease, stroke 220ms ease !important;
  transition-delay: 0ms !important;
}

/* Users who asked for less motion get an instant cut, not a fade. */
@media (prefers-reduced-motion: reduce) {
  .theme-transition,
  .theme-transition *,
  .theme-transition *::before,
  .theme-transition *::after {
    transition: none !important;
  }
}

/* ==========================================================================
   MOTION

   Added deliberately and sparingly. Every rule below animates only transform
   and opacity, stays under 300ms (Emil Kowalski's UI budget), and uses the
   project's existing easing vocabulary rather than inventing a parallel one.
   High-frequency controls are intentionally NOT animated.
   ========================================================================== */

/* --- 1. Catalog re-render ------------------------------------------------
   Filtering, searching or sorting replaces the grid's innerHTML, so cards
   teleport. A short rise+fade bridges the swap and makes it legible that the
   list changed. Staggered per card, capped so a 12-card grid still finishes
   well inside a beat. Purely decorative: cards are interactive immediately. */
@keyframes card-enter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.product-grid .product-card {
  animation: card-enter 260ms cubic-bezier(0.23, 1, 0.32, 1) both;
  animation-delay: calc(var(--card-index, 0) * 28ms);
}

/* --- 2. Section reveal ---------------------------------------------------
   Seen once per visit, so this is the delight budget, not a per-interaction
   cost. .is-visible is added by an IntersectionObserver in js/app.js; the
   observer marks everything visible immediately if the API is missing, so
   content can never be stranded hidden. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 280ms cubic-bezier(0.23, 1, 0.32, 1),
              transform 280ms cubic-bezier(0.23, 1, 0.32, 1);
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* --- 3. Press feedback ---------------------------------------------------
   Controls that had hover states but no press response. 140ms is below the
   press-feedback ceiling so it reads as tactile, not laggy. */
.floating-cart-btn:active,
.floating-wa-btn:active,
.quick-view-trigger:active,
.modal-close-btn:active,
.cart-close-btn:active,
.theme-toggle:active {
  transform: scale(0.95);
  transition-duration: 140ms;
}

/* Quantity steppers are pressed repeatedly inside one session, so they get a
   near-imperceptible response rather than the full press scale. */
.qty-btn:active {
  transform: scale(0.90);
  transition-duration: 100ms;
}

/* --- Reduced motion: gentler, not zero ----------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .product-grid .product-card { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   TOUCH TARGETS

   On a coarse pointer, controls need ~44px of hittable area (WCAG 2.5.5 AAA /
   Apple HIG). Several controls were sized for a mouse: the theme toggle at
   32px, filter pills at ~31px, the sort select, the quick-view trigger and the
   card buttons. Padding is raised rather than font size so the visual design is
   unchanged on desktop.
   ========================================================================== */
@media (pointer: coarse) {
  .filter-pill-btn,
  .sort-select {
    min-height: 44px;
    padding-top: 10px;
    padding-bottom: 10px;
  }

  .btn-add-cart,
  .btn-out-of-stock {
    min-height: 46px;
  }

  .quick-view-trigger {
    min-height: 40px;
    padding: 9px 14px;
  }

  .qty-btn {
    min-width: 40px;
    min-height: 40px;
  }

  /* Footer category links are a navigation list, not prose, so the WCAG 2.5.5
     inline-link exception does not apply — they get a real target height. */
  .footer-links a,
  .modal-secondary-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .cart-item-remove,
  .cart-close-btn,
  .modal-close-btn {
    min-width: 44px;
    min-height: 44px;
  }

  /* The toggle keeps its 60x32 pill look, but the button around it takes the
     full target area via padding so the hit region is honest. */
  .theme-toggle {
    padding: 6px;
    margin: -6px;
  }
}

/* ==========================================================================
   HERO SUBJECT — SMALL SCREENS

   On a phone the plate is width-bound, so the vehicle rendered small AND the
   CTA lane landed across its middle. Widening past the viewport (the empty
   plate edges bleed off screen) and lifting the anchor fixes both.
   ========================================================================== */
@media (max-width: 700px) {
  .hero-sticky-viewport {
    --hero-subject-width: 1.32;
    --hero-subject-max-h: 0.46;
    --hero-subject-bottom: 0.30;
  }
}

/* Tablets fell through to the desktop values, where the CTA lane again landed
   across the vehicle. */
@media (min-width: 701px) and (max-width: 1024px) {
  .hero-sticky-viewport {
    --hero-subject-width: 0.92;
    --hero-subject-max-h: 0.50;
    --hero-subject-bottom: 0.25;
  }
}

@media (max-width: 700px) and (orientation: landscape) {
  /* Landscape phones are very short; give the subject less height and keep the
     copy from colliding with it. */
  .hero-sticky-viewport {
    --hero-subject-width: 0.80;
    --hero-subject-max-h: 0.40;
    --hero-subject-bottom: 0.34;
  }
}

/* On wide screens the CTA is centred and the Cart/Chat pills are anchored far
   right, so they cannot collide horizontally. The full clearance is only needed
   where the two share a column. */
@media (min-width: 1200px) {
  :root { --floating-bar-clearance: 40px; }
}

/* Short desktop viewports (laptops at 1280x800) have the same width but far
   less height, so the subject has to give some back or it runs into the copy. */
@media (min-width: 1025px) and (max-height: 860px) {
  .hero-sticky-viewport { --hero-subject-max-h: 0.39; }
}

/* ==========================================================================
   OUT OF STOCK

   The product stays in the grid — hiding it loses a browsing customer who
   might have waited. The image dims, the badge states the situation plainly,
   and the buy action becomes a restock request so demand is still captured
   instead of being dropped on the floor.
   ========================================================================== */
.btn-notify-me {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background-color: transparent;
  color: var(--text-heading);
  font-size: 0.9rem;
  font-weight: 600;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1.5px solid var(--border-strong);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
}

.btn-notify-me:hover {
  background-color: var(--surface-raised);
  border-color: var(--text-accent);
  color: var(--text-accent);
  transform: translateY(-1px);
}

.btn-notify-me:active {
  transform: scale(0.96);
  transition-duration: 100ms;
}

/* Out-of-stock cards recede so in-stock ones lead the eye. */
.product-card--oos .card-media {
  opacity: 0.82;
}

/* ==========================================================================
   FEATURED PRODUCTS

   Featured=TRUE in the sheet lifts a product to the top under the default
   "Featured First" sort. A quiet accent ring makes the promotion visible —
   without it the visitor only sees an ordering they cannot perceive. Kept
   deliberately subtle so it never competes with the badge.
   ========================================================================== */
.product-card--featured {
  border-color: var(--color-yellow);
  box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--color-yellow);
}

.product-card--featured:hover {
  border-color: var(--color-yellow);
}
