/* ---------------------------------------------------------------------------
   kjol — the shared Tailwind extension layer.
   ---------------------------------------------------------------------------
   Three layers stack to make a kjol app's stylesheet, in this order:

       base Tailwind (tw_theme.css + tw_preflight.css)   the framework defaults
       kjol extensions (THIS FILE)                        the shared design system
       app brand (the app's own style.css)                colours, fonts, one-offs

   tw.CompileApp / tw.CompileAppFiles prepend this file to the app's entry
   stylesheet, so the Tailwind engine sees it before the app's brand. That is why
   `@import "tailwindcss"` lives here rather than in the app's stylesheet: an
   @import has to come first, and the app's file no longer is. A kjol app therefore
   carries only brand — its palette, its fonts, its own rules — and names none of
   the tokens below; it inherits them.

   The vocabulary here is shared with the Go/WASM kit (webui.ThemeTokens) on
   purpose: two kits, one contract. A designer changes `surface` once and both
   layers of a site move together.
   --------------------------------------------------------------------------- */

@import "tailwindcss";

/* ---------------------------------------------------------------------------
   Dark mode: `dark:` as a CLASS, not a media query.
   ---------------------------------------------------------------------------
   Tailwind's built-in dark variant follows the operating system. A site with its
   own theme switch cannot use it: the OS says one thing, the switch says another,
   the media query wins, and the button appears to do nothing.

   This redefines the variant against a class on <html>, which the Theme controller
   (uikit/Theme.tsx, webui.Theme) toggles. The OS is still respected — it is the
   DEFAULT, applied by the boot script before first paint — just no longer the last
   word.
   --------------------------------------------------------------------------- */
@custom-variant dark (&:where(.dark, .dark *));

/* Icon family for uikit/Icons.tsx, read at runtime via getComputedStyle:
   --fa-style: classic → far/fas, sharp → fasr/fass; --fa-default-solid: 0|1.
   Kept in :root (not @theme) so Tailwind doesn't tree-shake it as unused — it is
   never named by a utility class, so nothing would mark it as reachable. */
:root {
    --fa-style: classic;
    --fa-default-solid: 0;
}

@theme {
    /* Custom text sizes */
    --text-ss: 0.8rem;   /* Override: Tailwind default is 0.75rem */

    /* Custom breakpoints (Tailwind defaults + xs + ultrawide) */
    --breakpoint-xs: 375px;
    --breakpoint-sm: 640px;
    --breakpoint-md: 768px;
    --breakpoint-lg: 1024px;
    --breakpoint-xl: 1280px;
    --breakpoint-2xl: 1536px;
    --breakpoint-ultrawide: 3840px;

    /* Custom containers */
    --container-8xl: 88rem;
    --container-9xl: 96rem;
    --container-10xl: 104rem;
    --container-ultrawide: 240rem;

    /* Custom radius */
    --radius-default: var(--radius-sm);

    /* ---- THE THEME CONTRACT ------------------------------------------------
       Every component in the kit says bg-surface / border-line / text-ink and
       NEVER names a colour. These are the tokens it is allowed to name.

       That is the whole trick. A theme is the twenty values below, not a `dark:`
       variant on four hundred class strings — so switching to dark is a rule that
       re-points these, and not one component knows it happened.

       The vocabulary is deliberately identical to the Go/WASM kit's (webui.
       ThemeTokens). Two kits, one contract: a designer changes `surface` once and
       both layers of the site move together. */

    /* Surfaces, in ascending prominence. */
    --color-surface: #ffffff;
    --color-surface-muted: #fafafa;
    --color-surface-raised: #f5f5f5;
    --color-surface-strong: #e5e5e5;

    /* Lines. */
    --color-line: #e5e5e5;
    --color-line-strong: #d4d4d4;

    /* Ink, in descending prominence. */
    --color-ink: #171717;
    --color-ink-soft: #525252;
    --color-ink-muted: #737373;
    --color-ink-faint: #a3a3a3;

    /* The solid neutral button. It INVERTS: a dark button on a light page, a light
       button on a dark one. That is why it is three tokens and not `bg-ink` — the
       text on top of it has to invert with it, and `text-white` would vanish the
       moment the fill went pale. */
    --color-fill-neutral: #404040;
    --color-fill-neutral-hover: #262626;
    --color-on-fill-neutral: #ffffff;

    /* The accent, in four parts, because a single "brand colour" cannot do four jobs.
       Same names as the Go kit (webui.ThemeTokens) — one vocabulary, two kits.

       primary is a FILL: it carries white text, so it has to stay dark enough for white
       to sit on it. accent is TEXT and icons: it has to stay readable ON the surface.
       One value cannot be both, and in dark mode they diverge completely — the fill
       stays put while the text has to climb.

       primary-subtle / primary-border are the tinted panel: a callout, a selected row.

       Brand supplies the values; see the app's style.css. These defaults keep the kit
       legible before an app has themed anything, NOT so that it can skip theming. */
    --color-primary: #404040;
    --color-primary-hover: #262626;
    --color-primary-subtle: #f5f5f5;
    --color-primary-border: #d4d4d4;
    --color-accent: #262626;

    /* ---- deliberately-dark chrome (the kit's `onDark` prop) ----------------
       Not the same thing as dark MODE. Several components take onDark, for when
       they sit on a dark bar or panel in an otherwise light page — so these stay
       dark in BOTH themes and are not overridden below.

       They are named by the components (bg-dark, text-text-on-dark, …); defining
       them here is what makes those onDark paths render styled rather than with no
       colour at all. */
    --color-dark: #101013;
    --color-dark-raised: #1f1f24;
    --color-text-on-dark: #f9fafb;
    --color-text-on-dark-muted: #9ca3af;
    --color-text-on-dark-faint: #6b7280;
    --color-border-on-dark: #2a2a30;

    /* State colours. These DO name a colour, because they mean one: an alert that
       is not red is not an alert. Their tinted BACKGROUNDS are the one place the
       kit still carries a `dark:` variant — a red-50 wash is invisible on a near
       black surface, and no re-pointed token can fix that. */
    --color-info: var(--color-sky-500);
    --color-on-info: var(--color-white);
    --color-success: var(--color-green-500);
    --color-on-success: var(--color-white);
    --color-warning: var(--color-amber-500);
    --color-on-warning: var(--color-white);
    --color-danger: var(--color-red-500);
    --color-on-danger: var(--color-white);

    /* ---- the categorical CHART palette -------------------------------------
       Eight fixed slots for uikit/Chart.tsx. A series is painted by its INDEX
       (slot 1, 2, 3 …) and never by a cycled/derived hue — a ninth series folds
       into "Other" rather than inventing a colour. Unlike the state colours these
       are a set, tuned as a set: the ordering maximises the minimum colour-blind
       ΔE between neighbouring slots, so adjacent series stay distinguishable under
       protanopia/deuteranopia (worst adjacent ΔE 24 in light, 10 in dark — see the
       data-viz palette validator).

       These CAN be named in a component because a chart is SVG and SVG fills read
       CSS variables (a canvas cannot, so it would need a literal hex). The dark
       column below is the same eight hues stepped for the near-black surface, not a
       second palette. Brand overrides by redefining these (or passing `palette` to a
       single chart). */
    --color-chart-1: #2a78d6; /* blue    */
    --color-chart-2: #1baf7a; /* aqua    */
    --color-chart-3: #eda100; /* yellow  */
    --color-chart-4: #008300; /* green   */
    --color-chart-5: #4a3aa7; /* violet  */
    --color-chart-6: #e34948; /* red     */
    --color-chart-7: #e87ba4; /* magenta */
    --color-chart-8: #eb6834; /* orange  */

    /* Sequential ramp for the choropleth (uikit/USHeatmap): one hue, light→dark, six
       steps low→high. Unlike the categorical slots it means MAGNITUDE, so it is a single
       blue stepped by lightness. Dark mode re-points it below: on a near-black surface a
       high value must read as BRIGHTER, not darker, so the ramp inverts its lightness
       direction while keeping the same hue. */
    --color-choropleth-1: #dbe9fb;
    --color-choropleth-2: #b3d0f6;
    --color-choropleth-3: #85b3ee;
    --color-choropleth-4: #5591e4;
    --color-choropleth-5: #2f6fca;
    --color-choropleth-6: #124f8f;
}

/* ---------------------------------------------------------------------------
   The dark theme.
   ---------------------------------------------------------------------------
   Only the token VALUES change. Not one component knows this block exists — they
   ask for bg-surface and text-ink, and here is where those come to mean something
   else.

   This is a plain rule, not another @theme block: @theme GENERATES utilities, and
   these are overrides of utilities that already exist.

   The surfaces are not pure black. Black gives a dark UI a hard, glaring edge
   against white text and makes every border invisible; a very dark grey leaves room
   for the raised surfaces and the lines above it to actually be seen.
   --------------------------------------------------------------------------- */
.dark {
    --color-surface: #101013;
    --color-surface-muted: #17171b;
    --color-surface-raised: #1f1f24;
    --color-surface-strong: #2c2c33;

    --color-line: #2a2a30;
    --color-line-strong: #3d3d45;

    --color-ink: #f2f2f3;
    --color-ink-soft: #c6c6cc;
    --color-ink-muted: #9a9aa3;
    --color-ink-faint: #71717a;

    /* Inverted, as promised above: pale fill, dark text. */
    --color-fill-neutral: #e5e5e5;
    --color-fill-neutral-hover: #ffffff;
    --color-on-fill-neutral: #171717;

    /* The fill stays where it is — white text still has to be readable on it — but the
       tinted panel and the accent TEXT both have to move, or they vanish into a near
       black surface. This is exactly why they are separate tokens. */
    --color-primary-subtle: #1f1f24;
    --color-primary-border: #3d3d45;
    --color-accent: #e5e5e5;

    /* The chart palette, re-stepped for the dark surface. Same eight hues, lifted
       into the dark-mode lightness band so every slot clears 3:1 against #101013 —
       a light-mode aqua or yellow would sink into the surface. Validated as a set
       against the dark surface, exactly as the light column was against white. */
    --color-chart-1: #3987e5;
    --color-chart-2: #199e70;
    --color-chart-3: #c98500;
    --color-chart-4: #008300;
    --color-chart-5: #9085e9;
    --color-chart-6: #e66767;
    --color-chart-7: #d55181;
    --color-chart-8: #d95926;

    /* Same blue hue, stepped for the dark surface and inverted in direction: step 1 (low)
       is the dimmest, step 6 (high) the brightest, so "more" reads as "brighter". */
    --color-choropleth-1: #1b2a44;
    --color-choropleth-2: #21406c;
    --color-choropleth-3: #2c5f97;
    --color-choropleth-4: #3f80c8;
    --color-choropleth-5: #649de8;
    --color-choropleth-6: #93c2f7;
}

/* The page's own background — painted before anything mounts, and behind it
   afterwards. Without this a dark app sits in a white window. */
html {
    background-color: var(--color-surface);
    color: var(--color-ink);
}
