/* File: shared/css/ecvalla-theme.css
 *
 * The ECVALLA design-system layer: semantic tokens, the dark theme's reach into the shared
 * chrome, and the contrast floor.
 *
 * HOW THEMING WORKS HERE
 *
 * Every component stylesheet in this system — the 350KB of legacy screens included — already
 * paints from CSS variables (--ecv-* primitives and legacy aliases like --border-color and
 * --text-color), and shared/css/ecvalla-identity.css already defines a complete dark value
 * set for all of them under `.dark-theme`. So the theme system is not a re-skin of every
 * component: it is (1) a reliable way to get that class onto <html> before first paint,
 * owned by shared/js/theme.js, and (2) this file, which adds what the token remap alone
 * could not reach — the portal chrome, the auth surfaces, scrollbars, and a semantic
 * vocabulary so new work stops hard-coding hex values.
 *
 * Load order: after ecvalla-identity.css (whose primitives these tokens alias) and after
 * portal-chrome.css (whose chrome this file themes).
 *
 * THE SEMANTIC LAYER
 *
 * Components should name what a colour is FOR, not what it is. These aliases resolve to the
 * primitives, so they follow the theme automatically and a future palette change touches one
 * file. `--sys-*` because unprefixed names like --border are one typo from a collision.
 */

:root {
    /* Surfaces */
    --sys-surface-page: var(--ecv-canvas, #f5f5f3);
    --sys-surface-raised: var(--ecv-paper, #ffffff);
    --sys-surface-secondary: var(--ecv-soft, #eff0ee);
    /* These two were being used by components and had never been defined here, so every
     * `var(--sys-surface-sunken, #f4f4f2)` fell through to its literal light fallback — a white
     * plate on an ink dialog, with light text on it. Measured at 1.1:1 before this line existed.
     * A missing alias fails silently and looks like a component bug, which is exactly why the
     * fix belongs in this file rather than in each caller. */
    --sys-surface: var(--ecv-paper, #ffffff);
    --sys-surface-sunken: var(--ecv-soft, #eff0ee);
    --sys-surface-hover: var(--ecv-soft, #eff0ee);
    --sys-surface-selected: var(--primary-light-transparent, rgba(23, 25, 27, .10));
    --sys-surface-sidebar: var(--rail-bg, #16181a);
    --sys-surface-nav: var(--topbar-bg, rgba(255, 255, 255, .86));

    /* Text */
    --sys-text-primary: var(--text-color, #17191b);
    --sys-text-secondary: var(--text-light, #73787b);
    --sys-text-muted: var(--text-muted, #6c7174);
    --sys-text-inverse: #ffffff;

    /* Structure */
    --sys-border: var(--border-color, #e5e6e4);
    --sys-border-strong: var(--ecv-muted, #73787b);
    /* One step firmer than the resting line — for hover, where the edge should tighten
       rather than announce itself. Reaching for --sys-border-strong or --ecv-ink here is
       what produced hard rings around hovered cards. */
    --sys-border-hover: #cfd1ce;
    --sys-focus-ring: var(--ecv-focus-ring, 0 0 0 4px rgba(23, 25, 27, .16));

    /* Actions */
    --sys-action-primary: var(--ecv-ink, #17191b);
    --sys-action-primary-text: var(--ecv-paper, #ffffff);
    --sys-action-secondary: var(--ecv-soft, #eff0ee);
    --sys-action-destructive: var(--danger-color, #ad291f);
    --sys-action-destructive-text: #ffffff;
    /* Warning as a PLATE, paired with its text. --ecv-amber is the text tint for ink
       surfaces (#e9c46a in dark), so using it as a button background gave white-on-gold at
       1.67:1. Same trap as --ecv-red; a plate needs its own value in each theme. */
    --sys-action-warning: #8a5d00;
    --sys-action-warning-text: #ffffff;
    --sys-state-success-plate: #13813b;

    /* States. Red is destruction and serious error only — never decoration. */
    --sys-state-success: var(--success-color, #13813b);
    --sys-state-warning: var(--warning-color, #8a6a12);
    --sys-state-error: var(--danger-color, #ad291f);
    --sys-state-info: var(--info-color, #4c5a60);

    /* Depth */
    --sys-overlay: rgba(17, 19, 21, .55);
    --sys-shadow-raise: var(--ecv-shadow-raise, 0 1px 2px rgba(23, 25, 27, .06), 0 14px 34px rgba(23, 25, 27, .08));
    --sys-shadow-float: var(--ecv-shadow-float, 0 22px 56px rgba(23, 25, 27, .16));

    /* Skeletons */
    --sys-skeleton-base: #ececea;
    --sys-skeleton-sheen: #f6f6f4;
}

:root.dark-theme,
:root[data-theme="dark"] {
    --sys-surface-selected: rgba(242, 242, 240, .12);
    --sys-text-inverse: #17191b;
    --sys-overlay: rgba(0, 0, 0, .66);
    --sys-skeleton-base: #202325;
    --sys-skeleton-sheen: #2a2d2f;
}

/* ------------------------------------------------------------------ *
 * Universal sign-in action
 *
 * Each public portal originally painted its hero button independently. In dark mode the
 * action plate inverts to paper, but a few portal rules kept a literal white label; another
 * lowered the entire disabled button's opacity. Both paths can collapse contrast. This
 * semantic pair is deliberately explicit and shared by Support, Department, Administration
 * and the public top bar. The resting pairs exceed WCAG AA with substantial margin.
 * ------------------------------------------------------------------ */

:root {
    --sys-signin-bg: #17191b;
    --sys-signin-text: #ffffff;
    --sys-signin-border: #17191b;
    --sys-signin-hover: #2b2e30;
    --sys-signin-focus: #17191b;
    --sys-signin-disabled-bg: #4c5256;
    --sys-signin-disabled-text: #ffffff;
}

:root.dark-theme,
:root[data-theme="dark"],
html.dark-theme,
[data-theme="dark"],
body.dark-theme {
    --sys-signin-bg: #ffffff;
    --sys-signin-text: #17191b;
    --sys-signin-border: #ffffff;
    --sys-signin-hover: #e5e6e4;
    --sys-signin-focus: #ffffff;
    --sys-signin-disabled-bg: #d5d6d4;
    --sys-signin-disabled-text: #17191b;
}

.uhero-btn:not(.is-ghost),
.ahero-btn:not(.is-ghost),
.dhero-btn:not(.is-ghost),
.pbar-action {
    background-color: var(--sys-signin-bg, #17191b) !important;
    border-color: var(--sys-signin-border, #17191b) !important;
    color: var(--sys-signin-text, #ffffff) !important;
}

.uhero-btn:not(.is-ghost) i,
.uhero-btn:not(.is-ghost) span,
.ahero-btn:not(.is-ghost) i,
.ahero-btn:not(.is-ghost) span,
.dhero-btn:not(.is-ghost) i,
.dhero-btn:not(.is-ghost) span,
.pbar-action i,
.pbar-action span {
    color: var(--sys-signin-text, #ffffff) !important;
}

.uhero-btn:not(.is-ghost):hover,
.ahero-btn:not(.is-ghost):hover,
.dhero-btn:not(.is-ghost):hover,
.pbar-action:hover {
    background-color: var(--sys-signin-hover, #2b2e30) !important;
    color: var(--sys-signin-text, #ffffff) !important;
}

.uhero-btn:focus-visible,
.ahero-btn:focus-visible,
.dhero-btn:focus-visible,
.pbar-action:focus-visible {
    outline: 2px solid var(--sys-signin-focus, #17191b) !important;
    outline-offset: 3px;
}

/* Explicit Dark Theme Overrides for all portals to prevent white-on-white text */
html.dark-theme .uhero-btn:not(.is-ghost),
[data-theme="dark"] .uhero-btn:not(.is-ghost),
body.dark-theme .uhero-btn:not(.is-ghost),
html.dark-theme .ahero-btn:not(.is-ghost),
[data-theme="dark"] .ahero-btn:not(.is-ghost),
body.dark-theme .ahero-btn:not(.is-ghost),
html.dark-theme .dhero-btn:not(.is-ghost),
[data-theme="dark"] .dhero-btn:not(.is-ghost),
body.dark-theme .dhero-btn:not(.is-ghost),
html.dark-theme .pbar-action,
[data-theme="dark"] .pbar-action,
body.dark-theme .pbar-action {
    background-color: #ffffff !important;
    border-color: #ffffff !important;
    color: #17191b !important;
}

html.dark-theme .uhero-btn:not(.is-ghost) i,
html.dark-theme .uhero-btn:not(.is-ghost) span,
[data-theme="dark"] .uhero-btn:not(.is-ghost) i,
[data-theme="dark"] .uhero-btn:not(.is-ghost) span,
body.dark-theme .uhero-btn:not(.is-ghost) i,
body.dark-theme .uhero-btn:not(.is-ghost) span,
html.dark-theme .ahero-btn:not(.is-ghost) i,
html.dark-theme .ahero-btn:not(.is-ghost) span,
[data-theme="dark"] .ahero-btn:not(.is-ghost) i,
[data-theme="dark"] .ahero-btn:not(.is-ghost) span,
body.dark-theme .ahero-btn:not(.is-ghost) i,
body.dark-theme .ahero-btn:not(.is-ghost) span,
html.dark-theme .dhero-btn:not(.is-ghost) i,
html.dark-theme .dhero-btn:not(.is-ghost) span,
[data-theme="dark"] .dhero-btn:not(.is-ghost) i,
[data-theme="dark"] .dhero-btn:not(.is-ghost) span,
body.dark-theme .dhero-btn:not(.is-ghost) i,
body.dark-theme .dhero-btn:not(.is-ghost) span,
html.dark-theme .pbar-action i,
html.dark-theme .pbar-action span,
[data-theme="dark"] .pbar-action i,
[data-theme="dark"] .pbar-action span,
body.dark-theme .pbar-action i,
body.dark-theme .pbar-action span {
    color: #17191b !important;
}

html.dark-theme .uhero-btn:not(.is-ghost):hover,
[data-theme="dark"] .uhero-btn:not(.is-ghost):hover,
body.dark-theme .uhero-btn:not(.is-ghost):hover,
html.dark-theme .ahero-btn:not(.is-ghost):hover,
[data-theme="dark"] .ahero-btn:not(.is-ghost):hover,
body.dark-theme .ahero-btn:not(.is-ghost):hover,
html.dark-theme .dhero-btn:not(.is-ghost):hover,
[data-theme="dark"] .dhero-btn:not(.is-ghost):hover,
body.dark-theme .dhero-btn:not(.is-ghost):hover,
html.dark-theme .pbar-action:hover,
[data-theme="dark"] .pbar-action:hover,
body.dark-theme .pbar-action:hover {
    background-color: #e5e6e4 !important;
    color: #17191b !important;
}

.uhero-btn:not(.is-ghost):disabled,
.ahero-btn:not(.is-ghost):disabled,
.dhero-btn:not(.is-ghost):disabled,
.pbar-action:disabled {
    background-color: var(--sys-signin-disabled-bg, #4c5256) !important;
    border-color: var(--sys-signin-disabled-bg, #4c5256) !important;
    color: var(--sys-signin-disabled-text, #ffffff) !important;
    opacity: 1;
}

.uhero-btn:not(.is-ghost):disabled i,
.uhero-btn:not(.is-ghost):disabled span,
.ahero-btn:not(.is-ghost):disabled i,
.ahero-btn:not(.is-ghost):disabled span,
.dhero-btn:not(.is-ghost):disabled i,
.dhero-btn:not(.is-ghost):disabled span,
.pbar-action:disabled i,
.pbar-action:disabled span {
    color: var(--sys-signin-disabled-text, #ffffff) !important;
}

/* ------------------------------------------------------------------ *
 * Contrast floor — light
 *
 * The one light-mode value that failed WCAG AA: --text-muted #8b9093 on white is 3.4:1,
 * under the 4.5:1 required for normal text, and it is used for helper text people actually
 * need to read. Raised to a value that clears the bar with margin. Everything else in the
 * light palette already passes (verified against white and the warm canvas).
 * ------------------------------------------------------------------ */

:root {
    --text-muted: #6c7174;   /* 5.1:1 on #ffffff, 4.7:1 on #f5f5f3 */
}

/* ------------------------------------------------------------------ *
 * Contrast floor — the rail
 *
 * The rail is ink in both themes, so its floor is theme-independent. The faint tier carries
 * the row subtitles and group headings — real reading text, not decoration — and at its old
 * 34% alpha it composited to roughly 3.2:1 against the rail ink. Raised to 52%, which
 * composites to ~5.6:1 and still reads as clearly subordinate to the 62% resting tier.
 * ------------------------------------------------------------------ */

:root,
:root.dark-theme,
:root[data-theme="dark"] {
    /* Lifted again 2026-08-22: at .52 the row subtitles still read murky on the ink rail
     * in practice. .6 composites to ~6.7:1 and stays clearly subordinate to the .74
     * resting tier and the pure-white active tier. */
    --rail-text-faint: rgba(255, 255, 255, .6);
}

/* ------------------------------------------------------------------ *
 * Dark theme — the chrome
 *
 * The rail is already ink and needs nothing. The top bar, the account card and its panel
 * were defined against light surfaces; these are their dark values. Not an inversion:
 * the bar sits a step above the page (lighter, not darker), which is how elevation reads
 * on dark surfaces.
 * ------------------------------------------------------------------ */

:root.dark-theme,
:root[data-theme="dark"] {
    --topbar-bg: rgba(24, 26, 28, .88);
    --topbar-edge: #2b2e30;
    --topbar-text: #e9eae8;
    --topbar-muted: #9aa0a3;

    /* The rail's edge needs a touch more presence when the page beside it is also dark. */
    --rail-edge: rgba(255, 255, 255, .12);
}

html.dark-theme .pacct-card,
[data-theme="dark"] .pacct-card,
html.dark-theme .ptopbar-btn,
[data-theme="dark"] .ptopbar-btn {
    background: #1c1f21;
    border-color: #2b2e30;
    color: #e9eae8;
}

html.dark-theme .pacct-card:hover,
[data-theme="dark"] .pacct-card:hover,
html.dark-theme .ptopbar-btn:hover,
[data-theme="dark"] .ptopbar-btn:hover {
    background: #24272a;
    border-color: #3a3e41;
}

html.dark-theme .pacct-avatar,
[data-theme="dark"] .pacct-avatar {
    background: #f2f2f0;
    color: #17191b;
}

html.dark-theme .pacct-panel,
[data-theme="dark"] .pacct-panel {
    background: #1c1f21;
    border-color: #2b2e30;
    box-shadow: 0 20px 48px rgba(0, 0, 0, .55);
}

html.dark-theme .pacct-panel a,
[data-theme="dark"] .pacct-panel a,
html.dark-theme .pacct-panel .pacct-action,
[data-theme="dark"] .pacct-panel .pacct-action {
    color: #e9eae8;
}

html.dark-theme .pacct-panel a:hover,
[data-theme="dark"] .pacct-panel a:hover,
html.dark-theme .pacct-panel .pacct-action:hover,
[data-theme="dark"] .pacct-panel .pacct-action:hover {
    background: #24272a;
}

html.dark-theme .pacct-panel-head,
[data-theme="dark"] .pacct-panel-head,
html.dark-theme .pacct-divider,
[data-theme="dark"] .pacct-divider {
    border-color: #2b2e30;
    background-color: transparent;
}

html.dark-theme .pacct-divider,
[data-theme="dark"] .pacct-divider {
    background: #2b2e30;
}

html.dark-theme .pacct-role,
[data-theme="dark"] .pacct-role {
    background: #24272a;
    color: #e9eae8;
}

/* Focus rings on the dark bar must be light to be seen. */
html.dark-theme .pacct-card:focus-visible,
[data-theme="dark"] .pacct-card:focus-visible,
html.dark-theme .ptopbar-btn:focus-visible,
[data-theme="dark"] .ptopbar-btn:focus-visible {
    outline-color: #f2f2f0;
}

/* ------------------------------------------------------------------ *
 * Dark theme — public bar and auth surfaces
 *
 * The ink variants (.pbar.is-dark, the overlay) are theme-independent by design. The paper
 * variants follow the tokens; what needs stating is the pieces that carried literal colours.
 * ------------------------------------------------------------------ */

html.dark-theme .pbar:not(.is-dark),
[data-theme="dark"] .pbar:not(.is-dark) {
    background: #181a1c;
    border-bottom-color: #2b2e30;
    color: #e9eae8;
}

html.dark-theme .auth-ms-btn,
[data-theme="dark"] .auth-ms-btn {
    /* Inverted plate, as on the ink login pages: white button, ink label. The Microsoft
     * squares are their brand mark and never recolour. */
    background: #f2f2f0;
    color: #17191b;
}

html.dark-theme .auth-ms-btn:hover:not(:disabled),
[data-theme="dark"] .auth-ms-btn:hover:not(:disabled) {
    background: #ffffff;
}

html.dark-theme .auth-error,
[data-theme="dark"] .auth-error {
    background: rgba(173, 41, 31, .2);
    border-color: rgba(239, 139, 128, .38);
    color: #f0a097;
}

html.dark-theme .auth-error::before,
[data-theme="dark"] .auth-error::before {
    background: #f0a097;
    color: #5c130d;
}

/* ------------------------------------------------------------------ *
 * Skeletons and scrollbars, both themes
 * ------------------------------------------------------------------ */

.up-skeleton,
.dover-skeleton {
    background: linear-gradient(90deg,
        var(--sys-skeleton-base) 25%, var(--sys-skeleton-sheen) 37%, var(--sys-skeleton-base) 63%);
    background-size: 400% 100%;
}

/* The content column's scrollbar follows the theme; the rail already styles its own. */
:root.dark-theme,
:root[data-theme="dark"] {
    scrollbar-color: #3a3e41 #16181a;
}

/* ------------------------------------------------------------------ *
 * Status is never colour alone
 *
 * The pills carry translated text and the alerts carry icons, so the information survives
 * monochrome. This rule guards the one place a bare dot appeared.
 * ------------------------------------------------------------------ */

.prail-badge::after {
    content: "";
    /* The badge shows a count — text, not colour — so nothing extra is needed; kept as an
     * anchor for any future dot-style indicator, which must gain text or an icon. */
}

@media (prefers-reduced-motion: reduce) {
    .up-skeleton,
    .dover-skeleton {
        animation: none;
    }
}

/* ------------------------------------------------------------------ *
 * Dark theme — the tokens the original dark block missed
 *
 * The pastel wash surfaces (--ecv-red-wash behind the admin UNASSIGNED tile, --ecv-green-wash
 * behind Pending Actions / "all caught up") and their hairlines had no dark values, so light
 * pink and mint cards survived into dark mode carrying near-white text — the two unreadable
 * patches in the screenshots. A wash on ink is a low-alpha tint of the hue, not a pastel; the
 * paired text colours are the lifted variants so every wash/text pairing clears 4.5:1.
 * ------------------------------------------------------------------ */

:root.dark-theme,
:root[data-theme="dark"] {
    --ecv-green: #6fcf95;                       /* 7.8:1 on the green wash below */
    --ecv-green-wash: rgba(19, 129, 59, .16);
    --ecv-red: #f0968c;                         /* 6.4:1 on the red wash below */
    --ecv-red-wash: rgba(173, 41, 31, .16);
    --ecv-red-line: rgba(240, 150, 140, .35);
    --ecv-green-line: rgba(111, 207, 149, .35);
    --ecv-amber: #e9c46a;                       /* lifted for the amber wash below */
    --ecv-amber-wash: rgba(176, 122, 12, .18);
    --ecv-amber-line: rgba(233, 196, 106, .35);
    /* The destructive plate stays saturated in dark so white text still clears 4.5:1 on it.
       --ecv-red above is the TEXT tint for ink surfaces and must not be used as a plate. */
    --sys-border-hover: #3f4448;
    --sys-action-warning: #8c5f04;
    --sys-action-warning-text: #ffffff;
    --sys-state-success-plate: #1a7f43;
    --sys-action-destructive: #c0392c;
    --sys-action-destructive-text: #ffffff;
}

/* ------------------------------------------------------------------ *
 * Dark theme — the grey text lift
 *
 * On ink surfaces the original secondary greys sat too close to the background: readable in
 * a contrast checker, murky on a real panel. Each tier moves up while the hierarchy stays
 * legible — primary is still clearly above secondary, secondary above muted — and every tier
 * now clears AA on the darkest surface it appears on (#111315).
 *
 *   secondary  #9aa0a3 -> #b4babd   (8.9:1 on #111315)
 *   muted      #7f8588 -> #9aa0a1   (6.4:1)
 *   disabled stays distinguishable at the old muted value rather than vanishing.
 * ------------------------------------------------------------------ */

:root.dark-theme,
:root[data-theme="dark"] {
    --text-light: #bcc2c5;
    --secondary-color: #bcc2c5;
    --ecv-muted: #b0b6b9;
    --text-muted: #a6acaf;
    --topbar-muted: #b0b6b9;
    --info-color: #b8c7cd;
}

/* ------------------------------------------------------------------ *
 * Dark theme — the ECVALLA mark
 *
 * The wordmark asset is black artwork on transparency. Anywhere it sits on a surface that
 * turns ink in dark mode — the content-loading veil, the sign-in card, the paper public
 * bar — it would vanish into its background, so those placements invert in dark. The rail's
 * mark is already inverted in both themes (ink rail) and is excluded so it cannot
 * double-flip; `screen` blending keeps the inversion clean on tinted surfaces.
 * ------------------------------------------------------------------ */

html.dark-theme .up-loading-mark,
[data-theme="dark"] .up-loading-mark,
html.dark-theme .ulogin-mark,
[data-theme="dark"] .ulogin-mark,
html.dark-theme .pbar-mark:not(.is-inverted),
[data-theme="dark"] .pbar-mark:not(.is-inverted) {
    filter: invert(1);
    mix-blend-mode: screen;
}

/* ------------------------------------------------------------------ *
 * Dark theme — ink plates that carried literal white text
 *
 * .up-toast, .up-fab, .up-msg-avatar and the hero button paint an --ecv-ink plate with
 * hard-coded #fff text. In dark the plate goes near-white, so the label must go ink with it.
 * ------------------------------------------------------------------ */

html.dark-theme .up-toast,
[data-theme="dark"] .up-toast,
html.dark-theme .up-fab,
[data-theme="dark"] .up-fab {
    color: var(--sys-action-primary-text, #17191b);
}


/* ------------------------------------------------------------------ *
 * A theme change is not an animation
 *
 * shared/js/theme.js stamps this for one frame while it flips the palette. Without it, every
 * component that transitions background-color for hover also animates it across a theme
 * change — while colour and border, which nobody transitions, snap at once. On an inverting
 * control (ink plate + paper label in one theme, the reverse in the other) those in-between
 * frames are genuinely unreadable.
 *
 * !important and the universal selector are both warranted: this must beat every component's
 * own transition, and it is live for a single frame.
 * ------------------------------------------------------------------ */

html[data-theme-switching] *,
html[data-theme-switching] *::before,
html[data-theme-switching] *::after {
    transition: none !important;
    animation-duration: 0s !important;
    animation-delay: 0s !important;
}

/* ------------------------------------------------------------------ *
 * Form fields: background and text from ONE source
 *
 * Two textareas measured 1.01:1 and 1.06:1 — dark text on a dark plate in light mode, and light
 * text on a light plate in dark mode. Neither was a wrong colour on its own. The cause was
 * mixing a PORTAL-scoped surface token (which follows the portal's ink identity) with a
 * THEME-scoped text token (which follows light/dark). When those two disagree, the field
 * disappears — and it disappears in whichever theme nobody happened to be testing.
 *
 * A field's plate and its ink are one decision, so they come from one pair. Any field that uses
 * both of these is readable in every combination of portal and theme, which is not something a
 * component author should have to reason about.
 * ------------------------------------------------------------------ */

:root {
    --sys-field-bg: #ffffff;
    --sys-field-text: #17191b;
    --sys-field-border: #e5e6e4;
    --sys-field-placeholder: #6c7174;
}

:root.dark-theme,
:root[data-theme="dark"] {
    --sys-field-bg: #1c1f21;
    --sys-field-text: #e9eae8;
    --sys-field-border: #2b2e30;
    --sys-field-placeholder: #bcc2c5;
}
