/* The dashboard controls' own design tokens.
 *
 * Every colour, size, font and duration drawn by the controls under
 * Application/NTI.Orbit.Client/DashboardControls/ resolves here, and nothing outside that folder reads these
 * names. This file is the whole palette of the dashboard surface, and re-declaring it is how that surface is
 * re-themed.
 *
 * THREE LAYERS, READ TOP DOWN.
 *
 *     base knobs      ->  base ramps            ->  semantic tokens             ->  a control
 *     --dbc-base-neutralHue   --dbc-base-neutral950     --dbc-theme-surfaceRaised     DbcPanel.razor.css
 *
 * - BASE (--dbc-base-*) is the theme editor's surface: a handful of knobs - two hues, two chromas, three
 *   scales, the font stacks - and the ramps computed from them. A control must never read one, and a test
 *   enforces that: a knob has no meaning on its own, and a palette whose consumers reach past the semantic
 *   layer can no longer be re-mapped without breaking them.
 * - SEMANTIC (--dbc-theme-<role>) is the only layer a control reads. Each name says what the colour is FOR,
 *   so a re-theme re-points a role at a different ramp step instead of hunting through 51 stylesheets.
 *
 * WHY IT EXISTS. The dashboard controls used to read FluentUI's own tokens, which no file in this repository
 * declares - FluentUI's JavaScript injects them onto <html> at run time. That left the appearance of every
 * dashboard owned by a third-party package, and it is what made the v4-to-v5 dead-token trap silent: a renamed
 * token fell back to its hex literal, freezing seven controls in light mode with nothing reporting it
 * (Documentation/THEMING.md, "The dead-token trap"). These names are Orbit's, so a missing one is a test
 * failure instead of a colour nobody notices.
 *
 * THE CARRIER RULE, WHICH IS WHAT MAKES THE DARK BLOCK SHORT. A var() inside a custom property is
 * substituted where the DECLARATION sits, and the substituted result is what descendants inherit. So
 * overriding a base value on an element that does NOT itself carry the semantic declarations does nothing:
 * that element inherits the semantic values its ancestor already resolved against the other ramp. Measured
 * in the browser, not assumed.
 *
 *     Every element carrying --dbc-theme-* declarations must also carry a complete --dbc-base-* set for the
 *     theme in force. Never override a base on an element the semantic layer is not also declared on.
 *
 * Two elements carry the semantic layer: <html> (via :root) and .dbc-theme. The dark rule's selectors name
 * both - :root:has(body[data-theme="dark"]) for the first, body[data-theme="dark"] .dbc-theme for the second -
 * so that its re-declarations actually land. body[data-theme="dark"] on its own would not be enough: <body>
 * carries no semantic declaration of its own, so a base override there would be inert.
 *
 * What the dark rule repeats is small and each line of it carries meaning: the two elevation knobs, and the
 * MAPPING - which ramp step each role points at, which is the whole of what a dark theme is. The ramp steps
 * themselves are identical in both themes and are declared once.
 *
 * @property RATHER THAN A FALLBACK PER USE. A registered custom property with an initial-value can never make
 * var() fail, so the call sites carry no fallback and cannot drift out of date - 822 of them did carry one, and
 * one still named the *previous* brand colour. It also removes a sharper failure: an unresolved var()
 * invalidates its whole declaration, so one missing token used to cost DbcPanel its border along with its
 * shadow, and seven controls their high-contrast focus ring.
 *
 * @layer SO A THEME NEED NOT BE AN INLINE STYLE. Dark mode is marked on <body>, so its rule has to name
 * that attribute - which would out-specify any later per-dashboard theme written as a class. Inside a layer it
 * does not: an unlayered rule beats every layered one whatever its specificity.
 *
 * TO RE-THEME, SET THE KNOBS ON .dbc-theme ITSELF, in an unlayered rule. Not on an ancestor: .dbc-theme
 * declares every token, and a declaration on an element always beats an inherited value, so an override
 * attached to a wrapper never reaches it. Setting the knobs alone is enough - the ramps and the semantic layer
 * are declared on that same element and re-derive from whatever the knobs now say, with no re-render and no C#
 * involved. There is deliberately no API for this yet, and nothing stops dashboard code from reading these
 * names, so "internal" is a convention, not a boundary.
 *
 * The light rule carries two selectors: :root so a control rendered outside a dashboard viewer still paints,
 * and .dbc-theme (DbcDashboard's root element) so a per-dashboard override has something to attach to. */


/* ==============================================================================================
 * THE DASHBOARD'S TYPEFACE
 *
 * Inter, self-hosted. It is the face the design was drawn in: a neo-grotesque with a tall x-height
 * and flat terminals, where the platform UI faces are humanist (Segoe UI Variable's splayed 'y' and
 * its double-storey 'g' are what make the difference visible at a glance).
 *
 * SHIPPED, NOT LINKED. The files are in wwwroot/fonts/ rather than fetched from a font CDN: a link
 * would put a third-party request on every dashboard load, and would leave the application without
 * its typeface on an air-gapped or locked-down network. Licence: SIL OFL 1.1, whose terms require
 * the notice to travel with the font - it is in wwwroot/fonts/Inter-LICENSE.txt.
 *
 * ONE FILE PER SUBSET, VARIABLE WEIGHT. `font-weight: 100 900` is the variable axis, so the 400,
 * 500 and 600 the controls use all come out of the same download rather than three static cuts.
 * The two subsets are split by `unicode-range`, so a page of Latin text fetches only the 48KB
 * file and the 85KB extended one is never requested. Anything outside both ranges - CJK, Cyrillic,
 * Greek - falls through to the stack's platform faces, which is why they are still listed there.
 *
 * NO ITALIC IS SHIPPED. Nothing in the controls sets `font-style: italic`, and a dashboard that does
 * gets the browser's synthetic oblique rather than a second ~50KB download.
 *
 * This applies to the DASHBOARD ONLY. The system application keeps the platform face; nothing outside
 * DashboardControls/ reads this file.
 * ============================================================================================== */

@font-face {
    font-family: "Inter Variable";
    font-style: normal;
    font-weight: 100 900;
    /* swap: the controls paint immediately in the fallback and re-flow to Inter when it arrives, rather
       than holding a dashboard's text invisible while the font downloads. */
    font-display: swap;
    src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
        U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Inter Variable";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
        U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
        U+A720-A7FF;
}

/* ==============================================================================================
 * REGISTRATIONS
 *
 * The initial-value is the light-theme value, and doubles as the documentation of what each token
 * is worth - the job the per-use hex fallbacks used to do.
 *
 * WHAT IS REGISTERED, AND WHAT IS NOT. A base token is registered when its value is a literal or a
 * trivial scale of one: the initial-value is then the same literal, and cannot drift. The COLOUR
 * RAMPS are deliberately not registered - an initial-value may not contain var(), so registering
 * oklch(25% calc(var(--dbc-base-neutralChroma) * 0.85) var(--dbc-base-neutralHue)) would mean
 * hand-computing a second copy of it that nothing can check against the first. Nothing is lost:
 * every ramp step is read only by a registered --dbc-theme-* token, so a broken step still lands on
 * that token's initial-value rather than making a declaration fail. What registration would have
 * caught - a MISTYPED ramp name - is caught instead by DashboardControlThemeTests, which asserts
 * that every --dbc-base-* named in this file is declared in this file.
 *
 * An initial-value must also be computationally independent: Chromium silently DROPS the whole
 * @property rule for var(), env() or a font-relative unit (em, rem, ...), leaving the token
 * unregistered at run time with nothing reported. A test rejects those.
 * ============================================================================================== */

/* Base: the knobs a theme editor edits. */
@property --dbc-base-neutralHue { syntax: "<number>"; inherits: true; initial-value: 258; }
@property --dbc-base-neutralChroma { syntax: "<number>"; inherits: true; initial-value: 0.045; }
@property --dbc-base-accentHue { syntax: "<number>"; inherits: true; initial-value: 264; }
@property --dbc-base-accentChroma { syntax: "<number>"; inherits: true; initial-value: 0.22; }
@property --dbc-base-dangerHue { syntax: "<number>"; inherits: true; initial-value: 27; }
@property --dbc-base-dangerChroma { syntax: "<number>"; inherits: true; initial-value: 0.19; }
@property --dbc-base-warningHue { syntax: "<number>"; inherits: true; initial-value: 70; }
@property --dbc-base-warningChroma { syntax: "<number>"; inherits: true; initial-value: 0.18; }
@property --dbc-base-successHue { syntax: "<number>"; inherits: true; initial-value: 145; }
@property --dbc-base-successChroma { syntax: "<number>"; inherits: true; initial-value: 0.15; }
@property --dbc-base-radiusScale { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --dbc-base-spaceScale { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --dbc-base-fontScale { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --dbc-base-elevationAlpha { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --dbc-base-shadowInk { syntax: "<color>"; inherits: true; initial-value: oklch(20% 0.04 258); }
@property --dbc-base-fontFamily { syntax: "*"; inherits: true; initial-value: "Inter Variable", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
@property --dbc-base-fontFamilyMono { syntax: "*"; inherits: true; initial-value: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace; }

/* The neutral and accent ramps are declared in the rules below, not here - see "WHAT IS REGISTERED" above. */

/* Base: the shape, spacing and type ramps. Each step is a literal times its scale knob, so the editor resizes
   a whole family with one number and never has to know the ramp itself. */
@property --dbc-base-radiusXs { syntax: "<length>"; inherits: true; initial-value: 4px; }
@property --dbc-base-radiusSm { syntax: "<length>"; inherits: true; initial-value: 6px; }
@property --dbc-base-radiusMd { syntax: "<length>"; inherits: true; initial-value: 8px; }
@property --dbc-base-radiusLg { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-base-space100 { syntax: "<length>"; inherits: true; initial-value: 4px; }
@property --dbc-base-space200 { syntax: "<length>"; inherits: true; initial-value: 8px; }
@property --dbc-base-space300 { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-base-space400 { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-base-fontSize100 { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-base-fontSize200 { syntax: "<length>"; inherits: true; initial-value: 14px; }
@property --dbc-base-fontSize300 { syntax: "<length>"; inherits: true; initial-value: 15px; }
@property --dbc-base-fontSize400 { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-base-fontSize500 { syntax: "<length>"; inherits: true; initial-value: 20px; }
@property --dbc-base-lineHeight100 { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-base-lineHeight200 { syntax: "<length>"; inherits: true; initial-value: 20px; }
@property --dbc-base-lineHeight300 { syntax: "<length>"; inherits: true; initial-value: 22px; }
@property --dbc-base-lineHeight500 { syntax: "<length>"; inherits: true; initial-value: 28px; }

/* NEW semantic layer. Grows one migration at a time: a role is added here when the control that needs it moves
   across, so a name in this list always has a reader. */
@property --dbc-theme-surfaceCanvas { syntax: "<color>"; inherits: true; initial-value: oklch(97.5% 0.0059 258); }
@property --dbc-theme-surfaceRaised { syntax: "<color>"; inherits: true; initial-value: oklch(100% 0 258); }
@property --dbc-theme-surfaceRaisedHeader { syntax: "<color>"; inherits: true; initial-value: oklch(100% 0 258); }
@property --dbc-theme-surfaceSunken { syntax: "<color>"; inherits: true; initial-value: oklch(95.5% 0.0072 258); }
@property --dbc-theme-surfaceGroup { syntax: "<color>"; inherits: true; initial-value: oklch(97.2% 0.0132 264); }
@property --dbc-theme-inkPrimary { syntax: "<color>"; inherits: true; initial-value: oklch(25% 0.0383 258); }
@property --dbc-theme-inkMuted { syntax: "<color>"; inherits: true; initial-value: oklch(55.5% 0.0405 258); }
@property --dbc-theme-inkAccent { syntax: "<color>"; inherits: true; initial-value: oklch(54.6% 0.2156 264); }
@property --dbc-theme-strokeSubtle { syntax: "<color>"; inherits: true; initial-value: oklch(95.5% 0.0072 258); }
@property --dbc-theme-strokeDefault { syntax: "<color>"; inherits: true; initial-value: oklch(91% 0.0117 258); }
@property --dbc-theme-elevation1 { syntax: "*"; inherits: true; initial-value: 0 1px 1px oklch(20% 0.04 258 / 0.03), 0 1px 3px oklch(20% 0.04 258 / 0.05); }
@property --dbc-theme-elevation2 { syntax: "*"; inherits: true; initial-value: 0 1px 2px oklch(20% 0.04 258 / 0.04), 0 2px 6px oklch(20% 0.04 258 / 0.06); }
@property --dbc-theme-elevation3 { syntax: "*"; inherits: true; initial-value: 0 1px 2px oklch(20% 0.04 258 / 0.05), 0 4px 12px oklch(20% 0.04 258 / 0.07); }
@property --dbc-theme-elevation4 { syntax: "*"; inherits: true; initial-value: 0 2px 4px oklch(20% 0.04 258 / 0.06), 0 6px 18px oklch(20% 0.04 258 / 0.09); }
@property --dbc-theme-elevation5 { syntax: "*"; inherits: true; initial-value: 0 4px 8px oklch(20% 0.04 258 / 0.07), 0 12px 28px oklch(20% 0.04 258 / 0.12); }
@property --dbc-theme-elevationRaised { syntax: "*"; inherits: true; initial-value: 0 1px 2px oklch(20% 0.04 258 / 0.05), 0 4px 12px oklch(20% 0.04 258 / 0.07); }
@property --dbc-theme-radiusControl { syntax: "<length>"; inherits: true; initial-value: 8px; }
@property --dbc-theme-radiusCard { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-theme-strokeHairline { syntax: "<length>"; inherits: true; initial-value: 1px; }
@property --dbc-theme-strokeFocusWidth { syntax: "<length>"; inherits: true; initial-value: 2px; }
@property --dbc-theme-motionFast { syntax: "<time>"; inherits: true; initial-value: 120ms; }
@property --dbc-theme-motionEase { syntax: "*"; inherits: true; initial-value: cubic-bezier(0.2, 0, 0.15, 1); }
@property --dbc-theme-typeFamily { syntax: "*"; inherits: true; initial-value: "Inter Variable", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
@property --dbc-theme-typeFamilyMono { syntax: "*"; inherits: true; initial-value: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace; }
@property --dbc-theme-typeCaptionSize { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-theme-typeCaptionLine { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-theme-typeBodySize { syntax: "<length>"; inherits: true; initial-value: 14px; }
@property --dbc-theme-typeBodyLine { syntax: "<length>"; inherits: true; initial-value: 20px; }
@property --dbc-theme-typeTitleSize { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-theme-typeTitleLine { syntax: "<length>"; inherits: true; initial-value: 22px; }
@property --dbc-theme-typeLargeSize { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-theme-typeLargeLine { syntax: "<length>"; inherits: true; initial-value: 22px; }
@property --dbc-theme-typeHeadingSize { syntax: "<length>"; inherits: true; initial-value: 20px; }
@property --dbc-theme-typeHeadingLine { syntax: "<length>"; inherits: true; initial-value: 28px; }
@property --dbc-theme-typeWeightBody { syntax: "<number>"; inherits: true; initial-value: 400; }
@property --dbc-theme-typeWeightMedium { syntax: "<number>"; inherits: true; initial-value: 500; }
@property --dbc-theme-typeWeightStrong { syntax: "<number>"; inherits: true; initial-value: 600; }
@property --dbc-theme-inkSecondary { syntax: "<color>"; inherits: true; initial-value: oklch(45% 0.04275 258); }
@property --dbc-theme-inkPlaceholder { syntax: "<color>"; inherits: true; initial-value: oklch(62% 0.0396 258); }
@property --dbc-theme-inkDisabled { syntax: "<color>"; inherits: true; initial-value: oklch(62% 0.0396 258); }
@property --dbc-theme-inkOnAccent { syntax: "<color>"; inherits: true; initial-value: oklch(100% 0 258); }
@property --dbc-theme-inkDanger { syntax: "<color>"; inherits: true; initial-value: oklch(55% 0.19 27); }
@property --dbc-theme-inkWarning { syntax: "<color>"; inherits: true; initial-value: oklch(57% 0.18 70); }
@property --dbc-theme-inkSuccess { syntax: "<color>"; inherits: true; initial-value: oklch(49% 0.15 145); }
@property --dbc-theme-inkAccentHover { syntax: "<color>"; inherits: true; initial-value: oklch(47% 0.209 264); }
@property --dbc-theme-accentSoftBorder { syntax: "<color>"; inherits: true; initial-value: oklch(87.8% 0.0572 264); }
@property --dbc-theme-dangerSoft { syntax: "<color>"; inherits: true; initial-value: oklch(95% 0.019 27); }
@property --dbc-theme-dangerSoftBorder { syntax: "<color>"; inherits: true; initial-value: oklch(85% 0.0665 27); }
@property --dbc-theme-warningSoft { syntax: "<color>"; inherits: true; initial-value: oklch(95% 0.018 70); }
@property --dbc-theme-warningSoftBorder { syntax: "<color>"; inherits: true; initial-value: oklch(85% 0.063 70); }
@property --dbc-theme-successSoft { syntax: "<color>"; inherits: true; initial-value: oklch(95% 0.015 145); }
@property --dbc-theme-successSoftBorder { syntax: "<color>"; inherits: true; initial-value: oklch(85% 0.0525 145); }
@property --dbc-theme-spaceLg { syntax: "<length>"; inherits: true; initial-value: 16px; }
@property --dbc-theme-motionNormal { syntax: "<time>"; inherits: true; initial-value: 200ms; }
@property --dbc-theme-surfaceHover { syntax: "<color>"; inherits: true; initial-value: oklch(97.5% 0.00585 258); }
@property --dbc-theme-surfaceActive { syntax: "<color>"; inherits: true; initial-value: oklch(95.5% 0.0072 258); }
@property --dbc-theme-surfaceSelected { syntax: "<color>"; inherits: true; initial-value: oklch(97.2% 0.0132 264); }
@property --dbc-theme-surfaceDisabled { syntax: "<color>"; inherits: true; initial-value: oklch(97.5% 0.00585 258); }
@property --dbc-theme-accentSolid { syntax: "<color>"; inherits: true; initial-value: oklch(54.6% 0.2156 264); }
@property --dbc-theme-accentSolidHover { syntax: "<color>"; inherits: true; initial-value: oklch(47% 0.209 264); }
@property --dbc-theme-accentSolidActive { syntax: "<color>"; inherits: true; initial-value: oklch(39% 0.176 264); }
@property --dbc-theme-solidStroke { syntax: "<color>"; inherits: true; initial-value: color-mix(in srgb, oklch(17.5% 0.0279 258) 22%, transparent); }
@property --dbc-theme-accentSoft { syntax: "<color>"; inherits: true; initial-value: oklch(97.2% 0.0132 264); }
@property --dbc-theme-accentSoftHover { syntax: "<color>"; inherits: true; initial-value: oklch(93% 0.0352 264); }
@property --dbc-theme-dangerSolid { syntax: "<color>"; inherits: true; initial-value: oklch(55% 0.19 27); }
@property --dbc-theme-dangerSolidHover { syntax: "<color>"; inherits: true; initial-value: oklch(48% 0.1862 27); }
@property --dbc-theme-dangerSolidActive { syntax: "<color>"; inherits: true; initial-value: oklch(40% 0.171 27); }
@property --dbc-theme-strokeStrong { syntax: "<color>"; inherits: true; initial-value: oklch(62% 0.0396 258); }
@property --dbc-theme-strokeAccent { syntax: "<color>"; inherits: true; initial-value: oklch(54.6% 0.2156 264); }
@property --dbc-theme-strokeDisabled { syntax: "<color>"; inherits: true; initial-value: oklch(91% 0.0117 258); }
@property --dbc-theme-focusHalo { syntax: "<color>"; inherits: true; initial-value: color-mix(in srgb, oklch(54.6% 0.2156 264) 55%, transparent); }
@property --dbc-theme-focusGlow { syntax: "*"; inherits: true; initial-value: inset 0 0 4px -1px color-mix(in srgb, oklch(54.6% 0.2156 264) 55%, transparent); }
@property --dbc-theme-elevationOverlay { syntax: "*"; inherits: true; initial-value: 0 2px 4px oklch(20% 0.04 258 / 0.06), 0 8px 24px oklch(20% 0.04 258 / 0.1); }
@property --dbc-theme-shadowColor { syntax: "<color>"; inherits: true; initial-value: color-mix(in srgb, oklch(20% 0.04 258) 8%, transparent); }
@property --dbc-theme-scrim { syntax: "<color>"; inherits: true; initial-value: color-mix(in srgb, oklch(17.5% 0.0279 258) 45%, transparent); }
@property --dbc-theme-spaceXs { syntax: "<length>"; inherits: true; initial-value: 4px; }
@property --dbc-theme-spaceSm { syntax: "<length>"; inherits: true; initial-value: 8px; }
@property --dbc-theme-spaceMd { syntax: "<length>"; inherits: true; initial-value: 12px; }
@property --dbc-theme-radiusSmall { syntax: "<length>"; inherits: true; initial-value: 4px; }
@property --dbc-theme-radiusPill { syntax: "<length>"; inherits: true; initial-value: 9999px; }

@layer dbc-theme {

    /* ==========================================================================================
     * LIGHT — the whole palette. The dark rule below repeats every part of it that differs.
     * ========================================================================================== */
    :root,
    .dbc-theme {

        /* ---------- BASE: knobs ---------- */

        /* Neutrals carry a slight blue cast rather than being pure grey, which is what makes the dark theme
           read as navy instead of charcoal. Chroma is the amount of that cast; each ramp step scales it. */
        --dbc-base-neutralHue: 258;
        --dbc-base-neutralChroma: 0.045;
        --dbc-base-accentHue: 264;
        --dbc-base-accentChroma: 0.22;

        /* Status hues are fixed rather than derived from the accent: red must stay red when the accent moves. */
        --dbc-base-dangerHue: 27;
        --dbc-base-dangerChroma: 0.19;
        /* The warning hue is requested well above where it lands: sRGB has no room for a saturated amber at
           this lightness, so the gamut clips 70 back to an effective ~54. Asking for 58 - the hue that looks
           right on paper - renders at ~46, which is only 19 degrees from the error ink and reproduces exactly
           the "a warning and an error looked alike" problem this palette already carries a note about.
           Chroma is likewise requested past the boundary and means "as saturated as sRGB allows here". */
        --dbc-base-warningHue: 70;
        --dbc-base-warningChroma: 0.18;
        --dbc-base-successHue: 145;
        --dbc-base-successChroma: 0.15;

        /* One number resizes a whole family. 1 is the ramp as written below. */
        --dbc-base-radiusScale: 1;
        --dbc-base-spaceScale: 1;
        --dbc-base-fontScale: 1;

        /* Elevation is an ink plus an alpha multiplier, so a theme deepens every shadow at once. Light mixes a
           tinted near-black at a few percent; dark uses true black much harder (see the dark rule). */
        --dbc-base-shadowInk: oklch(20% 0.04 258);
        --dbc-base-elevationAlpha: 1;

        /* "Inter Variable" is the @font-face above — the shipped file, so it always resolves. Bare `Inter`
           follows it for anyone with the static family installed, and the platform faces after that carry
           the characters the two shipped subsets do not. */
        --dbc-base-fontFamily: "Inter Variable", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        --dbc-base-fontFamilyMono: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;

        /* ---------- BASE: neutral ramp ---------- */

        --dbc-base-neutral0: oklch(100% 0 var(--dbc-base-neutralHue));
        --dbc-base-neutral50: oklch(97.5% calc(var(--dbc-base-neutralChroma) * 0.13) var(--dbc-base-neutralHue));
        --dbc-base-neutral100: oklch(95.5% calc(var(--dbc-base-neutralChroma) * 0.16) var(--dbc-base-neutralHue));
        --dbc-base-neutral200: oklch(91% calc(var(--dbc-base-neutralChroma) * 0.26) var(--dbc-base-neutralHue));
        --dbc-base-neutral300: oklch(84% calc(var(--dbc-base-neutralChroma) * 0.42) var(--dbc-base-neutralHue));
        --dbc-base-neutral400: oklch(76% calc(var(--dbc-base-neutralChroma) * 0.80) var(--dbc-base-neutralHue));
        --dbc-base-neutral500: oklch(62% calc(var(--dbc-base-neutralChroma) * 0.88) var(--dbc-base-neutralHue));
        --dbc-base-neutral600: oklch(55.5% calc(var(--dbc-base-neutralChroma) * 0.90) var(--dbc-base-neutralHue));
        --dbc-base-neutral700: oklch(45% calc(var(--dbc-base-neutralChroma) * 0.95) var(--dbc-base-neutralHue));
        --dbc-base-neutral800: oklch(34% calc(var(--dbc-base-neutralChroma) * 1.05) var(--dbc-base-neutralHue));
        --dbc-base-neutral850: oklch(27.5% calc(var(--dbc-base-neutralChroma) * 1.00) var(--dbc-base-neutralHue));
        --dbc-base-neutral900: oklch(25% calc(var(--dbc-base-neutralChroma) * 0.85) var(--dbc-base-neutralHue));
        --dbc-base-neutral950: oklch(22% calc(var(--dbc-base-neutralChroma) * 0.72) var(--dbc-base-neutralHue));
        --dbc-base-neutral1000: oklch(17.5% calc(var(--dbc-base-neutralChroma) * 0.62) var(--dbc-base-neutralHue));

        /* ---------- BASE: accent ramp ---------- */

        --dbc-base-accent50: oklch(97.2% calc(var(--dbc-base-accentChroma) * 0.06) var(--dbc-base-accentHue));
        --dbc-base-accent100: oklch(93% calc(var(--dbc-base-accentChroma) * 0.16) var(--dbc-base-accentHue));
        --dbc-base-accent200: oklch(87.8% calc(var(--dbc-base-accentChroma) * 0.26) var(--dbc-base-accentHue));
        --dbc-base-accent300: oklch(80% calc(var(--dbc-base-accentChroma) * 0.44) var(--dbc-base-accentHue));
        --dbc-base-accent400: oklch(71.4% calc(var(--dbc-base-accentChroma) * 0.64) var(--dbc-base-accentHue));
        --dbc-base-accent500: oklch(62.3% calc(var(--dbc-base-accentChroma) * 0.84) var(--dbc-base-accentHue));
        --dbc-base-accent600: oklch(54.6% calc(var(--dbc-base-accentChroma) * 0.98) var(--dbc-base-accentHue));
        --dbc-base-accent700: oklch(47% calc(var(--dbc-base-accentChroma) * 0.95) var(--dbc-base-accentHue));
        --dbc-base-accent800: oklch(39% calc(var(--dbc-base-accentChroma) * 0.80) var(--dbc-base-accentHue));
        --dbc-base-accent900: oklch(25.5% calc(var(--dbc-base-accentChroma) * 0.32) var(--dbc-base-accentHue));

        /* ---------- BASE: status ramps ---------- */

        /* Three fixed hues that must read as themselves whatever the accent is: a warning that drifted toward
           the accent would stop being a warning. Only the steps something reads are declared - danger carries a
           full fill ladder because it is a button appearance, warning and success are ink only. */
        --dbc-base-danger100: oklch(95% calc(var(--dbc-base-dangerChroma) * 0.10) var(--dbc-base-dangerHue));
        --dbc-base-danger300: oklch(85% calc(var(--dbc-base-dangerChroma) * 0.35) var(--dbc-base-dangerHue));
        --dbc-base-danger400: oklch(69% calc(var(--dbc-base-dangerChroma) * 0.75) var(--dbc-base-dangerHue));
        --dbc-base-danger500: oklch(62% calc(var(--dbc-base-dangerChroma) * 0.90) var(--dbc-base-dangerHue));
        --dbc-base-danger600: oklch(55% calc(var(--dbc-base-dangerChroma) * 1.00) var(--dbc-base-dangerHue));
        --dbc-base-danger700: oklch(48% calc(var(--dbc-base-dangerChroma) * 0.98) var(--dbc-base-dangerHue));
        --dbc-base-danger800: oklch(40% calc(var(--dbc-base-dangerChroma) * 0.90) var(--dbc-base-dangerHue));
        --dbc-base-danger900: oklch(26% calc(var(--dbc-base-dangerChroma) * 0.45) var(--dbc-base-dangerHue));
        --dbc-base-warning100: oklch(95% calc(var(--dbc-base-warningChroma) * 0.10) var(--dbc-base-warningHue));
        --dbc-base-warning300: oklch(85% calc(var(--dbc-base-warningChroma) * 0.35) var(--dbc-base-warningHue));
        --dbc-base-warning500: oklch(68% calc(var(--dbc-base-warningChroma) * 0.95) var(--dbc-base-warningHue));
        --dbc-base-warning600: oklch(57% calc(var(--dbc-base-warningChroma) * 1.00) var(--dbc-base-warningHue));
        --dbc-base-warning800: oklch(40% calc(var(--dbc-base-warningChroma) * 0.90) var(--dbc-base-warningHue));
        --dbc-base-warning900: oklch(26% calc(var(--dbc-base-warningChroma) * 0.45) var(--dbc-base-warningHue));
        --dbc-base-success100: oklch(95% calc(var(--dbc-base-successChroma) * 0.10) var(--dbc-base-successHue));
        --dbc-base-success300: oklch(85% calc(var(--dbc-base-successChroma) * 0.35) var(--dbc-base-successHue));
        --dbc-base-success500: oklch(68% calc(var(--dbc-base-successChroma) * 0.95) var(--dbc-base-successHue));
        --dbc-base-success600: oklch(49% calc(var(--dbc-base-successChroma) * 1.00) var(--dbc-base-successHue));
        --dbc-base-success800: oklch(40% calc(var(--dbc-base-successChroma) * 0.90) var(--dbc-base-successHue));
        --dbc-base-success900: oklch(26% calc(var(--dbc-base-successChroma) * 0.45) var(--dbc-base-successHue));

        /* ---------- BASE: shape, spacing, type ---------- */

        --dbc-base-radiusXs: calc(4px * var(--dbc-base-radiusScale));
        --dbc-base-radiusSm: calc(6px * var(--dbc-base-radiusScale));
        --dbc-base-radiusMd: calc(8px * var(--dbc-base-radiusScale));
        --dbc-base-radiusLg: calc(12px * var(--dbc-base-radiusScale));
        --dbc-base-space100: calc(4px * var(--dbc-base-spaceScale));
        --dbc-base-space200: calc(8px * var(--dbc-base-spaceScale));
        --dbc-base-space300: calc(12px * var(--dbc-base-spaceScale));
        --dbc-base-space400: calc(16px * var(--dbc-base-spaceScale));
        --dbc-base-fontSize100: calc(12px * var(--dbc-base-fontScale));
        --dbc-base-fontSize200: calc(14px * var(--dbc-base-fontScale));
        --dbc-base-fontSize300: calc(15px * var(--dbc-base-fontScale));
        --dbc-base-fontSize400: calc(16px * var(--dbc-base-fontScale));
        --dbc-base-fontSize500: calc(20px * var(--dbc-base-fontScale));
        --dbc-base-lineHeight100: calc(16px * var(--dbc-base-fontScale));
        --dbc-base-lineHeight200: calc(20px * var(--dbc-base-fontScale));
        --dbc-base-lineHeight300: calc(22px * var(--dbc-base-fontScale));
        --dbc-base-lineHeight500: calc(28px * var(--dbc-base-fontScale));

        /* ==========================================================================================
         * THE SEMANTIC LAYER — the only tokens a control reads.
         * ========================================================================================== */

        /* Surfaces. Canvas is the ground a dashboard is laid out on; raised is a card floating above it, and
           its header band is a shade apart from its body. Sunken is a recess - a scrollbar track, a well. */
        --dbc-theme-surfaceCanvas: var(--dbc-base-neutral50);
        --dbc-theme-surfaceRaised: var(--dbc-base-neutral0);
        --dbc-theme-surfaceRaisedHeader: var(--dbc-base-neutral0);
        --dbc-theme-surfaceSunken: var(--dbc-base-neutral100);
        /* The wash behind a Group: a grouping region's fill, at 25% so it composites over whatever the group
           sits on — a card, the canvas, or another group — rather than assuming one ground. A solid step would
           be wrong here twice: it would pick a fight with the surface underneath, and at full strength it would
           make the region read as a card, which is the one thing a Group must not do.

           Mixed from the ACCENT ramp rather than the neutral one, so the region carries a little colour instead
           of reading as grey.

           Kept deliberately DIM: the same ramp step an info message bar fills with, so the two tinted regions
           in the palette read at one strength. The region is marked by its OUTLINE — which sits at a higher
           lift than this wash — so the fill only has to warm the area, not delimit it. A group is passive
           furniture and must not pull attention from the controls inside it.

           It points at the base step rather than at --dbc-theme-accentSoft, even though the two are currently
           identical. accentSoft is also an outline button's hover fill; aliasing to it would mean a change made
           for a button silently restyled every group.

           This lands near --dbc-theme-surfaceSelected, which is worth knowing about and not worth avoiding: the
           only reader of that token is a ComboBox's selected option, inside a popup a Group can never appear
           in, so the two are never on screen together. */
        --dbc-theme-surfaceGroup: var(--dbc-base-accent50);

        /* Ink. Primary is the reading weight; muted is a caption or a disabled-looking label. Accent ink is
           the accent used as TEXT or an ICON, which is a different ramp step from an accent fill: it has to
           clear 4.5:1 against a surface, where a fill only has to be distinguishable. */
        --dbc-theme-inkPrimary: var(--dbc-base-neutral900);
        --dbc-theme-inkMuted: var(--dbc-base-neutral600);
        --dbc-theme-inkAccent: var(--dbc-base-accent600);
        --dbc-theme-inkSecondary: var(--dbc-base-neutral700);
        --dbc-theme-inkPlaceholder: var(--dbc-base-neutral500);
        --dbc-theme-inkDisabled: var(--dbc-base-neutral500);
        /* Ink that sits ON a filled shape rather than on a surface — it follows the FILL, not the theme, so it
           is the same in both. Every solid fill in the palette is dark enough for white at 4.5:1. */
        --dbc-theme-inkOnAccent: var(--dbc-base-neutral0);
        --dbc-theme-inkDanger: var(--dbc-base-danger600);
        --dbc-theme-inkWarning: var(--dbc-base-warning600);
        --dbc-theme-inkSuccess: var(--dbc-base-success600);
        /* A link darkens on hover where a filled accent lightens: ink on a light ground gains weight by going
           down the ramp, not up. */
        --dbc-theme-inkAccentHover: var(--dbc-base-accent700);

        /* Interaction fills for a neutral control — the default button, a menu row, a subtle icon button.
           Selected is accent-tinted rather than a darker grey, so "chosen" and "hovered" never look alike. */
        --dbc-theme-surfaceHover: var(--dbc-base-neutral50);
        --dbc-theme-surfaceActive: var(--dbc-base-neutral100);
        --dbc-theme-surfaceSelected: var(--dbc-base-accent50);
        --dbc-theme-surfaceDisabled: var(--dbc-base-neutral50);

        /* The accent as a FILL, with its own hover and pressed steps. Distinct from --dbc-theme-inkAccent,
           which is the accent as text: a fill only has to be distinguishable, ink has to clear 4.5:1. */
        --dbc-theme-accentSolid: var(--dbc-base-accent600);
        --dbc-theme-accentSolidHover: var(--dbc-base-accent700);
        --dbc-theme-accentSolidActive: var(--dbc-base-accent800);
        /* The faint accent wash an outline control hovers to, and the tint behind an accent-marked region. */
        /* The edge of a SOLID-filled control. A translucent veil rather than a ramp step, so it darkens
           whatever fill is behind it — the same token therefore defines the edge of a primary button, its
           hover and its pressed state, and of the danger button too, with no per-state rule. Without it a
           filled button has no boundary at all against a light card. */
        --dbc-theme-solidStroke: color-mix(in srgb, var(--dbc-base-neutral1000) 22%, transparent);
        --dbc-theme-accentSoft: var(--dbc-base-accent50);
        --dbc-theme-accentSoftHover: var(--dbc-base-accent100);

        --dbc-theme-dangerSolid: var(--dbc-base-danger600);
        --dbc-theme-dangerSolidHover: var(--dbc-base-danger700);
        --dbc-theme-dangerSolidActive: var(--dbc-base-danger800);

        /* Status SOFT pairs — the tinted panel a message bar paints and the border that closes it. One shape
           for all four severities, so a bar cannot look like four different designs. "info" borrows the accent
           rather than owning a hue of its own: an informational message is the neutral case. */
        --dbc-theme-accentSoftBorder: var(--dbc-base-accent200);
        --dbc-theme-dangerSoft: var(--dbc-base-danger100);
        --dbc-theme-dangerSoftBorder: var(--dbc-base-danger300);
        --dbc-theme-warningSoft: var(--dbc-base-warning100);
        --dbc-theme-warningSoftBorder: var(--dbc-base-warning300);
        --dbc-theme-successSoft: var(--dbc-base-success100);
        --dbc-theme-successSoftBorder: var(--dbc-base-success300);

        /* Strokes. Subtle is a divider inside a surface; default is the outline of a surface against the
           canvas.

           There is no neutral focus stroke. The keyboard ring is --dbc-theme-strokeAccent, thickened from the
           hairline to --dbc-theme-strokeFocusWidth, and the one case where an accent rim would be invisible -
           a control filled with accentSolid or dangerSolid - takes --dbc-theme-inkOnAccent instead.
           (--dbc-theme-strokeFocus, the neutral one, was pruned when the five focus recipes were unified;
           nothing read it afterwards, and an orphan fails the build.)

           WCAG 1.4.11 wants 3:1 for a focus indicator against both adjacent colours, and the RIM is what has
           to carry that - the glow is decorative and measures only 2.3:1 light / 2.7:1 dark over the surface
           it sits on. Measured in the browser, light / dark:
           <list>
             <item>accent rim on surfaceRaised - 5.19 / 4.66</item>
             <item>accent rim on surfaceSunken - 4.54 / 5.10</item>
             <item>inkOnAccent rim on accentSolid - 5.19 / 5.19</item>
             <item>inkOnAccent rim on dangerSolid - 5.32 / 5.32</item>
             <item>inkDanger rim on surfaceRaised - 5.32 / 4.38 (a focused invalid field)</item>
             <item>inkWarning rim on surfaceRaised - 4.62 / 5.84</item>
           </list>
           Re-measure if the accent ramp or a surface step moves; do not lighten a rim to taste. */
        --dbc-theme-strokeSubtle: var(--dbc-base-neutral100);
        --dbc-theme-strokeDefault: var(--dbc-base-neutral200);
        /* Strong is the stroke of a control whose BORDER carries the meaning — an unchecked checkbox, a field
           the pointer is over — where the default outline of a surface would be too quiet to read as a control.
           It is therefore the one stroke with a CONTRAST FLOOR: WCAG 1.4.11 wants 3:1 for the boundary that
           identifies a control, and an unchecked checkbox has nothing else to identify it. Measured on the card
           it sits on: this step is 3.65:1 light and 3.63:1 dark, where the next step out fails at 2.15 and 2.32.
           Do not lighten it to taste. */
        --dbc-theme-strokeStrong: var(--dbc-base-neutral500);
        --dbc-theme-strokeAccent: var(--dbc-base-accent600);
        --dbc-theme-strokeDisabled: var(--dbc-base-neutral200);
        /* The soft half of the focus indicator, as a COLOUR. Mixed rather than a ramp step so it composites
           over whatever surface the focused control sits on instead of assuming one. Dark carries it harder -
           the same alpha over a dark card barely registers.

           55% rather than something quieter because this is a BLURRED shadow, not a solid band: the blur
           spreads the ink out, so a mix that reads well as a 3px band beside a border cannot be seen at all
           as a bloom. Measured in the browser at 25%, which is what it was while the indicator was an outer
           band: invisible. Only --dbc-theme-focusGlow reads this - no control does. */
        --dbc-theme-focusHalo: color-mix(in srgb, var(--dbc-base-accent600) 55%, transparent);
        /* The soft half as a SHADOW: an accent bloom feathering INWARD from the focused control's own rim, so
           a focused control glows from its edge and paints nothing outside the rect the layout engine
           arranged for it. The rim itself is not here - it is an outline the control pulls in by its own
           width; Documentation/THEMING.md ("The focus indicator") says why the two halves are split.

           The negative SPREAD is what makes it hug the rim rather than wash the whole control: it pushes the
           shadow's edge 1px outside the padding box, so only the inner part of the 4px blur lands. Blur 4 and
           no more - at 6px the bloom reaches about 4px in, which on a 16px check box is most of the box, and
           a focused unchecked box starts to read as a filled one. */
        --dbc-theme-focusGlow: inset 0 0 4px -1px var(--dbc-theme-focusHalo);

        /* Elevation, as a five-step ramp a Panel picks from. Two layers each: a tight contact shadow that
           anchors the card, and a wide soft one that lifts it. Both mix from the shadow ink so a theme can
           deepen or tint the whole ramp with one knob.

           Each step's WIDE BLUR is what a consumer has to reserve room for. Panel.ts's PANEL_ELEVATION_GUTTERS
           holds that reservation — 2/4/8/12/18/28px for levels 0..5 — and every blur here stays inside its
           level's gutter. Deepen a step past its gutter and the soft edge clips against the panel's own rect,
           which reads as a hard line rather than as elevation. Level 0 has no token: it draws no shadow. */
        --dbc-theme-elevation1:
            0 1px 1px color-mix(in srgb, var(--dbc-base-shadowInk) calc(3% * var(--dbc-base-elevationAlpha)), transparent),
            0 1px 3px color-mix(in srgb, var(--dbc-base-shadowInk) calc(5% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation2:
            0 1px 2px color-mix(in srgb, var(--dbc-base-shadowInk) calc(4% * var(--dbc-base-elevationAlpha)), transparent),
            0 2px 6px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation3:
            0 1px 2px color-mix(in srgb, var(--dbc-base-shadowInk) calc(5% * var(--dbc-base-elevationAlpha)), transparent),
            0 4px 12px color-mix(in srgb, var(--dbc-base-shadowInk) calc(7% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation4:
            0 2px 4px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent),
            0 6px 18px color-mix(in srgb, var(--dbc-base-shadowInk) calc(9% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation5:
            0 4px 8px color-mix(in srgb, var(--dbc-base-shadowInk) calc(7% * var(--dbc-base-elevationAlpha)), transparent),
            0 12px 28px color-mix(in srgb, var(--dbc-base-shadowInk) calc(12% * var(--dbc-base-elevationAlpha)), transparent);
        /* The card step, named by role for the controls that want "a card" rather than a level: DbcDrawer's
           open panel and DbcFileUploadArea. One definition, so the two can never drift apart. */
        --dbc-theme-elevationRaised: var(--dbc-theme-elevation3);
        /* A popover floats higher than a card and over arbitrary content, so it needs a deeper, wider shadow to
           separate from whatever is beneath it. */
        --dbc-theme-elevationOverlay:
            0 2px 4px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent),
            0 8px 24px color-mix(in srgb, var(--dbc-base-shadowInk) calc(10% * var(--dbc-base-elevationAlpha)), transparent);
        /* The shadow as a plain COLOUR, for a shadow a box-shadow cannot draw. DbcDrawer paints its seam as a
           gradient INSIDE the band the layout engine reserved, because a box-shadow would spill over the main
           content — the one thing reserving that space exists to prevent. Same ink and the same elevation knob
           as the two lists above, so all three deepen together. */
        --dbc-theme-shadowColor: color-mix(in srgb, var(--dbc-base-shadowInk) calc(8% * var(--dbc-base-elevationAlpha)), transparent);
        /* The wash behind a modal, dimming everything the dialog is not. Mixed from the darkest neutral rather
           than from black: a neutral-black scrim over the blue-tinted surfaces reads as a grey film, where the
           ramp's own end keeps the dim in the palette's hue. Dark mode goes deeper — the surfaces beneath are
           already dark, so the same alpha would not separate the dialog from them. */
        --dbc-theme-scrim: color-mix(in srgb, var(--dbc-base-neutral950) 45%, transparent);

        /* Shape and motion. Card corners are noticeably rounder than a control's, which is what separates a
           surface from something you click. */
        /* Spacing a control pads and gaps with. A metric the LAYOUT ENGINE also budgets for stays a literal in
           the control instead — Button.ts and Panel.ts compute against those, and a token would let a re-theme
           move the chrome while the engine kept the old figure. */
        --dbc-theme-spaceXs: var(--dbc-base-space100);
        --dbc-theme-spaceSm: var(--dbc-base-space200);
        --dbc-theme-spaceMd: var(--dbc-base-space300);
        --dbc-theme-spaceLg: var(--dbc-base-space400);

        --dbc-theme-radiusSmall: var(--dbc-base-radiusXs);
        --dbc-theme-radiusControl: var(--dbc-base-radiusMd);
        --dbc-theme-radiusCard: var(--dbc-base-radiusLg);
        --dbc-theme-radiusPill: 9999px;
        --dbc-theme-strokeHairline: 1px;
        --dbc-theme-strokeFocusWidth: 2px;
        --dbc-theme-motionFast: 120ms;
        --dbc-theme-motionNormal: 200ms;
        --dbc-theme-motionEase: cubic-bezier(0.2, 0, 0.15, 1);

        /* Typography. Title is the large step: a card header has to carry the card, and at body size it read
           as just another line of text inside it. */
        --dbc-theme-typeFamily: var(--dbc-base-fontFamily);
        --dbc-theme-typeFamilyMono: var(--dbc-base-fontFamilyMono);
        --dbc-theme-typeCaptionSize: var(--dbc-base-fontSize100);
        --dbc-theme-typeCaptionLine: var(--dbc-base-lineHeight100);
        --dbc-theme-typeBodySize: var(--dbc-base-fontSize200);
        --dbc-theme-typeBodyLine: var(--dbc-base-lineHeight200);
        --dbc-theme-typeTitleSize: var(--dbc-base-fontSize400);
        --dbc-theme-typeTitleLine: var(--dbc-base-lineHeight300);
        --dbc-theme-typeLargeSize: var(--dbc-base-fontSize400);
        --dbc-theme-typeLargeLine: var(--dbc-base-lineHeight300);
        --dbc-theme-typeHeadingSize: var(--dbc-base-fontSize500);
        --dbc-theme-typeHeadingLine: var(--dbc-base-lineHeight500);
        --dbc-theme-typeWeightBody: 400;
        --dbc-theme-typeWeightMedium: 500;
        --dbc-theme-typeWeightStrong: 600;

    }

    /* ==============================================================================================
     * DARK — what differs from light: the elevation knobs and the semantic mapping.
     *
     * THE RAMPS ARE NOT REPEATED. Their steps are identical in both themes; what dark changes is which step
     * each role points at, which is the mapping below. Every element these selectors match either declares the
     * ramp itself (the light rule matches it too) or inherits it, so the var()s here resolve correctly.
     *
     * WHY THREE SELECTORS. A var() is substituted where its declaration sits, so a semantic token must be
     * re-declared on every element that carries the light rule's copy of it - <html> via :root and .dbc-theme -
     * or that element keeps the value it already resolved against the light mapping. See "THE CARRIER RULE" in
     * the header. <body> is in the list because a dashboard may be mounted directly on it, and matching all
     * three costs nothing.
     *
     * Shape, spacing, typography and motion are theme-independent and are not repeated.
     * ============================================================================================== */
    :root:has(body[data-theme="dark"]),
    body[data-theme="dark"],
    body[data-theme="dark"] .dbc-theme {

        /* ---------- BASE: the only two knobs that differ ---------- */

        /* True black rather than the tinted ink light uses, and much harder: on a dark ground a shadow is
           nearly the only thing separating a card from the canvas behind it. */
        --dbc-base-shadowInk: oklch(0% 0 0);
        --dbc-base-elevationAlpha: 6;

        /* ---------- THE MAPPING, read from the dark end of the ramp ---------- */

        /* The canvas becomes the DARKEST thing on screen and a card sits above it — the opposite of light
           mode, and what lets a card still read as raised without inverting its shadow into a glow. */
        --dbc-theme-surfaceCanvas: var(--dbc-base-neutral1000);
        --dbc-theme-surfaceRaised: var(--dbc-base-neutral950);
        --dbc-theme-surfaceRaisedHeader: var(--dbc-base-neutral900);
        --dbc-theme-surfaceSunken: var(--dbc-base-neutral1000);
        /* The same step an info message bar fills with here too. */
        --dbc-theme-surfaceGroup: var(--dbc-base-accent900);

        --dbc-theme-inkPrimary: var(--dbc-base-neutral100);
        --dbc-theme-inkMuted: var(--dbc-base-neutral500);
        --dbc-theme-inkSecondary: var(--dbc-base-neutral400);
        --dbc-theme-inkPlaceholder: var(--dbc-base-neutral500);
        --dbc-theme-inkDisabled: var(--dbc-base-neutral600);
        /* inkOnAccent is NOT repeated: it follows the fill it sits on, and every solid fill stays dark enough
           for white in both themes. */
        --dbc-theme-inkDanger: var(--dbc-base-danger500);
        --dbc-theme-inkWarning: var(--dbc-base-warning500);
        --dbc-theme-inkSuccess: var(--dbc-base-success500);
        --dbc-theme-inkAccentHover: var(--dbc-base-accent300);

        --dbc-theme-surfaceHover: var(--dbc-base-neutral900);
        --dbc-theme-surfaceActive: var(--dbc-base-neutral850);
        --dbc-theme-surfaceSelected: var(--dbc-base-accent900);
        --dbc-theme-surfaceDisabled: var(--dbc-base-neutral900);

        /* A filled accent stays at the same ramp step in both themes — it is a shape, not ink, and the mockups
           keep the same blue. Its hover goes LIGHTER here where light mode goes darker: on a dark ground,
           "more prominent" means brighter. */
        --dbc-theme-accentSolid: var(--dbc-base-accent600);
        --dbc-theme-accentSolidHover: var(--dbc-base-accent500);
        --dbc-theme-accentSolidActive: var(--dbc-base-accent400);
        --dbc-theme-solidStroke: color-mix(in srgb, var(--dbc-base-neutral0) 20%, transparent);
        --dbc-theme-accentSoft: var(--dbc-base-accent900);
        --dbc-theme-accentSoftHover: var(--dbc-base-accent800);

        --dbc-theme-dangerSolid: var(--dbc-base-danger600);
        --dbc-theme-dangerSolidHover: var(--dbc-base-danger500);
        --dbc-theme-dangerSolidActive: var(--dbc-base-danger400);

        /* Status soft pairs, read from the dark end: the tint is a deep step and the border a lighter one, so
           the panel reads as tinted rather than as a hole punched in the card. */
        --dbc-theme-accentSoftBorder: var(--dbc-base-accent800);
        --dbc-theme-dangerSoft: var(--dbc-base-danger900);
        --dbc-theme-dangerSoftBorder: var(--dbc-base-danger800);
        --dbc-theme-warningSoft: var(--dbc-base-warning900);
        --dbc-theme-warningSoftBorder: var(--dbc-base-warning800);
        --dbc-theme-successSoft: var(--dbc-base-success900);
        --dbc-theme-successSoftBorder: var(--dbc-base-success800);
        /* Two ramp steps lighter than light mode's accent ink: the 600 step is only ~3.4:1 against the dark
           card, where 400 clears 4.5:1. A FILL would stay at 600; ink cannot. */
        --dbc-theme-inkAccent: var(--dbc-base-accent400);

        --dbc-theme-strokeSubtle: var(--dbc-base-neutral850);
        --dbc-theme-strokeDefault: var(--dbc-base-neutral800);
        --dbc-theme-strokeStrong: var(--dbc-base-neutral600);
        --dbc-theme-strokeAccent: var(--dbc-base-accent500);
        --dbc-theme-strokeDisabled: var(--dbc-base-neutral850);
        --dbc-theme-focusHalo: color-mix(in srgb, var(--dbc-base-accent500) 65%, transparent);
        /* Same expression as light, repeated for the reason the elevations below are: focusHalo changed
           underneath it, and a var() does not re-substitute on an element that only inherits the result. */
        --dbc-theme-focusGlow: inset 0 0 4px -1px var(--dbc-theme-focusHalo);

        /* Same expression as light; it is repeated because the two knobs above changed underneath it and a
           var() does not re-substitute on an element that only inherits the result. */
        --dbc-theme-elevation1:
            0 1px 1px color-mix(in srgb, var(--dbc-base-shadowInk) calc(3% * var(--dbc-base-elevationAlpha)), transparent),
            0 1px 3px color-mix(in srgb, var(--dbc-base-shadowInk) calc(5% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation2:
            0 1px 2px color-mix(in srgb, var(--dbc-base-shadowInk) calc(4% * var(--dbc-base-elevationAlpha)), transparent),
            0 2px 6px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation3:
            0 1px 2px color-mix(in srgb, var(--dbc-base-shadowInk) calc(5% * var(--dbc-base-elevationAlpha)), transparent),
            0 4px 12px color-mix(in srgb, var(--dbc-base-shadowInk) calc(7% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation4:
            0 2px 4px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent),
            0 6px 18px color-mix(in srgb, var(--dbc-base-shadowInk) calc(9% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevation5:
            0 4px 8px color-mix(in srgb, var(--dbc-base-shadowInk) calc(7% * var(--dbc-base-elevationAlpha)), transparent),
            0 12px 28px color-mix(in srgb, var(--dbc-base-shadowInk) calc(12% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-elevationRaised: var(--dbc-theme-elevation3);
        --dbc-theme-elevationOverlay:
            0 2px 4px color-mix(in srgb, var(--dbc-base-shadowInk) calc(6% * var(--dbc-base-elevationAlpha)), transparent),
            0 8px 24px color-mix(in srgb, var(--dbc-base-shadowInk) calc(10% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-shadowColor: color-mix(in srgb, var(--dbc-base-shadowInk) calc(8% * var(--dbc-base-elevationAlpha)), transparent);
        --dbc-theme-scrim: color-mix(in srgb, var(--dbc-base-neutral950) 65%, transparent);

    }
}

/* What the dashboard subtree used to inherit from FluentUI's base stylesheet, restated from the tokens above,
 * plus the canvas the dashboard is laid out on.
 *
 * default-fuib.css puts typography, ink and the scrollbar palette on <body>, and half the dashboard's own
 * stylesheets never declare them - so those controls were being drawn by a FluentUI file. scrollbar-color is
 * the one with no trace at all in DashboardControls: without it every scroller in a dashboard reverts to the
 * light UA scrollbar, on a dark page.
 *
 * The background is what makes a card read as raised: the panels' elevation and hairline are calibrated
 * against this ground, not against whatever the page behind the viewer happens to be. */
.dbc-theme {
    background: var(--dbc-theme-surfaceCanvas);
    font-family: var(--dbc-theme-typeFamily);
    font-size: var(--dbc-theme-typeBodySize);
    font-weight: var(--dbc-theme-typeWeightBody);
    line-height: var(--dbc-theme-typeBodyLine);
    color: var(--dbc-theme-inkPrimary);
    scrollbar-color: var(--dbc-theme-inkMuted) var(--dbc-theme-surfaceSunken);
}

/* box-sizing does not inherit, so this has to name the descendants - declaring it on the root alone would
   style one element and leave every control below it on content-box. Every box in the folder is already
   border-box, so this changes nothing today and keeps it true once FluentUI's `*` rule is no longer relied on. */
.dbc-theme,
.dbc-theme * {
    box-sizing: border-box;
}
