/* ==========================================================================
   Netvia Shaper — design system (dark, clean, Roboto + Font Awesome 7)
   --------------------------------------------------------------------------
   Built on Bootstrap 5.3 (data-bs-theme="dark"). We only OVERRIDE Bootstrap
   CSS variables + add a thin layout/skin layer. Do NOT hand-roll component
   HTML — use the Jinja macros in templates/_components/ (see styleguide).

   Palette tokens live in :root. Change them here to re-theme the whole app.
   ========================================================================== */

:root {
  /* Brand palette */
  --nvs-bg:          #0f1115;   /* app background            */
  --nvs-surface:     #171a21;   /* sidebar, cards            */
  --nvs-surface-2:   #1e222b;   /* inputs, hover, table head */
  --nvs-surface-3:   #252a35;   /* active/hover accents      */
  --nvs-border:      #2a2f3a;
  --nvs-text:        #e6e8ec;
  --nvs-text-muted:  #98a2b3;
  --nvs-primary:     #4f8cff;
  --nvs-primary-600: #3f7ae6;
  --nvs-primary-700: #3568d4;  /* darker surface for white-text buttons */
  --nvs-radius:      12px;
  --nvs-sidebar-w:   260px;

  /* Map Bootstrap dark theme onto our palette so every BS component matches. */
  --bs-body-bg:            var(--nvs-bg);
  --bs-body-color:         var(--nvs-text);
  --bs-secondary-bg:       var(--nvs-surface-2);
  --bs-tertiary-bg:        var(--nvs-surface);
  --bs-border-color:       var(--nvs-border);
  --bs-emphasis-color:     #ffffff;
  --bs-secondary-color:    var(--nvs-text-muted);
  --bs-primary:            var(--nvs-primary);
  --bs-primary-rgb:        79, 140, 255;
  --bs-link-color:         var(--nvs-primary);
  --bs-link-hover-color:   var(--nvs-primary-600);
  --bs-border-radius:      var(--nvs-radius);
  --bs-font-sans-serif:    "Roboto", system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { scrollbar-color: var(--nvs-surface-3) transparent; }
body { font-family: var(--bs-font-sans-serif); background: var(--nvs-bg); }

/* Icons: Font Awesome 7 — <i class="fa-solid fa-router"></i>.
   FA ships its own sizing helpers (fa-sm/fa-lg/fa-xl, fa-fw). We only nudge
   the default glyph size so icons sit comfortably next to Roboto text. */
.fa-solid, .fa-regular, .fa-brands { line-height: 1; }

/* ==========================================================================
   App shell — CSS grid: [ sidebar | main ]
   ========================================================================== */
.nvs-app {
  display: grid;
  grid-template-columns: var(--nvs-sidebar-w) 1fr;
  min-height: 100vh;
}
.nvs-app.nvs-collapsed { grid-template-columns: 0 1fr; }

/* Backdrop is only used for the mobile drawer; keep it out of the grid on desktop. */
.nvs-backdrop { display: none; }

/* ---- Sidebar ---- */
.nvs-sidebar {
  background: var(--nvs-surface);
  border-right: 1px solid var(--nvs-border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.nvs-brand {
  display: flex; align-items: center; gap: .6rem;
  padding: 1rem 1.15rem; font-weight: 700; font-size: 1.1rem;
  border-bottom: 1px solid var(--nvs-border); color: var(--nvs-text);
}
.nvs-brand i { color: var(--nvs-primary); font-size: 1.4rem; }
.nvs-nav { padding: .6rem .55rem; flex: 1; }

/* nav group (collapsible) */
.nvs-nav-group > .nvs-nav-toggle {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  padding: .55rem .7rem; border: 0; background: transparent;
  color: var(--nvs-text-muted); border-radius: 8px;
  font-size: .82rem; text-transform: uppercase; letter-spacing: .04em;
  cursor: pointer;
}
.nvs-nav-group > .nvs-nav-toggle:hover { color: var(--nvs-text); }
.nvs-nav-group > .nvs-nav-toggle .nvs-chev { margin-left: auto; transition: transform .15s; }
.nvs-nav-group.open > .nvs-nav-toggle .nvs-chev { transform: rotate(90deg); }
.nvs-nav-group > .nvs-nav-items { display: none; padding: .15rem 0 .4rem; }
.nvs-nav-group.open > .nvs-nav-items { display: block; }

/* nav item (leaf link) */
.nvs-nav-item {
  display: flex; align-items: center; gap: .7rem;
  padding: .55rem .8rem; margin: .1rem .15rem;
  color: var(--nvs-text); text-decoration: none; border-radius: 8px;
  font-size: .92rem;
}
.nvs-nav-item i { color: var(--nvs-text-muted); font-size: 1rem; width: 1.25rem; text-align: center; }
.nvs-nav-item:hover { background: var(--nvs-surface-2); }
.nvs-nav-item.active { background: var(--nvs-surface-3); color: #fff; }
.nvs-nav-item.active i { color: var(--nvs-primary); }

/* ---- Main column ---- */
.nvs-main { display: flex; flex-direction: column; min-width: 0; }

.nvs-topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: .75rem;
  padding: .6rem 1.1rem; min-height: 56px;
  background: rgba(15,17,21,.85); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--nvs-border);
}
.nvs-topbar .nvs-toggle {
  background: transparent; border: 0; color: var(--nvs-text-muted);
  padding: .35rem; border-radius: 8px; cursor: pointer; display: flex;
}
.nvs-topbar .nvs-toggle:hover { background: var(--nvs-surface-2); color: var(--nvs-text); }

.nvs-content { padding: 1.25rem 1.4rem 2.5rem; }

/* Page head: breadcrumb + title + actions (lives INSIDE swappable content) */
.nvs-page-head { margin-bottom: 1.1rem; }
.nvs-page-head .nvs-crumbs { color: var(--nvs-text-muted); font-size: .82rem; margin-bottom: .25rem; }
.nvs-page-head .nvs-crumbs a { color: var(--nvs-text-muted); text-decoration: none; }
.nvs-page-head .nvs-crumbs a:hover { color: var(--nvs-text); }
.nvs-page-head .nvs-title-row { display: flex; align-items: center; gap: 1rem; }
.nvs-page-head h1 { font-size: 1.5rem; font-weight: 600; margin: 0; }
.nvs-page-head .nvs-actions { margin-left: auto; display: flex; gap: .5rem; }

/* ==========================================================================
   Cards
   ========================================================================== */
.card {
  background: var(--nvs-surface);
  border: 1px solid var(--nvs-border);
  border-radius: var(--nvs-radius);
}
.card .card-header {
  background: transparent; border-bottom: 1px solid var(--nvs-border);
  display: flex; align-items: center; gap: .6rem; padding: .85rem 1.1rem;
  font-weight: 600;
}
.card .card-header > i { color: var(--nvs-primary); font-size: 1.05rem; }
.card .card-header .nvs-card-tools { margin-left: auto; display: flex; gap: .4rem; }
.card .card-body { padding: 1.1rem; }

/* KPI tile */
.nvs-kpi { display: flex; align-items: center; gap: .9rem; }
.nvs-kpi .nvs-kpi-icon {
  width: 46px; height: 46px; border-radius: 11px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--nvs-primary) 18%, transparent);
  color: var(--nvs-primary);
}
.nvs-kpi .nvs-kpi-icon i { font-size: 1.2rem; }
.nvs-kpi .nvs-kpi-value { font-size: 1.55rem; font-weight: 700; line-height: 1.1; }
.nvs-kpi .nvs-kpi-label { color: var(--nvs-text-muted); font-size: .85rem; }

/* ==========================================================================
   Buttons
   --------------------------------------------------------------------------
   Flex layout so an inline <i class="fa-..."> icon is vertically centred with
   the label and gap-spaced from it.
   ========================================================================== */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; }

/* btn-primary: the brand blue (#4f8cff) is too light for white text (~2.5:1).
   Use a darker shade as the button surface, brightening to brand blue on hover. */
.btn-primary {
  --bs-btn-bg:                var(--nvs-primary-700);
  --bs-btn-border-color:      var(--nvs-primary-700);
  --bs-btn-hover-bg:          var(--nvs-primary-600);
  --bs-btn-hover-border-color:var(--nvs-primary-600);
  --bs-btn-active-bg:         var(--nvs-primary-600);
  --bs-btn-active-border-color:var(--nvs-primary-600);
  --bs-btn-disabled-bg:       var(--nvs-primary-700);
  --bs-btn-disabled-border-color:var(--nvs-primary-700);
}

/* ==========================================================================
   Forms / inputs
   ========================================================================== */
.form-control, .form-select {
  background: var(--nvs-surface-2); border-color: var(--nvs-border); color: var(--nvs-text);
}
.form-control:focus, .form-select:focus {
  background: var(--nvs-surface-2); color: var(--nvs-text);
  border-color: var(--nvs-primary);
  box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--nvs-primary) 25%, transparent);
}
.form-label { font-size: .85rem; color: var(--nvs-text-muted); margin-bottom: .3rem; }

/* ---- Select2 (searchable picker) — themed onto the dark inputs ---------- */
.select2-container--default .select2-selection--single {
  height: calc(1.5em + .75rem + 2px);
  background: var(--nvs-surface-2);
  border: 1px solid var(--nvs-border);
  border-radius: 8px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: calc(1.5em + .75rem); padding-left: .75rem; padding-right: 2rem;
  color: var(--nvs-text);
}
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--nvs-text-muted); }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: calc(1.5em + .75rem); right: 8px; }
.select2-container--default .select2-selection--single .select2-selection__arrow b { border-color: var(--nvs-text-muted) transparent transparent; }
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--single {
  border-color: var(--nvs-primary);
  box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--nvs-primary) 25%, transparent);
}
.select2-dropdown { background: var(--nvs-surface-2); border: 1px solid var(--nvs-border); border-radius: 8px; }
.select2-container--default .select2-search--dropdown .select2-search__field {
  background: var(--nvs-surface); border: 1px solid var(--nvs-border); color: var(--nvs-text); border-radius: 6px;
}
.select2-container--default .select2-results__option { color: var(--nvs-text); }
.select2-container--default .select2-results__option--highlighted,
.select2-container--default .select2-results__option--highlighted[aria-selected] { background: var(--nvs-primary-700); color: #fff; }
.select2-container--default .select2-results__option[aria-selected="true"] { background: var(--nvs-surface-3); }
/* .is-invalid select2 keeps the red border cue on the widget too */
.is-invalid + .select2-container--default .select2-selection--single { border-color: #e5484d; }

/* ==========================================================================
   Tables (DataTables + Bootstrap5)
   ========================================================================== */
.table { --bs-table-bg: transparent; color: var(--nvs-text); }
.table > thead th {
  color: var(--nvs-text-muted); text-transform: uppercase;
  font-size: .74rem; letter-spacing: .03em; border-bottom-color: var(--nvs-border);
}
.table > tbody td { border-color: var(--nvs-border); vertical-align: middle; }
table.dataTable > tbody tr:hover td { background: var(--nvs-surface-2); }
.dataTables_wrapper .dataTables_filter input,
.dataTables_wrapper .dataTables_length select {
  background: var(--nvs-surface-2); border: 1px solid var(--nvs-border);
  color: var(--nvs-text); border-radius: 8px;
}
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_length { color: var(--nvs-text-muted); }
.page-link { background: var(--nvs-surface-2); border-color: var(--nvs-border); color: var(--nvs-text); }
.page-item.active .page-link { background: var(--nvs-primary-700); border-color: var(--nvs-primary-700); color: #fff; }

/* Grid/flex children default to min-width:auto, which lets a wide table push
   its column wider than the row and overflow the whole page. Pin them to 0 so
   the table's container reflects the real available width — required for both
   the Responsive extension (column collapsing) and the scroll fallback below. */
.nvs-content .row > * { min-width: 0; }

/* Fallback for any non-DataTable / responsive-disabled wide table: scroll
   horizontally inside its card instead of overflowing the viewport. */
.dataTables_wrapper { overflow-x: auto; }

/* clickable rows (row -> detail via router) */
tr[data-detail-url] { cursor: pointer; }

/* ==========================================================================
   Misc
   ========================================================================== */
.nvs-pill { display: inline-flex; align-items: center; gap: .3rem; padding: .18rem .6rem;
  border-radius: 999px; font-size: .78rem; font-weight: 500; }
.nvs-pill-muted   { background: var(--nvs-surface-3); color: var(--nvs-text-muted); }
.nvs-pill-primary { background: color-mix(in srgb, var(--nvs-primary) 22%, transparent); color: var(--nvs-primary); }
.nvs-pill-success { background: color-mix(in srgb, #2fb380 22%, transparent); color: #48d09b; }
.nvs-pill-warning { background: color-mix(in srgb, #d9a441 22%, transparent); color: #e8bd6b; }
.nvs-pill-danger  { background: color-mix(in srgb, #e5484d 22%, transparent); color: #ff6b70; }

.modal-content { background: var(--nvs-surface); border: 1px solid var(--nvs-border); border-radius: var(--nvs-radius); }
.modal-header, .modal-footer { border-color: var(--nvs-border); }

.dropdown-menu { background: var(--nvs-surface-2); border-color: var(--nvs-border); }
.dropdown-item { color: var(--nvs-text); display: flex; align-items: center; gap: .55rem; }
.dropdown-item:hover { background: var(--nvs-surface-3); color: #fff; }
.dropdown-item.text-danger:hover { color: #ff6b70 !important; background: color-mix(in srgb, #e5484d 16%, transparent); }

/* Leading state icon inside a toast (see NVS.toast). */
.toast .nvs-toast-icon { flex: 0 0 auto; }

/* Avatar with initials */
.nvs-avatar { width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; font-size: .8rem; font-weight: 600;
  background: var(--nvs-surface-3); color: var(--nvs-text); }

/* Toast container */
#nvs-toasts { position: fixed; top: 1rem; right: 1rem; z-index: 1080; display: flex; flex-direction: column; gap: .5rem; }

/* Content fade during AJAX navigation */
.nvs-content.nvs-loading { opacity: .5; pointer-events: none; transition: opacity .1s; }

/* ==========================================================================
   Network tree — left-to-right org chart inside a pannable/zoomable "map"
   ========================================================================== */
/* Map viewport: clips; the canvas inside is translated + scaled. */
.nvs-map {
  position: relative; overflow: hidden; cursor: grab;
  height: calc(100vh - 190px); min-height: 420px;
  background: var(--nvs-surface); border: 1px solid var(--nvs-border); border-radius: var(--nvs-radius);
  background-image: radial-gradient(var(--nvs-border) 1px, transparent 1px);
  background-size: 22px 22px;
}
.nvs-map.nvs-grabbing { cursor: grabbing; }
.nvs-map-canvas { position: absolute; top: 0; left: 0; transform-origin: 0 0; padding: 1.5rem; }
/* `will-change: transform` keeps the canvas on its own compositor layer, which
   makes panning smooth — but a scaled-up layer is a scaled-up BITMAP, so text
   goes blurry. It is therefore switched on only while the view is moving and
   dropped once it settles, which forces a re-render at the final scale (see
   NVS._initMap). */
.nvs-map-canvas.is-transforming { will-change: transform; }
.nvs-map-controls { position: absolute; right: 12px; bottom: 12px; z-index: 3; display: flex; flex-direction: column; gap: 4px; }
.nvs-map-controls .btn { width: 34px; height: 34px; padding: 0; display: grid; place-items: center; }

/* LTR tree: root on the left, children stacked vertically to the right. */
.nvs-tree, .nvs-tree ul { display: flex; flex-direction: column; justify-content: center; list-style: none; margin: 0; padding: 0; }
.nvs-tree-li { position: relative; display: flex; flex-direction: row; align-items: center; padding: 5px 0 5px 22px; }
.nvs-tree ul { position: relative; padding-left: 22px; }
/* roots have no parent -> no incoming connector */
.nvs-tree > .nvs-tree-li { padding-left: 0; }
.nvs-tree > .nvs-tree-li::before, .nvs-tree > .nvs-tree-li::after { display: none; }
/* incoming connector for each child: vertical spine (split into halves) + horizontal stub */
.nvs-tree-li::before, .nvs-tree-li::after { content: ''; position: absolute; left: 0; width: 22px; height: 50%; }
.nvs-tree-li::before { bottom: 50%; border-left: 1px solid var(--nvs-border); }
.nvs-tree-li::after  { top: 50%; border-left: 1px solid var(--nvs-border); border-top: 1px solid var(--nvs-border); }
.nvs-tree-li:first-child::before { border-left: 0; }
.nvs-tree-li:last-child::after { border-left: 0; }
.nvs-tree-li:only-child::before { display: none; }
.nvs-tree-li:only-child::after { border-left: 0; }
.nvs-tree-li:only-child { padding-left: 22px; }
/* stem from a parent card into the children's spine */
.nvs-tree ul::before { content: ''; position: absolute; left: 0; top: 50%; width: 22px; height: 0; border-top: 1px solid var(--nvs-border); }
.nvs-tree-li.nvs-collapsed > ul { display: none; }

.nvs-tree-item { position: relative; display: inline-flex; flex: 0 0 auto; }
.nvs-tree-card {
  display: inline-flex; align-items: center; gap: .6rem; text-align: left;
  background: var(--nvs-surface-2); border: 1px solid var(--nvs-border);
  border-radius: 10px; padding: .55rem .8rem; width: 380px;
  cursor: pointer; transition: border-color .12s, background .12s;
}
.nvs-tree-card:hover { border-color: var(--nvs-primary); background: var(--nvs-surface-3); }
.nvs-tree-card:focus-visible { outline: 2px solid var(--nvs-primary); outline-offset: 2px; }
.nvs-tree-ic { width: 30px; height: 30px; border-radius: 8px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--nvs-primary) 16%, transparent); color: var(--nvs-primary); }
.nvs-tree-body { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.nvs-tree-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nvs-tree-meta { font-size: .74rem; color: var(--nvs-text-muted); white-space: nowrap; }
.nvs-tree-area .nvs-tree-ic { background: color-mix(in srgb, #4f8cff 18%, transparent); color: #7aa8ff; }
.nvs-tree-customer .nvs-tree-ic { background: color-mix(in srgb, #2fb380 18%, transparent); color: #48d09b; }

.nvs-tree-collapse {
  position: absolute; right: -11px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; border-radius: 50%; padding: 0;
  border: 1px solid var(--nvs-border); background: var(--nvs-surface); z-index: 1;
  color: var(--nvs-text-muted); font-size: .6rem; display: grid; place-items: center; cursor: pointer;
}
.nvs-tree-collapse:hover { color: var(--nvs-text); border-color: var(--nvs-primary); }

/* Tree search (page-head) + dropdown of matches */
.nvs-tree-search { position: relative; }
.nvs-tree-search .mi-search { position: absolute; left: .6rem; top: 50%; transform: translateY(-50%);
  color: var(--nvs-text-muted); font-size: .8rem; pointer-events: none; }
.nvs-tree-search input { width: 240px; padding-left: 1.9rem; }
.nvs-tree-search-results {
  position: absolute; top: calc(100% + 4px); right: 0; width: 360px; max-height: 60vh; overflow-y: auto;
  background: var(--nvs-surface-2); border: 1px solid var(--nvs-border); border-radius: 10px; z-index: 30;
  box-shadow: 0 12px 32px rgba(0,0,0,.45); padding: .3rem;
}
.nvs-tree-search-item { display: flex; align-items: center; gap: .55rem; width: 100%; text-align: left;
  background: transparent; border: 0; border-radius: 7px; padding: .4rem .5rem; color: var(--nvs-text); cursor: pointer; }
.nvs-tree-search-item:hover { background: var(--nvs-surface-3); }
.nvs-tree-search-item > i { color: var(--nvs-text-muted); width: 1rem; text-align: center; flex: 0 0 auto; }
.nvs-tree-search-item .s-name { font-weight: 600; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nvs-tree-search-item .s-meta { margin-left: auto; padding-left: .5rem; color: var(--nvs-text-muted); font-size: .74rem; white-space: nowrap; flex: 0 0 auto; }
.nvs-tree-search-note { padding: .5rem; color: var(--nvs-text-muted); font-size: .8rem; text-align: center; }

/* Flash a node when search jumps to it */
.nvs-tree-card.nvs-tree-hit { border-color: var(--nvs-primary); animation: nvs-tree-pulse 1.6s ease-out; }
@keyframes nvs-tree-pulse {
  0% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--nvs-primary) 55%, transparent); }
  100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--nvs-primary) 0%, transparent); }
}

/* ---- Mobile ---- */
@media (max-width: 992px) {
  .nvs-app { grid-template-columns: 1fr; }
  .nvs-sidebar {
    position: fixed; left: 0; top: 0; z-index: 1050; width: var(--nvs-sidebar-w);
    transform: translateX(-100%); transition: transform .2s;
  }
  .nvs-app.nvs-sidebar-open .nvs-sidebar { transform: translateX(0); }
  .nvs-backdrop { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 1040; }
  .nvs-app.nvs-sidebar-open .nvs-backdrop { display: block; }
}

/* --------------------------------------------------------------------------
   Detail-page tabs (.nvs-tabs) — one shareable URL per tab. See /styleguide.
   -------------------------------------------------------------------------- */
.nvs-tabs { border-bottom: 1px solid var(--nvs-border); gap: .25rem; }
.nvs-tabs .nav-link {
  color: var(--nvs-text-muted);
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: .5rem .9rem;
}
.nvs-tabs .nav-link:hover { color: var(--nvs-text); border-bottom-color: var(--nvs-surface-3); }
.nvs-tabs .nav-link.active {
  color: var(--nvs-text);
  background: transparent;
  border-bottom-color: var(--nvs-primary);
}

/* --------------------------------------------------------------------------
   Live indicator pill (.nvs-live-indicator) — a grey status pill with a white
   refresh icon and a label. Add .is-loading (nvs.js toggles it via
   [data-shaper-loading]) to spin the icon and turn the label blue while a
   background request is in flight. See /styleguide.
   -------------------------------------------------------------------------- */
.nvs-live-indicator { display: inline-flex; align-items: center; gap: .4em; }
.nvs-live-indicator i { color: #fff; }
.nvs-live-indicator.is-loading i { animation: nvs-spin .8s linear infinite; }
.nvs-live-indicator.is-loading .nvs-live-text { color: var(--nvs-primary); }
@keyframes nvs-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   Card spacing — stacked cards get a gap; cards inside a grid column rely on
   the row gutter instead (so spacing isn't doubled).
   -------------------------------------------------------------------------- */
.card { margin-bottom: 1rem; }
.row > [class*="col"] > .card { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Live utilization bar + inline SVG sparkline (shaper dashboard tree). Colors
   follow the same thresholds as elsewhere: >=50% orange, >=90% red.
   -------------------------------------------------------------------------- */
.nvs-util { height: 4px; margin-top: 3px; background: var(--nvs-surface-3); border-radius: 2px; overflow: hidden; }
.nvs-util-fill { height: 100%; width: 0; background: var(--nvs-primary); transition: width .4s ease; }
.nvs-util-fill.warn { background: #eda100; }
.nvs-util-fill.crit { background: #e34948; }
.nvs-hot-ok   { color: #48d09b; }
.nvs-hot-warn { color: #eda100; }
.nvs-hot-crit { color: #e34948; }
.nvs-spark { width: 90px; height: 24px; display: block; }

/* Read-only payload block (export JSON, generated keys). Scrolls on its own so
   a long payload never stretches the modal. */
.nvs-code {
  margin: 0;
  padding: .75rem 1rem;
  max-height: 55vh;
  overflow: auto;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--nvs-text);
  background: var(--nvs-surface-3);
  border: 1px solid var(--nvs-border);
  border-radius: var(--nvs-radius);
  white-space: pre;
  tab-size: 2;
}

/* Provenance marker (see the origin_mark macro): a single letter before a name,
   green for internal, blue for external. Deliberately quiet — it labels, it
   does not compete with the name. */
.nvs-origin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  margin-right: .4rem;
  border-radius: 50%;
  font-size: .6875rem;
  font-weight: 600;
  font-style: normal;
  line-height: 1;
  cursor: help;
  vertical-align: baseline;
}
.nvs-origin-internal { background: color-mix(in srgb, #2fb380 26%, transparent); color: #48d09b; }
.nvs-origin-external { background: color-mix(in srgb, var(--nvs-primary) 26%, transparent); color: var(--nvs-primary); }

/* Live rates on a tree card: a small two-line block on the right, and the card
   itself tinted by the worse of the two directions (see NVS.liveRows.setHot).
   The tint is a wash plus a left edge, so it reads at a glance without
   drowning the name. */
.nvs-tree-rates {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  flex: 0 0 auto;          /* never squeeze the name to fit the numbers */
  margin-left: auto;
  padding-left: .6rem;
  font-size: .6875rem;     /* deliberately small: a glance value, not a headline */
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  color: var(--nvs-text-muted);
}
.nvs-tree-rates > span {
  display: flex;
  align-items: center;
  gap: .25rem;
  white-space: nowrap;     /* "50.00 Mbps" must not break across two lines */
}
.nvs-tree-rates i { opacity: .5; font-size: .625rem; }

.nvs-tree-card.is-hot-warn {
  background: color-mix(in srgb, #eda100 14%, var(--nvs-surface-2));
  border-color: color-mix(in srgb, #eda100 45%, transparent);
}
.nvs-tree-card.is-hot-crit {
  background: color-mix(in srgb, #e34948 16%, var(--nvs-surface-2));
  border-color: color-mix(in srgb, #e34948 55%, transparent);
}
.nvs-tree-card.is-hot-warn .nvs-tree-rates,
.nvs-tree-card.is-hot-crit .nvs-tree-rates { color: var(--nvs-text); }
/* keep the hover cue on a tinted card */
.nvs-tree-card.is-hot-warn:hover,
.nvs-tree-card.is-hot-crit:hover { border-color: var(--nvs-primary); }
