/* ─────────────────────────────────────────────────────────
   Promora — self-hosted typefaces
   Plus Jakarta Sans (display) + Inter (UI). Both OFL 1.1.
   Self-hosted so customer deployments need no outbound
   internet and there is no flash of fallback text.
   ───────────────────────────────────────────────────────── */
@font-face {
    font-family: 'Plus Jakarta Sans';
    font-style: normal;
    font-weight: 500 800;
    font-display: swap;
    src: url('fonts/jakarta-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Plus Jakarta Sans';
    font-style: normal;
    font-weight: 500 800;
    font-display: swap;
    src: url('fonts/jakarta-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ─────────────────────────────────────────────────────────
   Light theme — "paper"
   A warm off-white canvas rather than the cold blue-grey
   every other B2B dashboard uses. Lifted wholesale from
   Trophyst, deliberately: the two products are siblings and
   should read as one family. Every surface, text, border,
   status and calendar value below is Trophyst's, unchanged.

   The one difference is the accent. Trophyst's is orange
   (#e8681f); Promora's is a steel blue — blue as the main
   tone, pulled well down towards grey so it sits on the warm
   canvas without shouting. That single token is what tells
   the two apart at a glance.
   ───────────────────────────────────────────────────────── */
:root {
    /* ── Typefaces ── */
    --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-display: 'Plus Jakarta Sans', 'Inter', -apple-system, 'Segoe UI', sans-serif;

    /* ── Surfaces ──
       Cards are a warm off-white rather than pure white. Pure #fff against the
       paper canvas separated them far more strongly than the dark theme does,
       which made every card read as a hard cut-out; this keeps them clearly
       lifted off the page but part of the same material. */
    --bg-body: #faf7f2;
    --bg-white: #fdfbf7;
    --bg-card: #fdfbf7;
    --bg-card-hover: #f6f1ea;
    --bg-sidebar: #faf7f2;      /* blends into the canvas */
    --bg-elevated: #fdfbf7;     /* modals, popovers, raised cards */
    --bg-subtle: #f3ece3;       /* subtle fills, tab badges, dividers bg */

    /* ── Text ── */
    --text-primary: #2b2521;
    --text-secondary: #6c6259;
    --text-muted: #9a9088;
    --text-strong: #17130f;     /* headlines, big numbers / KPI values */
    --text-on-accent: #ffffff;

    /* ── Accent — taken from the logo ──
       Trophyst's orange, swapped for the blue the Promora mark is actually made of: #0666F1 is
       the dominant colour of the ring's lower half, sampled from the artwork rather than picked
       to sit near it. The lighter passes of the same ring, #278EFB and #60B4FB, carry the
       gradient and the dark theme, so every blue in the interface comes off the logo. */
    --accent: #0666F1;
    --accent-hover: #0552c7;
    --accent-light: rgba(6, 102, 241, 0.10);

    /* ── Borders ── */
    --border-color: #e9e1d6;
    --border-subtle: #f2ebe1;

    /* ── Paper wash ──
       The warm bloom behind the top-left of a hero. In Trophyst this is mixed from the accent,
       which is orange there; here the accent is a steel blue and a blue bloom would read as a
       cold spill on warm paper rather than as light falling on it. So it gets a token of its
       own, holding Trophyst's orange — the glow is decoration and stays warm, while the blue
       stays a signal and is spent only on things you can act on. */
    --wash-tint: #e8681f;

    /* ── Status (warmed slightly so they sit on paper, not on blue-grey) ── */
    --success: #2e9e5b;
    --warning: #e0930f;
    --danger: #dc4c3e;
    --info: #2f7fd1;

    /* Text-weight status colours, used for tinted pills and inline status text.
       Darker than the fills above because they sit on a pale tint. */
    --status-success: #1f7c44;
    --status-warning: #a86c07;
    --status-danger: #bf3729;
    --status-info: #2264ab;
    --status-neutral: #6c6259;

    /* ── Gradient pairs (KPI / metric cards) ── */
    --grad-accent: linear-gradient(135deg, #278efb, #0666f1);
    --grad-success: linear-gradient(135deg, #27ae60, #1e8449);
    --grad-info: linear-gradient(135deg, #3498db, #2980b9);
    --grad-secondary: linear-gradient(135deg, #6c757d, #5a6268);
    --grad-blue: linear-gradient(135deg, #3a7bd5, #2b5ea7);
    --grad-teal: linear-gradient(135deg, #1abc9c, #148f77);
    --grad-purple: linear-gradient(135deg, #f0a35c, #d35400);

    /* ── Radius (generous, matching the reference design) ── */
    --border-radius: 14px;
    --border-radius-sm: 9px;

    /* ── Shadows — barely there; hairline borders do the separating ── */
    --shadow-sm: 0 1px 2px rgba(40, 28, 16, 0.04);
    --shadow-md: 0 6px 20px rgba(40, 28, 16, 0.07);

    /* ── Density scale ── */
    --font-size-base: 14px;
    --line-height-base: 1.45;
    --space-card: 0.85rem;      /* default card body padding */
    --space-card-sm: 0.6rem;
    --scrollbar-thumb: #d8cec1;
    --table-stripe: rgba(90, 60, 25, 0.022);
    --nav-hover-bg: rgba(90, 60, 25, 0.05);

    /* Calendar quarter tints (Q1 yellow, Q2 green, Q3 blue, Q4 purple) */
    --cal-q1-bg: #fff5eb; --cal-q1-fg: #7a3e0c;
    --cal-q2-bg: #ecf6f1; --cal-q2-fg: #1d6a3f;
    --cal-q3-bg: #eef2f9; --cal-q3-fg: #2a4a7f;
    --cal-q4-bg: #f6efff; --cal-q4-fg: #5e3a8f;

    /* Column bands for grouped tables — the calendar's quarter tints, with two
       more in the same key so a six-measure table has one each. A band colours
       its group heading, its column headings and the cells under them alike, so
       a wide table reads as blocks rather than a wall of numbers. */
    --band-1-fg: var(--cal-q1-fg);
    --band-2-fg: var(--cal-q2-fg);
    --band-3-fg: var(--cal-q3-fg);
    --band-4-fg: var(--cal-q4-fg);
    --band-5-fg: #8f3054;
    --band-6-fg: #1f6570;

    /* Mixed from each band's own ink rather than picked separately: the calendar's
       block tints wash out at table density, and a stronger tint of the same hue
       keeps the two screens recognisably the same family. */
    --band-1-bg: color-mix(in srgb, var(--band-1-fg) 11%, var(--bg-card));
    --band-2-bg: color-mix(in srgb, var(--band-2-fg) 11%, var(--bg-card));
    --band-3-bg: color-mix(in srgb, var(--band-3-fg) 11%, var(--bg-card));
    --band-4-bg: color-mix(in srgb, var(--band-4-fg) 11%, var(--bg-card));
    --band-5-bg: color-mix(in srgb, var(--band-5-fg) 11%, var(--bg-card));
    --band-6-bg: color-mix(in srgb, var(--band-6-fg) 11%, var(--bg-card));
}

/* ── Dark theme — "ember": a warm dark, not the usual blue-black ── */
[data-theme="dark"] {
    /* Surfaces */
    --bg-body: #14110d;
    --bg-white: #1d1915;
    --bg-card: #1d1915;
    --bg-card-hover: #272019;
    --bg-sidebar: #14110d;      /* same as the body, as in light — the arc divides */
    --bg-elevated: #272019;
    --bg-subtle: #272019;

    /* Text */
    --text-primary: #e8e0d5;
    --text-secondary: #a89c8d;
    --text-muted: #7d7365;
    --text-strong: #f7f2ea;
    --text-on-accent: #ffffff;

    /* Accent — the ring's lighter passes, which is how it lifts on dark without leaving the
       logo's palette. (Trophyst's dark hover is its light accent; #0666F1 is too dark to read on
       the ember ground, so the hover steps to the middle pass instead.) */
    --accent: #60B4FB;
    --accent-hover: #278EFB;
    --accent-light: rgba(96, 180, 251, 0.16);

    /* Borders */
    --border-color: #362e24;
    --border-subtle: #272019;

    /* Lifted the same way Trophyst lifts its accent on dark, so the bloom still reads. */
    --wash-tint: #f5843c;

    /* Shadows — deeper on dark */
    --shadow-sm: 0 1px 3px rgba(0,0,0,0.4);
    --shadow-md: 0 6px 18px rgba(0,0,0,0.5);

    /* Status text colours lift on dark so tinted pills stay readable */
    --status-success: #63d394;
    --status-warning: #e8b45c;
    --status-danger: #f08579;
    --status-info: #7db4ec;
    --status-neutral: #a89c8d;

    /* Misc */
    --scrollbar-thumb: #453a2d;
    --table-stripe: transparent;
    --nav-hover-bg: rgba(255, 240, 220, 0.06);

    /* Warm-dark "brothers" of the quarter tints for dark mode */
    --cal-q1-bg: #33291a; --cal-q1-fg: #e8b878;
    --cal-q2-bg: #1b3328; --cal-q2-fg: #74c99e;
    --cal-q3-bg: #1c2940; --cal-q3-fg: #93b6e8;
    --cal-q4-bg: #2a2142; --cal-q4-fg: #c2a4ea;

    --band-1-fg: var(--cal-q1-fg);
    --band-2-fg: var(--cal-q2-fg);
    --band-3-fg: var(--cal-q3-fg);
    --band-4-fg: var(--cal-q4-fg);
    --band-5-fg: #e79fb8;
    --band-6-fg: #7cc7c8;

    /* Dark needs a touch more of the ink to read at all against the card. */
    --band-1-bg: color-mix(in srgb, var(--band-1-fg) 15%, var(--bg-card));
    --band-2-bg: color-mix(in srgb, var(--band-2-fg) 15%, var(--bg-card));
    --band-3-bg: color-mix(in srgb, var(--band-3-fg) 15%, var(--bg-card));
    --band-4-bg: color-mix(in srgb, var(--band-4-fg) 15%, var(--bg-card));
    --band-5-bg: color-mix(in srgb, var(--band-5-fg) 15%, var(--bg-card));
    --band-6-bg: color-mix(in srgb, var(--band-6-fg) 15%, var(--bg-card));
    color-scheme: dark;
}

html {
    font-size: var(--font-size-base);
}

html, body {
    font-family: var(--font-ui);
    background-color: var(--bg-body);
    color: var(--text-primary);
    line-height: var(--line-height-base);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'cv05' 1, 'ss03' 1;  /* single-storey l, rounded quotes */
}

/* Tabular figures everywhere numbers are compared down a column */
.table td, .table th,
.stat-ribbon-value, .kpi-value, .hd-kpi-count, .hd-summary-num, .hd-pipeline-count {
    font-variant-numeric: tabular-nums;
}

/* Links */
a, .btn-link {
    color: var(--accent);
}

a:hover, .btn-link:hover {
    color: var(--accent-hover);
}

/* Buttons - rounded and modern */
.btn {
    border-radius: var(--border-radius-sm);
    font-weight: 500;
    transition: all 0.2s ease;
    --bs-btn-padding-y: 0.4rem;
    --bs-btn-padding-x: 0.85rem;
    --bs-btn-font-size: 0.9rem;
}

.btn-sm {
    --bs-btn-padding-y: 0.25rem;
    --bs-btn-padding-x: 0.6rem;
    --bs-btn-font-size: 0.8rem;
}

.btn-primary {
    color: #fff !important;
    background-color: var(--accent) !important;
    border-color: var(--accent) !important;
}

.btn-primary:hover, .btn-primary:focus, .btn-primary:active {
    background-color: var(--accent-hover) !important;
    border-color: var(--accent-hover) !important;
    color: #fff !important;
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.btn-primary:disabled, .btn-primary.disabled {
    background-color: var(--accent) !important;
    border-color: var(--accent) !important;
    opacity: 0.65;
}

.btn-outline-primary {
    color: var(--accent) !important;
    border-color: var(--accent) !important;
    background-color: transparent !important;
}

.btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:active {
    background-color: var(--accent) !important;
    border-color: var(--accent) !important;
    color: #fff !important;
}

.btn-secondary {
    background-color: #6c757d !important;
    border-color: #6c757d !important;
    color: #fff !important;
}

.btn-secondary:hover, .btn-secondary:focus, .btn-secondary:active {
    background-color: #5a6268 !important;
    border-color: #5a6268 !important;
    color: #fff !important;
}

.btn-outline-secondary {
    color: var(--text-secondary) !important;
    border-color: var(--border-color) !important;
    background-color: transparent !important;
}

.btn-outline-secondary:hover, .btn-outline-secondary:focus, .btn-outline-secondary:active {
    background-color: var(--bg-card-hover) !important;
    border-color: var(--border-color) !important;
    color: var(--text-primary) !important;
}

.btn-success {
    background-color: var(--success) !important;
    border-color: var(--success) !important;
    color: #fff !important;
}

.btn-success:hover, .btn-success:focus, .btn-success:active {
    background-color: #219a52 !important;
    border-color: #219a52 !important;
    color: #fff !important;
}

.btn-outline-success {
    color: var(--success) !important;
    border-color: var(--success) !important;
    background-color: transparent !important;
}

.btn-outline-success:hover, .btn-outline-success:focus, .btn-outline-success:active {
    background-color: var(--success) !important;
    border-color: var(--success) !important;
    color: #fff !important;
}

.btn-warning {
    background-color: var(--warning) !important;
    border-color: var(--warning) !important;
    color: #fff !important;
}

.btn-warning:hover, .btn-warning:focus, .btn-warning:active {
    background-color: #d68910 !important;
    border-color: #d68910 !important;
    color: #fff !important;
}

.btn-danger {
    background-color: var(--danger) !important;
    border-color: var(--danger) !important;
    color: #fff !important;
}

.btn-danger:hover, .btn-danger:focus, .btn-danger:active {
    background-color: #c0392b !important;
    border-color: #c0392b !important;
    color: #fff !important;
}

.btn-outline-danger {
    color: var(--danger) !important;
    border-color: var(--danger) !important;
    background-color: transparent !important;
}

.btn-outline-danger:hover, .btn-outline-danger:focus, .btn-outline-danger:active {
    background-color: var(--danger) !important;
    border-color: var(--danger) !important;
    color: #fff !important;
}

.btn-dark {
    background-color: #343a40 !important;
    border-color: #343a40 !important;
    color: #fff !important;
}

.btn-dark:hover, .btn-dark:focus, .btn-dark:active {
    background-color: #23272b !important;
    border-color: #23272b !important;
    color: #fff !important;
}

/* Focus states */
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 3px var(--accent-light);
}

.content {
    padding-top: 1.1rem;
}

/* Headings carry the display face — this is where the personality lives.
   Tight tracking + a near-black warm ink is what separates an editorial
   look from a generic dashboard. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: var(--font-display);
    color: var(--text-strong);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.021em;
}

h1, .h1 { font-size: 1.9rem; letter-spacing: -0.028em; }
h2, .h2 { font-size: 1.45rem; letter-spacing: -0.024em; }
h3, .h3 { font-size: 1.2rem; }
h4, .h4 { font-size: 1.05rem; }
h5, .h5 { font-size: 0.95rem; letter-spacing: -0.014em; }
h6, .h6 { font-size: 0.85rem; letter-spacing: -0.01em; }

h1:focus {
    outline: none;
}

/* Form controls - rounded */
.form-control, .form-select {
    background-color: var(--bg-white);
    border-color: var(--border-color);
    color: var(--text-primary);
    border-radius: var(--border-radius-sm);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
    font-size: 0.9rem;
    padding: 0.4rem 0.7rem;
}

.form-control-sm, .form-select-sm {
    font-size: 0.8rem;
    padding: 0.25rem 0.55rem;
}

/* Bootstrap draws a select's arrow as a background image and reserves room for
   it with padding-right. The padding shorthand above overwrites that, so the
   text of any select wide enough to reach the arrow runs underneath it. Put the
   room back rather than dropping the shorthand, which would lose the theme's
   vertical rhythm. */
.form-select {
    padding-right: 2.1rem;
}

.form-select-sm {
    padding-right: 1.85rem;
}

/* Native file picker button ("Choose Files") — Bootstrap renders it on a light bg */
.form-control::file-selector-button {
    background-color: var(--bg-card-hover);
    color: var(--text-primary);
    border-color: var(--border-color);
}

.form-control:hover:not(:disabled)::file-selector-button {
    background-color: var(--bg-subtle);
    color: var(--text-primary);
}

.form-control:focus, .form-select:focus {
    background-color: var(--bg-white);
    border-color: var(--accent);
    color: var(--text-primary);
    box-shadow: 0 0 0 3px var(--accent-light);
}

.form-control::placeholder {
    color: var(--text-muted);
}

/* Disabled / readonly inputs — Bootstrap defaults to a light grey that stays light in dark mode */
.form-control:disabled,
.form-select:disabled,
.form-control[readonly] {
    background-color: var(--bg-subtle);
    color: var(--text-muted);
    border-color: var(--border-color);
}

.form-label {
    color: var(--text-secondary);
    font-weight: 500;
    font-size: 0.875rem;
}

.form-check-input {
    background-color: var(--bg-white);
    border-color: var(--border-color);
    border-radius: 4px;
}

.form-check-input:checked {
    background-color: var(--accent);
    border-color: var(--accent);
}

.form-check-label {
    color: var(--text-primary);
}

/* Cards - rounded with shadow */
.card {
    --bs-card-spacer-y: var(--space-card);
    --bs-card-spacer-x: var(--space-card);
    --bs-card-cap-padding-y: var(--space-card-sm);
    --bs-card-cap-padding-x: var(--space-card);
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    box-shadow: var(--shadow-sm);
    color: var(--text-primary);
}

/* Panel headers sit on the card itself, divided by a hairline rather than a
   grey band — fewer boxes-inside-boxes, which is what made the old UI heavy. */
.card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--border-subtle);
    border-radius: var(--border-radius) var(--border-radius) 0 0;
    color: var(--text-strong);
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: -0.014em;
}

.card-footer {
    background-color: transparent;
    border-top: 1px solid var(--border-subtle);
    border-radius: 0 0 var(--border-radius) var(--border-radius);
}

/* Tables - modern styling */
.table {
    color: var(--text-primary);
    --bs-table-bg: transparent;
    --bs-table-color: var(--text-primary);
    --bs-table-striped-color: var(--text-primary);
    --bs-table-striped-bg: var(--table-stripe);
    --bs-table-hover-color: var(--text-primary);
    --bs-table-hover-bg: var(--bg-card-hover);
    --bs-table-border-color: var(--border-color);
    /* Bootstrap 5.2 hardcodes .table border-color:#dee2e6 (near-white) and cells inherit it for
       their bottom border — override it so row separators are the theme's thin grey, not white. */
    border-color: var(--border-color);
}

.table {
    --bs-table-cell-padding-y: 0.45rem;
    --bs-table-cell-padding-x: 0.6rem;
    font-size: 0.875rem;
}

.table td, .table th {
    color: var(--text-primary);
    vertical-align: middle;
}

.nav-tabs {
    --bs-nav-tabs-border-color: var(--border-color);
    --bs-nav-tabs-link-hover-border-color: var(--border-subtle) var(--border-subtle) var(--border-color);
    --bs-nav-tabs-link-active-color: var(--accent);
    --bs-nav-tabs-link-active-bg: var(--bg-card);
    --bs-nav-tabs-link-active-border-color: var(--border-color) var(--border-color) var(--bg-card);
}
.nav-tabs .nav-link {
    color: var(--text-secondary);
}
.nav-tabs .nav-link:hover {
    color: var(--accent);
}
.nav-tabs .nav-link.active {
    color: var(--accent);
    background-color: var(--bg-card);
    border-color: var(--border-color) var(--border-color) var(--bg-card);
}

.table > thead {
    border-bottom: 1px solid var(--border-color);
}

.table > thead th {
    color: var(--text-secondary);
    font-weight: 600;
    text-transform: uppercase;
    font-size: 0.75rem;
    letter-spacing: 0.5px;
}

/* Striping is handled by Bootstrap's native --bs-table-striped-bg (set on .table
   above) so contextual row variants like .table-success keep their tint. */

/* Compact tables — tighter padding, smaller text */
.table-sm th {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-weight: 600;
    color: #6c757d;
    white-space: nowrap;
}

.table-sm td {
    font-size: 0.85rem;
}

/* Accordion — make theme-aware (Bootstrap hardcodes a light bg/border) */
.accordion {
    --bs-accordion-bg: var(--bg-card);
    --bs-accordion-color: var(--text-primary);
    --bs-accordion-border-color: var(--border-color);
    --bs-accordion-btn-color: var(--text-primary);
    --bs-accordion-btn-bg: var(--bg-card);
    --bs-accordion-active-bg: var(--bg-card-hover);
    --bs-accordion-active-color: var(--accent);
    --bs-accordion-btn-focus-border-color: var(--accent);
    --bs-accordion-btn-focus-box-shadow: 0 0 0 3px var(--accent-light);
}

/* Bootstrap 5.2 hardcodes accordion colours (#fff / #212529 / #e7f1ff) instead of using the
   --bs-accordion-* vars above, so override the actual properties for the theme. */
.accordion-item {
    background-color: var(--bg-card);
    border-color: var(--border-color);
    color: var(--text-primary);
}
.accordion-button {
    background-color: var(--bg-card);
    color: var(--text-primary);
}
.accordion-button:not(.collapsed) {
    background-color: var(--bg-card-hover);
    color: var(--accent);
    box-shadow: inset 0 -1px 0 var(--border-color);
}
.accordion-body {
    color: var(--text-primary);
}

[data-theme="dark"] .accordion-button::after {
    filter: invert(1) grayscale(100%) brightness(1.6);
}

/* Light table header/rows — make theme-aware (Bootstrap hardcodes a light grey) */
.table-light,
.table-light > th,
.table-light > td,
.table > :not(caption) > .table-light > * {
    --bs-table-bg: var(--bg-card-hover);
    --bs-table-color: var(--text-secondary);
    --bs-table-border-color: var(--border-color);
    background-color: var(--bg-card-hover);
    color: var(--text-secondary);
}

/* Contextual row tints — drive the Bootstrap cell var so text stays readable, and
   darken the tint in dark mode (light cell text needs a deeper background) */
.table-success { --bs-table-bg: rgba(39, 174, 96, 0.10); --bs-table-color: var(--text-primary); }
.table-warning { --bs-table-bg: rgba(243, 156, 18, 0.10); --bs-table-color: var(--text-primary); }
.table-danger  { --bs-table-bg: rgba(231, 76, 60, 0.10); --bs-table-color: var(--text-primary); }

[data-theme="dark"] .table-success { --bs-table-bg: rgba(39, 174, 96, 0.22); }
[data-theme="dark"] .table-warning { --bs-table-bg: rgba(243, 156, 18, 0.22); }
[data-theme="dark"] .table-danger  { --bs-table-bg: rgba(231, 76, 60, 0.28); }

/* List groups */
.list-group-item {
    background-color: var(--bg-card);
    border-color: var(--border-color);
    color: var(--text-primary);
}

.list-group-item-action:hover, .list-group-item-action:focus {
    background-color: var(--bg-card-hover);
    color: var(--text-primary);
}

.list-group-item.active {
    background-color: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* ── Badges — tinted pills, not solid blocks ──
   Solid saturated badges are the single loudest thing in a data table.
   Tinting them keeps status legible while letting the data lead, and it
   is what the reference design does. Colour is driven by --badge-tint so
   each status is one line, and dark mode lifts the tints for contrast. */
.badge {
    --badge-tint: var(--status-neutral);
    border-radius: 999px;
    font-family: var(--font-ui);
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.015em;
    padding: 0.34em 0.72em;
    background-color: color-mix(in srgb, var(--badge-tint) 13%, var(--bg-card)) !important;
    color: var(--badge-tint) !important;
    border: 1px solid color-mix(in srgb, var(--badge-tint) 26%, transparent);
}

.badge.bg-primary { --badge-tint: var(--accent); }
.badge.bg-secondary { --badge-tint: var(--status-neutral); }
.badge.bg-success { --badge-tint: var(--status-success); }
.badge.bg-warning { --badge-tint: var(--status-warning); }
.badge.bg-danger { --badge-tint: var(--status-danger); }
.badge.bg-info { --badge-tint: var(--status-info); }
.badge.bg-dark { --badge-tint: var(--text-strong); }

/* Some callers pair a badge with .text-dark / .text-white for the old solid
   look; the tint already guarantees contrast, so keep the tinted colour. */
.badge.text-dark, .badge.text-white, .badge.text-light {
    color: var(--badge-tint) !important;
}

/* Alerts - rounded */
.alert {
    border-radius: var(--border-radius-sm);
    border-width: 0;
    border-left-width: 4px;
}

.alert-info {
    background-color: rgba(52, 152, 219, 0.1);
    border-color: var(--info);
    color: #2980b9;
}

.alert-success {
    background-color: rgba(39, 174, 96, 0.1);
    border-color: var(--success);
    color: #1e8449;
}

.alert-danger {
    background-color: rgba(231, 76, 60, 0.1);
    border-color: var(--danger);
    color: #c0392b;
}

.alert-warning {
    background-color: rgba(243, 156, 18, 0.1);
    border-color: var(--warning);
    color: #b7950b;
}

/* The neutral variants are not status messages — they are the quiet "here is what this data
   rests on" notes that sit under a report. Bootstrap resolves them from its own cold grey
   scale, which never learned about the theme, so they stayed a white card when the canvas went
   to ember. Point them at the theme's own subtle surface and they follow both ways. */
.alert-light,
.alert-secondary,
.alert-dark {
    background-color: var(--bg-subtle);
    border-color: var(--border-color);
    color: var(--text-secondary);
}

.alert-primary {
    background-color: var(--accent-light);
    border-color: var(--accent);
    color: var(--accent-hover);
}

/* Modals - rounded */
.modal-content {
    background-color: var(--bg-card);
    border: none;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow-md);
    color: var(--text-primary);
}

.modal-header {
    border-bottom: 1px solid var(--border-color);
    border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.modal-footer {
    border-top: 1px solid var(--border-color);
    border-radius: 0 0 var(--border-radius) var(--border-radius);
}

/* Input groups */
.input-group-text {
    background-color: var(--bg-card-hover);
    border-color: var(--border-color);
    color: var(--text-secondary);
    border-radius: var(--border-radius-sm);
}

/* Text utilities */
.text-muted {
    color: var(--text-muted) !important;
}

.text-primary {
    color: var(--accent) !important;
}

/* Validation */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--success);
}

.invalid {
    outline: 1px solid var(--danger);
}

.validation-message {
    color: var(--danger);
}

/* Error boundary */
.blazor-error-boundary {
    background: linear-gradient(135deg, var(--danger), #c0392b);
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
    border-radius: var(--border-radius-sm);
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

.darker-border-checkbox.form-check-input {
    border-color: var(--border-color);
}

/* Dashboard cards */
.card.text-bg-primary {
    background: linear-gradient(135deg, var(--accent), var(--accent-hover)) !important;
    border: none;
}

.card.text-bg-success {
    background: linear-gradient(135deg, var(--success), #1e8449) !important;
    border: none;
}

.card.text-bg-info {
    background: linear-gradient(135deg, var(--info), #2980b9) !important;
    border: none;
}

.card.text-bg-secondary {
    background: linear-gradient(135deg, #6c757d, #5a6268) !important;
    border: none;
}

/* Scrollbar styling */
::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: var(--bg-body);
}

::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--accent);
}

/* Page title. The old orange underline bar is gone deliberately — the
   display face and weight do that job now, and the bar read as dated. */
h1 {
    color: var(--text-strong);
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: 0.9rem;
}

/* Subtitle under a page title */
.lead {
    color: var(--text-secondary);
    font-size: 0.95rem;
    font-weight: 400;
}

/* Main content top row — sits on the page canvas, undivided */
main > .top-row {
    background-color: transparent !important;
    border-bottom: none !important;
}

main > .top-row a {
    color: var(--text-secondary) !important;
}

main > .top-row a:hover {
    color: var(--accent) !important;
}

/* Pagination - rounded with orange theme */
.pagination {
    --bs-pagination-bg: var(--bg-white);
    --bs-pagination-border-color: var(--border-color);
    --bs-pagination-color: var(--text-primary);
    --bs-pagination-hover-bg: var(--accent);
    --bs-pagination-hover-border-color: var(--accent);
    --bs-pagination-hover-color: #fff;
    --bs-pagination-focus-box-shadow: 0 0 0 3px var(--accent-light);
    --bs-pagination-active-bg: var(--accent);
    --bs-pagination-active-border-color: var(--accent);
    --bs-pagination-active-color: #fff;
    --bs-pagination-disabled-bg: var(--bg-body);
    --bs-pagination-disabled-border-color: var(--border-color);
    --bs-pagination-disabled-color: var(--text-muted);
}

.page-link {
    border-radius: var(--border-radius-sm);
    margin: 0 2px;
    color: var(--text-primary);
    background-color: var(--bg-white);
    border-color: var(--border-color);
}

.page-link:hover, .page-link:focus {
    color: #fff;
    background-color: var(--accent);
    border-color: var(--accent);
}

.page-item.active .page-link {
    color: #fff;
    background-color: var(--accent);
    border-color: var(--accent);
}

.page-item.disabled .page-link {
    color: var(--text-muted);
    background-color: var(--bg-body);
    border-color: var(--border-color);
}

.page-item:first-child .page-link,
.page-item:last-child .page-link {
    border-radius: var(--border-radius-sm);
}

/* Nav divider for light theme */
.nav-divider {
    border-color: var(--border-color) !important;
    opacity: 1;
}

/* ── Theme toggle button ── */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    background: var(--bg-card);
    color: var(--text-secondary);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.theme-toggle:hover {
    color: var(--accent);
    border-color: var(--accent);
}

.theme-toggle svg {
    width: 17px;
    height: 17px;
}

/* Variant for placement on a colored navbar (white icon/border) */
.theme-toggle.on-accent {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}

.theme-toggle.on-accent:hover {
    background: rgba(255, 255, 255, 0.22);
    border-color: #fff;
    color: #fff;
}

/* Show moon in light mode (click → dark), sun in dark mode (click → light) */
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: inline; }
[data-theme="dark"] .theme-toggle .icon-sun { display: inline; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* Menu-position toggle: each icon previews the layout you would switch to.
   Hidden on narrow viewports, where the top menu falls back to the sidebar
   anyway and the control would be a no-op. */
.nav-layout-toggle .icon-nav-vertical { display: none; }
.nav-layout-toggle .icon-nav-horizontal { display: inline; }
[data-nav="horizontal"] .nav-layout-toggle .icon-nav-vertical { display: inline; }
[data-nav="horizontal"] .nav-layout-toggle .icon-nav-horizontal { display: none; }

@media (max-width: 991.98px) {
    .nav-layout-toggle { display: none !important; }
}

/* Set for a moment while the menu changes position: the request to collapse an
   open group round-trips through Blazor, and without this the panel would be
   briefly visible re-laid-out in the layout being switched to. */
[data-nav-switching] .nav-submenu {
    display: none !important;
}

/* ───────────────────────────────────────────────
   Dark-theme component fixes
   (global components only; per-page scoped CSS is
   handled in the page-by-page cleanup phase)
   ─────────────────────────────────────────────── */

/* Supplier portal layout hardcodes a light body gradient — flatten it on dark */
[data-theme="dark"] body {
    background: var(--bg-body) !important;
}

/* Alert text needs lifting for contrast on dark surfaces */
[data-theme="dark"] .alert-info { color: #6cb6e8; }
[data-theme="dark"] .alert-success { color: #5fd99a; }
[data-theme="dark"] .alert-danger { color: #f08a7f; }
[data-theme="dark"] .alert-warning { color: #f0c060; }

/* Modal close button ('X') is a dark SVG — invert it on dark */
[data-theme="dark"] .btn-close {
    filter: invert(1) grayscale(100%) brightness(1.6);
}

/* Bootstrap text-bg-* helpers default to opaque white/light bg */
[data-theme="dark"] .bg-light {
    background-color: var(--bg-subtle) !important;
    color: var(--text-primary) !important;
}

[data-theme="dark"] .bg-white {
    background-color: var(--bg-card) !important;
}

/* Subtle borders that used Bootstrap defaults */
[data-theme="dark"] .border,
[data-theme="dark"] .border-top,
[data-theme="dark"] .border-bottom,
[data-theme="dark"] .border-start,
[data-theme="dark"] .border-end {
    border-color: var(--border-color) !important;
}

/* ── Promora additions to the harvested theme ─────────────────────────────── */


/* ── Page hero (hd-*) ──────────────────────────────────────────────────────
   Was scoped to the dashboard until the investments dashboard wanted the same banner. It is page
   furniture now rather than one page's decoration, so it lives here — the markup is identical on
   both, only the words differ.
   ── Card shell ── */
.hd-card {
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    overflow: hidden;
    /* A shadow this soft is barely a shadow — it lifts the card off the page without the drop
       shadow that dates an interface. Two layers: a hairline to sharpen the edge, and a wide
       diffuse one for the lift. */
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 8px 24px -12px rgba(16, 24, 40, 0.10);
}

[data-theme="dark"] .hd-card {
    /* Shadows do nothing on a dark ground; the border carries the separation instead. */
    box-shadow: none;
}

/* ── Hero ──────────────────────────────────────────────────────────────────
   The mountain sits to the right and is washed out towards the left by a gradient in the card's
   own colour, so the headline never sits on top of detail. The gradient is the same token as the
   card background, which is what lets one image work in both themes: light mode fades to white,
   dark mode fades to slate, and the photograph is dimmed to sit behind rather than shout. */
.hd-hero {
    position: relative;
    /* Its own stacking context: ::after is generated last in tree order and would otherwise
       paint the gradient over the copy, but lifting the copy in the *root* context put it over
       the header's user menu. Isolating keeps that fight inside the banner. */
    isolation: isolate;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 24px;
    padding: 30px 32px;
    min-height: 168px;
    border: 1px solid var(--border-color);
    border-radius: 16px;
    overflow: hidden;
    background-color: var(--bg-card);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 8px 24px -12px rgba(16, 24, 40, 0.10);
}

.hd-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: url("../img/summit-hero.webp");
    background-size: cover;
    background-position: 72% 38%;
    /* The photograph is a backdrop, not the subject. */
    opacity: 0.85;
}

.hd-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        100deg,
        var(--bg-card) 0%,
        var(--bg-card) 30%,
        color-mix(in srgb, var(--bg-card) 72%, transparent) 52%,
        transparent 82%);
}

[data-theme="dark"] .hd-hero::before {
    opacity: 0.30;
}

/* The page's warm bloom. Anchored to .page rather than to anything on this page, so it starts at
   the window's top-left corner and washes over the menu, the banner and the first cards alike —
   it is light on the paper, not a fill belonging to one panel.
   z-index 3 puts it above the sidebar and the cards (all of which sit at the auto level) and well
   below the header at 1030, so the controls and the user menu stay clear of it. */
.hd-wash {
    position: absolute;
    top: -300px;
    left: -260px;
    width: 1100px;
    height: 1100px;
    border-radius: 50%;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--wash-tint) 13%, transparent) 0%,
        transparent 68%);
    pointer-events: none;
    z-index: 3;
}

/* On a top bar the menu is a sticky strip at z-index 1031, which the wash would otherwise stop
   dead against — the bar read as a white band cut across the glow. Matching that z-index lifts
   the wash over it: same layer, and `main` follows the sidebar in the markup, so the wash wins on
   tree order. Still under the utility row at 1032, so the toggles and the user menu stay clear. */
[data-nav="horizontal"] .hd-wash {
    z-index: 1031;
}

.hd-hero-copy,
.hd-hero-aside {
    position: relative;
    z-index: 1;
}

.hd-hero-eyebrow {
    margin: 0 0 6px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

.hd-hero-title {
    margin: 0;
    font-size: 30px;
    line-height: 1.15;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--text-strong);
    max-width: 34ch;
}

/* Every h1 in the app carries a short accent rule beneath it as a page marker. The hero is not a
   page title — it is a banner — and the rule reads there as a stray mark under the sentence. */
.hd-hero-title::after {
    content: none;
}

.hd-hero-sub {
    margin: 8px 0 0;
    font-size: 14px;
    color: var(--text-secondary);
}

.hd-hero-aside {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 12px;
    text-align: right;
}

.hd-hero-unit {
    font-size: 12px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 999px;
    color: var(--text-secondary);
    background: color-mix(in srgb, var(--bg-card) 78%, transparent);
    border: 1px solid var(--border-color);
    backdrop-filter: blur(4px);
}

.hd-hero-tagline {
    margin: 0;
    font-family: Georgia, "Times New Roman", serif;
    font-style: italic;
    font-size: 20px;
    line-height: 1.3;
    color: var(--text-secondary);
}

/* Under about 900px the photograph and the text start fighting for the same room, so the
   tagline steps out and the image retreats further behind the copy. */
@media (max-width: 900px) {
    .hd-hero { padding: 24px; min-height: 0; }
    .hd-hero-title { font-size: 24px; }
    .hd-hero-aside { display: none; }
    .hd-hero::after {
        background: linear-gradient(
            100deg,
            var(--bg-card) 0%,
            var(--bg-card) 55%,
            color-mix(in srgb, var(--bg-card) 80%, transparent) 100%);
    }
}

/* Bootstrap's own neutral scale is a cold grey, and it surfaces in everything we do not restyle
   by hand — progress tracks, list groups, popovers, the frozen columns in the projection grids.
   Pointing its variables at ours keeps the cold grey off the paper canvas and, more importantly,
   keeps those components from staying light when the theme goes dark. Declared on :root, so the
   dark block's token values re-resolve these without having to repeat them. */
:root {
    --bs-body-bg: var(--bg-body);
    --bs-body-color: var(--text-primary);
    --bs-secondary-bg: var(--bg-subtle);
    --bs-tertiary-bg: var(--bg-card-hover);
    --bs-secondary-color: var(--text-secondary);
    --bs-emphasis-color: var(--text-strong);
    --bs-border-color: var(--border-color);
}

/* Bootstrap's helper text is too faint on the paper canvas — align it with the theme greys. */
.form-text {
    color: var(--text-secondary);
}

/* ── Paper wash ───────────────────────────────────────────────────────────
   The faint warm bloom behind the top-left of a hero area. Purely decorative; it sits under the
   content and ignores clicks. Put it on a container that has no fill of its own — over an opaque
   card there is nothing for it to bloom on. (Promora's dashboard hero is such a card, so it draws
   the same wash as an explicit child instead; see Home.razor.css.) */
.paper-wash {
    position: relative;
}

.paper-wash::before {
    content: '';
    position: absolute;
    top: -140px;
    left: -180px;
    width: 620px;
    height: 620px;
    border-radius: 50%;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--wash-tint) 13%, transparent) 0%,
        transparent 68%);
    pointer-events: none;
    z-index: 0;
}

.paper-wash > * { position: relative; z-index: 1; }

/* A table that fills a card (card-body.p-0) paints square into the card's rounded corners, so the
   tinted header strip cuts them off. The scroll container already clips horizontally — giving it
   the card's radius is enough, and adds no clipping that wasn't there. */
.card > .card-body.p-0 > .table-responsive {
    border-radius: var(--border-radius);
}

.card > .card-body.p-0:not(:first-child) > .table-responsive {
    border-radius: 0 0 var(--border-radius) var(--border-radius);
}
/* ── Commitment Support Matrix ── */
.matrix-cell:hover { background-color: var(--accent-light); }

/* ── Projection period calendar (pcal) ─────────────────────────────────── */
.pcal { font-size: .78rem; }
.pcal-scroll { overflow-x: auto; }
.pcal-row {
    display: flex;
    align-items: stretch;
    width: max-content;
    min-width: 100%;
    border-bottom: 1px solid var(--border-color, #e5e9f0);
}
.pcal-scroll .pcal-row:last-child { border-bottom: 0; }
.pcal-label {
    flex: 0 0 220px;
    width: 220px;
    position: sticky;
    left: 0;
    z-index: 6;
    background: var(--bg-card, #fff);
    border-right: 1px solid var(--border-color, #e5e9f0);
    padding: .3rem .6rem;
    display: flex;
    align-items: center;
    gap: .35rem;
    overflow: hidden;
    white-space: nowrap;
}
/* Taller only where seasons are in play — .pcal-seasons is set by the calendar when any window in
   view carries one, so a plan of plain week windows keeps the compact rows it always had. */
.pcal-track { position: relative; height: 38px; flex: 1 1 auto; min-width: 950px; }
.pcal-seasons .pcal-track { height: 54px; }
.pcal-seasons .pcal-head .pcal-track { height: 20px; }
.pcal-head .pcal-track { height: 20px; }
.pcal-head .pcal-label { padding-top: .1rem; padding-bottom: .1rem; }
.pcal-grid {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: linear-gradient(to right, rgba(100, 116, 139, .12) 1px, transparent 1px);
    background-size: calc(100% / var(--pcal-weeks, 52)) 100%;
}
.pcal-week {
    position: absolute; top: 0; bottom: 0;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-muted, #8a94a6);
    font-size: .6rem;
}
.pcal-month {
    position: absolute; top: 0; bottom: 0;
    display: flex; align-items: center;
    padding-left: 6px;
    border-left: 1px solid var(--border-color, #e5e9f0);
    color: var(--text-muted, #8a94a6);
    font-weight: 600; font-size: .64rem;
    text-transform: uppercase; letter-spacing: .04em;
    overflow: hidden; white-space: nowrap;
}
.pcal-inperiod {
    position: absolute; top: 0; bottom: 0;
    background: rgba(37, 99, 235, .08);
    pointer-events: none;
}
.pcal-bar {
    position: absolute; top: 6px; height: 26px;
    background: var(--bar, #2563eb);
    border-radius: 6px;
    color: #fff;
    display: flex; align-items: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
    touch-action: none;
    user-select: none;
    z-index: 2;
    overflow: hidden;
}
.pcal-seasons .pcal-bar { top: 6px; height: 42px; }

/* ── Season artwork ──
   Its own layer so it can be given a width of its own, and that width is a fixed number of pixels
   rather than a share of the bar. Two reasons: a window that runs a quarter is a very wide box and
   covering it scales the picture up until only a slice through the middle is left; and a share of
   a four-week bar is most of the bar, which leaves the name nowhere to go. A small square at the
   start, the same however long the window runs — the 45% ceiling is for windows too short to give
   it even that. The dark wash keeps the white label readable over a photograph of unknown
   brightness. */
.pcal-bar-art::before {
    content: "";
    position: absolute;
    top: 0; bottom: 0; left: 0;
    width: min(56px, 45%);
    background-image:
        linear-gradient(90deg, rgba(0,0,0,.45) 0%, rgba(0,0,0,.18) 60%, rgba(0,0,0,.05) 100%),
        var(--art);
    background-size: auto, cover;
    background-position: center, center;
    background-repeat: no-repeat, no-repeat;
    /* Fades out over its last stretch rather than ending on a hard vertical edge partway along,
       so the picture settles into the season's colour. */
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 62%, transparent 100%);
            mask-image: linear-gradient(90deg, #000 0%, #000 62%, transparent 100%);
    pointer-events: none;
}
.pcal-bar.pcal-dragging { opacity: .85; z-index: 4; }
/* Cash-back windows overlaid on the projection calendar. Hatched rather than merely a different
   hue: the two plans are different KINDS of thing, and a texture says that at a glance where one
   more colour would just look like one more projection. */
.pcal-bar.pcal-cashback {
    background-image: repeating-linear-gradient(
        135deg,
        rgba(255, 255, 255, .28) 0 5px,
        rgba(255, 255, 255, 0) 5px 10px);
    border: 1px dashed rgba(255, 255, 255, .75);
}
/* The period whose forecast field has focus on the KAM grid lights up. */
.pcal-bar.pcal-hl {
    outline: 3px solid #f59e0b;
    outline-offset: 1px;
    z-index: 3;
}
.pcal-bar-label {
    flex: 1 1 auto;
    text-align: center;
    overflow: hidden; white-space: nowrap;
    font-size: .64rem; font-weight: 600;
    padding: 0 2px;
    /* Above the artwork layer, which is painted by the bar's own ::before. */
    position: relative;
    z-index: 1;
}

/* With a season the label is two lines: the weeks, then what the weeks are. Left-aligned and
   pushed clear of the picture, which sits at the start of the bar. */
.pcal-bar-season .pcal-bar-label {
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: left;
    line-height: 1.25;
    padding-left: 6px;
}

/* Clear of the picture rather than over it — same measurement, so the two cannot drift apart. */
.pcal-bar-season.pcal-bar-art .pcal-bar-label { padding-left: calc(min(56px, 45%) + 8px); }

.pcal-bar-weeks { overflow: hidden; text-overflow: ellipsis; }

.pcal-bar-season-name {
    font-size: .68rem;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pcal-bar:not(.pcal-readonly) .pcal-bar-label { cursor: grab; }
.pcal-bar.pcal-dragging .pcal-bar-label { cursor: grabbing; }
.pcal-handle { flex: 0 0 8px; align-self: stretch; cursor: ew-resize; border-radius: 6px; }
.pcal-handle:hover { background: rgba(255, 255, 255, .35); }
.pcal-bar.pcal-readonly .pcal-handle { display: none; }
.pcal-del {
    position: absolute; top: -7px; right: -7px;
    width: 16px; height: 16px;
    border-radius: 50%; border: 0;
    background: #334155; color: #fff;
    font-size: 11px; line-height: 1;
    display: none; align-items: center; justify-content: center;
    padding: 0; z-index: 5;
}
.pcal-bar:hover .pcal-del { display: flex; }
.pcal-row-global .pcal-label { font-weight: 600; }
.pcal-rowbtn {
    border: 0; background: transparent; padding: 0 2px;
    color: var(--text-muted, #8a94a6); line-height: 1; font-size: .9rem;
}
.pcal-rowbtn:hover { color: var(--accent, #2563eb); }
.pcal-rowbtn-danger:hover { color: #dc2626; }

/* ── Collapsible sidebar: the rail the edge control shrinks the menu to ──
   The control itself lives on the sidebar's edge (MainLayout). Independent of the sidebar/top-bar
   choice, so these rules are undone again for a top bar below. */
@media (min-width: 641px) {
    html.nav-collapsed .sidebar { width: 64px !important; }
}

/* On a top bar the menu is never a rail, whatever the collapsed preference says. */
@media (min-width: 992px) {
    html.nav-collapsed[data-nav="horizontal"] .navbar-brand,
    html.nav-collapsed[data-nav="horizontal"] .nav-text,
    html.nav-collapsed[data-nav="horizontal"] .nav-caret {
        display: flex !important;
    }

    html.nav-collapsed[data-nav="horizontal"] .nav-text {
        display: inline !important;
    }

    html.nav-collapsed[data-nav="horizontal"] .nav-item .nav-link {
        justify-content: flex-start !important;
        padding-left: .7rem !important;
        padding-right: .7rem !important;
    }

    html.nav-collapsed[data-nav="horizontal"] .nav-icon {
        margin-right: 8px !important;
    }
}
/* The logo mark stays in the rail — it is what tells you which application this is; only the
   wordmark beside it goes. It is a single centred row again now that the collapse control has
   moved off it onto the sidebar's edge. */
html.nav-collapsed .brand-text { display: none !important; }
html.nav-collapsed .top-row { padding-left: 0 !important; }
html.nav-collapsed .top-row .container-fluid { justify-content: center; padding: 0; }
html.nav-collapsed .navbar-brand { gap: 0 !important; margin: 0; }
html.nav-collapsed .nav-text { display: none !important; }
html.nav-collapsed .nav-caret { display: none !important; }
html.nav-collapsed .nav-icon { margin-right: 0 !important; }
html.nav-collapsed .nav-item .nav-link { justify-content: center !important; padding-left: .4rem !important; padding-right: .4rem !important; }
html.nav-collapsed .nav-submenu .nav-link { padding-left: .4rem !important; }
html.nav-collapsed .version-footer { text-align: center; }
html.nav-collapsed .version-link { justify-content: center; }


/* ── ApexCharts chrome ─────────────────────────────────────────────────────
   The chart library ships a single light stylesheet and picks its dark variant from an option
   none of our dozen chart pages set, so every tooltip drew itself as a white card with a cold
   grey title band. Its tooltip text has no colour of its own and inherits the page's — cream on
   dark — which is why hovering a graph in dark mode gave white on white.

   Fixed here rather than in each chart's options: this is chrome, not data, and a shared
   stylesheet is the only place a fix reaches all twelve. Written against the theme tokens so it
   serves both modes; in light it also takes the library's cold greys off the paper canvas, the
   same reason the Bootstrap neutral scale is remapped above. Series colours stay where they are,
   in the pages that choose them. */
html .apexcharts-tooltip.apexcharts-theme-light {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    box-shadow: var(--shadow-md);
}

html .apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {
    background: var(--bg-subtle);
    border-bottom: 1px solid var(--border-color);
    color: var(--text-strong);
}

/* The axis crosshair labels — same light-only defaults, arrow included. */
html .apexcharts-xaxistooltip,
html .apexcharts-yaxistooltip {
    background: var(--bg-elevated);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
}

html .apexcharts-xaxistooltip-bottom:after { border-bottom-color: var(--bg-elevated); }
html .apexcharts-xaxistooltip-bottom:before { border-bottom-color: var(--border-color); }
html .apexcharts-xaxistooltip-top:after { border-top-color: var(--bg-elevated); }
html .apexcharts-xaxistooltip-top:before { border-top-color: var(--border-color); }
html .apexcharts-yaxistooltip-left:after { border-left-color: var(--bg-elevated); }
html .apexcharts-yaxistooltip-left:before { border-left-color: var(--border-color); }
html .apexcharts-yaxistooltip-right:after { border-right-color: var(--bg-elevated); }
html .apexcharts-yaxistooltip-right:before { border-right-color: var(--border-color); }

/* The export menu behind the toolbar hamburger, on the charts that show one. */
html .apexcharts-menu {
    background: var(--bg-elevated);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
}

html .apexcharts-menu-item:hover {
    background: var(--bg-card-hover);
}

/* Axis labels, axis titles and legend entries are drawn with the library's default foreground —
   a near-black that disappears on the ember ground. Apex writes those colours inline (as a fill
   style on the SVG text, as a colour on the legend span), so overriding them needs !important.
   Dark only: on paper the defaults are correct. */
html[data-theme="dark"] .apexcharts-xaxis-label,
html[data-theme="dark"] .apexcharts-yaxis-label,
html[data-theme="dark"] .apexcharts-xaxis-title text,
html[data-theme="dark"] .apexcharts-yaxis-title text,
html[data-theme="dark"] .apexcharts-datalabel,
html[data-theme="dark"] .apexcharts-datalabel-label {
    fill: var(--text-secondary) !important;
}

/* The figure in the middle of a donut is the one piece of chart text that should read as strong. */
html[data-theme="dark"] .apexcharts-datalabel-value {
    fill: var(--text-strong) !important;
}

html[data-theme="dark"] .apexcharts-legend-text {
    color: var(--text-secondary) !important;
}

/* Gridlines carry a hardcoded light grey from the pages' chart options; a presentation attribute
   loses to a stylesheet, so the theme can take them back without touching twelve files. */
html[data-theme="dark"] .apexcharts-gridline,
html[data-theme="dark"] .apexcharts-grid-borders line {
    stroke: var(--border-color);
}


/* ── Ranked bar list (isp-*) ───────────────────────────────────────────────
   A list of named things with a bar each — a logo or initials, the name, a bar scaled against the
   largest row, and the figures. Built for the investments dashboard's "Investment by Customer"
   split and moved here when the ROI report wanted the same treatment: it is page furniture used by
   more than one page now, like the hero above, so it belongs in the shared sheet rather than in one
   page's scoped file. The scoped copy is gone — do not re-add it. */
.isp-tabs .nav-link {
    border: 0;
    background: none;
    padding: 0.25rem 0.75rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
    border-bottom: 2px solid transparent;
    border-radius: 0;
}

.isp-tabs .nav-link:hover { color: var(--text-primary); }

.isp-tabs .nav-link.active {
    color: var(--accent);
    font-weight: 600;
    background: none;
    border-bottom-color: var(--accent);
}

.isp-list {
    display: flex;
    flex-direction: column;
}

/* Beside the chart the card is about a third of the page, so the name gets what it needs and the
   bar takes the rest — it is the one column that can shrink without losing meaning. */
.isp-row {
    display: grid;
    grid-template-columns: 30px minmax(64px, auto) minmax(30px, 1fr) auto 40px;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 4px;
    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;
    border-radius: var(--border-radius-sm);
    transition: background-color .12s;
}

.isp-row:hover { background: var(--nav-hover-bg); }
.isp-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Initials stand in for the customer logos in the design — we hold no logo for a customer. */
.isp-mark {
    width: 30px; height: 30px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--accent-light);
    color: var(--accent);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.isp-mark img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}

.isp-mark-others {
    background: var(--bg-subtle);
    color: var(--text-muted);
    letter-spacing: 0.08em;
}

.isp-name {
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.isp-bar {
    display: block;
    height: 22px;
    border-radius: 6px;
    background: var(--bg-subtle);
    overflow: hidden;
}

.isp-bar-fill {
    display: block;
    height: 100%;
    border-radius: 6px;
    background: var(--accent);
    min-width: 3px;
}

/* Each row further down is a little paler, so the ranking reads even where two bars are close. */
.isp-row:nth-child(2) .isp-bar-fill { background: color-mix(in srgb, var(--accent) 85%, transparent); }
.isp-row:nth-child(3) .isp-bar-fill { background: color-mix(in srgb, var(--accent) 70%, transparent); }
.isp-row:nth-child(4) .isp-bar-fill { background: color-mix(in srgb, var(--accent) 55%, transparent); }
.isp-row:nth-child(5) .isp-bar-fill { background: color-mix(in srgb, var(--accent) 42%, transparent); }
.isp-row:nth-child(n+6) .isp-bar-fill { background: color-mix(in srgb, var(--accent) 30%, transparent); }

.isp-value {
    font-weight: 700;
    color: var(--text-strong);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.isp-share {
    text-align: right;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* Narrow enough that the bar is no longer telling you anything — the figures still are. */
@media (max-width: 420px) {
    .isp-row { grid-template-columns: 28px minmax(64px, 1fr) auto 40px; }
    .isp-bar { display: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   AI run results
   Markdown rendered by AiResultRenderer. Everything here reads the theme tokens,
   so a result follows dark mode like the rest of the application — which is the
   reason the screen is styled from a stylesheet at all while the mail version has
   to carry its styles inline.
   ───────────────────────────────────────────────────────────────────────────── */
.ai-result { color: var(--text-primary); font-size: 0.9375rem; line-height: 1.6; }
.ai-result > *:first-child { margin-top: 0; }
.ai-result > *:last-child { margin-bottom: 0; }

.ai-result h1, .ai-result h2, .ai-result h3, .ai-result h4 {
    color: var(--text-strong);
    font-family: var(--font-display);
    font-weight: 700;
    margin: 1.5rem 0 0.5rem;
    line-height: 1.3;
}
.ai-result h1 { font-size: 1.2rem; }
.ai-result h2 { font-size: 1.08rem; }
.ai-result h3 { font-size: 0.98rem; }
.ai-result h4 { font-size: 0.92rem; color: var(--text-primary); }

.ai-result p { margin: 0 0 0.75rem; }
.ai-result ul, .ai-result ol { margin: 0 0 0.75rem; padding-left: 1.35rem; }
.ai-result li { margin-bottom: 0.3rem; }
.ai-result li > ul, .ai-result li > ol { margin-top: 0.3rem; }
.ai-result strong { color: var(--text-strong); font-weight: 650; }

.ai-result blockquote {
    margin: 0 0 0.9rem;
    padding: 0.5rem 0.9rem;
    border-left: 3px solid var(--border-color);
    color: var(--text-secondary);
}

.ai-result code {
    font-size: 0.85em;
    background: var(--bg-subtle);
    padding: 0.1rem 0.3rem;
    border-radius: 3px;
}
.ai-result pre {
    background: var(--bg-subtle);
    padding: 0.7rem 0.9rem;
    border-radius: 6px;
    overflow-x: auto;
    margin: 0 0 0.9rem;
}
.ai-result pre code { background: none; padding: 0; }

/* A weekly summary is mostly tables, and some of them are wider than the card.
   display:block turns the table into its own scroll container so a wide one
   scrolls sideways instead of pushing the whole page out. */
.ai-result table {
    display: block;
    overflow-x: auto;
    max-width: 100%;
    border-collapse: collapse;
    margin: 0 0 1rem;
    font-size: 0.85rem;
}
.ai-result th, .ai-result td {
    padding: 0.4rem 0.55rem;
    text-align: left;
    vertical-align: top;
    white-space: nowrap;
}
.ai-result th {
    background: var(--bg-subtle);
    color: var(--text-strong);
    font-weight: 650;
    border-bottom: 2px solid var(--border-color);
}
.ai-result td { border-bottom: 1px solid var(--border-subtle); }
.ai-result tbody tr:last-child td { border-bottom: 0; }
.ai-result tbody tr:hover td { background: var(--bg-card-hover); }

.ai-result hr { border: 0; border-top: 1px solid var(--border-color); margin: 1.25rem 0; }

/* ─────────────────────────────────────────────────────────────────────────────
   The assistant
   ───────────────────────────────────────────────────────────────────────────── */
.chat-shell {
    display: grid;
    grid-template-columns: 17rem 1fr;
    gap: 1rem;
    height: calc(100vh - 8.5rem);
    min-height: 26rem;
}
@media (max-width: 991.98px) {
    .chat-shell { grid-template-columns: 1fr; height: auto; }
    .chat-list { max-height: 12rem; }
    .chat-thread { height: calc(100vh - 20rem); }
}

.chat-list {
    overflow-y: auto;
    padding-right: 0.25rem;
    min-width: 0;
}
.chat-list-item {
    display: block;
    padding: 0.45rem 0.6rem;
    border-radius: 7px;
    text-decoration: none;
    color: var(--text-primary);
    margin-bottom: 0.15rem;
}
.chat-list-item:hover { background: var(--bg-card-hover); }
.chat-list-item.active { background: var(--accent-light); color: var(--accent); }
.chat-list-title {
    display: block;
    font-size: 0.875rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-list-meta { display: block; font-size: 0.72rem; color: var(--text-muted); }

.chat-thread {
    display: flex;
    flex-direction: column;
    /* Both of these are load-bearing. A grid item defaults to min-width:auto, so one long
       paragraph or a wide table stretches the column past the viewport and the whole page
       scrolls sideways — including the composer, off the bottom right. min-height does the
       same job vertically, without which the message list cannot scroll and pushes the
       composer off the screen instead. */
    min-width: 0;
    min-height: 0;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    overflow: hidden;
}
.chat-messages {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-wrap: anywhere;
    padding: 1.1rem 1.25rem;
    scroll-behavior: smooth;
}
.chat-empty {
    margin: auto;
    padding: 2rem;
    max-width: 34rem;
    text-align: center;
}

.chat-msg { margin-bottom: 1.35rem; }
.chat-msg.from-user { display: flex; justify-content: flex-end; }
.chat-bubble {
    background: var(--accent);
    color: var(--text-on-accent);
    padding: 0.55rem 0.85rem;
    border-radius: 14px 14px 3px 14px;
    max-width: min(42rem, 82%);
    white-space: pre-wrap;
}

.chat-working { display: flex; align-items: center; gap: 0.5rem; color: var(--text-secondary); font-size: 0.9rem; }

/* ── Mora ─────────────────────────────────────────────────────────────────────
   The assistant has a face. He appears in exactly three places and is sized by how
   much of the screen is idle at that moment: large on a blank conversation, small
   while thinking, and a badge on an open thread. Anywhere else he would be
   decoration competing with the answer, which is the thing people came for. */

.mora-hero {
    display: block;
    margin: 0 auto 0.75rem;
    /* The art is a cutout on white; the drop shadow is what stops it floating on
       the dark theme's ground. */
    filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.18));
    animation: mora-arrive 0.5s ease-out both;
}

@keyframes mora-arrive {
    from { opacity: 0; transform: translateY(8px) scale(0.96); }
    to   { opacity: 1; transform: none; }
}

/* Thinking. A gentle bob — he is working, not buffering. Slow on purpose: at this
   size anything quicker reads as agitation, and the wait it accompanies is a
   minute or more. */
/* The HEAD crop, not the whole figure. Below roughly 80px the full character — arm,
   tablet, feet — collapses into a blue smudge and reads as a loading artefact rather
   than a face. The head keeps the two things that identify him: the ring and the
   smile. */
.mora-thinking {
    flex: 0 0 auto;
    animation: mora-bob 2.4s ease-in-out infinite;
}

@keyframes mora-bob {
    0%, 100% { transform: translateY(0) rotate(-1.5deg); }
    50%      { transform: translateY(-4px) rotate(1.5deg); }
}

/* The three dots after the label, so there is still a sign of life for anyone who
   has turned animation off — see the reduced-motion block below, which stops the
   bob but leaves these fading. */
.mora-dots { display: inline-flex; gap: 3px; margin-left: 0.15rem; }

.mora-dots i {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.35;
    animation: mora-dot 1.4s ease-in-out infinite;
}

.mora-dots i:nth-child(2) { animation-delay: 0.2s; }
.mora-dots i:nth-child(3) { animation-delay: 0.4s; }

@keyframes mora-dot {
    0%, 60%, 100% { opacity: 0.25; }
    30%           { opacity: 1; }
}

/* On an open thread he is a mark, not a mascot: enough to say whose voice this is
   without sitting next to every answer. */
.mora-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-left: auto;
    padding: 0.1rem 0.5rem 0.1rem 0.2rem;
    border-radius: 999px;
    background: var(--bs-tertiary-bg, rgba(127, 127, 127, 0.12));
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .mora-hero, .mora-thinking { animation: none; }
}
.chat-steps {
    list-style: none;
    margin: 0.5rem 0 0;
    padding-left: 1.6rem;
    font-size: 0.82rem;
    color: var(--text-muted);
}
.chat-steps li { margin-bottom: 0.15rem; }

.chat-actions {
    display: flex; align-items: center; flex-wrap: wrap; gap: 0.35rem;
    margin-top: 0.7rem; padding-top: 0.6rem;
    border-top: 1px solid var(--border-subtle);
}

.chat-composer {
    flex: 0 0 auto;
    display: flex;
    gap: 0.5rem;
    align-items: flex-end;
    padding: 0.7rem 0.85rem;
    border-top: 1px solid var(--border-color);
    background: var(--bg-elevated);
}
.chat-composer textarea { resize: none; }

/* Conversation rows carry a delete control, so the row is a flex container and the link
   takes the space that is left. */
.chat-list-item { display: flex; align-items: center; gap: 0.25rem; }
.chat-list-link { flex: 1 1 auto; min-width: 0; text-decoration: none; color: inherit; }
.chat-list-delete {
    flex: 0 0 auto;
    border: 0; background: none; line-height: 1;
    font-size: 1.05rem; padding: 0 0.3rem; border-radius: 4px;
    color: var(--text-muted); opacity: 0;
}
.chat-list-item:hover .chat-list-delete { opacity: 1; }
.chat-list-delete:hover { color: var(--danger); background: var(--bg-subtle); }
.chat-list-item.active .chat-list-delete { opacity: 1; }

.chat-shared-tag {
    margin-left: 0.35rem; padding: 0 0.3rem; border-radius: 3px;
    background: var(--bg-subtle); color: var(--text-secondary); font-size: 0.66rem;
}

.chat-header {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.5rem 0.85rem;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-elevated);
}
.chat-header-title {
    flex: 1 1 auto; min-width: 0;
    font-weight: 600; font-size: 0.9rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.chat-share {
    flex: 0 0 auto;
    padding: 0.7rem 0.85rem;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-subtle);
}
.chat-share-chip {
    display: inline-flex; align-items: center; gap: 0.15rem;
    background: var(--bg-card); border: 1px solid var(--border-color);
    border-radius: 999px; padding: 0.1rem 0.5rem;
    font-size: 0.78rem; margin: 0 0.3rem 0.3rem 0;
}

.chat-banner {
    flex: 0 0 auto;
    padding: 0.5rem 0.85rem;
    background: var(--accent-light);
    color: var(--text-secondary);
    font-size: 0.82rem;
    border-bottom: 1px solid var(--border-color);
}

/* A month of daily spend, drawn as bars. Deliberately not a charting library: twenty-eight
   numbers whose shape is the whole message do not need one. */
.usage-bars { display: flex; align-items: flex-end; gap: 3px; height: 8rem; }
.usage-bar { flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end;
             height: 100%; min-width: 0; }
.usage-bar-fill { background: var(--accent); border-radius: 2px 2px 0 0; min-height: 2px; }
.usage-bar-label { font-size: 0.6rem; color: var(--text-muted); text-align: center;
                   margin-top: 2px; white-space: nowrap; overflow: hidden; }

/* ── Attaching files to a message ──────────────────────────────────────────────
   The composer is the drop target. The file input is stretched invisibly across it,
   because a browser will only hand a page a dropped file through an <input type=file>
   — there is no way to read one from a drop event otherwise. */
.chat-composer { position: relative; }
.chat-composer-main { flex: 1 1 auto; min-width: 0; }

.chat-drop-input {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    opacity: 0; cursor: pointer; z-index: 2;
}
.chat-composer.dragging { outline: 2px dashed var(--accent); outline-offset: -4px; }
.chat-composer.dragging::after {
    content: "Drop to attach";
    position: absolute; inset: 0; z-index: 3;
    display: flex; align-items: center; justify-content: center;
    background: var(--accent-light); color: var(--accent);
    font-size: .85rem; font-weight: 600; pointer-events: none;
}
/* The textarea and Send must stay clickable when nothing is being dragged. */
.chat-composer:not(.dragging) .chat-drop-input { width: 2.2rem; height: 2.2rem; inset: auto auto .6rem .6rem; }
.chat-composer:not(.dragging) .chat-composer-main { margin-left: 2.4rem; }
.chat-composer::before {
    content: "📎";
    position: absolute; left: .75rem; bottom: .95rem;
    font-size: .95rem; opacity: .55; pointer-events: none; z-index: 1;
}
.chat-composer.dragging::before { display: none; }

.chat-staged { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .35rem; }
.chat-file {
    display: inline-flex; align-items: center; gap: .3rem;
    background: var(--bg-subtle); border: 1px solid var(--border-color);
    border-radius: 999px; padding: .1rem .5rem; font-size: .75rem;
    color: var(--text-secondary); text-decoration: none;
}
.chat-file.unreadable { border-color: var(--warning); }
.chat-file.sent {
    background: rgba(255,255,255,.18); border-color: rgba(255,255,255,.35);
    color: var(--text-on-accent);
}
.chat-file.sent:hover { background: rgba(255,255,255,.3); }
.chat-bubble-files { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .4rem; }

/* ── The margin condition matrix ───────────────────────────────────────────────
   The three columns are tinted because they are three different commercial
   situations, not three numbers in a row — the colour is what stops somebody
   typing a campaign margin into the standard column. */
.margin-matrix td, .margin-matrix th { vertical-align: middle; }
.margin-matrix .col-standard { background: rgba(46, 158, 91, .07); }
.margin-matrix .col-campaign { background: rgba(232, 104, 31, .07); }
.margin-matrix .col-special  { background: rgba(220, 76, 62, .07); }
.margin-matrix tr.matrix-category { background: var(--bg-subtle); }
.margin-matrix tr.matrix-category td { font-weight: 600; }
.margin-matrix .matrix-cell {
    max-width: 7rem; margin: 0 auto; background: transparent; border-color: transparent;
}
.margin-matrix .matrix-cell:focus { background: var(--bg-card); border-color: var(--accent); }
.margin-matrix .matrix-cell::placeholder { color: var(--text-muted); opacity: .6; }

/* A figure that fell through to the group's own percentage rather than being agreed for this
   customer. Faint on purpose — the whole point of the preview is telling the two apart. */
.margin-default { color: var(--text-muted); font-style: italic; }

/* ══ Reporting page chrome ════════════════════════════════════════════════════
   Shared by the reporting screens rather than copied between them: market
   reporting drew these first, action signals asked for the same, and a second
   copy is how two pages that are meant to match stop matching. Global rather
   than scoped for the same reason — a scoped copy per page IS the duplication.
   ════════════════════════════════════════════════════════════════════════════ */
/* ── Page head ─────────────────────────────────────────────────────────────
   The title and, on the store tab, the invitation to ask Mora instead. */
.pg-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

/* ── The figures across the top ────────────────────────────────────────────
   Three readings and one invitation, on one row. Each figure carries its own
   hue at a low mix so the boxes read as a set rather than four loose chips,
   and the number is set at the weight the investment flow gives its stages —
   which is the point of the whole change: these are the page's headline, and
   they used to be styled like form labels. */
.kpi-row {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px;
}

.kpi {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 12px;
    background: color-mix(in srgb, var(--kpi) 9%, var(--bg-card));
    border: 1px solid color-mix(in srgb, var(--kpi) 22%, transparent);
    min-width: 0;
}

.kpi-icon {
    width: 38px; height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--kpi) 16%, var(--bg-card));
    color: var(--kpi);
    display: flex; align-items: center; justify-content: center;
}

.kpi-icon svg {
    width: 19px; height: 19px;
    stroke: currentColor; fill: none;
    stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

.kpi-body { min-width: 0; }

.kpi-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    line-height: 1.2;
}

.kpi-value {
    font-size: 26px;
    font-weight: 700;
    color: var(--text-strong);
    line-height: 1.15;
    margin-top: 2px;
    /* Long unit counts must not wrap into the note underneath. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.kpi-note {
    font-size: 11px;
    color: var(--text-muted);
    line-height: 1.25;
    margin-top: 2px;
}

/* ── Ask Mora ──────────────────────────────────────────────────────────────
   Warm where the figures are cool, because it is an offer rather than a
   reading — the one thing on the row that does something when clicked. */
.ask-mora {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px 10px 10px;
    border-radius: 12px;
    text-decoration: none;
    background: linear-gradient(135deg,
        color-mix(in srgb, #f59e0b 16%, var(--bg-card)),
        color-mix(in srgb, #fb7185 12%, var(--bg-card)));
    border: 1px solid color-mix(in srgb, #f59e0b 30%, transparent);
    min-width: 0;
    transition: transform .15s, box-shadow .15s;
}

.ask-mora:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 14px rgba(16, 24, 40, .14);
}

.ask-mora-face {
    width: 54px; height: 54px;
    flex-shrink: 0;
    object-fit: contain;
    object-position: top center;
}

.ask-mora-body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.ask-mora-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-strong);
    line-height: 1.2;
}

.ask-mora-sub {
    font-size: 11px;
    color: var(--text-secondary);
    line-height: 1.25;
}

.ask-mora-go {
    width: 18px; height: 18px;
    margin-left: auto;
    flex-shrink: 0;
    stroke: var(--text-secondary); fill: none;
    stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

/* Beside the page title the card has no column to fill, so it takes its own width. */
.ask-mora-compact {
    padding: 8px 12px 8px 8px;
    min-width: 260px;
}

.ask-mora-compact .ask-mora-face { width: 44px; height: 44px; }

/* ── Table headings ────────────────────────────────────────────────────────
   The testers read the old headings as part of the data. They are the labels
   for it, so they are now the darkest text in the table rather than the
   lightest. */
.bold-head thead th {
    font-weight: 700;
    color: var(--text-strong);
    text-transform: none;
    letter-spacing: 0;
}

/* The figure row folds before the page does: four boxes on one line need the width. */
@media (max-width: 1200px) {
    .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
    .kpi-row { grid-template-columns: 1fr; }
}

/* ── Country flags ────────────────────────────────────────────────────────────
   Drawn by CountryFlag.razor rather than typed as an emoji, because Windows ships
   no flag glyphs — see that component for the whole story. A hairline border so a
   flag with a white edge (Finland, Ireland) still reads as a rectangle on a pale
   page instead of bleeding into it. */
.cflag {
    width: 18px;
    height: 12px;
    flex-shrink: 0;
    margin-right: 6px;
    vertical-align: -1px;
    border-radius: 2px;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .14);
}

/* The fallback for a country we hold no drawing for: the code, said plainly. */
.cflag-code {
    display: inline-block;
    margin-right: 6px;
    padding: 0 4px;
    border-radius: 3px;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .02em;
    line-height: 1.35;
    vertical-align: 1px;
    background: var(--bg-subtle);
    color: var(--text-secondary);
}
