﻿/*
 * Space ERP — brand design tokens
 *
 * Colours are taken from the Space brand guide, with the gold sampled from the master logo
 * artwork (the guide marks gold a "special colour" and gives no hex).
 *
 * Light is the primary, default theme: white and pearl surfaces, navy used as an accent for
 * text, buttons and the logo — never as a background fill. Gold is used sparingly, per the
 * guide's "limit use" instruction: selection indicators and key figures, never body text (it
 * fails contrast against white). A dark theme is available as an opt-in (see the
 * [data-theme="dark"] block below) — every screen is still designed against light first.
 *
 * --st-accent/--st-accent-hover exist because --st-navy is also used as a solid FILL (primary
 * buttons, badges, the reading-progress pill) paired with white text. --st-accent is for the
 * other role, navy used as FOREGROUND text/links/borders sitting directly on a page surface,
 * which does need to lighten when the surface goes dark.
 *
 * The navy fill stays fixed on both themes where it sits on a light surface. It does NOT survive
 * on the dark theme's page background: navy #0A172D against --st-bg #12161f is almost no
 * contrast, so the button silhouette vanishes and only its white label reads. Primary buttons
 * therefore invert in dark mode (see the .btn-primary override) rather than keeping the fill.
 */

:root {
    /* Tells the browser which way to draw the parts of a control we cannot reach with CSS: the
       date field's calendar button, scrollbars, and the popup list a <select> opens. Without it
       those stay in their light-mode form on the dark theme — a near-black calendar glyph on a
       near-black field, and a white dropdown list under dark inputs. */
    color-scheme: light;

    /* --- Brand palette ---------------------------------------------------- */
    --st-navy: #0A172D;         /* Celestial Blue — brand guide */
    --st-navy-600: #16294a;     /* hover/active steps derived from navy */
    --st-navy-300: #5a6883;
    --st-pearl: #E9E5E3;        /* Pearl — brand guide */
    --st-pearl-light: #f5f3f1;
    --st-cloud: #777777;        /* Silken Cloud — brand guide */
    --st-gold: #BF8E36;         /* sampled from master logo artwork */
    --st-gold-soft: #e7d3ab;

    /* Navy used as foreground (text/links/borders) rather than as a fill — see note above. */
    --st-accent: var(--st-navy);
    --st-accent-hover: var(--st-navy-600);

    /* --- Surfaces --------------------------------------------------------- */
    --st-bg: #ffffff;
    --st-bg-subtle: var(--st-pearl-light);
    --st-surface: #ffffff;
    --st-border: #e2ded9;
    --st-border-strong: #cfc9c2;
    /* Column separators inside tables. Deliberately fainter than --st-border: rows are what the
       eye follows down a list, so vertical rules should organise without competing with them. */
    --st-border-subtle: #efebe6;

    /* --- Text ------------------------------------------------------------- */
    --st-text: #1c1a17;
    --st-text-muted: var(--st-cloud);
    --st-text-inverse: #ffffff;

    /* --- Status (icon + text always accompany colour, never colour alone) -- */
    --st-success: #2f6f4e;
    --st-success-bg: #eaf3ee;
    --st-warning: #9a6c15;
    --st-warning-bg: #fdf4e3;
    /* Warning is the one status hue that needs a second, darker step for TEXT. Amber sits high in
       the lightness band, so --st-warning reads at only 4.3:1 on --st-warning-bg — under the 4.5:1
       small-text floor, and every warning tint in the app is a surface we then write on. Use
       --st-warning-text for the words, --st-warning for rules, borders and fills. Success and
       danger are dark enough at one step and need no equivalent. */
    --st-warning-text: #6b4a09;
    --st-warning-border: #e6d9bd;
    --st-danger: #a1332c;
    --st-danger-bg: #fbeceb;
    --st-info: var(--st-accent);
    --st-info-bg: #eef1f6;
    /* The alert list's "information" severity, which is NOT --st-info: that one aliases navy, and
       navy at severity size is indistinguishable from body text, so the row loses its signal. This
       is a deliberately blue blue, held apart from the accent. */
    --st-severity-info: #1d4ed8;

    /* --- Chart series (categorical: identity, never magnitude) -------------
       Nine slots, validated as a set against #ffffff on ALL pairs rather than adjacent ones,
       because a slot belongs to an entity (a currency picks its colour on the rate screen) and
       any two can therefore land on one chart with nothing between them. Re-stepping one slot
       on its own invalidates the result: the set was chosen together.

       Worst pair 6.3 protan / 15.8 normal-vision (OKLab dE x100, floors 6 and 15); chroma floor
       and 3:1 contrast pass on all nine. The 6-8 colour-blind band is legal only where something
       other than colour carries identity, which every chart here has: the legend names the series.

       Slots 5-9 were what let the palette grow past six. They are separated from the first four
       partly by LIGHTNESS rather than hue alone, which is why maroon sits below the documented
       lightness band (L 0.32) — at 13.35:1 on white it is the most visible mark we draw, and
       contrast, not the band, is the legibility gate.

       A tenth series is not a tenth colour: fold the tail into one "everything else" row. */
    --st-series-1: #2a78d6;  /* blue     4.42:1 */
    --st-series-2: #b3842f;  /* gold     3.36:1 */
    --st-series-3: #4a3aa7;  /* violet   8.56:1 */
    --st-series-4: #0e8f63;  /* green    4.10:1 */
    --st-series-5: #630030;  /* maroon  13.35:1 */
    --st-series-6: #b2015d;  /* magenta  6.87:1 */
    --st-series-7: #f84690;  /* pink     3.35:1 */
    --st-series-8: #833d00;  /* brown    7.98:1 */
    --st-series-9: #a275fd;  /* lavender 3.23:1 */

    /* Ordinal ramp: one hue, ordered steps, for a pie's slices where the categories are already
       ranked and the colour should read as "more" rather than as identity. Ordered strongest
       first. FIVE steps is the ceiling, not a round number: each adjacent pair has to differ in
       lightness by enough to be told apart, and the palest step still has to be visible against
       the surface, which leaves room for exactly five. A sixth slice is a fold into "everything
       else", never another step. */
    --st-ramp-1: #104281;
    --st-ramp-2: #1c5cab;
    --st-ramp-3: #2a78d6;
    --st-ramp-4: #5598e7;
    --st-ramp-5: #86b6ef;

    /* Chart chrome. Recessive on purpose: the data is the ink, the scaffolding is not. */
    --st-chart-grid: #efebe6;
    --st-chart-axis: #b9b2a9;

    /* --- Typography ------------------------------------------------------- */
    /* Marcellus and Playfair Display are the brand faces; Roboto carries the interface.
       Self-hosted in wwwroot/fonts (no CDN — the content security policy blocks external hosts).
       Fallbacks keep the app legible before the web fonts load. */
    --st-font-display: "Playfair Display", Georgia, "Times New Roman", serif;
    --st-font-heading: "Marcellus", Georgia, "Times New Roman", serif;
    --st-font-body: "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
    --st-font-mono: "JetBrains Mono", Consolas, "Courier New", monospace;

    /* Tabular figures matter in an ERP: columns of numbers must align. */
    --st-font-numeric: "Roboto", -apple-system, "Segoe UI", sans-serif;

    /* --- Spacing & shape --------------------------------------------------- */
    --st-radius: 4px;           /* crisp and editorial rather than rounded/playful */
    --st-radius-lg: 6px;
    --st-shadow-sm: 0 1px 2px rgb(10 23 45 / 6%);
    --st-shadow: 0 2px 8px rgb(10 23 45 / 8%);
    --st-shadow-lg: 0 8px 24px rgb(10 23 45 / 12%);

    --st-sidebar-width: 248px;
    --st-topbar-height: 56px;

    /* --- Motion ------------------------------------------------------------ */
    /* 120–180ms only, and only on hover/overlay transitions: power users should never
       wait for the interface to finish animating. */
    --st-transition: 140ms ease-out;
}

/* ---------------------------------------------------------------------------
   Dark theme — opt-in via the topbar toggle, applied as data-theme="dark" on
   <html> (set server-side from a cookie, so there is no flash of the wrong
   theme on load). Redefining the raw brand swatches (--st-pearl-light,
   --st-cloud, --st-navy) that the semantic tokens above alias into means most
   of the app repaints correctly without every rule needing its own override —
   only the handful of places that used --st-navy as page-surface foreground
   text needed to move to --st-accent (see note at the top of this file).
   --------------------------------------------------------------------------- */
:root[data-theme="dark"] {
    color-scheme: dark;

    --st-pearl: #232a35;
    --st-pearl-light: #1a212b;
    --st-cloud: #9aa3b0;

    --st-accent: #9db8e0;
    --st-accent-hover: #c2d4f0;

    --st-bg: #12161f;
    --st-surface: #171d26;
    --st-border: #2b3542;
    --st-border-strong: #3a4555;
    --st-border-subtle: #212a35;

    --st-text: #e7e5e2;

    --st-success: #7bd9a5;
    --st-success-bg: #1c3327;
    --st-warning: #f0c56b;
    --st-warning-bg: #3a2c10;
    /* "Stronger" inverts with the surface, as the chart ramp below does: prominence against a dark
       background comes from light, not from depth. Equal to --st-warning here because the pale
       amber is already the readable end on #3a2c10 (8.3:1); the token still exists so callers do
       not have to know which theme they are in. */
    --st-warning-text: #f0c56b;
    --st-warning-border: #5a4517;
    --st-danger: #f2a39c;
    --st-danger-bg: #3a1e1b;
    --st-info-bg: #1c2636;
    --st-severity-info: #8ab0f0;

    /* The same nine hues re-stepped for the dark surface rather than flipped to it, and validated
       as their own set against #171d26 on all pairs: worst 6.5 protan / 16.2 normal-vision, chroma
       and 3:1 contrast pass on all nine.

       The previous four dark steps are GONE rather than kept and extended. They were validated on
       adjacent pairs only, and on the all-pairs list the old violet #9085e9 and blue #3987e5
       measured 1.9 apart — GBP and EUR were close to one colour on a dark screen. Nothing could be
       built on top of that.

       Slot order is unchanged, so a currency keeps its slot across themes, but a step here is not
       always the same hue as its light twin: up to about 24 degrees of drift was needed for the set
       to clear the floors. Nobody sees both themes at once and the legend names the series either
       way. Three steps sit above the documented lightness band; all clear 3:1 on this surface. */
    --st-series-1: #02739a;  /* blue      3.16:1 */
    --st-series-2: #fec921;  /* gold     10.96:1 */
    --st-series-3: #d19dff;  /* violet    8.05:1 */
    --st-series-4: #12b10d;  /* green     5.90:1 */
    --st-series-5: #d50b54;  /* maroon    3.23:1 */
    --st-series-6: #fe7f7a;  /* magenta   6.88:1 */
    --st-series-7: #df4ec4;  /* pink      4.86:1 */
    --st-series-8: #b66100;  /* brown     3.79:1 */
    --st-series-9: #4d5ef2;  /* lavender  3.39:1 */

    /* The ramp inverts on dark: "strongest" is the lightest step here, because prominence against
       a dark surface comes from light rather than from depth. Same hue, same five-step ceiling,
       validated against #171d26 in its own right. */
    --st-ramp-1: #9ec5f4;
    --st-ramp-2: #6da7ec;
    --st-ramp-3: #3987e5;
    --st-ramp-4: #256abf;
    --st-ramp-5: #184f95;

    --st-chart-grid: #262f3c;
    --st-chart-axis: #475261;

    --st-shadow-sm: 0 1px 2px rgb(0 0 0 / 30%);
    --st-shadow: 0 2px 8px rgb(0 0 0 / 40%);
    --st-shadow-lg: 0 8px 24px rgb(0 0 0 / 50%);
}

/* Respect users who ask for reduced motion (WCAG 2.1). */
@media (prefers-reduced-motion: reduce) {
    :root {
        --st-transition: 0ms;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------------------------------------------------------------------------
   Bootstrap variable overrides — one place, so components inherit the brand.
   --------------------------------------------------------------------------- */
:root {
    --bs-primary: var(--st-navy);
    --bs-primary-rgb: 10, 23, 45;
    --bs-body-bg: var(--st-bg);
    --bs-body-color: var(--st-text);
    --bs-body-font-family: var(--st-font-body);
    --bs-border-color: var(--st-border);
    --bs-border-radius: var(--st-radius);
    --bs-link-color: var(--st-accent);
    --bs-link-hover-color: var(--st-accent-hover);
    /* Feeds Bootstrap's .text-muted, form-text, etc. — Bootstrap ships its own dark value for
       this only under [data-bs-theme="dark"], which the app never sets, so without this override
       muted text stays fixed-dark-gray and disappears against our dark surface. */
    --bs-secondary-color: var(--st-text-muted);
    /* Same trap, one step further in: .table sets its cell colour from --bs-table-color, which
       resolves to --bs-emphasis-color — black by default, and again only themed by Bootstrap under
       [data-bs-theme="dark"]. Any table carrying Bootstrap's .table alongside our .st-table (the
       import histories do; the shared grid does not) therefore drew unmuted cells in flat black.
       Pointing it at --st-text fixes every such table at once, in both themes. */
    --bs-emphasis-color: var(--st-text);
    /* The last unmapped status colour. Bootstrap's .text-danger resolves through --bs-danger-rgb,
       not --bs-danger, and ships a fixed #dc3545 that is themed only under [data-bs-theme="dark"] —
       which this app never sets. So every .text-danger in the app (the back-order write-off link,
       destructive-action labels) drew in Bootstrap red on both themes, ignoring --st-danger
       entirely. The rgb triple has to be spelled out because Bootstrap composes it with
       --bs-text-opacity inside rgba(), where var(--st-danger) cannot be substituted. */
    --bs-danger: var(--st-danger);
    --bs-danger-rgb: 161, 51, 44;
}

/* Higher specificity than the :root above, so this wins regardless of block order. */
:root[data-theme="dark"] {
    --bs-danger-rgb: 242, 163, 156;
}

/* ---------------------------------------------------------------------------
   Base
   --------------------------------------------------------------------------- */
body {
    font-family: var(--st-font-body);
    font-size: 0.9375rem;   /* 15px — dense enough for data screens, still readable */
    line-height: 1.5;
    color: var(--st-text);
    background-color: var(--st-bg);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--st-font-heading);
    color: var(--st-accent);
    font-weight: 600;
    letter-spacing: 0.01em;
}

h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.0625rem; }

a {
    color: var(--st-accent);
    text-decoration-color: var(--st-gold-soft);
    text-underline-offset: 2px;
}

a:hover {
    color: var(--st-accent-hover);
    text-decoration-color: var(--st-gold);
}

/* Focus must always be visible — keyboard users navigate this app all day. */
:focus-visible {
    outline: 2px solid var(--st-gold);
    outline-offset: 2px;
    border-radius: 2px;
}

/* ---------------------------------------------------------------------------
   Numeric alignment: currency and quantities right-align with tabular figures.
   --------------------------------------------------------------------------- */
.st-numeric,
td.st-numeric,
th.st-numeric {
    font-family: var(--st-font-numeric);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.st-total {
    font-weight: 600;
    border-top: 2px solid var(--st-border-strong);
}

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */
.btn {
    --bs-btn-border-radius: var(--st-radius);
    font-weight: 500;
    transition: background-color var(--st-transition), border-color var(--st-transition);
}

.btn-primary {
    --bs-btn-bg: var(--st-navy);
    --bs-btn-border-color: var(--st-navy);
    --bs-btn-hover-bg: var(--st-navy-600);
    --bs-btn-hover-border-color: var(--st-navy-600);
    --bs-btn-active-bg: var(--st-navy-600);
    --bs-btn-disabled-bg: var(--st-navy-300);
    --bs-btn-disabled-border-color: var(--st-navy-300);
}

/* Dark theme inverts the primary button: the light accent becomes the fill and navy becomes the
   label, so the app's one primary action per screen stays the most prominent thing on the page
   instead of dissolving into the background. Scoped to .btn-primary rather than redefining
   --st-navy, because that swatch is also the fill for badges and pills that sit on light rows. */
:root[data-theme="dark"] .btn-primary {
    --bs-btn-bg: var(--st-accent);
    --bs-btn-border-color: var(--st-accent);
    --bs-btn-color: var(--st-navy);
    --bs-btn-hover-bg: var(--st-accent-hover);
    --bs-btn-hover-border-color: var(--st-accent-hover);
    --bs-btn-hover-color: var(--st-navy);
    --bs-btn-active-bg: var(--st-accent-hover);
    --bs-btn-active-border-color: var(--st-accent-hover);
    --bs-btn-active-color: var(--st-navy);
    --bs-btn-disabled-bg: var(--st-navy-300);
    --bs-btn-disabled-border-color: var(--st-navy-300);
    --bs-btn-disabled-color: var(--st-navy);
}

.btn-outline-primary {
    --bs-btn-color: var(--st-accent);
    --bs-btn-border-color: var(--st-border-strong);
    --bs-btn-hover-bg: var(--st-pearl-light);
    --bs-btn-hover-border-color: var(--st-accent);
    --bs-btn-hover-color: var(--st-accent);
}

/* The quiet button: Cancel, Back, the grid's own toolbar controls, the pager arrows. Bootstrap
   colours both its text and border with a fixed #6c757d grey, which owns neither the brand palette
   in light mode nor enough contrast in dark, so it is set from our tokens here. Neutral text
   rather than --st-accent keeps the three tiers apart: filled primary, accent outline, then this. */
.btn-outline-secondary {
    --bs-btn-color: var(--st-text);
    --bs-btn-border-color: var(--st-border-strong);
    --bs-btn-hover-bg: var(--st-bg-subtle);
    --bs-btn-hover-border-color: var(--st-accent);
    --bs-btn-hover-color: var(--st-accent);
    --bs-btn-active-bg: var(--st-bg-subtle);
    --bs-btn-active-border-color: var(--st-accent);
    --bs-btn-active-color: var(--st-accent);
    /* Disabled pager arrows still have to read as arrows, just plainly unavailable. */
    --bs-btn-disabled-color: var(--st-text-muted);
    --bs-btn-disabled-border-color: var(--st-border);
}

/* A button that is working says so, and disables itself — the page never freezes. */
.btn[data-loading="true"] {
    pointer-events: none;
    opacity: 0.75;
}

.btn[data-loading="true"] .st-btn-spinner {
    display: inline-block;
}

.st-btn-spinner {
    display: none;
    width: 0.875em;
    height: 0.875em;
    margin-right: 0.4em;
    border: 2px solid currentcolor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: st-spin 0.6s linear infinite;
    vertical-align: -0.125em;
}

@keyframes st-spin {
    to { transform: rotate(360deg); }
}

/* ---------------------------------------------------------------------------
   Status badges — colour is never the only signal (colour-blind safe).
   --------------------------------------------------------------------------- */
.st-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    padding: 0.15em 0.55em;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
}

.st-badge-success { color: var(--st-success); background: var(--st-success-bg); }
.st-badge-warning { color: var(--st-warning); background: var(--st-warning-bg); }
.st-badge-danger  { color: var(--st-danger);  background: var(--st-danger-bg); }
.st-badge-neutral { color: var(--st-cloud);   background: var(--st-pearl-light); }
.st-badge-info    { color: var(--st-info);    background: var(--st-info-bg); }

/* The chart colour a currency wears, picked on the exchange-rate screen. A named list with the
   colour shown beside it: nine bare swatches in a table cell were unreadable - nobody could tell
   what the row of dots was for - and a name is also the only part of this control that works for a
   reader who cannot separate two of the hues. The swatch is what stops the name being a guess, so
   both are present and neither carries the choice alone. */
.st-colour-pick {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.st-colour-pick select { min-width: 8.5rem; }

.st-colour-chip {
    width: 1.15rem;
    height: 1.15rem;
    flex: none;
    border-radius: 0.25rem;
    border: 1px solid var(--st-border-strong);
}

.st-colour-pick select:disabled + .st-colour-chip,
.st-colour-chip.is-disabled { opacity: 0.55; }
