:root {
    /* Neutral dark palette — matches the production Material Dark theme. */
    --rz-base-900: #121212;
    --rz-base-800: #1e1e1e;
    --rz-base-700: #252525;
    --rz-base-600: #2e2e2e;

    --icon-xs: 0.75rem;
    --icon-sm: 0.8125rem;
    --icon-md: 0.875rem;
    --icon-lg: 1rem;
    --icon-xl: 1.125rem;
    --icon-2xl: 1.25rem;

    /* Wizard code-block design tokens (consumed by wizard-code-block, wizard-token-code, wizard-pre, wizard-code-header,
       and the unified console-style classes .task-output / .pipeline-step-output / .server-detail-code). */
    --wizard-code-bg: var(--rz-base-800, #1e1e1e);
    --wizard-code-header-bg: var(--rz-base-700, #2c2c40);
    --wizard-code-border: var(--rz-base-700, #2e2e2e);
    --wizard-code-text: var(--rz-text-color, #c8c8c8);
    --wizard-code-text-muted: var(--rz-text-secondary-color, #9a9aaa);
    --wizard-code-radius: 0.375rem;
    /* State variants — applied via .is-success / .is-error modifiers (e.g. agent connected). */
    --wizard-code-bg-success: color-mix(in srgb, var(--rz-success, #28a745) 12%, var(--wizard-code-bg));
    --wizard-code-border-success: color-mix(in srgb, var(--rz-success, #28a745) 60%, var(--wizard-code-border));
    --wizard-code-bg-error: color-mix(in srgb, var(--rz-danger, #dc3545) 12%, var(--wizard-code-bg));
    --wizard-code-border-error: color-mix(in srgb, var(--rz-danger, #dc3545) 60%, var(--wizard-code-border));
}

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

h1:focus {
    outline: none;
}

a, .btn-link {
    color: var(--rz-primary);
}

.btn-primary {
    color: var(--rz-on-primary);
    background-color: var(--rz-primary);
    border-color: var(--rz-primary-dark);
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--rz-primary-light);
}

.content {
    padding-top: 1.1rem;
}

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

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

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

.app-splash {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.5rem;
    /* Theme-aware opaque backdrop so the chrome rendering behind is hidden until the fade-out. */
    background: var(--rz-body-background-color, #121212);
    transition: opacity 0.35s ease-out;
}

/* Applied by Aetheus.hideSplash once the app is ready; fades the single boot-splash node
   out (revealing the already-painted chrome) before it removes itself from the DOM. */
.app-splash--hidden {
    opacity: 0;
    pointer-events: none;
}

.app-splash-logo {
    width: 6rem;
    height: 6rem;
    /* The boot loader is the self-animated aetheus-icon-loading.svg (paper plane banking with
       flowing jet trails); the external CSS only handles the soft entrance + a bluish drop-shadow. */
    animation: splash-fade-in 0.4s ease-out;
    filter: drop-shadow(0 0.4rem 0.6rem rgba(59, 130, 246, 0.35));
}

@keyframes splash-fade-in { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }

.dev-exception-pre {
    max-width: 60rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    text-align: left;
    font-size: 0.8rem;
}

code {
    color: var(--rz-text-color, #c8c8c8);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Metric card smooth transitions */
.metric-value {
    transition: opacity 0.3s ease;
}

.metric-bar .rz-progressbar-value {
    transition: width 0.6s ease-in-out;
}

/* Edit panel slide-in animation */
@keyframes slideDown {
    from {
        opacity: 0;
        transform: translateY(-0.5rem);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.edit-panel {
    animation: slideDown 0.25s ease-out;
    transition: box-shadow 0.2s ease;
}

.edit-panel:hover {
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.15);
}

/* Clickable tag badges */
.tag-clickable {
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.tag-clickable:hover {
    opacity: 0.8;
}

/* Phase 2 / E: consistent row hover highlight on EVERY data grid. Radzen paints the row striping
   on the <td> CELLS (opaque) — NOT on the transparent <tr> — so a highlight on the row element is
   completely hidden behind the cells. The highlight therefore targets the cells, and uses
   !important to beat Radzen's more-specific striping rule. `cursor: pointer` is added only on rows
   that actually navigate (the `.aetheus-clickable-rows` marker set by lists with a RowClick),
   so a non-interactive grid never implies a click. */
.rz-datatable .rz-data-row td {
    transition: background-color 0.12s ease;
}

.rz-datatable .rz-data-row:hover td {
    background-color: rgba(66, 165, 245, 0.2) !important;
}

.aetheus-clickable-rows .rz-data-row {
    cursor: pointer;
}

/* E-row: uniform, compact row height on EVERY grid. Cell content is clipped to a single line
   (ellipsis) so a tall value (e.g. a long log Message or description) never wraps and inflates the
   row — every row in a grid keeps the same height. The full value stays reachable via the cell's
   native title tooltip / a dedicated view/copy action where present. */
.rz-datatable .rz-data-row .rz-cell-data {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Compact in-row action buttons so an action column never inflates the row height (an
   unconstrained Small/ExtraSmall button is ~36px and pushed rows to 44-45px; capped here so every
   grid keeps ~32px rows). Height-only cap — text labels keep their natural width. */
.rz-datatable .rz-data-row .rz-button.rz-button-xs,
.rz-datatable .rz-data-row .rz-button.rz-button-sm {
    min-height: 1.5rem;
    height: 1.5rem;
    padding-top: 0;
    padding-bottom: 0;
}

/* E: full-height list — uniform sizing model for every list grid. The grid has NO minimum height:
   it sizes exactly to its content (its bottom sits at the last row), and only grows up to the
   remaining space, then stays there and scrolls its body internally (the pager stays pinned at the
   bottom). `min-height: 0` (not the flex default `auto`) is what lets it both collapse to content
   AND shrink to scroll. Two tiers:
   1. PRIMARY (E-flex, below): when the grid is a direct child of the body wrapper, the wrapper
      becomes a flex column that exactly fills the scroll viewport, and the grid sizes to the
      REAL remaining space — no magic number, adapts to any chrome height (filters, toolbars,
      breadcrumb) above it.
   2. FALLBACK (this rule): the `max-height` cap is used only when the grid is NOT a direct child
      of the body wrapper (e.g. nested inside RadzenTabs, where the flex chain is broken). The
      15rem cap clears the app bar, a typical page header/filter row and the wrapper padding.
   Opt-in via AetheusDataGrid FullHeight; server-side pagination remains the scale strategy. */
.aetheus-grid-fullheight {
    display: flex;
    flex-direction: column;
    min-height: 0;
    max-height: calc(100vh - 15rem);
}

.aetheus-grid-fullheight .rz-data-grid-data {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* E-flex (PRIMARY): when the page body DIRECTLY hosts a full-height grid, make the body wrapper a
   flex column that exactly fills the scroll viewport. The grid (flex: 0 1 auto) then sizes to its
   content — collapsing to its last row when near-empty (no minimum) — and shrinks to the real
   remaining space, scrolling its body internally, with NO magic-number cap. The `> ` combinator means
   tab-nested or otherwise wrapped grids (e.g. Pipelines) don't trigger this and keep the
   max-height fallback above, so there is no regression for those. */
.app-body-wrapper:has(> .aetheus-grid-fullheight) {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.app-body-wrapper:has(> .aetheus-grid-fullheight) > .aetheus-grid-fullheight {
    flex: 0 1 auto;
    max-height: none;
}

/* E-bis: keep inline action buttons (e.g. "Run again") from inflating a row — compact + centered so
   every row in a grid keeps the same height regardless of whether it carries action buttons. */
.rz-datatable .rz-data-row .rz-button.rz-button-sm,
.rz-datatable .rz-data-row .rz-button.rz-button-xs {
    vertical-align: middle;
}

/* C / F-06: shared PageHeader. The spacer pushes actions to the right; the header keeps a small
   bottom margin so the page body never butts against the title row. */
.page-header {
    margin-bottom: 1rem;
}

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

.page-header-icon {
    font-size: var(--icon-lg, 1.5rem);
}

/* C / F-07: cap form/dialog width for readability (long single-column forms become unwieldy past
   ~45rem). Applied to edit/create form wrappers; two-column RadzenRow forms opt out by not using it. */
.form-narrow {
    max-width: 45rem;
}

/* F-07: mark required fields with a subtle asterisk on the RadzenFormField label. */
.rz-form-field.field-required .rz-form-field-content > label::after,
.field-required > .rz-form-field-label::after {
    content: " *";
    color: var(--rz-danger, #dc3545);
}

/* H: semantic threshold tint on the resource metric bars (CPU/RAM/disk). The fill turns amber as
   usage gets tight (>75%) and red near saturation (>90%); the ok state keeps the theme default. */
.metric-bar-warn .rz-progressbar-value {
    background-color: var(--rz-warning, #f59e0b);
}

.metric-bar-danger .rz-progressbar-value {
    background-color: var(--rz-danger, #dc3545);
}

/* F: project overview section tiles — admin-hub-style left accent that warms on hover. */
.project-section-tile {
    border-left: 0.1875rem solid var(--rz-primary, #3b82f6);
    transition: border-color 0.15s ease;
}

.tile-link:hover .project-section-tile {
    border-left-color: var(--rz-primary-light, #60a5fa);
}

/* H: recent-tasks mini-list row on the server overview. */
.task-row {
    padding: 0.25rem 0;
    border-bottom: 0.0625rem solid var(--rz-base-300, rgba(128, 128, 128, 0.15));
}

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

/* Dashboard clickable rows */
.dashboard-clickable-grid .rz-data-row {
    cursor: pointer;
}

.dashboard-clickable-grid .rz-data-row:hover {
    background-color: var(--rz-data-grid-row-hover-background-color, rgba(255, 255, 255, 0.05));
}

/* GENERIC TABLE-HEADER RULE - every data-grid column title stays on a SINGLE line, shown in full
   when the column is wide enough and ellipsis-truncated only when it genuinely doesn't fit (never
   wraps to a second line like "Pipelin/es"). Applies to every RadzenDataGrid site-wide. */
.rz-column-title,
.rz-column-title-content {
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Docker container row backgrounds */
.docker-row-running {
    background-color: rgba(40, 167, 69, 0.08) !important;
}

.docker-row-exited {
    background-color: rgba(220, 53, 69, 0.08) !important;
}

.docker-row-paused {
    background-color: rgba(255, 193, 7, 0.08) !important;
}

.docker-row-other {
    background-color: rgba(108, 117, 125, 0.05) !important;
}

/* Service log line-count selector */
.log-lines-select {
    width: 5.5rem;
}

/* Docker log viewer */
.docker-logs {
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    padding: 1rem;
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    max-height: 25rem;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-all;
    margin: 0;
}

/* Confirm dialog overlay */
.confirm-dialog-card {
    min-width: 20rem;
}

/* Docker project zoom dialog */
.docker-zoom-card {
    width: min(80rem, 95vw);
    max-height: 90vh;
    overflow: auto;
}

/* Docker relations interactive graph */
.docker-graph-svg {
    width: 100%;
    height: 36rem;
    border: 1px solid var(--rz-border-color, #e0e0e0);
    border-radius: 0.5rem;
    background: var(--rz-base-50, #fafafa);
    user-select: none;
    cursor: grab;
    display: block;
}

.docker-graph-svg:active {
    cursor: grabbing;
}

/* Docker search filter */
.docker-search {
    max-width: 14rem;
}

/* Docker memory progress bar */
.docker-mem-bar {
    height: 0.375rem;
}

.docker-mem-bar .rz-progressbar-value {
    transition: width 0.4s ease;
}

/* Docker memory progress bar colors */
.docker-mem-green .rz-progressbar-value {
    background-color: var(--rz-success, #28a745) !important;
}

.docker-mem-yellow .rz-progressbar-value {
    background-color: var(--rz-warning, #ffc107) !important;
}

.docker-mem-red .rz-progressbar-value {
    background-color: var(--rz-danger, #dc3545) !important;
}

/* Docker loading skeleton */
.docker-skeleton {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem 0;
}

.skeleton-row {
    height: 2.5rem;
    border-radius: 0.375rem;
    background: linear-gradient(90deg,
        var(--rz-base-800, #2a2a3e) 25%,
        var(--rz-base-700, #2e2e2e) 50%,
        var(--rz-base-800, #2a2a3e) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Prune button spin animation */
.prune-spinning .rz-button-icon {
    animation: spin 1s linear infinite;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* Compose editor textarea */
.docker-compose-editor {
    width: 100%;
    min-height: 20rem;
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 1rem;
    resize: vertical;
}

/* Shell terminal */
.docker-shell-output {
    min-height: 10rem;
    max-height: 20rem;
}

.docker-shell-input {
    flex: 1;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
}

/* Blinking cursor for shell input */
.docker-shell-input::placeholder {
    animation: blink-cursor 1s step-end infinite;
}

@keyframes blink-cursor {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

/* Fade-in for inspect/shell/env/browse panels */
@keyframes fadeInPanel {
    from {
        opacity: 0;
        transform: translateY(0.5rem);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.docker-panel-fadein {
    animation: fadeInPanel 0.3s ease-out;
}

/* YAML syntax highlighting (minimal CSS-based) */
.yaml-editor {
    width: 100%;
    min-height: 20rem;
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 1rem;
    resize: vertical;
    tab-size: 2;
}

/* Env vars table */
.docker-env-table {
    width: 100%;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
}

.docker-env-table th {
    text-align: left;
    padding: 0.375rem 0.75rem;
    border-bottom: 1px solid var(--rz-base-700, #2e2e2e);
    color: var(--rz-text-secondary-color, #999);
}

.docker-env-table td {
    padding: 0.375rem 0.75rem;
    border-bottom: 1px solid var(--rz-base-800, #2a2a3e);
    word-break: break-all;
}

/* File browser */
.docker-file-entry {
    cursor: pointer;
    padding: 0.25rem 0.5rem;
    border-bottom: 1px solid var(--rz-base-800, #2a2a3e);
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
}

.docker-file-entry:hover {
    background: var(--rz-base-800, #2a2a3e);
}

/* Dockerfile editor */
.docker-build-editor {
    width: 100%;
    min-height: 15rem;
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 1rem;
    resize: vertical;
}

/* Prune summary text */
.prune-summary {
    font-size: 0.75rem;
    color: var(--rz-text-secondary-color, #999);
}

/* Server configuration YAML */
.config-yaml-block {
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 1rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 30rem;
}

.config-yaml-editor {
    width: 100%;
    min-height: 15rem;
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #c8c8c8);
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 1rem;
    resize: vertical;
}

/* ==========================================================================
   Blade Layout — Azure-inspired sidebar navigation
   ========================================================================== */

.blade-layout {
    display: flex;
    gap: 0;
    min-height: calc(100vh - 14rem);
}

.blade-sidebar {
    width: 13rem;
    min-width: 13rem;
    border-right: 1px solid var(--rz-base-700, #2e2e2e);
    padding: 0.5rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.blade-sidebar-item {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.625rem 1rem;
    cursor: pointer;
    font-size: 0.875rem;
    color: var(--rz-text-color, #c8c8c8);
    border-left: 3px solid transparent;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    user-select: none;
}

.blade-sidebar-item:hover {
    background-color: var(--rz-base-800, #2a2a3e);
}

.blade-sidebar-item.active {
    background-color: var(--rz-base-800, #2a2a3e);
    border-left-color: var(--rz-primary, #1b6ec2);
    color: var(--rz-primary, #1b6ec2);
    font-weight: 600;
}

.blade-sidebar-item .rzi {
    font-size: var(--icon-xl);
}

.blade-content {
    flex: 1;
    padding: 0.25rem 0;
    overflow-x: auto;
    min-width: 0;
}

.blade-content-spacer {
    flex: 1;
}

/* Responsive: collapse sidebar on small screens */
@media (max-width: 768px) {
    .blade-layout {
        flex-direction: column;
    }

    .blade-sidebar {
        width: 100%;
        min-width: 100%;
        flex-direction: row;
        overflow-x: auto;
        border-right: none;
        border-bottom: 1px solid var(--rz-base-700, #2e2e2e);
        padding: 0;
    }

    .blade-sidebar-item {
        border-left: none;
        border-bottom: 3px solid transparent;
        padding: 0.5rem 0.75rem;
        white-space: nowrap;
        font-size: 0.8125rem;
    }

    .blade-sidebar-item.active {
        border-bottom-color: var(--rz-primary, #1b6ec2);
        border-left-color: transparent;
    }

    .blade-content {
        padding: 0.25rem 0;
    }
}

/* ==========================================================================
   Server List — Toolbar and Grid
   ========================================================================== */

.server-list-toolbar {
    margin-bottom: 1rem;
}

.server-list-spacer {
    flex: 1;
}

.server-list-search {
    min-width: 15rem;
}

.server-list-grid {
    margin-top: 0.5rem;
}

.server-status-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    flex-shrink: 0;
}

.server-status-online {
    background-color: var(--rz-success, #28a745);
}

.server-status-offline {
    background-color: var(--rz-danger, #dc3545);
}

.server-name-link {
    color: var(--rz-primary, #1b6ec2);
    text-decoration: none;
    font-weight: 500;
}

.server-name-link:hover {
    text-decoration: underline;
}

/* ==========================================================================
   Project Cards
   ========================================================================== */

.project-list-toolbar {
    margin-bottom: 1rem;
}

.project-list-spacer {
    flex: 1;
}

.project-list-search {
    min-width: 15rem;
}

.project-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    gap: 1rem;
}

.project-card {
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
    border: 1px solid var(--rz-base-700, #2e2e2e);
    height: 100%;
}

.project-card:hover {
    border-color: var(--rz-primary, #1b6ec2);
    box-shadow: 0 0.125rem 0.5rem rgba(27, 110, 194, 0.15);
}

.project-card-icon {
    font-size: var(--icon-2xl);
    color: var(--rz-primary, #1b6ec2);
}

.project-card-name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-card-desc {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.project-card-link {
    text-decoration: none;
    color: inherit;
    display: block;
    height: 100%;
}

/* Meta footer: a divider-separated row of chips that WRAPS to a second line instead of
   shrinking each item (which made captions break mid-word over their icon). */
.project-card-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 1rem;
    margin-top: 0.25rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--rz-base-700, #2e2e2e);
}

.project-card-meta {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex-shrink: 0;
    white-space: nowrap;
    font-size: 0.75rem;
    line-height: 1.4;
}

.project-card-meta-icon {
    font-size: var(--icon-md);
}

/* B3KP: chips inside the project card that have their own action (repository link / git history).
   They intercept the click so the surrounding card link doesn't also fire. */
.project-card-meta-clickable {
    cursor: pointer;
    border-radius: 0.25rem;
    transition: color 0.15s ease;
}

.project-card-meta-clickable:hover {
    color: var(--rz-primary);
}

/* Project overview: the two info/repository cards stretch to equal height so the row stays tidy
   regardless of which card holds more fields; long repo URLs wrap instead of overflowing. */
.overview-info-card {
    height: 100%;
}

.overview-break-anywhere {
    overflow-wrap: anywhere;
}

@media (max-width: 768px) {
    .project-card-grid {
        grid-template-columns: 1fr;
    }
}

/* ==========================================================================
   Pipeline List
   ========================================================================== */

.pipeline-list-toolbar {
    margin-bottom: 1rem;
}

.pipeline-list-spacer {
    flex: 1;
}

.pipeline-list-search {
    min-width: 15rem;
}

.pipeline-list-grid {
    margin-top: 0.5rem;
}

.pipeline-name-link {
    color: var(--rz-primary, #1b6ec2);
    text-decoration: none;
    font-weight: 500;
}

.pipeline-name-link:hover {
    text-decoration: underline;
}

/* Cross-link (git source / linked releases) */
.cross-link-icon {
    font-size: 1rem;
}

.cross-link-sha {
    font-family: monospace;
}

.cross-link-release {
    cursor: pointer;
}

/* Cross-link tiles (run/release/artifact/commit/branch) */
.run-tile-icon {
    font-size: 0.875rem;
    vertical-align: middle;
}

.run-tile-link {
    text-decoration: none;
    color: inherit;
    display: block;
}

.run-tile-link .run-overview-card {
    cursor: pointer;
    transition: box-shadow 0.15s ease;
}

.run-tile-link:hover .run-overview-card {
    box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.18);
}

/* Grouped detail panels (artifact / release detail pages): two labelled columns of
   label -> value rows, replacing the flat undifferentiated cross-link tile wrap so the
   reader can scan "where it comes from" vs "where it goes" instead of one uniform grid. */
.detail-panel-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding-bottom: 0.5rem;
    margin-bottom: 0.25rem;
    border-bottom: 0.0625rem solid var(--rz-base-500, #333333);
}

.detail-row {
    padding: 0.45rem 0;
}

.detail-row + .detail-row {
    border-top: 0.0625rem solid var(--rz-base-600, #2e2e2e);
}

.detail-value-link {
    color: var(--rz-primary);
    text-decoration: none;
    font-weight: 500;
}

.detail-value-link:hover {
    text-decoration: underline;
}

.detail-filepath-box {
    background: var(--rz-base-900, #121212);
    border: 0.0625rem solid var(--rz-base-500, #333333);
    border-radius: 0.25rem;
    padding: 0.5rem 0.75rem;
}

/* Run history dots */
.pipeline-run-dot {
    display: inline-block;
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    transition: transform 0.1s;
}

.pipeline-run-dot:hover {
    transform: scale(1.3);
}

.pipeline-run-dot-success {
    background-color: var(--rz-success, #28a745);
}

.pipeline-run-dot-failed {
    background-color: var(--rz-danger, #dc3545);
}

.pipeline-run-dot-running {
    background-color: var(--rz-info, #17a2b8);
    animation: pulse-dot 1.5s infinite;
}

.pipeline-run-dot-pending {
    background-color: var(--rz-base-500, #6c757d);
}

.pipeline-run-dot-cancelled {
    background-color: var(--rz-warning, #ffc107);
}

@keyframes pulse-dot {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

/* ==========================================================================
   Pipeline Detail (tabs)
   ========================================================================== */

.pipeline-detail-toolbar {
    margin-bottom: 0.5rem;
}

.pipeline-detail-tabs {
    min-height: 20rem;
}

/* Pipeline edit tab: compact meta row (name + description inline) + inline toolbar, and the editor
   flexes to fill the remaining viewport height (full-height chain below, scoped to .pipeline-edit-form). */
.pipeline-edit-form { display: flex; flex-direction: column; gap: 0.5rem; min-height: 0; }
.pipeline-edit-meta { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-start; }
.pipeline-edit-meta .pipeline-edit-name { flex: 1 1 16rem; }
.pipeline-edit-meta .pipeline-edit-desc { flex: 2 1 22rem; }
.pipeline-edit-meta .rz-textbox { width: 100%; }
.pipeline-edit-toolbar { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }

.pipeline-yaml-editor {
    width: 100%;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.pipeline-yaml-editor .monaco-editor-container { flex: 1 1 auto; height: auto; min-height: 12rem; }

/* Edit tab body: editor on the left, an optional read-only pipeline-definition peek on the right. */
.pipeline-edit-body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    gap: 1rem;
}
.pipeline-edit-body > .pipeline-yaml-editor { flex: 1 1 0; min-width: 0; width: auto; }
.pipeline-edit-body > .run-yaml-pane { flex: 1 1 0; min-width: 0; }

.monaco-editor-container {
    width: 100%;
    height: calc(100vh - 20rem);
    min-height: 20rem;
    border: 0.0625rem solid var(--rz-border-color);
    border-radius: var(--rz-border-radius);
    overflow: hidden;
}

.monaco-editor .monaco-scrollable-element > .scrollbar > .slider {
    background: rgba(121, 121, 121, 0.4);
    border-radius: 0.3125rem;
}

.monaco-editor .monaco-scrollable-element > .scrollbar > .slider:hover {
    background: rgba(121, 121, 121, 0.7);
}

.monaco-status-bar {
    display: flex;
    justify-content: flex-end;
    padding: 0.25rem 0.75rem;
    font-size: 0.75rem;
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    color: var(--rz-text-secondary-color);
    background: var(--rz-base-800);
    border: 0.0625rem solid var(--rz-border-color);
    border-top: none;
    border-radius: 0 0 var(--rz-border-radius) var(--rz-border-radius);
}

/* ==========================================================================
   Pipeline Run Detail — Stage Flow
   ========================================================================== */

.pipeline-run-toolbar {
    margin-bottom: 1rem;
}

.stage-flow {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 1rem 0;
    overflow-x: auto;
}

.stage-box {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.75rem 1rem;
    border-radius: 0.375rem;
    border: 1px solid var(--rz-base-700, #2e2e2e);
    min-width: 8rem;
    background-color: var(--rz-base-900, #1e1e2e);
}

.stage-box-completed {
    border-color: var(--rz-success, #28a745);
}

.stage-box-running {
    border-color: var(--rz-info, #17a2b8);
    box-shadow: 0 0 0.5rem rgba(23, 162, 184, 0.2);
}

.stage-box-failed {
    border-color: var(--rz-danger, #dc3545);
}

.stage-box-header {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-weight: 600;
}

.stage-box-icon {
    font-size: var(--icon-md);
}

.stage-box-name {
    font-size: 0.875rem;
}

.stage-box-info {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--rz-text-secondary-color, #999);
}

.stage-flow-arrow {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/* Expandable stage/step list */
.pipeline-run-stages {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.pipeline-run-stage {
    border: 1px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem;
    overflow: hidden;
}

.pipeline-run-stage-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 0.75rem;
    cursor: pointer;
    background-color: var(--rz-base-800, #2a2a3e);
    transition: background-color 0.15s;
}

.pipeline-run-stage-header:hover {
    background-color: var(--rz-base-700, #2e2e2e);
}

.pipeline-run-stage-header.active {
    background-color: var(--rz-base-700, #2e2e2e);
}

.stage-status-icon {
    font-size: var(--icon-md);
}

.pipeline-run-steps {
    padding: 0.25rem 0;
}

.pipeline-run-step {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.75rem 0.375rem 2.5rem;
    border-top: 1px solid var(--rz-base-800, #2a2a3e);
}

.pipeline-run-step-name {
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
}

.pipeline-run-matrix-header {
    cursor: pointer;
    background: var(--rz-base-900, #1e1e2e);
}

.pipeline-run-matrix-header:hover {
    background: var(--rz-base-800, #2a2a3e);
}

.matrix-toggle-icon {
    font-size: var(--icon-sm);
    flex-shrink: 0;
}

.pipeline-run-matrix-leg {
    padding-left: 4rem;
}

.step-status-icon {
    font-size: var(--icon-sm);
    flex-shrink: 0;
}

@media (max-width: 768px) {
    .stage-flow {
        flex-direction: column;
        align-items: stretch;
    }

    .stage-flow-arrow {
        justify-content: center;
        transform: rotate(90deg);
    }

    .pipeline-run-step {
        padding-left: 1.5rem;
    }

    .pipeline-run-matrix-leg {
        padding-left: 2.5rem;
    }
}

/* Vertical pipeline run timeline — Azure DevOps-style stage/step visualization.
   Left rail with status dots + connectors, right side with collapsible content. */
.run-timeline { display: flex; flex-direction: column; }
.run-timeline-stage { display: flex; gap: 0; min-height: 3rem; }

.run-timeline-rail {
    display: flex; flex-direction: column; align-items: center;
    width: 2rem; flex-shrink: 0; padding-top: 0.875rem;
}

.run-timeline-dot {
    position: relative; width: 0.875rem; height: 0.875rem;
    border-radius: 50%; flex-shrink: 0; z-index: 1;
}
.run-timeline-dot-success  { background: var(--rz-success); }
.run-timeline-dot-failed   { background: var(--rz-danger); }
.run-timeline-dot-running  { background: var(--rz-info); }
.run-timeline-dot-pending  { background: var(--rz-base-500); }

.run-timeline-pulse {
    position: absolute; inset: -4px; border-radius: 50%;
    border: 2px solid var(--rz-info); opacity: 0;
    animation: timeline-pulse 1.5s ease-out infinite;
}
@keyframes timeline-pulse {
    0%   { transform: scale(0.8); opacity: 0.8; }
    100% { transform: scale(1.6); opacity: 0; }
}

.run-timeline-connector {
    flex: 1; width: 2px; min-height: 0.5rem;
}
.run-timeline-connector-success  { background: var(--rz-success); }
.run-timeline-connector-failed   { background: var(--rz-danger); }
.run-timeline-connector-running  { background: var(--rz-info); }
.run-timeline-connector-pending  { background: var(--rz-base-500); }
/* S-DES-19: gradient connector at a success→failure boundary */
.run-timeline-connector-success-failed { background: linear-gradient(to bottom, var(--rz-success), var(--rz-danger)); }

.run-timeline-body { flex: 1; min-width: 0; padding-bottom: 0.25rem; }

.run-timeline-stage-header {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.5rem 0.75rem; cursor: pointer;
    border-radius: 0.375rem; transition: background-color 0.15s;
}
.run-timeline-stage-header:hover { background: var(--rz-base-800, #2a2a3e); }
.run-timeline-stage-header.active { background: var(--rz-base-800, #2a2a3e); }
.run-timeline-toggle { font-size: var(--icon-md); color: var(--rz-text-secondary-color); }

.run-timeline-steps {
    margin-left: 0.75rem; padding: 0.25rem 0;
    border-left: 1px solid var(--rz-base-700, #2e2e2e);
}

.run-timeline-step {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.375rem 0.75rem;
}
.run-timeline-step-name {
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
}
.run-timeline-step-icon {
    font-family: 'Material Symbols Outlined', 'Material Icons';
    font-size: 1.125rem; font-weight: normal; font-style: normal;
    line-height: 1; flex-shrink: 0;
}
.run-timeline-step-success { color: var(--rz-success); }
.run-timeline-step-running { color: var(--rz-info); }
.run-timeline-step-failed  { color: var(--rz-danger); }
.run-timeline-step-pending { color: var(--rz-text-secondary-color); }

.run-timeline-matrix-header { cursor: pointer; }
.run-timeline-matrix-header:hover { background: var(--rz-base-900, #121212); }
.run-timeline-matrix-leg { padding-left: 2rem; }

.run-timeline-step.active { background: var(--rz-base-700, #252525); border-radius: 0.25rem; }
.run-timeline-step:hover { background: var(--rz-base-800, #1e1e1e); border-radius: 0.25rem; }

.run-timeline-duration { white-space: nowrap; }

/* Pipeline step log panel — terminal style */
.step-log-panel {
    background: var(--rz-base-900, #121212);
    color: var(--rz-text-color, #e0e0e0);
    font-family: 'Cascadia Mono', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    padding: 0.75rem 1rem;
    margin: 0.25rem 0 0.5rem 1.75rem;
    border-radius: 0.375rem;
    border: 1px solid var(--rz-base-700, #252525);
    max-height: 25rem;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-all;
}
.step-log-line {
    padding: 0.0625rem 0;
}
.step-log-line:hover {
    background: var(--rz-base-800, #1e1e1e);
}
.step-log-error {
    /* S-DES-12: brighter red + faint row tint for stronger contrast on the dark terminal. */
    color: #ff8a80;
    background-color: rgba(239, 83, 80, 0.1);
}
.step-log-warning {
    color: var(--rz-warning, #ffa726);
}
.step-log-empty {
    color: var(--rz-text-secondary-color, #a0a0a0);
    font-style: italic;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 1rem 0;
}

@media (max-width: 768px) {
    .run-timeline-rail { width: 1.5rem; }
    .run-timeline-steps { margin-left: 0.25rem; }
    .run-split-layout { grid-template-columns: 1fr !important; }
    /* Single column on mobile: no full-height fill (the :has() chain is desktop-only), so the two
       stacked panels size to content. Cap the log panel at 70vh so its terminal still scrolls
       internally instead of running the whole page down. */
    .run-split-logs { min-height: 20rem; max-height: 70vh; }
}

/* --- Split view: timeline left + logs right --- */
.run-split-layout {
    display: grid;
    grid-template-columns: 22rem 1fr;
    gap: 1rem;
    min-height: 28rem;
}

.run-split-timeline {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding-right: 0.5rem;
}

/* Orchestration runs keep the side-by-side split but widen the left column so the run tree's
   stage label + child-pipeline chip + description fit on one line (logs stay on the right). */
.run-split-wide { grid-template-columns: 34rem 1fr; }

/* Stage wrapper — rail spans full height of header + sub-steps */
.run-tl-stage {
    display: flex;
}
.run-tl-content {
    flex: 1;
    min-width: 0;
}
.run-tl-grouped { padding-left: 1rem; }

/* Group header in logs timeline */
.run-tl-group-header {
    display: flex; align-items: center; gap: 0.375rem;
    padding: 0.375rem 0.25rem 0.125rem;
    font-weight: 600; font-size: 0.75rem;
    color: var(--rz-primary, #7c4dff);
    border-bottom: 1px solid var(--rz-base-700);
    margin-top: 0.375rem;
}
.run-tl-group-header:first-child { margin-top: 0; }

/* Unified timeline row — one line per step/stage */
.run-tl-row {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.25rem;
    border-radius: 0.25rem;
    cursor: pointer;
    font-size: 0.8125rem;
    transition: background 0.15s;
    position: relative;
}
.run-tl-row:hover { background: var(--rz-base-700, #252525); }
.run-tl-row.selected { background: var(--rz-base-600, #333); border-left: 0.1875rem solid var(--rz-primary, #7c4dff); }
.run-tl-stage-header { cursor: default; }
.run-tl-sub { padding-left: 0.5rem; }
.run-tl-rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 0.75rem;
    flex-shrink: 0;
}
.run-tl-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 0.375rem;
    position: relative;
}
.run-tl-line {
    display: none;
}
.run-status-badge {
    min-width: 4.5rem;
    text-align: center;
    flex-shrink: 0;
    font-size: 0.6875rem;
}
.run-tl-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}
.run-tl-bold { font-weight: 600; }
.run-tl-dur {
    color: var(--rz-text-secondary-color, #a0a0a0);
    font-size: 0.6875rem;
    flex-shrink: 0;
    white-space: nowrap;
}

/* Progress timeline: duration sits in a fixed left gutter (timers on the left), and the name no
   longer grows so the trailing badges sit right after the label instead of the far right. */
.run-progress-timeline .run-tl-dur { min-width: 2.75rem; text-align: right; }
.run-progress-timeline .run-tl-name { flex: initial; }

.run-split-logs {
    display: flex;
    flex-direction: column;
    background: var(--rz-base-900, #121212);
    border-radius: 0.5rem;
    border: 0.0625rem solid var(--rz-base-700, #252525);
    overflow: hidden;
    min-height: 20rem;
}

/* --- Full-height fill (desktop) ---------------------------------------------------------------
   The logs panel should fill the viewport so a short log doesn't leave an empty band below it and
   a long log scrolls inside the terminal (not the page). Rather than guess a `calc(100vh - Nrem)`
   reserve (fragile magic number), turn the shared layout shell into a real flex column *only on
   this page*, scoped with :has(.run-split-layout) so every other page is untouched. The chain is
   .rz-body -> .app-body-wrapper -> .rz-tabview -> .rz-tabview-panels -> .rz-tabview-panel -> split;
   each link flexes to fill and passes min-height:0 down so the terminal is the single scroll box.
   Mobile (<=768px, single column) keeps normal document flow — see the max-width media query. */
@media (min-width: 769px) {
    .rz-body:has(.run-split-layout, .run-yaml-split) { display: flex; flex-direction: column; }
    .app-body-wrapper:has(.run-split-layout, .run-yaml-split) {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
    .app-body-wrapper:has(.run-split-layout, .run-yaml-split) > .rz-tabview { flex: 1 1 auto; min-height: 0; }
    .rz-tabview-panels:has(.run-split-layout, .run-yaml-split) { flex: 1 1 auto; min-height: 0; overflow: hidden; }
    .rz-tabview-panel:has(.run-split-layout, .run-yaml-split) { height: 100%; }
    .run-split-layout:has(.run-split-logs) { height: 100%; min-height: 0; }
    .run-split-timeline { height: 100%; }
    .run-split-logs { height: 100%; }
    /* YAML definition tab fills the same shell; panes take full height, code scrolls internally. */
    .run-yaml-split { height: 100%; min-height: 0; }

    /* Pipeline edit tab: the Monaco editor fills the viewport below the compact meta + toolbar,
       with no page scrollbar (same flex-fill shell trick, scoped to the edit form). */
    .rz-body:has(.pipeline-edit-form) { display: flex; flex-direction: column; }
    .app-body-wrapper:has(.pipeline-edit-form) {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
    .app-body-wrapper:has(.pipeline-edit-form) > .rz-tabview { flex: 1 1 auto; min-height: 0; }
    .rz-tabview-panels:has(.pipeline-edit-form) { flex: 1 1 auto; min-height: 0; overflow: hidden; }
    .rz-tabview-panel:has(.pipeline-edit-form) { height: 100%; }
    .pipeline-edit-form { height: 100%; }
}

.run-logs-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    min-height: 20rem;
    opacity: 0.5;
}

.run-logs-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    border-bottom: 0.0625rem solid var(--rz-base-700, #252525);
    background: var(--rz-base-800, #1e1e1e);
    flex-shrink: 0;
}

.run-logs-search {
    max-width: 14rem;
}

/* S-FEAT-27: API reference page */
.api-ref-search { max-width: 18rem; }
.api-ref-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.4375rem 0.875rem; }
.api-ref-row + .api-ref-row { border-top: 0.0625rem solid var(--rz-base-700, #252525); }
.api-ref-method {
    flex: 0 0 4rem; text-align: center; font-size: 0.6875rem; font-weight: 700;
    padding: 0.125rem 0.375rem; border-radius: 0.25rem; text-transform: uppercase;
    color: #fff;
}
.api-ref-method-get { background: var(--rz-info, #29b6f6); }
.api-ref-method-post { background: var(--rz-success, #4caf50); }
.api-ref-method-put { background: var(--rz-warning, #ffa726); }
.api-ref-method-patch { background: var(--rz-warning, #ffa726); }
.api-ref-method-delete { background: var(--rz-danger, #f44336); }
.api-ref-path { font-family: 'Cascadia Code', 'Consolas', monospace; font-size: 0.8125rem; }
.api-ref-summary { font-size: 0.8125rem; margin-left: auto; text-align: right; }

/* S-UX-28: inline failed-step error card on the run Overview */
.run-failed-card { border-left: 3px solid var(--rz-danger, #f44336); }
.run-failed-step { padding: 0.375rem 0; }
.run-failed-step + .run-failed-step { border-top: 0.0625rem solid var(--rz-base-700, #252525); }

/* S-UX-18: executed command banner above the log terminal */
.run-cmd {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.5rem 1rem;
    background: var(--rz-base-900, #161616);
    border-bottom: 0.0625rem solid var(--rz-base-700, #252525);
    flex-shrink: 0;
}
.run-cmd-icon { color: var(--rz-success, #4caf50); font-size: 1rem; flex-shrink: 0; }
.run-cmd-text {
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
    color: var(--rz-text-color, #ddd);
    white-space: pre-wrap;
    word-break: break-all;
}

/* S-UX-32 / YAML definition tab: definition left (full-height), clickable `pipeline:` refs open a
   peek pane on the right (one at a time). Panes fill the viewport; only the code scrolls. */
.run-yaml-split {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    min-height: 28rem;
}
.run-yaml-split:has(.run-yaml-peek) { grid-template-columns: 1fr 1fr; }
.run-yaml-pane {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--rz-base-900, #161616);
    border: 0.0625rem solid var(--rz-base-700, #252525);
    border-radius: 0.5rem;
    overflow: hidden;
}
.run-yaml-pane .run-logs-header {
    padding: 0.5rem 0.75rem;
    border-bottom: 0.0625rem solid var(--rz-base-700, #252525);
    flex-shrink: 0;
}
.run-yaml-subtitle { font-size: 0.8125rem; }
.run-yaml-code {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 0.75rem 1rem;
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--rz-text-color, #e6edf3);
}
/* Real trailing spacer so the last line clears the horizontal scrollbar. A plain padding-bottom is
   ignored at scroll-end for a flex-item scroll container (Chrome), so use an ::after block instead. */
.run-yaml-code::after { content: ""; display: block; height: 1.5rem; }
.run-yaml-code .yaml-line { display: block; white-space: pre; min-height: 1.2em; }
/* Wrap toggle: soft-wrap long lines instead of scrolling horizontally. Independent per pane. */
.run-yaml-code.run-yaml-wrap .yaml-line { white-space: pre-wrap; overflow-wrap: anywhere; }
.run-yaml-empty { color: var(--rz-text-secondary-color, #a0a0a0); }
.yaml-pipeline-link {
    color: var(--rz-primary, #7c4dff);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 0.15em;
    border-radius: 0.1875rem;
}
.yaml-pipeline-link:hover { color: var(--rz-primary-light, #c9b8ff); background: var(--rz-primary-lighter, #241a4d); }

.run-logs-terminal {
    flex: 1;
    min-height: 0; /* let the flex child shrink below its content so it scrolls itself instead of overflowing the page */
    overflow-y: auto;
    padding: 0.75rem 1rem;
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
}

.run-logs-lines { display: flex; flex-direction: column; }
.run-log-line {
    display: flex;
    gap: 0.75rem;
    padding: 0.0625rem 0;
    white-space: pre-wrap;
    word-break: break-all;
}
.run-log-line:hover { background: var(--rz-base-800, #1e1e1e); }
/* S-DES-11: accent known variable names inside log lines */
.log-var { color: var(--rz-info, #29b6f6); font-weight: 600; }
.run-log-num {
    color: var(--rz-text-tertiary-color, #555);
    min-width: 2rem;
    text-align: right;
    flex-shrink: 0;
    user-select: none;
    font-size: 0.75rem;
}

/* System task styling — grey/muted to distinguish from user tasks */
.run-timeline-dot-system { background: var(--rz-base-500); border: 1px dashed var(--rz-base-400); }
.run-timeline-connector-system { background: var(--rz-base-500); }
.run-tl-system { color: var(--rz-text-tertiary-color, #888); font-style: italic; }
.run-tl-system-row { opacity: 0.75; }
.run-system-label { font-size: 0.625rem; }
.run-empty-icon { font-size: 3rem; opacity: 0.3; }
.step-log-empty-icon { font-size: 1.5rem; opacity: 0.5; }
.run-overview-stage { padding: 0.375rem 0.5rem; border-radius: 0.25rem; }
.run-overview-stage:hover { background: var(--rz-base-800, #1e1e1e); }
.run-overview-stage-system { border-left: 2px dashed var(--rz-base-500); }
/* Run overview tiles: a uniform responsive grid so every tile is the same width/height regardless
   of its content (badge, value, link), instead of flex items that stretched unevenly per row. */
.run-overview-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    grid-auto-rows: 1fr;
    gap: 0.75rem;
}
.run-overview-tiles > .run-tile-link { height: 100%; }
/* Keyboard focus ring for the tiles that act as buttons (jump-to-tab), matching the hover affordance. */
.run-tile-link[role="button"]:focus-visible { outline: 2px solid var(--rz-primary, #7c4dff); outline-offset: 2px; border-radius: 0.25rem; }
.run-overview-card {
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.run-overview-stage-grouped { margin-left: 1.5rem; }
.run-overview-stage-sub { padding-left: 1rem; opacity: 0.9; border-left: 1px solid var(--rz-base-600, #444); margin-left: 0.75rem; }
.run-group-header {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.5rem 0.25rem 0.25rem;
    font-weight: 600; font-size: 0.875rem;
    color: var(--rz-primary, #7c4dff);
    border-bottom: 1px solid var(--rz-base-700);
    margin-top: 0.5rem;
}
.run-group-header:first-child { margin-top: 0; }
/* S-DES-20: completed/total + progress bar inside a Build/Deploy group header */
.run-group-count { font-size: 0.75rem; font-weight: 400; color: var(--rz-text-secondary-color, #aaa); }
.run-group-progress { flex: 1; max-width: 12rem; height: 0.375rem; }

/* G (Phase 3): RadzenTimeline-based progress view rows */
.run-progress-timeline .rz-timeline-item-content { padding-bottom: 0.5rem; }
.run-tl-item-row {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
    padding: 0.25rem 0.5rem; border-radius: 0.25rem;
}
.run-tl-item-row.clickable-cell:hover { background: var(--rz-base-800, #1e1e1e); }
.run-tl-item-sub { margin-left: 0.75rem; }
.run-tl-item-grouped { margin-left: 0.75rem; }
.run-tl-item-group { padding-left: 0; }
.run-tl-item-stage { font-weight: 600; }
.run-icon-spin { animation: run-icon-spin 1.4s linear infinite; }
@keyframes run-icon-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* G: compact RadzenTimeline inside the Logs split (selectable step rail). LinePosition.Start gives
   the native left rail (point + connecting line stay aligned) and Radzen itself collapses the empty
   opposite side (.rz-timeline-start .rz-timeline-content-start { display:none }) and left-aligns the
   content — so no custom display:none / flex override is needed here (R2HD). */
.run-logs-timeline .rz-timeline-content-end { text-align: left; }
.run-logs-timeline .rz-timeline-item-content { padding-bottom: 0.25rem; }
.run-logs-timeline .run-tl-name-grow { flex: 1 1 auto; min-width: 0; white-space: normal; overflow: visible; text-overflow: clip; }
.run-logs-timeline .run-tl-row {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
    padding: 0.25rem 0.5rem; border-radius: 0.25rem; cursor: pointer;
}
.run-logs-timeline .run-tl-row.selected { background: var(--rz-primary-light, #2a2150); box-shadow: inset 0.1875rem 0 0 var(--rz-primary, #7c4dff); }
.run-logs-timeline .run-tl-row:hover { background: var(--rz-base-800, #1e1e1e); }
.run-logs-timeline .run-tl-stage-header { cursor: default; }
.run-logs-timeline .run-tl-sub { margin-left: 0.75rem; }
.run-logs-timeline .run-tl-grouped { margin-left: 0.75rem; }

/* A1-A4: recursive collapsible run tree (logs-tab left panel). The top-level tree is a bordered,
   rounded card with row separators (run-timeline mockup); nested child runs stay indented + railed. */
.run-tree { display: flex; flex-direction: column; gap: 0.125rem; }
.run-tree:not(.run-tree-nested) {
    gap: 0;
    border: 0.0625rem solid var(--rz-base-700, #30363d);
    border-radius: 0.75rem;
    overflow: hidden;
    background: var(--rz-base-800, #1a1a1a);
}
.run-tree:not(.run-tree-nested) > .run-tl-row {
    padding: 0.625rem 0.875rem;
    border-radius: 0;
    border-bottom: 0.0625rem solid var(--rz-base-700, #30363d);
}
.run-tree:not(.run-tree-nested) > .run-tl-row:last-child { border-bottom: none; }
/* Indent sub-tasks (steps within a multi-step stage) under their stage header. */
.run-tl-substep { padding-left: 2rem; }
.run-tree:not(.run-tree-nested) > .run-tl-substep { padding-left: 2.25rem; }
.run-tl-stage-header { padding-left: 0.5rem; }
.run-tree-nested {
    margin-left: 1.75rem;
    padding-left: 0.75rem;
    border-left: 0.125rem solid var(--rz-base-600, #333);
}
.run-tl-trigger { font-weight: 500; }
/* Stage label column (CI / QA / DEPLOY) + child-pipeline chip on a trigger row */
.run-tl-stage-label {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--rz-text-tertiary-color, #8b949e);
    width: 3.75rem;
    flex-shrink: 0;
}
.run-tl-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.75rem;
    padding: 0.125rem 0.5rem;
    border-radius: 0.5rem;
    background: var(--rz-primary-lighter, #241a4d);
    color: var(--rz-primary-light, #c9b8ff);
    white-space: nowrap;
    flex-shrink: 0;
    text-decoration: none;
    cursor: pointer;
}
/* The chip is a link to the triggered child run. */
.run-tl-chip:hover { background: var(--rz-primary, #7c4dff); color: #fff; }
.run-tl-chip .run-tl-chip-icon { font-size: 0.875rem; color: inherit; }
.run-tl-desc { color: var(--rz-text-secondary-color, #c0c6cd); font-weight: 400; }
.run-tl-caret {
    font-size: 1.125rem;
    flex-shrink: 0;
    color: var(--rz-text-secondary-color, #a0a0a0);
}
.run-tl-chip-icon {
    font-size: 1rem;
    flex-shrink: 0;
    color: var(--rz-primary, #7c4dff);
}
.run-tl-open-link {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    color: var(--rz-text-secondary-color, #a0a0a0);
}
.run-tl-open-link:hover { color: var(--rz-primary, #7c4dff); }
.run-tl-children { margin-top: 0.125rem; }
.run-tl-note {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    color: var(--rz-text-secondary-color, #a0a0a0);
}

/* S-UX-31: stage duration bars */
.run-os-icon { font-size: 1rem; flex-shrink: 0; }
.run-os-icon-linux { color: var(--rz-warning); }
.run-os-icon-windows { color: var(--rz-info); }

/* Q2BV: lock the connecting rail (thickness + neutral colour) to one value across the four
   RadzenTimeline instances — project activity, release changelog, pipeline run progress and run
   logs — so they read as one consistent visual language regardless of theme drift or local
   overrides. Status colour stays on the points/dots, never the rail. */
.project-activity-timeline,
.run-progress-timeline,
.run-logs-timeline {
    --rz-timeline-line-width: 0.125rem;
    --rz-timeline-line-color: var(--rz-base-600);
}

/* Q2BV: the release changelog now renders through RadzenTimeline (ProjectOverviewSection,
   reusing the .project-activity-timeline class), so it inherits the shared rail-lock above
   alongside project activity, run progress and run logs — all four read identically. The old
   custom .release-cl-* markup CSS was removed as dead leftover of the pre-Radzen changelog. */

/* Clickable grid cell — replaces inline style="cursor:pointer" */
.clickable-cell { cursor: pointer; }
.clickable-cell:hover { text-decoration: underline; }

/* Layout utilities */
.flex-spacer {
    flex: 1;
}

.sidebar-width {
    width: 250px;
}

/* Auth / Login */
.login-container {
    max-width: 400px;
    margin: 5rem auto;
}

/* S-DES-07: login page logo */
.login-logo {
    text-align: center;
    margin-bottom: 1.5rem;
}
.login-logo-img {
    width: 4.5rem;
    height: 4.5rem;
    border-radius: 1rem;
    opacity: 0.9;
}

.btn-full-width {
    width: 100%;
}

/* D6KR: login backend-status indicator (clickable to re-check). */
.login-backend-status {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    cursor: pointer;
    font-size: 0.8rem;
}
.login-backend-icon {
    font-size: var(--icon-md);
}
.login-backend-online {
    color: var(--rz-success);
}
.login-backend-offline {
    color: var(--rz-danger);
}

/* Dashboard status colors */
.text-success {
    color: var(--rz-success);
}

.text-danger {
    color: var(--rz-danger);
}

/* ==========================================================================
   Flex Spacer
   ========================================================================== */

.flex-spacer {
    flex: 1;
}

/* ==========================================================================
   Log Viewers (Tasks + Logs pages)
   ========================================================================== */

.task-log-viewer {
    max-height: 25rem;
    overflow-y: auto;
    background: var(--rz-base-900, #121212);
    padding: 1rem;
    border-radius: 0.25rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.85rem;
}

.live-log-panel {
    height: calc(100vh - 14rem);
    overflow-y: auto;
    /* F20+: keep terminal aesthetic in dark mode; switch to light surface in light mode for parity. */
    background: var(--rz-content-background-color, #121212);
    color: var(--rz-text-color, #e0e0e0);
    padding: 1rem;
    border: 1px solid var(--rz-border-color, transparent);
    border-radius: 0.25rem;
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.85rem;
    /* Smooth auto-scroll on batched LogsReceived appends. */
    scroll-behavior: smooth;
}

.log-entry {
    color: var(--rz-text-color, #e0e0e0);
    line-height: 1.4;
}

.log-timestamp {
    color: var(--rz-text-secondary-color, #888);
}

.log-task-id {
    color: var(--rz-info, #4fc3f7);
}

.log-level-error {
    color: var(--rz-danger, #d83b3b);
}

.log-level-warning {
    color: var(--rz-warning-darker, #b6892b);
}

.log-level-debug {
    color: var(--rz-text-tertiary-color, #888);
}

.masked-value {
    background: color-mix(in srgb, var(--rz-danger) 15%, transparent);
    color: var(--rz-danger);
    padding: 0 0.125rem;
    border-radius: 0.125rem;
    font-weight: 600;
}

/* ==========================================================================
   Token Display (#33 — neutral code color)
   ========================================================================== */

.token-code {
    color: var(--rz-text-color, #c8c8c8);
    font-family: 'Cascadia Code', 'Fira Code', monospace;
    font-size: 0.85rem;
}

/* ==========================================================================
   Visual Pipeline Editor
   ========================================================================== */

.vp-canvas-outer {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: calc(100vh - 24rem);
    min-height: 20rem;
    border: 0.0625rem solid var(--rz-border-color);
    border-radius: var(--rz-border-radius);
    background-color: var(--rz-base-900, #1e1e2e);
    background-image:
        radial-gradient(circle, var(--rz-base-700, #2e2e2e) 0.0625rem, transparent 0.0625rem);
    background-size: 1.25rem 1.25rem;
}

.vp-canvas-inner {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transform-origin: 0 0;
}

.vp-node {
    position: absolute;
    width: 13.75rem;
    border-radius: 0.5rem;
    border: 0.125rem solid var(--rz-base-600, #4a4a5e);
    background-color: var(--rz-base-800, #2a2a3e);
    box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.3);
    transition: border-color 0.15s, box-shadow 0.15s;
    z-index: 1;
}

.vp-node:hover {
    border-color: var(--rz-base-500, #5a5a6e);
}

.vp-node.vp-node-selected {
    border-color: var(--rz-primary, #1e88e5);
    box-shadow: 0 0 0.75rem rgba(30, 136, 229, 0.3);
}

.vp-node-header {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 0.0625rem solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.375rem 0.375rem 0 0;
    background-color: var(--rz-base-700, #2e2e2e);
    font-weight: 600;
    font-size: 0.8125rem;
    user-select: none;
}

.vp-node-header-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vp-node-agent {
    padding: 0.25rem 0.75rem;
    font-size: 0.75rem;
    color: var(--rz-text-secondary-color, #a0a0b0);
    border-bottom: 0.0625rem solid var(--rz-base-700, #2e2e2e);
}

.vp-node-steps {
    padding: 0.25rem 0;
    max-height: 10rem;
    overflow-y: auto;
}

.vp-node-step {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem 0.75rem;
    font-size: 0.75rem;
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
}

.vp-node-step-number {
    color: var(--rz-text-secondary-color, #a0a0b0);
    min-width: 1rem;
    text-align: right;
}

.vp-node-step-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vp-node-step-edit {
    opacity: 0;
    transition: opacity 0.15s;
    cursor: pointer;
    color: var(--rz-text-secondary-color, #a0a0b0);
    font-size: var(--icon-md);
}

.vp-node-step:hover .vp-node-step-edit {
    opacity: 1;
}

.vp-node-footer {
    padding: 0.375rem 0.75rem;
    border-top: 0.0625rem solid var(--rz-base-700, #2e2e2e);
}

.vp-node-action-btn {
    cursor: pointer;
    opacity: 0.6;
    display: flex;
}

.vp-node-action-btn:hover {
    opacity: 1;
}

.inline-text {
    display: inline;
}

.vp-edge-layer {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 0;
}

/* ─── Tabs: remove horizontal padding on panels ─── */
.rz-tabview .rz-tabview-panel {
    padding-left: 0;
    padding-right: 0;
}

/* ─── Wizard ─── */
.wizard-dialog {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    outline: none;
}

.wizard-progress-bar {
    height: 0.25rem;
    background: var(--rz-base-700, #333);
}
.wizard-progress-value {
    height: 100%;
    background: var(--rz-primary, #7c4dff);
    transition: width 0.4s ease;
}

.wizard-dialog .rz-steps {
    flex: 1;
    overflow: visible;
}

.wizard-dialog .rz-steps > ul {
    flex-wrap: nowrap;
    max-width: calc(100% - 21rem);
}

.wizard-dialog .rz-steps-bar .rz-steps-item {
    font-size: 0.8rem;
    padding: 0 0.25rem;
}

.wizard-dialog .rz-steps-content {
    padding-top: 0.5rem;
}

.wizard-step-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.wizard-step-icon {
    font-size: 1.5rem;
    color: var(--rz-primary, #4080ff);
}

.wizard-step-content {
    opacity: 1;
}

.wizard-step-exit,
.wizard-step-enter {
    /* Transition effect removed for instantaneous step switching. */
}

@keyframes wizardFadeIn {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.wizard-footer {
    border-top: 1px solid var(--rz-base-700, #2e2e2e);
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
    position: sticky;
    bottom: 0;
    background: var(--rz-base-background-color, #121212);
    z-index: 10;
}

.wizard-actions {
    position: absolute;
    top: 2rem;
    right: 0;
    z-index: 5;
}

/* ─── Add Agent Page ─── */
.add-agent-page {
    display: flex;
    flex-direction: column;
}

.add-agent-page .wizard-dialog {
    min-height: unset;
}

/* Platform cards */
.wizard-platform-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border: 2px solid var(--rz-base-700, #2e2e2e);
    border-radius: 0.5rem;
    cursor: pointer;
    transition: border-color 0.2s ease, background 0.2s ease;
}

.wizard-platform-card:hover {
    border-color: var(--rz-primary-lighter, #5a9aff);
    background: var(--rz-base-800, #1e1e1e);
}

.wizard-platform-selected {
    border-color: var(--rz-primary, #4080ff);
    background: var(--rz-base-800, #1e1e1e);
}

.wizard-platform-icon {
    font-size: 2rem;
    color: var(--rz-text-color, #c8c8c8);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
}

.wizard-platform-icon svg {
    width: 100%;
    height: 100%;
}

.wizard-polling-countdown {
    font-size: 0.85rem;
    color: var(--rz-text-secondary-color, #9a9aaa);
}

.wizard-platform-selected .wizard-platform-icon {
    color: var(--rz-primary, #4080ff);
}

.wizard-platform-label {
    font-size: 1.1rem;
    font-weight: 500;
    flex: 1;
}

.wizard-platform-check {
    font-size: 1.25rem;
    color: var(--rz-primary, #4080ff);
}

/* S-DES-25: a capability card forced on by another option (Docker implied by server-management) */
.wizard-card-locked { cursor: default; opacity: 0.85; }
.wizard-card-locked:hover { border-color: var(--rz-primary, #4080ff); background: var(--rz-base-800, #1e1e1e); }
/* S-DES-25: capability label is a stacked title + hint, not the larger single-line platform label */
.wizard-platform-card .wizard-platform-label > div { font-size: 0.95rem; font-weight: 500; }

.wizard-token-code {
    flex: 1;
    min-width: 0;
    font-family: monospace;
    font-size: 0.9rem;
    padding: 0.25rem 0.5rem;
    background: var(--wizard-code-bg);
    border-radius: calc(var(--wizard-code-radius) - 0.125rem);
    word-break: break-all;
    white-space: normal;
    user-select: all;
}

.wizard-code-block {
    margin-bottom: 0.5rem;
}

.wizard-pre-wrapper {
    position: relative;
}

.wizard-code-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    background: var(--wizard-code-header-bg);
    border: 1px solid var(--wizard-code-border);
    border-bottom: none;
    border-radius: var(--wizard-code-radius) var(--wizard-code-radius) 0 0;
    min-height: 2rem;
}

.wizard-code-header-label {
    font-size: 0.8rem;
    color: var(--wizard-code-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wizard-pre {
    background: var(--wizard-code-bg);
    border: 1px solid var(--wizard-code-border);
    border-radius: var(--wizard-code-radius);
    padding: 0.75rem 1rem;
    overflow-x: auto;
    font-size: 0.85rem;
    line-height: 1.5;
    margin: 0;
}

/* When a header sits on top, drop the upper rounding/border so the two pieces meld. */
.wizard-code-header + .wizard-pre {
    border-top: none;
    border-radius: 0 0 var(--wizard-code-radius) var(--wizard-code-radius);
}

.wizard-pre code {
    color: var(--wizard-code-text);
    white-space: pre;
}

.wizard-token-pre code {
    white-space: pre-wrap;
    word-break: break-all;
}

/* S-DES-14: expandable changelog cell in the releases grid */
.release-changelog-cell { white-space: pre-wrap; word-break: break-word; font-size: 0.8125rem; }

/* S-DES-15: accent the literal <TOKEN> placeholder so it reads as "replace me" */
.wizard-token-placeholder {
    color: var(--rz-warning, #ffa726);
    font-weight: 600;
}

/* ---- Console-style output blocks (unified with the wizard code tokens) ----
   .task-output           — Tasks page: stdout/stderr from agent shells
   .pipeline-step-output  — Pipelines page: per-step log streamed via SignalR
   .server-detail-code    — Servers detail: command output / inline scripts
   Use .is-success / .is-error to tint the block once a state is known. */
.task-output,
.pipeline-step-output,
.server-detail-code {
    background: var(--wizard-code-bg);
    border: 1px solid var(--wizard-code-border);
    border-radius: var(--wizard-code-radius);
    color: var(--wizard-code-text);
    font-family: 'Cascadia Code', 'Consolas', 'Menlo', monospace;
    font-size: 0.85rem;
    line-height: 1.5;
    padding: 0.75rem 1rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

.task-output.is-success,
.pipeline-step-output.is-success,
.server-detail-code.is-success,
.wizard-pre.is-success,
.wizard-code-block.is-success > .wizard-pre {
    background: var(--wizard-code-bg-success);
    border-color: var(--wizard-code-border-success);
}

.task-output.is-error,
.pipeline-step-output.is-error,
.server-detail-code.is-error,
.wizard-pre.is-error,
.wizard-code-block.is-error > .wizard-pre {
    background: var(--wizard-code-bg-error);
    border-color: var(--wizard-code-border-error);
}

.wizard-copy-btn {
    flex-shrink: 0;
}

/* Verify polling */
.wizard-polling {
    padding: 0.75rem;
    background: var(--rz-base-800, #1e1e1e);
    border-radius: 0.375rem;
}

.wizard-verify-success-icon {
    color: var(--rz-success, #4caf50);
    vertical-align: middle;
}

.wizard-verify-list {
    margin: 0;
    padding-left: 1.25rem;
}

.wizard-verify-list li {
    margin-bottom: 0.5rem;
}

/* Apache log viewer */
.apache-log-output {
    max-height: 32rem;
    overflow-y: auto;
    font-size: 0.8125rem;
    line-height: 1.4;
    padding: 0.75rem;
    border-radius: var(--rz-border-radius);
    background: var(--rz-base-900);
    color: var(--rz-text-color);
    white-space: pre-wrap;
    word-break: break-all;
}

.apache-log-follow {
    scroll-behavior: smooth;
    overflow-anchor: auto;
}

.vp-edge {
    fill: none;
    stroke: var(--rz-base-500, #5a5a6e);
    stroke-width: 2;
    transition: d 0.3s ease, stroke 0.2s ease, stroke-width 0.2s ease;
}

.vp-edge-selected {
    stroke: var(--rz-primary, #1e88e5);
    stroke-width: 2.5;
}

.vp-edge-arrow {
    fill: var(--rz-base-500, #5a5a6e);
}

.vp-edge-arrow-selected {
    fill: var(--rz-primary, #1e88e5);
}

.vp-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
    flex-wrap: wrap;
}

.vp-settings-panel {
    border: 0.0625rem solid var(--rz-border-color);
    border-radius: var(--rz-border-radius);
    padding: 0.75rem;
    margin-bottom: 0.75rem;
    background-color: var(--rz-base-800, #2a2a3e);
}

.vp-edit-panel {
    border: 0.0625rem solid var(--rz-border-color);
    border-radius: var(--rz-border-radius);
    padding: 0.75rem;
    margin-top: 0.75rem;
    background-color: var(--rz-base-800, #2a2a3e);
}

.vp-edit-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.75rem;
}

.vp-empty-canvas {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    gap: 1rem;
    color: var(--rz-text-secondary-color, #a0a0b0);
}

.vp-error-banner {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    border-radius: var(--rz-border-radius);
    background-color: var(--rz-danger-lighter, #3d1a1e);
    border: 0.0625rem solid var(--rz-danger, #dc3545);
    color: var(--rz-danger, #dc3545);
    margin-bottom: 0.75rem;
}

.vp-var-grid {
    display: grid;
    grid-template-columns: 1fr 1fr auto;
    gap: 0.25rem;
    align-items: center;
}

@media (max-width: 768px) {
    .vp-canvas-outer {
        height: calc(100vh - 28rem);
        min-height: 15rem;
    }

    .vp-node {
        width: 11rem;
    }
}

/* ---- Stat cards (Home dashboard) ---- */

.stat-card {
    border-left: 4px solid transparent;
    transition: border-color 0.15s;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* ---- Equal-height tiles — uniform height per row ----
   RadzenRow renders as flex with align-items:stretch by default, but
   RadzenColumn itself isn't flex — so a card inside it sizes to its
   content. We force the columns of these rows to be flex containers so
   their child card can stretch to the tallest sibling's height.

   Usage:
   - `equal-tile-row` on any RadzenRow → child RadzenCards auto-stretch
     (works for metric tiles on server overview, etc.)
   - `dashboard-tile-row` = `equal-tile-row` + 20rem min-height floor
     (dashboard widgets where short content should still leave breathing room)
*/
.equal-tile-row,
.dashboard-tile-row {
    align-items: stretch !important;
}

.equal-tile-row > .rz-col,
.equal-tile-row > [class*="rz-col-"],
.dashboard-tile-row > .rz-col,
.dashboard-tile-row > [class*="rz-col-"] {
    display: flex;
    flex-direction: column;
}

.equal-tile-row > .rz-col > .rz-card,
.equal-tile-row > [class*="rz-col-"] > .rz-card,
.dashboard-tile-row > .rz-col > .rz-card,
.dashboard-tile-row > [class*="rz-col-"] > .rz-card {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    height: auto;
}

.equal-tile-row .rz-card > .rz-card-body,
.dashboard-tile-row .rz-card > .rz-card-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Server overview — Pipeline runner / Container isolation posture tiles.
   The toggle button sinks to the bottom so the two side-by-side tiles align. */
.overview-feature-card .rz-card-body > .rz-stack {
    height: 100%;
}

.overview-feature-card .rz-button {
    margin-top: auto;
    align-self: flex-start;
}

/* Heartbeat pulse: a thick ring that fills over the 30 s beat cadence and resets on
   each fresh beat. Centre counts the cadence down (30 → 0). Laid out as a tile: the
   "Heartbeat" label sits at the top like the sibling metric tiles, the ring + meta
   centre in the remaining space. */
.heartbeat-pulse-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    height: 100%;
}

.heartbeat-pulse-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    flex: 1 1 auto;
    text-align: center;
}

.heartbeat-pulse {
    position: relative;
    width: 4.5rem;
    height: 4.5rem;
    flex-shrink: 0;
}

.heartbeat-pulse-ring {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.heartbeat-pulse-track {
    fill: none;
    stroke: var(--rz-base-300, #2a2a2a);
    stroke-width: 9;
}

.heartbeat-pulse-progress {
    fill: none;
    stroke-width: 9;
    stroke-linecap: round;
}

/* Live ring: a single cadence that fills then snaps back to empty and refills.
   The dash values match the r=42 circumference (2·π·42 ≈ 263.89). The circle element is
   re-keyed on each beat in the component, which restarts this animation from empty.
   The cadence is centralised in --heartbeat-cadence (HBSY) — one source of truth shared
   by the CSS loop and the component's HeartbeatCadenceSeconds constant. The component
   sets a negative animation-delay on (re)creation so the first cycle after page load is
   phase-aligned with the real age of the last beat, not just resynced at the next beat. */
.heartbeat-pulse-progress { --heartbeat-cadence: 30s; }

@keyframes heartbeat-fill {
    from { stroke-dashoffset: 263.89; }
    to { stroke-dashoffset: 0; }
}

/* HB8P: a brief scale flash each time the ring resets (the circle is re-keyed on every
   beat, so this one-shot animation replays on each fresh beat) — materialises the pulse. */
@keyframes heartbeat-flash {
    0% { transform: scale(1); }
    35% { transform: scale(1.05); }
    100% { transform: scale(1); }
}

.heartbeat-pulse-online .heartbeat-pulse-progress {
    stroke: var(--rz-success, #22c55e);
    animation: heartbeat-fill var(--heartbeat-cadence, 30s) linear infinite, heartbeat-flash 0.5s ease-out;
    transform-box: fill-box;
    transform-origin: center;
}

.heartbeat-pulse-offline .heartbeat-pulse-progress {
    stroke: var(--rz-danger, #ef4444);
}

.heartbeat-pulse-disabled .heartbeat-pulse-progress {
    stroke: var(--rz-base-500, #6b7280);
}

.heartbeat-pulse-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1rem;
    text-align: center;
}

.heartbeat-pulse-duration {
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--rz-text-color, #e0e0e0);
}

.heartbeat-pulse-state {
    font-size: 0.55rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.heartbeat-pulse-online .heartbeat-pulse-state {
    color: var(--rz-success, #22c55e);
}

.heartbeat-pulse-offline .heartbeat-pulse-state {
    color: var(--rz-danger, #ef4444);
}

.heartbeat-pulse-disabled .heartbeat-pulse-state {
    color: var(--rz-text-secondary, #9ca3af);
}

/* Services capability notice: the "package management disabled" message and the live heartbeat
   shown as two aligned, equal-height tiles above the services tables (the tables stay tables). */
.capability-warning-tile {
    border-left: 0.25rem solid var(--rz-warning, #f59e0b);
    display: flex;
    align-items: center;
}

.capability-warning-icon {
    color: var(--rz-warning, #f59e0b);
    flex-shrink: 0;
}

.heartbeat-tile {
    flex: 0 0 auto;
    min-width: 11rem;
}

/* Server overview — Essentials definition grid: icon + label/value pairs, two
   responsive columns collapsing to one on narrow viewports. */
.essentials-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.25rem 2rem;
}

@media (max-width: 768px) {
    .essentials-grid {
        grid-template-columns: 1fr;
    }
}

/* Single-column variant for the narrower half-width overview cards
   (project Information / Repository) — same icon+label+value treatment. */
.essentials-grid--stacked {
    grid-template-columns: 1fr;
    gap: 0;
}

/* No trailing divider under the last row in the stacked variant (rows have no
   column gap there, so the last border would sit flush against the card edge). */
.essentials-grid--stacked .essential-item:last-child {
    border-bottom: none;
}

.essential-item {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--rz-base-200, #ececec);
}

.essential-icon {
    font-size: 1.1rem;
    color: var(--rz-text-secondary, #9ca3af);
    margin-top: 0.1rem;
    flex-shrink: 0;
}

.essential-text {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.essential-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--rz-text-secondary, #9ca3af);
}

.essential-value {
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--rz-text-color, #e0e0e0);
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    word-break: break-word;
}

.dashboard-tile {
    min-height: 10rem;
}

.dashboard-tile .dashboard-clickable-grid {
    flex: 1 1 auto;
    min-height: 0;
}

/* Dashboard tile layout: the RadzenColumns are Size="12" so the default is ONE tile per line
   (dense tables get the full width on laptops / sub-1800 screens). On wide screens (>= 1800px)
   restore the 3-across layout. Radzen's grid has no 1800 breakpoint (it tops out at XXL = 1400),
   so this custom media query is the only way to break exactly at 1800. flex-basis subtracts the
   row's two 1rem gaps so three columns + gaps fit on one line. */
@media (min-width: 1800px) {
    .dashboard-tile-row > .rz-col,
    .dashboard-tile-row > [class*="rz-col-"] {
        flex: 1 1 calc((100% - 2rem) / 3);
        max-width: calc((100% - 2rem) / 3);
    }
}

/* Server overview metrics row: 5 equal-width tiles (Heartbeat, CPU, Memory, Disk,
   Services) on one line. A 12-col grid can't split into 5, so use a CSS grid with
   equal fractions. Collapses to 2-up on tablet, 1-up on phones. align-items:stretch
   gives every tile (incl. the shorter Services card) the same height. */
.metric-tile-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 1rem;
    align-items: stretch;
}

.metric-tile-grid > .rz-card,
.metric-tile-grid > .tile-link > .rz-card {
    height: 100%;
}

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

@media (max-width: 576px) {
    .metric-tile-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ---- Clickable metric tile (e.g. Services tile on server overview) ---- */
.tile-link {
    text-decoration: none;
    color: inherit;
    display: flex;
    height: 100%;
}

.tile-link .tile-clickable {
    width: 100%;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.tile-link:hover .tile-clickable {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
    border-color: var(--rz-primary);
}

/* Project Overview — Recent Activity list flush to the content edges (no L/R padding).
   Radzen DataList applies padding via three layers: .rz-datalist-data, its >li children
   (--rz-datalist-item-padding), and the >li margin-inline. Reset all three. */
.project-activity-flush .rz-datalist-data,
.project-activity-flush .rz-datalist-content,
.project-activity-flush .rz-g {
    padding-left: 0;
    padding-right: 0;
    margin-left: 0;
    margin-right: 0;
}

.project-activity-flush .rz-datalist-data > li {
    padding-left: 0;
    padding-right: 0;
    margin-inline: 0;
    border-left: 0;
    border-right: 0;
}

.stat-card-info {
    border-left-color: var(--rz-info);
}

.stat-card-success {
    border-left-color: var(--rz-success);
}

.stat-card-danger {
    border-left-color: var(--rz-danger);
}

.stat-card-warning {
    border-left-color: var(--rz-warning);
}

/* ---- Mobile sidebar backdrop ---- */

.sidebar-backdrop {
    display: none;
}

@media (max-width: 768px) {
    .sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        z-index: 999;
    }
}

/* ==========================================================================
   Cron expression live validation
   ========================================================================== */

.cron-next-run {
    color: var(--rz-success, #28a745);
    font-family: 'Cascadia Code', 'Fira Code', monospace;
}

.cron-error {
    color: var(--rz-danger, #dc3545);
}

/* ==========================================================================
   Docker container row — compose project accent
   ========================================================================== */

.docker-row-project {
    border-left: 0.25rem solid transparent;
}

.docker-project-accent-0 { border-left-color: var(--rz-info, #17a2b8); }
.docker-project-accent-1 { border-left-color: var(--rz-primary, #1b6ec2); }
.docker-project-accent-2 { border-left-color: var(--rz-success, #28a745); }
.docker-project-accent-3 { border-left-color: var(--rz-warning, #ffc107); }
.docker-project-accent-4 { border-left-color: var(--rz-danger, #dc3545); }
.docker-project-accent-5 { border-left-color: var(--rz-secondary); }
.docker-project-accent-6 { border-left-color: var(--rz-danger-light, #ff5722); }
.docker-project-accent-7 { border-left-color: var(--rz-base-500); }

/* ==========================================================================
   Error Boundary Card
   ========================================================================== */

.error-card {
    max-width: 32rem;
    margin-top: 4rem;
}

.error-icon {
    font-size: 3rem;
    color: var(--rz-danger);
}

/* ==========================================================================
   Metric Bar / Icon Sizing
   ========================================================================== */

.metric-bar-thin {
    height: 0.375rem;
}

.icon-sm {
    font-size: var(--icon-lg);
}

/* ==========================================================================
   Skip-to-content link (F21)
   ========================================================================== */

.skip-link {
    position: absolute;
    top: -3rem;
    left: 1rem;
    z-index: 10000;
    padding: 0.5rem 1rem;
    background: var(--rz-primary, #1b6ec2);
    color: #fff;
    text-decoration: none;
    border-radius: 0 0 0.25rem 0.25rem;
    transition: top 0.2s;
}

.skip-link:focus {
    top: 0;
}

/* ==========================================================================
   Keyboard focus visibility (F-040, a11y)
   :focus-visible matches keyboard / programmatic focus only — not mouse clicks —
   so keyboard users get a clear ring without adding visual noise for pointer users.
   ========================================================================== */

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--rz-primary, #1b6ec2);
    outline-offset: 2px;
}

/* Suppress the focus ring on full-page containers (wizard, dialogs) that carry
   tabindex="0" for keyboard event capture — the ring spans the entire viewport
   width and is visually jarring on page load. */
.wizard-dialog:focus-visible { outline: none; }

/* ==========================================================================
   Theme toggle contrast fix (F18)
   ========================================================================== */

.theme-toggle-btn {
    color: #fff !important;
}

/* ==========================================================================
   Utility classes (extracted from inline styles)
   ========================================================================== */

/* Hidden input file (replaces style="display:none") */
.input-file-hidden {
    display: none;
}

/* Pre-formatted changelog/text block */
.text-block-pre {
    white-space: pre-wrap;
    font-size: 0.8125rem;
    margin: 0;
}

/* Mail service status indicator dot */
.mail-status-dot {
    background-color: var(--rz-danger);
}

.mail-status-dot.is-running {
    background-color: var(--rz-success);
}

.lang-toggle-wrapper {
    display: inline-flex;
    align-items: center;
    position: relative;
}

.lang-badge {
    font-size: 0.625rem;
    font-weight: 700;
    line-height: 1;
    color: #fff;
    background-color: var(--rz-primary);
    padding: 0.125rem 0.25rem;
    border-radius: 0.25rem;
    position: absolute;
    right: -0.125rem;
    bottom: 0.125rem;
    pointer-events: none;
}

/* ==========================================================================
   404 Not Found page
   ========================================================================== */

.not-found-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 60vh;
    padding: 2rem;
}

.not-found-illustration {
    width: 16rem;
    max-width: 100%;
    height: auto;
    margin-bottom: 1.5rem;
}

/* ==========================================================================
   Mobile responsive fixes (F02)
   ========================================================================== */

@media (max-width: 576px) {
    .rz-datatable {
        overflow-x: auto;
    }

    .server-list-search,
    .pipeline-list-search {
        min-width: 0;
        width: 100%;
    }

    .stat-card .rz-text-subtitle2 {
        font-size: 0.75rem;
    }

    .stat-card .rz-text-h3 {
        font-size: 1.25rem;
    }
}

/* Help Center */
.help-search-box {
    max-width: 25rem;
    width: 100%;
}

.help-card {
    cursor: pointer;
    transition: box-shadow 0.2s ease, transform 0.15s ease;
    height: 100%;
}

.help-card:hover {
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.15);
    transform: translateY(-0.125rem);
}

/* HCF4: visible keyboard-focus state on the help tiles (role="button" + tabindex="0"),
   mirroring the hover lift so keyboard users get the same affordance as the mouse. */
.help-card:focus-visible {
    outline: 0.125rem solid var(--rz-primary, #7c4dff);
    outline-offset: 0.125rem;
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.15);
}

.help-card-icon {
    font-size: 1.5rem;
    opacity: 0.7;
}

.help-article-icon {
    font-size: 1.75rem;
    opacity: 0.7;
}

/* ==========================================================================
   Header Bar & User Menu (Astraia-style)
   ========================================================================== */

.header-bar {
    width: 100%;
    position: relative;
    height: 100%;
}

.app-home-link {
    text-decoration: none;
    color: inherit;
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

.app-header-icon {
    width: 1.5rem;
    height: 1.5rem;
}

.app-title {
    cursor: pointer;
}

.header-icon {
    font-size: 1.125rem;
}

.header-action-btn {
    min-height: 2.25rem;
    min-width: 2.25rem;
    height: 2.25rem;
    box-sizing: border-box;
}

/* Backend connection indicator: wifi glyph coloured by SignalR link state. */
.header-conn-icon {
    font-size: 1.25rem;
    padding: 0 0.25rem;
    cursor: default;
}

.header-conn-online {
    color: var(--rz-success, #22c55e);
}

.header-conn-warning {
    color: var(--rz-warning, #f59e0b);
}

.header-conn-offline {
    color: var(--rz-danger, #ef4444);
}

/* Org picker relocated into the user menu — fills the menu section width. */
.user-menu-org-picker {
    width: 100%;
}

.header-user-btn {
    padding: 0 0.5rem;
}

.display-name {
    margin: 0 0.25rem;
}

/* Dev-only top-bar banner (environment / label / branch) — never shown in prod.
   Absolutely centred on the header so it stays mid-bar regardless of the differing
   left (logo) and right (org picker + actions) widths; a single chip lands centred too.
   The container is click-through (pointer-events:none) so it never blocks header
   controls underneath; the chips re-enable pointer events for their tooltips. */
.dev-env-banner {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    max-width: 60%;
    overflow: hidden;
    pointer-events: none;
    z-index: 1;
}

.dev-env-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    max-width: 18rem;
    padding: 0.125rem 0.5rem;
    border-radius: 1rem;
    font-size: 0.75rem;
    line-height: 1.4;
    white-space: nowrap;
    pointer-events: auto;
    border: 1px solid var(--rz-base-600, #3a3a3a);
    background: var(--rz-base-800, #1e1e1e);
    color: var(--rz-text-color, #e0e0e0);
}

.dev-env-chip-icon {
    font-size: 0.875rem;
    opacity: 0.85;
}

.dev-env-chip-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dev-env-chip-env {
    border-color: var(--rz-info-light, #3b82f6);
    color: var(--rz-info-light, #3b82f6);
}

.dev-env-chip-label {
    border-color: var(--rz-warning, #f59e0b);
    color: var(--rz-warning, #f59e0b);
    font-weight: 600;
}

/* Tight headers drop the long branch chip first; the environment chip always stays. */
@media (max-width: 992px) {
    .dev-env-chip-branch {
        display: none;
    }
}

.user-menu-container {
    position: relative;
}

.user-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 999;
}

.user-menu-card {
    position: absolute;
    right: 0;
    top: calc(100% + 0.25rem);
    z-index: 1000;
    min-width: 15rem;
    max-width: calc(100vw - 1rem);
    padding: 0;
}

.user-menu-section {
    border-bottom: 1px solid var(--rz-base-300);
}

.user-menu-section-clickable {
    border-bottom: 1px solid var(--rz-base-300);
    cursor: pointer;
}

.user-menu-section-clickable:hover {
    background-color: var(--rz-base-200);
}

.theme-switch-readonly {
    pointer-events: none;
}

/* ==========================================================================
   Admin Tile Cards
   ========================================================================== */

.admin-tile-link {
    text-decoration: none;
    color: inherit;
    display: block;
    height: 100%;
}

.admin-tile-card {
    text-align: center;
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s;
    border-left: 0.25rem solid transparent;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    min-height: 10rem;
    height: 100%;
}

.admin-tile-card:hover {
    transform: translateY(-0.125rem);
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
}

/* Colored left borders for admin tiles */
.admin-tile-card.tile-primary   { border-left-color: var(--rz-primary); }
.admin-tile-card.tile-info      { border-left-color: var(--rz-info); }
.admin-tile-card.tile-success   { border-left-color: var(--rz-success); }
.admin-tile-card.tile-warning   { border-left-color: var(--rz-warning); }
.admin-tile-card.tile-secondary { border-left-color: var(--rz-secondary); }
.admin-tile-card.tile-danger    { border-left-color: var(--rz-danger); }

.admin-tile-icon {
    font-size: 2.5rem;
}

.color-primary {
    color: var(--rz-primary);
}

.color-success {
    color: var(--rz-success);
}

.color-info {
    color: var(--rz-info);
}

.color-warning {
    color: var(--rz-warning);
}

.color-danger {
    color: var(--rz-danger);
}

/* Responsive column visibility — used with RadzenDataGridColumn CssClass + HeaderCssClass. */
@media (max-width: 1400px) {
    .col-hide-xl { display: none !important; }
}
@media (max-width: 1200px) {
    .col-hide-lg { display: none !important; }
}
@media (max-width: 1024px) {
    .col-hide-md { display: none !important; }
}

/* Hint shown when responsive columns are hidden.
   Uses the SECONDARY (not DISABLED) text color: --rz-text-disabled-color is intentionally low-contrast
   (rgba .5/.38) and fails WCAG AA (3.17:1 on the #1e1e1e dark surface - axe color-contrast critical);
   --rz-text-secondary-color is theme-aware and AA-compliant in both the light and dark Radzen themes. */
.responsive-columns-hint {
    display: none;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.75rem;
    color: var(--rz-text-secondary-color);
    margin-bottom: 0.25rem;
}
@media (max-width: 1400px) {
    .responsive-columns-hint { display: flex; }
}

/* WCAG AA contrast for the Radzen dropdown/select placeholder text. Radzen's default placeholder color
   is the disabled token (rgba .5 on dark), which axe flags at 3.17:1 (< 4.5:1) on the #1e1e1e surface.
   The secondary token is theme-aware and AA-compliant in both the light and dark Radzen themes. */
.rz-dropdown .rz-placeholder,
.rz-placeholder.rz-dropdown-label {
    color: var(--rz-text-secondary-color);
}

/* Inherited-from badge for cross-access resources */
.inherited-badge {
    font-size: 0.7rem;
    opacity: 0.8;
}

/* Small badge variant for inline use */
.badge-xs .rz-badge {
    font-size: 0.6rem;
    padding: 0.05rem 0.35rem;
}

/* Column chooser popup (server list) */
.column-chooser-wrap {
    position: relative;
    display: inline-block;
}
.column-chooser-popup {
    position: absolute;
    top: 2.5rem;
    right: 0;
    z-index: 20;
    min-width: 12rem;
    padding: 0.75rem;
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.3);
}

/* Pipeline runner toggle pulse animation */
@keyframes runner-pulse {
    0% { box-shadow: 0 0 0 0 rgba(63, 185, 80, 0.4); }
    70% { box-shadow: 0 0 0 0.5rem rgba(63, 185, 80, 0); }
    100% { box-shadow: 0 0 0 0 rgba(63, 185, 80, 0); }
}
.pipeline-runner-icon-on {
    animation: runner-pulse 1s ease-out;
}

/* Agent update progress phase chevron */
.agent-update-phase-active {
    color: var(--rz-info);
    animation: phase-spin 1.5s linear infinite;
}
.agent-update-phase-done { color: var(--rz-success); }
.agent-update-phase-failed { color: var(--rz-danger); }
@keyframes phase-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* Focus-visible: exclude Radzen components that already have built-in focus rings */
.rz-button:focus-visible,
.rz-textbox:focus-visible,
.rz-dropdown:focus-visible,
.rz-inputtext:focus-visible {
    outline: none;
}

.color-secondary {
    color: var(--rz-secondary);
}

/* Message cell: truncate to a single line; the full text (and any exception) is reachable via the
   row's "view message" action button. */
.log-message-cell {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.correlation-id-text {
    font-size: 0.8rem;
    font-family: var(--rz-font-family-monospace, monospace);
    word-break: break-all;
}

.exception-pre {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 60vh;
    overflow: auto;
    font-size: 0.85rem;
    font-family: var(--rz-font-family-monospace, monospace);
    margin: 0;
}

/* ==========================================================================
   Alert Badge
   ========================================================================== */

.alert-badge-dot {
    font-size: 0.7rem;
    min-width: 1.25rem;
    height: 1.25rem;
    line-height: 1.25rem;
    padding: 0 0.25rem;
    border-radius: 0.625rem;
    animation: pulse-dot 2s infinite;
}


/* ==========================================================================
   Button Utilities
   ========================================================================== */

.btn-fit {
    width: fit-content;
}

.settings-form {
    max-width: 30rem;
}

.about-label {
    font-weight: 600;
    min-width: 7rem;
    color: var(--rz-text-secondary-color);
}

/* ==========================================================================
   Monaco Viewer (read-only)
   ========================================================================== */

.monaco-viewer-container {
    width: 100%;
    height: 25rem;
    border: 1px solid var(--rz-grid-border);
    border-radius: var(--rz-border-radius);
}

/* O: SVG commit lane graph (replaces the ASCII .commit-graph <pre>) */
.commit-graph-svg-wrap {
    overflow: auto;
    max-height: 36rem;
    background: var(--rz-base-background-color);
    border: 1px solid var(--rz-grid-border);
    border-radius: var(--rz-border-radius);
}
.git-svg-graph { display: flex; align-items: flex-start; min-width: fit-content; }
.git-svg-lanes { flex: 0 0 auto; }
.git-svg-rows { flex: 1 1 auto; min-width: 0; }
.git-svg-row { height: 2.125rem; display: flex; align-items: center; gap: 0.625rem; padding: 0 0.5rem; }
.git-svg-row:hover { background: var(--rz-base-800, #1e1e1e); }
.git-graph-sha { font-family: "Cascadia Code", "Fira Code", "Consolas", monospace; font-size: 0.8125rem; color: var(--rz-primary, #7c4dff); flex: 0 0 auto; }
.git-graph-subject { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
.git-graph-meta { font-size: 0.75rem; color: var(--rz-text-secondary-color, #aaa); flex: 0 0 auto; white-space: nowrap; }

.blame-view {
    font-family: "Cascadia Code", "Fira Code", "Consolas", monospace;
    font-size: 0.8125rem;
    line-height: 1.4;
    padding: 1rem;
    overflow: auto;
    max-height: 35rem;
    background: var(--rz-base-background-color);
    border: 1px solid var(--rz-grid-border);
    border-radius: var(--rz-border-radius);
    white-space: pre;
    margin: 0;
}
/* F26: width utility classes (replace inline Style="width:NNNpx") */
.w-rem-6 { width: 6rem; }      /* ~96px */
.w-rem-7-5 { width: 7.5rem; }  /* 120px */
.w-rem-8-75 { width: 8.75rem; }/* 140px */
.w-rem-10 { width: 10rem; }    /* 160px */
.w-rem-11 { width: 11.25rem; } /* 180px */
.w-rem-12-5 { width: 12.5rem; }/* 200px */
.w-rem-15 { width: 15rem; }    /* 240px */
.w-rem-15-625 { width: 15.625rem; } /* 250px */
.w-rem-16 { width: 16.25rem; } /* 260px */
.w-rem-37-5 { max-width: 37.5rem; } /* 600px */
.w-rem-34-375 { max-width: 34.375rem; } /* 550px */
.minw-rem-15 { min-width: 15rem; } /* 240px */
.h-progress-thin { height: 0.375rem; } /* 6px */
.fs-13 { font-size: 0.8125rem; }

/* F26: stage node positioning via CSS custom properties */
.stage-node-positioned {
    left: var(--node-x, 0);
    top: var(--node-y, 0);
}

/* ==========================================================================
   F-25 utility classes (replace inline Style="font-size:..." etc.)
   ========================================================================== */

.icon-xxs { font-size: 0.6875rem; vertical-align: middle; }
.icon-xs-app { font-size: 0.85rem; }
.icon-sm-app { font-size: 0.875rem; }
.icon-input-sm { font-size: 0.8125rem; }
.icon-md-app { font-size: 1rem; }
.icon-3xl { font-size: 3rem; }
.icon-3xl-success { font-size: 3rem; color: var(--rz-success); }
.icon-3xl-secondary { font-size: 3rem; color: var(--rz-secondary); }
.icon-3xl-disabled { font-size: 3rem; color: var(--rz-text-disabled-color); }
.icon-warn-sm { font-size: 0.875rem; color: var(--rz-warning); }
.text-mono { font-family: 'Cascadia Code', 'Fira Code', monospace; }
.text-mono-sm { font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.8125rem; }
.flex-1 { flex: 1; }
.text-num-cell { min-width: 1.5rem; text-align: right; }
.text-input-flex { font-size: 0.8125rem; flex: 1; }
.font-size-09 { font-size: 0.9rem; }

/* ==========================================================================
   F-25 utility classes (replace inline Style="font-size:..." etc.)
   ========================================================================== */

.icon-xxs { font-size: 0.6875rem; vertical-align: middle; }
.icon-xs-app { font-size: 0.85rem; }
.icon-sm-app { font-size: 0.875rem; }
.icon-input-sm { font-size: 0.8125rem; }
.icon-md-app { font-size: 1rem; }
.icon-3xl { font-size: 3rem; }
.icon-3xl-success { font-size: 3rem; color: var(--rz-success); }
.icon-3xl-secondary { font-size: 3rem; color: var(--rz-secondary); }
.icon-3xl-disabled { font-size: 3rem; color: var(--rz-text-disabled-color); }
.icon-warn-sm { font-size: 0.875rem; color: var(--rz-warning); }
.text-mono { font-family: 'Cascadia Code', 'Fira Code', monospace; }
.text-mono-sm { font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.8125rem; }
.flex-1 { flex: 1; }
.text-num-cell { min-width: 1.5rem; text-align: right; }
.text-input-flex { font-size: 0.8125rem; flex: 1; }
.font-size-09 { font-size: 0.9rem; }

/* ==========================================================================
   F-25 utility classes (replace inline Style="font-size:..." etc.)
   ========================================================================== */

.icon-xxs { font-size: 0.6875rem; vertical-align: middle; }
.icon-xs-app { font-size: 0.85rem; }
.icon-sm-app { font-size: 0.875rem; }
.icon-input-sm { font-size: 0.8125rem; }
.icon-md-app { font-size: 1rem; }
.icon-3xl { font-size: 3rem; }
.icon-3xl-success { font-size: 3rem; color: var(--rz-success); }
.icon-3xl-secondary { font-size: 3rem; color: var(--rz-secondary); }
.icon-3xl-disabled { font-size: 3rem; color: var(--rz-text-disabled-color); }
.icon-warn-sm { font-size: 0.875rem; color: var(--rz-warning); }
.text-mono { font-family: 'Cascadia Code', 'Fira Code', monospace; }
.text-mono-sm { font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.8125rem; }
.flex-1 { flex: 1; }
.text-num-cell { min-width: 1.5rem; text-align: right; }
.text-input-flex { font-size: 0.8125rem; flex: 1; }
.font-size-09 { font-size: 0.9rem; }

/* Enforce a consistent baseline height on all Radzen buttons so mixed sizes within
   the same action row never produce mismatched heights. */
.rz-button { min-height: 2.25rem; }

/* F-48 — Remove forced uppercase styling from Radzen Material buttons and tab titles
   for a more modern look that respects user-supplied casing. */
.rz-button .rz-button-text,
.rz-tabview-nav .rz-tabview-title {
    text-transform: none;
}

/* Keep every button label on a single line. Without this, long French labels
   (e.g. "Contacter l'agent", "Mettre à jour l'agent") wrap to two lines and
   produce mismatched heights inside the same action row — sibling buttons with
   shorter labels then look visually crushed between the wrapped ones. */
.rz-button .rz-button-text {
    white-space: nowrap;
}

/* Item #11 — Pipeline runner opt-in card: a glanceable status icon on the overview.
   Green play when armed, muted pause when locked down. */
.pipeline-runner-icon-on  { font-size: 2rem; color: var(--rz-success); }
.pipeline-runner-icon-off { font-size: 2rem; color: var(--rz-text-secondary-color); opacity: 0.7; }

/* Item #3 — Agent self-update progress card: live indicator on the server detail page.
   Phase-aware coloring so a successful update lands green, a failure lands red, and the
   in-progress phases stay info-blue without visually alarming the operator. */
.agent-update-progress-card { border-left: 4px solid var(--rz-info); transition: opacity 0.4s ease-out; }
.agent-update-progress-card.is-fading-out { opacity: 0; }
.agent-update-phase-active  { font-size: 1.25rem; color: var(--rz-info); }
.agent-update-phase-done    { font-size: 1.25rem; color: var(--rz-success); }
.agent-update-phase-failed  { font-size: 1.25rem; color: var(--rz-danger); }

/* Item #7 — top-bar task tracker widget. Sits between the help button and the user menu in the
   header, shows a numeric badge when in-flight tasks exist, opens a fixed-width popover on
   click. The backdrop covers the viewport so a click anywhere outside closes the popover. */
.task-tracker-container { position: relative; }
.task-tracker-btn { position: relative; overflow: visible; }
.task-tracker-btn.rz-button { overflow: visible; }
.task-tracker-badge {
    position: absolute; top: 0; right: 0;
    transform: translate(30%, -30%);
    min-width: 1.25rem; height: 1.25rem;
    padding: 0 0.3rem;
    border-radius: 0.625rem;
    background: var(--rz-info); color: white;
    font-size: 0.7rem; font-weight: 600; line-height: 1.25rem;
    text-align: center;
    pointer-events: none;
}
.task-tracker-backdrop {
    position: fixed; inset: 0; z-index: 999; background: transparent;
}
.task-tracker-popover {
    position: absolute; right: 0; top: calc(100% + 0.25rem);
    width: 22rem; max-height: 30rem;
    z-index: 1000;
    display: flex; flex-direction: column;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
    border: none;
    padding: 0;
}
.task-tracker-header {
    display: flex; align-items: center; justify-content: space-between;
    border-bottom: 1px solid var(--rz-base-300);
}
.task-tracker-list {
    flex: 1 1 auto; overflow-y: auto; min-height: 4rem;
}
.task-tracker-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 2rem 1rem; gap: 0.5rem;
}
.task-tracker-empty-icon {
    font-size: 2rem; color: var(--rz-text-secondary-color); opacity: 0.5;
}
.task-tracker-row {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.5rem 1rem;
    color: inherit; text-decoration: none;
    border-bottom: 1px solid var(--rz-base-200);
}
.task-tracker-row:last-child { border-bottom: none; }
.task-tracker-row:hover { background: var(--rz-base-100); }
.task-tracker-row-body { flex: 1 1 auto; min-width: 0; }
.task-tracker-row-name {
    font-size: 0.875rem; font-weight: 500;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.task-tracker-row-meta {
    font-size: 0.75rem; color: var(--rz-text-secondary-color);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.task-tracker-icon-running  { color: var(--rz-info); }
.task-tracker-icon-assigned { color: var(--rz-warning); }
.task-tracker-icon-pending  { color: var(--rz-text-secondary-color); }
.task-tracker-footer {
    border-top: 1px solid var(--rz-base-300);
    text-align: center;
}
.task-tracker-footer a {
    color: var(--rz-primary); font-size: 0.85rem; text-decoration: none;
}
.task-tracker-footer a:hover { text-decoration: underline; }

/* S-UX-08: grouped view when count > 5 */
.task-tracker-group-header {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.4rem 1rem 0.2rem;
    background: var(--rz-base-100);
    border-bottom: 1px solid var(--rz-base-200);
    position: sticky; top: 0; z-index: 1;
}
.task-tracker-group-icon { font-size: 1rem; color: var(--rz-text-secondary-color); }
.task-tracker-group-name {
    font-size: 0.8125rem; font-weight: 600;
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.task-tracker-group-badge { font-size: 0.6875rem; }
.task-tracker-row-grouped { padding-left: 2rem; }

/* Rendered markdown README inside git repository detail pages. */
.readme-rendered { font-size: 0.9375rem; line-height: 1.7; word-wrap: break-word; }
.readme-rendered h1,
.readme-rendered h2,
.readme-rendered h3,
.readme-rendered h4 { margin-top: 1.5rem; margin-bottom: 0.5rem; font-weight: 600; }
.readme-rendered h1 { font-size: 1.5rem; border-bottom: 1px solid var(--rz-base-300); padding-bottom: 0.3rem; }
.readme-rendered h2 { font-size: 1.25rem; border-bottom: 1px solid var(--rz-base-300); padding-bottom: 0.3rem; }
.readme-rendered h3 { font-size: 1.1rem; }
.readme-rendered p { margin: 0.5rem 0; }
.readme-rendered ul, .readme-rendered ol { padding-left: 1.5rem; margin: 0.5rem 0; }
.readme-rendered code {
    background: var(--rz-base-200, #2a2a3e);
    padding: 0.125rem 0.375rem; border-radius: 0.25rem;
    font-size: 0.85em;
}
.readme-rendered pre {
    background: var(--rz-base-200, #2a2a3e);
    padding: 1rem; border-radius: 0.375rem;
    overflow-x: auto; margin: 0.75rem 0;
}
.readme-rendered pre code { background: none; padding: 0; }
.readme-rendered table { border-collapse: collapse; width: 100%; margin: 0.75rem 0; }
.readme-rendered th, .readme-rendered td {
    border: 1px solid var(--rz-base-300);
    padding: 0.375rem 0.75rem; text-align: left;
}
.readme-rendered th { background: var(--rz-base-200, #2a2a3e); font-weight: 600; }
.readme-rendered a { color: var(--rz-primary); text-decoration: none; }
.readme-rendered a:hover { text-decoration: underline; }
.readme-rendered blockquote {
    border-left: 4px solid var(--rz-primary);
    margin: 0.75rem 0; padding: 0.5rem 1rem;
    color: var(--rz-text-secondary-color);
}
.readme-rendered img { max-width: 100%; height: auto; }

/* F-22 — Force dashboard cards to stack on narrow viewports.
   Radzen's mobile-first grid sometimes leaves Size="3" tiles squeezed on phones; explicitly force full width. */
@media (max-width: 767.98px) {
    .stat-card,
    .dashboard-tile {
        min-height: auto;
    }
    .dashboard-tile-row > .rz-col,
    .dashboard-tile-row > [class*="rz-col-"] {
        flex: 0 0 100% !important;
        max-width: 100% !important;
    }
}

/* F-38 / MA-3 — Ensure all modal dialogs have a clearly visible darkened backdrop
   and that the dialog itself has proper z-index isolation. */
.rz-dialog-mask {
    background-color: rgba(0, 0, 0, 0.55) !important;
    backdrop-filter: blur(2px);
}

.rz-dialog-wrapper {
    z-index: 1050;
}

/* F-33: replaces inline indent style on Teamspeak channel rows. */
.ts-channel-root { padding-left: 0; }
.ts-channel-child { padding-left: 1.5rem; }

/* Hardening (#37): replaces ad-hoc Style="..." attributes on Radzen components. */
.empty-state-icon { font-size: 3rem; color: var(--rz-text-secondary-color); }
.error-state-icon { font-size: 3rem; color: var(--rz-danger); }
.dlg-summary-pre { max-height: 12rem; overflow: auto; }
.tpl-select { width: 20rem; }
.bulk-perm-select { width: 10rem; }
.role-edit-stack { max-width: 32rem; }
.role-perm-select { width: 100%; }
.icon-inherit { font-size: inherit; }

.scan-status-clean { color: var(--rz-success); }
.scan-status-warning { color: var(--rz-warning); }
.scan-status-unknown { color: var(--rz-secondary); }

.clone-url-input { width: 100%; min-width: 28rem; max-width: 48rem; flex: 1 1 auto; }


/* Diagnostic meta row — small, secondary-colored chips of metadata under the
   "Why offline?" summary so the eye picks the summary first. */
.contact-agent-diagnostic-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    font-size: 0.8125rem;
    color: var(--rz-text-secondary-color);
}

/* S-DES-04: token staleness mini-bar */
.diagnostic-token-row { display: inline-flex; align-items: center; gap: 0.5rem; }
.diagnostic-token-bar {
    display: inline-block; width: 4rem; height: 0.375rem;
    border-radius: 0.1875rem; background: var(--rz-base-300);
    overflow: hidden; vertical-align: middle;
}
.diagnostic-token-bar-fill {
    display: block; height: 100%; border-radius: 0.1875rem;
    width: var(--fill-width, 0%);
    transition: width 0.3s ease;
}
.token-bar-ok .diagnostic-token-bar-fill       { background: var(--rz-success); }
.token-bar-warning .diagnostic-token-bar-fill  { background: var(--rz-warning); }
.token-bar-critical .diagnostic-token-bar-fill { background: var(--rz-danger); }
.token-bar-expired .diagnostic-token-bar-fill  { background: var(--rz-danger); width: 0 !important; }

/* 30-minute heartbeat sparkline. One bar per minute slot, color-graded by
   how many beats hit that slot (~2 expected at 30 s cadence). Bars use flex so
   the strip stretches to fill the parent without arithmetic. */
.heartbeat-sparkline { display: flex; flex-direction: column; gap: 0.375rem; }
.heartbeat-sparkline-header { display: flex; justify-content: space-between; align-items: baseline; }
.heartbeat-sparkline-loading { height: 1.25rem; }
.heartbeat-sparkline-row {
    display: flex;
    gap: 2px;
    align-items: flex-end;
    height: 1.5rem;
}
.heartbeat-bucket {
    flex: 1 1 0;
    min-width: 0;
    border-radius: 2px;
}
.heartbeat-bucket-ok   { background: var(--rz-success); height: 100%; }
.heartbeat-bucket-low  { background: var(--rz-warning); height: 65%; }
.heartbeat-bucket-miss { background: var(--rz-base-300); height: 35%; }

/* Audit remediation (front-a/front-b): inline-style removals. */
.status-dot-warning { background-color: var(--rz-warning); }
.status-dot-danger { background-color: var(--rz-danger); }
.status-dot-success { background-color: var(--rz-success); }

.version-alert-bar { display: flex; align-items: center; gap: 0.75rem; }
.version-alert-bar-text { flex: 1; }

.artifact-detail-label { min-width: 8rem; }

.dashboard-widget-preview { min-height: var(--widget-height, 6rem); }

.org-projects-listbox { width: 100%; height: 20rem; }
.org-edit-form { max-width: 40rem; }

.coverage-card { min-width: 10rem; }
.coverage-progress { height: 0.375rem; --rz-progressbar-fill-background-color: var(--coverage-color); }

/* K: actionable coverage tab — radial gauges, trend chart, per-file grid */
.coverage-gauge-wrap { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; }
.coverage-gauge { width: 9rem; height: 5.5rem; }
.coverage-gauge-label { text-align: center; }
.coverage-trend-chart { width: 28rem; max-width: 100%; height: 12rem; }
.coverage-file-grid { margin-top: 0.25rem; }
.coverage-file-name { font-family: "Cascadia Code", "Fira Code", "Consolas", monospace; font-size: 0.8125rem; }
.coverage-file-bar { display: flex; align-items: center; gap: 0.5rem; }
.coverage-file-bar .coverage-progress { flex: 1; }
.coverage-file-pct { font-size: 0.8125rem; min-width: 3rem; text-align: right; }
.run-logs-terminal-sm { max-height: 20rem; }
.run-logs-terminal-md { max-height: 25rem; }

.artifact-policy-filter { width: 10rem; }
.server-empty-icon { font-size: 3rem; opacity: 0.4; }
.project-repo-url-input { width: 100%; min-width: 22rem; }
.docker-graph-filter-dropdown { width: 14rem; }

.server-os-icon { font-size: 1.1rem; color: var(--os-color); }

/* P: queue-time run-parameters dialog */
.run-params-dialog { display: flex; flex-direction: column; gap: 1rem; }
.run-params-field { display: flex; flex-direction: column; gap: 0.25rem; }
.run-params-input { width: 100%; }
.run-params-actions { display: flex; gap: 0.5rem; justify-content: flex-end; margin-top: 0.5rem; }

/* PLAN-005 4.1: work-items kanban board */
.kanban-board { display: flex; gap: 1rem; overflow-x: auto; padding-bottom: 0.5rem; align-items: flex-start; }
.kanban-column { flex: 1 1 0; min-width: 15rem; background: var(--rz-base-200, rgba(128,128,128,0.06)); border-radius: 0.5rem; padding: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem; }
.kanban-column-header { display: flex; align-items: center; justify-content: space-between; padding: 0.25rem 0.5rem; font-weight: 600; }
.kanban-column-drop { min-height: 3rem; display: flex; flex-direction: column; gap: 0.5rem; border-radius: 0.375rem; transition: background-color 0.15s ease; }
.kanban-column-drop.kanban-drop-active { background: var(--rz-primary-lighter, rgba(64,128,255,0.15)); outline: 2px dashed var(--rz-primary, #4080ff); outline-offset: -2px; }
.kanban-card { cursor: grab; }
.kanban-card:active { cursor: grabbing; }
.kanban-card.kanban-card-dragging { opacity: 0.5; }
.kanban-card-title { font-weight: 600; }
.kanban-card-meta { display: flex; align-items: center; gap: 0.375rem; flex-wrap: wrap; margin-top: 0.375rem; }
.kanban-filter { min-width: 11rem; }
