/* locoloop brand tokens — the single source of truth.
 *
 * Taken from design/Brand.dc.html ("Brand guidelines · v1.0 · 2026"), which is
 * the authoritative identity.
 *
 * BOTH SURFACES CONSUME THIS FILE:
 *   - the marketing site, via website/build.py, which copies it to
 *     website/tokens.css and links it into every built page;
 *   - the application, via frontend/src/index.css, which imports it and maps
 *     it into Tailwind's colour scale in frontend/tailwind.config.js.
 * Change a value here and both move. Nothing else may hardcode a brand hex.
 *
 * api/tests/test_brand_parity.py fails if a value here stops matching the
 * canvas, so a recolour in Claude Design cannot silently leave this behind.
 *
 * Every colour is declared ONCE, as space-separated sRGB channels. The hex
 * token is derived from it. Tailwind needs the channels so that `bg-ink-950/40`
 * can inject an alpha; CSS and SVG need the `rgb()` form. Declaring the two
 * independently is how they drift, so `--x` is always built from `--x-rgb`.
 */

:root {
  /* ── Core ────────────────────────────────────────────────────────────────
     Per §06 of the canvas: "Blue carries actions. Green marks success and
     completion. Navy is the voice. Everything else is quiet." */
  --blue-rgb:   45 140 255;   /* Loop Blue  — buttons, links, focus */
  --green-rgb:   0 209 154;   /* Loop Green — success, completion */
  --navy-rgb:   15  23  42;   /* Deep Navy  — headings, dark surfaces */
  --slate-rgb: 100 116 139;   /* Slate      — body, descriptions, metadata */
  --offwhite-rgb: 248 250 252;/* Off White  — page and section backgrounds */
  --white-rgb:  255 255 255;  /* White      — cards, navigation, content */
  --divider-rgb: 230 236 244;

  --blue:     rgb(var(--blue-rgb));      /* #2D8CFF */
  --green:    rgb(var(--green-rgb));     /* #00D19A */
  --navy:     rgb(var(--navy-rgb));      /* #0F172A */
  --slate:    rgb(var(--slate-rgb));     /* #64748B */
  --offwhite: rgb(var(--offwhite-rgb));  /* #F8FAFC */
  --white:    rgb(var(--white-rgb));     /* #FFFFFF */
  --divider:  rgb(var(--divider-rgb));   /* #E6ECF4 */

  /* ── Blue ramp ───────────────────────────────────────────────────────────
     The canvas's --color-accent-* scale, unchanged. */
  --blue-100-rgb: 234 243 255;  --blue-200-rgb: 214 232 255;
  --blue-300-rgb: 169 207 255;  --blue-400-rgb: 127 185 255;
  --blue-500-rgb:  45 140 255;  --blue-600-rgb:  27 122 235;
  --blue-700-rgb:  27 111 214;  --blue-800-rgb:  20  83 159;
  --blue-900-rgb:  14  60 117;

  --blue-100: rgb(var(--blue-100-rgb));  /* #EAF3FF */
  --blue-200: rgb(var(--blue-200-rgb));  /* #D6E8FF */
  --blue-300: rgb(var(--blue-300-rgb));  /* #A9CFFF */
  --blue-400: rgb(var(--blue-400-rgb));  /* #7FB9FF */
  --blue-500: rgb(var(--blue-500-rgb));  /* #2D8CFF */
  --blue-600: rgb(var(--blue-600-rgb));  /* #1B7AEB */
  --blue-700: rgb(var(--blue-700-rgb));  /* #1B6FD6 */
  --blue-800: rgb(var(--blue-800-rgb));  /* #14539F */
  --blue-900: rgb(var(--blue-900-rgb));  /* #0E3C75 */

  /* ── Green ramp ──────────────────────────────────────────────────────────
     The canvas's --color-accent-2-* scale, unchanged. */
  --green-100-rgb: 227 251 244;  --green-200-rgb: 194 245 231;
  --green-300-rgb: 140 235 210;  --green-400-rgb:  78 223 185;
  --green-500-rgb:   0 209 154;  --green-600-rgb:   0 177 132;
  --green-700-rgb:   0 144 108;  --green-800-rgb:   4 107  82;
  --green-900-rgb:  10  76  60;

  --green-100: rgb(var(--green-100-rgb));  /* #E3FBF4 */
  --green-200: rgb(var(--green-200-rgb));  /* #C2F5E7 */
  --green-300: rgb(var(--green-300-rgb));  /* #8CEBD2 */
  --green-400: rgb(var(--green-400-rgb));  /* #4EDFB9 */
  --green-500: rgb(var(--green-500-rgb));  /* #00D19A */
  --green-600: rgb(var(--green-600-rgb));  /* #00B184 */
  --green-700: rgb(var(--green-700-rgb));  /* #00906C */
  --green-800: rgb(var(--green-800-rgb));  /* #046B52 */
  --green-900: rgb(var(--green-900-rgb));  /* #0A4C3C */

  /* ── Neutral ramp ────────────────────────────────────────────────────────
     The canvas's --color-neutral-* scale, unchanged. */
  --n-100-rgb: 248 250 252;  --n-200-rgb: 241 245 249;
  --n-300-rgb: 226 232 240;  --n-400-rgb: 203 213 225;
  --n-500-rgb: 148 163 184;  --n-600-rgb: 124 140 165;
  --n-700-rgb: 100 116 139;  --n-800-rgb:  71  85 105;
  --n-900-rgb:  30  41  59;

  --n-100: rgb(var(--n-100-rgb));  /* #F8FAFC */
  --n-200: rgb(var(--n-200-rgb));  /* #F1F5F9 */
  --n-300: rgb(var(--n-300-rgb));  /* #E2E8F0 */
  --n-400: rgb(var(--n-400-rgb));  /* #CBD5E1 */
  --n-500: rgb(var(--n-500-rgb));  /* #94A3B8 */
  --n-600: rgb(var(--n-600-rgb));  /* #7C8CA5 */
  --n-700: rgb(var(--n-700-rgb));  /* #64748B */
  --n-800: rgb(var(--n-800-rgb));  /* #475569 */
  --n-900: rgb(var(--n-900-rgb));  /* #1E293B */

  /* ── Status ──────────────────────────────────────────────────────────────
     Red is the canvas's own (#E5484D, on the error states in App.dc.html).
     Like Loop Blue it is an identity value, not a text value: white on it is
     3.91:1, so a destructive button takes --danger-700.

     Amber is NOT in the brand canvas -- the identity has blue, green, navy,
     slate and red, and nothing else. The product needs a warning state
     regardless (a source string changed after its translation was approved; a
     daily AI budget is spent), and one defined here is better than stock
     Tailwind amber scattered across six components. Replace these three when
     the identity gains a warning colour of its own. */
  --danger-100-rgb: 253 236 236;
  --danger-500-rgb: 229  72  77;   /* #E5484D — the canvas value */
  --danger-700-rgb: 196  56  60;   /* white on it: 5.28:1 */
  --danger-900-rgb: 143  26  30;   /* on the wash: 7.88:1 */

  --danger-100: rgb(var(--danger-100-rgb));
  --danger-500: rgb(var(--danger-500-rgb));
  --danger-700: rgb(var(--danger-700-rgb));
  --danger-900: rgb(var(--danger-900-rgb));

  --warning-100-rgb: 255 246 227;
  --warning-500-rgb: 242 169  22;
  --warning-700-rgb: 163 106   0;   /* #A36A00 — white on it: 4.55:1 */
  --warning-900-rgb: 107  69   0;

  --warning-100: rgb(var(--warning-100-rgb));
  --warning-500: rgb(var(--warning-500-rgb));
  --warning-700: rgb(var(--warning-700-rgb));
  --warning-900: rgb(var(--warning-900-rgb));

  /* ── Accessible roles ────────────────────────────────────────────────────
     Three places where the identity value cannot carry the job, and the shade
     that can — every one of them already in the ramps above, so this narrows
     the palette rather than inventing beside it.

       Loop Blue behind white text measures 3.33:1. Buttons run 14–16px
       Medium, which is not WCAG "large text", so AA wants 4.5:1 and the fill
       has to be --blue-700 (4.89:1). Loop Blue itself stays exactly what §06
       says it is: the brand accent, used for focus rings, borders, icons,
       fills and large graphics -- everywhere the contrast rule is 3:1, which
       it clears.

       A blue link on white is the same 3.33:1 problem, same answer.

       Loop Green behind white is 1.98:1 -- it is a light mint, and white on
       it is unreadable. Green marks success on a --green-100 wash with navy
       or --green-700 on top, never white on green.

     The control border is --n-600 rather than the --n-400 a divider uses:
     WCAG 1.4.11 asks 3:1 of a control's edge, and --n-400 is 1.48:1. --n-600
     measures 3.41:1 on white and 3.26:1 on the page.

     Muted text is Slate nudged two steps darker. Slate itself is 4.55:1 on
     the page and passes, but the app also sets it on a selected grid row,
     which is tinted --blue-100, and there it measures 4.25:1. The ramp is
     built against the darkest ground a colour can land on, not the lightest.
     Ratios are asserted in api/tests/test_brand_parity.py. */
  --action:         var(--blue-700);   /* button fills, link text */
  --action-hover:   var(--blue-800);
  --focus:          var(--blue-500);   /* focus ring — 3:1 territory */
  --control-border: var(--n-600);

  /* ── Application neutral ramp ────────────────────────────────────────────
     The product is a dense data grid and needs more steps than the nine
     above. Every value is one of them; only the names are the app's, so the
     ~350 existing `ink-*` call sites keep working. */
  --app-0-rgb:   255 255 255;   /* white  */
  --app-50-rgb:  248 250 252;   /* n-100  */
  --app-100-rgb: 241 245 249;   /* n-200  */
  --app-200-rgb: 230 236 244;   /* divider */
  --app-300-rgb: 226 232 240;   /* n-300  */
  --app-400-rgb: 203 213 225;   /* n-400  */
  --app-500-rgb: 124 140 165;   /* n-600 — control borders, 3.41:1 on white, 3.05:1 on the blue wash */
  --app-600-rgb:  96 112 134;   /* Slate, nudged — muted text, 4.51:1 on the blue wash a selected row uses */
  --app-700-rgb:  71  85 105;   /* n-800  */
  --app-800-rgb:  30  41  59;   /* n-900  */
  --app-900-rgb:  15  23  42;   /* navy   */
  --app-950-rgb:  11  18  32;   /* modal scrim */

  /* Semantic roles. Components reference these, never a raw value, so a
     palette change is one edit rather than an audit. */
  --bg:         var(--offwhite);
  --panel:      var(--white);
  --text:       var(--navy);
  --text-muted: var(--slate);
  --text-dim:   var(--n-600);
  --line:       var(--divider);
  --line-soft:  var(--n-300);
  --accent:     var(--blue);
  --accent-deep:var(--blue-700);

  /* Brand gradient — Loop Blue to Loop Green. §06: "Hero areas and selected
     marketing moments only. Never behind body text, and never simply because
     it appears in the logo." */
  --grad-primary: linear-gradient(135deg, var(--blue), var(--green));
  --grad-deep:    linear-gradient(135deg, var(--navy), var(--blue-800));
  --grad-wash:    linear-gradient(180deg, var(--blue-100), var(--offwhite));

  /* ── Type ────────────────────────────────────────────────────────────────
     §07: "Inter, one family." JetBrains Mono stays for anything that is a
     literal -- keys, locale codes, paths, code -- which the canvases still
     set in mono.

     Self-hosted, not from Google, even though the canvases link the CDN. No
     visitor IP reaches a third party — German courts have ruled Google Fonts
     unlawful under GDPR, which is an awkward thing to ship on the homepage of
     a product selling EU data residency — and it removes a DNS lookup and TLS
     handshake from first paint. Both faces are variable: one file per family,
     every weight.

     The two surfaces serve the same files from different origins
     (website/fonts/ on rondigi.com, frontend/public/fonts/ on
     app.rondigi.com), so each ships its own copy. They are immutable
     binaries; a build step to copy them would be machinery guarding against
     a change that cannot happen. */
  --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system,
    'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo,
    Consolas, monospace;

  --display-weight: 700;   /* H1 · 48–64px */
  --section-weight: 600;   /* H2 · 32–40px */
  --eyebrow-weight: 700;   /* 12px, +12% tracking, blue-700 */
  --tracking-display: -0.022em;

  /* Body runs 16–18px with generous line spacing, flush left, never
     justified. Paragraphs cap around 60 characters. */
  --measure: 60ch;

  /* §08: buttons 10px, cards 12–16px, inputs 10px. */
  --radius-sm: 8px;
  --radius:    10px;
  --radius-lg: 14px;
  --radius-pill: 999px;
}

/* Wordmark — "locoloop", lowercase, always.
 *
 * §02: four official assets (primary, reversed, mono, icon), placed from the
 * approved master artwork and never redrawn. Below 120px the lockup is
 * replaced by the icon, not shrunk; the icon floor is 16px.
 */

/* Voice — §09: clear, confident, technical but accessible.
 *
 * Say what the product does and what happens next. No corporate jargon, no
 * aggressive selling, no exaggerated claims.
 */
