/* ============================================================
   ZOXA.AI — DESIGN TOKENS · Ember v3.0
   Single source of truth. Every colour, font, size, space,
   radius, shadow, and motion value lives here as a variable.
   RULE: write the variable in code, never the hex.
   ============================================================ */

/* ------------------------------------------------------------
   1 · COLOUR — LIGHT THEME (default)
   Light = marketing, docs, pricing

   WARM NEUTRAL FAMILY — every off-white and warm grey below sits
   on hue 44 and is derived from --surface. The old ramp sat on hue
   ~27-32, which is pink-leaning, and read as cream.
   If you add a neutral, put it on hue 44 or it will look off.

   DO NOT LIGHTEN --surface FURTHER. The page canvas is pure white,
   so the plate only exists by contrast with it. At #F8F6F1 that
   contrast is 1.08:1 — already faint. Past roughly 1.05:1 a plate
   stops being perceptible on white at normal viewing distance and
   every card, pill and panel silently flattens into the page.
   If a lighter look is wanted, tint --bg instead and let the plates
   stay where they are.

   The text and control neutrals (--border-strong, --disabled, and
   --text/--muted/--bone on dark) were rehued at CONSTANT relative
   luminance, not constant HSL lightness. Rotating hue at fixed L
   moves luminance, because green is weighted ~7x blue — doing it
   the naive way cost --border-strong 0.45 of its contrast ratio.
   Match luminance, not L, if you ever retint these again.
   ------------------------------------------------------------ */
:root {
  --bg: #FFFFFF;                      /* page + section canvas    */
  --surface: #F8F6F1;                 /* cards, panels            */
  --surface-2: #F1EDE4;               /* nested, inputs, pills    */
  --border: #E4DED0;                  /* decorative dividers only */
  --border-strong: #7C7769;           /* form controls            */
  --text: #0F0A08;                    /* body copy                */
  --muted: #5D534D;                   /* secondary copy           */
  --disabled: #A09A8B;                /* inactive text            */
  --primary: #B93F17;                 /* actions, links           */
  --primary-hover: #943013;           /* hover, pressed           */
  --primary-soft: #FFF1E7;            /* tinted fill              */
  --on-primary: #FFFFFF;              /* label on a primary fill  */
  --signal: #8A5A00;                  /* live, listening, latency */
  --success: #0B7A52;                 /* resolved, uptime         */
  --danger: #A4231B;                  /* failed call, errors      */
  --grad: linear-gradient(160deg, #FF9E71, #B93F17 55%, #70210D);
  --card-media: #161010;              /* dark product panel on a light card */
  --card-media-2: #0F0A08;
}

/* ------------------------------------------------------------
   2 · COLOUR — DARK SURFACES
   Applies to any section marked [data-band="invert"]. A band's
   light/dark identity is fixed in the markup, so there is no theme
   state anywhere to fall out of sync.

   THE TWO EXTRA SELECTORS BELOW
   When the page turns over on scroll (assets/js/theme-scroll.js), the
   background is one surface shared by every section on screen. During
   a crossing, two sections with opposite bands are visible at once, so
   one of them is guaranteed to have its text on the wrong tone — a
   light section's body copy measured 1.30:1 against the darkened
   surface. Moving the blend around cannot fix that; something has to
   flip the TYPE as well.

   So the script marks whichever sections currently disagree with the
   surface, and those two classes let a section borrow the other set of
   tokens for as long as the disagreement lasts:

     .zx-force-dark          a light section, while the page is dark
     :not(.zx-force-light)   lets a dark section fall back to the
                             :root tokens while the page is light

   Written as one selector list rather than a second copy of the block,
   so there is still exactly one place these values live.
   ------------------------------------------------------------ */
[data-band="invert"]:not(.zx-force-light),
.zx-force-dark {
  --bg: #0F0A08;                      /* Ink — page canvas        */
  --surface: #1A1411;
  --surface-2: #2B221F;
  --border: #3F3631;
  --border-strong: #7C7769;
  /* Not the plate colour. Text on dark has to stay near-white: dropping it
     to #F2EFE7 put the hero headline at 2.97:1 on mid-ramp orange, under
     the 3:1 floor for display type. Rehued to 44 at its own luminance. */
  --text: #FBFAF6;
  --muted: #D3CBB7;
  --disabled: #A09A8B;
  --primary: #FF7A3E;
  --primary-hover: #FF9E71;
  --primary-soft: rgba(239, 90, 25, .14);
  --on-primary: #0F0A08;
  --signal: #F5C46B;
  --success: #3ED9A0;
  --danger: #FF8A80;
  --grad: linear-gradient(160deg, #FFC3A1, #FF7A3E 55%, #943013);
  --card-media: #2B221F;              /* must sit lighter than the card here */
  --card-media-2: #1F1815;
}

/* ------------------------------------------------------------
   3 · BRAND CONSTANTS (theme-independent)
   Ember 500 = logo / favicon / single-colour use ONLY.
   Never use as --primary — fails 4.5:1 on both canvases.
   ------------------------------------------------------------ */
:root {
  --ember-500: #EF5A19;
  --ink: #0F0A08;
  --bone: #FBFAF6;    /* near-white ink for dark surfaces — see --text above */
  /* Same colour as --bone, as bare channels. rgba() cannot take a hex var,
     so the decorative marks on dark card panels need this form. It is the
     one place a colour is duplicated: CHANGE IT WITH --bone OR THEY DRIFT.
     That drift is exactly how 74 elements kept painting the old cream after
     the rest of the palette had already moved. */
  --bone-rgb: 251, 250, 246;
  --white: #FFFFFF;   /* true white — for panels that must read cooler than
                         the warm neutrals, not a general-purpose surface */


  /* Ember ramp — atmosphere/gradient stops only. Never text colours. */
  --ember-100: #FFC3A1;
  --ember-300: #FF9E71;
  --ember-400: #FF7A3E;
  --ember-600: #B93F17;
  --ember-700: #943013;
  --ember-800: #70210D;

  /* ----------------------------------------------------------
     4 · TYPOGRAPHY — families
     Display = headings only. Body = everything readable.
     Mono = anything a machine produced.
     ---------------------------------------------------------- */
  --font-display: "Cabinet Grotesk", system-ui, sans-serif;
  --font-body: "Switzer", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* weights — ship these four only */
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-bold: 700;
  --fw-heavy: 800;

  /* type scale (fluid) */
  --fs-display: clamp(2.5rem, 1.4rem + 4.4vw, 5.5rem);   /* hero      */
  --fs-h1: clamp(2.5rem, 1.75rem + 3vw, 4rem);           /* h1        */
  --fs-h2: clamp(1.875rem, 1.4rem + 2vw, 2.75rem);       /* h2        */
  --fs-h3: clamp(1.25rem, 1.1rem + .7vw, 1.5rem);        /* h3        */
  --fs-h4: 1.125rem;                                      /* h4        */
  --fs-lead: clamp(1.0625rem, 1rem + .4vw, 1.25rem);     /* intros    */
  --fs-body: 1rem;                                        /* body      */
  --fs-small: .875rem;                                    /* small     */
  --fs-label: .6875rem;                                   /* eyebrows  */
  --fs-button: .9375rem;                                  /* buttons   */
  --fs-mono: .8125rem;                                    /* readouts  */

  /* line heights */
  --lh-display: 1.02;
  --lh-heading: 1.1;
  --lh-sub: 1.25;
  --lh-body: 1.6;
  --lh-small: 1.55;

  /* letter spacing */
  --ls-display: -.038em;   /* weight 800 headings   */
  --ls-heading: -.028em;   /* weight 700 headings   */
  --ls-label: .16em;       /* mono uppercase labels */

  /* ----------------------------------------------------------
     5 · SPACE — 4px base. Nine steps. Nothing between them.
     ---------------------------------------------------------- */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;
  --s9: 96px;

  /* section rhythm */
  --section-y: clamp(var(--s8), 10vw, 120px);
  --section-y-sm: clamp(var(--s7), 7vw, var(--s9));

  /* ----------------------------------------------------------
     6 · RADIUS — anchored to the hero panel.
     The hero's corner (24px) is the reference every other rounded
     surface is derived from, so nothing on the site is rounder than
     the hero and everything steps down from it in even 4px units.

     WRITE THE TOKEN, NEVER A RAW px VALUE.
     ---------------------------------------------------------- */
  --r-2xs:  4px;    /* micro tiles: grid cells, 6px dots          */
  --r-xs:   8px;    /* tag chips, tiny markers                    */
  --r-sm:  12px;    /* inputs, small badges, icon tiles           */
  --r-md:  16px;    /* buttons, nav bar — rounded rectangle       */
  --r-lg:  20px;    /* inner panels nested inside a card          */
  --r-xl:  24px;    /* ◀ HERO. Cards, panels, any large surface   */
  --r-2xl: 32px;    /* oversized feature panels only              */
  --r-full: 999px;  /* true circles only: dots, orbs, avatars     */

  /* semantic aliases — components reference these, so a component's
     intent is readable and one edit re-tunes every instance */
  --r-hero:   var(--r-xl);
  --r-card:   var(--r-xl);
  --r-nav:    var(--r-md);
  --r-button: var(--r-md);
  --r-input:  var(--r-md);   /* form controls share the button corner —
                                a 12px input beside a 16px button was the
                                mismatch visible in the footer */
  --r-chip:   var(--r-xs);
  /* arrow and icon tiles. A circle inside a squared button reads as a
     different family, so these step down from the button instead of
     going fully round. True circles (avatars, dots, orbs) use --r-full. */
  --r-icon:   var(--r-sm);

  /* ----------------------------------------------------------
     7 · LAYOUT
     ---------------------------------------------------------- */
  --container: 1200px;
  --container-wide: 1320px;
  --container-narrow: 800px;
  --container-nav: 1000px;   /* nav pill sits narrower than the content */
  --gutter: clamp(var(--s4), 4vw, var(--s6));
  --nav-height: 72px;

  /* ----------------------------------------------------------
     8 · ELEVATION — subtle. Warm-tinted, never grey-blue.
     ---------------------------------------------------------- */
  --shadow-sm: 0 1px 2px rgba(15, 10, 8, .05);
  --shadow-md: 0 4px 16px rgba(15, 10, 8, .07);
  --shadow-lg: 0 12px 40px rgba(15, 10, 8, .12);
  --shadow-glow: 0 0 64px rgba(239, 90, 25, .18);

  /* ----------------------------------------------------------
     9 · MOTION — fast, natural, consistent.
     transform + opacity only.
     ---------------------------------------------------------- */
  --dur-fast: 150ms;
  --dur-base: 250ms;
  /* Page theme turn-over. Deliberately the slowest thing on the site:
     it is a change of state, not a response to a click, so it should
     feel like the page settling rather than snapping.

     It can be this long precisely because it is time-based. The mid-
     fade greys are a zone where neither text colour reaches 4.5:1, but
     a timed transition always resolves out of them — they are a
     transient, never a resting state. A scroll-linked fade could not
     afford this duration. See .zx-backdrop in site.css. */
  --dur-theme: 760ms;
  --dur-slow: 450ms;
  --dur-reveal: 800ms;
  --dur-fill: 550ms;    /* radial hover fill */
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-spring: cubic-bezier(.34, 1.2, .64, 1);
  --ease-fill: cubic-bezier(.4, 0, .2, 1);

  /* ----------------------------------------------------------
     10 · Z-INDEX SCALE
     ---------------------------------------------------------- */
  --z-base: 0;
  --z-raised: 10;
  --z-nav: 100;
  --z-overlay: 200;
  --z-modal: 300;
  --z-toast: 400;
}
