html, body {
    font-family: var(--font-sans);
    background: var(--background);
    color: var(--foreground);
}

h1:focus {
    outline: none;
}

/* ===========================================================================
   Design-system tokens (UI Design PRD v1, Slice 0) — shadcn light neutral base
   + the Foundations brand trio, values verbatim from the design-source demo
   (PoC Src/app/globals.css). Light-only per D-UI3; the demo's .dark block is
   parked at the end of this section for a future revival.

   The legacy token names (--navy/--gold/--ink/--surface/--hair/--r-* …) are kept
   as ALIASES onto this set so the existing fx- component vocabulary re-skins
   without touching markup. New code should read the shadcn names directly.
   =========================================================================== */

:root {
    /* Brand palette — Building Industry style guide (docs/Foundations-StyleGuide.md).
       Steel blue primary + safety orange accent (the ONE accent, used sparingly).
       --brand-secondary has no distinct value in this palette → maps to primary, so
       existing "highlight" usages (KPI numbers, kickers, usage bars) read steel blue,
       not a third colour. */
    --brand-primary: #1F3A5F;               /* steel blue 500 */
    --brand-accent: #E8762C;                /* safety orange 500 */
    --brand-secondary: #1F3A5F;             /* = primary (no third brand colour) */

    /* Typography (§3.2) — self-hosted, no CDN */
    --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
    --font-heading: 'Montserrat', var(--font-sans);
    --font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Neutral + surface — style guide §2. Concrete page canvas, WHITE raised surfaces
       (cards/inputs), slate-grey text scale, steel-blue primary. */
    --background: #EDEAE4;                   /* concrete 200 — page canvas */
    --foreground: #1A1E21;                   /* slate/neutral 900 — body text */
    --card: #FFFFFF;                         /* raised surface */
    --card-foreground: #1A1E21;
    --popover: #FFFFFF;
    --popover-foreground: #1A1E21;
    --primary: #1F3A5F;                      /* steel blue — primary buttons + chrome */
    --primary-foreground: #FFFFFF;
    --secondary: #F5F3EF;                    /* concrete 100 — faint fill */
    --secondary-foreground: #1F3A5F;
    --muted: #F5F3EF;                        /* concrete 100 — header bands / muted fill */
    --muted-foreground: #5B6770;             /* slate 500 — muted text */
    --accent: #F5F3EF;
    --accent-foreground: #1F3A5F;
    --destructive: #C0392B;                  /* brick red — danger button fill (white text) */
    --border: #C8CDD1;                       /* neutral 200 — hairline */
    --input: #C8CDD1;
    --ring: #748EAD;                         /* primary 300 — focus ring */
    --chart-1: #748EAD;                      /* charts: steel-blue family + semantics */
    --chart-2: #E8762C;
    --chart-3: #2E7D4F;
    --chart-4: #5B6770;
    --chart-5: #1F3A5F;
    --sidebar: #FFFFFF;
    --sidebar-foreground: #1A1E21;
    --sidebar-primary: #1F3A5F;
    --sidebar-primary-foreground: #FFFFFF;
    --sidebar-accent: #F5F3EF;
    --sidebar-accent-foreground: #1F3A5F;
    --sidebar-border: #C8CDD1;
    --sidebar-ring: #748EAD;

    /* Radius scale (§3.3 — demo @theme inline, verbatim ratios) */
    --radius: 0.625rem;
    --radius-sm: calc(var(--radius) * 0.6);
    --radius-md: calc(var(--radius) * 0.8);
    --radius-lg: var(--radius);
    --radius-xl: calc(var(--radius) * 1.4);
    --radius-2xl: calc(var(--radius) * 1.8);
    --radius-3xl: calc(var(--radius) * 2.2);
    --radius-4xl: calc(var(--radius) * 2.6);

    /* ---- Legacy aliases (fx- vocabulary) — values only; names kept ---- */
    --navy: var(--brand-primary);           /* steel blue */
    --navy-700: #152A47;                    /* steel blue 700 (darker chrome) */
    --indigo: #1B3355;                       /* steel blue 600 — AI surfaces */
    --indigo-600: #102038;                   /* steel blue 800 */
    --gold: var(--brand-accent);            /* accent role → safety orange */
    --gold-deep: #A9511A;                   /* accent 700 (hover, white-text-safe) */
    --r-input: var(--radius-md);            /* shadcn input: rounded-md */
    --r-card: var(--radius-xl);             /* shadcn card: rounded-xl */
    --r-modal: var(--radius-lg);            /* shadcn dialog: rounded-lg */

    --bg: var(--background);                /* concrete canvas */
    --ink: var(--foreground);
    --ink-2: #3B4348;                       /* slate 700 — secondary text */
    --ink-3: var(--muted-foreground);       /* slate 500 — muted text */
    --surface: var(--card);
    --surface-2: var(--card);
    --data-surface: var(--card);
    --hair: var(--border);                  /* neutral 200 */
    --hair-2: #A6AEB4;                      /* neutral 300 — stronger edge */
    --field-bg: #FFFFFF;                    /* inputs are white, not concrete */
    --shadow: none;                         /* guide: prefer borders over shadows */
    --grid-head: #F5F3EF;                   /* concrete 100 — table header (guide §6) */
    --grid-head-text: #3B4348;              /* slate 700 */

    /* Grid rows, brandable since 17/08/2026. Defaults are exactly what the rules used to hardcode via other
       tokens, so declaring them changed nothing: rows sat on --card and were set in --ink-2, and there was no
       banding anywhere in the product. --grid-row-alt: transparent IS "no banding" — the banding rule below is
       unconditional, and painting a row transparent is the same as not painting it. */
    --grid-row: var(--card);
    --grid-row-ink: var(--ink-2);
    --grid-row-alt: transparent;

    /* Status hues — light tints + darker same-hue text (guide §2 badge rule, AA-safe).
       Chip TEXT uses the 700 shade so it passes on the 10% tint; solid fills
       (buttons) use --destructive / the 500 shades. No "info" hue in this palette →
       steel blue. */
    --c-success: #1F5837;                   /* site green 700 (chip text) */
    --c-warning: #9C7400;                   /* amber 700 (chip text) */
    --c-danger: #8A281E;                    /* brick red 700 (chip text) */
    --c-info: #1F3A5F;                      /* steel blue (no distinct info hue) */
    --c-neutral: var(--muted-foreground);   /* slate 500 */
    --c-success-bg: rgba(46,125,79,.10);    /* site green 500 tint */
    --c-warning-bg: rgba(224,168,0,.14);    /* amber 500 tint */
    --c-danger-bg: rgba(192,57,43,.10);     /* brick red 500 tint */
    --c-info-bg: rgba(31,58,95,.10);        /* steel blue tint */
    --c-neutral-bg: var(--muted);           /* concrete 100 */
    --c-gold-bg: rgba(232,118,44,.12);      /* safety orange tint */

    /* Stat tiles are plain quiet cards now */
    --stat-bg: var(--card);
    --stat-blur: none;
}

/* Dark mode is PARKED (D-UI3 — light-only for now). The demo's .dark token set
   is preserved here for a future revival; nothing applies it.

.dark {
    --background: oklch(0.145 0 0);
    --foreground: oklch(0.985 0 0);
    --card: oklch(0.205 0 0);
    --card-foreground: oklch(0.985 0 0);
    --popover: oklch(0.205 0 0);
    --popover-foreground: oklch(0.985 0 0);
    --primary: oklch(0.922 0 0);
    --primary-foreground: oklch(0.205 0 0);
    --secondary: oklch(0.269 0 0);
    --secondary-foreground: oklch(0.985 0 0);
    --muted: oklch(0.269 0 0);
    --muted-foreground: oklch(0.708 0 0);
    --accent: oklch(0.269 0 0);
    --accent-foreground: oklch(0.985 0 0);
    --destructive: oklch(0.704 0.191 22.216);
    --border: oklch(1 0 0 / 10%);
    --input: oklch(1 0 0 / 15%);
    --ring: oklch(0.556 0 0);
    --sidebar: oklch(0.205 0 0);
    --sidebar-foreground: oklch(0.985 0 0);
    --sidebar-primary: oklch(0.488 0.243 264.376);
    --sidebar-primary-foreground: oklch(0.985 0 0);
    --sidebar-accent: oklch(0.269 0 0);
    --sidebar-accent-foreground: oklch(0.985 0 0);
    --sidebar-border: oklch(1 0 0 / 10%);
    --sidebar-ring: oklch(0.556 0 0);
}
*/

/* Inline validation states (Blazor EditForm). */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid #10b981;
}

.invalid {
    outline: 1px solid #dc2626;
}

.validation-message {
    color: #dc2626;
}

.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."
    }

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1100;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

/* ===========================================================================
   Identity /Account pages — light shadcn card on the brand-primary background
   (AuthLayout owns the shell; these restyle the Bootstrap form chrome the
   scaffolded Identity pages render). Bootstrap stays loaded — it provides the
   layout classes; we restyle the surface.
   =========================================================================== */

.auth-body .row { margin: 0; }

.auth-body .col-lg-6,
.auth-body .col-lg-4,
.auth-body .col-md-4 {
    width: 100%;
    max-width: 100%;
    flex: 0 0 100%;
    padding: 0;
}

/* Hide the "use another service" external-login column on the brand card — no
   external providers are wired (internal Identity only, per standards). */
.auth-body .col-lg-4.col-lg-offset-2,
.auth-body .col-lg-offset-2 {
    display: none;
}

.auth-body hr {
    border-color: var(--border);
    opacity: 1;
}

.auth-body label,
.auth-body .form-label {
    color: var(--ink-2);
    font-weight: 500;
    font-size: 0.82rem;
}

.auth-body .form-control {
    background: var(--background);
    border: 1px solid var(--input);
    border-radius: var(--r-input);
    color: var(--foreground);
    padding: 0.65rem 0.85rem;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}

.auth-body .form-floating > label {
    color: var(--muted-foreground);
}

.auth-body .form-control::placeholder { color: var(--muted-foreground); }

/* Floating-label fields: keep Bootstrap's geometry (the generic padding override above
   would collapse the label space) and its transparent-placeholder trick — the label IS
   the placeholder, so a visible placeholder colour makes the two overlap. */
.auth-body .form-floating > .form-control {
    height: calc(3.5rem + 2px);
    padding: 1rem 0.85rem;
}
.auth-body .form-floating > .form-control::placeholder { color: transparent; }

.auth-body .form-control:focus {
    background: var(--background);
    border-color: var(--ring);
    box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5);
    color: var(--foreground);
}

.auth-body .checkbox label,
.auth-body .form-check-label { color: var(--ink-2); }

/* Primary action (Log in / Register) — brand accent, shadcn button shape. */
.auth-body .btn-primary,
.auth-body .btn-lg.btn-primary {
    background: var(--brand-primary);   /* steel blue + white = 11.5:1 (guide); orange stays an accent, and white-on-vivid-orange fails AA */
    border: none;
    color: #fff;
    font-weight: 600;
    font-size: 0.92rem;
    border-radius: var(--radius-lg);
    padding: 0.6rem 1.2rem;
    box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}

.auth-body .btn-primary:hover { background: var(--navy-700); color: #fff; }

.auth-body a,
.auth-body .btn-link {
    color: var(--brand-accent);
    text-decoration: none;
}

.auth-body a:hover { text-decoration: underline; }

/* Validation summary + status messages on the light card. */
.auth-body .text-danger,
.auth-body .validation-message { color: var(--destructive) !important; }

.auth-body .alert,
.auth-body [role="alert"] {
    background: var(--c-danger-bg);
    border: 1px solid rgba(220,38,38,0.25);
    border-radius: var(--r-input);
    color: #b91c1c;
    padding: 0.6rem 0.9rem;
}

/* ===========================================================================
   MudBlazor dialog backdrop — shadcn overlay (flat black/50, no blur).
   =========================================================================== */
.mud-overlay-dialog {
    background-color: rgba(0, 0, 0, 0.5) !important;
}

/* ===========================================================================
   Commercial UI — shared fx- component vocabulary, restyled to the shadcn
   look (quiet cards: 1px border, flat; Montserrat headings; accent links).
   Class names are structural and unchanged (Slice 0 rule) — only the look.
   =========================================================================== */

.fx-page-title {
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1.875rem;         /* demo: font-heading text-3xl font-bold */
    letter-spacing: -0.01em;
    color: var(--foreground);
    margin: 0;
}
.fx-page-sub { color: var(--muted-foreground); font-size: 0.92rem; margin-top: 4px; }

/* ---- Section headings, GLOBAL ----
   Reported 22/08/2026 (D3747BC3), on the project Delivery page: "all of the elements under each stage need
   bringing in line with the font and styling of the first section of the page … The fonts are different".

   They were, and it was not a subtle theming drift. `.fx-h2` was declared in SEVENTEEN separate page style
   blocks — byte-identical, every one of them — and used on twenty-seven pages. The other ten, Delivery
   among them, rendered their section headings as a browser-default <h2>: a different family, a different
   size, and browser margins. `.fx-h3` was worse: used on eight pages and declared NOWHERE, so every
   "Add a milestone"-style sub-heading in the product was unstyled.

   This is the same failure app.css already documents twice (the nine md-form copies, the five ::deep
   MudDataGrid blocks): a rule copied per page is a rule that is missing on the next page somebody writes.
   The declaration is here now and the per-page copies are deleted. */
.fx-h2 { font-family: var(--font-heading); font-weight: 600; font-size: 1.4rem; margin: 0; color: var(--ink); }
.fx-h3 { font-family: var(--font-heading); font-weight: 600; font-size: 1.08rem; margin: 0; color: var(--ink); }

.fx-panel {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-card);
    box-shadow: var(--shadow);
    color: var(--card-foreground);
}

.fx-stat {
    border-radius: var(--r-card);
    padding: 16px 18px;
    border: 1px solid var(--border);
    background: var(--stat-bg);
    box-shadow: var(--shadow);
}
.fx-stat .k-label { font-size: 0.72rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted-foreground); font-weight: 600; }
.fx-stat .k-num {
    font-family: var(--font-heading); font-size: 1.5rem; font-weight: 700;
    margin: 6px 0 4px; font-variant-numeric: tabular-nums; color: var(--foreground);
}
.fx-stat .k-num.gold { color: var(--brand-secondary); }   /* demo KPI headline: brand-secondary */
.fx-stat .k-delta { font-size: 0.8rem; font-weight: 500; color: var(--muted-foreground); }

.num { font-variant-numeric: tabular-nums; }

/* Status / RAG chips — demo badge rule: pill, light same-hue tint + darker text. */
.chip {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 0.76rem; font-weight: 500; padding: 2px 10px; border-radius: 999px;
    border: 1px solid transparent; white-space: nowrap;
}
.chip .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.chip-success { background: var(--c-success-bg); color: var(--c-success); }
.chip-warning { background: var(--c-warning-bg); color: var(--c-warning); }
.chip-danger  { background: var(--c-danger-bg); color: var(--c-danger); }
.chip-info    { background: var(--c-info-bg); color: var(--c-info); }
.chip-neutral { background: var(--c-neutral-bg); color: var(--c-neutral); }
.chip-gold    { background: var(--c-gold-bg); color: var(--brand-accent); }

/* Data grid — demo data-grid: flat gray-50 header, uppercase xs, hairline rows. */
.fx-grid-wrap { border-radius: var(--r-card); border: 1px solid var(--border); overflow: hidden; box-shadow: var(--shadow); }
.fx-grid-scroll { overflow-x: auto; background: var(--data-surface); }
table.fx-grid { border-collapse: collapse; width: 100%; min-width: 720px; }
table.fx-grid thead th {
    text-align: left; font-size: 0.72rem; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--grid-head-text); font-weight: 600; padding: 12px 16px;
    background: var(--grid-head);
    border-bottom: 1px solid var(--border);
}
table.fx-grid tbody td {
    padding: 12px 16px; font-size: 0.875rem; border-bottom: 1px solid var(--border);
    color: var(--grid-row-ink); background: var(--grid-row);
}

/* Banding. Unconditional on purpose — --grid-row-alt is `transparent` unless a brand sets it, so this rule is
   inert by default and needs no on/off switch. Specificity note: the clickable-hover rule below carries two
   classes and therefore still wins over this one pseudo-class, so hover keeps working on banded rows. */
table.fx-grid tbody tr:nth-child(even) td { background: var(--grid-row-alt); }

table.fx-grid tbody tr:last-child td { border-bottom: none; }
table.fx-grid tbody tr.clickable { cursor: pointer; }
table.fx-grid tbody tr.clickable:hover td { background: var(--muted); }
table.fx-grid tbody td .proj { color: var(--foreground); font-weight: 600; }
table.fx-grid td.num, table.fx-grid th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Reported 22/08/2026 (88824980): "The table headers and table entities are often misaligned in the
   milestone table. Fees, for example, the title is aligned to the far right-hand side of the column but
   the actual fees themselves are left-aligned or centre-aligned."

   Both true, and one cause. td.num right-aligns the cell's CONTENT, which right-aligns an input BOX — but
   the number inside that box keeps the browser's own left alignment for a number field. So a read-only
   figure lined up under its heading and an editable one did not, on the same column of the same table.
   Fixed here rather than on the one page, because the same pattern is on the estimate, WIP, billing and
   application grids. */
table.fx-grid td.num input,
table.fx-grid td.num select {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* And "the save button is completely skewed", from the same report. That cell carried an inline
   `display: flex` to sit its two buttons side by side — which stops the <td> being a table cell at all,
   so it no longer shares the row's height or takes its width from the column, and the buttons floated
   high in a cell whose borders had gone their own way. The row of actions is a DIV inside the cell now,
   and the class lives here so the next actions column does not repeat the shortcut. */
table.fx-grid td .fx-grid-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* ---- MudDataGrid (.fx-dg), themed GLOBALLY ----
   Four pages carried equivalent rules in their own style blocks written as `::deep .fx-dg …`. Blazor only
   processes `::deep` in a scoped .razor.css file; inside a plain <style> block it is an invalid selector, so
   every one of those rules was dropped and all five MudDataGrids rendered with MudBlazor's defaults —
   Projects (which had the CSS) and Feedback (which had none) were byte-identical when measured. Global rules
   here need no `::deep`, cover all five, and make the grid tokens actually reach them. */
.fx-dg { background: var(--grid-row); color: var(--grid-row-ink); }
.fx-dg .mud-table-root { background: var(--grid-row); }
.fx-dg .mud-table-head th,
.fx-dg .mud-table-head .mud-table-cell {
    background: var(--grid-head); color: var(--grid-head-text);
    text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.08em; font-weight: 700;
    border-bottom: 1px solid var(--hair-2);
}
.fx-dg .mud-table-body .mud-table-row .mud-table-cell {
    background: var(--grid-row); color: var(--grid-row-ink); border-bottom: 1px solid var(--border);
}
.fx-dg .mud-table-body .mud-table-row:nth-child(even) .mud-table-cell { background: var(--grid-row-alt); }
.fx-dg .mud-table-body .mud-table-row:hover .mud-table-cell { background: var(--muted); }
.fx-dg .proj { color: var(--foreground); font-weight: 600; }
.fx-dg .num, .fx-dg .num .mud-table-cell-content { text-align: right; justify-content: flex-end; font-variant-numeric: tabular-nums; }
.fx-dg .mud-table-pagination { border-top: 1px solid var(--border); color: var(--grid-row-ink); }
.fx-grid-subtle { color: var(--muted-foreground); }

/* Buttons — shadcn shapes (rounded-lg, h-8-ish). Base = outline variant;
   fx-btn-gold = the primary CTA (legacy name, accent role); danger = tint. */
.fx-btn {
    display: inline-flex; align-items: center; gap: 6px; justify-content: center;
    font-family: var(--font-sans); font-weight: 500; font-size: 0.875rem;
    padding: 6px 12px; border-radius: var(--radius-lg); border: 1px solid var(--border);
    color: var(--foreground); background: var(--background); text-decoration: none; cursor: pointer;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.fx-btn:hover { background: var(--muted); color: var(--foreground); }
/* A toggle button showing its current state — the programme's "Whole programme" view, which is either on
   or off and previously gave no sign which. */
.fx-btn.is-on { background: var(--muted); border-color: var(--input); font-weight: 600; }
.fx-btn-gold { background: var(--primary); color: var(--primary-foreground); border-color: transparent; box-shadow: 0 1px 2px rgba(0,0,0,0.08); }
/* Hover derives from the CTA fill (each channel -10%) instead of the near-black oklch() that was here.
   That literal was a shadcn leftover: it made the primary button jump from steel blue to almost black on
   hover, and on a rebranded portal it would have done that whatever the brand's colours were. --cta-hover
   is emitted with the resolved brand, and falls back to the primary here for a page rendered before any
   brand has been read. */
.fx-btn-gold:hover:not(:disabled) { background: var(--cta-hover, var(--primary)); color: var(--primary-foreground); }
.fx-btn-danger { background: var(--c-danger-bg); color: var(--destructive); border-color: transparent; }
.fx-btn-danger:hover:not(:disabled) { background: rgba(220,38,38,0.18); color: var(--destructive); }
.fx-btn-sm { padding: 3px 10px; font-size: 0.8rem; }
.fx-btn:disabled { opacity: 0.5; cursor: default; }

.fx-link { color: var(--brand-accent); text-decoration: none; font-size: 0.85rem; font-weight: 500; }
.fx-link:hover { text-decoration: underline; }

/* ===========================================================================
   Top navigation (Slice 1 — demo nav.tsx). Text links + grouped dropdowns on
   the white bar. Active = the demo's topButtonClass; dropdown panels = the
   demo's white rounded-xl ring/shadow popover.
   =========================================================================== */
.fx-topnav { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; min-width: 0; }

.fx-top-link {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 7px 12px; border-radius: var(--radius-lg); border: none;
    background: transparent; color: var(--ink-2); text-decoration: none;
    font-family: inherit; font-size: 0.875rem; font-weight: 500; cursor: pointer;
    white-space: nowrap;
    transition: background .12s ease, color .12s ease;
}
.fx-top-link:hover { background: var(--muted); color: var(--foreground); }
/* Active nav = steel-blue primary + white (reserves safety orange for the one CTA;
   the old orange-bg + steel-text combination failed contrast). */
.fx-top-link.on { background: var(--brand-primary); color: #fff; font-weight: 600; }

.fx-top-dd { position: relative; }
.fx-top-chevron { transition: transform .12s ease; }
.fx-top-link.open .fx-top-chevron { transform: rotate(180deg); }

.fx-top-backdrop { position: fixed; inset: 0; z-index: 1400; background: transparent; }

.fx-top-panel {
    position: absolute; left: 0; top: calc(100% + 6px); z-index: 1500;
    min-width: 220px;
    background: var(--popover); border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: 0 10px 30px rgba(0,0,0,0.12);
    overflow: hidden; padding: 5px;
}
.fx-top-panel a {
    display: block; padding: 9px 14px; border-radius: var(--radius-md);
    color: var(--ink-2); text-decoration: none; font-size: 0.875rem;
    transition: background .12s ease, color .12s ease;
}
.fx-top-panel a:hover { background: var(--muted); color: var(--foreground); }
.fx-top-panel a.on { background: rgba(11,120,94,0.12); color: var(--brand-primary); font-weight: 600; }

.fx-empty { text-align: center; padding: 56px 24px; color: var(--muted-foreground); }

/* ===========================================================================
   Master-data detail 360s (Slice 3 — demo customer/supplier detail pages):
   header row, KPI strip, native tab bar (demo shadcn tabs underline), detail
   cards with label/value rows, inline edit form.
   =========================================================================== */
.cd-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin: 10px 0 20px; flex-wrap: wrap; }
.cd-head-actions { display: flex; align-items: center; gap: 10px; }
.cd-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 20px; }

.cd-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.cd-tab {
    padding: 8px 14px; border: none; background: transparent; cursor: pointer;
    font-family: inherit; font-size: 0.875rem; font-weight: 500; color: var(--muted-foreground);
    border-bottom: 2px solid transparent; margin-bottom: -1px;
    transition: color .12s ease, border-color .12s ease;
}
.cd-tab:hover { color: var(--foreground); }
.cd-tab.on { color: var(--brand-primary); border-bottom-color: var(--brand-accent); font-weight: 600; }

.cd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 20px; }
.cd-card { padding: 18px 20px; }
.cd-card h3 { margin: 0 0 12px; font-family: var(--font-heading); font-size: 1rem; font-weight: 600; }
.cd-row { display: flex; justify-content: space-between; gap: 16px; padding: 6px 0; font-size: 0.875rem; }
.cd-row-label { color: var(--muted-foreground); flex-shrink: 0; }
.cd-row-value { text-align: right; }
.cd-notes-text { margin: 0; font-size: 0.875rem; color: var(--ink-2); white-space: pre-wrap; }

.cd-edit { padding: 18px 20px; margin-bottom: 20px; }
.cd-edit h3 { margin: 0 0 12px; font-family: var(--font-heading); font-size: 1rem; font-weight: 600; }
/* align-items: end is the fix for a reported defect (77BDD542, 21/08/2026): "The order number isn't
   aligned with the other options and just needs tweaking slightly so it's clean and tidy."

   The label is a flex COLUMN — caption above input — and every cell in a grid row shares that row's
   height. "Order number (the client's)" is long enough to wrap onto a second line at this column width,
   which made its cell taller and pushed its input DOWN relative to Quoted on and Order received beside
   it. Bottom-aligning the cells lines the inputs up whatever the caption does, so the same thing cannot
   happen again the next time somebody writes a two-word label. Global, because .cd-form is on every
   project/master-data edit form and the next long label will be on a different one. */
.cd-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; align-items: end; }
.cd-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.78rem; color: var(--ink-2); font-weight: 500; }
/* The caption grows upward from the field rather than pushing it down. */
.cd-form label > input, .cd-form label > select, .cd-form label > textarea { margin-top: auto; }
.cd-form input {
    font-family: var(--font-sans); font-size: 0.9rem; color: var(--foreground);
    background: var(--field-bg); border: 1px solid var(--input); border-radius: var(--r-input);
    padding: 8px 11px; outline: none;
}
.cd-form input:focus { border-color: var(--ring); box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5); }
.cd-form .cd-notes { grid-column: 1 / -1; }
.cd-edit-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; }
/* cd-form select — global, matches cd-form input (was page-local in ProjectDetail). */
.cd-form select {
    font-family: var(--font-sans); font-size: 0.9rem; color: var(--foreground);
    background: var(--field-bg); border: 1px solid var(--input); border-radius: var(--r-input);
    padding: 8px 11px; outline: none; width: 100%;
}
.cd-form select:focus { border-color: var(--ring); box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5); }

/* ---------------------------------------------------------------------------
   md-form fields — the master-data editors (customers, suppliers, cost codes,
   catalogue, rates, materials, assets, party links, finance reference).

   GLOBAL on purpose. Each of those nine pages previously carried its own copy of
   this rule with the pre-re-skin dark-theme values (a white-alpha fill over a
   white-alpha border). Against the concrete/white surfaces this palette actually
   uses, a 15%-white border on a white card is INVISIBLE — the fields had no edge
   at all, so "there is no outline of the boxes that need filling in" (reported on
   the new-customer form). Nine copies is also how the next re-skin reintroduces
   the same bug nine times, so the rule lives here and matches .cd-form/.fx-field.
   --------------------------------------------------------------------------- */
.md-form input, .md-form select, .md-form textarea {
    font-family: var(--font-sans); font-size: 0.88rem; color: var(--foreground);
    background: var(--field-bg); border: 1px solid var(--input); border-radius: var(--r-input);
    padding: 7px 10px; outline: none;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.md-form input::placeholder, .md-form textarea::placeholder { color: var(--muted-foreground); }
.md-form input:focus, .md-form select:focus, .md-form textarea:focus {
    border-color: var(--ring); box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5);
}
/* A checkbox must keep its native box — the field styling above would erase it. */
.md-form input[type="checkbox"] {
    width: auto; padding: 0; box-shadow: none; background: none; border: none;
}

/* Shared 4-up stat grid (Home dashboard, partner workspace). */
.fx-stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 16px; }
@media (max-width: 980px) { .fx-stat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .fx-stat-grid { grid-template-columns: 1fr; } }

/* ============================================================================
   D23 partner workspace — DEFINED console cards.
   The shadcn default (--shadow:none, white card on a white page, no card padding)
   leaves card edges invisible and content flush to the border. These pages are dense
   admin consoles, so partner cards get a FINDABLE edge (stronger border + a gentle
   elevation), real PADDING, and header BANDS that separate title from data.
   Candidate to promote app-wide + fold into the styleguide once signed off.
   ============================================================================ */
.pt-crumb { font-size: 0.82rem; color: var(--muted-foreground); margin-bottom: 14px; }
.pt-crumb a { color: var(--ink-2); text-decoration: none; }
.pt-crumb a:hover { color: var(--brand-accent); }
.pt-crumb span { margin: 0 6px; }
.pt-kicker { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--brand-secondary); margin: 0 0 2px; }

/* Shared console-card shell — findable edge + padding (the fix for "no edges / no padding"). */
.pt-hero, .pt-card, .pt-create-panel {
    background: var(--card);
    border: 1px solid var(--hair-2);
    border-radius: var(--r-card);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 10px 24px -12px rgba(16, 24, 40, 0.18);
    padding: 20px 22px;
}
.pt-create-panel { margin-bottom: 16px; }
/* Stat cards get the same stronger edge + lift (later than .fx-stat, so it wins). */
.pt-stat { border: 1px solid var(--hair-2); box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06); }

.pt-hero { margin-bottom: 16px; position: relative; overflow: hidden; }
.pt-hero.is-suspended::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--destructive); }
.pt-hero-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.pt-identity { display: flex; align-items: center; gap: 14px; }
.pt-monogram { width: 48px; height: 48px; border-radius: 12px; flex-shrink: 0; display: grid; place-items: center; background: var(--brand-primary); color: #fff; font-family: var(--font-heading); font-weight: 800; font-size: 1.3rem; }
.pt-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pt-num-sub { color: var(--muted-foreground); font-weight: 600; font-size: 1rem; }
.pt-num-word { font-size: 1.2rem; }
.pt-warn { color: var(--c-warning); }
.pt-suspend-note { margin: 14px 0 0; padding: 8px 12px; font-size: 0.82rem; background: var(--c-danger-bg); color: var(--c-danger); border-radius: var(--radius-md); }

/* Two independent columns — each packs its own cards (no cross-column void). */
.pt-cols { display: flex; gap: 16px; align-items: flex-start; }
.pt-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
@media (max-width: 900px) { .pt-cols { flex-direction: column; } }

/* Header BAND — bled to the card edges (negative margin cancels card padding), faint
   tint + divider + a bold Montserrat heading, so the header clearly outranks the data. */
.pt-panel-head {
    display: flex; align-items: center; gap: 9px;
    margin: -20px -22px 18px; padding: 13px 22px;
    background: var(--muted); border-bottom: 1px solid var(--hair-2);
    border-radius: var(--r-card) var(--r-card) 0 0; color: var(--brand-primary);
}
.pt-panel-head h3 { font-family: var(--font-heading); font-weight: 700; font-size: 1.02rem; color: var(--ink); margin: 0; }
.pt-ico { flex-shrink: 0; }
.pt-head-meta { margin-left: auto; font-size: 0.8rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }

.pt-actions { display: flex; gap: 10px; margin-top: 16px; }
.pt-env-add, .pt-user-add { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--hair); }
.pt-hint { font-size: 0.8rem; color: var(--muted-foreground); margin: 8px 0 0; }

/* Internal list dividers use the FAINT hairline (--hair); the card border (--hair-2) is the strong edge. */
.pt-licence-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--hair); }
.pt-licence-row:last-of-type { border-bottom: none; }
.pt-licence-text { min-width: 0; }
.pt-licence-name { margin: 0; font-weight: 600; font-size: 0.9rem; color: var(--foreground); }
.pt-licence-blurb { margin: 0; font-size: 0.78rem; color: var(--muted-foreground); }
.pt-licence-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.pt-required { font-size: 0.78rem; }

.pt-env-list, .pt-user-list { display: flex; flex-direction: column; }
.pt-env-row { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--hair); font-size: 0.86rem; }
.pt-env-row:last-child { border-bottom: none; }
.pt-env-name { font-weight: 500; color: var(--foreground); flex: 1; }
.pt-env-meta { font-size: 0.78rem; color: var(--muted-foreground); }
.pt-user-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--hair); }
.pt-user-row:last-child { border-bottom: none; }
.pt-user-avatar { width: 28px; height: 28px; border-radius: 999px; flex-shrink: 0; display: grid; place-items: center; background: var(--brand-primary); color: #fff; font-size: 0.74rem; font-weight: 700; font-family: var(--font-heading); }
.pt-user-email { font-size: 0.86rem; color: var(--ink-2); flex: 1; }
.pt-user-role { flex-shrink: 0; }

.pt-cred { display: flex; gap: 10px; align-items: flex-start; margin-top: 16px; padding: 12px 14px; background: var(--c-success-bg); border-left: 3px solid var(--brand-secondary); border-radius: var(--radius-md); color: var(--c-success); }
.pt-cred-title { margin: 0 0 2px; font-size: 0.76rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
.pt-cred-body { margin: 0; font-size: 0.85rem; color: var(--ink-2); font-family: var(--font-mono); overflow-wrap: anywhere; }

.pt-env-use { display: flex; align-items: center; gap: 8px; min-width: 120px; }
.pt-env-track { flex: 1; height: 6px; max-width: 80px; background: var(--muted); border-radius: 999px; overflow: hidden; }
.pt-env-fill { display: block; height: 100%; background: var(--brand-secondary); border-radius: 999px; }
.pt-env-count { font-size: 0.8rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }

.pt-empty { text-align: center; padding: 48px 24px; color: var(--muted-foreground); }
.pt-empty svg { color: var(--brand-primary); opacity: 0.35; margin-bottom: 10px; }
.pt-empty-title { font-family: var(--font-heading); font-weight: 600; font-size: 1.05rem; color: var(--foreground); margin: 0 0 4px; }

.pt-hero, .pt-card { animation: pt-rise 0.34s ease both; }
.pt-col:nth-child(1) .pt-card:nth-child(2) { animation-delay: 0.06s; }
.pt-col:nth-child(2) .pt-card:nth-child(1) { animation-delay: 0.06s; }
.pt-col:nth-child(2) .pt-card:nth-child(2) { animation-delay: 0.12s; }
@keyframes pt-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .pt-hero, .pt-card { animation: none; } }

/* Shared horizontal bar list (Directors' dashboard breakdowns, Practice Overview
   utilisation) — single-hue proportional bars with text values (dataviz: text wears
   text tokens; the bar carries magnitude only). */
.dd-bar-row { display: grid; grid-template-columns: minmax(110px, 1fr) 2fr auto; align-items: center; gap: 10px; padding: 5px 0; font-size: 0.85rem; }
.dd-bar-label { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-bar-track { height: 10px; background: var(--muted); border-radius: 4px; overflow: hidden; }
.dd-bar-fill { display: block; height: 100%; background: #007fa3; border-radius: 4px; }
.dd-bar-value { color: var(--foreground); font-weight: 500; }

/* PRD 18 §18.2 — drill-through affordances. Every clickable figure looks clickable; a number that
   opens a record list but reads as plain text is a feature nobody finds. */
a.dd-drill { color: inherit; text-decoration: none; cursor: pointer; }
a.dd-drill:hover { text-decoration: underline; text-underline-offset: 3px; }
a.fx-stat.dd-drill:hover { border-color: var(--gold); }
td .dd-drill { display: inline-block; }

.dd-half { font-weight: 600; }
.dd-clarity { margin-top: 18px; padding: 14px 16px; }
.dd-clarity summary { cursor: pointer; font-weight: 600; }
.dd-defs { margin: 12px 0 0; display: grid; grid-template-columns: minmax(140px, 220px) 1fr; gap: 6px 16px; font-size: 0.85rem; }
.dd-defs dt { color: var(--foreground); font-weight: 600; }
.dd-defs dd { margin: 0; color: var(--ink-2); }
.dd-def { display: block; margin-top: 4px; font-size: 0.72rem; font-weight: 400; color: var(--ink-2); }

/* §18.1 — the reporting landing page: one block per financial year, buttons through to each area. */
.rh-years { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.rh-year { padding: 18px 20px; }
.rh-year-title { margin: 0 0 12px; font-size: 1.05rem; display: flex; align-items: center; gap: 8px; }
.rh-chip { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; padding: 2px 8px; border-radius: 999px; background: var(--muted); color: var(--ink-2); }
.rh-chip-next { background: transparent; border: 1px solid var(--muted); }
.rh-buttons { display: flex; flex-wrap: wrap; gap: 8px; }

/* ===========================================================================
   Dialogs — MudDialog provides the shell (radius via --r-modal + the flat
   overlay above); these style title, form fields and notes on the light card.
   =========================================================================== */
.fx-dialog-head { display: flex; flex-direction: column; gap: 4px; }
.fx-dialog-title { font-family: var(--font-heading); font-weight: 600; font-size: 1.25rem; color: var(--foreground); margin: 0; }
.fx-dialog-sub { font-size: 0.88rem; color: var(--ink-2); margin: 0; }
.fx-dialog-note { font-size: 0.8rem; color: var(--muted-foreground); margin: 0; }

.fx-form { display: flex; flex-direction: column; gap: 16px; min-width: min(440px, 80vw); padding-top: 4px; }
.fx-field { display: flex; flex-direction: column; gap: 6px; }
.fx-field label { font-size: 0.78rem; color: var(--ink-2); font-weight: 500; }
.fx-field .fx-optional { color: var(--muted-foreground); font-weight: 400; }
/* A one-line explanation under a field — "carried through from the enquiry", "no active streams are
   configured". Used by the accept-estimate dialog and declared nowhere, so those lines rendered as ordinary
   body paragraphs with default margins, reading as content rather than as a hint. */
.fx-field-hint { font-size: 0.76rem; color: var(--muted-foreground); margin: 2px 0 0; line-height: 1.4; }
.fx-field input, .fx-field select {
    font-family: var(--font-sans); font-size: 0.9rem; color: var(--foreground);
    background: var(--field-bg); border: 1px solid var(--input); border-radius: var(--r-input);
    padding: 9px 12px; outline: none; width: 100%;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    transition: border-color .12s ease, box-shadow .12s ease;
}
.fx-field input::placeholder { color: var(--muted-foreground); }
.fx-field input:focus, .fx-field select:focus { border-color: var(--ring); box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5); }

/* ---- .fx-input — the field styling as a class, for a field outside .fx-field ----
   Used on four pages and, like .fx-form-row and .fx-h3, declared nowhere. Most of those uses happen to sit
   inside a .fx-field and were carried by the rules above, which is exactly why it went unnoticed. Two are
   not: the amount box on the project billing form (in a table cell) and the rename box on the programme,
   both of which rendered with no border, no padding and no focus ring — an editable money field with no
   visible edge, on the screen a reported pence defect was raised from. */
.fx-input {
    font-family: var(--font-sans); font-size: 0.9rem; color: var(--foreground);
    background: var(--field-bg); border: 1px solid var(--input); border-radius: var(--r-input);
    padding: 9px 12px; outline: none; width: 100%;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    transition: border-color .12s ease, box-shadow .12s ease;
}
.fx-input::placeholder { color: var(--muted-foreground); }
.fx-input:focus { border-color: var(--ring); box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5); }
.fx-input:disabled { background: var(--muted); color: var(--muted-foreground); }
.fx-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* ---- .fx-form-row — a row of fields filling a panel ----
   The other half of the 22/08/2026 styling report: "the words and drop downs all need indenting."

   This class was used on three pages (project Delivery, Billing and Resourcing) and declared NOWHERE, so
   it did nothing at all. `.fx-panel` deliberately carries no padding — it is a bare surface, and pages
   that need padding add their own class — so an undeclared row class left the labels and selects hard
   against the panel's border with no inset, which is what was reported. On Delivery it was worse than
   cosmetic: the div also carries `.fx-form`, a flex COLUMN, so the four fields of "Add a milestone"
   stacked full-width down the page instead of sitting in a row.

   Two classes in the selector (`.fx-form.fx-form-row`) rather than one, so it beats `.fx-form`'s
   flex-direction whichever order the two rules end up in. Equal specificity losing to source order is
   the trap the ShellSidebar/MainLayout shells hit. */
.fx-form-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
    padding: 18px 20px;
}
.fx-form.fx-form-row { flex-direction: row; min-width: 0; padding-top: 18px; }
/* Fields share the row and wrap rather than squeezing below a usable width. */
.fx-form-row > .fx-field { flex: 1 1 200px; min-width: 0; }
/* A field holding only a button aligns with the inputs beside it rather than stretching. */
.fx-form-row > .fx-field > button { flex: 0 0 auto; }
@media (max-width: 520px) { .fx-field-row { grid-template-columns: 1fr; } }
.fx-form-error {
    font-size: 0.84rem; color: var(--destructive); background: var(--c-danger-bg);
    border: 1px solid rgba(220,38,38,0.25); border-radius: var(--r-input); padding: 9px 12px;
}

/* ---------------------------------------------------------------------------
   Environment pills + dots (D23 §8).
   GLOBAL on purpose: AdminEnvironments and PartnerTenantView render these, and a
   partner / platform-owner principal is in NO environment, so the header badge
   component is not rendering on exactly those pages. A component <style> block only
   exists while its component renders — keeping these here is what stops those pills
   from losing their styling.
   --------------------------------------------------------------------------- */
.fx-env-badge {
    font-size: 0.66rem; font-weight: 700; letter-spacing: 0.05em;
    padding: 2px 6px; border-radius: 999px;
}
.fx-env-badge.fx-env--live { background: rgba(220,38,38,0.12); color: #dc2626; }
.fx-env-badge.fx-env--uat { background: rgba(3,105,161,0.12); color: #0369a1; }
.fx-env-badge.fx-env--test { background: rgba(180,83,9,0.12); color: #b45309; }
.fx-env-badge.fx-env--sandbox { background: rgba(124,58,237,0.12); color: #7c3aed; }

.fx-env-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.fx-env-dot.fx-env--live { background: #dc2626; }
.fx-env-dot.fx-env--uat { background: #0369a1; }
.fx-env-dot.fx-env--test { background: #b45309; }
.fx-env-dot.fx-env--sandbox { background: #7c3aed; }

/* LE-WC-4 — "no legal entity assigned" block (replaces page content, not an inline banner). */
.fx-nocompany {
    max-width: 44rem; margin: 8vh auto; padding: 28px 32px;
    background: var(--card); border: 1px solid var(--border);
    border-radius: var(--radius-lg); text-align: left;
}
.fx-nocompany h1 {
    font-family: var(--font-display, inherit); font-size: 1.4rem; font-weight: 700;
    margin: 0 0 12px; color: var(--foreground);
}
.fx-nocompany p { margin: 0 0 10px; color: var(--ink-2); line-height: 1.6; }
.fx-nocompany .fx-nocompany-sub { font-size: 0.86rem; color: var(--muted-foreground); margin-bottom: 0; }

/* PRD 18 §20.6 (REQ-195) — contacts edited in the box where they are shown. The affordance sits on the
   card, so nobody has to leave the surface to correct a phone number. */
.cd-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.cd-inline-edit {
    background: transparent; border: 1px solid var(--muted); border-radius: 999px;
    padding: 2px 12px; font: inherit; font-size: 0.76rem; color: var(--ink-2); cursor: pointer;
}
.cd-inline-edit:hover { border-color: var(--brand-primary); color: var(--brand-primary); }
.cd-inline-form { display: grid; gap: 8px; margin-top: 10px; }
.cd-inline-form label { display: flex; flex-direction: column; gap: 3px; font-size: 0.78rem; color: var(--ink-2); }
.cd-inline-form input { padding: 6px 9px; border: 1px solid var(--muted); border-radius: 8px; font: inherit; }

/* PRD 18 §20.5 (REQ-194) — sortable column headings on the hand-built grids. */
.fx-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.fx-sortable:hover { color: var(--brand-primary); }
.fx-sortable.on { color: var(--brand-primary); font-weight: 600; }
