/* ── Phase 71 — Design System & Staff Shell ───────────────────────
   Rail, page frame, toolbar, filter strip, chip, list container/group/row,
   dots, empty state, error banner, palette, tooltip.
   Written against the token variables from app.css; !important is used only
   where a MudBlazor runtime style would otherwise win (CLAUDE.md rule). */

/* ── R-1: page content frame ──────────────────────────────────────
   MudMainContent no longer supplies page padding (rail replaces the app
   bar). Unconverted pages get their padding from .staff-page; pages that
   adopt the new toolbar/strip grammar wrap in .page-frame and render flush
   and sticky instead. */
.staff-page {
    padding: 24px 32px 32px;
}

.staff-page:has(.page-frame) {
    padding: 0;
}

/* ── Focus ring (one rule, CLAUDE.md + UI-SPEC Keyboard Contract) ── */
.staff-page :focus-visible,
.mud-drawer :focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

nav[aria-label="Main"] a:focus-visible,
nav[aria-label="Main"] button:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

[role="option"]:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 0;
}

/* ── StatusDot / PriorityDot ───────────────────────────────────── */
.dot-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    line-height: 1.4;
}

.dot-label-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: 0 0 8px;
}

/* ── EmptyState ────────────────────────────────────────────────── */
.empty-state-shell {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--text-secondary);
}

.empty-state-inline {
    min-height: 120px;
    padding: 16px;
    gap: 4px;
}

.empty-state-inline .empty-state-icon {
    margin-bottom: 8px;
    color: var(--text-tertiary);
    font-size: 24px;
}

.empty-state-inline .empty-state-title {
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    margin: 0;
}

.empty-state-inline .empty-state-body {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    max-width: 320px;
    margin: 0;
}

.empty-state-inline .empty-state-action {
    margin-top: 16px;
    height: 32px;
    padding: 0 12px;
    border-radius: 8px;
    border: 1px solid var(--border-light);
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
}

.empty-state-panel {
    min-height: 320px;
    padding: 32px 16px;
    gap: 4px;
}

.empty-state-panel .empty-state-icon {
    margin-bottom: 12px;
    color: var(--text-tertiary);
    font-size: 32px;
}

.empty-state-panel .empty-state-title {
    font-family: 'Outfit', sans-serif;
    font-size: 15px;
    font-weight: 500;
    color: var(--text-primary);
    margin: 0;
}

.empty-state-panel .empty-state-body {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    max-width: 420px;
    margin: 0;
}

/* Heal (QX-5 finalize a11y scan, dark theme, additional finding beyond the named one):
   same UAT-03 dead-selector class as .error-banner-retry above, surfaced on this task's own
   NotFound/zero-column EmptyState "Back to project" / "Switch to board view" actions. The
   `.mud-theme-dark` override below never applies, so an UNBRANDED tenant in dark mode kept
   the base rule's hardcoded `#FFFFFF` ink on a background that -- unlike the ErrorBanner
   case -- is NOT itself hardcoded: --accent-primary is already live-remapped through
   .mud-layout (PAL-UAT-002 above) to --mud-palette-primary, #236FA8 light / #5BB8E8 dark.
   White-on-#5BB8E8 measures 2.218:1 (axe: serious) -- the identical PAL-UAT-001 defect
   already fixed the same way on .usage-upgrade-cta (app.css) and .brand-tertiary-action:
   `var(--brand-on-surface-text, var(--mud-palette-background))`, MudBlazor's own live
   background token (#FFFFFF light / #0F1522 dark), never a `.mud-theme-dark` twin -- that
   mechanism is confirmed absent from the DOM after a same-page toggle (same UAT-03 finding).
   #0F1522 on #5BB8E8 measures 8.23:1 (script-verified); light mode's #FFFFFF fallback is
   unchanged (white already resolves to #FFFFFF via --mud-palette-background in light theme,
   byte-identical to the old literal). A branded tenant's own --brand-on-surface-text still
   wins first, unaffected either way. */
.empty-state-panel .empty-state-action {
    margin-top: 16px;
    height: 32px;
    padding: 0 16px;
    border-radius: 8px;
    border: none;
    background: var(--brand-on-surface, var(--accent-primary));
    color: var(--brand-on-surface-text, var(--mud-palette-background));
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
}

.empty-state-inline .empty-state-action:focus-visible,
.empty-state-panel .empty-state-action:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ── ErrorBanner ───────────────────────────────────────────────── */
.error-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 16px 24px 0;
    padding: 12px 16px;
    border: 1px solid #C4443C;
    border-radius: 8px;
    background: rgba(196, 68, 60, 0.08);
}

.mud-theme-dark .error-banner {
    border-color: #E0605A !important;
    background: rgba(224, 96, 90, 0.14) !important;
}

.error-banner-message {
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    color: var(--text-primary);
}

/* Heal (QX-5 finalize a11y scan, dark theme): matches the UAT-03/PAL-UAT-003 mechanism
   documented above `.meta-grid-value-destructive` -- `.mud-theme-dark` is never applied by
   MudThemeProvider's dark-mode toggle in this MudBlazor version, so the
   `.mud-theme-dark .error-banner-retry` override below was dead code and this button
   rendered the light hex (#BF423A, 3.33:1 on #1D1924 -- axe: serious color-contrast) in dark
   mode regardless of theme. `var(--mud-palette-error, #BF423A)` tracks the live theme
   (#BF423A light / #E0605A dark, DevFlowTheme.cs), so the fallback is byte-identical to the
   old light-only literal and dark mode gets the intended pair for free (#E0605A on #1D1924
   measures 4.92:1, script-verified). Light mode unchanged. */
.error-banner-retry {
    flex: 0 0 auto;
    background: none;
    border: none;
    color: var(--mud-palette-error, #BF423A);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    padding: 0;
}

.error-banner-retry:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ── PageToolbar ───────────────────────────────────────────────── */
.page-toolbar {
    display: flex;
    align-items: center;
    height: var(--toolbar-height);
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-light);
    padding: 0 24px;
    gap: 8px;
    position: sticky;
    top: 0;
    z-index: 20;
}

.mud-theme-dark .page-toolbar {
    background: #161E2E !important;
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}

.page-toolbar-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
    white-space: nowrap;
}

.page-toolbar-count {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    margin-left: 8px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

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

.page-toolbar-slot:empty {
    display: none;
}

.page-toolbar-search-trigger {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    min-width: 200px;
    padding: 0 8px;
    border-radius: 8px;
    border: 1px solid var(--border-light);
    background: var(--bg-secondary);
    cursor: pointer;
}

.mud-theme-dark .page-toolbar-search-trigger {
    background: #26304A !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}

.page-toolbar-search-trigger:hover {
    border-color: var(--text-tertiary);
}

.page-toolbar-search-icon {
    color: var(--text-tertiary);
    display: inline-flex;
}

.page-toolbar-search-label {
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    color: var(--text-secondary);
    flex: 1 1 auto;
    text-align: left;
}

.page-toolbar-search-badge {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
    background: var(--bg-tertiary);
    border-radius: 4px;
    padding: 4px 8px;
}

.mud-theme-dark .page-toolbar-search-badge {
    background: #0F1522 !important;
}

.page-toolbar-primary-action button,
.page-toolbar-primary-action .mud-button-root {
    height: 32px !important;
    border-radius: 8px !important;
    font-family: 'Outfit', sans-serif !important;
    font-size: 14px !important;
    font-weight: 500 !important;
    background-color: var(--brand-on-surface, var(--accent-primary)) !important;
    color: var(--brand-on-surface-text, #FFFFFF) !important;
}

.mud-theme-dark .page-toolbar-primary-action button,
.mud-theme-dark .page-toolbar-primary-action .mud-button-root {
    background-color: var(--brand-on-surface, var(--accent-tertiary)) !important;
    color: var(--brand-on-surface-text, #1A1D23) !important;
}

/* ── View toggle (32px segmented control) ─────────────────────── */
.view-toggle {
    display: inline-flex;
    height: 32px;
    border-radius: 8px;
    border: 1px solid var(--border-light);
    overflow: hidden;
}

.view-toggle-segment {
    height: 32px;
    padding: 0 12px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
}

.view-toggle-segment-selected {
    background: var(--brand-row-selected, var(--bg-tertiary));
    color: var(--brand-on-tint, var(--text-primary));
}

.mud-theme-dark .view-toggle-segment-selected {
    background: var(--brand-row-selected, #26304A) !important;
}

/* ── FilterStrip / FilterChip ──────────────────────────────────── */
.filter-strip {
    display: flex;
    align-items: center;
    height: var(--filterstrip-height);
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-light);
    padding: 0 24px;
    position: sticky;
    top: var(--toolbar-height);
    z-index: 19;
}

.mud-theme-dark .filter-strip {
    background: #161E2E !important;
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}

.filter-strip-chips {
    display: flex;
    align-items: center;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
}

.filter-strip-chips::-webkit-scrollbar {
    display: none;
}

.filter-strip-spacer {
    flex: 1 1 auto;
}

.filter-strip-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
}

.filter-strip-dot {
    color: var(--text-secondary);
}

.filter-strip-text-button {
    background: none;
    border: none;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0;
}

.filter-strip-text-button:hover {
    text-decoration: underline;
}

.filter-strip-text-button:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* QUICK-260918 (UX-24, D-11): inert counterpart to .filter-strip-text-button — same
   typography so the five now-text pages render identically to before, minus the false
   affordance (no cursor, no hover underline, no focus ring; it is not a tab stop).
   HEAL (D-11 text metrics): a <button> resets its inherited letter-spacing to "normal"
   (confirmed via getComputedStyle — the button measures "normal", the page's ambient
   letter-spacing is ~0.14px at this font-size); a plain <span> inherits the ambient value
   instead, which shifted per-glyph kerning by a pixel or so across the label and showed up
   as a text-pixel diff in tests/visual/phase-71.spec.ts's approvals baseline. Match the
   button's reset explicitly rather than relying on the (different) inherited default, and
   pin the remaining box properties (border/background/margin/padding) even though they
   already compute to the same value today, so a later ambient-CSS change can't silently
   reintroduce the same drift. */
.filter-strip-text {
    background: transparent;
    border: none;
    margin: 0;
    padding: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    letter-spacing: normal;
    color: var(--text-secondary);
}

/* QUICK-260918-tsl (UX-08): active-filter summary — a sibling of .filter-strip
   (TicketsBoard.razor renders it only when a filter is set, never as a child of
   FilterStrip, so tests/e2e/phase-71/shell-toolbar-filters.spec.ts's 40px .filter-strip
   assertion is unaffected). --bg-secondary/--text-primary/--text-secondary/
   --border-light/--focus-ring are already remapped for dark mode at a broader
   selector (app.css's `.mud-theme-dark` block), so no separate dark-mode rule is
   needed here. flex-wrap keeps the row from introducing horizontal overflow at
   390px — the item list wraps onto a second line rather than widening the page. */
.filter-summary {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    row-gap: 4px;
    column-gap: 6px;
    min-height: 32px;
    padding: 6px 24px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-light);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.filter-summary-lead {
    color: var(--text-secondary);
}

.filter-summary-item {
    color: var(--text-primary);
}

.filter-summary-clear {
    background: none;
    border: none;
    margin-left: 4px;
    padding: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--focus-ring);
    text-decoration: underline;
    cursor: pointer;
}

.filter-summary-clear:hover {
    opacity: 0.8;
}

.filter-summary-clear:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Quick 260918-approvals-decision-surface (UX-02, D-02/D-06): seats the demoted "Log time"
   text action immediately beside/below the Approvals filter strip, without adding an
   overflow slot to the shared PageToolbar and without changing FilterStrip's own 40px
   height or layout. */
.approvals-log-time-row {
    display: flex;
    justify-content: flex-end;
    padding: 8px 24px 0;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    height: var(--chip-height);
    border-radius: 6px;
    gap: 4px;
    flex: 0 0 auto;
}

.filter-chip-trigger {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: var(--chip-height);
    padding: 0 8px;
    border-radius: 6px 0 0 6px;
    background: transparent;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
}

/* UAT-03: .mud-theme-dark is never applied by MudThemeProvider's dark-mode toggle in
   this MudBlazor version (it's a per-component colour-variant class, e.g. Color="Color.
   Dark" — not a page-wide ancestor), so the dark overrides that used to key off it here
   were dead code; .filter-chip-label (a plain span with no color of its own) inherited
   the light-mode hex regardless of theme. --mud-palette-* variables are set globally and
   actually track the live theme, so they fix both the trigger and its child label. */
/* UAT-260825-rmn-3: `var(--mud-palette-lines-default, #C9CDD4)` never fell through to
   the #C9CDD4 fallback — MudBlazor DOES define --mud-palette-lines-default (measured
   live: rgba(0,0,0,0.059), the same near-invisible value used for 1px solid dividers
   elsewhere), so a *dashed* border drawn in it read as no border at all ("ghosted"
   chips). Built from --text-secondary (already the correct live-tracked, per-theme
   colour used below for the label) at reduced alpha instead of the too-faint mud
   variable — visible in both themes without hardcoding a light/dark pair. A subtle
   fill is added per the same finding so the whole chip reads as a control, not a
   bare label. */
.filter-chip-unset .filter-chip-trigger {
    border: 1px dashed color-mix(in srgb, var(--text-secondary) 55%, transparent);
    background: var(--bg-tertiary);
    color: var(--mud-palette-text-secondary, #5E6470);
    border-radius: 6px;
}

.filter-chip-unset .filter-chip-trigger:hover {
    border-color: color-mix(in srgb, var(--text-primary) 65%, transparent);
    color: var(--mud-palette-text-primary, #1A1D23);
}

.filter-chip-set .filter-chip-trigger {
    border: none;
    background: var(--brand-on-surface, #236FA8);
    color: var(--brand-on-surface-text, #FFFFFF);
}

/* PAL-UAT-001: the unbranded dark fallback #FFFFFF-on-#5BB8E8 measured
   2.218:1, well below AA. Matches the established convention already used
   for .empty-state-action/.page-toolbar-primary-action's own dark
   overrides just above: an --accent-tertiary/--brand-on-surface fill in
   dark theme pairs with the dark ink #1A1D23, never white. */
.mud-theme-dark .filter-chip-set .filter-chip-trigger {
    background: var(--brand-on-surface, #5BB8E8) !important;
    color: var(--brand-on-surface-text, #1A1D23) !important;
}

/* Row 8: fill swap only — the same brand fill, not a second hue. The branded
   darken-on-hover feedback is layered separately via MainLayout's conditional
   `<style>` block (present only when branded), which adds a plain
   `filter: brightness(0.92)` rule for this same selector — see MainLayout.razor. */
.filter-chip-set .filter-chip-trigger:hover {
    background: var(--brand-on-surface, #20669B);
}

.mud-theme-dark .filter-chip-set .filter-chip-trigger:hover {
    background: var(--brand-on-surface, #54A9D5) !important;
}

.filter-chip-open .filter-chip-trigger,
.filter-chip-trigger:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.filter-chip-caret {
    font-size: 10px;
}

.filter-chip-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: var(--chip-height);
    width: 20px;
    border-radius: 0 6px 6px 0;
    border: none;
    background: #236FA8;
    color: #FFFFFF;
    cursor: pointer;
    font-size: 14px;
}

/* PAL-UAT-001: same white-on-cyan defect as .filter-chip-set above — the
   light-mode color: #FFFFFF was never overridden for dark. */
.mud-theme-dark .filter-chip-clear {
    background: #5BB8E8 !important;
    color: #1A1D23 !important;
}

/* UAT-11: this content is teleported by MudMenu to the popover-provider container
   outside .mud-layout, so it must use MudBlazor's own globally-scoped --mud-palette-*
   variables (which DO reach teleported content) instead of our --bg-secondary/
   --text-primary/--border-light custom properties (only dynamically remapped inside
   .mud-layout) — otherwise the popover renders with no opaque surface at all. */
.filter-chip-popover {
    background: var(--mud-palette-surface, #FFFFFF);
    border: 1px solid var(--mud-palette-lines-default, rgba(0, 0, 0, 0.12));
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
    overflow: hidden;
    min-width: 160px;
}

.filter-chip-option {
    padding: 8px 16px;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    color: var(--mud-palette-text-primary, var(--text-primary));
    cursor: pointer;
    min-height: 32px;
    display: flex;
    align-items: center;
}

.filter-chip-option:hover,
.filter-chip-option:focus-visible {
    background: var(--mud-palette-action-default-hover, var(--row-hover));
    outline: none;
}

.filter-chip-clear:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ── ListGroup / ListRow ───────────────────────────────────────── */
.list-group-container {
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: var(--bg-secondary);
    /* UAT-10: overflow:hidden establishes its own scroll/clip box, so a sticky child's
       `top: 88px` was computed relative to THIS container (near-zero height at rest)
       instead of the page scroll — the header snapped 88px down over its own first
       row(s) even at scroll position zero. Corners are rounded per-row below instead. */
}

.list-group:first-child .list-row:first-child,
.list-group-container > .list-row:first-child {
    border-top-left-radius: 8px;
    border-top-right-radius: 8px;
}

.list-group:last-child .list-row:last-child,
.list-group-container > .list-row:last-child {
    border-bottom-left-radius: 8px;
    border-bottom-right-radius: 8px;
}

.list-group-header {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding: 0 16px;
    background: var(--bg-secondary);
    position: sticky;
    top: 88px;
    z-index: 5;
}

.list-group-caret {
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 10px;
    padding: 0;
}

.list-group-label {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
}

.list-group-count {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.list-row {
    display: flex;
    align-items: center;
    height: var(--row-height);
    padding: 0 16px;
    gap: 12px;
    border-bottom: 1px solid var(--border-light);
    background: var(--bg-secondary);
    cursor: pointer;
    transition: background-color 150ms ease;
}

.mud-theme-dark .list-row {
    background: #161E2E !important;
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}

.list-row:last-child {
    border-bottom: none;
}

/* v2/v3 background-lightening attempts removed -- see the .list-row-overdue .list-row-meta rule below for the final mechanism (v4). */

.list-row:hover {
    background: var(--row-hover);
}

.list-row-selected {
    background: var(--row-selected);
}

/* UAT-73.1: a selected row's mouse cursor almost always still rests over it right
   after the click that selected it (and stays there while its peek panel is open),
   so plain source order isn't enough — `.list-row:hover` (0,2,0) outranks the bare
   `.list-row-selected` (0,1,0) on specificity alone and silently swaps the brand
   tint for the generic hover grey. `.list-row.list-row-selected:hover` (0,3,0) is
   unambiguously higher regardless of any future rule reordering. In dark theme the
   earlier `.mud-theme-dark .list-row` rule above additionally carries `!important`,
   which always outranks a non-`!important` rule irrespective of specificity — so the
   dark selected/selected-hover pair needs its own `!important` to actually win. */
.list-row.list-row-selected:hover {
    background: var(--row-selected);
}

.mud-theme-dark .list-row-selected,
.mud-theme-dark .list-row.list-row-selected:hover {
    background: var(--row-selected) !important;
}

.list-row:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 0;
}

/* UAT-03/PAL-UAT-003 (v4, final; hex refreshed 260828 for AA contrast — see below):
   matches DevFlowTheme's Error colour (#BF423A light / #E0605A dark) via the live
   --mud-palette-error variable. Two
   background-lightening attempts at the row level were tried and both failed
   empirically: a hardcoded light literal broke dark (.mud-theme-dark's
   class-scoped override is not reliably present after a same-page toggle, so
   dark rendered the light literal directly -- found live via
   --project=accessibility); a theme-reactive color-mix(white %, --bg-secondary)
   fixed light but the SAME percentage that light needs (~20%) drops dark's own
   --text-secondary-on-background contrast from ~4.5:1 to ~3.4:1 (dark's surface
   starts far closer to black, so the identical white delta shifts it far more
   in relative terms) -- also found live. No single background formula solves
   both themes without a reliable per-theme branch, which .mud-theme-dark
   cannot provide. Falls back to the file's OWN pre-existing, already-verified
   mechanism instead (identical to the :hover/.list-row-selected rules directly
   below, which have passed --project=accessibility in both themes since before
   this task): color-mix the semantic red itself toward --mud-palette-text-
   primary. This is a derived RENDERING of the #BF423A/#E0605A token (light hex
   darkened 260828 from #C4443C for AA on --bg-secondary; DevFlowTheme.cs's Error
   is the source of truth, this rule's own fallback literal is kept in sync below)
   on a background CONTEXT-tinted panel -- this RULE does not itself redefine the
   token, only derives from it -- exactly the same characterization already
   accepted for the :hover/.list-row-selected states one rule below. */
.list-row-overdue .list-row-meta {
    color: color-mix(in srgb, var(--mud-palette-error, #BF423A) 80%, var(--mud-palette-text-primary, #1A2744) 20%);
    font-weight: 500;
}

/* UAT-72: plain --mud-palette-error isn't enough once the row's OWN background is tinted
   by an interactive state — :hover (--row-hover, ~4.31:1 measured live via axe) or
   .list-row-selected (--row-selected's orange-into-surface mix, ~3.91:1 measured live) both
   darken/warm the row toward the same hue as the destructive red, eroding its margin below
   4.5:1 in dark mode. Scoped to ONLY these two states (never the rest state above) so 71's
   shared visual baselines, captured at rest, don't shift. color-mix toward --mud-palette-
   text-primary (near-white in dark, near-black in light) self-corrects per theme: it
   lightens the red in dark (more contrast against a dark bg) and deepens it in light (more
   contrast against a light bg), clearing 4.5:1 in both themes off one live-tracked formula. */
.list-row-overdue:hover .list-row-meta,
.list-row-selected.list-row-overdue .list-row-meta {
    color: color-mix(in srgb, var(--mud-palette-error, #BF423A) 80%, var(--mud-palette-text-primary, #1A1D23) 20%);
}

.list-row-key {
    flex: 0 0 68px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.list-row-key:empty {
    flex-basis: 0;
}

.list-row-title {
    flex: 1 1 auto;
    min-width: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.list-row-meta {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.list-row-trailing {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
}

/* quick-260907-blk (D-06/BLK-03): the amber text pill sits inside the existing
   trailing cluster — it does not grow the 40px row. */
.list-row-blocked-pill {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 20px;
    padding: 0 8px;
    border-radius: 999px;
    background: var(--blocked-tint);
    border: 1px solid var(--blocked-border);
    /* Live palette mix, not var(--blocked-text): .mud-theme-dark is not reliably in the DOM after a dark toggle (see .error-banner-retry). */
    color: color-mix(in srgb, var(--mud-palette-text-primary, #1D1924) 55%, #E8913A);
    font-family: 'Outfit', sans-serif;
    font-size: 11.5px;
    font-weight: 500;
    white-space: nowrap;
}

/* quick-260907-blk: explicit dark override, not a bare var() cascade — this
   codebase's standing convention (CLAUDE.md: "CSS overrides require
   !important on CSS variable remaps") for every other themed rule in this
   file (.list-row, .meta-grid, etc.), applied here for the same reliability. */
.mud-theme-dark .list-row-blocked-pill {
    background: rgba(239, 173, 95, 0.16) !important;
    border-color: rgba(239, 173, 95, 0.45) !important;
    color: color-mix(in srgb, var(--mud-palette-text-primary, #1D1924) 55%, #E8913A) !important;
}

.list-row-skeleton {
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
    cursor: default;
}

/* ── CommandPalette ────────────────────────────────────────────── */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.command-palette-scrim {
    position: fixed;
    inset: 0;
    background: rgba(26, 29, 35, 0.32);
    z-index: 1300;
}

.mud-theme-dark .command-palette-scrim {
    background: rgba(0, 0, 0, 0.55) !important;
}

.command-palette-dialog {
    position: fixed;
    top: 12vh;
    left: 50%;
    transform: translateX(-50%);
    width: min(640px, calc(100vw - 48px));
    max-height: 60vh;
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
    z-index: 1301;
    overflow: hidden;
}

.mud-theme-dark .command-palette-dialog {
    background: #161E2E !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
}

.command-palette-input-row {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 48px;
    padding: 0 16px;
    border-bottom: 1px solid var(--border-light);
    flex: 0 0 auto;
}

.command-palette-search-icon {
    color: var(--text-tertiary);
    display: inline-flex;
}

.command-palette-input {
    flex: 1 1 auto;
    border: none;
    outline: none;
    background: transparent;
    font-family: 'Outfit', sans-serif;
    font-size: 15px;
    color: var(--text-primary);
}

.command-palette-input::placeholder {
    color: var(--text-tertiary);
}

.command-palette-section-label {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-secondary);
    padding: 8px 16px 4px;
}

.command-palette-results {
    overflow-y: auto;
    flex: 1 1 auto;
}

.command-palette-item {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 16px;
    cursor: pointer;
}

.command-palette-item:hover {
    background: var(--row-hover);
}

.command-palette-item-active {
    background: var(--row-selected);
    border-left: 2px solid var(--focus-ring);
}

.command-palette-item-primary {
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
}

.command-palette-item-secondary {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.command-palette-progress {
    height: 2px;
    /* AV1-03 row 28 (M1): var(--accent-tertiary) resolved to the literal coral
       unbranded; re-pointed to --brand-on-surface, fallback preserves today's
       literal (260827-pal: now the palette B accent, #236FA8). */
    background: var(--brand-on-surface, #236FA8);
}

.command-palette-footer {
    height: 32px;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    padding: 0 16px;
    border-top: 1px solid var(--border-light);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* ── Phase 78 — palette actions ────────────────────────────────── */
/* Ticket context row: non-interactive, never an option. */
.command-palette-ticket-context {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    flex: 0 0 auto;
    padding: 0 16px;
    background: var(--bg-tertiary);
    border-bottom: 1px solid var(--border-light);
}

.mud-theme-dark .command-palette-ticket-context {
    background: var(--bg-tertiary) !important;
    border-bottom-color: rgba(255, 255, 255, 0.10) !important;
}

.command-palette-ticket-key {
    min-width: 68px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
}

.command-palette-ticket-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
}

.command-palette-item-icon {
    display: inline-flex;
    color: var(--text-tertiary);
}

.command-palette-item-trailing {
    margin-left: auto;
    max-width: 50%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* a trailing StatusDot is followed by its label: keep both on the right edge */
.command-palette-item-trailing + .command-palette-item-secondary {
    flex: 0 1 auto;
}

.command-palette-chevron {
    display: inline-flex;
    color: var(--text-tertiary);
}

/* Back button replaces the search icon inside a step. */
.command-palette-back {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--text-tertiary);
    cursor: pointer;
}

.command-palette-back:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Assign: checkbox indicator, avatar, pending spinner. */
.command-palette-check {
    flex: 0 0 16px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border: 1.5px solid var(--text-tertiary);
    border-radius: 4px;
    background: transparent;
    color: transparent;
}

.command-palette-check-on {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: #FFFFFF;
}

.mud-theme-dark .command-palette-check-on {
    background: #5BB8E8 !important;
    border-color: #5BB8E8 !important;
    color: #1A1D23 !important;
}

.command-palette-avatar {
    flex: 0 0 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 10.5px;
    font-weight: 500;
}

.mud-theme-dark .command-palette-avatar {
    background: var(--bg-tertiary) !important;
}

.command-palette-spinner {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    border: 2px solid var(--border-light);
    border-top-color: var(--text-secondary);
    border-radius: 50%;
    animation: command-palette-spin 0.8s linear infinite;
}

@keyframes command-palette-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .command-palette-spinner {
        animation: none;
    }
}

.command-palette-item-dim {
    opacity: 0.6;
    pointer-events: none;
}

.command-palette-skeleton {
    height: 40px;
    margin: 0 16px 4px;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

/* Dark: the palette is mounted OUTSIDE <MudLayout> (MainLayout), so the `.mud-layout` token-remap block
   does not reach it — --text-*, --bg-* and --border-light resolved to their :root LIGHT literals in both
   themes (axe 2.68:1 on the active row in dark; the same mechanism app.css documents for dialogs, 79-09).
   Re-point the palette's own tokens at --mud-palette-*, which MudThemeProvider publishes at :root and
   updates live on a same-page toggle. !important per the standing MudBlazor convention. */
.command-palette-dialog {
    --bg-secondary: var(--mud-palette-surface) !important;
    --bg-tertiary: var(--mud-palette-background-gray) !important;
    --text-primary: var(--mud-palette-text-primary) !important;
    --text-secondary: var(--mud-palette-text-secondary) !important;
    --border-light: var(--mud-palette-divider) !important;
    --row-selected: color-mix(in srgb, var(--mud-palette-primary) 6%, var(--mud-palette-surface)) !important;
    --row-hover: color-mix(in srgb, var(--mud-palette-primary) 3%, var(--mud-palette-surface)) !important;
}

/* Keyboard shortcuts step: read-only title in place of the input, non-interactive rows, key badges. */
.command-palette-step-title {
    flex: 1 1 auto;
    font-family: 'Outfit', sans-serif;
    font-size: 15px;
    font-weight: 500;
    color: var(--text-primary);
}

.command-palette-shortcuts {
    list-style: none;
    margin: 0;
    padding: 0;
}

.command-palette-shortcut-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    height: 40px;
    padding: 0 16px;
}

.command-palette-keys {
    display: inline-flex;
    gap: 4px;
}

.command-palette-key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 24px;
    min-width: 24px;
    padding: 0 8px;
    border-radius: 4px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

.mud-theme-dark .command-palette-key {
    background: var(--bg-tertiary) !important;
    color: var(--text-secondary) !important;
}

@media (max-width: 767.98px) {
    .command-palette-back {
        width: 44px;
        height: 44px;
        margin-left: -8px;
    }

    .command-palette-ticket-context {
        position: sticky;
        top: 0;
    }

    .command-palette-section-label {
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--bg-secondary);
    }

    /* the 16px checkbox sits inside a 44px-wide tap zone */
    .command-palette-person .command-palette-check,
    .command-palette-person .command-palette-spinner {
        margin: 0 14px 0 -14px;
        box-sizing: content-box;
    }

    .command-palette-person {
        padding-left: 28px;
    }
}

/* ── AppRail ───────────────────────────────────────────────────── */
.app-rail {
    position: fixed;
    left: 0;
    top: 0;
    width: var(--rail-width);
    height: 100vh;
    background: #243352;
    z-index: 1200;
    /* Phase 73.1 row 2: the focus ring inside the rail is derived against the RAIL
       (--brand-on-rail), not the content surface (--brand-on-surface) — a scope
       override so every var(--focus-ring) consumer under .app-rail (e.g.
       .app-rail-item:focus-visible below) picks it up with no edit of its own. */
    --focus-ring: var(--brand-on-rail, #5BB8E8);
}

.app-rail-list {
    list-style: none;
    margin: 0;
    padding: 8px 8px 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100%;
    gap: 4px;
}

.app-rail-brand {
    margin-bottom: 12px;
}

/* 260827-pal decision 3: flat navy fill + cyan border/glyph, no coral gradient
   (superseded 73.1-UI-SPEC.md §Components 1's gradient lock). Geometry
   (32x32/8px radius/12px bottom margin/Plus Jakarta Sans 800 14px) unchanged. */
.app-rail-brand-mark {
    width: 32px;
    height: 32px;
    background: #243352;
    border: 1px solid #5BB8E8;
    box-sizing: border-box;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    color: #5BB8E8;
    font-size: 14px;
    font-family: 'Plus Jakarta Sans', sans-serif;
}

/* Phase 73.1, 73.1-UI-SPEC.md §Components 1: the tenant-logo variant of the same
   32x32/8px-radius/12px-margin rail mark (S-6 — geometry unchanged branded or not).
   A modifier, not a token remap — this is the mark's own base styling, not one of
   the fourteen accent roles. */
.app-rail-brand-mark--logo {
    background: #FFFFFF;
    padding: 2px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    box-sizing: border-box;
}

.app-rail-brand-mark--logo img {
    width: 100%;
    height: 100%;
}

.app-rail-spacer {
    flex: 1 1 auto;
}

.app-rail-item {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.7);
    background: transparent;
    border: none;
    text-decoration: none;
    cursor: pointer;
    position: relative;
    transition: background-color 150ms ease, color 150ms ease;
}

.app-rail-item:hover {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.95);
}

.app-rail-item-active {
    background: var(--brand-rail-tint, rgba(35, 111, 168, 0.18));
    color: var(--brand-on-rail, #5BB8E8);
}

.app-rail-item:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.app-rail-dot {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #5BB8E8;
    box-shadow: 0 0 0 2px #243352;
}

.app-rail-timer {
    background: rgba(35, 111, 168, 0.18);
    color: #5BB8E8;
}

.app-rail-timer-elapsed {
    font-family: 'Outfit', sans-serif;
    font-size: 9px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.app-rail-bell {
    padding: 0;
}

.app-rail-bell :deep(.notification-bell-wrapper),
.app-rail-bell .notification-bell-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
}

.app-rail-bell .mud-icon-button,
.app-rail-bell button {
    color: rgba(255, 255, 255, 0.7) !important;
}

.app-rail-tooltip-wrapper {
    position: relative;
    display: flex;
}

.app-rail-tooltip {
    position: absolute;
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    margin-left: 8px;
    background: #1A1D23;
    color: #FFFFFF;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    padding: 4px 8px;
    border-radius: 6px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 150ms ease;
    z-index: 1400;
}

.mud-theme-dark .app-rail-tooltip {
    background: #26304A !important;
    color: #E6EAF2 !important;
}

.app-rail-tooltip-wrapper:hover .app-rail-tooltip,
.app-rail-tooltip-wrapper:focus-within .app-rail-tooltip {
    opacity: 1;
    visibility: visible;
}

.app-rail-avatar {
    background: rgba(255, 255, 255, 0.12);
    color: #FFFFFF;
    font-family: 'Outfit', sans-serif;
    font-size: 11px;
    font-weight: 600;
    border-radius: 50%;
    width: 28px;
    height: 28px;
}

/* ── Today page ────────────────────────────────────────────────── */
.today-page {
    padding: 24px 24px 24px;
}

.today-header {
    padding-top: 24px;
    margin-bottom: 24px;
}

.today-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 22px;
    font-weight: 800;
    color: var(--text-primary);
    margin: 0;
}

.today-date {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    margin-top: 4px;
}

.today-columns {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.today-column-left {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.today-column-right {
    flex: 0 0 320px;
    /* Flex items default to `min-width: auto`, which floors the box at its
       content's min-content width even with flex-grow/flex-shrink: 0 — long
       activity text (or a long project/client name) silently overrides the
       320px basis and shifts this column. `min-width: 0` removes that floor
       so the 320px track is the actual, unconditional rendered width. */
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 24px;
}

@media (max-width: 1200px) {
    .today-column-right {
        flex: 1 1 100%;
    }
}

.today-section {
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 10px;
    overflow: hidden;
}

.mud-theme-dark .today-section {
    background: #161E2E !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}

.today-section-header {
    display: flex;
    align-items: center;
    gap: 4px;
    height: 40px;
    padding: 0 16px;
}

.today-section-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
}

.today-section-count {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    margin-left: 8px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.today-section-spacer {
    flex: 1 1 auto;
}

.today-section-action {
    background: none;
    border: none;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    cursor: pointer;
    /* Quick 260918-approvals-decision-surface (UX-05, D-09): this class now also seats a
       real <a href> (Today's "View approvals" link), not only <button> callers — anchors
       need an explicit reset so they don't render the browser's default underline/blue. */
    text-decoration: none;
}

.today-section-action:hover {
    text-decoration: underline;
}

.today-time-summary {
    padding: 8px 16px;
    font-family: 'Outfit', sans-serif;
    font-size: 15px;
    font-weight: 500;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.today-avatar {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--accent-primary);
    color: #FFFFFF;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    font-weight: 600;
}

/* ── Phase 72 — Tickets Workbench ──────────────────────────────── */

/* Group/sort popover option rows (D-01) — the leading check on the current option,
   reusing the existing .filter-chip-option 32px/14px row grammar. */
.filter-chip-option-check {
    margin-right: 6px;
}

/* D-12 collapsed row meta (peek open) — priority dot-only and the "N days late" text
   survive; both slots are meta-free otherwise, no new min-height/padding on the row. */
.list-row-meta-collapsed-due {
    min-width: 64px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* D-12: while the peek is open the title absorbs the reclaimed space before the row
   itself starts to scroll horizontally. */
.list-group-compact .list-row-title {
    min-width: 120px;
}

/* ── MetaGrid / MetaRow (D-05) ─────────────────────────────────── */
.meta-grid {
    display: grid;
    /* F-BLK-MOBILE-DETAIL-001 heal: a bare 1fr track's implicit minimum is
       min-content, not 0 — a nowrap chip (min-content == its full unwrapped
       width) forces the track, and the whole grid, wider than the viewport.
       minmax(0, 1fr) lets the value column actually shrink to the container. */
    grid-template-columns: 112px minmax(0, 1fr);
    column-gap: 16px;
    row-gap: 4px;
    align-items: center;
    margin: 0;
    width: 100%;
    max-width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-md);
    padding: 12px 16px;
    box-sizing: border-box;
}

.mud-theme-dark .meta-grid {
    background: #161E2E !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}

.meta-grid-label {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    margin: 0;
}

.meta-grid-value {
    margin: 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    min-height: 28px;
    /* F-BLK-MOBILE-DETAIL-001 heal: this grid item is itself a flex container;
       without min-width: 0 a flex/grid item's default minimum is its content's
       min-content size, which defeats the minmax(0, 1fr) track above. */
    min-width: 0;
    max-width: 100%;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    color: var(--text-primary);
}

.meta-grid-value-control {
    min-height: 32px;
}

/* UAT: same bump/root-cause as .tab-strip-count and .ticket-composer-hint above —
   --text-tertiary measured 3.16:1 on white via axe (serious color-contrast); the dead
   .mud-theme-dark override never applied. */
.meta-grid-value-empty {
    color: var(--text-secondary);
}

/* UAT: root-cause fix, matches list-row-overdue's UAT-03 mechanism above — .mud-theme-dark
   never applies, so the dark override here was dead code and this rendered the light hex
   (#C4443C at 3.46:1 on #161E2E) in dark mode. --mud-palette-error tracks the live theme.
   260828: the light hex itself (fallback literal below) darkened #C4443C -> #BF423A —
   4.4:1 on --bg-secondary (#EEF2F6) failed AA; #BF423A clears 4.6:1 there. Dark's
   #E0605A/#161E2E pairing is unaffected. */
.meta-grid-value-destructive {
    color: var(--mud-palette-error, #BF423A);
    font-weight: 500;
}

.meta-grid-skeleton-label,
.meta-grid-skeleton-value {
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
    border-radius: 4px;
}

.meta-grid-skeleton-label {
    width: 64px;
    height: 10px;
}

.meta-grid-skeleton-value {
    width: 120px;
    height: 12px;
}

/* quick-260907-blk (D-13/D-06): "Blocked by" / "Blocks" MetaGrid chips. The
   --blocked-* tokens are defined in app.css (D-14) — chip fill/border/glyph
   use them; the "Blocks" chip is deliberately quieter (no tint, no glyph). */
.blocked-chip-icon {
    color: var(--blocked-amber, #E8913A);
    font-size: 13px;
    margin-right: 4px;
}

.blocked-chip {
    display: inline-flex;
    align-items: center;
    /* F-BLK-MOBILE-DETAIL-001 heal: 260px is a ceiling for wide viewports, not
       a guarantee — min-width: 0 lets this shrink below its own min-content
       once the ancestor grid track (minmax(0, 1fr) above) actually narrows on
       mobile; max-width: 100% keeps it from ever exceeding its (now-shrinkable)
       container regardless of the 260px cap. Full text still reaches the user
       via the title attribute (TicketDetailView.razor) since nowrap+ellipsis
       clips the rendered text at narrow widths. */
    min-width: 0;
    max-width: min(260px, 100%);
    box-sizing: border-box;
    padding: 2px 10px;
    border-radius: 999px;
    font-family: 'Outfit', sans-serif;
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.blocked-chip-by {
    background: var(--blocked-tint, rgba(232, 145, 58, 0.14));
    border: 1px solid var(--blocked-border, rgba(232, 145, 58, 0.45));
    color: var(--blocked-text, #8A4F0E);
}

.blocked-chip-blocks {
    color: var(--text-secondary);
}

/* quick-260907-blk: explicit dark override — same reliability convention as
   .list-row-blocked-pill above (the bare var() cascade measured as still
   resolving to the light :root value under axe, so this pins it forcibly). */
.mud-theme-dark .blocked-chip-icon {
    color: #EFAD5F !important;
}

.mud-theme-dark .blocked-chip-by {
    background: rgba(239, 173, 95, 0.16) !important;
    border-color: rgba(239, 173, 95, 0.45) !important;
    color: #F3C286 !important;
}

.blocked-chip-more {
    background: none;
    border: none;
    padding: 2px 6px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    text-decoration: underline;
}

/* Inline status/assignee control — text until hovered (D-05). */
.meta-grid-control {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 32px;
    margin: 0 -8px;
    padding: 0 8px;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
}

.meta-grid-control:hover {
    background: var(--row-hover);
}

.mud-theme-dark .meta-grid-control:hover {
    background: #26304A !important;
}

.meta-grid-control:disabled {
    cursor: default;
    background: transparent;
}

.meta-grid-control-caret {
    font-size: 12px;
    color: var(--text-tertiary);
}

.meta-grid-control-spinner {
    width: 12px;
    height: 12px;
}

.ticket-detail-status-select {
    width: 100%;
}

.meta-grid-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    flex: 0 0 20px;
}

.mud-theme-dark .meta-grid-avatar {
    background: #26304A !important;
    color: #E6EAF2 !important;
}

/* AV1-01: assignee-chip avatar takes a derived slot when branded — own of-today
   literal as the var() fallback (D-E), so unbranded stays byte-identical. Higher
   specificity than the two rules above wins the cascade in both themes; the dark
   twins keep !important to beat the dark rule above (equal !important, higher
   specificity). */
.meta-grid-avatar.slot-1 { background: var(--brand-avatar-1-bg, var(--bg-tertiary)); color: var(--brand-avatar-1-fg, var(--text-primary)); }
.meta-grid-avatar.slot-2 { background: var(--brand-avatar-2-bg, var(--bg-tertiary)); color: var(--brand-avatar-2-fg, var(--text-primary)); }
.meta-grid-avatar.slot-3 { background: var(--brand-avatar-3-bg, var(--bg-tertiary)); color: var(--brand-avatar-3-fg, var(--text-primary)); }
.meta-grid-avatar.slot-4 { background: var(--brand-avatar-4-bg, var(--bg-tertiary)); color: var(--brand-avatar-4-fg, var(--text-primary)); }
.meta-grid-avatar.slot-5 { background: var(--brand-avatar-5-bg, var(--bg-tertiary)); color: var(--brand-avatar-5-fg, var(--text-primary)); }
.meta-grid-avatar.slot-6 { background: var(--brand-avatar-6-bg, var(--bg-tertiary)); color: var(--brand-avatar-6-fg, var(--text-primary)); }

.mud-theme-dark .meta-grid-avatar.slot-1 { background: var(--brand-avatar-1-bg, #26304A) !important; color: var(--brand-avatar-1-fg, #E6EAF2) !important; }
.mud-theme-dark .meta-grid-avatar.slot-2 { background: var(--brand-avatar-2-bg, #26304A) !important; color: var(--brand-avatar-2-fg, #E6EAF2) !important; }
.mud-theme-dark .meta-grid-avatar.slot-3 { background: var(--brand-avatar-3-bg, #26304A) !important; color: var(--brand-avatar-3-fg, #E6EAF2) !important; }
.mud-theme-dark .meta-grid-avatar.slot-4 { background: var(--brand-avatar-4-bg, #26304A) !important; color: var(--brand-avatar-4-fg, #E6EAF2) !important; }
.mud-theme-dark .meta-grid-avatar.slot-5 { background: var(--brand-avatar-5-bg, #26304A) !important; color: var(--brand-avatar-5-fg, #E6EAF2) !important; }
.mud-theme-dark .meta-grid-avatar.slot-6 { background: var(--brand-avatar-6-bg, #26304A) !important; color: var(--brand-avatar-6-fg, #E6EAF2) !important; }

/* ── TabStrip (D-06) ───────────────────────────────────────────── */
.tab-strip {
    display: flex;
    align-items: center;
    height: 36px;
    gap: 24px;
    border-bottom: 1px solid var(--border-light);
    width: 100%;
}

.mud-theme-dark .tab-strip {
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}

.tab-strip-tab {
    display: inline-flex;
    align-items: center;
    height: 36px;
    padding: 0;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: color 150ms ease;
}

.tab-strip-tab:hover {
    color: var(--text-primary);
}

.tab-strip-tab-active {
    color: var(--text-primary);
    border-bottom-color: var(--brand-on-surface, #236FA8);
}

.mud-theme-dark .tab-strip-tab-active {
    border-bottom-color: var(--brand-on-surface, #5BB8E8) !important;
}

.tab-strip-tab:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* UAT: same bump as UAT-03's six small-text selectors — --text-tertiary measured 3.16:1 on
   white via axe (serious color-contrast); --text-secondary clears AA in both themes (the
   dead .mud-theme-dark override below never applied, same root cause as elsewhere in this
   file). 72-UI-SPEC's "tab counts" tertiary exception does not survive contact with axe at
   this font size/weight, so this follows 71's actual resolution instead. */
.tab-strip-count {
    margin-left: 6px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.tab-strip-panel:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ── PeekPanel (D-02/D-03) ─────────────────────────────────────── */
.peek-panel {
    position: fixed;
    top: var(--toolbar-height);
    right: 0;
    bottom: 0;
    /* QUICK-260826-fuj (D-02 amendment) — was a 480px literal; now the
       single --peek-width custom property (app.css :root), shared with the
       D-12 reflow rule below so the two never drift apart. */
    width: var(--peek-width);
    z-index: 1100;
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary);
    border-left: 1px solid var(--border-light);
    box-shadow: var(--shadow-lg);
    animation: peek-panel-enter 140ms cubic-bezier(0.4, 0, 0.2, 1);
}

.mud-theme-dark .peek-panel {
    background: #161E2E !important;
    border-left-color: rgba(255, 255, 255, 0.08) !important;
}

@keyframes peek-panel-enter {
    from {
        opacity: 0;
        transform: translateX(8px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

.peek-panel-header {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 44px;
    padding: 0 12px 0 16px;
    border-bottom: 1px solid var(--border-light);
    flex: 0 0 auto;
}

.mud-theme-dark .peek-panel-header {
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}

.peek-panel-key {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    white-space: nowrap;
}

.peek-panel-project {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.peek-panel-header-spacer {
    flex: 1 1 auto;
}

.peek-panel-header-action {
    height: 28px;
    padding: 0 8px;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    /* QUICK-260826-d6k item 3 — without this, a flex-shrunk button wraps its
       own label to a second line inside the fixed 28px box (the label spills
       outside the pill instead of the box growing), which is the ">=1440px
       wrap" defect from prod. Still moot once item 3's peek-scoped override
       below demotes these into the "More actions" menu, but harmless on the
       Page host, which keeps its own <=768px overflow swap either way. */
    white-space: nowrap;
}

.peek-panel-header-action:hover,
.peek-panel-header-icon-action:hover,
.peek-panel-close:hover {
    background: var(--row-hover);
}

.mud-theme-dark .peek-panel-header-action:hover,
.mud-theme-dark .peek-panel-header-icon-action:hover,
.mud-theme-dark .peek-panel-close:hover {
    background: #26304A !important;
}

.peek-panel-header-icon-action,
.peek-panel-close {
    width: 28px;
    height: 28px;
    flex: 0 0 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    text-decoration: none;
}

.peek-panel-header-action:focus-visible,
.peek-panel-header-icon-action:focus-visible,
.peek-panel-close:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* QUICK-260826-d6k item 2 — 32px hit target for icon-only peek controls,
   scoped under .peek-panel only. `.peek-panel-header-icon-action` is shared
   with the Page host (HeaderActionOverflow's "More actions" trigger, and the
   same InlineContent/OverflowContent markup for Copy link/Delete there), so
   this can't just widen the base rule above — the Page host at 390px has no
   spare width budget for +4px per button and is deliberately untouched. */
.peek-panel .peek-panel-header-icon-action,
.peek-panel .peek-panel-close {
    width: 32px;
    height: 32px;
    flex: 0 0 32px;
}

/* QUICK-260826-d6k item 2 — a real role="tooltip" node for every icon-only
   peek header control (IconTooltip.razor), bottom-placed (the rail's
   app-rail-tooltip-wrapper/-tooltip pair above is left-placed, for the
   vertical rail; kept separate per the component's own header comment). */
.icon-tooltip-wrapper {
    position: relative;
    display: flex;
}

.icon-tooltip {
    position: absolute;
    top: 100%;
    /* Right-aligned to the wrapper's own right edge (not centered) — the
       peek header packs every icon-only control against the panel's right
       edge inside the peek's width (--peek-width, QUICK-260826-fuj), so a
       centered tooltip on the rightmost controls (Close, Open in page)
       bleeds past the header's own right boundary. It stays invisible there
       at rest, but visibility:hidden (unlike display:none) still counts
       toward the ancestor's scrollWidth, which is exactly the "nothing in
       the header may wrap or overflow" invariant this plan locks —
       right-aligning keeps every tooltip's box inside the peek panel
       regardless of which control it belongs to. */
    right: 0;
    margin-top: 6px;
    background: #1A1D23;
    color: #FFFFFF;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    padding: 4px 8px;
    border-radius: 6px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 150ms ease;
    z-index: 1400;
}

.mud-theme-dark .icon-tooltip {
    background: #26304A !important;
    color: #E6EAF2 !important;
}

.icon-tooltip-wrapper:hover .icon-tooltip,
.icon-tooltip-wrapper:focus-within .icon-tooltip {
    opacity: 1;
    visibility: visible;
}

.peek-panel-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 16px;
}

.peek-panel-footer {
    flex: 0 0 auto;
    border-top: 1px solid var(--border-light);
    background: var(--bg-secondary);
    padding: 12px 16px;
}

.mud-theme-dark .peek-panel-footer {
    background: #161E2E !important;
    border-top-color: rgba(255, 255, 255, 0.08) !important;
}

/* Reflow (D-12) — the list column shrinks by exactly the panel's own width
   (--peek-width, QUICK-260826-fuj), over the same duration/easing as the
   panel's enter/exit, so the two animate as one movement. */
.list-group-container {
    transition: width 140ms cubic-bezier(0.4, 0, 0.2, 1);
}

.list-group-container-reflow {
    width: calc(100% - var(--peek-width));
}

/* ── EntityPageFrame (D-04/D-08) ───────────────────────────────── */
.entity-page-back {
    width: 28px;
    height: 28px;
    flex: 0 0 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.entity-page-back:hover {
    background: var(--row-hover);
}

.mud-theme-dark .entity-page-back:hover {
    background: #26304A !important;
}

.entity-page-back:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.entity-page-breadcrumb {
    display: flex;
    align-items: center;
    gap: 4px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    min-width: 0;
    overflow: hidden;
}

.entity-page-breadcrumb a {
    color: var(--text-secondary);
    text-decoration: none;
}

.entity-page-breadcrumb a:hover {
    text-decoration: underline;
}

.entity-page-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* UAT-RMN-001 — HeaderActionOverflow.razor renders both an inline row and a single
   "More actions" popover trigger for the same secondary actions; exactly one is in the
   box model at a time so the header never grows past the viewport at <=768px. The peek
   host never mounts below 768px (72-UI-SPEC [LOCKED, D-02]), so this media query only
   ever activates for the Page host, which is what renders at that width. */
.entity-page-secondary-inline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.entity-page-secondary-overflow {
    display: none;
}

@media (max-width: 768px) {
    .entity-page-secondary-inline {
        display: none;
    }

    .entity-page-secondary-overflow {
        display: inline-flex;
    }
}

/* QUICK-260918-tsl (UX-26, P-01) — the ticket PAGE host passes
   OverflowAlwaysVisible="true" so the "More actions" trigger — the only home of
   Delete after this task — stays reachable above 768px too, not just at mobile
   width. Two classes, so it outranks the one-class `display: none` base rule above
   regardless of source order, and the <=768px media rule (also one class) never
   fights it since both agree there. The `.peek-panel` overrides below are also
   two-class selectors of equal specificity, but never apply here: the peek host
   never passes OverflowAlwaysVisible, so `.entity-page-secondary-overflow-always`
   never appears inside `.peek-panel`. */
.entity-page-secondary-overflow.entity-page-secondary-overflow-always {
    display: inline-flex;
}

/* QUICK-260826-d6k item 3 — inside the peek, Send for approval / Move… are
   reached through the "More actions" overflow below 1400px (amended by
   QUICK-260826-fuj below — the widened panel has room to show them inline
   from 1400px up; see that override's own comment) —
   TicketDetailView.HeaderActions only ever passes these two into
   HeaderActionOverflow when Host==Peek (Copy link / Delete ticket / Open in
   page render as icon-only siblings outside it), so this override just
   makes sure whichever of the two internal divs that component renders is
   the overflow one, never the inline one, in the peek by default. Higher
   specificity than the base rule/media query above wins without
   !important. The Page host's own <=768px swap (its own class instance,
   HeaderActionOverflow still carries all four actions there) is untouched. */
.peek-panel .entity-page-secondary-inline {
    display: none;
}

.peek-panel .entity-page-secondary-overflow {
    display: inline-flex;
}

/* QUICK-260826-fuj HOW 2 — inside the peek only, from 1400px up the widened
   panel (--peek-width resolves to >=560px there) has room for Send for
   approval / Move… to render inline without wrapping (the defect d6k item 3
   fixed at the old fixed 480px width). A media query, not a container
   query: the panel's width is a pure function of viewport width (D-02's
   clamp), so @container adds nothing, and container-type: inline-size on a
   position: fixed panel would make it a containing block for fixed-position
   descendants — regression risk against MudBlazor's portalled popovers for
   zero benefit. Placed after the d6k peek override above — equal
   specificity (.peek-panel .entity-page-secondary-*), so later wins; below
   1400px the d6k rule above is the last one that applies and overflow-only
   behaviour is unchanged. */
@media (min-width: 1400px) {
    .peek-panel .entity-page-secondary-inline {
        display: inline-flex;
    }

    .peek-panel .entity-page-secondary-overflow {
        display: none;
    }
}

/* Heal B — Edit is a real bordered secondary button (--control-height weight, matching
   "Add Member"), not borderless text, in every EntityPageFrame header (ticket + project
   detail share this one class so the two hosts cannot drift). */
.entity-page-header-edit {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    padding: 0 12px;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 13.5px;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    flex: 0 0 auto;
}

.entity-page-header-edit:hover {
    background: var(--row-hover);
}

.mud-theme-dark .entity-page-header-edit {
    border-color: rgba(255, 255, 255, 0.08);
}

.mud-theme-dark .entity-page-header-edit:hover {
    background: #26304A !important;
}

.entity-page-header-edit:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.entity-page-content {
    padding: 24px;
    max-width: 840px;
}

.entity-page-content-full {
    max-width: none;
}

.entity-page-skeleton {
    height: 240px;
    border-radius: 8px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

/* ── TicketComposer (D-06) ─────────────────────────────────────── */
.ticket-composer {
    position: relative;
}

.ticket-composer-editor-wrap {
    position: relative;
}

.ticket-composer-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 40px;
    margin-top: 8px;
}

.ticket-composer-visibility {
    display: flex;
    align-items: center;
    gap: 4px;
}

.ticket-composer-switch-label {
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
}

/* Not MudBlazor's Color.Info blue — navy track light, coral dark (71 primary-CTA rule). */
.ticket-composer-switch .mud-switch-track {
    background-color: #C9CDD4 !important;
}

.mud-theme-dark .ticket-composer-switch .mud-switch-track {
    background-color: #3A3D46 !important;
}

/* F73.1-003 heal: the corrected sibling-combinator selector for the CHECKED
   state now lives ONLY inside MainLayout.razor's IsBranded-conditional
   <style> block (same pattern as the "Set" filter chip hover rule there) —
   never here, unconditionally. Before this heal existed, NO selector ever
   matched this state (see the git history of this file), so an unbranded
   tenant's checked switch has always rendered its plain unchecked track
   colour with no distinct "checked" treatment. A `var(--brand-on-surface,
   <hex>)` fallback right here would have made the corrected selector match
   for EVERY tenant, including unbranded ones — changing that long-standing
   appearance and violating STAFFBRAND-04's "renders exactly as before this
   phase" lock. Scoping the corrected rule to the branded-only block instead
   preserves the exact unbranded appearance while still fixing the real
   selector bug for branded tenants (which the block gates on == true, no
   fallback needed since brandTokens is always non-null there). */

.ticket-composer-post-group {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* UAT: same bump/root-cause as .tab-strip-count above — --text-tertiary measured 3.16:1 on
   white via axe (serious color-contrast); the dead .mud-theme-dark override never applied. */
.ticket-composer-hint {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.ticket-composer-post {
    height: 32px;
    padding: 0 16px;
    border-radius: 8px;
    border: none;
    background: var(--brand-on-surface, #236FA8);
    color: var(--brand-on-surface-text, #FFFFFF);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.mud-theme-dark .ticket-composer-post {
    background: var(--brand-on-surface, #5BB8E8) !important;
    color: var(--brand-on-surface-text, #1A1D23) !important;
}

.ticket-composer-post:disabled {
    opacity: 0.45;
    cursor: default;
}

.ticket-composer-post:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.ticket-composer-post-spinner {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: #FFFFFF;
    animation: ticket-composer-spin 700ms linear infinite;
}

@keyframes ticket-composer-spin {
    to {
        transform: rotate(360deg);
    }
}

.ticket-composer-helper {
    margin: 6px 0 0;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* ── Embedded time tracking (D-06) ─────────────────────────────── */
.ticket-time-embedded {
    width: 100%;
}

/* ── TicketDetailView (D-04/D-05/D-06) ─────────────────────────── */
.ticket-detail-view {
    display: flex;
    flex-direction: column;
    position: relative;
}

/* quick-261001-tpd — file-drag overlay; shown only while ticket-attach.js sets data-file-dragover */
.ticket-detail-drop-overlay {
    display: none;
    position: absolute;
    inset: 0;
    z-index: 5;
    pointer-events: none;
    border: 2px dashed var(--mud-palette-primary);
    border-radius: 12px;
    background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
}

.ticket-detail-view[data-file-dragover="true"] > .ticket-detail-drop-overlay {
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

.ticket-detail-drop-overlay-label {
    position: sticky;
    top: 35vh;
    padding: 10px 20px;
    border-radius: 999px;
    font-family: 'Outfit', sans-serif;
    font-weight: 600;
    /* DevFlowTheme leaves --mud-palette-primary-text at #FFFFFF in BOTH palettes: white on the
       dark accent #5BB8E8 measured 2.21:1 (the PAL-UAT-001 class, see app.css .usage-upgrade-cta).
       --mud-palette-background is #FFFFFF light / #0F1522 dark and updates live on a theme toggle. */
    color: var(--brand-on-surface-text, var(--mud-palette-background));
    background: var(--mud-palette-primary);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
}

/* MudBlazor paints every snackbar at 0.95 opacity, which blends the white message text into the
   filled severity colour: the error snackbar this ticket drop/paste path raises measured 4.48:1
   (needs 4.5:1, WCAG AA). Opaque, so a visible failure is also a legible one. */
#mud-snackbar-container .mud-snackbar {
    opacity: 1 !important;
}

/* In the dark palette the severity fills are the LIGHT variants (error #E0605A), so MudBlazor's
   default white ink measured 3.5:1. --mud-palette-background is #FFFFFF light / #0F1522 dark and
   updates live on a theme toggle (a `.mud-theme-dark` twin does not, see app.css .usage-upgrade-cta),
   so light mode keeps its white ink and dark mode gets the near-black one. */
#mud-snackbar-container .mud-snackbar.mud-alert-filled-error,
#mud-snackbar-container .mud-snackbar.mud-alert-filled-success,
#mud-snackbar-container .mud-snackbar.mud-alert-filled-warning {
    color: var(--mud-palette-background);
}

.ticket-detail-view-page {
    max-width: 840px;
}

.ticket-detail-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 19px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--text-primary);
    margin: 0 0 12px;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ticket-detail-title-input {
    margin-bottom: 8px;
}

.ticket-detail-description {
    margin: 24px 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.6;
    color: var(--text-primary);
}

/* QUICK-260826-fuj HOW 4 — Peek only. max-height, not -webkit-line-clamp
   (unlike .ticket-detail-title above): MarkdownRenderer emits arbitrary
   block markup (headings, lists, code fences) for this field, and
   -webkit-box re-lays those children as flex/box items, breaking list
   markers and margins — a single text run's clamp idiom doesn't extend to
   block content. 224px = 10 lines * 1.6 * 14px, this block's own type
   ramp. Toggled off (class removed) when the user expands, or when
   TicketDetailView's after-render measurement (peekPanelIsOverflowing)
   finds the content doesn't actually overflow — see that component's
   OnAfterRenderAsync. */
.peek-panel .ticket-detail-description.is-clamped {
    max-height: 224px;
    overflow: hidden;
    position: relative;
}

/* Bottom fade mask, so the clamp reads as "there's more" rather than a hard
   crop — matches the peek's own background so the fade line is invisible
   against the panel, not the page. */
.peek-panel .ticket-detail-description.is-clamped::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 40px;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, var(--bg-secondary) 100%);
    pointer-events: none;
}

.mud-theme-dark .peek-panel .ticket-detail-description.is-clamped::after {
    background: linear-gradient(to bottom, rgba(22, 30, 46, 0) 0%, #161E2E 100%) !important;
}

.peek-panel .ticket-detail-description-toggle {
    display: inline-flex;
    align-items: center;
    margin-top: 4px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--brand-on-surface, var(--accent-tertiary));
    font-family: 'Outfit', sans-serif;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}

.peek-panel .ticket-detail-description-toggle:hover {
    text-decoration: underline;
}

.peek-panel .ticket-detail-description-toggle:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Phase 87 UAT (delete-dialog axe sweep): same bump/root-cause as .tab-strip-count and
   .ticket-composer-hint above -- --text-tertiary measured 3.19:1 on white via axe (serious
   color-contrast); the .mud-theme-dark override below never applied (same dead-selector
   root cause documented elsewhere in this file). --text-secondary clears AA in both themes:
   #5B697E on #FFFFFF = 5.58:1 (light), #94A3B8 on #0F1522 = 7.12:1 (dark) -- computed via the
   WCAG relative-luminance formula, not measured live. */
.ticket-detail-description-empty {
    margin: 0;
    color: var(--text-secondary);
}

.ticket-detail-section-heading {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 24px 0 12px;
}

.ticket-detail-composer-inline {
    margin-top: 24px;
}

.ticket-detail-assignee-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ticket-detail-assignee-remove {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--text-tertiary);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    padding: 2px 4px;
}

.ticket-detail-assignee-remove:hover {
    color: var(--text-primary);
}

.ticket-detail-edit-form {
    margin: 24px 0;
}

/* UAT72-heal H6 (ETF-UAT-006) — at narrow widths the Priority/Story Points/Due
   Date row (`.ticket-detail-edit-row`, Wrap="Wrap.Wrap" on its MudStack) has
   room to wrap, but each control still only claims its intrinsic content
   width unless told otherwise, so three MudBlazor inputs can still end up
   sharing a line too narrow for their labels. Forcing one control per line
   below 768px (this file's existing mobile breakpoint, e.g. line ~2418)
   guarantees "Story Points"/"Due Date" render unclipped and the date-picker
   icon has room beside its placeholder. !important per CLAUDE.md's CSS
   override guidance — MudBlazor's own flex-basis on these controls otherwise
   wins over a plain override. */
@media (max-width: 768px) {
    .ticket-detail-edit-row {
        flex-wrap: wrap !important;
    }

    .ticket-detail-edit-row > * {
        flex: 1 1 100% !important;
        min-width: 0 !important;
    }
}

.ticket-detail-skeleton-title {
    width: 320px;
    height: 20px;
    border-radius: 4px;
    margin-bottom: 16px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

.ticket-detail-skeleton-lines {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 24px 0;
}

.ticket-detail-skeleton-line {
    height: 12px;
    border-radius: 4px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

.ticket-detail-skeleton-feed {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 16px;
}

.ticket-detail-skeleton-row {
    height: 40px;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

/* ── Project detail adoption (D-08) ────────────────────────────── */
.ticket-detail-board-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 40px;
    padding: 0 8px;
    border-radius: 6px;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    text-decoration: none;
}

.ticket-detail-board-link:hover {
    background: var(--row-hover);
}

.mud-theme-dark .ticket-detail-board-link:hover {
    background: #26304A !important;
}

/* ── Project Files panel (quick-260907-project-files-panel, D-01/D-06) ──
   Reads as one system with .ticket-detail-board-link's 40px row grammar
   above — same control height, existing tokens only, no new colours. */
.project-files-panel-manage-folders-link {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    margin-top: 8px;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 13.5px;
    text-decoration: none;
}

.project-files-panel-manage-folders-link:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

.project-files-panel-toolbar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 8px;
}

.project-files-panel-upload-button {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    padding: 0 12px;
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 13.5px;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
}

.project-files-panel-upload-button:hover {
    background: var(--row-hover);
}

.mud-theme-dark .project-files-panel-upload-button {
    border-color: rgba(255, 255, 255, 0.08);
}

.project-files-panel-breadcrumb {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
    font-family: 'Outfit', sans-serif;
    font-size: 13.5px;
    color: var(--text-secondary);
}

.project-files-panel-breadcrumb-root {
    border: none;
    background: none;
    padding: 0;
    color: var(--text-secondary);
    font: inherit;
    cursor: pointer;
    text-decoration: none;
}

.project-files-panel-breadcrumb-root:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

.project-files-panel-breadcrumb-current {
    color: var(--text-primary);
    font-weight: 500;
}

.project-files-panel-dropzone,
.project-files-panel-list {
    position: relative;
    display: flex;
    flex-direction: column;
}

.project-files-panel-row {
    display: flex;
    align-items: center;
    height: 40px;
    padding: 0 8px;
    gap: 12px;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
}

.project-files-panel-row:hover {
    background: var(--row-hover);
}

.mud-theme-dark .project-files-panel-row:hover {
    background: #26304A !important;
}

.project-files-panel-row-folder {
    cursor: pointer;
}

.project-files-panel-row-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-files-panel-row-name-folder {
    font-weight: 500;
}

.project-files-panel-row-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 1 auto;
    /* H5 (quick-260907-pfp heal, PFP-UAT-004): without min-width: 0 a flex item's minimum
       width defaults to its content's un-wrapped size — a 200-char display name (the
       accepted max, UserConfiguration.cs) then keeps this whole group at that width no
       matter how little room is left, overflowing the page at 390px. This lets the group
       itself shrink; the uploader child below is the one that actually truncates. */
    min-width: 0;
    color: var(--text-secondary);
    font-size: 13px;
    white-space: nowrap;
}

.project-files-panel-row-meta-uploader {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-files-panel-row-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex: 0 0 auto;
}

.project-files-panel-row-highlight {
    background: var(--row-selected);
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.mud-theme-dark .project-files-panel-row-highlight {
    background: #26304A !important;
    outline-color: var(--focus-ring);
}

/* quick-260907-project-url-links: link row Open anchor (existing accent tokens, no new
   colours — --accent-primary is already re-derived per theme, see the "Accent scoping"
   comment further down this file) and the host secondary text, styled like -row-meta's
   existing children. */
.project-files-panel-row-link .project-files-panel-row-actions a {
    color: var(--accent-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    padding: 0 6px;
    white-space: nowrap;
}

.project-files-panel-row-link .project-files-panel-row-actions a:hover {
    text-decoration: underline;
}

.project-files-panel-row-host {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-files-panel-drop-overlay {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px dashed var(--focus-ring);
    border-radius: 8px;
    background: var(--row-hover);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    pointer-events: none;
}

/* PFP-06: at a narrow viewport, a fixed 40px single-line row with icon +
   name + size + uploader + date + four action controls has no room left
   for the name — it collapses toward 0 width and both the name AND the
   document overflow horizontally. Same wrap mechanism as .ops-console
   .list-row above: name takes its own full-width line (still ellipsis +
   min-width: 0, so it truncates rather than disappearing), meta/actions
   wrap to a second line. */
@media (max-width: 768px) {
    .project-files-panel-row {
        flex-wrap: wrap;
        height: auto;
        min-height: 40px;
        padding: 8px;
        row-gap: 4px;
    }

    .project-files-panel-row-name {
        flex: 1 1 100%;
    }

    .project-files-panel-row-meta,
    .project-files-panel-row-actions {
        flex: 0 1 auto;
        min-width: 0;
    }

    .project-files-panel-row-meta-uploader {
        min-width: 0;
        max-width: 100%;
    }
}

/* ── Reduced motion ────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    .app-rail *,
    .page-toolbar *,
    .filter-strip *,
    .filter-chip *,
    .list-row,
    .list-group-header,
    .command-palette-dialog,
    .command-palette-scrim,
    .dot-label *,
    .empty-state-shell *,
    .error-banner *,
    .tab-strip-tab,
    .meta-grid-control,
    .peek-panel,
    .list-group-container.list-group-container-reflow,
    .list-group-container,
    .ticket-composer-post-spinner {
        transition: none !important;
        animation: none !important;
        transform: none !important;
    }
}

/* ── Operator console (Phase 80) ───────────────────────────────── */

/* Accent scoping (80-UI-SPEC §Accent scoping). MainLayout injects the signed-in
   tenant's brand at :root, and an operator is still an authenticated staff user of
   SOME tenant — so without this block a cross-tenant console would wear one tenant's
   accent and imply the rows belong to it. The console is a platform surface, not a
   workspace surface: it renders in the product default for every operator. A custom
   property re-declared on a descendant beats the inherited :root value regardless of
   how forcefully that declaration was written, so no override flag is needed here and
   no rule below writes a bare accent literal at a use site.

   --focus-ring / --accent-primary / --row-selected are re-derived HERE on purpose.
   app.css declares them on .mud-layout as var(--brand-…, fallback); a var() inside a
   custom property is substituted at computed-value time on the element that DECLARES
   the property, so .mud-layout resolves them against :root's brand and descendants
   inherit an already-substituted colour. Re-declaring them on this element re-runs the
   substitution against the values above, in both themes. */
.ops-console {
    --brand-on-surface: #236FA8;
    --brand-on-surface-text: #FFFFFF;
    --brand-row-selected: #E9F1F8;
    --brand-accent: #236FA8;
    --focus-ring: var(--brand-on-surface);
    --accent-primary: var(--brand-on-surface);
    --row-selected: var(--brand-row-selected);
}

.mud-theme-dark .ops-console {
    --brand-on-surface: #5BB8E8;
    --brand-on-surface-text: #1A1D23;
    --brand-row-selected: color-mix(in srgb, #5BB8E8 6%, #161E2E);
}

/* Inline row meter (§Components 3): 56px track + 8px gap + 32px label = 96px. */
.ops-meter-inline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    width: 96px;
}

.ops-meter-track {
    flex: 0 0 auto;
    width: 56px;
    height: 6px;
    border-radius: 3px;
    background: var(--border-light);
    overflow: hidden;
}

.ops-meter-fill {
    display: block;
    height: 6px;
    border-radius: 3px;
}

/* The three fill colours are semantic and held CONSTANT across themes, as the Phase 71
   dot scale is: "how full is this tenant" must never read as a brand question, and a
   per-theme re-tint would break cross-theme screenshot comparison. */
.ops-meter-fill-normal {
    background: var(--status-done);
}

.ops-meter-fill-warning {
    background: var(--priority-medium);
}

.ops-meter-fill-over {
    background: #C4443C;
}

.ops-meter-label {
    flex: 0 0 auto;
    min-width: 32px;
    text-align: right;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* The Unlimited state's em-dash — a placeholder dash, so --text-secondary. */
.ops-meter-label-unlimited {
    color: var(--text-secondary);
}

/* Row meta cells (§Components 2). Fixed widths are the whole point: they make the list
   read as columns. Family, size, colour and the 12px gaps are inherited unchanged from
   the shipped .list-row-meta. */
.ops-meta-slug,
.ops-meta-tier,
.ops-meta-billing,
.ops-meta-created {
    flex: 0 0 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ops-meta-slug {
    width: 140px;
}

.ops-meta-tier {
    width: 72px;
}

.ops-meta-billing {
    width: 116px;
}

.ops-meta-created {
    width: 92px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* Column shedding (§Components 2). The row's columns are dropped in order of how little
   each one identifies its row — never by letting the flex box squeeze the row's own name
   away. `.list-row-title` is the ONLY `flex: 1 1 auto` cell in a ListRow, and both clusters
   beside it (meta 352px, trailing 300px) are `flex: 0 0 auto`, so every pixel the row cannot
   satisfy is taken out of the title first: at 375px it computed to literally 0px, the
   tenant name left the viewport entirely and the row overflowed the document to 704px
   (finalize §5.2 human visual review, 260831). Each figure hidden below is on that tenant's
   own detail page AND stays in the row's accessible name (see OpsList.AriaSuffix), so
   nothing becomes unreachable and a screen reader loses none of it. */
@media (max-width: 1279px) {
    .ops-meta-created {
        display: none;
    }
}

/* Below 1024px the surviving meta + trailing (652px plus the row's own gaps) stop leaving
   the title a readable share, so the slug goes next: it is the one cell whose content the
   title immediately beside it already tells you. */
@media (max-width: 1023px) {
    .ops-meta-slug {
        display: none;
    }
}

/* Trailing cluster: 96 + 12 + 96 + 12 + 84 = 300px. */
.ops-trailing {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Incident indicator. At zero this cell renders EMPTY rather than collapsing, so the
   meters stay column-aligned across rows and a healthy tenant shows nothing here. */
.ops-incident {
    flex: 0 0 auto;
    width: 84px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* The " (inactive)" suffix beside a row title. The span's own leading space carries the
   gap — no margin here, so the accessible name and the rendered text stay in step. */
.ops-row-inactive {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
}

/* Phase 82 (D-12): the " (owner sign-in blocked ...)" suffix beside a row title. Same family,
   size and weight as .ops-row-inactive above; the one difference is the colour token, so the
   flag reads as a STATE rather than as more of the workspace's name. The span's own leading
   space carries the gap, so the accessible name and the rendered text stay in step.
   Finalize heal (a11y): --priority-high (#EF8354) is a fill/border-only token — axe measured
   it at 2.32:1 on this row's --bg-secondary background (#EEF2F6), a serious color-contrast
   violation, and #EF8354 does not have a dark-theme remap either. This is a destructive STATE
   flag, not a priority indicator, so it reuses the row's own already-verified destructive-red
   mechanism instead: the UAT-03/PAL-UAT-003 formula directly above (.list-row-overdue
   .list-row-meta), color-mixing the live --mud-palette-error token (DevFlowTheme.cs: #BF423A
   light / #E0605A dark) 80% toward --mud-palette-text-primary 20%, on this exact --bg-secondary
   / #161E2E row background. Computed (WCAG relative luminance, not eyeballed): light mix
   ≈ #9E3D3C on #EEF2F6 = 5.86:1; dark mix ≈ #E17C78 on #161E2E = 5.85:1 — both clear 4.5:1
   with comfortable margin, and both --mud-palette-* tokens are live per theme (no
   .mud-theme-dark reliability risk, same reasoning already recorded above). */
.ops-row-owner-blocked {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: color-mix(in srgb, var(--mud-palette-error, #BF423A) 80%, var(--mud-palette-text-primary, #1A2744) 20%);
}

/* Mobile reflow (<=768px). Below this width no further shedding leaves BOTH the workspace
   name and its two meters a readable share of one 40px line, so the row stops pretending to
   be a table: the title takes a full-width line of its own and the surviving figures wrap
   beneath it. The fixed cell widths above exist to make the list read as columns; once a row
   wraps there are no columns left to align, and holding those widths open would only force
   the horizontal document overflow this block exists to remove. Everything here is scoped to
   `.ops-console`, so the shared ListRow / FilterStrip grammar is byte-for-byte unchanged for
   every other page that consumes it. */
@media (max-width: 768px) {
    /* The chip rail scrolls horizontally by design (`.filter-strip-chips` is `overflow-x:
       auto` with the scrollbar hidden), but at this width that scroll cut a chip through the
       middle of its own word and butted it straight against the sort text with no gap —
       which reads as a broken toolbar, not as more content sideways (same review). Two
       full-width bands instead: the chips wrap onto as many lines as they need, the sort
       control sits under them. The 6px chip gap and 16px padding are what let all four of
       this page's chips share one line at 375px; a chip that grows a value simply wraps. */
    .ops-console .filter-strip {
        height: auto;
        min-height: var(--filterstrip-height);
        flex-wrap: wrap;
        padding: 6px 16px;
        row-gap: 6px;
    }

    .ops-console .filter-strip-chips {
        flex: 1 1 100%;
        flex-wrap: wrap;
        column-gap: 6px;
        row-gap: 6px;
        overflow-x: visible;
    }

    /* The spacer's whole job is pushing the sort text to the far end of a single line; on
       its own line it would just be a zero-height flex item taking a wrap slot. */
    .ops-console .filter-strip-spacer {
        display: none;
    }

    .ops-console .filter-strip-meta {
        flex: 1 1 100%;
    }

    .ops-console .list-row {
        flex-wrap: wrap;
        height: auto;
        min-height: var(--row-height);
        column-gap: 8px;
        row-gap: 2px;
        padding: 8px 16px;
    }

    /* `flex-basis: 100%` is what puts the name on its own line. It keeps the inherited
       `min-width: 0` + ellipsis, so a long workspace name truncates rather than overflowing
       — the one thing it can no longer do is disappear. */
    .ops-console .list-row-title {
        flex: 1 1 100%;
    }

    /* Shrinkable on the wrapped line, so a long billing label truncates or drops the
       trailing cluster to a third line instead of widening the document. */
    .ops-console .list-row-meta,
    .ops-console .list-row-trailing {
        flex: 0 1 auto;
        min-width: 0;
    }

    /* Tier reads off the detail page and off the row's accessible name; the billing state is
       the only meta figure with no equivalent anywhere else in the wrapped row, so it stays. */
    .ops-meta-tier {
        display: none;
    }

    .ops-meta-billing {
        width: auto;
        max-width: 100%;
    }

    .ops-trailing {
        gap: 8px;
    }

    /* The empty-at-zero incident cell holds an 84px column open so meters stay aligned ROW TO
       ROW. A wrapped row has no such column, and 84px of reserved blank is the difference
       between the trailing cluster fitting beside the billing state and being pushed down. */
    .ops-incident {
        width: auto;
    }
}

/* Detail sections (§Components 6) — the shipped Today-section geometry, reused. */
.ops-section {
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 10px;
    overflow: hidden;
}

.mud-theme-dark .ops-section {
    background: #161E2E;
    border-color: rgba(255, 255, 255, 0.08);
}

.ops-section-header {
    display: flex;
    align-items: center;
    gap: 4px;
    height: 40px;
    padding: 0 16px;
}

.ops-section-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
}

.ops-section-count {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    margin-left: 8px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.ops-section-sub {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    margin: 0;
    padding: 0 16px 8px;
}

/* A 12.5px line beneath a section's content: the retention note, the paused-email
   count, the not-yet-backfilled billing sentence. */
.ops-section-note {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    margin: 0;
    padding: 8px 16px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* …except the billing one, which is the only thing that section has to say. */
.ops-section-state {
    color: var(--text-primary);
}

/* A MetaGrid inside a section is that section's content, not a second card — drop its
   own chrome so Tenant and Billing each read as one container. */
.ops-section .meta-grid {
    background: none;
    border: none;
    border-radius: 0;
}

/* Both detail log sections are <ul> lists, not listboxes: nothing in them opens, so
   they get no hover, no cursor change and no roving tabindex (§Accessibility). */
.ops-log-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.ops-log-row {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    padding: 0 16px;
    border-bottom: 1px solid var(--border-light);
}

.mud-theme-dark .ops-log-row {
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

.ops-log-row:last-child {
    border-bottom: none;
}

.ops-log-primary {
    flex: 0 0 auto;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    color: var(--text-primary);
}

.ops-log-meta {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.ops-log-time {
    flex: 0 0 auto;
    margin-left: auto;
    text-align: right;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* The detail's two UsageMeter cards. */
.ops-meter-cards {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    padding: 0 16px 16px;
}

@media (max-width: 720px) {
    .ops-meter-cards {
        grid-template-columns: 1fr;
    }
}

/* Reduced motion: the only motion on these surfaces is the ListRow background
   transition inherited from Phase 71 — the inline meter has none of its own to remove.
   Specificity alone carries this; this phase adds no override flag anywhere. */
@media (prefers-reduced-motion: reduce) {
    .ops-console .list-row {
        transition: none;
    }
}

/* ══ Phase 74 — phone ════════════════════════════════════════════════
   Staff app below 768px (74-UI-SPEC). Everything that targets existing
   selectors lives inside the media query so >= 768px is byte-for-byte
   unchanged. Tokens only; the one permitted hex values are the
   destructive pair UI-SPEC already names. */
@media (max-width: 767.98px) {
    .app-rail {
        display: none;
    }

    .staff-main {
        padding-left: 0 !important;
        padding-bottom: calc(var(--tabbar-height) + var(--safe-bottom)) !important;
    }

    .staff-page:not(:has(.page-frame)) {
        padding-left: 16px;
        padding-right: 16px;
    }
}
/* ── /Phase 74 — phone (T1) ───────────────────────────────────── */

/* ── Phase 74 — BottomSheet (new class names only; never media-gated because a sheet is only
      ever opened by a phone surface) ───────────────────────────────── */
.bottom-sheet-scrim {
    position: fixed;
    inset: 0;
    z-index: 1240;
    background: rgba(15, 21, 34, 0.48);
    animation: bottom-sheet-scrim-in 200ms linear;
}

.bottom-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1250;
    display: flex;
    flex-direction: column;
    max-height: 85vh;
    max-height: 85dvh;
    border-radius: 16px 16px 0 0;
    background: var(--bg-secondary);
    color: var(--text-primary);
    box-shadow: var(--shadow-lg);
    outline: none;
    animation: bottom-sheet-in 160ms cubic-bezier(0.4, 0, 0.2, 1);
    font-family: 'Outfit', sans-serif;
}

.bottom-sheet.bottom-sheet-full {
    height: 100vh;
    height: 100dvh;
    max-height: 100dvh;
    border-radius: 0;
}

.bottom-sheet-header {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 48px;
    padding: 8px 4px 0 16px;
    touch-action: none;
    user-select: none;
}

.bottom-sheet-grabber {
    position: absolute;
    top: 8px;
    left: 50%;
    width: 32px;
    height: 4px;
    margin-left: -16px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--text-tertiary) 50%, transparent);
}

.bottom-sheet-title {
    margin: 0;
    padding-top: 8px;
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--text-primary);
}

.bottom-sheet-close {
    width: 44px;
    height: 44px;
    margin-top: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.bottom-sheet-close:active {
    background: var(--row-hover);
}

.bottom-sheet-close:focus-visible,
.bottom-sheet-row:focus-visible,
.bottom-sheet-action:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.bottom-sheet-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0 16px 16px;
    padding-bottom: calc(16px + var(--safe-bottom));
}

.bottom-sheet-footer {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    padding: 8px 16px calc(16px + var(--safe-bottom));
    border-top: 1px solid var(--border-light);
}

.bottom-sheet-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 48px;
    margin: 0;
    padding: 0 16px;
    border: 0;
    border-bottom: 1px solid var(--border-light);
    background: none;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.45;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    box-sizing: border-box;
}

.bottom-sheet-list {
    margin: 0 -16px;
}

.bottom-sheet-row:active {
    background: var(--row-hover);
}

.bottom-sheet-row[aria-current="true"],
.bottom-sheet-row[aria-current="page"],
.bottom-sheet-row[aria-checked="true"],
.bottom-sheet-row.bottom-sheet-row-selected {
    background: var(--row-selected);
}

.bottom-sheet-row-label {
    flex: 1 1 auto;
    min-width: 0;
}

.bottom-sheet-row-selected .bottom-sheet-row-label,
.bottom-sheet-row[aria-current="page"] .bottom-sheet-row-label {
    color: var(--focus-ring);
    font-weight: 500;
}

.bottom-sheet-row-check {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    color: var(--focus-ring);
}

.bottom-sheet-row-chevron {
    flex: 0 0 auto;
    color: var(--text-tertiary);
}

.bottom-sheet-divider {
    height: 1px;
    margin: 8px 0;
    background: var(--border-light);
}

.bottom-sheet-action {
    min-height: 44px;
    padding: 0 16px;
    border: 0;
    border-radius: 8px;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    touch-action: manipulation;
    background: none;
    color: var(--text-primary);
}

.bottom-sheet-action-primary {
    width: 100%;
    background: var(--brand-on-surface, var(--accent-primary));
    color: var(--brand-on-surface-text, var(--mud-palette-background));
}

.bottom-sheet-skeleton {
    height: 48px;
    margin-bottom: 8px;
    border-radius: 8px;
    background: var(--bg-tertiary);
}

/* Short rise + fade rather than a full-height slide: a measured sheet box (and a swipe aimed at its header) must stay
   inside the 48px header while the open motion plays. Motion is still under prefers-reduced-motion's opacity-only form. */
@keyframes bottom-sheet-in {
    from { transform: translateY(24px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

@keyframes bottom-sheet-scrim-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .bottom-sheet {
        animation: bottom-sheet-fade 120ms linear;
    }

    .bottom-sheet-scrim {
        animation: none;
    }
}

@keyframes bottom-sheet-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ── Phase 74 — tab bar and More rows (T3) ─────────────────────── */
.bottom-tabs-list {
    list-style: none;
    margin: 0;
    padding: 0;
    height: var(--tabbar-height);
    display: flex;
}

.bottom-tabs-list > li {
    flex: 1 1 0;
    min-width: 44px;
    display: flex;
}

.bottom-tab {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 44px;
    height: var(--tabbar-height);
    padding: 0 2px;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    box-sizing: border-box;
}

.bottom-tab:active {
    background: var(--row-hover);
}

.bottom-tab:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.bottom-tab-icon {
    position: relative;
    display: inline-flex;
    width: 24px;
    height: 24px;
}

.bottom-tab-label {
    display: block;
    max-width: 100%;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    text-overflow: clip;
    overflow: visible;
}

.bottom-tab-active {
    color: var(--focus-ring);
}

.bottom-tab-active::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    width: 24px;
    height: 2px;
    margin-left: -12px;
    background: var(--focus-ring);
}

.bottom-tab-dot {
    position: absolute;
    top: -2px;
    right: -6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #C4443C;
    box-shadow: 0 0 0 2px var(--bg-secondary);
}

.bottom-sheet-row-dot {
    position: static;
    flex: 0 0 auto;
    box-shadow: none;
}

.bottom-tab-placeholder .bottom-tab {
    pointer-events: none;
}

@media (max-width: 767.98px) {
    .bottom-tabs {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1150;
        height: calc(var(--tabbar-height) + var(--safe-bottom));
        padding-bottom: var(--safe-bottom);
        background: var(--bg-secondary);
        border-top: 1px solid var(--border-light);
        box-sizing: border-box;
        transition: transform 100ms linear;
    }

    html[data-kb-open] .bottom-tabs {
        transform: translateY(100%);
        visibility: hidden;
    }
}

@media (min-width: 768px) {
    .bottom-tabs {
        display: none;
    }
}

/* ── Phase 74 — sheet form controls (new class names only) ─────── */
.bottom-sheet-note {
    margin: 0 0 8px;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.bottom-sheet-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.bottom-sheet-label {
    font-size: 12.5px;
    font-weight: 400;
    color: var(--text-secondary);
}

.bottom-sheet-input,
.bottom-sheet-search {
    box-sizing: border-box;
    width: 100%;
    min-height: 44px;
    padding: 0 12px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 1.4;
}

.bottom-sheet-search {
    margin-bottom: 8px;
}

.bottom-sheet-input:focus-visible,
.bottom-sheet-search:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 0;
}

.bottom-sheet-helper {
    margin: -8px 0 0;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.bottom-sheet-error {
    margin: 0;
    font-size: 12.5px;
    color: var(--mud-palette-error, #C4443C);
}

.bottom-sheet-row-destructive,
.bottom-sheet-row-destructive .bottom-sheet-row-label {
    color: var(--mud-palette-error, #C4443C);
}

.bottom-sheet-row .dot-label-dot {
    flex: 0 0 auto;
}

.time-form-only {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding-top: 8px;
}

.time-form-only .mud-input-control {
    width: 100%;
}

.time-form-only .mud-input-slot,
.time-form-only input,
.time-form-only textarea {
    font-size: 16px !important;
}

.time-form-only .mud-input-outlined-border,
.time-form-only .mud-input-root-outlined {
    min-height: 44px;
}

.time-form-only-actions {
    display: flex;
    gap: 8px;
}

.time-form-only-actions .bottom-sheet-action {
    flex: 1 1 0;
}

/* ── Phone chip row, composer, ticket page (T4/T5) ─────────────── */
.chip-row-wrap {
    position: relative;
}

.chip-row {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scroll-padding-left: 16px;
    scrollbar-width: none;
    padding: 0 16px;
    margin: 12px -16px 16px;
}

.chip-row::-webkit-scrollbar {
    display: none;
}

.chip-row-wrap::after {
    content: "";
    position: absolute;
    top: 12px;
    right: -16px;
    bottom: 16px;
    width: 16px;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--mud-palette-background, var(--bg-primary)));
}

.chip-row-chip {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    height: 44px;
    min-width: 44px;
    max-width: 60vw;
    padding: 0 12px;
    border: 1px solid var(--border-light);
    border-radius: 22px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.45;
    white-space: nowrap;
    scroll-snap-align: start;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

button.chip-row-chip:active {
    background: var(--row-hover);
}

.chip-row-chip:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.chip-row-chip-unset {
    border-style: dashed;
    color: var(--text-secondary);
}

.chip-row-chip-overdue {
    border-color: var(--mud-palette-error, #C4443C);
    color: var(--mud-palette-error, #C4443C);
    font-weight: 500;
}

.chip-row-chip-readonly {
    border: 0;
    background: none;
    padding: 0;
    cursor: default;
}

.chip-row-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.chip-row-plus {
    font-size: 16px;
    line-height: 1;
}

.chip-row-skeleton {
    flex: 0 0 auto;
    height: 44px;
    border-radius: 22px;
    background: var(--bg-tertiary);
}

.sticky-composer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--tabbar-height) + var(--safe-bottom) + 1px);
    z-index: 1160;
    box-sizing: border-box;
    min-height: 64px; /* collapsed floor; --composer-height is the MEASURED height (sticky-composer.js), 64px only until first measure */
    max-height: 40dvh;
    overflow-y: auto;
    padding: 9px 16px 10px;
    background: var(--bg-secondary);
    border-top: 1px solid var(--border-light);
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
}

html[data-kb-open] .sticky-composer {
    bottom: var(--kb-inset, 0px);
}

.ticket-composer-compact-row {
    display: flex;
    align-items: flex-end;
    gap: 6px;
}

.ticket-composer-compact-field {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
}

.ticket-composer-compact-input {
    display: block;
    box-sizing: border-box;
    width: 100%;
    min-height: 44px;
    max-height: 30dvh;
    margin: 0;
    padding: 10px 12px;
    border: 1px solid var(--border-light);
    border-radius: 22px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 1.4;
    resize: none;
    field-sizing: content;
}

.ticket-composer-compact-input:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 0;
}

.sticky-composer-log {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.sticky-composer-log:active {
    background: var(--row-hover);
}

.sticky-composer-log:focus-visible,
.ticket-composer-compact-post:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.ticket-composer-compact-post {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-width: 44px;
    height: 44px;
    padding: 0 12px;
    border: 0;
    border-radius: 22px;
    background: var(--brand-on-surface, var(--accent-primary));
    color: var(--brand-on-surface-text, var(--mud-palette-background));
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    touch-action: manipulation;
}

.ticket-composer-compact-post:disabled {
    opacity: 0.5;
    cursor: default;
}

.ticket-composer-compact-options {
    display: flex;
    align-items: center;
    min-height: 44px;
}

.ticket-composer-compact-switch {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex: 0 0 40px;
    width: 40px;
    height: 24px;
    margin: 0 12px 0 0;
    border-radius: 12px;
    background: var(--text-tertiary);
    cursor: pointer;
    transition: background-color 120ms linear;
}

.ticket-composer-compact-switch::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--bg-secondary);
    transition: transform 120ms linear;
}

.ticket-composer-compact-switch:checked {
    background: var(--brand-on-surface, var(--accent-primary));
}

.ticket-composer-compact-switch:checked::after {
    transform: translateX(16px);
}

.ticket-composer-compact-switch:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.ticket-composer-compact-switch-label {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
}

.ticket-composer-compact-helper {
    margin: 0 0 4px;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.ticket-composer-compact-mentions {
    position: absolute;
    left: 0;
    bottom: 100%;
    z-index: 1;
    min-width: 200px;
    max-height: 200px;
    overflow-y: auto;
}

.entity-page-phone-actions {
    width: 44px;
    height: 44px;
    flex: 0 0 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.entity-page-phone-actions:active {
    background: var(--row-hover);
}

@media (max-width: 767.98px) {
    body:has(.sticky-composer) .staff-main {
        padding-bottom: calc(var(--tabbar-height) + var(--composer-height) + var(--safe-bottom) + 16px) !important;
    }

    html[data-kb-open] body:has(.sticky-composer) .staff-main {
        padding-bottom: calc(var(--composer-height) + var(--kb-inset, 0px) + 16px) !important;
    }

    .entity-page-toolbar {
        padding: 0 4px 0 4px;
    }

    .entity-page-toolbar .entity-page-back {
        width: 44px;
        height: 44px;
        flex: 0 0 44px;
        border-radius: 22px;
    }

    .entity-page-breadcrumb {
        flex: 1 1 auto;
    }

    .entity-page-breadcrumb a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        min-width: 44px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .entity-page-toolbar .page-toolbar-spacer {
        flex: 0 0 0;
    }

    .entity-page-content {
        padding-left: 16px;
        padding-right: 16px;
    }

    .ticket-detail-view-page .tab-strip {
        height: 44px;
        gap: 16px;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .ticket-detail-view-page .tab-strip-tab {
        flex: 0 0 auto;
        height: 44px;
        min-width: 44px;
        touch-action: manipulation;
    }
}

/* ── Phase 74 — stacked rows, filter strip, audit, board, app bar, search, reports, snackbar (T6-T8) ── */
.audit-row-expand {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.audit-row-expand:active {
    background: var(--row-hover);
}

.audit-row-expand:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.board-column-switcher {
    position: sticky;
    top: var(--toolbar-height);
    z-index: 19;
    height: 44px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-light);
}

.board-column-switcher-tabs {
    display: flex;
    height: 100%;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
}

.board-column-switcher-tabs::-webkit-scrollbar {
    display: none;
}

.board-column-tab {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    box-sizing: border-box;
    min-width: 44px;
    height: 44px;
    padding: 0 14px;
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    scroll-snap-align: center;
    cursor: pointer;
    touch-action: manipulation;
}

.board-column-tab-selected {
    background: var(--row-selected);
    color: var(--text-primary);
    border-bottom-color: var(--focus-ring);
}

.board-column-tab:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.board-column-tab-count {
    font-size: 12.5px;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.phone-board-row {
    color: inherit;
    text-decoration: none;
}

.phone-board-add {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 44px;
    padding: 0 16px;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--border-light);
    color: var(--text-secondary);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    touch-action: manipulation;
}

.phone-board-add:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.phone-board-row-blocked {
    box-shadow: inset 4px 0 0 var(--blocked-amber);
}

.phone-board-blocked {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-weight: 500;
    /* Live palette mix (see .list-row-blocked-pill): holds in both themes without .mud-theme-dark. */
    color: color-mix(in srgb, var(--mud-palette-text-primary, #1D1924) 55%, #E8913A);
}

.phone-board-key {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.phone-board-due-overdue {
    color: var(--mud-palette-error, #C4443C);
    font-weight: 500;
}

.board-phone-header {
    margin-bottom: 12px;
}

.board-phone-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
}

.board-phone-back,
.board-phone-add {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    box-sizing: border-box;
    height: 44px;
    min-width: 44px;
    padding: 0 14px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: none;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
}

.board-phone-back-label {
    pointer-events: none;
}

.board-phone-back:focus-visible,
.board-phone-add:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.phone-search-button {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.phone-search-button:active {
    background: var(--row-hover);
}

.phone-search-button:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.command-palette-close-search {
    flex: 0 0 auto;
    min-width: 44px;
    height: 44px;
    padding: 0 12px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--focus-ring);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
}

@media (max-width: 767.98px) {
    /* Stacked two-line list rows (D-10). Scoped to the staff shell so the portal's ListGroup is untouched, and the
       ops console keeps its own bespoke reflow. */
    .staff-main:not(:has(.ops-console)) .list-row {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        column-gap: 12px;
        row-gap: 4px;
        align-items: center;
        align-content: center;
        box-sizing: border-box;
        height: auto;
        min-height: 56px;
        padding: 12px 16px;
    }

    .staff-main:not(:has(.ops-console)) .list-row:has(.list-row-key:not(:empty)) {
        min-height: 64px;
    }

    .staff-main:not(:has(.ops-console)) .list-row-title {
        grid-row: 1;
        grid-column: 1 / 3;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        white-space: normal;
        overflow: hidden;
        line-height: 1.3;
        overflow-wrap: anywhere;
    }

    .staff-main:not(:has(.ops-console)) .list-row-trailing {
        grid-row: 1;
        grid-column: 3;
        justify-self: end;
    }

    .staff-main:not(:has(.ops-console)) .list-row-key {
        grid-row: 2;
        grid-column: 1;
        flex: none;
        /* A long project key never widens the row: cap the key cell and ellipsise it. */
        min-width: 0;
        max-width: 42vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .staff-main:not(:has(.ops-console)) .list-row-key:empty {
        display: none;
    }

    .staff-main:not(:has(.ops-console)) .list-row-meta {
        grid-row: 2;
        grid-column: 2 / 4;
        position: relative;
        /* Block + inline children so text-overflow draws an ellipsis inside the 16px gutter. */
        display: block;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .staff-main:not(:has(.ops-console)) .list-row-meta > * {
        display: inline-flex;
        vertical-align: middle;
        margin-right: 8px;
    }

    /* Text-only cells flow as plain inline text so text-overflow can draw the ellipsis (atomic inline boxes clip hard). */
    .staff-main:not(:has(.ops-console)) .list-row-meta > *:not(:has(*)) {
        display: inline;
    }

    .staff-main:not(:has(.ops-console)) .list-row-key:empty + .list-row-title + .list-row-meta {
        grid-column: 1 / 4;
    }

    /* Priority text stays in the accessibility tree; only the dot shows (visually-hidden clip, not display:none). */
    .staff-main:not(:has(.ops-console)) .list-row .dot-label-text {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }

    .audit-row-detail {
        grid-column: 1 / -1;
        grid-row: 3;
        min-width: 0;
    }

    /* Phase 74 heal: raw palette error/success measured 4.27:1 (light) / 4.16:1 (dark) on the
       row surface at 11px. Mixing toward --text-primary darkens in light and lightens in dark,
       clearing AA 4.5:1 in both themes; phone-only (.audit-row-detail exists only here). */
    .audit-row-detail .audit-value-label-old {
        color: color-mix(in srgb, var(--mud-palette-error) 65%, var(--text-primary)) !important;
    }

    .audit-row-detail .audit-value-label-new {
        color: color-mix(in srgb, var(--mud-palette-success) 65%, var(--text-primary)) !important;
    }

    .audit-row-detail .audit-json {
        max-width: 100%;
        overflow-x: auto;
    }

    .list-group-container.audit-phone-list {
        width: 100%;
    }

    /* FilterStrip: one non-wrapping, horizontally scrolling row of 44px chips with a right-edge fade. */
    .filter-strip {
        --chip-height: 44px;
        height: auto;
        min-height: 52px;
        padding: 4px 16px;
        /* The group/sort text drops to its own row when it cannot sit beside the chips, so it never covers a chip. */
        flex-wrap: wrap;
        row-gap: 0;
    }

    .filter-strip-meta {
        min-width: 0;
        max-width: 100%;
        margin-left: auto;
    }

    .filter-strip-meta .filter-strip-text-button,
    .filter-strip-meta .filter-strip-text {
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .filter-strip-chips {
        flex: 1 1 auto;
        max-width: 100%;
        min-width: 0;
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 16px), transparent);
        mask-image: linear-gradient(to right, #000 calc(100% - 16px), transparent);
    }

    .filter-strip-text-button {
        min-height: 44px;
        min-width: 44px;
    }

    /* App bar */
    .page-toolbar {
        padding: 0 16px;
    }

    .page-toolbar-phone .page-toolbar-title {
        display: flex;
        align-items: baseline;
        flex: 0 1 auto;
        min-width: 0;
    }

    .page-toolbar-phone .page-toolbar-title-text {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .page-toolbar-phone .page-toolbar-count {
        flex: 0 0 auto;
        white-space: nowrap;
    }

    .page-toolbar-phone .page-toolbar-primary-action {
        flex: 0 0 auto;
    }

    .page-toolbar-phone .page-toolbar-primary-action button,
    .page-toolbar-phone .page-toolbar-primary-action .mud-button-root {
        height: 44px !important;
        min-width: 44px !important;
        padding: 0 16px !important;
        white-space: nowrap !important;
        flex-shrink: 0;
    }

    .page-toolbar-phone .page-toolbar-primary-action .mud-button-label {
        white-space: nowrap;
    }

    .page-toolbar-phone-subrow {
        display: flex;
        align-items: center;
        padding: 8px 16px;
        background: var(--bg-secondary);
        border-bottom: 1px solid var(--border-light);
    }

    .page-toolbar-phone-subrow .view-toggle,
    .page-toolbar-phone-subrow .view-toggle-segment {
        height: 44px;
    }

    .page-toolbar-phone-subrow .view-toggle-segment {
        min-width: 44px;
        touch-action: manipulation;
    }

    /* Palette: full-screen sheet */
    .command-palette-scrim {
        display: none;
    }

    .command-palette-dialog {
        top: 0;
        left: 0;
        transform: none;
        width: 100vw;
        max-width: none;
        height: 100vh;
        height: 100dvh;
        max-height: none;
        border: 0;
        border-radius: 0;
    }

    .command-palette-input-row {
        min-height: 56px;
    }

    .command-palette-input {
        font-size: 16px;
    }

    .command-palette-results {
        flex: 1 1 auto;
        max-height: none;
        overflow-y: auto;
    }

    .command-palette-item {
        min-height: 48px;
    }

    /* Reports */
    .time-report-filters > .mud-stack {
        flex-direction: column !important;
        align-items: stretch !important;
    }

    .time-report-filters > .mud-stack > .mud-stack {
        flex-direction: row !important;
        flex-wrap: nowrap !important;
    }

    .time-report-filters .mud-select,
    .time-report-filters .mud-input-control {
        min-width: 0 !important;
        max-width: none !important;
        width: 100%;
    }

    .time-report-filters .mud-button-root {
        flex: 1 1 0;
        min-height: 44px;
        white-space: nowrap;
    }

    .time-report-filters .mud-button-label {
        white-space: nowrap;
    }

    /* Snackbar sits above the tab bar, and above the sticky composer where one is mounted (D-13). */
    #mud-snackbar-container {
        left: 16px !important;
        right: 16px !important;
        bottom: calc(var(--tabbar-height) + var(--safe-bottom) + 8px) !important;
        z-index: 1400 !important;
    }

    body:has(.sticky-composer) #mud-snackbar-container {
        bottom: calc(var(--tabbar-height) + var(--composer-height) + var(--safe-bottom) + 8px) !important;
    }

    html[data-kb-open] #mud-snackbar-container {
        bottom: calc(var(--kb-inset, 0px) + var(--composer-height) + 8px) !important;
    }

    #mud-snackbar-container .mud-snackbar {
        width: calc(100vw - 32px);
        max-width: none;
    }

    #mud-snackbar-container .mud-snackbar .mud-button-root,
    #mud-snackbar-container .mud-snackbar .mud-icon-button {
        min-width: 44px;
        min-height: 44px;
    }

    /* Message-box dialogs */
    .mud-dialog {
        width: calc(100vw - 32px);
    }

    .mud-dialog .mud-button-root {
        min-height: 44px;
    }
}

@media (max-width: 767.98px) {
    /* A label whose line box equals its glyph box reads as exactly one line to a text-range measurement. */
    .page-toolbar-phone .page-toolbar-primary-action .mud-button-label,
    .time-report-filters .mud-button-label {
        line-height: normal;
    }

    .time-report-filters .mud-button-icon-start {
        display: none;
    }

    /* MudBlazor's ripple ::after rests at scale(10) and counts toward scrollWidth; the resting ripple is kept inside its own box so a button's scrollWidth equals its clientWidth. */
    .page-toolbar-phone .page-toolbar-primary-action .mud-ripple:not(:active)::after,
    .time-report-filters .mud-ripple:not(:active)::after {
        transform: none !important;
    }

    /* The ViewToggle sub-row is a child of the banner, overlaid directly below the 48px bar; the header reserves its
       height so content and the sticky FilterStrip start beneath it. */
    .page-toolbar-phone-subrow {
        position: absolute;
        left: 0;
        right: 0;
        top: 100%;
        height: 60px;
        box-sizing: border-box;
    }

    .page-toolbar-phone:has(.page-toolbar-phone-subrow) {
        margin-bottom: 60px;
    }

    .page-toolbar-phone:has(.page-toolbar-phone-subrow) ~ .filter-strip {
        top: calc(var(--toolbar-height) + 60px);
    }
}


/* Phone: report date-preset chips are interactive, so they meet the 44px target (D-09). */
@media (max-width: 767.98px) {
    .date-shortcuts .mud-chip {
        min-height: 44px;
        height: 44px !important;
        min-width: 44px;
        padding: 0 14px;
        font-size: 0.8125rem !important;
    }
}

/* Phone, narrowest widths (<= 380px): the full "Post comment" label stays visible; tighten its type/padding so the one-line editor keeps its whole placeholder at 360. */
@media (max-width: 380px) {
    .ticket-composer-compact-post {
        padding: 0 10px;
        font-size: 13px;
    }
}

/* Phase 75 — client page */
.client-page {
    display: flex;
    flex-direction: column;
    gap: 24px;
    min-width: 0;
}

.client-header {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.client-header-title-row {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
}

.client-header-title-row .ticket-detail-title {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    overflow-wrap: anywhere;
}

.client-header-status {
    margin-top: -4px;
}

.client-header-actions {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 22px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    touch-action: manipulation;
}

.client-header-actions:active {
    background: var(--row-hover);
}

.client-header-actions:focus-visible,
.client-section-action:focus-visible,
.portal-link-copy:focus-visible,
.client-row-link:focus-visible,
.progress-row:focus-visible,
.client-row-actions:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.client-section {
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 10px;
    overflow: hidden;
}

.mud-theme-dark .client-section {
    background: #161E2E !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}

.client-section-header {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 0 16px;
}

.client-section-title {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--text-primary);
    margin: 0;
}

.client-section-count {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-tertiary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.client-section-spacer {
    flex: 1 1 auto;
}

.client-section-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    padding: 0 8px;
    background: none;
    border: none;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}

.client-section-action:hover {
    text-decoration: underline;
}

.client-section-action-outline {
    border: 1px solid var(--border-light);
    border-radius: 8px;
}

.client-section-body .error-banner {
    margin: 0 16px 16px;
}

.client-section-body .empty-state-shell {
    padding: 16px;
}

.client-section-skeleton {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.client-section-skeleton-row {
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

.client-section-footer {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 16px;
}

/* Usage bar */
.usage-bar {
    flex: 1 1 auto;
    min-width: 0;
    height: 8px;
    border-radius: 4px;
    background: var(--bg-tertiary);
    overflow: hidden;
}

.usage-bar-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 150ms ease;
}

/* Progress row (Projects) */
.progress-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 56px;
    padding: 12px 16px;
    border-top: 1px solid var(--border-light);
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    box-sizing: border-box;
}

.progress-row:hover {
    background: var(--row-hover);
}

.progress-row-line {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.progress-row-key {
    flex: 0 0 68px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.progress-row-name {
    flex: 1 1 auto;
    min-width: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.progress-row-status {
    flex: 0 0 auto;
    font-size: 12.5px;
}

.progress-row-tickets-caption {
    flex: 0 0 auto;
    min-width: 120px;
    text-align: right;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.progress-row-chevron {
    flex: 0 0 auto;
    color: var(--text-tertiary);
}

.progress-row-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-left: 80px;
    min-width: 0;
}

.progress-row-budget-caption,
.budget-row-caption {
    flex: 0 0 auto;
    min-width: 160px;
    text-align: right;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.progress-row-budget-over,
.budget-row-caption.progress-row-budget-over {
    color: var(--mud-palette-error, #BF423A);
    font-weight: 500;
}

/* Hours vs budget */
.budget-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px;
    border-top: 1px solid var(--border-light);
}

.budget-row-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.budget-row-name {
    min-width: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.budget-row-period {
    flex: 0 0 auto;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.budget-row-bar {
    display: flex;
    align-items: center;
    gap: 12px;
}

.hours-figure {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px 16px;
}

.hours-figure-label {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.hours-figure-value {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.hours-figure-helper {
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* Compact rows: open requests, waiting, portal users, status update */
.client-row {
    display: grid;
    grid-template-columns: 92px minmax(0, 1fr) auto auto;
    align-items: center;
    column-gap: 12px;
    row-gap: 4px;
    min-height: 40px;
    padding: 8px 16px;
    border-top: 1px solid var(--border-light);
    box-sizing: border-box;
    color: inherit;
    text-decoration: none;
}

a.client-row-link {
    cursor: pointer;
}

.client-user-row {
    grid-template-columns: minmax(0, 1fr) auto;
}

.client-user-name {
    grid-column: 1;
    grid-row: 1;
    white-space: normal;
}

.client-user-actions {
    grid-column: 2;
    grid-row: 1;
}

.client-user-meta {
    grid-column: 1 / -1;
    grid-row: 2;
}

a.client-row-link:hover {
    background: var(--row-hover);
}

.client-row-key {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.client-row-title {
    min-width: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.client-row-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.client-row-meta-overdue,
.client-row-meta-aged,
.client-row-meta-warn {
    color: var(--mud-palette-error, #BF423A);
    font-weight: 500;
}

.client-row-trailing {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    color: var(--text-tertiary);
}

.client-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 11px;
    font-weight: 500;
}

.client-row-actions {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 16px;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 16px;
}

.client-row-actions:hover {
    background: var(--row-hover);
}

.client-row-edit {
    display: flex;
    align-items: center;
    gap: 8px;
}

.client-row-edit input {
    flex: 1 1 auto;
    min-width: 0;
    height: 32px;
    padding: 0 8px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
}

.status-update-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px;
    border-top: 1px solid var(--border-light);
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.status-update-row:hover {
    background: var(--row-hover);
}

.status-update-excerpt {
    margin: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.5;
    color: var(--text-secondary);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Clients list row */
.client-row-open-count {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.client-row-open-count-zero {
    color: var(--text-tertiary);
}

/* Portal link field */
.portal-link-field {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
}

.portal-link-value {
    min-width: 0;
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.portal-link-copy {
    height: 32px;
    padding: 0 12px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
}

.mud-theme-dark .portal-link-copy {
    background: #161E2E !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}

.portal-link-error {
    flex: 1 1 100%;
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    color: var(--mud-palette-error, #BF423A);
}

/* Credentials */
.client-credentials-grid {
    padding: 0 8px 8px;
}

.client-credential-secret {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 14px;
    overflow-wrap: anywhere;
}

.client-sheet-row {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 48px;
    padding: 0 16px;
    border: 0;
    border-bottom: 1px solid var(--border-light);
    background: none;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
}

.client-sheet-row-destructive {
    color: var(--mud-palette-error, #BF423A);
}

.client-sheet-row:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.client-sheet-secret {
    margin: 12px 16px;
    padding: 12px;
    border-radius: 8px;
    background: var(--bg-tertiary);
}

@media (prefers-reduced-motion: reduce) {
    .usage-bar-fill {
        transition: none !important;
    }
}

@media (max-width: 767.98px) {
    .client-page {
        gap: 16px;
    }

    .client-section-header {
        min-height: 48px;
    }

    .client-section-action,
    .portal-link-copy,
    .client-section-body .empty-state-action {
        min-height: 44px;
        min-width: 44px;
    }

    .client-row-actions {
        width: 44px;
        height: 44px;
        border-radius: 22px;
    }

    .progress-row {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        column-gap: 8px;
        row-gap: 4px;
        min-height: 72px;
    }

    .progress-row-line {
        display: contents;
    }

    .progress-row-name {
        grid-column: 1 / 3;
        grid-row: 1;
        white-space: normal;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
    }

    .progress-row-chevron {
        grid-column: 3;
        grid-row: 1;
    }

    .progress-row-key {
        grid-column: 1;
        grid-row: 2;
        flex-basis: auto;
    }

    .progress-row-status {
        grid-column: 2 / 4;
        grid-row: 2;
    }

    .progress-row > .progress-row-bar:not(.progress-row-budget) {
        grid-column: 1 / -1;
        grid-row: 3;
    }

    .progress-row-tickets-caption {
        grid-column: 1 / -1;
        grid-row: 4;
        min-width: 0;
        text-align: left;
    }

    .progress-row-budget {
        grid-column: 1 / -1;
    }

    .progress-row-bar,
    .budget-row-bar {
        flex-direction: column;
        align-items: stretch;
        gap: 4px;
        padding-left: 0;
    }

    .progress-row-budget-caption,
    .budget-row-caption {
        min-width: 0;
        text-align: left;
        white-space: normal;
    }

    .client-row {
        grid-template-columns: auto minmax(0, 1fr) auto;
        min-height: 56px;
        padding: 12px 16px;
    }

    .client-row-title {
        grid-column: 1 / 3;
        grid-row: 1;
        white-space: normal;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
    }

    .client-row-key {
        grid-column: 1;
        grid-row: 2;
    }

    .client-row-meta {
        grid-column: 2 / 4;
        grid-row: 2;
    }

    .client-row-trailing {
        grid-column: 3;
        grid-row: 1;
    }

    .client-user-row {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .client-user-name {
        grid-column: 1;
        grid-row: 1;
    }

    .client-user-meta {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .client-user-actions {
        grid-column: 2;
        grid-row: 1;
    }

    .client-section-footer {
        min-height: 44px;
        padding-bottom: 8px;
    }

    .client-page .tab-strip {
        height: 44px;
        gap: 16px;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .client-page .tab-strip-tab {
        flex: 0 0 auto;
        height: 44px;
        min-width: 44px;
        touch-action: manipulation;
    }

    .client-page .meta-grid-value a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        min-width: 44px;
    }
}

/* Quick 261005-cro: Manager+ credential grid rows open the credential on click. */
.credential-row-clickable,
.credential-row-clickable td {
    cursor: pointer;
}
/* Phase 76 — time surface */
.time-page .time-panel {
    padding: 16px 24px 32px;
}

.time-panel-skeleton > div,
.time-grid-skeleton > div,
.week-drill-skeleton > div {
    height: 40px;
    margin-bottom: 8px;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

.time-panel .error-banner {
    margin: 16px 0 0;
}

.time-note {
    margin: 16px 0 0;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.time-page .tab-strip-panel {
    outline: none;
}

/* Tab strip aligns with the page content gutter (same 24px as .time-panel). */
.time-page .tab-strip {
    margin: 0 24px;
    width: auto;
}

/* period bar */
.time-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 16px;
    min-height: var(--filterstrip-height);
    padding: 4px 8px;
    margin-bottom: 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 8px;
}

.time-nav-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.time-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.time-nav-btn:hover {
    background: var(--row-hover);
}

.time-nav-controls > .time-nav-btn:first-child svg {
    transform: rotate(180deg);
}

.time-nav-label {
    min-width: 150px;
    text-align: center;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.45;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.time-nav-current {
    height: 32px;
    padding: 0 12px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
}

.time-nav-current:hover:not(:disabled) {
    background: var(--row-hover);
}

.time-nav-current:disabled {
    color: var(--text-secondary);
    cursor: default;
}

.time-nav-total {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.time-nav-total-label {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.time-nav-total-value {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--text-primary);
}

.time-nav-total-zero .time-nav-total-value {
    color: var(--text-tertiary);
}

/* week grid (desktop) */
.week-grid-wrap {
    overflow: visible;
}

.week-grid-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 8px;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.week-grid-table th,
.week-grid-table td {
    padding: 0 12px;
    height: 40px;
    border-bottom: 1px solid var(--border-light);
    text-align: right;
    font-weight: 400;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.week-grid-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    height: 48px;
    background: var(--bg-secondary);
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--text-secondary);
}

.week-grid-table thead th.week-grid-today {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.week-grid-table thead th.week-grid-weekend {
    color: var(--text-secondary);
}

.week-grid-table thead th .week-grid-day-name {
    color: var(--text-primary);
}

.week-grid-table thead th.week-grid-weekend .week-grid-day-name {
    color: var(--text-secondary);
}

.week-grid-day-name,
.week-grid-day-num {
    display: block;
}

.week-grid-person-head,
.week-grid-person {
    width: 200px;
    text-align: left !important;
    font-weight: 500 !important;
    background: var(--bg-secondary);
}

.week-grid-total-head,
.week-grid-total {
    width: 80px;
    border-left: 1px solid var(--border-light);
    font-weight: 500 !important;
}

.week-grid-total-zero {
    color: var(--text-tertiary) !important;
}

.week-grid-you {
    font-weight: 400;
    color: var(--text-secondary);
}

.week-grid-cell {
    position: relative;
    cursor: default;
}

.week-grid-cell.week-grid-today,
.week-grid-foot-cell.week-grid-today {
    background: color-mix(in srgb, var(--bg-tertiary) 50%, transparent);
}

.week-grid-cell-active {
    cursor: pointer;
}

.week-grid-cell-active:hover {
    background: var(--row-hover);
}

.week-grid-cell-dash {
    color: var(--text-tertiary);
}

.week-grid-cell-open {
    background: var(--row-selected) !important;
    box-shadow: inset 0 0 0 2px var(--focus-ring);
}

.week-grid-meter {
    position: absolute;
    right: 12px;
    bottom: 4px;
    height: 2px;
    background: var(--text-tertiary);
    opacity: 0.6;
}

.week-grid-table [tabindex]:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.week-grid-table tfoot th,
.week-grid-table tfoot td {
    font-weight: 500;
    border-bottom: none;
}

.week-drill > td {
    padding: 0 !important;
    height: auto !important;
    white-space: normal !important;
    text-align: left !important;
    background: var(--bg-secondary);
}

.week-drill-body {
    padding: 16px;
    max-height: 352px;
    overflow-y: auto;
}

.week-drill-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 32px;
}

.week-drill-title {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
}

.week-drill-close {
    height: 32px;
    padding: 0 8px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
}

.week-drill-close:hover {
    text-decoration: underline;
}

.week-drill-sub {
    margin: 0 0 8px;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.week-drill-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.week-drill-entry {
    display: grid;
    grid-template-columns: 68px minmax(0, 1fr) minmax(0, 220px) 64px;
    align-items: center;
    column-gap: 12px;
    min-height: 40px;
    border-top: 1px solid var(--border-light);
}

.week-drill-key {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
}

.week-drill-key:hover,
.week-drill-key:focus-visible {
    text-decoration: underline;
}

.week-drill-ticket {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
}

.week-drill-project {
    font-size: 12.5px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.week-drill-hours {
    text-align: right;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.week-drill-desc {
    grid-column: 2 / -1;
    padding-bottom: 8px;
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* week grid (phone) */
.week-phone-row {
    min-height: 96px;
    padding: 12px 16px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-light);
}

.week-phone-line1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 20px;
    margin-bottom: 8px;
    font-size: 14px;
    font-weight: 500;
}

.week-phone-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
}

.week-phone-total {
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.week-phone-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
}

.week-phone-day {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: none;
    background: transparent;
    font-family: 'Outfit', sans-serif;
    color: var(--text-primary);
    touch-action: manipulation;
}

button.week-phone-day {
    cursor: pointer;
}

.week-phone-day-label {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-primary);
}

.week-phone-day-label.week-phone-day-weekend {
    color: var(--text-secondary);
}

.week-phone-day-value {
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.week-phone-day-zero .week-phone-day-value {
    color: var(--text-tertiary);
}

.week-phone-day-today {
    background: var(--bg-tertiary);
}

.week-phone-day-today .week-phone-day-label {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 2px;
    color: var(--text-primary);
}

@media (max-width: 767.98px) {
    .time-page .time-panel {
        padding: 16px 16px 32px;
    }

    .time-nav {
        min-height: 48px;
    }

    .time-nav-btn {
        width: 44px;
        height: 44px;
    }

    .time-nav-current {
        min-height: 44px;
    }

    .time-nav-label {
        min-width: 0;
    }

    .time-page .tab-strip {
        margin: 0 16px;
        height: 44px;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .time-page .tab-strip-tab {
        flex: 0 0 auto;
        height: 44px;
        min-width: 44px;
        touch-action: manipulation;
    }

    .week-phone {
        margin: 0 -16px;
    }

    .week-drill-entry {
        grid-template-columns: 68px minmax(0, 1fr) 64px;
        min-height: 64px;
        row-gap: 4px;
        padding: 12px 0;
    }

    .week-drill-project {
        grid-column: 2;
        grid-row: 2;
    }

    .week-drill-desc {
        grid-column: 2 / -1;
        padding-bottom: 0;
    }

    .week-drill-key {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .time-panel-skeleton > div,
    .time-grid-skeleton > div,
    .week-drill-skeleton > div {
        background-size: 200% 100%;
        animation: time-shimmer 1.4s linear infinite;
    }
}

@keyframes time-shimmer {
    from { background-position: 200% 0; }
    to { background-position: -200% 0; }
}

@media (min-width: 768px) and (max-width: 1023.98px) {
    .week-grid-person-head,
    .week-grid-person {
        width: 160px;
    }
}

/* My timesheet */
.time-date-input {
    width: 168px;
}

.time-date-input .mud-input-label {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

.time-date-input .mud-input-outlined-border legend {
    display: none;
}

.timesheet-ribbon {
    display: grid;
    grid-template-columns: repeat(7, minmax(88px, 1fr));
    margin-bottom: 16px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    overflow: hidden;
}

.timesheet-ribbon-day {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    height: 56px;
    padding: 0;
    border: none;
    border-right: 1px solid var(--border-light);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    cursor: pointer;
}

.timesheet-ribbon-day:last-child {
    border-right: none;
}

.timesheet-ribbon-day:hover {
    background: var(--row-hover);
}

.timesheet-ribbon-day-selected {
    background: var(--row-selected);
    box-shadow: inset 0 -2px 0 var(--focus-ring);
}

.timesheet-ribbon-label {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.timesheet-ribbon-label.timesheet-ribbon-weekend {
    color: var(--text-secondary);
}

.timesheet-ribbon-hours {
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}

.timesheet-ribbon-zero {
    color: var(--text-tertiary);
}

.timesheet-list {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 8px;
}

.timesheet-row {
    display: flex;
    align-items: center;
    min-height: 40px;
    border-bottom: 1px solid var(--border-light);
}

.timesheet-row:last-child {
    border-bottom: none;
}

.timesheet-row:hover {
    background: var(--row-hover);
}

.timesheet-row-main {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: 76px minmax(0, 1fr) minmax(0, 1.4fr) 64px;
    align-items: center;
    column-gap: 12px;
    padding: 0 12px 0 16px;
    min-height: 40px;
    color: inherit;
    text-decoration: none;
}

.timesheet-key {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.timesheet-title {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
}

.timesheet-meta {
    font-size: 12.5px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.timesheet-hours {
    text-align: right;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.timesheet-actions {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin-right: 8px;
    padding: 0;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.timesheet-actions:hover {
    background: var(--row-hover);
}

.timesheet-destructive {
    color: #C4443C;
}

.mud-theme-dark .timesheet-destructive,
.mud-theme-dark .timesheet-sheet-destructive {
    color: #E0605A !important;
}

.timesheet-group {
    margin-bottom: 16px;
}

.timesheet-group-head {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding: 0 16px;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.timesheet-scope {
    margin: 8px 0 16px;
}

.timesheet-sheet-actions {
    display: flex;
    flex-direction: column;
}

.timesheet-sheet-action {
    min-height: 48px;
    padding: 0 16px;
    border: none;
    border-bottom: 1px solid var(--border-light);
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    text-align: left;
}

.timesheet-sheet-destructive {
    color: #C4443C;
}

.mud-dialog .error-banner {
    margin: 0 0 16px;
}

@media (max-width: 767.98px) {
    .time-date-input {
        width: 168px;
    }

    .time-date-input .mud-input-control,
    .time-date-input .mud-input-slot,
    .time-date-input .mud-input-adornment-end button {
        min-height: 44px;
    }

    .time-date-input input {
        font-size: 16px;
    }

    .timesheet-ribbon {
        grid-template-columns: repeat(7, minmax(0, 1fr));
    }

    .timesheet-ribbon-day {
        height: 48px;
        min-width: 44px;
    }

    .timesheet-ribbon-label,
    .timesheet-ribbon-hours {
        font-size: 11px;
    }

    .timesheet-row {
        min-height: 64px;
    }

    .timesheet-row-main {
        grid-template-columns: minmax(0, 1fr) 64px;
        grid-template-rows: auto auto;
        row-gap: 2px;
        padding: 12px 8px 12px 16px;
    }

    .timesheet-title {
        grid-column: 1;
        grid-row: 1;
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }

    .timesheet-hours {
        grid-column: 2;
        grid-row: 1;
    }

    .timesheet-key {
        grid-column: 1;
        grid-row: 2;
    }

    .timesheet-meta {
        display: none;
    }

    .timesheet-actions {
        flex: 0 0 44px;
        width: 44px;
        min-width: 44px;
        height: 44px;
        margin-right: 0;
    }
}

/* Export */
.export-filterbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
    padding: 16px;
    margin-bottom: 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 10px;
}

.export-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.export-field-label {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.export-groupby {
    display: inline-flex;
    height: 32px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    overflow: hidden;
    background: var(--bg-secondary);
}

.export-groupby-seg {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 32px;
    padding: 0 12px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    cursor: pointer;
}

.export-groupby-seg-selected {
    background: var(--row-selected);
    color: var(--text-primary);
    font-weight: 500;
}

.export-groupby-check {
    display: inline-flex;
    color: var(--focus-ring);
}

.export-date {
    width: 160px;
}

.export-select {
    position: relative;
    width: 180px;
}

.export-shortcuts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.export-shortcut {
    height: 26px;
    padding: 0 8px;
    border: 1px solid var(--border-light);
    border-radius: 13px;
    background: transparent;
    color: var(--text-secondary);
    font-family: 'Outfit', sans-serif;
    font-size: 12.5px;
    cursor: pointer;
}

.export-shortcut:hover {
    background: var(--row-hover);
}

.export-shortcut-pressed {
    background: var(--row-selected);
    color: var(--text-primary);
    font-weight: 500;
}

.export-actions {
    display: flex;
    gap: 8px;
    margin-left: auto;
    align-items: center;
}

.export-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding: 0 16px;
    border: 1px solid var(--border-light);
    border-radius: 8px;
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
}

.export-action:hover:not(:disabled) {
    background: var(--row-hover);
}

.export-action:disabled {
    color: var(--text-tertiary);
    cursor: not-allowed;
}

.export-spinner {
    width: 16px;
    height: 16px;
    border: 2px solid var(--border-light);
    border-top-color: var(--text-secondary);
    border-radius: 50%;
}

@media (prefers-reduced-motion: no-preference) {
    .export-spinner {
        animation: time-spin 0.8s linear infinite;
    }
}

@keyframes time-spin {
    to { transform: rotate(360deg); }
}

.export-skeleton > div {
    height: 40px;
    margin-bottom: 8px;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--row-hover) 50%, var(--bg-tertiary) 75%);
}

.export-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 24px;
    margin-bottom: 16px;
}

.export-summary-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.export-summary-label {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.export-summary-value {
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.export-summary-range {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.export-columns,
.export-entry {
    display: grid;
    grid-template-columns: 24px 104px 88px minmax(0, 1fr) 180px 64px;
    column-gap: 12px;
    align-items: center;
}

.export-columns {
    padding: 0 16px 8px;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
}

.export-col-hours,
.export-entry-hours {
    text-align: right;
}

.export-group {
    background: var(--bg-secondary);
    border: 1px solid var(--border-light);
    border-radius: 8px;
    margin-bottom: 8px;
    overflow: hidden;
}

.export-group-head {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 40px;
    padding: 0 16px;
    border: none;
    background: transparent;
    color: var(--text-primary);
    font-family: 'Outfit', sans-serif;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
}

.export-group-head:hover {
    background: var(--row-hover);
}

.export-group-sub {
    padding-left: 40px;
}

.export-chevron {
    display: inline-flex;
    width: 16px;
    color: var(--text-secondary);
}

.export-chevron-open svg {
    transform: rotate(90deg);
}

.export-group-name {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.export-group-meta {
    font-size: 12.5px;
    color: var(--text-secondary);
    flex: 1 1 auto;
}

.export-group-hours {
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

.export-entry {
    padding: 8px 16px;
    min-height: 40px;
    border-top: 1px solid var(--border-light);
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.export-entry-date,
.export-entry-ticket {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.export-entry-desc,
.export-entry-who {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.export-entry-who {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.export-entry-hours {
    font-weight: 500;
}

@media (max-width: 767.98px) {
    .export-filterbar {
        flex-direction: column;
        align-items: stretch;
        gap: 16px;
    }

    .export-groupby,
    .export-groupby-seg {
        height: 44px;
    }

    .export-groupby {
        display: flex;
    }

    .export-groupby-seg {
        flex: 1 1 0;
        justify-content: center;
    }

    .export-date,
    .export-select {
        width: 100%;
    }

    .export-filterbar .mud-input-control,
    .export-filterbar .mud-input-slot,
    .export-filterbar .mud-input-adornment-end button,
    .export-filterbar .mud-input-control button {
        min-height: 44px;
        min-width: 44px;
    }

    .export-filterbar input {
        font-size: 16px;
    }

    .export-filterbar > * {
        min-width: 0;
        max-width: 100%;
    }

    .export-shortcuts {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .export-shortcut {
        flex: 0 0 auto;
        height: 44px;
        padding: 0 16px;
        border-radius: 22px;
    }

    .export-actions {
        flex-direction: column;
        align-items: stretch;
        margin-left: 0;
    }

    .export-action {
        justify-content: center;
        height: 44px;
    }

    .export-group-head {
        min-height: 48px;
    }

    .export-entry {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
        min-height: 48px;
        padding: 8px 16px;
    }

    .export-entry-desc {
        white-space: normal;
        font-size: 12.5px;
        color: var(--text-secondary);
    }
}

/* Ticket Time tab header + Today footer */
.ticket-time-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 32px;
    margin-bottom: 8px;
}

.ticket-time-total {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ticket-time-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--text-secondary);
    font-size: 14px;
    text-decoration: none;
}

.ticket-time-link:hover,
.ticket-time-link:focus-visible {
    text-decoration: underline;
}

.ticket-time-link-arrow {
    display: inline-flex;
}

.today-time-footer {
    display: flex;
    align-items: center;
    min-height: 32px;
    padding: 0 16px;
    border-top: 1px solid var(--border-light);
    color: var(--text-secondary);
    font-size: 12.5px;
    font-weight: 500;
    text-decoration: none;
}

.today-time-footer:hover,
.today-time-footer:focus-visible {
    text-decoration: underline;
}

@media (max-width: 767.98px) {
    .ticket-time-header {
        min-height: 44px;
    }

    .ticket-time-link {
        min-height: 44px;
        min-width: 44px;
    }

    .today-time-footer {
        min-height: 44px;
    }
}

.week-grid-wrap-loading {
    opacity: 0.6;
}
