@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600&display=swap');

:root {
  --bg: #0b0f12;
  --surface: #12181c;
  --surface-2: #161d22;
  --border: #2d3941;
  --text: #e7ecee;
  --text-dim: #8a98a0;
  --text-faint: #74828c;
  --ok: #4ade9c;
  --warn: #f0b862;
  --crit: #e8543d;
  /* Lightened from the original #1c252b -- reported live (real screenshot,
     not a tight crop) as blending into --surface/--bg, both already
     near-black, the same "too dark to register on a dark background"
     problem --card-shadow hit above. Light theme's --track (below) was
     never reported as a problem and is unchanged. */
  --track: #313e47;
  /* A *dark* offset shadow (the original approach here) turned out to
     read as basically invisible in real full-page context -- confirmed by
     the user's own screenshot, not just theory -- since --surface and --bg
     are both already near-black, so going darker still barely registers.
     A light-colored glow works the opposite, more effective direction on
     a dark theme: still offset toward the bottom-right (same directional
     language as the light theme's shadow below, not a symmetric ambient
     halo), just brightening that edge instead of darkening it. */
  --card-shadow: 2px 2px 14px rgba(255, 255, 255, 0.12);
  /* Reuses --text-dim (same tone drawGauge already uses for the needle)
     rather than its own hex: the tick marks need real contrast against
     --surface to read as more than a dark smudge -- the original #4d5c66
     measured ~2.84:1 against this theme's --surface, under WCAG's 3:1
     floor for UI graphics. --text-dim measures ~4.5:1 here. */
  --tick: var(--text-dim);
  --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;
  --sans: 'Inter', system-ui, -apple-system, sans-serif;

  /* Zabbix's own severity palette -- fixed across both themes, same as
     Zabbix's frontend uses one severity color scheme regardless of theme. */
  --sev-0: #97aab3;
  --sev-1: #7499ff;
  --sev-2: #ffc859;
  --sev-3: #ffa059;
  --sev-4: #e97659;
  --sev-5: #e45959;
}

:root[data-theme="light"] {
  --bg: #f5f7f8;
  --surface: #ffffff;
  --surface-2: #eef1f3;
  --border: #dbe1e5;
  --text: #182126;
  --text-dim: #5b6a72;
  --text-faint: #8b979e;
  --ok: #1f9d63;
  --warn: #c88526;
  --crit: #c93f2c;
  --track: #e4e9ec;
  /* Lighter alpha than the dark theme's --card-shadow -- a white --surface
     against a light --bg already reads clearly on its own, so this only
     needs to be a soft hint, not real contrast. */
  --card-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
  /* Same reasoning as the dark theme's --tick above -- the original
     #c3ccd2 measured an even lower ~1.24:1 against this theme's white
     --surface (~2.3:1 with --text-dim; still not great, but the same tone
     the needle already uses at that same ratio without complaint). */
  --tick: var(--text-dim);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: 32px 24px 64px;
}
/* Wider than .wrap's default -- the admin links table (readonly link box +
   copy/revoke/delete buttons per row) needs the extra room to lay out
   without a horizontal scrollbar. Only used on /admin; the client-facing
   dashboard keeps the narrower default. */
.wrap-admin {
  max-width: 1320px;
}

/* ---------- header ---------- */

.head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 32px;
  margin-bottom: 28px;
  border-bottom: 1px solid var(--border);
}

/* Dashboard page only: title pinned to the left edge, theme toggle/live
   indicator pinned to the right, logo centered across the full header
   width -- a symmetric 3-column grid (1fr auto 1fr) rather than absolute
   positioning, so every piece stays in normal flow. That means padding
   and vertical centering apply the same way they do everywhere else in
   this stylesheet, instead of needing separate math for pieces that were
   taken out of flow. */
.head.head-centered {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}
.head.head-centered .head-title {
  grid-row: 1;
  grid-column: 1;
  justify-self: start;
}
.head.head-centered .brand-logo-link {
  grid-row: 1;
  grid-column: 2;
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

/* Dashboard page only: logo+wordmark pinned to the left edge instead of
   centered, hostname centered in the gap between the logo and the Dark
   mode/live controls -- overrides the admin page's default grid
   arrangement (title left / logo centered) above, without changing
   admin's markup or layout. This uses plain flexbox with
   justify-content:space-between (DOM order is logo, title, actions)
   rather than the grid -- grid's "1fr auto 1fr" ought to center the
   middle item the same way in theory, but did not in practice here, so
   this switches to the simpler, well-tested pattern instead. */
.head.head-dashboard {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* "Radar Telemetry" wordmark suffix next to the FireVM logo -- the logo
   image itself is a fixed monochrome asset (see .brand-logo), so this text
   is how the product name gets the brand accent color instead of needing a
   second logo asset. */
.brand-suffix {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 26px;
  color: var(--text);
  white-space: nowrap;
  text-decoration: none;
}
.head.head-centered .head-actions {
  grid-row: 1;
  grid-column: 3;
  justify-self: end;
}

.brand-logo {
  height: 46px;
  width: auto;
  display: block;
}
/* The source artwork is solid black on a transparent background, so invert
   it in dark mode rather than hosting a second asset. */
:root[data-theme="dark"] .brand-logo {
  filter: invert(1);
}

.head .eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 6px;
}

.head h1 {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 22px;
  margin: 0;
  color: var(--text);
}

.head .status {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 8px var(--ok);
}

.dot.warn {
  background: var(--warn);
  box-shadow: 0 0 8px var(--warn);
}

/* ---------- grid ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}

/* Fixed 3-across layout for System Performance, so its six cards land as
   two clean rows of three instead of wherever auto-fit happens to wrap. */
.grid.grid-3 {
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 700px) {
  .grid.grid-3 {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  }
}

/* Fixed 2-across layout for the MySQL/PostgreSQL database cards -- each one
   is wide (holds a top-5 table), so auto-fit's 220px minimum would still
   often stack them; this keeps them side by side down to a narrower width. */
.grid.grid-2 {
  grid-template-columns: repeat(2, 1fr);
}
@media (max-width: 700px) {
  .grid.grid-2 {
    grid-template-columns: 1fr;
  }
}

.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  box-shadow: var(--card-shadow);
}

.card.clickable {
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.card.clickable:hover,
.card.clickable:focus-visible {
  border-color: var(--ok);
  transform: translateY(-1px);
  outline: none;
}

/* Shown in place of a .card while its first real fetch is still in
   flight (see the shared-hosting dashboard's initial load -- the page
   now renders immediately rather than blocking on several SSH round
   trips, so there's a real gap to fill here). Same rounded-corner/height
   footprint as a real .no-gauge card, so nothing jumps when the real
   tiles swap in.
   Deliberately does NOT respect prefers-reduced-motion: this sweep is the
   one piece of evidence the page hasn't frozen while several SSH calls
   are in flight -- turning it off would remove the only signal, not just
   a decorative flourish. It's also a slow, single-direction linear sweep
   (no flashing/spinning/zooming), about as gentle as a loading indicator
   gets. --border (not --surface-2) is the highlight stop: --surface vs
   --surface-2 alone are too close in luminance in both themes to read as
   a moving band, especially dark mode (#12181c vs #161d22). */
@keyframes skeleton-shimmer {
  0% { background-position: 150% 0; }
  100% { background-position: -50% 0; }
}
.skeleton-card {
  min-height: 92px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background-image: linear-gradient(
    100deg,
    var(--surface-2) 35%,
    var(--border) 50%,
    var(--surface-2) 65%
  );
  background-size: 250% 100%;
  animation: skeleton-shimmer 1.6s linear infinite;
}

/* Same shimmer, no border/radius of its own -- for use inside an
   already-bordered container (.process-card below) rather than as its
   own standalone tile. */
.skeleton-bar {
  min-height: 60px;
  border-radius: 6px;
  background-image: linear-gradient(
    100deg,
    var(--surface-2) 35%,
    var(--border) 50%,
    var(--surface-2) 65%
  );
  background-size: 250% 100%;
  animation: skeleton-shimmer 1.6s linear infinite;
}

/* Full-width bordered box for the Processes section (unlock form, loading
   shimmer, or the process table itself) -- same visual language as a
   .card tile, just not part of the .grid layout since it's one wide
   section rather than several tiles side by side. */
.process-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  margin-top: 12px;
  box-shadow: var(--card-shadow);
}

/* Same shimmer as .skeleton-card, pill-shaped -- for a .badge-row's
   loading state (System Availability, Network status). */
.skeleton-badge {
  width: 130px;
  height: 33px;
  border-radius: 999px;
  background-image: linear-gradient(
    100deg,
    var(--surface-2) 35%,
    var(--border) 50%,
    var(--surface-2) 65%
  );
  background-size: 250% 100%;
  animation: skeleton-shimmer 1.6s linear infinite;
}

.card-graph-hint {
  position: absolute;
  top: 14px;
  right: 14px;
  display: flex;
  color: var(--text-faint);
  opacity: 0.7;
}
.card.clickable:hover .card-graph-hint,
.card.clickable:focus-visible .card-graph-hint {
  color: var(--ok);
  opacity: 1;
}

.card .label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 12px;
}

.card canvas.gauge {
  display: block;
  margin: 0 auto;
}

.card .value {
  text-align: center;
  font-family: var(--mono);
  font-size: 28px;
  font-weight: 500;
  margin-top: -8px;
}

.card.no-gauge .value {
  margin-top: 4px;
}

.card-centered-value {
  display: flex;
  flex-direction: column;
}

.card-centered-value .value {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 0;
}

.card .value .unit {
  font-size: 14px;
  color: var(--text-dim);
  font-weight: 400;
}

.card .value.ok { color: var(--ok); }
.card .value.warn { color: var(--warn); }
.card .value.crit { color: var(--crit); }

.card .metric-detail {
  text-align: center;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
  margin: 4px 0 0;
}

/* Databases section (MySQL/PostgreSQL cards) -- these hold several stat
   items, so they're left-aligned rather than following the centered
   gauge/stat-card layout above. */
.db-card {
  text-align: left;
}
.db-card .metric-detail {
  text-align: left;
  margin: 12px 0 0;
}
/* 3 columns, not one-per-item: with 5 stat items this naturally wraps into
   3 on top + 2 below (CSS grid auto-flow), rather than needing a 5-column
   row that's too narrow for values like "1 of ∞" to stay on one line. */
.db-stat-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-top: 12px;
}
.db-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.db-stat-value {
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 500;
}
.db-stat-value.crit {
  color: var(--crit);
}
.db-stat-label {
  font-size: 11px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
@media (max-width: 500px) {
  .db-stat-row {
    grid-template-columns: repeat(2, 1fr);
  }
}

canvas.spark {
  display: block;
  width: 100%;
  height: 36px;
  margin-top: 10px;
}

/* ---------- section headers ---------- */

.section-title {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 32px 0 12px;
}

.problems-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 32px;
}
.problems-header-left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 10px;
}
.problems-header-sep {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-faint);
}
.email-status {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 400;
  color: var(--text-dim);
}
.email-status a {
  color: inherit;
  text-decoration: underline;
}

/* ---------- status badges ---------- */

.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}

.status-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 14px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
}

.status-badge .name { color: var(--text); }
.status-badge .temp { color: var(--text-faint); }

.pill {
  width: 7px;
  height: 7px;
  border-radius: 50%;
}
.pill.ok { background: var(--ok); }
.pill.warn { background: var(--warn); }
.pill.crit { background: var(--crit); }

.empty {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-faint);
  padding: 12px 0;
}

.list-count {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-faint);
  margin-top: 10px;
}

/* ---------- problems ---------- */

.problem-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Only takes effect inside the resolved-problems modal, where this sits
     in a fixed-height flex column below the header/range-picker and needs
     to be the thing that actually scrolls (see the .modal comment above).
     On the live dashboard page it's an unconstrained block, so flex/
     min-height/overflow are all no-ops there. */
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.problem-item {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: 8px;
  padding: 12px 16px;
}
.problem-item.sev-0 { border-left-color: var(--sev-0); }
.problem-item.sev-1 { border-left-color: var(--sev-1); }
.problem-item.sev-2 { border-left-color: var(--sev-2); }
.problem-item.sev-3 { border-left-color: var(--sev-3); }
.problem-item.sev-4 { border-left-color: var(--sev-4); }
.problem-item.sev-5 { border-left-color: var(--sev-5); }

/* Resolved-history rows need more fields (start/recovery/duration) than
   the active-problems row, so they stack as two lines instead of one. */
.problem-item.problem-item-resolved {
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.problem-resolved-main {
  display: flex;
  align-items: center;
  gap: 10px;
}
.problem-resolved-meta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-faint);
}

.problem-name {
  flex: 1;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text);
}

.problem-duration {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-faint);
  white-space: nowrap;
}

.severity-pill {
  display: inline-block;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 3px 9px;
  border-radius: 999px;
  color: #1a1a1a;
  white-space: nowrap;
  flex-shrink: 0;
}
.severity-pill.sev-0 { background: var(--sev-0); }
.severity-pill.sev-1 { background: var(--sev-1); color: #fff; }
.severity-pill.sev-2 { background: var(--sev-2); }
.severity-pill.sev-3 { background: var(--sev-3); }
.severity-pill.sev-4 { background: var(--sev-4); }
.severity-pill.sev-5 { background: var(--sev-5); color: #fff; }

.problems-empty {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  color: var(--ok);
  font-family: var(--mono);
  font-size: 14px;
}
.problems-empty svg { flex-shrink: 0; }

.foot {
  margin-top: 48px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-faint);
  text-align: center;
}

/* ---------- admin ---------- */

.admin-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 13px;
}
.admin-table th, .admin-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  overflow-wrap: break-word;
}
/* table-layout: fixed makes these percentages the actual column widths,
   instead of auto-layout's default of growing each column to fit its
   widest cell -- which is what let the table quietly outgrow its 100%
   container (and the page's right edge) as columns were added over time.
   Sums to 100%. */
.admin-table th:nth-child(1), .admin-table td:nth-child(1) { width: 6%; }
.admin-table th:nth-child(2), .admin-table td:nth-child(2) { width: 20%; }
.admin-table th:nth-child(3), .admin-table td:nth-child(3) { width: 14%; }
.admin-table th:nth-child(4), .admin-table td:nth-child(4) { width: 10%; }
.admin-table th:nth-child(5), .admin-table td:nth-child(5) { width: 50%; }
/* table-layout: fixed derives column widths from the header row only, so
   the detail row's single colspan="5" cell just spans those five tracks --
   its own width doesn't need (and shouldn't get) a nth-child rule. */
.admin-table th {
  color: var(--text-faint);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.btn {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  background: var(--ok);
  color: #06120c;
  border: none;
  border-radius: 6px;
  padding: 8px 14px;
  cursor: pointer;
}
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn.secondary {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
}
.btn.danger {
  background: transparent;
  color: var(--crit);
  border: 1px solid var(--crit);
}

/* Full pill radius so longer-text buttons (e.g. "View Plesk Shared
   Accounts...") still read unmistakably as a button rather than a
   readonly input box -- the standard 6px .btn radius gets visually lost
   on a wide, short box. */
.btn-pill {
  border-radius: 999px;
  padding: 8px 18px;
}

.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
}
.btn-icon:hover {
  color: var(--ok);
  border-color: var(--ok);
}

.info-popover-wrap {
  position: relative;
  display: inline-flex;
}
.info-popover {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 100;
  width: 300px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.5;
}
.info-popover[hidden] { display: none; }

/* Requests/Distinct Source IPs consolidated card (public/shared-dashboard.js's
   renderTrafficSection) -- a literal circle with a "?" (not the admin
   panel's "i" INFO_ICON_SVG, which is a different glyph) since that's what
   was actually asked for. Its explanation opens in the same
   .modal-backdrop/.modal dialog the history-graph popup already uses
   (ensureInfoModal in shared-dashboard.js) rather than a relative-
   positioned popover -- a popover anchored to the button ran off-screen
   whenever the button was near a viewport edge (confirmed live, reported
   with a screenshot); a centered modal has no positioning math to get
   wrong, at the cost of not visually pointing at the button that opened
   it -- an explicit tradeoff, not an oversight (the user's own suggestion
   when reporting the positioning bug). */
.traffic-stats-card {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  gap: 16px;
}
.traffic-stat-item {
  text-align: center;
}
.traffic-stat-item .value {
  /* The base .card .value rule's negative margin-top is there to pull the
     value up closer to a gauge canvas above it (see makeGaugeCard) -- this
     card has no gauge, so that would just look cramped against the label
     above; same fix already used for statCard's own no-gauge variant. */
  margin-top: 4px;
}
.traffic-stat-item .label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.traffic-stat-divider {
  width: 100%;
  border: none;
  border-top: 1px solid var(--border);
  margin: 0;
}
.info-btn {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--text-faint);
  background: none;
  color: var(--text-faint);
  font-family: var(--sans);
  font-size: 10px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  vertical-align: middle;
}
.info-btn:hover {
  color: var(--text);
  border-color: var(--text-dim);
}
/* Compact, auto-height variant of the shared .modal for a couple of
   sentences of explanation -- the base .modal's 60vw/60vh sizing is meant
   for the history-graph chart, way oversized for this. */
.modal.modal-info {
  width: 90vw;
  max-width: 420px;
  height: auto;
  min-height: 0;
  max-height: 85vh;
}
.modal-info-body {
  margin: 0;
  color: var(--text-dim);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
}
.modal-info-body p {
  margin: 0 0 12px;
}
.modal-info-body p:last-child {
  margin-bottom: 0;
}
.modal-info-body strong {
  color: var(--text);
}

.label-form {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
}

.settings-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 28px;
}
.settings-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.settings-label {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
  width: 190px;
  flex-shrink: 0;
}
.settings-control {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0;
}

.admin-notice {
  padding: 10px 14px;
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 13px;
  margin-bottom: 20px;
}
.admin-notice-ok {
  background: rgba(74, 222, 156, 0.12);
  color: var(--ok);
  border: 1px solid var(--ok);
}
.admin-notice-error {
  background: rgba(232, 84, 61, 0.12);
  color: var(--crit);
  border: 1px solid var(--crit);
}

.email-cell {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.email-cell .label-form {
  flex: 1;
  min-width: 0;
}
.email-cell form[action*="test-mail"] {
  flex-shrink: 0;
}

.views-cell {
  display: flex;
  align-items: center;
  gap: 8px;
}
.views-cell .btn-icon {
  width: 22px;
  height: 22px;
}

.link-toggle-cell {
  text-align: center;
}
.link-detail-toggle svg {
  transition: transform 0.15s;
}
.link-detail-toggle[aria-expanded="true"] svg {
  transform: rotate(90deg);
}

.link-detail-row td {
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.reseller-group-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
}
.reseller-toggle svg {
  transition: transform 0.15s;
}
.reseller-toggle[aria-expanded="true"] svg {
  transform: rotate(90deg);
}
.link-detail {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 10px 4px;
}
.link-detail-fields {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 24px;
  flex-wrap: wrap;
}
.link-detail-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ssh-port-inline {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 8px;
}

/* ---------- Plesk shared/reseller accounts listing ---------- */

.accounts-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 13px;
}
.accounts-table th, .accounts-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}
.accounts-table th {
  color: var(--text-faint);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.code-block-wrap {
  position: relative;
}
.code-block {
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.6;
  background: var(--track);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 14px 16px;
  border-radius: 8px;
  overflow-x: auto;
  white-space: pre;
  margin: 0;
}
.code-block-wrap .btn.secondary {
  position: absolute;
  top: 10px;
  right: 10px;
}
.link-detail-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  flex: 1 1 160px;
  min-width: 0;
}
.link-detail-item-wide {
  flex: 2 1 340px;
}
.link-detail-item-narrow {
  flex: 0 0 auto;
}
.link-detail-item > .label-form,
.link-detail-item > .linkbox,
.link-detail-item > .views-cell {
  width: 100%;
  min-width: 0;
}
.link-detail-label {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.sort-header {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.sort-header:hover { color: var(--text); }
.sort-header svg { opacity: 0.6; flex-shrink: 0; }
.sort-header:hover svg, .sort-header.sort-active svg { opacity: 1; }
.sort-header.sort-active { color: var(--text); }
.sort-header.sort-desc svg { transform: rotate(180deg); }
.label-form input {
  font-family: var(--sans);
  font-size: 13px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 10px;
  border-radius: 6px;
  width: 100%;
  min-width: 0;
}

.linkbox {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
}
.linkbox > button, .linkbox > form {
  flex-shrink: 0;
}
.linkbox input {
  font-family: var(--mono);
  font-size: 12px;
  background: var(--track);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 6px 10px;
  border-radius: 6px;
  width: 100%;
  min-width: 0;
  flex: 1;
}

select, .field {
  font-family: var(--sans);
  font-size: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 8px 12px;
  border-radius: 6px;
}

.exclusions-form {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.exclusions-textarea {
  width: 100%;
  flex: 1;
  min-height: 120px;
  font-family: var(--mono);
  font-size: 13px;
  resize: vertical;
}

.field-error {
  border-color: var(--crit) !important;
}

/* ---------- host search combobox ---------- */

.combobox {
  position: relative;
  width: 240px;
}
.combobox .field {
  width: 100%;
}

.combobox-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  z-index: 10;
}
.combobox-list[hidden] { display: none; }

.combobox-option {
  padding: 8px 12px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.combobox-option:hover,
.combobox-option.active {
  background: var(--surface-2);
  color: var(--ok);
}

.toplink { color: var(--text-dim); text-decoration: none; font-family: var(--mono); font-size: 12px; }
.toplink:hover { color: var(--text); }
button.toplink { background: none; border: none; padding: 0; cursor: pointer; }

/* "View process list" specifically -- not every .toplink (sign out, Back
   to admin, etc. stay plain) -- underlined so it visibly reads as a link
   next to the plain "PROCESSES" label beside it, not just a hover cue. */
#process-list-btn { text-decoration: underline; }

/* ---------- metric drill-down modal ---------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 1000;
}
.modal-backdrop[hidden] { display: none; }

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 24px;
  width: 60vw;
  height: 60vh;
  min-width: 320px;
  min-height: 360px;
  display: flex;
  flex-direction: column;
  /* hidden, not auto -- a scrollbar drawn directly on a rounded-corner box
     renders as a straight-edged rectangle that cuts into the corner
     radius (visible at the top/bottom-right of a scrolled modal). The
     modal itself never scrolls; whichever inner element actually holds
     the overflowing content (the resolved-problems list, the exclusion
     textarea's own form, etc.) scrolls on its own instead, inset from
     the rounded edges by the modal's padding. */
  overflow: hidden;
}
/* Sized to content instead of the fixed 60vh above -- for short forms
   (a handful of labeled fields) rather than the exclusion list's textarea,
   where a fixed height would leave a large blank gap underneath. */
.modal.modal-auto {
  height: auto;
  min-height: 0;
  max-height: 85vh;
}

.mail-settings-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
  overflow-y: auto;
}
.mail-settings-field label {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.mail-settings-field .field {
  width: 100%;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  margin-bottom: 16px;
  flex-shrink: 0;
}
.modal-header h2 {
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 500;
  margin: 0;
  color: var(--text);
}
.modal-close {
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.modal-close:hover { color: var(--text); }

.range-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
  flex-shrink: 0;
}
.range-picker button {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
}
.range-picker button.active {
  background: var(--ok);
  border-color: var(--ok);
  color: #06120c;
}

.modal-chart-wrap {
  position: relative;
  margin-bottom: 16px;
  flex: 1;
  min-height: 120px;
}
canvas.modal-chart {
  display: block;
  width: 100%;
  height: 100%;
}

.modal-spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px;
  border: 3px solid var(--border);
  border-top-color: var(--ok);
  border-radius: 50%;
  animation: modal-spin 0.7s linear infinite;
}
.modal-spinner[hidden] { display: none; }

@keyframes modal-spin {
  to { transform: rotate(360deg); }
}
.modal-chart-wrap .empty {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  transform: translateY(-50%);
  text-align: center;
  margin: 0;
}

.modal-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  border-top: 1px solid var(--border);
  padding-top: 16px;
  flex-shrink: 0;
}
.modal-stats .stat { text-align: center; }
.modal-stats .stat-label {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 4px;
}
.modal-stats .stat-value {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
}
