html, body {
    margin: 0;
    padding: 0;
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-md);
    line-height: var(--bz-lh);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

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

a {
    text-decoration: none;
}

a:hover { text-decoration: underline; }

button {
    font-family: inherit;
    font-size: inherit;
    color: inherit;
}

/* Consistent keyboard focus ring across all interactive elements. */
:focus-visible {
    outline: 2px solid var(--bz-brand-primary);
    outline-offset: 2px;
    border-radius: var(--bz-radius-sm);
}

/* Subtle scrollbars. WebKit/Chromium/Edge get a custom track+thumb;
   Firefox falls back to its native thin scrollbar via scrollbar-width.
   Other engines keep their platform default — acceptable progressive
   enhancement, no JS-based scrollbar polyfill needed. */
html { scrollbar-width: thin; scrollbar-color: var(--bz-color-border) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--bz-color-border);
    border-radius: var(--bz-radius-pill);
    border: 2px solid var(--bz-color-bg);
}
::-webkit-scrollbar-thumb:hover { background: var(--bz-color-border-strong); }

/* --- Auth pages (shared between /login and /host/login) ------------------
   Global rather than scoped because both pages render a matching split
   layout and share the branded background image. Prefixed with `auth-`
   so they never collide with component-scoped classes. */
.auth-page {
    min-height: 100vh;
    width: 100%;
}

/* Split-panel branded background. The image is a CSS custom property so a resolved tenant can
   override it per-session (Login.razor sets --bz-login-image / --bz-login-image-dark inline) without
   a reload; unset it falls back to the product default illustration. A subtle top-to-bottom scrim is
   layered above the image (first background layer) so the panel's heading/hero text stays readable
   over any artwork. */
.auth-branded-bg {
    background-image:
        linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.28) 55%, rgba(255, 255, 255, 0.55) 100%),
        var(--bz-login-image, url('/branding/login-default.svg'));
}

html.dark .auth-branded-bg {
    background-image:
        linear-gradient(180deg, rgba(15, 23, 42, 0.1) 0%, rgba(15, 23, 42, 0.45) 55%, rgba(15, 23, 42, 0.7) 100%),
        var(--bz-login-image-dark, var(--bz-login-image, url('/branding/login-default-dark.svg')));
}

/* Frosted "glass" panel behind the hero text. The scrim above only darkens the bottom of the panel,
   but the hero text sits at the TOP — so over a poorly-contrasting uploaded image it can wash out.
   This translucent, backdrop-blurred card sits directly behind the text and guarantees legibility
   over ANY artwork: a light card (dark text) in light mode, a dark card (light text) in dark mode.
   Hugs its content (align-self:start) so it reads as a card, not a full-width band. */
.auth-hero-content {
    align-self: flex-start;
    max-inline-size: 34rem;
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-4);
    padding: var(--bz-space-5) var(--bz-space-6);
    border-radius: var(--bz-radius-lg, 14px);
    background: rgba(255, 255, 255, 0.6);
    -webkit-backdrop-filter: blur(12px) saturate(130%);
    backdrop-filter: blur(12px) saturate(130%);
    border: 1px solid rgba(255, 255, 255, 0.45);
    box-shadow: 0 10px 34px rgba(15, 23, 42, 0.14);
    text-shadow: 0 1px 2px rgba(255, 255, 255, 0.5);
}

html.dark .auth-hero-content {
    background: rgba(15, 23, 42, 0.5);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}

/* Browsers without backdrop-filter (rare) fall back to a more opaque panel so text stays readable. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .auth-hero-content { background: rgba(255, 255, 255, 0.85); }
    html.dark .auth-hero-content { background: rgba(15, 23, 42, 0.8); }
}

/* Theme-aware brand logo pair. When a tenant has both a light and dark logo, the shell renders both
   <img>s and CSS shows the one matching the active theme. Default (no theme class yet) = light. */
.bz-dark-only { display: none; }
html.dark .bz-light-only { display: none; }
html.dark .bz-dark-only { display: revert; }

/* ── Browser autofill — preserve dark mode colours ────────────────────
   Chromium/Safari forcibly paint a light-yellow/white overlay on
   autofilled inputs via :-webkit-autofill.  The only reliable cross-
   browser override is box-shadow inset (background-color is ignored
   by the UA stylesheet).  We re-apply Metronic's --card / --foreground
   tokens so the input matches the surrounding card in both modes. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
    -webkit-box-shadow: 0 0 0 1000px var(--card, #fff) inset !important;
    -webkit-text-fill-color: var(--foreground, #09090b) !important;
    caret-color: var(--foreground, #09090b);
    transition: background-color 0s 600000s; /* delay so Chrome never flashes */
}

#sidebar_menu {
    flex-shrink: 1;
    min-height: 0;
    overflow: hidden;
}

#sidebar_menu > .kt-scrollable-y-auto {
    max-height: 100%;
    min-height: 0;
    overflow-y: auto;
}

/* ── DevExpress Blazor — global grid + button overrides ──────────────
   Applied here (global) so every DxGrid instance across all modules
   shares the same visual language, including raw DxGrid usage in
   HostAdmin / TenantAdmin pages that don't go through ProjectionGrid.
   We map BizsOn design tokens to DevExpress CSS variables and add
   a few structural fixes for filling available width. */

/* Every DxGrid fills its parent container horizontally */
.dxbl-grid {
    width: 100%;
}

/* Map BizsOn design tokens to DevExpress Fluent grid CSS variables */
.dxbl-grid {
    --dxbl-grid-bg:                var(--bz-color-surface);
    --dxbl-grid-color:             var(--bz-color-fg);
    --dxbl-grid-border-color:      var(--bz-color-border);
    --dxbl-grid-header-bg:         var(--bz-color-surface-2);
    --dxbl-grid-header-color:      var(--bz-color-fg);
    --dxbl-grid-header-border-color: var(--bz-color-border);
    --dxbl-grid-row-hover-bg:      var(--bz-color-surface-3);
    --dxbl-grid-footer-bg:         var(--bz-color-surface-2);
    --dxbl-grid-pager-bg:          var(--bz-color-surface-2);
    --dxbl-grid-filter-row-bg:     var(--bz-color-surface);
    --dxbl-grid-group-bg:          var(--bz-color-surface-2);
    --dxbl-grid-font-size:         var(--bz-fs-md);
    --dxbl-grid-font-family:       var(--bz-font-sans);
}

/* Command cells (data rows only): row of small action buttons, vertically
   centred. Scoped to td — the command-column HEADER cell must stay a normal
   table cell so it matches the height/alignment of every other header cell. */
.dxbl-grid td.dxbl-grid-command-cell {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--bz-space-2);
    padding: 0.25rem 0.5rem !important;
    flex-wrap: wrap;
}

/* Command-column header: same metrics as other headers; centre any residual
   built-in header button (grids that intentionally keep the new-row button) */
.dxbl-grid th.dxbl-grid-command-cell {
    vertical-align: middle;
    text-align: center;
}
.dxbl-grid th.dxbl-grid-command-cell .dxbl-btn {
    width: 28px;
    height: 28px;
    min-width: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--bz-radius-sm);
}

/* Make Link-style DxButtons inside command cells look like visible
   ghost actions rather than plain hyperlinks */
.dxbl-grid-command-cell .dxbl-btn-link,
.dxbl-grid-command-cell .dxbl-btn-link:visited {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.2rem 0.55rem;
    border-radius: var(--bz-radius-sm);
    border: 1px solid var(--bz-color-border);
    background: var(--bz-color-surface);
    color: var(--bz-color-fg) !important;
    text-decoration: none !important;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    line-height: 1.4;
    cursor: pointer;
    white-space: nowrap;
    /* transform repeated here (and in the two rules below): these selectors outrank
       the shared press-feedback rule, so omitting it would silently drop the press. */
    transition: background var(--bz-duration-fast) var(--bz-ease),
                border-color var(--bz-duration-fast) var(--bz-ease),
                transform var(--bz-duration-press) var(--bz-ease);
}

.dxbl-grid-command-cell .dxbl-btn-link:hover {
    background: var(--bz-color-surface-3) !important;
    border-color: var(--bz-color-border-strong) !important;
    color: var(--bz-brand-primary) !important;
    text-decoration: none !important;
}

/* Toolbar buttons — ensure DxButton looks like a button everywhere */
.toolbar .dxbl-btn,
.bz-toolbar .dxbl-btn {
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    border-radius: var(--bz-radius-sm);
    min-height: var(--bz-control-height, 34px);
    padding: 0.3rem 0.8rem;
    cursor: pointer;
}

/* ── Press feedback ─────────────────────────────────────────────────
   Every pressable surface confirms it heard the click. transform only, so the
   whole thing stays on the GPU, and :not(disabled) so dead controls stay dead.
   scale() also scales the label and icon inside — that is the point: the whole
   button compresses as one object rather than the border moving alone. */
:is(.dxbl-btn, .bz-icon-action, .kt-btn, .bz-chip-x,
    .bz-avatar-action, .bz-toast-close, .bz-tabs a) {
    transition: transform var(--bz-duration-press) var(--bz-ease);
}

:is(.dxbl-btn, .bz-icon-action, .kt-btn, .bz-chip-x,
    .bz-avatar-action, .bz-toast-close, .bz-tabs a):active:not(:disabled):not(.dxbl-disabled) {
    transform: scale(0.97);
}

/* A form control paired with a trailing icon button (e.g. a field + its info/help button). */
.bz-inline-field {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
}

.bz-inline-field > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}

/* Square icon-only action button — shared by DxButton (CssClass="bz-icon-action"),
   plain <button>, and <a>. Size aligned to --bz-control-height. */
.bz-icon-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--bz-control-height);
    min-width: var(--bz-control-height);
    height: var(--bz-control-height);
    padding: 0;
    border-radius: var(--bz-radius-sm);
    line-height: 1;
    cursor: pointer;
    text-decoration: none;
}

.bz-icon-action i,
.bz-icon-action .dxbl-image {
    margin: 0;
    font-size: 1.05rem;
    line-height: 1;
}

/* DxButton flavour: quiet ghost button — semantic colour comes from the icon,
   hover shows a subtle tinted surface (Metronic-style row actions). */
.dxbl-btn.bz-icon-action {
    background: transparent !important;
    border-color: transparent !important;
    color: var(--bz-color-fg-muted) !important;
    box-shadow: none !important;
    transition: background var(--bz-duration-fast) var(--bz-ease),
                color var(--bz-duration-fast) var(--bz-ease),
                transform var(--bz-duration-press) var(--bz-ease);
}
.dxbl-btn.bz-icon-action:hover,
.dxbl-btn.bz-icon-action:focus-visible {
    background: var(--bz-color-surface-3) !important;
    color: var(--bz-color-accent) !important;
    border-color: var(--bz-color-border) !important;
}
/* Semantic variants keyed off the DevExpress render-style class */
.dxbl-btn.bz-icon-action.dxbl-btn-danger        { color: var(--bz-color-danger) !important; }
.dxbl-btn.bz-icon-action.dxbl-btn-danger:hover,
.dxbl-btn.bz-icon-action.dxbl-btn-danger:focus-visible {
    background: color-mix(in srgb, var(--bz-color-danger) 12%, transparent) !important;
    color: var(--bz-color-danger) !important;
}
.dxbl-btn.bz-icon-action.dxbl-btn-warning       { color: var(--bz-color-warn) !important; }
.dxbl-btn.bz-icon-action.dxbl-btn-warning:hover,
.dxbl-btn.bz-icon-action.dxbl-btn-warning:focus-visible {
    background: color-mix(in srgb, var(--bz-color-warn) 12%, transparent) !important;
    color: var(--bz-color-warn) !important;
}
.dxbl-btn.bz-icon-action.dxbl-btn-primary       { color: var(--bz-color-accent) !important; }
.dxbl-btn.bz-icon-action.dxbl-btn-primary:hover,
.dxbl-btn.bz-icon-action.dxbl-btn-primary:focus-visible {
    background: color-mix(in srgb, var(--bz-color-accent) 12%, transparent) !important;
    color: var(--bz-color-accent) !important;
}
.dxbl-btn.bz-icon-action.dxbl-btn-success       { color: var(--bz-color-ok) !important; }
.dxbl-btn.bz-icon-action.dxbl-btn-success:hover,
.dxbl-btn.bz-icon-action.dxbl-btn-success:focus-visible {
    background: color-mix(in srgb, var(--bz-color-ok) 12%, transparent) !important;
    color: var(--bz-color-ok) !important;
}
.dxbl-btn.bz-icon-action:disabled,
.dxbl-btn.bz-icon-action.dxbl-disabled { opacity: .45; }

/* Plain <button>/<a> flavour (RecordDocuments.razor, PM Files.razor, …) */
button.bz-icon-action,
a.bz-icon-action {
    background: transparent;
    border: 1px solid transparent;
    color: var(--bz-color-fg-muted);
    transition: background var(--bz-duration-fast) var(--bz-ease),
                color var(--bz-duration-fast) var(--bz-ease),
                transform var(--bz-duration-press) var(--bz-ease);
}
button.bz-icon-action:hover,
a.bz-icon-action:hover {
    background: var(--bz-color-surface-3);
    color: var(--bz-color-accent);
    text-decoration: none;
}
button.bz-icon-action.kt-btn-danger,
a.bz-icon-action.kt-btn-danger {
    color: var(--bz-color-danger);
}
button.bz-icon-action.kt-btn-danger:hover,
a.bz-icon-action.kt-btn-danger:hover {
    background: color-mix(in srgb, var(--bz-color-danger) 12%, transparent);
    color: var(--bz-color-danger);
}

/* Plain <button> and <a> styled as buttons via legacy module CSS classes —
   normalize to match DxButton visual weight */
.btn-primary, a.btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    background: var(--bz-color-accent);
    color: #fff;
    border: 1px solid var(--bz-color-accent);
    border-radius: var(--bz-radius-sm);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}
.btn-primary:hover, a.btn-primary:hover {
    background: var(--bz-color-accent-hover);
    border-color: var(--bz-color-accent-hover);
    text-decoration: none;
    color: #fff;
}

.btn-secondary, a.btn-secondary {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    background: var(--bz-color-surface);
    color: var(--bz-color-fg);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-sm);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}
.btn-secondary:hover, a.btn-secondary:hover {
    background: var(--bz-color-surface-3);
    border-color: var(--bz-color-border-strong);
    text-decoration: none;
    color: var(--bz-color-fg);
}

.btn-warning, a.btn-warning {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    background: var(--bz-color-warn);
    color: #fff;
    border: 1px solid var(--bz-color-warn);
    border-radius: var(--bz-radius-sm);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}

.btn-danger, a.btn-danger {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.8rem;
    background: var(--bz-color-danger);
    color: #fff;
    border: 1px solid var(--bz-color-danger);
    border-radius: var(--bz-radius-sm);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}

.btn-link, a.btn-link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.5rem;
    background: transparent;
    color: var(--bz-color-accent);
    border: 1px solid transparent;
    border-radius: var(--bz-radius-sm);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}
.btn-link:hover, a.btn-link:hover {
    background: var(--bz-color-surface-3);
    text-decoration: none;
    color: var(--bz-brand-primary);
}

.btn-icon-only, a.btn-icon-only {
    justify-content: center;
    min-width: 2rem;
    width: 2rem;
    padding-inline: 0;
}

.btn-icon-only i,
.btn-icon-only .ki-filled,
.btn-icon-only .ki-outline,
.btn-icon-only .ki-solid,
a.btn-icon-only i,
a.btn-icon-only .ki-filled,
a.btn-icon-only .ki-outline,
a.btn-icon-only .ki-solid {
    font-size: 1rem;
}

/* Toolbar layout — legacy class kept for backward compat */
.toolbar {
    display: flex;
    gap: var(--bz-space-2);
    align-items: center;
    margin-bottom: var(--bz-space-3);
    flex-wrap: wrap;
}

/* ── Page card — wraps a DxGrid (or any content) inside a surface card ── */
.bz-page-card {
    --bz-card-pad: var(--bz-space-4);
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-lg);
    box-shadow: var(--bz-shadow-sm);
    /* The card owns the inset so no content ever touches its border; the genuinely full-bleed
       children (grids, head bars) cancel it below. */
    padding: var(--bz-card-pad);
    /* overflow-x: auto (not hidden) so a grid widened by column resize scrolls within the card
       instead of escaping to the page's own scroll container and shifting the whole layout. */
    overflow-x: auto;
    overflow-y: hidden;
    margin-bottom: var(--bz-space-5);
}

/* Full-bleed children: DevExpress grids (direct or inside a wrapper element) and the padded
   head bars own the card's edges, exactly as they did before the card gained padding. */
.bz-page-card > :is(.dxbl-grid, .bz-dxgrid, *:has(> .dxbl-grid),
                    .bz-page-card-head, .bz-dash-section-head) {
    margin-left: calc(var(--bz-card-pad) * -1);
    margin-right: calc(var(--bz-card-pad) * -1);
    /* Grids carry width:100%, which resolves against the card's CONTENT box — without this the
       negative margins would shift them left and leave a gap on the right. */
    width: calc(100% + var(--bz-card-pad) * 2);
}
.bz-page-card > :is(.dxbl-grid, .bz-dxgrid, *:has(> .dxbl-grid),
                    .bz-page-card-head, .bz-dash-section-head):first-child {
    margin-top: calc(var(--bz-card-pad) * -1);
}
.bz-page-card > :is(.dxbl-grid, .bz-dxgrid, *:has(> .dxbl-grid)):last-child {
    margin-bottom: calc(var(--bz-card-pad) * -1);
}
/* Head bar keeps its divider gap to the now-inset body below it. */
.bz-page-card > :is(.bz-page-card-head, .bz-dash-section-head):not(:last-child) {
    margin-bottom: var(--bz-card-pad);
}
/* These already carried their own inset — don't double it now that the card has one. */
.bz-page-card > .bz-card-pad { padding: 0; }
.bz-page-card > .bz-filter-bar { padding-left: 0; padding-right: 0; }

.bz-page-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--bz-space-3) var(--bz-space-4);
    border-bottom: 1px solid var(--bz-color-border);
    background: var(--bz-color-surface-2);
    gap: var(--bz-space-3);
    flex-wrap: wrap;
}

.bz-page-card-title {
    font-size: var(--bz-fs-md);
    font-weight: var(--bz-fw-semibold);
    color: var(--bz-color-fg);
    margin: 0;
}

.bz-page-card-body { overflow: auto; }

/* ── Styled toolbar — replaces bare <section class="toolbar"> ───────── */
.bz-toolbar {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    padding: var(--bz-space-3) 0;
    margin-bottom: var(--bz-space-3);
    flex-wrap: wrap;
}

/* Heading toolbar row above a grid/section card (pattern B — see AGENTS.md UI standard) */
.bz-grid-toolbar {
    margin-bottom: var(--bz-space-4);
}

/* Search input with leading magnifier icon */
.bz-search-input {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-width: 220px;
    max-width: 340px;
    flex: 1 1 220px;
}

.bz-search-input i {
    position: absolute;
    left: 10px;
    font-size: 15px;
    color: var(--bz-color-fg-subtle);
    pointer-events: none;
    line-height: 1;
}

.bz-search-input input {
    width: 100%;
    padding: 0.38rem 0.75rem 0.38rem 2.1rem;
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    color: var(--bz-color-fg);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    line-height: 1.5;
    transition: border-color var(--bz-duration-fast) var(--bz-ease),
                box-shadow var(--bz-duration-fast) var(--bz-ease);
    min-height: var(--bz-control-height);
}

.bz-search-input input::placeholder { color: var(--bz-color-fg-subtle); }

.bz-search-input input:focus {
    outline: none;
    border-color: var(--bz-brand-primary);
    box-shadow: 0 0 0 3px var(--bz-color-focus-ring);
}

/* Toolbar select filter */
.bz-toolbar-select {
    padding: 0.38rem 0.7rem;
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    color: var(--bz-color-fg);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    min-height: var(--bz-control-height);
    cursor: pointer;
    transition: border-color var(--bz-duration-fast) var(--bz-ease);
}

.bz-toolbar-select:focus {
    outline: none;
    border-color: var(--bz-brand-primary);
    box-shadow: 0 0 0 3px var(--bz-color-focus-ring);
}

/* Toolbar spacer — pushes right-side actions to the end */
.bz-toolbar-spacer { flex: 1; }

/* Toolbar action group */
.bz-toolbar-actions {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    flex-shrink: 0;
}

/* ── Global status badge utilities ──────────────────────────────────── */
/* Use .bz-badge + one of the variants. Replaces per-page .badge-* */
.bz-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: var(--bz-radius-pill);
    font-size: var(--bz-fs-xs);
    font-weight: var(--bz-fw-medium);
    white-space: nowrap;
    line-height: 1.5;
}

.bz-badge-ok      { color: var(--bz-color-ok);     background: color-mix(in srgb, var(--bz-color-ok)     13%, transparent); }
.bz-badge-warn    { color: var(--bz-color-warn);    background: color-mix(in srgb, var(--bz-color-warn)   13%, transparent); }
.bz-badge-danger  { color: var(--bz-color-danger);  background: color-mix(in srgb, var(--bz-color-danger) 13%, transparent); }
.bz-badge-info    { color: var(--bz-color-info);    background: color-mix(in srgb, var(--bz-color-info)   13%, transparent); }
.bz-badge-neutral { color: var(--bz-color-fg-muted); background: var(--bz-color-surface-2); }

/* Row of badges in a grid cell */
.bz-badge-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--bz-space-1);
    align-items: center;
}

/* ── Text utility helpers (referenced from multiple modules) ─────────── */
.bz-text-danger  { color: var(--bz-color-danger) !important; }
.bz-text-warn    { color: var(--bz-color-warn) !important; }

/* `.text-muted` is NOT Bootstrap's here: the Metronic/Tailwind build emits it as
   `color: var(--muted)` — the muted *surface* color, not a text color (that is
   `--muted-foreground`). It therefore renders near-invisible, badly so in dark mode.
   ~258 usages across the web modules mean it, so alias it to the same theme-aware
   token `.bz-text-muted` uses instead of rewriting every call site. */
.text-muted,
.bz-text-muted   { color: var(--bz-color-fg-muted) !important; }
.bz-text-subtle  { color: var(--bz-color-fg-subtle) !important; }
.bz-text-accent  { color: var(--bz-color-accent) !important; }
.bz-fw-medium    { font-weight: var(--bz-fw-medium) !important; }
.bz-fw-semibold  { font-weight: var(--bz-fw-semibold) !important; }
.bz-fs-xs        { font-size: var(--bz-fs-xs) !important; }
.bz-fs-sm        { font-size: var(--bz-fs-sm) !important; }

/* ── Suggestion/alert strip (used in TenantAdmin) ───────────────────── */
.bz-suggestion {
    display: flex;
    align-items: flex-start;
    gap: var(--bz-space-3);
    padding: var(--bz-space-3) var(--bz-space-4);
    border-radius: var(--bz-radius-md);
    background: color-mix(in srgb, var(--bz-color-info) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--bz-color-info) 25%, transparent);
    margin-top: var(--bz-space-3);
    font-size: var(--bz-fs-sm);
    color: var(--bz-color-fg-muted);
}
.bz-suggestion i { color: var(--bz-color-info); margin-top: 2px; flex-shrink: 0; font-size: 16px; }

/* ── Form feedback row ──────────────────────────────────────────────── */
.bz-form-feedback {
    margin-bottom: var(--bz-space-3);
}

/* ── Improved DxGrid inside page cards ─────────────────────────────── */
/* Remove outer border when grid sits inside a bz-page-card */
.bz-page-card .dxbl-grid {
    border: none !important;
    border-radius: 0 !important;
}

/* Tighter header padding for better vertical rhythm */
.dxbl-grid .dxbl-grid-header-cell {
    padding-top: 9px !important;
    padding-bottom: 9px !important;
    font-size: var(--bz-fs-xs) !important;
    font-weight: var(--bz-fw-semibold) !important;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
    vertical-align: middle;
    color: var(--bz-color-fg-muted);
}

/* Standalone grids (outside bz-page-card) get soft corners, and scroll horizontally in place
   rather than letting a resized column push the whole page (see .bz-page-card above). */
.bz-dxgrid {
    border-radius: var(--bz-radius-md);
    overflow-x: auto;
    overflow-y: hidden;
}

/* Filter-row editors: compact, fill the cell, no visual competition with data rows */
.dxbl-grid .dxbl-grid-filter-row td {
    padding: 4px 6px !important;
    background: var(--bz-color-surface);
}
.dxbl-grid .bz-filter-cell {
    width: 100%;
    min-width: 0;
    font-size: var(--bz-fs-sm);
}
.dxbl-grid .bz-filter-range {
    display: inline-flex;
    gap: 4px;
    width: 100%;
}
.dxbl-grid .bz-filter-range .bz-filter-cell {
    width: 50%;
}

/* Data row height */
.dxbl-grid .dxbl-grid-data-row td {
    padding-top: 8px !important;
    padding-bottom: 8px !important;
}

/* Link styling inside grids */
.dxbl-grid a {
    color: var(--bz-color-accent);
    text-decoration: none;
    font-weight: var(--bz-fw-medium);
}
.dxbl-grid a:hover { text-decoration: underline; }

/* Pager container */
.dxbl-grid .dxbl-grid-pager {
    border-top: 1px solid var(--bz-color-border);
    padding: 6px 12px;
    font-size: var(--bz-fs-sm);
}

/* ── DevExpress popup / window — border refinements ─────────────────
   Dark-mode colours are handled by the DevExpress dark.min.css which is
   loaded dynamically by syncDxDarkTheme() in App.razor / SidebarFooter.razor.js
   whenever html.dark is active.  Only visual overrides that go beyond what
   the DevExpress theme provides are placed here. */
.dxbl-modal,
.dxbl-window {
    border-radius: var(--bz-radius-lg);
    box-shadow: var(--bz-shadow-lg);
}

/* ── Popup width standard ────────────────────────────────────────────
   Product decision: every modal popup in the system is 90% of the
   viewport wide. DevExpress drives popup width via --dxbl-popup-width
   (fed by each DxPopup's Width parameter and by adaptive mode), so the
   override must land on the dialog element with !important. Scoped to
   .dxbl-modal so dropdowns/toasts are unaffected. */
.dxbl-modal .dxbl-popup {
    width: 90vw !important;
    max-width: 90vw !important;
}

.dxbl-modal .dxbl-popup-footer,
.dxbl-window .dxbl-popup-footer {
    border-top: 1px solid var(--bz-color-border);
    gap: var(--bz-space-2);
}

/* ── Modal / drawer form polish ──────────────────────────────────────
   Consistent presentation for DxFormLayout-based forms hosted inside
   DevExpress popups (create/edit/confirm dialogs across all modules).
   Inputs fill their column so forms never look cramped, and captions
   read consistently. Scoped to popups so page-level layouts are intact. */
.dxbl-modal .dxbl-form-layout .dxbl-text-edit,
.dxbl-window .dxbl-form-layout .dxbl-text-edit,
.dxbl-modal .dxbl-form-layout .dxbl-edit,
.dxbl-window .dxbl-form-layout .dxbl-edit,
.dxbl-modal .dxbl-form-layout .dxbl-memo,
.dxbl-window .dxbl-form-layout .dxbl-memo,
.dxbl-modal .dxbl-form-layout .dxbl-combobox,
.dxbl-window .dxbl-form-layout .dxbl-combobox,
.dxbl-modal .dxbl-form-layout .dxbl-dropdown,
.dxbl-window .dxbl-form-layout .dxbl-dropdown,
.dxbl-modal .dxbl-form-layout .dxbl-date-edit,
.dxbl-window .dxbl-form-layout .dxbl-date-edit,
.dxbl-modal .dxbl-form-layout .dxbl-spin-edit,
.dxbl-window .dxbl-form-layout .dxbl-spin-edit {
    width: 100%;
}

/* ── DxGrid inline edit form ─────────────────────────────────── */
.bz-edit-form {
    background: var(--bz-color-bg-subtle);
    border-top: 2px solid var(--bz-color-accent);
}

.bz-edit-form-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 16px 16px;
    border-top: 1px solid var(--bz-color-border);
}

/* ── IntelligentAutomation visibility hardening (prompt 040) ─────────── */

/* Success badge variant (sits alongside bz-badge-danger / bz-badge-neutral). */
.bz-badge-success { color: var(--bz-color-ok); background: color-mix(in srgb, var(--bz-color-ok) 14%, transparent); }

/* Filter bar: a row of labelled inputs above a grid. */
.bz-filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--bz-space-3);
    align-items: flex-end;
    padding: var(--bz-space-3) var(--bz-space-4);
}

.bz-inline-label { display: inline-flex; align-items: center; gap: var(--bz-space-2); margin: 0; }
.bz-input-inline { width: auto; min-width: 9rem; }

/* Chip editor (allowed tools / permissions). */
.bz-chip-editor { margin: var(--bz-space-3) 0; }
.bz-chips { display: flex; flex-wrap: wrap; gap: var(--bz-space-2); margin: var(--bz-space-2) 0; }
.bz-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--bz-space-1);
    padding: 2px var(--bz-space-2);
    font-size: var(--bz-fs-sm);
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-pill);
}
.bz-chip-read    { color: var(--bz-color-accent); background: color-mix(in srgb, var(--bz-color-accent) 12%, transparent); }
.bz-chip-propose { color: var(--bz-color-ok); background: color-mix(in srgb, var(--bz-color-ok) 12%, transparent); }
.bz-chip-x {
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--bz-color-fg-muted);
    font-size: 1rem;
    line-height: 1;
    padding: 0 2px;
}
.bz-chip-x:hover { color: var(--bz-color-danger); }

/* Disabled (no-access) dashboard quick-action card. */
.bz-dash-nav-card.bz-disabled { opacity: .55; cursor: not-allowed; pointer-events: none; }

/* Subtle inner panel (e.g. MCP tool preview). */
.bz-subtle { background: var(--bz-color-bg-subtle); box-shadow: none; }

/* Ordered/unordered helper list (MCP setup steps). */
.bz-list { margin: var(--bz-space-2) 0; padding-left: var(--bz-space-5); }
.bz-list li { margin-bottom: var(--bz-space-1); }

/* Review item + secret banner + advanced disclosure (shared by IA pages). */
.bz-review-item {
    padding: var(--bz-space-3) var(--bz-space-4);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    margin-bottom: var(--bz-space-3);
    background: var(--bz-color-surface);
}
.bz-review-item-head { display: flex; align-items: center; gap: var(--bz-space-2); margin-bottom: var(--bz-space-2); }
.bz-advanced { margin: var(--bz-space-2) 0; }
.bz-advanced > summary { cursor: pointer; color: var(--bz-color-fg-muted); font-size: var(--bz-fs-sm); }
.bz-secret-banner { border-left: 3px solid var(--bz-color-accent); padding: var(--bz-space-3) var(--bz-space-4); }

/* ─────────────────────────────────────────────────────────────────────────
   Shared form controls & helper text.
   These utility classes are used by hand-authored (non-DevExpress) forms across
   many module pages (AI smart entry, MCP clients, settings panels, wizards…).
   Defining them globally here keeps those pages visually consistent with the
   DevExpress surfaces instead of falling back to unstyled native controls.
   ───────────────────────────────────────────────────────────────────────── */

/* Field label — block by default so the control sits on its own line. */
.bz-label {
    display: block;
    margin-bottom: var(--bz-space-1);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    color: var(--bz-color-fg-muted);
}

/* Text input / textarea / select — full-width control matching the search box. */
.bz-input {
    display: block;
    width: 100%;
    padding: 0.45rem 0.75rem;
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    color: var(--bz-color-fg);
    font-family: var(--bz-font-sans);
    font-size: var(--bz-fs-sm);
    line-height: 1.5;
    min-height: var(--bz-control-height);
    transition: border-color var(--bz-duration-fast) var(--bz-ease),
                box-shadow var(--bz-duration-fast) var(--bz-ease);
}
textarea.bz-input { min-height: 5rem; resize: vertical; }
.bz-input::placeholder { color: var(--bz-color-fg-subtle); }
.bz-input:focus {
    outline: none;
    border-color: var(--bz-brand-primary);
    box-shadow: 0 0 0 3px var(--bz-color-focus-ring);
}
.bz-input:disabled,
.bz-input[readonly],
.bz-input[readonly="readonly"] {
    background: var(--bz-color-surface-2);
    color: var(--bz-color-fg-muted);
    cursor: not-allowed;
}
.bz-mono { font-family: var(--bz-font-mono); font-size: var(--bz-fs-xs); }

/* Staged record-document upload — file chip, type picker and description composer with the
   Upload button parked in the textarea's bottom-right corner. */
.bz-doc-upload {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    margin-bottom: var(--bz-space-3);
    padding: var(--bz-space-3);
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
}
.bz-doc-upload-file { display: flex; align-items: center; gap: var(--bz-space-2); }
.bz-doc-compose { position: relative; }
.bz-doc-compose textarea.bz-input { padding-bottom: 2.9rem; }
.bz-doc-compose > .kt-btn { position: absolute; right: var(--bz-space-2); bottom: var(--bz-space-2); }

/* Inline control (e.g. the voice-language picker) keeps its intrinsic width even
   though .bz-input sets width:100% — compound selector wins regardless of order. */
.bz-input.bz-input-inline { width: auto; min-width: 9rem; }

/* Responsive two-column form grid for review / detail field sets. */
.bz-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--bz-space-3) var(--bz-space-4);
    margin: var(--bz-space-3) 0;
}

/* Muted helper / hint line with an optional leading icon. */
.bz-hint {
    display: flex;
    align-items: flex-start;
    gap: var(--bz-space-2);
    margin: var(--bz-space-2) 0 0;
    color: var(--bz-color-fg-muted);
    font-size: var(--bz-fs-sm);
    line-height: 1.45;
}
.bz-hint i { color: var(--bz-color-info); margin-top: 1px; flex-shrink: 0; font-size: 15px; }

/* Inline error and empty-state messages. */
.bz-error-msg {
    margin: var(--bz-space-2) 0 0;
    color: var(--bz-color-danger);
    font-size: var(--bz-fs-sm);
}
.bz-empty-msg {
    margin: var(--bz-space-3) 0;
    color: var(--bz-color-fg-subtle);
    font-size: var(--bz-fs-sm);
}

/* Small button size modifier (pairs with .btn-primary/.btn-secondary). */
.btn-sm {
    padding: 0.2rem 0.55rem;
    font-size: var(--bz-fs-xs);
}

/* Lightweight data table for simple read-only lists (non-DevExpress surfaces). */
.bz-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--bz-fs-sm);
    margin: var(--bz-space-2) 0;
}
.bz-table th,
.bz-table td {
    text-align: left;
    padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--bz-color-border);
}
.bz-table th {
    color: var(--bz-color-fg-muted);
    font-weight: var(--bz-fw-semibold);
    background: var(--bz-color-surface-2);
}
.bz-table tbody tr:hover { background: var(--bz-color-surface-2); }

/* ── Business Partner (Relationship Management) wizard + detail ─────────
   This app ships only a subset of Bootstrap utilities (spacing/sizing,
   not flex/grid/alert/form-select), so these layout helpers live here as
   first-class bz-* classes loaded globally via tokens+shell. */

/* Generic flex helpers (replacements for the missing d-flex utilities). */
.bz-form-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--bz-space-3);
    margin-top: var(--bz-space-5);
}
.bz-actions-end {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--bz-space-2);
    margin-bottom: var(--bz-space-3);
}
.bz-actions-end-inline { display: inline-flex; gap: var(--bz-space-2); }

/* Centered wizard column. */
.bz-wizard { max-width: 980px; margin: 0 auto; padding: var(--bz-space-5); }
/* Wide variant: fill 90% of the available width (tenant onboarding). The shared EmptyLayout caps
   its content column (max-width 728px), so a page hosting a wide wizard lifts that cap too. */
.bz-wizard-wide { max-width: 90%; }
/* EmptyLayout caps content via max-inline-size and sizes shrink-to-fit as a flex item — lift both. */
main.empty-layout:has(.bz-wizard-wide) { max-inline-size: none; width: 100%; flex: 1 1 auto; }

/* Horizontal step indicator. */
.bz-wizard-steps {
    display: flex;
    /* 7+ steps with long labels overflow the card and clip the last tab — wrap instead. */
    flex-wrap: wrap;
    gap: var(--bz-space-2);
    list-style: none;
    padding: 0;
    margin: 0 0 var(--bz-space-5);
}
.bz-wizard-steps li {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: break-word;
    text-align: center;
    padding: 0.6rem 0.5rem;
    border-radius: var(--bz-radius-md);
    background: var(--bz-color-surface-2);
    color: var(--bz-color-fg-subtle);
    font-weight: var(--bz-fw-medium);
    font-size: var(--bz-fs-sm);
    border: 1px solid var(--bz-color-border);
}
.bz-wizard-steps li.active {
    background: var(--bz-brand-primary);
    color: var(--bz-color-accent-fg);
    border-color: var(--bz-brand-primary);
}
.bz-wizard-steps li.done {
    background: var(--bz-color-surface);
    color: var(--bz-color-ok);
    border-color: var(--bz-color-ok);
}
.bz-wizard-steps-clickable li { cursor: pointer; transition: background .12s, color .12s; }
.bz-wizard-steps-clickable li:hover { border-color: var(--bz-brand-primary); }
.bz-wizard-step { padding: var(--bz-space-2) 0 var(--bz-space-4); }
.bz-wizard-step h5 {
    font-size: var(--bz-fs-md);
    font-weight: var(--bz-fw-semibold);
    margin: 0 0 var(--bz-space-2);
    color: var(--bz-color-fg);
}
.bz-wizard-step h6 {
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-semibold);
    margin: var(--bz-space-4) 0 var(--bz-space-2);
    color: var(--bz-color-fg);
}

/* Selectable platform cards in the Add-connector wizard. */
.bz-connector-platform {
    display: flex;
    align-items: center;
    gap: var(--bz-space-3);
    padding: var(--bz-space-3);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    background: transparent;
    color: var(--bz-color-fg);
    cursor: pointer;
    text-align: left;
    transition: background .12s, border-color .12s, box-shadow .12s;
}
.bz-connector-platform:hover { border-color: var(--bz-color-accent); }
.bz-connector-platform-active {
    border-color: var(--bz-color-accent);
    background: color-mix(in srgb, var(--bz-color-accent) 12%, transparent);
    box-shadow: inset 0 0 0 1px var(--bz-color-accent);
}
.bz-connector-platform-active .ki-filled { color: var(--bz-color-accent); }

/* Field label + radio group row. */
.bz-field-label {
    display: block;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    color: var(--bz-color-fg-muted);
    margin-bottom: var(--bz-space-2);
}
.bz-field-block { margin-bottom: var(--bz-space-4); }
.bz-radio-row { display: flex; gap: var(--bz-space-5); flex-wrap: wrap; }
.bz-radio-row label { display: inline-flex; align-items: center; gap: var(--bz-space-1); cursor: pointer; }
.bz-help { color: var(--bz-color-fg-subtle); font-size: var(--bz-fs-sm); margin: 0 0 var(--bz-space-4); }

/* Padded body for a bz-page-card whose content sits directly under a bz-page-card-head
   (the card itself has no inner padding and clips to its radius). */
.bz-card-pad { padding: var(--bz-space-4) var(--bz-space-5); }

/* MCP clients page: endpoint row + tool-picker dropdown option + effective-tools preview. */
.bz-mcp-endpoint { display: flex; align-items: center; gap: var(--bz-space-2); flex-wrap: wrap; margin: var(--bz-space-2) 0; }
.bz-mcp-option { padding: var(--bz-space-1) 0; }
.bz-mcp-option-head { display: flex; align-items: center; gap: var(--bz-space-2); }
.bz-mcp-tagbox { width: 100%; }
.bz-mcp-preview {
    margin-top: var(--bz-space-5);
    padding: var(--bz-space-4);
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
}
.bz-mcp-preview > .bz-label {
    display: block;
    margin-bottom: var(--bz-space-2);
    text-transform: uppercase;
    font-size: var(--bz-fs-xs);
    letter-spacing: .04em;
    color: var(--bz-color-fg-subtle);
}

/* Inline action buttons inside a DxGrid command cell. */
.bz-grid-actions { display: inline-flex; align-items: center; gap: var(--bz-space-2); }

/* "Select all / Clear" shortcuts under a tag-box picker. */
.bz-picker-actions { display: flex; gap: var(--bz-space-3); margin-top: var(--bz-space-2); }

/* Assistant chat: rendered markdown inside message bubbles. */
.bz-ai-chat-md { font-size: var(--bz-fs-sm); line-height: 1.5; }
.bz-ai-chat-md p { margin: 0 0 var(--bz-space-2); }
.bz-ai-chat-md p:last-child { margin-bottom: 0; }
.bz-ai-chat-md ul, .bz-ai-chat-md ol { margin: 0 0 var(--bz-space-2); padding-left: 1.2rem; }
.bz-ai-chat-md code {
    font-family: var(--bz-font-mono);
    font-size: var(--bz-fs-xs);
    background: var(--bz-color-surface-2);
    border-radius: var(--bz-radius-sm);
    padding: 0 4px;
}
.bz-ai-chat-md pre {
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-2) var(--bz-space-3);
    overflow-x: auto;
}
.bz-ai-chat-md table { border-collapse: collapse; margin: var(--bz-space-2) 0; max-width: 100%; }
.bz-ai-chat-md th, .bz-ai-chat-md td {
    border: 1px solid var(--bz-color-border);
    padding: 4px 8px;
    text-align: left;
    font-size: var(--bz-fs-xs);
}
.bz-ai-chat-md th { background: var(--bz-color-surface-2); font-weight: var(--bz-fw-semibold); }

/* Assistant chat: Results cards (read-tool datasets rendered as tables + export actions). */
.bz-ai-chat-results { padding: var(--bz-space-2) var(--bz-space-3); overflow-y: auto; max-height: 40%; }
.bz-ai-chat-result-card {
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-2) var(--bz-space-3);
    margin-bottom: var(--bz-space-2);
}
.bz-ai-chat-result-head {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    font-weight: var(--bz-fw-semibold);
    font-size: var(--bz-fs-sm);
    margin-bottom: var(--bz-space-2);
}
.bz-ai-chat-result-head .bz-hint { margin: 0 0 0 auto; }
.bz-ai-chat-result-scroll { overflow: auto; max-height: 240px; border: 1px solid var(--bz-color-border); border-radius: var(--bz-radius-sm); }
.bz-ai-chat-table { width: 100%; border-collapse: collapse; font-size: var(--bz-fs-xs); }
.bz-ai-chat-table th, .bz-ai-chat-table td {
    border-bottom: 1px solid var(--bz-color-border);
    padding: 4px 8px;
    text-align: left;
    white-space: nowrap;
}
.bz-ai-chat-table th { position: sticky; top: 0; background: var(--bz-color-surface-2); font-weight: var(--bz-fw-semibold); }
.bz-ai-chat-result-actions { display: flex; gap: var(--bz-space-2); margin-top: var(--bz-space-2); }

/* Schema-driven review form (AiSchemaForm): nested object groups + repeatable array items. */
.bz-schema-form { margin: var(--bz-space-2) 0; }
.bz-schema-form-caption { display: block; margin: var(--bz-space-3) 0 var(--bz-space-1); font-weight: var(--bz-fw-semibold); }
.bz-schema-form-group { margin-top: var(--bz-space-2); }
.bz-schema-form-item {
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-2) var(--bz-space-3);
    margin-bottom: var(--bz-space-2);
    background: var(--bz-color-surface-2);
}

/* Geo/address search row. */
.bz-geo-search { display: flex; gap: var(--bz-space-2); align-items: stretch; margin-bottom: var(--bz-space-3); }
.bz-geo-search .bz-search-input { max-width: none; flex: 1; }

/* Inline editable people grid in the wizard. */
.bz-mini-grid { width: 100%; border-collapse: collapse; margin-bottom: var(--bz-space-3); }
.bz-mini-grid th {
    text-align: left;
    font-size: var(--bz-fs-xs);
    font-weight: var(--bz-fw-semibold);
    color: var(--bz-color-fg-subtle);
    padding: var(--bz-space-2);
    border-bottom: 1px solid var(--bz-color-border);
}
.bz-mini-grid td { padding: var(--bz-space-2); vertical-align: middle; }

/* Alert boxes (no Bootstrap .alert in this theme). */
.bz-alert {
    border: 1px solid transparent;
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-3) var(--bz-space-4);
    margin-bottom: var(--bz-space-4);
    font-size: var(--bz-fs-sm);
}
.bz-alert ul { margin: var(--bz-space-2) 0 0; padding-left: 1.1rem; }
.bz-alert-danger { background: color-mix(in srgb, var(--bz-color-danger) 12%, var(--bz-color-surface)); color: var(--bz-color-danger); border-color: color-mix(in srgb, var(--bz-color-danger) 40%, transparent); }
.bz-alert-warn { background: color-mix(in srgb, var(--bz-color-warn) 12%, var(--bz-color-surface)); color: var(--bz-color-warn); border-color: color-mix(in srgb, var(--bz-color-warn) 40%, transparent); }
.bz-alert-info { background: color-mix(in srgb, var(--bz-color-info) 12%, var(--bz-color-surface)); color: var(--bz-color-info); border-color: color-mix(in srgb, var(--bz-color-info) 40%, transparent); }

/* Review definition list (replaces the missing .row/.col grid). */
.bz-review { display: grid; grid-template-columns: 180px 1fr; gap: var(--bz-space-2) var(--bz-space-4); margin: 0; }
.bz-review dt { font-weight: var(--bz-fw-medium); color: var(--bz-color-fg-subtle); }
.bz-review dd { margin: 0; color: var(--bz-color-fg); }

/* Entity detail field grid — each child <div> is one <label>Caption</label><div>Value</div> pair,
   wrapping into a responsive multi-column layout (used by ProjectManagement Detail/Config pages). */
.bz-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--bz-space-4);
    margin: var(--bz-space-3) 0;
}
.bz-detail-grid > div > label {
    display: block;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    color: var(--bz-color-fg-subtle);
    margin-bottom: var(--bz-space-1);
}
.bz-detail-grid > div > div { color: var(--bz-color-fg); }
/* Span-based variant of the same pair, used by read-only quick views / detail pages
   (AddressQuickView, AddressDetail, ContactDetail). */
.bz-detail-field > .bz-detail-label {
    display: block;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    color: var(--bz-color-fg-subtle);
    margin-bottom: var(--bz-space-1);
}

.bz-detail-desc { color: var(--bz-color-fg-muted); margin: var(--bz-space-3) 0; line-height: 1.5; }

/* Rendered rich-text (RichTextView) — the tag set SafeHtml allows, nothing else. */
.bz-richtext p, .bz-richtext ul, .bz-richtext ol, .bz-richtext blockquote { margin: 0 0 var(--bz-space-2); }
.bz-richtext > :last-child { margin-bottom: 0; }
.bz-richtext ul, .bz-richtext ol { padding-left: 1.2rem; }
.bz-richtext blockquote {
    border-left: 3px solid var(--bz-color-border);
    padding-left: var(--bz-space-3);
    color: var(--bz-color-fg-subtle);
}
.bz-richtext code {
    font-family: var(--bz-font-mono);
    font-size: var(--bz-fs-xs);
    background: var(--bz-color-surface-2);
    border-radius: var(--bz-radius-sm);
    padding: 0 4px;
}
.bz-richtext pre {
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-2) var(--bz-space-3);
    overflow-x: auto;
}

/* Horizontal sub-page navigation strip (e.g. project Detail tabs: WBS, diary, defects…). */
.bz-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--bz-space-1);
    border-top: 1px solid var(--bz-color-border);
    margin-top: var(--bz-space-4);
    padding-top: var(--bz-space-3);
}
.bz-tabs a {
    padding: var(--bz-space-2) var(--bz-space-3);
    border-radius: var(--bz-radius-md);
    color: var(--bz-color-fg-muted);
    text-decoration: none;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    /* transform repeated: this rule outranks the shared press-feedback selector. */
    transition: background var(--bz-duration-fast) var(--bz-ease),
                color var(--bz-duration-fast) var(--bz-ease),
                transform var(--bz-duration-press) var(--bz-ease);
}
.bz-tabs a:hover { background: var(--bz-color-surface-2); color: var(--bz-color-fg); }

/* Detail summary metric cards. */
.bz-summary-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--bz-space-4);
    margin: var(--bz-space-4) 0;
}
.bz-card {
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-lg);
    padding: var(--bz-space-4);
    box-shadow: var(--bz-shadow-sm);
}
.bz-card-label { font-size: var(--bz-fs-xs); color: var(--bz-color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
.bz-card-value { font-size: var(--bz-fs-lg, 18px); font-weight: var(--bz-fw-semibold); margin-top: var(--bz-space-1); color: var(--bz-color-fg); }

/* Header row pairing a <RecordDocumentAvatar> with a <PageHeader> on detail pages. */
.bz-page-header-row {
    display: flex;
    align-items: center;
    gap: var(--bz-space-4);
}
.bz-page-header-row .bz-page-header { flex: 1; }

/* <RecordDocumentAvatar> — circular image/initials with a hover-reveal upload/remove overlay. */
.bz-avatar {
    position: relative;
    flex: 0 0 auto;
    border-radius: var(--bz-radius-pill);
    overflow: hidden;
    background: var(--bz-primary-50);
    box-shadow: var(--bz-shadow-sm);
}
.bz-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.bz-avatar-initials {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--bz-primary);
    font-weight: var(--bz-fw-semibold);
    font-size: 1.5rem;
}
.bz-avatar-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--bz-space-2);
    background: color-mix(in srgb, black 45%, transparent);
    opacity: 0;
    transition: opacity var(--bz-duration-fast) var(--bz-ease);
}
.bz-avatar:hover .bz-avatar-overlay,
.bz-avatar:focus-within .bz-avatar-overlay {
    opacity: 1;
}
.bz-avatar-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--bz-radius-pill);
    border: none;
    background: var(--bz-surface);
    color: var(--bz-color-fg);
    cursor: pointer;
    padding: 0;
}
.bz-avatar-action:hover { background: var(--bz-primary-50); color: var(--bz-primary); }
.bz-avatar-error {
    margin-top: var(--bz-space-1);
    font-size: var(--bz-fs-xs);
    color: var(--bz-color-danger);
}

/* <RecordDocumentAvatar Shape="rect"> — rectangular logo variant (e.g. tenant logo). Square corners,
   object-fit:contain so the whole image shows instead of a cropped/cover circle. Reuses
   .bz-avatar-initials/-overlay/-action; only the hover-reveal trigger needs its own selector. */
.bz-logo-upload {
    position: relative;
    flex: 0 0 auto;
    border-radius: var(--bz-radius-md);
    overflow: hidden;
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    box-shadow: var(--bz-shadow-sm);
}
.bz-logo-img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
.bz-logo-upload:hover .bz-avatar-overlay,
.bz-logo-upload:focus-within .bz-avatar-overlay {
    opacity: 1;
}

/* image-crop.js — JS-owned crop overlay (outside the Blazor render tree, so plain CSS here). */
.bz-cropper-backdrop {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, black 55%, transparent);
}
.bz-cropper-modal {
    background: var(--bz-color-surface);
    border-radius: var(--bz-radius-lg);
    box-shadow: var(--bz-shadow-lg, var(--bz-shadow-sm));
    padding: var(--bz-space-5);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--bz-space-3);
    max-width: 90vw;
}
.bz-cropper-title {
    font-weight: var(--bz-fw-semibold);
    font-size: var(--bz-fs-lg, 18px);
    color: var(--bz-color-fg);
    align-self: flex-start;
}
.bz-cropper-stage {
    position: relative;
    border-radius: var(--bz-radius-pill);
    overflow: hidden;
    background: var(--bz-color-surface-2);
    touch-action: none;
    cursor: grab;
}
.bz-cropper-stage:active { cursor: grabbing; }
/* Shape="rect" (e.g. tenant logo) — rectangular stage, no pill mask. */
.bz-cropper-stage-rect { border-radius: var(--bz-radius-md); }
.bz-cropper-img {
    position: absolute;
    max-width: none;
    pointer-events: none;
    user-select: none;
}
.bz-cropper-hint {
    font-size: var(--bz-fs-xs);
    color: var(--bz-color-fg-subtle);
}
.bz-cropper-controls {
    width: 100%;
    display: flex;
    align-items: center;
}
.bz-cropper-zoom { width: 100%; accent-color: var(--bz-primary); }
.bz-cropper-actions {
    display: flex;
    gap: var(--bz-space-2);
    align-self: flex-end;
}

/* Filter select reusing the toolbar-select look. */
.bz-filter {
    padding: 0.38rem 0.7rem;
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    color: var(--bz-color-fg);
    font-size: var(--bz-fs-sm);
    min-width: 170px;
}

/* Settings field label with info button + status badge. */
.bz-setting-label {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-medium);
    color: var(--bz-color-fg-muted);
    margin-bottom: var(--bz-space-2);
}
.bz-info-btn {
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--bz-brand-primary);
    padding: 0;
    display: inline-flex;
    align-items: center;
}
.bz-info-btn i { font-size: 16px; }

/* AI-assist panel on the create wizard. */
.bz-ai-panel {
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-lg);
    background: linear-gradient(180deg, rgba(31,95,216,0.06), rgba(31,95,216,0.02));
    padding: var(--bz-space-4);
    margin-bottom: var(--bz-space-4);
}
.bz-ai-head {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    font-weight: var(--bz-fw-semibold);
    color: var(--bz-brand-primary);
    margin-bottom: var(--bz-space-1);
}
.bz-ai-head i { font-size: 18px; }

/* "or" divider between AI assist and the manual form. */
.bz-or {
    display: flex;
    align-items: center;
    text-align: center;
    color: var(--bz-color-fg-subtle);
    font-size: var(--bz-fs-sm);
    margin: var(--bz-space-2) 0 var(--bz-space-4);
}
.bz-or::before, .bz-or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--bz-color-border);
}
.bz-or span { padding: 0 var(--bz-space-3); }

/* ============================================================
   Global AI assistant chat widget (bottom-right). Built from --bz-* tokens.
   ============================================================ */
.bz-ai-chat-root { position: fixed; bottom: var(--bz-space-5); right: var(--bz-space-5); z-index: 50; }

/* Embedded (full-page) variant: same panel, undocked and stretched to fill the host page. */
.bz-ai-chat-root.is-embedded { position: static; z-index: auto; }
.bz-ai-chat-root.is-embedded .bz-ai-chat-panel {
    width: 100%; max-width: none;
    height: calc(100vh - 230px); min-height: 460px; max-height: none;
    animation: none;
}

.bz-ai-chat-launcher {
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--bz-color-accent); color: #fff;
    border: none; cursor: pointer;
    box-shadow: var(--bz-shadow-md);
    font-size: 22px; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: transform var(--bz-duration-fast) var(--bz-ease), filter var(--bz-duration-fast) var(--bz-ease);
}
/* Gated: a touch tap fires :hover and leaves the button stuck lifted until the
   next tap elsewhere. Pointer devices only. */
@media (hover: hover) and (pointer: fine) {
    .bz-ai-chat-launcher:hover { transform: translateY(-2px); filter: brightness(1.05); }
}
.bz-ai-chat-launcher:active { transform: scale(0.97); }

.bz-ai-chat-panel {
    width: 480px; max-width: calc(100vw - 2 * var(--bz-space-4));
    height: 700px; max-height: calc(100vh - 2 * var(--bz-space-5));
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    box-shadow: var(--bz-shadow-md);
    display: flex; flex-direction: column; overflow: hidden;
    /* Anchored to its launcher in the bottom-right corner, so it scales out of the
       launcher rather than out of its own centre. 280ms, not 120ms: this is a
       480x700 panel, and button-press timing on it reads as a snap. */
    transform-origin: bottom right;
    animation: bz-ai-chat-slide-up var(--bz-duration-slow) var(--bz-ease);
    transition: width var(--bz-duration-base) var(--bz-ease), height var(--bz-duration-base) var(--bz-ease);
}
/* Full-screen within the tab/viewport; restore via the header icon. */
.bz-ai-chat-panel.is-maximized {
    position: fixed; inset: var(--bz-space-4);
    width: auto; height: auto; max-width: none; max-height: none;
}
/* The small scale makes it read as emerging FROM the launcher; a pure translate
   reads as an unrelated panel sliding past. Never from scale(0) — nothing in the
   real world appears out of nothing. */
@keyframes bz-ai-chat-slide-up {
    from { opacity: 0; transform: translateY(12px) scale(0.97); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.bz-ai-chat-head {
    display: flex; align-items: center; gap: var(--bz-space-2);
    padding: var(--bz-space-3) var(--bz-space-4);
    border-bottom: 1px solid var(--bz-color-border);
    background: var(--bz-color-bg);
}
.bz-ai-chat-title { font-weight: 600; flex: 1; min-width: 0; color: var(--bz-color-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bz-ai-chat-icon-btn {
    border: none; background: transparent; cursor: pointer;
    color: var(--bz-color-fg); padding: 4px; border-radius: var(--bz-radius-sm);
    display: inline-flex; align-items: center; justify-content: center;
}
.bz-ai-chat-icon-btn:hover { background: var(--bz-color-border); }

.bz-ai-chat-body { flex: 1; display: flex; min-height: 0; }
.bz-ai-chat-threads {
    width: 150px; border-right: 1px solid var(--bz-color-border);
    overflow-y: auto; background: var(--bz-color-bg);
}
.bz-ai-chat-threads-empty { padding: var(--bz-space-3); color: var(--bz-color-fg-muted, #64748b); font-size: 13px; }
.bz-ai-chat-thread-item {
    display: flex; align-items: center; gap: 4px;
    padding: var(--bz-space-2) var(--bz-space-3); cursor: pointer;
    border-bottom: 1px solid var(--bz-color-border);
}
.bz-ai-chat-thread-item:hover { background: var(--bz-color-border); }
.bz-ai-chat-thread-item.is-active { background: var(--bz-color-border); font-weight: 600; }
.bz-ai-chat-thread-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.bz-ai-chat-thread-del { opacity: 0; }
.bz-ai-chat-thread-item:hover .bz-ai-chat-thread-del { opacity: 1; }

.bz-ai-chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* min-height, not 0: the proposals block below may grow to 80% of the column, and a chat surface
   collapsed to nothing looks like the assistant died. */
.bz-ai-chat-surface { flex: 1; min-height: 120px; }

.bz-ai-chat-welcome {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--bz-space-3); text-align: center; padding: var(--bz-space-5); color: var(--bz-color-fg);
}
.bz-ai-chat-welcome-icon { font-size: 36px; color: var(--bz-color-accent); }

/* Review block under the chat. Height is a custom property so the drag handle can override it from
   JS (ai-proposals-resize.js) without a Blazor round-trip per pointermove; the 55% default is a
   share of the panel column, so `is-maximized` scales it up with the panel instead of capping it. */
.bz-ai-chat-proposals {
    /* flex-basis (not height): resolves against the flex column's main size, so the 55% default
       tracks the panel — including `is-maximized` — and a px value from the drag handle overrides it. */
    flex: 0 0 var(--bz-ai-proposals-h, 55%);
    min-height: 132px; /* one collapsed card */
    max-height: 80%;
    display: flex; flex-direction: column;
    border-top: 1px solid var(--bz-color-border);
    background: var(--bz-color-bg);
    overflow: hidden;
}
.bz-ai-chat-proposals-grip {
    flex: 0 0 auto; height: 10px; cursor: ns-resize;
    display: flex; align-items: center; justify-content: center;
    background: var(--bz-color-bg);
    touch-action: none; /* the pointer drag owns the gesture, not the scroller */
}
/* The grippy itself: a short bar, widening slightly on hover so the handle reads as grabbable. */
.bz-ai-chat-proposals-grip::before {
    content: ""; width: 32px; height: 3px; border-radius: var(--bz-radius-pill);
    background: var(--bz-color-border);
    transition: width var(--bz-duration-fast) var(--bz-ease), background-color var(--bz-duration-fast) var(--bz-ease);
}
.bz-ai-chat-proposals-grip:hover::before,
.bz-ai-chat-proposals-grip.is-dragging::before { width: 48px; background: var(--bz-color-accent); }

.bz-ai-chat-proposals-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: var(--bz-space-3); }

.bz-ai-chat-proposal-card {
    border: 1px solid var(--bz-color-border); border-radius: var(--bz-radius-sm);
    margin-bottom: var(--bz-space-3); background: var(--bz-color-surface);
    overflow: hidden;
}
.bz-ai-chat-proposal-head {
    display: flex; align-items: center; gap: 6px; font-weight: 600;
    padding: var(--bz-space-2) var(--bz-space-3);
    border-bottom: 1px solid var(--bz-color-border);
    background: var(--bz-color-bg);
}
.bz-ai-chat-proposal-icon { color: var(--bz-color-accent); }
.bz-ai-chat-proposal-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Items are separated by a rule rather than margin — several staged records in one card otherwise
   read as one long form. */
.bz-ai-chat-proposal-item { padding: var(--bz-space-3); }
.bz-ai-chat-proposal-item + .bz-ai-chat-proposal-item { border-top: 1px solid var(--bz-color-border); }
.bz-ai-chat-proposal-fields { list-style: none; margin: 4px 0 0; padding: 0; font-size: 13px; }
.bz-ai-chat-proposal-fields li { padding: 1px 0; }
.bz-ai-chat-field-name { color: var(--bz-color-fg-muted, #64748b); }
.bz-ai-chat-proposal-validation { color: var(--bz-color-danger, #b91c1c); font-size: 13px; margin: 2px 0; }
/* Sticky bottom bar: approve/reject stay reachable while a long item list scrolls past. */
.bz-ai-chat-proposal-actions {
    position: sticky; bottom: 0; z-index: 1;
    display: flex; align-items: center; gap: var(--bz-space-2); flex-wrap: wrap;
    padding: var(--bz-space-2) var(--bz-space-3);
    border-top: 1px solid var(--bz-color-border);
    background: var(--bz-color-bg);
}
.bz-ai-chat-skip-dup { margin-left: auto; font-size: 13px; }
.bz-ai-chat-proposal-note { color: var(--bz-color-fg-muted, #64748b); font-size: 13px; margin: 0; padding: var(--bz-space-2) var(--bz-space-3); }

@media (max-width: 520px) {
    .bz-ai-chat-panel { width: calc(100vw - 2 * var(--bz-space-4)); height: calc(100vh - 2 * var(--bz-space-5)); }
}

/* ── Progress bars (storage migrations / backups live progress) ─────────────── */
.bz-progress { height: 8px; background: var(--bz-surface-3); border-radius: var(--bz-radius-pill); overflow: hidden; }
.bz-progress-fill { height: 100%; background: var(--bz-primary); transition: width var(--bz-duration-slow) var(--bz-ease); }
.bz-progress-fill--indeterminate { width: 40%; animation: bz-indeterminate 1.1s var(--bz-ease-in-out) infinite; }
/* Over 100% of a known capacity (workload board). The bar itself stays clamped at full
   width — the number next to it carries the overshoot; a bar wider than its track lies. */
.bz-progress-fill--over { background: var(--bz-color-danger); }
/* transform, NOT margin-left: margin forces layout -> paint -> composite on every
   frame, and this loop runs for the whole life of every API call in the app.
   translateX is a % of the element's OWN width (40% of the track), so the track's
   -40%..100% margin sweep becomes -100%..250% here. */
@keyframes bz-indeterminate {
    from { transform: translateX(-100%); }
    to   { transform: translateX(250%); }
}

/* Global API activity bar (MainLayout). Pinned above everything so a slow save is visible wherever
   the user has scrolled to; fades out rather than disappearing, so a burst of quick calls does not
   flicker. pointer-events:none — it must never intercept a click. */
.bz-topbar-progress {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 3px;
    z-index: 2000;
    overflow: hidden;
    background: transparent;
    pointer-events: none;
    opacity: 1;
    transition: opacity .25s ease;
}
.bz-topbar-progress--idle { opacity: 0; }



/* ── Toasts (<ToastHost>, rendered once in MainLayout) ─────────────────────────
   Lives here rather than in a ToastHost.razor.css: AGENTS.md puts cross-cutting
   component classes in shell.css, and Blazor's scoped-CSS rewriter has no defined
   behaviour for the @starting-style at-rule below. */
.bz-toast-host {
    position: fixed;
    right: var(--bz-space-4);
    /* --header-height is set on <body> in App.razor (60px); this tracks the mobile topbar. */
    top: calc(var(--header-height) + var(--bz-space-3));
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    z-index: 2000;
    pointer-events: none;
}

.bz-toast {
    pointer-events: auto;
    min-width: 260px;
    max-width: 420px;
    padding: var(--bz-space-3) var(--bz-space-4);
    background: var(--bz-color-surface);
    color: var(--bz-color-fg);
    border: 1px solid var(--bz-color-border);
    border-left: 4px solid var(--bz-color-accent);
    border-radius: var(--bz-radius-md);
    box-shadow: var(--bz-shadow-md);
    display: flex;
    align-items: center;
    gap: var(--bz-space-3);
    font-size: var(--bz-fs-sm);
    transition: opacity var(--bz-duration-base) var(--bz-ease),
                transform var(--bz-duration-base) var(--bz-ease);
}

/* Enters from above — the direction the stack grows from, so the motion says
   where it came from. Never from scale(0): things do not appear from nothing.
   ponytail: enter only. An exit needs IToastService to hold the item through its
   exit window (a C# change); a toast vanishing is far less jarring than one
   popping into existence, so the enter is where the value is. */
@starting-style {
    .bz-toast { opacity: 0; transform: translateY(-8px) scale(0.97); }
}

.bz-toast-success { border-left-color: var(--bz-color-ok); }
.bz-toast-warning { border-left-color: var(--bz-color-warn); }
.bz-toast-error { border-left-color: var(--bz-color-danger); }

.bz-toast-msg { flex: 1; }

.bz-toast-close {
    background: transparent;
    border: 0;
    color: var(--bz-color-fg-muted);
    font-size: 18px;
    cursor: pointer;
    padding: 0 var(--bz-space-1);
}

.bz-toast-close:hover { color: var(--bz-color-fg); }


/* ── Search-term highlight (record-document search results) ─────────────────── */
/* Built from --bz-color-warn so it flips with the theme: a hard-coded yellow is
   unreadable in dark mode (same trap as .text-muted mapping to a surface token). */
.bz-mark {
    background: color-mix(in srgb, var(--bz-color-warn) 38%, transparent);
    color: inherit;
    border-radius: var(--bz-radius-sm, 3px);
    padding: 0 2px;
    font-weight: 600;
}


/* ── Task boards (/task-management/board) ───────────────────────────────────── */
/* Hand-built columns: no Kanban package is referenced anywhere in the repo and one
   flex row of scrolling columns does not justify adding one. Drag/drop affordances
   (--over on a hovered column, --drop-before as the placeholder, --dragging on the
   held card) are toggled by kanban.js; every colour comes from a --bz-* token so the
   board flips with the theme. */
.bz-kanban {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-3);
    padding: var(--bz-space-3) 0;
    min-height: 12rem;
}

/* One swimlane row. A board without swimlanes renders exactly one of these, so the
   column strip behaves identically whether or not lanes exist. */
.bz-kanban-lane {
    display: flex;
    gap: var(--bz-space-3);
    align-items: flex-start;
    overflow-x: auto;
}

/* A swimlane block = its header + the column strip below it. Nested flex rather than
   one CSS grid: the columns already scroll horizontally as a flex row, and a grid
   would have to re-declare the column track per lane just to stay aligned. */
.bz-kanban-swimlane {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
}

.bz-kanban-lane-head {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    padding: var(--bz-space-2) var(--bz-space-3);
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    /* Sticks to the left edge while the column strip scrolls sideways, so the lane a
       row belongs to never scrolls out of sight. */
    position: sticky;
    left: 0;
}

.bz-kanban-lane-name { font-weight: var(--bz-fw-semibold); }

/* Lanes stack vertically, so a full-height column per lane would push the next lane
   off screen. Each cell gets its own modest scroll instead. */
.bz-kanban-swimlane .bz-kanban-col { max-height: 26rem; }

/* Workload rollup under a column header (Σ hours / capacity + the unestimated badge). */
.bz-kanban-col-load {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-1);
    padding: var(--bz-space-2) var(--bz-space-3);
    border-bottom: 1px solid var(--bz-color-border);
}

.bz-kanban-col-load-text {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    font-size: var(--bz-fs-xs);
    color: var(--bz-color-fg-muted);
}

/* Board selector: which board is open, not a filter — hence pills, not a select. */
.bz-board-pills {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    flex-wrap: wrap;
    padding: var(--bz-space-2) 0;
}

.bz-board-pill {
    padding: var(--bz-space-1) var(--bz-space-3);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-pill);
    background: var(--bz-color-surface);
    color: var(--bz-color-fg);
    font-size: var(--bz-fs-sm);
    cursor: pointer;
}

.bz-board-pill:hover { border-color: var(--bz-primary); }

.bz-board-pill--active {
    background: color-mix(in srgb, var(--bz-primary) 12%, var(--bz-color-surface));
    border-color: var(--bz-primary);
    color: var(--bz-primary);
    font-weight: var(--bz-fw-semibold);
}

.bz-board-pill:disabled { opacity: .6; cursor: default; }

.bz-kanban-col {
    display: flex;
    flex-direction: column;
    flex: 0 0 20rem;
    max-height: calc(100vh - 19rem);
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-lg);
}

.bz-kanban-col--over {
    border-color: var(--bz-primary);
    background: color-mix(in srgb, var(--bz-primary) 8%, var(--bz-color-surface-2));
}

/* A collapsed column keeps its header (name + count) so nothing disappears silently;
   it just stops taking a full column's width. */
.bz-kanban-col--collapsed { flex: 0 0 14rem; }

.bz-kanban-col-toggle {
    border: 0;
    background: none;
    color: var(--bz-color-fg-muted);
    padding: 0;
    line-height: 1;
    cursor: pointer;
    flex: 0 0 auto;
}

.bz-kanban-col-toggle:hover { color: var(--bz-primary); }

.bz-kanban-col-head {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    padding: var(--bz-space-3);
    border-bottom: 1px solid var(--bz-color-border);
}

.bz-kanban-col-name {
    font-weight: var(--bz-fw-semibold);
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bz-kanban-dot {
    width: 10px;
    height: 10px;
    border-radius: var(--bz-radius-pill);
    flex: 0 0 auto;
}

/* Only the card list scrolls, so the header and the "new task" footer stay put. */
.bz-kanban-list {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    padding: var(--bz-space-2);
    overflow-y: auto;
    flex: 1;
    min-height: 3rem;
}

.bz-kanban-col-foot {
    padding: var(--bz-space-2);
    border-top: 1px solid var(--bz-color-border);
}

.bz-kanban-card {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    padding: var(--bz-space-3);
    background: var(--bz-color-surface);
    border: 1px solid var(--bz-color-border);
    border-left: 3px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    cursor: pointer;
}

.bz-kanban-card:hover { border-color: var(--bz-primary); }

.bz-kanban-card--dragging { opacity: .45; }

/* Drop placeholder: the card the dragged one would land above. */
.bz-kanban-card--drop-before { box-shadow: 0 -3px 0 0 var(--bz-primary); }

.bz-kanban-card-top {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    justify-content: space-between;
}

.bz-kanban-card-no {
    font-size: var(--bz-fs-xs);
    color: var(--bz-color-fg-muted);
}

.bz-kanban-card-title { line-height: 1.35; }

.bz-kanban-card-foot {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    flex-wrap: wrap;
}

/* ── Comment @mentions (task comments) ──────────────────────────────────────── */
.bz-mention {
    background: color-mix(in srgb, var(--bz-primary) 16%, transparent);
    color: var(--bz-primary);
    border-radius: var(--bz-radius-sm);
    padding: 0 2px;
    font-weight: var(--bz-fw-medium);
}

/* Autocomplete list under the comment box. Not a popup: it sits in flow so it never
   needs positioning JS and can never be clipped by the tab panel's overflow. */
.bz-mention-list {
    display: flex;
    flex-direction: column;
    margin-top: var(--bz-space-1);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    background: var(--bz-color-surface);
    max-height: 14rem;
    overflow-y: auto;
}

.bz-mention-item {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    padding: var(--bz-space-2) var(--bz-space-3);
    background: none;
    border: 0;
    text-align: left;
    cursor: pointer;
    color: inherit;
}

.bz-mention-item:hover { background: var(--bz-color-surface-2); }

/* ── Aufgabenplan workspace (task plan pin viewer) ──────────────────────────── */
/* Split layout: pin list on the left, pdf.js page + marker overlay on the right.
   CSS grid rather than the shell's row/col helpers, which this app does not ship. */
.bz-plan-layout {
    display: grid;
    grid-template-columns: minmax(18rem, 22rem) minmax(0, 1fr);
    gap: var(--bz-space-4);
    align-items: start;
}

@media (max-width: 1100px) {
    .bz-plan-layout { grid-template-columns: minmax(0, 1fr); }
}

.bz-plan-side {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    max-height: 78vh;
    overflow-y: auto;
}

/* Scroll box around the page canvas — a zoomed-in plan is meant to pan, not to stretch the page.
   Deliberately NOT a flex container: the viewer measures its own element's clientWidth to compute the
   fit-width scale, and a flex item shrinks to its content (i.e. to zero before the first render). */
.bz-plan-stage {
    overflow: auto;
    max-height: 78vh;
    background: var(--bz-color-surface-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    padding: var(--bz-space-3);
}

/* Centred while it fits, overflowing (and scrollable) once zoomed past the stage. */
.bz-plan-canvas {
    position: relative;
    display: block;
    margin: 0 auto;
    line-height: 0;
    box-shadow: 0 1px 6px rgb(0 0 0 / 18%);
    cursor: crosshair;
    touch-action: none; /* pointer events own the drag; the browser must not pan instead */
}

.bz-plan-canvas.is-dragging { cursor: grabbing; }

.bz-plan-page { display: block; }

/* The overlay never takes pointer events — the wrapper does all hit-testing. */
.bz-plan-markers {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.bz-plan-pin {
    display: flex;
    align-items: flex-start;
    gap: var(--bz-space-2);
    width: 100%;
    padding: var(--bz-space-2);
    border: 1px solid var(--bz-color-border);
    border-radius: var(--bz-radius-md);
    background: var(--bz-color-surface);
    text-align: left;
    cursor: pointer;
    color: inherit;
}

.bz-plan-pin:hover { background: var(--bz-color-surface-2); }

.bz-plan-pin.is-active {
    border-color: var(--bz-primary);
    box-shadow: 0 0 0 1px var(--bz-primary);
}

.bz-plan-pin-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.65rem;
    height: 1.65rem;
    border-radius: 999px;
    font-size: var(--bz-fs-sm);
    font-weight: var(--bz-fw-semibold);
}

.bz-plan-pin-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.bz-plan-pin-title {
    line-height: 1.3;
    overflow-wrap: anywhere;
}

/* ── Calendar availability strip (Phase 2) ─────────────────────────────────
   One track per attendee across a fixed 07:00–20:00 working window; blocks are
   positioned as percentages by the component, so the track needs no grid. */
.bz-availability { margin-top: var(--bz-space-3); }

.bz-availability-row {
    display: flex;
    align-items: center;
    gap: var(--bz-space-2);
    margin-bottom: var(--bz-space-1);
}

.bz-availability-name {
    flex: 0 0 10rem;
    font-size: var(--bz-fs-sm);
    color: var(--bz-color-fg-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bz-availability-track {
    position: relative;
    display: block;
    flex: 1 1 auto;
    height: 1.25rem;
    border-radius: var(--bz-radius-sm);
    background: var(--bz-color-surface-2);
}

.bz-availability-block {
    position: absolute;
    top: 0;
    bottom: 0;
    border-radius: var(--bz-radius-sm);
}

.bz-availability-busy { background: var(--bz-color-accent); }
.bz-availability-tentative { background: var(--bz-color-warn); opacity: .6; }
.bz-availability-oof { background: var(--bz-color-danger); }

/* Ranked "Suggest times" results, rendered under the availability strip. */
.bz-availability-suggestions {
    display: flex;
    flex-direction: column;
    gap: var(--bz-space-2);
    margin-top: var(--bz-space-3);
    padding-top: var(--bz-space-3);
    border-top: 1px solid var(--bz-color-border);
}

/* ── Resource booking blocks (Calendar Phase 4) ──────────────────────────────
   A PENDING booking is not holding the slot yet: it renders hollow (dashed
   outline, transparent fill) so the grid never claims a resource is taken when
   any other request can still win it. An approved/no-approval booking is a
   solid block, i.e. the scheduler's own default. */
.bz-res-block {
    display: block;
    width: 100%;
    height: 100%;
    padding: 0 var(--bz-space-1);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bz-res-block-pending {
    background: repeating-linear-gradient(
        45deg,
        transparent,
        transparent 4px,
        var(--bz-color-surface-2) 4px,
        var(--bz-color-surface-2) 8px);
    border: 1px dashed var(--bz-color-warn);
    border-radius: var(--bz-radius-sm);
    color: var(--bz-color-fg-muted);
    font-style: italic;
}
