/* ============================================================================
   NET-WATCH NOC — DASNET Theme
   Zero external dependency: no Bootstrap, no FontAwesome, no Google Fonts.
   Semua warna berasal dari token di bawah. Ganti 8 token brand = re-theme total.
   ============================================================================ */

/* ── 1. BRAND TOKENS (SINGLE SOURCE OF TRUTH) ───────────────────────────────
   Ubah HANYA blok ini untuk menyamakan warna dengan dataartasedaya.net.id.
   Cek hex asli situs:
     curl -s https://dataartasedaya.net.id/ \
       | grep -oE '#[0-9a-fA-F]{6}' | sort | uniq -c | sort -rn | head -20
   ------------------------------------------------------------------------- */
:root {
  --brand-900: #071426;   /* navy paling gelap  */
  --brand-800: #0d1e35;   /* permukaan card     */
  --brand-700: #132b49;   /* permukaan elevated */
  --brand-600: #1e3a5f;   /* garis / border     */
  --brand-500: #1d6fd0;   /* PRIMARY  (azure DASNET) */
  --brand-400: #2f88ea;   /* primary hover      */
  --brand-300: #56a8f5;   /* aksen teks / ikon  */
  --brand-100: #d6e8fb;   /* tint terang        */

  /* Status — konsisten di dark & light, jangan diubah tanpa alasan */
  --ok:      #12b76a;
  --ok-dim:  rgba(18, 183, 106, .14);
  --warn:    #f5a524;
  --warn-dim:rgba(245, 165, 36, .14);
  --crit:    #e5484d;
  --crit-dim:rgba(229, 72, 77, .14);
  --idle:    #7b93b2;
  --idle-dim:rgba(123, 147, 178, .12);

  /* Skala & ritme */
  --r-sm: 6px;  --r-md: 10px;  --r-lg: 14px;  --r-pill: 999px;
  --sp-1: 4px;  --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px;  --sp-7: 48px;
  --rail-w: 240px;
  --tabbar-h: 62px;
  --dur: .18s;

  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
             "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", "Cascadia Mono",
               Menlo, Consolas, "Liberation Mono", monospace;
}

/* ── 2. THEME: DARK (default, untuk wallboard NOC) ───────────────────────── */
:root, [data-theme="dark"] {
  /* Rack punya paletnya sendiri. Sebelumnya seluruh chassis di-hardcode gelap,
     jadi di tema terang ia jadi kotak kelabu yang menempel di latar putih dan
     nomor U-nya nyaris tak terbaca. */
  --rack-body:    linear-gradient(180deg, #0a0f1a, #060a12);
  --rack-frame:   #232f44;
  --rack-rail:    linear-gradient(90deg, #141c2b, #1b2536);
  --rack-rail-2:  linear-gradient(90deg, #1b2536, #141c2b);
  --rack-hole:    #05080f;
  --rack-u-text:  #7b8ca6;
  --rack-slot:    #29344a;
  --rack-dev:     linear-gradient(180deg, #26314a 0%, #1a2336 18%, #161e2f 100%);
  --rack-dev-line:#38455f;
  --rack-screw:   radial-gradient(circle at 30% 30%, #6b7a94, #232c3d);
  --rack-dev-text:#e8f0fa;
  /* Latar mendekati hitam dengan semburat biru. Kontras antar permukaan
     dinaikkan supaya kartu benar-benar "mengambang" di atas latar, bukan
     menyatu seperti versi sebelumnya. */
  --bg:        #04070e;
  --bg-rail:   #070b15;
  --surface:   #0c1322;
  --surface-2: #141d30;
  --line:      #1f2b42;
  --line-soft: rgba(255, 255, 255, .05);
  --text:      #eaf1fb;
  --text-2:    #b9c8dd;
  --muted:     #77879f;
  --accent:    #56a8f5;
  --shadow:    0 16px 44px rgba(0, 0, 0, .62);
  --input-bg:  rgba(255, 255, 255, .035);
  --glow:      0 0 0 1px rgba(86, 168, 245, .18), 0 8px 28px rgba(29, 111, 208, .14);
  color-scheme: dark;
}

/* ── 3. THEME: LIGHT (untuk kerja siang / laporan) ───────────────────────── */
[data-theme="light"] {
  /* Rack 19 inci berlapis cat abu terang: badan terang, rail metalik dengan
     lubang gelap, perangkat sebagai bezel putih bergradasi. */
  --rack-body:    linear-gradient(180deg, #e8ecf3, #dbe1ea);
  --rack-frame:   #b9c3d2;
  --rack-rail:    linear-gradient(90deg, #c3ccd9, #d6dde7);
  --rack-rail-2:  linear-gradient(90deg, #d6dde7, #c3ccd9);
  --rack-hole:    #8a95a6;
  --rack-u-text:  #4a5568;
  --rack-slot:    #aeb9c9;
  --rack-dev:     linear-gradient(180deg, #ffffff 0%, #f1f4f9 18%, #e3e8f0 100%);
  --rack-dev-line:#a9b4c5;
  --rack-screw:   radial-gradient(circle at 30% 30%, #ffffff, #97a2b3);
  --rack-dev-text:#132437;
  --bg:        #f1f5fa;
  --bg-rail:   #ffffff;
  --surface:   #ffffff;
  --surface-2: #f2f6fb;
  --line:      #dde5f0;
  --line-soft: rgba(11, 31, 56, .07);
  --text:      #0a1c33;
  --text-2:    #3b5573;
  --muted:     #6a819c;
  --accent:    var(--brand-500);
  --shadow:    0 10px 30px rgba(15, 35, 65, .09);
  --input-bg:  #ffffff;
  --glow:      0 0 0 1px rgba(29, 111, 208, .16), 0 8px 24px rgba(29, 111, 208, .10);
  color-scheme: light;
}

/* ── 4. RESET ────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  /* Dua sapuan radial sangat tipis. Tanpa ini, latar hampir-hitam terlihat
     rata dan mati; dengan ini ada kedalaman tanpa mengganggu keterbacaan. */
  background:
    radial-gradient(1200px 620px at 78% -12%, rgba(29, 111, 208, .10), transparent 60%),
    radial-gradient(900px 520px at -6% 104%, rgba(86, 168, 245, .06), transparent 58%),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}
h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
p { margin: 0 0 var(--sp-3); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
button { font: inherit; color: inherit; }
svg.i {
  width: 1em; height: 1em; flex: none; vertical-align: -.125em;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}

:focus-visible {
  outline: 2px solid var(--brand-400);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: var(--r-pill); }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* ── 5. UTILITAS ─────────────────────────────────────────────────────────── */
.mono   { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.muted  { color: var(--muted); }
.hidden { display: none !important; }
.eyebrow {
  font-size: 10px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.row     { display: flex; align-items: center; gap: var(--sp-2); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.wrap    { flex-wrap: wrap; }
.grow    { flex: 1 1 auto; min-width: 0; }
.truncate{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stack   { display: flex; flex-direction: column; gap: var(--sp-3); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── 6. SHELL: RAIL + KONTEN ─────────────────────────────────────────────── */
.shell { display: flex; min-height: 100vh; }

.rail {
  width: var(--rail-w); flex: none; position: fixed; inset: 0 auto 0 0; z-index: 40;
  background: var(--bg-rail); border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.rail-brand {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4); border-bottom: 1px solid var(--line);
}
.rail-logo {
  width: 34px; height: 34px; flex: none; border-radius: 9px;
  background: linear-gradient(145deg, var(--brand-500), var(--brand-400));
  display: grid; place-items: center; color: #fff; font-size: 17px;
  box-shadow: 0 4px 12px rgba(29, 111, 208, .35);
}
.rail-title { font-size: 14px; font-weight: 700; letter-spacing: .02em; line-height: 1.15; }
.rail-sub   { font-size: 10px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase; }

.rail-nav { padding: var(--sp-4) var(--sp-3); display: flex; flex-direction: column; gap: 2px; }
.nav-link {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 10px var(--sp-3); border-radius: var(--r-md);
  color: var(--text-2); font-size: 13.5px; font-weight: 500;
  transition: background var(--dur), color var(--dur);
}
.nav-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav-link.is-active { background: var(--brand-500); color: #fff; }
.nav-link.is-active svg.i { color: #fff; }
.nav-link svg.i { font-size: 16px; color: var(--muted); }
.nav-link:hover svg.i { color: var(--accent); }

.rail-foot { margin-top: auto; padding: var(--sp-3); border-top: 1px solid var(--line); }
.clock {
  text-align: center; padding: var(--sp-3) 0 var(--sp-4);
  border-bottom: 1px solid var(--line-soft); margin-bottom: var(--sp-3);
}
.clock-time { font-family: var(--font-mono); font-size: 26px; font-weight: 600; letter-spacing: .02em; }
.clock-date { font-size: 11px; color: var(--muted); margin-top: 2px; }

.who { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2); }
.avatar {
  width: 34px; height: 34px; flex: none; border-radius: var(--r-pill);
  background: var(--brand-500); color: #fff; display: grid; place-items: center;
  font-weight: 700; font-size: 14px;
}
.who-name { font-size: 13px; font-weight: 600; }
.who-role { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }

.main { flex: 1 1 auto; min-width: 0; margin-left: var(--rail-w); display: flex; flex-direction: column; }
.topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.page-title { font-size: 15px; font-weight: 650; }
.content { padding: var(--sp-5); max-width: 1560px; width: 100%; }
.foot {
  margin-top: auto; padding: var(--sp-5); text-align: center;
  color: var(--muted); font-size: 11.5px; border-top: 1px solid var(--line-soft);
}

/* Bottom tab bar (mobile) */
.tabbar { display: none; }

/* ── 7. KOMPONEN DASAR ───────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
[data-theme="light"] .card { box-shadow: 0 1px 2px rgba(15, 35, 65, .05); }
.card-pad { padding: var(--sp-4); }
.card-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line);
  font-size: 13px; font-weight: 650;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 34px; padding: 0 13px; border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text);
  font-size: 13px; font-weight: 550; cursor: pointer; white-space: nowrap;
  transition: background var(--dur), border-color var(--dur), color var(--dur);
}
.btn:hover { background: var(--line); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--brand-500); border-color: var(--brand-500); color: #fff; }
.btn-primary:hover { background: var(--brand-400); border-color: var(--brand-400); }
.btn-danger  { background: var(--crit); border-color: var(--crit); color: #fff; }
.btn-danger:hover { filter: brightness(1.08); }
.btn-ghost   { background: transparent; }
.btn-ghost:hover { background: var(--surface-2); }
.btn-sm { height: 28px; padding: 0 10px; font-size: 12px; }
.btn-icon { width: 34px; padding: 0; }
.btn-icon.btn-sm { width: 28px; }
.btn-block { width: 100%; }

.input, .select, textarea.input {
  width: 100%; height: 36px; padding: 0 11px;
  background: var(--input-bg); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--r-md);
  font-size: 13px; font-family: inherit; transition: border-color var(--dur), box-shadow var(--dur);
}
.select {
  appearance: none; padding-right: 30px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 15px) 15px, calc(100% - 10px) 15px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.input:focus, .select:focus {
  outline: none; border-color: var(--brand-500);
  box-shadow: 0 0 0 3px rgba(29, 111, 208, .18);
}
.input::placeholder { color: var(--muted); }
.input[type="file"] { padding: 6px 10px; height: auto; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field > label { font-size: 11.5px; font-weight: 600; color: var(--muted); }
.hint { font-size: 11px; color: var(--muted); }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--r-pill);
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid transparent;
}
.badge-ok   { background: var(--ok-dim);   color: var(--ok);   border-color: rgba(18,183,106,.3); }
.badge-warn { background: var(--warn-dim); color: var(--warn); border-color: rgba(245,165,36,.3); }
.badge-crit { background: var(--crit-dim); color: var(--crit); border-color: rgba(229,72,77,.35); }
.badge-idle { background: var(--idle-dim); color: var(--idle); border-color: var(--line); }
.badge-info { background: rgba(29,111,208,.14); color: var(--accent); border-color: rgba(29,111,208,.3); }

.dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }

.divider { height: 1px; background: var(--line); border: 0; margin: var(--sp-4) 0; }

/* ── 8. SIGNATURE: SEVERITY STRIP ────────────────────────────────────────────
   Satu baris proporsional = kondisi seluruh jaringan. Dibaca dari jarak 5 m. */
.strip-wrap { display: flex; flex-direction: column; gap: var(--sp-3); }
.strip {
  display: flex; height: 10px; width: 100%; overflow: hidden;
  border-radius: var(--r-pill); background: var(--surface-2);
  border: 1px solid var(--line);
}
.strip > span { height: 100%; transition: width .45s cubic-bezier(.4,0,.2,1); }
.strip .s-down   { background: var(--crit); }
.strip .s-lag    { background: var(--warn); }
.strip .s-up     { background: var(--ok); }
.strip .s-paused { background: var(--idle); opacity: .5; }

.legend { display: flex; gap: var(--sp-4); flex-wrap: wrap; }
.legend-item {
  display: flex; align-items: baseline; gap: 7px;
  background: none; border: 0; padding: 2px 0; cursor: pointer;
  color: var(--muted); font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  font-weight: 650; transition: color var(--dur);
}
.legend-item .dot { align-self: center; }
.legend-item .n { font-family: var(--font-mono); font-size: 15px; font-weight: 700; color: var(--text); }
.legend-item:hover { color: var(--text); }
.legend-item.is-on { color: var(--text); }
.legend-item.is-on .n { color: inherit; }
.legend-item[data-filter="down"].is-on   { color: var(--crit); }
.legend-item[data-filter="lag"].is-on    { color: var(--warn); }
.legend-item[data-filter="up"].is-on     { color: var(--ok); }
.legend-item[data-filter="paused"].is-on { color: var(--idle); }
.legend-item[data-filter="down"] .dot   { color: var(--crit); }
.legend-item[data-filter="lag"] .dot    { color: var(--warn); }
.legend-item[data-filter="up"] .dot     { color: var(--ok); }
.legend-item[data-filter="paused"] .dot { color: var(--idle); }
.legend-item[data-filter="all"] .dot    { color: var(--accent); }

.hero {
  display: grid; grid-template-columns: 1fr auto; gap: var(--sp-5);
  align-items: center; padding: var(--sp-4) var(--sp-5);
}
.uptime { text-align: right; }
.uptime .n { font-family: var(--font-mono); font-size: 30px; font-weight: 700; line-height: 1; }
.uptime.is-ok   .n { color: var(--ok); }
.uptime.is-warn .n { color: var(--warn); }
.uptime.is-crit .n { color: var(--crit); }

/* ── 9. TOOLBAR ──────────────────────────────────────────────────────────── */
.toolbar {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
}
.search { position: relative; flex: 1 1 200px; max-width: 320px; min-width: 160px; }
.search .input { padding-left: 32px; padding-right: 30px; }
.search .s-icon {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--muted); font-size: 13px; pointer-events: none;
}
.search .s-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  background: none; border: 0; color: var(--muted); cursor: pointer;
  width: 22px; height: 22px; border-radius: var(--r-sm); line-height: 1;
}
.search .s-clear:hover { color: var(--text); background: var(--surface-2); }

.live {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--r-pill);
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: .05em;
  background: var(--ok-dim); color: var(--ok); border: 1px solid rgba(18,183,106,.3);
  white-space: nowrap;
}
.live .dot { animation: pulse 1.9s ease-in-out infinite; }
.live.is-off  { background: var(--crit-dim); color: var(--crit); border-color: rgba(229,72,77,.35); }
.live.is-idle { background: var(--idle-dim); color: var(--idle); border-color: var(--line); }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

/* ── 10. GROUP + HOST CARD ───────────────────────────────────────────────── */
.group { margin-bottom: var(--sp-4); }
.group-head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px var(--sp-3) 9px var(--sp-4);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); cursor: pointer; user-select: none;
  transition: border-color var(--dur), background var(--dur);
}
.group-head:hover { background: var(--surface-2); }
.group-head.is-crit { border-color: rgba(229,72,77,.45); background: var(--crit-dim); }
.group-head.is-warn { border-color: rgba(245,165,36,.4);  background: var(--warn-dim); }
.group-name { font-size: 12.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.group-head.is-crit .group-name { color: var(--crit); }
.group-head.is-warn .group-name { color: var(--warn); }
.chev { transition: transform var(--dur); color: var(--muted); font-size: 13px; }
.group-head.is-open .chev { transform: rotate(180deg); }

.grid {
  display: grid; gap: var(--sp-3); margin-top: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
}

.host {
  position: relative; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 11px 12px 10px 15px; overflow: hidden;
  transition: border-color var(--dur), background var(--dur);
}
.host::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--ok); transition: background var(--dur);
}
.host.is-down   { border-color: rgba(229,72,77,.45); background: var(--crit-dim); }
.host.is-down::before   { background: var(--crit); }
.host.is-lag    { border-color: rgba(245,165,36,.4); }
.host.is-lag::before    { background: var(--warn); }
.host.is-paused { opacity: .55; border-style: dashed; }
.host.is-paused::before { background: var(--idle); }

.host-top { display: flex; align-items: flex-start; gap: var(--sp-2); }
.host-name { font-size: 13px; font-weight: 650; line-height: 1.3; }
.host.is-paused .host-name { text-decoration: line-through; }
.host-ip { font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); margin-top: 1px; }

.host-bottom { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-2); margin-top: 9px; }
.host-state { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; letter-spacing: .05em; }
.host.is-up     .host-state { color: var(--ok); }
.host.is-lag    .host-state { color: var(--warn); }
.host.is-down   .host-state { color: var(--crit); animation: blink 1.6s ease-in-out infinite; }
.host.is-paused .host-state { color: var(--idle); }
@keyframes blink { 50% { opacity: .45; } }

.host-lat { font-family: var(--font-mono); font-size: 17px; font-weight: 700; line-height: 1; text-align: right; }
.host-lat small { font-size: 10px; font-weight: 500; color: var(--muted); margin-left: 2px; }
.host.is-lag  .host-lat { color: var(--warn); }
.host.is-down .host-lat { color: var(--crit); }
.host-meta { font-size: 10px; color: var(--muted); font-family: var(--font-mono); margin-top: 3px; text-align: right; }

/* Bar latency relatif terhadap limit host itu sendiri */
.host-bar { height: 3px; border-radius: var(--r-pill); background: var(--line); margin-top: 9px; overflow: hidden; }
.host-bar > span { display: block; height: 100%; background: var(--ok); transition: width .4s ease, background var(--dur); }
.host.is-lag  .host-bar > span { background: var(--warn); }
.host.is-down .host-bar > span { background: var(--crit); }

.host.flash { animation: flash 1.2s ease-out; }
@keyframes flash {
  0%   { box-shadow: 0 0 0 0 rgba(86, 168, 245, .5); }
  100% { box-shadow: 0 0 0 12px rgba(86, 168, 245, 0); }
}

/* Mode padat untuk wallboard >100 host */
.is-compact .grid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--sp-2); }
.is-compact .host { padding: 8px 9px 8px 12px; }
.is-compact .host-lat { font-size: 15px; }
.is-compact .host-bar, .is-compact .host-meta { display: none; }

/* ── 11. DROPDOWN ────────────────────────────────────────────────────────── */
.dd { position: relative; }
.dd-menu {
  position: absolute; right: 0; top: calc(100% + 5px); z-index: 60;
  min-width: 168px; padding: 5px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow);
  display: none;
}
.dd.is-open .dd-menu { display: block; }
.dd-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 9px; border: 0; background: none; border-radius: var(--r-sm);
  font-size: 12.5px; text-align: left; cursor: pointer; color: var(--text);
}
.dd-item:hover { background: var(--surface-2); }
.dd-item.is-danger { color: var(--crit); }
.dd-sep { height: 1px; background: var(--line); margin: 4px 0; }
.host-cell:has(.dd.is-open) { z-index: 50; position: relative; }

/* ── 12. MODAL ───────────────────────────────────────────────────────────── */
.modal {
  position: fixed; inset: 0; z-index: 200; display: none;
  align-items: center; justify-content: center; padding: var(--sp-4);
  background: rgba(4, 12, 23, .68); backdrop-filter: blur(3px);
}
.modal.is-open { display: flex; }
.modal-box {
  width: 100%; max-width: 440px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow); animation: pop .2s ease-out;
}
.modal-box.sm { max-width: 340px; }
@keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.98); } }
.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line);
  font-size: 13.5px; font-weight: 650;
}
.modal-body { padding: var(--sp-4); }
.modal-foot {
  display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--line);
}
.modal-foot .btn { flex: 1; }

/* ── 13. TOAST ───────────────────────────────────────────────────────────── */
.toasts {
  /* Kanan-BAWAH. Di kanan-atas ia menimpa kartu pertama dashboard, dan
     pemberitahuan yang menutupi data justru menghalangi pekerjaan. */
  position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: 90;
  display: flex; flex-direction: column-reverse; gap: var(--sp-2);
  max-width: min(380px, calc(100vw - var(--sp-5)));
  pointer-events: none;
}
.toast {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 12px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  box-shadow: var(--shadow); font-size: 12.5px;
  animation: slidein .22s ease-out;
}
.toast.out { animation: slideout .18s ease-in forwards; }
.toast .t-msg { flex: 1; line-height: 1.4; word-break: break-word; }
.toast .t-x { background: none; border: 0; color: var(--muted); cursor: pointer; padding: 0 2px; line-height: 1; font-size: 15px; }
.toast .t-x:hover { color: var(--text); }
.toast.t-success { border-left-color: var(--ok); }   .toast.t-success svg.i { color: var(--ok); }
.toast.t-danger  { border-left-color: var(--crit); } .toast.t-danger  svg.i { color: var(--crit); }
.toast.t-warning { border-left-color: var(--warn); } .toast.t-warning svg.i { color: var(--warn); }
.toast.t-info    { border-left-color: var(--accent); } .toast.t-info  svg.i { color: var(--accent); }
@keyframes slidein  { from { opacity: 0; transform: translateX(20px); } }
@keyframes slideout { to { opacity: 0; transform: translateX(20px); } }

/* ── 14. TABEL ───────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
table.tbl th {
  text-align: left; padding: 9px var(--sp-3);
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.tbl td { padding: 10px var(--sp-3); border-bottom: 1px solid var(--line-soft); vertical-align: top; }
table.tbl tbody tr:hover { background: var(--surface-2); }
table.tbl tbody tr:last-child td { border-bottom: 0; }
.empty { text-align: center; padding: var(--sp-7) var(--sp-4); color: var(--muted); }
.empty svg.i { font-size: 30px; opacity: .4; display: block; margin: 0 auto var(--sp-3); }

.log-cards { display: none; }
.log-card {
  border: 1px solid var(--line); border-left-width: 3px; border-radius: var(--r-md);
  background: var(--surface); padding: var(--sp-3); margin-bottom: var(--sp-2);
}
.log-card.k-DOWN { border-left-color: var(--crit); }
.log-card.k-LAG  { border-left-color: var(--warn); }
.log-card.k-UP   { border-left-color: var(--ok); }

.pager { display: flex; align-items: center; justify-content: center; gap: var(--sp-4); padding: var(--sp-4); }

/* ── 15. SKELETON ────────────────────────────────────────────────────────── */
.skel {
  border-radius: var(--r-md);
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 50%, var(--surface) 75%);
  background-size: 200% 100%; animation: shim 1.4s linear infinite;
}
@keyframes shim { from { background-position: 200% 0; } to { background-position: -200% 0; } }
mark.hl { background: rgba(86,168,245,.28); color: inherit; padding: 0 2px; border-radius: 3px; }

/* ── 16. LOGIN ───────────────────────────────────────────────────────────── */
body.auth {
  display: grid; place-items: center; padding: var(--sp-4);
  background:
    radial-gradient(900px 500px at 50% -8%, rgba(29,111,208,.20), transparent 62%),
    radial-gradient(700px 420px at 8% 108%, rgba(86,168,245,.11), transparent 58%),
    var(--bg);
}
.auth-box { width: 100%; max-width: 372px; }
.auth-brand { text-align: center; margin-bottom: var(--sp-5); }
.auth-brand .rail-logo { width: 46px; height: 46px; font-size: 23px; margin: 0 auto var(--sp-3); border-radius: 12px; }
.auth-brand h1 { font-size: 19px; letter-spacing: .01em; }
.auth-brand .eyebrow { margin-top: 5px; }
.auth-card { padding: var(--sp-5); }
.auth-foot { text-align: center; margin-top: var(--sp-5); font-size: 11px; color: var(--muted); }
.alert {
  display: flex; gap: 9px; padding: 10px 12px; border-radius: var(--r-md);
  font-size: 12.5px; margin-bottom: var(--sp-4);
  background: var(--crit-dim); color: var(--crit); border: 1px solid rgba(229,72,77,.3);
}

/* ── 17. RESPONSIVE ──────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .rail { display: none; }
  .main { margin-left: 0; }
  .content { padding: var(--sp-3); padding-bottom: calc(var(--tabbar-h) + var(--sp-5)); }
  .topbar { padding: var(--sp-3); }
  .hero { grid-template-columns: 1fr; gap: var(--sp-3); padding: var(--sp-4); }
  .uptime { text-align: left; }
  .legend { gap: var(--sp-3); }
  .toasts { top: auto; bottom: calc(var(--tabbar-h) + 10px); right: var(--sp-3); left: var(--sp-3); width: auto; }
  .foot { padding-bottom: calc(var(--tabbar-h) + var(--sp-4)); }

  .tabbar {
    display: flex; position: fixed; inset: auto 0 0 0; z-index: 100;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--bg-rail); border-top: 1px solid var(--line);
  }
  .tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; color: var(--muted); font-size: 10px; font-weight: 600; letter-spacing: .03em;
  }
  .tab:hover { text-decoration: none; }
  .tab svg.i { font-size: 19px; }
  .tab.is-active { color: var(--accent); }

  .table-wrap { display: none; }
  .log-cards  { display: block; }
}

@media (max-width: 560px) {
  .grid { grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
  .host { padding: 9px 9px 8px 12px; }
  .host-lat { font-size: 15px; }
  .host-meta, .host-bar { display: none; }
  .search { max-width: none; flex-basis: 100%; }
  .toolbar { padding: var(--sp-3); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@media print {
  .rail, .tabbar, .topbar, .toolbar, .toasts, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  .card { border-color: #ccc; }
}

/* ── 18. TABEL EDIT INLINE (halaman Kelola Host, V21) ────────────────────── */
.tbl-edit td { padding: 5px 7px; vertical-align: middle; }
.tbl-edit th { padding: 9px 7px; }

/* Sel yang bisa diedit HARUS terlihat bisa diedit.

   Versi sebelumnya membuatnya transparan tanpa garis sampai di-hover, jadi
   tabel terbaca sebagai teks statis dan operator tidak tahu bisa mengetik di
   situ. Garis tipis permanen mengembalikan afordansnya tanpa membuat tabel
   ramai. */
.cell {
  width: 100%; height: 30px; padding: 0 8px;
  background: var(--input-bg); color: var(--text);
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  font: inherit; font-size: 12.5px;
  transition: border-color var(--dur), background var(--dur);
}
.cell:hover  { border-color: var(--line); background: var(--surface-2); }
.cell:focus  { outline: none; background: var(--input-bg); border-color: var(--brand-500);
               box-shadow: 0 0 0 3px rgba(29, 111, 208, .16); }
.cell::-webkit-outer-spin-button,
.cell::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cell[type="number"] { -moz-appearance: textfield; }

.cell.is-bad,
.cell.is-bad:hover { border-color: var(--crit); background: var(--crit-dim); color: var(--crit); }

tr.is-dirty > td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
tr.is-dirty .cell { background: var(--warn-dim); border-color: rgba(245, 165, 36, .28); }
tr.is-bad-row > td:first-child { box-shadow: inset 3px 0 0 var(--crit); }

input[type="checkbox"] {
  width: 15px; height: 15px; accent-color: var(--brand-500);
  cursor: pointer; margin: 0; vertical-align: middle;
}

.bulkbar {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface-2); border-top: 1px solid var(--line);
}

/* Di layar sempit, tabel edit tetap tabel (bukan kartu): kolomnya saling
   terkait dan harus dibandingkan berdampingan. Cukup digeser horizontal. */
@media (max-width: 900px) {
  .tbl-edit { min-width: 780px; }
  .table-wrap:has(.tbl-edit) { display: block; overflow-x: auto; }
}


/* ── 19. DCIM (v23) ──────────────────────────────────────────────────────── */
.only-mobile { display: none; }
@media (max-width: 900px) { .only-mobile { display: inline-flex; } }

.cell-select {
  width: 100%; height: 30px; padding: 0 24px 0 6px;
  background: var(--input-bg); color: var(--text);
  border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  font: inherit; font-size: 12.5px; cursor: pointer; appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 12px) 13px, calc(100% - 8px) 13px;
  background-size: 4px 4px, 4px 4px; background-repeat: no-repeat;
}
.cell-select:hover { border-color: var(--line); background-color: var(--surface-2); }
.cell-select:focus { outline: none; background-color: var(--input-bg); border-color: var(--brand-500); }

.chip-status { text-transform: capitalize; }
.st-active        { background: var(--ok-dim);   color: var(--ok);   border-color: rgba(18,183,106,.3); }
.st-planned       { background: rgba(29,111,208,.14); color: var(--accent); border-color: rgba(29,111,208,.3); }
.st-staged        { background: var(--warn-dim); color: var(--warn); border-color: rgba(245,165,36,.3); }
.st-offline       { background: var(--crit-dim); color: var(--crit); border-color: rgba(229,72,77,.35); }
.st-decommissioned{ background: var(--idle-dim); color: var(--idle); border-color: var(--line); }

.role-dot { width: 9px; height: 9px; border-radius: 3px; flex: none; display: inline-block; }

.kv { display: grid; grid-template-columns: 130px 1fr; gap: 7px var(--sp-3); font-size: 13px; }
.kv dt { color: var(--muted); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; padding-top: 2px; }
.kv dd { margin: 0; }

.slot-grid { display: flex; flex-wrap: wrap; gap: 5px; }
.slot {
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  padding: 3px 8px; border-radius: var(--r-sm);
  background: var(--ok-dim); color: var(--ok); border: 1px solid rgba(18,183,106,.3);
}

.panel-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); align-items: start; }

/* ── 20. IPAM (v24) ──────────────────────────────────────────────────────── */
.util-bar {
  height: 6px; border-radius: var(--r-pill); background: var(--surface-2);
  border: 1px solid var(--line); overflow: hidden; min-width: 120px;
}
.util-bar > span { display: block; height: 100%; background: var(--brand-500); transition: width .4s ease; }

/* Grid alamat: 16 kolom untuk /24 — satu layar, satu pandang. Filosofinya
   sama dengan Severity Strip di dashboard: informasi padat, terbaca cepat. */
.ipgrid {
  display: grid; grid-template-columns: repeat(16, minmax(0, 1fr)); gap: 3px;
}
.ipcell {
  aspect-ratio: 1 / 1; min-height: 26px;
  display: grid; place-items: center; cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
  border-radius: 4px; border: 1px solid transparent; color: var(--text);
  transition: transform .08s ease, box-shadow .12s ease;
  overflow: hidden;
}
.ipcell:hover { transform: scale(1.14); z-index: 5; box-shadow: 0 3px 10px rgba(0,0,0,.4); }
.ipcell.is-dim { opacity: .18; }

/* HANTU merah: alamat tidak terdokumentasi yang membalas = konflik / perangkat
   liar, hal paling mendesak di halaman ini. MATI kuning: kandidat direklamasi,
   penting tapi tidak mendesak. */
.ip-ghost      { background: var(--crit);     color: #fff; border-color: var(--crit); }
.ip-active     { background: var(--ok-dim);   color: var(--ok);   border-color: rgba(18,183,106,.45); }
.ip-dead       { background: var(--warn-dim); color: var(--warn); border-color: rgba(245,165,36,.5); }
.ip-documented { background: rgba(29,111,208,.18); color: var(--accent); border-color: rgba(29,111,208,.45); }
.ip-free       { background: var(--surface-2); color: var(--muted); border-color: var(--line); }
.ip-unknown    { background: transparent; color: var(--muted); border: 1px dashed var(--line); }
.ip-reserved   { background: var(--idle-dim); color: var(--idle); border-color: var(--line); opacity: .6; }

.legend-item.ip-ghost      .dot { color: var(--crit); }
.legend-item.ip-active     .dot { color: var(--ok); }
.legend-item.ip-dead       .dot { color: var(--warn); }
.legend-item.ip-documented .dot { color: var(--accent); }
.legend-item.ip-free       .dot { color: var(--muted); }
.legend-item.ip-unknown    .dot { color: var(--line); }
.legend-item.ip-reserved   .dot { color: var(--idle); }
.legend-item.ip-ghost, .legend-item.ip-active, .legend-item.ip-dead,
.legend-item.ip-documented, .legend-item.ip-free, .legend-item.ip-unknown,
.legend-item.ip-reserved { background: none; border: 0; }
.legend-item.is-on { text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 900px) {
  .ipgrid { grid-template-columns: repeat(8, minmax(0, 1fr)); }
  .ipcell { font-size: 10px; }
}

/* ── 21. RACK ELEVATION (v25) ────────────────────────────────────────────── */
.rack-pair { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); align-items: start; }

/* Rack digambar seperti lemari sungguhan: dua rail dengan lubang mounting,
   badan gelap, dan bezel pada tiap perangkat. Bukan hiasan — engineer membaca
   elevation dengan menghitung lubang, dan tampilan yang mirip aslinya membuat
   perhitungan itu bisa dipindahkan langsung ke lapangan. */
.rack {
  display: grid;
  grid-template-columns: 26px 1fr 26px;
  grid-template-rows: repeat(var(--rack-u), 24px);
  gap: 2px;
  padding: var(--sp-2) 4px;
  background: var(--rack-body);
  border: 1px solid var(--rack-frame);
  border-radius: var(--r-md);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .04),
              inset 0 12px 26px rgba(0, 0, 0, .30);
}

.u-num {
  grid-column: 1; display: grid; place-items: center;
  font-size: 9px; color: var(--rack-u-text); user-select: none; position: relative;
  background: var(--rack-rail);
  border-radius: 2px;
}
.u-num.is-right { grid-column: 3; background: var(--rack-rail-2); }
/* Lubang mounting: tiga titik per U, persis seperti rail 19 inci. */
.u-num::before, .u-num::after {
  content: ""; position: absolute; width: 3px; height: 3px; border-radius: 1px;
  background: var(--rack-hole); box-shadow: 0 0 0 1px rgba(255, 255, 255, .07);
}
.u-num::before { top: 3px; }
.u-num::after  { bottom: 3px; }
.u-num { padding: 0 2px; }

.u-slot {
  grid-column: 2; border-radius: 2px; cursor: pointer;
  border: 1px dashed var(--rack-slot);
  background: repeating-linear-gradient(90deg,
    rgba(255,255,255,.012) 0 7px, transparent 7px 14px);
  transition: background var(--dur), border-color var(--dur);
}
.u-slot:hover, .u-slot:focus-visible { border-color: var(--brand-400); background: rgba(29,111,208,.16); }
.u-slot.is-target { border-color: var(--ok); background: var(--ok-dim); border-style: solid; }
.u-slot.is-blocked { border-color: var(--crit); background: var(--crit-dim); }

.u-dev {
  grid-column: 2; position: relative; overflow: hidden;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 10px; border-radius: 3px;
  background: var(--rack-dev);
  border: 1px solid var(--rack-dev-line);
  color: var(--rack-dev-text);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .10),
              inset 0 -1px 0 rgba(0, 0, 0, .5),
              0 1px 3px rgba(0, 0, 0, .45);
  cursor: grab;
}
/* Dua sekrup rack-mount di tiap sisi bezel. */
.u-dev::before, .u-dev::after {
  content: ""; position: absolute; top: 50%; transform: translateY(-50%);
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--rack-screw);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .5);
}
.u-dev::before { left: 3px; }
.u-dev::after  { right: 3px; }
.u-dev .u-dev-body { padding-left: 6px; }
.u-dev:active { cursor: grabbing; }
.u-dev.is-dragging { opacity: .4; }
.u-dev.is-moving { border-color: var(--brand-400); box-shadow: 0 0 0 2px rgba(29,111,208,.35); }

/* Blok bergaris = ruang yang dipakai perangkat full-depth dari sisi seberang.
   Tidak bisa diklik, tidak bisa diseret: secara fisik memang sudah terpakai. */
.u-dev.is-through {
  cursor: not-allowed; opacity: .62; border-style: dashed;
  background: repeating-linear-gradient(135deg,
    var(--surface) 0 7px, var(--surface-2) 7px 14px);
}

.u-dev-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; line-height: 1.15; }
.u-dev-name { font-size: 11.5px; font-weight: 650; }
.u-dev-meta { font-size: 9.5px; color: var(--muted); }
.u-dev-act { display: none; gap: 1px; }
.u-dev:hover .u-dev-act { display: flex; }
.u-dev[style*="span 1"] .u-dev-meta { display: none; }

body.is-picking .u-slot { border-color: var(--ok); background: var(--ok-dim); }

@media (max-width: 560px) {
  .rack { grid-template-columns: 22px 1fr 22px; grid-template-rows: repeat(var(--rack-u), 21px); }
  .u-dev-act { display: flex; }
}

/* ── 22. TOPOLOGI (v26) ──────────────────────────────────────────────────── */
.topo-wrap { position: relative; overflow: hidden; background: var(--bg); height: min(72vh, 720px); }
#topoSvg { width: 100%; height: 100%; display: block; cursor: grab; touch-action: none; }
#topoSvg.is-panning { cursor: grabbing; }

.topo-box { fill: var(--surface); stroke: var(--line); stroke-width: 1.5; }
.topo-accent { fill: var(--brand-500); }
.topo-name { fill: var(--text); font-size: 13px; font-weight: 650; font-family: var(--font-ui); }
.topo-sub  { fill: var(--muted); font-size: 10.5px; font-family: var(--font-ui); }
.topo-dot  { fill: var(--idle); stroke: var(--surface); stroke-width: 2; }

.topo-node { cursor: grab; }
.topo-node:active { cursor: grabbing; }
.topo-node:hover .topo-box { stroke: var(--brand-400); }
.topo-node:focus-visible .topo-box { stroke: var(--brand-400); stroke-width: 2.5; }
.topo-node.is-dragging .topo-box { stroke: var(--brand-400); stroke-width: 2; }
.topo-node.is-source .topo-box { stroke: var(--accent); stroke-width: 2.5; }

/* Node diwarnai dari status ping target yang tertaut. Abu = TIDAK DIPANTAU,
   bukan sehat — perangkat di peta yang tidak dipantau adalah titik buta. */
.ns-down .topo-dot { fill: var(--crit); }
.ns-down .topo-box { stroke: var(--crit); background: var(--crit-dim); fill: var(--crit-dim); }
.ns-lag  .topo-dot { fill: var(--warn); }
.ns-lag  .topo-box { stroke: rgba(245,165,36,.6); }
.ns-up   .topo-dot { fill: var(--ok); }
.ns-paused .topo-dot, .ns-unknown .topo-dot { fill: var(--idle); }
.ns-unknown .topo-box { stroke-dasharray: 4 3; }

.topo-line { stroke: var(--line); stroke-width: 2.5; }
.topo-hit  { stroke: transparent; stroke-width: 14; cursor: pointer; }
.topo-link-label { fill: var(--muted); font-size: 10px; font-family: var(--font-mono); pointer-events: none; }
.ls-up   .topo-line { stroke: var(--ok); }
.ls-lag  .topo-line { stroke: var(--warn); }
.ls-down .topo-line { stroke: var(--crit); stroke-width: 3; }
.ls-unknown .topo-line { stroke: var(--line); stroke-dasharray: 6 4; }
.ls-planned .topo-line { stroke: var(--accent); stroke-dasharray: 2 5; }
.ls-decommissioned .topo-line { stroke: var(--idle); opacity: .4; stroke-dasharray: 8 6; }
.topo-link:hover .topo-line { stroke-width: 4; }

@media (max-width: 900px) { .topo-wrap { height: 60vh; } }


/* ── 22b. Topologi: keadaan kosong & penanda mendesak (v26.0.1) ──────────── */
.topo-empty {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; text-align: center; padding: var(--sp-5);
  color: var(--muted); pointer-events: none;
}
.topo-empty svg.i { font-size: 30px; opacity: .4; }
.topo-empty .hint { max-width: 380px; }

.topo-ip { font-family: var(--font-mono); }

/* Node down berdenyut. Dipinjam dari The Dude: yang mendesak harus menarik
   mata lebih dulu daripada yang sekadar berbeda warna. */
.ns-down .topo-dot { animation: topopulse 1.6s ease-in-out infinite; }
@keyframes topopulse { 50% { opacity: .25; r: 7; } }
@media (prefers-reduced-motion: reduce) { .ns-down .topo-dot { animation: none; } }


/* ── 23. GERAK (v27) ──────────────────────────────────────────────────────
   Semuanya CSS murni: nol JavaScript, nol dependensi, nol risiko gagal.
   Durasi ditahan di bawah 260 ms — animasi yang lebih lama terasa seperti
   aplikasi yang lambat, bukan aplikasi yang halus. */

/* Konten halaman memudar masuk saat berpindah menu.

   SENGAJA tanpa transform. Elemen dengan animasi yang menyentuh `transform`
   diperlakukan sebagai punya transform selama animasi berjalan MAUPUN saat
   fill-mode menahannya — termasuk ketika nilai akhirnya `none`. Itu membuat
   containing block baru dan mematahkan `position: fixed` pada seluruh anaknya.
   Gerak translateY dipindah ke .stagger, yang isinya kartu dan tidak pernah
   memuat elemen fixed. */
.content { animation: pageIn .2s ease-out both; }
@keyframes pageIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Sidebar & topbar tidak ikut beranimasi: elemen yang tetap di tempat
   membuat perpindahan terasa cepat, bukan berkedip. */

/* Login "terbelah": dua bilah menyibak dari tengah, kartu muncul di baliknya. */
body.auth::before, body.auth::after {
  content: ""; position: fixed; left: 0; right: 0; z-index: 50;
  background: var(--bg-rail);
  border-color: var(--brand-500);
  animation: splitOut .62s cubic-bezier(.76, 0, .24, 1) both;
  pointer-events: none;
}
body.auth::before { top: 0; height: 50vh; border-bottom: 1px solid; }
body.auth::after  { bottom: 0; height: 50vh; border-top: 1px solid; animation-name: splitOutDown; }
@keyframes splitOut     { from { transform: none; } to { transform: translateY(-52vh); } }
@keyframes splitOutDown { from { transform: none; } to { transform: translateY(52vh); } }

.auth-box { animation: authRise .5s .32s cubic-bezier(.22, .61, .36, 1) both; }
@keyframes authRise {
  from { opacity: 0; transform: translateY(18px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Kartu di halaman ikhtisar muncul berurutan, jeda sangat pendek. */
.stagger > * { animation: pageIn .26s cubic-bezier(.22, .61, .36, 1) both; }
.stagger > *:nth-child(2) { animation-delay: .04s; }
.stagger > *:nth-child(3) { animation-delay: .08s; }
.stagger > *:nth-child(4) { animation-delay: .12s; }
.stagger > *:nth-child(5) { animation-delay: .16s; }
.stagger > *:nth-child(6) { animation-delay: .20s; }

@media (prefers-reduced-motion: reduce) {
  .content, .auth-box, .stagger > * { animation: none !important; }
  body.auth::before, body.auth::after { display: none; }
}

/* ── 24. IKHTISAR MODUL (v27) ────────────────────────────────────────────── */
.tiles { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
.tile {
  display: block; padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line);
  transition: border-color var(--dur), transform var(--dur), box-shadow var(--dur);
}
.tile:hover {
  text-decoration: none; transform: translateY(-2px);
  border-color: var(--brand-500); box-shadow: var(--glow);
}
.tile-top { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.tile-top svg.i { font-size: 15px; color: var(--accent); }
.tile-label { font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.tile-value { font-family: var(--font-mono); font-size: 27px; font-weight: 700; line-height: 1; color: var(--text); }
.tile-sub { font-size: 11.5px; color: var(--muted); margin-top: 6px; }
.tile-sub b { color: var(--text-2); }
.tile.is-alert { border-color: rgba(229, 72, 77, .5); background: var(--crit-dim); }
.tile.is-alert .tile-value, .tile.is-alert .tile-top svg.i { color: var(--crit); }

/* ── 25. PANEL REFERENSI (v27) ───────────────────────────────────────────────
   Empat panel berdampingan di layar 1920 menyisakan ~386 px per kartu. Tabel
   lima kolom di ruang selebar itu membuat <input class="cell"> menyusut sampai
   isinya terpotong — "RACK 1 - FNA" terbaca "RA". Dua panel per baris memberi
   ruang yang cukup, dan tabelnya diberi lebar minimum supaya menggeser
   mendatar alih-alih menghimpit isinya. */
.ref-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(460px, 1fr)); align-items: start; }
.ref-grid .tbl-edit { min-width: 420px; }
.ref-grid .table-wrap { overflow-x: auto; }
@media (max-width: 1000px) { .ref-grid { grid-template-columns: 1fr; } }


/* ── 26. PANDUAN (v27) ───────────────────────────────────────────────────── */
.guide { max-width: 1500px; }
.guide p { line-height: 1.6; font-size: 13.5px; }
.guide .kv { grid-template-columns: 150px 1fr; }
.guide .kv dt { text-transform: none; letter-spacing: 0; font-size: 12.5px; font-weight: 650; color: var(--text-2); }

.guide-steps { margin: 0; padding-left: 20px; display: grid; gap: 7px; font-size: 13.5px; line-height: 1.55; }
.guide-steps li::marker { color: var(--accent); font-weight: 700; }

.kbd {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-bottom-width: 2px; font-family: var(--font-mono);
  font-size: 11px; font-weight: 700; color: var(--text-2);
}

/* Label status IPAM di panduan memakai warna aslinya supaya legenda di sini
   dan di halaman IPAM tidak bisa berbeda arti. */
.guide dt.ip-lg {
  text-transform: uppercase; letter-spacing: .05em; font-size: 10.5px;
  font-weight: 700; padding: 2px 8px; border-radius: var(--r-pill);
  border: 1px solid transparent; justify-self: start; align-self: start;
}
.guide dt.ip-active     { background: var(--ok-dim);   color: var(--ok);   border-color: rgba(18,183,106,.4); }
.guide dt.ip-dead       { background: var(--warn-dim); color: var(--warn); border-color: rgba(245,165,36,.45); }
.guide dt.ip-ghost      { background: var(--crit);     color: #fff; }
.guide dt.ip-free       { background: var(--surface-2); color: var(--muted); border-color: var(--line); }
.guide dt.ip-unknown    { background: transparent; color: var(--muted); border: 1px dashed var(--line); }

/* ── 27. UBIN SEBAGAI FILTER (v28) ───────────────────────────────────────── */
.tile-btn {
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface);
}
.tile-btn.is-on {
  border-color: var(--brand-500); background: var(--surface-2);
  box-shadow: var(--glow);
}
.tile-btn.is-on .tile-label { color: var(--accent); }
.tile-btn:focus-visible { outline: 2px solid var(--brand-400); outline-offset: 2px; }

.c-crit { color: var(--crit); }
.c-warn { color: var(--warn); }

/* ── 28. FACEPLATE VIRTUAL (v31) ─────────────────────────────────────────────
   Bentuk cage dibedakan supaya port bisa dikenali sekilas tanpa membaca label:
   RJ45 bertakik seperti konektor 8P8C, SFP cage sempit satu lane, QSFP cage
   lebar empat lane. Ukurannya juga proporsional terhadap aslinya — QSFP memang
   lebih lebar dari SFP, dan SFP lebih lebar dari RJ45. */
.chassis {
  border-radius: 8px; padding: 14px;
  background: linear-gradient(180deg, #1a2334, #0f1626);
  border: 1px solid #2a3549;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 6px 18px rgba(0,0,0,.4);
}
[data-theme="light"] .chassis {
  background: linear-gradient(180deg, #58657c, #3d4859);
  border-color: #2f3949;
}
.chassis-brand {
  display: flex; align-items: baseline; gap: 8px; margin-bottom: 12px;
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: #9fb1c9;
}

/* Tiap kelompok media jadi satu "bay", persis seperti chassis nyata yang
   memisahkan blok tembaga dari blok optik. */
.chassis-bays { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.bay {
  padding: 8px 10px 6px; border-radius: 5px;
  background: rgba(0,0,0,.22); border: 1px solid rgba(255,255,255,.05);
}
.bay-ports { display: grid; gap: 5px; grid-template-columns: repeat(var(--per-row, 8), auto); }
.bay-label {
  margin-top: 7px; font-size: 9.5px; letter-spacing: .05em;
  text-transform: uppercase; color: #8b9db7; text-align: center;
}

.port {
  position: relative; height: 30px; border-radius: 2px;
  display: grid; place-items: center; cursor: default;
  font-family: var(--font-mono); font-size: 9px; color: #6d7f98;
}
.port-num { position: relative; z-index: 2; pointer-events: none; }
.port-face { position: absolute; inset: 0; border-radius: 2px; }

/* RJ45: badan persegi dengan takik di bawah, meniru 8P8C. */
.port-rj45 { width: 30px; }
.port-rj45 .port-face {
  background: #0e1626; border: 1px solid #33415a;
  box-shadow: inset 0 2px 5px rgba(0,0,0,.6);
  clip-path: polygon(0 0, 100% 0, 100% 72%, 70% 72%, 70% 100%, 30% 100%, 30% 72%, 0 72%);
}
/* SFP: cage sempit satu lane, ada bibir di atas. */
.port-sfp { width: 40px; }
.port-sfp .port-face {
  background: linear-gradient(180deg, #16203300 0 5px, #0e1626 5px);
  border: 1px solid #3a4a66; border-radius: 3px;
  box-shadow: inset 0 3px 6px rgba(0,0,0,.65);
}
.port-sfp::before {
  content: ""; position: absolute; top: 4px; left: 5px; right: 5px; height: 2px;
  background: #33415a; border-radius: 1px; z-index: 1;
}
/* QSFP: cage lebar, empat penanda lane. */
.port-qsfp { width: 58px; }
.port-qsfp .port-face {
  background: #0c1424; border: 1px solid #44567a; border-radius: 3px;
  box-shadow: inset 0 3px 8px rgba(0,0,0,.7);
}
.port-qsfp::before {
  content: ""; position: absolute; top: 4px; left: 7px; right: 7px; height: 3px;
  z-index: 1; border-radius: 1px;
  background: repeating-linear-gradient(90deg, #3d4f70 0 4px, transparent 4px 9px);
}
/* Combo: dua cage bertumpuk, digambar dengan garis putus. */
.port-combo { width: 40px; }
.port-combo .port-face {
  background: #0e1626; border: 1px dashed #4a5c7d; border-radius: 3px;
  box-shadow: inset 0 2px 5px rgba(0,0,0,.55);
}
.port-virtual { width: 34px; }
.port-virtual .port-face { background: transparent; border: 1px dashed #33415a; border-radius: 3px; }

/* Hijau = ifOperStatus up. Diambil dari perangkat, bukan ditebak dari model. */
.port.ps-up { color: #b9f5d8; }
.port.ps-up .port-face {
  background: linear-gradient(180deg, #12503a, #0d3a2b);
  border-color: #17a06a;
  box-shadow: inset 0 2px 5px rgba(0,0,0,.4), 0 0 9px rgba(18,183,106,.4);
}
.port.ps-down { opacity: .8; }
.port.has-desc::after {
  content: ""; position: absolute; top: 2px; right: 2px; z-index: 2;
  width: 4px; height: 4px; border-radius: 50%; background: var(--brand-300);
}

.chassis-legend {
  display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: 12px;
  padding-top: 10px; border-top: 1px solid rgba(255,255,255,.06);
  font-size: 11px; color: #9fb1c9;
}
.port-dot { width: 9px; height: 9px; border-radius: 2px; display: inline-block;
            background: #10192a; border: 1px solid #33415a; }
.port-dot.ps-up { background: #12503a; border-color: #17a06a; }

/* Kunci media: bentuk yang sama persis dengan yang di chassis, disertai
   penjelasan singkat. Legenda yang memakai ikon berbeda dari gambarnya tidak
   mengajarkan apa pun. */
.media-key {
  display: grid; gap: var(--sp-3); margin-top: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.media-key-item {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 9px 11px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--line);
}
.media-key-item .port { flex: none; }
.media-key-item .hint { font-size: 11.5px; line-height: 1.45; margin-top: 2px; }

/* ── 29. PENANDA KOLOM EDITABEL (v30) ────────────────────────────────────── */
th.is-editable::after {
  content: "";
  display: inline-block; width: 9px; height: 9px; margin-left: 5px;
  vertical-align: -1px; opacity: .45;
  background: currentColor;
  -webkit-mask: var(--pencil) center / contain no-repeat;
  mask: var(--pencil) center / contain no-repeat;
}
:root {
  --pencil: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M12 20h9'/><path d='M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4z'/></svg>");
}


/* Bayangan bezel disesuaikan per tema: di tema terang, bayangan gelap pekat
   membuat perangkat terlihat kotor, bukan timbul. */
[data-theme="light"] .u-dev {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9),
              inset 0 -1px 0 rgba(0, 0, 0, .12),
              0 1px 3px rgba(20, 35, 60, .18);
}
[data-theme="light"] .u-dev.is-through {
  background: repeating-linear-gradient(135deg, #eef1f6 0 7px, #dfe4ec 7px 14px);
}
[data-theme="light"] .u-slot:hover, [data-theme="light"] .u-slot:focus-visible {
  background: rgba(29, 111, 208, .12);
}

/* ── 30. PANEL OPERASIONAL DASHBOARD (v34) ───────────────────────────────────
   Dua panel berbagi satu baris dengan tinggi yang SAMA. Versi v32 memaksa
   panel alarm setinggi dua baris grid, sehingga saat alarmnya sedikit ia
   menyisakan rongga ~220 px dan panel di sebelahnya jadi tidak sejajar. */
.ops-grid {
  display: grid; gap: var(--sp-3); align-items: stretch;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
}
@media (max-width: 1100px) { .ops-grid { grid-template-columns: 1fr; } }

.ops-grid > .card { display: flex; flex-direction: column; }
/* Tinggi dikunci: daftar yang panjang menggulir di dalam kartunya sendiri,
   bukan mendorong seluruh halaman ke bawah. */
.ops-scroll { flex: 1; overflow-y: auto; max-height: 232px; min-height: 0; }
.ops-alarm.is-hot { border-color: rgba(229, 72, 77, .45); }
.ops-alarm .tbl td { padding: 6px var(--sp-3); }
.ops-alarm .tbl tr:last-child td { border-bottom: 0; }

/* ── Statistik mendatar ──────────────────────────────────────────────────────
   Kapasitas dan Engine dulu jadi dua kartu tinggi yang tidak pernah sejajar
   dengan tetangganya. Sebagai baris angka, keduanya terbaca sekali pandang. */
.statline {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2) var(--sp-5); padding: var(--sp-3) var(--sp-4);
}
.statline.is-sub { border-top: 1px solid var(--line); background: var(--surface-2); }
.statline-head {
  display: flex; align-items: center; gap: 7px;
  min-width: 116px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted);
}
.statline-head svg.i { font-size: 14px; color: var(--accent); }

.stat {
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
  padding: 3px 0; border-radius: var(--r-sm);
}
a.stat { text-decoration: none; }
a.stat:hover .stat-n { color: var(--accent); }
a.stat:hover { text-decoration: none; }
.stat-n { font-size: 17px; font-weight: 700; line-height: 1.15; color: var(--text); }
.stat-l { font-size: 11px; color: var(--text-2); white-space: nowrap; }
.stat-l .hint { font-size: 11px; }
.stat.is-alert .stat-n { color: var(--crit); }

@media (max-width: 700px) {
  .statline { gap: var(--sp-3) var(--sp-4); }
  .stat-l .hint { display: none; }
}

/* ── 31. DATA REFERENSI (v32) ────────────────────────────────────────────────
   Kolom aksi diberi lebar tetap di semua panel supaya tombolnya sejajar dari
   kartu ke kartu. Sebelumnya tiap tabel melebar sendiri dan tombol simpan
   berpindah tempat setiap kali mata berpindah panel. */
.col-act { width: 76px; text-align: right; white-space: nowrap; }
.ref-grid .card-head { min-height: 44px; }
.ref-grid .tbl th { white-space: nowrap; }

/* ── 32. TOPOLOGI v33: sorot, wallboard, link hasil penemuan ─────────────── */
.topo-node.is-dim, .topo-link.is-dim { opacity: .16; }
.topo-node.is-hit .topo-box { stroke: var(--brand-400); stroke-width: 3; }
.topo-node.is-hit { filter: drop-shadow(0 0 10px rgba(29, 111, 208, .55)); }

/* Link hasil LLDP diberi garis putus halus: ia berasal dari perangkat, bukan
   dari tangan operator, dan bedanya perlu terlihat saat dokumentasi diperiksa. */
.topo-link.is-discovered .topo-line { stroke-dasharray: 10 3; }

/* Wallboard: sidebar, topbar, dan toolbar disembunyikan; kanvas mengisi layar. */
body.is-wallboard .rail,
body.is-wallboard .topbar,
body.is-wallboard .tabbar { display: none; }
body.is-wallboard .shell { grid-template-columns: 1fr; }
body.is-wallboard .content { padding: 0; }
body.is-wallboard .card { border: 0; border-radius: 0; background: transparent; }
body.is-wallboard .topo-wrap { height: 100vh; }
body.is-wallboard .toolbar,
body.is-wallboard .card-pad.hint { display: none; }


/* Di layar sempit, tabbar ada di bawah — toast digeser ke atasnya. */
@media (max-width: 900px) { .toasts { bottom: calc(var(--tabbar-h, 58px) + var(--sp-3)); } }


/* ── 35. NOC COMMAND CENTER ──────────────────────────────────────────────── */
.noc-hero { display:grid; grid-template-columns:minmax(0,1.35fr) minmax(430px,1fr); gap:18px; padding:18px; border-color:var(--line); }
.noc-hero.is-warning { border-color:rgba(245,165,36,.45); }
.noc-hero.is-critical { border-color:rgba(229,72,77,.55); }
.noc-hero-main { min-width:0; }
.noc-health-row { display:flex; align-items:center; gap:16px; margin:6px 0 16px; }
.noc-health-score { font:700 48px/1 var(--font-mono); letter-spacing:-.045em; }
.noc-health-score small { font-size:18px; margin-left:3px; color:var(--muted); }
.noc-health-state { font:800 11px/1 var(--font-mono); letter-spacing:.14em; }
.noc-health-state.is-good { color:var(--ok); }
.noc-health-state.is-warning { color:var(--warn); }
.noc-health-state.is-critical { color:var(--crit); }
.noc-metrics { display:grid; grid-template-columns:repeat(5,minmax(72px,1fr)); gap:8px; align-content:start; }
.noc-metric, .noc-engine { min-height:70px; background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-md); padding:10px 11px; text-align:left; }
.noc-metric { cursor:pointer; color:var(--text); }
.noc-metric:hover { border-color:var(--accent); background:var(--surface); }
.noc-metric span, .noc-engine .eyebrow { display:block; font-size:9px; color:var(--muted); letter-spacing:.08em; text-transform:uppercase; }
.noc-metric strong, .noc-engine strong { display:block; margin-top:5px; font:800 22px/1 var(--font-mono); }
.metric-critical strong { color:var(--crit); }
.metric-warning strong { color:var(--warn); }
.metric-muted strong { color:var(--muted); }
.noc-engine { grid-column:span 2; }
.noc-engine strong { font-size:13px; }
.severity-strip { display:flex; height:8px; overflow:hidden; border-radius:999px; background:var(--line); }
.severity-strip span { min-width:0; transition:width .35s ease; }
.severity-strip .s-down { background:var(--crit); }
.severity-strip .s-lag { background:var(--warn); }
.severity-strip .s-up { background:var(--ok); }
.severity-strip .s-paused { background:var(--idle); }
.noc-grid { display:grid; grid-template-columns:minmax(0,1.75fr) minmax(320px,.8fr); gap:12px; margin-top:12px; }
.noc-grid-secondary { grid-template-columns:minmax(0,1.65fr) minmax(320px,.9fr); }
.noc-panel { min-width:0; overflow:hidden; }
.noc-panel-title { display:flex; align-items:center; gap:7px; margin-top:3px; font-size:13px; font-weight:750; }
.noc-table-wrap { overflow:auto; max-height:360px; }
.noc-incident-table th { position:sticky; top:0; z-index:1; background:var(--surface); font-size:9px; letter-spacing:.08em; text-transform:uppercase; }
.noc-incident-table td { vertical-align:middle; }
.noc-incident-table .incident-row { cursor:pointer; }
.noc-incident-table .incident-row:hover { background:var(--surface-2); }
.noc-incident-table td:last-child { white-space:nowrap; }
.problem-grid { display:grid; gap:1px; grid-template-columns:1fr; background:var(--line); }
.problem-item { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:11px 13px; background:var(--surface); }
.problem-item strong { max-width:62%; text-align:right; font-size:12px; }
.problem-critical { color:var(--crit); }.problem-warn { color:var(--warn); }.problem-muted { color:var(--muted); }
.trend-grid { padding:8px 12px 12px; }
.trend-legend { display:flex; flex-wrap:wrap; gap:12px; align-items:center; font-size:10px; color:var(--muted); margin-bottom:5px; }
.trend-dot { width:7px; height:7px; display:inline-block; border-radius:50%; margin-right:5px; background:currentColor; }
.trend-ok { color:var(--ok); }.trend-blue { color:var(--accent); }.trend-crit { color:var(--crit); }
.trend-unavailable { margin-bottom:4px; }
.trend-canvas { width:100%; display:block; }
.trend-range { display:flex; gap:4px; }
.trend-range .is-on { border-color:var(--accent); color:var(--accent); }
.site-list { display:grid; gap:1px; background:var(--line); }
.site-row { display:grid; grid-template-columns:minmax(110px,1.3fr) auto minmax(160px,1.2fr); align-items:center; gap:10px; border:0; padding:10px 12px; background:var(--surface); color:var(--text); text-align:left; cursor:pointer; }
.site-row:hover { background:var(--surface-2); }
.site-copy b, .site-copy span { display:block; }.site-copy b { font-size:12px; }.site-copy span { margin-top:2px; font-size:9px; }
.site-status { font:800 14px var(--font-mono); }.site-ok { color:var(--ok); }.site-warn { color:var(--warn); }
.site-counts { display:flex; justify-content:flex-end; gap:8px; flex-wrap:wrap; font:9px var(--font-mono); color:var(--muted); }.site-counts i { font-style:normal; }
.noc-monitor-heading { margin-top:12px; }
.filter-toolbar { display:flex; align-items:center; flex-wrap:wrap; gap:7px; padding:10px 12px; border-top:1px solid var(--line); background:var(--surface-2); }
.search-wide { flex:1 1 260px; max-width:none; }
.filter-toolbar .select { width:auto; min-width:120px; }
.filter-toolbar .btn.is-active { color:var(--accent); border-color:var(--accent); }
body.is-wallboard .noc-hero { border-radius:0; }
body.is-wallboard .filter-toolbar, body.is-wallboard .noc-monitor-heading { display:none; }
body.is-wallboard .content { padding:12px; }
body.is-wallboard .noc-grid-primary { grid-template-columns:minmax(0,2.2fr) minmax(300px,.8fr); }
body.is-wallboard .noc-table-wrap { max-height:42vh; }
body.is-wallboard .site-list { max-height:42vh; overflow:auto; }
body.is-wallboard .group { margin-bottom:7px; }
body.is-wallboard .group-head { padding:7px 10px; }
body.is-wallboard .grid { margin-top:7px; gap:7px; }
body.is-wallboard .host { padding:7px 8px 7px 11px; }

@media (max-width:1180px) {
  .noc-hero { grid-template-columns:1fr; }
  .noc-metrics { grid-template-columns:repeat(5,minmax(75px,1fr)); }
}
@media (max-width:900px) {
  .noc-grid,.noc-grid-secondary { grid-template-columns:1fr; }
  .noc-metrics { grid-template-columns:repeat(5,minmax(60px,1fr)); }
  .noc-engine { grid-column:span 1; }
  .site-row { grid-template-columns:1fr auto; }.site-counts { grid-column:1/-1; justify-content:flex-start; }
}
@media (max-width:640px) {
  .noc-hero { padding:13px; }.noc-health-score { font-size:38px; }.noc-metrics { grid-template-columns:repeat(2,1fr); }.noc-metric:nth-child(1),.noc-metric:nth-child(2){grid-column:span 1}.noc-engine{grid-column:span 1;}
  .problem-item { align-items:flex-start; flex-direction:column; gap:4px; }.problem-item strong { max-width:none; text-align:left; }
  .filter-toolbar .select,.filter-toolbar .search { width:100%; max-width:none; }
  .noc-incident-table { min-width:760px; }
}
.host-context{font-size:11px;color:var(--muted);line-height:1.3;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.host-cell[data-device-url]{cursor:pointer}.incident-row[data-device-url]{cursor:pointer}.incident-row:hover{background:var(--surface-2)}

/* ============================================================================
   NET-WATCH NOC v36 — Design System / Operations UX
   ========================================================================== */
:root{
  --focus-ring:0 0 0 3px rgba(86,168,245,.24);
  --metric-gap:10px;
  --content-max:1680px;
}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.48;cursor:not-allowed}
.btn-xs{height:28px;padding:0 9px;font-size:11px}
.btn-icon{display:inline-grid;place-items:center}
.search-xl{min-height:46px}
.search kbd,.nav-search kbd{font:600 10px var(--font-mono);color:var(--muted);border:1px solid var(--line);padding:3px 5px;border-radius:4px;background:var(--surface-2)}
.rail-nav{overflow:auto;min-height:0}
.nav-search{width:100%;display:flex;align-items:center;gap:9px;background:var(--surface-2);border:1px solid var(--line);color:var(--text-2);border-radius:8px;padding:8px 10px;margin-bottom:10px;cursor:pointer}
.nav-search:hover{border-color:var(--brand-400);color:var(--text)}
.nav-primary{margin-bottom:7px}
.nav-group{margin-top:7px}
.nav-group-title{width:100%;display:flex;align-items:center;justify-content:space-between;padding:7px 10px;border:0;background:transparent;color:var(--muted);font:700 9px var(--font-ui);letter-spacing:.12em;text-align:left;cursor:pointer}
.nav-group-title .i{font-size:11px;transition:transform .16s}
.nav-group-title[aria-expanded="false"] .i{transform:rotate(-90deg)}
.nav-group-title[aria-expanded="false"]+.nav-group-items{display:none}
.nav-group-items{display:flex;flex-direction:column;gap:2px}
.nav-link{margin:0 3px}
.nav-link span{min-width:0}
.nav-link.is-active{box-shadow:0 0 0 1px rgba(255,255,255,.08) inset}
[data-nav].is-active{font-weight:650}
.global-results{margin-top:14px;display:grid;gap:5px;max-height:56vh;overflow:auto}
.global-group{padding-top:9px}.global-group-title{font:700 10px var(--font-ui);color:var(--muted);letter-spacing:.1em;margin:0 0 5px 2px}
.global-result{display:flex;align-items:center;gap:10px;padding:9px 10px;border:1px solid transparent;border-radius:8px;background:var(--surface-2);color:var(--text)}
.global-result:hover{text-decoration:none;border-color:var(--line);background:var(--surface)}
.global-result .type{font-size:10px;color:var(--muted);min-width:58px}.global-result .meta{font-size:11px;color:var(--muted)}
.ops-section{margin-top:var(--sp-4)}.section-head{display:flex;align-items:end;justify-content:space-between;gap:var(--sp-3);margin-bottom:var(--sp-2)}
.section-title{font-size:13px;font-weight:700;letter-spacing:.02em}.section-desc{font-size:11px;color:var(--muted)}
.metric-grid{display:grid;grid-template-columns:repeat(6,minmax(130px,1fr));gap:var(--metric-gap)}
.metric-card{position:relative;min-width:0;border:1px solid var(--line);background:var(--surface);padding:12px;border-radius:8px}
.metric-card .k{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.metric-card .v{font:700 24px/1 var(--font-mono);margin-top:7px}.metric-card .sub{margin-top:5px;font-size:10px;color:var(--muted)}
.metric-card[data-filter]{cursor:pointer}.metric-card[data-filter]:hover{border-color:var(--brand-400)}
.health-hero{display:grid;grid-template-columns:1.35fr 2fr;gap:12px}.health-score{display:flex;align-items:center;gap:18px;border:1px solid var(--line);background:var(--surface);padding:16px;border-radius:8px}
.health-score .score{font:700 clamp(36px,4vw,58px)/1 var(--font-mono);letter-spacing:-.04em}.health-ring{width:82px;height:82px;border-radius:50%;display:grid;place-items:center;background:conic-gradient(var(--ok) var(--health,100%),var(--surface-2) 0);position:relative}.health-ring:after{content:"";position:absolute;inset:7px;border-radius:50%;background:var(--surface)}
.health-ring span{position:relative;z-index:1;font:700 18px var(--font-mono)}
.status-line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.incident-table .incident-row{cursor:pointer}.incident-table .incident-row:hover{background:var(--surface-2)}
.badge-dot{display:inline-flex;align-items:center;gap:5px}
.badge-dot:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
.badge-critical{color:var(--crit)}.badge-warning{color:var(--warn)}.badge-info2{color:var(--accent)}
.timeline{display:grid;gap:0;border-left:1px solid var(--line);margin-left:6px;padding-left:16px}
.timeline-item{position:relative;padding:0 0 14px}.timeline-item:before{content:"";position:absolute;left:-20px;top:5px;width:7px;height:7px;border:2px solid var(--accent);border-radius:50%;background:var(--surface)}
.timeline-item .ts{font:10px var(--font-mono);color:var(--muted)}.timeline-item .action{font-weight:650;font-size:12px}
.kpi-strip{display:flex;gap:8px;flex-wrap:wrap}.kpi{display:inline-flex;gap:7px;align-items:center;padding:7px 9px;border:1px solid var(--line);border-radius:7px;background:var(--surface-2);font-size:11px}.kpi b{font:700 12px var(--font-mono)}
.table-dense th,.table-dense td{padding:8px 10px}
.tabs-ops{display:flex;gap:2px;border-bottom:1px solid var(--line);overflow:auto}.tabs-ops button{border:0;background:transparent;padding:9px 12px;color:var(--muted);border-bottom:2px solid transparent;cursor:pointer;white-space:nowrap}.tabs-ops button.is-active{color:var(--text);border-color:var(--accent)}
.card-flat{border:1px solid var(--line);background:var(--surface);border-radius:8px}.no-shadow{box-shadow:none!important}
.state-label{display:inline-flex;align-items:center;gap:6px;font-weight:700;font-size:11px}.state-label .dot{width:7px;height:7px;border-radius:50%;background:currentColor}.state-up{color:var(--ok)}.state-down{color:var(--crit)}.state-warn{color:var(--warn)}.state-paused{color:var(--idle)}
.skeleton-line{height:10px;border-radius:4px;background:var(--surface-2);animation:nwPulse 1.2s infinite}.skeleton-line.w60{width:60%}.skeleton-line.w30{width:30%}
@keyframes nwPulse{50%{opacity:.45}}
@media(max-width:1200px){.metric-grid{grid-template-columns:repeat(3,minmax(130px,1fr))}.health-hero{grid-template-columns:1fr}}
@media(max-width:760px){.metric-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.content{padding:12px}.topbar{padding:10px 12px}.nav-group-title{padding-top:10px;padding-bottom:10px}.health-score{padding:12px}.health-ring{width:68px;height:68px}.health-score .score{font-size:36px}}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}

/* DCIM card mode */
.tbl.device-card-table{display:block}.tbl.device-card-table thead{display:none}.tbl.device-card-table tbody{display:grid;grid-template-columns:repeat(auto-fit,minmax(270px,1fr));gap:10px;padding:10px}.tbl.device-card-table tbody tr{display:grid;grid-template-columns:1fr;gap:8px;border:1px solid var(--line);border-radius:8px;background:var(--surface-2);padding:12px}.tbl.device-card-table tbody td{display:block!important;border:0!important;padding:0!important}.tbl.device-card-table tbody td:first-child{position:absolute}.tbl.device-card-table tbody td:nth-child(2) .cell{font-weight:700;font-size:15px}.tbl.device-card-table tbody td:nth-child(3)::before{content:'Role ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(4)::before{content:'Site ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(5)::before{content:'Vendor ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(6)::before{content:'Model ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(7)::before{content:'Rack ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(8)::before{content:'Height ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(9)::before{content:'Status ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(10)::before{content:'Monitoring ';color:var(--muted)}.tbl.device-card-table tbody td:nth-child(11){text-align:right!important;padding-top:4px!important;border-top:1px solid var(--line-soft)!important}.mode-switch{display:inline-flex;border:1px solid var(--line);border-radius:7px;overflow:hidden}.mode-switch .mode-btn{border:0;border-radius:0}.mode-switch .mode-btn.is-active{background:var(--brand-500);color:#fff}

/* v36.1 final gap closure */
.subnav-tabs{display:flex;gap:2px;overflow:auto;border-bottom:1px solid var(--line);margin:0 0 var(--sp-3)}
.subnav-tabs .subtab{display:inline-flex;align-items:center;min-height:38px;padding:8px 12px;color:var(--muted);text-decoration:none;border-bottom:2px solid transparent;white-space:nowrap}
.subnav-tabs .subtab:hover{color:var(--text);background:var(--surface-2)}
.subnav-tabs .subtab.is-active{color:var(--text);border-color:var(--accent);font-weight:700}
.notice-row{display:flex;gap:14px;justify-content:space-between;align-items:flex-start;padding:13px 0;border-bottom:1px solid var(--line)}
.notice-row:last-child{border-bottom:0}.notice-main{display:grid;gap:5px;min-width:0}.notice-row.is-unread{background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 5%,transparent),transparent);padding-left:10px}
.error-state{padding:20px;text-align:center;color:var(--crit);border:1px solid color-mix(in srgb,var(--crit) 35%,var(--line));border-radius:8px;background:var(--surface)}
.metric-inline{display:inline-flex;align-items:center;gap:7px;font-size:12px}.metric-inline .dot{width:7px;height:7px;border-radius:50%;background:var(--warn)}
[hidden]{display:none!important}
@media(max-width:760px){.notice-row{flex-direction:column}.notice-row .row{width:100%}.subnav-tabs .subtab{padding-left:10px;padding-right:10px}}

.nav-drawer-link{display:flex;align-items:center;gap:10px;padding:11px 12px;border:1px solid var(--line);border-radius:8px;color:var(--text);text-decoration:none;background:var(--surface-2)}.nav-drawer-link:hover{background:var(--surface-3)}.modal-drawer .modal-box{max-width:420px;margin-left:auto;margin-right:auto}
@media(min-width:761px){.modal-drawer{display:none!important}}

/* v38 operational UX: panduan terpadu + 404 yang diagnostik */
.guide-layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:14px;align-items:start}
.guide-index{position:sticky;top:14px}
.guide-index-list{display:grid;gap:2px;padding:8px}
.guide-index-list a{display:block;padding:8px 10px;border-radius:8px;color:var(--muted);font-size:12px;border:1px solid transparent}
.guide-index-list a:hover,.guide-index-list a:focus-visible{color:var(--text);background:var(--panel-2);border-color:var(--line);outline:none}
.guide-content{padding:0 24px}
.guide-section{padding:28px 0;border-bottom:1px solid var(--line)}
.guide-section:last-child{border-bottom:0}
.guide-section h2{margin:5px 0 10px;font-size:20px;letter-spacing:-.01em}
.guide-section h3{margin:20px 0 8px;font-size:14px}
.guide-section p,.guide-section li{font-size:13px;line-height:1.7;color:var(--muted)}
.guide-section ul{margin:10px 0 0;padding-left:20px}
.guide-rule{margin-top:14px;padding:12px 14px;border-left:3px solid var(--accent);background:var(--panel-2);border-radius:0 8px 8px 0;color:var(--muted);font-size:12.5px;line-height:1.65}
.guide-dl{display:grid;grid-template-columns:170px 1fr;gap:8px 18px;margin:14px 0 0}
.guide-dl dt{font-weight:700;color:var(--text);font-size:12px}
.guide-dl dd{margin:0;color:var(--muted);font-size:12.5px;line-height:1.55}
.guide-flow{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:14px 0;padding:10px 0}
.guide-flow span{padding:6px 9px;border:1px solid var(--line);background:var(--panel-2);border-radius:7px;font-size:10px;font-weight:800;letter-spacing:.06em}
.guide-flow i{font-style:normal;color:var(--muted)}
.guide-meta{display:flex;align-items:center;gap:10px}
.guide-last{padding-bottom:30px}
.shortcut-table{display:grid;gap:7px;max-width:520px}
.shortcut-table>div{display:flex;align-items:center;gap:6px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--panel-2);font-size:12px;color:var(--muted)}
.shortcut-table span:last-child{margin-left:4px;color:var(--text)}
.empty-state-page{min-height:55vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:40px 20px}
.empty-state-icon{display:grid;place-items:center;width:56px;height:56px;border-radius:14px;border:1px solid var(--line);background:var(--panel-2);color:var(--warn);margin-bottom:12px}
.empty-state-icon .i{width:28px;height:28px}
.center-actions{justify-content:center;margin-top:16px}
@media (max-width:900px){.guide-layout{grid-template-columns:1fr}.guide-index{position:static}.guide-content{padding:0 16px}.guide-dl{grid-template-columns:1fr;gap:4px}.guide-dl dd{margin-bottom:8px}.guide-flow{align-items:flex-start}.guide-meta{display:none}}
