/* ═══════════════════════════════════════════════════════════════════════
   PostRequest Dashboard — Styles
   Minimal, clean design system with glanceable health monitoring
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Design Tokens ────────────────────────────────────────────────────── */

:root {
    /* Colors */
    --color-text: #111;
    --color-text-muted: #666;
    --color-border: #e5e5e5;
    --color-bg-page: #f8f8f8;
    --color-bg-card: #fff;
    --color-bg-input: #fff;
    --color-bg-hover: #f8f8f8;

    /* Accents */
    --color-success: #10a37f;
    --color-error: #ef4444;
    --color-warning: #f59e0b;

    /* Spacing scale (4px base) */
    --spacing-1: 4px;
    --spacing-2: 8px;
    --spacing-3: 12px;
    --spacing-4: 16px;
    --spacing-5: 24px;
    --spacing-6: 32px;
    --spacing-7: 48px;

    /* Border radius */
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --radius-xl: 12px;

    /* Typography */
    --font-base: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif;

    /* Type scale */
    --font-size-xs: 0.625rem;   /* 10px */
    --font-size-sm: 0.75rem;    /* 12px */
    --font-size-base: 0.8125rem; /* 13px */
    --font-size-md: 0.875rem;   /* 14px */
    --font-size-lg: 1rem;       /* 16px */
    --font-size-xl: 1.125rem;   /* 18px */
    --font-size-2xl: 1.25rem;   /* 20px */

    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;

    /* Layout */
    --sidebar-width: 220px;
    --topbar-height: 56px;
}

/* ── Reset & Base ──────────────────────────────────────────────────────── */

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

html {
    font-size: 16px;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--font-base);
    font-size: var(--font-size-base);
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg-page);
}

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

a:hover {
    text-decoration: underline;
}

img {
    max-width: 100%;
    height: auto;
}

/* ── Typography ────────────────────────────────────────────────────────── */

h1, h2, h3, h4, h5, h6 {
    font-weight: var(--font-weight-semibold);
    line-height: 1.25;
    color: var(--color-text);
    margin-bottom: 0.5em;
}

h1 { font-size: var(--font-size-2xl); } /* 1.25rem ≈ 1.375rem */
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }

code, pre, .mono {
    font-family: var(--font-base);
}

.text-muted {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-normal);
    font-size: var(--font-size-base);
}

/* ── Color Utilities ───────────────────────────────────────────────────── */

.text-success { color: var(--color-success); }
.text-error, .text-danger { color: var(--color-error); }
.text-warning { color: var(--color-warning); }
.text-info { color: var(--color-text-muted); }

/* ── Layout ────────────────────────────────────────────────────────────── */

.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--sidebar-width);
    height: 100vh;
    background: var(--color-bg-card);
    color: var(--color-text);
    overflow-y: auto;
    z-index: 1000;
    transition: transform 0.3s ease;
    border-right: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
}

.sidebar-header {
    padding: var(--spacing-4);
    border-bottom: 1px solid var(--color-border);
}

.brand {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
}

.brand-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: var(--color-text);
    color: var(--color-bg-card);
    font-weight: 700;
    font-size: var(--font-size-sm);
    border-radius: var(--radius-lg);
    flex-shrink: 0;
}

.brand-text {
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
}

/* Navigation Links */
.nav-links {
    list-style: none;
    padding: var(--spacing-3) 0;
    flex: 1;
}

.nav-links li a {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-3);
    margin: var(--spacing-1) var(--spacing-2);
    color: var(--color-text-muted);
    text-decoration: none;
    transition: all 0.15s ease;
    font-size: var(--font-size-base);
    border-radius: var(--radius-md);
    position: relative;
}

.nav-links li a:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
    text-decoration: none;
}

.nav-links li a.active {
    background: var(--color-bg-hover);
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

.nav-links li a.active::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--color-text);
    border-radius: 0 2px 2px 0;
}

.nav-icon {
    font-size: var(--font-size-lg);
    width: 20px;
    text-align: center;
    color: inherit;
    flex-shrink: 0;
}

/* Count bubble on a nav item (e.g. total countable errors across clients).
   margin-left:auto pushes it to the right edge of the flex nav link. */
.nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 var(--spacing-1);
    margin-left: auto;
    background: var(--color-error);
    color: #fff;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    border-radius: 9px;
    flex-shrink: 0;
}

/* Amber variant for "needs attention" counts (e.g. unhealthy clients),
   distinct from the red error-count bubble. */
.nav-badge-warning {
    background: var(--color-warning);
}

/* Sidebar Footer */
.sidebar-footer {
    padding: var(--spacing-4);
    border-top: 1px solid var(--color-border);
    margin-top: auto;
}

.sidebar-user {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
}

.sidebar-user-email {
    flex: 1;
    font-size: var(--font-size-sm);
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sidebar-logout {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-md);
    background: var(--color-bg-hover);
    color: var(--color-text);
    text-decoration: none;
    flex-shrink: 0;
    transition: background 0.15s ease;
}

.sidebar-logout:hover {
    background: #e5e5e5;
    text-decoration: none;
}

/* Main Content Area */
.main-content {
    margin-left: var(--sidebar-width);
    min-height: 100vh;
}

.content-area {
    padding: var(--spacing-6);
}

/* Sidebar Toggle for Mobile */
.sidebar-toggle {
    display: none;
    position: fixed;
    top: var(--spacing-4);
    right: var(--spacing-4);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    color: var(--color-text);
    padding: var(--spacing-2);
    z-index: 1001;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* Sidebar Backdrop for Mobile */
.sidebar-backdrop {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    z-index: 999;
}

.sidebar-backdrop.active {
    display: block;
}

/* ── Dashboard Page ────────────────────────────────────────────────────── */

.dashboard-page {
    background: var(--color-bg-page);
}

/* ── Clients Page ──────────────────────────────────────────────────────── */

/* Filter Bar */
.clients-filter-bar {
    display: flex;
    gap: var(--spacing-3);
    align-items: center;
    padding: var(--spacing-4);
}

.filter-search {
    flex: 1;
    min-width: 200px;
    height: 36px;
    padding: var(--spacing-2) var(--spacing-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--font-size-base);
    font-family: var(--font-base);
    background: var(--color-bg-input);
    transition: border-color 0.15s ease;
    box-sizing: border-box;
}

.filter-search:focus {
    outline: none;
    border-color: var(--color-text-muted);
}

.filter-search::placeholder {
    color: var(--color-text-muted);
}

.filter-select {
    height: 36px;
    padding: var(--spacing-2) var(--spacing-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--font-size-base);
    font-family: var(--font-base);
    background: var(--color-bg-input);
    transition: border-color 0.15s ease;
    min-width: 140px;
    box-sizing: border-box;
}

.filter-select:focus {
    outline: none;
    border-color: var(--color-text-muted);
}

/* Errors page filter bar: search + filters share the row equally.
   Hidden (display:none) selects drop out of the flex flow, so the visible
   controls split the width 100% / 50% / 33% depending on how many show. */
.filter-bar-equal .filter-search,
.filter-bar-equal .filter-select {
    flex: 1 1 0;
    min-width: 0;
}

/* Clients Table */
.clients-table {
    font-size: var(--font-size-base);
}

.clients-table th {
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
    font-size: var(--font-size-sm);
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.clients-table .col-health {
    width: 60px;
}

.clients-table .col-client {
    min-width: 200px;
}

.clients-table .col-server {
    width: 120px;
}

.clients-table .col-php {
    width: 80px;
}

.clients-table .col-errors {
    width: 80px;
}

.clients-table .col-ssl {
    width: 80px;
}

.clients-table .col-last-seen {
    width: 120px;
}

.clients-table .col-digest {
    width: 50px;
    text-align: center;
}

/* The Update column is the only header that is both centered AND sortable, so its
   trailing sort-arrow would sit inside the centered content and push the "Update"
   label left of centre — leaving it misaligned with the single bell icon that is
   dead-centred in the body cells. Cancel the arrow's horizontal footprint (its
   0.9em width + 0.25em left margin) so the label stays centred over the icon; the
   arrow still shows, overhanging into the cell's right padding. */
.clients-table .col-digest .sort-arrow {
    margin-right: -1.15em;
}

.clients-table .col-diagnosis,
.clients-table .diagnosis-cell {
    text-align: center;
}

/* Sortable column headers */
.clients-table th.sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.clients-table th.sortable:hover {
    color: var(--color-text);
}

.clients-table th.sortable:focus {
    outline: 2px solid var(--color-success);
    outline-offset: -2px;
}

.clients-table th.sortable.sort-active {
    color: var(--color-text);
}

.clients-table th.sortable .sort-arrow {
    display: inline-block;
    width: 0.9em;
    margin-left: 0.25em;
    font-size: 0.85em;
    opacity: 0.5;
}

.clients-table th.sortable.sort-active .sort-arrow {
    opacity: 1;
}

/* Neutral affordance: hint an arrow on hover for inactive sortable headers */
.clients-table th.sortable:not(.sort-active):hover .sort-arrow::before {
    content: "\2195"; /* ↕ */
    opacity: 0.6;
}

/* Client Row Styles */
.client-row {
    cursor: pointer;
    transition: background-color 0.15s ease;
    border-left: 3px solid transparent;
}

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

/* Row health states with left border accent */
.client-row.row-error {
    border-left-color: var(--color-error);
}

.client-row.row-warning {
    border-left-color: var(--color-warning);
}

.client-row.row-healthy {
    border-left-color: transparent;
}

/* Neutral "checking / unknown" state — no colored line, like healthy. */
.client-row.row-neutral {
    border-left-color: transparent;
}

/* Health Indicator */
.health-indicator {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin: 0 auto;
}

.health-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    transition: background-color 0.15s ease;
}

.health-dot.health-healthy {
    background: var(--color-success);
}

.health-dot.health-error {
    background: var(--color-error);
}

.health-dot.health-warning {
    background: var(--color-warning);
}

/* Client Name & Project */
.client-domain {
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    margin-right: 6px;
}

.client-project-name {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    display: block;
}

/* Environment Badge */
.env-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px var(--spacing-2);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    line-height: 1.4;
}

.env-badge.env-production {
    background: #fef2f2;
    color: var(--color-error);
}

.env-badge.env-staging {
    background: #fffbeb;
    color: #92400e;
}

.env-badge.env-development {
    background: #ecfdf5;
    color: #065f46;
}

.env-badge.env-other {
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
}

/* User-defined client tags (from settings), shown inline in the client list.
   Same shape as the env badge; just a different (neutral blue) background so
   tags read as labels rather than the semantic env states. */
.client-tag-badge {
    display: inline-flex;
    align-items: center;
    margin-left: var(--spacing-1);
    padding: 2px var(--spacing-2);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    line-height: 1.4;
    background: #eff6ff;
    color: #1e40af;
}

/* Env & tag badges sit on their own row beneath the client name, wrapping as
   needed, so a client with several tags never widens the Client column. The gap
   controls spacing uniformly, so the badges' own inline margins are reset here. */
.client-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-1);
    margin-top: var(--spacing-1);
}

.client-badges .env-badge,
.client-badges .client-tag-badge {
    margin: 0;
}

/* Long server hostnames are truncated with an ellipsis so they never stretch the
   Server column; the full value stays available via the cell's title tooltip. */
.clients-table .server-name {
    display: inline-block;
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* Setup Modal Styles */
.setup-step {
    margin-bottom: var(--spacing-5);
}

.setup-step:last-child {
    margin-bottom: 0;
}

.setup-step-title {
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--spacing-2);
    color: var(--color-text);
}

.setup-step p {
    margin-bottom: var(--spacing-3);
}

/* Preflight items can contain long, unbreakable paths (no spaces, "/" doesn't
   break by default). Force them to wrap inside the card instead of clipping. */
.setup-step .form-group > .flex {
    align-items: flex-start;
}

/* Server Secret row: stretch the field and Copy button to equal height so the
   btn-sm button matches the padded .setup-secret field box (it sits shorter
   under the row's default top alignment). The button keeps its label centered
   via .btn's own inline-flex centering; the field keeps its own styling. */
.setup-step .form-group > .flex.setup-secret-row {
    align-items: stretch;
}

.setup-step .form-group > .flex > span:last-child {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Env / Software-update check rows put the badge in its own column and stack
   the message + remediation in this body column, so the remediation lines up
   under the message (not under the badge) regardless of badge width. */
.setup-step .form-group > .flex > .setup-check-body {
    flex: 1;
    min-width: 0;
}

/* Keep the PR #48 long-path wrap inside the card: the message line must still
   force-wrap unbreakable paths (the remediation wraps via .setup-step
   .text-muted below). */
.setup-step .setup-check-body > span {
    display: block;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.setup-step .text-muted {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Created/replaced path lists on the Software Update result card. */
.path-list {
    overflow-wrap: anywhere;
    word-break: break-word;
}

.setup-code-wrap {
    position: relative;
    margin-top: var(--spacing-3);
}

.setup-code-wrap .code-block {
    margin-bottom: var(--spacing-2);
    /* Both boxes now hold the real client library, so cap the pane and let it scroll
       rather than stretching the modal. Lines are NOT wrapped — long minified lines
       scroll horizontally, as they did before. */
    max-height: 320px;
    overflow-y: auto;
}

.setup-code-label {
    margin-top: var(--spacing-3);
    margin-bottom: 0;
    font-size: var(--font-size-sm);
}

.setup-code-label + .setup-code-wrap {
    margin-top: var(--spacing-2);
}

.setup-code-wrap .btn {
    margin-top: var(--spacing-2);
}

.setup-secret {
    display: inline-block;
    padding: var(--spacing-2) var(--spacing-3);
    background: var(--color-bg-hover);
    border-radius: var(--radius-md);
    font-family: var(--font-base);
    font-size: var(--font-size-sm);
    color: var(--color-text);
    user-select: all;
}

/* ── Auth Pages ────────────────────────────────────────────────────────── */

.auth-page {
    background: var(--color-bg-page);
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    flex-direction: column;
}

.auth-container {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: var(--spacing-5);
    width: 100%;
}

.auth-card {
    background: var(--color-bg-card);
    padding: 40px;
    border-radius: var(--radius-xl);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    max-width: 400px;
    width: 100%;
}

.auth-brand {
    text-align: center;
    margin-bottom: var(--spacing-5);
}

.auth-brand h1 {
    font-size: var(--font-size-2xl);
    margin-top: var(--spacing-3);
    color: var(--color-text);
}

.auth-card h2 {
    text-align: center;
    font-size: var(--font-size-xl);
    margin-bottom: var(--spacing-2);
}

.auth-subtitle {
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--font-size-base);
    margin-bottom: var(--spacing-5);
}

.auth-form {
    margin-top: var(--spacing-5);
}

.auth-links {
    display: flex;
    justify-content: space-between;
    margin-top: var(--spacing-5);
    padding-top: var(--spacing-4);
    border-top: 1px solid var(--color-border);
}

.inline-form {
    display: inline;
}

.link-btn {
    background: none;
    border: none;
    color: var(--color-text);
    cursor: pointer;
    font-size: var(--font-size-base);
    padding: 0;
    font-weight: var(--font-weight-medium);
}

.link-btn:hover {
    text-decoration: underline;
}

/* ── Cards ─────────────────────────────────────────────────────────────── */

.card {
    background: var(--color-bg-card);
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border);
    padding: var(--spacing-5);
    margin-bottom: var(--spacing-5);
}

.card h2 {
    margin-bottom: var(--spacing-4);
}

/* ── Forms ─────────────────────────────────────────────────────────────── */

.form-group {
    margin-bottom: var(--spacing-4);
}

#user-settings-step-code .form-group {
    margin-top: var(--spacing-5);
}

#user-settings-step-main h4:not(:first-child) {
    margin-top: var(--spacing-5);
}

.form-group label {
    display: block;
    font-weight: var(--font-weight-medium);
    margin-bottom: var(--spacing-2);
    font-size: var(--font-size-base);
    color: var(--color-text);
}

.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="password"],
.form-group input[type="number"],
.form-group input[type="url"],
.form-group input[type="date"],
.form-group select,
/* The one field that is not in a .form-group: it shares a row with two buttons,
   so it is laid out by .mailbox-add-sender instead. Without this it kept the
   browser's own input styling — no padding, no height, and the placeholder in
   the UA font rather than ours, which is what gave it away next to everything
   else in the dialogue. Listed here rather than restyled locally, so it cannot
   drift away from the fields it sits among. */
.mailbox-add-sender input[type="email"] {
    display: block;
    width: 100%;
    height: 36px;
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-base);
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg-input);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color 0.15s, box-shadow 0.15s;
    font-family: inherit;
    box-sizing: border-box;
}

/* Filter selects on a list header (settings → MCP activity). They stay on the
   header's one line and are held narrow: an option can be a whole email address
   or a long tool name, and a select left to size itself to its widest option
   pushes the buttons beside it off the row. Truncation is the browser's, which
   is why the full value is still there when the menu is open. */
.log-filter {
    max-width: 130px;
    min-width: 0;
    flex: 0 1 auto;
    text-overflow: ellipsis;
}

/* A button (or select) that shares a field's row belongs to that row, so it is
   the field's height — 36px, set above. Neither button size gets there on its
   own: .btn-sm lands ~5px short and a plain .btn ~3px over, and either way the
   control beside the input is visibly the wrong size for it. Opt-in by class
   rather than by matching every .form-group row, because a row can hold a
   control the browser sizes itself (a file input), and matching the styled
   fields' height there would only move the mismatch. */
.field-row > .btn,
.field-row > select {
    height: 36px;
}

/* Date inputs: WebKit lays the inner date fields (::-webkit-datetime-edit) out
   top-aligned inside a fixed height, so the text doesn't sit on the same
   vertical centre as the other inputs. Making the field a flex container
   centres it. */
.form-group input[type="date"] {
    display: flex;
    align-items: center;
}

.form-group textarea {
    display: block;
    width: 100%;
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-base);
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg-input);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color 0.15s, box-shadow 0.15s;
    font-family: inherit;
    box-sizing: border-box;
}

select {
    display: block;
    width: 100%;
    height: 36px;
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-base);
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg-input);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-family: inherit;
    transition: border-color 0.15s, box-shadow 0.15s;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--spacing-3) center;
    padding-right: var(--spacing-6);
    cursor: pointer;
    box-sizing: border-box;
}

select:focus {
    outline: none;
    border-color: var(--color-success);
    box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.1);
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus,
.mailbox-add-sender input[type="email"]:focus {
    outline: none;
    border-color: var(--color-success);
    box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.1);
}

.form-group-inline {
    display: flex;
    align-items: center;
}

.checkbox-label {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    cursor: pointer;
    font-weight: var(--font-weight-normal);
}

.checkbox-label input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--color-success);
}

.input-code {
    font-family: var(--font-base);
    font-size: var(--font-size-2xl) !important;
    text-align: center;
    letter-spacing: 0.5em;
    padding: 14px !important;
}

/* ── Buttons ───────────────────────────────────────────────────────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-2) var(--spacing-4);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: all 0.15s ease;
    font-family: inherit;
    gap: var(--spacing-2);
    white-space: nowrap;
}

.btn:hover {
    text-decoration: none;
}

.btn:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: 2px;
}

.btn-sm {
    padding: var(--spacing-1) var(--spacing-3);
    font-size: var(--font-size-base);
}

.btn-primary {
    background: var(--color-text);
    color: var(--color-bg-card);
    border-color: var(--color-text);
}

.btn-primary:hover {
    background: #2b2b2b;
    border-color: #2b2b2b;
}

.btn-danger {
    background: var(--color-error);
    color: var(--color-bg-card);
    border-color: var(--color-error);
}

.btn-danger:hover {
    background: #dc2626;
    border-color: #dc2626;
}

.btn-success {
    background: var(--color-success);
    color: var(--color-bg-card);
    border-color: var(--color-success);
}

.btn-success:hover {
    background: #0d8a6a;
    border-color: #0d8a6a;
}

.btn-outline {
    background: transparent;
    color: var(--color-text-muted);
    border-color: var(--color-border);
}

.btn-outline:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
    border-color: #d1d1d1;
}

select.btn {
    height: auto;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--spacing-2) center;
    padding-right: var(--spacing-6);
}

.btn:disabled,
.btn[disabled] {
    opacity: 0.35;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-block {
    display: block;
    width: 100%;
}

/* ── Alerts ────────────────────────────────────────────────────────────── */

.alert {
    padding: var(--spacing-3) var(--spacing-4);
    border-radius: var(--radius-md);
    font-size: var(--font-size-base);
    margin-bottom: var(--spacing-4);
}

.alert-error {
    background: #fef2f2;
    color: var(--color-error);
    border: 1px solid #fecaca;
}

.alert-success {
    background: #ecfdf5;
    color: #065f46;
    border: 1px solid #a7f3d0;
}

.alert-info {
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
}

.alert-warning {
    background: #fffbeb;
    color: #92400e;
    border: 1px solid #fde68a;
}

/* Licensed-client-limit notice: message on the left, "License" button pinned to
   the right of the box. .hidden wins over this (it is !important). */
#clientLimitNotice {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-4);
}

#clientLimitNotice .btn {
    flex-shrink: 0;
}

/* ── Flash Messages ────────────────────────────────────────────────────── */

.flash {
    padding: var(--spacing-3) 40px var(--spacing-3) var(--spacing-4);
    margin: var(--spacing-4) var(--spacing-6) 0;
    border-radius: var(--radius-md);
    font-size: var(--font-size-base);
    position: relative;
}

.flash-success {
    background: #ecfdf5;
    color: #065f46;
    border-bottom: 1px solid #a7f3d0;
}

.flash-error {
    background: #fef2f2;
    color: var(--color-error);
    border-bottom: 1px solid #fecaca;
}

.flash-info {
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-border);
}

.flash-warning {
    background: #fffbeb;
    color: #92400e;
    border-bottom: 1px solid #fde68a;
}

.flash-centered {
    position: fixed;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2000;
    min-width: 300px;
    text-align: center;
    border: 1px solid var(--color-border);
    margin: 0;
}

.flash-close {
    position: absolute;
    right: var(--spacing-3);
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    font-size: var(--font-size-xl);
    cursor: pointer;
    color: inherit;
    opacity: 0.5;
    line-height: 1;
}

.flash-close:hover {
    opacity: 1;
}

/* ── Tables ────────────────────────────────────────────────────────────── */

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-base);
}

.table th,
.table td {
    padding: var(--spacing-3) var(--spacing-4);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    /* Long unbreakable cell content — full URLs, long error messages, API tokens,
       license IDs, domain hostnames — would otherwise force a table wider than its
       container and require left/right scrolling (inside .table-responsive where
       present, or widening the whole card/page where there is no wrapper). Let such
       content break so every table reflows to fit. `anywhere` (not `break-word`)
       because only it shrinks the cell's min-content width, which is what actually
       stops the table demanding extra width. Cells that opt into white-space:nowrap
       (short dates, badges, headers, fixed tree columns) are unaffected. */
    overflow-wrap: anywhere;
}

.table th {
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    background: transparent;
    /* Column headers are short labels and must stay on one line — the cells'
       overflow-wrap:anywhere (inherited from the .table th,td rule above) would
       otherwise let them break. Overrides that only for headers, not body cells. */
    white-space: nowrap;
}

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

/* ── Status Dots ───────────────────────────────────────────────────────── */

.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: var(--spacing-2);
}

.status-online { background: var(--color-success); }
.status-offline { background: var(--color-error); }
.status-error { background: var(--color-error); }
.status-warning { background: var(--color-warning); }

/* ── Client Metadata Strip ────────────────────────────────────────────── */

.client-meta-strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1) var(--spacing-5);
    margin-bottom: var(--spacing-4);
    padding: var(--spacing-3) var(--spacing-4);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

.client-meta-item {
    display: flex;
    align-items: baseline;
    gap: var(--spacing-2);
}

.client-meta-label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    white-space: nowrap;
}

.client-meta-value {
    font-size: var(--font-size-base);
    color: var(--color-text);
}

/* ── Tabs ──────────────────────────────────────────────────────────────── */

.tabs {
    display: flex;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--spacing-5);
    gap: 0;
}

.tab {
    padding: var(--spacing-2) var(--spacing-4);
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: all 0.15s ease;
    background: none;
    border-top: none;
    border-left: none;
    border-right: none;
    font-family: inherit;
}

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

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

.tab.active {
    color: var(--color-text);
    border-bottom-color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

/* ── Code Blocks ───────────────────────────────────────────────────────── */

pre, .code-block {
    background: var(--color-text);
    color: var(--color-border);
    padding: var(--spacing-4);
    border-radius: var(--radius-lg);
    overflow-x: auto;
    font-size: var(--font-size-base);
    line-height: 1.6;
    font-family: var(--font-base);
}

code {
    background: var(--color-bg-hover);
    padding: 2px var(--spacing-2);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-base);
}

pre code {
    background: none;
    padding: 0;
}

/* ── Modals ────────────────────────────────────────────────────────────── */

.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    z-index: 1500;
    display: none;
    align-items: center;
    justify-content: center;
}

.modal-overlay.active {
    display: flex;
}

.modal {
    background: var(--color-bg-card);
    border-radius: var(--radius-xl);
    border: 1px solid var(--color-border);
    max-width: 600px;
    width: 90%;
    max-height: 80vh;
    overflow-y: auto;
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-4) var(--spacing-5);
    border-bottom: 1px solid var(--color-border);
}

.modal-header h3 {
    margin: 0;
}

.modal-close:not(.btn) {
    background: none;
    border: none;
    font-size: var(--font-size-2xl);
    cursor: pointer;
    color: var(--color-text-muted);
    line-height: 1;
}

.modal-close:not(.btn):hover {
    color: var(--color-text);
}

.modal-close:not(.btn):focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: 2px;
}

.modal-body {
    padding: var(--spacing-5);
}

.modal-footer {
    padding: var(--spacing-4) var(--spacing-5);
    border-top: 1px solid var(--color-border);
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-3);
}

/* ── Toast Notifications ───────────────────────────────────────────────── */

#toast-container {
    position: fixed;
    bottom: var(--spacing-5);
    right: var(--spacing-5);
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.toast {
    padding: var(--spacing-3) var(--spacing-4);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-base);
    border: 1px solid var(--color-border);
    animation: toastIn 0.3s ease;
    max-width: 400px;
    color: var(--color-bg-card);
}

.toast-success { background: var(--color-success); border-color: var(--color-success); }
.toast-error { background: var(--color-error); border-color: var(--color-error); }
.toast-info { background: var(--color-text); border-color: var(--color-text); }
.toast-warning { background: var(--color-warning); border-color: var(--color-warning); color: var(--color-text); }

@keyframes toastIn {
    from {
        opacity: 0;
        transform: translateY(var(--spacing-3));
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes toastOut {
    from {
        opacity: 1;
        transform: translateY(0);
    }
    to {
        opacity: 0;
        transform: translateY(var(--spacing-3));
    }
}

/* ── Loading Spinner ───────────────────────────────────────────────────── */

.spinner {
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-text);
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
}

.spinner-lg {
    width: 40px;
    height: 40px;
    border-width: 3px;
}

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

.loading-center {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 12px;
    padding: 40px;
    text-align: center;
}

.spinner-inline {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-text);
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
    vertical-align: middle;
}

/* ── Transfer Progress Bar ────────────────────────────────────────────── */

.transfer-progress {
    text-align: center;
    padding: var(--spacing-4) 0;
}

.progress-bar-wrap {
    width: 100%;
    max-width: 300px;
    height: 6px;
    background: var(--color-border);
    border-radius: 3px;
    overflow: hidden;
    margin: 0 auto var(--spacing-2);
}

.progress-bar-fill {
    height: 100%;
    background: var(--color-text);
    border-radius: 3px;
    transition: width 0.3s ease;
    width: 0%;
}

.progress-text {
    font-size: var(--font-size-sm);
    margin: 0;
}

.progress-cancel-btn {
    margin-top: var(--spacing-2);
}

/* ── Badges ───────────────────────────────────────────────────────────── */

.badge {
    display: inline-block;
    padding: 2px var(--spacing-2);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    border-radius: var(--radius-sm);
    line-height: 1.5;
    /* Badges are atomic pill labels — error-type tags (E_WARNING, TypeError…),
       counts, statuses. They must never break mid-token, which the table cells'
       overflow-wrap:anywhere would otherwise allow. */
    white-space: nowrap;
}

/* A PHP version number (e.g. 8.1.29) is a single atomic token and must not wrap
   between its dot-separated parts, which the table cells' overflow-wrap:anywhere
   would otherwise permit. */
.php-version {
    white-space: nowrap;
}

.badge-success {
    background: #ecfdf5;
    color: #065f46;
}

.badge-danger {
    background: #fef2f2;
    color: var(--color-error);
}

.badge-critical {
    background: #b91c1c;
    color: #fff;
}

.badge-warning {
    background: #fffbeb;
    color: #92400e;
}

.badge-info {
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
}

.badge-muted {
    background: var(--color-bg-hover);
    color: var(--color-text-muted);
    opacity: 0.7;
}

/* DNS overview link — clickable rows in heartbeat overview */
.dns-overview-link {
    cursor: pointer;
}

.dns-overview-link:hover {
    opacity: 0.7;
}

/* ── Utility Classes ───────────────────────────────────────────────────── */

/* Display */
.hidden,
.d-none {
    display: none !important;
}

/* Spacing */
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: var(--spacing-2); }
.mb-2 { margin-bottom: var(--spacing-4); }
.mb-3 { margin-bottom: var(--spacing-5); }
.mb-4 { margin-bottom: var(--spacing-6); }
.mb-5 { margin-bottom: var(--spacing-7); }
.mt-1 { margin-top: var(--spacing-2); }
.mt-2 { margin-top: var(--spacing-4); }
.mt-3 { margin-top: var(--spacing-5); }

/* Text alignment */
.text-center { text-align: center; }
.text-right { text-align: right; }

/* Flexbox */
.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.flex-between { display: flex; justify-content: space-between; align-items: center; }
.items-end { align-items: flex-end; }
.items-center { align-items: center; }
.self-end { align-self: flex-end; }
.gap-1 { gap: var(--spacing-2); }
.gap-2 { gap: var(--spacing-4); }

/* ── Filter Bar ────────────────────────────────────────────────────────── */

.filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--spacing-4);
}

.filter-bar .form-group {
    flex: 1;
    min-width: 140px;
    margin-bottom: 0;
}

.filter-bar .form-group:first-child {
    min-width: 200px;
}

/* ── Card Table ────────────────────────────────────────────────────────── */

.card-table {
    padding: 0;
    overflow-x: auto;
}

.table-responsive {
    overflow-x: auto;
}

/* ── Empty State ───────────────────────────────────────────────────────── */

.empty-state {
    padding: 40px var(--spacing-5);
    text-align: center;
    color: var(--color-text-muted);
}

/* ── Setup Steps (Add Client modal) ────────────────────────────────────── */

.setup-step-title {
    font-size: var(--font-size-md);
    margin-bottom: var(--spacing-2);
}

.setup-code-wrap {
    position: relative;
}

.setup-code-wrap .btn {
    position: absolute;
    top: var(--spacing-2);
    right: var(--spacing-2);
    background: var(--color-bg-card);
    color: var(--color-text);
}

.setup-secret {
    flex: 1;
    background: var(--color-bg-hover);
    padding: var(--spacing-2) var(--spacing-3);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    font-size: var(--font-size-base);
    word-break: break-all;
}

/* ── Modal Sizes ───────────────────────────────────────────────────────── */

.modal-lg {
    max-width: 700px;
}

/* ── Compare Page ──────────────────────────────────────────────────────── */

/* Compare Table Columns */
.col-compare-field { width: 25%; }
.col-compare-value { width: 35%; }
.col-compare-status { width: 5%; }

.compare-selectors {
    display: flex;
    align-items: flex-end;
    gap: var(--spacing-4);
    flex-wrap: wrap;
}

.compare-selector {
    flex: 1;
    min-width: 200px;
}

.compare-selector .form-group {
    margin-bottom: 0;
}

.compare-vs {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-muted);
    padding-bottom: var(--spacing-2);
    flex-shrink: 0;
}

.compare-action {
    padding-bottom: 0;
    flex-shrink: 0;
}

.diff-match td {
    background: transparent;
}

.diff-mismatch td {
    background: #fffbeb;
}

.diff-mismatch td:nth-child(2) {
    background: #fef2f2;
}

.diff-mismatch td:nth-child(3) {
    background: #ecfdf5;
}

.diff-status-icon {
    text-align: center;
    font-size: var(--font-size-lg);
}

/* Highlight items unique to one side (extensions not in the other) */
.diff-item-unique {
    background: #fef08a;
    border-radius: 3px;
    padding: 1px 4px;
}

/* Highlight items present in both but with different values (ini settings) */
.diff-item-changed {
    background: #fed7aa;
    border-radius: 3px;
}

/* INI settings diff layout */
.diff-ini-list {
    font-size: var(--font-size-sm);
    font-family: var(--font-base);
}

.diff-ini-row {
    display: flex;
    gap: var(--spacing-2);
    padding: 2px 0;
    border-bottom: 1px solid rgba(0,0,0,0.04);
}

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

.diff-ini-row.diff-item-unique,
.diff-ini-row.diff-item-changed {
    padding: 2px 4px;
    margin: 0 -4px;
}

.diff-ini-key {
    color: var(--color-text-muted);
    flex-shrink: 0;
    min-width: 180px;
}

.diff-ini-val {
    word-break: break-all;
}

/* ── Users Page ────────────────────────────────────────────────────────── */

.user-actions {
    display: flex;
    gap: var(--spacing-2);
    justify-content: flex-end;
}

/* ── Settings Page ─────────────────────────────────────────────────────── */

.readonly-field {
    background: var(--color-bg-hover);
    padding: var(--spacing-2) var(--spacing-3);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    font-size: var(--font-size-base);
    word-break: break-all;
}

/* Revealed secret is a 64-char hex string. Keep it on a single line that
   scrolls horizontally rather than wrapping, so the Secret field stays the
   same height as the Server ID field (masked or revealed) and the row's
   action buttons don't stretch. */
#settings-secret {
    white-space: nowrap;
    overflow-x: auto;
    word-break: normal;
}

/* Server Version row: field + button share one stretched flex row so the
   button matches the read-only field height. */
.server-version-row {
    display: flex;
    gap: var(--spacing-2);
}

.server-version-row .readonly-field {
    flex: 1;
}

/* Server Info actions: the Show / Regenerate buttons live in a label-less
   form-group inside the flex-end .filter-bar, so the smaller btn-sm vertical
   padding leaves them shorter than the adjacent Server ID / Secret read-only
   fields. Give them the field's vertical padding so each button box equals the
   field box height (tops and bottoms line up), keeping them side by side. */
.settings-info-actions {
    display: flex;
    gap: var(--spacing-2);
}

.settings-info-actions .btn {
    padding-top: var(--spacing-2);
    padding-bottom: var(--spacing-2);
}

/* Licensing summary rows.

   Equal columns: the default .filter-bar rule sizes a group by a content floor
   (140px, and 200px for the first), so the three fields on the top row came out
   at three different widths depending on how long the edition name and licence
   id happened to be. Basis zero with the floor cleared makes them exact thirds,
   and makes the single field on rows two and three fill the width.

   Truncate, do not wrap: .readonly-field breaks on any character so a long
   licence id or customer name became a two-line box, leaving the row ragged and
   its labels no longer on one baseline. These fields keep their line and clip
   with an ellipsis; the view puts the full value on the title. */
.filter-bar.license-fields .form-group,
.filter-bar.license-fields .form-group:first-child {
    flex: 1 1 0;
    min-width: 0;
}

.license-fields .readonly-field {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: normal;
}

/* ── Framework Rule Cards ──────────────────────────────────────────────── */

.rule-card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--spacing-3);
    background: var(--color-bg-card);
    transition: opacity 0.2s;
}

.rule-card.dragging {
    opacity: 0.5;
}

.rule-card.drag-over {
    border-top: 2px solid var(--color-success);
}

.rule-card-header {
    display: flex;
    align-items: center;
    padding: var(--spacing-3) var(--spacing-4);
    cursor: pointer;
    gap: var(--spacing-2);
    user-select: none;
    border-bottom: 1px solid transparent;
}

.rule-card.expanded .rule-card-header {
    border-bottom-color: var(--color-border);
}

.rule-card-drag {
    cursor: grab;
    color: #d1d1d1;
    font-size: var(--font-size-xl);
    padding: 2px var(--spacing-1);
    line-height: 1;
}

.rule-card-drag:active {
    cursor: grabbing;
}

.rule-card-chevron {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    transition: transform 0.2s;
    flex-shrink: 0;
}

.rule-card.expanded .rule-card-chevron {
    transform: rotate(90deg);
}

.rule-card-title {
    flex: 1;
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-base);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rule-card-title.empty {
    color: #d1d1d1;
    font-style: italic;
}

.rule-card-remove {
    background: none;
    border: none;
    color: #d1d1d1;
    font-size: var(--font-size-xl);
    cursor: pointer;
    padding: 2px var(--spacing-2);
    line-height: 1;
    border-radius: var(--radius-sm);
    transition: color 0.15s, background 0.15s;
}

.rule-card-remove:hover {
    color: var(--color-error);
    background: #fef2f2;
}

.rule-card-body {
    display: none;
    padding: var(--spacing-4);
}

.rule-card.expanded .rule-card-body {
    display: block;
}

/* Tag Inputs */
.tag-input-wrap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    min-height: 40px;
    cursor: text;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.tag-input-wrap:focus-within {
    border-color: var(--color-success);
    box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.1);
}

.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    background: var(--color-bg-hover);
    color: var(--color-text);
    padding: 2px var(--spacing-2);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-base);
    font-family: var(--font-base);
    line-height: 1.5;
    border: 1px solid var(--color-border);
}

.tag-chip-remove {
    background: none;
    border: none;
    color: var(--color-text-muted);
    cursor: pointer;
    font-size: var(--font-size-md);
    padding: 0 2px;
    line-height: 1;
    opacity: 0.5;
}

.tag-chip-remove:hover {
    opacity: 1;
}

.tag-input-field {
    border: none;
    outline: none;
    font-size: var(--font-size-base);
    font-family: inherit;
    min-width: 120px;
    flex: 1;
    padding: 2px 0;
    background: transparent;
}

/* ── Client-specific Styles ────────────────────────────────────────────── */

.expand-icon {
    display: inline-block;
    font-size: var(--font-size-sm);
    transition: transform 0.2s;
    cursor: pointer;
}

.client-row td {
    cursor: pointer;
}

.client-project-name {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-normal);
    color: var(--color-text-muted);
    line-height: 1.4;
}

.error-file-line {
    font-family: var(--font-base);
    font-size: var(--font-size-base);
    word-break: break-all;
}

.error-row:hover {
    background: var(--color-bg-hover);
}

/* ── Error Detail Modal ────────────────────────────────────────────────── */

.error-detail-modal {
    max-width: 900px;
    width: 92%;
    min-height: 60vh;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
}

.error-detail-modal .modal-header {
    flex-shrink: 0;
}

.error-detail-modal .modal-body {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}

.error-detail-title {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    min-width: 0;
    flex: 1;
}

.error-detail-title .badge {
    flex-shrink: 0;
}

.error-detail-title .error-detail-msg {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-md);
}

.error-detail-tabs {
    margin-bottom: 0;
    padding: 0 var(--spacing-5);
    flex-shrink: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
}
.error-detail-tabs .tab {
    flex-shrink: 0;
    white-space: nowrap;
    /* Drop the 1px underline overhang: the tabs row has overflow-x:auto (which
       also clips vertically), so the overhang was trimming the 2px underline to
       ~1px. Without it the full underline shows, flush on the baseline. */
    margin-bottom: 0;
}
/* Match the subtabs' active weight (600) so Diagnosis reads like Summary. */
.error-detail-tabs .tab.active {
    font-weight: var(--font-weight-semibold);
}

.error-detail-content {
    padding: var(--spacing-4) var(--spacing-5);
    overflow-y: auto;
    flex: 1;
    display: flex;
    flex-direction: column;
}

.error-detail-content a {
    color: var(--color-text);
    text-decoration: none;
}

.error-detail-content a:hover {
    text-decoration: underline;
}

/* Clickable file reference inside the raw stack-trace dump */
.trace-raw-file-link {
    color: inherit;
    text-decoration: underline;
    text-decoration-style: dotted;
    cursor: pointer;
}

.trace-raw-file-link:hover {
    text-decoration-style: solid;
}

/* Stack level badge before a file in the 'Stack trace files' list */
.trace-level-badge {
    flex: 0 0 auto;
    font-family: var(--font-mono, monospace);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    background: var(--color-bg-hover);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 1px 5px;
}

.error-detail-content .kv-table {
    width: 100%;
    border-collapse: collapse;
}

.error-detail-content .kv-table th {
    text-align: left;
    padding: var(--spacing-2) var(--spacing-3) var(--spacing-2) 0;
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
    vertical-align: top;
    width: 160px;
    font-size: var(--font-size-sm);
    border-bottom: 1px solid #f0f0f0;
}

.error-detail-content .kv-table td {
    padding: var(--spacing-2) 0;
    word-break: break-word;
    border-bottom: 1px solid #f0f0f0;
    font-size: var(--font-size-sm);
}

.error-detail-content .kv-table tr:last-child th,
.error-detail-content .kv-table tr:last-child td {
    border-bottom: none;
}

.error-detail-content pre {
    margin: 0;
    font-size: var(--font-size-sm);
    max-height: 400px;
    overflow: auto;
}

.error-detail-content .detail-section {
    margin-top: var(--spacing-4);
}

/* ── Diagnosis report ─────────────────────────────────────── */
.error-detail-content #diagnosisTabBody {
    flex: 1;
    display: flex;
    flex-direction: column;
}
.error-detail-content .diagnosis-report {
    margin-top: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
}
.diagnosis-subtab-bar {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    border-bottom: 1px solid var(--color-border);
    /* Generous gap below the bar; it is a plain margin so it scrolls away with
       the content (not pinned to the bar). */
    margin-bottom: var(--spacing-5);
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--color-bg-card);
    /* Fill the gap ABOVE the bar (the scroll container's top padding) with white
       while stuck, so scrolling content can't show between the main tabs and the
       subtabs. It's clipped at the scroll container's top edge, so it never
       reaches (or covers) the main tab row above it. */
    box-shadow: 0 calc(-1 * var(--spacing-4)) 0 var(--color-bg-card);
}
.diagnosis-subtabs {
    display: flex;
    flex: 1;
    flex-wrap: wrap;
    gap: var(--spacing-1);
}
.diagnosis-subtab {
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    padding: var(--spacing-2) var(--spacing-3);
    margin-bottom: -1px;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    cursor: pointer;
    white-space: nowrap;
}
.diagnosis-subtab:hover {
    color: var(--color-text);
}
.diagnosis-subtab.active {
    color: var(--color-text);
    border-bottom-color: var(--color-text);
    font-weight: 600;
}
.diagnosis-copy-btn,
.diagnosis-fullcopy-btn {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 2px var(--spacing-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    cursor: pointer;
}
.diagnosis-copy-btn:hover,
.diagnosis-fullcopy-btn:hover {
    color: var(--color-text);
    border-color: var(--color-text);
}
/* Clarify: black call-to-action in the subtab bar. "Back to report" (the clarify
   header's action) uses the same style. */
.diagnosis-clarify-btn,
.diagnosis-clarify-close {
    flex: 0 0 auto;
    background: var(--color-text);
    border: 1px solid var(--color-text);
    border-radius: var(--radius-sm);
    padding: 2px var(--spacing-2);
    font-size: var(--font-size-sm);
    color: #fff;
    cursor: pointer;
}
.diagnosis-clarify-btn:hover,
.diagnosis-clarify-close:hover {
    background: #2b2b2b;
    border-color: #2b2b2b;
}

/* Clarify chat */
.diagnosis-clarify {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    flex: 1 1 auto;
    min-height: 0; /* allow the thread to scroll instead of overflowing */
}
.diagnosis-clarify-head {
    /* Rendered as a single-tab .diagnosis-subtab-bar (styling inherited from it);
       the .diagnosis-clarify flex gap provides spacing, so drop its bottom margin. */
    margin-bottom: 0;
}
.diagnosis-clarify-tab {
    cursor: default; /* the single "Clarify this diagnosis" tab is a label, not clickable */
}
.diagnosis-chat-thread {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    flex: 1 1 auto;
    min-height: 0;      /* the scroll area — grows to fill, never caps content */
    overflow-y: auto;
    padding: var(--spacing-1);
}
.diagnosis-chat-msg {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-width: 92%;
}
.diagnosis-chat-user {
    align-self: flex-end;
    align-items: flex-end;
}
.diagnosis-chat-ai {
    align-self: flex-start;
    align-items: flex-start;
}
.diagnosis-chat-role {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}
.diagnosis-chat-bubble {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-2) var(--spacing-3);
    line-height: 1.55;
    word-break: break-word;
}
/* Click-to-copy affordance for chat message bubbles. */
.diagnosis-chat-bubble[data-copy-raw] {
    cursor: pointer;
}
.diagnosis-chat-ai .diagnosis-chat-bubble {
    background: var(--color-bg-card);
}
.diagnosis-chat-user .diagnosis-chat-bubble {
    background: var(--color-text);
    border-color: var(--color-text);
    color: #fff;
}
/* Markdown inside a chat bubble — mirrors the report pane so numbered/bulleted
   lists keep their markers INSIDE the bubble and long content wraps cleanly. */
.diagnosis-chat-bubble .md-p { margin: 0 0 var(--spacing-2); }
.diagnosis-chat-bubble .md-p:first-child { margin-top: 0; }
.diagnosis-chat-bubble .md-p:last-child { margin-bottom: 0; }
.diagnosis-chat-bubble .md-h {
    margin: var(--spacing-3) 0 var(--spacing-1);
    font-size: var(--font-size-md);
}
.diagnosis-chat-bubble .md-list {
    margin: 0 0 var(--spacing-2);
    padding-left: var(--spacing-5); /* room for the marker inside the box */
}
.diagnosis-chat-bubble .md-list:last-child { margin-bottom: 0; }
.diagnosis-chat-bubble .md-list li { margin-bottom: 2px; }
.diagnosis-chat-ai .diagnosis-chat-bubble code {
    background: var(--color-bg-hover);
    color: var(--color-text);
    padding: 1px 4px;
    border-radius: var(--radius-sm);
    font-family: monospace;
    font-size: 0.92em;
}
.diagnosis-chat-user .diagnosis-chat-bubble code {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    padding: 1px 4px;
    border-radius: var(--radius-sm);
    font-family: monospace;
    font-size: 0.92em;
}
.diagnosis-chat-ai .diagnosis-chat-bubble .md-pre {
    background: var(--color-bg-hover);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-2) var(--spacing-3);
    overflow-x: auto;
    margin: 0 0 var(--spacing-2);
    cursor: pointer; /* click to copy just this code block */
}
.diagnosis-chat-ai .diagnosis-chat-bubble .md-pre:last-child { margin-bottom: 0; }
.diagnosis-chat-ai .diagnosis-chat-bubble .md-pre code {
    background: none;
    padding: 0;
    font-size: var(--font-size-sm);
}
/* Keep the highlight.js theme's token colours but drop its own block background/
   padding so the code sits on our .md-pre surface. */
.diagnosis-chat-bubble .md-pre code.hljs { background: none; padding: 0; }
/* Markdown tables. display:block + overflow-x lets a wide table scroll inside the bubble. */
.diagnosis-chat-bubble .md-table {
    display: block;
    width: fit-content;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    margin: 0 0 var(--spacing-2);
    font-size: var(--font-size-sm);
}
.diagnosis-chat-bubble .md-table:last-child { margin-bottom: 0; }
.diagnosis-chat-bubble .md-table th,
.diagnosis-chat-bubble .md-table td {
    border: 1px solid var(--color-border);
    padding: var(--spacing-1) var(--spacing-2);
    text-align: left;
}
.diagnosis-chat-bubble .md-table thead th {
    background: var(--color-bg-hover);
    font-weight: 600;
}
.diagnosis-chat-bubble .md-quote {
    margin: 0 0 var(--spacing-2);
    padding: var(--spacing-1) var(--spacing-3);
    border-left: 3px solid var(--color-border);
    color: var(--color-text-muted);
}
.diagnosis-chat-bubble .md-quote:last-child { margin-bottom: 0; }
.diagnosis-chat-bubble .md-quote .md-p:last-child { margin-bottom: 0; }
.diagnosis-chat-bubble .md-hr {
    border: none;
    border-top: 1px solid var(--color-border);
    margin: var(--spacing-3) 0;
}
/* A message typed while the assistant is still answering: shown greyed at the end
   of the thread until the current turn finishes, then sent as one combined turn. */
/* Space between the Stop (abort) and Send/Queue buttons in the composer actions. */
#explainAbort, .diagnosis-clarify-abort { margin-right: var(--spacing-2); }
.explain-queued, .clarify-queued { opacity: 0.5; cursor: pointer; }
/* While inline-editing a queued message it's fully opaque and not a click target. */
.explain-queued.queued-editing, .clarify-queued.queued-editing { opacity: 1; cursor: default; }
/* The textarea edits directly inside the message bubble (which keeps its own
   background/padding), so it has no chrome of its own. */
.queued-edit-input {
    width: 100%;
    box-sizing: border-box;
    resize: none;          /* height is driven by auto-grow, not the drag handle */
    overflow: hidden;
    display: block;
    font: inherit;
    color: inherit;
    background: transparent;
    border: none;
    padding: 0;
    outline: none;
}
.queued-edit-actions {
    display: flex;
    gap: var(--spacing-2);
    margin-top: var(--spacing-2);
}
/* White Save button (not the default black primary). */
.queued-edit-save {
    background: var(--color-bg-card);
    color: var(--color-text);
    border-color: var(--color-border);
}
.queued-edit-save:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
}
.explain-queued .diagnosis-chat-role::after,
.clarify-queued .diagnosis-chat-role::after {
    content: ' · queued';
    color: var(--color-text-muted);
    font-weight: 400;
}
.diagnosis-chat-update {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    margin-top: var(--spacing-2);
    flex-wrap: wrap;
}
.diagnosis-chat-update-hint {
    font-size: var(--font-size-sm);
}
.diagnosis-clarify-composer {
    border-top: 1px solid var(--color-border);
    /* Blank line between the last message and the bar above the input. */
    margin-top: var(--spacing-4);
    padding-top: var(--spacing-3);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}
.diagnosis-clarify-composer-head {
    font-weight: 600;
}
.diagnosis-clarify-intro {
    margin: 0 0 var(--spacing-2);
    font-size: var(--font-size-sm);
}
.diagnosis-clarify-input {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-2);
    font: inherit;
    background: var(--color-bg-input);
    color: var(--color-text);
}
.diagnosis-clarify-input:focus {
    outline: none;
    border-color: var(--color-text);
}
.diagnosis-clarify-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    margin-top: var(--spacing-2);
}

/* Running cost of the current chat conversation (Explain + Clarify), left of Send. */
.explain-cost {
    margin-right: auto;
    font-size: var(--font-size-sm);
}
/* Per-turn client context for the global Explain chat. Sits between the model
   picker and Send; auto-reflects the client the agent resolved for the last turn
   and stays overridable. Styled lighter (muted text, page-tinted background) so it
   reads as a secondary status/override control rather than a primary action. */
.explain-context-select {
    max-width: 180px;
    font-size: var(--font-size-base);
    line-height: 1.5;
    padding: var(--spacing-1) var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    background: var(--color-bg-input); /* white text + bg, matching the model dropdown */
    /* height:auto releases the global `select{height:36px}` so align-self:stretch
       matches this control to the Send button's height in the actions row. */
    height: auto;
    align-self: stretch;
    margin-right: var(--spacing-2);
}
/* Per-message model picker (Explain + Clarify), sits just left of Send and matches
   the Send button's height exactly (same box metrics as .btn-sm, border-box). */
.explain-model {
    max-width: 220px;
    font-size: var(--font-size-base);
    line-height: 1.5;
    padding: var(--spacing-1) var(--spacing-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    /* height:auto releases the global `select{height:36px}` so align-self:stretch
       can match this control to the Send button's height in the actions row. */
    height: auto;
    align-self: stretch;
    margin-right: var(--spacing-2);
}
/* Rendered ```mermaid diagram in a chat answer (SVG swapped in by flushMermaid();
   the <pre> source shows as a fallback until then / if rendering fails). */
.mermaid-diagram {
    overflow-x: auto;
    margin: var(--spacing-2) 0;
    text-align: center;
}
.mermaid-diagram svg {
    max-width: 100%;
    height: auto;
    cursor: pointer; /* click to download as SVG */
}
/* Live tool-call / reasoning step feed shown while the agent works, rendered
   client-side from the step/exec loop's local steps. */
.explain-progress {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.explain-progress-step {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}
.explain-progress-step.active {
    color: var(--color-text);
}
.explain-progress-tick {
    color: var(--color-success);
    font-weight: 600;
}
/* Per-message tokens + cost, shown under an agent answer. */
.explain-msg-usage {
    font-size: var(--font-size-xs);
    margin-top: 4px;
}

/* Explain chat (global nav view + client tab) */
.explain-layout {
    display: flex;
    gap: var(--spacing-3);
    align-items: stretch;
    height: 70vh;
    min-height: 420px;
}
/* Global Explain page: fill the window height (no blank space) AND bound it so the
   chat thread scrolls internally instead of growing the page. A fixed height on the
   page + min-height:0 on the flex children lets .explain-thread's overflow scroll. */
.explain-page {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 2 * var(--spacing-6));
}
.explain-page .explain-layout {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
}
.explain-history {
    flex: 0 0 240px;
    overflow-y: auto;
    padding: var(--spacing-2);
}
.explain-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    padding: var(--spacing-3);
}
.explain-thread {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--spacing-1);
}
.explain-composer {
    border-top: 1px solid var(--color-border);
    padding-top: var(--spacing-3);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}
.explain-empty {
    padding: var(--spacing-4);
    line-height: 1.55;
}
.explain-history-head {
    font-weight: 600;
    padding: var(--spacing-2);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.explain-history-new {
    border: 1px solid var(--color-border);
    background: transparent;
    border-radius: var(--radius-sm);
    padding: 2px var(--spacing-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    cursor: pointer;
}
.explain-history-new:hover {
    color: var(--color-text);
    border-color: var(--color-text);
}
.explain-history-empty {
    padding: var(--spacing-2);
    font-size: var(--font-size-sm);
}
.explain-history-item {
    position: relative;
    padding: var(--spacing-2) 28px var(--spacing-2) var(--spacing-2);
    border-radius: var(--radius-md);
    cursor: pointer;
}
.explain-history-item:hover,
.explain-history-item.active {
    background: var(--color-bg-hover);
}
.explain-history-title {
    font-size: var(--font-size-sm);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.explain-history-desc {
    font-size: var(--font-size-xs);
    line-height: 1.4;
    margin-top: 2px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.explain-history-sub {
    font-size: var(--font-size-sm);
    margin-top: 4px;
}
/* Client-context badge on its own line, below the metadata. */
.explain-history-clientline {
    margin-top: 4px;
}
.explain-history-client {
    display: inline-block;
    max-width: 100%;
    font-size: var(--font-size-xs);
    padding: 0 6px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
}
.explain-history-client-global {
    color: var(--color-text-muted);
}
.explain-history-del {
    position: absolute;
    top: 4px;
    right: 4px;
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    font-size: var(--font-size-md);
    line-height: 1;
    padding: 2px 4px;
    opacity: 0;
}
.explain-history-item:hover .explain-history-del {
    opacity: 1;
}
.explain-history-del:hover {
    color: var(--color-text);
}

/* Info (ⓘ) button on an agent message → "answer context" overlay */
.explain-info-btn {
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: 0;
    margin-left: var(--spacing-2);
    vertical-align: middle;
    line-height: 0;
}
.explain-info-btn:hover {
    color: var(--color-text);
}
.explain-info-btn:focus-visible {
    outline: 2px solid var(--color-text);
    outline-offset: 2px;
    border-radius: 50%;
}
/* Answer-context overlay body */
.explain-ctx-section {
    margin-bottom: var(--spacing-4);
}
.explain-ctx-section:last-child {
    margin-bottom: 0;
}
.explain-ctx-h {
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-sm);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    margin-bottom: var(--spacing-2);
}
.explain-artefacts {
    list-style: none;
    margin: 0;
    padding: 0;
}
.explain-artefact {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--spacing-2);
    padding: 4px 0;
    border-bottom: 1px solid var(--color-border);
    word-break: break-word;
}
.explain-artefact:last-child {
    border-bottom: 0;
}
.explain-artefact-kind {
    flex: 0 0 auto;
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0 6px;
}
.explain-artefact-label {
    font-family: var(--font-mono, monospace);
    font-size: var(--font-size-sm);
}
.explain-artefact-detail {
    font-size: var(--font-size-sm);
}
.explain-artefact-failed .explain-artefact-label {
    text-decoration: line-through;
}
.diagnosis-pane {
    word-break: break-word;
    line-height: 1.55;
}
.diagnosis-pane .md-p {
    margin: 0 0 var(--spacing-2);
}
.diagnosis-pane .md-p:last-child {
    margin-bottom: 0;
}
.diagnosis-pane .md-h {
    margin: var(--spacing-3) 0 var(--spacing-1);
    font-size: var(--font-size-md);
    color: var(--color-text);
}
.diagnosis-pane .md-list {
    margin: 0 0 var(--spacing-2);
    padding-left: var(--spacing-5);
}
.diagnosis-pane .md-list li {
    margin-bottom: 2px;
}
.diagnosis-pane code {
    background: var(--color-bg-hover);
    color: var(--color-text);
    padding: 1px 4px;
    border-radius: var(--radius-sm);
    font-family: monospace;
    font-size: 0.92em;
}
.diagnosis-pane .md-pre {
    background: var(--color-bg-hover);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-2) var(--spacing-3);
    overflow-x: auto;
    margin: 0 0 var(--spacing-2);
}
.diagnosis-pane .md-pre code {
    background: none;
    padding: 0;
    font-size: var(--font-size-sm);
}
.diagnosis-meta {
    margin-top: auto; /* pin to the bottom of the report area */
    padding-top: var(--spacing-4); /* keep separation when content fills the height */
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
}
.diagnosis-meta-info {
    flex: 1;
    min-width: 0;
}
.diagnosis-meta .btn {
    flex: 0 0 auto;
    font-size: var(--font-size-sm);
    padding: 2px 8px;
}
.diagnosis-goto-connected {
    text-decoration: underline;
    cursor: pointer;
}
.diagnosis-goto-connected:hover {
    color: var(--color-text);
}
.error-detail-content .connected-list {
    margin-top: 0;
}
.connected-error-item {
    padding: var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--spacing-2);
    cursor: pointer;
    font-size: var(--font-size-base);
}
.connected-error-item:hover {
    background: var(--color-bg-hover);
    border-color: var(--color-text-muted);
}

.error-detail-content .detail-section h4 {
    font-size: var(--font-size-base);
    margin-bottom: var(--spacing-2);
    color: var(--color-text-muted);
}

.error-detail-content .analysis-card {
    background: var(--color-bg-hover);
    border-radius: var(--radius-lg);
    padding: var(--spacing-3) var(--spacing-4);
    margin-bottom: var(--spacing-2);
}

.error-detail-content .analysis-card h5 {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--spacing-1);
    font-weight: var(--font-weight-medium);
}

.error-detail-content .analysis-card p {
    margin: 0;
    font-size: var(--font-size-base);
}

.error-detail-content .occurrence-card {
    background: var(--color-bg-hover);
    border-radius: var(--radius-lg);
    padding: var(--spacing-3) var(--spacing-4);
    margin-bottom: var(--spacing-2);
}

.error-detail-content .occurrence-card .kv-table th {
    width: 100px;
}

/* ── Schema Summary Bar ────────────────────────────────────────────────── */

.schema-summary-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1) var(--spacing-5);
    padding: var(--spacing-3) var(--spacing-4);
    background: var(--color-bg-hover);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--spacing-3);
}

.schema-summary-item {
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.schema-summary-num {
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    font-size: var(--font-size-lg);
    margin-right: var(--spacing-1);
}

.schema-expand-toggle {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--spacing-2);
}

/* ── Schema Table List ─────────────────────────────────────────────────── */

.schema-list-table {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    table-layout: auto;
}

.schema-list-table thead th {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-weight: 600;
    padding: var(--spacing-2);
    border-bottom: 1px solid var(--color-border);
}

.schema-stat-header {
    width: 60px;
    text-align: center;
}

.schema-table-row {
    cursor: pointer;
    transition: background 0.15s;
}

.schema-table-row:hover {
    background: var(--color-bg-hover);
}

.schema-table-name-cell {
    font-weight: 500;
    font-size: 0.8125rem;
    font-family: var(--font-base);
    padding: var(--spacing-2);
}

.schema-table-chevron {
    display: inline-block;
    font-size: 10px;
    color: var(--color-text-muted);
    transition: transform 0.2s;
    width: 14px;
}

.schema-stat-cell {
    text-align: center;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    padding: var(--spacing-2);
    font-variant-numeric: tabular-nums;
}

.schema-detail-cell {
    padding: var(--spacing-3) var(--spacing-4) !important;
    background: var(--color-bg-hover);
}

.schema-sub-table {
    font-size: var(--font-size-sm);
    margin-bottom: 0;
}

.schema-sub-table th {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.schema-sub-table th,
.schema-sub-table td {
    padding: var(--spacing-1) var(--spacing-2);
}

/* Schema diff highlights */
.schema-table-row.schema-added { background: rgba(34, 197, 94, 0.05); }
.schema-table-row.schema-removed { opacity: 0.7; }
.schema-table-row.schema-changed { background: rgba(245, 158, 11, 0.05); }

/* ── Heartbeat Sub-Tabs ────────────────────────────────────────────────── */

.subtabs {
    display: flex;
    align-items: center;
    gap: var(--spacing-1);
    padding: var(--spacing-1);
    background: var(--color-bg-hover);
    border-radius: var(--radius-lg);
    margin-bottom: var(--spacing-4);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
}

.subtab {
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    cursor: pointer;
    border: none;
    background: transparent;
    border-radius: var(--radius-md);
    white-space: nowrap;
    transition: color 0.15s, background 0.15s, box-shadow 0.15s;
    font-family: inherit;
    scroll-snap-align: start;
}

.subtab:hover {
    color: var(--color-text);
}

.subtab:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: -2px;
}

.subtab.active {
    background: var(--color-bg-card);
    color: var(--color-text);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.subtab-content {
    display: none;
}

.subtab-content.active {
    display: block;
}

/* ── Overview Card Grid ────────────────────────────────────────────────── */

.overview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--spacing-4);
}

.overview-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-4);
    animation: cardFadeIn 150ms ease both;
}

.overview-card.has-changes {
    border-left: 3px solid var(--color-warning);
}

.overview-card.no-changes.dimmed {
    opacity: 0.5;
    transition: opacity 0.2s ease;
}

.hb-show-all-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    cursor: pointer;
    user-select: none;
    margin-left: var(--spacing-2);
}

.hb-show-all-toggle input[type="checkbox"] {
    margin: 0;
}

@keyframes cardFadeIn {
    from {
        opacity: 0;
        transform: translateY(var(--spacing-1));
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Card header */
.oc-header {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    margin-bottom: var(--spacing-3);
    padding-bottom: var(--spacing-3);
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}

.oc-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    color: var(--color-text-muted);
}

.oc-title {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    flex: 1;
}

.oc-title-link {
    text-decoration: none;
    color: inherit;
}
.oc-title-link:hover {
    opacity: 0.7;
}

.oc-badge {
    flex-shrink: 0;
}

/* Hero value */
.oc-hero {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    font-family: var(--font-base);
    color: var(--color-text);
    margin-bottom: var(--spacing-3);
    line-height: 1.3;
}

/* Detail rows */
.oc-details {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    padding-top: var(--spacing-2);
}

.oc-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--spacing-4);
    font-size: var(--font-size-sm);
    line-height: 1.5;
    padding-bottom: var(--spacing-1);
    border-bottom: 1px solid rgba(0, 0, 0, 0.03);
}

.oc-row:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.oc-key {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-normal);
    flex-shrink: 0;
}

.oc-val {
    color: var(--color-text);
    font-family: var(--font-base);
    font-size: var(--font-size-sm);
    text-align: right;
    word-break: break-word;
    overflow-wrap: anywhere;
    min-width: 0;
}

/* ── Disk Usage Bar ────────────────────────────────────────────────────── */

.disk-bar-wrap {
    margin-top: var(--spacing-2);
}

.disk-bar-label {
    display: flex;
    justify-content: space-between;
    font-size: var(--font-size-sm);
    margin-bottom: var(--spacing-1);
}

.disk-bar-label-key {
    color: var(--color-text-muted);
}

.disk-bar-label-val {
    font-family: var(--font-base);
    font-size: var(--font-size-base);
    color: var(--color-text);
}

.disk-bar {
    height: 6px;
    background: var(--color-bg-hover);
    border-radius: 3px;
    overflow: hidden;
}

.disk-bar-fill {
    height: 100%;
    border-radius: 3px;
    background: var(--color-success);
    width: 0;
    transition: width 300ms ease-out;
}

.disk-bar-fill.warn {
    background: var(--color-warning);
}

.disk-bar-fill.critical {
    background: var(--color-error);
}

/* ── Recent Requests Timeline ──────────────────────────────────────────── */

.overview-card-wide {
    grid-column: span 2;
}

@media (max-width: 640px) {
    .overview-card-wide {
        grid-column: span 1;
    }
}

.req-summary {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--spacing-2);
    padding-bottom: var(--spacing-2);
    border-bottom: 1px solid var(--color-border);
}

.req-list {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.req-entry {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-1) 0;
    font-size: var(--font-size-sm);
    font-family: var(--font-base);
    border-bottom: 1px solid rgba(0,0,0,0.03);
}

.req-entry:last-child {
    border-bottom: none;
}

.req-entry-error {
    border-left: 2px solid var(--color-error);
    padding-left: var(--spacing-2);
}

.req-time {
    color: var(--color-text-muted);
    flex-shrink: 0;
    width: 60px;
    font-size: var(--font-size-xs);
}

.req-method {
    font-weight: var(--font-weight-semibold);
    flex-shrink: 0;
    width: 36px;
    font-size: var(--font-size-xs);
    text-transform: uppercase;
}

.req-url {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    color: var(--color-text);
}

a.req-url {
    color: var(--color-text);
    text-decoration: none;
}

a.req-url:hover {
    text-decoration: underline;
}

.req-status {
    flex-shrink: 0;
    width: 28px;
    text-align: right;
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-xs);
}

.req-status-2xx {
    color: var(--color-success);
}

.req-status-4xx {
    color: var(--color-warning);
}

.req-status-5xx {
    color: var(--color-error);
}

.req-errors {
    color: var(--color-error);
    font-size: var(--font-size-xs);
    flex-shrink: 0;
    width: 36px;
    text-align: right;
}

.req-errors-link {
    text-decoration: none;
    cursor: pointer;
}
.req-errors-link:hover {
    text-decoration: underline;
}

/* ── DNS Tab ─────────────────────────────────────────────────────────── */

.dns-txt-value {
    word-break: break-all;
    font-size: var(--font-size-xs);
    font-family: var(--font-base);
}

/* ── Collapsible phpinfo Sections ──────────────────────────────────────── */

.phpinfo-section {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--spacing-2);
    overflow: hidden;
}

.phpinfo-section-header {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-4);
    cursor: pointer;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    background: var(--color-bg-hover);
    border: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
}

.phpinfo-section-header:hover {
    background: #ececec;
}

.phpinfo-section-header:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: -2px;
}

.phpinfo-section-chevron {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    transition: transform 0.2s;
}

.phpinfo-section.expanded .phpinfo-section-chevron {
    transform: rotate(90deg);
}

.phpinfo-section-body {
    display: none;
}

.phpinfo-section.expanded .phpinfo-section-body {
    display: block;
}

/* ── Sitemap Tree ──────────────────────────────────────────────────────── */

.sitemap-tree-toggle {
    cursor: pointer;
    display: inline-block;
    width: 16px;
    text-align: center;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    user-select: none;
}

.sitemap-tree-toggle:hover {
    color: var(--color-text);
}

.sitemap-folder-row td:first-child {
    font-weight: var(--font-weight-medium);
}

.table td.sitemap-tree-indent-0 { padding-left: var(--spacing-4); }
.table td.sitemap-tree-indent-1 { padding-left: 36px; }
.table td.sitemap-tree-indent-2 { padding-left: 56px; }
.table td.sitemap-tree-indent-3 { padding-left: 76px; }
.table td.sitemap-tree-indent-4 { padding-left: 96px; }
.table td.sitemap-tree-indent-5 { padding-left: 116px; }
.table td.sitemap-tree-indent-6 { padding-left: 136px; }
.table td.sitemap-tree-indent-7 { padding-left: 156px; }
.table td.sitemap-tree-indent-8 { padding-left: 176px; }
.table td.sitemap-tree-indent-9 { padding-left: 196px; }

/* Depth indicator */
tr[data-sm-depth="1"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.06); }
tr[data-sm-depth="2"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.10); }
tr[data-sm-depth="3"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.14); }
tr[data-sm-depth="4"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.18); }
tr[data-sm-depth="5"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.22); }
tr[data-sm-depth="6"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.25); }
tr[data-sm-depth="7"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.28); }
tr[data-sm-depth="8"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.30); }
tr[data-sm-depth="9"] > td:first-child { border-left: 2px solid rgba(0,0,0,0.32); }

.sitemap-row-click {
    cursor: pointer;
}

.sitemap-row-click:hover {
    background: rgba(0, 0, 0, 0.03) !important;
}

.sitemap-type-icon {
    vertical-align: -3px;
    flex-shrink: 0;
}

.sitemap-tree-table {
    table-layout: fixed;
}

.sitemap-tree-table td:first-child {
    word-break: break-all;
    overflow-wrap: anywhere;
}

.sitemap-tree-table td:not(:first-child):not(:last-child) {
    white-space: nowrap;
    overflow: hidden;
}

.sitemap-tree-table td:last-child {
    padding-right: 8px;
}

/* ── Sitemap Download Buttons ──────────────────────────────────────────── */

.sitemap-dl-btn svg {
    vertical-align: -2px;
}

.sitemap-row-dl {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.sitemap-row-dl-btn {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    padding: 2px var(--spacing-2);
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.15s, border-color 0.15s;
    line-height: 1;
}

.sitemap-row-dl-btn:hover {
    color: var(--color-text);
    border-color: #d1d1d1;
}

.sitemap-row-dl-btn .spinner {
    width: 16px;
    height: 16px;
    border-width: 1.5px;
}

.sitemap-dl-dropdown {
    display: none;
    position: absolute;
    right: 0;
    left: auto;
    top: 100%;
    margin-top: var(--spacing-1);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: 0 4px 12px rgba(0,0,0,0.08);
    z-index: 100;
    min-width: 140px;
    padding: var(--spacing-1) 0;
}

.sitemap-dl-dropdown.active {
    display: block;
}

.sitemap-dl-dropdown-item {
    display: block;
    width: 100%;
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-base);
    color: var(--color-text);
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    white-space: nowrap;
    font-family: inherit;
}

.sitemap-dl-dropdown-item:hover {
    background: var(--color-bg-hover);
}

.sitemap-dl-progress-panel {
    position: absolute;
    right: 0;
    top: 100%;
    margin-top: 2px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 12px rgba(0,0,0,0.08);
    z-index: 100;
    white-space: nowrap;
    padding: 3px var(--spacing-2);
    font-size: var(--font-size-sm);
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    color: var(--color-text-muted);
}

.sitemap-dl-progress-panel .dl-cancel {
    cursor: pointer;
    text-decoration: underline;
}

.sitemap-dl-progress-panel .dl-cancel:hover {
    color: var(--color-text);
}

/* ── File Preview Overlay ──────────────────────────────────────────────── */

.file-preview-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-5);
}

.file-preview-panel {
    background: var(--color-bg-card);
    border-radius: var(--radius-xl);
    border: 1px solid var(--color-border);
    max-width: 90vw;
    max-height: 90vh;
    width: 900px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
}

.file-preview-header {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.file-preview-header .file-preview-title {
    flex: 1;
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-base);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-family: var(--font-base);
}

.file-preview-header .file-preview-dl-btn {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    padding: var(--spacing-1) var(--spacing-2);
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.15s, border-color 0.15s;
    line-height: 1;
    flex-shrink: 0;
}

.file-preview-header .file-preview-dl-btn:hover {
    color: var(--color-text);
    border-color: #d1d1d1;
}

.file-preview-close {
    background: none;
    border: none;
    font-size: var(--font-size-2xl);
    cursor: pointer;
    color: var(--color-text-muted);
    line-height: 1;
    padding: var(--spacing-1);
    flex-shrink: 0;
}

.file-preview-close:hover {
    color: var(--color-text);
}

.file-preview-body {
    flex: 1;
    overflow: auto;
    min-height: 0;
}

.file-preview-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 60px;
}

.file-preview-error {
    padding: 40px var(--spacing-5);
    text-align: center;
    color: var(--color-error);
    font-size: var(--font-size-base);
}

.file-preview-unsupported {
    padding: 40px var(--spacing-5);
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--font-size-base);
}

/* ── File Preview: Search Bar ──────────────────────────────────────────── */

.file-preview-search {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-4);
    border-bottom: 1px solid var(--color-border);
    background: var(--color-bg-hover);
    flex-shrink: 0;
}

.file-preview-search input {
    flex: 1;
    padding: var(--spacing-1) var(--spacing-2);
    font-size: var(--font-size-base);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-family: inherit;
    outline: none;
}

.file-preview-search input:focus {
    border-color: var(--color-success);
    box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.1);
}

.file-preview-search .search-count {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    white-space: nowrap;
    min-width: 60px;
    text-align: center;
}

.file-preview-search button {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    padding: 3px var(--spacing-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    line-height: 1;
}

.file-preview-search button:hover {
    color: var(--color-text);
    border-color: #d1d1d1;
}

.file-preview-search button:disabled {
    opacity: 0.4;
    cursor: default;
}

/* ── File Preview: Code Lines ──────────────────────────────────────────── */

.file-preview-lines {
    display: table;
    width: 100%;
    font-family: var(--font-base);
    font-size: var(--font-size-sm);
    line-height: 1.6;
}

.file-preview-line {
    display: table-row;
}

.file-preview-line:hover {
    background: var(--color-bg-hover);
}

.file-preview-line.preview-line-highlight,
.file-preview-line.preview-line-highlight .file-preview-gutter,
.file-preview-line.preview-line-highlight .file-preview-code {
    background: #fff3bf;
}

.file-preview-line.preview-line-highlight .file-preview-gutter {
    color: #92400e;
    font-weight: 600;
}

.file-preview-gutter {
    display: table-cell;
    width: 1px;
    white-space: nowrap;
    padding: 0 var(--spacing-3);
    text-align: right;
    color: #d1d1d1;
    user-select: none;
    border-right: 1px solid var(--color-border);
    background: #fafafa;
    vertical-align: top;
}

.file-preview-code {
    display: table-cell;
    padding: 0 var(--spacing-4);
    white-space: pre;
    overflow-x: auto;
    vertical-align: top;
}

/* ── File Preview: Search Highlights ───────────────────────────────────── */

.search-highlight {
    background: #fef08a;
    border-radius: 2px;
}

.search-highlight-current {
    background: #fb923c;
    color: var(--color-bg-card);
    border-radius: 2px;
}

/* ── File Preview: Image ───────────────────────────────────────────────── */

.file-preview-image {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-5);
}

.file-preview-image img {
    max-width: 90vw;
    max-height: 70vh;
    object-fit: contain;
}

/* ── File Preview: Clickable filenames ─────────────────────────────────── */

.sitemap-file-name {
    cursor: pointer;
    color: var(--color-text);
}

.sitemap-file-name:hover {
    text-decoration: underline;
    color: var(--color-success);
}

.sitemap-file-name.sitemap-file-empty {
    cursor: default;
}

.sitemap-file-name.sitemap-file-empty:hover {
    text-decoration: none;
    color: var(--color-text);
}

/* ── Sitemap view toggle (Tree | Recently Modified) ────────────────────── */

.sitemap-view-toggle-wrap {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--spacing-2);
    flex-wrap: wrap;
    margin: var(--spacing-2) 0;
}

.sitemap-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 220px;
    min-width: 0;
    max-width: 360px;
}

.sitemap-search-input {
    width: 100%;
    padding: var(--spacing-1) var(--spacing-6) var(--spacing-1) var(--spacing-3);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-family: inherit;
    font-size: var(--font-size-base);
    line-height: 1.5;
}

.sitemap-search-input::placeholder {
    color: var(--color-text-muted);
}

.sitemap-search-input:focus {
    outline: none;
    border-color: var(--color-text);
}

.sitemap-search-input::-webkit-search-cancel-button,
.sitemap-search-input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}

.sitemap-search-clear {
    position: absolute;
    right: var(--spacing-1);
    top: 50%;
    transform: translateY(-50%);
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--radius-md);
}

.sitemap-search-clear:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
}

.sitemap-search-clear[hidden] {
    display: none;
}

.sitemap-view-toggle {
    display: inline-flex;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.sitemap-view-btn {
    background: transparent;
    border: 0;
    padding: var(--spacing-1) var(--spacing-3);
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.sitemap-view-btn + .sitemap-view-btn {
    border-left: 1px solid var(--color-border);
}

.sitemap-view-btn:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
}

.sitemap-view-btn.active,
.sitemap-view-btn.active:hover {
    background: var(--color-text);
    color: var(--color-bg-card);
}

.sitemap-flat-folder {
    color: var(--color-text-muted);
    text-decoration: none;
}

.sitemap-flat-folder:hover {
    text-decoration: underline;
}

.sitemap-row-highlight > td {
    animation: sitemap-row-highlight-pulse 1500ms ease-out;
}
@keyframes sitemap-row-highlight-pulse {
    0%   { background-color: rgba(250, 204, 21, 0.45); }
    100% { background-color: transparent; }
}

/* ── Health Columns ────────────────────────────────────────────────────── */

.health-stale {
    font-weight: var(--font-weight-medium);
}

/* ── Digest Bell ───────────────────────────────────────────────────────── */

.digest-bell {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background 0.15s, color 0.15s, opacity 0.15s;
}

.digest-bell:hover {
    background: #f0f0f2;
}

.digest-bell-svg {
    width: 16px;
    height: 16px;
}

.digest-bell-none {
    color: #c5c5d2;
}

.digest-bell-daily {
    color: var(--color-text);
}

.digest-bell-daily .digest-bell-svg {
    fill: var(--color-text);
}

.digest-bell-weekly {
    color: #c5c5d2;
}

.digest-bell-weekly .digest-bell-svg {
    fill: currentColor;
}

.digest-bell-saving {
    opacity: 0.5;
    pointer-events: none;
}

.digest-cell {
    text-align: center;
}

.clients-table .col-actions {
    width: 36px;
}

.actions-cell {
    text-align: center;
}

.btn-icon {
    background: transparent;
    border: none;
    padding: 4px;
    cursor: pointer;
    color: var(--color-text-muted);
    border-radius: 4px;
    line-height: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.btn-icon:hover {
    background: var(--color-surface-hover, #f1f5f9);
}

.btn-icon-danger:hover {
    color: #b91c1c;
    background: #fee2e2;
}

/* ── Actions Tab Sections ──────────────────────────────────────────────── */

.action-section {
    margin-bottom: var(--spacing-4);
}

.action-section:last-child {
    margin-bottom: 0;
}

/* ── Notification Recipients ───────────────────────────────────────────── */

.notif-table {
    margin-bottom: 0;
    table-layout: fixed;
}

.notif-table th,
.notif-table td {
    padding: var(--spacing-2) var(--spacing-2);
}

/* Pin the Email column to the same width in BOTH the 2-col user table and
   the 3-col custom table so the Digest Frequency dropdowns start at the
   same x position. */
.notif-table th:first-child,
.notif-table td:first-child {
    width: 60%;
    word-break: break-word;
}

/* Fixed × (remove) action column — only present in the custom table; the
   nth-child(3) selector is harmless on the 2-col user table. */
.notif-table th:nth-child(3),
.notif-table td:nth-child(3) {
    width: 52px;
    text-align: right;
}

.notif-digest-select,
.notif-custom-digest-select,
#notifCustomFreqSelect {
    height: 36px;
    padding: var(--spacing-1) var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-base);
    background: var(--color-bg-card);
    cursor: pointer;
    box-sizing: border-box;
}

/* In-table selects fall back to the global select rule (width:100%;
   display:block) and fill their column. The add-row select stays inline
   so the "email input + select + Add button" row doesn't wrap. */
#notifCustomFreqSelect {
    width: auto;
    display: inline-block;
}

.notif-digest-select:disabled,
.notif-custom-digest-select:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.notif-custom-label {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--spacing-2);
}

.notif-custom-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-1) var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--spacing-1);
    font-size: var(--font-size-md);
}

.notif-remove-btn {
    padding: 2px var(--spacing-2);
    font-size: var(--font-size-lg);
    line-height: 1;
    min-width: auto;
}

.notif-email-input {
    flex: 1;
    padding: var(--spacing-2) var(--spacing-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-md);
}

.notif-add-row .flex {
    max-width: 400px;
}

/* ── Responsive ────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .sidebar {
        transform: translateX(-100%);
    }

    .sidebar.open {
        transform: translateX(0);
    }

    .main-content {
        margin-left: 0;
    }

    .sidebar-toggle {
        display: block;
    }

    .content-area {
        padding: var(--spacing-4);
    }

    /* Clients filter bar stacks on mobile */
    .clients-filter-bar {
        flex-direction: column;
        align-items: stretch;
    }

    .filter-search,
    .filter-select {
        width: 100%;
    }

    .flash {
        margin: 0 var(--spacing-4);
    }

    .auth-card {
        padding: var(--spacing-5);
    }

    .table th,
    .table td {
        padding: var(--spacing-2) var(--spacing-2);
    }

    .compare-selectors {
        flex-direction: column;
    }

    .compare-vs {
        text-align: center;
        padding: 0;
    }

    .tabs {
        overflow-x: auto;
    }

    .client-meta-strip {
        gap: var(--spacing-1) var(--spacing-4);
    }

    .subtabs {
        gap: 2px;
        padding: 3px;
    }

    .subtab {
        padding: var(--spacing-1) var(--spacing-2);
        font-size: var(--font-size-xs);
    }

    .overview-grid {
        grid-template-columns: 1fr;
        gap: var(--spacing-3);
    }

    .overview-card {
        padding: var(--spacing-4);
    }

    .file-preview-overlay {
        padding: var(--spacing-2);
    }

    .file-preview-panel {
        max-width: 100vw;
        max-height: 100vh;
        width: 100%;
        border-radius: var(--radius-lg);
    }

    /* Client detail mobile adjustments */
    .client-summary-card {
        padding: var(--spacing-4);
    }

    .client-summary-grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--spacing-4);
    }

    .page-header {
        margin-bottom: var(--spacing-4);
    }
}

/* ── Client Detail Page ────────────────────────────────────────────────── */

/* Page Header */
.page-header {
    margin-bottom: var(--spacing-6);
}

.back-link {
    display: inline-block;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    margin-bottom: var(--spacing-2);
    transition: color 0.15s ease;
}

.back-link:hover {
    color: var(--color-text);
    text-decoration: none;
}

.back-link:focus-visible {
    outline: 2px solid var(--color-text);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* Client Summary Card */
.client-summary-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-5);
    margin-bottom: var(--spacing-5);
}

.client-summary-status {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    margin-bottom: var(--spacing-4);
}

.client-summary-domain {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-semibold);
    margin: 0;
}

.client-summary-link {
    display: inline-flex;
    align-items: center;
    margin-left: var(--spacing-2);
    color: var(--color-text-muted);
    opacity: 0.5;
    transition: opacity 0.15s;
    vertical-align: middle;
}

.client-summary-link:hover {
    opacity: 1;
    color: var(--color-text);
}

.client-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--spacing-5);
}

.client-summary-item {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.client-summary-label {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.025em;
    font-weight: var(--font-weight-medium);
}

.client-summary-value {
    font-size: var(--font-size-base);
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

/* Tab Badge */
.tab-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 var(--spacing-1);
    background: var(--color-error);
    color: white;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    border-radius: 9px;
    margin-left: var(--spacing-1);
}

/* Heartbeat Subtabs */
.hb-subtabs {
    display: flex;
    flex-direction: column;
}

.hb-subtab-bar {
    display: flex;
    gap: var(--spacing-1);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--spacing-4);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.hb-subtab {
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-normal);
    color: var(--color-text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
    white-space: nowrap;
}

.hb-subtab:hover {
    color: var(--color-text);
}

.hb-subtab.active {
    color: var(--color-text);
    border-bottom-color: var(--color-text);
    font-weight: var(--font-weight-semibold);
}

.hb-subtab:focus-visible {
    outline: 2px solid var(--color-text);
    outline-offset: 2px;
}

.hb-subtab-content {
    padding-top: var(--spacing-4);
}

/* The "Saved ✓" that follows an autosaving field, and what one says when it
   will not save. Both were written inline on every section that has them,
   against --success and --danger — neither of which this stylesheet defines, so
   both were drawing their hard-coded fallback and neither matched the green and
   the red used everywhere else on the dashboard. */
.settings-saved-indicator {
    color: var(--color-success);
    font-size: var(--font-size-sm);
    transition: opacity 0.4s ease;
}

.settings-inline-error {
    color: var(--color-error);
    font-size: var(--font-size-sm);
    margin-top: var(--spacing-1);
}

/* A level of PHP error and the constants that make it up. The group is the
   thing being decided; the constants under it are what that means, so they are
   set in the code font and indented under their own heading. */
.error-types-group-header {
    display: block;
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--spacing-1);
}

.error-types-members {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1) var(--spacing-4);
    margin-left: var(--spacing-5);
}

.error-types-member {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    font-family: var(--font-mono, monospace);
    font-size: var(--font-size-sm);
}

/* Settings Section Titles */
.settings-section {
    margin-bottom: var(--spacing-4);
}

.settings-section:last-child {
    margin-bottom: 0;
}

.settings-section-title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--spacing-3);
}

/* What the AI key has cost: five features over two spans, four numbers each.
   Four numbers per row are read by comparing them down the column, so it is a
   table and takes the full width of the block — a narrow one would set the
   numbers side by side with nothing between them and the labels. Borderless
   apart from the two rules below, so it still reads as part of a settings
   block of paragraphs rather than as a grid dropped into one. */
/* The gap above belongs to the range bar now — the table hangs directly under
   the span it is showing, or the two read as separate things. */
.ai-spend-table {
    width: 100%;
    margin-top: var(--spacing-2);
    border-collapse: collapse;
    font-size: var(--font-size-sm);
}

/* The numbers line up on the right; only the feature name is prose. */
.ai-spend-table th,
.ai-spend-table td {
    padding: var(--spacing-1) 0;
    text-align: right;
}

.ai-spend-table th:first-child,
.ai-spend-table td:first-child {
    text-align: left;
    font-weight: var(--font-weight-normal);
}

/* Column headings, drawn the way every other table on the dashboard draws
   them. */
.ai-spend-head th {
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
    border-bottom: 1px solid var(--color-border);
}

/* Which span the table is showing. The three are one choice, so they sit
   together on a line above it rather than being three things to find. */
.ai-spend-ranges {
    display: flex;
    gap: var(--spacing-1);
    margin-top: var(--spacing-4);
    border-bottom: 1px solid var(--color-border);
}

.ai-spend-range {
    padding: var(--spacing-2) var(--spacing-3);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-normal);
    color: var(--color-text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
    white-space: nowrap;
}

.ai-spend-range:hover {
    color: var(--color-text);
}

.ai-spend-range.active {
    color: var(--color-text);
    border-bottom-color: var(--color-text);
    font-weight: var(--font-weight-semibold);
}

.ai-spend-range:focus-visible {
    outline: 2px solid var(--color-text);
    outline-offset: 2px;
}

.ai-spend-sum th,
.ai-spend-sum td,
.ai-spend-sum th:first-child {
    border-top: 1px solid var(--color-border);
    font-weight: var(--font-weight-semibold);
}

/* ── Additional Utilities ──────────────────────────────────────────────── */

.m-0 { margin: 0; }
.p-0 { padding: 0; }
.relative { position: relative; }
.text-xs { font-size: var(--font-size-sm); }
.text-sm-tight { font-size: var(--font-size-base); white-space: nowrap; line-height: 1; }

/* Error Table Columns */
.col-error-date { width: 140px; }
.col-error-level { width: 80px; }
.col-error-count { width: 50px; }
.req-error-type { margin: 0 4px 2px 0; }
.col-error-client { width: 180px; }
.col-error-actions { width: 40px; text-align: center; }

/* Icon button for row actions (hide / recover an error). */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: all 0.15s ease;
}
.icon-btn:hover { background: var(--color-bg-hover); }
.error-hide-btn:hover { color: var(--color-error); }
.error-recover-btn { color: var(--color-success, #10a37f); }
.error-recover-btn:hover { color: var(--color-success, #10a37f); background: var(--color-bg-hover); }

/* A hidden ("solved") error shown via the "Show solved" toggle is dimmed. */
.error-row-hidden > td { opacity: 0.5; }
.error-row-hidden > td.col-error-actions { opacity: 1; }
.all-error-client-link { color: inherit; text-decoration: none; }
.all-error-client-link:hover { text-decoration: underline; }
.all-errors-cap-notice {
    padding: 8px 12px;
    margin-bottom: 12px;
    background: #fffbeb;
    color: #92400e;
    border: 1px solid #fde68a;
    border-radius: var(--radius-sm);
    font-size: 0.8125rem;
}

/* DB Connection Dropdown */
.db-conn-select { min-width: 180px; padding-right: 28px; height: 36px; box-sizing: border-box; }
.db-conn-delete-btn {
    position: absolute;
    right: 2px;
    top: 50%;
    transform: translateY(-50%);
    padding: 0 4px;
    background: none;
    border: none;
    color: var(--color-error);
    font-size: var(--font-size-xl);
    line-height: 1;
}

/* DB Form Checkbox Label */
.db-remember-label {
    display: flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
    margin: 0;
    font-weight: normal;
}

/* DB Form Button Group */
.db-form-actions { display: flex; gap: 4px; }
.db-form-group { display: flex; gap: 8px; align-items: center; }

/* Settings Reference Hints (jQuery .show() toggles display) */
.settings-ref-hint {
    font-size: var(--font-size-sm);
    display: none;
}

/* Read-only active endpoint display (Settings > Endpoint card) */
.settings-active-endpoint {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    padding: var(--spacing-3);
    background: var(--color-bg-page);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.settings-active-endpoint-row {
    display: flex;
    align-items: baseline;
    gap: var(--spacing-2);
    flex-wrap: wrap;
}

.settings-active-endpoint-label {
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

.settings-active-endpoint-url {
    font-size: var(--font-size-sm);
    word-break: break-all;
}

.settings-active-endpoint-value {
    font-size: var(--font-size-sm);
    word-break: break-all;
}

/* Notification Section Spacing */
.notif-section-mt { margin-top: var(--spacing-3); }
.notif-error-hint { font-size: var(--font-size-base); margin-top: var(--spacing-1); }

/* ── Charts ────────────────────────────────────────────────────────────── */

/* Chart Containers */
.chart-wrap {
    margin-top: var(--spacing-3);
    margin-bottom: var(--spacing-3);
    overflow: hidden;
    border-radius: var(--radius-sm);
}

.chart-container {
    position: relative;
    width: 100%;
    height: 160px;
    margin-bottom: var(--spacing-2);
}

.chart-container-lg {
    height: 200px;
}

#fileCountChartCard,
#tableSizeChartCard {
    display: flex;
    flex-direction: column;
}

#fileCountChartCard .chart-container,
#tableSizeChartCard .chart-container {
    flex: 1;
    height: auto;
    min-height: 250px;
}

#fileCountCanvas svg {
    min-height: 180px;
}

.chart-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 160px;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.charts-row {
    display: flex;
    gap: var(--spacing-3);
    margin-bottom: var(--spacing-3);
}

.charts-row > div {
    flex: 1;
    min-width: 0;
}

/* HTML/CSS Charts */

/* Stacked bar chart (error trend) */
.css-bar-chart {
    width: 100%;
}

.css-bar-chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 120px;
}

.css-bar-col {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 0;
    height: 100%;
}

.css-bar-stack {
    flex: 1;
    width: 100%;
    display: flex;
    flex-direction: column-reverse;
    align-items: stretch;
    cursor: default;
}

.css-bar-segment {
    width: 100%;
    min-height: 1px;
    transition: opacity 0.1s;
}

.css-bar-segment:hover {
    opacity: 0.8;
}

.css-bar-label {
    font-size: 10px;
    color: var(--color-text-muted);
    margin-top: 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    text-align: center;
}

.css-bar-legend {
    display: flex;
    gap: var(--spacing-3);
    margin-top: var(--spacing-2);
    flex-wrap: wrap;
}

.css-bar-legend-item {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    color: var(--color-text-muted);
}

.css-bar-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* Horizontal bar chart (error dist, table sizes) */
.css-hbar-chart {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.css-hbar-row {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    min-height: 20px;
}

.css-hbar-label {
    font-size: 11px;
    color: var(--color-text-muted);
    width: 100px;
    flex-shrink: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.css-hbar-track {
    flex: 1;
    height: 12px;
    background: var(--color-border);
    border-radius: 2px;
    overflow: hidden;
}

.css-hbar-fill {
    height: 100%;
    border-radius: 2px;
    min-width: 2px;
    transition: width 0.3s ease;
}

.css-hbar-value {
    font-size: 11px;
    color: var(--color-text-muted);
    width: 60px;
    flex-shrink: 0;
    text-align: right;
}

/* Fleet Health Bar */
.fleet-health-bar {
    margin-bottom: var(--spacing-2);
}

.fleet-health-bar-wrap {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2);
    background: var(--color-bg-card);
    border-radius: var(--radius-md);
}

.fleet-health-bar-label {
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--color-text);
    min-width: 80px;
}

.fleet-health-bar-container {
    flex: 1;
    height: 8px;
    background: var(--color-border);
    border-radius: 4px;
    overflow: hidden;
    display: flex;
}

.fleet-health-segment {
    height: 100%;
    transition: width 0.3s ease;
}

.fleet-health-segment.healthy {
    background: var(--color-success);
}

.fleet-health-segment.warning {
    background: var(--color-warning);
}

.fleet-health-segment.error {
    background: var(--color-error);
}

.fleet-health-legend {
    display: flex;
    gap: var(--spacing-3);
    align-items: center;
    font-size: var(--font-size-sm);
}

.fleet-health-legend-item {
    display: flex;
    align-items: center;
    gap: var(--spacing-1);
}

.fleet-health-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
}

.fleet-health-legend-dot.healthy {
    background: var(--color-success);
}

.fleet-health-legend-dot.warning {
    background: var(--color-warning);
}

.fleet-health-legend-dot.error {
    background: var(--color-error);
}

/* ── Reduced Motion ────────────────────────────────────────────────────────── */

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

    .overview-card {
        animation: none;
    }

    .disk-bar-fill {
        transition: none;
    }
}

/* Requests tab error row highlighting */
#requestsTable .row-error {
    background: rgba(239, 68, 68, 0.05);
}
#requestsTable .row-error:hover {
    background: rgba(239, 68, 68, 0.1);
}

/* ── Cron Jobs (Settings) ───────────────────────────────────────────────── */
.cron-jobs-list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
}

.cron-job-row {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
    padding: var(--spacing-3) 0;
    border-top: 1px solid var(--color-border);
}

.cron-job-row:first-child {
    border-top: 0;
    padding-top: 0;
}

.cron-job-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--spacing-3);
    flex-wrap: wrap;
}

.cron-job-title {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
}

.cron-job-label {
    font-weight: var(--font-weight-medium);
}

.cron-job-status {
    font-size: var(--font-size-sm);
}

.cron-job-meta {
    font-size: var(--font-size-sm);
    cursor: help;
}

.cron-job-description {
    font-size: var(--font-size-sm);
}

.cron-job-command-row {
    display: flex;
    align-items: stretch;
    gap: var(--spacing-2);
}

.cron-job-command {
    flex: 1;
    min-width: 0;
}

.cron-job-error {
    font-size: var(--font-size-sm);
}

/* ── Licensing: File preview feature off ─────────────────────────────────
   The body carries .no-file-preview when the license omits "file-preview".
   Front-end only: the sitemap still lists files and the AI (Explain / MCP)
   still reads them — this only removes the preview and download affordances.
   app.js additionally makes openFilePreview()/downloadSingleFile() no-ops, so
   a file row click does nothing rather than relying on the buttons being gone. */
body.no-file-preview .preview-single-file,
body.no-file-preview .download-single-file,
body.no-file-preview .preview-trace-file,
body.no-file-preview .download-trace-file,
body.no-file-preview .download-all-included-files,
body.no-file-preview .sitemap-dl-btn,
body.no-file-preview .sitemap-row-dl,
body.no-file-preview .sitemap-row-dl-btn,
body.no-file-preview #filePreviewDownload,
body.no-file-preview #errorPreviewFile,
body.no-file-preview #errorDownloadFiles {
    display: none !important;
}

/* ── Risk Engine (proactive findings feed) ─────────────────────────── */
.risk-badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 10px;
    font-size: var(--font-size-xs, 0.75rem);
    font-weight: var(--font-weight-semibold, 600);
    text-transform: capitalize;
}
.risk-sev-critical { background: rgba(198, 40, 40, 0.14); color: var(--color-danger, #c62828); }
.risk-sev-high     { background: rgba(230, 126, 0, 0.15); color: #b45309; }
.risk-sev-medium   { background: var(--color-bg-hover, #f1f1f1); color: var(--color-text, #222); }
.risk-sev-low,
.risk-sev-info     { background: var(--color-bg-hover, #f1f1f1); color: var(--color-text-muted, #666); }
.risk-when, .risk-actions { white-space: nowrap; }
.risk-title { cursor: pointer; }
.risk-title:hover { text-decoration: underline; }
.risk-status {
    display: inline-block;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: 8px;
    font-size: var(--font-size-xs, 0.7rem);
    border: 1px solid var(--color-border, #ddd);
    color: var(--color-text-muted, #666);
    text-transform: capitalize;
}
.risk-ai { margin-left: 6px; font-size: var(--font-size-xs, 0.7rem); color: var(--color-text-muted, #666); }
.risk-diag-cell { white-space: nowrap; }
.risk-diag {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 10px;
    font-size: var(--font-size-xs, 0.75rem);
    font-weight: var(--font-weight-semibold, 600);
    white-space: nowrap;
}
.risk-diag-done    { background: rgba(46, 125, 50, 0.14); color: #2e7d32; } /* AI-diagnosed */
.risk-diag-pending { background: var(--color-bg-hover, #f1f1f1); color: var(--color-text-muted, #666); }
.risk-detail-head  { margin-bottom: 8px; }
.risk-detail-label { font-weight: var(--font-weight-semibold, 600); font-size: var(--font-size-sm, 0.875rem); margin: 10px 0 2px; }
.risk-match-table { margin: 4px 0 6px; }
.risk-match-table th, .risk-match-table td { vertical-align: top; }
/* White chip + border so the pattern reads against the grey detail-row box (the
   default inline-code bg is grey and would blend in). */
.risk-match-fn { font-size: var(--font-size-xs, 0.75rem); background: var(--color-bg-card, #fff); border: 1px solid var(--color-border, #e5e5e5); }
.risk-row-dismissed > td { opacity: 0.5; } /* acked/snoozed: greyed in place until refresh */
.risk-detail-row > td { background: var(--color-bg-subtle, #fafafa); }
.risk-evidence { margin: 4px 0 6px; padding-left: 18px; font-size: var(--font-size-sm, 0.875rem); }
.risk-evidence li { margin-bottom: 2px; }
.risk-match-dir { color: var(--color-text-muted); } /* muted folder prefix inside the file link */
.risk-fix { margin-top: 8px; font-size: var(--font-size-sm, 0.875rem); }
/* The suggested fix is rendered markdown; scope the shared md-* classes here so the
   list/paragraphs aren't left with the browser default (huge indent + margins). */
.risk-fix .md-p { margin: 0 0 6px; }
.risk-fix .md-p:last-child { margin-bottom: 0; }
.risk-fix .md-list { margin: 4px 0 6px; padding-left: 18px; }
.risk-fix .md-list li { margin-bottom: 2px; }
/* White chip + border for inline code so it reads against the grey detail box
   (matches .risk-match-fn); fenced code blocks keep their plain background. */
.risk-fix code { background: var(--color-bg-card, #fff); border: 1px solid var(--color-border, #e5e5e5); }
.risk-fix pre code { background: none; border: 0; }
.risk-fix-label { font-weight: var(--font-weight-semibold, 600); font-size: var(--font-size-sm, 0.875rem); margin-bottom: 2px; }

/* ── Agents ────────────────────────────────────────────────────────────── */

/* Two utilities the agent views need that the sheet did not already have. */
.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--spacing-4);
}

@media (max-width: 640px) {
    .form-row { grid-template-columns: 1fr; }
}

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

.agent-card {
    cursor: pointer;
    transition: border-color 120ms ease, transform 120ms ease;
    position: relative;
}

/* The order of these boxes is a routing preference, not a layout: when two
   agents could both answer, the one higher up is asked first. The grip is the
   only thing on the page that says so, so it is always present rather than
   appearing on hover — a control nobody can see is a preference nobody sets. */
.agent-card-grip {
    position: absolute;
    /* Bottom-right, not top-right: the head is a two-child space-between row
       and the model badge already owns that corner. The tags sit bottom-left
       and wrap leftwards, so this corner is the one free spot on the box. */
    bottom: var(--spacing-2);
    right: var(--spacing-2);
    cursor: grab;
    color: var(--color-text-muted);
    opacity: 0.35;
    line-height: 1;
    letter-spacing: -0.18em;
    padding: 2px 4px;
    border-radius: var(--radius-sm);
    transition: opacity 120ms ease;
}

.agent-card:hover .agent-card-grip,
.agent-card-grip:hover,
.agent-card-grip:focus-visible {
    opacity: 1;
}

.agent-card-grip:active {
    cursor: grabbing;
}

/* Out of the grid entirely while it is being dragged, so the gap below is the
   only place it can be — and the other boxes close up behind it exactly as they
   will after the drop. Hidden rather than faded: a faded box still occupies a
   cell, so the arrangement on screen would be one box longer than the one being
   previewed. */
.agent-card-dragging {
    display: none;
}

/* Where it would land. Sized in JS to the box it stands in for, so the grid
   does not change height the moment a drag starts. Dashed and empty because it
   is a space rather than a thing — a filled box here reads as a second copy of
   the one being dragged. */
.agent-card-placeholder {
    /* 1px, the same as a box's own border — it is standing in for one, and a
       heavier outline reads as a different kind of thing rather than as the
       space one would occupy. Dashed is what marks it as a space. */
    border: 1px dashed var(--color-text-muted);
    border-radius: var(--radius-lg);
    background: var(--color-bg-hover);
    opacity: 0.7;
}

/* No pointer-events rule here, and that is deliberate. Taking the hit area off
   a box's children for the length of a drag looks like it would give one clean
   target per box — but the grip that started the drag is one of those children,
   and a drag source that loses its hit area mid-gesture is cancelled outright
   in Chrome and WebKit. It bought nothing anyway: dragenter and dragover bubble
   out of the children, the handler measures the box rather than whatever was
   under the pointer, and nothing here listens for dragleave, so a seam between
   the heading and the padding around it costs nothing to cross.

   The box does not lift under the pointer while it is being dragged over.
   A 1px rise on the thing you are aiming at, on a grid that is already
   reflowing, is a shift you have to correct for. */
body.agent-dragging .agent-card:hover {
    transform: none;
}

.agent-card:hover,
.agent-card:focus-visible {
    border-color: var(--color-text-muted);
    transform: translateY(-1px);
}

/* A disabled agent stays visible — it is part of the team the operator built,
   and hiding it would make "why is nobody answering?" harder to answer. */
/* A disabled agent should read as out of service at a glance without the box
   looking broken. Fading the whole card — which this used to do — takes the
   border, the badges and the "disabled" label down with it, and a washed-out
   card reads as "still loading" rather than "switched off". So the text greys
   out instead, and everything that carries meaning keeps its contrast. */
.agent-card-off .agent-card-name {
    color: var(--color-text-muted);
}

/* The lines already at the muted colour go one step lighter. There is no
   lighter grey in the scale, so this is the muted colour at reduced strength
   rather than a one-off hex that nothing else in the dashboard uses. */
.agent-card-off .agent-card-role,
.agent-card-off .agent-card-address,
.agent-card-off .agent-card-desc {
    opacity: 0.75;
}

.agent-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--spacing-2);
}

.agent-card-name {
    margin: 0;
    font-size: var(--font-size-lg);
}

.agent-card-model {
    flex-shrink: 0;
    max-width: 45%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.agent-card-address {
    display: block;
    margin: var(--spacing-1) 0 var(--spacing-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.agent-card-desc {
    margin: 0 0 var(--spacing-2);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.agent-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1);
}

.agent-tool-groups {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--spacing-3);
}

.agent-tool-group strong {
    display: block;
    margin-bottom: var(--spacing-1);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.agent-client-list {
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-2);
}

/*
 * A folded-away block of settings inside an overlay. Same shape as the
 * collapsible phpinfo sections — chevron, .expanded on the wrapper, body
 * hidden until then — kept separate because this one sits in a form and
 * needs the padding a form group expects.
 */
.adv-section {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.adv-section-header {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    width: 100%;
    padding: var(--spacing-2) var(--spacing-4);
    border: none;
    text-align: left;
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    background: var(--color-bg-hover);
    cursor: pointer;
}

.adv-section-header:hover {
    background: var(--color-border);
}

.adv-section-header:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: -2px;
}

.adv-section-chevron {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    transition: transform 0.2s;
}

.adv-section.expanded .adv-section-chevron {
    transform: rotate(90deg);
}

.adv-section-body {
    display: none;
    padding: var(--spacing-4);
    border-top: 1px solid var(--color-border);
}

.adv-section.expanded .adv-section-body {
    display: block;
}

/* The add-a-sender line. The field takes what the two buttons leave, and
   min-width: 0 keeps a flex child from refusing to shrink below its content. */
.mailbox-add-sender {
    margin-bottom: var(--spacing-5);
}

.mailbox-add-sender label {
    display: block;
    margin-bottom: var(--spacing-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.mailbox-add-sender .form-control {
    flex: 1;
    min-width: 0;
}

/* The status doubles as the switch between allowed and blocked, so it is a real
   button — reachable by keyboard, announced as one. A button carries a border
   and a background of its own, which would make it stop looking like the badge
   it is standing in for. */
.agent-sender-toggle {
    border: none;
    font-family: inherit;
    cursor: pointer;
}

.agent-sender-toggle:hover {
    filter: brightness(0.92);
}

.agent-sender-toggle:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: 1px;
}

.agent-sender-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    padding: var(--spacing-2) 0;
    border-bottom: 1px solid var(--color-border);
}

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

/* The agent that answers the plain address is pinned first and marked, since
   it is the one whose address people will actually use. */
.agent-card-general {
    border-left: 3px solid var(--color-success);
}

/* Breathing room between the intro text above the roster and the boxes
   themselves — a paragraph sitting directly on a grid of cards reads as a
   caption for the first one. */
#agentsDefaultsNote {
    margin: 0 0 var(--spacing-5);
    max-width: 70ch;
}

#agentsGrid {
    margin-top: var(--spacing-4);
}

/* The queue is a table in a dialogue, so it needs its own width and a scroll
   of its own — the modal must not grow past the viewport on a narrow screen. */
.agent-queue-modal {
    max-width: 1100px;
    width: 95vw;
}

.agent-queue-modal .table-wrap {
    overflow-x: auto;
    max-height: 55vh;
    overflow-y: auto;
}

.agent-queue-modal th[data-sort] {
    cursor: pointer;
    white-space: nowrap;
}

.agent-queue-modal th[data-sort]:hover {
    color: var(--color-text);
}

/* The Queue and Mailbox buttons carry their counts inline, so the badge must
   not inherit the absolute positioning the nav badges use. */
#agentsQueueBtn .nav-badge,
#agentsMailboxBtn .nav-badge {
    position: static;
    margin-left: 4px;
}

/* The queue filters sit inline with the surrounding text rather than in a card
   — one dialogue inside another dialogue reads as clutter. Spacing above and
   below does the separating instead of a border. */
.agent-queue-filters {
    margin: var(--spacing-4) 0;
    padding: 0;
    border: none;
    background: none;
}

.agent-queue-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    margin-top: var(--spacing-3);
    flex-wrap: wrap;
}

.agent-queue-foot p {
    margin: 0;
}

/* Mailbox settings spacing: a paragraph that introduces a group of fields, and
   a field followed by a checkbox row, both need space the default form rhythm
   does not give them. */
.mailbox-intro {
    margin: 0 0 var(--spacing-4);
}

.mailbox-spaced {
    margin-bottom: var(--spacing-5);
}

/* Browsers indent a <ul> with padding, which the dialogue's own padding then
   swallows — so the markers end up flush with the text above and the list stops
   reading as a list. */
.mailbox-actions {
    margin: var(--spacing-2) 0 0;
    padding-left: var(--spacing-5);
    list-style: disc outside;
}

.mailbox-actions li {
    margin-bottom: var(--spacing-2);
    line-height: 1.5;
}

/* Before a mailbox exists the box shows a codename where an address will go.
   Dimmed so it does not read as an address that simply does not work. */
.agent-card-address-pending {
    opacity: 0.65;
    font-style: italic;
}

/* Holds the left-hand footer actions. Rendered even when everything inside it
   is hidden, so space-between keeps two children and the confirm buttons on
   the right stay where they are. */
.modal-footer-slot {
    min-height: 1px;
}

/* The mailbox footer carries what "Test connection" and a failed save have to
   say, in the slot beside the button rather than on a row of its own — a row
   appearing and disappearing moves the buttons under the pointer that just
   clicked them.

   The slot takes the free width and the note may shrink inside it, so a long
   connection error wraps within the footer instead of pushing Close and Save
   out of it. */
.mailbox-footer .modal-footer-slot {
    flex: 1;
    min-width: 0;
    align-items: center;
}

.mailbox-footer-note {
    min-width: 0;
    font-size: var(--font-size-sm);
}

/* A hint that needs air between it and the field above. <small> is inline, so
   it lands hard against the input; this gives it a line of its own with a gap
   rather than a literal <br>. */
.form-hint-spaced {
    display: block;
    margin-top: var(--spacing-3);
}

/* An input shown as part of a larger value: the fixed parts of the address sit
   either side of the editable middle. */
.input-affix {
    display: flex;
    align-items: center;
    gap: 0;
}

.input-affix .form-control {
    flex: 1;
    min-width: 0;
    border-radius: 0;
}

.input-affix .form-control:first-child {
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
}

.input-affix .form-control:last-child {
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}

.input-affix-part {
    padding: var(--spacing-2) var(--spacing-3);
    background: var(--color-bg-hover);
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    white-space: nowrap;
    font-size: var(--font-size-sm);
}

.input-affix-part:first-child {
    border-right: none;
    border-radius: var(--radius-md) 0 0 var(--radius-md);
}

.input-affix-part:last-child {
    border-left: none;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

/* Guidance you are meant to act on belongs before the box, not under it where
   it is read after the fact. */
.field-hint-above {
    display: block;
    margin: 0 0 var(--spacing-2);
}

/* When an agent has a personal name the box leads with it, and the role it
   owns sits underneath — both matter, and the name is what a sender uses. */
.agent-card-role {
    display: block;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin-top: 2px;
}

.agent-card-titles {
    min-width: 0;
}

/* "What to do" needs air above it when it follows the checks table; with no
   table it sits under the verdict box, which already has its own margin. */
.mailbox-actions-title {
    margin-top: var(--spacing-5);
}

/* "What ran", as a table. It set its own type a step down, from when it was six
   narrow columns fighting for width in a dialogue; paired into four, it does not
   need to, and the step made its first line smaller than the queue's beside it.
   Two tables in the same dialogue reading at two sizes look like one of them is
   wrong, and the reader is left working out which. Both take the table default
   now, and the sub-line is the only step down in either.

   The numbers stay right-aligned and tabular — a column of counts is read by
   comparing them, which needs the digits to line up. */
.task-steps td,
.task-steps th {
    white-space: nowrap;
}

.task-steps .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Two lines to a cell: what it was, and under it in lighter grey what it did or
   what that cost. Six narrow columns in a dialogue each wrapped somewhere, and a
   row that wraps in three places is read as three rows — stacked, the top line
   is the one the eye runs down and the rest hangs off it. */
.task-step-who,
.task-step-used {
    white-space: nowrap;
}
/* .task-step-what is styled with .queue-sub, further down — the queue table
   pairs its cells the same way and the two must not drift apart. */

/* A row that carries more opens onto it. Clickable in its own right, so it says
   so before it is clicked — a table where some rows do something and nothing
   distinguishes them is one where nobody finds out. */
.task-steps .task-step-row {
    cursor: pointer;
}

.task-steps .task-step-row:hover > td {
    background: var(--color-bg-subtle, #fafafa);
}

.task-steps .task-step-row:focus-visible {
    outline: 2px solid var(--color-success);
    outline-offset: -2px;
}

.task-step-more {
    color: var(--color-text-muted);
    font-size: 0.75em;
}

.task-steps .task-step-detail > td {
    background: var(--color-bg-subtle, #fafafa);
    /* The row above is nowrap because six columns in a dialogue do not fit
       otherwise. This one is prose and arguments, so it gives that up. */
    white-space: normal;
}

.task-step-field {
    display: flex;
    gap: var(--spacing-3);
    margin-bottom: var(--spacing-1);
}

.task-step-field:last-child {
    margin-bottom: 0;
}

/* A fixed label column, so the values line up and the eye runs down them
   instead of hunting for where each one starts. */
.task-step-key {
    flex: 0 0 8.5rem;
    color: var(--color-text-muted);
}

.task-step-val {
    /* Long enough to be worth reading and long enough to run off the side:
       min-width 0 is what lets a flex item wrap instead. */
    min-width: 0;
    word-break: break-word;
}

.task-step-args {
    min-width: 0;
}

.task-step-args code {
    margin-right: var(--spacing-2);
}

.task-step-args > div {
    word-break: break-word;
}

.task-steps-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    margin-top: var(--spacing-2);
    font-size: var(--font-size-sm);
}

/* The address copies on click, so it needs to look clickable in its own right
   inside a box that is itself one big button. */
.agent-card-address {
    cursor: copy;
}

.agent-card-address:hover {
    color: var(--color-text);
}

/* …except before a mailbox exists, when it is only a codename and the click
   belongs to the box. */
.agent-card-address-pending {
    cursor: pointer;
}

/* Queue rows open the conversation's technical record. */
.queue-row {
    cursor: pointer;
}

.queue-row:hover,
.queue-row:focus-visible {
    background: var(--color-bg-hover);
}

/* The second line of a paired cell: what the conversation was about, under who
   it was with, and what it cost under how much was said. Quieter than the line
   it hangs under, or the pair reads as two facts of equal weight and the column
   stops having a subject. Shares the rule with the step table's sub-line rather
   than copying it, so the two cannot drift apart. */
.queue-sub,
.task-step-what {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    /* The sub-line carries a refusal reason or a list of clients, either of
       which is longer than the line above: it is the part of the row allowed to
       wrap. */
    white-space: normal;
}

/* An empty sub-line still holds the row's height, so rows with and without one
   do not step up and down the table. */
.queue-sub:empty::after,
.task-step-what:empty::after {
    content: '\00a0';
}

/* A cost is one number: "$0.0043" wrapped after the dollar sign is unreadable
   and, worse, briefly reads as a different amount. It is also a sub-line now,
   and .queue-sub above lets a sub-line wrap — so this has to come after it to
   take the permission back. */
.queue-cost {
    white-space: nowrap;
}

/* A header line is a sort control whether or not it is the whole cell. */
#queueTable thead [data-sort] {
    cursor: pointer;
}

/* Only the stacked lines are made into blocks — four of the headers carry
   data-sort on the th itself, and a th set to display: block leaves the table
   layout entirely, taking the header row with it. */
#queueTable thead span[data-sort] {
    display: block;
}
