/* SiteTensor brand tokens — the single source for the application interface.
 *
 * UPSTREAM: static/sitetensor-brand-style-sheet.html, v1.0, 31 August 2026,
 * section 05 ("Tokens, for the developer"). The brand pack ships the same
 * block as tokens/tokens.css; this file is the repository's counterpart, so
 * the names below are the brand's contract and not a local invention.
 *
 * WHY THIS FILE EXISTS. The block first landed inline in templates/login.html
 * (D-087). Copying it into the app shell and the change-password page would
 * have made three copies of one palette, and the failure mode of a duplicated
 * palette is silent divergence rather than a broken build: someone corrects a
 * hex in one file and the other two keep the old one for months. Principle 11
 * decides it on future-proofing — one brand decision must not require three
 * identical edits.
 *
 * tests/smoke/test_theming.py parses the brand sheet and asserts these values
 * match it, so the committed specification, not this file, is the authority.
 * A hand-edited hex here fails CI.
 *
 * WHERE THE SHEET SITS, AND WHEN IT DOES NOT WIN. The sheet is a committed
 * specification in tier 3 of docs/project/SOURCE_OF_TRUTH.md. A documented
 * application requirement beats a brand guideline; the departure is recorded as
 * a decision and marked here at the point of departure (see the caution block
 * below). A brand rule that restates a safety or accessibility standard is the
 * exception and is not the brand's to waive.
 *
 * NOTHING HERE IS EDITABLE AT RUNTIME. This file was briefly the default layer
 * under a set of database-stored overrides that Root could edit from the
 * Developer section. ADR-0005 removed that: a theme is now a committed file, the
 * database stores only which theme is chosen, and the values below are the last
 * word rather than a default. Company branding for PDF paperwork is a separate
 * system and is stored per company; it does not reach this file.
 */
:root {
    /* --- Colour ------------------------------------------------------------
     * Every ratio below is measured, not estimated (brand sheet, section 02).
     * They are all at or above WCAG AA, which is why the app adopting them
     * closes the standing --primary 4.3:1 finding of 27/07/2026.
     */
    --st-graphite: #0F1518;          /* Ink, dark surfaces, mark outlines · 18.4:1 */
    --st-ink-2: #3B474D;             /* Secondary text · 9.6:1 */
    --st-steel: #5E6A71;             /* Tertiary text, rules · 5.6:1 */
    --st-instrument-white: #F4F6F7;  /* Application ground · 18.0:1 */
    --st-surface: #FFFFFF;
    --st-surface-2: #E9EDEF;
    --st-line: #D5DCDF;

    --st-blue: #0B63D6;              /* Accent, light grounds · 5.6:1 */
    --st-blue-dark: #3D8BF0;         /* Accent, dark grounds · 5.4:1 on Graphite */
    --st-blue-soft: #E4EEFC;

    --st-hold: #0D7660;              /* On target · 5.6:1 */
    --st-hold-dark: #309C85;
    --st-slip: #D0021B;              /* Off target · 5.7:1 */
    --st-slip-dark: #FF3D4A;

    /* DERIVED, not specified. The brand sheet defines no hover or disabled
     * state, so these two were derived once for the sign-in screen (D-087)
     * and are recorded here rather than re-derived per screen: the hover is
     * Tensor Blue darkened, and "disabled" is opacity on the token colour so
     * that no colour outside the palette is ever invented.
     */
    --st-blue-hover: #0953B4;
    --st-disabled-opacity: 0.45;

    /* Also derived, and for the same reason: the brand publishes no tint, no
     * disabled ink and no focus ring, and a theme file must be able to map a
     * role without inventing a colour at the mapping site. Keeping every VALUE
     * here and every MAPPING in the theme files is what lets a test assert
     * that no theme file contains a raw colour at all.
     *
     * The two tints are the accent laid over the light ground at low strength,
     * so they stay inside the palette. Disabled is set to mirror the light
     * pair's relationship to its ground (2.20:1) rather than to reach AA:
     * WCAG 1.4.3 exempts inactive controls, and a disabled control that meets
     * AA does not read as disabled.
     *
     * Focus rings are rgba literals because CSS cannot take the channels out
     * of a hex custom property to build one. Same alpha as the ring has always
     * had; only the hue moves between modes.
     */
    --st-slip-soft: #FEF2F2;
    --st-hold-soft: #E9F5F2;         /* carries --st-hold at 4.98:1 */

    /* A DEEPER accent, for ink that sits over the Gallery's glass and its
     * photographic backdrop rather than over a flat ground. Derived, because
     * the brand publishes one accent and this is a second use of it at a
     * different depth, not a new colour: same hue as Tensor Blue, darker.
     *
     * 8.45:1 on Instrument White... and that figure is NOT the reason for the
     * value. --st-blue itself passes AA on every flat ground in the
     * application; the Gallery needs more because the ground there is a
     * photograph, and a measurement against a photograph is not something this
     * container can take. The number chosen mirrors the relationship the
     * G-Scapes original had between its gallery ink (8.84:1) and its accent
     * (5.22:1), on the reasoning that whoever picked that gap had the
     * photographs in front of them. See D-108; it is a judgement standing in
     * for a measurement, and it owes a browser check.
     */
    --st-blue-deep: #0A4A9E;         /* 8.45:1 on Instrument White */
    --st-disabled-ink: #A0AAA7;      /* 2.20:1 on Instrument White */
    --st-focus-ring: rgba(11, 99, 214, 0.25);

    /* --- Caution: a DELIBERATE DEPARTURE from the brand, not a derivation ---
     *
     * The brand sheet forbids this colour. Section 04, rule 2, in full:
     *
     *   "Status is never carried by colour alone. Every status figure ships
     *    with a glyph and a signed number. There is no amber: green, amber and
     *    red measure 9.4 apart for normal colour vision on a scale where 15 is
     *    the floor for telling two colours apart, so a three-state light is
     *    illegible before any colour deficiency is considered. Two states only."
     *
     * That is TWO rules in one sentence, and only the second is overruled.
     *
     *   OVERRULED, on the owner's instruction (D-103, 01/09/2026): "there is no
     *   amber, two states only". The application has a genuine third state --
     *   a success rate between 70 and 90 per cent, a caution callout, an import
     *   with warnings -- and flattening it to green or red would say something
     *   the data does not say. An application requirement beats a brand
     *   guideline; see docs/project/SOURCE_OF_TRUTH.md.
     *
     *   NOT OVERRULED, and not the brand's to waive: "status is never carried
     *   by colour alone". That is WCAG 2.2 SC 1.4.1 (Use of Color, Level A) in
     *   the brand's own words, and overruling the first rule makes it MORE
     *   load-bearing, because amber against green is exactly the pair
     *   red-green colour deficiency affects. Every amber site in the
     *   application already carries the figure, the bar width or a glyph, and
     *   tests/smoke/test_theming.py holds that.
     *
     * WHY THE LIGHT INK IS A BRIGHT ORANGE THAT FAILS AA, AND THE DARK ONE IS
     * NOT. D-103 chose #9A5B06, a dark ochre, on the reasoning that an amber
     * reaching 4.5:1 on a light ground is necessarily dark -- photometry
     * rather than taste. The owner looked at it on the DEFAULT theme on
     * 02/09/2026, reached the same judgement they had already reached for the
     * Custom theme, and replaced it with main's own #f39c12 (D-130). That is
     * tier 1 of docs/project/SOURCE_OF_TRUTH.md overriding tier 2, the same
     * route R-35 took for the Custom theme, and it is NOT the D-104 brand
     * carve-out: no brand waived this one, the owner did.
     *
     * The cost is recorded rather than absorbed. In LIGHT the ink measures
     * 2.02:1 on the application ground, 2.19:1 on a card and 2.00:1 on its own
     * tint, all below the 4.5:1 floor and all pinned in
     * tests/smoke/test_theming.py. They are the FIRST AA exemptions the
     * default theme has ever carried, which is why they get their own risk
     * (R-36) rather than joining R-35: R-35's mitigation is that Custom is
     * optional, and this is what a new installation shows. DARK is untouched
     * and still passes at 10.11:1, 9.37:1 and 8.64:1.
     *
     * Text ON the tint is unaffected and is deliberately NOT exempt --
     * --text-primary reads on it at 16.75:1, and a caution panel is the common
     * case. What fails is amber used AS TEXT against a light ground.
     */
    --st-caution: #f39c12;           /* 2.02:1 on Instrument White -- FAILS AA, see above */
    --st-caution-soft: #FDF3E3;      /* carries --st-caution at 2.00:1 -- FAILS AA */

    /* --- Dark neutrals -----------------------------------------------------
     * SOURCED FROM THE BRAND SHEET, but not from its token table. Section 05
     * ("Tokens, for the developer") publishes the light neutrals and the three
     * dark ACCENTS above, and no dark neutrals at all. The eight below are the
     * values the sheet uses to render its own dark ground, in the
     * prefers-color-scheme block at the head of the document, where it names
     * them --ground / --surface / --surface-2 / --ink / --ink-2 / --muted /
     * --line / --line-strong.
     *
     * That distinction is recorded rather than smoothed over, because it means
     * these eight are the brand DEMONSTRATED rather than the brand PUBLISHED.
     * If the brand pack later ships dark neutrals in tokens.css proper and they
     * differ, the pack wins and these change. tests/smoke/test_theming.py parses
     * that block and asserts these match it, so they cannot drift from the sheet
     * in the meantime.
     *
     * Named with the -dark suffix the sheet's own accents already use, so one
     * convention covers the whole palette.
     */
    --st-ground-dark: #0D1012;
    --st-surface-dark: #15191B;
    --st-surface-2-dark: #1B2023;
    --st-ink-dark: #E9ECED;
    --st-ink-2-dark: #BAC1C4;
    --st-muted-dark: #8B9599;
    --st-line-dark: #242A2D;
    --st-line-strong-dark: #333A3E;

    /* The dark counterparts of the four derived values above, chosen the same
     * way: inside the palette, measured, and recorded with the figure rather
     * than asserted. Every ratio below is against the dark ground #0D1012.
     *
     *   --st-blue-hover-dark   7.62:1   lighter than the 5.59:1 accent it hovers
     *   --st-blue-soft-dark    a tint; carries --st-ink-dark at 12.45:1
     *   --st-slip-soft-dark    a tint; carries --st-slip-dark at  4.97:1
     *   --st-disabled-ink-dark 2.24:1   mirroring the light pair's 2.20:1
     */
    --st-blue-hover-dark: #6BA6F4;
    --st-blue-soft-dark: #17293D;
    --st-slip-soft-dark: #2A1416;
    --st-hold-soft-dark: #10241E;    /* carries --st-hold-dark at 4.81:1 */
    --st-disabled-ink-dark: #454E52;
    --st-focus-ring-dark: rgba(61, 139, 240, 0.35);
    --st-caution-dark: #F5B027;      /* 10.11:1 */
    --st-caution-soft-dark: #2A1E08; /* carries --st-caution-dark at 8.64:1 */

    /* --- Type --------------------------------------------------------------
     * The brand sheet names the families only. The fallback stacks are ours,
     * so a page still reads correctly when fonts.googleapis.com is
     * unreachable. Plus Jakarta Sans (the logotype) is deliberately absent:
     * it ships as outlined artwork and is never set as live text.
     */
    --st-font-ui: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    --st-font-figure: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

    /* Scale, from the brand sheet's section-03 table. Size / line height /
     * tracking / weight are one row each and are kept together for that
     * reason: changing a size without its line height breaks the rhythm. */
    --st-size-display: 36px;   --st-lh-display: 1.05;  --st-tr-display: -0.035em;
    --st-size-h1: 28px;        --st-lh-h1: 1.10;       --st-tr-h1: -0.030em;
    --st-size-h2: 21px;        --st-lh-h2: 1.15;       --st-tr-h2: -0.025em;
    --st-size-h3: 17px;        --st-lh-h3: 1.20;       --st-tr-h3: -0.020em;
    --st-size-body: 15px;      --st-lh-body: 1.62;     --st-tr-body: -0.005em;
    --st-size-small: 13px;     --st-lh-small: 1.55;    --st-tr-small: 0;
    --st-size-label: 11px;     --st-lh-label: 1.40;    --st-tr-label: 0.10em;

    --st-weight-regular: 400;
    --st-weight-medium: 500;
    --st-weight-semibold: 600;
    --st-weight-bold: 700;

    /* --- Spacing -----------------------------------------------------------
     * "Spacing runs 4, 8, 12, 16, 24, 32, 48, 72" (brand sheet, section 03).
     */
    --st-s1: 4px;
    --st-s2: 8px;
    --st-s3: 12px;
    --st-s4: 16px;
    --st-s5: 24px;
    --st-s6: 32px;
    --st-s7: 48px;
    --st-s8: 72px;

    /* --- Shape -------------------------------------------------------------
     * "Interface corner radius is 3px. The mark's corners are square and stay
     * square." The radius is for interface chrome only, never the logo.
     */
    --st-radius: 3px;
    --st-border-width: 1px;
}
