/* ==========================================================================
   ShopFront — Design Tokens
   --------------------------------------------------------------------------
   Three-layer token architecture:

     1. PRIMITIVES  raw, unopinionated values (ramps, scales). Rarely change.
     2. SEMANTIC    purpose-based aliases. This is the theming seam.
     3. COMPONENT   per-component knobs built on semantic tokens.

   Rules of engagement:
     - Components never reference primitives directly.
     - Dark mode overrides the SEMANTIC layer only.
     - Colour ramps are authored in OKLCH so lightness steps are
       perceptually even and hue stays stable across the ramp.
   ========================================================================== */


/* ==========================================================================
   TYPEFACE
   ========================================================================== */

/* ---- Yekan Bakh FaNum (primary) --------------------------------------
   Eight real weights, so nothing is synthesised. Written here rather than
   importing the vendor's fonts/yekanbakh/fontiran.css, which has four
   faults: its 800/900/950 rules point at filenames containing spaces
   ("Yekan Bakh FaNum-ExtraBold.woff") that do not exist on disk, its Thin
   rule lowercases a capitalised filename (404s on a case-sensitive host),
   it lists woff before woff2 so every browser fetches the larger file, and
   it sets no font-display, so text stays invisible while loading.

   size-adjust is deliberate: Yekan Bakh's x-height is 0.450em against
   Dana's 0.500em, so at an identical font-size it renders about 10%
   smaller. 110% restores the intended optical size without disturbing a
   single value in the type scale. Browsers without size-adjust (Safari
   ≤16) just get slightly smaller text — it degrades, it does not break.

   The family has no 500; see --weight-medium in the scale below.

   Full coverage of every codepoint this page renders, Latin included,
   plus the separators Intl.NumberFormat("fa-IR") emits: ٪ U+066A,
   ٬ U+066C, ٫ U+066B, and ZWNJ U+200C. */

@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-Thin.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-Thin.woff") format("woff");
  font-weight: 100;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-Light.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-Light.woff") format("woff");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
/* 400 500: the family ships no Medium, so a 500 request is pinned to
   Regular rather than left to the browser's nearest-match rules. */
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-Regular.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-Regular.woff") format("woff");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-SemiBold.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-SemiBold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-Bold.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-Bold.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-ExtraBold.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-ExtraBold.woff") format("woff");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-Black.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-Black.woff") format("woff");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}
@font-face {
  font-family: "Yekan Bakh FaNum";
  src: url("fonts/yekanbakh/fonts/woff2/YekanBakhFaNum-ExtraBlack.woff2") format("woff2"),
       url("fonts/yekanbakh/fonts/woff/YekanBakhFaNum-ExtraBlack.woff") format("woff");
  font-weight: 950;
  font-style: normal;
  font-display: swap;
  size-adjust: 110%;
}

/* ---- Dana (fallback) -------------------------------------------------- */

@font-face {
  font-family: "Dana";
  src: url("fonts/Dana/Dana-Regular.woff2") format("woff2");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Dana";
  src: url("fonts/Dana/Dana-DemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Dana";
  src: url("fonts/Dana/Dana-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Dana";
  src: url("fonts/Dana/Dana-ExtraBold.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Dana";
  src: url("fonts/Dana/Dana-Black.woff2") format("woff2");
  font-weight: 900 950;
  font-style: normal;
  font-display: swap;
}

/* ---- Vazirmatn (fallback) --------------------------------------------
   Kept as the second stack entry purely as a safety net for the Persian
   text if Dana fails to load — Tahoma is a poor substitute for it. Note
   these particular files are an Arabic-only subset with no Latin glyphs
   at all, so Latin falls through to the next entry per character. */

@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/vazirmatn-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/vazirmatn-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/vazirmatn-700.woff2") format("woff2");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/vazirmatn-800.woff2") format("woff2");
  font-weight: 800 900;
  font-style: normal;
  font-display: swap;
}


/* ==========================================================================
   LAYER 1 — PRIMITIVES
   ========================================================================== */

:root {

  /* ---- Colour · Brand (teal, hue 167) ------------------------------------
     Derived from the logo. assets/logo.svg is drawn in #037c5c, which is
     exactly oklch(0.521 0.106 167) — so step 600 IS the logo colour, not an
     approximation of it, and the mark never sits beside a near-miss of
     itself. It measures 5.2:1 against white, so it carries white body text
     unaided.

     600 is also the lightest step that clears 4.5:1 with white: steps 500
     and lighter must never carry small white text. See the gradient notes
     in the semantic layer. */
  --teal-50:  oklch(0.972 0.018 167);
  --teal-100: oklch(0.943 0.040 167);
  --teal-200: oklch(0.888 0.068 167);
  --teal-300: oklch(0.808 0.092 167);
  --teal-400: oklch(0.706 0.104 167);
  --teal-500: oklch(0.600 0.108 167);
  --teal-600: oklch(0.521 0.106 167);  /* #037c5c — the logo */
  --teal-700: oklch(0.440 0.092 167);
  --teal-800: oklch(0.378 0.079 167);
  --teal-900: oklch(0.322 0.066 167);
  --teal-950: oklch(0.232 0.046 167);

  /* ---- Colour · Red ------------------------------------------------------
     No longer the brand. Retained solely for --danger: an error state must
     stay red whatever the brand happens to be. */
  --red-50:  oklch(0.972 0.013 22);
  --red-100: oklch(0.941 0.031 24);
  --red-200: oklch(0.888 0.062 25);
  --red-300: oklch(0.809 0.108 26);
  --red-400: oklch(0.704 0.181 27);
  --red-500: oklch(0.632 0.215 27);
  --red-600: oklch(0.562 0.216 27.2);
  --red-700: oklch(0.502 0.198 27.5);
  --red-800: oklch(0.451 0.178 27.8);
  --red-900: oklch(0.392 0.146 28);
  --red-950: oklch(0.262 0.097 28);

  /* ---- Colour · Neutral (cool slate, hue 260) ---------------------------
     Blue-tinted, which keeps it on the cool side of the teal brand and the
     navy accent rather than fighting either. Chroma stays low enough
     (0.002–0.045) that the hue barely reads as colour. */
  --slate-0:    oklch(1 0 0);
  --slate-25:   oklch(0.990 0.002 260);
  --slate-50:   oklch(0.979 0.003 260);
  --slate-100:  oklch(0.961 0.005 260);
  --slate-150:  oklch(0.936 0.006 260);
  --slate-200:  oklch(0.906 0.008 260);
  --slate-300:  oklch(0.854 0.011 260);
  --slate-400:  oklch(0.718 0.017 260);
  --slate-500:  oklch(0.604 0.022 260);
  /* Half-step, and the lightest neutral that still clears 4.5:1 on white
     (4.7:1). It exists so --fg-subtle has somewhere accessible to point;
     slate-500 measures only 3.9:1 and is for borders and graphics. */
  --slate-550:  oklch(0.556 0.022 260);
  --slate-600:  oklch(0.506 0.027 260);
  --slate-700:  oklch(0.418 0.032 261);
  --slate-800:  oklch(0.328 0.038 262);
  --slate-900:  oklch(0.243 0.045 262);
  --slate-950:  oklch(0.184 0.040 263);
  --slate-1000: oklch(0.139 0.034 263);

  /* ---- Colour · Accent (navy, hue 253) ---------------------------------- */
  --navy-50:  oklch(0.968 0.014 245);
  --navy-100: oklch(0.930 0.030 246);
  --navy-200: oklch(0.876 0.053 248);
  --navy-300: oklch(0.790 0.080 250);
  --navy-400: oklch(0.652 0.109 252);
  --navy-500: oklch(0.530 0.118 253);
  --navy-600: oklch(0.452 0.111 253);
  --navy-700: oklch(0.385 0.096 255);
  --navy-800: oklch(0.316 0.079 258);
  --navy-900: oklch(0.262 0.064 260);
  --navy-950: oklch(0.196 0.048 262);

  /* ---- Colour · Support ------------------------------------------------- */
  /* Hue 140, not 152. The brand is now teal at hue 167; a success green at
     152 sits only 15° away and reads as "brand colour" rather than as a
     status. 140 is a distinctly yellower green, 27° clear of the brand. */
  --green-50:  oklch(0.966 0.028 140);
  --green-100: oklch(0.928 0.060 140);
  --green-400: oklch(0.724 0.165 140);
  --green-500: oklch(0.640 0.150 140);
  --green-600: oklch(0.560 0.135 140);
  --green-700: oklch(0.470 0.112 141);

  --amber-50:  oklch(0.976 0.028 85);
  --amber-100: oklch(0.945 0.065 82);
  --amber-400: oklch(0.822 0.148 78);
  --amber-500: oklch(0.760 0.152 70);
  --amber-600: oklch(0.682 0.148 62);
  --amber-700: oklch(0.562 0.128 55);

  /* Monogram plates — fixed, not themeable. Each is dark enough that a white
     glyph on it clears 3:1 as a graphical object. They are never used as
     text colour: at these lightnesses they fail 4.5:1 on either theme's
     surface, so the label beside the plate renders in --fg-default instead.
     Named for the hue, so which content sits on which plate stays free. */
  --brandmark-amber:    oklch(0.652 0.188 45);
  --brandmark-crimson:  oklch(0.505 0.196 358);
  --brandmark-graphite: oklch(0.548 0.010 260);
  --brandmark-indigo:   oklch(0.430 0.120 258);

  /* ---- Space · 4px base grid ------------------------------------------- */
  --space-0:    0rem;
  --space-px:   0.0625rem;  /*  1 */
  --space-0-5:  0.125rem;   /*  2 */
  --space-1:    0.25rem;    /*  4 */
  --space-1-5:  0.375rem;   /*  6 */
  --space-2:    0.5rem;     /*  8 */
  --space-2-5:  0.625rem;   /* 10 */
  --space-3:    0.75rem;    /* 12 */
  --space-3-5:  0.875rem;   /* 14 */
  --space-4:    1rem;       /* 16 */
  --space-5:    1.25rem;    /* 20 */
  --space-6:    1.5rem;     /* 24 */
  --space-7:    1.75rem;    /* 28 */
  --space-8:    2rem;       /* 32 */
  --space-9:    2.25rem;    /* 36 */
  --space-10:   2.5rem;     /* 40 */
  --space-11:   2.75rem;    /* 44 */
  --space-12:   3rem;       /* 48 */
  --space-14:   3.5rem;     /* 56 */
  --space-16:   4rem;       /* 64 */
  --space-20:   5rem;       /* 80 */
  --space-24:   6rem;       /* 96 */
  --space-28:   7rem;       /* 112 */
  --space-32:   8rem;       /* 128 */

  /* ---- Typography · families ------------------------------------------- */
  --font-sans: "Yekan Bakh FaNum", "Dana", "Vazirmatn", "Segoe UI", Tahoma, Arial, system-ui, sans-serif;

  /* ---- Typography · fluid size scale -----------------------------------
     Base is 14px: the comfortable reading size for Vazirmatn UI text,
     which carries a larger apparent x-height than Latin faces at the
     same nominal size. */
  --text-2xs: 0.6875rem;  /* 11 */
  --text-xs:  0.75rem;    /* 12 */
  --text-sm:  0.8125rem;  /* 13 */
  --text-md:  0.875rem;   /* 14 — base */
  --text-lg:  0.9375rem;  /* 15 */
  --text-xl:  1rem;       /* 16 */
  --text-2xl: 1.125rem;   /* 18 */
  --text-3xl: clamp(1.25rem,  1.16rem + 0.35vw, 1.375rem);   /* 20 → 22 */
  --text-4xl: clamp(1.375rem, 1.24rem + 0.55vw, 1.625rem);   /* 22 → 26 */
  --text-5xl: clamp(1.625rem, 1.36rem + 1.05vw, 2.125rem);   /* 26 → 34 */
  --text-6xl: clamp(1.875rem, 1.42rem + 1.85vw, 2.75rem);    /* 30 → 44 */

  /* ---- Typography · weights ------------------------------------------- */
  --weight-normal:    400;
  /* Yekan Bakh has no Medium. 500 is pinned to Regular in the @font-face
     above, so this step renders identically to --weight-normal; reach for
     --weight-semibold when text genuinely needs to step up. */
  --weight-medium:    500;
  --weight-semibold:  600;
  --weight-bold:      700;
  --weight-extrabold: 800;
  --weight-black:     900;

  /* ---- Typography · line height ---------------------------------------
     Persian needs more leading than Latin: ascenders/descenders and
     diacritics collide below ~1.5 for body copy. */
  --leading-none:    1;
  --leading-tight:   1.25;
  --leading-snug:    1.45;
  --leading-normal:  1.65;
  --leading-relaxed: 1.85;

  /* ---- Typography · tracking ------------------------------------------
     Persian is a connected script: negative tracking shortens the joining
     stroke between letters, so nothing here goes far negative. (The logo
     is artwork now, not set type, so it needs no tracking token at all.) */
  --tracking-tight:  -0.01em;
  --tracking-normal: 0em;
  --tracking-wide:   0.02em;

  /* ---- Radius ---------------------------------------------------------- */
  --radius-none:   0;
  --radius-xs:     0.375rem;  /*  6 */
  --radius-sm:     0.5rem;    /*  8 */
  --radius-md:     0.75rem;   /* 12 */
  --radius-lg:     1rem;      /* 16 */
  --radius-xl:     1.25rem;   /* 20 */
  --radius-2xl:    1.5rem;    /* 24 */
  --radius-3xl:    1.75rem;   /* 28 */
  --radius-4xl:    2rem;      /* 32 */
  --radius-pill:   62.4375rem;
  --radius-circle: 50%;

  /* ---- Elevation ------------------------------------------------------
     The design is FLAT. Surfaces are told apart by border and tone, not by
     shade, so the whole ramp resolves to nothing. The call sites are left
     in place on purpose: this block is the single lever, and putting
     elevation back is one edit here rather than sixty across styles.css.

     Elevation survives in exactly one situation — a layer that floats over
     arbitrary page content and has to stay legible against whatever
     happens to be beneath it. That is the search panel, the category
     menu, the toast, the skip link and the drawer, and nothing else. They
     use --shadow-overlay* below. If you find yourself reaching for one on
     a card or a button, the answer is a border. */
  --shadow-none: 0 0 #0000;

  --shadow-xs:  var(--shadow-none);
  --shadow-sm:  var(--shadow-none);
  --shadow-md:  var(--shadow-none);
  --shadow-lg:  var(--shadow-none);
  --shadow-xl:  var(--shadow-none);
  --shadow-2xl: var(--shadow-none);

  --shadow-brand-sm:  var(--shadow-none);
  --shadow-brand-md:  var(--shadow-none);
  --shadow-brand-lg:  var(--shadow-none);
  --shadow-accent-md: var(--shadow-none);

  --shadow-inset-top: inset 0 1px 0 oklch(1 0 0 / 0.18);

  /* Overlays only — see the note above. Two layers, tight contact plus
     wide ambient, tinted with the neutral hue so they read as shade
     rather than grey smudge. */
  --shadow-overlay:
    0 20px 40px -12px oklch(0.243 0.045 262 / 0.14),
    0 8px 16px -8px oklch(0.243 0.045 262 / 0.08);
  --shadow-overlay-lg:
    0 32px 64px -16px oklch(0.243 0.045 262 / 0.20),
    0 12px 24px -12px oklch(0.243 0.045 262 / 0.10);

  /* Side-drawer shadow. Offset is physical (-x): the drawer enters from
     the right in this RTL document, so its shade falls to the left. */
  --shadow-drawer:
    -1.25rem 0 3rem -0.5rem oklch(0.243 0.045 262 / 0.20),
    -0.375rem 0 1rem -0.375rem oklch(0.243 0.045 262 / 0.12);

  /* ---- Motion ---------------------------------------------------------- */
  --duration-instant: 80ms;
  --duration-fast:    140ms;
  --duration-base:    220ms;
  --duration-slow:    340ms;
  --duration-slower:  520ms;

  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:      cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:   cubic-bezier(0.34, 1.4, 0.64, 1);

  /* ---- Border width ---------------------------------------------------- */
  --border-hairline: 1px;
  --border-thin:     1.5px;
  --border-thick:    2px;
  --border-heavy:    3px;

  /* ---- Z-index scale --------------------------------------------------- */
  --z-below:            -1;
  --z-base:              0;
  --z-raised:           10;
  --z-sticky:          100;
  --z-dropdown:        200;
  --z-drawer-backdrop: 300;
  --z-drawer:          400;
  --z-modal:           500;
  --z-toast:           600;
  --z-skip-link:       700;
  /* Above everything, including the skip link: while the intro curtain is up
     there is nothing behind it to skip to. */
  --z-preloader:       800;

  /* ---- Layout ----------------------------------------------------------
     1440, not the 1280 this design shipped with. At 1280 the content used
     only 67% of a 1920 screen and 50% of a 2560 one, which reads as a
     narrow column stranded between wide dead gutters. 1440 keeps the
     four-column product grid at a comfortable ~340px per card; going wider
     would want a fifth column rather than fatter cards.
     This is the single knob for overall page width. */
  --container-max:   1440px;
  --container-inline: clamp(1rem, 0.5rem + 2vw, 2.5rem);
  --icon-sm:  1rem;
  --icon-md:  1.25rem;
  --icon-lg:  1.5rem;
  --icon-xl:  2rem;
  --icon-2xl: 2.625rem;

  /* Minimum interactive target — WCAG 2.2 AA is 24px, this is the
     comfortable touch value. */
  --tap-min: 2.75rem; /* 44 */
}


/* ==========================================================================
   LAYER 2 — SEMANTIC  (light theme)
   --------------------------------------------------------------------------
   This is the only layer a theme overrides.
   ========================================================================== */

:root {
  color-scheme: light;

  /* ---- Surfaces -------------------------------------------------------- */
  --bg-page:        var(--slate-50);
  --bg-shell:       var(--slate-25);
  --bg-surface:     var(--slate-0);
  --bg-surface-2:   var(--slate-50);
  --bg-surface-3:   var(--slate-100);
  --bg-inset:       var(--slate-100);
  --bg-inverse:     var(--slate-900);
  --bg-brand-subtle: var(--teal-50);
  --bg-accent-subtle: var(--navy-50);

  /* ---- Foreground ------------------------------------------------------
     4 steps only. Everything that used to be one of ~20 near-identical
     greys maps onto one of these. */
  /* Contrast ratios are measured against --bg-surface. All four clear AA
     for body text, so any of them is safe on a card. */
  --fg-default: var(--slate-900);   /* headings, primary copy   14.3:1 */
  --fg-body:    var(--slate-700);   /*  body copy                8.4:1 */
  --fg-muted:   var(--slate-600);   /*  secondary, labels        5.9:1 */
  --fg-subtle:  var(--slate-550);   /*  metadata, placeholders   4.7:1 */
  --fg-on-brand:   var(--slate-0);
  --fg-on-accent:  var(--slate-0);
  --fg-on-inverse: var(--slate-50);

  /* ---- Borders --------------------------------------------------------- */
  --border-subtle:  var(--slate-150);
  --border-default: var(--slate-200);
  --border-strong:  var(--slate-300);
  --border-brand:   var(--teal-200);
  --border-inverse: oklch(1 0 0 / 0.16);

  /* ---- Brand ----------------------------------------------------------- */
  --brand:         var(--teal-600);
  --brand-hover:   var(--teal-700);
  --brand-active:  var(--teal-800);
  --brand-bright:  var(--teal-500);
  --brand-text:    var(--teal-700);  /* brand teal as text on white: 7.4:1 */

  /* ---- Accent ---------------------------------------------------------- */
  --accent:        var(--navy-800);
  --accent-hover:  var(--navy-900);
  --accent-text:   var(--navy-700);

  /* ---- Status ---------------------------------------------------------- */
  --success:        var(--green-600);
  --success-subtle: var(--green-50);
  --success-text:   var(--green-700);
  --warning:        var(--amber-500);
  --warning-subtle: var(--amber-50);
  --warning-text:   var(--amber-700);
  --danger:         var(--red-600);
  --danger-subtle:  var(--red-50);
  --danger-text:    var(--red-700);
  --rating:         var(--amber-400);

  /* ---- Gradients ------------------------------------------------------
     The design leans on gradients heavily; they belong in the system
     rather than being re-invented per component. */
  /* Every stop is red-600 or darker. These gradients all carry white body
     text — the promo bar, the hero slides, the deals panel, the footer — so
     no stop may be lighter than the 4.9:1 step. Reintroducing red-500 or
     red-400 here silently drops that text to ~4.0:1. */
  --gradient-brand: linear-gradient(135deg, var(--teal-600) 0%, var(--teal-700) 55%, var(--teal-800) 100%);
  --gradient-brand-flat: linear-gradient(90deg, var(--teal-600) 0%, var(--teal-700) 52%, var(--teal-800) 100%);
  --gradient-brand-vivid: linear-gradient(145deg, var(--teal-600), var(--teal-800));
  --gradient-accent: linear-gradient(145deg, var(--navy-700), var(--navy-900));
  --gradient-skeleton: linear-gradient(
      100deg,
      var(--bg-surface-3) 0%,
      var(--bg-surface-2) 40%,
      var(--bg-surface-3) 80%);

  /* Faint glow that stops large flat fills from looking dead. Anchored at
     25% — over the slide's artwork, not its copy: a white glow behind
     white text costs about 0.4:1 of contrast. */
  --glow-brand: radial-gradient(circle at 25% 30%, oklch(1 0 0 / 0.10), transparent 34%);

  /* ---- Overlay & focus ------------------------------------------------- */
  --overlay: oklch(0.184 0.040 263 / 0.42);
  --ring-width: 3px;
  --ring-offset: 2px;
  --ring-color: oklch(0.521 0.106 167 / 0.50);
  --ring-color-inverse: oklch(1 0 0 / 0.65);
  --ring: 0 0 0 var(--ring-width) var(--ring-color);

  /* ---- Composed transitions ------------------------------------------- */
  --transition-colors:
    color var(--duration-fast) var(--ease-standard),
    background-color var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard);
  --transition-transform: transform var(--duration-base) var(--ease-out);
  --transition-elevate:
    transform var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out);

  /* ---- Semantic spacing ----------------------------------------------- */
  --gap-inline-xs: var(--space-1-5);
  --gap-inline-sm: var(--space-2);
  --gap-inline-md: var(--space-3);
  --gap-inline-lg: var(--space-4);
  --gap-grid:      var(--space-5);
  --gap-grid-lg:   var(--space-6);
  /* Product grids run a much wider gutter than the generic grid gap. In a
     fixed-column grid the cards absorb it, so raising this both slims the
     cards and separates them — the two move together. Shared by the picks,
     deals and lineup grids, and by the .picks__panel width calc, which
     divides by the same value. */
  --gap-product-grid: var(--space-12);

  /* ---- Store-picks slider ---------------------------------------------
     The rail is a peek carousel: card width is fixed so the next card is
     deliberately cut by the container edge, which is what signals there is
     more to scroll. --picks-lead is the offset of the first card from the
     container start, i.e. how much of the dark panel shows before it. */
  --picks-card-w: 18.75rem;   /* 300 */
  --picks-gap:    var(--space-4);
  --picks-lead:   var(--space-10);

  /* ---- Hero slider ------------------------------------------------------
     One height for both the slider and its viewport. The slides are
     absolutely positioned, so the viewport has no in-flow content to hold it
     open; it needs the same minimum, from the same token, or the two drift
     apart and it collapses. */
  --slider-h: 27.5rem;

  /* ---- Rail (shared slider) -------------------------------------------
     Defaults for every product rail. A section overrides --rail-card-w when
     its card is a different shape — the horizontal best-seller row is far
     wider than a standard product card. */
  --rail-card-w: var(--picks-card-w);
  --rail-gap:    var(--picks-gap);
  --pad-card:      var(--space-5);
  --pad-panel:     var(--space-7);
  --section-gap:   clamp(var(--space-12), 6vw, var(--space-20));
  --section-head-gap: var(--space-8);
}


/* ==========================================================================
   LAYER 2b — SEMANTIC  (dark theme)
   --------------------------------------------------------------------------
   Applied by the inline bootstrap script in <head>, which resolves
   localStorage → prefers-color-scheme before first paint. Declaring the
   palette once (rather than duplicating it inside a media query) keeps
   a single source of truth.

   Dark is not an inversion: chroma comes down, brand lightness comes
   *up* so the red keeps contrast against dark surfaces, and shadows
   switch from tinted-slate to near-black plus a top highlight, since
   soft grey shadows are invisible on dark ground.
   ========================================================================== */

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg-page:        var(--slate-1000);
  --bg-shell:       oklch(0.162 0.036 263);
  --bg-surface:     var(--slate-950);
  --bg-surface-2:   oklch(0.214 0.041 263);
  --bg-surface-3:   oklch(0.252 0.043 262);
  --bg-inset:       oklch(0.226 0.041 263);
  --bg-inverse:     var(--slate-50);
  --bg-brand-subtle: oklch(0.268 0.048 167);
  --bg-accent-subtle: oklch(0.246 0.058 258);

  --fg-default: oklch(0.968 0.005 260);
  --fg-body:    oklch(0.878 0.010 260);
  --fg-muted:   oklch(0.744 0.016 260);
  --fg-subtle:  oklch(0.632 0.020 260);
  --fg-on-brand:   oklch(0.99 0 0);
  --fg-on-accent:  oklch(0.99 0 0);
  --fg-on-inverse: var(--slate-900);

  --border-subtle:  oklch(1 0 0 / 0.07);
  --border-default: oklch(1 0 0 / 0.11);
  --border-strong:  oklch(1 0 0 / 0.18);
  --border-brand:   oklch(0.521 0.106 167 / 0.52);
  --border-inverse: oklch(0 0 0 / 0.14);

  /* Lift the brand two steps so it survives a dark backdrop. */
  /* The brand fill does NOT lift in dark the way the red one did. Teal-500
     measures only 3.7:1 against white, so lifting it would quietly break
     every white label sitting on a brand button. Teal-600 is legible on a
     dark surface as a fill and still carries white text at 5.2:1. */
  --brand:        var(--teal-600);
  --brand-hover:  var(--teal-500);
  --brand-active: var(--teal-700);
  --brand-bright: var(--teal-400);
  --brand-text:   var(--teal-300);

  --accent:        var(--navy-700);
  --accent-hover:  var(--navy-600);
  --accent-text:   var(--navy-300);

  --success:        var(--green-500);
  --success-subtle: oklch(0.268 0.062 152);
  --success-text:   var(--green-400);
  --warning:        var(--amber-500);
  --warning-subtle: oklch(0.288 0.066 75);
  --warning-text:   var(--amber-400);
  --danger:         var(--red-500);
  --danger-subtle:  oklch(0.262 0.075 27);
  --danger-text:    var(--red-400);
  --rating:         var(--amber-400);

  --gradient-brand: linear-gradient(135deg, var(--teal-600) 0%, var(--teal-700) 55%, var(--teal-800) 100%);
  --gradient-brand-flat: linear-gradient(90deg, var(--teal-700) 0%, var(--teal-600) 52%, var(--teal-800) 100%);
  --gradient-brand-vivid: linear-gradient(145deg, var(--teal-600), var(--teal-800));
  --gradient-accent: linear-gradient(145deg, var(--navy-800), var(--navy-950));
  --gradient-skeleton: linear-gradient(
      100deg,
      var(--bg-surface-2) 0%,
      var(--bg-surface-3) 40%,
      var(--bg-surface-2) 80%);

  /* Flat here too. Only the overlay pair is re-stated for dark, where it
     goes near-black and deeper: on a dark surface a tinted shade is
     invisible, and a floating layer still has to detach from the page. */
  --shadow-overlay:
    0 22px 46px -14px oklch(0 0 0 / 0.68),
    inset 0 1px 0 oklch(1 0 0 / 0.07);
  --shadow-overlay-lg:
    0 36px 72px -18px oklch(0 0 0 / 0.76),
    inset 0 1px 0 oklch(1 0 0 / 0.08);
  --shadow-drawer:
    -1.25rem 0 3rem -0.5rem oklch(0 0 0 / 0.60),
    -0.375rem 0 1rem -0.375rem oklch(0 0 0 / 0.40);

  --overlay: oklch(0.11 0.02 263 / 0.66);
  --ring-color: oklch(0.706 0.104 167 / 0.68);
  --glow-brand: radial-gradient(circle at 72% 28%, oklch(1 0 0 / 0.06), transparent 32%);
}


/* ==========================================================================
   LAYER 3 — COMPONENT TOKENS
   --------------------------------------------------------------------------
   Each entry is a knob a component reads. Retheme a single component by
   overriding here; nothing else needs to know.
   ========================================================================== */

:root {

  /* ---- Button ---------------------------------------------------------- */
  --btn-height:        var(--tap-min);
  --btn-height-lg:     3.25rem;   /* 52 */
  --btn-pad-inline:    var(--space-5);
  --btn-radius:        var(--radius-pill);
  --btn-radius-square: var(--radius-md);
  --btn-weight:        var(--weight-bold);
  --btn-font-size:     var(--text-lg);

  --btn-primary-bg:       var(--gradient-brand-vivid);
  --btn-primary-bg-active: var(--brand-active);
  --btn-primary-fg:       var(--fg-on-brand);
  --btn-primary-shadow:   var(--shadow-brand-md);
  --btn-primary-shadow-hover: var(--shadow-brand-lg);

  --btn-neutral-bg:       var(--bg-surface-3);
  --btn-neutral-fg:       var(--fg-body);
  --btn-neutral-bg-hover: var(--bg-inset);

  --btn-onbrand-bg:       var(--bg-surface);
  --btn-onbrand-fg:       var(--accent);

  /* ---- Card ------------------------------------------------------------ */
  --card-bg:            var(--bg-surface);
  --card-border:        var(--border-subtle);
  --card-border-hover:  var(--border-brand);
  --card-radius:        var(--radius-2xl);
  --card-pad:           var(--pad-card);
  --card-shadow:        var(--shadow-md);
  --card-shadow-hover:  var(--shadow-lg);
  --card-lift:          -5px;

  /* ---- Product card --------------------------------------------------- */
  --product-media-height: 10rem;    /* 160 */
  --product-title-lines:  2;
  /* Hover outline. One border, not two: this ring is painted over the card's
     own hairline rather than inside it, so the card never shows a coloured
     border and a separate bar at once. Bold brand on the bottom edge, gone
     by mid-height, where the hairline takes the outline back over. */
  --product-accent-width: var(--border-heavy);
  --product-accent-ring: linear-gradient(
      to top,
      var(--brand) 0%,
      var(--brand) 12%,
      color-mix(in oklab, var(--brand) 42%, transparent) 45%,
      color-mix(in oklab, var(--brand)  0%, transparent) 78%);

  /* ---- Input ----------------------------------------------------------- */
  --input-height:       3.25rem;
  --input-bg:           var(--bg-surface);
  --input-fg:           var(--fg-default);
  --input-placeholder:  var(--fg-subtle);
  --input-border:       var(--border-strong);
  --input-border-focus: var(--brand);
  --input-radius:       var(--radius-pill);
  --input-pad-inline:   var(--space-4);
  --input-shadow:       var(--shadow-xs);

  /* ---- Badge ----------------------------------------------------------- */
  --badge-radius:    var(--radius-xs);
  --badge-pad:       var(--space-1) var(--space-2);
  --badge-font-size: var(--text-2xs);
  --badge-weight:    var(--weight-extrabold);
  /* Not --brand: the dark theme lifts --brand to red-500 for visibility on
     dark surfaces, which drops white 11px badge text to 3.8:1. */
  --badge-discount-bg: var(--brand);
  --badge-discount-fg: var(--fg-on-brand);

  /* ---- Logo -------------------------------------------------------------
     Width only; the mark's aspect-ratio supplies the height. At 168px the
     "invest shop" lettering is still comfortably legible, and the compact
     step keeps it readable in the collapsed header. */
  --logo-width:         10.5rem;   /* 168 → 46 tall */
  --logo-width-compact:  8.75rem;  /* 140 → 38 tall */

  /* ---- Header ---------------------------------------------------------- */
  --header-height:        7.25rem;   /* 116 */
  --header-height-compact: 4.5rem;   /* 72 */
  --header-bg:            oklch(1 0 0 / 0.72);
  --header-bg-scrolled:   oklch(1 0 0 / 0.86);
  --header-blur:          18px;

  /* ---- Promo bar ------------------------------------------------------- */
  --promobar-height: 4.5rem;
  --promobar-radius: var(--radius-pill);
  --promobar-bg:     var(--gradient-brand-flat);

  /* ---- Timer ----------------------------------------------------------
     Width and height are separate so the cell can be squarer at the large
     size; the separator centres itself against --timer-cell-h, which is why
     that has to be a token rather than a magic number in the component. */
  --timer-cell-w:      2.375rem;
  --timer-cell-h:      2.25rem;
  --timer-cell-bg:     var(--bg-surface);
  --timer-cell-fg:     var(--fg-default);
  --timer-cell-radius: var(--radius-sm);
  --timer-value-size:  var(--text-2xl);

  /* ---- Panel (dark editorial block) ----------------------------------- */
  --panel-bg:     var(--gradient-accent);
  --panel-fg:     var(--fg-on-accent);
  --panel-radius: var(--radius-4xl);
  --panel-pad:    var(--pad-panel);

  /* ---- Drawer / toast -------------------------------------------------- */
  --drawer-width:  min(86vw, 23.125rem);
  --drawer-bg:     var(--bg-surface);
  --drawer-shadow: var(--shadow-drawer);
  --toast-bg:      var(--bg-inverse);
  --toast-fg:      var(--fg-on-inverse);
  --toast-radius:  var(--radius-lg);

  /* ---- Footer ---------------------------------------------------------- */
  --footer-bg:     var(--gradient-brand);
  --footer-fg:     var(--fg-on-brand);
  --footer-radius: var(--radius-4xl);

  /* ---- Trust seal ------------------------------------------------------
     A certification badge is a fixed artefact, like a brand mark, and must
     not invert with the theme — an eNAMAD seal is a white seal. These
     therefore reference primitives directly and are absent from the dark
     block on purpose. */
  --trustbadge-bg: var(--slate-0);
  --trustbadge-fg: var(--navy-700);

  /* ---- Notch ----------------------------------------------------------
     The design repeatedly cuts a page-coloured bite out of a panel edge.
     Centralised so the "cut-out" colour tracks the page background. */
  --notch-color: var(--bg-page);
  --notch-ring:  5px;

  /* ---- Intro curtain ---------------------------------------------------
     The full-screen mark animation that plays over the page until load.
     It is the first thing a visitor sees, so it gets the one deliberately
     rich surface in the system: a lit centre falling to a tinted floor.
     The canvas resolves to the page background at its edges, which is what
     lets the curtain dissolve into the page rather than cut to it. */
  --curtain-canvas:
    /* spotlight */
    radial-gradient(46% 42% at 50% 44%, oklch(1 0 0 / 0.95), transparent 74%),
    /* floor */
    radial-gradient(120% 84% at 50% 118%, oklch(0.888 0.068 167 / 0.60), transparent 72%),
    /* vignette — frames the mark instead of letting it float in flat paper */
    radial-gradient(148% 118% at 50% 45%, transparent 52%, oklch(0.808 0.092 167 / 0.30) 100%),
    linear-gradient(180deg, var(--slate-25) 0%, var(--teal-50) 100%);
  /* Slow conic sweep behind the mark. Blurred past legibility in the
     component, so the stops only say where the light is, not its shape —
     and kept faint, because a visible arc reads as a stain. */
  --curtain-halo:
    conic-gradient(from 0deg,
      transparent 0deg 140deg,
      oklch(0.521 0.106 167 / 0.20) 218deg,
      oklch(0.822 0.148 78 / 0.22) 286deg,
      transparent 350deg 360deg);
  --curtain-glow: radial-gradient(closest-side, oklch(0.888 0.068 167 / 0.55), transparent 100%);
  --curtain-mark:   var(--brand-text);
  --curtain-stroke: var(--teal-600);
  /* Light lifts the mark off the paper; dark lights it from behind, because
     a cast shadow on a near-black field is invisible. */
  --curtain-mark-shadow: drop-shadow(0 14px 26px oklch(0.440 0.092 167 / 0.22));
  /* The gold pass over the finished mark. Narrow, off-axis, and screened —
     a glint across metal, not a highlight on plastic. */
  --curtain-sheen:
    linear-gradient(102deg,
      transparent 40%,
      oklch(0.945 0.065 82 / 0.55) 47%,
      oklch(0.995 0.030 92 / 0.95) 50%,
      oklch(0.945 0.065 82 / 0.55) 53%,
      transparent 60%);
  --curtain-label:  var(--fg-subtle);
  --curtain-rule:   linear-gradient(90deg, transparent, var(--border-strong) 50%, transparent);
  --curtain-track:  oklch(0.521 0.106 167 / 0.14);
  --curtain-fill:
    linear-gradient(90deg, var(--teal-600), var(--teal-400) 55%, var(--amber-400));

  /* Timings. --curtain-draw is one shape's outline-to-fill; the stagger in
     the stylesheet is layered on top of it, and app.js holds the curtain
     open long enough for the last shape to land. */
  --curtain-draw: 820ms;
  --curtain-exit: 620ms;
}

:root[data-theme="dark"] {
  --header-bg:          oklch(0.184 0.040 263 / 0.72);
  --header-bg-scrolled: oklch(0.184 0.040 263 / 0.90);
  --btn-onbrand-bg:     var(--bg-surface-2);
  --btn-onbrand-fg:     var(--fg-default);

  /* Same construction inverted: the lit centre becomes a teal ember over
     near-black, so the mark still sits in the brightest part of the field. */
  --curtain-canvas:
    radial-gradient(46% 42% at 50% 44%, oklch(0.322 0.066 167 / 0.85), transparent 74%),
    radial-gradient(120% 84% at 50% 118%, oklch(0.232 0.046 167 / 0.90), transparent 74%),
    radial-gradient(148% 118% at 50% 45%, transparent 46%, oklch(0.139 0.034 263 / 0.80) 100%),
    linear-gradient(180deg, var(--slate-1000) 0%, oklch(0.160 0.032 250) 100%);
  --curtain-halo:
    conic-gradient(from 0deg,
      transparent 0deg 140deg,
      oklch(0.706 0.104 167 / 0.22) 218deg,
      oklch(0.822 0.148 78 / 0.18) 286deg,
      transparent 350deg 360deg);
  --curtain-glow: radial-gradient(closest-side, oklch(0.440 0.092 167 / 0.62), transparent 100%);
  --curtain-stroke: var(--teal-300);
  --curtain-mark-shadow: drop-shadow(0 0 30px oklch(0.706 0.104 167 / 0.28));
  --curtain-track:  oklch(1 0 0 / 0.10);
}
