/* ==========================================================================
   AI Workforce Orchestrator: design system
   Layer order: tokens → reset → texture → type → surfaces → controls →
                data → feedback → layout → responsive → motion
   Every component consumes tokens from this file. Razor components must not
   introduce local color literals or duplicate these primitives.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
    color-scheme: dark;

    /* Surfaces: near-black canvas, dark charcoal panels */
    --color-background: #050607;
    --color-background-raised: #0a0b0d;
    --color-background-elevated: #08090b;
    --color-sidebar: #030405;
    --color-surface: #0d0f11;
    --color-surface-raised: #14171a;
    --color-surface-hover: #1a1e22;
    --color-field: #07080a;
    --color-field-hover: #0b0d10;

    /* Structure */
    --color-border: #24282d;
    --color-border-strong: #3b4149;
    --color-border-loud: #565d66;

    /* Text: high-contrast white and gray.
       Every step clears WCAG AA (4.5:1) against the lightest surface
       (--color-surface-hover): muted 8.8:1, subtle 6.4:1, faint 4.8:1. */
    --color-text: #f6f6f7;
    --color-text-muted: #b9bcc2;
    --color-text-subtle: #9ba1a9;
    --color-text-faint: #848a92;
    --color-ink: #050607;

    /* Accent: hot pink is the single brand colour */
    --color-accent: #f20a73;
    --color-accent-hover: #ff2d8a;
    --color-accent-active: #c9065e;
    --color-accent-text: #ff4d97;
    --color-accent-soft: rgba(242, 10, 115, 0.16);
    --color-accent-faint: rgba(242, 10, 115, 0.07);
    --color-accent-glow: rgba(242, 10, 115, 0.3);

    /* Semantic status: never used as alternative brand colours */
    --color-info: #4d9cff;
    --color-info-soft: rgba(77, 156, 255, 0.14);
    --color-purple: #b06bff;
    --color-purple-soft: rgba(176, 107, 255, 0.14);

    

/* A named agent that is neither an anonymous process nor a person. Neon cyan-blue, chosen to
       sit clear of the purple every other agent carries and the pink a human carries. */
    --color-familiar: #35d6ff;
    --color-familiar-text: #7ee7ff;
    --color-familiar-soft: rgba(0, 200, 255, 0.12);
    --color-familiar-glow: rgba(53, 214, 255, 0.28);
    --color-warning: #ffa53d;
    --color-warning-soft: rgba(255, 165, 61, 0.14);
    --color-success: #45de83;
    --color-success-soft: rgba(69, 222, 131, 0.14);
    --color-danger: #ff5468;
    --color-danger-soft: rgba(255, 84, 104, 0.14);
    /* The rung between amber and red on the importance ramp. Not a status colour: nothing is
       ever "hot", only more or less important than the thing beside it. */
    --color-hot: #ff7a45;
    --color-hot-soft: rgba(255, 122, 69, 0.14);
    --color-neutral: #9aa0a8;
    --color-neutral-soft: rgba(154, 160, 168, 0.12);

    --overlay-dark: rgba(0, 0, 0, 0.66);

    /* Typography */
    --font-sans: Inter, "Segoe UI Variable Text", "Segoe UI", Roboto, Arial, sans-serif;
    --font-display: Bahnschrift, "Archivo Narrow", Oswald, "Roboto Condensed",
        "Fira Sans Condensed", "Arial Narrow", "Franklin Gothic Medium", "Segoe UI", sans-serif;
    /* Poster face for h1 and stat numerals. Deliberately NOT a pre-condensed named
       instance (e.g. "Bahnschrift SemiBold Condensed"): stacking font-stretch on
       top of one double-condenses the glyphs and wrecks legibility at display size.
       Width is controlled by font-stretch alone. */
    --font-poster: var(--font-display);
    --font-mono: "Cascadia Mono", "Cascadia Code", "SFMono-Regular", Consolas, "Liberation Mono", monospace;

    --tracking-display: -0.005em;
    --tracking-label: 0.12em;
    --tracking-kicker: 0.18em;
    /* Label rung shared by chips, kickers, and compact count tiles (0.62–0.72rem). */
    --font-size-label: 0.66rem;

    /* Spacing */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-7: 2rem;
    --space-8: 3rem;

    /* Type scale.
       Named by role rather than by size so the phone tier can retune the ramp in one
       place instead of per component. --text-body is what body actually renders at;
       the rest hang off it. Components written against literals still work — these
       are additive, and the density tier below retunes both. */
    --text-2xs: 0.6875rem;
    --text-xs: 0.75rem;
    --text-sm: 0.8125rem;
    --text-body: 0.9375rem;
    --text-md: 1rem;
    --text-lg: 1.15rem;
    --text-xl: 1.4rem;

    /* The one type value that is a hard floor rather than a preference: any focusable
       text-entry control computing below 16px makes iOS Safari zoom the viewport on
       focus and never zoom back. Density on those controls comes from height and
       padding, never from this. See the rule below the token block. */
    --text-control-min: 16px;

    /* Control geometry. --control-h is the visual height of a single-line control;
       --touch-min stays the separate hit-area floor, because a control may be drawn
       small and still need a 44px target around it. On the phone tier the two
       converge, which is why both are retuned together there. */
    --control-h: 2.7rem;
    --control-h-sm: 2.25rem;

    /* Geometry: the theme is square; shape comes from die-cut notches */
    --radius: 0;
    --hairline: 1px;
    --notch-sm: 0.45rem;
    --notch-md: 0.8rem;
    --notch-lg: 1.35rem;

    /* Effects */
    --shadow-panel: 0 1.25rem 2.75rem rgba(0, 0, 0, 0.45);
    --shadow-raised: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.5);
    --shadow-accent: 0 0 1.75rem var(--color-accent-glow);
    /* Inset dual-tone: survives clip-path. Accent edge reads on dark fills; light edge on accent fills. */
    --focus-ring: inset 0 0 0 2px var(--color-accent-hover), inset 0 0 0 4px var(--color-text);
    --transition-fast: 130ms ease;
    --transition-slow: 240ms ease;

    /* Shell metrics.
       --topbar-height is the single offset for sticky chrome and scroll-margin.
       Redeclare it at every breakpoint where the topbar's actual height changes
       (46rem, 26.875rem) so consumers stay honest without per-callsite copies. */
    --sidebar-width: 16.5rem;
    --topbar-height: 5rem;
    --tab-bar-height: 0px;
    --content-max-width: 108rem;

    /* Touch: 44 CSS px floor and themed tap flash. Used by the phone tier only for
       sizing; tap highlight and touch-action apply everywhere so desktop mouse use
       is unaffected while coarse pointers get immediate feedback. */
    --touch-min: 2.75rem;
    --touch-gap: 0.5rem;
    --tap-highlight: color-mix(in srgb, var(--color-accent) 28%, transparent);

    /* Texture: kept extremely low contrast so content stays readable */
    --texture-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
    --texture-scratch: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='1'%3E%3Cpath d='M12 46 L96 39 L188 44 L302 36'/%3E%3Cpath d='M-4 132 L74 126 L166 134 L268 124 L320 129'/%3E%3Cpath d='M20 228 L118 221 L214 229 L316 219'/%3E%3Cpath d='M8 292 L102 286 L206 293'/%3E%3C/g%3E%3C/svg%3E");
    --texture-halftone: radial-gradient(circle at center, rgba(255, 255, 255, 0.55) 0.6px, transparent 0.7px);
    --texture-line: rgba(255, 255, 255, 0.016);

}



/* Die-cut shapes.
   Written inline as `clip-path` rather than shared custom properties: a custom
   property containing var(--notch) resolves against the element it is *declared*
   on, so a :root-level path would freeze one notch size for the whole app.
   Each rule below sets --notch, then the polygon resolves against it.

   PANEL    top-right + bottom-left: panels, cards, tiles
   CUT-BR   bottom-right: buttons, fields, alerts, board cards
   CUT-BOTH top-left + bottom-right: chips, glyph tiles, pager links
*/

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    background: var(--color-background);
    font-family: var(--font-sans);
    min-width: min(20rem, 100%);
    -webkit-tap-highlight-color: var(--tap-highlight);
    -webkit-text-size-adjust: 100%;
}

body {
    background:
        repeating-linear-gradient(112deg, transparent 0 7rem, var(--texture-line) 7rem calc(7rem + 1px)),
        var(--color-background);
    color: var(--color-text);
    font-size: 0.9375rem;
    line-height: 1.55;
    margin: 0;
    /* vh fallback, then dvh so mobile URL-bar chrome does not clip the page. */
    min-height: 100vh;
    min-height: 100dvh;
    overscroll-behavior-y: none;
}

/*
 * Set by wwwroot/mobile-menu.js while the More sheet is open so the workspace
 * behind the panel cannot scroll. Targets html because the class is applied there
 * from plain script (not scoped layout CSS).
 */
html.mobile-nav-open,
html.mobile-nav-open body {
    overflow: hidden;
}

html.mobile-nav-open .workspace {
    overflow: hidden;
}

/* Drop the 300ms double-tap zoom delay on controls; pinch-zoom stays available. */
a,
button,
summary,
label,
.button,
.text-action,
.sort-header,
.pager-link,
.notification-trigger,
.check-control,
.sign-out-button,
.search-toggle,
.search-submit {
    touch-action: manipulation;
}

/* Fixed grain wash. Sits above the canvas, below every interactive layer. */
body::before {
    background-image: var(--texture-grain);
    content: "";
    inset: 0;
    mix-blend-mode: overlay;
    opacity: 0.28;
    pointer-events: none;
    position: fixed;
    z-index: 0;
}

button,
input,
select,
textarea {
    font: inherit;
}

/*
 * iOS Safari zooms the viewport whenever a focused form control computes below 16px, and it
 * does not zoom back out on blur, so the user is left magnified and horizontally scrolled after
 * every field. Body text is 0.9375rem (15px) and controls inherit it, which puts every input,
 * select and textarea one pixel under the threshold.
 *
 * Raise the controls to exactly 1rem rather than changing body typography, which would rescale
 * the whole desktop layout, and rather than pinning the viewport scale, which would disable
 * pinch-zoom for everyone. `min-height: 2.7rem` (43.2px) still comfortably contains 16px text,
 * and the clip-path notch is sized from --notch, not from the font, so neither is affected.
 *
 * Coarse pointer as well as narrow width: the zoom is a touch-browser behaviour, not a
 * narrow-window one. An iPad in landscape is wider than any phone breakpoint and still zooms.
 */
@media (max-width: 40rem), (pointer: coarse) {
    .field-control,
    .select-control,
    .text-area-control,
    input,
    select,
    textarea,
    /* contenteditable composers zoom exactly like a textarea does; a rich-text
       composer is still a focusable text-entry control to Safari. */
    [contenteditable]:not([contenteditable="false"]) {
        font-size: 16px;
        font-size: var(--text-control-min, 16px);
    }
}

a {
    color: var(--color-accent-text);
    text-underline-offset: 0.2em;
}

img,
svg {
    max-width: 100%;
}

h1,
h2,
h3,
h4,
p {
    margin-top: 0;
}

::selection {
    background: var(--color-accent);
    color: var(--color-text);
}

:focus-visible {
    outline: 2px solid var(--color-accent-hover);
    outline-offset: 3px;
}

/*
 * Die-cut controls clip anything outside the polygon, including outline and outer
 * box-shadow. One shared inset ring stays inside the clip. Form controls cannot
 * host ::before/::after, so the ring is applied to the element; buttons and
 * linked tiles paint it on ::after (the fill layer) so it is not buried under
 * the negative-z border/fill stack.
 */
.button:focus-visible,
.field-control:focus-visible,
.select-control:focus-visible,
.text-area-control:focus-visible,
.tab:focus-visible,
.pager-link:focus-visible,
.status-chip:focus-visible,
a.stat-tile:focus-visible,
.board-card:focus-visible,
.instruction-card:focus-visible,
.app-dialog.app-dialog-confirm:focus-visible,
.notification-list li > a:focus-visible,
.notification-item-button:focus-visible {
    outline: none;
}

.field-control:focus-visible,
.select-control:focus-visible,
.text-area-control:focus-visible,
.tab:focus-visible,
.pager-link:focus-visible,
.status-chip:focus-visible,
.board-card:focus-visible,
.instruction-card:focus-visible,
.app-dialog.app-dialog-confirm:focus-visible,
.notification-list li > a:focus-visible,
.notification-item-button:focus-visible {
    box-shadow: var(--focus-ring);
}

.button:focus-visible::after,
a.stat-tile:focus-visible::after {
    box-shadow: var(--focus-ring);
}

.visually-hidden {
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
    color: var(--color-text);
    font-family: var(--font-display);
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-display);
    line-height: 1;
    text-transform: uppercase;
}

/* Page title. Semi-condensed with slightly open tracking: the poster weight still
   reads as punk, but the counters stay legible at 40px+. */
h1 {
    font-family: var(--font-poster);
    font-size: clamp(2rem, 4vw, 3.15rem);
    font-stretch: 85%;
    letter-spacing: 0.01em;
    line-height: 0.95;
    margin-bottom: var(--space-3);
}

h1:focus {
    outline: none;
}

/* Eyebrow / kicker / label: small, wide-tracked, condensed */
.eyebrow,
.panel-kicker,
.stat-label,
.sidebar-heading,
.field-group > label,
.data-table th,
.definition-grid dt {
    font-family: var(--font-display);
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.eyebrow {
    align-items: center;
    color: var(--color-accent-text);
    display: flex;
    font-size: 0.7rem;
    gap: var(--space-2);
    letter-spacing: var(--tracking-kicker);
    margin-bottom: var(--space-2);
}

/* Short pink slab that opens every eyebrow: the recurring brand tick. */
.eyebrow::before {
    background: var(--color-accent);
    content: "";
    flex: none;
    height: 0.7rem;
    transform: skewX(-18deg);
    width: 0.28rem;
}

.page-description,
.account-copy {
    color: var(--color-text-muted);
    line-height: 1.6;
    margin-bottom: 0;
    max-width: 54rem;
}

.preserve-text {
    color: var(--color-text-muted);
    line-height: 1.65;
    margin: 0;
    white-space: pre-wrap;
}

code,
.record-key,
.correlation-value,
.definition-grid code {
    font-family: var(--font-mono);
}

/* Long opaque tokens may break; display keys must stay intact (AIWO-19). */
code,
.correlation-value,
.definition-grid code {
    overflow-wrap: anywhere;
}


/* --------------------------------------------------------------------------
   4. Die-cut surface primitive

   Panels draw their border and fill as two clipped pseudo-layers so the
   notched corners keep a real hairline instead of a raw cut edge.
   -------------------------------------------------------------------------- */

.panel,
.account-card,
.stat-tile {
    --notch: var(--notch-lg);
    --panel-accent: var(--color-accent);
    --panel-border: var(--color-border);
    --panel-fill: linear-gradient(152deg, var(--color-surface), var(--color-background-raised));
    background: transparent;
    filter: drop-shadow(0 1rem 2rem rgba(0, 0, 0, 0.4));
    isolation: isolate;
    min-width: 0;
    position: relative;
    z-index: 0;
}

.panel > *,
.account-card > *,
.stat-tile > * {
    position: relative;
    z-index: 1;
}

/* A panel's padding comes from its body. The Panel component renders one; a hand-written
   <article class="panel"> does not, so its content sat flush against the frame - the marketing
   cards put their title directly on the panel's accent band, which is why that band read as a
   stray underline appearing on short titles and vanishing behind long ones, and why the list
   rules inside a card ran edge to edge. Any panel without a body gets the same inset the
   component's body would have given it. */
.panel:not(:has(> .panel-body)):not(:has(> .panel-header)) {
    padding: var(--space-5);
}

/* Border layer */
.panel::before,
.account-card::before,
.stat-tile::before {
    background: var(--panel-border);
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% var(--notch), 100% 100%, var(--notch) 100%, 0 calc(100% - var(--notch)));
    content: "";
    inset: 0;
    position: absolute;
    z-index: -2;
}

/* Fill layer, inset by the hairline, carrying the offset accent stub */
.panel::after,
.account-card::after,
.stat-tile::after {
    background:
        linear-gradient(90deg, var(--panel-accent) 0 5rem, transparent 5rem) top left / 100% 2px no-repeat,
        var(--panel-fill);
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% var(--notch), 100% 100%, var(--notch) 100%, 0 calc(100% - var(--notch)));
    content: "";
    inset: var(--hairline);
    position: absolute;
    z-index: -1;
}

.panel[data-accent="ai"] { --panel-accent: var(--color-purple); }
.panel[data-accent="info"] { --panel-accent: var(--color-info); }
.panel[data-accent="attention"] { --panel-accent: var(--color-warning); }
.panel[data-accent="success"] { --panel-accent: var(--color-success); }
.panel[data-accent="danger"] { --panel-accent: var(--color-danger); }
.panel[data-accent="brand"] { --panel-accent: var(--color-accent); }
.panel[data-accent="neutral"] { --panel-accent: var(--color-neutral); }

/* Elevate panels, filter disclosures, and field groups containing an open dropdown */
.panel:has(.multi-select-filter[open]),
.panel:has(.multi-select-filter.is-open) {
    z-index: 30;
}

.filter-disclosure:has(.multi-select-filter[open]),
.filter-disclosure:has(.multi-select-filter.is-open) {
    position: relative;
    z-index: 30;
}

.field-group:has(.multi-select-filter[open]),
.field-group:has(.multi-select-filter.is-open) {
    position: relative;
    z-index: 50;
}

.panel-header {
    align-items: center;
    border-bottom: var(--hairline) solid var(--color-border);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: space-between;
    min-height: 3.75rem;
    padding: var(--space-4) var(--space-5);
}

.panel-kicker {
    color: var(--color-text-faint);
    font-size: 0.62rem;
    letter-spacing: var(--tracking-kicker);
    margin: 0 0 var(--space-1);
}

/* Section heading: condensed pink title over a scratched rule. */
/* One colour for every card title. It used to inherit the panel accent, which gave the
   application seven card-title colours with no rule behind any of them; colour that varies
   without meaning is colour a reader learns to ignore. State is carried by the accent rule
   along the panel edge instead. */
.panel-title {
    color: var(--color-text);
    font-size: 1.05rem;
    margin: 0;
    position: relative;
}

/* A solid rule in the panel's accent. The previous dash pattern used three unequal segments,
   which rendered as uneven fragments and read as a broken border rather than a deliberate mark,
   and it took the title's colour rather than the accent's, so it carried no state either. */
.panel-title::after {
    background: var(--panel-accent, var(--color-border-strong));
    bottom: -0.35rem;
    content: "";
    height: 2px;
    left: 0;
    position: absolute;
    width: 2.75rem;
}

.panel-actions,
.button-row {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.panel-body {
    min-width: 0;
    padding: var(--space-5);
}

/* One measure for prose. A paragraph directly inside a card ran the full 1,600px column on six
   pages, which is roughly 200 characters a line.

   Prose only, and the selector has to say so. Capping every ul and ol in a card also capped the
   lists that are layout rather than reading matter — the discussion index, the vote board, the
   activity feed — to 72ch, which on a 1,600px panel left a 580px column of content beside a
   1,000px gap. A list that carries a class of its own is a component and sizes itself. */
.panel-body > p,
.panel-body > .stack-form > p,
.panel-body > ul:not([class]),
.panel-body > ol:not([class]) {
    max-width: 72ch;
}

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

.button,
.text-action {
    --notch: var(--notch-sm);
    --button-fill: transparent;
    --button-border: transparent;
    /* Opaque backdrop for translucent --button-fill values; see .button::after. */
    --button-base: transparent;
    align-items: center;
    background: transparent;
    border: 0;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text);
    cursor: pointer;
    display: inline-flex;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-stretch: 75%;
    font-weight: 700;
    gap: var(--space-2);
    isolation: isolate;
    justify-content: center;
    letter-spacing: 0.06em;
    min-height: var(--control-h-sm);
    padding: 0 var(--space-4);
    position: relative;
    text-decoration: none;
    text-transform: uppercase;
    transition: color var(--transition-fast), transform var(--transition-fast);
    z-index: 0;
}

.button::before,
.text-action::before {
    background: var(--button-border);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    content: "";
    inset: 0;
    position: absolute;
    transition: background var(--transition-fast);
    z-index: -2;
}

/* The fill sits directly on top of the border layer, so a translucent
   --button-fill would composite over the border colour rather than the page:
   14% red over solid red is still solid red, and a same-coloured label
   disappears. Paint the fill over an opaque --button-base instead. Contexts
   on a surface other than a panel override --button-base. */
.button::after,
.text-action::after {
    background: linear-gradient(var(--button-fill), var(--button-fill)), var(--button-base);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    content: "";
    inset: var(--hairline);
    position: absolute;
    transition: background var(--transition-fast);
    z-index: -1;
}

.button:hover:not(:disabled),
.text-action:hover:not(:disabled) {
    transform: translateY(-1px);
}

.button:active:not(:disabled),
.text-action:active:not(:disabled) {
    transform: translateY(0);
}

.button:disabled,
.button[aria-disabled="true"],
.text-action:disabled,
.text-action[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.42;
    transform: none;
}

.button-primary {
    --button-fill: var(--color-accent);
    --button-border: var(--color-accent);
    color: var(--color-ink);
}

.button-primary:hover:not(:disabled) {
    --button-fill: var(--color-accent-hover);
    --button-border: var(--color-accent-hover);
    filter: drop-shadow(0 0 0.75rem var(--color-accent-glow));
}

.button-secondary,
.text-action {
    --button-fill: var(--color-surface-raised);
    --button-border: var(--color-border-strong);
    color: var(--color-text);
}

.button-secondary:hover:not(:disabled),
.text-action:hover:not(:disabled) {
    --button-fill: var(--color-surface-hover);
    --button-border: var(--color-accent);
    color: var(--color-accent-text);
}

.button-danger,
.text-action-danger {
    --button-fill: var(--color-danger-soft);
    --button-base: var(--color-surface);
    --button-border: var(--color-danger);
    color: var(--color-danger);
}

.button-danger:hover:not(:disabled),
.text-action-danger:hover:not(:disabled) {
    --button-fill: var(--color-danger);
    color: var(--color-ink);
}

/* Overflow menu. Folds utilities and secondary actions behind one control so a header can
   show its primary action instead of five equal buttons. */
.overflow-menu {
    display: inline-block;
    position: relative;
}

.overflow-menu-trigger {
    min-width: 2.4rem;
    padding-inline: var(--space-2);
}

.overflow-menu-scrim {
    inset: 0;
    position: fixed;
    z-index: 40;
}

.overflow-menu-items {
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border-strong);
    display: grid;
    gap: 1px;
    min-width: 12rem;
    padding: var(--space-1);
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-1));
    z-index: 41;
}

.overflow-menu-items .button,
.overflow-menu-items a,
.overflow-menu-items button {
    border: 0;
    justify-content: flex-start;
    text-align: left;
    width: 100%;
}

/* The lowest-emphasis variant: a row action that must not compete with the row's content.
   It was previously spelled "button-quiet" and had no styling at all, so four buttons rendered
   with the base shape and no fill or border. */
.button-ghost {
    --button-fill: transparent;
    --button-base: transparent;
    --button-border: transparent;
    color: var(--color-text-muted);
}

.button-ghost:hover:not(:disabled) {
    --button-fill: var(--color-surface-hover);
    --button-border: var(--color-border-strong);
    color: var(--color-text);
}

.button-block {
    width: 100%;
}

.button-small,
.text-action {
    font-size: 0.72rem;
    min-height: 2.1rem;
    padding-inline: var(--space-3);
}

/* --------------------------------------------------------------------------
   6. Forms
   -------------------------------------------------------------------------- */

.field-group {
    display: grid;
    gap: var(--space-2);
    min-width: 0;
}

/* An attempt ceiling is opt-in: the number only exists once its checkbox is ticked. Done in
   CSS rather than script so the field is right on first paint and with JS off; the server
   still treats the checkbox, not this input, as the switch. */
.attempt-limit-value {
    display: none;
}

.check-control:has(#limit-attempts:checked) + .attempt-limit-value {
    display: grid;
}

.field-group > label {
    color: var(--color-text-muted);
    font-size: 0.7rem;
}

.field-control,
.select-control,
.text-area-control {
    --notch: var(--notch-sm);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border-strong);
    border-radius: var(--radius);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text);
    min-height: var(--control-h);
    padding: 0 var(--space-3);
    transition: border-color var(--transition-fast), background var(--transition-fast);
    width: 100%;
}

.select-control {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--color-accent-text) 50%),
        linear-gradient(135deg, var(--color-accent-text) 50%, transparent 50%);
    background-position: right 1.15rem center, right 0.8rem center;
    background-repeat: no-repeat;
    background-size: 0.35rem 0.35rem, 0.35rem 0.35rem;
    padding-right: var(--space-7);
}

.text-area-control {
    line-height: 1.6;
    min-height: 8rem;
    padding-block: var(--space-3);
    resize: vertical;
}

.field-control:hover,
.select-control:hover,
.text-area-control:hover {
    background: var(--color-field-hover);
    border-color: var(--color-border-loud);
}

.field-control:focus-visible,
.select-control:focus-visible,
.text-area-control:focus-visible {
    border-color: var(--color-accent);
}

.field-control::placeholder,
.text-area-control::placeholder {
    color: var(--color-text-faint);
}

.check-control,
.check-row {
    align-items: center;
    color: var(--color-text-muted);
    cursor: pointer;
    display: flex;
    font-size: 0.84rem;
    gap: var(--space-2);
    min-width: 0;
}

.check-control input,
.check-row input {
    accent-color: var(--color-accent);
    flex: none;
    height: 1rem;
    width: 1rem;
}

/* A set of checkboxes read as one field: a bordered field surface that columns up
   while it can and scrolls once the list outgrows the form. */
.check-grid {
    --notch: var(--notch-sm);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    display: grid;
    gap: var(--space-2) var(--space-4);
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    max-height: 15rem;
    overflow-y: auto;
    overscroll-behavior-y: contain;
    padding: var(--space-3);
}

.toolbar-form {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: flex-end;
}

.toolbar-form .select-control {
    min-height: 2.1rem;
    min-width: 10rem;
    width: auto;
}

.toolbar-form .check-control {
    min-height: 2.1rem;
    padding-inline: var(--space-2);
}

.bulk-status-bar {
    align-items: center;
    background: var(--color-surface-raised);
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-md, 0.5rem);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: space-between;
    margin-bottom: var(--space-3);
    padding: var(--space-3) var(--space-4);
}

.bulk-status-count {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    margin: 0;
}

.bulk-status-form {
    flex: 1 1 18rem;
    justify-content: flex-start;
}

.bulk-status-note {
    flex: 1 1 14rem;
    min-width: 12rem;
}

.bulk-status-result {
    margin-bottom: var(--space-3);
}

/* Phone: the bar stacks so the status select and its confirm button each get a full row.
   This lived in two page stylesheets for a control that three pages render. */
@media (max-width: 52rem) {
    .bulk-status-bar {
        gap: var(--space-3);
        padding: var(--space-3);
    }

    .bulk-status-form {
        align-items: stretch;
        display: grid;
        grid-template-columns: 1fr;
        width: 100%;
    }

    .bulk-status-form .button,
    .bulk-status-form .field-control,
    .bulk-status-form .select-control {
        width: 100%;
    }
}

.cell-select {
    text-align: center;
    width: 2.5rem;
}

.bulk-select-all {
    display: inline-flex;
    margin: 0;
}

.data-table > tbody > tr.is-selected > td {
    background: color-mix(in srgb, var(--color-surface-hover) 70%, transparent);
}

.field-help,
.form-section-heading p {
    color: var(--color-text-subtle);
    font-size: 0.72rem;
    line-height: 1.5;
    margin: 0;
}

/* Inline label hint: keep it quieter than the uppercase field label. */
.field-optional {
    color: var(--color-text-faint);
    font-family: var(--font-body);
    font-size: 0.78em;
    font-stretch: normal;
    font-weight: 500;
    letter-spacing: normal;
    text-transform: none;
}

.code-input {
    font-family: var(--font-mono);
    font-size: 0.84rem;
}

/*
 * `.code-input` is declared after the shared phone/coarse 1rem control rule and has equal
 * specificity to `.field-control` / `.text-area-control`, so without this reassertion mono
 * fields stay at 0.84rem (~13.4px) and iOS Safari still zooms on focus (AC1). Desktop keeps
 * the denser mono size; body font and viewport meta stay untouched.
 */
@media (max-width: 40rem), (pointer: coarse) {
    .code-input {
        font-size: 1rem;
    }
}

.instruction-editor {
    min-height: 14rem;
}

.stack-form {
    display: grid;
    gap: var(--space-4);
    margin-top: var(--space-6);
}

.entity-form {
    display: grid;
    gap: var(--space-6);
}

.form-section {
    border-bottom: var(--hairline) solid var(--color-border);
    display: grid;
    gap: var(--space-5);
    padding-bottom: var(--space-6);
}

.form-section:last-of-type {
    border-bottom: 0;
    padding-bottom: 0;
}

/* Numbered step marker, set as a pink die-cut tile. */
.form-section-heading {
    align-items: start;
    display: grid;
    gap: var(--space-4);
    grid-template-columns: 2.25rem 1fr;
}

.form-section-heading > span {
    --notch: 0.35rem;
    align-items: center;
    background: var(--color-accent-soft);
    border: var(--hairline) solid var(--color-accent);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-accent-text);
    display: inline-flex;
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-stretch: 75%;
    font-weight: 700;
    height: 2.25rem;
    justify-content: center;
}

.form-section-heading h2 {
    font-size: 1.05rem;
    margin-bottom: var(--space-2);
}

.form-grid {
    display: grid;
    gap: var(--space-4);
}

.form-grid.two-column {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-grid.three-column {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.field-span-2 {
    grid-column: span 2;
}

/* Field width by content type.

   Width was decided per form, so a checklist item's Title and a project's Name each stretched
   the full 1570px column while a whole form elsewhere was pinned to 790px. A short identifier
   in a very wide box also reads as an error waiting to happen: there is nothing to suggest how
   much belongs in it. Prose keeps the full measure; everything shorter is capped.

   Capping also settles the orphaned trailing field: a lone date or key at the end of a
   two-column row now sits at its natural width rather than stretching across half the form and
   leaving a conspicuous empty column beside it. */
.field-identifier .field-control,
.field-identifier .select-control {
    max-width: 20rem;
}

.field-name .field-control,
.field-name .select-control {
    max-width: 35rem;
}

.field-prose .field-control {
    max-width: 72ch;
}

/* Required is marked; optional is not. The product previously marked one optional field and no
   required ones, so the absence of a mark meant nothing. */
.field-group label .required-mark {
    color: var(--color-accent-text);
    font-weight: 700;
    margin-left: 0.15em;
}

.field-align-end {
    align-self: end;
    min-height: 2.7rem;
}

.form-actions {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: flex-end;
}

/* Full-page forms keep their actions in view. The pattern already existed in the skill detail
   drawer; this is the same treatment for a form that owns the whole page, so Save is reachable
   without scrolling to the end of a long form. */
.form-actions.is-sticky {
    background: linear-gradient(180deg, transparent, var(--color-background) 35%);
    bottom: 0;
    margin-top: var(--space-5);
    padding: var(--space-4) 0 var(--space-2);
    position: sticky;
    z-index: 5;
}

.page-actions {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: flex-end;
}

/* PageHeading action frame. Responsive placement lives with the shared heading below. */
.page-heading-toolbar {
    --notch: var(--notch-md);
    min-width: 0;
    position: relative;
}

.page-heading-toolbar > * {
    position: relative;
    z-index: 1;
}

/* Framed only around real controls: a heading whose actions are just a status
   chip is showing a label, and a box drawn around a label reads as a mistake. */
/* The notched silhouette lives on the ::before/::after layers only. A clip-path on the plate
   itself also clipped the OverflowMenu dropdown that hangs below it, so "..." opened invisibly. */
.page-heading-toolbar:has(.button, form) {
    isolation: isolate;
    padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
    z-index: 0;
}

/* Border layer */
.page-heading-toolbar:has(.button, form)::before {
    background: var(--color-border);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    content: "";
    inset: 0;
    position: absolute;
    z-index: -2;
}

/* Fill layer, inset by the hairline, carrying the accent rail. Same wash as a
   panel, so the plate is recognisably one of this app's surfaces and
   --button-base keeps resolving correctly for translucent button fills. */
.page-heading-toolbar:has(.button, form)::after {
    background:
        linear-gradient(180deg, var(--color-accent) 0 100%) left top / 2px 100% no-repeat,
        linear-gradient(152deg, var(--color-surface), var(--color-background-raised));
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    content: "";
    inset: var(--hairline);
    position: absolute;
    z-index: -1;
}

/* The frame and the trailing control both cut the same corner at the same size, so the two
   notches stacked and the angle read as doubled. The frame owns the corner; the control inside
   it squares off. */
.page-heading-toolbar:has(.button, form) > * > :last-child.button,
.page-heading-toolbar:has(.button, form) > :last-child.button {
    clip-path: none;
}

/* The plate is its own stacking context at z-index 0, so an open menu inside it would paint
   under any later positioned panel. Lift the whole plate while a menu is open. */
.page-heading-toolbar:has(.overflow-menu.is-open) {
    z-index: 45;
}

/* Hide the frame when AuthorizeView / conditionals leave the slot empty. */
.page-heading-toolbar:not(:has(.button, .status-chip, form)) {
    display: none;
}

/* Sharing a row with buttons, status reads as the label on the cluster: same
   height as its neighbours, but never mistakable for another button. */
.page-actions:has(.button) > .status-chip {
    margin-right: var(--space-1);
    min-height: 2.6rem;
    padding-inline: 0.75rem;
}

.page-actions form,
.form-actions form,
.button-row form {
    display: inline-flex;
}

/* --------------------------------------------------------------------------
   7. Status chips
   -------------------------------------------------------------------------- */

.status-chip {
    --notch: 0.3rem;
    --chip-fill: var(--color-neutral-soft);
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-text-muted);
    align-items: center;
    background: var(--chip-fill);
    border: var(--hairline) solid var(--chip-border);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--chip-text);
    display: inline-flex;
    font-family: var(--font-display);
    font-size: 0.66rem;
    font-stretch: 75%;
    font-weight: 700;
    gap: var(--space-2);
    letter-spacing: 0.08em;
    line-height: 1;
    padding: 0.38rem 0.55rem;
    text-transform: uppercase;
    white-space: nowrap;
}

.status-dot {
    background: currentColor;
    flex: none;
    height: 0.36rem;
    transform: rotate(45deg);
    width: 0.36rem;
}

/* One tone vocabulary, shared by chips, stat tiles and panel accents. Names say what a state
   means, never which hue to draw. See Components/Shared/Tone.cs. */
.status-neutral { --chip-fill: var(--color-neutral-soft); --chip-border: var(--color-border-strong); --chip-text: var(--color-text-muted); }
.status-info { --chip-fill: var(--color-info-soft); --chip-border: var(--color-info); --chip-text: var(--color-info); }
.status-ai { --chip-fill: var(--color-purple-soft); --chip-border: var(--color-purple); --chip-text: var(--color-purple); }
.status-attention { --chip-fill: var(--color-warning-soft); --chip-border: var(--color-warning); --chip-text: var(--color-warning); }
.status-success { --chip-fill: var(--color-success-soft); --chip-border: var(--color-success); --chip-text: var(--color-success); }
.status-danger { --chip-fill: var(--color-danger-soft); --chip-border: var(--color-danger); --chip-text: var(--color-danger); }
.status-brand { --chip-fill: var(--color-accent-soft); --chip-border: var(--color-accent); --chip-text: var(--color-accent-text); }

/* Two more chip vocabularies, refining the defaults above.

   They had been declared inside the :root token block, which modern CSS nests rather than
   rejects - so they applied as ":root .status-p-high", and that accidental specificity was the
   only thing keeping them ahead of the .status-chip defaults. Moving them to the top level
   without moving them here made every rung render neutral. They sit after the defaults they
   refine now, so plain source order settles it. */

/* Project lifecycle ramp. A third axis alongside status and priority: where a project is in its
   life is not a statement about its health, so Production must not arrive in the same green as
   the Active status beside it. The ramp reads as a progression and is outlined rather than
   filled, which is what keeps it legible as a different kind of fact from the solid status chip
   in the next column. */
.status-ph-planning,
.status-ph-development,
.status-ph-staging,
.status-ph-production,
.status-ph-maintenance,
.status-ph-retired {
    --chip-fill: transparent;
    border-left-width: 2px;
    border-left-style: solid;
}

.status-ph-planning {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-text-subtle);
    border-left-color: var(--color-border-loud);
}

.status-ph-development {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-info);
    border-left-color: var(--color-info);
}

.status-ph-staging {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-purple);
    border-left-color: var(--color-purple);
}

.status-ph-production {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-success);
    border-left-color: var(--color-success);
}

.status-ph-maintenance {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-warning);
    border-left-color: var(--color-warning);
}

.status-ph-retired {
    --chip-border: var(--color-border);
    --chip-text: var(--color-text-faint);
    border-left-color: var(--color-border-strong);
    opacity: 0.72;
}

/* Priority and severity ramp. A separate axis from status - importance is not an outcome - but
   a scale the eye has to read at a glance, which means hue. It climbs cool to hot: blue at the
   bottom, green at the baseline, then amber, orange and red.

   Four of the six rungs used to be greyscale, with only the top two tinted. Beside a fully
   coloured status column that read as unstyled - a column of HIGH and NORMAL chips looked like
   chips whose styling had failed to load, and the scale only became visible at the top.

   These stay outlined where a status chip is filled, so two columns of coloured chips still read
   as two different kinds of fact. */
.status-p-lowest,
.status-p-low,
.status-p-normal,
.status-p-high,
.status-p-higher,
.status-p-highest {
    --chip-fill: transparent;
}

.status-p-lowest {
    --chip-border: var(--color-border-strong);
    --chip-text: var(--color-neutral);
    opacity: 0.8;
}

.status-p-low {
    --chip-border: var(--color-info);
    --chip-text: var(--color-info);
}

.status-p-normal {
    --chip-border: var(--color-success);
    --chip-text: var(--color-success);
}

.status-p-high {
    --chip-border: var(--color-warning);
    --chip-text: var(--color-warning);
    font-weight: 700;
}

/* Urgent sits between High and Critical. Both used to render as High, so two priorities an
   operator has to tell apart were the same chip. */
.status-p-higher {
    --chip-border: var(--color-hot);
    --chip-text: var(--color-hot);
    font-weight: 700;
}

/* The top of the scale is the one rung that fills, so it is findable in a long column. */
.status-p-highest {
    --chip-fill: var(--color-danger-soft);
    --chip-border: var(--color-danger);
    --chip-text: var(--color-danger);
    font-weight: 700;
}

/* The ramp reads as a scale, so the dot becomes a rung marker rather than a status light. */
.status-p-high .status-dot,
.status-p-higher .status-dot,
.status-p-highest .status-dot { transform: rotate(45deg) scale(1.15); }
.status-p-lowest .status-dot,
.status-p-low .status-dot { opacity: 0.5; }

/* A named agent that is neither an anonymous process nor a person. Neon cyan-blue: distinct
   from the purple every other agent carries and from the pink a human carries, so the word and
   the colour say the same thing. Lit rather than tinted, since it marks one participant. */
.status-familiar {
    --chip-fill: var(--color-familiar-soft);
    --chip-border: var(--color-familiar);
    --chip-text: var(--color-familiar-text);
    box-shadow: 0 0 0.5rem var(--color-familiar-glow), inset 0 0 0.4rem var(--color-familiar-soft);
    text-shadow: 0 0 0.4rem var(--color-familiar-glow);
}

/* --------------------------------------------------------------------------
   8. Stat tiles
   -------------------------------------------------------------------------- */


/* Stat row container. */
/* Auto-fit rather than a fixed four. A fixed track count strands any row that is not a
   multiple of it: the review queue and the project claims tab both show five tiles, so the
   fifth sat alone with three empty columns and about 1200px of dead space beside it. The
   breakpoint overrides below become unnecessary at wide sizes but are kept for the narrow
   ones, where a minimum track width alone would still overflow. */
.metric-grid {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    margin-bottom: var(--space-6);
}

.stat-tile {
    --notch: var(--notch-md);
    --panel-accent: var(--color-accent);
    align-content: start;
    display: grid;
    gap: var(--space-2);
    grid-template-areas:
        "glyph label"
        "glyph value"
        "meta  meta";
    grid-template-columns: auto minmax(0, 1fr);
    padding: var(--space-4) var(--space-5);
    text-decoration: none;
}

.stat-tile[data-tone="success"] { --panel-accent: var(--color-success); }
.stat-tile[data-tone="attention"] { --panel-accent: var(--color-warning); }
.stat-tile[data-tone="info"] { --panel-accent: var(--color-info); }
.stat-tile[data-tone="ai"] { --panel-accent: var(--color-purple); }
.stat-tile[data-tone="danger"] { --panel-accent: var(--color-danger); }
.stat-tile[data-tone="brand"] { --panel-accent: var(--color-accent); }
.stat-tile[data-tone="neutral"] { --panel-accent: var(--color-neutral); }

.stat-glyph {
    --notch: 0.3rem;
    align-items: center;
    align-self: center;
    background: color-mix(in srgb, var(--panel-accent) 14%, transparent);
    border: var(--hairline) solid color-mix(in srgb, var(--panel-accent) 55%, transparent);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--panel-accent);
    display: inline-flex;
    font-size: 1.15rem;
    grid-area: glyph;
    grid-row: span 2;
    height: 2.6rem;
    justify-content: center;
    line-height: 1;
    margin-right: var(--space-1);
    width: 2.6rem;
}

.stat-label {
    color: var(--color-text-subtle);
    font-size: 0.66rem;
    grid-area: label;
    letter-spacing: var(--tracking-kicker);
    margin: 0;
}

.stat-value {
    color: var(--color-text);
    font-family: var(--font-poster);
    font-size: 2.15rem;
    font-stretch: 82%;
    grid-area: value;
    letter-spacing: 0;
    line-height: 0.95;
}

.stat-meta {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    grid-area: meta;
    margin-top: var(--space-1);
}

.stat-note {
    color: var(--color-text-faint);
    font-size: 0.7rem;
    line-height: 1.4;
}

a.stat-tile {
    color: var(--color-text);
    transition: transform var(--transition-fast);
}

a.stat-tile:hover {
    --panel-border: var(--panel-accent);
    --panel-fill: linear-gradient(152deg, var(--color-surface-raised), var(--color-surface));
    transform: translateY(-2px);
}

a.stat-tile:hover .stat-value {
    color: var(--panel-accent);
}

/* --------------------------------------------------------------------------
   9. Tables
   -------------------------------------------------------------------------- */

.table-scroll,
.table-shell {
    overflow-x: auto;
    overscroll-behavior-x: contain;
}

.panel-subtitle {
    color: var(--color-text-muted);
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    margin: 0 0 var(--space-3);
}

.data-table {
    border-collapse: collapse;
    min-width: 44rem;
    width: 100%;
}

/* A single-line row measured 84px on the connections table, so five rows filled a screen and
   the list stopped being scannable. The vertical padding is the whole difference. */
.data-table th,
.data-table td {
    border-bottom: var(--hairline) solid var(--color-border);
    padding: var(--space-2) var(--space-3);
    text-align: left;
    vertical-align: middle;
}

.data-table thead th {
    background: var(--color-background-elevated);
    border-bottom: var(--hairline) solid var(--color-border-strong);
    color: var(--color-text-subtle);
    font-size: 0.66rem;
    position: relative;
    /* The checklist board broke GO-LIVE across two lines mid-word, which reads as two columns.
       A header wraps between words or not at all. */
    hyphens: none;
    overflow-wrap: normal;
    word-break: normal;
}

/* Thin pink rule closing the header row. */
.data-table thead th::after {
    background: var(--color-accent);
    bottom: -1px;
    content: "";
    height: 1px;
    left: 0;
    opacity: 0.4;
    position: absolute;
    right: 0;
}

.data-table td {
    color: var(--color-text-muted);
    font-size: 0.82rem;
}

/* A count that means "eleven work items are blocked" should take you to those eleven. */
.count-link {
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
    text-decoration: none;
}

.count-link:hover,
.count-link:focus-visible {
    color: var(--color-accent-text);
    text-decoration: underline;
}

/* A statistic in a table cell: the number leads, its unit sits beside it, and the detail goes
   on one line underneath. Nothing breaks mid-phrase — "3.1% failure rate" wrapping to "3.1%
   failure" over "rate" is not a narrower cell, it is an unreadable one. .table-scroll already
   handles a table that outgrows its container. */
.cell-stat {
    align-items: baseline;
    display: flex;
    gap: var(--space-2);
    white-space: nowrap;
}

.cell-stat strong {
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

.cell-stat span {
    color: var(--color-text-faint);
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    letter-spacing: var(--tracking-kicker);
    text-transform: uppercase;
}

.cell-stat-meta {
    color: var(--color-text-subtle);
    display: block;
    margin-top: var(--space-1);
    white-space: nowrap;
}

/* Keys and timestamps stay on one line; .table-scroll handles overflow. */
.data-table .record-key,
.data-table time {
    white-space: nowrap;
}

.data-table tbody tr {
    transition: background var(--transition-fast);
}

.data-table tbody tr:hover {
    background: var(--color-surface-hover);
}

/* Left marker on the hovered row: selection is never colour-only. */
.data-table tbody tr:hover td:first-child {
    box-shadow: inset 2px 0 0 var(--color-accent);
}

.data-table tbody tr:last-child td {
    border-bottom: 0;
}

/* Sortable headers: keep the condensed label look, accent only the active column. */
.sort-header {
    align-items: center;
    color: inherit;
    display: inline-flex;
    gap: 0.35rem;
    letter-spacing: inherit;
    text-decoration: none;
    text-transform: inherit;
}

.sort-header:hover {
    color: var(--color-accent-text);
}

.sort-header.is-active {
    color: var(--color-accent-text);
}

/* The audit found no visible sort affordance on any table: the indicator appeared only after
   you had already guessed the header was clickable. An idle sortable column now shows a muted
   pair of carets, and the active one shows its direction in the accent. */
.sort-indicator-idle {
    color: var(--color-text-faint);
    font-size: 0.6rem;
    line-height: 1;
    opacity: 0.65;
}

.sort-header:hover .sort-indicator-idle,
.sort-header:focus-visible .sort-indicator-idle {
    color: var(--color-accent-text);
    opacity: 1;
}

.sort-indicator {
    color: var(--color-accent);
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-stretch: 75%;
    font-weight: 700;
    line-height: 1;
    transform: translateY(-0.05em);
}

/* Credential metadata tables. Prefixes, states and timestamps are single-token
   values, so they never wrap; the slack in the row goes to the action column
   instead of stretching the data columns apart. */
.keys-table {
    min-width: 52rem;
}

.keys-table th,
.keys-table td {
    padding: var(--space-2) var(--space-3);
}

.keys-table .cell-prefix,
.keys-table .cell-state,
.keys-table .cell-time {
    white-space: nowrap;
}

.keys-table .cell-prefix code {
    overflow-wrap: normal;
    white-space: nowrap;
}

.keys-table .cell-scopes {
    max-width: 16rem;
    overflow-wrap: anywhere;
    white-space: normal;
}

.keys-table .cell-actions {
    width: 99%;
}

.keys-table .cell-actions .button {
    white-space: nowrap;
}

/* API key metadata: issue/rotate form nested in the orange credentials panel. */
.key-metadata {
    display: grid;
    gap: var(--space-4);
}

.key-issue {
    --notch: var(--notch-md);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    border-left: 2px solid var(--color-warning);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    display: grid;
    gap: var(--space-5);
    min-width: 0;
    padding: var(--space-4) var(--space-5) var(--space-5);
}

.key-issue-heading {
    align-items: start;
    display: flex;
    gap: var(--space-3);
    min-width: 0;
}

.key-issue-index {
    --notch: 0.35rem;
    align-items: center;
    align-self: start;
    background: var(--color-warning-soft);
    border: var(--hairline) solid var(--color-warning);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-warning);
    display: inline-flex;
    flex: none;
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-stretch: 75%;
    font-weight: 700;
    height: 2.25rem;
    justify-content: center;
    width: 2.25rem;
}

.key-issue-heading .panel-kicker {
    margin: 0 0 var(--space-1);
}

.key-issue-heading h3 {
    font-size: 1rem;
    margin: 0 0 var(--space-2);
}

.key-issue-heading p {
    color: var(--color-text-subtle);
    font-size: 0.72rem;
    line-height: 1.5;
    margin: 0;
    max-width: 42rem;
}

.key-issue .stack-form {
    margin-top: 0;
}

/* Scope cells: a count that expands on demand, so one heavily scoped key does
   not make every row in the table four lines tall. */
.scope-chips {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
}

/* Bounded so expanding a scope cell borrows width from the action column
   instead of stretching the table into a horizontal scroll. */
.scope-chips-expanded {
    margin-top: var(--space-2);
    max-width: 20rem;
    min-width: 11rem;
}

.scope-empty {
    color: var(--color-text-faint);
}

.scope-disclosure > summary {
    align-items: center;
    cursor: pointer;
    display: inline-flex;
    gap: var(--space-2);
    list-style: none;
}

.scope-disclosure > summary::-webkit-details-marker {
    display: none;
}

.scope-toggle-hint {
    color: var(--color-text-subtle);
    font-family: var(--font-display);
    font-size: 0.62rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    transition: color var(--transition-fast);
}

.scope-toggle-hint::after {
    content: "Show";
}

.scope-disclosure[open] .scope-toggle-hint::after {
    content: "Hide";
}

.scope-disclosure > summary:hover .scope-toggle-hint,
.scope-disclosure > summary:focus-visible .scope-toggle-hint {
    color: var(--color-accent-text);
}

.record-key {
    color: var(--color-accent-text);
    font-size: 0.8rem;
    font-weight: 700;
    hyphens: none;
    overflow-wrap: normal;
    text-decoration: none;
    white-space: nowrap;
    word-break: keep-all;
}

.record-title {
    color: var(--color-text);
    font-weight: 600;
    hyphens: none;
    overflow-wrap: break-word;
    text-decoration: none;
}

/*
 * Line clamping for titles in dense lists.
 *
 * Both properties are required, not one with the other as a fallback: current mobile
 * Safari implements only the -webkit- pair, and bare `line-clamp` silently does
 * nothing there — which would be a clamp that appears to work in review on a desktop
 * browser and does not work on the device the density pass is for.
 *
 * Clamping hides text, so every clamped element must keep the full string reachable.
 * The markup carries it in `title` (pointer hover) and, where the element is a link,
 * the accessible name is the full text because the clamp is purely visual — the DOM
 * text is never truncated. Do not clamp anything whose full value exists nowhere else.
 */
.title-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}

/* Work-item titles get a third line: they are the one string in the product that
   routinely carries a sentence rather than a label, and two lines cut most of them. */
.title-clamp-work-item {
    -webkit-line-clamp: 3;
    line-clamp: 3;
}

.record-preview {
    color: var(--color-text-faint);
    font-size: 0.8rem;
    margin-top: 0.2rem;
}

.record-key:hover,
/* A record title that opens in place rather than navigating. Project Files rendered each
   filename as a bordered secondary button, so a list of twelve files read as twelve controls. */
button.record-title {
    background: none;
    border: 0;
    cursor: pointer;
    font-family: inherit;
    font-size: inherit;
    padding: 0;
    text-align: left;
}

button.record-title:disabled {
    cursor: default;
    opacity: 0.6;
}

.record-title:hover {
    color: var(--color-accent-hover);
    text-decoration: underline;
}

.correlation-value {
    color: var(--color-text-faint);
    font-size: 0.68rem;
}

.definition-grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin: 0;
}

.definition-grid.single-column {
    grid-template-columns: 1fr;
}

/* Only the dt/dd row wrappers stack; nested rows such as .button-row keep their own layout. */
.definition-grid > div {
    display: grid;
    gap: var(--space-2);
    min-width: 0;
}

.definition-grid dt {
    color: var(--color-text-faint);
    font-size: 0.64rem;
}

.definition-grid dd {
    color: var(--color-text-muted);
    font-size: 0.84rem;
    margin: 0;
}

.definition-grid code {
    color: var(--color-accent-text);
}

/* --------------------------------------------------------------------------
   10. Tabs
   -------------------------------------------------------------------------- */

.tabs {
    border-bottom: var(--hairline) solid var(--color-border);
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-1);
    margin-bottom: var(--space-5);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-bottom: 0;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
}

.tab {
    --notch: 0.4rem;
    background: transparent;
    border: 0;
    clip-path: polygon(0 0, calc(100% - var(--notch)) 0, 100% var(--notch), 100% 100%, 0 100%);
    color: var(--color-text-subtle);
    cursor: pointer;
    flex: none;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: var(--space-3) var(--space-4);
    position: relative;
    text-decoration: none;
    text-transform: uppercase;
    transition: background var(--transition-fast), color var(--transition-fast);
    white-space: nowrap;
}

.tab::after {
    background: transparent;
    bottom: 0;
    content: "";
    height: 2px;
    left: 0;
    position: absolute;
    right: 0;
    transition: background var(--transition-fast);
}

.tab:hover {
    background: var(--color-surface);
    color: var(--color-text);
}

.tab:hover::after {
    background: var(--color-border-loud);
}

.tab.active,
.tab[aria-selected="true"] {
    background: var(--color-accent-soft);
    color: var(--color-text);
}

.tab.active::after,
.tab[aria-selected="true"]::after {
    background: var(--color-accent);
}

/* --------------------------------------------------------------------------
   11. Pagination
   -------------------------------------------------------------------------- */

.pager {
    align-items: center;
    border-top: var(--hairline) solid var(--color-border);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: space-between;
    margin-top: var(--space-4);
    padding-top: var(--space-4);
}

.pager-status {
    color: var(--color-text-subtle);
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-stretch: 75%;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Page size sits with the pager, the one place it belongs. */
.pager-size {
    align-items: center;
    display: flex;
    gap: var(--space-2);
}

.pager-size label {
    color: var(--color-text-faint);
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    letter-spacing: var(--tracking-kicker);
    text-transform: uppercase;
}

.pager-size .select-control {
    min-width: 5rem;
    width: auto;
}

.pager-list {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    list-style: none;
    margin: 0;
    padding: 0;
}

.pager-link {
    --notch: 0.3rem;
    align-items: center;
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-text-muted);
    display: inline-flex;
    font-family: var(--font-display);
    font-size: 0.76rem;
    font-stretch: 75%;
    font-weight: 700;
    justify-content: center;
    min-height: 2.1rem;
    min-width: 2.1rem;
    padding: 0 var(--space-2);
    text-decoration: none;
    transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.pager-link:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-accent);
    color: var(--color-accent-text);
}

.pager-link[aria-current="page"] {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-ink);
}

.pager-ellipsis {
    color: var(--color-text-faint);
    padding-inline: var(--space-1);
}

.pager-edge {
    color: var(--color-text-subtle);
}

/* --------------------------------------------------------------------------
   12. Lists: activity, instructions, board, operations
   -------------------------------------------------------------------------- */

.activity-feed {
    display: grid;
    list-style: none;
    margin: 0;
    padding: 0;
}

.activity-feed li {
    align-items: start;
    border-bottom: var(--hairline) solid var(--color-border);
    display: grid;
    gap: var(--space-3);
    grid-template-columns: auto minmax(0, 1fr);
    padding: var(--space-3) 0;
}

.activity-feed li:first-child { padding-top: 0; }
.activity-feed li:last-child { border-bottom: 0; padding-bottom: 0; }

/* Fleet replay: a horizontally scrollable live claim strip and proportional event lanes. */
.fleet-claim-strip {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(17rem, 22rem);
    gap: 1rem;
    overflow-x: auto;
    padding: .2rem .1rem .65rem;
    scroll-snap-type: x proximity;
}

.fleet-claim-card {
    display: grid;
    gap: .35rem;
    padding: 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface-raised);
    scroll-snap-align: start;
}

.fleet-claim-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}

.fleet-claim-card span,
.fleet-claim-card small,
.fleet-lane-label small { color: var(--color-text-muted); }

.fleet-legend {
    display: flex;
    flex-wrap: wrap;
    gap: .65rem 1rem;
    margin-bottom: 1rem;
    color: var(--color-text-muted);
    font-size: .82rem;
}

.fleet-legend span { display: inline-flex; align-items: center; gap: .4rem; }
.fleet-legend .fleet-event-dot { position: static; transform: none; }

.fleet-range {
    display: flex;
    justify-content: space-between;
    margin: 0 0 .4rem min(18rem, 35%);
    color: var(--color-text-muted);
    font-size: .75rem;
}

.fleet-lanes { display: grid; gap: .65rem; }

.fleet-lane {
    display: grid;
    grid-template-columns: minmax(12rem, 18rem) minmax(28rem, 1fr);
    align-items: center;
    gap: 1rem;
    min-width: 48rem;
}

.fleet-lane-label { display: grid; gap: .15rem; min-width: 0; }
.fleet-lane-label strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.fleet-lane-track {
    position: relative;
    height: 2.2rem;
    border-radius: 999px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--color-border) 55%, transparent), var(--color-border), color-mix(in srgb, var(--color-border) 55%, transparent)) center / 100% 2px no-repeat;
}

.fleet-event-dot {
    position: absolute;
    top: 50%;
    width: .78rem;
    height: .78rem;
    border: 2px solid var(--color-surface-raised);
    border-radius: 50%;
    background: var(--color-info);
    box-shadow: 0 0 0 1px color-mix(in srgb, currentColor 35%, transparent);
    transform: translate(-50%, -50%);
}

.fleet-event-heartbeat { width: .48rem; height: .48rem; background: var(--color-info); }
.fleet-event-claimgranted { background: var(--color-accent); }
.fleet-event-leaselapsed { background: var(--color-warning); }
.fleet-event-reclaimed { background: var(--color-purple); }
.fleet-event-submitted { background: var(--color-purple); }
.fleet-event-reviewclaimed { background: var(--color-info); }
.fleet-event-reviewdecided { background: var(--color-success); }

@media (max-width: 760px) {
    .fleet-lanes { overflow-x: auto; padding-bottom: .5rem; }
    .fleet-range { margin-left: 0; }
}

.activity-feed li > div {
    display: grid;
    gap: var(--space-1);
    min-width: 0;
}

.activity-feed strong {
    color: var(--color-text-muted);
    font-size: 0.8rem;
    font-weight: 600;
}

.activity-feed small {
    color: var(--color-text-faint);
    font-size: 0.68rem;
}

.instruction-list {
    display: grid;
    gap: var(--space-3);
}

.instruction-card {
    --notch: var(--notch-md);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    border-left: 2px solid var(--color-purple);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    padding: var(--space-4);
}

.instruction-card.is-inactive {
    border-left-color: var(--color-text-faint);
    opacity: 0.7;
}

.instruction-card > header {
    align-items: flex-start;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
    margin-bottom: var(--space-3);
}

.instruction-card > header > div:first-child {
    display: flex;
    gap: var(--space-3);
    min-width: 0;
}

.instruction-card h3 {
    font-size: 0.95rem;
    margin: 0 0 var(--space-1);
}

.instruction-card header p,
.instruction-card footer {
    color: var(--color-text-faint);
    font-size: 0.7rem;
    margin: 0;
}

.instruction-card footer {
    border-top: var(--hairline) solid var(--color-border);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
}

.instruction-order {
    --notch: 0.25rem;
    align-items: center;
    background: var(--color-purple-soft);
    border: var(--hairline) solid var(--color-purple);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-purple);
    display: inline-flex;
    flex: none;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-stretch: 75%;
    font-weight: 700;
    height: 1.9rem;
    justify-content: center;
    width: 1.9rem;
}

/* Global Rules.

   Same card silhouette as an instruction, because a Rule reads the same way: an
   ordered, titled block of text an agent must obey. The one difference is that a
   Rule also carries an enforcement mode, and that mode is the single most
   important thing about it, so it drives the card's rail rather than a fixed
   colour. --rule-accent is set once per mode and every accented part of the card
   (rail, order tile, legend swatch) reads from it, so adding a mode is one line.

   Warning / info / neutral rather than the brand pink: these are the same three
   tones project Rules already use for the same three modes, and pink is the
   brand, not a severity. */
.rule-list {
    display: grid;
    gap: var(--space-3);
}

.rule-card {
    --notch: var(--notch-md);
    --rule-accent: var(--color-neutral);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    border-left: 2px solid var(--rule-accent);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    display: grid;
    gap: var(--space-3);
    padding: var(--space-4);
}

.rule-card[data-mode="Enforced"] { --rule-accent: var(--color-warning); }
.rule-card[data-mode="Default"] { --rule-accent: var(--color-info); }
.rule-card[data-mode="Advisory"] { --rule-accent: var(--color-neutral); }

/* Archived or deactivated: still legible, visibly not in force. */
.rule-card.is-inactive {
    --rule-accent: var(--color-text-faint);
    opacity: 0.72;
}

.rule-card-head {
    align-items: flex-start;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    justify-content: space-between;
}

.rule-card-identity {
    display: flex;
    gap: var(--space-3);
    min-width: 0;
}

.rule-card h3 {
    font-size: 0.95rem;
    margin: 0 0 var(--space-1);
}

/* Category, contexts and timestamp on one dotted-off line: three short facts that
   belong together and would each waste a row of their own. */
.rule-card-meta {
    color: var(--color-text-faint);
    display: flex;
    flex-wrap: wrap;
    font-size: 0.7rem;
    gap: var(--space-2);
    margin: 0;
}

.rule-card-meta > span + span::before {
    content: "·";
    margin-right: var(--space-2);
}

.rule-order {
    --notch: 0.25rem;
    align-items: center;
    background: color-mix(in srgb, var(--rule-accent) 14%, transparent);
    border: var(--hairline) solid color-mix(in srgb, var(--rule-accent) 55%, transparent);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--rule-accent);
    display: inline-flex;
    flex: none;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-stretch: 75%;
    font-weight: 700;
    height: 1.9rem;
    justify-content: center;
    width: 1.9rem;
}

/* The Rule as an agent receives it: the payload of the card, so it is set as a quoted
   block rather than more prose. Recessed rather than ruled — the card already carries a
   left rail for the mode, and a second vertical line beside it reads as a stray mark. */
.rule-content {
    background: var(--color-background-elevated);
    color: var(--color-text);
    font-size: 0.875rem;
    margin: var(--space-2) 0 0;
    max-width: 68ch;
    padding: var(--space-3);
}

/* Content runs to 8000 characters, so it folds behind its own label and the human
   description carries the card in a scan. */
.rule-content-disclosure > summary {
    align-items: baseline;
    cursor: pointer;
    display: flex;
    gap: var(--space-2);
    list-style: none;
    min-height: var(--touch-min);
}

.rule-content-disclosure > summary::-webkit-details-marker {
    display: none;
}

.rule-content-label {
    color: var(--color-text-subtle);
    font-family: var(--font-display);
    font-size: 0.66rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.rule-content-hint {
    color: var(--color-text-faint);
    font-family: var(--font-display);
    font-size: 0.62rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    transition: color var(--transition-fast);
}

.rule-content-hint::after {
    content: "Show";
}

.rule-content-disclosure[open] .rule-content-hint::after {
    content: "Hide";
}

.rule-content-disclosure > summary:hover .rule-content-label,
.rule-content-disclosure > summary:hover .rule-content-hint,
.rule-content-disclosure > summary:focus-visible .rule-content-label,
.rule-content-disclosure > summary:focus-visible .rule-content-hint {
    color: var(--color-accent-text);
}

/* Now the line the library is read by, so it takes body weight rather than the
   metadata weight it carried when the full content sat above it. */
.rule-description {
    color: var(--color-text-muted);
    font-size: 0.84rem;
    line-height: 1.55;
    margin: 0;
    max-width: 68ch;
}

/* What the mode actually costs a project, in words. The chip names the mode; this
   line says what it means, so the policy is readable without knowing the vocabulary. */
.rule-mode-note {
    color: var(--rule-accent);
    font-size: 0.7rem;
    margin: 0;
    opacity: 0.85;
}

.rule-card-foot {
    align-items: center;
    border-top: var(--hairline) solid var(--color-border);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: space-between;
    padding-top: var(--space-3);
}

/* The open editor is a distinct surface inside the card, not more card: the card is a
   record and this is a workspace over it, so it steps up a shade and squares off. */
.rule-inline-editor {
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border-strong);
    padding: var(--space-4);
}

.rule-inline-editor .form-actions {
    justify-content: flex-start;
}

/* The card being edited is lifted out of the list so the open form reads as attached
   to its own record rather than floating between two of them. */
.rule-card.is-editing {
    background: var(--color-background-raised);
    border-color: var(--color-border-strong);
}

/* An archived Rule is dimmed, but its editor must stay fully legible while open. */
.rule-card.is-editing.is-inactive {
    opacity: 1;
}

.rule-count {
    color: var(--color-text-faint);
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    font-stretch: 75%;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    white-space: nowrap;
}

.inline-editor {
    border-top: var(--hairline) solid var(--color-border);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
}

/* Acceptance criteria: keep the Actions column to a short button strip;
   verify/edit forms expand below instead of crowding the cell. */
.criteria-table {
    min-width: 52rem;
}

.criteria-table .cell-order,
.criteria-table .cell-flag {
    text-align: center;
    white-space: nowrap;
    width: 4.5rem;
}

.criteria-table .cell-method,
.criteria-table .cell-result {
    white-space: nowrap;
}

.criteria-table .cell-actions {
    min-width: 14rem;
    vertical-align: top;
    width: 1%;
}

.criterion-result {
    align-items: flex-start;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.criterion-verified-by {
    color: var(--color-text-faint);
    font-size: 0.7rem;
}

.criterion-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 12rem;
}

.criterion-manage {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.criterion-editor,
.criterion-verify-panel {
    min-width: 0;
}

.criterion-editor > summary,
.criterion-verify-panel > summary {
    list-style: none;
}

.criterion-editor > summary::-webkit-details-marker,
.criterion-verify-panel > summary::-webkit-details-marker {
    display: none;
}

.criterion-editor-form,
.criterion-verify {
    background: var(--color-surface-raised);
    border: var(--hairline) solid var(--color-border);
    display: grid;
    gap: var(--space-3);
    margin-top: var(--space-2);
    max-width: 22rem;
    padding: var(--space-3);
}

.criterion-editor-form .form-actions,
.criterion-verify .form-actions {
    margin: 0;
}

.inline-editor > summary {
    cursor: pointer;
    display: inline-flex;
    list-style: none;
}

.inline-editor > summary::-webkit-details-marker {
    display: none;
}

.inline-editor .text-area-control {
    min-height: 6rem;
}

/* Copy/paste agent prompts: collapsed by default with a clear expand affordance. */
.copy-prompt-disclosure {
    background: var(--color-surface-raised);
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-md, 0.5rem);
    margin-top: var(--space-3);
}

.copy-prompt-disclosure > summary {
    align-items: center;
    cursor: pointer;
    display: flex;
    gap: var(--space-3);
    list-style: none;
    min-height: var(--touch-min, 2.75rem);
    padding: var(--space-3) var(--space-4);
    user-select: none;
}

.copy-prompt-disclosure > summary::-webkit-details-marker {
    display: none;
}

.copy-prompt-disclosure-chevron {
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border);
    border-radius: 0.35rem;
    color: var(--color-text-muted);
    display: inline-grid;
    flex: 0 0 auto;
    font-size: 0.7rem;
    height: 1.6rem;
    place-items: center;
    transition: transform var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
    width: 1.6rem;
}

.copy-prompt-disclosure-chevron::before {
    content: "▸";
    line-height: 1;
}

.copy-prompt-disclosure[open] .copy-prompt-disclosure-chevron {
    border-color: var(--color-accent-border, var(--color-border));
    color: var(--color-accent-text);
    transform: rotate(90deg);
}

.copy-prompt-disclosure-title {
    color: var(--color-text);
    flex: 1 1 auto;
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-stretch: 80%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.copy-prompt-disclosure-hint {
    flex: 0 0 auto;
}

.copy-prompt-disclosure-hint .is-expanded {
    display: none;
}

.copy-prompt-disclosure[open] .copy-prompt-disclosure-hint .is-collapsed {
    display: none;
}

.copy-prompt-disclosure[open] .copy-prompt-disclosure-hint .is-expanded {
    display: inline;
}

.copy-prompt-disclosure > summary:hover,
.copy-prompt-disclosure > summary:focus-visible {
    background: color-mix(in srgb, var(--color-surface-raised) 70%, var(--color-surface));
}

.copy-prompt-disclosure > summary:focus-visible {
    outline: 2px solid var(--color-accent-text);
    outline-offset: -2px;
}

.copy-prompt-disclosure-body {
    border-top: var(--hairline) solid var(--color-border);
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4) var(--space-4);
}

.copy-prompt-disclosure-label {
    color: var(--color-text-muted);
    font-size: 0.78rem;
    font-weight: 600;
}

.copy-prompt-disclosure .code-input {
    margin: 0;
    min-height: 8rem;
}

.operation-list {
    display: grid;
}

.operation-list a {
    align-items: center;
    border-bottom: var(--hairline) solid var(--color-border);
    color: var(--color-text-muted);
    display: flex;
    gap: var(--space-4);
    justify-content: space-between;
    padding: var(--space-3);
    text-decoration: none;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.operation-list a:last-child {
    border-bottom: 0;
}

.operation-list a:hover {
    background: var(--color-surface-hover);
    box-shadow: inset 2px 0 0 var(--color-accent);
    color: var(--color-text);
}

.operation-list a > span:first-child {
    display: grid;
    gap: var(--space-1);
}

.operation-list strong {
    color: var(--color-text);
    font-size: 0.84rem;
}

.operation-list small {
    color: var(--color-text-faint);
    font-size: 0.72rem;
}

/* Columns were 10.5rem, about 168px, which forced card titles to wrap to four lines and made
   the board harder to read than the list it replaces. A wider minimum with horizontal scroll
   trades a scrollbar for legible cards. */
.board-grid {
    display: grid;
    gap: var(--space-2);
    grid-auto-columns: minmax(17rem, 1fr);
    grid-auto-flow: column;
    overflow-x: auto;
    padding-bottom: var(--space-2);
}

.board-column {
    --board-tone: var(--color-neutral);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    border-top: 2px solid var(--board-tone);
    display: grid;
    gap: var(--space-2);
    grid-auto-rows: min-content;
    min-height: 12rem;
    padding: var(--space-3);
}

.board-column[data-tone="success"] { --board-tone: var(--color-success); }
.board-column[data-tone="info"] { --board-tone: var(--color-info); }
.board-column[data-tone="danger"] { --board-tone: var(--color-danger); }
.board-column[data-tone="ai"] { --board-tone: var(--color-purple); }
.board-column[data-tone="attention"] { --board-tone: var(--color-warning); }
.board-column[data-tone="brand"] { --board-tone: var(--color-accent); }
.board-column[data-tone="neutral"] { --board-tone: var(--color-neutral); }

.board-column > header {
    align-items: center;
    display: flex;
    gap: var(--space-2);
    justify-content: space-between;
}

.board-column h3 {
    color: var(--board-tone);
    font-size: 0.76rem;
    margin: 0;
}

.board-card {
    --notch: 0.4rem;
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text-muted);
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3);
    text-decoration: none;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.board-card:hover {
    background: var(--color-surface-raised);
    border-color: var(--board-tone);
    color: var(--color-text);
}

.board-card code {
    color: var(--color-accent-text);
    font-size: 0.68rem;
}

.board-card strong {
    color: var(--color-text);
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.35;
}

.board-card > span {
    align-items: center;
    color: var(--color-text-faint);
    display: flex;
    flex-wrap: wrap;
    font-size: 0.66rem;
    gap: var(--space-2);
}

.board-empty,
.board-more {
    color: var(--color-text-faint);
    font-size: 0.72rem;
    margin: 0;
    text-decoration: none;
}

.board-more:hover {
    color: var(--color-accent-text);
}

/* --------------------------------------------------------------------------
   13. Empty, loading and feedback states
   -------------------------------------------------------------------------- */

.empty-state {
    align-items: center;
    color: var(--color-text-muted);
    display: flex;
    gap: var(--space-4);
    min-height: 8rem;
    padding: var(--space-4) 0;
}

.empty-state.compact {
    min-height: 4rem;
    padding: var(--space-2) 0;
}

.empty-state > div {
    min-width: 0;
}

.empty-state strong {
    color: var(--color-text);
    display: block;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.empty-state p {
    color: var(--color-text-subtle);
    font-size: 0.78rem;
    line-height: 1.5;
    margin: var(--space-1) 0 0;
    max-width: 44rem;
}

.empty-state .button {
    margin-top: var(--space-3);
}

/* Die-cut outline mark. Reads as a stamped placeholder, not decoration. */
.empty-mark {
    --notch: 0.4rem;
    align-items: center;
    border: 2px dashed var(--color-border-strong);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-accent);
    display: inline-flex;
    flex: none;
    font-family: var(--font-display);
    font-size: 1.5rem;
    height: 3.25rem;
    justify-content: center;
    line-height: 1;
    width: 3.25rem;
}

.empty-state.compact .empty-mark {
    font-size: 1.15rem;
    height: 2.5rem;
    width: 2.5rem;
}

/* Read-only credential display. Masked until asked for; see SecretValue.razor. */
.secret-value {
    display: grid;
    gap: var(--space-2);
    min-width: 0;
}

.secret-value-text {
    background: var(--color-field);
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: 0.76rem;
    overflow-wrap: anywhere;
    padding: var(--space-2) var(--space-3);
    min-width: 0;
    flex: 1 1 16rem;
}

.secret-value-text.is-masked {
    color: var(--color-text-faint);
    letter-spacing: 0.12em;
    user-select: none;
}

/* Error state. Shares the empty-state skeleton so a failure and an absence read as the
   same family of outcome, but carries danger tone and the two ways out: retry, or go back. */
.error-state {
    align-items: center;
    border-left: 3px solid var(--color-danger);
    color: var(--color-text-muted);
    display: flex;
    gap: var(--space-4);
    min-height: 8rem;
    padding: var(--space-4);
    background: var(--color-danger-soft);
}

.error-state > div {
    min-width: 0;
}

.error-state strong {
    color: var(--color-text);
    display: block;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.error-state p {
    color: var(--color-text-subtle);
    font-size: 0.78rem;
    line-height: 1.5;
    margin: var(--space-1) 0 0;
    max-width: 44rem;
}

.error-mark {
    --notch: 0.4rem;
    align-items: center;
    border: 2px solid var(--color-danger);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-danger);
    display: inline-flex;
    flex: none;
    font-family: var(--font-display);
    font-size: 1.5rem;
    height: 3.25rem;
    justify-content: center;
    line-height: 1;
    width: 3.25rem;
}

.error-state-actions,
.empty-state-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.error-correlation {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.error-correlation span {
    color: var(--color-text-faint);
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.error-correlation code {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--color-text-muted);
    user-select: all;
}

/* Loading */
.loading-state {
    display: grid;
    gap: var(--space-4);
    padding: var(--space-5) 0;
}

.loading-state header {
    align-items: center;
    display: flex;
    gap: var(--space-3);
}

.loading-state strong {
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-stretch: 75%;
    font-weight: 700;
    text-transform: uppercase;
}

.loading-state p {
    color: var(--color-text-subtle);
    font-size: 0.78rem;
    margin: var(--space-1) 0 0;
}

.loading-bars {
    display: grid;
    gap: var(--space-2);
}

.skeleton {
    background: linear-gradient(
        100deg,
        var(--color-surface) 20%,
        var(--color-surface-hover) 40%,
        var(--color-surface) 60%
    );
    background-size: 220% 100%;
    animation: skeleton-sweep 1.5s linear infinite;
    height: 0.85rem;
}

.skeleton:nth-child(2) { width: 82%; }
.skeleton:nth-child(3) { width: 64%; }
.skeleton:nth-child(4) { width: 73%; }

@keyframes skeleton-sweep {
    from { background-position: 130% 0; }
    to { background-position: -30% 0; }
}

/* Pulsing pink bar used as the loading marker. */
.loading-mark {
    background: var(--color-accent);
    flex: none;
    height: 2.25rem;
    transform: skewX(-16deg);
    width: 0.35rem;
    animation: loading-pulse 1.1s ease-in-out infinite;
}

@keyframes loading-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

/* Alerts and validation */
.form-alert,
.page-alert {
    --notch: var(--notch-sm);
    background: var(--color-danger-soft);
    border: var(--hairline) solid var(--color-danger);
    border-left: 3px solid var(--color-danger);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text);
    font-size: 0.84rem;
    line-height: 1.5;
    padding: var(--space-3) var(--space-4);
}

.form-alert {
    margin-top: var(--space-4);
}

.page-alert {
    margin: 0 0 var(--space-4);
}

.form-success {
    background: var(--color-success-soft);
    border-color: var(--color-success);
    border-left-color: var(--color-success);
}

.connection-result {
    align-items: flex-start;
    display: flex;
    gap: var(--space-3);
}

.connection-result p {
    margin: 0;
    min-width: 0;
}

.connection-result-pending {
    background: var(--color-info-soft);
    border-color: var(--color-info);
    border-left-color: var(--color-info);
}

.entity-form > .form-alert:first-of-type {
    margin-top: 0;
}

.valid.modified:not([type="checkbox"]) {
    border-color: var(--color-success);
}

.invalid {
    border-color: var(--color-danger);
}

.validation-message {
    align-items: center;
    color: var(--color-danger);
    display: flex;
    font-size: 0.76rem;
    gap: var(--space-2);
}

.validation-message::before {
    content: "!";
    font-family: var(--font-display);
    font-weight: 700;
}

.route-message {
    color: var(--color-text-muted);
    padding: var(--space-7);
}

.request-id {
    --notch: var(--notch-sm);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    display: grid;
    gap: var(--space-2);
    margin: var(--space-5) 0;
    padding: var(--space-3);
}

.request-id strong {
    color: var(--color-text-subtle);
    font-family: var(--font-display);
    font-size: 0.66rem;
    font-stretch: 75%;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.request-id code {
    color: var(--color-text-muted);
    font-size: 0.72rem;
}

/* --------------------------------------------------------------------------
   14. Dialogs
   -------------------------------------------------------------------------- */

.app-dialog {
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border-strong);
    border-top: 2px solid var(--color-accent);
    box-shadow: var(--shadow-panel);
    color: var(--color-text);
    max-width: 38rem;
    padding: 0;
    width: calc(100% - 2rem);
}

.app-dialog.app-dialog-confirm {
    --notch: var(--notch-md);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
}

.app-dialog.app-dialog-danger {
    border-top-color: var(--color-danger);
}

.app-dialog.app-dialog-danger .panel-kicker {
    color: var(--color-danger);
}

.app-dialog::backdrop {
    backdrop-filter: blur(3px);
    background: var(--overlay-dark);
}

.dialog-header,
.dialog-body,
.dialog-footer {
    padding: var(--space-4) var(--space-5);
}

.dialog-header {
    border-bottom: var(--hairline) solid var(--color-border);
}

.dialog-body {
    font-size: 0.9rem;
    line-height: 1.55;
}

.dialog-body p:last-child {
    margin-bottom: 0;
}

.dialog-footer {
    border-top: var(--hairline) solid var(--color-border);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: flex-end;
}

.dialog-footer form {
    display: inline-flex;
}

/* --------------------------------------------------------------------------
   15. Page layout
   -------------------------------------------------------------------------- */

/* Two tracks on the title row, one full-width track under it. The title and the
   action cluster share the top line; the description spans the header beneath
   both, so a long paragraph no longer pushes the actions down beside its last
   line. Not a flex pair: the title track is floored at a readable measure, so a
   wide action cluster gives up width before the title does, the cluster wraps
   inside its own track and stays right-aligned, and a wrapped button never
   widens to the whole header while its peers stay small. Row spacing is the
   h1's own margin rather than a grid gap, so the rhythm from title to prose
   matches every other heading in the app. */
/* Explanatory line under a page heading, e.g. that the Bridge installer also updates machines. */
.page-note {
    margin: -0.35rem 0 1.25rem;
    max-width: 68ch;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    line-height: 1.5;
}

.page-heading {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
    padding: var(--page-heading-padding, 0 0 var(--space-4));
    position: relative;
    isolation: isolate;
}

.page-heading-main {
    align-items: start;
    display: flex;
    gap: var(--space-5);
    min-width: 0;
}

.page-heading-main > .page-heading-title {
    flex: 1;
}

/* Art has its own bounded box; a longer title never enlarges the illustration. */
.page-heading-art {
    aspect-ratio: 16 / 9;
    background: var(--page-heading-art, none) right center / cover no-repeat;
    border-radius: var(--radius);
    display: var(--page-heading-art-display, none);
    flex: 0 0 clamp(10rem, 22vw, 18rem);
    max-height: 10rem;
    pointer-events: none;
}

/* Shared title constraints outrank the generic poster heading, in every theme.
   Sentences and identifiers wrap; no ellipsis or fixed-height clipping. */
.page-heading h1 {
    font-size: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
    letter-spacing: 0.01em;
    line-height: 1.22;
    margin: 0;
    max-width: 56ch;
    overflow-wrap: anywhere;
    text-transform: none;
    text-wrap: pretty;
}

.page-heading > .page-heading-toolbar {
    align-self: flex-start;
    margin: 0;
    max-width: 100%;
    width: fit-content;
}

/* Lift the header's stacking context with its menu, above subsequent panels. */
.page-heading:has(.overflow-menu.is-open) {
    z-index: 45;
}

.page-heading-toolbar :is(.page-actions, .button-row) {
    justify-content: flex-start;
    min-width: 0;
}

.page-heading-toolbar .page-actions:has(> .page-heading-action-group) {
    column-gap: var(--space-4);
}

.page-heading-toolbar .button {
    min-height: 44px;
    min-width: 44px;
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
}

.page-heading-action-group {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    min-width: 0;
    max-width: 100%;
}

.page-heading-action-group:empty {
    display: none;
}

/* A management action and its overflow trigger stay together at enlarged text sizes. */
.page-heading-action-group-compact {
    flex-wrap: nowrap;
}

.page-heading .page-heading-toolbar .page-heading-action-group-compact > .button {
    flex: 0 1 auto;
}

.page-heading-action-group-compact > .overflow-menu {
    flex: none;
}

/* Offset pink rule under every page title: asymmetric by design. */
.page-heading::after {
    background: linear-gradient(90deg, var(--color-accent) 0 6rem, var(--color-border) 6rem);
    bottom: 0;
    content: "";
    height: 1px;
    left: 0;
    position: absolute;
    right: 0;
}

/* Project navigation precedes the record heading. */
.work-item-project-nav {
    margin-bottom: var(--space-5);
}

/* Callout. One treatment for explanation and for state that is not a record's own status.
   Tone comes from the shared vocabulary, so a warning callout and a warning chip are the same
   amber rather than two decisions. */
.callout {
    --notch: var(--notch-sm);
    --callout-accent: var(--color-border-strong);
    --callout-fill: var(--color-surface);
    background: var(--callout-fill);
    border: var(--hairline) solid var(--color-border);
    border-left: 3px solid var(--callout-accent);
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text-muted);
    display: grid;
    font-size: 0.84rem;
    gap: var(--space-1);
    line-height: 1.55;
    margin: 0 0 var(--space-4);
    max-width: 72ch;
    padding: var(--space-3) var(--space-4);
}

.callout-title {
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.callout-body > :first-child { margin-top: 0; }
.callout-body > :last-child { margin-bottom: 0; }

.callout-info      { --callout-accent: var(--color-info);    --callout-fill: var(--color-info-soft); }
.callout-ai        { --callout-accent: var(--color-purple);  --callout-fill: var(--color-purple-soft); }
.callout-attention { --callout-accent: var(--color-warning); --callout-fill: var(--color-warning-soft); }
.callout-success   { --callout-accent: var(--color-success); --callout-fill: var(--color-success-soft); }
.callout-danger    { --callout-accent: var(--color-danger);  --callout-fill: var(--color-danger-soft); }
.callout-brand     { --callout-accent: var(--color-accent);  --callout-fill: var(--color-accent-faint); }

/* File inputs.

   A label wrapping an InputFile is the themed pattern: the label carries the button styling and
   the real control is hidden but still operable, because clicking the label activates it. The
   hiding class was referenced but never defined, so the browser's own "Choose File  No file
   chosen" rendered inside the pink Upload file button and spilled out of it. */
.file-input-hidden {
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/* Where a bare file input has to stay (a plain form post, no Blazor), theme the browser's
   button so it belongs to this application rather than to the operating system. */
.file-control {
    cursor: pointer;
    padding: var(--space-2);
}

.file-control::file-selector-button {
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border-strong);
    color: var(--color-text);
    cursor: pointer;
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    letter-spacing: var(--tracking-label);
    margin-right: var(--space-3);
    padding: var(--space-2) var(--space-3);
    text-transform: uppercase;
}

.file-control::file-selector-button:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-accent);
    color: var(--color-accent-text);
}

/* Rendered Markdown from agents and operators. Constrained to a readable measure: the audit
   found instruction and definition-of-done prose running the full 1600px column. */
.rich-text {
    max-width: 72ch;
    overflow-wrap: anywhere;
}

.rich-text > :first-child { margin-top: 0; }
.rich-text > :last-child { margin-bottom: 0; }

.rich-text code {
    background: var(--color-field);
    font-family: var(--font-mono);
    font-size: 0.85em;
    padding: 0.1em 0.35em;
}

.rich-text pre {
    background: var(--color-background-raised);
    border: var(--hairline) solid var(--color-border);
    overflow-x: auto;
    padding: var(--space-4);
}

.rich-text pre code { background: none; padding: 0; }

.rich-text.board-body,
.rich-text.is-lead { max-width: none; }

/* Breadcrumb. Occupies the line the eyebrow used to, so adding a trail costs no vertical
   space, and reads as navigation because every rung but the last is a link. */
.breadcrumb ol {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
    list-style: none;
    margin: 0 0 var(--space-1);
    padding: 0;
}

.breadcrumb li {
    align-items: center;
    display: flex;
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    gap: var(--space-2);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.breadcrumb li + li::before {
    color: var(--color-text-faint);
    content: "/";
}

.breadcrumb a {
    color: var(--color-text-subtle);
    text-decoration: none;
}

.breadcrumb a:hover {
    color: var(--color-accent-text);
}

.breadcrumb [aria-current="page"] {
    color: var(--color-text-muted);
}

/* Status beside the title rather than among the actions. */
.page-heading-status {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.page-heading-title {
    hyphens: none;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Metadata and description use the complete content width, independently of art. */
.page-heading-body {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Heading prose uses the page container's measure. */
.page-heading-body .page-description {
    max-width: none;
}

/* Preserve the record modifier with the shared readable title measure. */
.page-heading-record h1 {
    max-width: 56ch;
}

.dashboard-grid {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: minmax(0, 1.85fr) minmax(20rem, 0.85fr);
}

.dashboard-main {
    grid-row: span 2;
}

.detail-grid {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Blocks are spaced by the container that stacks them, never by the blocks themselves.

   This used to be the other way round: .panel + .panel carried a top margin, and every grid
   that could hold panels had to be named in an exception list to cancel it. That list is
   impossible to keep complete - it is what produced the audit's ragged marketing rows, and
   naming three more grids did not fix it either, because .landing-system-grid was not one of
   them and the first card in every row still sat 25px above its siblings.

   A grid or flex container spaces its own children with gap. Only a flow container needs to
   space its children, and a flow container that stacks blocks says so here. Nothing a grid
   contains can be caught by these rules, whatever the grid is called. */
.page-container > * + *,
.admin-settings-body > * + *,
.project-workspace-body > * + * {
    margin-top: var(--space-6);
}

/* The print stamp is display:none on screen but is still a DOM child, so the
   block after it would otherwise start one gap below the container padding. */
.page-container > .print-document-stamp + * {
    margin-top: 0;
}

.detail-wide {
    grid-column: 1 / -1;
}

.code-crumbs {
    align-items: center;
    color: var(--color-text-subtle);
    display: flex;
    flex-wrap: wrap;
    font-family: var(--font-mono);
    font-size: 0.82rem;
    gap: 0.35rem 0.5rem;
    margin: 0 0 var(--space-4);
}

.code-crumbs a {
    color: var(--color-accent-text);
    text-decoration: none;
}

.code-crumbs a:hover {
    text-decoration: underline;
}

.code-crumbs [aria-current="page"] {
    color: var(--color-text);
}

.code-tree-name {
    align-items: center;
    color: var(--color-text);
    display: inline-flex;
    gap: var(--space-2);
    text-decoration: none;
}

.code-tree-name:hover {
    color: var(--color-accent-text);
}

.code-viewer {
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: 0.78rem;
    line-height: 1.55;
    margin: 0;
    max-height: 42rem;
    overflow: auto;
    padding: var(--space-4);
    white-space: pre;
}

.code-viewer code {
    color: inherit;
    font-family: inherit;
    overflow-wrap: normal;
}

.code-viewer .tok-kw {
    color: var(--color-accent-text);
}

.code-viewer .tok-str {
    color: var(--color-text);
}

.code-viewer .tok-cmt {
    color: var(--color-text-faint);
    font-style: italic;
}

[id] {
    scroll-margin-top: calc(var(--topbar-height) + var(--space-4));
}

/* Account / auth surfaces */
.account-card {
    --notch: var(--notch-lg);
    --panel-border: var(--color-border-strong);
    --panel-fill: linear-gradient(150deg, var(--color-surface-raised), var(--color-surface));
    padding: clamp(1.5rem, 5vw, 2.75rem);
}

/* Account card titles sit in a 30rem shell with padded gutters — reuse the
   record-heading clamp and measure so multi-word titles (Access denied,
   Page not found, Request failed) wrap cleanly at phone widths. */
.account-card h1 {
    font-size: clamp(1.75rem, 2.6vw, 2.4rem);
    max-width: 32ch;
    text-wrap: balance;
}

.account-card .button {
    margin-top: var(--space-2);
}

/* The way back out of sign-in. The only route to the public site was the logo above the card,
   which does not read as a link. */
.account-footnote {
    border-top: var(--hairline) solid var(--color-border);
    color: var(--color-text-subtle);
    font-size: 0.8rem;
    margin: var(--space-5) 0 0;
    padding-top: var(--space-4);
}

.account-request-id {
    color: var(--color-text-subtle);
    font-size: 0.8rem;
    margin: var(--space-4) 0 0;
}

/* Diagonal ink swipe raked across the auth card, layered into the fill. */
.slash-accent {
    --panel-fill:
        linear-gradient(114deg, transparent 0 36%, var(--color-accent-faint) 36% 43%, transparent 43%),
        linear-gradient(114deg, transparent 0 47%, var(--color-accent-faint) 47% 49.5%, transparent 49.5%),
        linear-gradient(150deg, var(--color-surface-raised), var(--color-surface));
}

/* --------------------------------------------------------------------------
   16. Scrollbars
   -------------------------------------------------------------------------- */

* {
    scrollbar-color: var(--color-border-strong) transparent;
    scrollbar-width: thin;
}

::-webkit-scrollbar {
    height: 10px;
    width: 10px;
}

::-webkit-scrollbar-track {
    background: var(--color-background);
}

::-webkit-scrollbar-thumb {
    background: var(--color-border-strong);
    border: 2px solid var(--color-background);
}

::-webkit-scrollbar-thumb:hover {
    background: var(--color-accent);
}

::-webkit-scrollbar-corner {
    background: var(--color-background);
}

/* --------------------------------------------------------------------------
   17. Framework error surfaces
   -------------------------------------------------------------------------- */

.blazor-error-boundary {
    background: var(--color-danger-soft);
    border: var(--hairline) solid var(--color-danger);
    color: var(--color-text);
    padding: var(--space-4);
}

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

#blazor-error-ui {
    background: var(--color-surface-raised);
    border-top: 2px solid var(--color-danger);
    bottom: 0;
    box-shadow: var(--shadow-panel);
    color: var(--color-text);
    display: none;
    left: 0;
    /* Keep reload/dismiss clear of the home indicator and side notches. */
    padding:
        var(--space-3)
        max(var(--space-5), env(safe-area-inset-right, 0px))
        max(var(--space-3), env(safe-area-inset-bottom, 0px))
        max(var(--space-5), env(safe-area-inset-left, 0px));
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui.show {
    display: block;
}

#blazor-error-ui .reload {
    background: none;
    border: 0;
    color: var(--color-accent-text);
    cursor: pointer;
    font-family: var(--font-display);
    font-size: 0.76rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: 0.06em;
    margin-left: var(--space-3);
    text-decoration: none;
    text-transform: uppercase;
}

#blazor-error-ui .reload:hover {
    text-decoration: underline;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: max(var(--space-4), env(safe-area-inset-right, 0px));
    top: var(--space-3);
}

/* --------------------------------------------------------------------------
   18. Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 76rem) {
    .metric-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .dashboard-grid,
    .detail-grid {
        grid-template-columns: 1fr;
    }

    .detail-wide {
        grid-column: auto;
    }

    .dashboard-main {
        grid-row: auto;
    }
}

/* Too narrow to hold a title and an action cluster side by side: the cluster
   moves below the metadata and reads left-to-right with it. */
@media (max-width: 62rem) {
    :root {
        --tab-bar-height: 3.5rem;
    }

    /* At tablet widths the illustration becomes a subdued background. It no longer
       reserves a content column, including when text is enlarged by the user. */
    .page-heading-art {
        flex: none;
        inset: 0 0 auto auto;
        max-width: 100%;
        opacity: 0.16;
        position: absolute;
        width: 18rem;
        z-index: -1;
    }

    .page-actions {
        justify-content: flex-start;
    }
}

@media (max-width: 46rem) {
    .page-heading {
        margin-bottom: var(--space-4);
        padding-bottom: var(--space-3);
    }

    .page-heading h1 {
        font-size: clamp(1.25rem, 6.4vw, 1.65rem);
        hyphens: none;
        line-height: 1.15;
        overflow-wrap: break-word;
    }

    /* Keep all controls visible and let complete groups wrap. No scrolling row
       may clip the overflow menu or hide a keyboard target. */
    .page-heading-toolbar .page-actions,
    .page-heading-toolbar .button-row {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2);
        overflow: visible;
    }

    .page-heading-toolbar .page-heading-action-group {
        flex: 1 1 100%;
    }

    .page-heading-toolbar .page-heading-action-group > .button {
        flex: 1 1 10rem;
    }

}

@media (max-width: 52rem) {
    .form-grid.two-column,
    .form-grid.three-column,
    .definition-grid {
        grid-template-columns: 1fr;
    }

    .field-span-2 {
        grid-column: auto;
    }
}

/* --------------------------------------------------------------------------
   Phone tier: data tables as stacked record cards

   A table is a grid of columns whose meaning comes from the header row above
   them. That contract cannot hold on a phone: the narrowest table here asks for
   44rem and the widest for 56rem, against roughly 20rem of usable width, so the
   only way to keep the columns is to hand the user a horizontal scroll region
   that carries the record's identity off screen the moment they reach the later
   fields. Below the breakpoint each row is therefore re-presented as a
   self-contained card: identity first and prominent, then every remaining field
   as a labelled value pair. No column is dropped and nothing is shrunk to fit.

   52rem is the threshold because it is the tier at which the existing two-column
   grids already collapse, and because no table here fits below it: past this
   point the alternative is not a narrower table, it is a scrollbar.

   Every table in the app carries `.data-table`, so this one block drives all of
   them. Two things are required of the markup it works on:

     - each `<td>` carries `data-label` with its column's header text, since a
       bare value with no header is meaningless once the header row is gone;
     - the table keeps explicit ARIA roles, because setting `display` away from
       the table values strips the implicit table semantics in every engine.

   Sorting survives as a chip strip built from the header row itself, so it stays
   the same links driven by the same query string as on desktop.
   -------------------------------------------------------------------------- */

@media (max-width: 52rem) {
    /* The scroll containers have nothing left to scroll, and leaving them as
       scroll ports would clip the cards' focus rings. */
    .table-scroll,
    .table-shell {
        overflow-x: visible;
    }

    .data-table {
        display: block;
        min-width: 0;
        width: 100%;
    }

    /* ---- Header row: reduced to a sort strip ---- */

    .data-table > thead {
        display: block;
    }

    .data-table > thead > tr {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2);
    }

    /* Labels for a grid that no longer exists. The sortable ones stay because
       they are controls, not decoration; the values carry their own labels. */
    .data-table > thead th {
        display: none;
    }

    .data-table > thead th::after {
        display: none;
    }

    .data-table > thead th.th-sortable {
        background: transparent;
        border-bottom: 0;
        display: block;
        padding: 0;
    }

    /* Names the strip for what it now is. Decorative only: the chips work
       whether or not the engine supports :has(). */
    .data-table > thead > tr:has(.th-sortable)::before {
        align-self: center;
        color: var(--color-text-faint);
        content: "Sort by";
        font-family: var(--font-display);
        font-size: 0.64rem;
        font-stretch: 75%;
        font-weight: 700;
        letter-spacing: var(--tracking-label);
        text-transform: uppercase;
    }

    .data-table > thead .sort-header {
        --notch: 0.3rem;
        background: var(--color-surface);
        border: var(--hairline) solid var(--color-border);
        clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
        color: var(--color-text-muted);
        font-family: var(--font-display);
        font-size: 0.72rem;
        font-stretch: 75%;
        font-weight: 700;
        min-height: 2.4rem;
        padding: 0 var(--space-3);
    }

    /* Clip-path is applied only in this card layout; desktop sort links keep the global outline. */
    .data-table > thead .sort-header:focus-visible {
        box-shadow: var(--focus-ring);
        outline: none;
    }

    .data-table > thead .sort-header.is-active {
        border-color: var(--color-accent);
        color: var(--color-accent-text);
    }

    /* ---- Body rows: one card per record ---- */

    .data-table > tbody {
        display: block;
    }

    .data-table > tbody > tr {
        --notch: var(--notch-sm);
        background: var(--color-field);
        border: var(--hairline) solid var(--color-border);
        clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
        display: block;
        margin-top: var(--space-3);
        padding: var(--space-3) var(--space-4);
    }

    .data-table > tbody > tr:hover {
        box-shadow: inset 2px 0 0 var(--color-accent);
    }

    /* The desktop hover marker lived on the first cell, which is now the card
       head rather than the card's left edge. */
    .data-table > tbody > tr:hover > td:first-child {
        box-shadow: none;
    }

    /* Phone cards wrap at word boundaries and split only oversized identifiers. */
    .data-table > tbody > tr > td {
        border-bottom: 0;
        display: grid;
        gap: var(--space-1) var(--space-3);
        grid-template-columns: minmax(0, 1fr);
        hyphens: none;
        min-width: 0;
        overflow-wrap: break-word;
        padding: var(--space-2) 0;
    }

    .data-table > tbody > tr > td[data-label] {
        align-items: baseline;
        grid-template-columns: minmax(0, var(--table-card-label-width, 6.5rem)) minmax(0, 1fr);
    }

    .data-table > tbody > tr > td[data-label]::before {
        color: var(--color-text-faint);
        content: attr(data-label);
        font-family: var(--font-display);
        font-size: 0.64rem;
        font-stretch: 75%;
        font-weight: 700;
        letter-spacing: var(--tracking-label);
        line-height: 1.35;
        text-transform: uppercase;
    }

    /* A cell holding controls or its own disclosure needs the full card width;
       squeezed into the value column the form inside it becomes unusable. */
    .data-table > tbody > tr > td.cell-actions,
    .data-table > tbody > tr > td:has(.button, form, details, .inline-editor, .text-action) {
        grid-template-columns: minmax(0, 1fr);
    }

    /* ---- Card head: the record's identity ---- */

    .data-table > tbody > tr > td:first-child {
        padding-top: 0;
    }

    .data-table > tbody > tr > td.cell-select {
        margin-bottom: 0;
        padding-bottom: var(--space-2);
    }

    .data-table > tbody > tr > td:has(.record-key),
    .data-table > tbody > tr > td:has(.record-title) {
        border-bottom: var(--hairline) solid var(--color-border);
        font-size: 0.95rem;
        grid-template-columns: minmax(0, 1fr);
        margin-bottom: var(--space-2);
        padding-bottom: var(--space-3);
    }

    .data-table > tbody > tr > td:has(.record-key)::before,
    .data-table > tbody > tr > td:has(.record-title)::before {
        display: none;
    }

    .data-table > tbody > tr > td:has(.record-key) .record-key,
    .data-table > tbody > tr > td:has(.record-title) .record-title {
        font-size: 0.95rem;
    }

    /* Every labelled field remains available in card mode. Class names describe
       styling, not whether a timestamp, notification body or second status matters.
       Pages can group secondary content in an explicitly labelled native disclosure;
       the shared table never silently removes it or a record's actions. */

    /* ---- Values that were held to one line by the scroll region ---- */

    /* Nothing scrolls sideways any more, so single-line values that no longer
       fit have to be allowed to wrap rather than push the card wider. */
    .data-table time,
    .keys-table .cell-prefix,
    .keys-table .cell-state,
    .keys-table .cell-time,
    .keys-table .cell-prefix code,
    .criteria-table .cell-order,
    .criteria-table .cell-flag,
    .criteria-table .cell-method,
    .criteria-table .cell-result {
        white-space: normal;
    }

    .keys-table .cell-prefix code {
        overflow-wrap: anywhere;
    }

    /* Column sizing is meaningless once the columns are gone, and a percentage
       width on a grid cell would fight the label/value tracks. */
    .keys-table,
    .criteria-table {
        min-width: 0;
    }

    .data-table > tbody > tr > td.cell-order,
    .data-table > tbody > tr > td.cell-flag {
        text-align: left;
        width: auto;
    }

    .keys-table .cell-scopes,
    .scope-chips-expanded {
        max-width: none;
        min-width: 0;
    }

    .keys-table .cell-actions,
    .criteria-table .cell-actions {
        min-width: 0;
        width: auto;
    }

    .criterion-actions {
        min-width: 0;
    }

    /*
     * Projects directory (AIWO-125): reclaim nested gutters and stop mid-word
     * breaks on long names like AI_Workforce_Orchestrator. Desktop table layout
     * is unchanged; these rules only apply in the stacked-card tier.
     */
    .projects-directory-panel > .panel-header,
    .projects-directory-panel > .panel-body {
        padding-inline: var(--space-3);
    }

    .projects-directory > tbody > tr {
        display: grid;
        gap: var(--space-2) var(--space-3);
        grid-template-columns: auto minmax(0, 1fr);
        margin-top: var(--space-2);
        padding: var(--space-2) var(--space-3);
    }

    .projects-directory > tbody > tr > td:has(.record-key),
    .projects-directory > tbody > tr > td:has(.record-title) {
        border-bottom: 0;
        margin-bottom: 0;
        padding: 0;
    }

    .projects-directory > tbody > tr > td:has(.record-key) {
        align-self: baseline;
        grid-column: 1;
    }

    .projects-directory > tbody > tr > td:has(.record-title) {
        align-self: baseline;
        border-bottom: var(--hairline) solid var(--color-border);
        grid-column: 2;
        min-width: 0;
        padding-bottom: var(--space-2);
    }

    .projects-directory > tbody > tr > td:has(.status-chip) {
        align-items: center;
        grid-column: 1 / -1;
        grid-template-columns: auto minmax(0, 1fr);
        padding: var(--space-1) 0 0;
    }

    .projects-directory .record-title {
        display: -webkit-box;
        hyphens: none;
        line-clamp: 2;
        overflow: hidden;
        overflow-wrap: normal;
        word-break: keep-all;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
    }

    .projects-directory .record-key {
        font-size: 0.75rem;
    }
}

@media (max-width: 40rem) {
    :root {
        --notch-lg: 0.9rem;
    }

    .metric-grid {
        gap: var(--space-3);
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .stat-tile {
        padding: var(--space-3);
    }

    .stat-value {
        font-size: 1.65rem;
    }

    .stat-note {
        display: none;
    }

    .panel-header,
    .panel-body {
        padding-inline: var(--space-4);
    }

    .form-section-heading {
        grid-template-columns: 1fr;
    }

    .key-issue {
        padding: var(--space-4);
    }

    /* Form submit rows stay stacked. Card and heading clusters stay two-up. */
    .form-actions,
    .instruction-card > header {
        align-items: stretch;
        display: grid;
        justify-content: stretch;
    }

    .form-actions .button,
    .form-actions form,
    .form-actions form .button {
        width: 100%;
    }

    .button-row,
    .page-actions {
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .button-row .button,
    .page-actions .button {
        flex: 1 1 9rem;
        width: auto;
    }

    /* Chip rows inside a definition grid carry metadata, not actions, so they keep wrapping. */
    .definition-grid .button-row {
        align-items: center;
        display: flex;
    }

    .toolbar-form {
        align-items: stretch;
        display: grid;
        width: 100%;
    }

    .toolbar-form .select-control,
    .toolbar-form .button {
        width: 100%;
    }

    .pager {
        justify-content: center;
    }

    .empty-state {
        display: grid;
        justify-items: start;
    }
}

/* --------------------------------------------------------------------------
   Narrow topbar: ≤ 46rem

   MainLayout collapses the topbar here (tighter padding, search disclosure).
   Keep --topbar-height equal to the collapsed bar: --touch-min + 2× --space-3,
   with border-box so padding is inside the min-height.
   -------------------------------------------------------------------------- */

@media (max-width: 46rem) {
    :root {
        --topbar-height: 4.25rem;
    }

}

/* --------------------------------------------------------------------------
   Phone tier: ≤ 26.875rem (430 CSS px)

   The 40rem block serves everything from 640px down. Common phones report 360–
   430 CSS px, so spacing and type that are merely tight at 620px become cramped
   at 375px. This tier retunes for that range only; 431px–640px keep the 40rem
   rules, and 1280px+ is untouched.

   Hit areas use --touch-min (2.75rem = 44 CSS px). Where a control is visually
   small by design, min-height / min-width expand the box the finger hits without
   changing the desktop look.
   -------------------------------------------------------------------------- */

@media (max-width: 26.875rem) {
    :root {
        --notch-md: 0.65rem;
        --notch-lg: 0.75rem;
        --space-4: 0.875rem;
        --space-5: 1rem;
        --space-6: 1.15rem;
        --space-7: 1.5rem;
        --space-8: 2.25rem;
        /* Phone tier pads the topbar with --space-2; match that height. */
        --topbar-height: 3.75rem;
    }

    body {
        font-size: 0.9rem;
        line-height: 1.5;
    }

    h1 {
        font-size: clamp(1.55rem, 8vw, 1.85rem);
    }

    h2 {
        font-size: 1.15rem;
    }

    .panel-header,
    .panel-body {
        padding-inline: var(--space-3);
    }

    .projects-directory-panel > .panel-header,
    .projects-directory-panel > .panel-body {
        padding-inline: var(--space-2);
    }

    .panel-body {
        padding-block: var(--space-4);
    }

    .dialog-header,
    .dialog-body,
    .dialog-footer {
        padding: var(--space-3) var(--space-4);
    }

    .dialog-footer {
        gap: var(--touch-gap);
    }

    .metric-grid {
        gap: var(--space-4);
    }

    /* ---- 44×44 hit areas (audit list) ---- */

    .button,
    .button-small {
        min-height: var(--touch-min);
        min-width: var(--touch-min);
        padding-inline: var(--space-4);
    }

    .button-row,
    .page-actions,
    .form-actions,
    .panel-actions {
        gap: var(--touch-gap);
    }

    .field-control,
    .select-control {
        min-height: var(--touch-min);
    }

    /* Label is the hit target; the native box stays visually small. */
    .check-control {
        gap: var(--space-3);
        min-height: var(--touch-min);
        padding-block: var(--space-2);
    }

    .toolbar-form .check-control {
        min-height: var(--touch-min);
    }

    .pager-list {
        gap: var(--touch-gap);
    }

    .pager-link {
        min-height: var(--touch-min);
        min-width: var(--touch-min);
        padding-inline: var(--space-3);
    }

    /* Phone card presentation already restyles these; enforce the floor. */
    .data-table > thead .sort-header {
        min-height: var(--touch-min);
        padding: 0 var(--space-3);
    }

    .notification-trigger {
        box-sizing: border-box;
        justify-content: center;
        min-height: var(--touch-min);
        min-width: var(--touch-min);
        padding: 0;
        width: var(--touch-min);
    }

    .text-action {
        display: inline-flex;
        align-items: center;
        min-height: var(--touch-min);
        padding-inline: var(--space-2);
    }

    /* Blazor error dismiss is the only dedicated close control in the shell. */
    #blazor-error-ui .dismiss {
        align-items: center;
        display: inline-flex;
        justify-content: center;
        min-height: var(--touch-min);
        min-width: var(--touch-min);
        right: var(--space-2);
        top: var(--space-2);
    }
}

/* --------------------------------------------------------------------------
   Mobile density tier: ≤ 48rem (768 CSS px)

   The tiers above this one are about *layout*: what collapses, what stacks, what
   turns into a card. None of them change how big anything is, so a phone renders
   the desktop's type ramp and desktop's spacing scale in a 390px column and burns
   most of the viewport on padding. This tier is about *density*, and it is the
   last responsive block in the file on purpose: it has to win the equal-specificity
   ties against the 52 / 46 / 40 / 26.875rem blocks that precede it.

   It works token-first. Because the shell and every component already size
   themselves from --space-*, --touch-min, --font-size-label and --topbar-height,
   retuning those here moves most of the app in one place; the rules that follow
   are only for metrics that were written as literals. Nothing is hidden, no
   component is restructured, and the die-cut geometry is untouched — the notch
   tokens shrink with the boxes they cut so the shapes stay in proportion.

   Readability and targets share the desktop role tokens. Compact gutters remain,
   while body text, labels and actions retain a legible hierarchy. Text entry keeps
   its independent 16px focus-zoom floor. Controls share the 44px touch minimum;
   shell offsets derive from that same minimum and their actual padding.
   -------------------------------------------------------------------------- */

@media (max-width: 48rem) {
    :root {
        /* Compact spacing scale: 4 / 6 / 8 / 10 / 12 / 16 / 20 / 24. */
        --space-1: 0.25rem;
        --space-2: 0.375rem;
        --space-3: 0.5rem;
        --space-4: 0.625rem;
        --space-5: 0.75rem;
        --space-6: 1rem;
        --space-7: 1.25rem;
        --space-8: 1.5rem;

        --font-size-label: var(--text-2xs);
        --tracking-label: 0.1em;
        --tracking-kicker: 0.14em;

        /* Phone type is compact without shrinking operational text to 8-11px. */
        --text-2xs: 0.75rem;
        --text-xs: 0.8125rem;
        --text-sm: 0.875rem;
        --text-body: 0.9375rem;
        --text-md: 1rem;
        --text-lg: 1.0625rem;
        --text-xl: 1.25rem;
        --text-control-min: 16px;
        --table-card-label-width: 5.5rem;

        --control-h: var(--touch-min);
        --control-h-sm: var(--touch-min);

        --notch-sm: 0.35rem;
        --notch-md: 0.55rem;
        --notch-lg: 0.7rem;

        --touch-min: 2.75rem;
        --touch-gap: 0.375rem;

        /* The topbar contains one touch-height row plus its two padding edges.
           Safe-area padding participates in the same sticky offset. */
        --topbar-height: calc(var(--touch-min) + var(--space-2) + max(var(--space-2), env(safe-area-inset-top, 0px)));
        --tab-bar-height: 3.25rem;
    }

    /* ---- Typography ---- */

    body {
        font-size: var(--text-body);
        line-height: 1.5;
    }

    /* Compound selectors, not bare `h1`: .page-heading h1, .page-heading-record h1
       and .account-card h1 all set their own size and would otherwise outrank a
       single-element selector here. */
    h1,
    .page-heading h1,
    .page-heading-record h1,
    .account-card h1 {
        font-size: 1.375rem;
        letter-spacing: 0.01em;
        line-height: 1.2;
        margin-bottom: var(--space-2);
        max-width: none;
    }

    h2 {
        font-size: var(--text-lg);
    }

    h3 {
        font-size: var(--text-md);
    }

    h4 {
        font-size: var(--text-body);
    }

    .eyebrow {
        font-size: var(--font-size-label);
        gap: var(--space-1);
        margin-bottom: var(--space-1);
    }

    .eyebrow::before {
        height: 0.55rem;
        width: 0.22rem;
    }

    .page-description,
    .account-copy,
    .preserve-text {
        font-size: var(--text-sm);
        line-height: 1.5;
    }

    /* ---- Panels ---- */

    .panel-header {
        gap: var(--space-2);
        min-height: 0;
        padding: var(--space-3) var(--space-4);
    }

    .panel-kicker {
        font-size: var(--text-2xs);
        margin-bottom: 0;
    }

    .panel-title {
        font-size: var(--text-lg);
    }

    .panel-title::after {
        bottom: -0.25rem;
        width: 2rem;
    }

    .panel-body {
        padding: var(--space-4);
    }

    .panel-subtitle {
        font-size: var(--text-sm);
    }

    /* clamp() bottoms out at 1.5rem, which is still desktop padding on a phone. */
    .account-card {
        padding: var(--space-5) var(--space-4);
    }

    .account-card .button {
        margin-top: var(--space-1);
    }

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

    .button {
        font-size: var(--text-xs);
        gap: var(--space-1);
        letter-spacing: 0.05em;
        min-height: var(--touch-min);
        padding: 0 var(--space-4);
        text-align: center;
        white-space: normal;
    }

    .button-small,
    .text-action {
        font-size: var(--text-2xs);
        min-height: var(--touch-min);
        padding-inline: var(--space-3);
    }

    /* Shared controls retain the touch floor at every phone breakpoint. */
    .button,
    .button-small {
        padding-inline: var(--space-4);
    }

    .button-row,
    .panel-actions,
    .page-actions,
    .form-actions {
        gap: var(--space-2);
    }

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

    .field-group {
        gap: var(--space-1);
    }

    .field-group > label {
        font-size: var(--text-2xs);
    }

    /* Text entry retains its 16px floor; control height follows the shared target. */
    .field-control,
    .select-control,
    .text-area-control {
        min-height: var(--control-h);
        padding: 0 var(--space-3);
    }

    .select-control {
        background-position: right 0.85rem center, right 0.55rem center;
        padding-right: 1.6rem;
    }

    .text-area-control {
        line-height: 1.45;
        min-height: 4.5rem;
        padding-block: var(--space-2);
    }

    .check-control {
        font-size: var(--text-sm);
        gap: var(--space-2);
        min-height: var(--touch-min);
        padding-block: var(--space-1);
    }

    /* Spacers and alignment shims, not controls: each exists to line something up
       with a field or a button, so they have to move with the new control heights
       or they reintroduce the gap they were added to close. */
    .field-align-end {
        min-height: var(--touch-min);
    }

    .page-actions:has(.button) > .status-chip {
        min-height: var(--touch-min);
    }

    .toolbar-form .select-control,
    .toolbar-form .check-control {
        min-height: var(--touch-min);
    }

    /* Long-form editors: a fixed rem height written for a desktop column is most
       of a phone screen. They all keep resize: vertical. */
    .instruction-editor {
        min-height: 7rem;
    }

    .inline-editor .text-area-control {
        min-height: 4.5rem;
    }

    .copy-prompt-disclosure .code-input {
        min-height: 5rem;
    }

    .field-help,
    .form-section-heading p,
    .validation-message,
    .field-optional {
        font-size: var(--text-2xs);
        line-height: 1.4;
    }

    .form-section {
        gap: var(--space-3);
        padding-bottom: var(--space-4);
    }

    .form-section-heading {
        gap: var(--space-1);
    }

    .form-section-heading h2 {
        font-size: var(--text-md);
    }

    .form-grid {
        gap: var(--space-3);
    }

    .stack-form,
    .entity-form {
        gap: var(--space-3);
    }

    .toolbar-form {
        gap: var(--space-2);
    }

    .code-input {
        font-size: var(--text-sm);
    }

    /* ---- Chips ---- */

    .status-chip {
        font-size: var(--font-size-label);
        gap: var(--space-1);
        letter-spacing: 0.06em;
        padding: 0.2rem 0.35rem;
    }

    .status-dot {
        height: 0.3rem;
        width: 0.3rem;
    }

    /* ---- Stat tiles ---- */

    .metric-grid {
        gap: var(--space-2);
        margin-bottom: var(--space-4);
    }

    .stat-tile {
        gap: var(--space-1);
        padding: var(--space-3) var(--space-4);
    }

    .stat-glyph {
        font-size: 0.8rem;
        height: 1.85rem;
        margin-right: 0;
        width: 1.85rem;
    }

    .stat-label {
        font-size: var(--font-size-label);
    }

    .stat-value {
        font-size: 1.375rem;
    }

    .stat-meta {
        gap: var(--space-1);
        margin-top: 0;
    }

    /* ---- Tables presented as record cards (the ≤52rem layout) ---- */

    .data-table > tbody > tr {
        margin-top: var(--space-2);
        padding: var(--space-2) var(--space-3);
    }

    .data-table > tbody > tr > td {
        gap: var(--space-1) var(--space-2);
        padding: 0.1875rem 0;
    }

    .data-table > tbody > tr > td[data-label]::before {
        font-size: var(--text-2xs);
        line-height: 1.3;
    }

    /* The value track is a grid column, so a chip in it stretches to the full card
       width by default and stops reading as a chip. It sizes to its label instead. */
    .data-table > tbody > tr > td > .status-chip {
        justify-self: start;
    }

    .data-table > tbody > tr > td:has(.record-key),
    .data-table > tbody > tr > td:has(.record-title) {
        font-size: var(--text-md);
        margin-bottom: var(--space-1);
        padding-bottom: var(--space-2);
    }

    .data-table > tbody > tr > td:has(.record-key) .record-key,
    .data-table > tbody > tr > td:has(.record-title) .record-title {
        font-size: var(--text-md);
    }

    .data-table > thead > tr {
        gap: var(--space-1);
    }

    .data-table > thead > tr:has(.th-sortable)::before {
        font-size: var(--text-2xs);
    }

    .data-table > thead .sort-header {
        font-size: var(--text-2xs);
        min-height: var(--touch-min);
        padding: 0 var(--space-3);
    }

    .record-key,
    .record-preview {
        font-size: var(--text-sm);
    }

    .correlation-value {
        font-size: var(--text-2xs);
    }

    .definition-grid {
        gap: var(--space-3);
    }

    .definition-grid > div {
        gap: var(--space-1);
    }

    .definition-grid dt {
        font-size: var(--text-2xs);
    }

    .definition-grid dd {
        font-size: var(--text-sm);
    }

    /* ---- Tabs and pagination ---- */

    .tabs {
        gap: 0;
        margin-bottom: var(--space-3);
    }

    .tab {
        font-size: var(--text-xs);
        padding: var(--space-2) var(--space-3);
    }

    .pager {
        gap: var(--space-2);
        margin-top: var(--space-3);
        padding-top: var(--space-3);
    }

    .pager-status {
        font-size: var(--text-2xs);
    }

    .pager-link {
        font-size: var(--text-xs);
        min-height: var(--touch-min);
        min-width: var(--touch-min);
        padding-inline: var(--space-2);
    }

    /* ---- Lists ---- */

    .activity-feed li {
        gap: var(--space-2);
        padding: var(--space-2) 0;
    }

    .activity-feed strong {
        font-size: var(--text-body);
    }

    .activity-feed small {
        font-size: var(--text-2xs);
    }

    .operation-list a {
        gap: var(--space-2);
        padding: var(--space-2) var(--space-3);
    }

    .operation-list strong {
        font-size: var(--text-body);
    }

    .operation-list small {
        font-size: var(--text-2xs);
    }

    .instruction-list {
        gap: var(--space-2);
    }

    .instruction-card {
        padding: var(--space-3);
    }

    .instruction-card h3 {
        font-size: var(--text-md);
    }

    .instruction-card header p,
    .instruction-card footer {
        font-size: var(--text-2xs);
    }

    .board-grid {
        gap: var(--space-2);
    }

    .board-column {
        padding: var(--space-3);
    }

    .board-column h3 {
        font-size: var(--text-body);
    }

    .board-card {
        gap: var(--space-1);
        padding: var(--space-2);
    }

    /* ---- Empty, loading and alert states ---- */

    .empty-state,
    .empty-state.compact {
        gap: var(--space-3);
        min-height: 0;
        padding: var(--space-3) 0;
    }

    .empty-state strong {
        font-size: var(--text-body);
    }

    .empty-state p {
        font-size: var(--text-xs);
    }

    .empty-state .button {
        margin-top: var(--space-2);
    }

    .empty-mark {
        font-size: 1rem;
        height: 2.25rem;
        width: 2.25rem;
    }

    .empty-state.compact .empty-mark {
        font-size: 0.85rem;
        height: 1.85rem;
        width: 1.85rem;
    }

    .loading-state {
        gap: var(--space-3);
        padding: var(--space-3) 0;
    }

    .loading-state strong {
        font-size: var(--text-body);
    }

    .loading-state p {
        font-size: var(--text-xs);
    }

    .loading-mark {
        height: 1.6rem;
    }

    .form-alert,
    .page-alert {
        font-size: var(--text-sm);
        padding: var(--space-2) var(--space-3);
    }

    .request-id {
        font-size: var(--text-2xs);
    }

    /* ---- Dialogs ---- */

    .dialog-header,
    .dialog-body,
    .dialog-footer {
        padding: var(--space-3) var(--space-4);
    }

    .dialog-body {
        font-size: var(--text-sm);
        line-height: 1.5;
    }

    /* ---- Page layout ---- */

    .page-heading {
        margin-bottom: var(--space-4);
        padding-bottom: var(--space-2);
    }

    .page-heading-toolbar {
        margin-top: var(--space-2);
    }

    /*
     * The 46rem heading cluster is a nowrap overflow-x scroller. That is still
     * horizontal scroll on a 390px viewport. Wrapping compact buttons keeps the
     * page itself from panning; Chat/Board list-row treatment lives in those
     * pages' own sheets so Dashboard/Projects keep the fold.
     */
    .page-heading-toolbar .page-actions,
    .page-heading-toolbar .button-row {
        flex-wrap: wrap;
        overflow-x: visible;
        padding-bottom: 0;
    }

    .dashboard-grid,
    .detail-grid {
        gap: var(--space-2);
    }

    .page-container > * + *,
    .admin-settings-body > * + *,
    .project-workspace-body > * + * {
        margin-top: var(--space-4);
    }

    .page-container > .print-document-stamp + * {
        margin-top: 0;
    }

    /* ---- Import surfaces ---- */

    .import-intro p {
        font-size: var(--text-xs);
    }

    .import-drop-zone {
        padding: var(--space-4);
    }

    .import-drop-zone span {
        font-size: var(--text-xs);
    }

    .import-preview h3 {
        font-size: var(--text-body);
    }

    /* ---- Code and key surfaces ---- */

    .code-viewer {
        font-size: var(--text-xs);
        line-height: 1.45;
        max-height: 24rem;
        padding: var(--space-3);
    }

    .code-crumbs {
        font-size: var(--text-xs);
        margin-bottom: var(--space-3);
    }

    .key-issue {
        padding: var(--space-3);
    }

    .key-issue-heading h3 {
        font-size: var(--text-md);
    }

    .key-issue-heading p {
        font-size: var(--text-xs);
    }

    .scope-chips {
        gap: var(--space-1);
    }
}

@media (max-width: 48rem) and (display-mode: standalone) {
    :root {
        --topbar-height: calc(var(--touch-min) + var(--space-2) + max(var(--space-3), env(safe-area-inset-top, 0px)));
    }
}

/* --------------------------------------------------------------------------
   19. Motion and contrast preferences
   -------------------------------------------------------------------------- */

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

    .button:hover:not(:disabled),
    a.stat-tile:hover {
        transform: none;
    }
}

@media (prefers-contrast: more) {
    :root {
        --color-border: #4a5058;
        --color-border-strong: #6b727b;
        --color-text-muted: #e4e6e8;
        --color-text-subtle: #c8ccd1;
        --color-text-faint: #b0b5bb;
        --color-accent-text: #ff7ab0;
        --texture-line: transparent;
        --focus-ring: inset 0 0 0 3px var(--color-accent-hover), inset 0 0 0 6px var(--color-text);
    }

    body::before {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   20. Phase 6 notifications

   Topbar bell + dropdown. Consumes tokens only: no colour / shadow / radius /
   spacing literals. Trigger matches neighbouring topbar icon controls
   (search-toggle, mobile-menu summary): same height and CUT-BR die-cut.
   -------------------------------------------------------------------------- */

.notification-panel {
    position: relative;
}

/* Matches neighbouring topbar icon controls (search-toggle): --touch-min square. */
.notification-trigger {
    --notch: var(--notch-sm);
    align-items: center;
    background: transparent;
    border: var(--hairline) solid var(--color-border-strong);
    box-sizing: border-box;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: var(--color-text);
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font: inherit;
    gap: var(--space-1);
    justify-content: center;
    line-height: 1;
    list-style: none;
    min-height: var(--touch-min);
    min-width: var(--touch-min);
    padding: 0;
    position: relative;
    transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
    width: var(--touch-min);
}

.notification-trigger:hover {
    border-color: var(--color-accent);
    color: var(--color-accent-text);
}

.notification-trigger:focus-visible {
    border-color: var(--color-accent);
    box-shadow: var(--focus-ring);
    outline: 0;
}

.notification-trigger[aria-expanded="true"] {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-ink);
}

.notification-trigger[aria-expanded="true"]:focus-visible {
    box-shadow: var(--focus-ring);
}

/* CUT-BOTH die-cut count tile; padding grows for two- and three-digit counts. */
.notification-badge {
    --notch: calc(var(--notch-sm) * 2 / 3);
    align-items: center;
    background: var(--color-accent);
    border: var(--hairline) solid var(--color-accent);
    clip-path: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
    color: var(--color-ink);
    display: inline-flex;
    font-family: var(--font-display);
    font-size: var(--font-size-label);
    font-stretch: 75%;
    font-weight: 700;
    height: var(--space-5);
    justify-content: center;
    letter-spacing: var(--tracking-label);
    line-height: 1;
    min-width: var(--space-5);
    padding: 0 var(--space-1);
    position: absolute;
    right: calc(var(--space-1) * -1);
    top: calc(var(--space-1) * -1);
}

/* Keep the count legible when the trigger fills with accent. */
.notification-trigger[aria-expanded="true"] .notification-badge {
    background: var(--color-ink);
    border-color: var(--color-ink);
    color: var(--color-accent-text);
}

.notification-backdrop {
    display: none;
}

/*
 * Floating dropdown menu
 */
.notification-dropdown {
    background: var(--color-surface);
    border: var(--hairline) solid var(--color-border-strong);
    border-top: 2px solid var(--color-accent);
    border-radius: var(--radius-md, 0.5rem);
    box-shadow: 0 16px 36px rgba(0, 0, 0, 0.65), 0 0 16px rgba(255, 42, 109, 0.12);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-height: min(32rem, calc(100dvh - var(--topbar-height) - var(--space-6)));
    max-width: calc(100vw - var(--space-8));
    padding: var(--space-4);
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-2));
    width: min(26rem, calc(100vw - var(--space-8)));
    z-index: 40;
    animation: notificationFadeIn 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}

.notification-dropdown-header {
    align-items: center;
    border-bottom: var(--hairline) solid var(--color-border);
    display: flex;
    flex-shrink: 0;
    gap: var(--space-3);
    justify-content: space-between;
    padding-bottom: var(--space-3);
}

.notification-header-title {
    align-items: center;
    display: flex;
    gap: var(--space-2);
}

.notification-header-icon {
    font-size: 1rem;
    line-height: 1;
}

.notification-header-title strong {
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

.notification-unread-chip {
    background: var(--color-accent-soft);
    border: var(--hairline) solid var(--color-accent);
    border-radius: var(--radius-sm);
    color: var(--color-accent-text);
    font-family: var(--font-display);
    font-size: 0.65rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    padding: 0.12rem 0.45rem;
    text-transform: uppercase;
}

.notification-header-actions {
    align-items: center;
    display: flex;
    gap: var(--space-2);
}

.notification-mark-read {
    font-size: 0.78rem;
    white-space: nowrap;
}

.notification-close-btn {
    align-items: center;
    background: transparent;
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-subtle);
    cursor: pointer;
    display: inline-flex;
    height: 1.85rem;
    justify-content: center;
    transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
    width: 1.85rem;
}

.notification-close-btn:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-accent);
    color: var(--color-accent-text);
}

.notification-empty {
    align-items: center;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    justify-content: center;
    padding: var(--space-5) var(--space-3);
    text-align: center;
}

.notification-empty-glyph {
    color: var(--color-accent);
    font-size: 1.6rem;
    line-height: 1;
    margin-bottom: var(--space-1);
}

.notification-empty-title {
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: 0.88rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    margin: 0;
    text-transform: uppercase;
}

.notification-empty-desc {
    color: var(--color-text-muted);
    font-size: 0.8rem;
}

.notification-list {
    display: grid;
    flex: 1 1 auto;
    gap: var(--space-2);
    list-style: none;
    margin: 0;
    max-height: calc(var(--space-8) * 6);
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-1) 0;
}

.notification-list li {
    display: block;
}

.notification-list li > a,
.notification-item-button {
    --notch: var(--notch-sm);
    background: var(--color-field);
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-sm);
    box-sizing: border-box;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
    color: inherit;
    cursor: pointer;
    display: grid;
    font: inherit;
    gap: var(--space-1);
    max-width: 100%;
    min-width: 0;
    overflow-wrap: anywhere;
    padding: 0.65rem 0.85rem;
    text-align: left;
    text-decoration: none;
    transition: background var(--transition-fast), border-color var(--transition-fast);
    width: 100%;
    word-break: break-word;
}

.notification-list li > a:hover,
.notification-item-button:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-border-strong);
}

.notification-list li > a:focus-visible,
.notification-item-button:focus-visible {
    border-color: var(--color-accent);
    box-shadow: var(--focus-ring);
    outline: none;
}

.notification-list li > a:hover:focus-visible,
.notification-item-button:hover:focus-visible {
    box-shadow: var(--focus-ring);
}

.notification-list li.unread > a,
.notification-list li.unread .notification-item-button {
    background: color-mix(in srgb, var(--color-accent-soft) 28%, var(--color-field));
    border-color: var(--color-accent);
    border-left: 3px solid var(--color-accent);
}

.notification-list li.unread > a:hover,
.notification-list li.unread .notification-item-button:hover {
    background: color-mix(in srgb, var(--color-accent-soft) 42%, var(--color-field));
}

.notification-item-header {
    align-items: baseline;
    display: flex;
    gap: var(--space-2);
    justify-content: space-between;
}

.notification-item-title {
    color: var(--color-text);
    font-size: 0.86rem;
    font-weight: 600;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.notification-list li.unread .notification-item-title {
    color: var(--color-accent-text);
}

.notification-item-body {
    color: var(--color-text-muted);
    font-size: 0.78rem;
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.notification-time {
    color: var(--color-text-faint);
    flex-shrink: 0;
    font-family: var(--font-display);
    font-size: 0.68rem;
    font-stretch: 75%;
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    white-space: nowrap;
}

.notification-dropdown-footer {
    border-top: var(--hairline) solid var(--color-border);
    display: flex;
    flex-shrink: 0;
    justify-content: stretch;
    padding-top: var(--space-3);
}

.notification-view-all-link {
    font-size: 0.82rem;
    justify-content: center;
    text-align: center;
    width: 100%;
}

.notification-dropdown .field-help {
    margin: 0;
}

/* Animations */
@keyframes notificationFadeIn {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes notificationSlideIn {
    from {
        opacity: 0;
        transform: translateY(-10px) scale(0.98);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes notificationBackdropFade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Mobile Media Queries */
@media (max-width: 48rem) {
    .notification-backdrop {
        animation: notificationBackdropFade 0.2s ease-out;
        backdrop-filter: blur(6px);
        -webkit-backdrop-filter: blur(6px);
        background: rgba(4, 7, 13, 0.75);
        display: block;
        inset: 0;
        position: fixed;
        z-index: 99;
    }

    /*
     * Keep all responsive notification overrides after the base Phase 6 block.
     * Equal-specificity rules earlier in this file are intentionally avoided so
     * desktop positioning cannot win through source order.
     */
    .notification-panel {
        position: static;
    }

    .notification-dropdown {
        --notification-block-end: max(var(--space-3), env(safe-area-inset-bottom, 0px));
        --notification-block-start: calc(var(--topbar-height) + max(var(--space-2), env(safe-area-inset-top, 0px)));
        --notification-inline-end: max(var(--space-3), env(safe-area-inset-right, 0px));
        --notification-inline-start: max(var(--space-3), env(safe-area-inset-left, 0px));
        animation: notificationSlideIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
        background: linear-gradient(170deg, var(--color-surface) 0%, var(--color-background-raised) 100%);
        border: var(--hairline) solid var(--color-border-strong);
        border-radius: var(--radius-md, 0.5rem);
        border-top: 2px solid var(--color-accent);
        box-shadow: 0 20px 48px rgba(0, 0, 0, 0.8), 0 0 24px rgba(255, 42, 109, 0.18);
        box-sizing: border-box;
        left: var(--notification-inline-start);
        max-height: calc(100dvh - var(--notification-block-start) - var(--notification-block-end));
        max-width: calc(100vw - var(--notification-inline-start) - var(--notification-inline-end));
        padding: var(--space-4);
        position: fixed;
        right: var(--notification-inline-end);
        top: var(--notification-block-start);
        width: auto;
        z-index: 100;
    }

    .notification-dropdown-header,
    .notification-header-title,
    .notification-item-header {
        min-width: 0;
    }

    .notification-dropdown-header,
    .notification-header-title,
    .notification-item-header {
        align-items: flex-start;
        flex-wrap: wrap;
    }

    .notification-header-title {
        flex: 1 1 10rem;
    }

    .notification-header-actions {
        flex: 0 1 auto;
        margin-left: auto;
        min-width: 0;
    }

    .notification-header-title strong,
    .notification-unread-chip,
    .notification-mark-read,
    .notification-time {
        max-width: 100%;
        overflow-wrap: anywhere;
        white-space: normal;
    }

    .notification-item-title {
        flex: 1 1 12rem;
        min-width: 0;
    }

    .notification-list {
        gap: var(--space-2);
        max-height: none;
    }

    .notification-list li > a,
    .notification-item-button {
        min-height: var(--touch-min);
        padding: 0.65rem 0.85rem;
    }
}

@media (max-width: 26.875rem) {
    .notification-dropdown {
        --notification-block-end: max(var(--space-2), env(safe-area-inset-bottom, 0px));
        --notification-block-start: calc(var(--topbar-height) + max(var(--space-1), env(safe-area-inset-top, 0px)));
        --notification-inline-end: max(var(--space-2), env(safe-area-inset-right, 0px));
        --notification-inline-start: max(var(--space-2), env(safe-area-inset-left, 0px));
        padding: var(--space-3);
    }

    .notification-list {
        gap: var(--space-1);
    }
}

.row-emphasis td {
    background: color-mix(in srgb, var(--color-accent-text) 6%, transparent);
}

.row-muted td {
    color: var(--color-text-faint);
    opacity: 0.72;
}

.import-intro {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
}

.import-intro p {
    flex: 1 1 32rem;
    margin: 0;
}

.work-item-import,
.project-import {
    margin-top: var(--space-5);
}

.import-drop-zone {
    align-items: center;
    border: 1px dashed var(--color-border-strong);
    cursor: pointer;
    display: grid;
    gap: var(--space-2);
    justify-items: center;
    padding: var(--space-7) var(--space-4);
    text-align: center;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.import-drop-zone:hover,
.import-drop-zone.is-dragging {
    background: var(--color-surface-hover);
    border-color: var(--color-accent);
}

.import-drop-zone span {
    color: var(--color-text-muted);
    font-size: 0.82rem;
}

.import-drop-zone input {
    max-width: 100%;
}

.import-preview {
    margin-top: var(--space-5);
}

.import-preview h3 {
    margin-bottom: var(--space-3);
}

.import-client-errors[hidden],
.import-preview[hidden] {
    display: none;
}

/* --------------------------------------------------------------------------
   Print
   Ink-efficient light rendering for work items, project/agent detail, audit
   and activity views, and the work queue. Screen styles are untouched; every
   rule lives inside @media print.
   -------------------------------------------------------------------------- */

.print-document-stamp {
    display: none;
}

@media print {
    :root {
        color-scheme: light;
        --color-background: #ffffff;
        --color-background-raised: #ffffff;
        --color-background-elevated: #ffffff;
        --color-sidebar: #ffffff;
        --color-surface: #ffffff;
        --color-surface-raised: #ffffff;
        --color-surface-hover: #ffffff;
        --color-field: #ffffff;
        --color-field-hover: #ffffff;
        --color-border: #bbbbbb;
        --color-border-strong: #888888;
        --color-border-loud: #555555;
        --color-text: #111111;
        --color-text-muted: #222222;
        --color-text-subtle: #333333;
        --color-text-faint: #444444;
        --color-ink: #111111;
        --color-accent: #111111;
        --color-accent-hover: #111111;
        --color-accent-active: #111111;
        --color-accent-text: #111111;
        --color-accent-soft: transparent;
        --color-accent-faint: transparent;
        --color-accent-glow: transparent;
        --color-info: #111111;
        --color-info-soft: transparent;
        --color-purple: #111111;
        --color-purple-soft: transparent;
        --color-warning: #111111;
        --color-warning-soft: transparent;
        --color-success: #111111;
        --color-success-soft: transparent;
        --color-danger: #111111;
        --color-danger-soft: transparent;
        --color-neutral: #333333;
        --color-neutral-soft: transparent;
        --overlay-dark: transparent;
        --shadow-panel: none;
        --shadow-raised: none;
        --shadow-accent: none;
        --focus-ring: none;
        --texture-grain: none;
        --texture-scratch: none;
        --texture-halftone: none;
        --texture-line: transparent;
    }

    @page {
        margin: 1.25cm;
    }

    html,
    body {
        background: #ffffff !important;
        color: #111111 !important;
        min-height: 0;
        min-width: 0;
    }

    body::before,
    .app-shell::after,
    .sidebar::after,
    .topbar::after {
        display: none !important;
    }

    *,
    *::before,
    *::after {
        background-image: none !important;
        box-shadow: none !important;
        text-shadow: none !important;
        transition: none !important;
        animation: none !important;
        filter: none !important;
        backdrop-filter: none !important;
        clip-path: none !important;
    }

    /* Shell chrome: navigation, topbar, notifications, install prompt, error/reconnect UI. */
    .sidebar,
    .topbar,
    .mobile-menu,
    .app-tab-bar,
    .notification-bell,
    .notification-dropdown,
    .account-summary,
    .search-toggle,
    .search-control,
    .install-prompt,
    .pager,
    .tabs,
    .toolbar-form,
    .panel-actions,
    .form-actions,
    .inline-editor,
    .copy-prompt-disclosure,
    .import-drop-zone,
    .sign-out-button,
    .status-pulse,
    #blazor-error-ui,
    .reconnect-modal,
    .components-reconnect-modal,
    dialog,
    .print-sensitive {
        display: none !important;
    }

    /* Filter panels and form controls cannot be used on paper (queue / activity /
       audit / etc.). Hide GET filter forms (and their panels), plus every
       interactive field so leftover labels do not print alone. */
    .panel:has(> .panel-body > form[method="get"]),
    form[method="get"],
    .form-grid,
    .field-group,
    .field-control,
    .select-control,
    .check-control,
    .field-help,
    input:not([type="hidden"]),
    select,
    textarea {
        display: none !important;
    }

    /* Action controls cannot be used on paper; keep status chips in those rows. */
    .button,
    .text-action,
    .page-heading-toolbar .button,
    .page-heading-toolbar form,
    .button-row .button,
    .button-row form,
    .button-row .text-action,
    button:not([data-print-keep]) {
        display: none !important;
    }

    .print-document-stamp {
        border-bottom: var(--hairline) solid #888888;
        color: #333333;
        display: block;
        font-family: var(--font-mono);
        font-size: 0.7rem;
        margin: 0 0 0.75rem;
        padding: 0 0 0.4rem;
    }

    .app-shell,
    .workspace,
    .page-container {
        background: transparent !important;
        display: block;
        margin: 0;
        max-width: none;
        padding: 0;
        width: 100%;
    }

    .page-heading,
    .panel,
    .stat-tile,
    .board-card,
    .instruction-card,
    .empty-state,
    .loading-state {
        background: transparent !important;
        border-color: #bbbbbb;
        break-inside: avoid;
        page-break-inside: avoid;
        color: #111111;
    }

    h1,
    h2,
    h3,
    .panel-title,
    .eyebrow,
    .panel-kicker,
    .record-key,
    .record-title {
        break-after: avoid;
        color: #111111 !important;
        page-break-after: avoid;
    }

    /* Paper has no hover and no tap, so a clamp there hides the title with no way
       to recover it. Print the whole string. */
    .title-clamp,
    .title-clamp-work-item {
        display: block;
        overflow: visible;
        -webkit-line-clamp: none;
        line-clamp: none;
    }

    /* Status is text on paper: chip labels stay; colour fills are dropped so a
       monochrome printer still distinguishes Ready / Blocked / Failed by words. */
    .status-chip {
        background: transparent !important;
        border: var(--hairline) solid #555555 !important;
        color: #111111 !important;
        print-color-adjust: economy;
        -webkit-print-color-adjust: economy;
    }

    .status-dot {
        display: none !important;
    }

    /* Release overflow clips and width floors so tables reflow across pages. */
    .table-scroll,
    .table-shell,
    .panel-body,
    .page-container,
    .workspace {
        overflow: visible !important;
    }

    .data-table,
    .criteria-table,
    table {
        min-width: 0 !important;
        width: 100% !important;
    }

    .data-table thead,
    .criteria-table thead,
    table thead {
        display: table-header-group;
    }

    .data-table tfoot,
    table tfoot {
        display: table-footer-group;
    }

    .data-table tr,
    .criteria-table tr,
    table tr {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    .data-table th,
    .data-table td,
    .criteria-table th,
    .criteria-table td {
        background: transparent !important;
        color: #111111 !important;
        white-space: normal;
    }

    .data-table thead th::after,
    .criteria-table thead th::after {
        display: none !important;
    }

    /* Expand outbound link targets on printed content; skip in-page anchors. */
    .page-container a[href]::after {
        color: #333333;
        content: " (" attr(href) ")";
        font-family: var(--font-mono);
        font-size: 0.65rem;
        font-weight: 400;
        letter-spacing: 0;
        text-transform: none;
        word-break: break-all;
    }

    .page-container a[href^="#"]::after,
    .page-container a[href^="javascript:"]::after,
    .page-container a[href=""]::after {
        content: none;
    }

    a {
        color: #111111 !important;
        text-decoration: underline;
    }

    /* One-time plaintext credentials must never leave the printer. */
    #one-time-agent-key,
    .print-sensitive,
    .print-sensitive * {
        display: none !important;
    }
}

/* Phone shell (AIWO-126): the persistent bottom bar is removed, so content no
   longer reserves its height. Tablet widths still use --tab-bar-height from 48/62rem. */
@media (max-width: 46rem) {
    :root {
        --tab-bar-height: 0px;
    }
}

.avatar-cell {
    align-items: center;
    display: inline-flex;
    gap: var(--space-2);
}

/* --------------------------------------------------------------------------
   Public site (AIWO-149)
   Marketing and documentation pages served anonymously under PublicLayout.
   Shell chrome lives in PublicLayout.razor.css; these are the content
   primitives the public pages share. Tokens only, no local colour literals.
   -------------------------------------------------------------------------- */

.public-hero {
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-8);
    max-width: 52rem;
    padding-bottom: var(--space-7);
}

.public-hero-compact {
    margin-bottom: var(--space-7);
    padding-bottom: var(--space-5);
}

.public-hero-title {
    font-family: var(--font-poster);
    font-size: clamp(2.25rem, 6vw, 4rem);
    font-stretch: 87.5%;
    letter-spacing: var(--tracking-display);
    line-height: 1.02;
    margin: var(--space-2) 0 var(--space-4);
    text-wrap: balance;
}

.public-lead {
    color: var(--color-text-muted);
    font-size: var(--text-lg);
    line-height: 1.6;
    margin: 0 0 var(--space-5);
}

.public-hero-actions {
    margin-bottom: var(--space-5);
}

.public-points {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    list-style: none;
    margin: 0;
    padding: 0;
}

.public-points > li {
    color: var(--color-text-subtle);
    font-size: var(--text-sm);
    padding-left: var(--space-4);
    position: relative;
}

.public-points > li::before {
    color: var(--color-accent);
    content: "▍";
    left: 0;
    position: absolute;
}

/* Stacked variant for a genuine list rather than a row of pull quotes. */
.public-points-block {
    display: block;
    max-width: 52rem;
}

.public-points-block > li {
    line-height: 1.6;
    margin-bottom: var(--space-2);
}

.public-section {
    margin-bottom: var(--space-8);
}

.public-section-title {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3vw, 2rem);
    letter-spacing: var(--tracking-display);
    margin: 0 0 var(--space-4);
    position: relative;
}

.public-section-title::after {
    background: var(--color-accent);
    content: "";
    display: block;
    height: 2px;
    margin-top: var(--space-2);
    opacity: 0.85;
    width: 3rem;
}

.public-body {
    color: var(--color-text-muted);
    line-height: 1.7;
    margin: 0 0 var(--space-4);
    max-width: 52rem;
}

.public-body code {
    background: var(--color-field);
    border: 1px solid var(--color-border);
    border-radius: 0.25rem;
    font-family: var(--font-mono);
    font-size: 0.9em;
    padding: 0.05em 0.35em;
}

.public-card-grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}

.public-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.public-card > p {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    line-height: 1.65;
    margin: 0;
}

.public-card code {
    font-family: var(--font-mono);
    font-size: 0.9em;
}

.public-card-title {
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: var(--text-md);
    letter-spacing: var(--tracking-display);
    margin: 0;
}

/* Numbered lifecycle steps. The counter is drawn rather than relying on the
   default marker so it can carry the brand accent at display weight. */
.public-steps {
    counter-reset: public-step;
    list-style: none;
    margin: 0;
    max-width: 52rem;
    padding: 0;
}

.public-step {
    border-left: 1px solid var(--color-border);
    counter-increment: public-step;
    padding: 0 0 var(--space-5) var(--space-6);
    position: relative;
}

.public-step:last-child {
    border-left-color: transparent;
    padding-bottom: 0;
}

.public-step::before {
    background: var(--color-background-raised);
    border: 1px solid var(--color-accent);
    border-radius: 50%;
    color: var(--color-accent-text);
    content: counter(public-step);
    display: grid;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    height: 1.75rem;
    left: -0.875rem;
    place-items: center;
    position: absolute;
    top: 0;
    width: 1.75rem;
}

.public-step-title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    letter-spacing: var(--tracking-display);
    margin: 0 0 var(--space-2);
}

.public-step > p {
    color: var(--color-text-muted);
    line-height: 1.7;
    margin: 0;
}

.public-closing {
    border-top: 1px solid var(--color-border);
    margin-bottom: 0;
    padding-top: var(--space-6);
}

@media (max-width: 48rem) {
    .public-hero {
        margin-bottom: var(--space-6);
        padding-bottom: var(--space-5);
    }

    .public-lead {
        font-size: var(--text-md);
    }

    .public-points {
        display: block;
    }

    .public-points > li {
        margin-bottom: var(--space-2);
    }

    .public-section {
        margin-bottom: var(--space-7);
    }

    .public-step {
        padding-left: var(--space-5);
    }
}

/* Project directory mobile cards */
.projects-mobile-list {
    display: none;
}

@media (max-width: 52rem) {
    .projects-directory-panel .table-scroll {
        display: none;
    }

    .projects-mobile-list {
        display: grid;
        gap: 0.55rem;
    }

    .project-mobile-card {
        --notch: var(--notch-sm);
        background: var(--color-field);
        border: var(--hairline) solid var(--color-border);
        clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%);
        color: inherit;
        display: grid;
        gap: 0.42rem;
        min-width: 0;
        padding: 0.7rem 0.8rem;
        text-decoration: none;
        transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
    }

    .project-mobile-card:hover {
        background: var(--color-surface-hover);
        border-color: var(--color-border-strong);
        box-shadow: inset 2px 0 0 var(--color-accent);
    }

    .project-mobile-card:focus-visible {
        box-shadow: var(--focus-ring);
        outline: none;
    }

    .project-mobile-card-head {
        align-items: center;
        display: flex;
        gap: var(--space-2);
        justify-content: space-between;
        min-width: 0;
    }

    .project-mobile-key {
        background: color-mix(in srgb, var(--color-accent) 10%, transparent);
        border: var(--hairline) solid color-mix(in srgb, var(--color-accent) 45%, var(--color-border));
        color: var(--color-accent-text);
        display: inline-block;
        font-family: var(--font-mono);
        font-size: 0.66rem;
        font-weight: 700;
        line-height: 1.2;
        max-width: calc(100% - 1.75rem);
        overflow: hidden;
        padding: 0.16rem 0.42rem;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .project-mobile-open {
        color: var(--color-text-faint);
        flex: 0 0 auto;
        font-size: 1.1rem;
        line-height: 1;
    }

    .project-mobile-title {
        color: var(--color-text);
        font-size: 0.95rem;
        font-weight: 700;
        line-height: 1.28;
        min-width: 0;
    }

    .project-mobile-meta {
        align-items: center;
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem 0.4rem;
        min-width: 0;
    }

    .project-mobile-meta .status-chip {
        font-size: 0.62rem;
        line-height: 1.2;
        min-height: 0;
        padding: 0.18rem 0.4rem;
    }

    .project-mobile-company {
        color: var(--color-text-faint);
        font-size: 0.68rem;
        line-height: 1.25;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* AIWO-356. Work breakdown and dependency verdict on the work-item detail page. Hierarchy and
   dependencies are shown as separate ideas, so they read as separate ideas. */
.hierarchy-parent {
    margin: 0 0 .75rem;
}

.hierarchy-rollup {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    margin: 0 0 .85rem;
}

.hierarchy-progress {
    opacity: .82;
}

.hierarchy-container-mark {
    margin-left: .35rem;
    opacity: .65;
}

.dependency-verdict {
    margin: 0 0 .85rem;
    font-weight: 600;
}

.dependency-verdict.is-blocked {
    color: #b3261e;
}

.dependency-verdict.is-clear {
    color: #1b6b3a;
}

/* AIWO-416. The drop target is the composer region - the message field and its attachment row -
   because dropping a screenshot onto the text you are writing is the natural gesture. The class is
   set by image-attachments.js on an element outside AttachmentComposer, so it cannot live in that
   component's scoped stylesheet. Its own name, not the existing .is-dragging, which already means
   something for .import-drop-zone. */
.aiwo-composer-dropping {
    box-shadow: inset 0 0 0 2px var(--color-accent);
    border-radius: var(--radius-sm);
}

/* AIWO-462. Agent CLI sessions: provider output is long, unwrapped stream-json, so it scrolls inside
   its cell instead of widening the sessions table. */
.cli-output {
    max-height: 24rem;
    max-width: 48rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
}

.cli-failure {
    color: var(--color-danger);
}

/* AIWO-463. A scheduled run links to /agent-cli-sessions#cli-session-{jobId}; mark the row it lands on. */
.cli-session-row:target {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
}

.schedule-advanced > summary {
    cursor: pointer;
    font-weight: 600;
}

/* AIWO-602-A: a readable notification center. All colors come from shared theme tokens. */
.notification-trigger .notification-badge {
    min-width: var(--space-5);
    min-height: var(--space-5);
    height: auto;
    padding: 0.16rem 0.34rem;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.notification-dropdown {
    width: min(32rem, calc(100vw - var(--space-8)));
    max-height: min(43rem, calc(100dvh - var(--topbar-height) - var(--space-5)));
    gap: 0;
    padding: 0;
    overflow: hidden;
}
.notification-dropdown-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-3);
    align-items: center;
    padding: var(--space-4);
}
.notification-header-title {
    flex-wrap: wrap;
    min-width: 0;
}
.notification-unread-chip {
    font-size: 0.76rem;
    line-height: 1.4;
    overflow-wrap: anywhere;
}
.notification-header-actions {
    min-width: 0;
}
.notification-close-btn {
    flex: 0 0 auto;
    width: var(--touch-min);
    height: var(--touch-min);
    font-size: 1.4rem;
}
.notification-list {
    display: grid;
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-gutter: stable;
    overscroll-behavior: contain;
    padding: var(--space-3);
    gap: var(--space-3);
}
.notification-list li {
    min-width: 0;
}
.notification-item-card {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3);
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-field);
    min-width: 0;
    overflow-wrap: anywhere;
}
.notification-list li.unread .notification-item-card {
    border-left: 3px solid var(--color-accent);
    background: color-mix(in srgb, var(--color-accent-soft) 28%, var(--color-field));
}
.notification-item-meta,
.notification-item-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    min-width: 0;
}
.notification-item-meta .notification-time {
    margin-left: auto;
    font-size: 0.75rem;
    white-space: normal;
    text-align: right;
}
.notification-item-category {
    color: var(--color-text-muted);
    font-size: 0.78rem;
    font-weight: 600;
}
.notification-item-status {
    color: var(--color-text-muted);
    font-size: 0.75rem;
    border: var(--hairline) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-1);
}
.notification-list li.unread .notification-item-status {
    color: var(--color-accent-text);
    border-color: var(--color-accent);
}
.notification-item-card .notification-item-title {
    display: block;
    font-size: 0.94rem;
    line-height: 1.45;
    font-weight: 650;
}
.notification-item-preview {
    color: var(--color-text-muted);
    font-size: 0.87rem;
    line-height: 1.55;
    margin: 0;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}
.notification-item-detail {
    min-width: 0;
    font-size: 0.85rem;
}
.notification-item-detail summary {
    width: fit-content;
    color: var(--color-accent-text);
    cursor: pointer;
    font-weight: 600;
}
.notification-item-detail summary:hover {
    text-decoration: underline;
}
.notification-item-detail summary:focus-visible,
.notification-header-actions button:focus-visible,
.notification-item-actions :is(a, button):focus-visible,
.notification-view-all-link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 3px;
}
.notification-item-detail p {
    margin: var(--space-2) 0 0;
    padding: var(--space-2);
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.55;
}
.notification-item-actions {
    border-top: var(--hairline) solid var(--color-border);
    padding-top: var(--space-2);
}
.notification-item-actions .text-action {
    padding: var(--space-1);
}
.notification-dropdown-footer {
    padding: var(--space-3) var(--space-4);
}
.notification-view-all-link {
    min-height: var(--touch-min);
    display: inline-flex;
    align-items: center;
}
@media (max-width: 48rem) {
    .notification-dropdown {
        max-height: calc(100dvh - var(--notification-block-start) - var(--notification-block-end));
        padding: 0;
    }
    .notification-dropdown-header {
        align-items: center;
        flex-wrap: initial;
    }
    .notification-list {
        max-height: none;
        padding: var(--space-3);
    }
}
@media (max-width: 30rem) {
    .notification-dropdown-header {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-2);
    }
    .notification-header-actions {
        justify-content: space-between;
        margin-left: 0;
        width: 100%;
    }
    .notification-list {
        padding: var(--space-2);
    }
    .notification-dropdown-footer {
        padding: var(--space-2);
    }
}
