/* =============================================================================
 * Atlas Cloud Tools — design tokens
 *
 * CANONICAL COPY. This file is the single source of every colour, radius and
 * shell metric on the platform. Each tool carries a byte-identical copy at
 * wwwroot/atlas-tokens.css; scripts\Sync-AtlasTokens.ps1 copies it out and
 * -Check fails the build if any copy has drifted. Edit here, never in a copy.
 *
 * Values are BIReports' — it is the gold standard and is not modified to match
 * anything. See UnifiedLogin/docs/atlas-tools-style-guide.md (ACT-70).
 *
 * Tokens are SEMANTIC, not a palette dump. A tool that needs a grey picks the
 * one that says what the grey is for; it does not add --grey-7.
 * ========================================================================== */

:root {
    /* --- Action ----------------------------------------------------------
     * WET ASPHALT, AGAINST THE CHARCOAL CHROME.
     *
     * Flat UI (materialui.co/flatuicolors) is now the whole platform palette:
     * Wet Asphalt #34495E acts, Midnight Blue #2C3E50 is its pressed state,
     * Concrete #95A5A6 is disabled, Pomegranate #C0392B is danger, and Silver
     * and Clouds are the only two greys on the page.
     *
     * A BUTTON'S FILL AND ITS INK ARE TWO TOKENS, not one. The fill is Clouds,
     * which is light, so the label is Midnight Blue on it — 11.6:1 — and the
     * SAME ink carries every text use on a white surface: an outlined
     * secondary's label, a .btn-link, a hovered icon. One token could not do
     * both jobs, because a light fill and readable text are opposite demands.
     *
     * The border is its own token again: a Clouds button sits on Clouds section
     * bands and table heads and needs an edge, but the ink is too hard for one.
     *
     * Hover flips the label to white. It was the dashboard blue #0E5C8A (the
     * midpoint of the report palette's two blues); since 2026-10-20 every dark
     * hover is #3C5273. The tick (--color-check) and the focus ring keep the
     * dashboard blue — neither is a hover. */
    --color-action: #ECF0F1;            /* Clouds — the fill of a button */
    --color-action-hover: #3C5273;      /* slate blue (2026-10-20, ACT-112; was the dashboard blue #0E5C8A) */
    --color-action-fg: #2C3E50;         /* Midnight Blue: 11.6:1 on Clouds */
    --color-action-hover-fg: #FFFFFF;   /* white on the hover fill — 7.9:1 */
    --color-action-ink: #2C3E50;        /* Midnight Blue — the accent as TEXT */

    /* The EDGE is Silver. Midnight Blue around a Clouds fill is a hard outline
       — a box drawn around the label rather than the button's own shape — and
       Concrete is still heavy enough to read as one. A Clouds button on a Clouds
       band is separated by its SHADOW, not by a ring, so the line can be light. */
    --color-action-edge: #BDC3C7;       /* Silver */

    /* THE LIGHT INK. Every label that sits on a dark or saturated fill — a
       hovered button on Peter River, a .btn-danger on Pomegranate, the app bar,
       a disabled control on Concrete — is Clouds. White is not in this palette
       and does not belong on a page painted from it. */
    --color-on-dark: #ECF0F1;           /* Clouds */

    /* Disabled is a COLOUR, not an opacity. Fading the accent produced a
       washed-out copy of the button beside it, which reads as a rendering
       fault rather than as "not available yet". Concrete, one step down from
       the Clouds a live button is filled with, with muted ink on it. */
    --color-disabled: #BDC3C7;          /* Silver */
    --color-disabled-fg: #7F8C8D;       /* Asbestos — washed out on purpose */

    /* --- Link -------------------------------------------------------------
     * Same family as the action, so a link and a button are recognisably the
     * same intent at different weights. */
    --color-link: var(--color-action-ink);
    --color-link-hover: var(--color-action-hover);

    /* Ticks and radios. The browser's default checked blue is brighter than
       anything else on the page and is not ours. Applied through accent-color,
       so the control keeps its native shape and platform behaviour. This is
       also what the Power BI slicer checkbox is set to, so a tick is the same
       blue whether the user is on a page or in a report. */
    --color-check: #0E5C8A;             /* the button hover — a tick is the same blue */

    /* Tints, hovers, badges, selected rows. Never behind text. */
    --color-accent-soft: #5D6D7E;
    --color-accent-wash: #DCE3EA;

    /* Focus is derived from the action colour so a focused control relates to
       the thing it becomes when pressed.

       ONE RING, AND IT IS SOLID. This was rgba(52,73,94,0.3) painted as
       `box-shadow: 0 0 0 3px`, which is a translucent 3px band bleeding outside
       the control — a halo, not a ring, and the Fluent fields drew it OUTSIDE a
       solid 2px outline as well, so a focused field carried two indicators.
       A solid `outline` is the whole statement now: it follows border-radius,
       it never participates in layout, and one declaration cannot be half-
       overridden the way a shadow stack can. The dashboard blue is 7.2:1 on
       white and 6.3:1 on the Clouds band — AA for a non-text indicator either
       way, which the 30% wash was not, and well clear of the 3.9:1 and 3.1:1
       the slate it replaced was holding. */
    --color-focus-ring: #0E5C8A;        /* dashboard blue — the action hover */
    --focus-ring-w: 2px;
    --focus-ring-offset: 1px;
    /* THE FILL OF THE FIELD YOU ARE IN. The border is not part of this and
       never changes — not at rest, not on hover, not when active. Repainting it
       thicker or in another colour puts a gradient down one edge at 125%/150%
       display scaling and stops the straight runs meeting the corner radius;
       a fill has no edges of its own, so it is the same at every scaling. */
    --color-field-active-bg: #E4E9F0;
    /* THE FILL OF THE FIELD UNDER THE POINTER — a step lighter than the field
       you are in, so hover and active never read as the same state. The same
       tint the platform dropdown button already takes on hover. */
    --color-field-hover-bg: var(--color-surface-3);

    /* --- Shell ----------------------------------------------------------
     * The dark app bar. Identical in every tool. */
    --color-shell-bg: #1f2937;
    --color-shell-fg: var(--color-on-dark);
    --color-shell-fg-muted: rgba(255, 255, 255, 0.8);
    --color-shell-fg-dim: rgba(255, 255, 255, 0.7);
    /* TWO ROLES, TWO NAMES. These were one token doing both jobs, which is how
       the bar ended up with two shades of control: a FILLED control took the
       white wash and composited to #363F4B, while every button beside it took
       --color-action-ink and came out #2C3E50.

       --color-shell-field-* is the hover TINT on the bar's flat affordances —
       the menu toggle, the tabs, the user-menu rows, Return to Tools. Those have
       no fill at rest, so the tint has to be lighter than the bar or nothing
       happens; Midnight on Wet Asphalt is no change at all.

       --color-shell-control-* is the FILL of a control that is filled at rest —
       the tenant picker, and any native select or input in the bar. Midnight,
       lifting to the slate on hover, which is what the section comment in
       atlas-fluent.css §4 has always said a bar control does. */
    --color-shell-field-bg: rgba(255, 255, 255, 0.1);
    --color-shell-field-bg-hover: rgba(255, 255, 255, 0.2);
    --color-shell-control-bg: var(--color-action-ink);
    --color-shell-control-bg-hover: var(--color-action-hover);
    /* TRANSPARENT. A CONTROL IN THE BAR HAS NO OUTLINE.
       This was rgba(255,255,255,0.35), and the comment that used to sit here
       argued the case well: at 0.30 the edge measured 2.65:1 over #1f2937, under
       the 3:1 a non-text indicator needs, so it went to 0.35 for contrast. The
       argument was sound and the premise was wrong — atlas-ui-standard.md §6 has
       said "No outlines" the whole time, and a 35%-white ring around Refresh
       Report, the tenant picker and My Views is the thing that keeps being
       reported.
       It is fixed on the TOKEN, not on the five rules that read it
       (atlas-appbar, atlas-fluent ×3, atlas-theme, atlas-components), because
       fixing one rule is how four of them stayed. The fill — white at 10%, and
       20% on hover — is the whole affordance. Audit-Header.js now fails on any
       bar rule that names a visible edge. */
    --color-shell-field-border: transparent;
    --color-shell-option-bg: #2c3e50;   /* native <option> in a dark select */

    /* --- Surfaces -------------------------------------------------------- */
    --color-page-bg: #f8f9fa;           /* the ground content sits on */
    --color-surface: #ffffff;           /* cards, tables, inputs */
    --color-surface-2: #ECF0F1;         /* Clouds — table heads, wells, tints */
    --color-surface-3: #F4F6F7;         /* Clouds lifted — table zebra, under the head */

    /* --- Text ------------------------------------------------------------ */
    --color-text-strong: #2C3E50;       /* Midnight Blue — quoted source, emphasis */
    --color-text: #34495E;              /* Wet Asphalt — body */
    --color-text-muted: #7F8C8D;        /* Asbestos — labels, secondary */
    --color-text-subtle: #95A5A6;       /* Concrete — placeholders, "not set" */

    /* --- Lines and rows --------------------------------------------------- */
    --color-border: #dee2e6;
    --color-border-strong: #BDC3C7;     /* Silver — input strokes */
    --color-row-hover: #E4E9EB;         /* Clouds deepened — reads over the zebra */
    --color-row-selected: var(--color-accent-wash);

    /* --- Status ----------------------------------------------------------
     * Colour never carries meaning alone; every state also carries a word. */
    --color-danger: #C0392B;            /* Pomegranate */
    --color-danger-hover: #A93226;
    --color-danger-bg: #FDEDEC;
    --color-danger-border: #E6B0AA;
    --color-success: #1E8449;           /* Nephritis, darkened to clear 4.5:1 as text */
    --color-success-bg: #E8F6EF;
    --color-success-border: #A9DFBF;
    --color-warning: #D35400;           /* Pumpkin */
    --color-warning-hover: #A04000;
    --color-warning-bg: #FDF0E6;
    --color-warning-border: #EDBB99;
    --color-info-bg: #EAF2F8;
    --color-info-border: #AED6F1;

    /* --- Payment tone ------------------------------------------------------
       Statements grades a customer on five steps, good to critical, and had all
       ten colours as raw hex inside ToneBadge.tsx.

       THESE FIVE FILLS ARE THE ONES IN THE DONUT, and they are the authored
       scale. The badges used to be built out of the status palette instead —
       --color-success-bg, --color-warning-bg, --color-danger-bg — which are
       WASHES, three steps lighter than the ramp. So the same customer was one
       colour in the ring and a pale version of it in the legend and the row
       beside it, and there was no way to read the two together. The ring was
       right; it just held its colours as raw hex in ToneDonut.tsx, where nothing
       could reach them. They are here now, and the ring reads them like
       everything else.

       This ramp is NOT the status palette and does not answer to the one-red
       rule: --color-danger is the platform's single red for a destructive
       action, and these are five steps of a data scale that happen to end in a
       deep maroon. A tone is a measurement, not a warning.

       The ink is Midnight on the four light steps and Clouds on the dark one.
       Hue-matched ink — green on green — was legible on a wash and is not on a
       fill. */
    --tone-good-bg: #85D2A0;
    --tone-good-fg: var(--color-action-ink);
    --tone-good-dot: #85D2A0;

    --tone-late-1-bg: #FFD859;
    --tone-late-1-fg: var(--color-action-ink);
    --tone-late-1-dot: #FFD859;

    --tone-late-2-bg: #FFB56B;
    --tone-late-2-fg: var(--color-action-ink);
    --tone-late-2-dot: #FFB56B;

    --tone-delinquent-bg: #F0A4A8;
    --tone-delinquent-fg: var(--color-action-ink);
    --tone-delinquent-dot: #F0A4A8;

    --tone-critical-bg: #7A1F1F;
    --tone-critical-fg: var(--color-on-dark);
    --tone-critical-dot: #7A1F1F;

    /* The ring's unfilled remainder. It was #e9ecef in ToneDonut.tsx. */
    --tone-empty: var(--color-border);

    /* --- Shape ------------------------------------------------------------ */
    /* ONE CORNER. Every box on the platform rounds at --radius: a button, a
       field, a card, a menu, a modal, a toast, a tab, a pill.
       --radius-sm existed at 4px and that was the whole problem: the two paint
       layers picked different ones — atlas-fluent.css (the React tools) took
       --radius, atlas-theme.css (Blazor and the static pages) took --radius-sm
       — so the same Save was 6px in BIReports and 4px in Warranty, and nothing
       in the build compared them. It is an ALIAS now, not a second value, so a
       file that still asks for it cannot reintroduce the split. Retuning the
       corner is this one line.
       Only two shapes are not this: 50% (a circle — an avatar, a spinner, a
       status dot) and 0 (a deliberate square edge, e.g. a joined group). A
       LITERAL radius anywhere in our CSS is a bug; `node
       UnifiedLogin\scripts\Audit-Shape.js` fails on one. */
    --radius: 6px;
    --radius-sm: var(--radius);
    /* ALMOST SQUARE. The third and last corner on the platform, and it is not a
       loophole in the rule above — it is for the two things that are marks
       rather than boxes: a tone badge and a tick. At --radius a 16px tick box
       is 37% corner and reads as a pill, and a badge reads as a button. 2px
       keeps the corner off the pixel grid without pretending to be a control.
       Nothing else may take it; Audit-Shape.js still fails on a literal. */
    --radius-tight: 2px;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
    /* A dialog sits above everything, so it casts further than a card does.
       Three apps each invented their own; this is the one they now share. */
    --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.30);
    /* What a modal lays over the page. Statements had rgba(0,0,0,.5) inline. */
    --color-scrim: rgba(0, 0, 0, 0.5);

    /* --- Spacing -----------------------------------------------------------
     * A 4px scale, and the ONLY vertical rhythm in the platform.
     *
     * The content column is a flex column, so margins never collapse inside it:
     * whatever a page sets is ADDED to whatever its neighbour set. Pages
     * therefore set none. atlas-theme.css applies these to the gap BETWEEN
     * blocks, so retuning page density is an edit here and not a hunt through
     * markup. */
    --space-1: 2px;
    --space-2: 4px;                     /* heading → the content it introduces */
    --space-3: 8px;
    --space-4: 12px;                    /* between blocks */
    --space-5: 16px;
    --space-6: 24px;                    /* between groups: above a heading */

    /* ONE control height. Buttons, inputs, selects and the file picker's own
       button all resolve to it, so a row of controls lines up without anybody
       measuring. There is no "sm" height — a compact control tightens its
       horizontal padding, never its box. */
    --control-h: 30px;

    /* ...AND ONE CONTROL BOX. The height was the only part of the box that was
       ever a token, so the rest drifted exactly as the corner did:
       atlas-fluent.css (the React tools) padded a button 0 12px with a 4px gap
       at 14px type, atlas-theme.css (Blazor and the static pages) padded it
       .25rem 1rem with a .375rem gap at .8125rem — the same Save, two boxes,
       and the Blazor side written in rem literals where no token audit could
       see it. The Blazor box won on sight (2026-09-18) and is the platform's
       now; both layers read these.
       A FIELD keeps its own horizontal padding: its text starts closer to the
       edge than a button's centred label does, and equalising them pushed the
       value away from the stroke. It was three values — .625rem on .form-control
       and .btn-sm, .5rem on the typed inputs — which is the same drift again,
       inside one file. Everything else about a field and a button is the same. */
    --control-pad-y: 4px;
    --control-pad-x: 16px;              /* a button */
    --control-pad-x-tight: 10px;        /* an input, a select, a compact button */
    --control-pad-x-wide: 20px;         /* .btn-lg — a size variant moves the
                                           horizontal padding, never the box */
    --control-gap: 6px;                 /* a glyph → its label */

    /* A ROW IN A MENU is taller than a control, deliberately: it is a pointer
       target in a floating panel, not a control in a row of controls, and at
       --control-h the four entries of a user menu sat on top of each other. */
    --menu-row-h: 36px;

    /* THE GAP BETWEEN A TRIGGER AND THE PANEL IT OPENS. Zero: the panel hangs
       off the bottom edge of the control, so the two read as one thing. A strip
       of page between them reads as two objects that happen to be near each
       other, and a menu stops looking attached to the button that opened it.

       It is a TOKEN because four panels have to agree on it and they are written
       in four places — the menu and the picker in atlas-fluent.css, the
       hand-built select and the date grid in atlas-components.css — plus
       atlas-picker.jsx, which is portalled and positions itself in script. That
       is five copies of one number, which is how it came to be 4px, 2px, 4px and
       4px at the same time. Retune the gap here and every panel moves. */
    --popup-gap: 0px;

    /* WHEN A PICKER GROWS A SEARCH BOX. Under this many options the list is
       shorter than the panel and the eye finds the row faster than the hands
       find the keyboard — a search field over eleven payment terms is a control
       asking to be used for nothing. Over it, the list scrolls and typing wins.

       It is here rather than in atlas-picker.jsx for the same reason --popup-gap
       is: it is a platform decision about how a control behaves, and the two
       apps that had this component before the platform did had each picked their
       own number. One place to change it, and the change reaches every picker in
       all six tools. Unitless, because it is a count. */
    --picker-search-min: 20;

    /* THE TENANT PICKER IS ONE WIDTH. The three Blazor tools each passed
       Width="230px" to their own CompanySwitcher and the three React ones passed
       nothing, so the picker sized to its content there — which means it changed
       width with the tenant NAME as well as with the tool. It sits dead centre
       of the bar, so anything that moves its edges moves the one element your
       eye uses to check you are still in the same product. */
    --tenant-w: 230px;

    /* Clearance around a BUTTON — above, below, and between two of them.
       Buttons sat hard against the control, the table or the text next to them,
       and the gap differed per app because each one patched it in its own
       markup. This matches the air a table already puts around its rows
       (table.picker cells are 4px 8px, so 8px between items); 0.25em was still
       too tight. One token, applied on the button host in atlas-fluent.css, so
       every tool gets the same clearance and retuning it is an edit here. Set
       it to 0 on a container whose buttons must stay aligned with the fields
       beside them. */
    --button-gap: var(--space-3);

    /* --- Shell metrics ----------------------------------------------------- */
    --app-bar-h: 57px;
    --app-footer-h: 2.5rem;
    --content-max-w: 1600px;
    --content-max-w-narrow: 1200px;     /* form-heavy screens */

    /* THERE IS NO PROSE MEASURE TOKEN, deliberately. Prose takes the content
       column, which is already bounded at 1600px (1200 form-heavy) and centred.
       A second cap inside that one is capping twice: it throws away width that
       was kept on purpose and makes the reader scroll for text that would have
       fitted. These are dense working screens, not an article.

       The per-class caps the tools had grown — .hint at 78ch, .reasoning at
       80ch — are what produced an intro paragraph at 572px beside a warning at
       1521px on one screen. atlas-theme.css now overrides them to none. */

    /* --- Type -------------------------------------------------------------- */
    --font-stack: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans,
                  Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
    --font-size-base: 16px;
    --font-size-body: 14px;             /* prose: a paragraph, an overlay message */
    --font-size-control: 13px;          /* EVERY control — button, field, select,
                                           option, menu item, checkbox label.
                                           It matches --font-size-table on purpose:
                                           a Pay button in a table row is the same
                                           size as the amount beside it. */
    --font-size-table: 13px;
    --font-size-micro: 11px;            /* uppercase field and column labels */
}
