/* ============================================================================
   Nouri Narie 2.0 — design tokens

   Built from three references, not two.

   kyliecosmetics.com and rhodeskin.com set the type, spacing, radius and
   elevation scales. Where the two disagree they are NOT averaged into a
   midpoint — a value halfway between 4px and 7px is 5.5px, which is nobody's
   design. Each is given the role it is genuinely better at, so both appear at
   full strength somewhere on the page.

   The COLOUR comes from a third reference, added in the aluminium re-base:
   the physical packaging. Neither Kylie nor Rhode ships anodised aluminium,
   so neither can source a palette built around it. Three exacts sampled off a
   photograph of the real bottles are a stronger provenance than a scraped
   stylesheet, because they are the actual object being sold:

     --alu-light  #E9E9E7   satin specular, key side
     --alu        #A8A8A6   diffuse mid, the metal itself
     --alu-shadow #7D7974   shadow side, warming as it falls off

   These are MEASURED, and the measurement corrected a guess. The first pass
   at this file assumed the metal was a cool green-grey and derived every
   neutral from hue 132. Sampling the real thing found hue 30-60 at 1-9%
   saturation: near-neutral in the highlights, warming through the mids. The
   metal is warm-neutral, not cool, and an invented hue had been sitting in
   here describing a product that does not look like that.

   So EVERY neutral is generated from HSL 40 — between the warm mid tones and
   the near-neutral speculars — at 3-6% saturation, lightness varied. Low
   saturation is what keeps warm-neutral from becoming beige, which the brief
   rules out by name. That is a derivation anyone can audit with a colour
   picker against the same photograph.

   Discarded from the original extraction as scraper artefacts, not brand:
     #0070e0 / #005bd3   Shopify's admin-bar blue, present on every Shopify
                         storefront on earth. Neither is a brand colour.
     swiper-icons        a carousel library's icon font, not a typeface.
     --oke-*             the Okendo reviews widget's private variables.
     the "radius scales" every radius on the page including third-party chrome.

   What this file must never grow:
     - backdrop-filter. Both reference systems name it an anti-pattern and
       neither reference site uses it. v1 had 29 instances; they are gone.
     - a --matcha or --pink token, nor the rose family the aluminium re-base
       removed: --blush, --rose, --mauve, --cocoa, --chestnut. v1 carried 151
       references to dead names REPOINTED to greys; the re-base refused to
       repeat that and renamed instead, so every changed site got read once.
       build/check.py asserts all seven names stay gone.
     - a colour that is not a reference exact, a documented midpoint of two
       exacts, or a stated HSL derivation off hue 132. Nothing invented.
   ========================================================================= */

:root {
  /* ── grounds ──────────────────────────────────────────────────────────────
     The alternation is a TEMPERATURE alternation, not a value one: --paper is
     warm ivory (hue 36, Rhode's own) and --mist is the near-neutral silver
     white the metal's speculars actually are. Relative luminances 0.8814 and
     0.9041, about 2.3 points apart. The page changes temperature under you
     and barely changes brightness — the "soft clinical luxury" idea in two
     hex values.

     This is a quieter alternation than the warm/cool one the first pass
     designed, because the metal turned out not to be cool. It is the true
     one. If it proves too quiet on an uncalibrated panel, widen --mist toward
     --alu-light and accept a small value step — do not warm --paper, and do
     not cool --mist past what the photograph supports. */
  --shell:       #FFFFFF;   /* both references agree — cards, panels */
  --paper:       #F3F1EE;   /* Rhode #f1f0ed warmed one step — page ground */
  --mist:        #F4F4F3;   /* midpoint of --shell and --alu-light:
                               (255+233)/2, (255+233)/2, (255+231)/2 */

  /* The metal itself, sampled. --alu-light is a ground (bands, buy box);
     --alu is a fill and a rule; --alu-shadow exists to tint --shadow-3. */
  --alu-light:   #E9E9E7;
  --alu:         #A8A8A6;
  --alu-shadow:  #7D7974;

  --graphite:    #312F2B;   /* H40 S6 L18 — ticker, footer, dark band */

  /* ── ink ──────────────────────────────────────────────────────────────────
     Rhode's #2d2d2d is already a charcoal and matches the brief word for
     word. It is carried onto the aluminium ramp's hue so that ink and metal
     are one family rather than two greys that disagree, then darkened for
     headroom against the four light grounds above. */
  --ink:          #292724;  /* H40 S6 L15   — 13.21:1 on --paper, 12.25 on --alu-light */
  --ink-soft:     #464441;  /* H40 S4 L26.5 —  8.61:1 on --paper — secondary prose */
  --ink-muted:    #62615D;  /* H40 S3 L37.5 —  5.50:1 on --paper, 5.10:1 on --alu-light.
                               Measured, not chosen. --alu-light is the tightest of the
                               four grounds and the one carrying the NouriNarie+ copy;
                               this value is set by that pair and nothing else. */
  --ink-disabled: #979591;  /*  disabled text. Never opacity — see base.css. */
  --on-dark:      #EEEEEC;  /* H40 S6 L93 — 11.50:1 on --graphite */
  --on-dark-mute: #BAB9B5;  /* H40 S4 L72 —  6.80:1 on --graphite */

  /* ── accent ───────────────────────────────────────────────────────────────
     Muted sage, and the only chromatic thing in the system. It is chosen by
     CONTRAST-MATCHING the dusty rose it replaces, not by eye, so every
     button, band and rule keeps the exact optical weight it was designed
     with and no layout needed re-balancing:

       outgoing --accent      #A06674  4.01 on --paper / 4.52 on --shell
       incoming --sage        #6B7A62  4.06            / 4.58
       outgoing --accent-deep #7C4653  6.52            / 7.35
       incoming --sage-deep   #4F5A49  6.44            / 7.26

     Sage is the one surviving thread to the original botanical identity.
     Restraint is the point: it appears as type, a fill or a rule, and never
     as a photographed object. build/media/write_prompts.py enforces the
     second half of that at the prompt level. */
  --sage:      #6B7A62;   /* 4.06:1 on --paper — a FILL, not a text colour.
                             Buttons, bands, rules, the quiz CTA ground. */
  --sage-deep: #4F5A49;   /* 6.44:1 on --paper — the text and link form. Any
                             sage-coloured word on a light ground uses this
                             one; --sage fails AA below 24px. */
  --sage-wash: #EDEFEB;   /* focus halo, hover fill. Never a text colour on
                             --sage: that pair is 3.98:1 and fails. */

  /* Kylie exact. Reserved for the promo band and the low-stock sticker, and
     capped at one instance per viewport — an alarm colour used twice is
     decoration, and stops working the third time. Watch it against metal:
     if it starts reading as a warm-metal detail rather than as an alarm,
     the substitute is --sage-deep, which costs the band its urgency. */
  --ember:       #C74A21;   /* 4.20:1 on --paper — fill only, like --sage */

  /* ── rules ────────────────────────────────────────────────────────────────
     Both references draw a genuinely visible 1px border on cards (#525252 and
     #393939) rather than floating them on a soft shadow. Keeping that is the
     single strongest defence this system has against generic-AI-card drift. */
  --rule:      #474643;   /* H40 S3 L27 — 9.44:1 on --shell, visible on purpose */
  --rule-soft: #D8D7D5;   /* H40 S4 L84 — list dividers, accordion rows */
  --rule-hair: #E7E6E4;   /* H40 S5 L90 — the faintest separation that reads */

  /* Semantic, not identity — unchanged by the re-base. Note that --ok and
     --sage are both greens; --ok carries roughly three times the saturation,
     which is what stops a success message reading as page chrome. */
  --ok:     #2C7A52;
  --warn:   #9A5A18;
  --danger: #9C3218;

  /* ── type ─────────────────────────────────────────────────────────────────
     Rhode sets Rektorat Heavy and Kylie sets UniversLTStd-Bold. Both are
     licensed and neither can ship here, so each is substituted by the closest
     freely-available face rather than by whatever is nearest to hand:

       Archivo      the only Google variable grotesque with a real width axis
                    (wght 100-900, wdth 62-125). At wght 800 / wdth 88 it sits
                    within a hair of Rektorat's tight-heavy proportions at
                    display size. Anton is too condensed and has one weight.
       Inter Tight  tightened sidebearings and closed apertures track Univers
                    at UI sizes far better than Inter or Roboto. Already proven
                    on v1, so it carries no new rendering risk.
       DM Mono      Nouri Narie's own, kept. Restricted to <=0.75rem uppercase
                    labels and numeric fields (step indices, SKUs, order nos). */
  --font-display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-text:    'Inter Tight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-mono:    'DM Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Rhode's scale. Reserved for the homepage hero, the story statement and the
     footer wordmark — three places on the whole site. The contrast between
     these and the interior scale below is what makes a homepage read as one. */
  --t-mega:    clamp(3.5rem, 18vw, 11rem);
  --t-display: clamp(2.5rem, 7vw, 5.5rem);

  /* Kylie's scale. Every interior page. Its literal 37px H1 sits inside the
     --t-h1 clamp at desktop. */
  --t-h1:      clamp(2rem, 4vw, 2.75rem);
  --t-h2:      2.25rem;      /* Kylie exact */
  --t-h3:      1.5rem;
  --t-h4:      1.25rem;
  --t-lede:    1.125rem;
  --t-body:    1rem;         /* Rhode exact */
  --t-sm:      0.9375rem;    /* Kylie body exact */
  --t-caption: 0.875rem;     /* Rhode caption exact */
  --t-micro:   0.75rem;      /* mono only, uppercase, tracked */

  --lh-mega:  0.82;
  --lh-tight: 0.92;
  --lh-head:  1.06;
  --lh-body:  1.55;
  --lh-prose: 1.65;

  --ls-mega:  -0.035em;
  --ls-head:  -0.02em;
  --ls-body:   0;
  --ls-micro:  0.12em;

  /* ── spacing ──────────────────────────────────────────────────────────────
     Strict 4px grid. Every clamp() endpoint below is a multiple of 4; the
     fluid middle is free to land wherever the viewport puts it, which is what
     the "no arbitrary spacing" rule is actually about. */
  --s-1:  4px;   --s-2:  8px;   --s-3: 12px;   --s-4: 16px;
  --s-5: 20px;   --s-6: 24px;   --s-8: 32px;   --s-10: 40px;
  --s-12: 48px;  --s-16: 64px;  --s-20: 80px;  --s-24: 96px;  --s-32: 128px;

  --section-y: clamp(48px, 8vw, 128px);
  --gutter:    clamp(16px, 4vw, 64px);

  /* ── radius ───────────────────────────────────────────────────────────────
     Rhode says 7px, Kylie says 4px. Neither is wrong: Kylie's 4px is on dense
     UI (inputs, chips, tags) and Rhode's 7px is on cards. Split by role and
     both references ship at full strength. Five values, every one present in
     at least one genuine scale. There is no sixth. */
  --r-xs:   4px;    /* Kylie exact — inputs, chips, tags, stepper buttons */
  --r-sm:   7px;    /* Rhode exact — buttons, product cards, thumbnails */
  --r-md:  12px;    /* in both — panels, buy box, drawer */
  --r-lg:  20px;    /* in both — media frames, hero panels */
  --r-pill: 999px;  /* in both — badges, pills, progress, stepper track */

  /* ── elevation ────────────────────────────────────────────────────────────
     The default is none. Cards carry --rule instead, per both references.

     --shadow-3 was Rhode's #bc9e9e7f exact and was the last rose object in
     the system — a pink haze under the primary CTA. Rhode's GEOMETRY and
     ALPHA are kept exactly; only the tint moves, to --alu-shadow. It is still
     spent on ONE element per page — the primary CTA on hover, or the PDP buy
     box. Used everywhere it stops being a signature and becomes a haze. */
  --shadow-0: none;
  --shadow-1: 0 1px 0 rgba(41, 39, 36, 0.10);      /* stuck nav / ticker seam */
  --shadow-2: 0 5px 20px rgba(34, 41, 47, 0.10);   /* Rhode #22292f1a exact */
  --shadow-3: 0 5px 20px rgba(125, 121, 116, 0.50);/* Rhode's alpha, alu tint */
  --shadow-4: 0 20px 48px -16px rgba(41, 39, 36, 0.28);
  --shadow-drawer: -10px 0 24px rgba(41, 39, 36, 0.22);

  /* ── measure ──────────────────────────────────────────────────────────────
     Rhode's 1040px and Kylie's 74.99em (~1200px) are both correct, for
     different content. Prose wants the narrower measure; a product grid and a
     nav want the wider one. Ship both rather than picking a loser. */
  --measure-text: 1040px;   /* Rhode exact — PDP copy, story, ingredients, FAQ */
  --measure:      1200px;   /* Kylie 74.99em — nav, footer, grids, cart, account */
  --measure-wide: 1440px;   /* campaign bands and full-bleed media only */

  /* ── chrome ───────────────────────────────────────────────────────────────
     The ticker sits above the nav and both are fixed, so every in-page anchor
     has to clear the sum. v1 used 84px for a nav alone; getting this wrong
     parks each target heading underneath the chrome, including the #products
     jump home.js performs once the film has sized its track. */
  --h-ticker: 32px;
  --h-nav:    64px;
  --h-chrome: 96px;

  /* ── motion ───────────────────────────────────────────────────────────────
     Both references' duration scales overlap almost entirely in the 150-350ms
     band; the easing below is Rhode's cubic-bezier(.4,0,.22,1) and the
     GSAP power3.out equivalent, which is what the JS layer uses. */
  --d-fast: 150ms;
  --d-base: 220ms;
  --d-slow: 350ms;
  --ease:     cubic-bezier(0.4, 0, 0.22, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io:  cubic-bezier(0.76, 0, 0.24, 1);

  --z-base: 1;
  --z-stuck: 40;
  --z-nav: 50;
  --z-ticker: 60;
  --z-drawer: 80;
  --z-modal: 90;
  --z-skip: 100;
}

/* Breakpoints are 480 / 768 / 1024 / 1280 throughout. Both references cluster
   genuinely at 768, 1024 and ~1200-1280; v1's 620/820/900 related to neither.
   Custom properties cannot be used in media queries, so the numbers are
   written literally at each site — these four and no others. A fifth needs a
   reason written next to it. */
