/* ═══════════════════════════════════════════════════════════════
   AURAVOX · Brand System v2
   Methodology: Three-Tier Token Architecture

   ╔══════════════════════════════════════════════════════════╗
   ║  TIER 1 — BRAND                                         ║
   ║  Raw values. No role, no UI assignment.                  ║
   ║  · Color scales  · Font families  · Number scale        ║
   ╠══════════════════════════════════════════════════════════╣
   ║  TIER 2 — ALIAS                                         ║
   ║  Brand values assigned to roles.                        ║
   ║  primary · neutral · info · error · success · warning   ║
   ║  Border widths and radii reference the number scale.    ║
   ╠══════════════════════════════════════════════════════════╣
   ║  TIER 3 — MAPS  (what CSS classes consume)              ║
   ║  --surface-*  --text-*  --border-*  --icon-*            ║
   ║  Rule: components reference ONLY Tier 3 tokens.         ║
   ╚══════════════════════════════════════════════════════════╝

   Dark-mode rule: brand colours (maroon, beige) are FIXED —
   they do not invert. Neutrals invert. Status colours adjust.
   ═══════════════════════════════════════════════════════════════ */


/* ─── FONT FACES ────────────────────────────────────────────── */
@font-face {
  font-family: 'Coconat';
  src: url('../coconat_font/Coconat-Regular.woff2') format('woff2'),
       url('../coconat_font/Coconat-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Coconat';
  src: url('../coconat_font/Coconat-Demi.woff2') format('woff2'),
       url('../coconat_font/Coconat-Demi.woff') format('woff');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Coconat';
  src: url('../coconat_font/Coconat-Bold.woff2') format('woff2'),
       url('../coconat_font/Coconat-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}


/* ════════════════════════════════════════════════════════════════
   TIER 1 · BRAND — Raw values in purest form
   ════════════════════════════════════════════════════════════════ */
:root {

  /* ────────────────────────────────────────────────────────────
     1A · COLOR SCALES
     Generated via opacity-on-white (lighter tints) and
     opacity-on-black (darker shades), then colour-matched to
     opaque hex — no opacity values in the final scale.
     Higher number = darker. Brand anchor sits at 500.
     50 / 150 / 250 used when a step breaks the opacity interval.
     ────────────────────────────────────────────────────────────  */

  /* Maroon — primary brand colour */
  --maroon-50:  #faf0f2;
  --maroon-100: #f0d9de;
  --maroon-200: #daadb7;
  --maroon-300: #c07d8e;
  --maroon-400: #8a4358;
  --maroon-500: #401F28;   /* ★ brand anchor */
  --maroon-600: #311520;   /* darker — generated on-black */
  --maroon-700: #200e16;
  --maroon-800: #12080d;

  /* Beige — secondary brand colour */
  --beige-50:   #fdfcfb;
  --beige-100:  #faf8f6;
  --beige-200:  #f2ede8;
  --beige-300:  #ece6df;
  --beige-400:  #e4dcd3;
  --beige-500:  #E9E2DA;   /* ★ brand anchor */
  --beige-600:  #d0c8bf;
  --beige-700:  #b8b0a7;
  --beige-800:  #9e968e;
  --beige-900:  #7a6e68;

  /* Steel Blue — info / interactive accent */
  --blue-50:    #f0f4f7;
  --blue-100:   #dde8f0;
  --blue-200:   #C0CDD8;   /* ★ brand light blue (from brand-core) */
  --blue-300:   #97B3C4;
  --blue-400:   #6B96AE;
  --blue-500:   #3D6E8C;   /* ★ interactive anchor — WCAG AA on white */
  --blue-600:   #2f5a75;
  --blue-700:   #24475d;
  --blue-800:   #193446;

  /* ────────────────────────────────────────────────────────────
     1B · FONT FAMILIES   (string values only — no role yet)
     ────────────────────────────────────────────────────────────  */
  --font-coconat: 'Coconat', 'Georgia', serif;

  /* ────────────────────────────────────────────────────────────
     1C · NUMBER SCALE   (4px base unit)
     Everything numeric — spacing, radius, border width —
     derives from this one scale.

     Naming: every clean 4px multiple = a 100-step value.
       scale-25  = 1px   (quarter step, for border widths)
       scale-50  = 2px   (half step, for focus rings)
       scale-100 = 4px   (first full step)
       …
     When the scale gets large, jump in larger increments
     (900→40, 1000→48, 1100→64) rather than listing 64 steps.
     ────────────────────────────────────────────────────────────  */
  --scale-25:   1px;
  --scale-50:   2px;
  --scale-100:  4px;
  --scale-150:  6px;
  --scale-200:  8px;
  --scale-250:  10px;
  --scale-300:  12px;
  --scale-400:  16px;
  --scale-500:  20px;
  --scale-600:  24px;
  --scale-700:  28px;
  --scale-800:  32px;
  --scale-900:  40px;   /* jump: 32 → 40 */
  --scale-1000: 48px;
  --scale-1100: 64px;
  --scale-1200: 80px;
  --scale-1300: 96px;
  --scale-1400: 128px;


  /* ════════════════════════════════════════════════════════════
     TIER 2 · ALIAS — Brand values assigned to roles
     Role mapping (Auravox):
       primary   → maroon scale
       neutral   → beige/warm-gray scale
       info      → blue scale
       error     → #c03030  (distinct from primary maroon)
       success   → #2e7a4a
       warning   → #9e5a10
     ════════════════════════════════════════════════════════════ */

  /* ─── Border Widths — from number scale ─── */
  --border-w-none:   0px;
  --border-w-small:  var(--scale-25);   /* 1px — default borders */
  --border-w-medium: var(--scale-50);   /* 2px — focus rings      */
  --border-w-large:  var(--scale-100);  /* 4px — heavy emphasis   */

  /* ─── Border Radii — from number scale ─── */
  --radius-none:  0px;
  --radius-sm:    var(--scale-50);    /* 2px */
  --radius-base:  var(--scale-150);   /* 6px  — buttons, inputs  */
  --radius-md:    var(--scale-200);   /* 8px  — cards, modals    */
  --radius-lg:    var(--scale-300);   /* 12px */
  --radius-xl:    var(--scale-400);   /* 16px */
  --radius-round: 9999px;

  /* Component aliases (alias → radius) */
  --radius-btn:    var(--radius-base);
  --radius-input:  var(--radius-base);
  --radius-card:   var(--radius-md);
  --radius-badge:  var(--radius-sm);
  --radius-chip:   var(--radius-round);


  /* ════════════════════════════════════════════════════════════
     TIER 3 · MAPS — Component-ready tokens
     Components consume ONLY these. Never reference Tier 1/2
     primitives directly in component CSS.

     Four groups: --surface-*  --text-*  --border-*  --icon-*

     FIXED tokens (marked ✦) do not change in dark mode.
     ════════════════════════════════════════════════════════════ */

  /* Status primitives — referenced only within maps below */
  --_success: #2e7a4a;
  --_warning: #9e5a10;
  --_error:   #c03030;
  --_info:    var(--blue-500);   /* #3D6E8C */

  /* ─── MAPS · Surface ─── */
  --surface-page:              var(--beige-100);   /* page background          */
  --surface-default:           #ffffff;             /* cards, inputs, modals    */
  --surface-raised:            var(--beige-200);   /* slightly elevated         */
  --surface-elevated:          var(--beige-300);   /* more elevated             */
  --surface-action:            var(--maroon-500);  /* ✦ primary button fill     */
  --surface-action-hover:      #5a2c38;            /* ✦ lighter — dark btn hover*/
  --surface-action-subtle:     var(--maroon-50);   /* ✦ tint for badges/tags    */
  --surface-info:              var(--blue-100);    /* light — alerts, info bg   */
  --surface-info-solid:        var(--blue-500);    /* ✦ solid — accent buttons  */
  --surface-info-solid-hover:  var(--blue-600);    /* ✦ accent button hover     */
  --surface-success:           rgba(46, 122, 74,   0.10);
  --surface-warning:           rgba(158, 90, 16,   0.10);
  --surface-error:             rgba(192, 48, 48,   0.10);
  --surface-disabled:          var(--beige-300);

  /* ─── MAPS · Text ─── */
  --text-heading:       #1a1512;              /* near-black, warm          */
  --text-body:          #1a1512;
  --text-muted:         var(--beige-900);     /* #7a6e68 secondary labels  */
  --text-subtle:        var(--beige-900);     /* #7a6e68 tertiary / hints — was beige-800
                                                  (#9e968e, 2.91:1 on white), which fails WCAG AA
                                                  for the small caption/hint text it's actually
                                                  used for sitewide. beige-900 is the darkest step
                                                  in the scale that still reads as "quiet" and is
                                                  the first one that clears 4.5:1 on beige-100 too
                                                  (4.66:1) — the same "only two tiers hold up"
                                                  finding the footer ramp below already made. */
  --text-action:        var(--maroon-500);    /* links, active states      */
  --text-action-hover:  var(--maroon-400);    /* lighter hover on dark text*/
  --text-disabled:      var(--beige-700);     /* #b8b0a7                   */
  --text-on-action:     var(--beige-500);     /* ✦ text ON maroon bg       */
  --text-on-accent:     #ffffff;              /* ✦ text ON blue bg         */
  --text-success:       var(--_success);
  --text-warning:       var(--_warning);
  --text-error:         var(--_error);

  /* ─── MAPS · Discount ramp ───
     The charged price of a discounted piece, in four rungs: the bigger the saving, the brighter
     the red. Five points of discount per rung, so the shipped 5/10/15/20 ladder uses all four.

     A ramp of its own rather than --text-error. They would read alike and mean the opposite: red
     on this shop means "something is wrong" everywhere else, and the one place it must not is
     the number a shopper is being told they saved on. So it starts ON the brand — rung 1 is
     within touching distance of --maroon-500 — and gains chroma rather than jumping to a
     signal red. Rung 4 is still no further from the anchor than --maroon-400 is.

     Measured on --surface-default, which is the card these sit on: 10.70 / 8.37 / 6.75 / 5.64
     against white. AA for normal text is 4.5, so the brightest rung still clears it with room.
     Contrast FALLS as the ramp brightens, which is the intended reading — the eye is meant to
     catch rung 4 first. */
  --price-off-1:        #6E2433;   /* >5%  — 10.70:1 */
  --price-off-2:        #93203A;   /* >10% —  8.37:1 */
  --price-off-3:        #B01F3E;   /* >15% —  6.75:1 */
  --price-off-4:        #C81E42;   /* >20% —  5.64:1 */

  /* The step bubble's fill, on a --surface-raised block. It must sit LIGHTER than what it is
     on, the way the weight card's bubble lifts off the maroon — a chip that is darker than its
     surroundings reads as a hole punched in the block rather than as a tag laid on it.
     --surface-elevated cannot do this job: the beige scale darkens as it elevates, so in light
     mode "elevated" is the wrong direction. It is a token per theme for that reason.

     ON the beige scale, not white. White is off the scale entirely and read as a hole cut
     through to the page beneath rather than as a warm chip sitting on a warm block — the one
     bright thing in a row whose loudest element is supposed to be the price. --beige-100 is the
     single step between white and --surface-raised, so it is the whole answer to "lighter than
     the block, darker than white".

     1.10:1 against #f2ede8, and 1.06:1 off white. Deliberately slight — enough to separate the
     chip, not so much that a percentage outshines the price it belongs to. The border does the
     defining. */
  --price-off-bubble:   var(--beige-100);
  --text-info:          var(--_info);

  /* ─── MAPS · Border ─── */
  --border-default:       #ddd6ce;
  --border-strong:        #c9bfb6;
  --border-action:        var(--maroon-500);  /* ✦ primary button border   */
  --border-action-hover:  #5a2c38;            /* ✦ matches surface hover   */
  --border-focus:         var(--blue-500);    /* focus rings               */
  --border-disabled:      var(--beige-400);
  --border-success:       rgba(46, 122, 74,   0.40);
  --border-warning:       rgba(158, 90, 16,   0.40);
  --border-error:         rgba(192, 48, 48,   0.40);
  --border-info:          var(--blue-300);

  /* ─── MAPS · Icon ─── */
  --icon-default:       var(--beige-900);    /* #7a6e68 neutral icon      */
  --icon-action:        var(--maroon-500);
  --icon-action-hover:  #5a2c38;
  --icon-on-action:     var(--beige-500);    /* ✦ on maroon bg            */
  --icon-on-accent:     #ffffff;             /* ✦ on blue bg              */
  --icon-disabled:      var(--beige-700);
  --icon-success:       var(--_success);
  --icon-warning:       var(--_warning);
  --icon-error:         var(--_error);
  --icon-info:          var(--_info);

  /* ─── MAPS · Badge hallmark (over-image) ─── ✦ all FIXED, theme-independent
     The 925 stamp and the "New" flag sit over photography, so their colours are
     fixed opaque values — a translucent tint would let the image show through —
     and must NOT invert in dark mode. Each is one hallmark ramp: a light fill,
     a mid-tone border, dark ink. The 925 is blue; the flag is green. */
  --badge-925-fill:    #dde8f0;   /* light blue  — fill   */
  --badge-925-border:  #97b3c4;   /* mid blue    — border */
  --badge-925-ink:     #2f5a75;   /* dark blue   — text — was #3d6e8c (blue-500), a borderline
                                      4.43:1 on the fill above; this is blue-600, 5.94:1, same hue */
  --badge-new-fill:    #ddefe4;   /* light green — fill   */
  --badge-new-border:  #93c1a4;   /* mid green   — border */
  --badge-new-ink:     #2e7a4a;   /* dark green  — text (brand success) */

  /* ─── MAPS · Result-card badge tiers ─── ✦ all FIXED, theme-independent
     TWO TONES, not five hues. The neutral badges on a find-by-fit card are one
     family in two weights, and the weight carries the TIER rather than the kind:

       note  — Classic, Lightest, Boldest, Densest, Longest   the rare ones
       spec  — Pendant, Dense, Light, Layering/Everyday/…      plain facts

     This replaced a four-hue scheme (warm beige / rose / blue / pale beige) that
     collided with the rest of the shop twice over. `substantial` was blue-200,
     one step off --badge-925-fill, so a "Dense" badge read as a second hallmark
     beside the real one. `delicate` was maroon-100, the fit badges' own hue —
     and maroon/blue carry this shop's GENDER convention (chain-copy WEARER, and
     the gauge guide's tone: 'male'), so light-vs-heavy arrived as
     feminine-vs-masculine, which is not a reading we chose or want.

     Blue now belongs to the hallmark alone, green to NEW, red to a discount, and
     maroon to the one badge that is us pointing at something. Everything factual
     is beige, and a badge is louder only by being rarer — which is also simply
     how fine jewellery is merchandised. The glyph says WHICH fact; the tone says
     how much to care.

     `note` sits a step deeper than the 925 stamp (--badge-925-fill), as the old
     rule required. `spec` is deliberately paler than it: that rule was written
     when there were two badges and both were claims, and this tier exists to be
     the one that does not compete.

     Inks are literals rather than scale steps: beige-900 lands at 4.1:1 on these
     fills, under AA at 10px. */
  --tag-note-fill:          var(--beige-400);
  --tag-note-border:        var(--beige-800);
  --tag-note-ink:           #3d352f;          /* deep warm brown — 8.9:1 on the fill */
  --tag-spec-fill:          var(--beige-100);
  --tag-spec-border:        var(--beige-700);
  --tag-spec-ink:           #5f544d;          /* mid warm brown — 6.9:1 on the fill */

  /* ─── MAPS · ON THE MAROON GROUND ─── ✦ all FIXED
     A whole surface — the shop footer — is beige on maroon, and none of the maps above work
     there. --border-default is a light warm grey that vanishes on maroon; --text-muted is a
     grey that goes muddy on it; --text-error is a red that is close to unreadable against a
     dark red ground. So the footer was carrying eight hardcoded rgba() literals and a hex,
     and the next component built on maroon would have invented its own, slightly different.

     These are beige-500 at set alphas, so they sit on the ground they are given rather than
     being flat colours that only happen to look right on one background. They do NOT invert in
     dark mode, because maroon does not: the footer looks the same in both themes, deliberately.

     Use `color:` with these rather than `opacity:` on the element — opacity fades an element's
     children too, which is fine for a bare link and wrong for anything with structure. Keep
     `opacity` for interaction states (a hover fade), where fading the whole element is exactly
     the intent.

     There are only two text tiers, and that is deliberate. The footer had been dimming beige to
     .72 / .55 / .50 for three levels of quiet — but .55 measures 4.46:1 against maroon and .50
     measures 3.92:1, and both were being used on the 10px uppercase eyebrows and the copyright
     line. That is small text, so WCAG AA wants 4.5:1, and the ramp does not clear it until .58.
     Once every legible tier has to sit at .58 or above, a third one is just two names for the
     same colour. Contrast measured, not guessed — the ratios are in the comments. */
  --surface-on-action-subtle:  rgba(233, 226, 218, 0.08);  /* input fill                  */
  --surface-on-action-hover:   rgba(233, 226, 218, 0.14);  /* input fill, focused         */
  --border-on-action-subtle:   rgba(233, 226, 218, 0.16);  /* hairline rules — decorative */
  --border-on-action:          rgba(233, 226, 218, 0.28);  /* input border                */
  --text-on-action-muted:      rgba(233, 226, 218, 0.72);  /* 6.56:1 — secondary copy     */
  --text-on-action-subtle:     rgba(233, 226, 218, 0.60);  /* 5.02:1 — the quietest text
                                                              that is still text: eyebrows,
                                                              the copyright line, the star */
  --text-error-on-action:      #f0b4b4;                    /* 8.23:1 — --text-error is a
                                                              dark red, near unreadable on
                                                              a dark red ground; this is a
                                                              light rose that holds up      */


  /* ════════════════════════════════════════════════════════════
     TYPOGRAPHY
     Scale: Major Third (×1.25) with base 16px,
            rounded to nearest 4px multiple.
     Line heights: font-size × 1.2, rounded to nearest 4px.
     ════════════════════════════════════════════════════════════ */

  --font-base: var(--font-coconat);

  /* ─── Type Scale — mobile-first
     Defaults are mobile sizes. Headings scale up at 768px via
     the @media (min-width: 768px) :root block below.
     Paragraphs (body/body-sm/caption/label) never change.
     ─── */
  --type-display:  3rem;      /* mobile 48px  → desktop 60px  */
  --type-h2:       2.5rem;    /* mobile 40px  → desktop 48px  */
  --type-h3:       2rem;      /* mobile 32px  → desktop 40px  */
  --type-h4:       1.75rem;   /* mobile 28px  → desktop 32px  */
  --type-h5:       1.5rem;    /* 24px — same both             */
  --type-h6:       1.25rem;   /* 20px — same both             */
  --type-body-lg:  1.25rem;   /* 20px — same both             */
  --type-body:     1rem;      /* 16px — baseline              */
  --type-body-sm:  0.875rem;  /* 14px                         */
  --type-caption:  0.75rem;   /* 12px — caption / legal       */
  --type-label:    0.625rem;  /* 10px — eyebrow / badge label */

  /* ─── Line Heights — match mobile type sizes ─── */
  --lh-display:  3.5rem;    /* mobile 56px  → desktop 72px */
  --lh-h2:       3rem;      /* mobile 48px  → desktop 56px */
  --lh-h3:       2.5rem;    /* mobile 40px  → desktop 48px */
  --lh-h4:       2rem;      /* mobile 32px  → desktop 40px */
  --lh-h5:       1.75rem;   /* 28px — same both            */
  --lh-h6:       1.5rem;    /* 24px — same both            */
  --lh-body-lg:  1.5rem;    /* 24px                        */
  --lh-body:     1.25rem;   /* 20px                        */
  --lh-body-sm:  1rem;      /* 16px                        */
  --lh-caption:  1rem;      /* 16px                        */

  /* ─── Leading — UNITLESS multipliers, for text that wraps ───
     The --lh-* tokens above are FIXED heights, each cut to pair with one --type-* size. That
     is right for a heading, which is set once at a known size and should sit on a predictable
     baseline. It is wrong for prose: --lh-body is 20px against 16px text — a ratio of 1.25,
     which is far too tight to read a paragraph in, and it does not scale if the font size does.

     So: fixed --lh-* for headings and single-line labels. Unitless --leading-* for anything
     that runs to a second line. Every line-height in the shop that was a bare number is one of
     these — they had drifted to 1.2/1.3/1.4/1.5/1.55/1.7, six values doing the work of four. */
  --leading-tight:   1.2;   /* headings, card titles — display text that must not sprawl */
  --leading-snug:    1.35;  /* compact UI copy, meta rows                                */
  --leading-normal:  1.5;   /* default for wrapping interface text                       */
  --leading-relaxed: 1.6;   /* notes, ledes                                              */
  --leading-loose:   1.7;   /* long-form prose — the legal pages                         */

  /* ─── Letter Spacing ─── */
  --tracking-tighter: -0.03em;
  --tracking-tight:   -0.01em;
  --tracking-normal:   0em;
  --tracking-wide:     0.04em;
  --tracking-wider:    0.10em;
  --tracking-widest:   0.18em;   /* eyebrows, all-caps micro labels */

  /* ─── Weights ─── */
  --weight-regular: 400;
  --weight-demi:    600;
  --weight-bold:    700;

  /* ─── Brand mark ───
     The four-pointed star (U+2726). It had been living in this file as a documentation
     glyph — the "✦ = FIXED in dark mode" marker below — but it is a brand element, not an
     annotation, and it is now set in the shop (the footer rule). One definition, so it
     cannot be typed as ✧ or ✳ somewhere and quietly become a second star.

     Usage: `content: var(--brand-star)` on a decorative pseudo-element, or the character
     itself inside an `aria-hidden` span. It is an ornament — never expose it to a screen
     reader, which reads it aloud as "black four pointed star". */
  --brand-star: '✦';


  /* ════════════════════════════════════════════════════════════
     SPACING — derived from the Tier 1 number scale
     ════════════════════════════════════════════════════════════ */
  --space-px:  var(--scale-25);    /*  1px */
  --space-0h:  var(--scale-50);    /*  2px */
  --space-1:   var(--scale-100);   /*  4px */
  --space-1h:  var(--scale-150);   /*  6px */
  --space-2:   var(--scale-200);   /*  8px */
  --space-2h:  var(--scale-250);   /* 10px */
  --space-3:   var(--scale-300);   /* 12px */
  --space-4:   var(--scale-400);   /* 16px */
  --space-5:   var(--scale-500);   /* 20px */
  --space-6:   var(--scale-600);   /* 24px */
  --space-7:   var(--scale-700);   /* 28px */
  --space-8:   var(--scale-800);   /* 32px */
  --space-10:  var(--scale-900);   /* 40px */
  --space-12:  var(--scale-1000);  /* 48px */
  --space-16:  var(--scale-1100);  /* 64px */
  --space-20:  var(--scale-1200);  /* 80px */
  --space-24:  var(--scale-1300);  /* 96px */
  --space-32:  var(--scale-1400);  /* 128px */


  /* ════════════════════════════════════════════════════════════
     SHADOWS — maroon-tinted for warmth
     ════════════════════════════════════════════════════════════ */
  --shadow-none:        none;
  --shadow-xs:          0 var(--scale-25)   var(--scale-50)    rgba(64, 31, 40, 0.05);
  --shadow-sm:          0 var(--scale-25)   var(--scale-100)   rgba(64, 31, 40, 0.07);
  --shadow-soft:        0 var(--scale-50)   var(--scale-250)   rgba(64, 31, 40, 0.08);
  --shadow-md:          0 var(--scale-100)  var(--scale-400)   rgba(64, 31, 40, 0.10);
  --shadow-lg:          0 var(--scale-200)  var(--scale-800)   rgba(64, 31, 40, 0.14);
  --shadow-xl:          0 var(--scale-400)  var(--scale-1100)  rgba(64, 31, 40, 0.18);
  --shadow-focus:       0 0 0 var(--scale-50)  rgba(61, 110, 140, 0.28);
  --shadow-focus-error: 0 0 0 var(--scale-50)  rgba(192, 48, 48, 0.22);


  /* ════════════════════════════════════════════════════════════
     MOTION
     ════════════════════════════════════════════════════════════ */
  --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-in:      cubic-bezier(0.4, 0, 1, 1);
  --ease-out:     cubic-bezier(0, 0, 0.2, 1);
  --ease-spring:  cubic-bezier(0.34, 1.56, 0.64, 1);

  --duration-fast:   100ms;
  --duration-base:   150ms;
  --duration-slow:   250ms;
  --duration-slower: 350ms;

  --transition-fast:   var(--duration-fast)   var(--ease-default);
  --transition-base:   var(--duration-base)   var(--ease-default);
  --transition-slow:   var(--duration-slow)   var(--ease-default);
  --transition-layout: var(--duration-slower) var(--ease-default);


  /* ════════════════════════════════════════════════════════════
     LAYOUT & Z-INDEX
     ════════════════════════════════════════════════════════════ */
  --max-w:        1200px;
  --max-w-prose:  680px;
  --max-w-narrow: 480px;
  --nav-h:        56px;        /* mobile → 64px at --bp-md */
  --page-px:      var(--space-4); /* 16px mobile gutters → 32px desktop */

  /* The air above a sticky tab strip's labels. The strips carry a bottom border and their tabs a
     2px indicator border, both of which add to the underside of the label; this is what makes the
     space above match the space below. /affiliate and /account.html share it. */
  --nav-strip-pad-top: 3px;

  --z-base:    1;
  --z-raised:  10;
  --z-nav:     100;
  --z-overlay: 200;
  --z-drawer:  300;
  --z-modal:   400;
  --z-toast:   500;
}


/* ════════════════════════════════════════════════════════════════
   DARK MODE
   Only Tier 3 maps tokens are overridden.
   ✦ FIXED tokens (brand colours) are NOT listed here —
     maroon surfaces, beige text-on-action, blue accent solids
     remain unchanged in dark mode.
   ════════════════════════════════════════════════════════════════ */
[data-theme="dark"] {

  /* ── Surfaces (neutrals invert) ── */
  --surface-page:         #100d0e;
  --surface-default:      #1c1618;
  --surface-raised:       #251e20;
  --surface-elevated:     #2e2326;
  --surface-disabled:     #2a2224;
  --surface-action-subtle: rgba(64, 31, 40, 0.28);

  /* Status surfaces — increase opacity for dark backgrounds */
  --surface-success: rgba(46, 122, 74,   0.18);
  --surface-warning: rgba(158, 90, 16,   0.18);
  --surface-error:   rgba(192, 48, 48,   0.18);
  --surface-info:    rgba(61, 110, 140,  0.18);

  /* ── Text (neutrals invert) ── */
  --text-heading:      var(--beige-500);   /* #E9E2DA */
  --text-body:         var(--beige-500);
  --text-muted:        #9e948e;
  --text-subtle:       #9e948e;   /* was #6a6060 (2.93:1 on --surface-default) — same AA-fail
                                      pattern as light mode; collapsed onto --text-muted's value */
  --text-action:       var(--maroon-300);  /* lighter for dark bg */
  --text-action-hover: var(--maroon-200);
  --text-info:         var(--blue-300);   /* lighter blue on dark bg */
  --text-disabled:     #5a5050;
  /* ✦ text-on-action: beige on maroon — stays */
  /* ✦ text-on-accent: white on blue — stays   */

  /* Discount ramp — inverted, because the light ramp darkens toward the anchor and a dark red
     on a #1c1618 card is unreadable at any rung. Same direction of travel (rung 4 the most
     vivid), reached by adding light instead of removing it: 6.83 / 6.41 / 6.09 / 5.98 on
     --surface-default. Flatter than the light ramp by necessity — there is less headroom above
     a dark ground — so the rungs separate on hue more than on contrast here. */
  --price-off-1:       #D98A99;   /* 6.83:1 */
  --price-off-2:       #E8798C;   /* 6.41:1 */
  --price-off-3:       #F4697F;   /* 6.09:1 */
  --price-off-4:       #FF5C75;   /* 5.98:1 */

  /* Lighter than --surface-raised here too — 1.08:1 against #251e20, matching the light theme's
     1.10 so the chip lifts by the same amount either way. --surface-elevated does the job
     directly on this side: the neutrals invert in dark mode, so "elevated" genuinely means
     lighter here, which is exactly why the light theme could not use the same token.
     --border-strong also reads better on it (1.58:1) than on anything brighter — the two
     converge as the fill lifts. */
  --price-off-bubble:  var(--surface-elevated);

  /* ── Borders (neutrals invert) ── */
  --border-default:  #3a3032;
  --border-strong:   #4e4244;
  --border-disabled: #3a3032;
  /* ✦ border-action and border-focus — stay */

  /* Status borders */
  --border-success: rgba(46, 122, 74,   0.38);
  --border-warning: rgba(158, 90, 16,   0.38);
  --border-error:   rgba(192, 48, 48,   0.38);
  --border-info:    var(--blue-600);

  /* ── Icons (neutrals invert) ── */
  --icon-default:  var(--beige-700);   /* #b8b0a7 */
  --icon-disabled: #5a5050;
  /* ✦ icon-on-action, icon-on-accent — stay */

  /* ── Shadows ── */
  --shadow-xs: 0 var(--scale-25)  var(--scale-50)    rgba(0, 0, 0, 0.25);
  --shadow-sm: 0 var(--scale-25)  var(--scale-100)   rgba(0, 0, 0, 0.30);
  --shadow-md: 0 var(--scale-100) var(--scale-400)   rgba(0, 0, 0, 0.40);
  --shadow-lg: 0 var(--scale-200) var(--scale-800)   rgba(0, 0, 0, 0.50);
  --shadow-xl: 0 var(--scale-400) var(--scale-1100)  rgba(0, 0, 0, 0.60);
}


/* ════════════════════════════════════════════════════════════════
   RESPONSIVE — Desktop scale-up at 768px
   Mobile is the default. This block upgrades layout tokens,
   type scale, and spacing for wider viewports.

   BREAKPOINT POLICY (docs/redesign/REDESIGN-PLAN.md §3):
   this file cannot expose --bp-* as real custom properties — a
   `@media` condition can't consume a CSS variable — so instead this is
   the one place they are written down, and every new `@media` rule
   anywhere in the shop must snap to one of these four literal values:
     sm 480px · md 768px · lg 1024px · xl 1200px
   Before the redesign pass this codebase had drifted to 20+ distinct
   breakpoint values (359, 400, 440, 560, 600, 640, 700, 760, 900,
   960, 1000, 1150, …) — components on the same page reflowing on
   different schedules. The visible grids (product/style/finder/guide/
   learn/value) were migrated onto the four values above; a handful of
   secondary component breakpoints in auth.css/affiliate.css were left
   as a follow-up (lower visual impact, flagged in the redesign PR).
   Three standing exceptions, each documented at its own rule and each
   keyed to CONTENT width rather than a device class:
     · the sub-380px nav-overflow hotfix a few lines below (real 320px
       viewport overflow);
     · .finder-grid, keyed to the space left beside the configurator
       panel, not the viewport;
     · .product-grid / .style-grid, which take their 2-up step at 400px.
       The sm tier would hold them at one column from 400-479px — iPhone
       XR/11 (414), Pro Max (428/430), most large Androids (412) — and
       halve what a shopper sees per screen on the main browse grids.
   An exception must say what sets it and be verifiable; a value with no
   such note is drift, and gets snapped to the scale.
   ════════════════════════════════════════════════════════════════ */
@media (min-width: 768px) {
  :root {
    /* Type scale — scale up headings for desktop */
    --type-display:  3.75rem;   /* 60px */
    --type-h2:       3rem;      /* 48px */
    --type-h3:       2.5rem;    /* 40px */
    --type-h4:       2rem;      /* 32px */

    /* Line heights to match */
    --lh-display:  4.5rem;    /* 72px */
    --lh-h2:       3.5rem;    /* 56px */
    --lh-h3:       3rem;      /* 48px */
    --lh-h4:       2.5rem;    /* 40px */

    /* Layout */
    --nav-h:    64px;
    --page-px:  var(--space-8); /* 32px gutters */
  }
}
