/* NexoVirt app styles (loaded after Tabler). Keep small and additive.
 * NOTE: all brand/colour theming, including the baked-in component overrides
 * (pagination, nav-pills, list-group active, file input), lives in
 * theme-overwrite.css. This file is app-specific, non-colour component CSS only. */

/*
 * The `hidden` attribute always wins. Tabler's display utilities (`.d-flex`, `.d-inline`, ...) are
 * `!important` and come after the reboot's `[hidden]` rule, so `el.hidden = true` on an element with
 * such a class left it visible (a loading block that never went away, a Retry form that never hid).
 * This file loads after Tabler, so the same-specificity rule here takes precedence.
 */
[hidden] { display: none !important; }

/*
 * Icon-only action buttons.
 * This Tabler build's `.btn-icon .icon { margin: calc(-1 * padding-x) }` trick
 * cancels out the icon's width, collapsing the button to ~2px so the icons
 * overlap. Restore symmetric padding and a zero icon margin so the button
 * renders as a proper square sized to its icon (scales with .btn-sm via the
 * padding-y variable).
 */
.btn-icon {
  padding-left: var(--tblr-btn-padding-y);
  padding-right: var(--tblr-btn-padding-y);
}
.btn-icon .icon {
  margin: 0;
}

/*
 * Vertical sidebar background.
 * Tabler's navbar-vertical ships a fixed dark surface (its demo forces
 * data-bs-theme="dark" on the <aside>). We dropped that attribute so the sidebar
 * follows the active theme, and pin its background to the normal page bg var so it
 * matches the body in BOTH light and dark mode, separated only by a hairline border.
 */
.navbar-vertical {
  background-color: var(--tblr-body-bg);
  border-right: var(--tblr-border-width) solid var(--tblr-border-color);
}

#nx-toasts .nx-toast { box-shadow: 0 .5rem 1rem rgba(0,0,0,.18); opacity: 1; transition: opacity .2s ease; }
#nx-toasts .nx-toast.nx-toast-out { opacity: 0; }

/* Guest Network topology connectors: animated marching dashes (theme-var colours).
   flex:1 so the connectors grow and spread the Server/NIC/IP cards across the full card width. */
.gd-conn { flex:1 1 auto; min-width:40px; height:3px; align-self:center; border-radius:2px;
  background-image: repeating-linear-gradient(90deg, var(--gd-c) 0 7px, transparent 7px 15px);
  background-size: 15px 100%; animation: gd-march .6s linear infinite; }
.gd-conn-nic { --gd-c: var(--tblr-warning); }
.gd-conn-ip  { --gd-c: var(--tblr-success); }
@keyframes gd-march { to { background-position: 15px 0; } }
@media (prefers-reduced-motion: reduce) { .gd-conn { animation: none; } }

/* Hide the main page (document) scrollbar: scrolling itself still works (wheel / keys / touch /
   trackpad). Inner scroll areas (dropdowns, the xterm viewport, etc.) keep their own scrollbars. */
html { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar { display: none; }
/* Hide the sidebar's own scrollbar too (scroll still works): its gutter was offsetting the brand
   from centre, and it matches the clean no-scrollbar look. */
.navbar-vertical { scrollbar-width: none; }
.navbar-vertical::-webkit-scrollbar { display: none; }

/* Sidebar nav-link count badges (Guests "n/n", Alerts count, etc.).
   Tabler core positions ANY `.navbar .navbar-nav .nav-link .badge` ABSOLUTELY at the
   nav-link's top-right with `transform: translate(50%,-50%)`: that's for a notification
   DOT on a horizontal top-navbar icon. In our VERTICAL sidebar it mis-targets the inline
   `ms-auto` count badges: they get shoved half their width past the fixed 15rem edge and
   clipped (the hidden scrollbar means no reveal). Make them normal inline items again so
   `ms-auto` right-aligns them fully inside the sidebar. */
.navbar-vertical .navbar-nav .nav-link .badge {
  position: static;
  transform: none;
  top: auto;
  right: auto;
}

/* Split.js gutters: resizable panes (Settings → Email → Templates). Flex-basis mode. */
.gutter { background-color: var(--tblr-border-color); background-clip: padding-box; flex-shrink: 0; }
.gutter.gutter-horizontal { cursor: col-resize; }

/* Resizable HTML body editor (Settings → Email → Templates): drag the bottom-right grip. */
#et-pane-editor .CodeMirror { resize: vertical; overflow: hidden; min-height: 12rem; }

/* 2FA OTP single-digit boxes. */
.tfa-digit { width: 3rem; padding-inline: 0; text-align: center; font-size: 1.5rem; font-weight: 600; }

/* NexoVirt logo (partials/logo.php): the whole mark follows the theme body colour (monochrome,
   as on the marketing site). A white-label custom logo is object-fit:contain so it
   never stretches to fill its box, capped at max-width:100%/max-height so a tall or square upload
   can't bleed past the sidebar/navbar/login-card edges (the .navbar-brand py-3 ps-2 padding on the
   sidebar/navbar wrapper gives it breathing room). */
.nx-logo { color: var(--tblr-body-color); display: block; object-fit: contain; max-width: 100%; max-height: 100%; }

/* OS group picker: logo-only borderless tiles (no card box). The logos are transparent
   SVGs, contain-fit so they aren't cropped; selection is a thin primary border + hover tint. */
.os-logo { height: 64px; width: auto; max-width: 100%; object-fit: contain; }
.os-logo-lg { height: 88px; }
.os-logo-sm { height: 36px; }
.js-os-card { display: block; padding: .75rem; border: 2px solid transparent;
  border-radius: var(--tblr-border-radius); cursor: pointer; }
.js-os-card:hover { background: var(--tblr-active-bg, rgba(0, 0, 0, .03)); }
/* Selected tile: a theme-aware tint + ring so it reads in BOTH light and dark (the brand --tblr-primary
   is near-white, so a border alone is invisible on light backgrounds). */
.js-os-card.active { border-color: var(--tblr-primary); background: var(--tblr-active-bg, rgba(0, 0, 0, .06)); box-shadow: inset 0 0 0 1px var(--tblr-border-color); }

/* Error-detail viewer (#nx-detail): readable, wrapping, scrollable message block. */
.nx-detail-pre { white-space: pre-wrap; word-break: break-word; max-height: 60vh; overflow: auto; }

/* Empty-state illustrations: constrain size. The bundled Tabler illustrations carry an intrinsic
   800×600 and Tabler's `.empty-img img { height:auto }` ignores the height attr, so they render
   huge; cap them (documented illustration-sizing quirk, same family as the .auth-illustration
   constraint). Applies to both the inlined SVG (.empty blocks) and the <img> (NexoTable empties). */
.empty-img svg, .empty-img img { max-height: 8rem; width: auto; height: auto; }

/* Alert icons: GLOBAL spacing fix. This Tabler build's `.alert-icon` only sets size/colour, no
   inline-end margin, so every alert-with-icon had to remember `me-2` and several were missed → the
   icon touched the heading (e.g. "Datacenter firewall is disabled"). Space them once, globally.
   Idempotent with an explicit `me-2` (both resolve to .5rem, so no double gap); works whether the
   icon is a direct flex child or wrapped in a <div>. Documented quirk-fix, same family as .btn-icon. */
.alert-icon { margin-inline-end: .5rem; }

/* ApexCharts dark-mode legibility: GLOBAL. ApexCharts bakes a hard-coded dark-grey foreColor into
   legend text and renders a light tooltip that don't follow the Tabler theme, so in dark mode the
   legend (e.g. "Down / Up") is near-black-on-black and the crosshair tooltip is light-on-dark. The
   window.Apex global default is unreliable once a chart sets its own legend/tooltip object, so we pin
   it in CSS (theme-reactive via --tblr-* vars, beats ApexCharts' inline styles, survives live theme
   toggle). Legend text follows the body colour in BOTH modes; the tooltip gets theme-surface colours
   in dark mode. Documented quirk-fix (same family as the .alert-icon / .btn-icon fixes above). */
.apexcharts-legend-text { color: var(--tblr-body-color) !important; }
/* radialBar centre value (node gauges): its SVG fill is set once at render from the theme, but a
   live theme toggle does NOT re-render ApexCharts, so a chart first drawn in dark keeps its light
   fill and vanishes in light mode. Force the fill from the live --tblr-* var so it re-themes with
   the page in both directions. Same quirk-fix family as .apexcharts-legend-text above. */
.apexcharts-datalabel-value { fill: var(--tblr-body-color) !important; }
[data-bs-theme="dark"] .apexcharts-tooltip {
  background: var(--tblr-bg-surface, #1a2234) !important;
  color: var(--tblr-body-color) !important;
  border-color: var(--tblr-border-color) !important;
  box-shadow: none !important;
}
[data-bs-theme="dark"] .apexcharts-tooltip-title {
  background: var(--tblr-bg-surface-secondary, #16202f) !important;
  border-bottom-color: var(--tblr-border-color) !important;
  color: var(--tblr-body-color) !important;
}
[data-bs-theme="dark"] .apexcharts-xaxistooltip,
[data-bs-theme="dark"] .apexcharts-yaxistooltip {
  background: var(--tblr-bg-surface, #1a2234) !important;
  color: var(--tblr-body-color) !important;
  border-color: var(--tblr-border-color) !important;
}
[data-bs-theme="dark"] .apexcharts-xaxistooltip-bottom:before { border-bottom-color: var(--tblr-border-color) !important; }
[data-bs-theme="dark"] .apexcharts-xaxistooltip-bottom:after  { border-bottom-color: var(--tblr-bg-surface, #1a2234) !important; }

/* OS / CT group picker cards (create + reinstall). Selectable bordered cards; the active one gets a
   primary-coloured border + ring. Requested explicitly; lives here with the other --tblr-* styling. */
.gd-os-card { cursor: pointer; transition: border-color .12s ease, box-shadow .12s ease; }
.gd-os-card:hover { border-color: var(--tblr-primary); }
.gd-os-card.active { border-color: var(--tblr-primary); box-shadow: 0 0 0 1px var(--tblr-primary); }

/* Compact OS tiles (create/reinstall picker): small logo + tight body; a multi-version group's
   version dropdown only appears on the ACTIVE tile, so idle tiles stay small (logo + name). */
.os-logo-tile { height: 34px; }
.gd-os-tile .card-body { min-height: 82px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.gd-os-sublabel { font-size: .72rem; line-height: 1.2; }

/* Steps indicator: drop the leading margin/padding/border so the stepper sits flush.
   Requested explicitly. */
.steps {
  margin-left: 0 !important;
  padding-left: 0 !important;
  border-left: 0 !important;
}

/* Settings → Branding → Colors: mini-panel live preview (sidebar mock). Requested explicitly;
   the content area reads --tblr-* vars directly via inline style, only the sidebar chrome
   (no Tabler equivalent for a mini nav rail) needs a rule here. */
.brand-preview-sidebar {
  width: 110px;
  flex: 0 0 110px;
  background: var(--tblr-bg-surface);
  border-right: 1px solid var(--tblr-border-color);
}
.brand-preview-nav-link {
  display: block;
  padding: 4px 8px;
  margin-bottom: 2px;
  border-radius: 4px;
  font-size: .7rem;
  color: var(--tblr-body-color);
  text-decoration: none;
  opacity: .7;
}
.brand-preview-nav-link.active {
  background: var(--tblr-primary);
  color: var(--tblr-primary-fg, #fff);
  opacity: 1;
}

.brand-thumb { max-height: 36px; width: auto; }

/* Dashboard KPI cards: label, big number, sublabel, and a plain outline icon top-right. */
.nx-kpi .card-body { position: relative; padding-right: 4.5rem; }
a.nx-kpi { color: var(--tblr-body-color); text-decoration: none; }
a.nx-kpi:hover .nx-kpi-label { color: var(--tblr-primary); }
.nx-kpi-label { font-size: .875rem; font-weight: 500; color: var(--tblr-secondary); }
.nx-kpi-value { font-size: 2rem; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; font-variant-numeric: tabular-nums; margin-top: .25rem; }
.nx-kpi-of { font-size: 1.25rem; font-weight: 600; color: var(--tblr-secondary); }
.nx-kpi-sub { font-size: .8125rem; color: var(--tblr-secondary); margin-top: .125rem; }
.nx-kpi-sub.text-danger { color: var(--tblr-danger); }
.nx-kpi-icon { position: absolute; top: 1.25rem; right: 1.25rem; width: 2rem; height: 2rem; color: var(--tblr-secondary); opacity: .55; }

/* Dashboard host cards: nodes as compact link chips (status dot + name). */
.nx-chip { display: inline-flex; align-items: center; gap: .375rem; padding: .125rem .625rem; font-size: .8125rem;
  border: var(--tblr-border-width, 1px) solid var(--tblr-border-color); border-radius: 999px; color: var(--tblr-body-color); text-decoration: none; }
.nx-chip:hover { border-color: var(--tblr-primary); color: var(--tblr-primary); text-decoration: none; }
.nx-chip-more { color: var(--tblr-secondary); }
/* Host cards share the row: 1 = full width, 2 = halves, 3 = thirds, never more than 3 per row; a
   shorter last row stretches to fill it. Exactly 4 hosts go 2 + 2 instead of 3 + 1. Mobile: 1 per row. */
.nx-hosts { --nx-hosts-gap: 1rem; display: flex; flex-wrap: wrap; gap: var(--nx-hosts-gap); }
.nx-host { flex: 1 1 100%; min-width: 0; }
@media (min-width: 992px) {
  .nx-host { flex-basis: calc((100% - 2 * var(--nx-hosts-gap)) / 3); }
  .nx-hosts:has(> .nx-host:nth-child(4):last-child) > .nx-host { flex-basis: calc((100% - var(--nx-hosts-gap)) / 2); }
}
/* Host network line: the summed node up/down rates. */
.nx-net { display: flex; flex-wrap: wrap; align-items: center; column-gap: 1rem; font-size: .8125rem; font-variant-numeric: tabular-nums; }
.nx-net .icon { width: 1rem; height: 1rem; margin-right: .125rem; vertical-align: -.125em; }

/* Dashboard usage bars (host aggregates): label, slim bar, percentage. */
.nx-usage { display: flex; align-items: center; gap: .5rem; flex: 1 1 9rem; min-width: 8rem; }
.nx-usage-label { width: 2.25rem; font-size: .8125rem; color: var(--tblr-secondary); }
.nx-usage-bar { flex: 1 1 auto; min-width: 3rem; }
.nx-usage-pct { width: 2.5rem; text-align: right; font-size: .8125rem; font-variant-numeric: tabular-nums; }

/* Nodes list: compact usage bar inside a table cell. */
.nx-usage.nx-usage-sm { flex: none; min-width: 0; }
.nx-usage-sm .nx-usage-bar { flex: none; width: 3.5rem; min-width: 0; }

/* Node page Info KPI: network up/down on one row under the uptime; the status badge sits top-right. */
.nx-node-net { display: flex; flex-wrap: wrap; column-gap: 1rem; row-gap: .125rem; margin-top: .5rem; white-space: nowrap; }
.nx-node-net > span { display: inline-flex; align-items: center; gap: .25rem; }
.nx-node-net .icon { width: 1rem; height: 1rem; }
.nx-node-net-val { font-weight: 600; font-variant-numeric: tabular-nums; }
.nx-kpi-badge { position: absolute; top: 1.25rem; right: 1.25rem; }
/* A vendor logo in the KPI icon slot: wordmarks are wide, so size by width. */
.nx-kpi-icon.nx-kpi-logo { width: 3rem; height: 2rem; opacity: 1; }

/* Node page tabs: a section title inside a tab (instead of a ruled hr-text divider). */
.nx-tab-section { margin: 1.5rem 0 .75rem; font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--tblr-secondary); }
/* A tab whose only content is a NexoTable sits flush in the tab card (no inset table frame). */
.card > .card-body:has(> .tab-content > .tab-pane.active > [data-nexo-table]:only-child) { padding: 0; }
/* KPI card progress bar spans the full card width, under the icon column too. */
.nx-kpi .progress { width: auto; margin-right: -3.25rem; }
.nx-kpi-value { white-space: nowrap; }
.nx-asof { font-size: .8125rem; letter-spacing: 0; }

/* CPU vendor logos (Simple Icons, monochrome via currentColor). */
.nx-cpu-logo-sm { width: 1.25rem; height: 1.25rem; flex-shrink: 0; color: var(--tblr-body-color); }
.nx-cpu-logo-xs { width: 1.375rem; height: 1.375rem; flex-shrink: 0; vertical-align: -.125em; margin-right: .375rem; color: var(--tblr-secondary); }

/* Overview Status card: CPU row, load meter, platform fact tiles (grouped by proximity). */
.nx-status-cpu { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem; }
.nx-status-cpu-logo { flex-shrink: 0; width: 4.5rem; display: flex; justify-content: center; }
.nx-cpu-logo-lg { width: 4.5rem; height: 2.5rem; }
.nx-status-label { font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--tblr-secondary); }
.nx-status-load { margin-bottom: 1.5rem; }
.nx-load-row { display: flex; align-items: center; gap: .75rem; margin-bottom: .375rem; }
.nx-load-lbl { width: 3.5rem; white-space: nowrap; font-size: .8125rem; color: var(--tblr-secondary); }
.nx-load-val { width: 3rem; text-align: right; font-size: .8125rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.nx-status-facts { display: flex; flex-wrap: wrap; gap: .75rem; }
/* Tiles grow to share the full row, whatever their count (wraps when narrow). */
.nx-status-facts > .nx-fact { flex: 1 1 9.5rem; }
.nx-fact { display: flex; align-items: flex-start; gap: .625rem; padding: .625rem .75rem; border: var(--tblr-border-width, 1px) solid var(--tblr-border-color); border-radius: var(--tblr-border-radius); }
.nx-fact-icon .icon { width: 1.25rem; height: 1.25rem; margin-top: .125rem; }
.nx-fact-value { font-weight: 600; }
.min-w-0 { min-width: 0; }
/* Copyable fact tile (DynDNS name): a real button, reset to look like the other tiles. */
button.nx-fact { text-align: left; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.nx-fact-copy:hover { border-color: var(--tblr-primary); }
.nx-fact-copy:focus-visible { outline: 2px solid var(--tblr-primary); outline-offset: 2px; }

/* Node page Network services tiles: a big plain icon (no plate), title, state, one line, action. */
.nx-svc-icon { width: 2rem; height: 2rem; flex-shrink: 0; color: var(--tblr-body-color); }
/* Six tiles: 3 + 3 on desktops, 2 per row on tablets, 1 on phones. Equal heights per row. */
.nx-svc-row { --nx-svc-gap: .75rem; display: flex; flex-wrap: wrap; gap: var(--nx-svc-gap); }
.nx-svc-col { flex: 1 1 100%; min-width: 0; }
@media (min-width: 576px)  { .nx-svc-col { flex-basis: calc((100% - var(--nx-svc-gap)) / 2); } }
@media (min-width: 992px)  { .nx-svc-col { flex-basis: calc((100% - 2 * var(--nx-svc-gap)) / 3); } }
.nx-svc .card-body { padding: 1rem; }
.nx-svc-title { font-size: .9375rem; }
.nx-svc-state { font-size: .8125rem; font-weight: 600; }

/* Top bar: when the page actions need the room, they wrap under the title instead of squeezing it. */
.page-wrapper > .page-header .row > .col { min-width: 14rem; }
