/* ==========================================================================
   Carbonly design system — eco styling, powered by Steorra Solutions.
   Brand tokens are defaults; tenants override --tenant-primary/--tenant-secondary
   via the hot-reloaded tenant config (emitted in App.razor). Fonts are
   self-hosted (OFL): Sora for display, Inter for text.
   ========================================================================== */

@font-face {
    font-family: 'Inter';
    src: url('fonts/inter-latin.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Sora';
    src: url('fonts/sora-latin.woff2') format('woff2');
    font-weight: 100 800;
    font-style: normal;
    font-display: swap;
}

:root {
    /* Carbonly brand palette */
    --c-pine: #0E5C4A;        /* primary — deep pine */
    --c-pine-deep: #0A3D31;   /* sidebar depths, hover */
    --c-leaf: #5FAF7F;        /* growth accent */
    --c-leaf-soft: #E4F1E8;   /* tinted surfaces */
    --c-sun: #F2B705;         /* amber — the carbon dot */
    --c-paper: #F6F5EF;       /* warm eco paper ground */
    --c-surface: #FFFFFF;
    --c-ink: #1C2A24;
    --c-ink-soft: #52645B;
    --c-line: #E1E4DA;
    --c-danger: #B3372B;
    --c-ok: #2E7D4F;

    /* Effective theme colours (tenant config wins when set) */
    --brand-primary: var(--tenant-primary, var(--c-pine));
    --brand-secondary: var(--tenant-secondary, var(--c-sun));

    --font-display: 'Sora', 'Inter', 'Segoe UI', system-ui, sans-serif;
    --font-text: 'Inter', 'Segoe UI', system-ui, sans-serif;

    /* Tints shared by every brand-tinted surface (row expansions, working panels,
       the two-step flow band) — one ground and one hairline, so an open row, the
       panel it opens and the cards inside it all read as the same block. */
    --c-tint: color-mix(in srgb, var(--brand-primary) 7%, var(--c-surface));
    --c-tint-strong: color-mix(in srgb, var(--brand-primary) 13%, var(--c-surface));
    --c-tint-line: color-mix(in srgb, var(--brand-primary) 22%, var(--c-line));

    --radius: 12px;
    --radius-sm: 8px;
    --shadow-soft: 0 1px 2px rgba(28, 42, 36, 0.06), 0 8px 24px -12px rgba(28, 42, 36, 0.18);
}

html, body {
    font-family: var(--font-text);
    background-color: var(--c-paper);
    color: var(--c-ink);
}

/* Sections scrolled to via a fragment (dashboard attention links) clear the sticky top bar */
[id] {
    scroll-margin-top: 4.5rem;
}

h1, h2, h3, .navbar-brand {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--c-ink);
    letter-spacing: -0.01em;
    text-wrap: balance;
}

h1 { font-size: clamp(1.5rem, 1.2rem + 1.5vw, 2.1rem); }
h2 { font-size: clamp(1.15rem, 1rem + 0.8vw, 1.5rem); }

.lead {
    color: var(--c-ink-soft);
    max-width: 62ch;
}

a, .btn-link {
    color: var(--brand-primary);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
}

a:hover, .btn-link:hover {
    color: var(--c-pine-deep);
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
    border-radius: var(--radius-sm);
    font-weight: 500;
    transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

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

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

/* Solid success/danger buttons keep Bootstrap's semantics but use the Carbonly
   palette instead of Bootstrap's stock green/red, so "Approve answer", "Import
   … into the ledger" and armed delete buttons sit in the same family as the rest. */

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

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

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

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

/* Link-styled buttons ("Clear filters", "Enter them manually", "Copy draft…"):
   same voice as navigational links — semibold brand text, underline only on
   hover. The sidebar's logout button (.btn-link.nav-link) keeps the nav look. */

.btn-link:not(.nav-link) {
    font-weight: 600;
    text-decoration: none;
}

.btn-link:not(.nav-link):hover, .btn-link:not(.nav-link):focus-visible {
    color: var(--c-pine-deep);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Tonal buttons — the Bootstrap outline variants are restyled app-wide into
   soft filled ("tonal") buttons: tinted ground, no hard outline, solid brand
   fill on hover. Markup keeps using btn-outline-* so Bootstrap's disabled /
   sizing behaviour still applies. */

.btn-outline-primary, .btn-outline-success {
    color: var(--c-pine-deep);
    background-color: var(--c-leaf-soft);
    border-color: transparent;
}

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

.btn-outline-secondary, .btn-outline-dark {
    color: var(--c-ink);
    background-color: #ECEEE6;
    border-color: transparent;
}

.btn-outline-secondary:hover, .btn-outline-secondary:focus, .btn-outline-secondary:active,
.btn-outline-secondary.active,
.btn-outline-dark:hover, .btn-outline-dark:focus, .btn-outline-dark:active,
.btn-outline-dark.active {
    color: var(--c-pine-deep) !important;
    background-color: #DDE2D4 !important;
    border-color: transparent !important;
}

.btn-outline-danger {
    color: var(--c-danger);
    background-color: #F9ECEA;
    border-color: transparent;
}

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

.btn-outline-primary:disabled, .btn-outline-secondary:disabled,
.btn-outline-danger:disabled, .btn-outline-success:disabled, .btn-outline-dark:disabled {
    color: var(--c-ink-soft);
    background-color: #EFF0EA;
    border-color: transparent;
    opacity: 0.65;
}

/* Solid buttons spend a lot of their life disabled (an action that needs a period
   picked, or rows ticked, first). Bootstrap's stock 0.65 opacity leaves a washed,
   faintly dirty pine; a flat muted ground reads as deliberately inert instead. */

.btn-primary:disabled, .btn-primary.disabled,
.btn-success:disabled, .btn-success.disabled,
.btn-danger:disabled, .btn-danger.disabled {
    color: var(--c-ink-soft) !important;
    background-color: #E7E9E1 !important;
    border-color: transparent !important;
    opacity: 1;
}

/* The round "?" that sits beside an action and opens its explainer popover. */

.btn-help {
    flex-shrink: 0;
    width: 1.7rem;
    height: 1.7rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    font-weight: 700;
}

/* --- Badges -------------------------------------------------------------- */
/* Status pills app-wide: Bootstrap's stock #ffc107 / #198754 / #6c757d are the one
   place the UI still shouted in another palette. Same semantics, Carbonly colours,
   pill-shaped so they never read as a small button. */

.badge {
    font-weight: 600;
    border-radius: 999px;
    padding: 0.32em 0.7em;
    letter-spacing: 0.01em;
}

.badge.text-bg-success {
    color: #fff !important;
    background-color: var(--c-ok) !important;
}

.badge.text-bg-warning {
    color: #6A4C00 !important;
    background-color: color-mix(in srgb, var(--c-sun) 32%, var(--c-surface)) !important;
}

.badge.text-bg-danger {
    color: #fff !important;
    background-color: var(--c-danger) !important;
}

.badge.text-bg-primary, .badge.text-bg-info {
    color: var(--c-pine-deep) !important;
    background-color: var(--c-leaf-soft) !important;
}

.badge.text-bg-light {
    color: var(--c-ink-soft) !important;
    background-color: #ECEEE6 !important;
}

.badge.text-bg-secondary {
    color: var(--c-ink) !important;
    background-color: #DDE2D4 !important;
}

/* --- Arrow links --------------------------------------------------------- */
/* "Open the workbook" style navigational links, styled as tonal pill chips so
   they read as buttons, not underlined text — tinted ground, semibold brand
   colour, an arrow glyph that nudges right on hover, solid fill on hover
   (same family as the tonal .btn-outline-* buttons). Markup supplies the text
   only — the arrow comes from ::after, so it never wraps away from the label. */

.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.28rem 0.8rem;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--c-pine-deep);
    background-color: var(--c-leaf-soft);
    text-decoration: none;
    border-radius: 999px;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.link-arrow::after {
    content: "\2192";
    font-weight: 400;
    transition: transform 0.15s ease;
}

/* A button wearing the pill (opens the document reader in place): the pill supplies its own
   ground and text, so only the browser's button border has to go. */
button.link-arrow {
    border: 0;
}

/* Inside tinted alerts the leaf-soft chip would vanish into the alert ground —
   give it a surface-white pill instead. */
.alert .link-arrow {
    background-color: var(--c-surface);
}

.link-arrow:hover, .link-arrow:focus-visible {
    color: #fff;
    background-color: var(--brand-primary);
    text-decoration: none;
}

.link-arrow:hover::after, .link-arrow:focus-visible::after {
    transform: translateX(3px);
}

/* Variant for links that leave the app or open a new tab (gov.uk provenance,
   supplier websites, stored documents): a north-east arrow instead of →. */
.link-arrow.link-ext::after {
    content: "\2197";
}

/* --- Grid toolbar & pager ------------------------------------------------ */
/* Every grid gets the same furniture: a .grid-toolbar row directly above the
   table (filters left, actions such as export right) and a .pager row under
   it. Both wrap cleanly on narrow screens. */

.grid-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.grid-toolbar .form-control {
    flex: 0 1 16rem;
    width: auto;
    min-width: 0;
}

.grid-toolbar .form-select {
    width: auto;
    min-width: 0;
}

/* The category filter sits beside the search box on desktop; the cap lives here
   (not inline) so the narrow-screen rules below can stretch it full-width. */
.grid-toolbar .category-filter {
    max-width: 16rem;
}

.grid-toolbar-spacer {
    flex: 1 1 auto;
}

.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
    margin-bottom: 1rem;
}

.pager .pager-status {
    font-size: 0.85rem;
    color: var(--c-ink-soft);
    font-variant-numeric: tabular-nums;
}

/* GridPager's rows-per-page dropdown: an inline "Show [25] per page" phrase. */
.pager .pager-size {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: auto;
    font-size: 0.85rem;
    color: var(--c-ink-soft);
    white-space: nowrap;
}

.pager .pager-size .form-select {
    width: auto;
}

/* --- Grid headers -------------------------------------------------------- */
/* Every grid's header row reads as an eyebrow rather than as body text: small, uppercase,
   letter-spaced and muted over a 2px rule, so the eye goes straight to the data. Labels
   never wrap — a two-word heading breaking mid-phrase ("Usual / category") doubled the
   header's height and pushed the sort indicator onto a line of its own. Grids already
   scroll sideways inside .table-responsive, which is the right trade for a data table.
   Only header cells are touched: a th used as a row label inside tbody keeps body text. */

.table > thead > tr > th {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--c-ink-soft);
    white-space: nowrap;
    vertical-align: bottom;
    border-bottom-width: 2px;
    border-bottom-color: var(--c-line);
}

/* Sortable column headers (SortableTh): the whole label is a button. A faint ↕ marks a
   sortable column; the active column's ▲/▼ shows at full strength. */
th .sort-btn {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    cursor: pointer;
    text-align: inherit;
    white-space: nowrap;
    transition: color 0.12s ease;
}

th .sort-btn:hover, th .sort-btn:focus-visible {
    color: var(--brand-primary);
}

th.text-end .sort-btn {
    width: 100%;
    justify-content: flex-end;
}

/* The indicator holds its own width whatever glyph is in it, so switching columns never
   nudges the label sideways. */
th .sort-ind {
    flex-shrink: 0;
    width: 0.7em;
    font-size: 0.8em;
    line-height: 1;
    opacity: 0.35;
}

th[aria-sort="ascending"] .sort-ind,
th[aria-sort="descending"] .sort-ind {
    opacity: 1;
    color: var(--brand-primary);
}

/* The sorted column keeps a faint tint, so "what am I looking at" survives a scroll. */
.table > thead > tr > th[aria-sort="ascending"],
.table > thead > tr > th[aria-sort="descending"] {
    color: var(--c-pine-deep);
    border-bottom-color: var(--brand-primary);
}

@media (max-width: 640.98px) {
    .grid-toolbar .form-control, .grid-toolbar .form-select {
        flex: 1 1 8rem;
    }

    .grid-toolbar > .btn, .grid-toolbar-actions > .btn {
        flex: 0 0 auto;
    }
}

.btn:focus-visible, .btn:focus, .btn:active:focus, .btn-link.nav-link:focus,
.form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.12rem var(--c-paper), 0 0 0 0.3rem var(--c-leaf);
}

/* --- Forms -------------------------------------------------------------- */

.form-control, .form-select {
    border-radius: var(--radius-sm);
    border-color: var(--c-line);
    background-color: var(--c-surface);
}

.form-control:focus {
    border-color: var(--c-leaf);
}

/* Checkboxes and radios: proper Bootstrap form-checks in the brand palette — a visible
   resting border, brand hover/focus, brand fill when checked. */
.form-check-input {
    width: 1.05em;
    height: 1.05em;
    border: 1.5px solid color-mix(in srgb, var(--c-ink-soft) 55%, var(--c-surface));
    cursor: pointer;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}

.form-check-input:hover:not(:disabled) {
    border-color: var(--brand-primary);
}

.form-check-input:focus {
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--brand-primary) 20%, transparent);
}

.form-check-input:disabled {
    cursor: not-allowed;
}

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

/* --- Two-step supplier flow band ----------------------------------------- */
/* Supplier data has a fixed order: ASK the supplier first (Step 1), and only
   research their public disclosures (Step 2) once that request has run its course —
   the request plus two monthly reminders, then "No response". The band states that
   order instead of offering two equal-looking buttons: numbered steps, an arrow for
   the hand-off, and a live status line under each. */

.flow-steps {
    display: grid;
    grid-template-columns: 1fr auto 1fr auto 1fr;
    align-items: stretch;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.flow-step {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 0;
    border: 1px solid var(--c-tint-line);
    border-radius: var(--radius);
    background: var(--c-tint);
    padding: 0.85rem 1rem 0.9rem;
}

/* Step 2 waits on Step 1: with nothing yet ready for it, it sits back on plain
   surface so the eye lands on Step 1 first. */
.flow-step.is-waiting {
    background: var(--c-surface);
    border-color: var(--c-line);
}

.flow-step-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.flow-step-number {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 50%;
    background: var(--brand-primary);
    color: #fff;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 700;
}

.flow-step.is-waiting .flow-step-number {
    background: var(--c-tint-strong);
    color: var(--c-pine-deep);
}

.flow-step-eyebrow {
    display: block;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--brand-primary);
}

.flow-step-title {
    margin: 0;
    font-size: 1rem;
    line-height: 1.2;
}

.flow-step-body {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--c-ink-soft);
}

.flow-step-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: auto;
    padding-top: 0.15rem;
}

/* Live state for the step: how many requests are out, how many came back, how many
   suppliers have fallen through to the next step. */
.flow-step-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.9rem;
    margin: 0;
    font-size: 0.78rem;
    color: var(--c-ink-soft);
}

.flow-step-status .status-count {
    font-weight: 600;
    color: var(--c-ink);
    font-variant-numeric: tabular-nums;
}

/* Something is waiting for the user right now (a response to review, suppliers ready
   for Step 2) — the one line on the step that should catch the eye. */
.flow-step-status .status-live {
    color: var(--c-pine-deep);
    font-weight: 600;
}

/* "see which" on a Step 2 exclusion line: the supplier names live in its tooltip, so a
   long tick list reads as one short line instead of a paragraph of names. */
.flow-step-status .status-names {
    margin-left: 0.35rem;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    cursor: help;
    white-space: nowrap;
}

/* The hand-off between the steps: sideways on a wide screen, downwards when stacked. */
.flow-steps-arrow {
    display: grid;
    place-items: center;
    color: var(--c-tint-line);
    font-size: 1.5rem;
    line-height: 1;
}

.flow-steps-arrow::before {
    content: "\2192";
}

@media (max-width: 900px) {
    .flow-steps {
        grid-template-columns: 1fr;
    }

    .flow-steps-arrow::before {
        content: "\2193";
    }
}

/* Narrow screens: the toolbar stacks — search full-width, buttons two-up — instead of
   ragged wrapping, and each step's action stretches across its card. */
@media (max-width: 640.98px) {
    .grid-toolbar .form-control {
        flex: 1 1 100%;
    }

    .grid-toolbar > .btn {
        flex: 1 1 calc(50% - 0.25rem);
    }

    .flow-step-actions > .btn {
        flex: 1 1 auto;
        white-space: normal;
    }
}

/* Expander strip at the bottom of each supplier row. The whole strip is the hit target,
   but the affordance is a centred pill with hairlines running out to the row edges, so the
   strip reads as a row divider AND a control. It previously showed a bare dot and a naked
   number on an invisible band — nothing said what opening it would give you, so the pill
   now carries a label and the count sits in a badge. */
.row-expander td {
    padding: 0;
}

.row-expander button {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    border: 0;
    background: none;
    padding: 0.25rem 0.75rem 0.4rem;
    cursor: pointer;
    color: var(--c-ink-soft);
}

/* Hairlines either side of the pill, filling the row width. */
.row-expander button::before,
.row-expander button::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--c-line);
}

.row-expander .expander-pill {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    gap: 0.4rem;
    padding: 0.28rem 0.75rem;
    border: 1px solid var(--c-line);
    border-radius: 999px;
    background: var(--c-surface);
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* A row that actually holds results advertises it before you hover. */
.row-expander.has-results .expander-pill {
    border-color: var(--c-tint-line);
    background: var(--c-tint);
    color: var(--c-pine-deep);
}

.row-expander button:hover .expander-pill,
.row-expander button:focus-visible .expander-pill,
.row-expander.is-open .expander-pill {
    background: var(--brand-primary);
    border-color: var(--brand-primary);
    color: #fff;
}

.row-expander button:focus {
    outline: none;
}

.row-expander button:focus-visible .expander-pill {
    box-shadow: 0 0 0 0.12rem var(--c-paper), 0 0 0 0.3rem var(--c-leaf);
}

/* Open: the strip is the handle of the panel below, so its hairlines join the panel's tint. */
.row-expander.is-open button::before,
.row-expander.is-open button::after {
    background: var(--c-tint-line);
}

/* The count badge is the "there is something here" signal the loose dot used to carry. */
.row-expander .expander-count {
    display: inline-grid;
    place-items: center;
    min-width: 1.2rem;
    height: 1.2rem;
    padding: 0 0.3rem;
    margin-left: -0.15rem;
    border-radius: 999px;
    background: var(--brand-primary);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.row-expander button:hover .expander-count,
.row-expander button:focus-visible .expander-count,
.row-expander.is-open .expander-count {
    background: var(--c-surface);
    color: var(--brand-primary);
}

/* State colours on the count badge: red means a lookup failed and needs attention, amber
   means something is waiting for the user's review, green means everything is allocated.
   The badge keeps its tone when the pill inverts on hover/open — state must stay legible. */
.row-expander.tone-danger .expander-count {
    background: var(--c-danger);
}

.row-expander.tone-warning .expander-count {
    background: var(--c-sun);
    color: var(--c-ink);
}

.row-expander.tone-ok .expander-count {
    background: var(--c-ok);
}

.row-expander.tone-danger button:hover .expander-count,
.row-expander.tone-danger button:focus-visible .expander-count,
.row-expander.tone-danger.is-open .expander-count {
    background: var(--c-surface);
    color: var(--c-danger);
}

.row-expander.tone-warning button:hover .expander-count,
.row-expander.tone-warning button:focus-visible .expander-count,
.row-expander.tone-warning.is-open .expander-count {
    background: var(--c-sun);
    color: var(--c-ink);
}

.row-expander.tone-ok button:hover .expander-count,
.row-expander.tone-ok button:focus-visible .expander-count,
.row-expander.tone-ok.is-open .expander-count {
    background: var(--c-surface);
    color: var(--c-ok);
}

.row-expander .chevron {
    display: inline-block;
    width: 0.4em;
    height: 0.4em;
    margin-left: 0.05rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translateY(-1px);
    transition: transform 0.15s ease;
}

.row-expander button[aria-expanded="true"] .chevron {
    transform: rotate(225deg) translateY(1px);
}

/* Card-mode grids on narrow screens (design-system pattern, first built for the supplier
   grid): the table becomes a stack of cards — .cell-select / .cell-name / .cell-actions as
   the card header row, every .cell-kv column an eyebrow-labelled line via its data-label,
   .cell-hide-mobile dropped as secondary — so nothing ever needs sideways scrolling.
   Opt a grid in with .card-grid on the table, .card-grid-wrap on its wrapper, .card-row on
   each data row and the cell classes + data-label on the tds. Same markup as desktop; the
   child combinators are load-bearing — they keep tables INSIDE expansions rendering as
   tables (unless those opt in themselves). */
@media (max-width: 640.98px) {
    .grid-toolbar > .form-select {
        flex: 1 1 100%;   /* Category filter on its own line, so Select all / Deselect all pair up */
        max-width: none;
    }

    .card-grid-wrap {
        border: 0;
        background: transparent;
        box-shadow: none;
        overflow: visible;
    }

    .card-grid,
    .card-grid > tbody {
        display: block;
        width: 100%;
    }

    .card-grid > thead {
        display: none;
    }

    .card-grid > tbody > tr {
        display: block;
    }

    .card-grid > tbody > tr > td {
        display: block;
        padding: 0;
        border: 0;
        background: none;
    }

    .card-grid > tbody > tr.card-row {
        display: grid;
        grid-template-columns: auto 1fr auto;
        column-gap: 0.6rem;
        align-items: start;
        padding: 0.75rem 0.75rem 0.5rem;
        margin-top: 0.75rem;
        border: 1px solid var(--c-line);
        border-radius: var(--radius-sm);
        background: var(--c-surface);
    }

    /* No checkbox column: the name starts at the card's left edge. */
    .card-grid > tbody > tr.card-row:not(:has(> td.cell-select)) {
        grid-template-columns: 1fr auto;
    }

    .card-grid > tbody > tr.card-row:not(:has(> td.cell-select)) > td.cell-name {
        grid-column: 1;
    }

    .card-grid > tbody > tr.card-row:not(:has(> td.cell-select)) > td.cell-actions {
        grid-column: 2;
    }

    .card-grid td.cell-select {
        grid-column: 1;
        grid-row: 1;
        padding-top: 0.1rem;
    }

    .card-grid td.cell-name {
        grid-column: 2;
        grid-row: 1;
        padding-bottom: 0.35rem;
    }

    .card-grid td.cell-actions {
        grid-column: 3;
        grid-row: 1;
        text-align: right;
    }

    /* Each data column becomes an eyebrow-labelled line, value on the right. */
    .card-grid td.cell-kv {
        grid-column: 1 / -1;
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 1rem;
        padding: 0.28rem 0 0;
        font-size: 0.8rem;
        text-align: right;
    }

    .card-grid td.cell-kv::before {
        content: attr(data-label);
        flex-shrink: 0;
        font-size: 0.68rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: var(--c-ink-soft);
        text-align: left;
    }

    /* Secondary columns not worth a card line. */
    .card-grid td.cell-hide-mobile {
        display: none;
    }

    /* Cards whose row has a strip/expansion below (the supplier grid): the card stays open
       at the bottom and the expander strip closes it — open, it squares off into the panel. */
    .card-grid > tbody > tr.card-row.has-footer {
        border-bottom: 0;
        border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    }

    .card-grid > tbody > tr.row-expander {
        border: 1px solid var(--c-line);
        border-top: 0;
        border-radius: 0 0 var(--radius-sm) var(--radius-sm);
        background: var(--c-surface);
    }

    .card-grid > tbody > tr.row-expander.is-open {
        border-radius: 0;
    }

    .card-grid > tbody > tr.expansion-row {
        border: 1px solid var(--c-tint-line);
        border-top: 0;
        border-radius: 0 0 var(--radius-sm) var(--radius-sm);
        overflow: hidden;
    }

}

/* Post-run research summary panel: a flow-panel with an outcome-coloured left rule and a
   highlighted failure tally, so a failure-heavy run reads at a glance. The dismiss × pins
   to the top-right corner regardless of how the tally text wraps on narrow screens — the
   .flow-panel qualifier keeps this padding from losing to .flow-panel's own shorthand,
   which previously let text run underneath the ×. */
.flow-panel.research-summary {
    position: relative;
    border-left: 3px solid var(--c-ok);
    padding-right: 2.9rem;
}

.flow-panel.research-summary > .btn-close {
    position: absolute;
    top: 0.7rem;
    right: 0.8rem;
}

/* Full-screen export overlay: dims the page and centres a card while a PDF/Excel export
   generates, so the trigger buttons never reflow to show busy state. */
.export-overlay {
    position: fixed;
    inset: 0;
    z-index: 1060;   /* over the sticky header and modals' backdrop level */
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--c-ink) 30%, transparent);
}

.export-overlay-card {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.4rem;
    border-radius: var(--radius-sm);
    background: var(--c-surface);
    box-shadow: 0 10px 30px rgb(0 0 0 / 0.25);
    font-weight: 600;
}

.export-overlay-card .spinner-border {
    color: var(--brand-primary);
}

/* Filter group above the supplier grid: one bordered fieldset holding every control that
   narrows the rows (status tiles, search, category), with a legend and a "Clear filters"
   link — so the tiles and the toolbar read as one set of filter options rather than two
   unrelated strips. Row-selection buttons sit outside it. */
.filter-group {
    margin: 0 0 0.75rem;
    padding: 0.65rem 0.85rem 0.75rem;
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--c-surface) 60%, var(--c-paper));
}

.filter-group-legend {
    float: none;
    width: auto;
    margin: 0 0 0.5rem;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.75rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--c-ink-soft);
}

.filter-group-clear {
    font-size: 0.78rem;
    text-transform: none;
    letter-spacing: normal;
    font-weight: 500;
}

.filter-group .status-tiles {
    margin-bottom: 0.5rem;
}

.filter-group .grid-toolbar {
    margin-bottom: 0;
}

/* Desktop: tiles, search and category share one line (wrapping only when the viewport
   cannot fit them); phones keep the stacked rows above. */
@media (min-width: 641px) {
    .filter-group-body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.5rem 1rem;
    }

    .filter-group .status-tiles,
    .filter-group .grid-toolbar {
        margin-bottom: 0;
    }

    .filter-group .grid-toolbar {
        flex: 1 1 24rem;
    }

    .filter-group .grid-toolbar .form-control {
        flex: 1 1 10rem;
    }
}

/* Status tiles above the supplier grid: waiting-review / failed / complete counts that
   double as one-click grid filters (and open the first matching row). Same tone palette
   as the expander badges, so the states read as one system. */
.status-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.status-tile {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.7rem;
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    background: var(--c-surface);
    font-size: 0.82rem;
    color: var(--c-ink);
    cursor: pointer;
}

.status-tile:disabled {
    cursor: default;
    opacity: 0.55;
}

.status-tile .status-tile-count {
    min-width: 1.5rem;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.status-tile.tone-warning .status-tile-count { background: var(--c-sun); color: var(--c-ink); }
.status-tile.tone-danger .status-tile-count { background: var(--c-danger); color: #fff; }
.status-tile.tone-ok .status-tile-count { background: var(--c-ok); color: #fff; }

.status-tile:not(:disabled):hover,
.status-tile.is-active {
    border-color: var(--brand-primary);
    background: var(--c-tint);
}

.status-tile.is-active {
    box-shadow: inset 0 0 0 1px var(--brand-primary);
}

@media (max-width: 640.98px) {
    .status-tile {
        flex: 1 1 calc(50% - 0.25rem);
        justify-content: center;
    }
}

.research-summary.is-error {
    border-left-color: var(--c-danger);
}

.research-summary .summary-fail {
    color: var(--c-danger);
    font-weight: 600;
}

/* Inline disclosure chevron for buttons that reveal a panel (e.g. the supplier upload):
   points down when closed, flips up when the panel is open. */
.btn .disclosure-chevron {
    display: inline-block;
    width: 0.4em;
    height: 0.4em;
    margin-left: 0.35rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translateY(-2px);
    transition: transform 0.15s ease;
}

.btn[aria-expanded="true"] .disclosure-chevron {
    transform: rotate(225deg) translateY(1px);
}

/* The "?" help popover: anchored under its icon on desktop; pinned as a readable sheet on
   mobile, where anchoring to a mid-toolbar icon would push it off the viewport edge. */
.help-popover {
    position: absolute;
    right: 0;
    margin-top: 0.25rem;
    z-index: 1050;
    width: min(34rem, 90vw);
}

@media (max-width: 640.98px) {
    .help-popover {
        position: fixed;
        left: 0.75rem;
        right: 0.75rem;
        top: 4.5rem;
        width: auto;
        max-height: calc(100vh - 6rem);
        overflow-y: auto;
    }
}

/* --- Row expansions ------------------------------------------------------- */
/* An open row and the panel under it are one block: the row itself tints, the chevron
   strip sits inside that tint, and the panel carries a brand rule down its left edge.
   Bootstrap's stock .bg-light grey made an open row read as a second, unrelated table.
   Hover shading is switched off across the block — the panel is not a row to click. */

.table > tbody > tr.is-expanded > td,
.table > tbody > tr.row-expander.is-open > td,
.table > tbody > tr.expansion-row > td {
    --bs-table-bg: var(--c-tint);
    --bs-table-accent-bg: transparent;
    --bs-table-hover-bg: transparent;
    border-bottom-color: transparent;
}

.table > tbody > tr.expansion-row > td {
    padding: 0;
    border-bottom: 1px solid var(--c-tint-line);
}

/* Full-width expansion panels inside horizontally-scrolling tables (per-supplier results,
   inline activities): the panel pins to the scrollport's left edge and sizes to the visible
   area, so reading it never requires sideways scrolling — the table itself still scrolls
   for the row columns. Sidebar is 260px from 641px up, hidden below. */
.grid-expansion {
    position: sticky;
    left: 0;
    max-width: calc(100vw - 260px - 5rem);
    background: var(--c-tint);
    border-left: 3px solid var(--brand-primary);
}

@media (max-width: 640.98px) {
    .grid-expansion {
        max-width: calc(100vw - 2rem);
    }
}

/* Every expansion opens with a header naming the supplier it belongs to and carrying that
   row's own actions (look up, activities). They used to sit out on the row itself, where they
   competed with the data columns and said nothing about where their output would land. */
.expansion-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.75rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--c-tint-line);
}

.expansion-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--brand-primary);
}

.expansion-head-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-left: auto;
}

/* One line under a grid toolbar saying what its rows do when you click or open them — a
   clickable row and an expander strip are both invisible affordances until something says so.
   The chevron matches the one on the expander pill. */
.grid-hint {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    margin: -0.35rem 0 0.65rem;
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--c-ink-soft);
}

.grid-hint::before {
    content: "";
    flex-shrink: 0;
    align-self: center;
    width: 0.4em;
    height: 0.4em;
    border-right: 2px solid var(--brand-primary);
    border-bottom: 2px solid var(--brand-primary);
    transform: rotate(45deg);
}

/* Rows that open something on click: the whole row is the target, so it needs the cursor and
   a focus ring of its own — the name is plain text now, not a link standing in for the row. */
.table > tbody > tr.row-clickable {
    cursor: pointer;
}

.table > tbody > tr.row-clickable:focus-visible {
    outline: 2px solid var(--brand-primary);
    outline-offset: -2px;
}

/* Cards inside an expansion — each lookup result, the manual-figures form, the live
   research feed: surface white on the tint, brand hairline, brand-coloured heading. */
.expansion-card {
    border: 1px solid var(--c-tint-line);
    border-radius: var(--radius-sm);
    background: var(--c-surface);
    box-shadow: var(--shadow-soft);
    padding: 0.7rem 0.85rem;
    margin-bottom: 0.75rem;
}

.expansion-card:last-child {
    margin-bottom: 0;
}

.expansion-card h3 {
    color: var(--brand-primary);
}

/* A tinted note inside a card: the supplier's own submission, quoted back. */
.expansion-note {
    border: 1px solid var(--c-tint-line);
    border-left: 3px solid var(--brand-primary);
    border-radius: var(--radius-sm);
    background: var(--c-tint);
    padding: 0.6rem 0.75rem;
    margin-bottom: 0.75rem;
}

.expansion-note > :last-child {
    margin-bottom: 0;
}

/* Working panels that open above a grid (the engagement composer, the spend-import
   preview, the live research feed) speak the same language as a row expansion. */
.flow-panel {
    border: 1px solid var(--c-tint-line);
    border-left: 3px solid var(--brand-primary);
    border-radius: var(--radius-sm);
    background: var(--c-tint);
    padding: 0.75rem 0.9rem;
    margin-bottom: 0.75rem;
}

.flow-panel > :last-child {
    margin-bottom: 0;
}

/* Banding rows in a grouped grid (supplier categories): a brand tint, not grey. */
.table > tbody > tr.group-row > td {
    --bs-table-bg: var(--c-tint-strong);
    --bs-table-accent-bg: transparent;
    --bs-table-hover-bg: transparent;
    color: var(--c-pine-deep);
}

/* Selectable option tiles (e.g. the Scope 3 allocation choice): each choice is a bordered,
   clickable card with an unmistakable selected state — plain radio rows blur together. */
.option-tile {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    background-color: var(--c-surface);
    padding: 0.5rem 0.7rem;
    margin-bottom: 0.375rem;
    cursor: pointer;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}

.option-tile:hover {
    border-color: var(--brand-primary);
}

.option-tile:has(.form-check-input:checked) {
    border-color: var(--brand-primary);
    background-color: color-mix(in srgb, var(--brand-primary) 8%, var(--c-surface));
    box-shadow: inset 3px 0 0 var(--brand-primary);
}

.option-tile .form-check-input {
    flex-shrink: 0;
    margin-top: 0.2rem;
    cursor: pointer;
}

/* A tile can host its option's own input (e.g. the manual Scope 3 figure). */
.option-tile .form-control {
    cursor: text;
}

/* Section accordions: a bordered container whose tinted header bar is the toggle
   (h2 > button, Bootstrap-accordion style) — collapsed sections read as closed drawers. */
.section-accordion {
    border: 1px solid var(--c-line);
    border-radius: var(--radius);
    background: var(--c-surface);
    box-shadow: var(--shadow-soft);
    margin-bottom: 1rem;
    overflow: hidden;   /* keeps the header tint inside the rounded corners */
}

.section-accordion > h2 {
    margin: 0;
}

.section-accordion .accordion-toggle {
    padding: 0.7rem 1rem;
    background-color: color-mix(in srgb, var(--brand-primary) 4%, var(--c-surface));
}

.section-accordion .accordion-toggle:hover {
    background-color: color-mix(in srgb, var(--brand-primary) 10%, var(--c-surface));
}

.section-accordion .accordion-body {
    padding: 1rem;
    border-top: 1px solid var(--c-line);
}

.accordion-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    text-align: left;
    cursor: pointer;
}

.accordion-toggle:hover {
    color: var(--brand-primary);
}

.accordion-toggle::after {
    content: "";
    flex-shrink: 0;
    width: 0.55em;
    height: 0.55em;
    margin-right: 0.2em;
    border-right: 2.5px solid var(--brand-primary);
    border-bottom: 2.5px solid var(--brand-primary);
    transform: rotate(45deg);
    transition: transform 0.15s ease;
}

.accordion-toggle[aria-expanded="false"]::after {
    transform: rotate(-45deg);
}

/* --- Cards & tables ----------------------------------------------------- */

.card {
    border: 1px solid var(--c-line);
    border-radius: var(--radius);
    background: var(--c-surface);
    box-shadow: var(--shadow-soft);
}

.card-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1rem;
    color: var(--brand-primary);
}

.table {
    background: var(--c-surface);
    border-color: var(--c-line);
}

.table-responsive, .tablewrap {
    overflow-x: auto;
}

/* --- Content region ----------------------------------------------------- */

.content {
    padding-top: 1.4rem;
    padding-bottom: 3rem;
}

h1:focus {
    outline: none;
}

/* Eco hairline under page titles */
article.content > h1:first-child::after,
article.content > h1:first-of-type::after {
    content: "";
    display: block;
    width: 3.25rem;
    height: 4px;
    border-radius: 2px;
    margin-top: 0.55rem;
    background: linear-gradient(90deg, var(--brand-primary) 60%, var(--brand-secondary) 60%);
}

/* --- Alerts / status ---------------------------------------------------- */

.alert {
    border-radius: var(--radius);
    border: 1px solid var(--c-line);
}

.alert-info {
    background-color: var(--c-leaf-soft);
    border-color: #CBE3D3;
    color: var(--c-pine-deep);
}

.alert-warning {
    background-color: color-mix(in srgb, var(--c-sun) 14%, var(--c-surface));
    border-color: color-mix(in srgb, var(--c-sun) 45%, var(--c-surface));
    color: #5E4300;
}

.alert-danger {
    background-color: #FBF1EF;
    border-color: #E4C7C2;
    color: #7E261D;
}

/* --- Account management ------------------------------------------------- */
/* The Identity manage pages are template markup (nav-pills, h3 sections, bare
   forms); these rules pull the whole area into the Carbonly design system so
   individual template pages need no restyling of their own. */

.account-manage-header h1 {
    margin-bottom: 0.15rem;
}

.account-manage-header .lead {
    margin-bottom: 1.4rem;
}

.account-manage .nav-pills {
    gap: 0.15rem;
    position: sticky;
    top: 1rem;
}

.account-manage .nav-pills .nav-link {
    color: var(--c-ink-soft);
    border-radius: var(--radius-sm);
    padding: 0.45rem 0.85rem;
    font-weight: 500;
    border-left: 3px solid transparent;
}

.account-manage .nav-pills .nav-link:hover {
    color: var(--c-pine-deep);
    background-color: var(--c-leaf-soft);
}

.account-manage .nav-pills .nav-link.active {
    color: #fff;
    background-color: var(--brand-primary);
    border-left-color: var(--brand-secondary);
}

.account-manage-panel .card-body {
    padding: 1.5rem;
}

.account-manage h3 {
    font-size: 1.15rem;
    color: var(--brand-primary);
    margin-bottom: 0.35rem;
}

.account-manage h3::after {
    content: "";
    display: block;
    width: 2.5rem;
    height: 3px;
    border-radius: 2px;
    margin-top: 0.45rem;
    background: linear-gradient(90deg, var(--brand-primary) 60%, var(--brand-secondary) 60%);
}

.account-manage h4 {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--c-ink);
    margin-top: 1.25rem;
}

.account-manage hr {
    border-color: var(--c-line);
    opacity: 1;
}

/* Template pages use w-100 btn-lg submit buttons — bring them down to scale. */
.account-manage .btn-lg {
    font-size: 1rem;
    padding: 0.55rem 1rem;
}

/* Sections inside a manage page (personal data, danger zone) */
.account-section {
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    padding: 1rem 1.15rem;
    margin-top: 1rem;
    background: var(--c-surface);
}

.account-section > h4 {
    margin-top: 0;
}

.account-section.danger {
    border-color: #E4C7C2;
    background: #FBF4F3;
}

.account-section.danger > h4 {
    color: var(--c-danger);
}

/* --- Validation (Blazor) ------------------------------------------------ */

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--c-ok);
}

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

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

.text-danger {
    color: var(--c-danger) !important;
}

/* --- Dashboard stats & bars --------------------------------------------- */

.stat-label {
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-ink-soft);
}

.stat-value {
    font-family: var(--font-display);
    font-size: 1.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--c-ink);
    line-height: 1.15;
}

.stat-unit {
    font-size: 0.78rem;
    color: var(--c-ink-soft);
}

.bar-row {
    display: grid;
    grid-template-columns: minmax(7rem, 14rem) 1fr 4.5rem;
    gap: 0.75rem;
    align-items: center;
    padding: 0.3rem 0;
    text-decoration: none;
    color: var(--c-ink);
    border-radius: var(--radius-sm);
}

a.bar-row:hover {
    background: var(--c-leaf-soft);
    color: var(--c-ink);
}

.bar-row-label {
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bar-row-track {
    background: var(--c-leaf-soft);
    border-radius: 4px;
    height: 12px;
    overflow: hidden;
}

.bar-row-fill {
    display: block;
    height: 100%;
    border-radius: 4px;
    background: var(--brand-primary);
    min-width: 2px;
}

.bar-row-fill.dq {
    background: var(--c-leaf);
}

.bar-row-value {
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--c-ink-soft);
}

/* --- Users & roles page -------------------------------------------------- */

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--c-line);
    padding: 0.85rem 1rem;
}

.card-header h2 {
    font-size: 1rem;
    color: var(--brand-primary);
    margin-bottom: 0;
}

.users-page .users-table > :not(caption) > * > * {
    padding: 0.6rem 1rem;
}

.users-page .users-table > tbody > tr:last-child > td {
    border-bottom: 0;
}

.user-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--c-leaf-soft);
    color: var(--c-pine-deep);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.8rem;
}

.users-page .user-roles-editor > td {
    background: var(--c-leaf-soft);
    box-shadow: inset 0 2px 4px -3px rgba(28, 42, 36, 0.35);
}

.users-page .perm-table > tbody > tr:hover > td {
    background: var(--c-leaf-soft);
}

/* On mobile the permission matrix would otherwise need a hidden sideways
   scroll to reach the "Can edit" column, and its column labels scroll out of
   view above the long page list — leaving unlabelled radios. Tighten the cells
   so all three option columns fit the viewport, and pin the header row. */
@media (max-width: 640.98px) {
    .users-page .perm-table > :not(caption) > * > * {
        padding-left: 0.3rem;
        padding-right: 0.3rem;
    }

    .users-page .perm-table > :not(caption) > * > *:first-child {
        padding-left: 0.6rem;
    }

    .users-page .perm-table > thead th:not(:first-child) {
        white-space: normal;
        line-height: 1.15;
    }

    /* The tightened matrix now fits without a sideways scroll, so drop the
       responsive wrapper's overflow — that scroll container is what would
       otherwise stop the header row from pinning to the viewport. */
    .users-page .table-responsive:has(.perm-table) {
        overflow: visible;
    }

    .users-page .perm-table > thead th {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--c-surface);
    }
}

/* --- Calculation trace (Activities expandable rows) ---------------------- */

.calc-box {
    background: var(--c-surface);
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    padding: 0.25rem 0.75rem;
    max-width: 34rem;
}

.calc-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.45rem 0;
    font-size: 0.9rem;
}

.calc-row + .calc-row {
    border-top: 1px dashed var(--c-line);
}

.calc-label {
    color: var(--c-ink-soft);
}

.calc-value {
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

.calc-total {
    border-top: 2px solid var(--c-line) !important;
    font-weight: 600;
}

.calc-total .calc-label {
    color: var(--c-ink);
}

.calc-total .calc-value {
    color: var(--brand-primary);
    font-size: 1rem;
}

@media (max-width: 575.98px) {
    .bar-row {
        grid-template-columns: minmax(5.5rem, 8rem) 1fr 3.5rem;
        gap: 0.4rem;
    }
}

/* Donut widgets (hotspots by category, emissions by site): on narrow screens
   the legend wraps under the ring — centre both instead of hugging the left. */
@media (max-width: 640.98px) {
    .donut-wrap {
        justify-content: center;
    }
}

/* --- Tab bars ------------------------------------------------------------ */

/* Page-level tabs (Activities Ledger/Import data, Suppliers): Bootstrap's boxed
   folder tabs replaced with the design system's quieter underline style — muted
   labels, tonal leaf-soft hover, and a brand-primary underline on the active
   tab so it reads as "you are here" rather than a raised card. */
.nav-tabs {
    border-bottom: 1px solid var(--c-line);
    gap: 0.25rem;
}

.nav-tabs .nav-link {
    color: var(--c-ink-soft);
    font-weight: 500;
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    padding: 0.55rem 1rem;
    margin-bottom: -1px; /* the active underline sits on the bar, not above it */
    transition: background-color 0.15s ease, color 0.15s ease;
}

.nav-tabs .nav-link:hover:not(.active),
.nav-tabs .nav-link:focus-visible:not(.active) {
    color: var(--c-ink);
    background-color: var(--c-leaf-soft);
    border-bottom-color: transparent;
}

.nav-tabs .nav-link.active {
    color: var(--brand-primary);
    font-weight: 600;
    background-color: transparent;
    border-bottom-color: var(--brand-primary);
}

/* Segmented toggles (Suppliers lookup, account settings menu): tonal pills in
   the same family as the soft-filled buttons. */
.nav-pills .nav-link {
    color: var(--c-ink-soft);
    font-weight: 500;
    border-radius: var(--radius-sm);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.nav-pills .nav-link:hover:not(.active),
.nav-pills .nav-link:focus-visible:not(.active) {
    color: var(--c-pine-deep);
    background-color: var(--c-leaf-soft);
}

.nav-pills .nav-link.active {
    color: #fff;
    background-color: var(--brand-primary);
}

/* Long tab labels (e.g. Suppliers' "Profiles & carbon lookup" / "Invitations &
   engagements") would wrap into a ragged two-row stack on narrow screens. Keep
   the bar on one row: tighten the tabs so they usually fit, and let the bar
   scroll sideways when they still cannot. */
@media (max-width: 640.98px) {
    .nav-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .nav-tabs::-webkit-scrollbar {
        display: none;
    }

    .nav-tabs .nav-link {
        white-space: nowrap;
        font-size: 0.9rem;
        padding: 0.5rem 0.75rem;
    }
}

/* --- Steorra attribution ------------------------------------------------ */

.powered-by {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.78rem;
    letter-spacing: 0.02em;
}

.powered-by img {
    width: 0.7rem;
    height: 0.7rem;
}

/* --- Blazor plumbing (kept from template) ------------------------------- */

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

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

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* On narrow screens the right-aligned placeholder hint can collide with the
   floating label when both are long (e.g. "Phone number" / "Enter your phone
   number"). Hide the hint until the field is focused — the label still names
   the field. */
@media (max-width: 640.98px) {
    .form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
        color: transparent;
    }

    .form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
        color: var(--bs-secondary-color);
    }
}

/* --- Motion restraint --------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

/* --- Tooltips ------------------------------------------------------------- */
/* Instant hover/focus tooltips for every data-tip="…" (see app-interop.js). Bootstrap's
   tooltip shape — dark pill, small arrow, quick fade — but the ground is the tenant's
   primary sunk into ink, so a rebranded tenant's hints sit in their palette rather than
   Bootstrap's stock black. Long "why is this disabled" hints wrap at a readable measure. */

.c-tip {
    --tip-bg: color-mix(in srgb, var(--c-ink) 72%, var(--brand-primary));
    --tip-arrow: 0.4rem;
    position: fixed;
    z-index: 1090;
    max-width: min(22rem, calc(100vw - 1rem));
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(2px);
    transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
    font-family: var(--font-text);
}

.c-tip.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: opacity 0.12s ease, transform 0.12s ease;
}

.c-tip-inner {
    padding: 0.35rem 0.6rem;
    color: #fff;
    background-color: var(--tip-bg);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-soft);
    font-size: 0.8125rem;
    line-height: 1.4;
    text-align: left;
    text-wrap: pretty;
    overflow-wrap: anywhere;
}

.c-tip-arrow {
    position: absolute;
    width: 0;
    height: 0;
    border: var(--tip-arrow) solid transparent;
}

.c-tip[data-place="top"] .c-tip-arrow {
    bottom: calc(-2 * var(--tip-arrow) + 1px);
    transform: translateX(-50%);
    border-top-color: var(--tip-bg);
}

.c-tip[data-place="bottom"] .c-tip-arrow {
    top: calc(-2 * var(--tip-arrow) + 1px);
    transform: translateX(-50%);
    border-bottom-color: var(--tip-bg);
}

.c-tip[data-place="left"] .c-tip-arrow {
    right: calc(-2 * var(--tip-arrow) + 1px);
    transform: translateY(-50%);
    border-left-color: var(--tip-bg);
}

.c-tip[data-place="right"] .c-tip-arrow {
    left: calc(-2 * var(--tip-arrow) + 1px);
    transform: translateY(-50%);
    border-right-color: var(--tip-bg);
}

@media (prefers-reduced-motion: reduce) {
    .c-tip {
        transition: none;
        transform: none;
    }
}

/* --- Document reader ---------------------------------------------------------- */
/* The evidence reader modal: a tall dialog whose body gives the whole height to the framed
   PDF / web page, scrolls an image or a workbook table, and shows text verbatim. Header
   holds the file name (truncating) with the Open / Download actions kept on one line. */
.doc-reader-modal {
    background: rgba(28, 42, 36, 0.45);
}

.doc-reader-dialog {
    height: calc(100vh - 3.5rem);
}

.doc-reader-dialog .modal-content {
    height: 100%;
}

.doc-reader-head {
    gap: 0.75rem;
    align-items: flex-start;
}

.doc-reader-heading {
    min-width: 0;
    flex: 1 1 auto;
}

.doc-reader-meta {
    font-size: 0.78rem;
    color: var(--c-ink-soft);
}

.doc-reader-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
}

.doc-reader-body.is-framed {
    padding: 0;
    overflow: hidden;
}

.doc-reader-frame {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 60vh;
    border: 0;
    background: #fff;
}

.doc-reader-image-wrap {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    min-height: 100%;
}

.doc-reader-image {
    max-width: 100%;
    height: auto;
    box-shadow: 0 1px 6px rgba(28, 42, 36, 0.15);
}

.doc-reader-sheets {
    gap: 0.25rem;
    margin-bottom: 0.75rem;
}

.doc-reader-sheets .nav-link {
    padding: 0.2rem 0.65rem;
    font-size: 0.82rem;
}

.doc-reader-sheet {
    font-size: 0.8rem;
}

.doc-reader-sheet th {
    white-space: nowrap;
    background: var(--c-tint);
}

.doc-reader-sheet td {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.doc-reader-text {
    font-size: 0.8rem;
    white-space: pre-wrap;
    word-break: break-word;
}

@media (max-width: 640.98px) {
    .doc-reader-dialog {
        height: calc(100vh - 1rem);
        margin: 0.5rem;
    }

    .doc-reader-head {
        flex-direction: column;
        align-items: stretch;
    }

    .doc-reader-actions {
        justify-content: flex-end;
    }
}
