/* ==========================================================================
   BNGView design system - native Bootstrap 5 theming
   Ink dark ground + Teal accent. Retheme by overriding Bootstrap's own
   CSS custom properties rather than fighting compiled component styles.
   Replaces the old bs3-compat.css + Glyphicons layer.
   ========================================================================== */

/* ---- palette tokens ---------------------------------------------------- */
:root {
    /* teal accent (light) - default; alternates live in the palette
       switcher block below, selected via data-accent on <html> */
    --bngv-accent:        #0f8a8a;
    --bngv-accent-rgb:    15, 138, 138;
    --bngv-accent-hover:  #0c7373;
    --bngv-accent-active: #0a6060;
    --bngv-on-accent:     #ffffff;

    /* neutrals (light) */
    --bngv-page:    #f4f6f9;
    --bngv-surface: #ffffff;
    --bngv-elevate: #eef2f7;
    --bngv-border:  #e2e7ee;
    --bngv-text:    #1a2230;
    --bngv-muted:   #6b7686;

    /* status (light) */
    --bngv-ok:      #5a922b;  --bngv-ok-bg:   #eaf3dd;
    --bngv-warn:    #b26a00;  --bngv-warn-bg: #fbf0dc;
    --bngv-crit:    #c23b3b;  --bngv-crit-bg: #fbe7e7;

    /* categorical hues for steering source types (distinct from status) */
    --bngv-st-cadence:  #00ADEE;
    --bngv-st-talktalk: #25A970;

    /* categorical hues for HTTP methods (distinct from status: GET is not "ok",
       DELETE is not "crit" - these are a separate method palette) */
    --bngv-method-get:    #2f8a3e;
    --bngv-method-post:   #2f6fd0;
    --bngv-method-put:    #b26a00;
    --bngv-method-delete: #c23b3b;

    /* map into Bootstrap */
    --bs-primary:            var(--bngv-accent);
    --bs-primary-rgb:        var(--bngv-accent-rgb);
    --bs-body-bg:            var(--bngv-page);
    --bs-body-color:         var(--bngv-text);
    --bs-secondary-bg:       var(--bngv-elevate);
    --bs-tertiary-bg:        var(--bngv-elevate);
    --bs-secondary-color:    var(--bngv-muted);
    --bs-tertiary-color:     var(--bngv-muted);
    --bs-border-color:       var(--bngv-border);
    --bs-link-color:         var(--bngv-accent);
    --bs-link-color-rgb:     var(--bngv-accent-rgb);
    --bs-link-hover-color:   var(--bngv-accent-hover);
    --bs-focus-ring-color:   rgba(var(--bngv-accent-rgb), 0.25);
    --bs-body-font-size:     0.9rem;
    --bs-border-radius:      0.5rem;
    --bs-card-bg:            var(--bngv-surface);
}

/* ---- Ink dark ground --------------------------------------------------- */
[data-bs-theme="dark"] {
    --bngv-accent:        #2bb3b0;
    --bngv-accent-rgb:    43, 179, 176;
    --bngv-accent-hover:  #3cc4c1;
    --bngv-accent-active: #4ececb;
    --bngv-on-accent:     #0b0f10;

    --bngv-page:    #0a0b0d;
    --bngv-surface: #131417;
    --bngv-elevate: #1c1e22;
    --bngv-border:  #2a2d33;
    --bngv-text:    #e9eaed;
    --bngv-muted:   #979ba3;

    --bngv-ok:      #93c95f;  --bngv-ok-bg:   #22300f;
    --bngv-warn:    #e0a33a;  --bngv-warn-bg: #33270f;
    --bngv-crit:    #ff6f6f;  --bngv-crit-bg: #351b1b;

    --bngv-st-cadence:  #38bff2;
    --bngv-st-talktalk: #55bc8f;

    --bngv-method-get:    #6cc27a;
    --bngv-method-post:   #6fa3f0;
    --bngv-method-put:    #e0a33a;
    --bngv-method-delete: #ff6f6f;

    --bs-primary:          var(--bngv-accent);
    --bs-primary-rgb:      var(--bngv-accent-rgb);
    --bs-body-bg:          var(--bngv-page);
    --bs-body-color:       var(--bngv-text);
    --bs-secondary-bg:     var(--bngv-elevate);
    --bs-tertiary-bg:      var(--bngv-elevate);
    --bs-secondary-color:  var(--bngv-muted);
    --bs-tertiary-color:   var(--bngv-muted);
    --bs-border-color:     var(--bngv-border);
    --bs-emphasis-color:   #ffffff;
    --bs-link-color:       var(--bngv-accent);
    --bs-link-color-rgb:   var(--bngv-accent-rgb);
    --bs-link-hover-color: var(--bngv-accent-hover);
    --bs-card-bg:          var(--bngv-surface);
}

/* ---- accent palette switcher ------------------------------------------
   The four Cadence brand accents. Teal is the default (defined inline in the
   :root / dark blocks above, and used as the fallback whenever data-accent is
   unset or unrecognised). The other three are data-accent overrides; each
   carries its own light + dark variant so both themes track the chosen brand.

   To switch the whole app, change the ONE attribute on <html> in
   resources/views/layouts/bngview.blade.php:

       <html lang="en" data-accent="teal">   <- teal | blue | green | purple

   Only the accent tokens are redefined here; everything downstream reads
   var(--bngv-accent*) and re-tints automatically. The teal block below
   mirrors the :root / dark defaults (kept explicit for parity with the other
   three) - keep the two teal definitions in sync. ------------------------ */

/* Teal - #0f8a8a (also the :root default / fallback) */
:root[data-accent="teal"] {
    --bngv-accent:        #0f8a8a;
    --bngv-accent-rgb:    15, 138, 138;
    --bngv-accent-hover:  #0c7373;
    --bngv-accent-active: #0a6060;
    --bngv-on-accent:     #ffffff;
}
/* Blue - #00ADEE */
:root[data-accent="blue"] {
    --bngv-accent:        #00adee;
    --bngv-accent-rgb:    0, 173, 238;
    --bngv-accent-hover:  #0091c8;
    --bngv-accent-active: #0079a7;
    --bngv-on-accent:     #ffffff;
}
/* Green - #3CB34B */
:root[data-accent="green"] {
    --bngv-accent:        #3cb34b;
    --bngv-accent-rgb:    60, 179, 75;
    --bngv-accent-hover:  #339840;
    --bngv-accent-active: #2b8136;
    --bngv-on-accent:     #ffffff;
}
/* Purple - #7E4197 */
:root[data-accent="purple"] {
    --bngv-accent:        #7e4197;
    --bngv-accent-rgb:    126, 65, 151;
    --bngv-accent-hover:  #6a3480;
    --bngv-accent-active: #562c67;
    --bngv-on-accent:     #ffffff;
}

/* Dark-theme variants - brighter accents on dark ink. Declared after the
   light blocks so that when both match (equal specificity) the dark rule
   wins by source order. */
[data-bs-theme="dark"][data-accent="teal"] {
    --bngv-accent:        #2bb3b0;
    --bngv-accent-rgb:    43, 179, 176;
    --bngv-accent-hover:  #3cc4c1;
    --bngv-accent-active: #4ececb;
    --bngv-on-accent:     #0b0f10;
}
[data-bs-theme="dark"][data-accent="blue"] {
    --bngv-accent:        #38bff2;
    --bngv-accent-rgb:    56, 191, 242;
    --bngv-accent-hover:  #57cbf5;
    --bngv-accent-active: #76d6f7;
    --bngv-on-accent:     #0b0f10;
}
[data-bs-theme="dark"][data-accent="green"] {
    --bngv-accent:        #5fc76c;
    --bngv-accent-rgb:    95, 199, 108;
    --bngv-accent-hover:  #78d283;
    --bngv-accent-active: #92dd9b;
    --bngv-on-accent:     #0b0f10;
}
[data-bs-theme="dark"][data-accent="purple"] {
    --bngv-accent:        #b57fd4;
    --bngv-accent-rgb:    181, 127, 212;
    --bngv-accent-hover:  #c295dd;
    --bngv-accent-active: #cfabe6;
    --bngv-on-accent:     #0b0f10;
}

/* ---- base -------------------------------------------------------------- */
body {
    background-color: var(--bngv-page);
    -webkit-font-smoothing: antialiased;
}

/* Inline code - subtle boxed teal treatment (identifiers, hostnames, values).
   Uses the accent tokens so it themes automatically in light and dark. */
code {
    font-family: var(--bs-font-monospace);
    font-size: 0.875em;
    color: var(--bngv-accent);
    background-color: rgba(var(--bngv-accent-rgb), 0.1);
    padding: 0.15em 0.35em;
    border-radius: 0.25rem;
}
pre {
    background: var(--bngv-elevate);
    border: 1px solid var(--bngv-border);
    border-radius: var(--bs-border-radius);
    padding: 0.75rem 0.9rem;
    color: var(--bngv-text);
}
/* Code inside a pre block shouldn't get the inline box */
pre code { color: inherit; background: none; padding: 0; }

/* ---- primary button (teal, both themes) -------------------------------- */
.btn-primary {
    --bs-btn-bg: var(--bngv-accent);
    --bs-btn-border-color: var(--bngv-accent);
    --bs-btn-color: var(--bngv-on-accent);
    --bs-btn-hover-bg: var(--bngv-accent-hover);
    --bs-btn-hover-border-color: var(--bngv-accent-hover);
    --bs-btn-hover-color: var(--bngv-on-accent);
    --bs-btn-active-bg: var(--bngv-accent-active);
    --bs-btn-active-border-color: var(--bngv-accent-active);
    --bs-btn-active-color: var(--bngv-on-accent);
    --bs-btn-disabled-bg: var(--bngv-accent);
    --bs-btn-disabled-border-color: var(--bngv-accent);
    --bs-btn-disabled-color: var(--bngv-on-accent);
}
.btn-outline-primary {
    --bs-btn-color: var(--bngv-accent);
    --bs-btn-border-color: var(--bngv-accent);
    --bs-btn-hover-bg: var(--bngv-accent);
    --bs-btn-hover-border-color: var(--bngv-accent);
    --bs-btn-hover-color: var(--bngv-on-accent);
    --bs-btn-active-bg: var(--bngv-accent);
    --bs-btn-active-border-color: var(--bngv-accent);
    --bs-btn-active-color: var(--bngv-on-accent);
}

/* Form focus adopts the accent */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--bngv-accent);
    box-shadow: 0 0 0 0.2rem var(--bs-focus-ring-color);
}
.form-check-input:checked {
    background-color: var(--bngv-accent);
    border-color: var(--bngv-accent);
}

/* ---- navbar ------------------------------------------------------------ */
.navbar {
    background-color: var(--bngv-surface);
    border-bottom: 1px solid var(--bngv-border);
    padding: 0.4rem 1rem;
    --bs-navbar-color: var(--bngv-muted);
    --bs-navbar-hover-color: var(--bngv-text);
    --bs-navbar-active-color: var(--bngv-text);
    --bs-navbar-brand-color: var(--bngv-accent);
    --bs-navbar-brand-hover-color: var(--bngv-accent);
}
.navbar-brand {
    font-weight: 700;
    letter-spacing: -0.01em;
}
.navbar .nav-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 500;
    border-radius: var(--bs-border-radius);
    text-decoration: none;
    transition: color 0.12s, box-shadow 0.12s;
}
/* Hover previews the active border-bottom (faint) - never a text-underline
   and never a filled highlight. */
.navbar .nav-link:hover,
.navbar .nav-link:focus-visible {
    color: var(--bngv-text);
    text-decoration: none;
    box-shadow: inset 0 -2px 0 rgba(var(--bngv-accent-rgb), 0.4);
    border-radius: 0;
}
/* Active: the full accent border-bottom. */
.navbar .nav-link.active {
    color: var(--bngv-text);
    box-shadow: inset 0 -2px 0 var(--bngv-accent);
    border-radius: 0;
}
/* Global search in the navbar */
.navbar-search {
    max-width: 340px;
}
.navbar-search .form-control {
    background-color: var(--bngv-page);
}

/* Theme toggle */
#theme-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.3rem 0.5rem;
    color: var(--bngv-muted);
    border-radius: var(--bs-border-radius);
    line-height: 1;
}
#theme-toggle:hover { background-color: var(--bngv-elevate); color: var(--bngv-text); }
#theme-toggle-icon { font-size: 1.2rem; vertical-align: middle; }

/* Menu dropdowns (navbar Steering / user menus): map Bootstrap's dropdown
   vars onto our tokens - otherwise the active item stays Bootstrap blue rather
   than our accent. */
.dropdown-menu {
    --bs-dropdown-bg: var(--bngv-surface);
    --bs-dropdown-border-color: var(--bngv-border);
    --bs-dropdown-link-color: var(--bngv-text);
    --bs-dropdown-link-hover-bg: var(--bngv-elevate);
    --bs-dropdown-link-hover-color: var(--bngv-text);
    --bs-dropdown-link-active-bg: var(--bngv-accent);
    --bs-dropdown-link-active-color: var(--bngv-on-accent);
}
.dropdown-item, .dropdown-item:hover, .dropdown-item:focus { text-decoration: none; }

/* ---- cards ------------------------------------------------------------- */
.card {
    margin-bottom: 1.25rem;
    background-color: var(--bngv-surface);
    border: 1px solid var(--bngv-border);
    --bs-card-border-color: var(--bngv-border);
}
.card-header {
    background-color: var(--bngv-elevate);
    border-bottom: 1px solid var(--bngv-border);
    padding: 0.4rem 1rem;
    min-height: 3.25rem;
    display: flex;
    align-items: center;
    font-weight: 600;
}
.card-header h4 { font-size: 1rem; font-weight: 600; }
/* Buttons in card headers stay compact so header height is consistent
   whether or not a header carries action buttons. */
.card-header .btn {
    --bs-btn-padding-y: 0.25rem;
    --bs-btn-padding-x: 0.6rem;
    --bs-btn-font-size: 0.85rem;
    white-space: nowrap;
}
/* Button wrappers in flex card headers must not shrink (else labels wrap) */
.card-header > div { flex: 0 0 auto; }
.card-header .btn + .btn,
.card-header > div + div { margin-left: 0.35rem; }
.card-header a:not(.btn) { color: inherit; text-decoration: none; }
.card-header a:not(.btn):hover { color: inherit; }
/* Collapsible card headers get a chevron affordance */
.card-header a[data-bs-toggle="collapse"] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
}
.card-header a[data-bs-toggle="collapse"]::before {
    content: "\F282"; /* bi-chevron-down */
    font-family: "bootstrap-icons";
    font-size: 0.8em;
    color: var(--bngv-muted);
    transition: transform 0.15s ease;
    transform: rotate(-90deg); /* collapsed → points right ">" */
}
.card-header a[data-bs-toggle="collapse"][aria-expanded="true"]::before {
    transform: rotate(0deg); /* expanded → points down "v" */
}
/* Some cards make the whole header the collapse toggle (no inner <a>) */
.card-header[data-bs-toggle="collapse"] { cursor: pointer; }
.card-header[data-bs-toggle="collapse"]::before {
    content: "\F282"; /* bi-chevron-down */
    font-family: "bootstrap-icons";
    font-size: 0.8em;
    color: var(--bngv-muted);
    margin-right: 0.5rem;
    transition: transform 0.15s ease;
    transform: rotate(-90deg); /* collapsed → ">" */
}
.card-header[data-bs-toggle="collapse"][aria-expanded="true"]::before {
    transform: rotate(0deg); /* expanded → "v" */
}
.card-header .btn + .btn { margin-left: 0.35rem; }

/* ---- tables - clean, hairline rows, no heavy grid ---------------------- */
.table {
    --bs-table-border-color: var(--bngv-border);
    --bs-table-bg: transparent;
    font-size: 0.9rem;
    margin-bottom: 0;
}
.table > thead {
    --bs-table-color: var(--bngv-muted);
}
.table > thead th {
    font-weight: 600;
    font-size: 0.82rem;
    text-transform: none;
    border-bottom: 2px solid var(--bngv-border);
    vertical-align: top;
}
.table > :not(caption) > * > * {
    padding: 0.55rem 0.7rem;
}
.table-hover > tbody > tr:hover > * {
    --bs-table-hover-bg: var(--bngv-elevate);
}
/* Soften table-bordered: keep it readable but not a heavy grid */
.table-bordered > :not(caption) > *,
.table-bordered > :not(caption) > * > * {
    border-color: var(--bngv-border);
}

/* ---- badges / status --------------------------------------------------- */
/* Fixed size (rem, not em) so badges don't balloon inside headings. */
.badge { font-weight: 600; font-size: 0.72rem; padding: 0.32em 0.6em; }
.badge.bngv-ok   { color: var(--bngv-ok);   background-color: var(--bngv-ok-bg); }
.badge.bngv-warn { color: var(--bngv-warn); background-color: var(--bngv-warn-bg); }
.badge.bngv-crit { color: var(--bngv-crit); background-color: var(--bngv-crit-bg); }
.badge.bngv-idle { color: var(--bngv-muted); background-color: var(--bngv-elevate); }

.text-ok   { color: var(--bngv-ok) !important; }
.text-warn { color: var(--bngv-warn) !important; }
.text-crit { color: var(--bngv-crit) !important; }

/* ---- alerts adopt themed status tints ---------------------------------- */
.alert-info {
    --bs-alert-color: var(--bngv-text);
    --bs-alert-bg: var(--bngv-elevate);
    --bs-alert-border-color: var(--bngv-border);
}

/* ---- compat: classes the templates still use -------------------------- */
/* Bootstrap 3 btn-xs (compact row-action buttons) */
.btn-xs {
    --bs-btn-padding-y: 0.15rem;
    --bs-btn-padding-x: 0.4rem;
    --bs-btn-font-size: 0.75rem;
    --bs-btn-border-radius: 0.3rem;
}
.btn-xs .bi { font-size: 0.85em; }
/* Bootstrap 4 form-inline (dropped in BS5) - restore inline layout */
.form-inline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}
/* A form-inline inside a centered container should stay centered (its flex
   display otherwise overrides the parent's text-align). */
.text-center .form-inline { justify-content: center; }
/* Many views lay cards out in a raw `display:flex` wrapper with .col-* children
   rather than a .row, so they get no Bootstrap gutter. Restore horizontal
   padding on columns (matches BS5's default 0.75rem gutter half) so adjacent
   cards don't touch. Inside a real .row this just matches the existing gutter. */
[class*="col-"] {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
}

/* ---- attribute cards --------------------------------------------------- */
/* Check + reply attributes render as two stacked tables in one card; fixed
   column widths keep the two tables' columns aligned with each other. */
.attrtable { table-layout: fixed; margin-bottom: 1rem; }
.attrtable th.attribute { width: 45%; }
.attrtable td.op { width: 4em; }
.attrtable th, .attrtable td { overflow-wrap: break-word; }
.attrtable-header { margin-bottom: 0.5rem; }
.attrtable + .attrtable-header { margin-top: 2rem; }

/* ---- admin user list: inheritance tree + group treatment -------------- */
table.user-tree { margin-bottom: 0; }
table.user-tree > tbody > tr > td { vertical-align: middle; }
/* Name cell: depth chip + glyph + username, indented by inheritance depth. */
table.user-tree td.username { padding-top: 0.35rem; padding-bottom: 0.35rem; }
.username-cell { display: flex; align-items: center; gap: 0.5rem; }
/* Depth rendered via CSS content so "L0"/"L1" never leaks into the
   client-side filter's text match (see filterable.js). */
.depthbadge {
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.62rem; font-weight: 700; letter-spacing: 0.04em;
    padding: 0.12rem 0.36rem; border-radius: 0.25rem; flex: none;
    background: var(--bngv-elevate); color: var(--bngv-muted);
    border-left: 2px solid var(--bngv-border);
}
.depthbadge::before { content: "L" attr(data-depth); }
.depthbadge[data-depth="0"] { border-left-color: var(--bngv-accent); }
.tree-glyph { color: var(--bngv-muted); flex: none; display: inline-flex; }
.username-text { font-weight: 500; }
/* Inactive accounts read quieter - normal weight + muted, on top of the
   "(inactive)" note and the Disabled badge. */
table.user-tree > tbody > tr[data-active="false"] .username-text { font-weight: 400; color: var(--bngv-muted); }
/* Collapse toggle: rows with children get a chevron; leaves get a spacer so
   names stay aligned. */
.tree-toggle {
    border: 0; background: transparent; color: var(--bngv-muted); cursor: pointer;
    padding: 0; width: 1.1rem; flex: none; display: inline-flex; align-items: center; justify-content: center;
}
.tree-toggle:hover { color: var(--bngv-text); }
.tree-toggle .bi { transition: transform 0.12s; }
tr[data-collapsed="true"] .tree-toggle .bi { transform: rotate(-90deg); }
.tree-toggle-spacer { width: 1.1rem; flex: none; }
.tree-hidden { display: none; }

/* Groups: teal wash + accent name + folder glyph + GROUP tag. */
table.user-tree > tbody > tr.grp-row > td { background-color: rgba(var(--bngv-accent-rgb), 0.055); }
table.user-tree > tbody > tr.grp-row:hover > td { background-color: rgba(var(--bngv-accent-rgb), 0.10); }
tr.grp-row .tree-glyph { color: var(--bngv-accent); }
tr.grp-row .username-text { color: var(--bngv-accent); font-weight: 600; }
.grouptag {
    display: inline-block; font-family: var(--bs-font-monospace, monospace);
    font-size: 0.62rem; font-weight: 700; letter-spacing: 0.08em;
    padding: 0.16rem 0.44rem; border-radius: 0.25rem;
    color: var(--bngv-accent); background: rgba(var(--bngv-accent-rgb), 0.14);
}
td.inherits { color: var(--bngv-muted); font-size: 0.82rem; white-space: nowrap; }
td.inherits .arrow { opacity: 0.6; margin-right: 0.15rem; }

/* Row actions: sit immediately right of the name, revealed on hover/focus. */
.row-actions { display: inline-flex; align-items: center; gap: 0.1rem; margin-left: 0.4rem; opacity: 0; transition: opacity 0.12s; }
tr:hover .row-actions, .row-actions:focus-within { opacity: 1; }
@media (hover: none) { .row-actions { opacity: 1; } }
.btn-icon {
    --bs-btn-padding-y: 0.2rem; --bs-btn-padding-x: 0.4rem;
    --bs-btn-color: var(--bngv-muted);
    --bs-btn-bg: transparent; --bs-btn-border-color: transparent;
    --bs-btn-hover-color: var(--bngv-text); --bs-btn-hover-bg: var(--bngv-elevate); --bs-btn-hover-border-color: transparent;
    --bs-btn-active-bg: var(--bngv-elevate); --bs-btn-active-border-color: transparent;
    line-height: 1;
}
.btn-icon.danger { --bs-btn-hover-color: var(--bngv-crit); --bs-btn-hover-bg: var(--bngv-crit-bg); }

/* ---- admin prefix list ------------------------------------------------ */
table.prefix-table > tbody > tr > td { vertical-align: middle; }
.prefix-value { font-family: var(--bs-font-monospace, monospace); font-weight: 600; }
td.prefix .prefix-cell { display: flex; align-items: center; }
.server-chip {
    display: inline-block; font-size: 0.72rem; color: var(--bngv-muted);
    background: var(--bngv-elevate); border-radius: 0.25rem; padding: 0.08rem 0.4rem; margin: 0.1rem 0.15rem 0.1rem 0;
    font-family: var(--bs-font-monospace, monospace);
}
/* Utilization meter: a bar + figures, coloured by fill level. */
.usage-meter { min-width: 9rem; }
.usage-bar { height: 6px; border-radius: 3px; background: var(--bngv-elevate); overflow: hidden; margin-bottom: 0.25rem; }
.usage-fill { display: block; height: 100%; border-radius: 3px; background: var(--bngv-accent); }
.usage-fill.warn { background: var(--bngv-warn); }
.usage-fill.crit { background: var(--bngv-crit); }
.usage-text { font-size: 0.78rem; font-variant-numeric: tabular-nums; }

/* ---- admin user edit: checklists, tag input, save bar ----------------- */
.checklist {
    border: 1px solid var(--bngv-border); border-radius: 0.4rem;
}
.checklist-item {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.4rem 0.6rem; margin: 0; cursor: pointer;
}
.checklist-item:hover { background: var(--bngv-elevate); }
.checklist-item + .checklist-item { border-top: 1px solid var(--bngv-border); }
.checklist-item.filtered-out { display: none; }

/* Custom checkbox rendering three states: empty, a solid accent tick for an
   explicit grant, and a muted grey tick for an inherited grant. */
.checklist-item > input[type=checkbox] {
    appearance: none; -webkit-appearance: none;
    flex: none; margin: 0; width: 17px; height: 17px; cursor: pointer; position: relative;
    border: 1.5px solid var(--bngv-border); border-radius: 4px; background: var(--bngv-page);
}
.checklist-item > input[type=checkbox]::after {
    content: ""; position: absolute; left: 5px; top: 2px; width: 4px; height: 8px;
    border: solid transparent; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.checklist-item > input[type=checkbox]:focus-visible {
    outline: 2px solid var(--bs-focus-ring-color); outline-offset: 1px;
}
/* Explicit grant: solid accent tick + accent label. */
.checklist-item > input[type=checkbox]:checked {
    background: var(--bngv-accent); border-color: var(--bngv-accent);
}
.checklist-item > input[type=checkbox]:checked::after { border-color: var(--bngv-on-accent); }
.checklist-item > input[type=checkbox]:checked ~ .checklist-label { color: var(--bngv-accent); font-weight: 600; }
/* Inherited but not explicitly granted: muted grey tick + grey label + a teal
   "inherited" tag. Still toggleable. */
.checklist-item.is-inherited > input[type=checkbox]:not(:checked) {
    background: var(--bngv-elevate); border-color: var(--bngv-muted);
}
.checklist-item.is-inherited > input[type=checkbox]:not(:checked)::after {
    border-color: var(--bngv-muted); opacity: 0.7;
}
.checklist-item.is-inherited > input[type=checkbox]:not(:checked) ~ .checklist-label { color: var(--bngv-muted); font-weight: 600; }
.checklist-item.is-inherited::after {
    content: "inherited"; margin-left: auto; flex: none;
    font-family: var(--bs-font-monospace, monospace); font-size: 0.66rem; letter-spacing: 0.04em;
    color: var(--bngv-accent); background: rgba(var(--bngv-accent-rgb), 0.14);
    border-radius: 0.25rem; padding: 0.05rem 0.35rem;
}
.checklist-controls { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.5rem; }
.checklist-controls .checklist-search { flex: 1; min-width: 8rem; }
.checklist-modes .btn.active { background: var(--bngv-accent); color: var(--bngv-on-accent); border-color: var(--bngv-accent); }

/* ---- checklist multi-select (filter dropdowns) ----------------------- */
/* An in-house searchable multi-select: a form-select-styled toggle showing a
   summary, opening a popover of the shared .checklist. Replaces the old
   bootstrap-select CDN widget on the log filter bars. The checkboxes are plain
   native `name="field[]"` inputs so the POST filter contract is unchanged;
   assets/js/checklist-select.js only enhances (summary, search, open/close). */
.ck-multi { position: relative; }
.ck-multi-toggle {
    width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ck-multi-summary.is-empty { color: var(--bngv-muted); }
.ck-multi[data-open] .ck-multi-toggle { border-color: var(--bngv-accent); }
.ck-multi-panel {
    display: none; position: absolute; z-index: 1050; top: calc(100% + 0.25rem); left: 0;
    min-width: 100%; width: max-content; max-width: 24rem;
    background: var(--bngv-surface); border: 1px solid var(--bngv-border);
    border-radius: 0.4rem; box-shadow: 0 6px 22px rgba(0, 0, 0, 0.18); padding: 0.6rem;
}
.ck-multi[data-open] .ck-multi-panel { display: block; }
.ck-multi-list { max-height: 15rem; overflow-y: auto; }
.ck-multi-actions { display: flex; gap: 0.25rem; flex: none; }
.inherited-block { margin-top: 0.6rem; }
.inherited-block > small { color: var(--bngv-muted); }
/* Inherited settings render one-per-line as locked, dashed rows. */
.inherited-list { display: flex; flex-direction: column; gap: 0.2rem; margin-top: 0.35rem; }
.inherited-row {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.3rem 0.55rem; font-size: 0.82rem; color: var(--bngv-muted);
    border: 1px dashed var(--bngv-border); border-radius: 0.3rem;
}
.inherited-row .bi { color: var(--bngv-accent); font-size: 0.85em; flex: none; }

/* Realm list: entries stack below the add box, each removable. */
.realm-list { display: flex; flex-direction: column; gap: 0.25rem; }
.list-row {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.3rem 0.55rem; border: 1px solid var(--bngv-border); border-radius: 0.3rem;
}
.list-row-text { flex: 1; font-size: 0.85rem; word-break: break-all; }
.btn-close-x {
    border: 0; background: transparent; color: var(--bngv-muted);
    cursor: pointer; font-weight: 700; line-height: 1; font-size: 1.1rem; padding: 0 0.2rem;
}
.btn-close-x:hover { color: var(--bngv-crit); }
.password-note { display: flex; align-items: flex-start; gap: 0.5rem; color: var(--bngv-muted); }
.password-note .bi { color: var(--bngv-accent); margin-top: 0.15rem; }

.save-bar {
    position: sticky; bottom: 1rem; z-index: 10;
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.75rem 1rem; margin-top: 1rem;
    background: var(--bngv-surface); border: 1px solid var(--bngv-border);
    border-radius: 0.6rem; box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
}

/* Field-level validation. The edit forms flag the *card-body* with .has-error
   (rather than the control), so key the reveal off that: show the otherwise
   display:none .invalid-feedback message and redden the control. Bootstrap 5
   dropped .has-error styling, so without this the rejection is invisible. */
.has-error .invalid-feedback { display: block; }
.has-error .form-control,
.has-error .form-select { border-color: var(--bngv-crit); }
.has-error .form-control:focus,
.has-error .form-select:focus {
    border-color: var(--bngv-crit);
    box-shadow: 0 0 0 0.2rem var(--bngv-crit-bg);
}

/* ---- steering: servers + redirects lists ------------------------------ */
/* Filter/action bar above the realm cards. */
.listbar { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.listbar .listbar-filter { flex: 1 1 18rem; max-width: 24rem; }
.realm-count { color: var(--bngv-muted); font-weight: 500; font-size: 0.82rem; white-space: nowrap; flex-shrink: 0; }
/* Keep the realm count off the header's Add button. */
.card-header .realm-count { margin-right: 0.9rem; }

/* Realm identity chip (leads each realm card header). */
.realm-chip {
    font-family: var(--bs-font-monospace, monospace); font-weight: 600; font-size: 0.9rem;
    color: var(--bngv-text); display: inline-flex; align-items: center; gap: 0.5rem;
}

/* Source-type sections inside a realm card: a band row per source type plus a
   colour-coded left spine, so the cadence / talktalk split reads at a glance.
   The hues are categorical (see --bngv-st-*), deliberately not the status
   colours. Unknown source types fall back to the neutral border. */
table.steering-servers > tbody > tr.st-group > td {
    background: var(--bngv-elevate); padding: 0.4rem 0.7rem;
    border-top: 1px solid var(--bngv-border); border-bottom: 1px solid var(--bngv-border);
    border-left: 3px solid var(--bngv-border);
}
table.steering-servers > tbody > tr.srv-row > td:first-child { border-left: 3px solid var(--bngv-border); }
table.steering-servers > tbody > tr.st-group[data-st="cadence"] > td,
table.steering-servers > tbody > tr.srv-row[data-st="cadence"] > td:first-child { border-left-color: var(--bngv-st-cadence); }
table.steering-servers > tbody > tr.st-group[data-st="talktalk"] > td,
table.steering-servers > tbody > tr.srv-row[data-st="talktalk"] > td:first-child { border-left-color: var(--bngv-st-talktalk); }
.st-band { display: inline-flex; align-items: center; gap: 0.5rem; }
.st-band .st-label { font-size: 0.72rem; color: var(--bngv-muted); text-transform: uppercase; letter-spacing: 0.06em; }
.st-band .st-count { color: var(--bngv-muted); font-size: 0.76rem; }
.st-name {
    font-family: var(--bs-font-monospace, monospace); font-weight: 700; font-size: 0.76rem; letter-spacing: 0.02em;
    padding: 0.14rem 0.55rem; border-radius: 0.3rem;
    color: var(--bngv-muted); background: var(--bngv-elevate);
}
/* Colour keys off data-st on the band row (servers) or on the chip itself
   (redirects list, delete summaries) so the pill is consistent everywhere. */
.st-group[data-st="cadence"] .st-name, .st-name[data-st="cadence"] { color: var(--bngv-st-cadence); background: color-mix(in srgb, var(--bngv-st-cadence) 15%, transparent); }
.st-group[data-st="talktalk"] .st-name, .st-name[data-st="talktalk"] { color: var(--bngv-st-talktalk); background: color-mix(in srgb, var(--bngv-st-talktalk) 15%, transparent); }

table.steering-servers > tbody > tr > td { vertical-align: middle; }
/* Fixed column widths so revealing a password (mask -> value) can't widen its
   cell and shift the row. Order/Status/Actions are locked small; Endpoint and
   Password get sensible fixed widths; Comment takes the remainder (widest).
   Columns: 1 endpoint · 2 password · 3 order · 4 status · 5 comment · 6 actions. */
table.steering-servers { table-layout: fixed; width: 100%; min-width: 77rem; }
table.steering-servers th, table.steering-servers td { overflow-wrap: anywhere; }
table.steering-servers > thead > tr > th:nth-child(1) { width: 13rem; }   /* endpoint */
table.steering-servers > thead > tr > th:nth-child(2) { width: 21rem; }   /* password (fits ~30 chars) */
table.steering-servers > thead > tr > th:nth-child(3) { width: 5rem; }    /* order */
table.steering-servers > thead > tr > th:nth-child(4) { width: 7.5rem; }  /* status */
table.steering-servers > thead > tr > th:nth-child(6) { width: 9.5rem; }  /* actions */
/* Comment is the remaining column (widest); the 77rem table min-width keeps it
   at least ~21rem, and the .table-responsive wrapper scrolls on thin screens
   rather than letting it collapse. */
/* Let a revealed password wrap inside its fixed cell rather than spill out. */
.pw-reveal { flex-wrap: wrap; }
.pw-reveal .pw-value { word-break: break-all; }
.steering-endpoint { font-family: var(--bs-font-monospace, monospace); font-weight: 600; }
/* Disabled servers read lighter: drop the endpoint back to normal weight and
   fade it, so the enabled (bold) ones stand out at a glance. */
tr.srv-row[data-enabled="false"] .steering-endpoint { font-weight: 400; color: var(--bngv-muted); }
.steering-order { font-variant-numeric: tabular-nums; color: var(--bngv-muted); }
td.steering-comment { color: var(--bngv-muted); }
/* The status badge doubles as an enable/disable toggle. */
.badge.toggle-status { cursor: pointer; user-select: none; }
.badge.toggle-status:hover { box-shadow: inset 0 0 0 1px currentColor; }
/* Rows/sections/cards hidden by the client-side filter. */
tr.srv-row.filtered-out, tr.st-group.filtered-out { display: none; }
.realm-card.filtered-out { display: none; }

/* Secret reveal, read-only display (servers list + user/group attribute tables):
   a dotted mask swapped for the value by a .pw-toggle eye button. */
.pw-reveal { display: inline-flex; align-items: center; gap: 0.4rem; }
.pw-reveal .pw-mask { font-family: var(--bs-font-monospace, monospace); letter-spacing: 0.1em; color: var(--bngv-muted); }
.pw-reveal .pw-value { font-family: var(--bs-font-monospace, monospace); }
.pw-reveal .pw-toggle {
    border: 0; background: transparent; color: var(--bngv-muted); cursor: pointer;
    padding: 0.1rem 0.2rem; display: inline-flex; line-height: 1;
}
.pw-reveal .pw-toggle:hover { color: var(--bngv-accent); }

/* Secret reveal, editable input (steering L2TP password, secret attribute value
   cells): an <input type=password> masked by default with an in-field .pw-eye
   button that flips it to text. The wrapper is position:relative so the eye
   overlays the input's right edge. */
.pw-field { position: relative; }
.pw-field > input { padding-right: 2.1rem; }
.pw-field > .pw-eye {
    position: absolute; top: 0; right: 0; height: 100%;
    border: 0; background: transparent; color: var(--bngv-muted); cursor: pointer;
    padding: 0 0.5rem; display: inline-flex; align-items: center; line-height: 1;
}
.pw-field > .pw-eye:hover { color: var(--bngv-accent); }

/* Redirect username cell: hover jumps sit to the left of the name. */
td.steering-username { font-family: var(--bs-font-monospace, monospace); }
td.steering-realm { font-family: var(--bs-font-monospace, monospace); }
/* Active redirects read heavier: bold the username so disabled ones recede.
   Disabled redirects fade to the muted colour to reinforce the state. */
tr[data-enabled="true"] td.steering-username { font-weight: 700; }
tr[data-enabled="false"] td.steering-username { color: var(--bngv-muted); }

/* ---- steering: delete confirmation ------------------------------------ */
.confirm-wrap { max-width: 560px; margin: 0 auto; }
.confirm-card { border-color: var(--bngv-crit); }
.confirm-card > .card-header { background: var(--bngv-crit-bg); color: var(--bngv-crit); border-bottom-color: var(--bngv-crit); }
.confirm-summary {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    padding: 0.7rem 0.85rem; margin-bottom: 0.9rem;
    background: var(--bngv-elevate); border-radius: 0.45rem;
    font-family: var(--bs-font-monospace, monospace); font-size: 0.85rem;
}
.confirm-summary .realm-chip { margin-left: auto; }

/* ---- misc -------------------------------------------------------------- */
a { text-decoration: none; }
a:hover { text-decoration: underline; }
.btn { --bs-btn-focus-box-shadow: 0 0 0 0.2rem var(--bs-focus-ring-color); }

/* ---- RADIUS user/group attribute editor (edituserorgroup) -------------- */
/* Side-by-side attribute · op · value · remove, with a resolved type chip and
   dictionary validation message on a compact line beneath each row. */
.attr-editor .card-body { padding-top: 0.75rem; }
.attr-rows { display: flex; flex-direction: column; }
.attr-row { padding: 0.4rem 0; }
.attr-row + .attr-row { border-top: 1px dashed var(--bngv-border); }
.r-fields {
    display: grid; gap: 0.4rem; align-items: center;
    grid-template-columns: minmax(0, 1fr) 72px minmax(0, 1fr) auto;
}
.r-fields-group { grid-template-columns: minmax(0, 1fr) 72px auto; }
.r-fields .cell { position: relative; min-width: 0; }
.name-in, .val-in, .group-in, .prio-in { font-family: var(--bs-font-monospace, monospace); }
.op-in { text-align: center; padding-left: 0.3rem; padding-right: 1.2rem; }
.prio-in { text-align: center; }
.attr-row .icon-btn { line-height: 1; }

.r-meta {
    display: none; justify-content: space-between; align-items: flex-start;
    gap: 0.5rem; margin-top: 0.28rem;
}
.r-meta .rowmsg {
    display: none; align-items: flex-start; gap: 0.3rem;
    font-size: 0.75rem; color: var(--bngv-crit);
}
.r-meta .rowmsg .bi { margin-top: 1px; }
.r-meta .type-chip {
    margin-left: auto; font-size: 0.68rem; padding: 0.08rem 0.45rem;
    border-radius: 999px; background: var(--bngv-elevate); color: var(--bngv-muted);
    font-family: var(--bs-font-monospace, monospace); white-space: nowrap;
}
.r-meta .type-chip.vendor { background: rgba(var(--bngv-accent-rgb), 0.12); color: var(--bngv-accent); }

/* Add button pinned above each list so it never moves as rows are added. */
.attr-add {
    width: 100%; margin-bottom: 0.6rem;
    border: 1px dashed var(--bngv-border); background: transparent; color: var(--bngv-accent);
    border-radius: 0.5rem; padding: 0.4rem 0.7rem; font-size: 0.85rem; cursor: pointer;
}
.attr-add:hover { border-color: var(--bngv-accent); background: rgba(var(--bngv-accent-rgb), 0.06); }

/* Attribute-name / group-name autocomplete popover. */
.ac {
    position: absolute; z-index: 1080; top: 100%; left: 0; right: 0; margin-top: 2px;
    min-width: 240px; max-height: 240px; overflow-y: auto;
    background: var(--bngv-surface); border: 1px solid var(--bngv-border);
    border-radius: 0.5rem; box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.22);
}
.ac-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.55rem; cursor: pointer; }
.ac-item:hover { background: var(--bngv-elevate); }
.ac-item .an { font-family: var(--bs-font-monospace, monospace); font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-item .at { margin-left: auto; font-size: 0.68rem; color: var(--bngv-muted); font-family: var(--bs-font-monospace, monospace); }
.ac-item .av { font-size: 0.68rem; color: var(--bngv-accent); }
.ac-empty { padding: 0.5rem 0.55rem; font-size: 0.8rem; color: var(--bngv-muted); }
/* Standalone single-select picker (ac-single.js): a relatively-positioned
   anchor so the shared .ac dropdown lands under the field, and a read-only
   input that reads as a dropdown (form-select chevron + pointer cursor). */
.ac-anchor { position: relative; display: block; }
.ac-anchor > .ac-input { cursor: pointer; }
/* Native <select> enhanced by ac-select.js is hidden; its .ac-input display
   stands in for it (the select stays in the DOM for value + form submission). */
.ac-hidden-select { display: none; }
.ac-anchor > .ac-input:read-only { background-color: var(--bs-body-bg); }

/* Save-bar status pill (reuses the existing .save-bar container). */
.save-bar .pill { font-size: 0.75rem; font-weight: 600; padding: 0.12rem 0.55rem; border-radius: 999px; }
.save-bar .pill.ok { background: var(--bngv-ok-bg); color: var(--bngv-ok); }
.save-bar .pill.err { background: var(--bngv-crit-bg); color: var(--bngv-crit); }

/* Masked attribute values (partial.attributetables) hidden until revealed, and
   generic filter-hidden rows. Centralised here so views don't each inline it. */
.displayOptionsHidden { display: none !important; }

/* ---- user/group view: quiet manage/actions blocks --------------------- */
.actions-block { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.actions-block + .actions-block { margin-top: 0.7rem; padding-top: 0.7rem; border-top: 1px solid var(--bngv-border); }
.actions-block .glabel {
    flex: 0 0 auto; min-width: 64px;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--bngv-muted);
}
/* Buttons read quiet by default; only Edit (btn-warning in the partials)
   keeps the accent. Danger turns red on hover only. */
.actions-block .btn {
    --bs-btn-bg: var(--bngv-surface);
    --bs-btn-border-color: var(--bngv-border);
    --bs-btn-color: var(--bngv-text);
    --bs-btn-hover-bg: var(--bngv-elevate);
    --bs-btn-hover-border-color: var(--bngv-accent);
    --bs-btn-hover-color: var(--bngv-text);
    --bs-btn-active-bg: var(--bngv-elevate);
    --bs-btn-active-border-color: var(--bngv-accent);
    --bs-btn-active-color: var(--bngv-text);
    font-size: 0.85rem;
}
.actions-block .btn-warning {
    --bs-btn-bg: var(--bngv-accent);
    --bs-btn-border-color: var(--bngv-accent);
    --bs-btn-color: var(--bngv-on-accent);
    --bs-btn-hover-bg: var(--bngv-accent-hover);
    --bs-btn-hover-border-color: var(--bngv-accent-hover);
    --bs-btn-hover-color: var(--bngv-on-accent);
    --bs-btn-active-bg: var(--bngv-accent-active);
    --bs-btn-active-border-color: var(--bngv-accent-active);
    --bs-btn-active-color: var(--bngv-on-accent);
}
.actions-block .btn-danger {
    --bs-btn-hover-bg: var(--bngv-crit-bg);
    --bs-btn-hover-border-color: var(--bngv-crit);
    --bs-btn-hover-color: var(--bngv-crit);
}

/* ---- user/group view: flat attribute tables ---------------------------- */
.attrtable-flat {
    width: 100%; border-collapse: collapse; table-layout: fixed;
    font-size: 0.85rem; margin-bottom: 1rem;
}
.attrtable-flat:last-child { margin-bottom: 0; }
.attrtable-flat th, .attrtable-flat td {
    text-align: left; padding: 0.38rem 0.5rem;
    border-bottom: 1px solid var(--bngv-border);
    vertical-align: top; overflow-wrap: break-word;
}
.attrtable-flat tr:last-child th, .attrtable-flat tr:last-child td { border-bottom: 0; }
.attrtable-flat th.attribute { font-family: var(--bs-font-monospace, monospace); font-weight: 600; width: 45%; }
.attrtable-flat td.op { color: var(--bngv-muted); font-family: var(--bs-font-monospace, monospace); width: 3.5em; }
.attrhdr {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--bngv-muted); font-weight: 700; margin: 0.1rem 0 0.35rem;
}

/* Small quiet link in card headers (e.g. group Details). */
.quiet-link {
    font-size: 0.78rem; text-decoration: none; color: var(--bngv-accent);
    border: 1px solid var(--bngv-border); border-radius: 0.4rem;
    padding: 0.15rem 0.5rem; display: inline-flex; align-items: center;
    gap: 0.3rem; white-space: nowrap;
}
.quiet-link:hover { border-color: var(--bngv-accent); background: rgba(var(--bngv-accent-rgb), 0.08); text-decoration: none; }

/* ---- group picker: full list with a search box on top ------------------ */
.ac.ac-picker { overflow: hidden; display: flex; flex-direction: column; }
/* Flip upward (ac-select.js sets .ac-up when there's no room below). */
.ac.ac-up { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 2px; }
.ac-picker .ac-list { overflow-y: auto; }
.ac-picker .ac-item.selected { background: rgba(var(--bngv-accent-rgb), 0.12); font-weight: 600; }
.ac-search {
    display: block; margin: 0.35rem; padding: 0.3rem 0.5rem;
    width: calc(100% - 0.7rem); font-size: 0.8rem;
    border: 1px solid var(--bngv-border); border-radius: 0.35rem;
    background: var(--bngv-surface); color: var(--bngv-text);
}
.ac-search:focus { outline: 2px solid rgba(var(--bngv-accent-rgb), 0.35); outline-offset: 1px; border-color: var(--bngv-accent); }
.group-in[readonly] { cursor: pointer; background: var(--bngv-surface); }

/* ---- server list: picker + user/group/prefix cards -------------------- */
/* The server-switcher list-group should use the accent, not Bootstrap blue. */
.list-group {
    --bs-list-group-bg: var(--bngv-surface);
    --bs-list-group-color: var(--bngv-text);
    --bs-list-group-border-color: var(--bngv-border);
    --bs-list-group-action-hover-bg: var(--bngv-elevate);
    --bs-list-group-action-hover-color: var(--bngv-text);
    --bs-list-group-active-bg: var(--bngv-accent);
    --bs-list-group-active-border-color: var(--bngv-accent);
    --bs-list-group-active-color: var(--bngv-on-accent);
}

/* The list cards reuse the shared coloured button partials (userbuttons /
   groupbuttons / genericlist buttons). Quiet them into subtle icon buttons in
   the list context only - the partials' markup is untouched, and the user/group
   view "Manage" block keeps its full buttons. Kept visible (not hover-hidden):
   this list's job is to drill into a user. */
td.username .btn, td.groupname .btn, td.thing .btn {
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--bngv-border);
    --bs-btn-color: var(--bngv-accent);
    --bs-btn-hover-bg: var(--bngv-accent);
    --bs-btn-hover-border-color: var(--bngv-accent);
    --bs-btn-hover-color: var(--bngv-on-accent);
    --bs-btn-active-bg: var(--bngv-accent-active);
    --bs-btn-active-border-color: var(--bngv-accent-active);
    --bs-btn-active-color: var(--bngv-on-accent);
    padding: 0.2rem 0.45rem;
    line-height: 1;
}
td.username .btn.btn-danger, td.groupname .btn.btn-danger, td.thing .btn.btn-danger {
    --bs-btn-hover-bg: var(--bngv-crit-bg); --bs-btn-hover-color: var(--bngv-crit);
}
/* Prefix / static-address identifiers read monospace. */
td.thing .thing-title { font-family: var(--bs-font-monospace, monospace); }

/* ---- accounting / authentication log tables --------------------------- */
/* Wide, busy diagnostic tables (standalone log pages + inline on the user
   view). Quiet rows in the flat house style: mono identifiers, status as a
   badge, and the per-cell filter/visit shortcuts hidden until row hover via
   the shared .row-actions mechanism. */
.logtable { font-size: 0.85rem; }
.logtable th, .logtable td { vertical-align: middle; }
/* A two-row head: labels, then an optional compact filter row. The label row
   drops its heavy bottom border so it reads as one unit with the filters. */
.logtable thead tr.labelrow th { border-bottom: 0; padding-bottom: 0.2rem; }
.logtable thead tr.filterrow th { padding-top: 0; }
.logtable thead tr.filterrow .form-control { min-width: 6rem; }
/* Identifiers (session id, NAS, IPs, MAC, port, row id) read monospace. */
.logtable .mono { font-family: var(--bs-font-monospace, monospace); }
.logtable td.cell-id { color: var(--bngv-muted); font-family: var(--bs-font-monospace, monospace); }
/* Byte counts / durations align on the decimal. */
.logtable td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The callingstation/vendor sub-line under an IP. */
.logtable .cell-sub { color: var(--bngv-muted); font-size: 0.76rem; }
.logtable .cell-sub .mono { color: inherit; }
/* Stacked key:value lists inside a cell (steering servers/request columns). */
.logtable .kv-list { list-style: none; padding-left: 0; margin: 0; }
.logtable .kv-list > li + li { margin-top: 0.1rem; }
.logtable .kv-list .kv-key { font-family: var(--bs-font-monospace, monospace); color: var(--bngv-muted); }
/* Top-align variant for the expanding log pages (steering / audit / api-debug),
   where cells hold multi-line lists or an expandable detail - rows read better
   anchored to the top than vertically centred. */
.logtable.logtable-top th, .logtable.logtable-top td { vertical-align: top; }

/* HTTP method pill - a categorical colour keyed off data-method (its own
   palette, never the green/amber/red status tokens). Falls back to the neutral
   idle badge for any method without a dedicated hue. */
.http-method[data-method="GET"]    { color: var(--bngv-method-get);    background: color-mix(in srgb, var(--bngv-method-get) 15%, transparent); }
.http-method[data-method="POST"]   { color: var(--bngv-method-post);   background: color-mix(in srgb, var(--bngv-method-post) 15%, transparent); }
.http-method[data-method="PUT"],
.http-method[data-method="PATCH"]  { color: var(--bngv-method-put);    background: color-mix(in srgb, var(--bngv-method-put) 15%, transparent); }
.http-method[data-method="DELETE"] { color: var(--bngv-method-delete); background: color-mix(in srgb, var(--bngv-method-delete) 15%, transparent); }

/* Standard page header. One consistent centred title with even spacing on
   every page, replacing the ad-hoc <br><br> stacks (which gave wildly uneven
   top padding). Title is deliberately smaller than a raw Bootstrap <h1>.
   Optional .page-sub is a one-line muted blurb under the title - use it where
   it clarifies the page, not on every page. */
.page-head { text-align: center; margin: 0.75rem 0 1.75rem; }
.page-head h1 { font-size: 1.8rem; font-weight: 600; letter-spacing: -0.01em; margin: 0; }
/* .page-sub also appears standalone as the per-server "Found on <code>" line
   (see DESIGN.md Headers), so it is not scoped to .page-head. */
.page-sub { margin: 0.4rem 0 0; color: var(--bngv-muted); font-size: 1.05rem; }
.page-sub code { font-size: 0.95em; }

/* Standard centred content caps. Prefer these over inline `max-width` so the
   widths stay consistent and can be retuned in one place. They work on any
   centred block - page container, card, save bar, list-group picker:
     pagewrap - wide / page content (the house default)
     formwrap - simple field-edit forms
     pickwrap - server / report list-group pickers
   (Widths had drifted across inline 600/880/900/1080/1200/1400 before this.) */
.pagewrap { max-width: 1400px; margin-inline: auto; }
.formwrap { max-width:  900px; margin-inline: auto; }
.pickwrap { max-width:  700px; margin-inline: auto; }

/* ---- admin dashboard --------------------------------------------------- */
/* Quick-action tiles: quiet by default, accent on hover - deliberately not a
   wall of solid buttons (see DESIGN.md). Icon chip · title + one-line hint. */
.admin-nav { display: flex; flex-direction: column; gap: 0.4rem; }
.admin-nav-item {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.55rem 0.7rem; border: 1px solid var(--bngv-border);
    border-radius: 0.5rem; text-decoration: none; color: var(--bngv-text);
    transition: border-color 0.12s, background 0.12s;
}
.admin-nav-item:hover, .admin-nav-item:focus-visible {
    border-color: var(--bngv-accent); color: var(--bngv-text);
    background: rgba(var(--bngv-accent-rgb), 0.06); text-decoration: none;
}
.admin-nav-icon { flex: 0 0 1.6rem; text-align: center; font-size: 1.15rem; color: var(--bngv-accent); }
.admin-nav-text { display: flex; flex-direction: column; line-height: 1.25; flex: 1 1 auto; min-width: 0; }
.admin-nav-title { font-weight: 600; }
.admin-nav-sub { font-size: 0.78rem; color: var(--bngv-muted); }
.admin-nav-go { color: var(--bngv-muted); font-size: 0.85rem; transition: transform 0.12s, color 0.12s; }
.admin-nav-item:hover .admin-nav-go { color: var(--bngv-accent); transform: translateX(2px); }

/* Small uppercase field label (e.g. the instance strip). */
.admin-glabel {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
    font-weight: 700; color: var(--bngv-muted);
}

/* Server-health cards: a status-coloured left spine so the worst state reads
   at a glance. Semantic status (ok/warn/crit) is correct here - this is health,
   not a category. */
.health-card { border-left: 3px solid var(--bngv-border); }
.health-card[data-status="ok"]   { border-left-color: var(--bngv-ok); }
.health-card[data-status="warn"] { border-left-color: var(--bngv-warn); }
.health-card[data-status="crit"] { border-left-color: var(--bngv-crit); }
.health-conn { font-size: 0.82rem; word-break: break-word; }
.health-conn code { font-size: 0.82rem; }
.health-clean { color: var(--bngv-muted); font-size: 0.85rem; }
.health-issues { list-style: none; padding-left: 0; font-size: 0.82rem; }
.health-issues li { display: flex; gap: 0.4rem; align-items: baseline; }
.health-issues li + li { margin-top: 0.3rem; }
.health-issues .bi { flex: 0 0 auto; }

/* Audit-log category pill - a per-category hue (--cat-h set inline, assigned
   evenly across the category set in the controller). Categorical identity
   colour, NOT status: it spans the whole wheel and deliberately never maps to
   the green/amber/red status tokens. */
.badge.cat-pill {
    --cat-s: 58%;
    color: hsl(var(--cat-h, 0) var(--cat-s) 34%);
    background-color: hsl(var(--cat-h, 0) var(--cat-s) 34% / 0.13);
}
[data-bs-theme="dark"] .badge.cat-pill {
    color: hsl(var(--cat-h, 0) var(--cat-s) 72%);
    background-color: hsl(var(--cat-h, 0) var(--cat-s) 72% / 0.16);
}

/* ---- pane tabs (Parsed/Raw toggles: audit detail, API-debug body views) --- */
.pane-tabs { display: flex; gap: 0.3rem; margin-bottom: 0.6rem; flex-wrap: wrap; }
.pane-tab {
    font-size: 0.74rem; padding: 0.12rem 0.55rem; border: 1px solid var(--bngv-border);
    border-radius: 0.35rem; color: var(--bngv-muted); text-decoration: none; cursor: pointer;
}
.pane-tab:hover { color: var(--bngv-text); text-decoration: none; }
.pane-tab.active { color: var(--bngv-accent); border-color: var(--bngv-accent); background: rgba(var(--bngv-accent-rgb), 0.08); }

/* ---- audit log expanded detail (partial.auditdata) --------------------- */

.audit-section + .audit-section { margin-top: 0.75rem; }
.audit-section-label {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--bngv-muted); font-weight: 700; margin-bottom: 0.3rem;
}
.audit-result-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.4rem; }
.audit-msg { color: var(--bngv-text); }

.audit-key { font-family: var(--bs-font-monospace, monospace); font-weight: 600; white-space: nowrap; }
.audit-val { font-family: var(--bs-font-monospace, monospace); white-space: pre-wrap; word-break: break-word; }

/* Key/value grid. */
.audit-kv { display: grid; grid-template-columns: minmax(7rem, max-content) 1fr; gap: 0; font-size: 0.82rem;
    border: 1px solid var(--bngv-border); border-radius: 0.4rem; overflow: hidden; max-width: 900px; }
.audit-kv-row { display: contents; }
.audit-kv-row > span { padding: 0.28rem 0.55rem; border-top: 1px solid var(--bngv-border); }
.audit-kv-row:first-child > span { border-top: 0; }
.audit-kv-row > .audit-key { background: var(--bngv-elevate); }

/* Old/new/diff grid. */
.audit-diff { display: grid; grid-template-columns: minmax(6rem, max-content) 1fr 1fr max-content; gap: 0;
    font-size: 0.82rem; border: 1px solid var(--bngv-border); border-radius: 0.4rem; overflow: hidden; }
.audit-diff-row { display: contents; }
.audit-diff-row > span { padding: 0.3rem 0.55rem; border-top: 1px solid var(--bngv-border); }
.audit-diff-head > span {
    border-top: 0; background: var(--bngv-elevate); font-weight: 700; color: var(--bngv-muted);
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em;
}
.audit-diffcol { display: flex; align-items: center; }
/* Row states (styled per-cell since the row itself is display:contents). */
.audit-diff-row.same > span { color: var(--bngv-muted); }
.audit-diff-row.changed > span { background: color-mix(in srgb, var(--bngv-warn) 8%, transparent); }
.audit-diff-row.changed > span:first-child { box-shadow: inset 3px 0 0 var(--bngv-warn); }
.audit-diff-row.changed .audit-old { color: var(--bngv-muted); text-decoration: line-through; }
.audit-diff-row.changed .audit-new { font-weight: 600; }
.audit-diff-row.set > span { background: color-mix(in srgb, var(--bngv-ok) 8%, transparent); }
.audit-diff-row.set > span:first-child { box-shadow: inset 3px 0 0 var(--bngv-ok); }
.audit-diff-row.set .audit-old { color: var(--bngv-muted); }
