/* ---------------------------------------------------------------------------
 * Design tokens — the single source for fonts, type scale and colour.
 *
 * This lives in its own file for one reason: Tailwind only picks up `@theme`
 * from an UNLAYERED import. Consumers that pull the component styles in with
 * `@import "@rebasepro/ui/index.css" layer(base)` — which the marketing site
 * and the docs both do, to keep component CSS below their own utilities — get
 * the layer wrapped around everything transitively, and the theme silently
 * does not register. That is why the font stacks used to be copy-pasted into
 * every consumer's own `@theme`.
 *
 * Import this file unlayered, alongside the layered index.css:
 *
 *     @import "@rebasepro/ui/theme.css";
 *     @import "@rebasepro/ui/index.css" layer(base);
 * ------------------------------------------------------------------------- */

@theme {
    /* Font Families — Instrument Sans for headings, Inter for UI and body copy. */
    --font-sans: 'Inter Variable', 'Inter', ui-sans-serif, system-ui, 'Helvetica', 'Arial', sans-serif;
    --font-headers: 'Instrument Sans Variable', 'Instrument Sans', 'Inter Variable', 'Inter', ui-sans-serif, system-ui, sans-serif;
    --font-mono: 'JetBrains Mono', 'Space Mono', 'Lucida Console', monospace;

    /* Type scale — three tiers keyed to RENDERED SIZE, not tag depth.
       Tailwind turns each into a `tracking-*` utility, so the admin panel, the
       console and the marketing site all spell the same intent the same way
       instead of each hardcoding its own em value. Pair display/title with
       font-semibold and heading with font-medium. */
    /* -0.025em, revised 2026-08-24 from -0.022em. The website's dev-only
       TypeDevPanel has shipped `td: -25` as its "SHIPPED" default all along, so
       every local preview and every design decision taken in front of one was
       made at -0.025em while the built site served -0.022em. Of the panel's
       eleven defaults these two — tracking and display weight — were the only
       ones that did not match the tokens. Both are now true. */
    --tracking-display: -0.025em; /* >= 30px — the headline tier; matches the marketing site */
    --tracking-title: -0.018em;   /* 20-24px — section titles */
    --tracking-heading: -0.01em;  /* <= 18px — labels; still a heading, not a headline */

    /* Sub-`xs` type. These exist because the marketing site had ~450
       hand-written `text-[10px]` / `text-[11px]` classes: the tier was real, it
       just wasn't in the system, so every page improvised it.

       In product UI there is exactly ONE sanctioned use — `typography-micro`,
       the uppercase field label above a value — and it earns the exception by
       never carrying a sentence. Everything a person actually *reads* stays at
       `text-xs` (12px) or above. `--text-3xs` remains marketing-only. */
    --text-2xs: 11px;
    --text-2xs--line-height: 1.45;
    --text-3xs: 10px;
    --text-3xs--line-height: 1.4;

    /* Display tier — above `text-4xl`, where the scale stops being a heading
       and starts being a statement. Added 2026-08-24.

       Fluid rather than fixed because the same token has to survive four
       locales: German and French run 15-25% longer than English, and a fixed
       112px headline that fits "The Postgres you already have" does not fit
       "Das Postgres, das Sie bereits haben". The `vw` middle term shrinks
       before it can overflow; the `rem` floor protects small screens, where
       the type is already proportionally large.

       Both carry their own line-height and tracking: at this size 1.1 reads as
       a gap and -0.025em reads as loose. Weight stays on the 600 ceiling —
       this tier separates itself by SIZE, which is the whole point of adding
       it rather than reaching for 700. */
    --text-display-2: clamp(2.25rem, 4.4vw, 4rem);      /* 36 -> 64px */
    --text-display-2--line-height: 1.0;
    --text-display-2--letter-spacing: -0.028em;
    /* 7.2vw capped at 7rem was too much: on a wide window the headline filled
       the viewport on its own and pushed the install terminal below the fold,
       which breaks the rule the hero exists to satisfy (SITE-STORY §5 — the
       hero carries a product artifact). Still ~1.7x the 48px it replaced. */
    --text-display-1: clamp(2.5rem, 5.2vw, 4.75rem);    /* 40 -> 76px */
    --text-display-1--line-height: 0.94;
    --text-display-1--letter-spacing: -0.032em;

    /* Control heights — the one scale every inline control resolves to, so a
       Button, TextField and Select at the same size share a baseline. Mirrors
       CONTROL_HEIGHT in styles.ts; that is the source for React components,
       these are for everyone else.

       Marketing pages and docs are plain markup and cannot import a JS mixin,
       so without these they hand-roll their own paddings and drift: the site's
       two hero CTAs sat at 52px and 54px, on no scale and not even matching
       each other. Reach for `min-h-(--control-xl)` instead of a magic number. */
    --control-smallest: 28px;
    --control-small: 32px;
    --control-medium: 40px;
    --control-large: 48px;
    --control-xl: 56px;   /* buttons only */
    --control-2xl: 64px;  /* buttons only */

    /* Radius ladder. Tailwind's defaults (6 / 8 / 12) read as square beside
       the reference, whose controls sit at ~10px and cards at 12–14; matching
       it outright (8 / 10 / 14) read as borrowed. This sits between: the two
       utilities the product uses for controls and containers move up one or
       two pixels, chips keep the default. Overriding the utilities rather than
       the call sites moves every control, card, menu and sheet together; no
       call site names a number. `rounded-full` is a rule, not a size, and it
       is rare: search fields, the switch and avatars. */
    --radius-md: 6px;    /* chip, code well, tile, segment (Tailwind's own value) */
    --radius-lg: 9px;    /* control, row highlight, menu, folder tab, segmented track */
    --radius-xl: 13px;   /* card, sheet, dialog */

    /* Colors */
    --color-primary: #0070F4;
    --color-primary-light: oklch(from var(--color-primary) calc(l + 0.15) c h);
    --color-primary-dark: oklch(from var(--color-primary) calc(l - 0.15) c h);
    /* rose-600. #FF5B79 was only 2.99:1 against white, so white text on it
       and it as text both failed WCAG AA. Same hue family, 4.70:1. */
    --color-secondary: #E11D48;
    --color-secondary-light: oklch(from var(--color-secondary) calc(l + 0.15) c h);
    --color-secondary-dark: oklch(from var(--color-secondary) calc(l - 0.15) c h);

    --color-primary-bg: oklch(from var(--color-primary) l c h / 0.1);
    --color-secondary-bg: oklch(from var(--color-secondary) l c h / 0.1);

    /* Field Colors */
    --color-field-disabled: rgb(224 224 226);
    --color-field-disabled-dark: rgb(35 35 37);

    /* Text Colors — using opaque values so icon strokes render solidly */
    --color-text-primary: #212121;
    /* #737373, not #757575. Two units, and they are the two that matter.
       The app's light page ground is #fafafa, not #ffffff, and #757575 lands at
       4.41:1 there — under AA for the 14px type this token carries. It clears
       4.5 only against pure white, which is not a surface the product actually
       uses. Every field label in light mode was failing by a whisker.
       #737373 measures 4.54:1 on #fafafa and 4.74:1 on #ffffff, so it passes on
       both grounds instead of the theoretical one. Same fix, and the same
       reasoning, as the `--color-surface-500` move recorded below. */
    --color-text-secondary: #737373;
    /* #8b8b8b, not #9e9e9e. Measured against the field fill a disabled label
       actually sits on (`surface-accent-200/50` over #fafafa ≈ #eef1f5),
       #9e9e9e reached 2.36:1 — present, but not readable.
       Full AA is not achievable here and should not be chased: 4.5:1 on that
       fill needs #6e6e6e, which is DARKER than the #737373 an ENABLED label
       uses, so the disabled state would read as the emphasised one. WCAG 1.4.3
       exempts inactive controls for exactly this reason.
       #8b8b8b lands at ~3:1 — legible at a glance, still unmistakably muted
       against its enabled neighbour. */
    --color-text-disabled: #8b8b8b;
    --color-text-primary-dark: #ffffff;
    --color-text-secondary-dark: #a0a0a9;
    --color-text-disabled-dark: #757580;

    /* Surface Colors */
    --color-surface-50: #fafafa;
    --color-surface-100: #f5f5f5;
    --color-surface-200: #e5e5e5;
    --color-surface-300: #d4d4d4;
    --color-surface-400: #a3a3a3;
    /* Muted text: captions, nav descriptions, table headers, eyebrows.
       #737373 was tuned for light and measured 4.74:1 on white but only
       4.43:1 on #000 and 4.18:1 on #0a0a0a, so every dark surface — the
       marketing site, the console, the admin panel in dark mode — carried a
       muted tier below AA. #797979 is the balance point: it is the single
       value where the white and #111111 curves cross, at 4.35:1 on each,
       and it clears 4.5:1 outright on the two backgrounds that carry most of
       this token (4.82:1 on #000, 4.55:1 on #0a0a0a). */
    --color-surface-500: #797979;
    --color-surface-600: #404040;
    --color-surface-700: #262626;
    --color-surface-800: #111111;
    --color-surface-900: #0a0a0a;
    --color-surface-950: #000000;

    /* Surface Accent Colors */
    --color-surface-accent-50: #f8fafc;
    --color-surface-accent-100: #f1f5f9;
    --color-surface-accent-200: #e2e8f0;
    --color-surface-accent-300: #cbd5e1;
    --color-surface-accent-400: #94a3b8;
    --color-surface-accent-500: #64748b;
    --color-surface-accent-600: #475569;
    --color-surface-accent-700: #334155;
    --color-surface-accent-800: #1e293b;
    --color-surface-accent-900: #172033;
    --color-surface-accent-950: #0f172a;
}

/* The semantic surfaces as Tailwind colors. `inline` is load-bearing: it makes
   `bg-surface-card` emit `var(--surface-card)` at the element, so the value
   resolves under whichever dark selector the consumer uses. In a plain
   `@theme` the alias would be computed once on `:root` and stay light. The
   variables themselves are defined at the bottom of this file. */
@theme inline {
    --color-surface-frame: var(--surface-frame);
    --color-surface-sheet: var(--surface-sheet);
    --color-surface-card: var(--surface-card);
    --color-surface-card-hover: var(--surface-card-hover);
    --color-surface-raised: var(--surface-raised);
    --color-surface-raised-hover: var(--surface-raised-hover);
    --color-surface-lifted: var(--surface-lifted);
    --color-surface-field: var(--surface-field);
    --color-surface-field-hover: var(--surface-field-hover);
    --color-surface-hover: var(--surface-hover);
    --color-surface-active: var(--surface-active);
    --color-surface-scrim: var(--surface-scrim);
    --color-surface-well: var(--surface-well);
    --color-hairline: var(--hairline);
    --color-hairline-strong: var(--hairline-strong);
}

/* ---------------------------------------------------------------------------
 * Semantic surfaces — one role, two themes. Added 2026-09-08.
 *
 * Measured on demo.rebase.pro in dark mode, the panel used exactly two opaque
 * surface values: the ground (#0a0a0a) and the content sheet (#111111). Every
 * card painted `dark:bg-surface-900` — the GROUND value — on top of the sheet,
 * so cards were holes cut into the surface they sat on, and the largest areas
 * on screen carried the darkest value. Retuning the numbers cannot fix that:
 * the sheet used `800` and cards used `900`, and `900` must stay darker.
 *
 * So a surface is now named by ROLE and the theme decides the value. Two rules:
 *
 *   1. Every nested surface is one step lifted from the surface it sits on.
 *      Lifted means lighter on both themes; the light frame is the greyest
 *      thing on the page. Fields are the one exception — a field is inset, so
 *      it is an alpha fill that goes the other way.
 *   2. A hairline marks an object, not a region. Cards on the sheet, floating
 *      surfaces and fields get a line. The sheet edge, tiles inside a card,
 *      rows, tracks, buttons and chips do not; the lightness step separates
 *      them.
 *
 * These are plain custom properties, deliberately outside `@theme`, so they
 * can switch on the theme selector. The `@theme inline` entries above alias
 * them into Tailwind, and `inline` matters: it makes `bg-surface-card` emit
 * `var(--surface-card)` at the element, which resolves under whichever dark
 * selector the consumer uses (`.dark` in the panel, `[data-theme=dark]` on the
 * marketing site). Without `inline` the value would be fixed on `:root`.
 *
 * Interaction fills are alpha so they compose over whatever they land on. The
 * solid surfaces carry their own hover value because an alpha hover on a solid
 * background REPLACES it — white at 6% over the sheet is darker than the card
 * it was meant to lift.
 *
 * The rules are in packages/ui/DESIGN.md (Surfaces); the measurements behind
 * them are in docs/design/instatic-distilled.html.
 * ------------------------------------------------------------------------- */
/* No `.light` class here on purpose: nothing in the app sets one, and third-party
   widgets (React Flow) stamp `light` on their own root, which re-lit every token
   under them on a dark page. The light ladder is the root; `[data-theme]` and
   `.dark` are the only switches. */
:root,
[data-theme="light"] {
    --surface-frame: #f0f0f2;
    --surface-sheet: #f9f9fa;
    --surface-card: #ffffff;
    --surface-card-hover: #f7f7f8;
    --surface-raised: #ececee;
    --surface-raised-hover: #e3e3e6;
    --surface-lifted: #ffffff;
    --surface-field: rgb(0 0 0 / 0.035);
    --surface-field-hover: rgb(0 0 0 / 0.055);
    --surface-hover: rgb(0 0 0 / 0.04);
    --surface-active: rgb(0 0 0 / 0.07);
    --surface-scrim: rgb(0 0 0 / 0.4);
    /* The one surface that goes DOWN the ladder on purpose: a code well, a
       query, a log tail, a connection string, recessed into its card. */
    --surface-well: #f5f5f5;
    --hairline: rgb(0 0 0 / 0.08);
    --hairline-strong: rgb(0 0 0 / 0.13);
}

.dark,
[data-theme="dark"] {
    --surface-frame: #0a0a0a;
    --surface-sheet: #131313;
    --surface-card: #181818;
    --surface-card-hover: #1d1d1d;
    --surface-raised: #242424;
    --surface-raised-hover: #2c2c2c;
    --surface-lifted: #2c2c2c;
    --surface-field: rgb(255 255 255 / 0.04);
    --surface-field-hover: rgb(255 255 255 / 0.07);
    --surface-hover: rgb(255 255 255 / 0.06);
    --surface-active: rgb(255 255 255 / 0.09);
    --surface-scrim: rgb(0 0 0 / 0.6);
    --surface-well: #0a0a0a;
    --hairline: rgb(255 255 255 / 0.08);
    --hairline-strong: rgb(255 255 255 / 0.14);
}
