/*
 * THE TOKENS — the whole colour, type, space and motion vocabulary of the kit.
 *
 * The public half is the shadcn/ui variable contract, so any shadcn or tweakcn
 * palette drops in unchanged; every `--lotics-*` below derives from it in CSS.
 * `docs/theming.md` holds the contract this file emits and the reasoning.
 *
 * The ONE stylesheet permitted a literal colour, type size or z-index — safe
 * only because nothing here selects a component or paints anything.
 */
@layer theme, base, lotics, components, utilities;
@layer lotics.tokens, lotics.reset, lotics.components;

@layer lotics.tokens {
  /* ─── The public contract ───────────────────────────────────────────────
     Light on `:root, .light`, so `<div class="light">` returns a subtree to
     light inside a dark shell; `.dark` follows it, because the two tie on
     specificity and order breaks the tie. */
  :root,
  .light {
    color-scheme: light;

    --background: #ffffff;
    --foreground: #18181b;
    --card: #ffffff;
    --card-foreground: #18181b;
    --popover: #ffffff;
    --popover-foreground: #18181b;
    --primary: #18181b;
    --primary-foreground: #ffffff;
    --secondary: #f4f4f5;
    --secondary-foreground: #18181b;
    --muted: #f4f4f5;
    /* SUPPORTING TEXT RECEDES, and 7.7:1 does not. The ramp has no rung where
       the recession and the AA floor both hold, so this sits between the two
       rungs and names which two. `text_ink_contrast.test.ts` holds both ends. */
    --muted-foreground: color-mix(in srgb, var(--lotics-zinc-500) 65%, var(--lotics-zinc-600));
    --accent: #f4f4f5;
    --accent-foreground: #18181b;
    /* The one hue the kit reads from the contract rather than from its own
       palette: a delete button IS shadcn's destructive, and the danger washes
       below are strengths of it. There is no `--destructive-foreground` — the
       kit paints no SOLID destructive surface. */
    --destructive: #dc2626;
    --border: #e4e4e7;
    --input: #e4e4e7;
    --ring: #18181b;

    /* The kit's brand hue, deliberately NOT shadcn's `--accent` — that one is a
       neutral interaction ground, and mapping ours onto it would paint every
       menu hover blue. */
    --lotics-accent: #2563eb;
    --lotics-accent-wash: color-mix(in srgb, var(--lotics-accent) 7%, transparent);

    --lotics-ink-inactive: var(--lotics-zinc-400);
    --lotics-ink-danger: var(--lotics-red-900);
    --lotics-ink-warning: var(--lotics-amber-700);
    --lotics-ink-success: var(--lotics-emerald-700);

    /* A TONE IS A ROLE, RESOLVED PER THEME — the ground a status pill, a callout
       or a category mark is painted on, its edge, its ink and the solid a dot
       takes. Four names per family, because a sheet that reached a rung instead
       froze that surface in light. The light wash is the 50 rung under 900 ink
       and the dark wash the 950 — except the five ACHROMATIC families, whose 50
       and 950 are the canvas itself, so those take 100 and 800. The SOLID is the
       one name the theme does not move; its rung is picked below.
       `tone_register.test.ts` measures every pair. */
    --lotics-tone-red: var(--lotics-red-50);
    --lotics-tone-red-strong: var(--lotics-red-100);
    --lotics-tone-red-ink: var(--lotics-red-900);
    --lotics-tone-orange: var(--lotics-orange-50);
    --lotics-tone-orange-strong: var(--lotics-orange-100);
    --lotics-tone-orange-ink: var(--lotics-orange-900);
    --lotics-tone-amber: var(--lotics-amber-50);
    --lotics-tone-amber-strong: var(--lotics-amber-100);
    --lotics-tone-amber-ink: var(--lotics-amber-900);
    --lotics-tone-yellow: var(--lotics-yellow-50);
    --lotics-tone-yellow-strong: var(--lotics-yellow-100);
    --lotics-tone-yellow-ink: var(--lotics-yellow-900);
    --lotics-tone-lime: var(--lotics-lime-50);
    --lotics-tone-lime-strong: var(--lotics-lime-100);
    --lotics-tone-lime-ink: var(--lotics-lime-900);
    --lotics-tone-green: var(--lotics-green-50);
    --lotics-tone-green-strong: var(--lotics-green-100);
    --lotics-tone-green-ink: var(--lotics-green-900);
    --lotics-tone-emerald: var(--lotics-emerald-50);
    --lotics-tone-emerald-strong: var(--lotics-emerald-100);
    --lotics-tone-emerald-ink: var(--lotics-emerald-900);
    --lotics-tone-teal: var(--lotics-teal-50);
    --lotics-tone-teal-strong: var(--lotics-teal-100);
    --lotics-tone-teal-ink: var(--lotics-teal-900);
    --lotics-tone-cyan: var(--lotics-cyan-50);
    --lotics-tone-cyan-strong: var(--lotics-cyan-100);
    --lotics-tone-cyan-ink: var(--lotics-cyan-900);
    --lotics-tone-sky: var(--lotics-sky-50);
    --lotics-tone-sky-strong: var(--lotics-sky-100);
    --lotics-tone-sky-ink: var(--lotics-sky-900);
    --lotics-tone-blue: var(--lotics-blue-50);
    --lotics-tone-blue-strong: var(--lotics-blue-100);
    --lotics-tone-blue-ink: var(--lotics-blue-900);
    --lotics-tone-indigo: var(--lotics-indigo-50);
    --lotics-tone-indigo-strong: var(--lotics-indigo-100);
    --lotics-tone-indigo-ink: var(--lotics-indigo-900);
    --lotics-tone-violet: var(--lotics-violet-50);
    --lotics-tone-violet-strong: var(--lotics-violet-100);
    --lotics-tone-violet-ink: var(--lotics-violet-900);
    --lotics-tone-purple: var(--lotics-purple-50);
    --lotics-tone-purple-strong: var(--lotics-purple-100);
    --lotics-tone-purple-ink: var(--lotics-purple-900);
    --lotics-tone-fuchsia: var(--lotics-fuchsia-50);
    --lotics-tone-fuchsia-strong: var(--lotics-fuchsia-100);
    --lotics-tone-fuchsia-ink: var(--lotics-fuchsia-900);
    --lotics-tone-pink: var(--lotics-pink-50);
    --lotics-tone-pink-strong: var(--lotics-pink-100);
    --lotics-tone-pink-ink: var(--lotics-pink-900);

    /* AN IDENTITY DISC IS A SOLID RUNG PAIR — `constitution.md` §8's one
       exception, in the order `identity.ts` deals them. A mark sits beside tonal
       status pills, and a wash of the same hue reads as one more pill.
       `identity_hue.test.ts` measures every pair. */
    --lotics-identity-cyan: var(--lotics-cyan-200);
    --lotics-identity-cyan-ink: var(--lotics-cyan-800);
    --lotics-identity-orange: var(--lotics-orange-200);
    --lotics-identity-orange-ink: var(--lotics-orange-800);
    --lotics-identity-green: var(--lotics-green-200);
    --lotics-identity-green-ink: var(--lotics-green-800);
    --lotics-identity-teal: var(--lotics-teal-200);
    --lotics-identity-teal-ink: var(--lotics-teal-800);
    --lotics-identity-blue: var(--lotics-blue-200);
    --lotics-identity-blue-ink: var(--lotics-blue-800);
    --lotics-identity-indigo: var(--lotics-indigo-200);
    --lotics-identity-indigo-ink: var(--lotics-indigo-800);
    --lotics-identity-violet: var(--lotics-violet-200);
    --lotics-identity-violet-ink: var(--lotics-violet-800);
    --lotics-identity-pink: var(--lotics-pink-200);
    --lotics-identity-pink-ink: var(--lotics-pink-800);

    --lotics-tone-rose: var(--lotics-rose-50);
    --lotics-tone-rose-strong: var(--lotics-rose-100);
    --lotics-tone-rose-ink: var(--lotics-rose-900);
    --lotics-tone-slate: var(--lotics-slate-100);
    --lotics-tone-slate-strong: var(--lotics-slate-200);
    --lotics-tone-slate-ink: var(--lotics-slate-900);
    --lotics-tone-gray: var(--lotics-gray-100);
    --lotics-tone-gray-strong: var(--lotics-gray-200);
    --lotics-tone-gray-ink: var(--lotics-gray-900);
    --lotics-tone-zinc: var(--lotics-zinc-100);
    --lotics-tone-zinc-strong: var(--lotics-zinc-200);
    --lotics-tone-zinc-ink: var(--lotics-zinc-900);
    --lotics-tone-neutral: var(--lotics-neutral-100);
    --lotics-tone-neutral-strong: var(--lotics-neutral-200);
    --lotics-tone-neutral-ink: var(--lotics-neutral-900);
    --lotics-tone-stone: var(--lotics-stone-100);
    --lotics-tone-stone-strong: var(--lotics-stone-200);
    --lotics-tone-stone-ink: var(--lotics-stone-900);
  }

  .dark {
    color-scheme: dark;

    --background: #09090b;
    --foreground: #fafafa;
    --card: #18181b;
    --card-foreground: #fafafa;
    --popover: #18181b;
    --popover-foreground: #fafafa;
    --primary: #fafafa;
    --primary-foreground: #18181b;
    --secondary: #27272a;
    --secondary-foreground: #fafafa;
    --muted: #27272a;
    /* The same recession from the other side, between zinc-400 and zinc-500. */
    --muted-foreground: color-mix(in srgb, var(--lotics-zinc-400) 55%, var(--lotics-zinc-500));
    --accent: #27272a;
    --accent-foreground: #fafafa;
    --destructive: #ef4444;
    --border: #27272a;
    --input: #3f3f46;
    --ring: #d4d4d8;

    --lotics-accent: #60a5fa;
    /* 7% of a hue over a near-black ground is invisible. */
    --lotics-accent-wash: color-mix(in srgb, var(--lotics-accent) 18%, transparent);

    --lotics-ink-inactive: var(--lotics-zinc-500);
    --lotics-ink-danger: var(--lotics-red-400);
    --lotics-ink-warning: var(--lotics-amber-400);
    --lotics-ink-success: var(--lotics-emerald-400);

    /* The same four inverted: the deep rung grounds, the light rung letters. */
    --lotics-tone-red: var(--lotics-red-950);
    --lotics-tone-red-strong: var(--lotics-red-900);
    --lotics-tone-red-ink: var(--lotics-red-200);
    --lotics-tone-orange: var(--lotics-orange-950);
    --lotics-tone-orange-strong: var(--lotics-orange-900);
    --lotics-tone-orange-ink: var(--lotics-orange-200);
    --lotics-tone-amber: var(--lotics-amber-950);
    --lotics-tone-amber-strong: var(--lotics-amber-900);
    --lotics-tone-amber-ink: var(--lotics-amber-200);
    --lotics-tone-yellow: var(--lotics-yellow-950);
    --lotics-tone-yellow-strong: var(--lotics-yellow-900);
    --lotics-tone-yellow-ink: var(--lotics-yellow-200);
    --lotics-tone-lime: var(--lotics-lime-950);
    --lotics-tone-lime-strong: var(--lotics-lime-900);
    --lotics-tone-lime-ink: var(--lotics-lime-200);
    --lotics-tone-green: var(--lotics-green-950);
    --lotics-tone-green-strong: var(--lotics-green-900);
    --lotics-tone-green-ink: var(--lotics-green-200);
    --lotics-tone-emerald: var(--lotics-emerald-950);
    --lotics-tone-emerald-strong: var(--lotics-emerald-900);
    --lotics-tone-emerald-ink: var(--lotics-emerald-200);
    --lotics-tone-teal: var(--lotics-teal-950);
    --lotics-tone-teal-strong: var(--lotics-teal-900);
    --lotics-tone-teal-ink: var(--lotics-teal-200);
    --lotics-tone-cyan: var(--lotics-cyan-950);
    --lotics-tone-cyan-strong: var(--lotics-cyan-900);
    --lotics-tone-cyan-ink: var(--lotics-cyan-200);
    --lotics-tone-sky: var(--lotics-sky-950);
    --lotics-tone-sky-strong: var(--lotics-sky-900);
    --lotics-tone-sky-ink: var(--lotics-sky-200);
    --lotics-tone-blue: var(--lotics-blue-950);
    --lotics-tone-blue-strong: var(--lotics-blue-900);
    --lotics-tone-blue-ink: var(--lotics-blue-200);
    --lotics-tone-indigo: var(--lotics-indigo-950);
    --lotics-tone-indigo-strong: var(--lotics-indigo-900);
    --lotics-tone-indigo-ink: var(--lotics-indigo-200);
    --lotics-tone-violet: var(--lotics-violet-950);
    --lotics-tone-violet-strong: var(--lotics-violet-900);
    --lotics-tone-violet-ink: var(--lotics-violet-200);
    --lotics-tone-purple: var(--lotics-purple-950);
    --lotics-tone-purple-strong: var(--lotics-purple-900);
    --lotics-tone-purple-ink: var(--lotics-purple-200);
    --lotics-tone-fuchsia: var(--lotics-fuchsia-950);
    --lotics-tone-fuchsia-strong: var(--lotics-fuchsia-900);
    --lotics-tone-fuchsia-ink: var(--lotics-fuchsia-200);
    --lotics-tone-pink: var(--lotics-pink-950);
    --lotics-tone-pink-strong: var(--lotics-pink-900);
    --lotics-tone-pink-ink: var(--lotics-pink-200);

    /* The same pair inverted, so a mark is as solid on near-black as on white. */
    --lotics-identity-cyan: var(--lotics-cyan-900);
    --lotics-identity-cyan-ink: var(--lotics-cyan-300);
    --lotics-identity-orange: var(--lotics-orange-900);
    --lotics-identity-orange-ink: var(--lotics-orange-300);
    --lotics-identity-green: var(--lotics-green-900);
    --lotics-identity-green-ink: var(--lotics-green-300);
    --lotics-identity-teal: var(--lotics-teal-900);
    --lotics-identity-teal-ink: var(--lotics-teal-300);
    --lotics-identity-blue: var(--lotics-blue-900);
    --lotics-identity-blue-ink: var(--lotics-blue-300);
    --lotics-identity-indigo: var(--lotics-indigo-900);
    --lotics-identity-indigo-ink: var(--lotics-indigo-300);
    --lotics-identity-violet: var(--lotics-violet-900);
    --lotics-identity-violet-ink: var(--lotics-violet-300);
    --lotics-identity-pink: var(--lotics-pink-900);
    --lotics-identity-pink-ink: var(--lotics-pink-300);
    --lotics-tone-rose: var(--lotics-rose-950);
    --lotics-tone-rose-strong: var(--lotics-rose-900);
    --lotics-tone-rose-ink: var(--lotics-rose-200);
    --lotics-tone-slate: var(--lotics-slate-800);
    --lotics-tone-slate-strong: var(--lotics-slate-700);
    --lotics-tone-slate-ink: var(--lotics-slate-200);
    --lotics-tone-gray: var(--lotics-gray-800);
    --lotics-tone-gray-strong: var(--lotics-gray-700);
    --lotics-tone-gray-ink: var(--lotics-gray-200);
    --lotics-tone-zinc: var(--lotics-zinc-800);
    --lotics-tone-zinc-strong: var(--lotics-zinc-700);
    --lotics-tone-zinc-ink: var(--lotics-zinc-200);
    --lotics-tone-neutral: var(--lotics-neutral-800);
    --lotics-tone-neutral-strong: var(--lotics-neutral-700);
    --lotics-tone-neutral-ink: var(--lotics-neutral-200);
    --lotics-tone-stone: var(--lotics-stone-800);
    --lotics-tone-stone-strong: var(--lotics-stone-700);
    --lotics-tone-stone-ink: var(--lotics-stone-200);
  }

  /* The half of the contract the theme does not move. ON `:root` ALONE: a
     declaration of ours on `.light` or `.dark` sits ON the element that a
     consumer's `:root` override only reaches by inheritance, so it would shadow
     that override inside every themed subtree. `tokens_scope.test.ts` holds the
     rule both ways. */
  :root {
    --radius: 0.625rem;
    --font-sans:
      Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
      "Helvetica Neue", Arial, sans-serif;
    --font-mono:
      ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
      "Liberation Mono", monospace;
  }

  /* ─── The palette ───────────────────────────────────────────────────────
     22 families at 11 shades — the CSS form of `color_tokens.ts`, asserted
     against it value-for-value. NOT themeable: a family name is how this system
     says what something IS, so repainting one would make it lie. */
  :root {
    /* What a glyph over IMAGERY takes: every ink role moves with the theme, and
       a photograph does not. The families carry no achromatic rung. */
    --lotics-white: #ffffff;
    --lotics-black: #000000;
    --lotics-red-50: #fef2f2;
    --lotics-red-100: #fee2e2;
    --lotics-red-200: #fecaca;
    --lotics-red-300: #fca5a5;
    --lotics-red-400: #f87171;
    --lotics-red-500: #ef4444;
    --lotics-red-600: #dc2626;
    --lotics-red-700: #b91c1c;
    --lotics-red-800: #991b1b;
    --lotics-red-900: #7f1d1d;
    --lotics-red-950: #450a0a;

    --lotics-orange-50: #fff7ed;
    --lotics-orange-100: #ffedd5;
    --lotics-orange-200: #fed7aa;
    --lotics-orange-300: #fdba74;
    --lotics-orange-400: #fb923c;
    --lotics-orange-500: #f97316;
    --lotics-orange-600: #ea580c;
    --lotics-orange-700: #c2410c;
    --lotics-orange-800: #9a3412;
    --lotics-orange-900: #7c2d12;
    --lotics-orange-950: #431407;

    --lotics-amber-50: #fffbeb;
    --lotics-amber-100: #fef3c7;
    --lotics-amber-200: #fde68a;
    --lotics-amber-300: #fcd34d;
    --lotics-amber-400: #fbbf24;
    --lotics-amber-500: #f59e0b;
    --lotics-amber-600: #d97706;
    --lotics-amber-700: #b45309;
    --lotics-amber-800: #92400e;
    --lotics-amber-900: #78350f;
    --lotics-amber-950: #451a03;

    --lotics-yellow-50: #fefce8;
    --lotics-yellow-100: #fef9c3;
    --lotics-yellow-200: #fef08a;
    --lotics-yellow-300: #fde047;
    --lotics-yellow-400: #facc15;
    --lotics-yellow-500: #eab308;
    --lotics-yellow-600: #ca8a04;
    --lotics-yellow-700: #a16207;
    --lotics-yellow-800: #854d0e;
    --lotics-yellow-900: #713f12;
    --lotics-yellow-950: #422006;

    --lotics-lime-50: #f7fee7;
    --lotics-lime-100: #ecfccb;
    --lotics-lime-200: #d9f99d;
    --lotics-lime-300: #bef264;
    --lotics-lime-400: #a3e635;
    --lotics-lime-500: #84cc16;
    --lotics-lime-600: #65a30d;
    --lotics-lime-700: #4d7c0f;
    --lotics-lime-800: #3f6212;
    --lotics-lime-900: #365314;
    --lotics-lime-950: #1a2e05;

    --lotics-green-50: #f0fdf4;
    --lotics-green-100: #dcfce7;
    --lotics-green-200: #bbf7d0;
    --lotics-green-300: #86efac;
    --lotics-green-400: #4ade80;
    --lotics-green-500: #22c55e;
    --lotics-green-600: #16a34a;
    --lotics-green-700: #15803d;
    --lotics-green-800: #166534;
    --lotics-green-900: #14532d;
    --lotics-green-950: #052e16;

    --lotics-emerald-50: #ecfdf5;
    --lotics-emerald-100: #d1fae5;
    --lotics-emerald-200: #a7f3d0;
    --lotics-emerald-300: #6ee7b7;
    --lotics-emerald-400: #34d399;
    --lotics-emerald-500: #10b981;
    --lotics-emerald-600: #059669;
    --lotics-emerald-700: #047857;
    --lotics-emerald-800: #065f46;
    --lotics-emerald-900: #064e3b;
    --lotics-emerald-950: #022c22;

    --lotics-teal-50: #f0fdfa;
    --lotics-teal-100: #ccfbf1;
    --lotics-teal-200: #99f6e4;
    --lotics-teal-300: #5eead4;
    --lotics-teal-400: #2dd4bf;
    --lotics-teal-500: #14b8a6;
    --lotics-teal-600: #0d9488;
    --lotics-teal-700: #0f766e;
    --lotics-teal-800: #115e59;
    --lotics-teal-900: #134e4a;
    --lotics-teal-950: #042f2e;

    --lotics-cyan-50: #ecfeff;
    --lotics-cyan-100: #cffafe;
    --lotics-cyan-200: #a5f3fc;
    --lotics-cyan-300: #67e8f9;
    --lotics-cyan-400: #22d3ee;
    --lotics-cyan-500: #06b6d4;
    --lotics-cyan-600: #0891b2;
    --lotics-cyan-700: #0e7490;
    --lotics-cyan-800: #155e75;
    --lotics-cyan-900: #164e63;
    --lotics-cyan-950: #083344;

    --lotics-sky-50: #f0f9ff;
    --lotics-sky-100: #e0f2fe;
    --lotics-sky-200: #bae6fd;
    --lotics-sky-300: #7dd3fc;
    --lotics-sky-400: #38bdf8;
    --lotics-sky-500: #0ea5e9;
    --lotics-sky-600: #0284c7;
    --lotics-sky-700: #0369a1;
    --lotics-sky-800: #075985;
    --lotics-sky-900: #0c4a6e;
    --lotics-sky-950: #082f49;

    --lotics-blue-50: #eff6ff;
    --lotics-blue-100: #dbeafe;
    --lotics-blue-200: #bfdbfe;
    --lotics-blue-300: #93c5fd;
    --lotics-blue-400: #60a5fa;
    --lotics-blue-500: #3b82f6;
    --lotics-blue-600: #2563eb;
    --lotics-blue-700: #1d4ed8;
    --lotics-blue-800: #1e40af;
    --lotics-blue-900: #1e3a8a;
    --lotics-blue-950: #172554;

    --lotics-indigo-50: #eef2ff;
    --lotics-indigo-100: #e0e7ff;
    --lotics-indigo-200: #c7d2fe;
    --lotics-indigo-300: #a5b4fc;
    --lotics-indigo-400: #818cf8;
    --lotics-indigo-500: #6366f1;
    --lotics-indigo-600: #4f46e5;
    --lotics-indigo-700: #4338ca;
    --lotics-indigo-800: #3730a3;
    --lotics-indigo-900: #312e81;
    --lotics-indigo-950: #1e1b4b;

    --lotics-violet-50: #f5f3ff;
    --lotics-violet-100: #ede9fe;
    --lotics-violet-200: #ddd6fe;
    --lotics-violet-300: #c4b5fd;
    --lotics-violet-400: #a78bfa;
    --lotics-violet-500: #8b5cf6;
    --lotics-violet-600: #7c3aed;
    --lotics-violet-700: #6d28d9;
    --lotics-violet-800: #5b21b6;
    --lotics-violet-900: #4c1d95;
    --lotics-violet-950: #2e1065;

    --lotics-purple-50: #faf5ff;
    --lotics-purple-100: #f3e8ff;
    --lotics-purple-200: #e9d5ff;
    --lotics-purple-300: #d8b4fe;
    --lotics-purple-400: #c084fc;
    --lotics-purple-500: #a855f7;
    --lotics-purple-600: #9333ea;
    --lotics-purple-700: #7e22ce;
    --lotics-purple-800: #6b21a8;
    --lotics-purple-900: #581c87;
    --lotics-purple-950: #3b0764;

    --lotics-fuchsia-50: #fdf4ff;
    --lotics-fuchsia-100: #fae8ff;
    --lotics-fuchsia-200: #f5d0fe;
    --lotics-fuchsia-300: #f0abfc;
    --lotics-fuchsia-400: #e879f9;
    --lotics-fuchsia-500: #d946ef;
    --lotics-fuchsia-600: #c026d3;
    --lotics-fuchsia-700: #a21caf;
    --lotics-fuchsia-800: #86198f;
    --lotics-fuchsia-900: #701a75;
    --lotics-fuchsia-950: #4a044e;

    --lotics-pink-50: #fdf2f8;
    --lotics-pink-100: #fce7f3;
    --lotics-pink-200: #fbcfe8;
    --lotics-pink-300: #f9a8d4;
    --lotics-pink-400: #f472b6;
    --lotics-pink-500: #ec4899;
    --lotics-pink-600: #db2777;
    --lotics-pink-700: #be185d;
    --lotics-pink-800: #9d174d;
    --lotics-pink-900: #831843;
    --lotics-pink-950: #500724;

    --lotics-rose-50: #fff1f2;
    --lotics-rose-100: #ffe4e6;
    --lotics-rose-200: #fecdd3;
    --lotics-rose-300: #fda4af;
    --lotics-rose-400: #fb7185;
    --lotics-rose-500: #f43f5e;
    --lotics-rose-600: #e11d48;
    --lotics-rose-700: #be123c;
    --lotics-rose-800: #9f1239;
    --lotics-rose-900: #881337;
    --lotics-rose-950: #4c0519;

    --lotics-slate-50: #f8fafc;
    --lotics-slate-100: #f1f5f9;
    --lotics-slate-200: #e2e8f0;
    --lotics-slate-300: #cbd5e1;
    --lotics-slate-400: #94a3b8;
    --lotics-slate-500: #64748b;
    --lotics-slate-600: #475569;
    --lotics-slate-700: #334155;
    --lotics-slate-800: #1e293b;
    --lotics-slate-900: #0f172a;
    --lotics-slate-950: #020617;

    --lotics-gray-50: #f9fafb;
    --lotics-gray-100: #f3f4f6;
    --lotics-gray-200: #e5e7eb;
    --lotics-gray-300: #d1d5db;
    --lotics-gray-400: #9ca3af;
    --lotics-gray-500: #6b7280;
    --lotics-gray-600: #4b5563;
    --lotics-gray-700: #374151;
    --lotics-gray-800: #1f2937;
    --lotics-gray-900: #111827;
    --lotics-gray-950: #030712;

    --lotics-zinc-50: #fafafa;
    --lotics-zinc-100: #f4f4f5;
    --lotics-zinc-200: #e4e4e7;
    --lotics-zinc-300: #d4d4d8;
    --lotics-zinc-400: #a1a1aa;
    --lotics-zinc-500: #71717a;
    --lotics-zinc-600: #52525b;
    --lotics-zinc-700: #3f3f46;
    --lotics-zinc-800: #27272a;
    --lotics-zinc-900: #18181b;
    --lotics-zinc-950: #09090b;

    --lotics-neutral-50: #fafafa;
    --lotics-neutral-100: #f5f5f5;
    --lotics-neutral-200: #e5e5e5;
    --lotics-neutral-300: #d4d4d4;
    --lotics-neutral-400: #a3a3a3;
    --lotics-neutral-500: #737373;
    --lotics-neutral-600: #525252;
    --lotics-neutral-700: #404040;
    --lotics-neutral-800: #262626;
    --lotics-neutral-900: #171717;
    --lotics-neutral-950: #0a0a0a;

    --lotics-stone-50: #fafaf9;
    --lotics-stone-100: #f5f5f4;
    --lotics-stone-200: #e7e5e4;
    --lotics-stone-300: #d6d3d1;
    --lotics-stone-400: #a8a29e;
    --lotics-stone-500: #78716c;
    --lotics-stone-600: #57534e;
    --lotics-stone-700: #44403c;
    --lotics-stone-800: #292524;
    --lotics-stone-900: #1c1917;
    --lotics-stone-950: #0c0a09;
  }

  /* ─── Derived, THEMED ───────────────────────────────────────────────────
     Every mix is `in srgb`, never `in oklab`: an oklab mix of the same
     percentage is a different colour.

     ON ALL THREE SCOPES, because a custom property substitutes its `var()`s at
     computed-value time on the element CARRYING the declaration — declared only
     on `:root`, one of these freezes at the root's theme. Override one in both
     blocks, or by moving the input it reads. */
  :root,
  .light,
  .dark {
    /* The neutral ladder, for a control whose ground is a SURFACE token. Alpha
       overlays, so they composite over whatever ground the row sits on. */
    --lotics-wash-hover: color-mix(in srgb, var(--foreground) 2%, transparent);
    --lotics-wash-selected: color-mix(in srgb, var(--foreground) 5%, transparent);
    --lotics-wash-press: color-mix(in srgb, var(--foreground) 12%, transparent);
    /* The DANGER ladder — three strengths of `--destructive`, so a delete
       button's tint follows a theme's destructive hue and composites over
       whatever ground it sits on. */
    --lotics-wash-danger: color-mix(in srgb, var(--destructive) 12%, transparent);
    --lotics-wash-danger-hover: color-mix(in srgb, var(--destructive) 24%, transparent);
    --lotics-wash-danger-press: color-mix(in srgb, var(--destructive) 40%, transparent);

    /* The row ladder shifted one rung: reaching a control means crossing its row. */
    --lotics-wash-control-hover: var(--lotics-wash-press);
    --lotics-wash-control-press: color-mix(in srgb, var(--foreground) 19%, transparent);

    /* A bordered control has two interactive signals: focus is the ring, hover
       is a darker border. Colour only — a `border` shorthand would also reset
       `border-image` and fight the rule that motion runs on `border-color`. */
    --lotics-border-hover: color-mix(in srgb, var(--foreground) 55%, var(--border));

    --lotics-ink-default: var(--foreground);
    --lotics-ink-muted: var(--muted-foreground);
    --lotics-ink-on-inverse: var(--primary-foreground);

    /* A PROMPT IS LIVE TEXT: WCAG 1.4.3 exempts an INACTIVE component from the
       contrast floor and a placeholder is not one, so it cannot share
       `--lotics-ink-inactive`. Mixed rather than pinned to a rung, so a theme
       that moves `--muted-foreground` moves this with it.
       `text_ink_contrast.test.ts` holds the floor on both grounds. */
    --lotics-ink-placeholder: color-mix(in srgb, var(--muted-foreground) 95%, var(--background));

    /* What a STICKY register head paints over the rows passing under it. The
       four surfaces that paint a ground of their own re-point it in their own
       sheets, so a register inside one needs no prop. */
    --lotics-register-ground: var(--background);

    /* An edge, not a shadow, which is why it follows the theme. */
    --lotics-shadow-hairline: 0 1px 2px 0 var(--border);
  }

  /* ─── Derived, THEME-INDEPENDENT ────────────────────────────────────────
     ON `:root` ALONE, for the mirror of the reason above. Nothing here reads a
     token the theme moves, so nothing here belongs on a theme scope. */
  :root {
    /* The on-solid ladder, for a control whose ground is a SOLID ROLE token: on
       the default theme `--primary` IS `--foreground`, so a foreground-mixed
       hover paints near-black on near-black. Two STRENGTHS rather than two
       colours — the component runs the mix, these fix how far it goes. */
    --lotics-on-solid-hover: 10%;
    --lotics-on-solid-press: 18%;

    /* One treatment everywhere — a disabled control that also changes hue reads
       as a different variant. */
    --lotics-disabled-opacity: 0.5;

    --lotics-ring-width: 2px;

    /* THE FAMILY'S SOLID — the few pixels that carry a hue outright: a status
       dot, a chart series, a swatch, a heat cell. ONE value in both themes and
       both LANGUAGES — `solid()` on `@lotics/ui/colors` answers the same
       question from JS, and `tokens_agreement.test.ts` holds the two together.
       The rung is per family by WCAG 1.4.11: each takes the lightest rung that
       clears 3:1 on BOTH canvases. */
    --lotics-tone-red-solid: var(--lotics-red-500);
    --lotics-tone-orange-solid: var(--lotics-orange-600);
    --lotics-tone-amber-solid: var(--lotics-amber-600);
    --lotics-tone-yellow-solid: var(--lotics-yellow-700);
    --lotics-tone-lime-solid: var(--lotics-lime-600);
    --lotics-tone-green-solid: var(--lotics-green-600);
    --lotics-tone-emerald-solid: var(--lotics-emerald-600);
    --lotics-tone-teal-solid: var(--lotics-teal-600);
    --lotics-tone-cyan-solid: var(--lotics-cyan-600);
    --lotics-tone-sky-solid: var(--lotics-sky-600);
    --lotics-tone-blue-solid: var(--lotics-blue-500);
    --lotics-tone-indigo-solid: var(--lotics-indigo-500);
    --lotics-tone-violet-solid: var(--lotics-violet-500);
    --lotics-tone-purple-solid: var(--lotics-purple-500);
    --lotics-tone-fuchsia-solid: var(--lotics-fuchsia-500);
    --lotics-tone-pink-solid: var(--lotics-pink-500);
    --lotics-tone-rose-solid: var(--lotics-rose-500);
    --lotics-tone-slate-solid: var(--lotics-slate-500);
    --lotics-tone-gray-solid: var(--lotics-gray-500);
    --lotics-tone-zinc-solid: var(--lotics-zinc-500);
    --lotics-tone-neutral-solid: var(--lotics-neutral-500);
    --lotics-tone-stone-solid: var(--lotics-stone-500);

    /* Spacing — every rung named by the pixel it is, which is also how the
       layout primitives take it (`gap={12}`). Ten rungs and no eleventh. 8
       between peers, 4 inside a pair, 2 for a hairline offset; 6, 10 and 12 are
       CONTROL INTERIORS and exist for nothing else; 16 / 24 / 32 / 48 are the
       region rungs. */
    --lotics-space-2: 2px;
    --lotics-space-4: 4px;
    --lotics-space-6: 6px;
    --lotics-space-8: 8px;
    --lotics-space-10: 10px;
    --lotics-space-12: 12px;
    --lotics-space-16: 16px;
    --lotics-space-24: 24px;
    --lotics-space-32: 32px;
    --lotics-space-48: 48px;
    /* One gutter for a list and the record it opens, or the content slides
       sideways at the moment the reader changes screens. The PAIR is the token,
       and `--lotics-page-pad` is the answer for a surface with no container to
       ask; one that establishes a container picks between the two off its own
       box. */
    --lotics-page-pad-narrow: var(--lotics-space-16);
    --lotics-page-pad-wide: var(--lotics-space-32);
    --lotics-page-pad: var(--lotics-page-pad-narrow);
    /* The dialog's left edge — its close row, header, scroll area, footer and
       any band a caller lays out inside them. Declared at the root so a band
       written for a dialog reads the same rung wherever it is rendered. */
    --lotics-dialog-gutter: var(--lotics-space-16);
    --lotics-row-wash-bleed: var(--lotics-space-8);

    /* Control metrics — every band control aligns to one height. */
    --lotics-control-height: 40px;
    --lotics-control-content-height: 28px;
    /* (40 − 28) / 2 − 1: the 1px border is part of the air. */
    --lotics-control-pad-y: 5px;
    --lotics-control-pad-x: 8px;
    /* 1px border + 8px padding — what a hanging line aligns to. */
    --lotics-control-text-inset: 9px;
    /* Can this still be OPERATED, and can this still be READ. The READ floor
       is not a value column's alone: a `Table` flex column and a heading's
       title column ask it too. */
    --lotics-control-min-width: 160px;
    --lotics-value-min-width: 200px;

    /* THE REGISTER BAND — one geometry for `Table`, `DataGrid`, `StateMatrix`
       and `Timetable`. The row IS the control height, because a pressable cell's
       whole box is the target; the head is the row, or a band of labels shorter
       than the records it names reads as a first row. Between columns there are
       two, by what the cells hold: words take the control interior, a grid of
       glyphs the hairline offset. */
    --lotics-register-row: var(--lotics-control-height);
    --lotics-register-head: var(--lotics-register-row);
    --lotics-register-inset: var(--lotics-space-12);
    --lotics-register-cell-gap: var(--lotics-space-2);
    /* ONE LINE OF A CELL — the rung a column's line budget is counted in
       (`TableColumn.lines`). The TIGHT body line box, which is what `CellStack`
       sets its pair in, so the two agree by construction. */
    --lotics-register-line: var(--lotics-leading-tight-sm);

    /* Identity marks — one scale for every avatar, and two of its four rungs
       ARE control metrics: `md` is the largest mark a 40px band can seat, `lg`
       is the mark that IS a control. */
    --lotics-avatar-sm: 24px;
    --lotics-avatar-md: var(--lotics-control-content-height);
    --lotics-avatar-lg: var(--lotics-control-height);
    --lotics-avatar-xl: 72px;
    /* Mark to label — the ONE gap between an identity mark and the text beside
       it. The 10 rung rather than 8: a mark is a round object and 8px reads
       tighter beside one than beside a box. */
    --lotics-lead-gap: var(--lotics-space-10);

    /* Radius — FOUR RUNGS BY ALTITUDE, picked by what the thing IS and never by
       how big it is. PROPORTIONAL to `--radius`, the way shadcn's own
       globals.css derives `--radius-sm/md/lg/xl` (× 0.6 / 0.8 / 1 / 1.4), so a
       tweakcn export scales this ladder and a consumer's `rounded-*` utilities
       identically. `card` IS shadcn's `xl`; `overlay` takes one more step. */
    --lotics-radius-control: var(--radius);
    --lotics-radius-card: calc(var(--radius) * 1.4);
    --lotics-radius-overlay: calc(var(--radius) * 2);
    --lotics-radius-full: 9999px;

    /* Shadows — anchored on their own colour, because a shadow stays dark in a
       dark theme: a warm theme sets `--lotics-shadow-color` once, on `:root`. */
    --lotics-shadow-color: var(--lotics-zinc-950);
    --lotics-shadow-raised: 0 0 6px 1px color-mix(in srgb, var(--lotics-shadow-color) 19%, transparent);
    --lotics-shadow-panel: -8px 0 24px color-mix(in srgb, var(--lotics-shadow-color) 8%, transparent);
    /* THE SCRIM LADDER — a dimming layer over CONTENT, here rather than with the
       themed washes because what it lies on is usually a PHOTOGRAPH, which does
       not invert. */
    --lotics-scrim-hover: color-mix(in srgb, var(--lotics-shadow-color) 6%, transparent);
    --lotics-scrim-press: color-mix(in srgb, var(--lotics-shadow-color) 12%, transparent);
    --lotics-scrim: color-mix(in srgb, var(--lotics-shadow-color) 15%, transparent);
    --lotics-scrim-strong: color-mix(in srgb, var(--lotics-shadow-color) 55%, transparent);
    --lotics-scrim-viewer: color-mix(in srgb, var(--lotics-shadow-color) 80%, transparent);
    /* The one scrim that carries a MEANING rather than a depth — a tile whose
       upload failed. Anchored on the danger family's deep rung rather than on
       `--destructive`, for the reason the ladder above sits here. */
    --lotics-scrim-danger: color-mix(in srgb, var(--lotics-red-800) 66%, transparent);

    /* Motion, named for what moves. Retime them from anywhere — the collapse
       below is `!important`, so it wins whatever a retiming declares. */
    --lotics-duration-fast: 120ms;
    --lotics-duration-base: 180ms;
    --lotics-duration-slow: 240ms;
    --lotics-ease-standard: cubic-bezier(0.2, 0, 0, 1);
    --lotics-ease-exit: cubic-bezier(0.4, 0, 1, 1);

    /* Overlays — a PUBLISHED ladder: anything outside the kit that must clear a
       Lotics overlay reads a rung from here rather than picking a literal. */
    --lotics-z-overlay: 9999;
    --lotics-z-overlay-above: 10000;
    --lotics-z-notification: 10001;
    --lotics-z-skip-link: 10002;
    /* In-page — LOCAL to the stacking context the component establishes, and
       never compared with an overlay rung. The first is in-flow content lifted
       back over an absolutely-positioned sibling that spans it, and it is
       strictly below the sticky header's: a STATIC row does not isolate, so on a
       shared rung the body would paint over the header. */
    --lotics-z-row-content: 1;
    --lotics-z-sticky-header: 2;
    --lotics-z-sticky-column: 3;
    --lotics-z-drag: 4;
    /* The TOP in-page rung: a bar that floats over the whole scroller and
       everything sticky or dragged inside it. The gap under it is deliberate —
       an app layers its own surface anywhere in 5–19 and the bar still clears
       it. */
    --lotics-z-floating-bar: 20;

    /* Type — two curves. `line-height` sets the box height of even a single
       line, so these decide the height of every label, value and control. */
    --lotics-text-xs: 12px;
    --lotics-text-sm: 14px;
    --lotics-text-md: 16px;
    --lotics-text-lg: 18px;
    --lotics-text-xl: 22px;
    --lotics-text-xxl: 28px;
    --lotics-text-xxxl: 32px;

    /* PROSE leading on the body rungs — a typed note and the same note rendered
       as markdown then sit at one rhythm. */
    --lotics-leading-xs: 18px;
    --lotics-leading-sm: 24px;
    --lotics-leading-md: 26px;
    --lotics-leading-lg: 28px;
    --lotics-leading-xl: 28px;
    --lotics-leading-xxl: 34px;
    --lotics-leading-xxxl: 38px;

    /* TIGHT — `size + 6` capped at the rung's own prose leading, for a STACKED
       PAIR, which is one object rather than prose. */
    --lotics-leading-tight-xs: 18px;
    --lotics-leading-tight-sm: 20px;
    --lotics-leading-tight-md: 22px;
    --lotics-leading-tight-lg: 24px;
    --lotics-leading-tight-xl: 28px;
    --lotics-leading-tight-xxl: 34px;
    --lotics-leading-tight-xxxl: 38px;

    /* Inter's own dynamic-metrics curve per rung — derived, never nudged. Stated
       once, in em, because an em already scales with the size. */
    --lotics-tracking-xs: 0em;
    --lotics-tracking-sm: -0.006em;
    --lotics-tracking-md: -0.011em;
    --lotics-tracking-lg: -0.014em;
    --lotics-tracking-xl: -0.018em;
    --lotics-tracking-xxl: -0.021em;
    --lotics-tracking-xxxl: -0.022em;
    /* The ONE rung the curve above does not answer: it is drawn for lowercase,
       and set in caps the same text reads shouted. Positive tracking is the
       standard micro-cap treatment (a stat label, a column header). */
    --lotics-tracking-caps: 0.05em;

    /* The input rung is the body rung at each width, which is also what stops
       Safari iOS auto-zooming a focused field. The WEIGHT is one of them so a
       surrounding box can move it without reaching into the field's own class. */
    --lotics-input-text: var(--lotics-text-md);
    --lotics-input-leading: var(--lotics-leading-md);
    --lotics-input-tracking: var(--lotics-tracking-md);
    --lotics-input-weight: var(--lotics-weight-regular);

    /* THE VALUE RUNG — what a value a reader READS is set in, and therefore what
       a field that draws no frame at rest is set in. `sm` at BOTH widths: its
       own three rather than the input's, because below 768 the input rung is 16
       — the floor Safari imposes on a FOCUSED field — and a value nobody is
       typing into is not one. The WEIGHT has no floor, so both faces read
       `--lotics-input-weight`. */
    --lotics-value-text: var(--lotics-text-sm);
    --lotics-value-leading: var(--lotics-leading-sm);
    --lotics-value-tracking: var(--lotics-tracking-sm);

    --lotics-weight-regular: 400;
    --lotics-weight-medium: 500;
    --lotics-weight-semibold: 600;
    /* Inter's stylistic alternates — `cv11` single-storey `a`, `ss01` alternate
       `1`, `ss03` alternate `g`. A TOKEN because the property does not inherit
       from anything the kit owns: every part that paints its own words has to
       name them. */
    --lotics-font-features: "cv11", "ss01", "ss03";
    /* FIGURES ARE LINING AND TABULAR, everywhere, and this is the only place
       that is decided. `reset.css` states it on the kit's own elements, so a
       page that disagrees cannot reach inside; `css_contract` refuses
       `oldstyle-nums` and `proportional-nums` in any sheet. */
    --lotics-font-numeric: lining-nums tabular-nums;
    /* Its own token because swapping the face a headline wears is one value with
       no dependencies; swapping the BODY face is a tracking curve and a
       diacritic check as well, which is why that one is `--font-sans`. */
    --lotics-font-display: var(--font-sans);
  }

  /* A conditional block repeats the scopes its base block uses — named on
     fewer, it loses to that block on the ones it omits. The ramp is
     theme-independent, so both are `:root`. */
  @media (min-width: 768px) {
    :root {
      --lotics-page-pad: var(--lotics-page-pad-wide);
      --lotics-dialog-gutter: var(--lotics-space-24);

      --lotics-text-lg: 20px;
      --lotics-text-xl: 24px;
      --lotics-text-xxl: 32px;
      --lotics-text-xxxl: 48px;

      --lotics-leading-lg: 30px;
      --lotics-leading-xl: 32px;
      --lotics-leading-xxl: 44px;
      --lotics-leading-xxxl: 52px;

      --lotics-leading-tight-lg: 26px;
      --lotics-leading-tight-xl: 30px;
      --lotics-leading-tight-xxl: 38px;
      --lotics-leading-tight-xxxl: 52px;

      --lotics-input-text: var(--lotics-text-sm);
      --lotics-input-leading: var(--lotics-leading-sm);
      --lotics-input-tracking: var(--lotics-tracking-sm);
    }
  }

  /* 1ms, never 0: an overlay that waits for `transitionend` before unmounting
     never unmounts if no transition runs. Collapsing at the token is also why no
     component writes a reduced-motion rule of its own.

     THE ONE `!important` IN THE KIT, and the one exception to "an unlayered rule
     of yours beats every LAYERED kit rule": without it a retiming is simply
     later at the same specificity and silently defeats this. A plain
     `--lotics-duration-base: 240ms` of yours still collapses here. */
  @media (prefers-reduced-motion: reduce) {
    :root {
      --lotics-duration-fast: 1ms !important;
      --lotics-duration-base: 1ms !important;
      --lotics-duration-slow: 1ms !important;
    }
  }
}
