/*
    SmartERP.Next — design tokens
    ------------------------------
    Every colour, size and timing in the application resolves to a token here.
    Components never hard-code a hex value, so retheming is a change to this file
    alone.

    ========================================================================
    TWO DIMENSIONS, TWO NAMESPACES
    ========================================================================
    There are now FOUR palettes, each with a light and a dark variant. Those are
    two independent choices and they are carried by two independent attributes
    on <html>:

        data-palette = "indigo" | "teal" | "sand" | "plum"   (absent = indigo)
        data-theme   = "light" | "dark"                      (absent = follow OS)

    The naive way to write that is 4 x 3 = twelve selector arms, and it walks
    straight into the specificity trap recorded further down this file: a
    palette's light arm :root[data-palette="teal"] is (0,2,0) and TIES with the
    dark arms :root:not([data-theme="light"]) and :root[data-theme="dark"], so
    the winner would be decided by source order — which is exactly the failure
    mode that left the no-backdrop-filter fallback dead for a year.

    So the arms were not multiplied. Instead the two dimensions were given
    DISJOINT TOKEN NAMESPACES, and they never compete:

      * A PALETTE declares raw values only, under --l-* (its light values) and
        --d-* (its dark values). It never writes a public token name.

      * The VARIANT switch maps the public names:
                :root                         --text: var(--l-text)
                @media dark :root:not(...)    --text: var(--d-text)
                :root[data-theme="dark"]      --text: var(--d-text)

    The consequence is the point: the specificity ladder is IDENTICAL to the one
    this file has always had — (0,1,0) light, (0,2,0) for both dark arms — and
    adding three palettes added no arm to it at all. A palette block is (0,2,0)
    and beats the (0,1,0) base, but it can never tie with a dark arm because the
    two blocks do not name a single property in common. There is no source-order
    dependency anywhere in the colour cascade.

    It also means the ABSOLUTE OVERRIDES at the foot of this file, and the print
    and forced-colors blocks in app.css, keep working untouched: they name the
    same three selectors they always did and they set public token names, which
    only the variant switch also sets.

    And it means app.css needs no palette selectors. Its existing
    :root[data-theme="dark"] rules still mean "the dark variant", whichever
    palette is on.

    ------------------------------------------------------------------------
    THE PALETTES
    ------------------------------------------------------------------------
      indigo  the original. Cool blue-grey, blue accent. The default, and
              byte-for-byte what it was before this file grew a second palette.
      teal    cool grey-green, deep teal accent. The same temperature as indigo
              but a different hue, for people who read blue chrome as noise.
      sand    warm stone neutrals, burnt-amber accent. The only warm ground;
              the one that stops looking like a screen after six hours.
      plum    cool violet-grey neutrals, muted violet accent.

    Every palette's semantic colours (success / warning / danger / info) and
    every palette's chart ramp are the SAME, because those carry meaning. A red
    that means "out of balance" must not become a different red because someone
    likes warm greys.

    ------------------------------------------------------------------------
    ON THE VALUES, RETUNED
    ------------------------------------------------------------------------
    The structure here was already right; the judgement expressed through it was
    not, and the interface read as a stock admin template. What changed and why:

      * Base type 13.5px -> 14px, and the scale given real contrast at the top
        end. The old scale stepped 15/18/22 — too close to distinguish a section
        from a page — so everything looked like one flat weight of information.

      * One control height. Inputs, selects and buttons each sized themselves, so
        a filter bar was three slightly different heights in a row. --control-h
        now decides it once.

      * Borders demoted. A 1px line was doing the work of separation everywhere,
        which is what makes an interface look busy and cheap. --border-subtle is
        for rules *inside* a component (table rows); --border stays for a real
        edge. Density now comes from spacing, not from lines.

      * Radius regularised to 6/8/10/14. The old base of 9px sat between the two
        conventions and matched nothing else on screen.

      * Shadows tinted with the brand hue rather than neutral black, and given a
        longer, softer falloff. Untinted black over a cool grey ground is the
        single most dated thing a stylesheet can do.

      * A neutral ramp and a chart ramp added, because components were inventing
        their own greys and the chart bars were hard-coded and could not theme.
*/

:root {
    color-scheme: light;

    /* ==================================================================== */
    /*  PALETTE DATA — indigo (the default)                                 */
    /*                                                                       */
    /*  --l-* light values, --d-* dark values. NOTHING here is a public      */
    /*  token: the variant switch below reads these. The other three         */
    /*  palettes restate this block and nothing else.                        */
    /* ==================================================================== */

    --l-accent-rgb: 37 99 235;            /* blue 600  */
    /*  the product mark's ramp; see wwwroot/css/brand.css        */
    --l-brand-grad: linear-gradient(100deg, rgb(37 99 235) 0%, rgb(124 58 237) 55%, rgb(219 39 119) 100%);
    --d-brand-grad: linear-gradient(100deg, rgb(109 168 255) 0%, rgb(167 139 250) 55%, rgb(244 114 182) 100%);
    --l-accent-strong-rgb: 29 78 216;     /* blue 700  */
    --l-accent-soft-rgb: 219 234 254;     /* blue 100  */
    --l-accent-contrast: #ffffff;

    --d-accent-rgb: 109 168 255;
    --d-accent-strong-rgb: 155 197 255;
    --d-accent-soft-rgb: 30 58 138;
    --d-accent-contrast: #0a1020;

    /*
        A neutral ramp, so a component never has to invent a grey. Tinted
        towards the palette's own hue, because a neutral that belongs to no
        palette is what makes a retheme look like a recoloured accent.
    */
    --l-n-50: #f7f8fa;  --l-n-100: #eef0f4; --l-n-150: #e6e9ef;
    --l-n-200: #dde1e9; --l-n-300: #c5ccd8; --l-n-400: #9aa4b5;
    --l-n-500: #6f7b8f; --l-n-600: #556073; --l-n-700: #3b4557;
    --l-n-800: #262e3d; --l-n-900: #141a25;

    --d-n-50: #141a25;  --d-n-100: #1a2130; --d-n-150: #1f2839;
    --d-n-200: #263044; --d-n-300: #33405a; --d-n-400: #5a6880;
    --d-n-500: #8090a8; --d-n-600: #a3b0c4; --d-n-700: #c3cddd;
    --d-n-800: #dee5f0; --d-n-900: #f2f5fa;

    /* app = the page ground, surface = cards, raised = popovers/menus */
    --l-surface-app: #f5f6f9;
    --l-surface: #ffffff;
    --l-surface-raised: #ffffff;
    --l-surface-sunken: #f0f2f6;
    --l-surface-hover: #f5f7fa;
    --l-surface-active: #eaeef4;

    --d-surface-app: #0a101c;
    --d-surface: #121a2a;
    --d-surface-raised: #1a2335;
    --d-surface-sunken: #0d1523;
    --d-surface-hover: #19222f;
    --d-surface-active: #212c3f;

    /* The rail is dark in BOTH variants; it is chrome, not page. */
    --l-sidebar-bg: #0e1526;
    --l-sidebar-fg: #c3cddd;
    --l-sidebar-fg-muted: #78859c;
    --l-sidebar-raised: #0b1220;

    --d-sidebar-bg: #070c16;
    --d-sidebar-fg: #93a1b8;
    --d-sidebar-fg-muted: #737f94;
    --d-sidebar-raised: #0b1220;

    --l-text: #121926;
    --l-text-muted: #525f75;
    --l-text-subtle: #6b7789;
    --l-text-inverse: #ffffff;

    --d-text: #e9eef7;
    --d-text-muted: #a2b0c6;
    --d-text-subtle: #78859b;
    --d-text-inverse: #0a101c;

    --l-border: #e3e7ee;
    --l-border-subtle: #edf0f5;
    --l-border-strong: #ccd3de;

    --d-border: #253049;
    --d-border-subtle: #1c2538;
    --d-border-strong: #364463;

    /* The hue the shadows are tinted with, and the ground a dark glass pane
       tints towards. */
    --l-shadow-rgb: 18 27 56;
    --d-shadow-rgb: 0 0 0;
    --d-glass-pane-rgb: 14 21 36;
    --d-glass-panel-rgb: 16 24 42;

    /*
        The ground blooms. app.css paints the page with four soft radial washes:
        one in the accent, three more that give the ground somewhere to go. They
        were hard-coded violet / cyan / pink, so every theme would have had the
        same indigo-flavoured ground behind a completely different palette.
    */
    --l-bloom-2-rgb: 139 92 246;
    --l-bloom-3-rgb: 6 182 212;
    --l-bloom-4-rgb: 236 72 153;
    --d-bloom-2-rgb: 139 92 246;
    --d-bloom-3-rgb: 6 182 212;
    --d-bloom-4-rgb: 236 72 153;

    /* ==================================================================== */
    /*  VARIANT DATA that every palette shares                              */
    /*  (semantic hues and their ink; module identity tones)                */
    /* ==================================================================== */

    --l-success-rgb: 21 128 61;
    --l-warning-rgb: 160 103 10;
    --l-danger-rgb: 205 33 33;
    --l-info-rgb: 7 126 151;

    --d-success-rgb: 74 222 128;
    --d-warning-rgb: 250 204 21;
    --d-danger-rgb: 248 113 113;
    --d-info-rgb: 34 211 238;

    /*
        The ink that goes ON a semantic fill. This used to be a literal #fff on
        .btn--success, .btn--danger and the notification count, and in dark
        those fills are LIGHT — white on --success #4ade80 is 1.8 : 1, which is
        not a button, it is a rumour.

        The light-variant semantic hues were retuned while this was measured:
        --warning was 180 116 6 and --info was 7 132 161, which are 3.86 : 1 and
        4.35 : 1 on a white surface — both under AA for the body text that
        .text-warning and .text-info actually are. They are now 4.71 and 4.75.
        Semantic, so the correction lands in every palette at once.
    */
    --l-on-success: #ffffff;
    --l-on-warning: #ffffff;
    --l-on-danger: #ffffff;
    --l-on-info: #ffffff;

    --d-on-success: #06210f;
    --d-on-warning: #2a1d00;
    --d-on-danger: #2c0707;
    --d-on-info: #032027;

    /*
        Module identity tones — Financial, HR, Procurement, everything else.
        These say WHICH module you are in, so they do not change with the
        palette; they only lift for the dark variant, where the light-theme
        values go muddy against a dark rail.
    */
    --l-tone-blue: #2f6fed;
    --l-tone-green: #17936a;
    --l-tone-amber: #c07d13;
    --l-tone-neutral: #5b6472;

    --d-tone-blue: #6da8ff;
    --d-tone-green: #34d399;
    --d-tone-amber: #e3a53a;
    --d-tone-neutral: #9aa6b8;

    /* The ink that goes ON a module tone. The launcher's module icons are a
       solid tone tile; in dark the tones lift, so white on them would be the
       same 2 : 1 mistake --on-success was. */
    --l-tone-contrast: #ffffff;
    --d-tone-contrast: #0c1119;

    /* ==================================================================== */
    /*  THE VARIANT SWITCH — light                                          */
    /*                                                                       */
    /*  From here down the names are PUBLIC and app.css consumes them. This  */
    /*  arm is (0,1,0); the two dark arms below are (0,2,0) and win on       */
    /*  specificity, not on order.                                           */
    /* ==================================================================== */

    --accent-rgb: var(--l-accent-rgb);
    --accent-strong-rgb: var(--l-accent-strong-rgb);
    --accent-soft-rgb: var(--l-accent-soft-rgb);
    --accent-contrast: var(--l-accent-contrast);
    --brand-gradient: var(--l-brand-grad);

    --success-rgb: var(--l-success-rgb);
    --warning-rgb: var(--l-warning-rgb);
    --danger-rgb: var(--l-danger-rgb);
    --info-rgb: var(--l-info-rgb);
    --neutral-rgb: 100 116 139;

    --accent: rgb(var(--accent-rgb));
    --accent-strong: rgb(var(--accent-strong-rgb));

    --success: rgb(var(--success-rgb));
    --warning: rgb(var(--warning-rgb));
    --danger: rgb(var(--danger-rgb));
    --info: rgb(var(--info-rgb));

    --on-success: var(--l-on-success);
    --on-warning: var(--l-on-warning);
    --on-danger: var(--l-on-danger);
    --on-info: var(--l-on-info);

    --tone-blue: var(--l-tone-blue);
    --tone-green: var(--l-tone-green);
    --tone-amber: var(--l-tone-amber);
    --tone-neutral: var(--l-tone-neutral);
    --tone-contrast: var(--l-tone-contrast);

    /*
        The same tones AS THEY APPEAR ON THE RAIL. The rail is dark in both
        variants, so a tone picked to read on white does not read on it — which
        is why the sidebar's module icons used to carry their own hard-coded
        #60a5fa / #d2a679 / #cbd5e1, a second copy of the identity palette that
        no theme could reach. Derived rather than restated, so there is still
        one source for what "Financial blue" is.
    */
    --rail-tone-blue:    color-mix(in srgb, var(--tone-blue) 55%, #ffffff);
    --rail-tone-green:   color-mix(in srgb, var(--tone-green) 55%, #ffffff);
    --rail-tone-amber:   color-mix(in srgb, var(--tone-amber) 55%, #ffffff);
    --rail-tone-neutral: color-mix(in srgb, var(--tone-neutral) 55%, #ffffff);
    --rail-accent:       color-mix(in srgb, rgb(var(--accent-rgb)) 55%, #ffffff);
    /* Text and hairlines inside the rail, above --sidebar-fg. */
    --sidebar-fg-strong: color-mix(in srgb, var(--sidebar-fg) 60%, #ffffff);
    --sidebar-line:      color-mix(in srgb, var(--sidebar-fg) 45%, transparent);

    --n-50: var(--l-n-50);
    --n-100: var(--l-n-100);
    --n-150: var(--l-n-150);
    --n-200: var(--l-n-200);
    --n-300: var(--l-n-300);
    --n-400: var(--l-n-400);
    --n-500: var(--l-n-500);
    --n-600: var(--l-n-600);
    --n-700: var(--l-n-700);
    --n-800: var(--l-n-800);
    --n-900: var(--l-n-900);

    --surface-app: var(--l-surface-app);
    --surface: var(--l-surface);
    --surface-raised: var(--l-surface-raised);
    --surface-sunken: var(--l-surface-sunken);
    --surface-hover: var(--l-surface-hover);
    --surface-active: var(--l-surface-active);

    /* A row or card the user has picked out, as against merely hovered. */
    --surface-selected: rgb(var(--accent-rgb) / 7%);

    /* Behind a modal or an open drawer. */
    --overlay: rgb(15 23 42 / 38%);

    --sidebar-bg: var(--l-sidebar-bg);
    --sidebar-fg: var(--l-sidebar-fg);
    --sidebar-fg-muted: var(--l-sidebar-fg-muted);
    /* The module menu and any other popover that opens INSIDE the dark rail. */
    --sidebar-raised: var(--l-sidebar-raised);
    --sidebar-hover: rgb(255 255 255 / 6%);
    --sidebar-active: rgb(var(--accent-rgb) / 22%);
    --sidebar-active-fg: #ffffff;
    --sidebar-border: rgb(255 255 255 / 7%);

    --text: var(--l-text);
    --text-muted: var(--l-text-muted);
    --text-subtle: var(--l-text-subtle);
    --text-inverse: var(--l-text-inverse);

    /* -------------------------------------------------------------- Borders */
    /*
        --border      a real edge: a card against the page, an input against its
                      surroundings.
        --border-subtle  a rule INSIDE a component: between table rows, between
                      the items of a list. Kept much lighter on purpose — this
                      is the one that was doing too much work before.
    */
    --border: var(--l-border);
    --border-subtle: var(--l-border-subtle);
    --border-strong: var(--l-border-strong);
    --border-focus: rgb(var(--accent-rgb));

    --bloom-2-rgb: var(--l-bloom-2-rgb);
    --bloom-3-rgb: var(--l-bloom-3-rgb);
    --bloom-4-rgb: var(--l-bloom-4-rgb);

    /* --------------------------------------------------------------- Shadow */
    /*
        Tinted with the palette's own hue and given a longer falloff. Neutral
        black on a cool ground reads muddy, which is most of why the old cards
        looked flat and dated at the same time.
    */
    --shadow-rgb: var(--l-shadow-rgb);
    --shadow-xs: 0 1px 2px rgb(var(--shadow-rgb) / 5%);
    --shadow-sm: 0 1px 2px rgb(var(--shadow-rgb) / 5%), 0 2px 6px rgb(var(--shadow-rgb) / 5%);
    --shadow-md: 0 2px 4px rgb(var(--shadow-rgb) / 5%), 0 8px 20px rgb(var(--shadow-rgb) / 8%);
    --shadow-lg: 0 4px 8px rgb(var(--shadow-rgb) / 6%), 0 24px 48px rgb(var(--shadow-rgb) / 13%);

    /*
        Focus: a ring with an offset, so it reads on a white input and on a
        coloured button alike. Two tokens because the offset needs the ground.
    */
    --ring: 0 0 0 2px var(--surface), 0 0 0 4px rgb(var(--accent-rgb) / 45%);
    --ring-inset: inset 0 0 0 1px rgb(var(--accent-rgb) / 55%);

    /* --------------------------------------------------------------- Radius */
    /*
        Softer than the old scale. Generous corners are most of what separates
        the current platform look from the 4px-everywhere convention the
        previous values came from — and a floating pane in particular needs a
        radius you can actually see, or it reads as a rectangle that has come
        loose rather than as a panel.
    */
    --radius-xs: 5px;
    --radius-sm: 8px;
    --radius: 10px;
    --radius-lg: 16px;
    --radius-xl: 22px;
    --radius-pill: 999px;

    /* -------------------------------------------------------------- Spacing */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-8: 32px;
    --space-10: 40px;
    --space-12: 48px;

    /* ----------------------------------------------------------- Typography */
    /*
        Inter first where it is installed — its figures and its tighter default
        tracking are what most of this interface's peers are set in. The Segoe
        fallback keeps a stock Windows machine looking deliberate rather than
        defaulting to Arial.
    */
    --font-sans: "Inter", "Inter var", "Segoe UI Variable Text", "Segoe UI",
                 system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    /*
        One typeface, at three optical sizes. Windows 11 — which is what this
        client runs — ships Segoe UI Variable as three named families cut for
        three jobs: Small below about 12px, Text for reading sizes, Display for
        headings. Asking for the right one costs a token and no layout.
    */
    --font-sans-small: "Inter", "Inter var", "Segoe UI Variable Small", "Segoe UI",
                       system-ui, -apple-system, Arial, sans-serif;
    --font-sans-display: "Inter", "Inter var", "Segoe UI Variable Display", "Segoe UI",
                         system-ui, -apple-system, Arial, sans-serif;
    /* Tabular figures keep money columns aligned digit-for-digit. */
    --font-mono: "Cascadia Mono", "SF Mono", "JetBrains Mono", Consolas,
                 "Liberation Mono", monospace;

    --text-xs: 11.5px;
    --text-sm: 12.5px;
    --text-base: 14px;
    --text-md: 15px;
    --text-lg: 17px;
    --text-xl: 20px;
    --text-2xl: 26px;
    --text-3xl: 32px;

    --weight-normal: 400;
    --weight-medium: 500;
    /* The half-step the file was already writing by hand. Tokenised so it is a
       decision rather than a number, and so the rules using a literal 550 or
       650 stop rendering differently on Inter and on the static Segoe fallback
       most of this client's machines will actually have. */
    --weight-strong: 550;
    --weight-semibold: 600;
    --weight-bold: 700;

    /* Headings tighten; small print opens up. Both are what stops a screen
       reading as one undifferentiated block of 13px. */
    --tracking-tight: -0.015em;
    --tracking-tighter: -0.025em;
    --tracking-wide: 0.04em;

    --leading-tight: 1.25;
    --leading-normal: 1.55;

    /* ------------------------------------------------------------- Geometry */
    --sidebar-width: 248px;
    --sidebar-width-collapsed: 64px;
    --topbar-height: 56px;
    --content-max: 1560px;

    /*
        One height for every control. A filter bar was previously three
        different heights in a row because the input, the select and the button
        each decided for themselves.
    */
    --control-h: 36px;
    --control-h-sm: 30px;
    --control-h-lg: 42px;

    /* Table rhythm, so density is a decision made once. */
    --row-h: 40px;
    --row-h-dense: 34px;
    --cell-x: var(--space-4);

    /*
        A table row's height comes from THIS, not from --row-h.

        Cells used to carry `height: var(--row-h)`, and a browser treats that
        as a definite height on a table cell, not the minimum the spec
        suggests: a cell whose text wrapped to two lines stayed 40px and
        painted its second line straight over the row beneath it. Measured on
        General types, where "Attendance Award" plus its .cell-sub needed 62px
        in a 40px cell and spilled 27px onto the next row's name.

        12px is what reproduces the old 40px row for a single line of body
        text, so every existing table keeps the height it had -- verified on a
        40-row staff list, where all four distinct row heights were unchanged.

        --row-h itself is still the number this is derived FROM, and is still
        used directly by the command palette's rows.
    */
    --cell-y: 12px;

    /* ------------------------------------------------------------- Motion */
    --ease: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
    --duration-fast: 110ms;
    --duration: 180ms;

    /* ------------------------------------------------------------ Materials */
    /*
        Translucent surfaces, in the manner of the current platform look: a
        frosted layer that takes its colour from whatever is behind it, an edge
        catching the light, and a highlight along the top.

        Two rules govern where these may be used, and they are not stylistic:

          1. Glass needs something behind it. Over a flat ground it is just a
             grey box with an expensive filter on it, which is why the page ground
             below is a set of soft colour blooms rather than one colour.

          2. Glass goes on the furniture, never under dense data. A forty-row
             ledger over a blurred background is unreadable, and no amount of
             fashion is worth that. Chrome, overlays and summary tiles are
             translucent; tables and forms sit on a solid surface.

        Glass is a LENS, and it is specified as a function rather than as a
        look:

            blur()  contrast()  brightness()  saturate()

        The two middle terms are the whole reason body text may sit on this
        material at all. contrast(<1) compresses whatever is behind the pane
        towards mid-grey; brightness() then moves the compressed range into the
        light half (or, on dark, the dark half). Together they turn an UNKNOWN
        backdrop into a KNOWN one, and the fill's alpha puts a floor under it.
        saturate() runs LAST, so the colour it restores is not flattened again
        by the contrast term — the old chain ran saturate first, which is why
        the blur greyed things out and the saturation could not rescue them.

        THE FLOOR, worked out rather than hoped for. Light theme,
        --glass-panel, worst case a SOLID BLACK backdrop (sRGB 0) — worse than
        anything that can actually occur inside this shell:

            contrast(0.45)    (0.00 - 0.5) * 0.45 + 0.5          = 0.2750
            brightness(1.30)                                     = 0.3575
            fill 78% white    0.78 + 0.22 * 0.3575               = 0.8587
                              relative luminance                 = 0.7081

            vs --text        #121926   L 0.00964   ->  12.7 : 1
            vs --text-muted  #525f75   L 0.11260   ->   4.66 : 1

        --text-muted at 12.5px is the smallest, lowest-contrast text this
        application puts on glass, and it clears 4.5 : 1 against a backdrop
        that cannot happen. Against the backdrop that DOES happen — the pane's
        own fill over the page ground, sRGB ~0.86 — it is 6.0 : 1.

        The other three palettes' --text-muted are all DARKER than indigo's
        #525f75 in light and LIGHTER than indigo's #a2b0c6 in dark, so the same
        arithmetic bounds them: teal #4b5e5c, sand #5b5244 and plum #554e66 are
        each nearer the ink end than the figure this floor was computed for.

        Dark runs the same arithmetic the other way: contrast(0.45)
        brightness(0.72) under an 86% dark fill caps the composite at sRGB
        0.215 even when pure white passes behind it, which against
        --text-muted #a2b0c6 is 6.8 : 1.

        TWO FILLS, because there are only two questions: does text sit on this,
        or does it not.

        AND THE RULE THAT MAKES IT AFFORDABLE: at most ONE backdrop-filter in
        any vertical stack, never on anything that repeats per row, and never
        over a backdrop with no detail. A blur costs by AREA per frame, and a
        pane whose backdrop is background-attachment: fixed does not change
        while the page scrolls — blurring it buys nothing and throws away the
        browser's ability to cache the result. Three elements qualify, and they
        are named by job rather than numbered, so nobody reaches for level 3
        because it sounded stronger.
    */
    --lens-tone: contrast(0.45) brightness(1.30);
    --lens-sat: saturate(170%);

    --lens-bar:  blur(24px) var(--lens-tone) var(--lens-sat);   /* the topbar   */
    --lens-rail: blur(30px) var(--lens-tone) var(--lens-sat);   /* mobile rail  */
    --lens-over: blur(40px) var(--lens-tone) var(--lens-sat);   /* the palette  */

    /* The old names kept as aliases, so every existing call site in app.css
       picks up the new function before it is edited. */
    --blur: var(--lens-bar);
    --blur-strong: var(--lens-over);

    /* The fills. The alpha IS the contrast floor, so these are not free
       numbers.
         --glass-pane   carries no text of its own (the shell pane)
         --glass-panel  carries text (topbar, card frame, tiles, palette)   */
    --glass-pane: rgb(255 255 255 / 58%);
    --glass-panel: rgb(255 255 255 / 78%);

    /* The three-level names survive as aliases: nothing in app.css breaks
       while you work through it, and the judgement now lives in two values. */
    --glass-thin: var(--glass-pane);
    --glass: var(--glass-panel);
    --glass-thick: var(--glass-panel);

    /*
        The edge. A pane has an OUTER hairline and an INNER rim, and in a light
        theme they are not the same colour.

        --glass-line is the outer hairline, and in light it is SHADE: a 70%
        white border on a near-white ground is nothing at all, which is why the
        cards read as floating rectangles rather than as panels.
    */
    --glass-line: rgb(15 23 42 / 9%);
    --glass-border: var(--glass-line);      /* alias for existing call sites */
    --glass-edge: rgb(15 23 42 / 8%);

    /*
        The rim: light enters the top edge and is brightest there; the bottom
        and the right return it as shade, because that is where a lit solid
        loses it. One inset white line along the top was a BEVEL — a different
        material, and an older one. Four white lines is a dark-mode object: on
        a light card composited at sRGB ~0.98 a white lip is a two-point step
        and a 6% dark line at the foot is a six-point step, so in light the
        bottom does the work and the top lip waits for something dark to pass
        behind it.
    */
    --rim:
        inset 0 1px 0 rgb(255 255 255 / 85%),
        inset 1px 0 0 rgb(255 255 255 / 30%),
        inset -1px 0 0 rgb(15 23 42 / 4%),
        inset 0 -1px 0 rgb(15 23 42 / 6%);
    --rim-soft:
        inset 0 1px 0 rgb(255 255 255 / 55%),
        inset 0 -1px 0 rgb(15 23 42 / 5%);
    /* Kept so anything still asking for the single line gets the whole rim. */
    --glass-highlight: var(--rim);

    /* The lit lower lip of a recess — a step cut INTO a sheet, not a box on
       it. Used by .filters, .card__foot and .tree__summary. */
    --lip: rgb(255 255 255 / 42%);

    /* --------------------------------------------------------------- Charts */
    /*
        A categorical ramp. The dashboard bars were a hard-coded blue that could
        not theme and could not tell two series apart.

        Series 2-6 are the SAME in every palette on purpose: a chart colour is
        an identity for a series, and it must not shift meaning because someone
        changed the chrome. Only series 1 follows the accent.
    */
    --chart-1: rgb(var(--accent-rgb));
    --chart-2: #0891b2;
    --chart-3: #7c3aed;
    --chart-4: #16a34a;
    --chart-5: #ea8b04;
    --chart-6: #db2777;
    --chart-grid: var(--border-subtle);
    --chart-track: var(--surface-sunken);
}

/* ======================================================================== */
/*  PALETTE: teal                                                           */
/*  Cool grey-green. The same temperature as indigo, a different hue.       */
/*  (0,2,0) — beats the base, ties with nothing, because it names only      */
/*  --l-* / --d-* and the variant arms name only public tokens.             */
/* ======================================================================== */
:root[data-palette="teal"] {
    --l-accent-rgb: 15 118 110;           /* teal 700 — 5.5 : 1 on white     */
    /*  the product mark's ramp; see wwwroot/css/brand.css        */
    --l-brand-grad: linear-gradient(100deg, rgb(13 148 136) 0%, rgb(8 145 178) 55%, rgb(22 163 74) 100%);
    --d-brand-grad: linear-gradient(100deg, rgb(45 212 191) 0%, rgb(34 211 238) 55%, rgb(134 239 172) 100%);
    --l-accent-strong-rgb: 17 94 89;
    --l-accent-soft-rgb: 204 251 241;
    --l-accent-contrast: #ffffff;

    --d-accent-rgb: 45 212 191;           /* teal 400 — 9.9 : 1 on --surface */
    --d-accent-strong-rgb: 94 234 212;
    --d-accent-soft-rgb: 19 78 74;
    --d-accent-contrast: #04211f;

    --l-n-50: #f5f9f8;  --l-n-100: #eaf2f0; --l-n-150: #e2ecea;
    --l-n-200: #d9e5e3; --l-n-300: #bfd0cd; --l-n-400: #94a6a3;
    --l-n-500: #697c79; --l-n-600: #50615f; --l-n-700: #384745;
    --l-n-800: #233130; --l-n-900: #111d1c;

    --d-n-50: #0c1917;  --d-n-100: #12211f; --d-n-150: #162825;
    --d-n-200: #1c3230; --d-n-300: #26443f; --d-n-400: #4d6b66;
    --d-n-500: #7c9994; --d-n-600: #a0bab5; --d-n-700: #c2d9d5;
    --d-n-800: #dfeeec; --d-n-900: #f1f8f7;

    --l-surface-app: #f3f8f7;
    --l-surface: #ffffff;
    --l-surface-raised: #ffffff;
    --l-surface-sunken: #edf4f2;
    --l-surface-hover: #f2f8f6;
    --l-surface-active: #e5f0ed;

    --d-surface-app: #061311;
    --d-surface: #0e1c1a;
    --d-surface-raised: #152523;
    --d-surface-sunken: #0a1614;
    --d-surface-hover: #132220;
    --d-surface-active: #1b2d2a;

    --l-sidebar-bg: #0b1f1d;
    --l-sidebar-fg: #bcd2ce;
    --l-sidebar-fg-muted: #728e89;
    --l-sidebar-raised: #08201e;

    --d-sidebar-bg: #030e0c;
    --d-sidebar-fg: #8fa8a4;
    --d-sidebar-fg-muted: #6f8481;
    --d-sidebar-raised: #08201e;

    --l-text: #0f201e;
    --l-text-muted: #4b5e5c;          /* 6.9 : 1 on white */
    --l-text-subtle: #667875;
    --l-text-inverse: #ffffff;

    --d-text: #e5f2f0;                /* 15.4 : 1 on --surface */
    --d-text-muted: #9db3b0;          /*  8.0 : 1 on --surface */
    --d-text-subtle: #728784;
    --d-text-inverse: #061311;

    --l-border: #dfe9e7;
    --l-border-subtle: #ecf3f1;
    --l-border-strong: #c6d4d1;

    --d-border: #213130;
    --d-border-subtle: #182625;
    --d-border-strong: #324644;

    --l-shadow-rgb: 8 40 38;
    --d-shadow-rgb: 0 0 0;
    --d-glass-pane-rgb: 10 24 22;
    --d-glass-panel-rgb: 12 28 26;

    --l-bloom-2-rgb: 8 145 178;
    --l-bloom-3-rgb: 5 150 105;
    --l-bloom-4-rgb: 13 148 136;
    --d-bloom-2-rgb: 8 145 178;
    --d-bloom-3-rgb: 5 150 105;
    --d-bloom-4-rgb: 13 148 136;
}

/* ======================================================================== */
/*  PALETTE: sand                                                           */
/*  Warm stone neutrals, burnt amber. The only warm ground of the four.     */
/* ======================================================================== */
:root[data-palette="sand"] {
    --l-accent-rgb: 180 83 9;             /* amber 700 — 5.0 : 1 on white    */
    /*  the product mark's ramp; see wwwroot/css/brand.css        */
    --l-brand-grad: linear-gradient(100deg, rgb(217 119 6) 0%, rgb(234 88 12) 55%, rgb(219 39 119) 100%);
    --d-brand-grad: linear-gradient(100deg, rgb(251 191 36) 0%, rgb(251 146 60) 55%, rgb(244 114 182) 100%);
    --l-accent-strong-rgb: 146 64 14;
    --l-accent-soft-rgb: 254 243 199;
    --l-accent-contrast: #ffffff;

    --d-accent-rgb: 251 191 36;           /* amber 400 */
    --d-accent-strong-rgb: 253 224 71;
    --d-accent-soft-rgb: 69 26 3;
    --d-accent-contrast: #1f1400;

    --l-n-50: #faf8f4;  --l-n-100: #f2eee7; --l-n-150: #ebe6dd;
    --l-n-200: #e3ddd2; --l-n-300: #cec6b6; --l-n-400: #a49b89;
    --l-n-500: #7a7261; --l-n-600: #5f584a; --l-n-700: #443f34;
    --l-n-800: #2c2820; --l-n-900: #191712;

    --d-n-50: #15110b;  --d-n-100: #1d1810; --d-n-150: #241e15;
    --d-n-200: #2d261a; --d-n-300: #3f3626; --d-n-400: #6b5f47;
    --d-n-500: #998c70; --d-n-600: #b9ac92; --d-n-700: #d6cab4;
    --d-n-800: #ece3d4; --d-n-900: #f8f3ea;

    --l-surface-app: #f8f5ef;
    --l-surface: #fffefb;
    --l-surface-raised: #fffefb;
    --l-surface-sunken: #f1ece3;
    --l-surface-hover: #f7f3ec;
    --l-surface-active: #ece6da;

    --d-surface-app: #13100a;
    --d-surface: #1d1811;
    --d-surface-raised: #262017;
    --d-surface-sunken: #16120c;
    --d-surface-hover: #241e15;
    --d-surface-active: #2d261c;

    --l-sidebar-bg: #211b13;
    --l-sidebar-fg: #d1c8b8;
    --l-sidebar-fg-muted: #8c8272;
    --l-sidebar-raised: #171209;

    --d-sidebar-bg: #0d0a06;
    --d-sidebar-fg: #b0a48f;
    --d-sidebar-fg-muted: #8c8171;
    --d-sidebar-raised: #171209;

    --l-text: #1c1812;
    --l-text-muted: #5b5244;          /* 7.6 : 1 on --surface */
    --l-text-subtle: #7b7362;
    --l-text-inverse: #ffffff;

    --d-text: #f2ece1;                /* 14.9 : 1 on --surface */
    --d-text-muted: #b4a894;          /*  7.4 : 1 on --surface */
    --d-text-subtle: #8f8574;
    --d-text-inverse: #13100a;

    --l-border: #e8e1d6;
    --l-border-subtle: #f1ebe2;
    --l-border-strong: #d2c9ba;

    --d-border: #332c22;
    --d-border-subtle: #251f18;
    --d-border-strong: #493f31;

    --l-shadow-rgb: 56 40 20;
    --d-shadow-rgb: 0 0 0;
    --d-glass-pane-rgb: 22 18 12;
    --d-glass-panel-rgb: 26 21 14;

    --l-bloom-2-rgb: 217 119 6;
    --l-bloom-3-rgb: 202 138 4;
    --l-bloom-4-rgb: 194 65 12;
    --d-bloom-2-rgb: 217 119 6;
    --d-bloom-3-rgb: 202 138 4;
    --d-bloom-4-rgb: 194 65 12;
}

/* ======================================================================== */
/*  PALETTE: plum                                                           */
/*  Cool violet-grey neutrals, a muted violet accent.                       */
/* ======================================================================== */
:root[data-palette="plum"] {
    --l-accent-rgb: 109 40 217;           /* violet 700 — 7.1 : 1 on white   */
    /*  the product mark's ramp; see wwwroot/css/brand.css        */
    --l-brand-grad: linear-gradient(100deg, rgb(124 58 237) 0%, rgb(192 38 211) 55%, rgb(219 39 119) 100%);
    --d-brand-grad: linear-gradient(100deg, rgb(167 139 250) 0%, rgb(232 121 249) 55%, rgb(244 114 182) 100%);
    --l-accent-strong-rgb: 91 33 182;
    --l-accent-soft-rgb: 237 233 254;
    --l-accent-contrast: #ffffff;

    --d-accent-rgb: 196 181 253;          /* violet 300 */
    --d-accent-strong-rgb: 221 214 254;
    --d-accent-soft-rgb: 76 29 149;
    --d-accent-contrast: #150a2b;

    --l-n-50: #f9f8fb;  --l-n-100: #f0eef5; --l-n-150: #e9e6f0;
    --l-n-200: #e0dceb; --l-n-300: #c8c2d9; --l-n-400: #9c95b1;
    --l-n-500: #716a86; --l-n-600: #57506a; --l-n-700: #3e384e;
    --l-n-800: #282334; --l-n-900: #16121f;

    --d-n-50: #120d1f;  --d-n-100: #191330; --d-n-150: #1f1938;
    --d-n-200: #272040; --d-n-300: #342b55; --d-n-400: #574b7d;
    --d-n-500: #8478a8; --d-n-600: #aa9fc8; --d-n-700: #c9c0e0;
    --d-n-800: #e4dff0; --d-n-900: #f4f1fa;

    --l-surface-app: #f7f5fa;
    --l-surface: #ffffff;
    --l-surface-raised: #ffffff;
    --l-surface-sunken: #f1eef7;
    --l-surface-hover: #f6f3fa;
    --l-surface-active: #eae5f3;

    --d-surface-app: #0d0917;
    --d-surface: #171126;
    --d-surface-raised: #1f1832;
    --d-surface-sunken: #110c1e;
    --d-surface-hover: #1d1630;
    --d-surface-active: #261e3b;

    --l-sidebar-bg: #17102a;
    --l-sidebar-fg: #c6bddb;
    --l-sidebar-fg-muted: #857b9c;
    --l-sidebar-raised: #120c22;

    --d-sidebar-bg: #090512;
    --d-sidebar-fg: #a89dc2;
    --d-sidebar-fg-muted: #837aa0;
    --d-sidebar-raised: #120c22;

    --l-text: #171220;
    --l-text-muted: #554e66;          /* 8.2 : 1 on white */
    --l-text-subtle: #787090;
    --l-text-inverse: #ffffff;

    --d-text: #ece7f7;                /* 15.2 : 1 on --surface */
    --d-text-muted: #ada4c4;          /*  7.8 : 1 on --surface */
    --d-text-subtle: #827a99;
    --d-text-inverse: #0d0917;

    --l-border: #e7e2ef;
    --l-border-subtle: #f0ecf6;
    --l-border-strong: #cfc8de;

    --d-border: #2b2341;
    --d-border-subtle: #201932;
    --d-border-strong: #3d3358;

    --l-shadow-rgb: 40 24 66;
    --d-shadow-rgb: 0 0 0;
    --d-glass-pane-rgb: 18 13 32;
    --d-glass-panel-rgb: 21 16 38;

    --l-bloom-2-rgb: 168 85 247;
    --l-bloom-3-rgb: 99 102 241;
    --l-bloom-4-rgb: 219 39 119;
    --d-bloom-2-rgb: 168 85 247;
    --d-bloom-3-rgb: 99 102 241;
    --d-bloom-4-rgb: 219 39 119;
}

/*
    ========================================================================
    THE VARIANT SWITCH — dark
    ========================================================================
    Dark is not the light palette inverted. The surfaces are lifted away from
    pure black so shadows still read, the borders are raised in contrast because
    a dark ground hides them, and the semantic colours are lightened — the
    success green and danger red chosen for white are close to unreadable here.
    All of that judgement lives in each palette's --d-* values; these two arms
    contain no colours of their own beyond the material constants, and they are
    identical to one another by construction.

    Two arms, not one, and the OS arm stays inside its media query:
    :root:not([data-theme="light"]) is TRUE on a default light page, so written
    outside the query it would hand every light-theme user the dark palette.

    Both are (0,2,0) and the light arm above is (0,1,0), so these win on
    specificity and not on order. A palette block is also (0,2,0) but declares
    no property either of these declares, so the tie cannot arise.
*/
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --accent-rgb: var(--d-accent-rgb);
        --accent-strong-rgb: var(--d-accent-strong-rgb);
        --accent-soft-rgb: var(--d-accent-soft-rgb);
        --accent-contrast: var(--d-accent-contrast);
        --brand-gradient: var(--d-brand-grad);

        --success-rgb: var(--d-success-rgb);
        --warning-rgb: var(--d-warning-rgb);
        --danger-rgb: var(--d-danger-rgb);
        --info-rgb: var(--d-info-rgb);

        --on-success: var(--d-on-success);
        --on-warning: var(--d-on-warning);
        --on-danger: var(--d-on-danger);
        --on-info: var(--d-on-info);

        --tone-blue: var(--d-tone-blue);
        --tone-green: var(--d-tone-green);
        --tone-amber: var(--d-tone-amber);
        --tone-neutral: var(--d-tone-neutral);
        --tone-contrast: var(--d-tone-contrast);

        --n-50: var(--d-n-50);
        --n-100: var(--d-n-100);
        --n-150: var(--d-n-150);
        --n-200: var(--d-n-200);
        --n-300: var(--d-n-300);
        --n-400: var(--d-n-400);
        --n-500: var(--d-n-500);
        --n-600: var(--d-n-600);
        --n-700: var(--d-n-700);
        --n-800: var(--d-n-800);
        --n-900: var(--d-n-900);

        --surface-app: var(--d-surface-app);
        --surface: var(--d-surface);
        --surface-raised: var(--d-surface-raised);
        --surface-sunken: var(--d-surface-sunken);
        --surface-hover: var(--d-surface-hover);
        --surface-active: var(--d-surface-active);
        --surface-selected: rgb(var(--accent-rgb) / 14%);
        --overlay: rgb(3 7 16 / 62%);

        --sidebar-bg: var(--d-sidebar-bg);
        --sidebar-fg: var(--d-sidebar-fg);
        --sidebar-fg-muted: var(--d-sidebar-fg-muted);
        --sidebar-raised: var(--d-sidebar-raised);
        --sidebar-active-fg: #ffffff;
        --sidebar-border: rgb(255 255 255 / 6%);

        --text: var(--d-text);
        --text-muted: var(--d-text-muted);
        --text-subtle: var(--d-text-subtle);
        --text-inverse: var(--d-text-inverse);

        --border: var(--d-border);
        --border-subtle: var(--d-border-subtle);
        --border-strong: var(--d-border-strong);

        --bloom-2-rgb: var(--d-bloom-2-rgb);
        --bloom-3-rgb: var(--d-bloom-3-rgb);
        --bloom-4-rgb: var(--d-bloom-4-rgb);

        --shadow-rgb: var(--d-shadow-rgb);
        --shadow-xs: 0 1px 2px rgb(var(--shadow-rgb) / 34%);
        --shadow-sm: 0 1px 2px rgb(var(--shadow-rgb) / 38%), 0 2px 6px rgb(var(--shadow-rgb) / 30%);
        --shadow-md: 0 2px 4px rgb(var(--shadow-rgb) / 40%), 0 8px 20px rgb(var(--shadow-rgb) / 42%);
        --shadow-lg: 0 4px 8px rgb(var(--shadow-rgb) / 44%), 0 24px 48px rgb(var(--shadow-rgb) / 55%);

        --ring: 0 0 0 2px var(--surface), 0 0 0 4px rgb(var(--accent-rgb) / 55%);

        /*
            Dark glass is a tint over what is behind it, not a wash of white.
            The highlight drops to a tenth of its light-mode strength — a bright
            line on a dark panel reads as a scratch, not as a lit edge.
        */
        --lens-tone: contrast(0.45) brightness(0.72);

        --glass-pane: rgb(var(--d-glass-pane-rgb) / 62%);
        --glass-panel: rgb(var(--d-glass-panel-rgb) / 86%);

        --glass-line: rgb(255 255 255 / 11%);
        --glass-edge: rgb(0 0 0 / 45%);

        /* On a dark panel a bright line reads as a scratch, so the rim drops
           to a tenth — but it stays on all four sides, because on dark the rim
           is the only thing that says where the pane ends. */
        --rim:
            inset 0 1px 0 rgb(255 255 255 / 13%),
            inset 1px 0 0 rgb(255 255 255 / 5%),
            inset -1px 0 0 rgb(255 255 255 / 5%),
            inset 0 -1px 0 rgb(255 255 255 / 7%);
        --rim-soft:
            inset 0 1px 0 rgb(255 255 255 / 10%),
            inset 0 -1px 0 rgb(255 255 255 / 4%);

        --lip: rgb(255 255 255 / 6%);

        --chart-2: #22d3ee;
        --chart-3: #a78bfa;
        --chart-4: #4ade80;
        --chart-5: #fbbf24;
        --chart-6: #f472b6;
    }
}

/* An explicit choice wins over the OS preference, in both directions. */
:root[data-theme="dark"] {
    color-scheme: dark;

    --accent-rgb: var(--d-accent-rgb);
    --accent-strong-rgb: var(--d-accent-strong-rgb);
    --accent-soft-rgb: var(--d-accent-soft-rgb);
    --accent-contrast: var(--d-accent-contrast);
    --brand-gradient: var(--d-brand-grad);

    --success-rgb: var(--d-success-rgb);
    --warning-rgb: var(--d-warning-rgb);
    --danger-rgb: var(--d-danger-rgb);
    --info-rgb: var(--d-info-rgb);

    --on-success: var(--d-on-success);
    --on-warning: var(--d-on-warning);
    --on-danger: var(--d-on-danger);
    --on-info: var(--d-on-info);

    --tone-blue: var(--d-tone-blue);
    --tone-green: var(--d-tone-green);
    --tone-amber: var(--d-tone-amber);
    --tone-neutral: var(--d-tone-neutral);
    --tone-contrast: var(--d-tone-contrast);

    --n-50: var(--d-n-50);
    --n-100: var(--d-n-100);
    --n-150: var(--d-n-150);
    --n-200: var(--d-n-200);
    --n-300: var(--d-n-300);
    --n-400: var(--d-n-400);
    --n-500: var(--d-n-500);
    --n-600: var(--d-n-600);
    --n-700: var(--d-n-700);
    --n-800: var(--d-n-800);
    --n-900: var(--d-n-900);

    --surface-app: var(--d-surface-app);
    --surface: var(--d-surface);
    --surface-raised: var(--d-surface-raised);
    --surface-sunken: var(--d-surface-sunken);
    --surface-hover: var(--d-surface-hover);
    --surface-active: var(--d-surface-active);
    --surface-selected: rgb(var(--accent-rgb) / 14%);
    --overlay: rgb(3 7 16 / 62%);

    --sidebar-bg: var(--d-sidebar-bg);
    --sidebar-fg: var(--d-sidebar-fg);
    --sidebar-fg-muted: var(--d-sidebar-fg-muted);
    --sidebar-raised: var(--d-sidebar-raised);
    --sidebar-active-fg: #ffffff;
    --sidebar-border: rgb(255 255 255 / 6%);

    --text: var(--d-text);
    --text-muted: var(--d-text-muted);
    --text-subtle: var(--d-text-subtle);
    --text-inverse: var(--d-text-inverse);

    --border: var(--d-border);
    --border-subtle: var(--d-border-subtle);
    --border-strong: var(--d-border-strong);

    --bloom-2-rgb: var(--d-bloom-2-rgb);
    --bloom-3-rgb: var(--d-bloom-3-rgb);
    --bloom-4-rgb: var(--d-bloom-4-rgb);

    --shadow-rgb: var(--d-shadow-rgb);
    --shadow-xs: 0 1px 2px rgb(var(--shadow-rgb) / 34%);
    --shadow-sm: 0 1px 2px rgb(var(--shadow-rgb) / 38%), 0 2px 6px rgb(var(--shadow-rgb) / 30%);
    --shadow-md: 0 2px 4px rgb(var(--shadow-rgb) / 40%), 0 8px 20px rgb(var(--shadow-rgb) / 42%);
    --shadow-lg: 0 4px 8px rgb(var(--shadow-rgb) / 44%), 0 24px 48px rgb(var(--shadow-rgb) / 55%);

    --ring: 0 0 0 2px var(--surface), 0 0 0 4px rgb(var(--accent-rgb) / 55%);

    --lens-tone: contrast(0.45) brightness(0.72);

    --glass-pane: rgb(var(--d-glass-pane-rgb) / 62%);
    --glass-panel: rgb(var(--d-glass-panel-rgb) / 86%);

    --glass-line: rgb(255 255 255 / 11%);
    --glass-edge: rgb(0 0 0 / 45%);

    /* On a dark panel a bright line reads as a scratch, so the rim drops to a
       tenth — but it stays on all four sides, because on dark the rim is the
       only thing that says where the pane ends. */
    --rim:
        inset 0 1px 0 rgb(255 255 255 / 13%),
        inset 1px 0 0 rgb(255 255 255 / 5%),
        inset -1px 0 0 rgb(255 255 255 / 5%),
        inset 0 -1px 0 rgb(255 255 255 / 7%);
    --rim-soft:
        inset 0 1px 0 rgb(255 255 255 / 10%),
        inset 0 -1px 0 rgb(255 255 255 / 4%);

    --lip: rgb(255 255 255 / 6%);

    --chart-2: #22d3ee;
    --chart-3: #a78bfa;
    --chart-4: #4ade80;
    --chart-5: #fbbf24;
    --chart-6: #f472b6;
}

/*
    ========================================================================
    ABSOLUTE OVERRIDES
    ========================================================================
    Everything below here must beat BOTH variant arms, and it does so exactly
    as it did before the palettes arrived — because the palettes did not raise
    the ceiling. The dark arms are still (0,2,0), so a block naming all three
    selectors still wins on the last-declared rule of equal specificity.

    THE TRAP, kept on the record because it will be walked into again: the old
    version of the block below targeted bare :root (0,1,0) and therefore LOST
    to :root:not([data-theme="light"]) and :root[data-theme="dark"] (both
    (0,2,0)) regardless of source order — so on a dark machine with a
    blocklisted GPU this fallback never once applied, and the rail and the
    palette rendered as flat tints over live content. The fix is to name every
    arm, and the reason four palettes did not make it worse is that a palette
    declares no public token name at all.
*/

/*
    Where the platform cannot blur, glass becomes OPAQUE rather than
    transparent. A translucent panel with no blur behind it is text over
    whatever happens to be underneath, which is the one outcome worse than no
    glass at all.
*/
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    :root,
    :root[data-theme="dark"],
    :root:not([data-theme="light"]) {
        --lens-bar: none;
        --lens-rail: none;
        --lens-over: none;
        --blur: none;
        --blur-strong: none;
        --glass-pane: var(--surface);
        --glass-panel: var(--surface);
    }
}

/*
    Apple ships this material with a Reduce Transparency switch, and taking the
    material seriously means taking that seriously. The honest response is the
    same as the no-backdrop-filter response: go opaque, keep the rim, keep the
    depth. It should still look like glass; it just stops being see-through.

    Firefox does not report this preference yet. Said rather than papered over:
    a Firefox user who wants less transparency gets the @supports path or
    nothing.
*/
@media (prefers-reduced-transparency: reduce) {
    :root,
    :root[data-theme="dark"],
    :root:not([data-theme="light"]) {
        --lens-bar: none;
        --lens-rail: none;
        --lens-over: none;
        --blur: none;
        --blur-strong: none;
        --glass-pane: var(--surface);
        --glass-panel: var(--surface);
    }
}

/* Somebody who asked for less motion gets less of it, everywhere. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --duration-fast: 0ms;
        --duration: 0ms;
    }
}
