﻿/* ── Self-hosted font (CSP font-src 'self' — no external font CDNs) ─────
   Inter variable covers the whole UI (weights 300-700, latin + punctuation
   subset, 34 KB). Subset from the upstream fontsource build with fonttools
   (pyftsubset; unused glyphs and weight ranges trimmed). Files live in
   /static/fonts/ and are preloaded from the page <head>. License: SIL OFL
   1.1 (LICENSE-*.txt next to the font files). */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('fonts/inter-latin-wght-normal.woff2') format('woff2');
}

/* ── Edge portal — unified display type scale (16px root) ──────────────
   UI: 11 / 12 / 13 / 14 / 16 px. Display: 20 / 24 px.
   Dormant heading steps (h2/h3 defaults, no live usage): 28 px.
   Body stays .875rem. Theme-independent: never declare sizes under
   [data-theme]; both themes resolve through these tokens. */
:root {
  --fs-micro:      0.6875rem; /* 11px — uppercase micro-labels, chips, data-labels (FLOOR) */
  --fs-caption:    0.75rem;   /* 12px — captions, timestamps, table headers, hints, badges */
  --fs-compact:    0.8125rem; /* 13px — tables, buttons, inputs, tabs, alerts, dense rows */
  --fs-body:       0.875rem;  /* 14px — default body / card content (unchanged) */
  --fs-lead:       1rem;      /* 16px — card titles, topbar/dialog titles, small numerals */
  --fs-title:      1.25rem;   /* 20px — section/page titles (h5), ring numerals */
  --fs-display:    1.5rem;    /* 24px — KPI/display numerals */
  --fs-display-lg: 1.75rem;   /* 28px — h2/h3 heading steps (legacy) */
  --fs-hero:       2rem;      /* 32px — h1 heading step (legacy) */
}
:root {
    --sidebar-w: 264px;
    --bg: #f1f5f9;
    --surface: #ffffff;
    --surface-alt: #f8fafc;
    --sidebar: #0b1524;
    --sidebar-hover: #16233a;
    --sidebar-active: #1e3a5f;
    --accent: #1156fd;
    --accent-light: #ecf1ff;
    --accent-hover: #0a3fd8;
    --success: #16a34a;
    --success-light: #f0fdf4;
    --danger: #dc2626;
    --danger-light: #fef2f2;
    --warning: #d97706;
    --warning-light: #fffbeb;
    --text: #0f172a;
    --text-secondary: #475569;
    --text-muted: #64748b;
    --border: #e2e8f0;
    --border-light: #f1f5f9;
    --radius: 10px;
    --radius-sm: 8px;
    --radius-xs: 6px;
    --shadow-xs: 0 1px 2px rgba(15,23,42,.04);
    --shadow-sm: 0 1px 3px rgba(15,23,42,.06), 0 1px 2px rgba(15,23,42,.04);
    --shadow: 0 4px 12px -2px rgba(15,23,42,.08), 0 2px 4px -2px rgba(15,23,42,.04);
    --shadow-md: 0 8px 20px -4px rgba(15,23,42,.10), 0 4px 8px -4px rgba(15,23,42,.06);
    --shadow-lg: 0 16px 32px -8px rgba(15,23,42,.16), 0 8px 16px -8px rgba(15,23,42,.08);
    --transition: 150ms cubic-bezier(.4,0,.2,1);
    /* Action colors (same in both themes). Success uses the darker shade so
       white button/badge text meets WCAG AA (5.0:1). */
    --action-success: #15803d;
    --action-success-hover: #166534;
    --action-warning: #d97706;
    --action-warning-hover: #b45309;
    --action-danger: #dc2626;
    --action-danger-hover: #b91c1c;
    /* Notification severity palette — the ONLY place a notification gets its
       colour. Light values here; dark overrides in [data-theme="dark"].
       Consumed once by the .ntf--* rules below. */
    --ntf-success-bg: #f0fdf4; --ntf-success-strip: #16a34a; --ntf-success-chip: #dcfce7; --ntf-success-fg: #15803d; --ntf-success-line: rgba(22,163,74,.22);
    --ntf-info-bg: #ecf1ff;    --ntf-info-strip: #1156fd;    --ntf-info-chip: #dbe6ff;    --ntf-info-fg: #1156fd;    --ntf-info-line: rgba(17,86,253,.22);
    --ntf-warning-bg: #fffbeb; --ntf-warning-strip: #d97706; --ntf-warning-chip: #fef3c7; --ntf-warning-fg: #b45309; --ntf-warning-line: rgba(217,119,6,.26);
    --ntf-danger-bg: #fef2f2;  --ntf-danger-strip: #dc2626;  --ntf-danger-chip: #fee2e2;  --ntf-danger-fg: #b91c1c;  --ntf-danger-line: rgba(220,38,38,.24);
}

[data-theme="dark"] {
    --bg: #0f172a;
    --surface: #1e293b;
    --surface-alt: #24334a;
    --sidebar: #0b1524;
    --sidebar-hover: #17263d;
    --sidebar-active: #1e3a5f;
    --accent: #5b8cff;
    --accent-light: rgba(91,140,255,.15);
    --accent-hover: #3b6ef5;
    --success: #4ade80;
    --success-light: rgba(74,222,128,.13);
    --danger: #f87171;
    --danger-light: rgba(248,113,113,.13);
    --warning: #fbbf24;
    --warning-light: rgba(251,191,36,.13);
    --text: #e2e8f0;
    --text-secondary: #a3b1c6;
    --text-muted: #94a3b8;
    --border: #334155;
    --border-light: #2b3a52;
    --shadow-xs: 0 1px 2px rgba(0,0,0,.3);
    --shadow-sm: 0 1px 3px rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.3);
    --shadow: 0 4px 12px -2px rgba(0,0,0,.45), 0 2px 4px -2px rgba(0,0,0,.3);
    --shadow-md: 0 8px 20px -4px rgba(0,0,0,.5), 0 4px 8px -4px rgba(0,0,0,.35);
    --shadow-lg: 0 16px 32px -8px rgba(0,0,0,.55), 0 8px 16px -8px rgba(0,0,0,.35);
    --ntf-success-bg: rgba(74,222,128,.10); --ntf-success-strip: #4ade80; --ntf-success-chip: rgba(74,222,128,.18); --ntf-success-fg: #86efac; --ntf-success-line: rgba(74,222,128,.26);
    --ntf-info-bg: rgba(91,140,255,.13);    --ntf-info-strip: #5b8cff;    --ntf-info-chip: rgba(91,140,255,.20);    --ntf-info-fg: #93c5fd;    --ntf-info-line: rgba(91,140,255,.30);
    --ntf-warning-bg: rgba(251,191,36,.10); --ntf-warning-strip: #fbbf24; --ntf-warning-chip: rgba(251,191,36,.20); --ntf-warning-fg: #fcd34d; --ntf-warning-line: rgba(251,191,36,.28);
    --ntf-danger-bg: rgba(248,113,113,.10); --ntf-danger-strip: #f87171; --ntf-danger-chip: rgba(248,113,113,.20); --ntf-danger-fg: #fca5a5; --ntf-danger-line: rgba(248,113,113,.30);
}

*, *::before, *::after { box-sizing: border-box; }

/* Form controls do not inherit the page font by default (browsers fall back
   to Arial / the OS control font); pull them into the Inter stack. Font sizes
   stay governed by .btn / .form-control / .form-select as before. */
button, input, optgroup, select, textarea { font-family: inherit; }

/* Controls skip the double-tap-zoom gesture on iOS (pinch-zoom stays). */
a, button, [role="button"], input, select, textarea, label { touch-action: manipulation; }

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    background: var(--bg);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-size: .875rem;
}

::selection { background: rgba(17,86,253,.18); }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ── Sidebar ── */
.sidebar {
    width: var(--sidebar-w);
    background: var(--sidebar);
    color: #e2e8f0;
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 1030;
    padding: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid rgba(255,255,255,.06);
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 20px 18px 22px;
    border-bottom: 1px solid rgba(255,255,255,.06);
    margin-bottom: 10px;
}

.brand-icon {
    width: 42px; height: 42px;
    background: var(--accent);
    border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.25rem; flex-shrink: 0;
    box-shadow: 0 4px 12px rgba(17,86,253,.35);
}

.brand-logo {
    height: 26px; width: auto; display: block;
    filter: drop-shadow(0 2px 6px rgba(17,86,253,.35));
}

.brand-logo-lg {
    height: 40px; width: auto; display: block; margin: 0 auto 14px;
    filter: drop-shadow(0 4px 12px rgba(17,86,253,.3));
}

.brand-text {
    font-weight: 700; font-size: .875rem; line-height: 1.3;
    color: #fff;
    letter-spacing: -.01em;
}

.brand-version {
    display: inline-block; font-size: .6875rem; font-weight: 600;
    color: #94a3b8; margin-top: 3px;
    background: rgba(255,255,255,.08);
    padding: 1px 8px; border-radius: 100px;
}

.sidebar-brand .brand-version { margin-left: auto; }

.sidebar .nav { padding: 0 10px; flex: 1; overflow-y: auto; }

/* Sidebar section labels and link text sit at 62% white on the #0b1524 rail
   (~7.5:1) so the nav holds up on glare-prone on-site screens; 11px labels at
   46% white were at the AA floor (~4.7:1). */
.nav-section {
    font-size: .75rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .1em; color: rgba(255,255,255,.62);
    padding: 16px 12px 6px;
}

.sidebar .nav-link {
    color: rgba(255,255,255,.62);
    border-radius: 10px;
    padding: 9px 12px;
    font-weight: 500; font-size: .8125rem;
    transition: all var(--transition);
    margin-bottom: 2px;
    position: relative;
    display: flex; align-items: center; gap: 10px;
}

.sidebar .nav-link i {
    font-size: 1rem; width: 20px; text-align: center; opacity: .75;
}

.sidebar .nav-link:hover {
    color: #e2e8f0; background: var(--sidebar-hover);
}

.sidebar .nav-link.active {
    color: #fff; background: rgba(17,86,253,.22);
    font-weight: 600;
}

.sidebar .nav-link.active::before {
    content: '';
    position: absolute; left: -10px; top: 50%; transform: translateY(-50%);
    width: 3px; height: 20px; background: var(--accent);
    border-radius: 0 3px 3px 0;
}

.sidebar .nav-link.active i { opacity: 1; }

.sidebar-footer {
    padding: 14px 14px; border-top: 1px solid rgba(255,255,255,.06);
}

.status-dot {
    width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
    box-shadow: 0 0 0 3px rgba(255,255,255,.05);
}
.status-unknown { background: #64748b; }
.status-running { background: #22c55e; box-shadow: 0 0 0 3px rgba(34,197,94,.18); }
.status-starting { background: var(--accent); box-shadow: 0 0 0 3px rgba(17,86,253,.15); }
.status-stopped { background: #64748b; box-shadow: 0 0 0 3px rgba(100,116,139,.16); }
[data-theme="dark"] .status-stopped { background: #94a3b8; }
.status-error { background: var(--danger); animation: error-blink 1.5s infinite; }

@keyframes error-blink {
    0%, 100% { opacity: 1; }
    50% { opacity: .35; }
}

.sidebar-user { display: flex; align-items: center; gap: 10px; }

.user-avatar {
    width: 34px; height: 34px;
    background: var(--accent);
    border-radius: 50%; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: .75rem; color: #fff; flex-shrink: 0;
}

.user-name { font-size: .75rem; color: rgba(255,255,255,.7); line-height: 1.2; font-weight: 600; }

/* ── Main Content ── */
.main-content {
    margin-left: var(--sidebar-w);
    min-height: 100vh;
    display: flex; flex-direction: column;
}

.topbar {
    position: sticky; top: 0; z-index: 1020;
    background: rgba(255,255,255,.85);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--border);
    padding: 14px 32px;
    display: flex; align-items: center; gap: 12px;
}
[data-theme="dark"] .topbar { background: rgba(15,23,42,.85); }

.topbar-title {
    font-size: 1rem; font-weight: 700; letter-spacing: -.01em;
    margin: 0;
}

.topbar-crumb { display: flex; align-items: baseline; gap: 8px; }
.topbar-root {
    font-size: .75rem; font-weight: 500; color: var(--text-muted);
}
.topbar-sep { color: var(--border); font-weight: 300; }

.topbar-sub {
    font-size: .75rem; color: var(--text-muted); font-weight: 500;
}

.topbar-status {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 100px; padding: 5px 14px; font-size: .75rem; font-weight: 600;
    color: var(--text-secondary);
}

.topbar-status .status-dot { width: 8px; height: 8px; }

/* The pill links to the dashboard: quiet at rest, tinted on hover/focus. */
a.topbar-status { text-decoration: none; cursor: pointer; transition: border-color var(--transition), background var(--transition); }
a.topbar-status:hover { border-color: var(--accent); background: var(--accent-light); }
a.topbar-status:hover #topbar-restart-req,
a.topbar-status:focus-visible #topbar-restart-req { text-decoration: underline; }
a.topbar-status:hover #topbar-restart-req::after,
a.topbar-status:focus-visible #topbar-restart-req::after { content: " \2192"; }
a.topbar-status:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Onboarding job chip: pill containing a link plus an optional dismiss. */
.topbar-status-actionable { padding-right: 8px; gap: 6px; }
.topbar-status-link { display: flex; align-items: center; gap: 8px; color: inherit; text-decoration: none; }
.topbar-status:has(.topbar-status-link:hover) { border-color: var(--accent); background: var(--accent-light); }
.topbar-status-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 100px; }
.topbar-status-x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 20px; height: 20px; padding: 0; border: 0; border-radius: 50%;
    background: transparent; color: var(--text-muted); cursor: pointer; flex-shrink: 0;
}
.topbar-status-x:hover { color: var(--text-secondary); background: var(--border); }
.topbar-status-x .icon { width: 11px; height: 11px; }
/* Badge + stamp together can overflow tiny phones: the badge wins. */
@media (max-width: 560px) {
    .topbar-status:has(#topbar-restart-req:not(.d-none)) .tstamp { display: none; }
}
/* Compact "Checked" stamp inside the pill (phones only). */
.topbar-status .tstamp { color: var(--text-muted); font-weight: 500; }
.topbar-status .tstamp::before { content: "\00b7\00a0"; }

.insight-filter {
    flex-shrink: 0;
}

#intelligence-page { color: var(--text); }
#intelligence-page .card { --bs-card-color: var(--text); color: var(--text); }

.insight-row {
    display: flex; gap: 12px; padding: 13px 0;
    border-bottom: 1px solid var(--border-light);
}
.insight-row:last-of-type { border-bottom: none; }
.insight-row .sev-icon { font-size: 1rem; margin-top: 1px; flex-shrink: 0; }
.insight-row .body { min-width: 0; }
.insight-row .t { font-size: .8125rem; font-weight: 700; }
.insight-row .d { font-size: .75rem; color: var(--text-secondary); margin-top: 1px; }
.insight-row .ts { font-size: .6875rem; color: var(--text-muted); margin-top: 3px; font-variant-numeric: tabular-nums; }
.insight-row .tags { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; align-items: center; }
.insight-tag { text-decoration: none; }
.insight-tag.time { background: var(--surface-alt); color: var(--text-muted); }
.insight-tag.link { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.insight-tag.link:hover { text-decoration: underline; }
.insight-tag.danger-soft { background: var(--danger-light); border-color: transparent; color: var(--danger); cursor: pointer; }
.insight-tag.danger-soft:hover { text-decoration: underline; }
.insight-row .hint {
    font-size: .75rem; color: var(--text-secondary); margin-top: 4px;
    display: flex; align-items: flex-start; gap: 4px;
}

/* Equipment fleet */
.mono { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }
.fleet-summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.fleet-summary.cols-5 { grid-template-columns: repeat(5, 1fr); }
.fleet-summary.cols-6 { grid-template-columns: repeat(6, 1fr); }
.fleet-tile {
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 8px; padding: 7px 3px; text-align: center; min-width: 0;
}
.fleet-tile .n { font-size: 1rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.fleet-tile .l {
    font-size: .6875rem; color: var(--text-muted); margin-top: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fleet-tile.ok .n { color: var(--success); }
.fleet-tile.warn .n { color: var(--warning); }
.fleet-tile.high .n { color: #f97316; }
.fleet-tile.info .n { color: var(--accent); }
.fleet-tile.err .n { color: var(--danger); }
.fleet-tile.na .n { color: var(--text-muted); }
.fleet-tile.clickable { cursor: pointer; transition: filter .15s ease; }
.fleet-tile.clickable:hover { filter: brightness(.9); }
.fleet-tile.clickable.active { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Fleet status badge — canonical badge family (metrics/typography come from
   the family base; success tone follows the shared success recipe). */
.fleet-badge.b-active { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.fleet-badge.b-partial { background: var(--warning-light); border-color: transparent; color: var(--warning); }
.fleet-badge.b-no-data { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.fleet-badge.b-unknown { background: var(--surface-alt); color: var(--text-muted); }
.ev-line-link { margin-left: auto; color: var(--accent); text-decoration: none; font-weight: 600; white-space: nowrap; }
.ev-line-link:hover { text-decoration: underline; }
.sparkline { display: block; width: 100%; height: 26px; margin: 2px 0 2px; }
.sparkline path { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: .85; }
.sparkline .dot { fill: var(--accent); }
.sparkline .hit { fill: transparent; cursor: crosshair; }
.spark-wrap { position: relative; }
.spark-tip {
    display: none; position: absolute; top: -24px; z-index: 30;
    background: var(--surface-alt); border: 1px solid var(--border); border-radius: 6px;
    padding: 3px 8px; font-size: .6875rem; color: var(--text);
    white-space: nowrap; pointer-events: none;
    box-shadow: 0 2px 8px rgba(0,0,0,.35);
    transform: translateX(-50%);
}
.spark-caption { font-size: .6875rem; color: var(--text-muted); margin-bottom: 6px; }
.trend-group {
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-top: 8px;
    padding: 10px 12px;
}
.trend-group:first-child { margin-top: 0; }
.trend-sep { border-top: 2px solid var(--border); margin: 8px 0; }
.trend-group-title {
    font-size: .6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
    color: var(--text); margin-bottom: 5px;
}
.risk-eq { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.risk-info { cursor: help; font-size: .75rem; color: #f4b400; }
.risk-info .icon { width: 15px; height: 15px; vertical-align: -2px; }
.cf-title .risk-info { display: inline-flex; align-items: center; }
.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.sortable:hover { color: var(--accent); }
.sort-icon { font-size: .75rem; }
.risk-n { color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.risk-meta-row td { border-top: none; padding-top: 0; }
.risk-tier.low { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.risk-tier.medium { background: var(--warning-light); border-color: transparent; color: var(--warning); }
.risk-tier.high, .risk-tier.critical { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.risk-bar-wrap { display: flex; align-items: center; gap: 6px; }
.risk-bar { display: block; width: 52px; height: 4px; background: var(--surface-alt); border: 1px solid var(--border); border-radius: 100px; overflow: hidden; }
.risk-bar-fill { display: block; height: 100%; border-radius: 100px; }
.risk-bar-fill.low { background: var(--success); }
.risk-bar-fill.medium { background: var(--warning); }
.risk-bar-fill.high { background: #f97316; }
.risk-bar-fill.critical { background: var(--danger); }
.risk-factors { display: flex; gap: 4px; flex-wrap: wrap; }
.risk-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 2px 0 5px; }
.risk-delta.up { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.risk-delta.down { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.risk-delta.new { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.risk-since { font-size: .6875rem; color: var(--text-muted); white-space: nowrap; }
.anom-pt { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anom-since { color: var(--text-muted); white-space: nowrap; }
.anom-badge.stuck { background: var(--warning-light); border-color: transparent; color: var(--warning); }
.anom-badge.out_of_band { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.anom-badge.step { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.anom-badge.normal { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.anom-badge.no_data { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.trend-note { font-size: .6875rem; color: var(--text-muted); }

/* flex-basis auto (not 0) so the area grows to its content; otherwise long
   pages overflow it and the footer lands on top of the content. */
.content-area { flex: 1 1 auto; padding: 28px 32px 40px !important; }

.main-footer {
    border-top: 1px solid var(--border);
    padding: 12px 0; font-size: .75rem; color: var(--text-muted);
}

/* ── Page Headings ── */
.page-heading {
    font-size: 1.5rem; font-weight: 700;
    color: var(--text); margin-bottom: 24px;
    letter-spacing: -.02em;
}

/* ── Cards ── */
.card {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
    background: var(--surface);
    transition: box-shadow var(--transition), border-color var(--transition);
}

.card:hover { box-shadow: var(--shadow); }

.card-header {
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius) var(--radius) 0 0 !important;
    padding: 14px 20px; font-weight: 600; font-size: .875rem;
    letter-spacing: -.01em;
    color: var(--text);
}

.card-body { padding: 20px; }

/* ── Stat Cards ── */
.stat-card {
    text-align: center;
    border: 1px solid var(--border);
    overflow: hidden;
}
.stat-card .card-body { padding: 22px 16px; }
.stat-card .stat-icon {
    width: 44px; height: 44px; margin: 0 auto 10px;
    border-radius: 12px;
    background: var(--accent-light);
    color: var(--accent);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.25rem;
}
.stat-card .stat-value {
    font-size: 1.5rem; font-weight: 700; color: var(--text);
    line-height: 1.2; margin-bottom: 4px; letter-spacing: -.02em;
}
.stat-card .stat-label {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .09em; color: var(--text-muted);
}

/* ── Health Cards ── */
.health-card { border-top: 3px solid var(--border); }
.health-card .card-body { padding: 18px 20px; }
.health-info { min-width: 0; }
.health-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 8px;
}
.health-title {
    font-size: .8125rem; font-weight: 700; color: var(--text);
    display: flex; align-items: center;
}
.health-value {
    font-size: 1rem; font-weight: 700; letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
}
.health-title i { font-size: .875rem; color: var(--text-muted); }
.health-desc { font-size: .75rem; color: var(--text-muted); }
.health-bar {
    height: 5px; border-radius: 100px;
    background: var(--surface-alt); overflow: hidden;
}
.health-bar .health-bar-fill {
    height: 100%; border-radius: 100px;
    background: var(--accent);
    transition: width .6s cubic-bezier(.4,0,.2,1), background .3s;
}
.health-bar .health-bar-fill.low { background: var(--success); }
.health-bar .health-bar-fill.mid { background: var(--warning); }
.health-bar .health-bar-fill.high { background: var(--danger); }

/* ── Health / Progress ── */
.health-bar {
    height: 6px; margin-top: 10px;
    background: var(--surface-alt); border-radius: 100px; overflow: hidden;
}
.health-bar-fill {
    height: 100%; border-radius: 100px;
    background: var(--accent);
    transition: width .6s cubic-bezier(.4,0,.2,1), background .3s;
}
.health-bar-fill.low { background: var(--success); }
.health-bar-fill.mid { background: var(--warning); }
.health-bar-fill.high { background: var(--danger); }

/* ── Buttons ── */
.btn {
    font-weight: 500; font-size: .8125rem;
    border-radius: var(--radius-sm); padding: .5rem 1rem;
    transition: all var(--transition);
}

.btn-primary {
    background: var(--accent); border-color: var(--accent); color: #fff;
}
.btn-primary:hover {
    background: var(--accent-hover); border-color: var(--accent-hover);
    box-shadow: 0 2px 8px rgba(17,86,253,.28);
}
/* Dark theme: white on the light #5b8cff accent is only 3.2:1, so the solid
   primary uses a deeper blue that keeps white text at 5.3:1. */
[data-theme="dark"] .btn-primary { background: #2f62e0; border-color: #2f62e0; }
[data-theme="dark"] .btn-primary:hover { background: #2452c4; border-color: #2452c4; }

.btn-success { background: var(--action-success); border-color: var(--action-success); color: #fff; }
.btn-success:hover { background: var(--action-success-hover); border-color: var(--action-success-hover); box-shadow: 0 2px 8px rgba(22,163,74,.25); }

/* #b45309 keeps white button text at 5.0:1; the #d97706 token stays for
   badges that pair it with dark text. */
.btn-warning { background: #b45309; border-color: #b45309; color: #fff; }
.btn-warning:hover { background: #92400e; border-color: #92400e; box-shadow: 0 2px 8px rgba(180,83,9,.25); }

.btn-danger { background: var(--action-danger); border-color: var(--action-danger); color: #fff; }
.btn-danger:hover { background: var(--action-danger-hover); border-color: var(--action-danger-hover); box-shadow: 0 2px 8px rgba(220,38,38,.25); }

.btn-outline-secondary { border-color: var(--border); color: var(--text-secondary); }
.btn-outline-secondary:hover { background: var(--bg); color: var(--text); border-color: #cbd5e1; }
[data-theme="dark"] .btn-outline-secondary:hover { border-color: var(--border); background: var(--surface-alt); }

[data-theme="dark"] .btn-outline-primary {
    --bs-btn-color: #5b8cff; --bs-btn-border-color: #5b8cff;
    --bs-btn-hover-bg: #3b6ef5; --bs-btn-hover-border-color: #3b6ef5; --bs-btn-hover-color: #fff;
    --bs-btn-active-bg: #1156fd; --bs-btn-active-border-color: #1156fd; --bs-btn-active-color: #fff;
}
[data-theme="dark"] .btn-outline-success {
    --bs-btn-color: #4ade80; --bs-btn-border-color: #22c55e;
    --bs-btn-hover-bg: #22c55e; --bs-btn-hover-border-color: #22c55e; --bs-btn-hover-color: #0f172a;
    --bs-btn-active-bg: #16a34a; --bs-btn-active-border-color: #16a34a; --bs-btn-active-color: #fff;
}
[data-theme="dark"] .btn-outline-warning {
    --bs-btn-color: #fbbf24; --bs-btn-border-color: #f59e0b;
    --bs-btn-hover-bg: #f59e0b; --bs-btn-hover-border-color: #f59e0b; --bs-btn-hover-color: #0f172a;
    --bs-btn-active-bg: #d97706; --bs-btn-active-border-color: #d97706; --bs-btn-active-color: #fff;
}
[data-theme="dark"] .btn-outline-danger {
    --bs-btn-color: #fca5a5; --bs-btn-border-color: #ef4444;
    --bs-btn-hover-bg: #ef4444; --bs-btn-hover-border-color: #ef4444; --bs-btn-hover-color: #fff;
    --bs-btn-active-bg: #dc2626; --bs-btn-active-border-color: #dc2626; --bs-btn-active-color: #fff;
}
[data-theme="dark"] .btn-link { color: #5b8cff; }

.btn-sm { padding: .32rem .7rem; font-size: .75rem; }

.btn:disabled, .btn.disabled {
    opacity: .4; pointer-events: none; box-shadow: none !important;
}

/* ── Badges ──
   .badge and the .bg-* helpers below are badge-only in this portal and are
   restyled as canonical badge-family tints; the shared base (metrics,
   typography, neutral skin) lives with the canonical badge family rules at
   the end of this file. */
.bg-info { background: var(--accent-light) !important; color: var(--accent) !important; border-color: transparent; }
.bg-success { background: var(--success-light) !important; color: var(--action-success) !important; border-color: transparent; }
.bg-danger { background: var(--danger-light) !important; color: var(--danger) !important; border-color: transparent; }
.bg-warning { background: var(--warning-light) !important; color: var(--warning) !important; border-color: transparent; }
.bg-secondary { background: var(--surface-alt) !important; color: var(--text-muted) !important; }

/* ── Forms ── */
.form-control, .form-select {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm); padding: .5rem .8rem;
    font-size: .8125rem; transition: border-color var(--transition), box-shadow var(--transition);
    background: var(--surface); color: var(--text);
}

.form-select {
    background-color: var(--surface);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 10px center; padding-right: 2rem;
    cursor: pointer; appearance: none;
}

.form-control:focus, .form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(17,86,253,.12);
    outline: none;
    background: var(--surface);
    color: var(--text);
}

/* Browser autofill paints a white background/text over inputs — keep theme colors */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
    transition: background-color 9999s ease-in-out 0s;
}

/* Native date/time pickers follow the theme */
[data-theme="dark"] input[type="datetime-local"],
[data-theme="dark"] input[type="date"],
[data-theme="dark"] input[type="time"] { color-scheme: dark; }
[data-theme="light"] input[type="datetime-local"],
[data-theme="light"] input[type="date"],
[data-theme="light"] input[type="time"] { color-scheme: light; }

.form-control::placeholder { color: var(--text-muted); }

/* ── File inputs (theme-aware) ── */
input[type="file"].form-control {
    color: var(--text-secondary);
    background: var(--surface);
    padding: .35rem .5rem;
    cursor: pointer;
}
input[type="file"].form-control::-webkit-file-upload-button,
input[type="file"].form-control::file-selector-button {
    background: var(--surface-alt);
    color: var(--text-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    padding: .3rem .7rem;
    margin-right: .6rem;
    font-size: .75rem;
    font-weight: 600;
    cursor: pointer;
    transition: all var(--transition);
}
input[type="file"].form-control:hover::-webkit-file-upload-button,
input[type="file"].form-control:hover::file-selector-button {
    background: var(--accent-light);
    color: var(--accent);
    border-color: var(--accent);
}

.form-label {
    font-size: .75rem; font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase; letter-spacing: .05em;
    margin-bottom: 6px;
}

.input-group-text {
    background: var(--surface-alt); border: 1px solid var(--border);
    color: var(--text-muted); font-size: .8125rem;
}

/* ── Tables ── */
.table {
    --bs-table-bg: var(--surface);
    --bs-table-color: var(--text);
    --bs-table-border-color: var(--border-light);
    --bs-table-hover-bg: var(--accent-light);
    --bs-table-hover-color: var(--text);
    --bs-table-striped-bg: var(--surface-alt);
    --bs-table-striped-color: var(--text);
    font-size: .8125rem; margin-bottom: 0;
}
.table thead th {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .07em; color: var(--text-muted);
    background: var(--surface-alt); border-bottom: 1px solid var(--border);
    padding: 10px 14px;
    position: sticky; top: 0; z-index: 2;
}
.table tbody td {
    padding: 10px 14px; vertical-align: middle;
    border-bottom: 1px solid var(--border-light);
}
.table-hover tbody tr { transition: background var(--transition); }
.table-hover tbody tr:hover td { background: var(--accent-light); }
.table-sm th, .table-sm td { padding: 7px 12px; }

/* ── Nav Tabs (single definition; .tab-pane rules live further down) ── */
.nav-tabs {
    border-bottom: 2px solid var(--border);
    display: flex; gap: 4px; padding: 0; list-style: none; margin-bottom: 1rem;
}
.nav-tabs .nav-link {
    display: inline-flex; align-items: center;
    border: none; color: var(--text-muted); text-decoration: none;
    font-weight: 500; font-size: .8125rem; padding: 10px 18px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    transition: all var(--transition);
    position: relative;
}
.nav-tabs .nav-link:hover { color: var(--text); background: var(--surface-alt); }
.nav-tabs .nav-link.active {
    color: var(--accent); background: var(--accent-light);
    font-weight: 600;
}
.nav-tabs .nav-link.active::after {
    content: ''; position: absolute; bottom: -2px; left: 0; right: 0;
    height: 2px; background: var(--accent);
}

/* ── Terminal / Gateway Output ── */
.log-terminal {
    background: #0f172a;
    color: #cbd5e1;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
    font-size: .75rem; line-height: 1.65;
    /* No <pre> margin, minimal top padding: the first line sits right under
       the titlebar instead of floating below it. */
    margin: 0;
    padding: 3px 20px 14px; border-radius: 0 0 var(--radius) var(--radius);
    overflow-y: auto; height: calc(100vh - 265px); white-space: pre-wrap;
    /* Long unbroken payload tokens must not push the terminal sideways. */
    overflow-wrap: anywhere;
    -webkit-overflow-scrolling: touch;
    border: 1px solid #1e293b; border-top: none;
}

.terminal-window {
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    border: 1px solid #1e293b;
}

/* Gateway output: "searching journal" indicator. The bar is a sibling of the
   swapped region, so htmx keeps the .htmx-request class on it while a gateway
   request (which can scan the whole journal) is in flight. It is pinned to the
   top of the output area - a centred overlay would be off-screen whenever the
   output is long - and sticks while the reader scrolls that area. */
.gw-output-wrap { position: relative; min-height: 0; }
.search-overlay {
    display: none;
    position: sticky; top: 0; z-index: 6;
    margin-bottom: -32px;   /* overlay the first row instead of shifting it */
    align-items: center; justify-content: center; gap: 8px;
    padding: 6px 10px;
    background: rgba(15, 23, 42, .92);
    border-bottom: 1px solid rgba(148, 163, 184, .25);
    color: #e2e8f0; font-size: .75rem; font-weight: 500;
    pointer-events: none;
}
.search-overlay.htmx-request { display: flex; }

/* Loading state for drawer content (e.g. the transaction entry detail). */
.drawer-loading {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    padding: 48px 16px; color: var(--text-muted); font-size: .8125rem;
}

/* Settings -> gateway logs card (file rotation and journald variants). */
.rot-stats { display: flex; flex-wrap: wrap; gap: 8px; }
.rot-stat {
    flex: 1 1 140px; min-width: 0;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-alt); padding: 8px 10px;
}
.rot-stat-key {
    display: block; font-size: .6875rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted);
}
.rot-stat-val {
    display: block; font-size: .8125rem; font-weight: 600;
    overflow-wrap: anywhere;
}
.rot-file-list {
    max-height: 190px; overflow-y: auto;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-alt);
}
.rot-file-row {
    display: flex; justify-content: space-between; align-items: center;
    gap: 10px; padding: 5px 10px; font-size: .75rem;
}
.rot-file-row + .rot-file-row { border-top: 1px solid var(--border-light); }
.rot-file-name { min-width: 0; }
.rot-file-size { white-space: nowrap; }

.terminal-titlebar {
    background: #1e293b;
    padding: 8px 14px 7px;
    display: flex; align-items: center; gap: 8px;
}

.terminal-titlebar .title {
    color: #94a3b8; font-size: .75rem; font-weight: 600;
    letter-spacing: .03em;
}

.terminal-titlebar .spacer { flex: 1; }

.gw-warning { color: #facc15; }
.gw-error { color: #f87171; }
.gw-highlight { background: #facc15; color: #0f172a; padding: 0 2px; border-radius: 2px; font-weight: 600; }

#integration-restart-alert .ntf__link { color: var(--accent); text-decoration: underline; font-weight: 700; }

/* ── Structured log line ── */
.gw-time { color: #64748b; }
.gw-sep { color: #334155; }
.gw-level { font-weight: 700; }
.gw-level-info { color: #38bdf8; }
.gw-level-warning { color: #facc15; }
.gw-level-error { color: #f87171; }

.buffer-pending td { background: var(--warning-light) !important; }

/* ── Unified notification component (.ntf) ────────────────────────────
   One container · severity via --ntf-* custom properties (declared once in
   :root / [data-theme="dark"]) · context via modifiers. Shared by page
   banners, flash messages, inline validation, dialogs and toasts. */
.ntf {
    --ntf-bg: var(--surface); --ntf-strip: var(--accent); --ntf-chip: var(--accent-light);
    --ntf-fg: var(--accent); --ntf-line: var(--border);
    position: relative; display: flex; gap: 12px; align-items: flex-start;
    background: var(--ntf-bg); color: var(--text);
    border: 1px solid var(--ntf-line); border-left: 4px solid var(--ntf-strip);
    border-radius: var(--radius); padding: 12px 16px;
    box-shadow: var(--shadow-xs); font-size: .8125rem; line-height: 1.5;
    animation: ntf-in .2s cubic-bezier(.4, 0, .2, 1);
}
.ntf--success { --ntf-bg: var(--ntf-success-bg); --ntf-strip: var(--ntf-success-strip); --ntf-chip: var(--ntf-success-chip); --ntf-fg: var(--ntf-success-fg); --ntf-line: var(--ntf-success-line); }
.ntf--info    { --ntf-bg: var(--ntf-info-bg);    --ntf-strip: var(--ntf-info-strip);    --ntf-chip: var(--ntf-info-chip);    --ntf-fg: var(--ntf-info-fg);    --ntf-line: var(--ntf-info-line); }
.ntf--warning { --ntf-bg: var(--ntf-warning-bg); --ntf-strip: var(--ntf-warning-strip); --ntf-chip: var(--ntf-warning-chip); --ntf-fg: var(--ntf-warning-fg); --ntf-line: var(--ntf-warning-line); }
.ntf--danger  { --ntf-bg: var(--ntf-danger-bg);  --ntf-strip: var(--ntf-danger-strip);  --ntf-chip: var(--ntf-danger-chip);  --ntf-fg: var(--ntf-danger-fg);  --ntf-line: var(--ntf-danger-line); }
.ntf--secondary { --ntf-bg: var(--surface-alt); --ntf-strip: var(--text-muted); --ntf-chip: var(--border-light); --ntf-fg: var(--text-secondary); --ntf-line: var(--border); }

/* The chip carries the only saturated colour; body text stays neutral so the
   message reads as considered information, not a colour flood. */
.ntf__icon { flex: 0 0 auto; width: 30px; height: 30px; border-radius: var(--radius-xs);
    display: flex; align-items: center; justify-content: center; margin-top: 1px;
    background: var(--ntf-chip); color: var(--ntf-fg); }
.ntf__icon .icon { width: 17px; height: 17px; }
.ntf__body { flex: 1 1 auto; min-width: 0; }
.ntf__title { font-weight: 700; font-size: .875rem; color: var(--text); letter-spacing: -.01em; }
.ntf__tag { display: block; width: fit-content; white-space: nowrap; margin-top: 7px;
    font-size: .625rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ntf-fg); background: var(--ntf-chip); padding: 3px 8px; border-radius: 100px; }
.ntf__text { color: var(--text-secondary); margin-top: 2px; }
.ntf__text b { color: var(--text); font-weight: 600; }
.ntf__text .mono, .ntf__text .font-monospace { color: var(--text); font-weight: 600; }
.ntf__list { list-style: none; margin: 11px 0 0; padding: 11px 0 0; border-top: 1px dashed var(--ntf-line);
    display: flex; flex-direction: column; gap: 8px; }
.ntf__list li { display: flex; gap: 8px; align-items: flex-start; font-size: .75rem; color: var(--text-secondary); }
.ntf__list li .icon { width: 14px; height: 14px; margin-top: 2px; color: var(--ntf-fg); flex-shrink: 0; }
.ntf__list b { color: var(--text); font-weight: 600; }
.ntf__actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 11px; }
.ntf__meta { color: var(--text-muted); font-size: .75rem; display: flex; align-items: center; gap: 5px; }
.ntf__meta .icon { width: 13px; height: 13px; }

/* Dismiss — one affordance, identical everywhere. */
.ntf__close { position: absolute; top: 8px; right: 8px; width: 26px; height: 26px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
    border: none; border-radius: 6px; background: transparent; color: var(--text-muted);
    opacity: .7; transition: opacity var(--transition), background var(--transition); }
.ntf__close .icon { width: 14px; height: 14px; }
.ntf__close:hover { opacity: 1; background: rgba(128, 128, 128, .18); }
.ntf--dismissible { padding-right: 40px; }

.ntf__link { color: var(--ntf-fg); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.ntf-btn { display: inline-flex; align-items: center; gap: 6px; font-size: .75rem; font-weight: 600;
    padding: 5px 11px; border-radius: var(--radius-xs); border: 1px solid var(--ntf-line);
    background: var(--surface); color: var(--ntf-fg); cursor: pointer; transition: background var(--transition); }
.ntf-btn:hover { background: var(--ntf-chip); }

/* — context: inline (in-form) ————————————————————— */
.ntf--inline { margin-bottom: 0; }
.ntf--compact { padding: 8px 12px; gap: 9px; font-size: .75rem; border-radius: var(--radius-sm); }
.ntf--compact.ntf--dismissible { padding-right: 34px; }
.ntf--compact .ntf__icon { width: 22px; height: 22px; }
.ntf--compact .ntf__icon .icon { width: 13px; height: 13px; }
.ntf--compact .ntf__close { top: 5px; right: 5px; width: 22px; height: 22px; }

/* — context: toast ——————————————————————————— */
.ntf--toast { --ntf-bg: var(--surface); --ntf-line: var(--border);
    border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
    overflow: hidden; padding-bottom: 16px; pointer-events: auto;
    animation: ntf-toast-in .22s cubic-bezier(.4, 0, .2, 1); }
.ntf--toast .ntf__title { font-size: .8125rem; }
.ntf--toast .ntf__text { font-size: .75rem; }
.ntf__progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: transparent; }
.ntf__progress i { display: block; height: 100%; background: var(--ntf-strip); width: 100%;
    animation: ntf-progress var(--ntf-dur, 6s) linear forwards; }
.ntf__progress.is-static i { animation: none; width: 58%; }
.ntf-out { opacity: 0; transition: opacity .45s ease; }

/* — context: drawer / dialog embedded (destructive) ———————— */
.ntf--emphasis { border-width: 1px; box-shadow: var(--shadow-sm); }
.ntf--emphasis .ntf__icon { width: 44px; height: 44px; border-radius: 12px; }
.ntf--emphasis .ntf__icon .icon { width: 22px; height: 22px; }
.ntf--drawer { box-shadow: none; }

/* — context: inline field validation ————————————— */
.ntf--field { background: transparent; border: none; border-left: none; box-shadow: none;
    padding: 6px 0 0; gap: 6px; font-size: .75rem; color: var(--ntf-danger-fg); animation: none; }
.ntf--field .ntf__icon { width: auto; height: auto; background: transparent; color: var(--ntf-danger-fg); margin-top: 1px; }
.ntf--field .ntf__icon .icon { width: 14px; height: 14px; }
.ntf--field .ntf__text { color: var(--ntf-danger-fg); margin-top: 0; }

/* — banners rendered by the polled topbar status region — */
#alert-banner-container .ntf { margin: 0 0 12px; }
#alert-banner-container .ntf:last-child { margin-bottom: 0; }
/* Polled hosts re-insert their banner every cycle; animate only a changed
   message (app.js adds .ntf--enter when the banner text changes). */
#alert-banner-container .ntf, #gw-output-region .ntf { animation: none; }
#alert-banner-container .ntf.ntf--enter, #gw-output-region .ntf.ntf--enter { animation: ntf-in .2s cubic-bezier(.4, 0, .2, 1); }

/* — motion ———————————————————————————————————— */
@keyframes ntf-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@keyframes ntf-toast-in { from { opacity: 0; transform: translateX(26px); } to { opacity: 1; transform: none; } }
@keyframes ntf-progress { from { width: 100%; } to { width: 0; } }
@media (prefers-reduced-motion: reduce) {
    .ntf { animation: none; }
    #alert-banner-container .ntf.ntf--enter, #gw-output-region .ntf.ntf--enter { animation: none; }
    .ntf__progress i { animation: none; width: 58%; }
}

/* ── Dataflow ── */
.dataflow-age-flowing { color: var(--success) !important; }
.dataflow-age-stale { color: var(--warning) !important; }

/* ── Audit Badges ──
   Canonical badge family: unknown actions fall back to the neutral chip
   from the family base; the action groups below tint it. */
.audit-badge-login_success, .audit-badge-password_change, .audit-badge-user_create,
.audit-badge-network_keep, .audit-badge-admin_recovery { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.audit-badge-login_failed, .audit-badge-cert_delete, .audit-badge-user_delete,
.audit-badge-admin_recovery_failed, .audit-badge-recovery_code_generate_failed { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.audit-badge-gateway_start, .audit-badge-gateway_stop, .audit-badge-gateway_restart,
.audit-badge-user_update, .audit-badge-network_revert { background: var(--warning-light); border-color: transparent; color: var(--warning); }
.audit-badge-config_save, .audit-badge-datapoint_save, .audit-badge-header_save,
.audit-badge-display_save, .audit-badge-display_settings_save, .audit-badge-network_save,
.audit-badge-cert_view, .audit-badge-cert_edit, .audit-badge-cert_upload,
.audit-badge-cert_rename, .audit-badge-password_reset, .audit-badge-mdns_toggle,
.audit-badge-recovery_code_generate { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.audit-badge-log_download, .audit-badge-logout { background: var(--surface-alt); color: var(--text-muted); }

/* ── Toolbar Chips ── */
.toolbar-group {
    display: flex; align-items: center; gap: 6px;
    background: var(--surface-alt); border-radius: var(--radius-sm);
    border: 1px solid var(--border); padding: 4px;
}
.toolbar-group .form-select,
.toolbar-group .btn {
    border: none; background: transparent; box-shadow: none;
    border-radius: var(--radius-xs);
}
.toolbar-group .form-select:focus,
.toolbar-group .btn:hover {
    background: var(--surface);
}

/* ── Stat card lift ── */
.stat-card { transition: box-shadow var(--transition), transform var(--transition); }
.stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }

/* ── Gateway Hero ── */
.gateway-hero {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    position: relative;
    overflow: hidden;
}
.gateway-hero { background: var(--surface); }
.gateway-hero .card-body { position: relative; padding: 20px 24px; }
.hero-title {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .1em; color: var(--text-muted); margin-bottom: 2px;
}
.hero-meta { display: flex; gap: 22px; margin-left: 8px; }

/* ── Identity Strip ── */
.id-strip {
    display: flex; flex-wrap: wrap; gap: 8px 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px 20px;
    box-shadow: var(--shadow-xs);
}
.id-chip {
    display: flex; align-items: center; gap: 8px;
    font-size: .8125rem;
}
.id-chip i {
    font-size: 1rem; color: var(--accent);
    opacity: .85;
}
.id-key {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .08em; color: var(--text-muted);
}
.id-val {
    font-weight: 600; color: var(--text);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-size: .75rem;
}

/* ── Metric Tiles ── */
.metric-tile {
    display: flex; flex-direction: column; align-items: center;
    padding: 8px 4px 10px;
    transition: transform var(--transition);
}
.metric-head {
    display: flex; align-items: center; gap: 6px;
    margin-bottom: 4px;
}
.metric-tile:hover { transform: translateY(-2px); }
@media (min-width: 768px) {
    #dataflow-card .col-md-4 + .col-md-4 .metric-tile { border-left: 1px solid var(--border-light); }
}
.metric-icon {
    width: 20px; height: 20px; margin: 0;
    border-radius: 6px;
    display: flex; align-items: center; justify-content: center;
    font-size: .75rem;
    transition: background var(--transition), color var(--transition);
}
.metric-blue { background: #e6edff; color: #1156fd; }
.metric-indigo { background: #e0e7ff; color: #4338ca; }
.metric-amber { background: #fef3c7; color: #b45309; }
.metric-label {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .09em; color: var(--text-muted); margin: 0;
}
.metric-value-wrap {
    font-size: 1.5rem; font-weight: 700; color: var(--text);
    line-height: 1.2; letter-spacing: -.02em;
}
.metric-hint {
    font-size: .6875rem; color: var(--text-muted); margin-top: 3px;
    transition: color var(--transition);
}
#dataflow-card[data-status="flowing"] .metric-blue { background: #d1fae5; color: #047857; }
#dataflow-card[data-status="stale"] .metric-blue { background: #fef3c7; color: #b45309; }
#dataflow-card[data-status="nodata"] .metric-blue { background: #fee2e2; color: #b91c1c; }
#dataflow-card[data-status="flowing"] #dataflow-age-hint { color: var(--success); }
#dataflow-card[data-status="stale"] #dataflow-age-hint { color: var(--warning); }
#dataflow-card[data-status="nodata"] #dataflow-age-hint { color: var(--danger); }
[data-theme="dark"] .metric-blue { background: rgba(17,86,253,.18); color: #93c5fd; }
[data-theme="dark"] .metric-indigo { background: rgba(99,102,241,.18); color: #a5b4fc; }
[data-theme="dark"] .metric-amber { background: rgba(245,158,11,.16); color: #fcd34d; }
[data-theme="dark"] #dataflow-card[data-status="flowing"] .metric-blue { background: rgba(34,197,94,.16); color: #86efac; }
[data-theme="dark"] #dataflow-card[data-status="stale"] .metric-blue { background: rgba(245,158,11,.16); color: #fcd34d; }
[data-theme="dark"] #dataflow-card[data-status="nodata"] .metric-blue { background: rgba(239,68,68,.16); color: #fca5a5; }

/* ── Ring Gauges ── */
.ring-gauge {
    --ring-color: var(--accent);
    --ring-track: var(--surface-alt);
    width: 96px; height: 96px;
    margin: 0 auto;
    border-radius: 50%;
    background: conic-gradient(var(--ring-color) 0deg, var(--ring-track) 0deg);
    display: flex; align-items: center; justify-content: center;
    position: relative;
    transition: background .6s cubic-bezier(.4,0,.2,1);
}
.ring-gauge::before {
    content: '';
    position: absolute; inset: 8px;
    border-radius: 50%;
    background: var(--surface);
    box-shadow: inset 0 1px 3px rgba(15,23,42,.06);
}
.ring-gauge .stat-value {
    position: relative; z-index: 1;
    font-size: 1.25rem; margin: 0;
}
.ring-gauge.low { --ring-color: var(--success); }
.ring-gauge.mid { --ring-color: var(--warning); }
.ring-gauge.high { --ring-color: var(--danger); }

/* ── Live indicator ── */
.live-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--success);
    animation: livePulse 2s infinite;
    flex-shrink: 0;
    transition: background var(--transition);
}
.live-dot.stopped { background: var(--text-muted); animation: none; }
.live-dot.error { background: var(--danger); animation: none; }
@keyframes livePulse {
    0% { box-shadow: 0 0 0 0 rgba(22,163,74,.45); }
    70% { box-shadow: 0 0 0 7px rgba(22,163,74,0); }
    100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); }
}

/* ── Activity feed ── */
.activity-scroll { max-height: 460px; overflow-y: auto; }

/* ── Empty state ── */
.empty-state {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    padding: 12px 0;
}
.empty-state i { font-size: 1.75rem; color: var(--border); }
.empty-state div { font-size: .8125rem; color: var(--text-muted); }

/* ── Settings page ── */
.setting-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
}
.setting-label { min-width: 0; }
.setting-live {
    display: flex; align-items: center; gap: 8px;
    color: var(--text-secondary);
}
.setting-live b { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; font-variant-numeric: tabular-nums; font-size: .8125rem; }

.cert-panel {
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 14px;
}
.cert-detail-grid {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 10px 18px;
}
.cert-detail-val {
    margin-top: 2px;
    word-break: break-all;
}
.cert-empty {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    padding: 18px 0;
    background: var(--surface-alt);
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
}
.cert-empty i { font-size: 1.5rem; color: var(--text-muted); }

/* ── Small ring gauge (settings) ── */
.ring-sm {
    width: 74px; height: 74px; flex-shrink: 0;
    background: conic-gradient(var(--ring-color) calc(var(--pct) * 1%), var(--ring-track) 0);
}
.ring-dash {
    width: 92px; height: 92px; flex-shrink: 0;
    background: conic-gradient(var(--ring-color) 0deg, var(--ring-track) 0deg);
}
.ring-dash::before { inset: 8px; }
.ring-dash .stat-value { font-size: 1.5rem; }
.ring-sm::before { inset: 6px; }
.ring-center { position: relative; z-index: 1; text-align: center; }
.ring-num {
    font-size: 1.25rem; font-weight: 700; line-height: 1.1;
    color: var(--text);
}
.ring-unit { font-size: .6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); }

/* ── Dashboard: fit-to-viewport ── */
body.dashboard-fit { overflow: hidden; }
body.dashboard-fit .main-content { height: 100vh; overflow: hidden; }
body.dashboard-fit .content-area {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden;
    padding: 20px 32px 24px !important;
}
body.dashboard-fit .content-area > * { flex-shrink: 0; }
body.dashboard-fit .activity-card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}
body.dashboard-fit .activity-card .card-body {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.dashboard-fit .activity-scroll {
    flex: 1 1 auto; min-height: 0;
    max-height: none;
}
body.dashboard-fit .id-strip,
body.dashboard-fit .gateway-hero,
body.dashboard-fit #dataflow-card { margin-bottom: 16px !important; }
body.dashboard-fit .row.mb-4 { margin-bottom: 16px !important; }

/* Short viewports / zoom / long alert lists: unlock page scrolling instead of
   clipping panels when the dashboard content no longer fits (class set by JS). */
body.dashboard-fit.dashboard-overflow { overflow-y: auto; }
body.dashboard-fit.dashboard-overflow .main-content { height: auto; min-height: 100vh; overflow: visible; }
body.dashboard-fit.dashboard-overflow .content-area { overflow: visible; }
body.dashboard-fit.dashboard-overflow .activity-card { flex: 0 0 auto; }
body.dashboard-fit.dashboard-overflow .activity-scroll { max-height: 40vh; }

@media (max-height: 850px) {
    body.dashboard-fit .content-area { padding: 14px 32px 18px !important; }
    body.dashboard-fit .id-strip,
    body.dashboard-fit .gateway-hero,
    body.dashboard-fit #dataflow-card { margin-bottom: 12px !important; }
    body.dashboard-fit .row.mb-4 { margin-bottom: 12px !important; }
    body.dashboard-fit .ring-gauge { width: 82px; height: 82px; }
    body.dashboard-fit .stat-card .card-body { padding: 16px 14px; }
}

/* ── Table pages: fit-to-viewport (audit, certs, integration points) ── */
body.table-fit { overflow: hidden; }
body.table-fit .main-content { height: 100vh; overflow: hidden; }
body.table-fit .content-area {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden;
    padding: 16px 32px 20px !important;
}
body.table-fit .nav-tabs { flex-shrink: 0; }
body.table-fit .tab-content {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit .tab-pane {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.table-fit .tab-pane.active {
    display: flex; flex-direction: column;
}
body.table-fit .tab-pane.active:not(#main) {
    overflow: hidden;
}
body.table-fit .tab-pane.active:not(#main) .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}
body.table-fit > .main-content > .content-area > .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}
body.table-fit .table-card-body {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.table-fit .table-card-body > .d-flex,
body.table-fit .table-card-body > form {
    flex-shrink: 0;
}
body.table-fit .table-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.table-fit .table-scroll .table thead th {
    position: sticky; top: 0;
}
body.table-fit .raw-editor-wrap {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit .raw-editor-textarea { flex: 1 1 auto; min-height: 0 !important; max-height: none !important; resize: none; }

/* ── Logs page: fit-to-viewport ── */
body.logs-fit { overflow: hidden; }
body.logs-fit .main-content { height: 100vh; overflow: hidden; }
body.logs-fit .content-area {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden;
    padding: 16px 32px 20px !important;
}
body.logs-fit .nav-tabs { flex-shrink: 0; }
body.logs-fit .tab-content {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.logs-fit .tab-pane {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.logs-fit .tab-pane#gw.active {
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit .tab-pane#gw.active .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}
body.logs-fit .terminal-card-body {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
    padding-top: 0 !important;
}
body.logs-fit .terminal-card-body > .d-flex {
    flex-shrink: 0;
    padding-bottom: 12px;
}
/* ── Logs: unified command bar (gateway / transactions / equipment events) ── */
.log-toolbar {
    display: flex; flex-direction: column; gap: 10px;
    padding-bottom: 12px;
}
.log-toolbar-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

/* Search is the primary control: icon inside the field, a clear affordance
   only while there is text, and a result-count chip next to it. */
.log-search { position: relative; flex: 1 1 300px; min-width: 180px; max-width: 440px; }
.log-search .form-control { height: 32px; padding-left: 34px; padding-right: 34px; font-size: .75rem; }
.log-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); display: flex; color: var(--text-muted); pointer-events: none; }
.log-search-icon .icon { width: 15px; height: 15px; }
.log-search-clear { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 24px; height: 24px; display: none; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--text-muted); cursor: pointer; }
.log-search-clear:hover { background: var(--surface-alt); color: var(--text); }
.log-search-clear .icon { width: 14px; height: 14px; }
.log-search.has-value .log-search-clear { display: inline-flex; }
.log-search.log-search-plain { flex: 0 1 170px; min-width: 130px; max-width: 220px; }
.log-search.log-search-plain .form-control { padding-left: 10px; }

.log-count { flex: 0 0 auto; background: var(--accent-light); border-color: transparent; color: var(--accent); }
.log-count[hidden] { display: none; }

/* Labelled filter fields */
.log-field { display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto; }
.log-inlabel { font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-secondary); white-space: nowrap; }
.log-select { min-width: 0; width: auto; max-width: 260px; }
.log-toolbar .form-select.log-select { padding-right: 1.9rem; }

/* Select with a state dot: grey = default, colour = filtering */
.log-level { display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 6px 0 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); }
.log-level .log-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-muted); flex: 0 0 auto; }
.log-level select { appearance: none; -webkit-appearance: none; height: 30px; border: 0; background-color: transparent; font: inherit; font-size: .75rem; font-weight: 500; color: var(--text); padding: 0 16px 0 0; cursor: pointer; outline: 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'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right center; }
.log-level.is-active { border-color: var(--accent); }
.log-toolbar .form-select.log-select.is-active { border-color: var(--accent); }
.log-level.sev-info .log-dot { background: #38bdf8; }
.log-level.sev-warning .log-dot { background: var(--warning); }
.log-level.sev-error .log-dot { background: var(--danger); }
.log-level.sev-ok .log-dot { background: var(--success); }

/* One control height across the bar */
.log-toolbar .form-control,
.log-toolbar .form-select { height: 32px; font-size: .75rem; }
.log-toolbar .form-control-sm,
.log-toolbar .form-select-sm { padding-top: 0; padding-bottom: 0; }

/* Time filter: trigger shows the active range; inline clear appears when set */
.log-time-btn { display: inline-flex; align-items: center; }
.time-pop.is-active .log-time-btn { border-color: var(--accent); color: var(--accent); }
.time-pop.is-active .log-time-btn .icon { color: var(--accent); }
.log-clear-x { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--text-muted); cursor: pointer; }
.log-clear-x:hover { background: var(--surface-alt); color: var(--text); }
.log-clear-x .icon { width: 14px; height: 14px; }
.log-clear-x[hidden] { display: none; }

/* Utilities: reset (reserved space), live toggle, refresh, download */
.log-toolbar-actions { display: flex; align-items: center; gap: 8px; }
.log-reset { display: inline-flex; align-items: center; gap: 5px; height: 32px; padding: 0 8px; border: 0; border-radius: 6px; background: transparent; color: var(--text-secondary); font: inherit; font-size: .75rem; font-weight: 500; cursor: pointer; }
.log-reset:hover { color: var(--accent); background: var(--accent-light); }
.log-reset .icon { width: 13px; height: 13px; }
.log-reset.is-off { visibility: hidden; }

.live-ctl { position: relative; display: inline-flex; }
.live-ctl .live-main { display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 10px; border: 1px solid var(--border); border-right: 0; border-radius: var(--radius-sm) 0 0 var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; font-size: .75rem; font-weight: 500; cursor: pointer; }
.live-ctl .live-caret { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 32px; padding: 0; border: 1px solid var(--border); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; background: var(--surface); color: var(--text-muted); cursor: pointer; }
.live-ctl .live-main:hover, .live-ctl .live-caret:hover { background: var(--surface-alt); }
.live-ctl button:focus-visible { position: relative; z-index: 1; }
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--success); box-shadow: 0 0 0 3px var(--success-light); flex: 0 0 auto; }
.live-ctl.is-off .live-dot { background: var(--text-muted); box-shadow: none; }
.live-menu { display: none; position: absolute; top: calc(100% + 6px); right: 0; min-width: 104px; z-index: 46; flex-direction: column; padding: 4px; background: var(--surface-alt); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: 0 10px 26px rgba(2, 6, 23, .3); }
.live-ctl.menu-open .live-menu { display: flex; }
.live-menu .live-item { padding: 7px 10px; border: 0; border-radius: 6px; background: transparent; color: var(--text-secondary); font: inherit; font-size: .75rem; text-align: left; cursor: pointer; }
.live-menu .live-item:hover { background: var(--accent-light); color: var(--accent); }
.live-menu .live-item[aria-checked="true"] { color: var(--accent); font-weight: 600; }

.log-visually-hidden { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

.log-ibtn { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text-secondary); cursor: pointer; }
.log-ibtn:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-light); }
.log-ibtn.disabled { opacity: .4; pointer-events: none; }
.log-ibtn .icon { width: 15px; height: 15px; }

.log-filter-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 4px; margin-left: 5px; border-radius: 100px; background: var(--accent-light); color: var(--accent); font-size: .6875rem; font-weight: 700; }
.log-filter-badge[hidden] { display: none; }

body.logs-fit .log-toolbar { flex-shrink: 0; }
.time-pop { position: relative; }
.time-pop .time-pop-label { min-width: 74px; display: inline-block; text-align: center; }
.time-pop-panel {
    display: none; position: absolute; top: calc(100% + 6px); left: 0;
    min-width: 250px; z-index: 45;
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 8px; padding: 10px;
    box-shadow: 0 10px 26px rgba(2, 6, 23, .3);
}
.time-pop.open .time-pop-panel { display: block; }
.time-pop-panel .time-presets { width: 100%; }
.time-pop-field { display: block; margin-top: 6px; }
.time-pop-field span { display: block; margin-bottom: 2px; }
body.logs-fit .terminal-card-body > .gw-output-wrap {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit .terminal-card-body > .gw-output-wrap > #gw-output-region {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit #gw-output-region .gw-nav,
body.logs-fit #gw-output-region .gw-nav-older { flex-shrink: 0; }
.gw-nav { margin-bottom: 6px; }
.gw-nav-older { padding-bottom: 4px; }
body.logs-fit .terminal-window {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.logs-fit .terminal-window .terminal-titlebar {
    flex-shrink: 0;
}
body.logs-fit .log-terminal {
    flex: 1 1 auto; min-height: 0;
    height: auto;
    max-height: none;
}
body.logs-fit .tab-pane#txn.active,
body.logs-fit .tab-pane#buffer.active {
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit .tab-pane#txn.active .card,
body.logs-fit .tab-pane#buffer.active .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}
body.logs-fit .txn-card-body {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit .txn-card-body > .d-flex,
body.logs-fit .txn-pagination {
    flex-shrink: 0;
}
body.logs-fit .txn-table-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.logs-fit .txn-table-scroll .table thead th {
    position: sticky; top: 0;
}
body.logs-fit #txn-table-region,
body.logs-fit #eq-table-region,
body.logs-fit #buffer-table-region {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.logs-fit #txn-table-region .table thead th,
body.logs-fit #eq-table-region .table thead th {
    position: sticky; top: 0;
    background: var(--surface);
}
body.logs-fit .tab-pane#equipment-events.active {
    display: flex; flex-direction: column;
    overflow: hidden;
}
body.logs-fit .tab-pane#equipment-events.active .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
    margin-bottom: 0;
}

/* ── Page fade-in ── */
.content-area { animation: pageIn .25s ease-out; }
@keyframes pageIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ── Responsive ──
   Mobile / small-screen overrides live at the END of this file so they win
   the cascade over the fit-to-viewport and component rules defined below. */

/* ── Standalone Pages (login, etc.) ── */
body.standalone {
    background:
        radial-gradient(ellipse at 20% 0%, rgba(17,86,253,.22) 0%, transparent 55%),
        radial-gradient(ellipse at 80% 100%, rgba(17,86,253,.14) 0%, transparent 50%),
        #0b1524;
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; margin: 0;
}

.standalone-card {
    background: var(--surface);
    border-radius: 16px;
    box-shadow: var(--shadow-lg), 0 0 0 1px rgba(255,255,255,.06);
    padding: 40px 36px; width: 100%; max-width: 420px;
}

.standalone-card .brand-icon {
    width: 56px; height: 56px; font-size: 1.25rem;
    border-radius: 14px; margin: 0 auto 14px;
}

.standalone-card h5 { font-weight: 700; letter-spacing: -.01em; }

/* ── Misc ── */
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

hr { border-color: var(--border); opacity: 1; }

.text-muted { color: var(--text-muted) !important; }
.text-success { color: var(--success) !important; }
.text-warning { color: var(--warning) !important; }
.text-danger { color: var(--danger) !important; }

/* Topbar gateway state text: darker shades on light theme for 4.5:1. */
#topbar-status-text.text-success { color: #15803d !important; }
#topbar-status-text.text-danger { color: #b91c1c !important; }
[data-theme="dark"] #topbar-status-text.text-success { color: var(--success) !important; }
[data-theme="dark"] #topbar-status-text.text-danger { color: var(--danger) !important; }

.form-switch .form-check-input:checked {
    background-color: var(--accent); border-color: var(--accent);
}

.page-link {
    color: var(--text-secondary); border-color: var(--border);
    border-radius: var(--radius-xs) !important;
}
.page-link:hover { background: var(--accent-light); color: var(--accent); }
.page-item.active .page-link {
    background: var(--accent); border-color: var(--accent);
}

::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
[data-theme="dark"] ::-webkit-scrollbar-thumb { background: #3b4a63; }
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: #4a5b76; }

.form-check-input:checked {
    background-color: var(--accent); border-color: var(--accent);
}

/* ── Raw Editor with line numbers ── */
.raw-editor-wrap {
    position: relative; overflow: hidden;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.raw-editor-lines {
    position: absolute; left: 0; top: 0; bottom: 0;
    width: 54px; overflow: hidden;
    background: var(--surface-alt);
    border-right: 1px solid var(--border);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
    font-size: .8125rem; line-height: 1.55; color: var(--text-muted);
    padding: 9px 0; text-align: right; user-select: none;
    pointer-events: none;
}
.raw-editor-lines span {
    display: block; padding: 0 8px 0 4px; height: 1.55em;
}
.raw-editor-textarea {
    display: block; width: 100%; min-height: 300px; max-height: 600px;
    padding: 9px 9px 9px 66px;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-size: .8125rem; line-height: 1.55; resize: vertical;
    border: none; border-radius: 0;
    tab-size: 2; white-space: pre; overflow-wrap: normal; overflow-x: auto;
}
.raw-editor-textarea:focus { outline: none; box-shadow: none; }

/* =====================================================================
   htmx-era additions: native dialogs + Bootstrap-compatible utilities
   ===================================================================== */
dialog { border: none; padding: 0; border-radius: 12px; box-shadow: 0 20px 60px rgba(0,0,0,.35); max-width: min(90vw, 720px); max-height: 85vh; background: var(--surface); color: var(--text); }
dialog::backdrop { background: rgba(0,0,0,.45); backdrop-filter: blur(2px); }
.dialog-box { padding: 1.25rem 1.5rem; overflow: auto; max-height: 85vh; }
dialog[open] { animation: dialog-in .15s ease-out; }
@keyframes dialog-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }

.d-none { display: none !important; }

.ms-auto { margin-left: auto !important; }
.me-auto { margin-right: auto !important; }
.w-auto { width: auto !important; }
.w-100 { width: 100% !important; }
.h-100 { height: 100% !important; }
.fw-bold { font-weight: 700 !important; }
.fw-semibold { font-weight: 600 !important; }
.fw-normal { font-weight: 400 !important; }
.fs-2 { font-size: 1.5rem !important; }
.fs-4 { font-size: 1.25rem !important; }
.fs-5 { font-size: 1rem !important; }
.gap-1 { gap: .25rem !important; }
.gap-2 { gap: .5rem !important; }
.gap-3 { gap: 1rem !important; }
.gap-4 { gap: 1.5rem !important; }
.m-0 { margin: 0 !important; }
.me-1 { margin-right: .25rem !important; }
.me-2 { margin-right: .5rem !important; }
.ms-1 { margin-left: .25rem !important; }
.ms-2 { margin-left: .5rem !important; }
.ms-3 { margin-left: 1rem !important; }
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: .25rem !important; }
.mb-2 { margin-bottom: .5rem !important; }
.mb-3 { margin-bottom: 1rem !important; }
.mb-4 { margin-bottom: 1.5rem !important; }
.mb-auto { margin-bottom: auto !important; }
.mt-1 { margin-top: .25rem !important; }
.mt-2 { margin-top: .5rem !important; }
.mt-3 { margin-top: 1rem !important; }
.mt-4 { margin-top: 1.5rem !important; }
.mt-auto { margin-top: auto !important; }
.mx-1 { margin-left: .25rem !important; margin-right: .25rem !important; }
.mx-2 { margin-left: .5rem !important; margin-right: .5rem !important; }
.mx-auto { margin-left: auto !important; margin-right: auto !important; }
.py-0 { padding-top: 0 !important; padding-bottom: 0 !important; }
.py-2 { padding-top: .5rem !important; padding-bottom: .5rem !important; }
.py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; }
.py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; }
.py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; }
.px-2 { padding-left: .5rem !important; padding-right: .5rem !important; }
.px-3 { padding-left: 1rem !important; padding-right: 1rem !important; }
.p-0 { padding: 0 !important; }
.pt-3 { padding-top: 1rem !important; }

.spinner-border { display: inline-block; width: 1rem; height: 1rem; border: .2em solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin .75s linear infinite; vertical-align: -.125em; }
.spinner-border-sm { width: .75rem; height: .75rem; border-width: .15em; }
@keyframes spin { to { transform: rotate(360deg); } }

.detail-pre { background: var(--surface-alt); border-radius: 8px; padding: .75rem; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; font-size: .75rem; max-height: 60vh; overflow: auto; white-space: pre-wrap; word-break: break-word; }
.mono { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }
.font-monospace { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }

.flex-grow-1 { flex-grow: 1 !important; }
.flex-shrink-0 { flex-shrink: 0 !important; }
.text-nowrap { white-space: nowrap !important; }
.text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rounded { border-radius: var(--radius-sm) !important; }
.bg-white { background-color: #fff !important; }
.border-top { border-top: 1px solid var(--border) !important; }
.p-1 { padding: .25rem !important; }

.gw-highlight { background: var(--accent-soft, rgba(255, 220, 90, .35)); border-radius: 2px; }
.gw-level-error { color: #ff6b6b; font-weight: 600; }
.gw-level-warning { color: #ffb454; font-weight: 600; }
.gw-level-info { color: #5ccfe6; }
.gw-time { color: var(--text-muted); }
.gw-sep { color: var(--text-muted); opacity: .5; }
.sort-icon { width: .8rem; height: .8rem; }
.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.sortable:hover { text-decoration: underline; }.risk-eq { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tab-pane:not(.active) { display: none; }

.form-text { display: block; margin-top: .25rem; font-size: .8em; }
.is-invalid { border-color: #ff6b6b !important; }
.btn-secondary { background: var(--surface-alt, rgba(128,128,128,.15)); color: var(--text, #ddd); border: 1px solid var(--border, rgba(128,128,128,.3)); }
.btn-secondary:hover { background: var(--surface-hover, rgba(128,128,128,.25)); }
.bg-primary { background: var(--accent-light); color: var(--accent); border-color: transparent; }
.text-info { color: #5ccfe6 !important; }

.d-inline { display: inline !important; }
.d-inline-flex { display: inline-flex !important; }

.icon {
    width: 1em; height: 1em;
    display: inline-block;
    vertical-align: -0.125em;
    flex-shrink: 0;
}
.icon.sort-icon { width: .8rem; height: .8rem; }

.sidebar .nav-link .icon { width: 1rem; height: 1rem; }

/* ---------- standalone auth pages (login / change-password / security) ---------- */
body.standalone {
    background:
        radial-gradient(ellipse at 18% 0%, rgba(17,86,253,.18) 0%, transparent 55%),
        radial-gradient(ellipse at 82% 100%, rgba(17,86,253,.12) 0%, transparent 50%),
        var(--bg, #0b1524);
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; margin: 0;
}
.standalone-card {
    box-shadow: var(--shadow-lg, 0 24px 64px rgba(0,0,0,.25)), 0 0 0 1px var(--border);
}
.input-group { display: flex; align-items: stretch; }
.input-group .form-control { flex: 1 1 auto; min-width: 0; }
.input-group > :first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group > :not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.input-group .btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.input-group-text {
    display: flex; align-items: center;
    padding: 0 .7rem;
    background: var(--surface-alt); border: 1px solid var(--border);
    color: var(--text-muted);
    border-right: 0;
}
.input-group:focus-within .input-group-text { border-color: var(--accent); color: var(--accent); }
.standalone-card .card-foot { font-size: .75rem; }
.standalone-card .card-foot a { color: var(--text-muted); text-decoration: none; }
.standalone-card .card-foot a:hover { color: var(--accent); }

.id-chip .icon { color: var(--accent); opacity: .85; }

/* =====================================================================
   Bootstrap-compatible layout utilities (grid / flex / text / spacing)
   ===================================================================== */

/* --- grid --- */
.row {
    --bs-gutter-x: 1.5rem;
    --bs-gutter-y: 0;
    display: flex; flex-wrap: wrap;
    margin-top: calc(-1 * var(--bs-gutter-y));
    margin-right: calc(-.5 * var(--bs-gutter-x));
    margin-left: calc(-.5 * var(--bs-gutter-x));
}
.row > * {
    box-sizing: border-box;
    flex-shrink: 0;
    width: 100%; max-width: 100%;
    padding-right: calc(var(--bs-gutter-x) * .5);
    padding-left: calc(var(--bs-gutter-x) * .5);
    margin-top: var(--bs-gutter-y);
}
.g-2{ --bs-gutter-x: .5rem; }
.g-2{ --bs-gutter-y: .5rem; }
.g-3{ --bs-gutter-x: 1rem; }
.g-3{ --bs-gutter-y: 1rem; }
.col-6 { flex: 0 0 auto; width: 50%; }
@media (min-width: 768px) {
    .col-md-2 { flex: 0 0 auto; width: 16.66666667%; }
    .col-md-3 { flex: 0 0 auto; width: 25%; }
    .col-md-4 { flex: 0 0 auto; width: 33.33333333%; }
    .col-md-5 { flex: 0 0 auto; width: 41.66666667%; }
    .col-md-6 { flex: 0 0 auto; width: 50%; }
    .d-md-inline { display: inline !important; }
    .text-md-end { text-align: right !important; }
}
@media (min-width: 992px) {
    .col-lg-4 { flex: 0 0 auto; width: 33.33333333%; }
    .col-lg-6 { flex: 0 0 auto; width: 50%; }
    .col-lg-8 { flex: 0 0 auto; width: 66.66666667%; }
    .text-lg-end { text-align: right !important; }
}

/* --- flex --- */
.flex-wrap { flex-wrap: wrap !important; }
.flex-column { flex-direction: column !important; }
.align-items-start { align-items: flex-start !important; }
.align-items-center { align-items: center !important; }
.align-items-end { align-items: flex-end !important; }
.align-items-baseline { align-items: baseline !important; }
.justify-content-start { justify-content: flex-start !important; }
.justify-content-center { justify-content: center !important; }
.justify-content-end { justify-content: flex-end !important; }
.justify-content-between { justify-content: space-between !important; }

/* --- text --- */
.text-center { text-align: center !important; }
.text-end { text-align: right !important; }
.text-white { color: #fff !important; }
.text-dark { color: #0f172a !important; }
.text-decoration-none { text-decoration: none !important; }
.small { font-size: .875em; }
.table-warning { background-color: rgba(217,119,6,.12); }

/* --- spacing (completing the set) --- */
.mt-0 { margin-top: 0 !important; }
.my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; }
.my-2 { margin-top: .5rem !important; margin-bottom: .5rem !important; }
.mx-3 { margin-left: 1rem !important; margin-right: 1rem !important; }
.ps-1 { padding-left: .25rem !important; }
.ps-2 { padding-left: .5rem !important; }
.ps-3 { padding-left: 1rem !important; }
.pe-1 { padding-right: .25rem !important; }
.pe-2 { padding-right: .5rem !important; }
.pe-3 { padding-right: 1rem !important; }
.pt-1 { padding-top: .25rem !important; }
.pt-2 { padding-top: .5rem !important; }

/* --- forms --- */
.form-control-sm, .form-select-sm {
    min-height: calc(1.5em + .5rem + 2px);
    padding: .25rem .5rem; font-size: .75rem;
}
.input-group-sm > .form-control, .input-group-sm > .form-select,
.input-group-sm > .input-group-text {
    min-height: calc(1.5em + .5rem + 2px);
    padding: .25rem .5rem; font-size: .75rem;
}
.form-check-label { color: var(--text-secondary); font-size: .75rem; }

/* --- nav --- */
.nav { display: flex; flex-wrap: wrap; padding-left: 0; margin-bottom: 0; list-style: none; }
.nav-pills { flex-direction: column; gap: 2px; }
.nav-item { margin: 0; }

/* --- misc --- */
.border-2 { border-width: 2px !important; }
.opacity-75 { opacity: .75 !important; }
.cert-tab-pane { padding-top: .25rem; }
.cert-pre { max-height: 55vh; overflow: auto; white-space: pre-wrap; word-break: break-all; }
.cert-edit-textarea { min-height: 320px; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; font-size: .75rem; }
.user-info { display: flex; flex-direction: column; min-width: 0; }

.dp-pt-key, .dp-pt-val { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; font-size: .75rem; }
.dp-pt-val { font-variant-numeric: tabular-nums; }

/* --- modern gateway status hero --- */
.gateway-hero .card-body { position: relative; padding: 22px 26px; }
.hero-main { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px 24px; }
.hero-status { display: flex; align-items: center; gap: 16px; }
.hero-icon {
    width: 48px; height: 48px; border-radius: 14px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.25rem; flex-shrink: 0;
    transition: all var(--transition);
}
.hero-icon .icon { width: 1.2em; height: 1.2em; }
.hero-icon-running {
    background: rgba(22,163,74,.13); color: var(--success);
    box-shadow: 0 0 0 4px rgba(22,163,74,.07), 0 6px 18px rgba(22,163,74,.22);
}
.hero-icon-error {
    background: rgba(220,38,38,.13); color: var(--danger);
    box-shadow: 0 0 0 4px rgba(220,38,38,.07), 0 6px 18px rgba(220,38,38,.2);
}
.hero-icon-stopped {
    background: rgba(100,116,139,.14); color: var(--text-secondary);
    box-shadow: 0 0 0 4px rgba(100,116,139,.07);
}
.hero-icon-starting {
    background: rgba(91,140,255,.13); color: var(--accent);
    box-shadow: 0 0 0 4px rgba(91,140,255,.08);
}
.hero-icon-unknown { background: var(--surface-alt); color: var(--text-muted); }
.hero-title { margin-bottom: 4px; }
.hero-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Status pills are part of the canonical badge family (metrics/typography
   from the family base); running/error keep their AA darker shades in light
   mode, stopped/unknown are the neutral chip. */
.status-pill-running { background: var(--success-light); border-color: transparent; color: #15803d; }
.status-pill-error { background: var(--danger-light); border-color: transparent; color: #b91c1c; }
[data-theme="dark"] .status-pill-running { color: var(--success); }
[data-theme="dark"] .status-pill-error { color: var(--danger); }
.status-pill-stopped { background: var(--surface-alt); color: var(--text-muted); }
.status-pill-starting { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.status-pill-unknown { background: var(--surface-alt); color: var(--text-muted); }
.pill-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.status-pill-running .pill-dot { animation: pill-pulse 2s infinite; }
@keyframes pill-pulse {
    0% { box-shadow: 0 0 0 0 rgba(34,197,94,.45); }
    70% { box-shadow: 0 0 0 7px rgba(34,197,94,0); }
    100% { box-shadow: 0 0 0 0 rgba(34,197,94,0); }
}
/* #b45309 passes AA on the light surface; the amber token only clears 3:1. */
.hero-note { display: inline-flex; align-items: center; gap: 4px; font-size: .75rem; font-weight: 600; color: #b45309; }
[data-theme="dark"] .hero-note { color: var(--warning); }
.hero-actions { display: flex; align-items: center; gap: 8px; }
.hero-stats {
    display: flex; flex-wrap: wrap; gap: 12px 34px;
    margin-top: 18px; padding-top: 16px;
    border-top: 1px dashed var(--border);
}
.hero-stat { display: flex; flex-direction: column; gap: 3px; min-width: 90px; }
.hero-stat-key {
    font-size: .6875rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .1em; color: var(--text-muted);
}
.hero-stat-val {
    font-size: 1rem; font-weight: 700; color: var(--text);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
}
.dash-hero .hero-stat-val { font-size: var(--fs-title); }
.hero-stat-cap { font-size: .6875rem; color: var(--text-muted); }
.hero-links { display: flex; flex-direction: column; gap: 5px; margin-top: 9px; }
.hero-endpoint { display: flex; align-items: center; gap: 8px; font-size: .8125rem; }
.hero-endpoint .net-chip { flex-shrink: 0; }

/* --- recent activity feed: transaction-log row anatomy --- */
.activity-feed { display: flex; flex-direction: column; gap: 10px; padding: 12px 16px 14px; }
.table tbody tr[data-dialog] { cursor: pointer; }
.activity-feed > .net-row { background: var(--surface-alt); }
.activity-feed .net-row-main { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Alarm entries keep the danger emphasis: tinted fill + 3px left accent. The
   border width folds into the padding so the text aligns with sibling rows. */
.activity-feed > .feed-row-alarm { background: var(--danger-light); border-left: 3px solid var(--danger); padding-left: 14px; }
.activity-feed > .feed-row-alarm:hover { border-left-color: var(--danger); }
.activity-card.card > .net-list-head { padding: 14px 20px 10px; margin: 0; border-bottom: 1px solid var(--border-light); }

.d-flex { display: flex !important; }
.d-block { display: block !important; }
.d-inline { display: inline !important; }
.d-inline-flex { display: inline-flex !important; }

/* --- heading sizes (Bootstrap-compatible; UA default for h6 is 0.67em) --- */
h1, h2, h3, h4, h5, h6 {
    margin-top: 0; margin-bottom: .5rem;
    font-weight: 500; line-height: 1.2;
}
h1 { font-size: 2rem; }
h2 { font-size: 1.75rem; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }

/* --- JSON syntax highlighting (pretty payload views) --- */
.jv-key { color: #1156fd; }
.jv-str { color: #16a34a; }
.jv-num { color: #d97706; }
.jv-bool { color: #a855f7; }
.jv-null { color: #64748b; font-style: italic; }
[data-theme="dark"] .jv-key { color: #7c9dff; }
[data-theme="dark"] .jv-str { color: #9ecb7a; }
[data-theme="dark"] .jv-num { color: #e5a55d; }
[data-theme="dark"] .jv-bool { color: #c77dff; }
[data-theme="dark"] .jv-null { color: #8296ab; }

/* JSON payloads inside the (always dark) gateway terminal need the dark palette
   regardless of the portal theme. */
.log-terminal .jv-key { color: #7c9dff; }
.log-terminal .jv-str { color: #9ecb7a; }
.log-terminal .jv-num { color: #e5a55d; }
.log-terminal .jv-bool { color: #c77dff; }
.log-terminal .jv-null { color: #8296ab; }

/* --- modern confirm dialog (service start/stop/restart) --- */
.cf-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.cf-icon {
    width: 44px; height: 44px; border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.25rem; flex-shrink: 0;
}
.cf-icon .icon { width: 1.15em; height: 1.15em; }
.cf-icon-start { background: var(--success-light); color: var(--success); }
.cf-icon-stop { background: var(--danger-light); color: var(--danger); }
.cf-icon-restart { background: var(--warning-light); color: var(--warning); }
.cf-head-text { min-width: 0; }
.cf-title { font-size: 1rem; font-weight: 700; color: var(--text); letter-spacing: -.01em; }
.cf-sub { font-size: .75rem; color: var(--text-muted); margin-top: 2px; }
.cf-note {
    display: flex; align-items: center; gap: 8px;
    font-size: .75rem; color: var(--text-secondary);
    padding: 8px 2px;
}
.cf-note .icon { width: .95em; height: .95em; color: var(--text-muted); }
.cf-footer {
    display: flex; justify-content: flex-end; gap: 8px;
    margin-top: 18px; padding-top: 14px;
    border-top: 1px solid var(--border-light);
}

/* =====================================================================
   Modern dialogs (native <dialog> polish)
   ===================================================================== */
dialog {
    border: none; padding: 0;
    border-radius: 18px;
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 2px 8px rgba(2,6,23,.10), 0 24px 80px rgba(2,6,23,.38);
    max-width: min(92vw, 720px);
    max-height: 85vh;
    overflow: hidden;
}
dialog::backdrop {
    background: rgba(3, 7, 18, .55);
    -webkit-backdrop-filter: blur(5px);
    backdrop-filter: blur(5px);
}
dialog[open] { animation: dialog-pop .22s cubic-bezier(.2, .9, .3, 1.15); }
@keyframes dialog-pop {
    from { opacity: 0; transform: translateY(16px) scale(.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.dialog-box { padding: 24px 28px; }

/* --- confirm dialog (start/stop/restart) --- */

#service-confirm-dialog .dialog-box { padding: 0; }
.cf-icon {
    width: 48px; height: 48px; border-radius: 14px;
    font-size: 1.25rem;
}
.cf-icon-start   { box-shadow: 0 0 0 4px rgba(22,163,74,.08),  0 6px 22px rgba(22,163,74,.28); }
.cf-icon-stop    { box-shadow: 0 0 0 4px rgba(220,38,38,.08),  0 6px 22px rgba(220,38,38,.22); }
.cf-icon-restart { box-shadow: 0 0 0 4px rgba(217,119,6,.08),  0 6px 22px rgba(217,119,6,.22); }
.cf-title { font-size: 1rem; }
.cf-sub { font-size: .75rem; }
.cf-footer {
    display: flex; justify-content: flex-end; gap: 10px;
    margin: 22px -28px -26px; padding: 14px 28px 16px;
    background: var(--surface-alt);
    border-top: 1px solid var(--border-light);
}
.cf-footer .btn { padding: .45rem 1.1rem; }
.cf-footer .btn-success { box-shadow: 0 4px 14px rgba(22,163,74,.25); }
.cf-footer .btn-danger  { box-shadow: 0 4px 14px rgba(220,38,38,.22); }
.cf-footer .btn-warning { box-shadow: 0 4px 14px rgba(217,119,6,.22); }

/* =====================================================================
   Right slide-over drawer (service confirm panel)
   ===================================================================== */
dialog.drawer-dialog {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: auto;
    margin: 0;
    width: 440px; max-width: 94vw;
    height: 100vh; max-height: 100vh;
    border-radius: 0;
    box-shadow: -28px 0 90px rgba(2, 6, 23, .40);
}
dialog.drawer-dialog.drawer-lg {
    width: min(92vw, 860px);
}
dialog.drawer-dialog[open] {
    display: flex;
    animation: drawer-in .3s cubic-bezier(.2, .9, .3, 1);
}
@keyframes drawer-in {
    from { transform: translateX(100%); }
    to   { transform: translateX(0); }
}
.drawer-root { flex: 1; display: flex; min-width: 0; }
.drawer { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.drawer-header {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px;
    padding: 20px 24px;
    border-bottom: 1px solid var(--border-light);
}
.drawer-header .cf-head { margin-bottom: 0; }
.drawer-close { flex-shrink: 0; }
.drawer-body {
    flex: 1 1 auto; overflow-y: auto;
    padding: 20px 24px;
}
.drawer-footer {
    display: flex; justify-content: flex-end; gap: 10px;
    padding: 14px 24px;
    background: var(--surface-alt);
    border-top: 1px solid var(--border-light);
}
.drawer-footer .btn { padding: .45rem 1.1rem; }
.drawer-footer .btn-success { box-shadow: 0 4px 14px rgba(22,163,74,.25); }
.drawer-footer .btn-danger  { box-shadow: 0 4px 14px rgba(220,38,38,.22); }
.drawer-footer .btn-warning { box-shadow: 0 4px 14px rgba(217,119,6,.22); }
.drawer-body--vpn-log {
    display: flex; flex-direction: column; min-height: 0; overflow: hidden;
}
.drawer-body--vpn-log > * { flex-shrink: 0; }
.drawer-body--vpn-log .log-terminal {
    flex: 1 1 auto; min-height: 0; height: auto; max-height: none;
}

/* --- VPN drawer: config drop zone, file card, parsed chips --------------- */
/* The drop zone is a <label> for the visually-hidden file input, so it is
   click-to-browse and keyboard-reachable; the loaded file card keeps the
   same class as a live drop target for replace-on-redrop. */
.dropzone {
    display: block;
    position: relative;
    border: 1.5px dashed var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    padding: 22px 16px 18px;
    text-align: center;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.dropzone:hover { border-color: var(--text-muted); background: var(--surface-alt); }
.dropzone:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.dropzone.is-drag {
    border: 1.5px dashed var(--accent);
    background: var(--accent-light);
    box-shadow: 0 0 0 3px var(--accent-light);
}
.dz-icon {
    width: 38px; height: 38px; margin: 0 auto 10px;
    border-radius: 10px; display: flex; align-items: center; justify-content: center;
    background: var(--accent-light); color: var(--accent);
}
.dz-icon .icon { width: 18px; height: 18px; }
.dropzone.is-drag .dz-icon { background: var(--surface); box-shadow: var(--shadow-md); }
.dz-title { display: block; font-size: var(--fs-compact); font-weight: 600; color: var(--text); }
.dropzone.is-drag .dz-title { color: var(--accent); }
.dz-sub { display: block; font-size: var(--fs-caption); color: var(--text-muted); margin-top: 3px; }
.dz-browse { color: var(--accent); font-weight: 600; }
.dz-link {
    display: inline; padding: 0; border: none; background: none; font: inherit;
    color: var(--accent); font-weight: 600; cursor: pointer;
}
.dz-link:hover { text-decoration: underline; }
.dz-release { display: none; font-size: var(--fs-compact); font-weight: 700; color: var(--accent); }
.dropzone.is-drag .dz-release {
    display: block;
    position: absolute; left: 16px; right: 16px;
    /* padding-top 22 + .dz-icon height 38 + its margin-bottom 10 = title line top */
    top: 70px;
}
.dropzone.is-drag .dz-title, .dropzone.is-drag .dz-sub { visibility: hidden; }
.vpn-file-input {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.vpn-paste { margin-top: 8px; }
/* Loaded state: the file card (rendered into #vpn-summary) replaces the idle
   zone. is-loaded is set by app.js after a summary swap; :has() covers a
   first paint before the class lands. */
#vpn-config-block.is-loaded .dropzone:not(.file-card),
#vpn-config-block:has(.file-card) .dropzone:not(.file-card) { display: none; }
#vpn-drop-hint { margin-top: 6px; font-size: var(--fs-caption); font-weight: 600; color: var(--ntf-danger-fg); }
#vpn-drop-hint[hidden] { display: none; }
#vpn-summary > * { margin-top: 9px; }
.vpn-chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* Loaded state: the staged file card doubles as the drop target. */
.file-card {
    display: flex; align-items: center; gap: 10px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    padding: 9px 12px; background: var(--surface);
}
.file-card.dropzone { border: 1px solid var(--border); padding: 9px 12px; text-align: left; }
.file-card.dropzone.is-drag { border: 1px dashed var(--accent); background: var(--accent-light); }
.fc-icon {
    width: 32px; height: 32px; flex-shrink: 0; border-radius: var(--radius-sm);
    display: flex; align-items: center; justify-content: center;
    background: var(--accent-light); color: var(--accent);
}
.fc-icon .icon { width: 15px; height: 15px; }
.file-card.is-drag .fc-icon { background: var(--surface); }
.fc-body { flex: 1 1 auto; min-width: 0; }
.fc-name {
    font-size: var(--fs-compact); font-weight: 600; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fc-meta { font-size: var(--fs-micro); color: var(--text-muted); margin-top: 1px; }
.fc-drop { display: none; color: var(--accent); font-weight: 600; }
.file-card.is-drag .fc-drop { display: inline; }
.fc-actions { margin-left: auto; display: flex; gap: 5px; flex-shrink: 0; }
.fc-btn {
    font: inherit; font-size: var(--fs-micro); font-weight: 600;
    color: var(--text-secondary); background: var(--surface);
    border: 1px solid var(--border); border-radius: var(--radius-xs);
    padding: 3px 9px; cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
}
.fc-btn:hover { border-color: var(--accent); color: var(--accent); }
.fc-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Edit-mode type lock and credential reveal. */
.vpn-type-fixed { margin-top: 2px; }
/* .net-chip's display:inline-flex beats the UA [hidden] rule. */
#vpn-name-suggest[hidden] { display: none; }
.vpn-cred-fields { margin-top: 10px; }
.vpn-cred-fields .vpn-field + .vpn-field { margin-top: 12px; }
.vpn-cred-reveal {
    border: 1px dashed var(--border); border-radius: var(--radius-sm);
    padding: 8px 12px; margin-top: 4px;
}
.vpn-cred-reveal > summary { cursor: pointer; font-size: var(--fs-compact); font-weight: 600; color: var(--text-secondary); }
.vpn-cred-reveal[open] > summary { margin-bottom: 8px; }
.vpn-cred-reveal > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Coarse pointers: comfortable hit areas inside the drawer. */
@media (pointer: coarse) {
    .drawer .form-control, .drawer .form-select,
    .drawer .btn, .drawer .btn-sm,
    .drawer .net-chip, .drawer .state-chip,
    .drawer .fc-btn, .drawer .seg-btn,
    .drawer .dz-link {
        min-height: 40px;
    }
    .drawer .dz-link { display: inline-flex; align-items: center; }
}

.hover-tip {
    position: fixed; z-index: 9999; display: none;
    max-width: 320px;
    padding: 8px 10px;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: .75rem; line-height: 1.5; color: var(--text);
    box-shadow: 0 8px 24px rgba(2, 6, 23, .35);
    pointer-events: none;
}

/* --- form controls: consistent sizing + modern switch --- */
.form-control, .form-select {
    height: 38px;
    width: 100%;
}
textarea.form-control { height: auto; }
.form-check { display: flex; align-items: center; gap: .4rem; margin: 0; }
.form-check-input {
    width: 15px; height: 15px;
    accent-color: var(--accent);
    cursor: pointer;
}
.form-switch .form-check-input {
    width: 40px; height: 22px;
    appearance: none; -webkit-appearance: none;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 999px;
    position: relative;
    transition: background .2s ease, border-color .2s ease;
}
.form-switch .form-check-input::after {
    content: '';
    position: absolute; top: 2px; left: 2px;
    width: 16px; height: 16px; border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
    transition: transform .2s ease;
}
.form-switch .form-check-input:checked {
    background: var(--accent); border-color: var(--accent);
}
.form-switch .form-check-input:checked::after {
    transform: translateX(18px);
}
.integration-switch {
    min-height: 38px;
    display: flex; align-items: center;
}

.table { width: 100%; }

/* --- datapoint regions participate in the table-fit flex layout --- */
body.table-fit #dp-telemetry-region,
body.table-fit #dp-cov-region {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit #dp-telemetry-region > .d-flex,
body.table-fit #dp-cov-region > .d-flex,
body.table-fit #dp-telemetry-region > .ntf,
body.table-fit #dp-cov-region > .ntf {
    flex-shrink: 0;
}
body.table-fit #dp-telemetry-region .table-scroll,
body.table-fit #dp-cov-region .table-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}
body.table-fit #dp-telemetry-region .raw-editor-wrap,
body.table-fit #dp-cov-region .raw-editor-wrap {
    flex: 1 1 auto; min-height: 0;
}

/* --- certificate region participates in the table-fit flex layout ---
   Header (hint + chips + upload) stays fixed; the row-card list scrolls. */
body.table-fit #cert-table-region {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit #cert-table-region > .d-flex {
    flex-shrink: 0;
}
body.table-fit #cert-table-region .net-adapters {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
}

.cf-icon-edit { background: var(--accent-light); color: var(--accent); box-shadow: 0 0 0 4px rgba(17,86,253,.08), 0 6px 22px rgba(17,86,253,.22); }
.drawer-body .form-label { margin-bottom: 4px; }

.cf-icon-detail { background: var(--accent-light); color: var(--accent); box-shadow: 0 0 0 4px rgba(17,86,253,.08), 0 6px 22px rgba(17,86,253,.22); }

/* --- dashboard overview participates in the dashboard-fit flex chain ---
   Two columns: the left rail (gateway + vitals) and the activity feed, which
   owns the remaining viewport height and scrolls internally. */
body.dashboard-fit #dashboard-overview {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.dashboard-fit #dashboard-overview > .card,
body.dashboard-fit #dashboard-overview > .row,
body.dashboard-fit .dash-cols > * {
    flex-shrink: 0;
}
body.dashboard-fit .dash-cols {
    flex: 1 1 auto; min-height: 0;
    display: flex; gap: 16px; align-items: stretch;
}
body.dashboard-fit .dash-main {
    flex: 1.25 1 0; min-width: 0; min-height: 0;
    display: flex; flex-direction: column;
}
body.dashboard-fit .dash-main > .card:last-child { margin-bottom: 0 !important; }
body.dashboard-fit #dashboard-overview .activity-card {
    flex: 1 1 0; min-width: 0; min-height: 0;
}
/* Identity chips folded into the gateway hero card. */
.hero-id { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px; }
/* Vitals: dataflow metrics + health bars share one card. */
.dash-vitals-sep { border-top: 1px solid var(--border-light); margin: 10px 0 0; }
.vital-tile { padding: 10px 8px 4px; min-width: 0; }

/* --- in-flight feedback for drawer action buttons --- */
.action-btn { position: relative; min-width: 104px; justify-content: center; }
.action-btn .action-spinner {
    display: none;
    width: 13px; height: 13px;
    border-width: 2px;
    margin-right: 6px;
    vertical-align: -2px;
}
.action-btn.htmx-request { pointer-events: none; opacity: .8; cursor: wait; }
.action-btn.htmx-request .action-spinner { display: inline-block; }

/* --- network apply auto-reconnect overlay --- */
.net-reconnect {
    position: fixed; inset: 0; z-index: 3000;
    display: flex; align-items: center; justify-content: center;
    background: rgba(15, 23, 42, .6);
    backdrop-filter: blur(2px);
}
.net-reconnect-box {
    display: flex; align-items: center; gap: 10px;
    max-width: min(90vw, 480px);
    padding: 14px 18px;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--shadow-lg); font-size: .875rem;
}

/* --- integration test result container (holds a .ntf) --- */
.test-result { animation: ntf-in .25s ease; }
.test-result .ntf { margin-bottom: 10px; }

/* --- integration action bar (save / test) ---
   Sticky to the bottom of the scrolling pane so Save + the dirty cue are
   never scrolled away, on desktop fit layouts and on phones alike. The bar
   is a card-like surface — same radius, border and background as .net-strip
   and .card — with inline padding insetting the content so the hint never
   sits under the pane edge or its scrollbar. Padding is used instead of the
   removed negative margins, which had created scrollable overflow in the
   pane. On phones (<=480px) it rejoins the full-bleed pattern used by the
   dialogs: square corners, top border only. */
.integration-action-bar {
    position: sticky; bottom: 0; z-index: 5;
    background: var(--surface);
    margin: 1.5rem 0 0; padding: 14px 20px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 -6px 16px rgba(15,23,42,.05);
}
.btn-action {
    display: inline-flex; align-items: center; gap: 6px;
    min-height: 32px;
}
.btn-action .icon { width: 15px; height: 15px; }
#integration-test-result:empty { display: none; }

/* crisp outline buttons (replaces the muddy gray fill) */
.btn-outline-secondary {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-secondary);
}
.btn-outline-secondary:hover {
    background: var(--accent-light);
    border-color: var(--accent);
    color: var(--accent);
}

/* --- toolbar controls (search / add / upload) --- */
.btn-outline-primary {
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--accent);
}
.btn-outline-primary:hover {
    background: var(--accent);
    color: #fff;
}

/* Bootstrap isn't loaded, so outline variants need real styles. Using theme
   variables keeps them correct in both light and dark mode. */
.btn-outline-danger {
    background: transparent;
    border: 1px solid var(--danger);
    color: var(--danger);
}
.btn-outline-danger:hover {
    background: var(--action-danger);
    border-color: var(--action-danger);
    color: #fff;
}
.toolbar-btn {
    display: inline-flex; align-items: center; gap: 7px;
    height: 32px; cursor: pointer;
    font-size: .75rem;
}
.toolbar-btn .icon { width: 15px; height: 15px; }
.toolbar-row { display: flex; width: 100%; gap: 6px; }
.toolbar-row .toolbar-btn { flex: 1 1 0; justify-content: center; }
.integration-toolbar .input-group { max-width: 280px; }
.integration-toolbar .form-control { height: 32px; }

/* --- points badge hover tooltip (tag list) --- */
.pts-badge { position: relative; display: inline-block; cursor: help; }
.pts-pop {
    position: fixed;
    left: -9999px; top: -9999px;
    background: #0f172a; color: #e2e8f0;
    border-radius: 8px; padding: 7px 10px;
    font-size: .75rem; font-weight: 500; line-height: 1.5;
    box-shadow: 0 10px 28px rgba(2, 6, 23, .35);
    opacity: 0; visibility: hidden;
    z-index: 60; pointer-events: none;
    display: flex; flex-direction: column; gap: 1px;
    min-width: 120px; max-width: 320px;
    transition: opacity .16s ease;
}
.pts-pop.pts-show { opacity: 1; visibility: visible; }
.pts-pop::after {
    content: ''; position: absolute; left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
}
.pts-pop.pts-above::after {
    top: 100%; border-top-color: #0f172a;
}
.pts-pop.pts-below::after {
    bottom: 100%; border-bottom-color: #0f172a;
}
.pts-pop-tag {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    white-space: nowrap;
}

/* =====================================================================
   Table action buttons — quiet ghost icon buttons (unified)
   ===================================================================== */
.row-actions {
    display: inline-flex; align-items: center; gap: 3px;
    white-space: nowrap;
}
.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; padding: 0; margin: 0;
    border: none; border-radius: 6px;
    background: transparent;
    color: var(--text-secondary);
    text-decoration: none; cursor: pointer;
    transition: background .15s ease, color .15s ease;
    flex-shrink: 0;
}
.icon-btn .icon { width: 15px; height: 15px; }
.icon-btn:hover {
    background: var(--accent-light);
    color: var(--accent);
}
.icon-btn.icon-danger:hover {
    background: var(--danger-light);
    color: var(--danger);
}
.icon-btn.icon-warn:hover {
    background: var(--warning-light);
    color: var(--warning);
}
.icon-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Row actions stay quiet until the row is hovered or keyboard-focused.
   Touch devices (coarse pointers) keep them permanently visible. */
@media (hover: hover) and (pointer: fine) {
    .table td .row-actions,
    .table td > .icon-btn { opacity: 0; transition: opacity .12s ease; }
    .table tbody tr:hover td .row-actions,
    .table tbody tr:hover td > .icon-btn,
    .table tbody tr:focus-within td .row-actions,
    .table tbody tr:focus-within td > .icon-btn { opacity: 1; }
}

/* sidebar logout — ghost button with danger hover */
.logout-link {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: .75rem; font-weight: 500;
    padding: 4px 8px; margin-top: 2px;
    border: none; border-radius: 6px;
    background: transparent;
    color: rgba(255, 255, 255, .6);
    text-decoration: none; cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.logout-link .icon { width: 13px; height: 13px; }
.logout-link:hover {
    color: #fff;
    background: rgba(220, 38, 38, .22);
}

/* Table headers align with their column data: text left, numbers/dates
   right (tabular figures), statuses and action columns as noted. */
.table thead th { text-align: left; }
.table th.col-num, .table td.col-num { text-align: right; font-variant-numeric: tabular-nums; }
.table th.col-center, .table td.col-center { text-align: center; }
.table th.col-actions, .table td.col-actions { text-align: right; }

/* Keep the page footer (e.g. the "Report a vulnerability" link) clear of the
   mobile browser chrome / gesture bar. `py-2` on the element forces 8px, so
   this needs to win with !important. env() is 0 on desktop. */
.main-footer {
    padding-bottom: calc(12px + env(safe-area-inset-bottom)) !important;
}

/* Collapsible log filter panel: the toggle is mobile-only, and on desktop the
   panel is always shown inline with the toolbar. */
.log-filters {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: 10px 14px; flex: 0 1 auto; min-width: 0;
}
.log-filter-toggle { display: none; }

/* =====================================================================
   Mobile / small-screen support
   ===================================================================== */

/* Horizontal scroll for wide tables. `.table-responsive` (and the
   table-scroll / txn-table-scroll variants used by the fit layouts) were
   referenced by templates but never given overflow behaviour, so multi-column
   tables pushed past the viewport on phones. */
.table-responsive,
.table-scroll,
.txn-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.table-responsive > .table,
.table-scroll > .table,
.txn-table-scroll > .table { margin-bottom: 0; }

/* Off-canvas navigation controls (mobile only) */
.nav-toggle {
    display: none;
    align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0; flex-shrink: 0;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--surface-alt); color: var(--text-secondary);
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}
.nav-toggle:hover { color: var(--text); border-color: #cbd5e1; }
.nav-toggle .icon { width: 18px; height: 18px; }
.nav-close {
    display: none;
    align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0; flex-shrink: 0;
    margin-left: 6px;
    border: none; border-radius: 8px;
    background: transparent; color: rgba(255,255,255,.6);
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}
.nav-close:hover { background: rgba(255,255,255,.1); color: #fff; }
.nav-close .icon { width: 18px; height: 18px; }
.nav-backdrop { display: none; }

/* Fit-layout shells: dvh at all widths so tablets clear the Safari toolbar
   too (dvh == vh on desktop; phones unlock further down the cascade). */
@supports (height: 100dvh) {
    body.dashboard-fit .main-content,
    body.table-fit .main-content,
    body.logs-fit .main-content { height: 100dvh; }
}

/* Short viewports (landscape phones) are wider than the mobile breakpoint, so
   the width-based rules never run. The fit-to-viewport pages lock scrolling to
   a 100vh shell and would clip badly at ~430px height — fall back to normal
   document scrolling here too. */
@media (max-height: 560px) {
    body.dashboard-fit,
    body.table-fit,
    body.logs-fit { overflow: auto; }
    .content-area { flex: 0 0 auto; }
    .nav-tabs {
        position: sticky; top: var(--topbar-h, 57px); z-index: 20;
        background: var(--bg);
    }
    body.dashboard-fit .main-content,
    body.table-fit .main-content,
    body.logs-fit .main-content { height: auto; overflow: visible; }
    body.dashboard-fit .content-area,
    body.table-fit .content-area,
    body.logs-fit .content-area {
        display: block; min-height: 0; overflow: visible;
        padding: 16px !important;
    }
    body.table-fit .tab-content,
    body.logs-fit .tab-content { display: block; }
    body.table-fit .tab-pane.active,
    body.logs-fit .tab-pane.active {
        display: block !important;
        overflow: visible !important;
    }
    body.dashboard-fit .activity-scroll { max-height: 460px; }
    body.dashboard-fit .dash-cols { display: block; }
    body.logs-fit .log-terminal { height: 60vh; max-height: 60vh; }
}

@media (max-width: 768px) {
    /* Off-canvas navigation drawer */
    body { flex-direction: column; }
    .sidebar {
        position: fixed; inset: 0 auto 0 0;
        width: min(64vw, 248px); height: 100%;
        flex-direction: column; flex-wrap: nowrap;
        padding: 0;
        transform: translateX(-100%);
        visibility: hidden;
        transition: transform .25s cubic-bezier(.2,.9,.3,1), visibility .25s;
        z-index: 1045;
    }
    body.nav-open .sidebar {
        transform: translateX(0);
        visibility: visible;
        box-shadow: 24px 0 60px rgba(2,6,23,.45);
    }
    .nav-close { display: inline-flex; }
    .sidebar .nav {
        flex-direction: column !important; flex-wrap: wrap;
        flex: 1 1 auto; min-width: 0;
        overflow-x: hidden; overflow-y: auto;
        padding: 0 10px; gap: 0;
    }
    .sidebar .nav-link {
        padding: 12px 12px; font-size: .8125rem; margin-bottom: 2px;
        white-space: normal; flex: 0 0 auto;
    }
    .nav-section { display: block; }
    .sidebar-footer { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
    .logout-link { padding: 8px 10px; font-size: .8125rem; }

    .nav-toggle { display: inline-flex; }
    .nav-backdrop {
        display: none;
        position: fixed; inset: 0; z-index: 1040;
        background: rgba(3,7,18,.55);
        -webkit-backdrop-filter: blur(2px);
        backdrop-filter: blur(2px);
    }
    body.nav-open .nav-backdrop { display: block; }
    body.nav-open { overflow: hidden; }

    body { margin: 0; }
    .main-content { margin-left: 0; min-height: 100dvh; flex-shrink: 0; }
    .topbar { padding: 10px 14px; gap: 8px; flex-wrap: nowrap; }
    .topbar-crumb { flex: 1 1 auto; min-width: 0; }
    .topbar-root, .topbar-sep { display: none; }
    .topbar-title {
        font-size: 1rem; min-width: 0;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .topbar-status, #theme-toggle { flex-shrink: 0; }
    .content-area { flex: 0 0 auto; padding: 16px !important; }

/* Tab strips scroll horizontally instead of wrapping into several rows,
       and stay pinned under the topbar while the page scrolls. */
    .nav-tabs {
        flex-wrap: nowrap;
        /* Horizontal scroll only. `overflow-x: auto` would otherwise compute
           overflow-y to auto as well, and the active tab's 2px underline
           (bottom: -2px) pokes past the box and spawns a vertical scrollbar.
           The padding gives that underline somewhere to live. */
        overflow-x: auto; overflow-y: hidden;
        padding-bottom: 2px;
        -webkit-overflow-scrolling: touch;
        position: sticky; top: var(--topbar-h, 57px); z-index: 20;
        background: var(--bg);
    }
    .nav-tabs .nav-link { flex: 0 0 auto; white-space: nowrap; padding: 8px 12px; }
    .nav-tabs::-webkit-scrollbar { height: 4px; }

/* fit-to-viewport layouts (dashboard / integration / logs) must flow and scroll
       normally on small screens instead of clipping behind a 100vh shell. */
    body.dashboard-fit,
    body.table-fit,
    body.logs-fit { overflow: auto; }
    body.dashboard-fit .main-content,
    body.table-fit .main-content,
    body.logs-fit .main-content { height: auto; overflow: visible; }
    body.dashboard-fit .content-area,
    body.table-fit .content-area,
    body.logs-fit .content-area {
        display: block; min-height: 0; overflow: visible;
        padding: 16px !important;
    }
    body.table-fit .tab-content,
    body.logs-fit .tab-content { display: block; }
    body.table-fit .tab-pane.active,
    body.logs-fit .tab-pane.active {
        display: block !important;
        overflow: visible !important;
    }
    body.dashboard-fit .activity-scroll { max-height: 460px; }
    body.logs-fit .log-terminal { height: 60vh; max-height: 60vh; }

/* Slide-over drawers fill the phone screen. */
    dialog.drawer-dialog,
    dialog.drawer-dialog.drawer-lg {
        width: 100vw; max-width: 100vw;
        height: 100vh; max-height: 100vh;
    }
    .drawer-header { padding: 14px 16px; }
    .drawer-body { padding: 16px; }
    .drawer-footer { padding: 12px 16px; }

/* Dashboard */
    .hero-id { gap: 6px 14px; }
    .hero-id .id-chip { min-width: 0; max-width: 100%; }
    .hero-id .id-val { min-width: 0; overflow-wrap: anywhere; }

/* Dataflow metrics: keep the three tiles on one row instead of stacking
       them full-width (they consumed ~240px of vertical space on phones). */
    #dataflow-card .card-body { padding-left: 8px; padding-right: 8px; }
    #dataflow-card .col-md-4 { flex: 0 0 auto; width: 33.3333%; }
    #dataflow-card .metric-tile { padding: 6px 2px 8px; }
    #dataflow-card .metric-head {
        flex-wrap: wrap; justify-content: center;
        gap: 2px 5px; margin-bottom: 2px;
    }
    #dataflow-card .metric-icon { width: 18px; height: 18px; }
    #dataflow-card .metric-label { font-size: .6875rem; letter-spacing: .05em; }
    #dataflow-card .metric-value-wrap { font-size: 1rem; }
    #dataflow-card .metric-hint { font-size: .6875rem; margin-top: 1px; }
    .gateway-hero .card-body { padding: 16px; }
    .hero-main { gap: 12px 16px; }
    .hero-actions { width: 100%; flex-wrap: wrap; gap: 6px; }
    .hero-actions .btn { flex: 1 1 auto; justify-content: center; min-height: 36px; }
    .hero-stats { gap: 10px 20px; margin-top: 14px; padding-top: 12px; }
    .hero-stat { min-width: 72px; }

/* Dashboard: gateway + vitals stack above the feed; CPU / RAM / Disk stay
   side by side on one phone row. */
    body.dashboard-fit .dash-cols { display: block; }
    body.dashboard-fit .dash-main > .card:last-child { margin-bottom: 16px !important; }
    #dataflow-card .vitals-row > .col-md-4 { flex: 0 0 auto; width: 33.3333%; }
    #dataflow-card .vital-tile { padding: 10px 8px; }
    #dashboard-overview .health-head {
        flex-wrap: wrap; justify-content: center;
        gap: 0 6px; margin-bottom: 6px;
    }
    #dashboard-overview .health-title { font-size: .6875rem; }
    #dashboard-overview .health-value { font-size: .8125rem; }
    #dashboard-overview .health-bar {
        height: 4px; margin-top: 4px; margin-bottom: 0 !important;
    }
    #dashboard-overview .health-desc { display: none; }
    .activity-card .card-header { flex-wrap: wrap; gap: 8px; }

/* Integration page: readable tables with reachable row actions */
    .integration-toolbar .input-group.integration-search { max-width: none; flex: 1 1 100%; }
    .integration-toolbar .form-control,
    .integration-toolbar .toolbar-btn,
    #gw .toolbar-btn { height: 38px; }

/* Logs: compact the command bar — one row of query + one compact utility
       row, with the filter panel expanding below when toggled. */
    .log-toolbar { gap: 8px; padding-bottom: 8px; }
    .log-toolbar-row { gap: 8px; }
    .log-search { flex: 1 1 150px; max-width: none; min-width: 0; }
    .log-filters { display: none; order: 30; width: 100%; gap: 8px; }
    .log-toolbar.filters-open .log-filters,
    .txn-card-body.filters-open .log-filters { display: flex; }
    .log-field { flex: 0 1 auto; }
    .log-filter-toggle { display: inline-flex; align-items: center; flex: 0 0 auto; }
    .log-filter-toggle[aria-expanded="true"] {
        background: var(--accent-light); border-color: var(--accent); color: var(--accent);
    }
    /* Utilities get their own short row so row 1 stays search + Filters. */
    .log-toolbar-actions { order: 20; width: 100%; justify-content: flex-end; gap: 6px; }
    .log-toolbar .form-select,
    .log-toolbar .form-control { height: 32px; font-size: .75rem; }
    .log-toolbar .btn { padding: .3rem .55rem; font-size: .75rem; }
    .log-ibtn { width: 36px; height: 36px; }
    .live-ctl .live-main, .live-ctl .live-caret { height: 36px; }
    .log-search.log-search-plain { flex: 1 1 100%; max-width: none; }
    .time-pop .time-pop-label { min-width: 54px; }

/* (The transaction toolbar now uses the shared .log-toolbar grammar, so the
   old .txn-card-body > .d-flex.flex-wrap overrides are no longer needed.) */

/* Logs: transaction / equipment-events / buffer tables use cards on phones. */
    #txn-table-region .table-responsive,
    #eq-table-region .table-responsive,
    #buffer-table-region .table-responsive { overflow-x: visible; }
    #txn-table-region .table,
    #txn-table-region .table tbody,
    #txn-table-region .table tr,
    #txn-table-region .table td,
    #eq-table-region .table,
    #eq-table-region .table tbody,
    #eq-table-region .table tr,
    #eq-table-region .table td,
    #buffer-table-region .table,
    #buffer-table-region .table tbody,
    #buffer-table-region .table tr,
    #buffer-table-region .table td { display: block; width: auto; }
    #txn-table-region .table thead,
    #eq-table-region .table thead,
    #buffer-table-region .table thead { display: none; }
    #txn-table-region .table tbody tr,
    #eq-table-region .table tbody tr,
    #buffer-table-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #txn-table-region .table tbody tr:last-child,
    #eq-table-region .table tbody tr:last-child,
    #buffer-table-region .table tbody tr:last-child { margin-bottom: 0; }
    #txn-table-region .table td,
    #eq-table-region .table td,
    #buffer-table-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
    }
    #txn-table-region .table td.text-truncate,
    #buffer-table-region .table td.text-truncate { max-width: none !important; white-space: normal; }
    #txn-table-region .table td[data-label="Time"],
    #eq-table-region .table td[data-label="Time"],
    #buffer-table-region .table td[data-label="Topic"] {
        font-size: .75rem; font-weight: 600; padding-bottom: 6px;
    }
    #txn-table-region .table td[data-label="Time"] small,
    #eq-table-region .table td[data-label="Time"] small { font-size: inherit; }
    #txn-table-region .table td[data-label]:not([data-label="Time"]),
    #eq-table-region .table td[data-label]:not([data-label="Time"]),
    #buffer-table-region .table td[data-label]:not([data-label="Topic"]) {
        display: grid; grid-template-columns: 76px 1fr; gap: 10px;
        align-items: start;
    }
    #txn-table-region .table td[data-label]:not([data-label="Time"])::before,
    #eq-table-region .table td[data-label]:not([data-label="Time"])::before,
    #buffer-table-region .table td[data-label]:not([data-label="Topic"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #txn-table-region .table td > *,
    #eq-table-region .table td > *,
    #buffer-table-region .table td > * { justify-self: start; }
    #txn-table-region .table td[data-label="Actions"] .icon-btn,
    #buffer-table-region .table td[data-label="Expand"] .icon-btn { width: 34px; height: 34px; }
    #txn-table-region .table td[colspan],
    #eq-table-region .table td[colspan],
    #buffer-table-region .table td[colspan] { padding: 16px 0; }

/* Integration -> Telemetry / COV "Raw" editor: the deskop fit-layout stretch is
       disabled on mobile, which collapsed the textarea to two rows. Give it the
       screen height (minus the tabs/toolbar above and the Save row below). */
    .raw-editor-textarea,
    body.table-fit .raw-editor-textarea {
        height: max(220px, calc(100vh - 380px));
        height: max(220px, calc(100dvh - 380px));
        min-height: max(220px, calc(100vh - 380px)) !important;
        min-height: max(220px, calc(100dvh - 380px)) !important;
        max-height: none !important;
        resize: none;
    }

/* Gateway output: comfortable controls and denser lines on phones. */
    .gw-nav { flex-wrap: wrap; row-gap: 6px; }
    .gw-nav .btn,
    .gw-nav-older .btn {
        min-height: 38px; flex: 1 1 auto; justify-content: center;
    }
    .gw-nav-older .btn { width: 100%; }
    .log-terminal { line-height: 1.45; }

/* Audit log: five columns can't fit a phone — use the card pattern. */
    #audit-filter { flex: 1 1 100%; }
    #audit-table-region .table-responsive { overflow-x: visible; }
    #audit-table-region .table,
    #audit-table-region .table tbody,
    #audit-table-region .table tr,
    #audit-table-region .table td { display: block; width: auto; }
    #audit-table-region .table thead { display: none; }
    #audit-table-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #audit-table-region .table tbody tr:last-child { margin-bottom: 0; }
    #audit-table-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
    }
    #audit-table-region .table td.text-truncate { max-width: none !important; white-space: normal; }
    #audit-table-region .table td[data-label="Time"] {
        font-size: .75rem; font-weight: 600; padding-bottom: 6px;
    }
    #audit-table-region .table td[data-label="Time"] small { font-size: inherit; }
    #audit-table-region .table td:not([data-label="Time"]) {
        display: grid; grid-template-columns: 76px 1fr; gap: 10px;
        align-items: start;
    }
    #audit-table-region .table td:not([data-label="Time"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #audit-table-region .table td > * { justify-self: start; }
    #audit-table-region .table tr.audit-empty-row {
        border: none; background: transparent; padding: 0;
    }
    #audit-table-region .table tr.audit-empty-row td { padding: 16px 0; }
    #audit-table-region .table tr td[colspan] { display: block; }
    #audit-table-region .table tr td[colspan]::before { content: none; }

/* Users: same card pattern (was the last table scrolling sideways on phones). */
    #users-table-region .table-responsive { overflow-x: visible; }
    #users-table-region .table,
    #users-table-region .table tbody,
    #users-table-region .table tr,
    #users-table-region .table td { display: block; width: auto; }
    #users-table-region .table thead { display: none; }
    #users-table-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #users-table-region .table tbody tr:last-child { margin-bottom: 0; }
    #users-table-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
    }
    #users-table-region .table td[data-label="Username"] {
        font-size: .875rem; padding-bottom: 6px;
    }
    #users-table-region .table td:not([data-label="Username"]) {
        display: grid; grid-template-columns: 76px 1fr; gap: 10px;
        align-items: start;
    }
    #users-table-region .table td:not([data-label="Username"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #users-table-region .table td > * { justify-self: start; }
    #users-table-region .table td[data-label="Actions"] .icon-btn {
        width: 34px; height: 34px;
    }
    #users-table-region .table tr td[colspan] {
        display: block; padding: 16px 0;
    }
    #users-table-region .table tr td[colspan]::before { content: none; }

/* Upstream / Downstream stack on phones — separate them visually. */
    #main-integration-form .col-md-6 > h6 {
        margin-top: 18px; padding-top: 14px;
        border-top: 1px solid var(--border-light);
    }
    #main-integration-form .col-md-6:first-child > h6 {
        margin-top: 0; padding-top: 0; border-top: none;
    }

/* Telemetry / COV datapoints: same card pattern as the certificates grid. */
    #dp-telemetry-region .table-scroll,
    #dp-cov-region .table-scroll { overflow-x: visible; }
    #dp-telemetry-region .table,
    #dp-telemetry-region .table tbody,
    #dp-telemetry-region .table tr,
    #dp-telemetry-region .table td,
    #dp-cov-region .table,
    #dp-cov-region .table tbody,
    #dp-cov-region .table tr,
    #dp-cov-region .table td { display: block; width: auto; }
    #dp-telemetry-region .table thead,
    #dp-cov-region .table thead { display: none; }
    #dp-telemetry-region .table tbody tr,
    #dp-cov-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #dp-telemetry-region .table tbody tr:last-child,
    #dp-cov-region .table tbody tr:last-child { margin-bottom: 0; }
    #dp-telemetry-region .table td,
    #dp-cov-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
    }
    #dp-telemetry-region .table td.text-truncate,
    #dp-cov-region .table td.text-truncate {
        max-width: none !important; white-space: normal;
    }
    #dp-telemetry-region .table td[data-label="Equipment"],
    #dp-cov-region .table td[data-label="Equipment"] {
        font-size: .8125rem; font-weight: 600; padding-bottom: 6px;
    }
    #dp-telemetry-region .table td:not([data-label="Equipment"]),
    #dp-cov-region .table td:not([data-label="Equipment"]) {
        display: grid; grid-template-columns: 76px 1fr; gap: 10px;
        align-items: start;
    }
    #dp-telemetry-region .table td:not([data-label="Equipment"])::before,
    #dp-cov-region .table td:not([data-label="Equipment"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #dp-telemetry-region .table td > *,
    #dp-cov-region .table td > * { justify-self: start; }
    #dp-telemetry-region .table .row-actions,
    #dp-cov-region .table .row-actions { white-space: nowrap; }
    #dp-telemetry-region .table td[data-label="Actions"] .icon-btn,
    #dp-cov-region .table td[data-label="Actions"] .icon-btn {
        width: 34px; height: 34px;
    }
    #dp-telemetry-region .table tr.dp-empty-row,
    #dp-cov-region .table tr.dp-empty-row {
        border: none; background: transparent; padding: 0;
    }
    #dp-telemetry-region .table tr.dp-empty-row td,
    #dp-cov-region .table tr.dp-empty-row td { padding: 16px 0; }
    #dp-telemetry-region .table tr td[colspan],
    #dp-cov-region .table tr td[colspan] { display: block; }
    #dp-telemetry-region .table tr td[colspan]::before,
    #dp-cov-region .table tr td[colspan]::before { content: none; }

/* Insights "browse" dialogs (datapoints / fleet): same card pattern on phones. */
    #datapoint-table-region .table-responsive,
    #fleet-table-region .table-responsive { overflow-x: visible; }
    #datapoint-table-region .table,
    #datapoint-table-region .table tbody,
    #datapoint-table-region .table tr,
    #datapoint-table-region .table td,
    #fleet-table-region .table,
    #fleet-table-region .table tbody,
    #fleet-table-region .table tr,
    #fleet-table-region .table td { display: block; width: auto; }
    #datapoint-table-region .table thead,
    #fleet-table-region .table thead { display: none; }
    #datapoint-table-region .table tbody tr,
    #fleet-table-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #datapoint-table-region .table tbody tr:last-child,
    #fleet-table-region .table tbody tr:last-child { margin-bottom: 0; }
    #datapoint-table-region .table td,
    #fleet-table-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
        text-align: left;
    }
    #datapoint-table-region .table td[data-label="Equipment"],
    #fleet-table-region .table td[data-label="Equipment"] {
        font-size: .8125rem; font-weight: 600; padding-bottom: 6px;
    }
    #datapoint-table-region .table td:not([data-label="Equipment"]),
    #fleet-table-region .table td:not([data-label="Equipment"]) {
        display: grid; grid-template-columns: 106px 1fr; gap: 10px;
        align-items: start;
    }
    #datapoint-table-region .table td:not([data-label="Equipment"])::before,
    #fleet-table-region .table td:not([data-label="Equipment"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #datapoint-table-region .table td > *,
    #fleet-table-region .table td > * { justify-self: start; }
    #datapoint-table-region .table tr.dp-empty-row,
    #fleet-table-region .table tr.dp-empty-row {
        border: none; background: transparent; padding: 0;
    }
    #datapoint-table-region .table tr.dp-empty-row td,
    #fleet-table-region .table tr.dp-empty-row td { padding: 16px 0; }
    #datapoint-table-region .table tr td[colspan],
    #fleet-table-region .table tr td[colspan] { display: block; }
    #datapoint-table-region .table tr td[colspan]::before,
    #fleet-table-region .table tr td[colspan]::before { content: none; }

/* Onboarding "Discover points" rows: cards on phones; long NodeIDs wrap. */
    #ob-discover-table .table-responsive { overflow-x: visible; }
    #ob-discover-table .table,
    #ob-discover-table .table tbody,
    #ob-discover-table .table tr,
    #ob-discover-table .table td { display: block; width: auto; }
    #ob-discover-table .table thead { display: none; }
    #ob-discover-table .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #ob-discover-table .table tbody tr:last-child { margin-bottom: 0; }
    #ob-discover-table .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
        text-align: left;
    }
    #ob-discover-table .table td[data-label="Point Name"],
    #ob-discover-table .table td[data-label="Object Name"] {
        font-size: .8125rem; font-weight: 600; padding-bottom: 6px;
    }
    #ob-discover-table .table td:not([data-label="Point Name"]):not([data-label="Object Name"]) {
        display: grid; grid-template-columns: 106px 1fr; gap: 10px;
        align-items: start;
    }
    #ob-discover-table .table td:not([data-label="Point Name"]):not([data-label="Object Name"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }

/* Gateway certificates: a 6-column table can't fit a phone, and horizontal
       scrolling hides the content. Turn each row into a labelled card instead. */
    #cert-table-region .table-scroll { overflow-x: visible; }
    #cert-table-region .table,
    #cert-table-region .table tbody,
    #cert-table-region .table tr,
    #cert-table-region .table td { display: block; width: auto; }
    #cert-table-region .table thead { display: none; }
    #cert-table-region .table tbody tr {
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface-alt);
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    #cert-table-region .table tbody tr:last-child { margin-bottom: 0; }
    #cert-table-region .table td {
        border: none; padding: 3px 0;
        white-space: normal; overflow-wrap: anywhere;
    }
    #cert-table-region .table td[data-label="File"] {
        font-size: .8125rem; font-weight: 600; padding-bottom: 6px;
    }
    #cert-table-region .table td:not([data-label="File"]) {
        display: grid; grid-template-columns: 106px 1fr; gap: 10px;
        align-items: start;
    }
    #cert-table-region .table td:not([data-label="File"])::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 4px; line-height: 1.2; white-space: nowrap;
    }
    #cert-table-region .table td > * { justify-self: start; }
    #cert-table-region .table .row-actions { white-space: nowrap; }
    #cert-table-region .table td[data-label="Actions"] .icon-btn {
        width: 34px; height: 34px;
    }
    #cert-table-region .table tr td[colspan] { display: block; }
    #cert-table-region .table tr td[colspan]::before { content: none; }

    .cert-detail-grid { grid-template-columns: 1fr; }
}

/* Drawers track the dynamic viewport at every width (tablets included) so the
   footer clears the Safari toolbar; dvh == vh on desktop. */
@supports (height: 100dvh) {
    dialog.drawer-dialog,
    dialog.drawer-dialog.drawer-lg { height: 100dvh; max-height: 100dvh; }
}

@media (max-width: 480px) {
    .content-area { padding: 12px !important; }
    .card-body { padding: 16px; }
    .integration-action-bar { margin: 1.25rem -16px -16px; padding: 12px 16px 14px; border: 0; border-top: 1px solid var(--border); border-radius: 0; }
    .card-header { padding: 12px 16px; }

/* Full-bleed standard dialogs and room for the inner card. */
    dialog:not(.drawer-dialog) { width: 100vw; max-width: 100vw; border-radius: 0; }
    .dialog-box { padding: 18px 16px; }
    .cf-footer { margin: 18px -16px -20px; padding: 12px 16px 14px; }

    body.standalone { padding: 16px; }
    .standalone-card { padding: 28px 20px; }

/* Topbar theme toggle: icons only so everything fits. */
    #theme-toggle .seg-btn { padding: 6px 9px; }
    #theme-toggle .seg-btn span { display: none; }
    #theme-toggle .seg-btn .icon { width: 15px; height: 15px; }

    .log-search { min-width: 0; flex: 1 1 100%; max-width: none; }
}

/* ── Unified htmx feedback: top progress bar + toasts ── */
.hx-progress {
    position: fixed; top: 0; left: 0; right: 0; height: 3px;
    z-index: 3000; display: none; overflow: hidden; pointer-events: none;
}
body:has(.htmx-request) .hx-progress { display: block; }
.hx-progress::after {
    content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 40%;
    background: var(--accent); border-radius: 2px;
    animation: hx-progress-slide 1.1s linear infinite;
}
@keyframes hx-progress-slide {
    from { transform: translateX(-100%); }
    to { transform: translateX(350%); }
}

.toast-host {
    position: fixed; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 3000; display: flex; flex-direction: column; gap: 8px;
    max-width: min(360px, calc(100vw - 32px)); pointer-events: none;
}
.toast-host .ntf--toast { pointer-events: auto; }

/* ── Audit details expander ── */
.audit-details summary.audit-details-summary {
    cursor: pointer; max-width: 220px; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap;
    color: var(--text-secondary);
}
.audit-details[open] summary.audit-details-summary { white-space: normal; }
.audit-details pre.detail-pre { margin: 6px 0 0; max-height: 260px; overflow: auto; }

/* ── Timezone chip + keyboard focus affordances ── */
.tz-chip {
    border: 1px solid var(--border); border-radius: 999px;
    padding: 1px 8px; font-size: .6875rem; text-transform: uppercase;
    letter-spacing: .04em;
}
.sortable:focus-visible,
.pts-badge:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px;
}

/* ── Coarse pointers (on-site tablets/gloves): comfortable hit areas ── */
@media (pointer: coarse) {
    .icon-btn,
    #txn-table-region .table td[data-label="Actions"] .icon-btn,
    #buffer-table-region .table td[data-label="Expand"] .icon-btn,
    #dp-telemetry-region .table td[data-label="Actions"] .icon-btn,
    #dp-cov-region .table td[data-label="Actions"] .icon-btn,
    #cert-table-region .table td[data-label="Actions"] .icon-btn {
        width: 44px; height: 44px;
    }
    .btn-sm { min-height: 40px; padding-top: 8px; padding-bottom: 8px; }
    .ntf__close { min-width: 40px; min-height: 40px; }
    .nav-link { min-height: 44px; }
}

/* =====================================================================
   Review round (v14.14): keyboard access, small components, motion
   ===================================================================== */

/* Sidebar nav landmark wrapper: transparent to the flex layout. */
.sidebar-nav { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* Skip link: first tab stop jumps straight past the sidebar to the content. */
.skip-link {
    position: fixed; left: 10px; top: -60px; z-index: 4000;
    background: var(--surface); color: var(--accent);
    border: 1px solid var(--accent); border-radius: 8px;
    padding: 8px 14px; font-weight: 600; font-size: .8125rem;
    text-decoration: none; transition: top .15s ease;
}
.skip-link:focus { top: 10px; }

/* Unsaved-changes dot on the Configurations tab label (#b45309 keeps 3:1 on the
   light tab strip; the amber token is fine on the dark surface). */
.tab-dirty-dot {
    display: inline-block; width: 7px; height: 7px; flex-shrink: 0;
    border-radius: 50%; background: #b45309;
}
[data-theme="dark"] .tab-dirty-dot { background: var(--warning); }

/* Unsaved-changes text: #b45309 passes AA on the light surface. */
#integration-dirty.text-warning { color: #b45309 !important; }
[data-theme="dark"] #integration-dirty.text-warning { color: var(--warning) !important; }

/* Integration section headings (Upstream / Downstream). */
.integration-sect {
    font-size: .75rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .07em; color: var(--text-secondary);
    padding-bottom: 6px; border-bottom: 1px solid var(--border-light);
}

/* Table empty states reuse the dashboard empty-state component. */
.empty-cell { padding: 18px 0 !important; }
.empty-state .icon { width: 1.6rem; height: 1.6rem; opacity: .55; }
.empty-state .empty-actions { margin-top: 2px; }

/* Show/hide password toggle (login page). */
.pw-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0 .6rem;
}
.pw-toggle .icon { width: 1rem; height: 1rem; }

/* Respect users who prefer reduced motion: entrance effects, pulses and the
   indeterminate progress bar all collapse to effectively no animation. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Configurations pane: stretch the card + form to the pane so the action bar
   rests on the pane bottom even when the form is shorter than the viewport
   (the sticky rule keeps it visible while scrolling long forms). The form
   gap keeps a 1.5rem minimum between the cards and the bar: when the form
   overflows, `margin-top: auto` collapses to 0, so without the gap the
   cards would touch the bar. */
body.table-fit .tab-pane#main.active { display: flex; flex-direction: column; }
body.table-fit .tab-pane#main.active > .card {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit .tab-pane#main.active .card-body {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.table-fit #main-integration-form { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 1.5rem; }
body.table-fit #main-integration-form .integration-action-bar { margin-top: auto; }

/* Utilities added for the topbar round: phone-only visibility + SR-only. */
@media (min-width: 768px) { .d-md-none { display: none !important; } }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ─────────────────────────── Networks page (LAN + Discovery redesign) ─────────────────────────── */

/* Summary strip: links up · portal-session adapter · discovery state · age. */
.net-strip {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 11px 18px;
    box-shadow: var(--shadow-xs); margin-bottom: 1rem;
}
.net-strip-item {
    /* Wrap instead of crushing: long endpoints (.net-strip-val) squeeze to a
       one-character column when a single nowrap line can't fit a phone. */
    display: inline-flex; align-items: center; flex-wrap: wrap; gap: 7px;
    font-size: .8125rem; color: var(--text-secondary);
}
.net-strip-item b { color: var(--text); font-weight: 600; }
.net-strip-item > .icon { color: var(--text-muted); }
.net-strip-sep { width: 1px; height: 16px; background: var(--border); }
.net-updated { margin-left: auto; font-size: .75rem; color: var(--text-muted); }

/* State dots: one visual language for adapters and discovery. */
.net-dot {
    width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
    display: inline-block; background: var(--text-muted);
}
.net-dot.up { background: var(--success); }
.net-dot.warn { background: var(--warning); }
.net-dot.off { background: var(--text-muted); }

/* Tab count badge (LAN tab). */
.net-tab-count {
    font-size: .6875rem; font-weight: 700; line-height: 1.5;
    background: var(--surface-alt); border: 1px solid var(--border);
    color: var(--text-muted); border-radius: 100px; padding: 0 7px; margin-left: 7px;
}
.nav-tabs .nav-link.active .net-tab-count {
    background: var(--surface); color: var(--accent); border-color: var(--accent-light);
}

/* Adapter list. */
.net-list-head {
    display: flex; align-items: center; justify-content: space-between;
    margin: 2px 2px 10px; gap: 8px;
}
.net-list-head .lh-title {
    font-size: .6875rem; text-transform: uppercase; letter-spacing: .08em;
    font-weight: 700; color: var(--text-muted);
}
.net-adapters { display: flex; flex-direction: column; gap: 10px; }
.net-row {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow-xs);
    padding: 13px 16px;
    display: grid; grid-template-columns: 1fr auto;
    column-gap: 14px; row-gap: 3px;
    transition: box-shadow var(--transition), border-color var(--transition);
}
.net-row:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
.net-row-unmanaged { background: var(--surface-alt); }

/* Tinted rows for the long log/certificate lists (transaction log,
   equipment events, upstream buffer, certificates): white rows on the white
   card body blended together, so the row fill steps down one tone — the same
   value used for table striping. Scoped per region: in other views .net-row
   stays a plain surface, and --surface-alt keeps its "unmanaged" meaning
   where that state applies. */
#txn-table-region .net-adapters > .net-row,
#eq-table-region .net-adapters > .net-row,
#buffer-table-region .net-adapters > .net-row,
#cert-table-region .net-adapters > .net-row {
    background: var(--surface-alt);
}
.net-row-id {
    grid-column: 1; display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    font-size: .8125rem; font-weight: 600; color: var(--text-secondary);
}
.net-row-id .net-name {
    font-size: .875rem; font-weight: 700; color: var(--text);
}
.net-row-act { grid-column: 2; grid-row: 1 / span 3; align-self: center; }
.net-row-main { grid-column: 1; font-size: .8125rem; color: var(--text); min-width: 0; }
#txn-table-region .net-row-main { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.net-row-main .net-ip {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-weight: 600; word-break: break-all;
}
.net-row-facts {
    grid-column: 1; font-size: .75rem; color: var(--text-muted);
    word-break: break-word;
}
.net-row-facts .font-monospace { color: var(--text-secondary); }

/* Dashboard: endpoint rows in the gateway card (aligned label column, URLs
   may wrap) and clickable activity rows (role=button rows get a pointer). */
.gw-endpoint-label { min-width: 7rem; }
.gw-endpoint-url { word-break: break-all; }
.net-row[role="button"] { cursor: pointer; }

/* Chips: Uplink / Portal session / pending. */
.net-chip {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: .6875rem; font-weight: 700; white-space: nowrap;
    border-radius: 100px; padding: 2px 9px;
    background: var(--surface-alt); border: 1px solid var(--border); color: var(--text-muted);
}
.net-chip > .icon { width: .85em; height: .85em; }
.net-chip-accent { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.net-chip-warn { background: var(--warning-light); border-color: transparent; color: var(--warning); }
/* Danger variant (Logs: alarm subject, parse errors), success variant (VPN
   detected type) and clickable chips (Logs: subject summary chips act as
   filters). */
.net-chip-danger { background: var(--danger-light); border-color: transparent; color: var(--danger); }
.net-chip-ok { background: var(--success-light); border-color: transparent; color: var(--ntf-success-fg); }
button.net-chip { cursor: pointer; }
button.net-chip:hover { border-color: var(--accent); }

/* Canonical badge family (v14.34): every badge in the portal (feed / fleet /
   anomaly / risk / audit / .badge + .bg-* / status pills) shares the
   .net-chip metrics, typography and neutral skin above. The base rules use
   zero-specificity :where() so each family's own tone rules keep winning
   regardless of where they sit in this file. Tone recipe: tinted (-light)
   background + same-hue text + transparent border; neutral = surface-alt +
   1px border + text-muted. */
:where(.badge, .fleet-badge, .anom-badge, .risk-tier, .risk-delta,
       .factor-chip, .audit-badge, .hero-pill, .insight-tag, .state-chip, .log-count) {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: .6875rem; font-weight: 700; white-space: nowrap;
    border-radius: 100px; padding: 2px 9px;
    background: var(--surface-alt); border: 1px solid var(--border); color: var(--text-muted);
}

/* Success tone flip in dark theme: the action tokens are static light-mode
   shades, so dark uses the --success token (same recipe as
   .status-pill-running). */
[data-theme="dark"] .fleet-badge.b-active,
[data-theme="dark"] .anom-badge.normal,
[data-theme="dark"] .risk-tier.low,
[data-theme="dark"] .risk-delta.down,
[data-theme="dark"] .audit-badge-login_success,
[data-theme="dark"] .audit-badge-password_change,
[data-theme="dark"] .audit-badge-user_create,
[data-theme="dark"] .audit-badge-network_keep,
[data-theme="dark"] .audit-badge-admin_recovery,
[data-theme="dark"] .state-chip.ok { color: var(--success); }

/* Pending-change strip: sticky, names the adapter, countdown + progress. */
.net-pending {
    position: sticky; top: calc(var(--topbar-h, 57px) + 10px); z-index: 20;
    border: 1px solid rgba(217, 119, 6, .4);
    background: var(--warning-light);
    border-radius: var(--radius); padding: 12px 16px 10px;
    margin-bottom: 14px; box-shadow: var(--shadow);
    display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px 12px;
}
[data-theme="dark"] .net-pending { border-color: rgba(251, 191, 36, .45); }
.net-pending-text { min-width: 220px; font-size: .8125rem; color: var(--text); }
.net-pending-text b { font-weight: 700; }
.net-countdown {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
    font-weight: 700; font-size: 1rem; color: var(--warning);
}
.net-pending-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.net-pbar {
    grid-column: 1 / -1; height: 4px; border-radius: 100px;
    background: rgba(217, 119, 6, .25); overflow: hidden;
}
.net-pbar > i {
    display: block; height: 100%; width: 100%;
    background: var(--warning); border-radius: 100px; transition: width 1s linear;
}
[data-theme="dark"] .net-pbar { background: rgba(251, 191, 36, .2); }

/* Discovery card: custom head (no nested card framing, no accent bar). */
.net-card-head {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    padding: 13px 20px; border-bottom: 1px solid var(--border);
}
.net-card-title { display: inline-flex; align-items: center; gap: 7px; font-weight: 600; font-size: .875rem; }
.net-card-title > .icon { color: var(--text-muted); }
.net-card-head .btn { margin-left: auto; }
.net-state { display: inline-flex; align-items: center; gap: 6px; font-size: .75rem; font-weight: 700; }
.net-state.is-up { color: var(--success); }
.net-state.is-warn { color: var(--warning); }
.net-state.is-off { color: var(--text-muted); }
.net-lede { font-size: .8125rem; color: var(--text-secondary); margin-bottom: 16px; max-width: 660px; }
.net-hint { font-size: .8125rem; color: var(--text-secondary); margin: 0 0 16px; }

.net-urlbox { border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; margin-bottom: 16px; }
.net-urlrow {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 11px 14px; background: var(--surface-alt);
}
.net-url {
    flex: 1; min-width: 0; font-size: .875rem; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.net-urlrow .btn { white-space: nowrap; }
.net-urlmeta {
    padding: 8px 14px 9px; font-size: .75rem; color: var(--text-muted);
    border-top: 1px solid var(--border); background: var(--surface);
}
.net-qrrow { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.net-qr {
    flex-shrink: 0; border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: #fff; padding: 2px;
}
.net-qrnote { font-size: .75rem; color: var(--text-secondary); max-width: 460px; }
.net-card-foot {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px;
    padding: 12px 20px; border-top: 1px solid var(--border); background: var(--surface-alt);
}
.net-card-foot form { margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; width: 100%; }
.net-foot-note { font-size: .75rem; color: var(--text-muted); }

/* Users list: identity (username + role) leads the row, larger than the meta line. */
.net-row-user .net-name { font-size: 1rem; }
.net-row-user .net-row-id { gap: 10px; }

/* Audit list: day separators between groups of event rows. Rows stack with
   the same 10px rhythm as .net-adapters (Networks/Certificates) — flush
   card rows would merge borders and pinch the rounded corners. */
.audit-day { margin: 16px 2px 10px; }
#audit-table-region > .net-row + .net-row { margin-top: 10px; }
.net-row[data-audit-expandable] { cursor: pointer; }

@media (max-width: 991.98px) {
    .net-strip-sep { display: none; }
    .net-updated { margin-left: 0; }
    .net-row { grid-template-columns: 1fr; }
    .net-row-act { grid-column: 1; grid-row: auto; align-self: stretch; margin-top: 8px; }
    .net-row-act .btn { width: 100%; justify-content: center; }
}
@media (max-width: 575.98px) {
    .net-pending { grid-template-columns: 1fr; }
    .net-pending-text { min-width: 0; }
    .net-pending-actions .btn { flex: 1; justify-content: center; }
    .net-urlrow .btn { width: 100%; justify-content: center; }
    .net-qrrow { flex-direction: column; align-items: flex-start; }
}

/* =====================================================================
   Integration page (v14.20): page-level saved-config strip, two connection
   cards with network-style card heads, certificate row cards. Reuses the
   .net-* components defined in the Networks page section above.
   ===================================================================== */

/* Values inside the page-level saved-config strip (long hosts may wrap). */
.net-strip-val { font-size: .75rem; color: var(--text); min-width: 0; overflow-wrap: anywhere; }

/* Two connection cards (upstream / downstream). */
.cfg-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.cfg-cards .card { margin-bottom: 0; }
.cfg-sub { font-size: .75rem; color: var(--text-muted); margin-top: 1px; }
.net-card-head .seg { margin-left: auto; }

/* Field-group captions inside a column. */
.fgroup {
    font-size: .6875rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .08em; color: var(--text);
    border-bottom: 2px solid var(--text-muted);
    padding-bottom: 6px; margin: 18px 0 12px;
}
.f-group-item { margin-bottom: 12px; }

/* Width-proportional field rows (port stays numeric-width, host grows). */
.field-row { display: flex; gap: 12px; }
.field-row .f-grow { flex: 1 1 auto; min-width: 0; }
.field-row .f-port { flex: 0 0 110px; width: 110px; }
.poll-row { align-items: flex-start; }
.poll-row .f-poll { flex: 0 0 130px; }
.poll-row .f-toggle { flex: 1 1 auto; min-width: 0; }
.form-label-inline { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Stacked-pair labels share one box height so a state chip in one half
   cannot push its control below the sibling's. */
.field-row.stack-sm .form-label { display: flex; align-items: center; min-height: 20px; }

/* Segmented control (protocol switch, view switch). */
.seg {
    display: inline-flex; gap: 3px; flex-shrink: 0;
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 100px; padding: 3px;
}
.seg-opt { position: relative; display: inline-flex; margin: 0; }
.seg-opt input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.seg-opt span,
.seg-btn {
    display: inline-flex; align-items: center; gap: 6px;
    border: 1px solid transparent; background: transparent; color: var(--text-muted);
    font-family: inherit; font-size: .75rem; font-weight: 600; line-height: 1.2;
    padding: 5px 12px; border-radius: 100px; cursor: pointer;
    white-space: nowrap; text-decoration: none;
}
.seg-btn:hover { color: var(--text); }
.seg-opt input:checked + span,
.seg-btn.on,
.seg-btn.active {
    background: var(--surface); color: var(--accent);
    border-color: var(--border); box-shadow: var(--shadow-xs);
}
.seg-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.seg-sm .seg-opt span, .seg-sm .seg-btn { padding: 3px 10px; font-size: .75rem; }
/* Full-width variant (VPN client-type switch). */
.seg.seg-fill { display: flex; width: 100%; }
.seg.seg-fill .seg-btn { flex: 1 1 0; justify-content: center; }

/* Small status chips (credential saved state). */
.state-chip .icon { width: .85em; height: .85em; }
.state-chip.ok { background: var(--success-light); border-color: transparent; color: var(--action-success); }
.state-chip.accent { background: var(--accent-light); border-color: transparent; color: var(--accent); }
.state-chip.warn { background: var(--warning-light); border-color: transparent; color: var(--ntf-warning-fg); }

/* Inline point-tag chips (first tags visible, rest behind +N popover). */
.dp-points-cell { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; }
.tag-chip {
    display: inline-flex; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    font-size: .6875rem; font-weight: 600; color: var(--text-secondary);
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 6px; padding: 1px 7px;
}
.tag-more { font-size: .6875rem; font-weight: 700; color: var(--accent); }

/* Test Connections feedback: the summary stays in the sticky action bar and
   the per-destination panel opens upward from it. */
.integration-test-result { margin: 0 0 12px; }

.integration-test-busy { display: none; margin: 0 0 12px; }
.integration-action-bar.htmx-request .integration-test-result { display: none; }
.integration-action-bar.htmx-request .integration-test-busy { display: block; }

.test-disclosure { margin: 0; }
.test-result-summary {
    display: flex; align-items: center; gap: 10px;
    margin: 0; padding: 7px 10px;
    list-style: none; cursor: pointer;
}
.test-result-summary::-webkit-details-marker { display: none; }
.test-result-summary .ntf__icon { width: 24px; height: 24px; margin-top: 0; }
.test-result-summary .ntf__icon .icon { width: 14px; height: 14px; }
.test-result-summary .ntf__body { display: flex; align-items: center; min-width: 0; }
.test-result-summary .ntf__text { margin-top: 0; }
.test-result-summary .test-result-meta { color: var(--text-muted); }
.test-result-summary .ntf-btn { margin-left: auto; flex: 0 0 auto; }
.test-result-summary .test-chevron { transition: transform var(--transition); }
.test-disclosure[open] .test-chevron { transform: rotate(180deg); }
.test-result-summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.test-busy-row, .test-result-static { cursor: default; }
.test-busy-row .spinner-border { color: var(--ntf-info-fg); }

.test-details {
    position: absolute; z-index: 10; right: 0; bottom: calc(100% + 10px);
    width: min(600px, calc(100% - 24px));
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow-lg);
    padding: 14px 16px 12px;
    animation: ntf-in .18s cubic-bezier(.4, 0, .2, 1);
}
.test-details::after {
    content: ""; position: absolute; right: 24px; bottom: -6px;
    width: 10px; height: 10px; background: var(--surface);
    border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
    transform: rotate(45deg);
}
.test-details-head {
    display: flex; align-items: center; gap: 8px;
    padding-bottom: 10px; border-bottom: 1px solid var(--border-light);
}
.test-details-title { font-weight: 700; font-size: .8125rem; color: var(--text); }
.test-details-time { margin-left: auto; font-size: .75rem; color: var(--text-muted); }
.test-details-body {
    display: flex; flex-direction: column; gap: 6px;
    margin-top: 10px; max-height: min(42vh, 300px); overflow-y: auto;
}
.test-details-body .ntf { margin-bottom: 0; }
.test-details-foot {
    display: flex; align-items: flex-start; gap: 6px;
    margin-top: 10px; padding-top: 10px;
    border-top: 1px solid var(--border-light);
    font-size: .75rem; color: var(--text-muted);
}
.test-details-foot .icon { width: 13px; height: 13px; margin-top: 2px; flex-shrink: 0; }

#integration-test-btn .btn-label-busy { display: none; }
.integration-action-bar.htmx-request #integration-test-btn .btn-label-idle { display: none; }
.integration-action-bar.htmx-request #integration-test-btn .btn-label-busy { display: inline-flex; align-items: center; gap: 6px; }
.integration-action-bar.htmx-request #integration-test-btn { opacity: .85; cursor: wait; pointer-events: none; }

@media (max-width: 575.98px) {
    .test-result-summary { flex-wrap: wrap; row-gap: 6px; }
    .test-result-summary .ntf__body { flex: 1 1 auto; }
    .test-details {
        left: 0; right: 0; width: auto;
        max-height: 60dvh; overflow-y: auto;
    }
    .test-details::after { display: none; }
    .test-details-body { max-height: none; }
}

@media (max-width: 991.98px) {
    .cfg-cards { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
    .field-row.stack-sm { flex-wrap: wrap; row-gap: 12px; }
    .field-row.stack-sm > * { flex: 1 1 100%; }
    .form-label { flex-wrap: wrap; row-gap: 4px; }
    .poll-row { flex-wrap: wrap; row-gap: 12px; }
    .poll-row .f-poll { flex: 0 0 100%; }
    .poll-row .f-toggle { flex: 1 1 40%; min-width: 130px; }
}

/* =====================================================================
   Profile page (v14.21): account/security summary rows in the Networks
   design language; the password form lives in a right-side drawer.
   ===================================================================== */

/* Setting-row titles read as content, not as a secondary status line. */
.net-row-id .net-card-title { color: var(--text); }

/* Live clock values inside the summary strip (net-updated is muted). */
.net-updated b { color: var(--text-secondary); font-weight: 600; }

/* Mapping exceptions (design spec section 4c) — applied after the value transform */
.card-header { font-size: 1rem; }
.net-card-title { font-size: 1rem; }
.fs-2 { font-size: 1.75rem !important; }
.standalone-card .brand-icon { font-size: 1.5rem; }

/* =====================================================================
   Onboarding — Templates step (v14.38): two-path empty state, grouped
   row editor with the filter toolbar, contextual bulk bar, the discovery
   queue card and the dirty-state save bar. Reuses the .net-* component
   family, the .seg segmented control and the .ntf notification system.
   ===================================================================== */

/* --- empty state: two side-by-side path cards ------------------------- */
.ob-paths { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: stretch; }
.ob-path {
    border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--surface); box-shadow: var(--shadow-xs);
    padding: 14px 16px; display: flex; flex-direction: column; gap: 9px;
}
.ob-path-title { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: var(--fs-body); color: var(--text); }
.ob-path-title .icon { width: 15px; height: 15px; color: var(--text-muted); }
.ob-hint { font-size: var(--fs-caption); color: var(--text-muted); line-height: 1.55; margin: 0; }
.ob-hint .font-monospace { color: var(--text-secondary); }

/* numbered offline round-trip steps (chips joined by arrows) */
.ob-rsteps { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ob-rstep {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--fs-micro); font-weight: 600; color: var(--text-secondary);
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 100px; padding: 3px 9px; white-space: nowrap;
}
.ob-rstep .n {
    width: 15px; height: 15px; border-radius: 50%;
    background: var(--accent); color: #fff; font-size: .625rem; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.ob-rarrow { color: var(--text-muted); display: inline-flex; }
.ob-rarrow .icon { width: 12px; height: 12px; }

/* fixed file-name chip (lock + name + note) */
.ob-filechip {
    display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: var(--radius-sm); padding: 5px 10px; width: fit-content;
    font-size: var(--fs-caption); color: var(--text-secondary);
}
.ob-filechip b { color: var(--text); font-weight: 600; }
.ob-filechip .icon { width: 13px; height: 13px; color: var(--text-muted); }

/* --- toolbar (search / status filter / view switch) ------------------- */
.ob-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.ob-search {
    display: flex; align-items: center; gap: 7px; flex: 0 1 260px; min-width: 180px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface); padding: 4px 10px; color: var(--text-muted);
}
.ob-search .icon { width: 14px; height: 14px; flex-shrink: 0; }
.ob-search input {
    border: none; outline: none; background: transparent; width: 100%;
    color: var(--text); font-size: var(--fs-compact); padding: 2px 0;
}
.ob-search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.ob-filter-note { font-size: var(--fs-caption); color: var(--text-muted); }

/* --- grouped editor table --------------------------------------------- */
.ob-table-wrap { border: 1px solid var(--border); border-radius: var(--radius-sm); }
.ob-tbl thead th { white-space: nowrap; }
.ob-tbl .ob-check { width: 36px; padding-right: 0; }
.ob-tbl tr.ob-grp > td {
    background: var(--surface-alt);
    border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
    padding-top: 7px; padding-bottom: 7px;
}
.ob-tbl tr.ob-grp:first-child > td { border-top: none; }
.ob-tbl .ob-caret {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; padding: 0; border: 1px solid transparent;
    border-radius: var(--radius-xs); background: transparent; color: var(--text-muted);
    cursor: pointer; transition: transform var(--transition), color var(--transition);
}
.ob-tbl .ob-caret:hover { color: var(--text); background: var(--surface); border-color: var(--border); }
.ob-tbl .ob-caret .icon { width: 13px; height: 13px; }
.ob-tbl .ob-caret.is-collapsed { transform: rotate(-90deg); }
.ob-tbl tr.ob-row.ob-collapsed { display: none; }
.ob-tbl tr.ob-row td { vertical-align: middle; }
.ob-meta { font-weight: 400; color: var(--text-muted); font-size: var(--fs-caption); }

/* status chips — foregrounds reuse the notification severity tokens, the
   only palette tuned for text on tinted severity backgrounds in both themes */
.ob-st {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: var(--fs-micro); font-weight: 700; white-space: nowrap;
    border-radius: 100px; padding: 2px 9px;
    background: var(--surface-alt); border: 1px solid var(--border); color: var(--text-muted);
}
.ob-st .icon { width: 11px; height: 11px; }
.ob-st--ok { background: var(--success-light); border-color: transparent; color: var(--ntf-success-fg); }
.ob-st--warn { background: var(--warning-light); border-color: transparent; color: var(--ntf-warning-fg); }
.ob-st--dan { background: var(--danger-light); border-color: transparent; color: var(--ntf-danger-fg); }
.ob-st--off { border-style: dashed; }

/* --- contextual bulk bar ---------------------------------------------- */
.ob-bulkbar {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    background: var(--accent-light); border: 1px solid transparent;
    border-radius: var(--radius-sm); padding: 6px 12px;
    font-size: var(--fs-compact); color: var(--accent); font-weight: 600;
    margin-bottom: 10px; transition: background var(--transition), color var(--transition);
}
.ob-bulkbar.is-empty { background: var(--surface-alt); color: var(--text-muted); font-weight: 500; }
.ob-bulkbar-sep { opacity: .55; }

/* --- discovery queue card --------------------------------------------- */
.ob-queue-card { margin-bottom: 0; }
.ob-queue-card .card-body { padding: 0; }
.ob-queue-body .table { margin-bottom: 0; }
.ob-queue-body td { vertical-align: middle; }
.ob-q-val { overflow-wrap: anywhere; }
.ob-queue-filter { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 10px 12px 4px; }
.ob-queue-filter .ob-search { flex: 1 1 260px; }
.ob-q-name .text-truncate { max-width: 26rem; }
.ob-q-tbl .ob-q-act { text-align: right; width: 1%; }
.ob-queue-pager { padding: 2px 12px 10px; }
.ob-queue-empty { padding: 4px 12px 12px; }

/* --- save bar ---------------------------------------------------------- */
.ob-savebar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 10px 14px;
    box-shadow: var(--shadow-xs); margin-top: 12px;
}
.ob-dirty { display: inline-flex; align-items: center; gap: 7px; font-size: var(--fs-compact); font-weight: 600; color: var(--ntf-warning-fg); }
.ob-dirtydot { width: 7px; height: 7px; border-radius: 50%; background: var(--warning); display: inline-block; flex-shrink: 0; }
.ob-savedok { display: inline-flex; align-items: center; gap: 7px; font-size: var(--fs-compact); font-weight: 600; color: var(--ntf-success-fg); }
.ob-savedok .icon { width: 14px; height: 14px; }

/* --- jump-to-equipment menu (pure <details>, works without JS) -------- */
.ob-jump { position: relative; display: inline-block; margin: 0; }
.ob-jump > summary { list-style: none; cursor: pointer; }
.ob-jump > summary::-webkit-details-marker { display: none; }
.ob-jump[open] > summary { background: var(--accent-light); border-color: var(--accent); color: var(--accent); }
.ob-jump-menu {
    position: absolute; z-index: 40; top: calc(100% + 4px); left: 0;
    min-width: 240px; max-height: 300px; overflow-y: auto;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius-sm); box-shadow: var(--shadow-md); padding: 6px;
}
.ob-jump-menu a {
    display: flex; align-items: center; gap: 8px; padding: 6px 10px;
    border-radius: var(--radius-xs); color: var(--text-secondary);
    font-size: var(--fs-compact); text-decoration: none;
}
.ob-jump-menu a:hover, .ob-jump-menu a:focus-visible { background: var(--surface-alt); color: var(--text); }
.ob-jump-count { margin-left: auto; color: var(--text-muted); font-size: var(--fs-caption); }

/* --- responsive -------------------------------------------------------- */
@media (max-width: 991.98px) {
    .ob-paths { grid-template-columns: 1fr; }
    .ob-search { flex: 1 1 100%; }
    .ob-toolbar .seg.ms-auto { margin-left: 0; }
}

/* ── Touch / small viewports: 16px text-entry controls kill iOS focus
   auto-zoom; desktop keeps the compact 13px density. ── */
@media (max-width: 768px), (pointer: coarse) {
    .form-control, .form-select,
    .form-control-sm, .form-select-sm,
    .log-search .form-control,
    .log-toolbar .form-control, .log-toolbar .form-select,
    .log-level select,
    .ob-search input {
        font-size: 1rem;
    }
    /* Time-range popover: right-anchor and clamp to the viewport. */
    .time-pop-panel {
        min-width: 0;
        max-width: calc(100vw - 24px);
        left: auto;
        right: 0;
    }
}

/* ── Coarse pointers: 44px minimum tap targets ── */
@media (pointer: coarse) {
    .nav-toggle, .nav-close { width: 44px; height: 44px; }
    .seg-btn { min-height: 44px; }
    .log-ibtn { width: 44px; height: 44px; }
    .log-search-clear { width: 40px; height: 40px; }
    .log-clear-x { width: 40px; height: 40px; }
    /* Enlarge the pill-dismiss hit area without growing the visual dot. */
    .topbar-status-x { position: relative; }
    .topbar-status-x::after { content: ''; position: absolute; inset: -10px; }
    .form-check-input { width: 20px; height: 20px; }
    .form-switch .form-check-input { width: 44px; height: 24px; }
    /* Keep the switch knob centered in the larger track. */
    .form-switch .form-check-input::after { top: 3px; }
    .form-switch .form-check-input:checked::after { transform: translateX(22px); }
    .ob-tbl .ob-caret { width: 44px; height: 44px; }
    .ob-q-act .btn { min-height: 44px; }
}

/* ── Onboarding template editor (Telemetry + COV): rows become cards on
   phones — desktop keeps the table (proposed.css in the approved mockup). ── */
@media (max-width: 768px) {
    #ob-templates-region .ob-table-wrap { border: none; border-radius: 0; }
    #ob-templates-region .ob-table-wrap .table-responsive { overflow-x: visible; }
    #ob-templates-region .ob-tbl, #ob-templates-region .ob-tbl tbody { display: block; width: auto; }
    #ob-templates-region .ob-tbl thead { display: none; }

    /* Group header becomes a full-width section band. */
    .ob-tbl tr.ob-grp { display: block; margin: 14px 0 8px; }
    .ob-tbl tr.ob-grp:first-child { margin-top: 0; }
    .ob-tbl tr.ob-grp > td { display: block; background: transparent; border: none; padding: 0; }
    .ob-tbl tr.ob-grp > td > .d-flex {
        background: var(--surface-alt); border: 1px solid var(--border);
        border-radius: 10px; padding: 8px 10px;
    }

    /* Row card: checkbox + title + actions on the first line, labeled rows below. */
    .ob-tbl tr.ob-row {
        display: grid; grid-template-columns: auto 1fr auto;
        column-gap: 8px; row-gap: 3px;
        border: 1px solid var(--border); border-radius: 10px;
        background: var(--surface); padding: 10px 12px; margin-bottom: 10px;
    }
    .ob-tbl tr.ob-row.ob-collapsed { display: none; }
    .ob-tbl tr.ob-row > td { border: none; padding: 1px 0; text-align: left; vertical-align: middle; }
    .ob-tbl tr.ob-row > td.ob-check { grid-row: 1; grid-column: 1; padding-top: 3px; }
    .ob-tbl--grouped tr.ob-row > td:nth-child(2),
    .ob-tbl--flat tr.ob-row > td:nth-child(4) {
        grid-row: 1; grid-column: 2;
        font-weight: 600; font-size: .8125rem; align-self: center;
    }
    .ob-tbl--grouped tr.ob-row > td:nth-child(3),
    .ob-tbl--grouped tr.ob-row > td:nth-child(4),
    .ob-tbl--grouped tr.ob-row > td:nth-child(5),
    .ob-tbl--flat tr.ob-row > td:nth-child(2),
    .ob-tbl--flat tr.ob-row > td:nth-child(3),
    .ob-tbl--flat tr.ob-row > td:nth-child(5),
    .ob-tbl--flat tr.ob-row > td:nth-child(6),
    .ob-tbl--flat tr.ob-row > td:nth-child(7) {
        grid-column: 2 / 4;
        display: grid; grid-template-columns: 92px 1fr; gap: 10px; align-items: start;
    }
    .ob-tbl--grouped tr.ob-row > td:nth-child(3)::before,
    .ob-tbl--grouped tr.ob-row > td:nth-child(4)::before,
    .ob-tbl--grouped tr.ob-row > td:nth-child(5)::before,
    .ob-tbl--flat tr.ob-row > td:nth-child(2)::before,
    .ob-tbl--flat tr.ob-row > td:nth-child(3)::before,
    .ob-tbl--flat tr.ob-row > td:nth-child(5)::before,
    .ob-tbl--flat tr.ob-row > td:nth-child(6)::before,
    .ob-tbl--flat tr.ob-row > td:nth-child(7)::before {
        content: attr(data-label);
        font-size: .6875rem; font-weight: 600; text-transform: uppercase;
        letter-spacing: .05em; color: var(--text-muted);
        padding-top: 2px; line-height: 1.2; white-space: nowrap;
    }
    .ob-tbl--grouped tr.ob-row > td:nth-child(4),
    .ob-tbl--flat tr.ob-row > td:nth-child(6) { overflow-wrap: anywhere; }
    .ob-tbl--grouped tr.ob-row > td:nth-child(5) > .ob-st,
    .ob-tbl--flat tr.ob-row > td:nth-child(7) > .ob-st { justify-self: start; }
    .ob-tbl--grouped tr.ob-row > td:nth-child(6),
    .ob-tbl--flat tr.ob-row > td:nth-child(8) {
        grid-row: 1; grid-column: 3; text-align: right; align-self: center; white-space: nowrap;
    }
    .ob-tbl tr.ob-row > td[colspan] { grid-column: 1 / 4; }
    .ob-tbl tr.ob-row > td[colspan]::before { content: none; }

    /* Discovery queue: rows become stacked cards — name + Add on the first
       line, the NodeID below as full-width monospace that breaks anywhere. */
    .ob-q-tbl, .ob-q-tbl tbody { display: block; width: auto; }
    .ob-q-tbl tr.ob-q-row {
        display: grid; grid-template-columns: 1fr auto;
        column-gap: 10px; row-gap: 4px; align-items: center;
        border: 1px solid var(--border); border-radius: 10px;
        background: var(--surface); padding: 10px 12px; margin-bottom: 10px;
    }
    .ob-q-tbl tr.ob-q-row:last-child { margin-bottom: 0; }
    .ob-q-tbl tr.ob-q-row > td { display: block; border: none; padding: 0; text-align: left; }
    .ob-q-tbl .ob-q-name { grid-column: 1; grid-row: 1; min-width: 0; }
    .ob-q-tbl .ob-q-name .text-truncate { max-width: none; white-space: normal; overflow-wrap: anywhere; }
    .ob-q-tbl .ob-q-val { grid-column: 1 / -1; grid-row: 2; }
    .ob-q-tbl .ob-q-act { grid-column: 2; grid-row: 1; width: auto; justify-self: end; }
}

