/* Read-only display patterns — Shell-owned, split out of shared.css (Sprint 9.5 Story 22,
   architecture/SHARED-CSS-LAYER-SPLIT.md). .app-field-list and its modifiers, loading/empty states, and
   the key-figure/ageing stat tiles. Linked once in App.razor's <head>, reaching every Blick's DOM the
   same way shared.css already did. */

/* ── Read-only label-value list (.app-field-list) ────────────────────────────────────────────────────────
   Duane's ruled pattern (2026-08-28): the one pattern for a
   plain read-only <dl> of label/value pairs, replacing two forks that had drifted — CustomerProfile.razor's
   `.cp-panel dl/dt/dd` (CCP.CustomerContext.Blick/blick.css, values lifted verbatim below) and
   WorkOrderDetails.razor's `.wo-detail-grid` (CCP.WorkManagementContext.Blick/blick.css, deleted). Both
   private rules are gone from their Blicks' own stylesheets; every screen with this shape uses this class.
   Not `OneRecord` — evaluated and rejected for this shape (WorkOrderDetails.razor's own header comment):
   `ShowDataColumnsInGridColumns` doesn't run specs through `VisibleColumnParser.GetColumnSettings`, so it
   cannot express friendly labels or the app's "—" null-display convention, and a panel composed from several
   data sources (e.g. CustomerProfile's Account panel) is not one record from one data list anyway. */
/* align-items: baseline -- Will's visual inspection FAIL 6 (backlog/plan_will-2026-09-04-screen-review-artefact-triage.md §1): the
   --inline modifier below puts dt/dd on one shared grid row, and the sm-sized label vs base-sized value gave
   each its own top-aligned box 5px apart. Harmless on the base (stacked) shape, where each row holds one item
   alone. */
.app-field-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--brand-space-2);
    align-items: baseline;
    margin: 0;
}

.app-field-list dt {
    font-weight: var(--brand-font-weight-medium);
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-xs);
}

.app-field-list dd {
    margin: 0 0 var(--brand-space-1);
    color: var(--brand-text);
}

/* ── Read-only label-value list, inline modifier (.app-field-list--inline) ──────────────────────────────
   Detail-screen pattern (DESIGN-SYSTEM-DETAIL-SCREENS.md §3): the reference's muted-label-plus-value pair
   reads "Label: Value" on ONE line, not stacked. A MODIFIER on .app-field-list above (Duane's explicit call),
   never a second component -- the base class and its existing stacked consumers are untouched. */
.app-field-list--inline {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--brand-space-2);
}

.app-field-list--inline dt {
    font-size: var(--brand-font-size-sm);
}

.app-field-list--inline dt::after {
    content: ":";
}

.app-field-list--inline dd {
    margin: 0;
    /* DESIGN-SYSTEM-DETAIL-SCREENS.md:354/362: an unbroken long value (e.g. a long approver email address in an
       approval list) must not overflow its grid cell -- the grid's fixed auto/1fr columns give it nowhere to
       wrap on its own. */
    overflow-wrap: anywhere;
}

/* Pairs may be bare <dt>/<dd> children OR <div>-wrapped (<div><dt>...<dd>...</div>). This rule makes a wrapper
   div transparent to the grid, so a wrapped pair falls into the two columns above like a bare one does -- without
   it the wrapper is a single grid cell and dt/dd stack inside it. Same reasoning as the --ledger rule below. */
.app-field-list--inline > div {
    display: contents;
}

/* ── Read-only label-value list, band modifier (.app-field-list--band) ──────────────────────────────────
   DESIGN-SYSTEM-DETAIL-SCREENS.md §3a.2: a horizontal strip of stacked pairs that wraps — the summary row
   at the top of a dialog or a record panel. A MODIFIER on .app-field-list above, replacing
   CCP.FinanceContext.Blick's .fin-detail-grid fork (§3a.3). */
.app-field-list--band {
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--brand-space-4);
}

.app-field-list--band dt {
    font-size: var(--brand-font-size-xs);
}

.app-field-list--band > div {
    display: flex;
    flex-direction: column;
}

/* ── Read-only label-value list, ledger modifier (.app-field-list--ledger) ──────────────────────────────
   DESIGN-SYSTEM-DETAIL-SCREENS.md §3a.2: a column of money read down to a total. A MODIFIER on
   .app-field-list above, replacing CCP.QuoteContext.Blick's .qw-totals dl fork (§3a.3). */
.app-field-list--ledger {
    grid-template-columns: 1fr auto;
    gap: var(--brand-space-1) var(--brand-space-3);
}

.app-field-list--ledger dt {
    font-size: var(--brand-font-size-sm);
}

.app-field-list--ledger dd {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* S5 UI polish pass #3 (Brian's live smoke): each row is markup as <div><dt>Label</dt><dd>Value</dd></div> so
   the dt/dd pair can host per-row conditional ReadOnly/edit markup — but the two-column grid above applies to
   dl's DIRECT children, which are these wrapper divs, not dt/dd. Without this rule each div becomes a single
   grid cell and dt/dd stack inside it (label above value, exactly Brian's screenshot). display: contents makes
   the wrapper disappear for layout purposes while dt/dd still fall directly into the grid's two columns. */
.app-field-list--ledger > div {
    display: contents;
}

.app-field-list--ledger .qw-grand-total dt,
.app-field-list--ledger .qw-grand-total dd {
    font-weight: var(--brand-font-weight-bold);
    font-size: var(--brand-font-size-lg);
}

/* ── Loading state (.app-loading) ────────────────────────────────────────────────────────────────────────
   Story 17 (2026-08-25 conformance sweep, item 1): the loading state rendered four different ways across 42
   instances in 37 files, 36 of them with no `role="status"` — the wait was silent for a screen-reader user.
   Ruled single shape (Duane): `<p class="app-loading" role="status">Loading…</p>` — literal `…`, never the
   `&hellip;` entity, which breaks text search. Styled as the muted hint treatment CCP.FinanceContext.Blick's
   `.fin-hint` already uses, the deliberate one of the two looks in use today. Shipped once, here; an existing
   screen converges onto it the next time it is touched (no dedicated rewrite is scheduled). */
.app-loading {
    font-size: var(--brand-font-size-sm);
    color: var(--brand-neutral-text);
    margin: 0;
}

/* ── Empty state (.app-empty) ─────────────────────────────────────────────────────────────────────────────
   Duane's grid-state ruling (2026-08-28): the "no rows" state was
   forked four ways — `.fin-empty` (Finance), `.inv-empty` (Inventory), `.qw-empty` (Quote), `.wo-empty`
   (Work Management) — the same DESIGN-SYSTEM.md §4.32 / D-0183 styling fork the `.app-loading` hoist above already removed
   for the loading state. `.fin-empty`'s treatment is taken as the canonical look (the deliberate, inspected
   one of the four): visibly a designed state — muted text, padding, dashed border, rounded corners — not a
   blank hole. Shipped once, here; each Blick swaps its fork for `.app-empty` on this same change and deletes
   the local rule. Scope: `CCP.*` Blicks only — a `BD.*` Blick may never reference it. */
.app-empty {
    font-size: var(--brand-font-size-sm);
    color: var(--brand-neutral-text);
    padding: var(--brand-space-4);
    border: 1px dashed var(--brand-border);
    border-radius: var(--brand-radius-md);
    margin: 0;
}

/* ── Placeholder / hint text (input::placeholder) ────────────────────────────────────────────────────────
   Duane's ruling (2026-08-28): app-wide,
   Shell-owned so every form shares one look — a per-Blick rule would fork it the way `.app-empty` above was
   forked before its hoist. Theme is Syncfusion bootstrap5 (App.razor), so this emulates Material Design's
   hint-text look with our own brand tokens rather than pulling in Material itself. No italics, no size
   reduction — hint text matches the input's own size and weight, just muted. */
input::placeholder,
textarea::placeholder,
.e-input::placeholder {
    color: var(--brand-text-muted);
    opacity: 0.65;
    font-weight: 400;
    font-style: normal;
    font-size: inherit;
}

/* Syncfusion's multi-select draws its hint on an `e-multiselect` input (inside `.e-multi-select-wrapper`), not an
   `e-input`, and sets that input to 0.875rem — so `font-size: inherit` above would keep the hint at 14px. 1rem is the size
   the `.e-input` / `.form-control` inputs beside it use; colour and opacity already arrive from the shared rule above. */
.e-multi-select-wrapper input.e-multiselect::placeholder,
.e-multiselect::placeholder {
    color: var(--brand-text-muted);
    opacity: 0.65;
    font-weight: 400;
    font-style: normal;
    font-size: 1rem;
}

/* Inside an add/edit dialog the other inputs' hint is `--brand-text-subtle` at full opacity
   (`.b3-addone-editone .form-control::placeholder`, shared-dialogs.css); Syncfusion's own colour rule beats the rule above on
   the multi-select, so match the dialog inputs here with the extra `.e-dropdownbase` class for specificity. */
.b3-addone-editone .e-multi-select-wrapper input.e-multiselect.e-dropdownbase::placeholder {
    color: var(--brand-text-subtle);
    opacity: 1;
}

/* ── Key-figure tile (.app-stat-tile / .app-stat-tile__item / .app-stat-tile__label / .app-stat-tile__value / .app-stat-tile__caption) ──
   Story 16's rider (D-0183 route): the Executive Dashboard's `.kpi-card` (theme.css) and the Finance Blick's
   `.fin-summary` were two implementations of the same widget — a label, a big value, and sometimes a caption
   below it. Converged here onto Finance's box-and-item shape UNCHANGED: it already carries four screens (the
   cheque-distribution totals strip, the invoice-detail totals strip, the Overdue-invoices stats, and the
   Finance Dashboard's own key figures) as one bordered box holding one item per metric side by side. The
   Executive Dashboard and the Dev State page ("Home") converge onto it as the N=1 case of the same shape —
   one `.app-stat-tile` per metric, since the box already carries its own border/background/padding and needs
   no second per-metric card wrapper the way `.kpi-card` was. `.app-stat-tile__caption` is new: Finance's own
   tiles never carried a caption line under the value, the Executive tiles' "from last month" / "MTD Average"
   sub-line does. `.kpi-card`'s horizontal label-value-caption-link row (theme.css, deleted) was also the
   cramped layout that wrapped "View Finance Dashboard" mid-word beside the value on a `col-md-3` tile — the
   vertical stack below reads cleanly at that width instead. */
.app-stat-tile {
    display: flex;
    flex-wrap: wrap;
    gap: var(--brand-space-6);
    padding: var(--brand-space-4);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius-md);
    background: var(--brand-neutral-bg);
}

.app-stat-tile__item {
    display: flex;
    flex-direction: column;
}

.app-stat-tile__item:has(.stretched-link:focus-visible) {
    border-radius: var(--brand-radius-md);
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--brand-primary) 50%, transparent);
}

.app-stat-tile__item .stretched-link:focus-visible {
    outline: none;
}

.app-stat-tile__label {
    font-size: var(--brand-font-size-sm);
    font-weight: var(--brand-font-weight-medium);
    color: var(--brand-text);
}

.app-stat-tile__value {
    font-size: var(--brand-font-size-xl);
    font-weight: var(--brand-font-weight-bold);
    color: var(--brand-primary);
}

/* An at-risk or attention-worthy figure that is still not an error — a non-zero cheque remainder, a warning
   count — reads as ATTENTION, never as danger. Deliberately the warning token, not the danger one. */
.app-stat-tile__value--attention {
    color: var(--brand-warning-text);
}

/* A figure that is wrong by its meaning, not merely worth a look — more applied than was received. The danger token. */
.app-stat-tile__value--danger {
    color: var(--brand-danger-text);
}

.app-stat-tile__caption {
    font-size: var(--brand-font-size-sm);
    margin-top: var(--brand-space-1);
    color: var(--brand-neutral-text);
}

/* ── Ageing tile variant (.app-stat-tile--ageing / .app-stat-tile__item--{success,warning,danger,neutral}) ──
   git show 7f0616da:backlog/MOCKUP-SPEC-CUSTOMER-AGEING-TILES.md §2 — the customer screen's five ageing money chips (Current, 1-30,
   31-60, 61-90, Over 90). D-0210 (Brian, 2026-09-01) removed the sixth, Total Outstanding, and every
   :last-child rule that dressed it — Over 90 is now a plain danger-coloured peer, the new last tile.
   Extends .app-stat-tile rather than minting a rival: the base box
   shape (border/background/padding) is dropped so each ITEM becomes the visible chip, and label/value go
   inline on one line ("Current: $0.00") instead of the base shape's stacked layout. Additive app-* contract
   entries (card #231 rider 2) — the base class and its existing stacked consumers are untouched. */
.app-stat-tile--ageing {
    background: none;
    border: none;
    padding: 0;
    gap: var(--brand-space-3);
    margin-bottom: var(--brand-space-4);
}

.app-stat-tile--ageing .app-stat-tile__item {
    flex-direction: row;
    align-items: baseline;
    gap: 0;
    padding: var(--brand-space-2) var(--brand-space-4);
    border-radius: var(--brand-radius-md);
}

/* Same colon technique as .app-field-list--inline (DESIGN-SYSTEM-DETAIL-SCREENS.md §3) — CSS-generated, so
   screen readers and text search never see a literal colon character. */
.app-stat-tile--ageing .app-stat-tile__label {
    font-size: inherit;
    font-weight: inherit;
    color: inherit;
}

.app-stat-tile--ageing .app-stat-tile__label::after {
    content: ":";
    margin-right: var(--brand-space-1);
}

/* The base .app-stat-tile__value's --brand-primary colour is the WRONG axis here — colour on an ageing chip is
   severity, never "this is a key figure", so each severity modifier below overrides it via `color: inherit`. */
.app-stat-tile--ageing .app-stat-tile__value {
    font-size: var(--brand-font-size-base);
    font-weight: var(--brand-font-weight-semibold);
    color: inherit;
}

.app-stat-tile__item--success {
    background: var(--brand-success-bg);
    color: var(--brand-success-text);
}

/* Corrected mapping (git show 7f0616da:backlog/MOCKUP-SPEC-CUSTOMER-AGEING-TILES.md §3, 2026-09-01, after Will's visual-inspection
   FAIL 1): 31-60 and 61-90 used to share ONE fill (#FDEFD9) with only a 1.15:1 hairline border distinguishing
   61-90 — position, not colour, carried the three middle buckets. The base rule below is now 31-60's own
   step (Warning-150 fill / Warning-900 text); the border is DROPPED entirely, since it was doing the work the
   fill should do and did not read. */
.app-stat-tile__item--warning {
    background: var(--brand-warning-mid-bg);
    color: var(--brand-warning-mid-text);
}

/* §3's per-bucket fill differences within the warning family (1-30 palest, 61-90 deepest) are structural —
   keyed to the five-tile row's fixed bucket order (§1: Current, 1-30, 31-60, 61-90, Over 90) — the
   positional nth-child selectors below are keyed to that order — rather than two more class tokens, since
   the spec names exactly four severity modifiers as the contract
   addition. 31-60 is the plain .app-stat-tile__item--warning fill above; 1-30 (2nd item) and 61-90 (4th item)
   are the two structural exceptions, each with its own text colour (Warning-800 / Warning-950) as well as its
   own fill — the ramp step 25 -> 150 -> 300 darkens the text 800 -> 900 -> 950 in step as a second cue. */
.app-stat-tile--ageing .app-stat-tile__item--warning:nth-child(2) {
    background: var(--brand-warning-soft-bg);
    color: var(--brand-warning-text);
}

.app-stat-tile--ageing .app-stat-tile__item--warning:nth-child(4) {
    background: var(--brand-warning-strong-bg);
    color: var(--brand-warning-strong-text);
}

.app-stat-tile__item--danger {
    background: var(--brand-danger-bg);
    color: var(--brand-danger-text);
}

/* D-0210 (Brian, 2026-09-01): the unavailable-state treatment on a failed CustomerCreditPosition read — all
   five bucket tiles drop to neutral grey (AgeingSuccessTileClass/AgeingWarningTileClass/AgeingDangerTileClass,
   CustomerProfile.razor), Carrie's never-colour-unknown-data ruling. Total Outstanding, its former only
   normal-state consumer, is removed; this class stays for the unavailable state alone. */
.app-stat-tile__item--neutral {
    background: var(--brand-neutral-bg);
    color: var(--brand-neutral-text);
}

/* ── Neutral chip (.app-chip) — mockup-spec-vendor-team-management.md §2.7: "Neutral chip — --brand-neutral-bg
   / --brand-neutral-text, --brand-radius-pill" — a plain label (a role name, a permission name), never a
   lifecycle status. Distinct from .badge-status--*, which is reserved for a fixed, named lifecycle state
   (§4.3a) — a role like "Admin" is a category, not a state a record moves through. */
.app-chip {
    display: inline-block;
    padding: 0 var(--brand-space-2);
    background: var(--brand-neutral-bg);
    color: var(--brand-neutral-text);
    border-radius: var(--brand-radius-pill);
    font-size: var(--brand-font-size-sm);
}

/* ── Progress bar (.app-progress / .app-progress__label / .app-progress__track / .app-progress__fill /
   .app-progress__fill--complete / .app-progress__value) ──────────────────────────────────────────────────
   DESIGN-SYSTEM.md §4.13 (04-vendor-dashboard.mockup, "Active Jobs in Production" rows carry a production
   progress bar with a trailing percentage label). Painted here, consumed by
   CCP.UI.Components/ProgressBar.razor — same host-paints-it split as .app-tabstrip/.app-tab
   (MOCKUP-SPEC-TABSTRIP-COMPONENT.md §2): the component ships no CSS of its own. */
.app-progress {
    display: flex;
    align-items: center;
    gap: var(--brand-space-2);
}

.app-progress__label {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
}

.app-progress__track {
    flex: 1 1 auto;
    height: 8px;
    background: var(--brand-neutral-bg);
    border-radius: var(--brand-radius-pill);
    overflow: hidden;
}

.app-progress__fill {
    height: 100%;
    background: var(--brand-primary);
    border-radius: var(--brand-radius-pill);
}

/* §4.13: "100% (consider fill --brand-success)". */
.app-progress__fill--complete {
    background: var(--brand-success);
}

.app-progress__value {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
}

/* ── Activity list / row (.app-activity-list / .app-activity-item / __main / __identifier / __summary /
   __meta / __amount / __aside) ────────────────────────────────────────────────────────────────────────
   04-vendor-dashboard.mockup §3.4 (DESIGN-SYSTEM.md §4.25) — the shared row shape for the three vendor-dashboard
   activity panels. Painted here, consumed by CCP.UI.Components/ActivityList.razor + ActivityItem.razor — same
   host-paints-it split as .app-tabstrip/.app-tab and .app-progress above: the components ship no CSS of their
   own. §2.7 of that spec: a row earns NO border/fill/radius at rest — only a hairline divider between siblings
   and a neutral hover fill — so three rows never read as three cards nested inside the .app-card panel. */
.app-activity-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.app-activity-item {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--brand-space-3);
    padding: var(--brand-space-3) 0;
    border-bottom: 1px solid var(--brand-border);
}

.app-activity-item:last-child {
    border-bottom: none;
}

.app-activity-item:hover {
    background: var(--brand-neutral-bg);
    transition: background var(--brand-transition-fast);
}

.app-activity-item__main {
    display: flex;
    flex-direction: column;
    gap: var(--brand-space-1);
    min-width: 0;
}

.app-activity-item__identifier {
    margin: 0;
    font-size: var(--brand-font-size-lg);
    font-weight: var(--brand-font-weight-semibold);
}

.app-activity-item__identifier a {
    color: var(--brand-primary);
}

.app-activity-item__summary {
    margin: 0;
    font-size: var(--brand-font-size-base);
    color: var(--brand-text);
}

.app-activity-item__meta {
    margin: 0;
    font-size: var(--brand-font-size-sm);
    color: var(--brand-text-muted);
}

/* §3.5.1 — deadline urgency (Panels A/B). The warning colour is one of the meta line's THREE signals, never
   the sole carrier — the words ("· N days left") and the warning glyph (aria-hidden) are the other two. */
.app-activity-item__meta--urgent {
    color: var(--brand-warning-text);
}

/* Panel C only (§3.5 C3) — the invoice amount leads its row, drawn deliberately. */
.app-activity-item__amount {
    font-size: var(--brand-font-size-xl);
    font-weight: var(--brand-font-weight-bold);
    color: var(--brand-text);
    font-variant-numeric: tabular-nums;
}

.app-activity-item__aside {
    display: flex;
    align-items: center;
    gap: var(--brand-space-3);
    flex-shrink: 0;
}

/* §3.4: "below the md breakpoint __aside wraps under __main and left-aligns" (G13) — 767.98px is this
   codebase's standard below-md threshold (DESIGN-SYSTEM-GRIDS-AND-DIALOGS.md §4f.2; the retired 641px is
   never reintroduced). flex-wrap on .app-activity-item above does the wrap; this rule only re-aligns __aside
   once it has dropped to its own line. */
@media (max-width: 767.98px) {
    .app-activity-item__aside {
        justify-content: flex-start;
        width: 100%;
    }
}

/* ── Avatar (.app-avatar) — DESIGN-SYSTEM.md §4.3's avatar variant ─────────────────────────────────────────
   CCP.UI.Components/Avatar.razor (wave 2, F3): a circular avatar image, or initials on --brand-neutral-bg
   with --brand-neutral-text when there is no image, leading the badge/row label (Badges.png). Both shapes are
   the same size/radius so they interchange without reflowing whatever row/menu they sit in. */
.app-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    flex-shrink: 0;
}

.app-avatar__image {
    object-fit: cover;
}

/* ── Status history timeline (.app-timeline / __entry / __glyph / __content / __label / __note / __date) ──
   mockup-spec-vendor-job-management.md §3.4/§2.7 (Story 5): a real <ol> of dated facts, in chronological
   order — "they are a list of facts, not four cards stacked", so each entry earns a hairline border and no
   fill or shadow. The glyph is --brand-primary (a completed STEP), never --brand-success, which is reserved
   for the job's own terminal Completed outcome (§3.4's own reasoning — semantic green on every step would
   spend the one colour that should mean "this job is done"). Library-owned (L-154 wording fix, 2026-09-16 --
   stale since this file itself moved from Shell-owned to the shared CCP.Brand library on 2026-09-10) so a
   later screen with its own status history reuses it rather than forking a second timeline. The right FILE
   per SHARED-CSS-LAYER-SPLIT.md's boundary rule; the matching DESIGN-SYSTEM.md entry is §4.26 (confirmed by
   Duane, 2026-09-16). */
.app-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--brand-space-2);
}

.app-timeline__entry {
    display: flex;
    align-items: baseline;
    gap: var(--brand-space-2);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius-md);
    padding: var(--brand-space-2) var(--brand-space-3);
}

.app-timeline__glyph {
    color: var(--brand-primary);
    flex: 0 0 auto;
}

.app-timeline__content {
    flex: 1 1 auto;
    min-width: 0;
}

.app-timeline__label {
    font-weight: var(--brand-font-weight-semibold);
    color: var(--brand-text);
    font-size: var(--brand-font-size-base);
}

.app-timeline__note {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
    margin: 0;
}

.app-timeline__attachment {
    margin-top: var(--brand-space-1);
}

/* L-169 (Will, 2026-09-16): detail.png and §3.4 put the date at the right edge, level with the label -- it
   must be a sibling flex child of .app-timeline__entry (never nested inside .app-timeline__content, which
   stacks it under the note on the left instead). margin-left: auto pushes it to the far edge of the
   entry's own flex row; the entry's align-items: baseline still lines it up with the label's text. */
.app-timeline__date {
    color: var(--brand-text-muted);
    font-size: var(--brand-font-size-sm);
    white-space: nowrap;
    margin-left: auto;
    flex: 0 0 auto;
}

.app-avatar__initials {
    background: var(--brand-neutral-bg);
    color: var(--brand-neutral-text);
    font-size: var(--brand-font-size-sm);
    font-weight: var(--brand-font-weight-semibold);
    line-height: 1;
}

/* CCP.UI.Components/VersionFooter.razor (Q-A6, Brian 2026-09-17) -- host-required because that project ships
   no CSS of its own. Two grounds: a dark sidebar rail (staff Shell, vendor portal) and a light footer strip
   (customer portal, inline in its legal line). WI-4 (Will, 2026-09-17): side padding matches the staff Shell's
   menu rows' own Bootstrap px-3 (16px) -- --brand-space-4, not --brand-space-3 (12px). */
.version-footer--dark {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--brand-space-1);
    padding: var(--brand-space-3) var(--brand-space-4) var(--brand-space-4);
    border-top: 1px solid var(--brand-surface-sidebar-divider);
}

.version-footer__version {
    color: var(--brand-text-subtle);
    font-size: var(--brand-font-size-xs);
}

/* DESIGN-SYSTEM.md §4.38 / WCAG 2.1 AA (Francie, 2026-09-18): --brand-text-muted measures 4.29:1 against the customer
   portal's --brand-primary-lighter footer tint (axe color-contrast, serious) -- below the 4.5:1 floor. Same
   fix CCP.CustomerPortal.Shell/wwwroot/css/app.css's .portal-footer-legal made for the same background. */
.version-footer--light .version-footer__version {
    color: var(--brand-text);
}

/* Reviewer fix (round 1, Will/Carrie/Arthur): "© 2026 Corporate Communications Center Ver: 1.0.0" read as one
   run-on line -- the light-strip ground has no border-top/padding of its own (unlike .version-footer--dark
   above) to separate it from the © text it sits beside in PortalFooter.razor's markup. */
.version-footer--light {
    margin-left: var(--brand-space-3);
}

.version-footer__link {
    display: inline-flex;
    line-height: 0;
}

/* Reviewer fix (round 1): the project's own link focus-visible ring (.app-breadcrumb a:focus-visible,
   shared-page.css) -- copied rather than the color/underline half of that same rule, since .version-footer__link
   wraps an IMAGE with no text colour to change, so a colour-only indicator would be invisible on it. Applied to
   both grounds' links for one consistent focus treatment. */
.version-footer__link:focus-visible,
.version-footer__text-link:focus-visible {
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--brand-primary) 25%, transparent);
    border-radius: var(--brand-radius-sm);
}

.version-footer__logo {
    height: 32px;
    width: auto;
}

/* DESIGN-SYSTEM.md §4.38 / WCAG 2.1 AA (Francie, 2026-09-18): same --brand-text-muted-on-tint failure as
   .version-footer--light .version-footer__version above -- this text link only ever renders on the same
   light-strip ground (ShowPoweredByB3 is currently off for the customer portal, but this must not regress the
   moment it is turned on). */
.version-footer__text-link {
    margin-left: var(--brand-space-1);
    color: var(--brand-text);
    font-size: var(--brand-font-size-xs);
}
