/* AEKE .sg — design tokens.
 *
 * Sourced from reference/tokens-extracted.css, which is generated from the **live
 * aeke.com theme** by scripts/fetch_theme_assets.py. Variable names are kept exactly
 * as the theme defines them so any future comparison against the live site is direct
 * (plan.md §2.1) — this is a faithful replica, not an interpretation.
 *
 * Values marked `OURS` are the only deliberate departures. Each one states why.
 *
 * This file is the single source of colour. Nothing else in the project may contain
 * a hex literal — tests/test_tokens.py enforces that.
 */

:root {
  /* ======================================================== ground & surfaces */
  --bg-body: #0d0e11;
  --bg-body-darken: #060708;
  --bg-body-rgb: 13, 14, 17;
  --color-footer-bg: #0b0b0d;
  --color-drawer-bg: #1a1a1e;
  --color-announcement-bar-bg: #1c1c20;
  --color-secondary-menu-bg: #1c1c20;
  --color-product-card-bg: #2e2e35;
  --color-article-card-bg: #2e2e35;
  --timer-bg: #050606;
  --logo-bg: #0b0b0b;

  /* The dark shell is blue-tinted, not neutral grey. That tint is what stops it
     reading as a generic dark template. */

  /* ================================================================== text */
  --color-heading: #ffffff;
  --color-body: #e5e7eb;
  /* The `-rgb` companions exist because the theme composites several surfaces at
     low alpha — `rgba(var(--color-body-rgb), .03)` for a slideshow's ground. A hex
     cannot be used inside rgba(), so the channels have to be named separately and
     kept in step with the solid value above. */
  --color-body-rgb: 229, 231, 235;
  --color-text: #ffffff;
  --color-price: #ffffff;
  --color-secondary-menu-text: #a0a3a8;
  --color-header-bg: #0d0e11;
  --color-header-links: #ffffff;
  --color-header-text: #ffffff;
  --color-header-icons: #c0c4cc;
  --color-announcement-bar-text: #ffffff;
  --color-footer-heading: #ffffff;
  --color-footer-link: #c0c4cc;
  --color-footer-text: #a0a3a8;

  /* ============================================================== header */
  /* The homepage header is an overlay: it sits on top of the hero with no
     background of its own and only acquires one on hover. Text over an arbitrary
     photograph needs its own token rather than inheriting --color-header-links,
     because the two are free to diverge upstream. */
  --color-header-transparent-text: #ffffff;
  --logo-height-mobile: 26px;

  /* Slide text that sits on a photograph rather than on the dark shell.
     `--color-ink` is the theme's own default body colour (it appears as the
     fallback in dozens of `var(--color-body, <value>)` declarations); the hero's
     light slides were configured to `#2c2d2e` and `#030303` by hand in the theme
     editor. Both are here so a slide can name a colour instead of carrying a hex.
     The light value on the same slides is `--color-heading`. */
  --color-ink: #2c2d2e;
  --color-ink-strong: #030303;

  /* The media grid's tiles alternate. One group is white with dark text, the other
     sits on the page ground with none — upstream sets both inline, per tile, as
     `--color-bg: #ffffff` and `--color-bg: #0d0e11`. Named here so a tile says which
     one it wants rather than carrying a hex. */
  --surface-tile-light: #ffffff;
  --surface-tile-dark: var(--bg-body);
  --menu-badge-bg: #01a3b8;
  --menu-badge-text: #272422;
  /* Backdrop behind an open mega menu. The theme writes rgba(var(--color-overlay-rgb), .4). */
  --color-overlay-rgb: 0, 0, 0;
  /* The tinted panel a slide can put behind its text, and how far it is blurred.
     Both are per-slide on the live site; these are the defaults for slides that do
     not override them. */
  --color-slide-rgb: 0, 0, 0;
  --color-slide-blur: 0px;
  --color-slide-opacity: 0;
  /* Crossfade between slides. Measured off the live carousel: the incoming slide
     reaches 0.95 opacity at 470ms and settles around 650ms, so 0.7s on the theme's
     own easing curve. Not a guess, and not the 0.4s a Flickity default suggests. */
  --fade-duration: 0.7s;

  /* Row heights, measured off the live rendering. The row is taller on desktop
     because the logo's 20px vertical margin only applies there. Between 1068px and
     ~1218px the live nav wraps onto a second line and the row grows to 93px — see
     the note in header.css; that is upstream behaviour, replicated deliberately. */
  --header-row-height: 66px;      /* < 1068px */
  --header-row-height-lg: 80px;   /* >= 1068px */
  --header-offset: 0px;           /* set at runtime: distance from viewport top */
  --header-height: 0px;           /* set at runtime: measured row height */
  /* The pinned header's lift. The theme writes these as two 8-digit hex values;
     kept here rather than in header.css so that stylesheet stays free of colour
     literals, which a test enforces. */
  --shadow-header-sticky: 0 9px 38px rgb(0 0 0 / 5%), 0 5px 12px rgb(0 0 0 / 10%);

  /* ================================================================ accent */
  --color-accent: #01A3B8;
  --color-accent-hover: #018494;
  --color-accent-rgb: 1, 163, 184;
  --color-header-links-hover: #01A3B8;
  --color-footer-link-hover: #01A3B8;

  /* The `text_with_icons` links on `/pages/support`. Upstream carries this as a per-section theme
     setting — the merchant picked a green for these four "Learn more" links while the rest of the
     site is teal. Kept verbatim: 8.6:1 on the page ground, so there is nothing to correct, and a
     section that names another colour overrides it through `--icon-link-color`. */
  --color-icon-link: #32C48C;

  /* Buttons. The live theme's solid button is teal with DARK text — 6.37:1, which
     passes AA comfortably. We adopt it verbatim rather than "fixing" it. */
  --solid-button-background: #01A3B8;
  --solid-button-background-hover: #018494;
  --solid-button-label: #0d0e11;
  --button-background-color: #ffffff;
  --button-text-color: #0d0e11;
  --button-border-radius: 25px;
  --button-letter-spacing: 0em;

  /* OURS — the white button's label. The theme pairs
     `--white-button-label: #01A3B8` with a #ffffff background, which measures
     **3.03:1** and fails WCAG AA (4.5:1) for normal-size text. This is the same
     ratio that made the accent look suspect, but the failing pairing is the
     *inverse* of the obvious one — teal text on white, not white text on teal.
     Same hue, darkened until it passes: ≈4.69:1 on white, 3.02:1 apart from the
     brand teal so it still reads as the same colour family. */
  --accent-on-light: #017F8E;

  /* =============================================================== borders */
  --color-border: #1f1f23;
  --color-header-border: #1f1f23;
  --color-form-border: #2e2e32;
  --color-footer-border: #454545;

  /* OURS — an input's boundary needs 3:1 to be perceivable (WCAG 1.4.11), and the
     theme's `--color-form-border` (#2e2e32) measures only ≈1.4:1 against the dark
     ground, which makes a field look like unbounded empty space. Same defect class
     v1 hit, same fix: a dedicated control token, leaving `--color-form-border` in
     place for anything purely decorative. */
  --control-border: #767E88;

  /* ======================================================= state & status */
  --color-inventory-instock: #279A4B;
  --color-inventory-lowstock: #ffa41d;
  --color-badge-sale: #ff4d4d;
  --color-badge-sold-out: #6d6b6b;
  --color-badge-preorder: #666666;
  --color-badge-text: #0d0e11;
  --color-price-discounted: #ff4d4d;
  --color-star: #FFAA47;

  /* ============================== one-off widget surfaces (read from the live page) */

  /* The extended-protection block is a third-party app's widget, and its plan cards invert
     from transparent to white when one is chosen — a white-surface palette inside a dark
     page. These four are the app's own literals, read back from the rendered widget rather
     than guessed at, and they only ever apply inside that block. */
  --protection-card-border: #EFEFEF;
  --protection-card-checked-bg: #FFFFFF;
  --protection-card-checked-border: #E1E5E3;
  --protection-card-checked-text: #1D1D1F;

  /* The compact feature grid's secondary copy, from the same page's own stylesheet. The
     second value is the one its small-screen rule swaps in. */
  --color-feature-text: #BBBBBB;
  --color-feature-text-small: #7D7D7D;

  /* The specification table (`product_specifications`) is another light panel inside the dark
     page, and these five are the theme's own literals on the B1 page — a grey #f5f5f5 surface
     with a #333 heading, #666 labels and #333 values. Read back from the rendered page: the
     contrast pairs they form are asserted in tests/test_tokens.py like every other surface. */
  --surface-specs-panel: #F5F5F5;
  --color-specs-title: #333333;
  --color-specs-name: #666666;
  --color-specs-value: #333333;
  /* A 0.8px hairline under every row, including the last. */
  --color-specs-rule: rgba(0, 0, 0, 0.1);

  /* The three-step row's description. Upstream sets it inline on each step (`#cccccc`), which is
     why it is a shade lighter than the compact grid's copy above. */
  --color-step-text: #CCCCCC;

  /* ------------------------------------------------- toggle-box panel palettes */

  /* The K1's card rows paint their panel and their label bar from per-section theme settings.
     Upstream there are two: a white one for the machine row and a charcoal one for the
     accessories row. Upstream also carries two inks per palette — `#1A1C1D` for the label and
     `#2C2D2E` for the copy — which are 4% apart and indistinguishable on screen, so each
     palette has one ink here. */
  --toggle-light-surface: #FFFFFF;
  --toggle-light-ink: #2C2D2E;
  --toggle-dark-surface: #262729;
  --toggle-dark-ink: #FFFFFF;

  /* The YouTube gallery's own two colours: the platform's red, and the grey a tile shows
     before its still has loaded. */
  --color-youtube: #FF0000;
  --video-tile-bg: #F5F5F5;

  /* ======================================================== radii (as live) */
  --button-border-radius: 25px;
  --badge-corner-radius: 14px;
  --input-border-radius: 6px;
  --block-border-radius: 4px;

  /* ============================================================== layout */
  --grid-width: 1440px;
  --grid-width-row: 1540px;
  --section-spacing-mobile: 50px;
  --section-spacing-desktop: 70px;
  --logo-height: 26px;
  --gallery-columns: 4;
  --logo-columns: 6;

  /* One card in a mobile swipe strip. Upstream computes it as calc(90vw - 15px):
     wide enough to dominate the viewport, narrow enough that the next card peeks —
     which is the only affordance telling a thumb the row scrolls. */
  --mobile-swipe-width: calc(90vw - 15px);

  /* OURS — the theme has no explicit gutter token; its container padding is baked
     into per-section rules. One shared gutter keeps every page aligned.
     Measured from the live layout: 15px below 768px, 50px from 768px up. */
  --gutter: 0.9375rem;

  /* ============================================================== typography */
  --font-body: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-heading: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* The header's own scale. aeke.com multiplies every navigation size by this so a
     merchant can retune the menu from the theme editor without touching CSS; the
     live site ships 1.1, which is what makes its 15px base render at 16.5px.
     Keeping the multiply (rather than hard-coding 16.5px) means the two numbers
     stay in the same relationship they have upstream. */
  --font-navigation-scale: 1.1;

  --font-body-scale: 1;
  --font-body-weight: 400;
  --font-body-medium-weight: 500;
  --font-body-bold-weight: 600;
  --font-body-letter-spacing: 0em;
  --font-heading-letter-spacing: -0.02em;
  --font-heading-line-height-scale: 1;
  --font-product-title-line-height-scale: 0.9;

  /* OURS — the operator panel prints machine values (a build id, a payment reference,
     a SKU) where digits must line up and a `0` must not read as an `O`. Deliberately a
     *system* stack: the customer-facing site ships one family (Poppins) and loading a
     second webfont for an internal sign-in screen would be bytes spent on the wrong
     audience. Nothing here is downloaded. */
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* Base sizes. 17px / 27.2px is a line-height of exactly 1.6 — measured, not
     inferred. An earlier pass used 1.5, which is visually close enough to look
     "right" and wrong enough to shift every paragraph on every page. */
  --type-body: 1.0625rem;        /* 17px */
  --type-body-lh: 1.7rem;        /* 27.2px */
  --type-small: 0.9375rem;       /* 15px */
  --type-caption: 0.8125rem;     /* 13px */

  /* ==================================================================== scale */
  /* The heading scale, EXACTLY as the live site computes it — see
     reference/live-profile.json. Size and line-height are separate tokens because
     the theme specifies both in px and they do not move in lockstep.

     Read that file before changing anything here. The theme's own stylesheet
     declares larger values (h1 64px, h2 54px) that later rules override; matching
     the stylesheet instead of the rendering is how the first pass ended up ~22%
     too large. Measured values win.

     The scale steps at 768px and 1440px — note 1440, not the stylesheet's 66.75em. */
  --type-h1: 2rem;               --type-h1-lh: 2.5rem;      /* 32 / 40 */
  --type-h2: 1.75rem;            --type-h2-lh: 2.25rem;     /* 28 / 36 */
  --type-h3: 1.625rem;           --type-h3-lh: 1.875rem;    /* 26 / 30 */
  --type-h4: 1.25rem;            --type-h4-lh: 1.75rem;     /* 20 / 28 */
  --type-h5: 1.5rem;             --type-h5-lh: 2rem;        /* 24 / 32 */
  --type-h6: 1.125rem;           --type-h6-lh: 1.625rem;    /* 18 / 26 */

  /* ======================================================= OURS — focus ring */
  /* The theme has no single focus token. White is used deliberately: it measures
     17.6:1 on the dark ground and 3.03:1 on the accent, so one ring is visible on
     every surface we ship — including on top of a teal button, where a teal ring
     would disappear. 3.03:1 meets the 3:1 non-text requirement (WCAG 1.4.11). */
  --focus-ring-color: #ffffff;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;

  /* ================================================= OURS — motion & easing */
  /* The theme repeats this cubic-bezier on every transition it defines (drawers,
     submenus, the header background). Pulling it into a token means our header
     moves at exactly the speed theirs does, instead of at whatever `ease` a
     utility class happens to apply. */
  --ease-theme: cubic-bezier(0.104, 0.204, 0.492, 1);
  --duration-theme: 0.25s;
}

/* ---- the live site's breakpoints: 48em (768px) and 90em (1440px) ----
   Both verified by measuring the live rendering at 375/768/1024/1440/1920. The
   gutter moves once (15px -> 50px); the heading scale moves twice. ---- */

@media (min-width: 48em) {
  :root {
    --gutter: 3.125rem;          /* 50px — measured, not the 30px first assumed */
    --type-h1: 2.25rem;          --type-h1-lh: 2.75rem;     /* 36 / 44 */
    --type-h2: 2.25rem;          --type-h2-lh: 2.75rem;     /* 36 / 44 */
    --type-h3: 1.875rem;         --type-h3-lh: 2.375rem;    /* 30 / 38 */
    /* h4, h5 and h6 do NOT change at this breakpoint on the live site. */
  }
}

@media (min-width: 90em) {
  :root {
    --type-h1: 3.125rem;         --type-h1-lh: 3.625rem;    /* 50 / 58 */
    --type-h2: 2.625rem;         --type-h2-lh: 3.125rem;    /* 42 / 50 */
    --type-h3: 2.125rem;         --type-h3-lh: 2.625rem;    /* 34 / 42 */
    --type-h4: 1.75rem;          --type-h4-lh: 2.25rem;     /* 28 / 36 */
  }
}

/* ---------------------------------------------------------------- base layer */

/* The element-level base styles live in `tailwind.css`'s `@layer base`, NOT here.
 *
 * This is deliberate and was learned the hard way: tokens.css is loaded *before*
 * app.css, and Tailwind's preflight (inside app.css) includes
 *     h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit }
 * which — being later in the cascade at equal specificity — silently overrode the
 * heading sizes declared here. The line-heights survived only because preflight
 * does not touch them, so headings rendered at 17px/58px: right rhythm, wrong size.
 * Moving the rules into `@layer base` puts them after preflight where they belong.
 *
 * This file is therefore ONLY custom properties. Nothing else.
 */

