/* === De-bootstrapped compatibility utilities (#466) ===
   bootstrap.min.css was retired in the MudBlazor migration. These are the handful of generic
   Bootstrap utility classes still referenced on plain HTML elements (validation text, table
   cells, tag badges, the Login remember-me checkbox), reimplemented against the MudBlazor
   palette so they survive without the Bootstrap dependency. MudBlazor (pinned at 9.5.0 in
   Directory.Packages.props) already ships d-flex / gap-* / m{t,b,e,s,x,y}-* / px-* /
   flex-column / flex-wrap / align-center / justify-space-between / rounded / rounded-pill /
   border / d-inline-block / mud-text-secondary, so those are NOT redefined here. A MudBlazor
   major upgrade should re-confirm that set still ships (the .mw-kv key-value grid lower in this
   file is the other layout dependency these pages rely on). */

a {
    color: var(--mw-accent);
}

/* Text colour helpers, mapped to the Mud theme palette. */
.text-danger { color: var(--mud-palette-error); }
.text-warning { color: var(--mud-palette-warning); }

/* Typography + alignment helpers. */
.text-end { text-align: end; }
.text-center { text-align: center; }
.text-nowrap { white-space: nowrap; }
.small { font-size: 0.875em; }
.fw-semibold { font-weight: 600; }
.fs-1 { font-size: 2.5rem; }

/* Opacity + border helpers (placement tag chips). */
.opacity-50 { opacity: 0.5; }
.opacity-75 { opacity: 0.75; }
.border-0 { border: 0 !important; }

/* Literal white background — the enrollment QR needs a fixed white field for scannability,
   independent of the theme background. */
/* stylelint-disable-next-line declaration-property-value-disallowed-list -- QR code needs a literal, theme-independent white field */
.bg-white { background-color: #fff; }

/* Pill/category badge base; per-category colours live in the .tag-* rules below. */
.badge {
    display: inline-block;
    padding: 0.35em 0.65em;
    font-size: 0.75em;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    text-align: center;
    vertical-align: baseline;
    border-radius: 0.375rem;
}

/* Remember-me checkbox: Login keeps a raw <InputCheckbox> for its POST semantics, so style the
   native control to the brand accent with a brand focus ring now that Bootstrap's
   .form-check-input rules are gone. */
.form-check-input {
    accent-color: var(--mw-forest);
}
.form-check-input:focus {
    box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--mw-accent);
}


.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

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

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

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

.blazor-error-boundary {
    /* stylelint-disable-next-line declaration-property-value-disallowed-list -- inline base64 SVG icon + fixed error-red fallback for the framework 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."
    }

/* Monospace utility for IDs, dates, and codes */
td.font-mono,
td.font-mono a {
    font-family: var(--mw-font-mono);
    font-size: 1em;
    letter-spacing: 0.04em;
}

/* === Bootstrap Icons (inline SVG data URIs) === */

.bi {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    vertical-align: middle;
    background-size: cover;
}

.bi-x-lg {
    background-image: url("icons/x-lg.svg");
}

.bi-play-fill {
    background-image: url("icons/play-fill.svg");
}

.bi-three-dots-vertical {
    background-image: url("icons/three-dots-vertical.svg");
}

.bi-three-dots {
    background-image: url("icons/three-dots.svg");
}


/* Vertically center cells in a MudSimpleTable (replaces Bootstrap's .align-middle, which
   MudSimpleTable has no parameter for) — used where a row mixes short labels with taller
   controls like a MudTextField. */
.mw-valign-middle td {
    vertical-align: middle;
}

.table-row-spaced td {
    padding-top: 2.5rem;
    padding-bottom: 2.5rem;
}

.table-row-spaced tbody tr:not(:has(td:not(:empty))) {
    display: none;
}

.table-row-spaced th {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
}

.paginator-container {
    padding-top: 0.5rem;
    padding-left: 1rem;
}

/* ?? Tag category badges ??????????????????????????????????? */

/* Location & Geography — purple */
.tag-region,
.tag-timezone,
.tag-market,
.tag-state             { background-color: var(--mw-tag-geography); color: var(--mw-white); }

/* Business & Client — blue */
.tag-retailer,
.tag-contract-type,
.tag-customer-segment  { background-color: var(--mw-tag-business); color: var(--mw-white); }

/* Operational Status — red */
.tag-priority          { background-color: var(--mw-tag-priority); color: var(--mw-white); }

/* Service & Maintenance — cyan (dark ink for contrast) */
.tag-service-route,
.tag-service-frequency { background-color: var(--mw-tag-service); color: var(--mw-charcoal); }

/* Location Characteristics — green */
.tag-location-type,
.tag-access-type       { background-color: var(--mw-tag-facility); color: var(--mw-white); }

/* Analytics & Reporting — indigo */
.tag-usage-pattern,
.tag-reporting-group   { background-color: var(--mw-tag-analytics); color: var(--mw-white); }

/* Fallback for custom / unknown categories */
.tag-default           { background-color: var(--mw-tag-default); color: var(--mw-white); }

/* Key-value display lists (semantic <dl>, de-Bootstrapped from dl.row/col-*) used across the migrated
   detail/settings pages. Centralized here (one rule) rather than duplicated per-page via CSS isolation. */
.mw-kv {
    display: grid;
    /* Label column sizes to its longest label (min 6rem), value takes the rest. Content-sized rather
       than a fixed % so the single centralized rule fits every page's labels without per-page tuning. */
    grid-template-columns: minmax(6rem, max-content) 1fr;
    column-gap: 12px;
    row-gap: 4px;
    margin: 0;
}
.mw-kv dt {
    color: var(--mud-palette-text-secondary);
    font-weight: 400;
    white-space: nowrap;
}
.mw-kv dd {
    margin: 0;
}

/* Detail-page tab strip (Kiosk / Station Details / Signage sub-nav). Sets the tab row apart from the
   cards below with a "shelf" bottom border + a gap, so the tabs read as a control bar above the content
   rather than another flat sibling. Applied via Class="mw-detail-tabs" on the shared <MudTabs>.
   The rendered tab-bar element is `.mud-tabs-tabbar` (MudBlazor 9.5.0) — NOT `.mud-tabs-toolbar`, which
   matches nothing and silently no-ops. Like the file's other rules it rides the top-of-file "a MudBlazor
   major upgrade should re-confirm the selectors/tokens" contract. */
.mw-detail-tabs .mud-tabs-tabbar {
    border-bottom: 1px solid var(--mud-palette-lines-default);
    margin-bottom: 1.25rem;
}

/* Fleet page two-column layout (rail + detail). The rail is a fixed 240px column on a wide viewport; below
   768px that leaves the detail pane too narrow to use (meshware#1646), so it stacks full-width above the
   detail pane instead. Plain CSS classes rather than inline styles so the media query can override them. */
.mw-fleet-layout {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
}

.mw-fleet-rail-col {
    flex: 0 0 240px;
    min-width: 0;
}

.mw-fleet-detail-col {
    flex: 1 1 auto;
    min-width: 0;
}

@media (max-width: 768px) {
    .mw-fleet-layout {
        flex-direction: column;
    }

    /* align-items: flex-start (the row layout's cross-axis alignment) still applies once flex-direction flips
       to column, so both columns need an explicit width — otherwise they size to their intrinsic content width
       instead of stretching across the stacked container. */
    .mw-fleet-rail-col,
    .mw-fleet-detail-col {
        flex: 1 1 auto;
        width: 100%;
    }
}

/* Fleet page scope rail (tenant default ▸ groups ▸ stations). A quiet master-detail list: selectable rows,
   a low-emphasis section header, and a group-member highlight tint. Colors ride MudBlazor palette tokens so
   the rail tracks light/dark like the rest of Admin. */
.mw-fleet-rail {
    display: flex;
    flex-direction: column;
}

.mw-fleet-section {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mud-palette-text-secondary);
    margin: 0.9rem 0.25rem 0.4rem;
}

.mw-fleet-row {
    /* Rendered as a <button> for real click/keyboard/focus semantics — reset the native chrome, then style. */
    appearance: none;
    -webkit-appearance: none;
    font: inherit;
    color: inherit;
    text-align: left;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.55rem;
    border-radius: var(--mud-default-borderradius);
    cursor: pointer;
    margin-bottom: 4px;
    /* A resting surface + border so the row reads as a distinct, pressable control rather than plain text. */
    background: var(--mud-palette-background-grey);
    border: 1px solid var(--mud-palette-lines-default);
    border-left: 3px solid transparent;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
    transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}

/* Depth accent: a left-border + icon tint per rail level (tenant ▸ group ▸ station), independent of .mw-sel
   below — a selected row keeps its own level color on the left edge while primary takes the resting
   border/background. Rides the brand's ring colors (MeshwareTheme.cs) rather than inventing new hues: group is
   Secondary (olive), station is Tertiary (fern). This is a depth cue, not a real expand/collapse tree — the rail
   selects siblings, not containment (see the comment above the rail markup); rows deliberately don't indent, so
   this stays a color cue rather than implying containment. */
.mw-fleet-row.mw-lvl-tenant {
    border-left-color: var(--mud-palette-lines-default);
}

.mw-fleet-row.mw-lvl-group {
    border-left-color: var(--mud-palette-secondary);
}

.mw-fleet-row.mw-lvl-station {
    border-left-color: var(--mud-palette-tertiary);
}

.mw-fleet-row.mw-lvl-group .mw-fleet-ico {
    color: var(--mud-palette-secondary);
}

.mw-fleet-row.mw-lvl-station .mw-fleet-ico {
    color: var(--mud-palette-tertiary);
}

/* A trailing chevron on every row — the resting affordance that says "this navigates". Faint at rest, brighter
   on hover/focus/selection. */
.mw-fleet-row::after {
    content: "›";
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 1.05rem;
    line-height: 1;
    color: var(--mud-palette-text-secondary);
    opacity: 0.28;
    transition: opacity 0.12s ease, transform 0.12s ease;
}

/* border-color is a shorthand for all four sides, so it would clobber the level accent set on border-left-color
   above — set the other three sides explicitly instead so the depth cue survives hover/selection/match. */
.mw-fleet-row:hover {
    background: var(--mud-palette-action-default-hover);
    border-top-color: var(--mud-palette-primary);
    border-right-color: var(--mud-palette-primary);
    border-bottom-color: var(--mud-palette-primary);
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.10);
}

.mw-fleet-row:hover::after {
    opacity: 0.75;
    transform: translateX(2px);
}

.mw-fleet-row:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 1px;
}

.mw-fleet-row.mw-sel {
    background: var(--mud-palette-primary-hover);
    border-top-color: var(--mud-palette-primary);
    border-right-color: var(--mud-palette-primary);
    border-bottom-color: var(--mud-palette-primary);
}

.mw-fleet-row.mw-sel::after {
    opacity: 0.9;
    color: var(--mud-palette-primary);
}

.mw-fleet-row.mw-match {
    border-top-color: var(--mud-palette-success);
    border-right-color: var(--mud-palette-success);
    border-bottom-color: var(--mud-palette-success);
}

/* A stale in-flight LoadMembersAsync response can race a subsequent station selection and leave a row both
   matched and selected (meshware#1648 tracks the underlying race) — selected must win, since it's the more
   important state to communicate. Three classes outrank .mw-match/.mw-sel's two, so this applies regardless
   of the rules' source order. */
.mw-fleet-row.mw-match.mw-sel {
    border-top-color: var(--mud-palette-primary);
    border-right-color: var(--mud-palette-primary);
    border-bottom-color: var(--mud-palette-primary);
}

.mw-fleet-ico {
    color: var(--mud-palette-text-secondary);
    flex: 0 0 auto;
}

.mw-fleet-label {
    font-size: 0.86rem;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mw-fleet-sub {
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
}

.mw-fleet-filter {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.75rem;
    color: var(--mud-palette-success);
    margin: 0 0.25rem 0.4rem;
}

.mw-fleet-clear {
    cursor: pointer;
    text-decoration: underline;
    color: var(--mud-palette-text-secondary);
}

/* Detail-pane breadcrumb (master-detail linkage for the fleet rail): repeats the rail selection as its full
   ancestry, colored/iconed to the selected level, so the pane still says what it belongs to after a tab switch
   or scroll — the rail's .mw-sel tint alone doesn't survive that. Sits directly above <DetailTabs>. */
.mw-detail-crumb {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 0.5rem 0.7rem;
    margin-bottom: 1rem;
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-background-grey);
    border: 1px solid var(--mud-palette-lines-default);
    border-top: 3px solid var(--mud-palette-lines-default);
}

.mw-detail-crumb.mw-lvl-group {
    border-top-color: var(--mud-palette-secondary);
}

.mw-detail-crumb.mw-lvl-station {
    border-top-color: var(--mud-palette-tertiary);
}

.mw-detail-crumb-ico {
    flex: 0 0 auto;
    color: var(--mud-palette-text-secondary);
}

.mw-detail-crumb.mw-lvl-group .mw-detail-crumb-ico {
    color: var(--mud-palette-secondary);
}

.mw-detail-crumb.mw-lvl-station .mw-detail-crumb-ico {
    color: var(--mud-palette-tertiary);
}

/* The path itself is a <nav aria-label="Breadcrumb"><ol> — real breadcrumb semantics, not a text run, so a
   screen reader announces it as a landmark + an ordered ancestry rather than unstructured spans. */
.mw-detail-crumb-nav {
    min-width: 0;
}

.mw-detail-crumb-path {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 1.05rem;
    color: var(--mud-palette-text-secondary);
}

.mw-detail-crumb-path li {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 280px;
}

/* A generated separator, not a list item — a screen reader shouldn't announce "chevron" as an ancestry step. */
.mw-detail-crumb-path li:not(:last-child)::after {
    content: "›";
    opacity: 0.5;
    margin: 0 0.35em;
}

.mw-detail-crumb-current {
    color: var(--mud-palette-text-primary);
    font-weight: 600;
}

.mw-detail-crumb-pill {
    flex: 0 0 auto;
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 99px;
    color: var(--mud-palette-text-secondary);
    background: var(--mud-palette-surface);
}

.mw-detail-crumb.mw-lvl-group .mw-detail-crumb-pill {
    color: var(--mud-palette-secondary);
}

.mw-detail-crumb.mw-lvl-station .mw-detail-crumb-pill {
    color: var(--mud-palette-tertiary);
}

.mw-detail-crumb-open {
    margin-left: auto;
}

/* Audit-trail list (de-Bootstrapped from list-unstyled). */
.mw-audit {
    list-style: none;
    padding: 0;
    margin: 0;
}

/* Narrow single-column form body for the Identity/Account pages (replaces Bootstrap row/col-md-4). */
.mw-form-narrow {
    max-width: 24rem;
}

/* Brand-primary action button for the PasskeySubmit custom element. PasskeySubmit must render a
   real sibling <button> for its JS, so it can't be a MudButton; this skins that raw button to read
   as a MudBlazor filled-primary button using the Mud palette vars (no bootstrap .btn dependency). */
.mw-passkey-button {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.46rem 1rem;
    border: none;
    border-radius: var(--mud-default-borderradius, 4px);
    background-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.75;
    cursor: pointer;
    transition: background-color 0.2s ease;
}
.mw-passkey-button:hover {
    background-color: var(--mud-palette-primary-darken);
}

/* Responsive-density ADR (S4): in Compact density an index grid collapses to a single stacked column, so its
   header row is vestigial — hide it. Sort moves to the shared IndexToolbar "Sort by…" control. MudDataGrid
   renders a <thead>; this is global (not scoped) because the grid's DOM belongs to the MudBlazor library, not a
   scoped component. */
.mw-grid-compact thead {
    /* !important to beat MudBlazor's own thead display rule (higher base specificity). */
    display: none !important;
}

/* Responsive-density ADR, Decision 5: reserve the docked operator-assistant pane's width so the fixed pane sits
   BESIDE the content, not over it. Driven purely by the pane's presence in the DOM (`.mw-assistant-pane` exists
   only while the pane is open) — a cross-component `:has()`, so it's global (scoped CSS can't reach across
   components) and, crucially, it needs no JS-set attribute: it survives Blazor navigation automatically because
   the pane element persists with the circuit (an attribute toggled by JS gets wiped by the nav re-render). 380px
   matches AssistantPaneHost's pane width + DensityResolver.AssistantPaneWidth. */
.page:has(.mw-assistant-pane) main {
    margin-right: 380px;
}

/* ── Kiosk-index attention (#1803, #1839) ───────────────────────────────────────────────────────────────
   The tint on a row whose kiosk wants an operator, and on the expansion that row opens onto. (The banner
   these rules used to serve is gone: the rows carry the signal and now hold the incidents themselves.)
   Global rather than scoped for the same reason .mw-grid-compact is: MudDataGrid renders the <tr> these
   classes land on (via RowClassFunc), so the DOM belongs to the MudBlazor library and a scoped component's
   attribute never reaches it. Colors come from the brand tokens — raw hex is banned here by stylelint's
   declaration-property-value-disallowed-list and, in markup, by StyleTokenConventionTests. */

/* Row tints. The wash alone carries it. There WAS a left accent as well — but the tint lands on every <td>,
   which is the only hook MudDataGrid gives a row, so a single "row edge" accent was in fact a coloured bar
   drawn down the left of every cell: four or five stripes marching across each troubled row. Deliberately
   pale — a tinted row must still read as a table row, and the Health chip carries the actual severity. */
.mw-attention-row-critical td {
    background-color: var(--mw-error-wash);
}

.mw-attention-row-warning td {
    background-color: var(--mw-warning-wash);
}

/* Every open incident on this kiosk is acknowledged: someone has picked it up. It stays in the set (acked is
   not fixed) but stops shouting — a neutral wash rather than a severity one, so the row is still findable
   without claiming to be on fire. This used to be the accent's one solo job; with the accent gone it needs a
   wash of its own, or a quiet kiosk would be indistinguishable from an untroubled one. */
.mw-attention-row-acked td {
    background-color: var(--mw-mist);
}

/* The expanded row's incident list (#1839). The grid renders it as its own <tr>, which RowClassFunc never
   touches, so the tint is repeated here on the content itself — an expansion in a different colour from the
   row it belongs to reads as a floating panel rather than as that row opening up. Same washes as the row
   tints above, deliberately: the pair is one block. */
.mw-attention-expansion {
    background-color: var(--mw-mist);
}

.mw-attention-expansion-critical {
    background-color: var(--mw-error-wash);
}

.mw-attention-expansion-warning {
    background-color: var(--mw-warning-wash);
}

/* The muted cause line under a row's identity cell. */
.mw-attention-cause {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 2px;
    font-size: 0.8em;
    color: var(--mw-muted);
}

/* Tag filter chips on the kiosk index. Tag values are slugified but NOT length-capped (Tag.Normalize), and a
   chip's content does not wrap — so one long "category:value" could push the shared controls strip wider than a
   narrow viewport and shove the search field out of reach. The cap plus an ellipsis keeps the strip inside the
   viewport; the full value stays in each chip's title, which is where it already was.

   Global rather than scoped for the same reason the rest of this block is: the module renders these through
   MudChip, so the element carrying the class is MudBlazor's, and .mud-chip-content — the inner element that
   actually overflows — is only reachable from here. */
/* Compound `.mud-chip.mw-tag-chip`, not `.mw-tag-chip` alone: MudBlazor's own .mud-chip sets max-width:100%,
   which is the same specificity and wins on source order — the single-class version computed to 100% and did
   nothing, which is invisible until a tag is long enough to prove it. */
.mud-chip.mw-tag-chip {
    max-width: 14rem;
}

.mw-tag-chip .mud-chip-content {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The cause line as the row's second expand control. It is a real <button> so it is focusable and works from
   the keyboard; these rules strip the browser's button chrome so it still reads as the caption it was, and
   keep the focus ring, which is the whole point of making it a button. */
.mw-attention-cause-button {
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    text-align: start;
    cursor: pointer;

    /* Undo the browser's centering of button content. The element is a flex container (.mw-attention-cause),
       and a <button>'s UA styling centres its flex line — so with width:100% the caption sat centred in the
       cell, and every row started at a different x depending on how long its cause text was. text-align
       alone does NOT fix this: it governs the text inside a line box, not where the flex line begins. */
    justify-content: flex-start;
}

.mw-attention-ico-critical {
    color: var(--mw-error);
}

.mw-attention-ico-warning {
    color: var(--mw-warning);
}

/* ── Nav row badge (#1805) ──────────────────────────────────────────────────────────────────────────────
   A small count pill at a nav row's trailing edge. Global because the badge component is rendered by a
   module through DynamicComponent, so a scoped rule in either NavMenu or the module would not reach both
   ends of that seam. `auto` left margin pushes it to the row's far edge without the row needing a
   flex-specific layout of its own. */

.mw-nav-badge {
    margin-left: auto;
    min-width: 20px;
    padding: 0 6px;
    border-radius: 10px;
    font-size: 0.75rem;
    line-height: 1.25rem;
    text-align: center;
    color: var(--mw-white);
}

.mw-nav-badge-critical {
    background-color: var(--mw-error);
}

.mw-nav-badge-warning {
    background-color: var(--mw-warning);
}

/* "We could not read the incidents." Muted and borderless, unlike the tinted attention banner above it: this
   reports a gap in our own knowledge rather than a fault on a kiosk, so it must not wear alert chrome — but it
   must exist, because rendering nothing would be indistinguishable from a clear fleet. Global for the same
   reason the rest of the attention CSS is: the module renders it through shared card slots. */
.mw-attention-unavailable {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
    font-size: 0.85em;
    color: var(--mw-muted);
}

/* Badge for "the count is unknown", not zero — a failed read on the fleet's only always-visible alert
   affordance. Neutral grey on purpose: it is not an alarm, and colouring it error/warning would imply a
   severity nobody has established. */
.mw-nav-badge-unknown {
    background-color: var(--mw-muted);
}
