/* ══ A.I.M.S. — the shared token layer ══════════════════════════════════════════════════════
   ONE source for every connected surface: acheevy.digital, chat.acheevy.digital,
   blog.acheevy.digital, and the funnels. They hand off to each other, so a visitor crossing
   between them must not feel a seam. Three copies of a palette is three palettes.

   EXTRACTED FROM THE DESIGNS, not chosen. Sampled across four screens in
   `keqSV0hR8Y58BMCs9MNsNO` — Landing / 01 RUN, Chat w/ACHEEVY / Default, Workspace / Missions,
   Workspace / Approval Center. All four agree: ground #000000, accent #ff8806.

   TWO PALETTES, AND THEY ARE NOT INTERCHANGEABLE:
     · PRODUCT (this file) — AgenticUI on pure black. Every app and marketing surface.
     · BRAND    — ONYX CORE / SMELTER ORANGE / ION CYAN / NEON VIBE / COPPER ALLOY. Identity
       expression: brand imagery, decks, physical, social. NOT the UI ground.
   Reaching for the brand card to paint a product surface is the mistake this header exists to
   stop. The designs are the authority for anything a user operates.
   ═════════════════════════════════════════════════════════════════════════════════════════ */

/* ══ THE FACES LIVE HERE, WITH THE NAMES THAT REFERENCE THEM ═══════════════════════════════
   Declaring a font-family in one file and its @font-face in another is how a face silently
   stops loading. That had already happened on three surfaces:

     landing.html  — set the rotating hero verb in "Permanent Marker" and never loaded it.
                     The centrepiece of the lockup was rendering in Geist in production.
     pricing.html  — --mono names "Departure Mono", no @font-face. Fell back to Geist Mono.
     studio.html   — same.

   Only chat.html and governance.html carried their own declarations, which is exactly the
   duplication that let the other three drift. A name and its face now ship together. Any
   surface that links this file can use every family named below.
   ═════════════════════════════════════════════════════════════════════════════════════════ */

/* The marker face uses `block`, not `swap`. Permanent Marker's metrics are nothing like
   Geist's, and the hero verb is size-tuned per word (RUN 72 → OPERATE 58) against THOSE
   metrics. Swapping in a fallback first paints a visibly wrong headline that then reflows —
   the same overflow that orphaned "IT." onto the image. `block` waits instead of lying. */
@font-face{font-family:'Permanent Marker';font-style:normal;font-weight:400;
  font-display:block;src:url(/assets/permanent-marker.woff2) format('woff2')}

/* Chrome and numerals are supporting tiers — a brief fallback there costs nothing. */
@font-face{font-family:'Departure Mono';font-style:normal;font-weight:400;
  font-display:swap;src:url(/assets/departure-mono.woff2) format('woff2')}
@font-face{font-family:'Doto';font-style:normal;font-weight:100 900;
  font-display:swap;src:url(/assets/doto-variable.woff2) format('woff2-variations')}

:root{
  /* ── ground and surfaces ─────────────────────────────────────────────────────────── */
  --aims-bg:        #000000;   /* every designed screen sits on pure black          */
  --aims-surface:   #090909;   /* cards, inputs, secondary buttons                   */
  --aims-surface-2: #0b0b0b;   /* nested panels inside a surface                     */
  --aims-inset:     #141414;   /* wells, tracks, disabled fills                      */

  /* ── line ────────────────────────────────────────────────────────────────────────── */
  --aims-border:    #393939;   /* the single border value across all four screens    */
  --aims-hairline:  #1f1f1f;   /* section rules, quieter than a border               */

  /* ── content, in the tiers the designs actually use ──────────────────────────────── */
  --aims-text:      #f7f7f7;   /* headlines, primary content                         */
  --aims-text-2:    #d1d1d1;   /* body, values                                       */
  --aims-text-3:    #a6a6a6;   /* supporting copy                                    */
  --aims-muted:     #8f8f8f;   /* labels, eyebrows, metadata  (AgenticUI N500)       */
  --aims-muted-2:   #616161;   /* the quietest legible tier   (AgenticUI CONTENT/Sec)*/
  --aims-nav:       #b8b8b8;   /* navigation items                                   */

  /* ── accent ──────────────────────────────────────────────────────────────────────── */
  --aims-accent:    #ff8806;   /* AgenticUI ORANGE O400 — the one accent             */
  --aims-accent-2:  #ec7303;   /* O500, pressed / hover                              */
  /* ── DECIDED 2026-07-30: the label on a FILLED accent is BLACK. ─────────────────────────
     The standing rule is white text on dark or coloured backgrounds. This is the ONE
     documented exception, and it is arithmetic rather than taste:

         white on #ff8806  =  2.26:1   fails WCAG AA (needs 4.5:1)
         black on #ff8806  =  9.34:1   passes AAA

     Every designed frame in the kit also specifies a black label on the accent fill, so the
     design and the contrast maths agree. `test_a_label_on_the_accent_fill_is_readable`
     enforces it by COMPUTING the ratio, so if the accent ever changes the rule re-evaluates
     itself instead of going stale.

     TO SWITCH TO WHITE, change the FILL and not the label — white needs a darker orange:
         --aims-accent:#C4400E (burnt)   white = 5.9:1  passes AA
         --aims-accent:#FF5C22 (smelter) white = 3.4:1  large text only, still fails for body
     Setting --aims-on-accent:#fff on the current accent would ship unreadable buttons, so
     the test refuses it. One line either way — but the fill moves, not the text. */
  --aims-on-accent: #000000;

  /* ── status ──────────────────────────────────────────────────────────────────────── */
  --aims-ok:        #3cc14e;   /* AgenticUI GREEN G500  — running, returned, healthy  */
  --aims-info:      #1bbfca;   /* AgenticUI TEAL T500   — signal, routing, in flight  */
  --aims-warn:      #ff8806;   /* attention borrows the accent; it is not a new hue   */
  --aims-danger:    #f02d2d;   /* AgenticUI RED R500                                  */

  /* ── type. Domaine is design-time only (Klim, unlicensed) — never in a shipped stack.
        Departure Mono is MIT and self-hosted. Doto carries numerals. ───────────────── */
  --aims-sans:      "Geist", system-ui, -apple-system, sans-serif;
  --aims-mono:      "Geist Mono", ui-monospace, monospace;
  --aims-chrome:    "Departure Mono", "Geist Mono", ui-monospace, monospace;
  --aims-num:       "Doto", "Geist Mono", ui-monospace, monospace;
  --aims-marker:    "Permanent Marker", var(--aims-sans);   /* the rotating hero verb  */
  /* The name is NOT set in the body face. Departure Mono is our licensed chrome face (MIT,
     self-hosted) and reads as a system entity rather than a paragraph — which is what ACHEEVY
     is. Deliberately not Instrument Serif: that treatment was rejected. */
  --aims-wordmark:  "Departure Mono", "Geist Mono", ui-monospace, monospace;

  /* ── the ACHEEVY name ─────────────────────────────────────────────────────────────────
     FROSTY WHITE on dark, NEON GREEN on light. Frost is white with Ion Cyan breathed into
     it — cold, never the warm cream, and never flat #ffffff.
     The light value is not invented: the brand palette already fixes Neon Vibe AS TYPE at
     #2E8B18, because #73FF47 on a light ground is ~1.6:1 and unreadable. Pure hue stays for
     fills; type darkens to keep the identity legible. */
  --aims-frost:     #eaf4f7;   /* dark surfaces  */
  --aims-neon:      #73FF47;   /* NEON VIBE, brand — fills and dark-ground accents */
  --aims-neon-type: #2E8B18;   /* NEON VIBE as type on light, per palette canon */
  --aims-acheevy:   var(--aims-frost);

  /* ── the kit's own ladders (FUNDAMENTALS) ────────────────────────────────────────── */
  --aims-r-check:   4px;
  --aims-r-badge:   6px;
  --aims-r-control: 8px;
  --aims-r-card:    12px;
  --aims-r-modal:   16px;
  --aims-r-chat:    20px;
  --aims-r-pill:    9999px;

  --aims-e1: 0 1px 2px #0000000D;
  --aims-e2: 0 8px 16px -8px #0000000A, 0 6px 6px -3px #0000000A,
             0 3px 3px -1.5px #0000000A, 0 1px 1px -0.5px #0000000A;
  --aims-e4: 0 0 0 1px rgba(0,0,0,.08), 0 16px 16px #0000000A, 0 12px 12px #0000000A,
             0 6px 6px #0000000A, 0 3px 3px #0000000A;

  /* Authored ease. Generic easing is the motion equivalent of a default font. */
  --aims-settle: cubic-bezier(.16,.84,.44,1);
}

/* LIGHT SURFACES flip the name to neon green.

   The trigger is the SURFACE, not `prefers-color-scheme`. Every product page here paints a
   pure-black ground unconditionally, so keying off the OS preference would put dark green on
   a black page for anyone whose system is set to light — a worse bug than the one it fixes.
   Mark a light region explicitly instead. Email bodies are the live case: those render on
   white in the client, entirely outside our CSS ground. */
[data-surface="light"],
.on-light{ --aims-acheevy: var(--aims-neon-type); }

/* Surfaces with a real theme TOGGLE (pricing, studio, console) flip at runtime, so the name has
   to follow the attribute rather than the page's starting state. `:root[data-theme="dark"]` is
   (0,2,0) against `[data-surface="light"]`'s (0,1,0), so a light-default page that the visitor
   switches to dark correctly returns to frost. */
:root[data-theme="dark"]  { --aims-acheevy: var(--aims-frost); }
:root[data-theme="light"] { --aims-acheevy: var(--aims-neon-type); }

/* ══ THE LIGHT THEME ═══════════════════════════════════════════════════════════════════════
   Owner, 2026-08-03: "there is no light and dark design." Correct — until now `data-theme`
   flipped exactly ONE variable (the name colour) while every ground, text and border token
   stayed dark, so "light mode" was a switch wired to nothing.

   THIS IS NOT AN INVERSION. Inverting a dark palette gives you grey mud and a glowing accent
   that burns on white. The light theme is built from the BRAND's own light values, which the
   palette canon already fixed for exactly this reason:
     Smelter Orange as TYPE → #C4400E   (pure #FF5C22 on cream is ~2.4:1 — unreadable as text)
     Ion Cyan   → #0B7FA8      Neon Vibe → #2E8B18      Copper Alloy → #8A5326
   Fills keep the pure hue; TYPE darkens. That rule is what keeps the identity intact across
   both themes instead of producing two unrelated-looking products.

   The ground is CREAM (#F3EDE1), never #FFFFFF — the brand's warm paper value. Pure white next
   to Smelter Orange reads clinical and breaks the material richness the disposition calls for. */
:root[data-theme="light"]{
  /* grounds — cream paper, each step slightly deeper rather than greyer */
  --aims-bg:        #F3EDE1;
  --aims-surface:   #FFFFFF;   /* cards LIFT off the cream ground; on dark they recede into it */
  --aims-surface-2: #FAF7F0;
  --aims-inset:     #EBE4D6;   /* wells and tracks sink BELOW the ground */

  /* lines — warm-neutral, never the cool greys a naive inversion produces */
  --aims-border:    #D6CDBB;
  --aims-hairline:  #E6DFD1;

  /* type — ink, then progressively lighter, each step still clearing 4.5:1 on cream */
  --aims-text:      #0E0E11;
  --aims-text-2:    #2E2C28;
  --aims-text-3:    #565149;
  --aims-muted:     #6B655B;
  --aims-muted-2:   #8A8378;
  --aims-nav:       #4A463F;

  /* accent — the TYPE value, because on light this colour is read far more than it is filled */
  --aims-accent:    #C4400E;
  --aims-accent-2:  #A33409;
  --aims-on-accent: #FFFFFF;   /* white on burnt orange = 5.9:1, passes AA (pure orange fails) */

  /* the other four brand hues, at their canon light-mode type values */
  --aims-neon:      #2E8B18;
  --aims-info:      #0B7FA8;

  /* Shadows do real work on light and almost none on dark — on cream a card is separated by
     its shadow, on black by its border. Stating it here means components need no theme logic. */
  --aims-shadow-1:  0 1px 2px rgba(14,14,17,.06), 0 4px 12px rgba(14,14,17,.05);
  --aims-shadow-2:  0 8px 28px -10px rgba(14,14,17,.16);
}

/* Dark keeps shadows nearly absent — a glow on black is haze, not elevation. */
:root[data-theme="dark"], :root:not([data-theme]){
  --aims-shadow-1: 0 1px 2px rgba(0,0,0,.5);
  --aims-shadow-2: 0 14px 34px -18px rgba(0,0,0,.9);
}

/* ══ 3D CARDS — the iNTERFACE card treatment, available to every surface ═══════════════════
   Owner: "I want to have the 3D cards like we did for the AIMS interface." Lives in the token
   layer, not in one page's <style>, so every surface gets the same card instead of three
   near-misses. Theme-aware by construction: it reads the tokens above, so a card tilts the
   same way on cream and on black without a second rule set. */
.aims-3dcard{ perspective:900px }
.aims-3dcard__inner{
  position:relative; display:block; padding:18px; border-radius:var(--r-card,12px);
  background:linear-gradient(160deg,var(--aims-surface),var(--aims-surface-2));
  border:1px solid var(--aims-border); box-shadow:var(--aims-shadow-1);
  transform-style:preserve-3d; will-change:transform; text-decoration:none;
  transition:transform .2s var(--aims-settle), box-shadow .2s var(--aims-settle),
             border-color .2s var(--aims-settle);
}
.aims-3dcard__inner:hover{ border-color:var(--aims-accent); box-shadow:var(--aims-shadow-2) }
/* Depth is carried by Z-offset per layer, not by drop shadows on text. The glyph sits highest
   so it reads as a physical token on the face of the card. */
.aims-3dcard__glyph{ display:block; transform:translateZ(26px); color:var(--aims-accent);
  font:400 20px/1 var(--aims-mono); margin-bottom:10px }
.aims-3dcard__title{ transform:translateZ(16px); color:var(--aims-text);
  font:600 15px/1.25 var(--aims-sans); margin:0 0 5px }
.aims-3dcard__body{ transform:translateZ(9px); color:var(--aims-muted);
  font:400 12.5px/1.5 var(--aims-sans); margin:0 }
@media (prefers-reduced-motion:reduce){ .aims-3dcard__inner{ transition:none } }
/* Touch has no hover: the tilt would only ever fire mid-tap, so it is not offered there. */
@media (pointer:coarse){ .aims-3dcard__inner{ transform:none !important } }

/* Motion belongs to a state change, never to ambience. Honour the system preference once,
   here, so no surface has to remember to. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important; scroll-behavior:auto !important;
  }
}
