/*
 * eSIM Store — Design tokens
 * Direction: Voyager (cream base, sage green, warm coral)
 *
 * Source of truth: deliverables/design/tokens.css
 * This file is a verbatim port MINUS the Google Fonts @import (fonts are
 * self-hosted via @font-face in enqueue.php / inc/enqueue.php).
 *
 * Variable naming: uses --color-* (design system names).
 * A shim block at the bottom maps WP theme.json --wp--preset--color--*
 * outputs back onto these names so components.css works without change.
 *
 * ADR: docs/decisions/ADR-004-components-css-wholesale-port.md
 */

/*
 * ESM-49 — every colour below that is used AS TEXT carries a measured WCAG 2.1
 * AA ratio against the ground it renders on. Numbers are in ADR-010; the sweep
 * that produces them is Standards/tools/visual-audit/esm49-contrast.mjs.
 * Two rules when editing a value here:
 *   1. re-run the sweep — a token is only "safe" against a specific ground;
 *   2. never re-introduce contrast via `opacity`. Opacity MULTIPLIES down the
 *      tree (0.78 × 0.75 = 0.585) and the declared hex then tells you nothing
 *      about what the visitor sees. Express muting as a token, not an alpha.
 */
:root {
  /* —— Brand palette —————————————————————————— */
  --color-base:                #FBF7F0;
  --color-base-elevated:       #FFFFFF;
  --color-base-raised:         #FFFFFF;
  --color-contrast:            #0F1A2E;
  --color-contrast-muted:      #5A6478;
  --color-contrast-faint:      #697286;
  /* ESM-64 — #3C8369 measured 4.52:1 against white on the composited pixel: it
     PASSED AA, by 0.02. That is not a margin, it is a rounding artefact, and it
     is the ground under every CTA on the site ("Find eSIM", "Get this plan",
     "Place Order") AND the link colour on the cream base, where the same hex
     measured 4.24:1 and FAILED. Darkened to #35745D: 5.52:1 on white,
     5.17:1 on the cream base. Hover follows it down so the two stay
     distinguishable (#285846, 8.16:1).
     The value is pinned by `audit.mjs fidelity` (home → cta-contrast-lock), so
     a future tweak to the hue turns the gate red instead of passing silently —
     which was the second half of the finding. */
  --color-accent-1:            #35745D;
  --color-accent-1-hover:      #285846;
  --color-accent-1-soft:       #E4F0EA;
  --color-accent-2:            #D87A5C;
  --color-accent-2-hover:      #B65F44;
  --color-accent-2-soft:       #FBE8DF;
  --color-neutral:             #E6E0D4;
  --color-neutral-strong:      #CFC7B5;
  --color-success:             #2C7657;
  --color-success-soft:        #DDEEE4;
  --color-warning:             #8F5E18;
  --color-warning-soft:        #F5E6CC;
  --color-error:               #B63728;
  --color-error-soft:          #F6DCD6;
  --color-info:                #2F5E9E;
  --color-info-soft:           #DEE7F3;

  /* —— Live-data tokens (constant — never overridden by brand) ——————— */
  --color-region-europe:       #1F3360;
  --color-region-europe-soft:  #DCE4F4;
  --color-region-asia:         #7A3326;
  --color-region-asia-soft:    #F8DDD3;
  --color-region-americas:     #2B4A22;
  --color-region-americas-soft:#DDE9D9;
  --color-region-mena:         #6B3A0B;
  --color-region-mena-soft:    #F6DDB4;
  --color-region-africa:       #3D2D5C;
  --color-region-africa-soft:  #E5DCEE;
  --color-region-oceania:      #1F4D44;
  --color-region-oceania-soft: #D5E8E4;
  --color-region-global:       #2C2D33;
  --color-region-global-soft:  #E6E0D4;

  --color-tier-light:          #6B7280;
  --color-tier-standard:       #3968A6;
  --color-tier-heavy:          #3C8369;
  --color-tier-unlimited:      #7C5BC2;
  --color-tier-lifetime:       #B8862B;

  --color-status-created:      #6B7280;
  --color-status-installed:    #3968A6;
  --color-status-active:       #2C7657;
  --color-status-expiring:     #8F5E18;
  --color-status-expired:      #646C7B;
  --color-status-depleted:     #B63728;

  --color-hotspot-yes:         #2C7657;
  --color-hotspot-no:          #B63728;
  --color-hotspot-capped:      #8F5E18;

  /* —— Typography ———————————————————————————— */
  --font-family-heading: "Plus Jakarta Sans", system-ui, -apple-system, Segoe UI, sans-serif;
  --font-family-body:    "Plus Jakarta Sans", system-ui, -apple-system, Segoe UI, sans-serif;
  --font-family-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --font-size-sm:   0.875rem;
  --font-size-base: 1rem;
  --font-size-md:   1.125rem;
  --font-size-lg:   1.25rem;
  --font-size-xl:   1.875rem;
  --font-size-2xl:  2.5rem;
  --font-size-3xl:  3.5rem;
  --font-size-hero: clamp(2.5rem, 1.8rem + 3.5vw, 4rem);
  --font-size-page-h1: clamp(2rem, 1.5rem + 2.2vw, 2.75rem);

  --font-weight-regular:  400;
  --font-weight-medium:   500;
  --font-weight-semibold: 600;
  --font-weight-bold:     700;

  --line-height-tight:   1.15;
  --line-height-normal:  1.5;
  --line-height-relaxed: 1.7;

  --letter-spacing-tight:  -0.025em;
  --letter-spacing-normal: -0.005em;
  --letter-spacing-wide:    0.04em;

  /* —— Spacing scale ——————————————————————————— */
  --spacing-20: 0.4375rem;
  --spacing-30: 0.6875rem;
  --spacing-40: 1rem;
  --spacing-50: 1.5rem;
  --spacing-60: 2.25rem;
  --spacing-70: 3.375rem;
  --spacing-80: 5.0625rem;

  /* —— Radii ———————————————————————————————— */
  --radius-sm:   0.375rem;
  --radius-md:   0.625rem;
  --radius-lg:   1.125rem;
  --radius-xl:   1.75rem;
  --radius-full: 9999px;

  /* —— Shadows —————————————————————————————— */
  --shadow-sm:    0 1px 2px rgba(15,26,46,0.04), 0 1px 1px rgba(15,26,46,0.03);
  --shadow-md:    0 6px 18px -8px rgba(15,26,46,0.12), 0 2px 6px -2px rgba(15,26,46,0.06);
  --shadow-lg:    0 24px 48px -16px rgba(15,26,46,0.18), 0 4px 12px -4px rgba(15,26,46,0.08);
  --shadow-focus: 0 0 0 3px rgba(53,116,93,0.30);

  /* —— Transitions ————————————————————————————— */
  --transition-duration:      180ms;
  --transition-duration-slow: 280ms;
  --transition-easing:        ease-out;
  --transition-easing-soft:   cubic-bezier(0.4, 0, 0.2, 1);

  /* —— Layout ———————————————————————————————— */
  --container-max-width:  1280px;
  --container-gutter:     3.5rem;
  --touch-target:         44px;

  /* Reading measure — the width long-form text is set at, and the ONE place it
     is written down. 1168px of body copy is ~150 characters a line, which is
     unreadable; 44rem is ~85. Consumed only through `.es-measure-grid` in
     components.css, which centres it by construction — see the comment there
     before adding a `max-width: 44rem` anywhere else. */
  --measure-prose:        44rem;
  /* The signed-out auth columns: two 22rem cards plus the 24px gutter between
     them (ESM-72), and the single-card width the two password screens use.
     Same construction as the prose measure, different track. */
  --measure-auth:         46rem;
  --measure-auth-narrow:  30rem;

  --z-header-sticky: 50;
  --z-popover:       80;
  --z-modal:         100;
  --z-toast:         120;
}

@media (max-width: 1023.98px) { :root { --container-gutter: 2rem; } }
@media (max-width: 767.98px)  { :root { --container-gutter: 1.25rem; } }

/* ——————————————————————————————————————————————————————
   WP theme.json shim (bidirectional)
   WP generates --wp--preset--color--{slug} from theme.json palette.
   This block defines the --color-* design vars first (above), so this
   shim block is only needed for ONE direction: ensuring that any PHP
   code / patterns that reference --wp--preset--color--* get the right
   hex value in environments where WP's global styles sheet may not load
   (e.g. editor iframe before styles hydrate).

   Direction 2 (WP vars used in region-card.php gradient strings):
   The --wp--preset--color--region-* values ARE generated by WP from
   theme.json (region-* slugs are in the palette). So the region-card.php
   gradient references work. But we also define them here so they resolve
   in the front-end even if for some reason WP's global-styles.css loads
   after ours.
   —————————————————————————————————————————————————————— */
:root {
  /* Safety fallbacks: ensure WP preset vars always resolve */
  --wp--preset--color--base:                var(--color-base);
  --wp--preset--color--base-elevated:       var(--color-base-elevated);
  --wp--preset--color--contrast:            var(--color-contrast);
  --wp--preset--color--contrast-muted:      var(--color-contrast-muted);
  --wp--preset--color--contrast-faint:      var(--color-contrast-faint);
  --wp--preset--color--accent-1:            var(--color-accent-1);
  --wp--preset--color--accent-1-hover:      var(--color-accent-1-hover);
  --wp--preset--color--accent-1-soft:       var(--color-accent-1-soft);
  --wp--preset--color--accent-2:            var(--color-accent-2);
  --wp--preset--color--accent-2-hover:      var(--color-accent-2-hover);
  --wp--preset--color--accent-2-soft:       var(--color-accent-2-soft);
  --wp--preset--color--neutral:             var(--color-neutral);
  --wp--preset--color--neutral-strong:      var(--color-neutral-strong);
  --wp--preset--color--success:             var(--color-success);
  --wp--preset--color--success-soft:        var(--color-success-soft);
  --wp--preset--color--warning:             var(--color-warning);
  --wp--preset--color--warning-soft:        var(--color-warning-soft);
  --wp--preset--color--error:               var(--color-error);
  --wp--preset--color--error-soft:          var(--color-error-soft);
  --wp--preset--color--info:                var(--color-info);
  --wp--preset--color--info-soft:           var(--color-info-soft);

  /* Region tokens — used in region-card.php gradient strings */
  --wp--preset--color--region-europe:       var(--color-region-europe);
  --wp--preset--color--region-europe-soft:  var(--color-region-europe-soft);
  --wp--preset--color--region-asia:         var(--color-region-asia);
  --wp--preset--color--region-asia-soft:    var(--color-region-asia-soft);
  --wp--preset--color--region-americas:     var(--color-region-americas);
  --wp--preset--color--region-americas-soft:var(--color-region-americas-soft);
  --wp--preset--color--region-mena:         var(--color-region-mena);
  --wp--preset--color--region-mena-soft:    var(--color-region-mena-soft);
  --wp--preset--color--region-africa:       var(--color-region-africa);
  --wp--preset--color--region-africa-soft:  var(--color-region-africa-soft);
  --wp--preset--color--region-oceania:      var(--color-region-oceania);
  --wp--preset--color--region-oceania-soft: var(--color-region-oceania-soft);
  --wp--preset--color--region-global:       var(--color-region-global);
  --wp--preset--color--region-global-soft:  var(--color-region-global-soft);
}

/* —— Base reset ——————————————————————————————— */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--color-base);
  color: var(--color-contrast);
  font-family: var(--font-family-body);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
  letter-spacing: var(--letter-spacing-normal);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5 {
  font-family: var(--font-family-heading);
  margin: 0;
  letter-spacing: var(--letter-spacing-tight);
  line-height: var(--line-height-tight);
}
a { color: inherit; }

/* Focus visibility — WCAG 2.1 AA */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 0;
  box-shadow: var(--shadow-focus);
  border-radius: var(--radius-sm);
}

/* ── Theme-wide [hidden] safety net (TBE-21, layer 2) ─────────────────────────
 * `hidden` is a USER-AGENT rule, and author CSS beats the UA stylesheet by
 * ORIGIN — resolved before specificity and before source order. So ANY author
 * `display` on a hidden-toggled element, however weak the selector, makes it
 * paint while `el.hidden` still reads true. Nothing throws; the DOM says closed
 * and the pixels say open. Four recurrences on this lineage, two of them not
 * cosmetic (a 9,500px sidebar; a subscription confirmation shown to anonymous
 * visitors — a no-fabricated-data violation).
 *
 * This is layer 2 only. Every component keeps its own `.thing[hidden]` guard —
 * that is what `hidden-attr-guard.sh` category A enforces, and a net the gate
 * accepted as a substitute would be a gate that can never fire. The net exists
 * for what a static scan cannot resolve: classes composed at runtime, elements
 * built entirely in JS, `display` arriving from a plugin stylesheet.
 *
 * Two selectors, not one: `[class^=]` only matches when the class ATTRIBUTE
 * starts with the prefix, so it misses `class="empty-state es-foo"`.
 * `:not([hidden="until-found"])` is mandatory — that value is
 * `content-visibility: hidden`, and the element must stay display-able for
 * find-in-page to reveal it. `!important` is required or the rule merely ties a
 * component's own declaration and lets source order decide. Scoped to `es-`
 * rather than a blanket `[hidden]` so it can never reach WooCommerce's markup.
 *
 * Blast radius proven before shipping, not after: noop-probe-hidden.mjs over
 * 9 pages matched 6 elements, 0 of which computed a non-none display — i.e.
 * this rule provably cannot change a pixel on the tree as it stands today.
 * ─────────────────────────────────────────────────────────────────────────── */
[class^="es-"][hidden]:not([hidden="until-found"]),
[class*=" es-"][hidden]:not([hidden="until-found"]) { display: none !important; }
