/* ==========================================================================
   Self-hosted Inter — replaces 7 render-blocking @imports to Google
   ==========================================================================
   The vendor stylesheet opened with seven `@import url("https://fonts.
   googleapis.com/...")` lines pulling Cairo, Poppins, Open Sans, Montserrat,
   Roboto, Nunito, DM Sans and Inter. Measured on /dashboard: 7 requests,
   ~277ms. Of those eight families the UI actually paints with exactly one --
   Inter, on all 95 text elements. The other seven were downloaded and never used.

   Worse than the waste, a CSS @import is a CHAINED blocking fetch: the browser
   must download style.css, parse it, discover the imports, and only then reach
   out to a third party -- all before it can paint. That round trip was on the
   critical path of every navigation.

   Now self-hosted, so the panel makes NO third-party requests at all. That
   matters here beyond speed: this is a VPN admin console, and every page load
   was previously announcing itself to Google along with the operator's IP and
   usage pattern.

   Inter is SIL Open Font License 1.1, which permits redistribution. Only the
   latin and latin-ext subsets are shipped (134KB total); the Cyrillic, Greek
   and Vietnamese subsets Google serves are not needed for this UI.
   Ranges below are copied verbatim from Google's own response. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   Privio admin console — design system
   Palette source of truth: PSY-PVW-UI-001 v1.1 §8.1 (Color Tokens) / §9.1 (states)

   Loaded LAST (after the vendor theme's style.css) so it re-points the vendor's
   tokens at the Privio palette instead of editing theme internals.

   THEMING MODEL
   -------------
   Every colour below is a semantic token, and components are styled against the
   TOKENS, never against raw hex. Switching theme therefore only swaps the token
   block — no component rule needs to know which theme is active.

     :root                             -> dark values (the product's default)
     @media (prefers-color-scheme:light) -> light values, when the OS asks for it
     :root[data-theme="light"|"dark"]  -> explicit choice, always wins

   The explicit [data-theme] block is declared last so a user's toggle beats the
   OS preference in BOTH directions. privio-theme.js sets it on <html>, and also
   mirrors it onto <body data-theme-version> because the vendor theme keys ~2900
   rules off that attribute.

   PALETTE RULES FROM THE SPEC
     - secure/connected = Secure Teal      failure = Critical Red
     - caution = Warning Amber             degraded = Degraded Orange
     - disabled/unknown = Disabled Gray
     - Champagne gold is a SELECTION accent only, NEVER a state colour.

   The sidebar stays dark in both themes: it is the product's identity surface,
   and a dark rail against a light canvas is the intended look.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS — dark (default)
   -------------------------------------------------------------------------- */
:root {
    color-scheme: dark;

    /* Canvas */
    --page:        #080C12;   /* app background            */
    --surface:     #001117;   /* cards, panels, modals     */
    --surface-2:   #0B1219;   /* inputs, subtle fills      */
    --sidebar:     #001117;
    --sidebar-2:   #06212B;   /* sidebar hover             */

    /* Ink */
    --ink:         #E8EAED;   /* body text, headings       */
    --muted:       #9AA0A6;   /* labels, secondary text    */
    --faint:       #838D96;   /* column heads, timestamps  */

    /* Lines */
    --border:        #2A3040;
    --border-strong: #3A4356;

    /* Accent — Secure Teal */
    --accent:      #00BFA5;
    --accent-2:    #00A38D;   /* hover                     */
    --accent-ink:  #00BFA5;   /* accent used as TEXT       */
    --accent-bg:   rgba(0, 191, 165, 0.15);
    --accent-on:   #001117;   /* text on a solid accent    */

    /* States */
    --ok:      #00BFA5;  --ok-bg:   rgba(0, 191, 165, 0.15);
    --warn:    #D6A11D;  --warn-bg: rgba(214, 161, 29, 0.15);
    --bad:     #FF4444;  --bad-bg:  rgba(255, 68, 68, 0.15);
    --degraded:#E08A3C;
    --off:     #5E6775;  --off-bg:  rgba(94, 103, 117, 0.18);

    /* Selection accent — never a state */
    --gold:    #C9A962;

    /* Terminal output substrate */
    --term-bg: #050A0F;

    --radius:    10px;
    --radius-sm: 8px;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    --shadow: none;
}

/* --------------------------------------------------------------------------
   2. TOKENS — light (follows the OS unless the toggle says otherwise)
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: light) {
    :root {
        color-scheme: light;

        --page:        #EEF2F1;
        --surface:     #FFFFFF;
        --surface-2:   #F4F7F6;
        --sidebar:     #001117;   /* stays dark by design */
        --sidebar-2:   #06212B;

        --ink:         #13202A;
        --muted:       #55636D;
        --faint:       #67727B;

        --border:        #DFE6E4;
        --border-strong: #CBD5D2;

        /* #00BFA5 on white is ~2.3:1 — unreadable as text. The light theme uses a
           darkened teal wherever the accent carries meaning, and keeps the bright
           teal only for large solid fills. */
        --accent:      #00806E;
        --accent-2:    #006757;
        --accent-ink:  #00695A;
        --accent-bg:   #E2F3EF;
        --accent-on:   #FFFFFF;

        --ok:      #00755F;  --ok-bg:   #E1F1EC;
        --warn:    #7F5D07;  --warn-bg: #FAF0D8;
        --bad:     #C13232;  --bad-bg:  #FBE7E7;
        --degraded:#B4661F;
        --off:     #6B7580;  --off-bg:  #ECEFF1;

        --term-bg: #0B1219;   /* terminal output stays dark in both themes */
        --shadow: 0 1px 2px rgba(16, 32, 40, .06), 0 1px 3px rgba(16, 32, 40, .04);
    }
}

/* --------------------------------------------------------------------------
   3. TOKENS — explicit choice. Declared last so the toggle always wins.
   -------------------------------------------------------------------------- */
:root[data-theme="dark"] {
    color-scheme: dark;
    --page:#080C12; --surface:#001117; --surface-2:#0B1219;
    --sidebar:#001117; --sidebar-2:#06212B;
    --ink:#E8EAED; --muted:#9AA0A6; --faint:#838D96;
    --border:#2A3040; --border-strong:#3A4356;
    --accent:#00BFA5; --accent-2:#00A38D; --accent-ink:#00BFA5;
    --accent-bg:rgba(0,191,165,.15); --accent-on:#001117;
    --ok:#00BFA5; --ok-bg:rgba(0,191,165,.15);
    --warn:#D6A11D; --warn-bg:rgba(214,161,29,.15);
    --bad:#FF4444; --bad-bg:rgba(255,68,68,.15);
    --degraded:#E08A3C; --off:#5E6775; --off-bg:rgba(94,103,117,.18);
    --term-bg:#050A0F; --shadow:none;
}
:root[data-theme="light"] {
    color-scheme: light;
    --page:#EEF2F1; --surface:#FFFFFF; --surface-2:#F4F7F6;
    --sidebar:#001117; --sidebar-2:#06212B;
    --ink:#13202A; --muted:#55636D; --faint:#67727B;
    --border:#DFE6E4; --border-strong:#CBD5D2;
    --accent:#00806E; --accent-2:#006757; --accent-ink:#00695A;
    --accent-bg:#E2F3EF; --accent-on:#FFFFFF;
    --ok:#00755F; --ok-bg:#E1F1EC;
    --warn:#7F5D07; --warn-bg:#FAF0D8;
    --bad:#C13232; --bad-bg:#FBE7E7;
    --degraded:#B4661F; --off:#6B7580; --off-bg:#ECEFF1;
    --term-bg:#0B1219;
    --shadow:0 1px 2px rgba(16,32,40,.06), 0 1px 3px rgba(16,32,40,.04);
}

/* --------------------------------------------------------------------------
   4. Bridge — re-point the vendor theme + Bootstrap at the tokens above
   -------------------------------------------------------------------------- */
:root, body {
    /* Legacy Privio aliases kept so older rules/templates keep resolving. */
    --privio-substrate: var(--page);
    --privio-panel:     var(--surface);
    --privio-border:    var(--border);
    --privio-teal:      var(--accent);
    --privio-gold:      var(--gold);
    --privio-text:      var(--ink);
    --privio-text-2:    var(--muted);
    --privio-red:       var(--bad);
    --privio-amber:     var(--warn);
    --privio-orange:    var(--degraded);
    --privio-gray:      var(--off);

    /* Vendor theme accent (was #1D69D6 blue) */
    --primary:       var(--accent);
    --primary-hover: var(--accent-2);
    --primary-dark:  var(--accent-2);
    --bs-primary:    var(--accent);
    --bs-primary-rgb: 0, 191, 165;
    --rgba-primary-1: rgba(0, 191, 165, 0.1);
    --rgba-primary-2: rgba(0, 191, 165, 0.2);
    --rgba-primary-3: rgba(0, 191, 165, 0.3);
    --rgba-primary-4: rgba(0, 191, 165, 0.4);
    --rgba-primary-5: rgba(0, 191, 165, 0.5);
    --rgba-primary-6: rgba(0, 191, 165, 0.6);
    --rgba-primary-7: rgba(0, 191, 165, 0.7);
    --rgba-primary-8: rgba(0, 191, 165, 0.8);
    --rgba-primary-9: rgba(0, 191, 165, 0.9);

    --nav-headbg: var(--sidebar);
    --sidebar-bg: var(--sidebar);
    --headerbg:   var(--surface);

    /* Bootstrap semantic vars. NOTE: Bootstrap's utilities read the -rgb
       triplets, not these — see the block below. Overriding only these is why
       .bg-body-tertiary once rendered near-white on a dark page. */
    --bs-body-bg:         var(--page);
    --bs-body-color:      var(--ink);
    --bs-emphasis-color:  var(--ink);
    --bs-secondary-color: var(--muted);
    --bs-border-color:    var(--border);
    --bs-tertiary-bg:     var(--surface);
    --bs-secondary-bg:    var(--surface-2);

    --bs-success: var(--ok);
    --bs-danger:  var(--bad);
    --bs-warning: var(--warn);

    --bs-success-bg-subtle:      var(--ok-bg);
    --bs-success-text-emphasis:  var(--ok);
    --bs-danger-bg-subtle:       var(--bad-bg);
    --bs-danger-text-emphasis:   var(--bad);
    --bs-warning-bg-subtle:      var(--warn-bg);
    --bs-warning-text-emphasis:  var(--warn);
    --bs-secondary-bg-subtle:    var(--off-bg);
    --bs-secondary-text-emphasis:var(--muted);
}

/* Bootstrap 5.3 background utilities read the -rgb triplets:
     .bg-body-tertiary { background-color: rgba(var(--bs-tertiary-bg-rgb), ...) }
   These cannot be var()-composed, so they are restated per theme. */
:root { --bs-body-bg-rgb: 8,12,18; --bs-tertiary-bg-rgb: 0,17,23;
        --bs-secondary-bg-rgb: 11,18,25; --bs-body-color-rgb: 232,234,237;
        --bs-emphasis-color-rgb: 232,234,237; }
@media (prefers-color-scheme: light) {
  :root { --bs-body-bg-rgb: 238,242,241; --bs-tertiary-bg-rgb: 255,255,255;
          --bs-secondary-bg-rgb: 244,247,246; --bs-body-color-rgb: 19,32,42;
          --bs-emphasis-color-rgb: 19,32,42; }
}
:root[data-theme="dark"] { --bs-body-bg-rgb: 8,12,18; --bs-tertiary-bg-rgb: 0,17,23;
        --bs-secondary-bg-rgb: 11,18,25; --bs-body-color-rgb: 232,234,237;
        --bs-emphasis-color-rgb: 232,234,237; }
:root[data-theme="light"] { --bs-body-bg-rgb: 238,242,241; --bs-tertiary-bg-rgb: 255,255,255;
        --bs-secondary-bg-rgb: 244,247,246; --bs-body-color-rgb: 19,32,42;
        --bs-emphasis-color-rgb: 19,32,42; }

/* --------------------------------------------------------------------------
   5. Surfaces
   -------------------------------------------------------------------------- */
body,
#main-wrapper,
.content-body,
.content-body.finance-bg {
    background-color: var(--page) !important;
    color: var(--ink);
}

.header, .header-content { background-color: var(--surface) !important; }
.header { border-bottom: 1px solid var(--border); }

.deznav, .nav-header, .deznav .metismenu > li > ul {
    background-color: var(--sidebar) !important;
}

.card, .modal-content, .dropdown-menu, .footer {
    background-color: var(--surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: 12px;
    box-shadow: var(--shadow);
}
.card-header { border-bottom: 1px solid var(--border) !important; background: transparent; }

/* --------------------------------------------------------------------------
   6. Lines & text
   -------------------------------------------------------------------------- */
.table > :not(caption) > * > *, .table thead th, hr, .border,
.modal-header, .modal-footer, .card-footer {
    border-color: var(--border) !important;
}

body, h1, h2, h3, h4, h5, h6, .card-title,
.table, .table > :not(caption) > * > *, label, .form-label {
    color: var(--ink) !important;
}
.text-muted, .text-body-secondary, small, .health-when { color: var(--muted) !important; }
.page-titles .breadcrumb-item a { color: var(--muted); }
.page-titles .breadcrumb-item.active a { color: var(--accent-ink); }

/* --------------------------------------------------------------------------
   7. Forms
   -------------------------------------------------------------------------- */
.form-control, .form-select, textarea.form-control,
.dataTables_wrapper input, .dataTables_wrapper select {
    background-color: var(--surface-2) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--radius-sm) !important;
    color: var(--ink) !important;
}
.form-control::placeholder { color: var(--faint) !important; }
.form-control:focus, .form-select:focus {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px var(--accent-bg) !important;
}
.input-group-text { background: var(--surface-2) !important; border-color: var(--border) !important; color: var(--muted) !important; }

/* --------------------------------------------------------------------------
   8. Buttons
   -------------------------------------------------------------------------- */
.btn { border-radius: var(--radius-sm); font-size: 13px; }

.btn-primary, .btn-success {
    background-color: var(--accent) !important;
    border-color: var(--accent) !important;
    color: var(--accent-on) !important;
}
.btn-primary:hover, .btn-success:hover, .btn-primary:focus, .btn-success:focus {
    background-color: var(--accent-2) !important;
    border-color: var(--accent-2) !important;
    color: var(--accent-on) !important;
}
.btn-danger  { background-color: var(--bad)  !important; border-color: var(--bad)  !important; color:#fff !important; }
/* Caution ACTION — amber is the caution token. */
.btn-warning { background-color: var(--warn) !important; border-color: var(--warn) !important; color:#fff !important; }
/* Secondary action. NOT gold: gold is a selection accent only, never a plain
   button. Rendered as a tinted accent so it reads below the solid primary. */
.btn-info {
    background-color: var(--accent-bg) !important;
    border-color: var(--accent-bg) !important;
    color: var(--accent-ink) !important;
}
.btn-info:hover, .btn-info:focus {
    border-color: var(--accent) !important;
    color: var(--accent-ink) !important;
}
.btn-secondary { background-color: var(--surface-2) !important; border-color: var(--border-strong) !important; color: var(--ink) !important; }
.btn-outline-secondary { color: var(--muted) !important; border-color: var(--border-strong) !important; background: var(--surface) !important; }
.btn-outline-secondary:hover {
    background-color: var(--accent-bg) !important;
    color: var(--accent-ink) !important;
    border-color: var(--accent) !important;
}

/* --------------------------------------------------------------------------
   9. Badges, pills, chips
   -------------------------------------------------------------------------- */
.bg-primary, .badge-primary { background-color: var(--accent)  !important; color: var(--accent-on) !important; }
.bg-success, .badge-success { background-color: var(--accent)  !important; color: var(--accent-on) !important; }
.bg-danger,  .badge-danger  { background-color: var(--bad)   !important; color:#fff !important; }
.bg-warning, .badge-warning { background-color: var(--warn)  !important; color:#fff !important; }
.bg-info,    .badge-info    { background-color: var(--accent-bg) !important; color: var(--accent-ink) !important; }
.bg-secondary, .badge-secondary { background-color: var(--off) !important; color:#fff !important; }

.text-primary { color: var(--accent-ink) !important; }
.text-success { color: var(--ok)   !important; }
.text-danger  { color: var(--bad)  !important; }
.text-warning { color: var(--warn) !important; }

/* Status pill with a leading dot — the console's standard state marker. */
.pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px; border-radius: 20px;
    font-size: 11.5px; font-weight: 500; white-space: nowrap;
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; background: currentColor; }
.pill-ok   { background: var(--ok-bg);   color: var(--ok); }
.pill-warn { background: var(--warn-bg); color: var(--warn); }
.pill-bad  { background: var(--bad-bg);  color: var(--bad); }
.pill-off  { background: var(--off-bg);  color: var(--muted); }

/* Existing status-badge markup (servers / mesh) mapped onto the same look. */
.status-badge { display:inline-block; padding:3px 10px; border-radius:20px; font-size:11.5px; font-weight:500; }
.status-healthy { background: var(--ok-bg);   color: var(--ok); }
.status-down    { background: var(--bad-bg);  color: var(--bad); }
.status-stale   { background: var(--warn-bg); color: var(--warn); }
.status-unknown { background: var(--off-bg);  color: var(--muted); }

.chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px; border: 1px solid var(--border); border-radius: 20px;
    font-size: 12.5px; color: var(--muted); background: var(--surface); cursor: pointer;
}
.chip.on { background: var(--accent-bg); color: var(--accent-ink); border-color: transparent; }

/* --------------------------------------------------------------------------
   10. Tables
   -------------------------------------------------------------------------- */
.table { font-size: 13px; }
.table thead th {
    text-transform: uppercase;
    letter-spacing: .03em;
    font-size: 11px;
    font-weight: 500;
    color: var(--faint) !important;
    padding: 10px 8px;
}
.table tbody td { padding: 11px 8px; vertical-align: middle; }
.table tbody tr:hover { background: var(--surface-2); }
.num, .tabular { font-variant-numeric: tabular-nums; }

/* The vendor right-aligns the last cell of EVERY table
   (.table tbody tr td:last-child { text-align:right }). Correct for a list whose
   final column is Actions, wrong for a key/value table — it strands each value
   against the far edge, far from the label naming it. Opt out with .table-kv. */
.table-kv tbody tr td:last-child { text-align: left; }
.table-kv tbody tr th { font-weight: 600; color: var(--muted); }
.table-kv tbody tr td { color: var(--ink); }
.table-kv tbody tr:hover { background: transparent; }

/* --------------------------------------------------------------------------
   11. KPI tiles
   -------------------------------------------------------------------------- */
.kpi {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 16px;
}
.kpi .kpi-label { font-size: 12px; color: var(--muted); }
.kpi .kpi-value { font-size: 26px; font-weight: 500; font-variant-numeric: tabular-nums; margin-top: 2px; line-height: 1.15; }
.kpi.kpi-ok   .kpi-value { color: var(--ok); }
.kpi.kpi-warn .kpi-value { color: var(--warn); }
.kpi.kpi-bad  .kpi-value { color: var(--bad); }

/* Dashboard stat icons — a teal tonal ramp. Deliberately NOT gold/amber/red:
   those are selection- and state-colours, and using them decoratively would
   imply a caution or failure the metric does not represent. */
.icon-box.privio-tone-1 { background-color: var(--accent) !important; }
.icon-box.privio-tone-2 { background-color: rgba(0, 191, 165, 0.62) !important; }
.icon-box.privio-tone-3 { background-color: rgba(0, 191, 165, 0.38) !important; }
.icon-box.privio-tone-4 { background-color: rgba(0, 191, 165, 0.22) !important; }
.icon-box.privio-tone-1 svg, .icon-box.privio-tone-2 svg { color: #001117 !important; }
.icon-box.privio-tone-3 svg, .icon-box.privio-tone-4 svg { color: var(--ink) !important; }

/* --------------------------------------------------------------------------
   12. Tabs
   -------------------------------------------------------------------------- */
.nav-tabs { border-bottom: 1px solid var(--border); gap: 2px; }
.nav-tabs .nav-link {
    border: 0; border-bottom: 2px solid transparent;
    color: var(--muted); font-size: 13px; padding: 9px 12px; background: none;
}
.nav-tabs .nav-link:hover { color: var(--ink); }
.nav-tabs .nav-link.active {
    color: var(--accent-ink); border-bottom-color: var(--accent);
    background: none; font-weight: 500;
}

/* --------------------------------------------------------------------------
   13. Icon buttons & row actions
   -------------------------------------------------------------------------- */
.btn.btn-icon {
    width: 34px; height: 34px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center; line-height: 1;
}
.btn.btn-icon svg { display: block; }
.table-actions { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.table-actions form { display: inline-flex; margin: 0; }
.btn > svg + .btn-label { margin-left: 7px; }
.btn:has(> svg) { display: inline-flex; align-items: center; justify-content: center; }
/* In-flight state for the per-row health re-probe (the icon must survive). */
.btn-icon.is-busy svg { animation: privio-spin .9s linear infinite; }
@keyframes privio-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   14. Sidebar
   -------------------------------------------------------------------------- */
/* The vendor styles the rail as `[data-theme-version="dark"] .deznav .metismenu a`
   -- an attribute selector, so (0,3,1). A plain `.deznav .metismenu > li > a` is
   only (0,2,2) and LOSES on class count no matter how many !importants it
   carries, which is why the active row silently kept the vendor's grey. Matching
   the attribute prefix takes these to (0,4,2) and settles it on specificity
   rather than an escalating !important war. body always carries the attribute,
   in either theme, so the prefix is unconditional. */
body[data-theme-version] .deznav .metismenu > li > a {
    color: #A8B4BC !important;
    border-radius: var(--radius-sm);
}
body[data-theme-version] .deznav .metismenu > li > a:hover,
body[data-theme-version] .deznav .metismenu > li > a.active {
    color: #FFFFFF !important;
    background-color: var(--sidebar-2) !important;
}
body[data-theme-version] .deznav .metismenu > li.mm-active > a {
    background-color: var(--accent) !important;
    color: var(--accent-on) !important;
}
/* Uppercase section label between nav groups. */
.deznav .nav-group-label {
    font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
    color: #5F7568; padding: 14px 16px 5px; font-weight: 500;
}

/* --------------------------------------------------------------------------
   15. Theme toggle
   -------------------------------------------------------------------------- */
.theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; border-radius: 50%;
    border: 1px solid var(--border); background: var(--surface-2);
    color: var(--muted); cursor: pointer; padding: 0;
}
.theme-toggle:hover { color: var(--accent-ink); border-color: var(--accent); }
.theme-toggle svg { width: 18px; height: 18px; display: block; }
/* Show the icon for the theme you would switch TO. */
:root[data-theme="dark"]  .theme-toggle .icon-sun,
:root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"]  .theme-toggle .icon-moon,
:root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun  { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .theme-toggle .icon-sun  { display: none; }
  :root:not([data-theme]) .theme-toggle .icon-moon { display: block; }
}

/* --------------------------------------------------------------------------
   16. Links
   -------------------------------------------------------------------------- */
a:not(.btn):not(.nav-link):not(.dropdown-item) { color: var(--accent-ink); }
a:not(.btn):hover { color: var(--accent-2); }

/* --------------------------------------------------------------------------
   17. Terminal-style output (SSH + diagnostics) — dark in BOTH themes
   -------------------------------------------------------------------------- */
.bg-dark { background-color: var(--term-bg) !important; }
.text-success.bg-dark, pre.bg-dark { color: var(--accent) !important; }

.diag-out {
    background: var(--term-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: #E8EAED;
    font-family: var(--mono);
    font-size: 12.5px;
    line-height: 1.55;
    padding: 12px 14px;
    margin: 0;
    max-height: 220px;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
}
.diag-out:empty::after { content: "(no output)"; color: var(--faint); font-style: italic; }
/* Equal-height panes in the two-column diagnostics row. */
.diag-row { display: flex; flex-wrap: wrap; }
.diag-row > [class*="col-"] { display: flex; flex-direction: column; }
.diag-row .diag-out { flex: 1 1 auto; }

/* Pass/fail markers in the health-check verdict. Sized to sit on the text
   baseline rather than inflating the row. */
.check-mark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%;
    font-size: 13px; font-weight: 700; line-height: 1;
}
.check-mark.ok   { background: var(--ok-bg);  color: var(--ok); }
.check-mark.fail { background: var(--bad-bg); color: var(--bad); }

/* --------------------------------------------------------------------------
   18. Misc
   -------------------------------------------------------------------------- */
/* Status toggle switch. Was defined twice, inline, in servers.html and
   view_server.html with hardcoded #ccc / white / #4CAF50 (Material green, not a
   Privio colour). Defined once here so it follows the theme and there is one
   place to change it. */
.switch { position: relative; display: inline-block; width: 34px; height: 20px; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
    position: absolute; cursor: pointer; inset: 0;
    background-color: var(--off);
    transition: background-color .25s ease;
    border-radius: 34px;
}
.slider:before {
    position: absolute; content: "";
    height: 14px; width: 14px; left: 3px; bottom: 3px;
    background-color: #FFFFFF;
    transition: transform .25s ease;
    border-radius: 50%;
}
input:checked + .slider { background-color: var(--accent); }
input:checked + .slider:before { transform: translateX(14px); }

/* Health badge helpers used by the servers list. */
.health-when { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
.btn-check   { padding: 2px 8px; font-size: 11px; }
/* Escalation sign next to DOWN/STALE -- tap for the reason. */
.health-alert {
    cursor: pointer; color: var(--bad); font-size: 16px;
    margin-left: 6px; vertical-align: middle; user-select: none;
}
.health-alert:hover { opacity: .7; }

/* Login screen (standalone page, outside the app shell) */
body.vh-100 { background-color: var(--page) !important; }
body.vh-100 .login-form, body.vh-100 .authincation-content { background-color: var(--surface) !important; }

/* Preloader must not flash white in dark mode. */
#preloader { background: var(--page) !important; }

/* --------------------------------------------------------------------------
   19. Vendor containers the token layer has to reclaim
   -------------------------------------------------------------------------- */
/* The vendor paints a handful of large surfaces from hardcoded hex rather than
   its own vars — .element-wrapper is #fff in light and #272627 (a warm grey) in
   dark, neither of which is a Privio surface. They are wrappers, so they read as
   "the card" to anyone looking at the page; left alone the servers table sat on
   warm grey inside an otherwise blue-black console. */
.element-wrapper,
.element-wrapper .element-right,
.widget-stat .media > span,
.widget-media .timeline .timeline-panel,
.new-arrival-content .item {
    background-color: var(--surface) !important;
    border-color: var(--border) !important;
    color: var(--ink);
}
.element-wrapper { border-radius: 12px; box-shadow: var(--shadow); }

/* DataTables chrome (length/search/pagination) follows the theme too. */
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info { color: var(--muted) !important; }
.dataTables_wrapper .dataTables_paginate .paginate_button {
    color: var(--muted) !important;
    background: transparent !important;
    border-color: var(--border) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
    background: var(--accent) !important;
    border-color: var(--accent) !important;
    color: var(--accent-on) !important;
}

/* --------------------------------------------------------------------------
   20. Paint immediately — no artificial blank screen on every navigation
   --------------------------------------------------------------------------
   The vendor theme ships a marketing-demo loading flourish:

     #preloader      full-screen fixed overlay, z-index 99999
     #main-wrapper   opacity: 0 until JS adds .show

   and custom.js only reveals it on a hard-coded timer:

     handlePreloader: setTimeout(function(){
       jQuery('#preloader').remove(); $('#main-wrapper').addClass('show'); }, 800)

   So EVERY page load and every navigation showed a blank overlay for at least
   800ms after the HTML was already parsed and painted — and if custom.js was
   slow, failed, or the tab was throttled, the console stayed blank indefinitely,
   because the content was merely transparent rather than absent.

   An admin console has no use for a staged reveal. Content is shown as soon as
   the browser can paint it. custom.js still runs and still adds .show / removes
   the node; both are now no-ops, so nothing had to be patched in vendor JS. */
#main-wrapper { opacity: 1 !important; transition: none !important; }
#preloader { display: none !important; }

/* --------------------------------------------------------------------------
   21. Sidebar: active icon, and the collapsed rail
   --------------------------------------------------------------------------
   The vendor forces the ACTIVE item's icon to the accent:

     .deznav .metismenu > li.mm-active > a .menu-icon svg path { fill: var(--primary) }

   which was fine when the active row had no background. It now has an accent
   background, so that rule painted a teal icon onto a teal pill -- the icon
   vanished entirely and the active item read as an empty coloured block.

   The icons are not uniform, so this is done by shape rather than blanket:
     filled   <svg fill="currentColor">          -> paths inherit
     dashboard <svg fill="none"><path fill="currentColor">
     stroked  <svg fill="none" stroke="currentColor"> -> paths must NOT be filled
   Blanket `fill: currentColor` would turn the stroked icons (Mesh, DNS, API
   Docs, App Update) into solid blobs, so each case is matched explicitly. */
body[data-theme-version] .deznav .metismenu > li.mm-active > a .menu-icon svg[fill="currentColor"] path,
body[data-theme-version] .deznav .metismenu > li.mm-active > a .menu-icon svg path[fill="currentColor"] {
    fill: currentColor !important;
}
/* Stroked icons: keep them stroked. The vendor's blanket path rule would fill them. */
body[data-theme-version] .deznav .metismenu > li.mm-active > a .menu-icon svg[fill="none"] path:not([fill]) {
    fill: none !important;
    stroke: currentColor !important;
}
body[data-theme-version] .deznav .metismenu > li.mm-active > a .menu-icon svg { color: var(--accent-on) !important; }

/* Collapsed rail: there is no room for the group words, and left in place they
   read as orphaned text stacked above unlabelled icons. Keep the grouping as a
   divider rule instead of dropping the information entirely. */
/* The collapse class lives on #main-wrapper, NOT on body -- the vendor hides the
   labels with
     [data-sidebar-style="full"][data-layout="vertical"] .menu-toggle .deznav .nav-text
   so the group headings have to hook the same condition. Keying this off
   `body.menu-toggle` silently never matched, which is why the words stayed. */
[data-sidebar-style="full"][data-layout="vertical"] .menu-toggle .deznav .nav-group-label,
body.menu-toggle .deznav .nav-group-label {
    height: 0;
    min-height: 0;
    padding: 0;
    margin: 14px 16px 10px;
    overflow: hidden;
    border-top: 1px solid rgba(255, 255, 255, .10);
}

/* --------------------------------------------------------------------------
   22. List screens — toolbar and pager
   --------------------------------------------------------------------------
   Servers and Clients render the identical shell (partials/list-header.html,
   list-toolbar.html, pagination.html) so the two screens cannot drift apart
   again. Pagination is server-side, so this styles real links, not a JS widget. */
.list-toolbar { margin-bottom: 14px; }
.list-search { min-width: 220px; max-width: 320px; flex: 1 1 220px; }
.list-search .form-control { height: 38px; }

/* Filter chips are submit buttons, so they need the chip look without the
   browser's default button chrome. */
button.chip { border: 1px solid var(--border); font: inherit; font-size: 12.5px; line-height: 1.2; }
button.chip:hover { border-color: var(--accent); color: var(--accent-ink); }
button.chip .num { font-variant-numeric: tabular-nums; opacity: .75; margin-left: 2px; }
button.chip.on .num { opacity: .9; }

.pagination-bar { border-top: 1px solid var(--border); padding-top: 12px; }
.pagination-bar .btn-sm { min-width: 34px; padding: 4px 8px; font-variant-numeric: tabular-nums; }
.pagination-bar .btn.disabled { opacity: .4; pointer-events: none; }

/* Row count in the empty state, so an empty list still reads as a real screen. */
.list-empty { text-align: center; color: var(--muted); padding: 34px 20px; }
.list-empty .list-empty-title { color: var(--ink); font-weight: 500; margin-bottom: 4px; }

/* ---------------------------------------------------------------------------
   Navigation loading overlay (privio-nav-loading.js)

   Raised on the page being LEFT, because these screens render server-side and the
   slow ones (Fleet Doctor SSHes every node) send nothing until that work finishes.
   Until then the browser still shows the old page, so without this a click looks
   like it did nothing. All colours come from the theme tokens so it follows the
   light/dark toggle like everything else.
--------------------------------------------------------------------------- */
#privio-nav-loading {
    position: fixed;
    inset: 0;
    z-index: 20000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--page) 78%, transparent);
    backdrop-filter: blur(2px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .15s ease, visibility .15s ease;
}
#privio-nav-loading.is-on { opacity: 1; visibility: visible; }

#privio-nav-loading .pnl-box {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 22px;
    border-radius: 12px;
    /* Same surface/border/shadow tokens .card uses, so the dialog reads as part of
       the design system in both themes. */
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    max-width: min(90vw, 460px);
}
#privio-nav-loading .pnl-text {
    color: var(--ink);
    font-size: 14px;
    line-height: 1.35;
}
#privio-nav-loading .pnl-spin {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--border-strong);
    border-top-color: var(--accent);
    animation: pnl-spin .7s linear infinite;
}
@keyframes pnl-spin { to { transform: rotate(360deg); } }

/* Honour the OS setting: keep the overlay (it is the actual feedback) but stop the
   motion for anyone who has asked for reduced animation. */
@media (prefers-reduced-motion: reduce) {
    #privio-nav-loading .pnl-spin { animation-duration: 2.4s; }
    #privio-nav-loading { transition: none; }
}
