/* ============================================================
   global.css — TechnoFix  |  Design System Terpusat
   v2.0 — Refactored for full visual consistency across:
   Dashboard ↔ Pelanggan ↔ Detail Pelanggan

   Isi:
   1.  Reset & Box Sizing
   2.  CSS Variables (satu sumber kebenaran)
   3.  Base — html, body, background bertekstur
   4.  Header — navy + safe-area + animasi partikel jaringan
   5.  Topbar Nav
   6.  Header Actions (icon-btn, avatar, profile)
   7.  Bottom Navbar (mobile, myBCA style)
   8.  Page Wrapper
   9.  Tombol Umum
   10. Stat Cards (3 kolom maks, gradient warna)
   11. Badge & Status
   12. Modal (overlay + sheet + centered popup)
   13. Toast Notification
   14. Spinner / Loading
   15. Form Input (seragam semua halaman)
   16. Empty State
   17. Date Badge
   18. List Header
   19. Device Card (global)
   20. Utility Classes
   20b. Zebra Striping Global
   21. Animasi Global
   22. Perangkat Bottom Sheet (psheet)
   ━━━ BAGIAN BARU (v2.0) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   23. Dropdown Global — standar box, padding, chevron
   24. Section Card Global — wrapper konten, head, table
   25. Skeleton Loader Global — shimmer konsisten
   26. Profile Dropdown
   27. Responsive Global
   ============================================================ */


/* ══════════════════════════════════════════════════════════
   1. RESET & BOX SIZING
══════════════════════════════════════════════════════════ */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}


/* Font ikon Material Symbols Outlined ada di statis/icons.css (file
   TERPISAH, di-<link> sendiri di tiap HTML) — bukan di sini, supaya
   halaman yang TIDAK load global.css (login, invoice/struk, landing,
   isolir, superadmin) tetap kebagian tanpa perlu ikut semua desain
   global.css yang tidak relevan buat mereka. Lihat icons.css. */


/* ══════════════════════════════════════════════════════════
   2. CSS VARIABLES — satu sumber kebenaran
══════════════════════════════════════════════════════════ */
:root {
  /* ── Skala Font — 6 level baku, dipakai di seluruh app ──
     Diperluas dari 3 ke 6 level (Agustus 2026) — banyak komponen baru
     (tab Detail OLT: Redaman/Per Port/ONU Liar/Script/Konsol, dsb) pakai
     angka px ad-hoc langsung (11px, 10.5px, 12px, dst) tanpa acuan,
     hasilnya ukuran teks tidak konsisten antar-bagian walau fungsinya
     sama (mis. keterangan/hint di satu tempat 11px, di tempat lain
     10px). 6 level ini WAJIB dipakai (bukan angka px baru lagi) tiap
     nulis komponen baru, dipilih berdasar FUNGSI teksnya:

     --fs-hero      28px  Sangat jarang — angka besar/highlight utama
                          (mis. nilai redaman final di kalkulator).
     --fs-title-lg  22px  Judul halaman (h1.page-title).
     --fs-title-sm  15px  Judul card/section (form-card-title, dash-
                          section-title, judul modal, dst).
     --fs-body      13px  Teks isi utama: label, isi tabel, tombol,
                          teks chart (axis/tick/legend) — bacaan normal.
     --fs-caption   12px  Sub-teks/keterangan pendukung: hint, deskripsi
                          field, badge, meta info sekunder.
     --fs-small     11px  Detail kecil: catatan tambahan, timestamp,
                          keterangan di bawah keterangan (2 level turun).

     Kalau butuh lebih kecil dari --fs-small, itu tandanya teksnya
     sebaiknya disembunyikan/diringkas, BUKAN dikecilkan terus — jangan
     bikin level ke-7. */
  --fs-hero:     28px;
  --fs-title-lg: 22px;
  --fs-title-sm: 15px;
  --fs-body:     13px;
  --fs-caption:  12px;
  --fs-small:    11px;

  /* ── Warna Utama ── */
  --primary:        #0040a1;
  --primary-dark:   #003080;
  --primary-light:  #e8eeff;
  --primary-ring:   rgba(0, 64, 161, .12);

  /* ── Header (navy, selaras bottom-nav) ── */
  --header-bg:      #003f88;
  --header-border:  rgba(255,255,255,.08);
  --header-text:    #ffffff;
  --header-sub:     rgba(255,255,255,.60);
  --header-item:    rgba(255,255,255,.70);
  --header-active:  #ffffff;
  --header-h:       78px;

  /* ── Warna Status ── */
  --green:          #006c47;
  --green-bg:       #e6f4ee;
  --green-border:   #a3d9c0;

  --red:            #ba1a1a;
  --red-bg:         #fde8e8;
  --red-border:     #f3b4b4;

  --amber:          #b45309;
  --amber-bg:       #fef3e2;
  --amber-border:   #fcd9a0;

  --blue:           #1d4ed8;
  --blue-bg:        #eff6ff;
  --blue-border:    #bfdbfe;

  --navy:        #0f172a;
  --navy-bg:     #f8fafc;
  --navy-border: #e2e8f0;

  /* ── Warna Neutral ── */
  --bg:             #ffffff;
  --surface:        #f4f6fb;
  --surface-2:      #eef1f8;
  --border:         #e4e8f0;
  --border-2:       #c8d0e0;

  /* ── Teks ── */
  --text:           #003f88;
  --text-muted:     #2a4a7a;
  --text-dim:       #6a82a8;

  /* ── Font ── */
  --sans:           'Poppins', sans-serif;
  --heading:        'Montserrat', sans-serif;

  /* ── Border Radius ── */
  --r-sm:   8px;
  --r-md:   12px;
  --r-lg:   16px;
  --r-xl:   22px;

  /* ── Shadow ── */
  --shadow-xs: 0 1px 2px rgba(0,0,0,.05);
  --shadow-sm: 0 1px 4px rgba(0,0,0,.07), 0 1px 2px rgba(0,0,0,.04);
  --shadow-md: 0 4px 16px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04);
  --shadow-lg: 0 12px 36px rgba(0,0,0,.11), 0 4px 8px rgba(0,0,0,.05);

  /* ── Card / Section Header ── */
  --card-head-bg:      #003f88;
  --card-head-text:    #ffffff;
  --card-head-icon:    rgba(255,255,255,.80);
  --card-head-border:  rgba(255,255,255,.12);

  /* ── Bottom Navbar ── */
  --bnav-bg:        #003f88;
  --bnav-active:    #ffffff;
  --bnav-inactive:  rgba(255,255,255,.55);
  --bnav-h:         62px;

  /* ── Background Texture ── */
  --page-bg: #f0f4fb;

  /* ── Stat Card — Blue Family ── */
  /* Card 1 — Biru Royal */
  --card-1-bg:      linear-gradient(135deg, #1a3a8f 0%, #2554c7 100%);
  --card-1-border:  rgba(255,255,255,.15);
  --card-1-shadow:  rgba(37, 84, 199, 0.30);
  --card-1-accent:  #ffffff;
  --card-1-solid:   #2554c7;

  /* Card 2 — Biru Teal / Cyan */
  --card-2-bg:      linear-gradient(135deg, #0e6e8c 0%, #0ea5c9 100%);
  --card-2-border:  rgba(255,255,255,.15);
  --card-2-shadow:  rgba(14, 165, 201, 0.28);
  --card-2-accent:  #ffffff;
  --card-2-solid:   #0ea5c9;

  /* Card 3 — Biru Slate / Steel */
  --card-3-bg:      linear-gradient(135deg, #1e3a5f 0%, #2e6197 100%);
  --card-3-border:  rgba(255,255,255,.15);
  --card-3-shadow:  rgba(46, 97, 151, 0.28);
  --card-3-accent:  #ffffff;
  --card-3-solid:   #2e6197;

  /* Card 4 — Biru Indigo / Ungu Biru */
  --card-4-bg:      linear-gradient(135deg, #312e81 0%, #4f46e5 100%);
  --card-4-border:  rgba(255,255,255,.15);
  --card-4-shadow:  rgba(79, 70, 229, 0.28);
  --card-4-accent:  #ffffff;
  --card-4-solid:   #4f46e5;

  /* Card 5 — Hijau Emerald */
  --card-5-bg:      linear-gradient(135deg, #064e3b 0%, #059669 100%);
  --card-5-border:  rgba(255,255,255,.15);
  --card-5-shadow:  rgba(5, 150, 105, 0.28);
  --card-5-accent:  #ffffff;
  --card-5-solid:   #059669;

  /* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     TOKEN BARU v2.0 — Spacing & Component Standards
     Digunakan oleh Dashboard, Pelanggan, Detail Pelanggan.
     Satu titik perubahan → semua halaman sinkron.
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */

  /* Spacing rhythm — konsisten di semua card & section */
  --space-xs:  8px;
  --space-sm:  12px;
  --space-md:  16px;
  --space-lg:  20px;
  --space-xl:  24px;
  --space-2xl: 32px;

  /* Section/Card padding standar (sama dengan detail_pelanggan) */
  --section-pad-v:  20px;   /* padding vertikal section */
  --section-pad-h:  24px;   /* padding horizontal section */
  --section-gap:    16px;   /* jarak antar section */

  /* Dropdown standar */
  --dd-h:          40px;    /* tinggi box dropdown */
  --dd-pad-h:      12px;    /* padding horizontal */
  --dd-font-size:  13px;    /* ukuran font */
  --dd-font-weight: 600;    /* bobot font */
  --dd-radius:     var(--r-md);
  --dd-border:     1.5px solid var(--border);
  --dd-focus-ring: none;

  /* Tabel */
  --tbl-head-size:   11px;
  --tbl-head-weight: 700;
  --tbl-head-case:   uppercase;
  --tbl-head-spacing: .06em;
  --tbl-cell-size:   13px;
  --tbl-row-h:       44px;   /* tinggi baris tabel */

  /* Skeleton shimmer */
  --skel-base:  var(--surface);
  --skel-shine: var(--surface-2);

  /* ── BW Realtime Section — selaras Resource MikroTik ──
     Warna diambil dari palette yang sama dengan sparkline
     CPU (biru) dan Memory (teal) di Resource section.
  ── */
  --bw-rx:       #378add;
  --bw-tx:       #1d9e75;
  --bw-live-dot: #4ade80;
}


/* ══════════════════════════════════════════════════════════
   3. BASE
══════════════════════════════════════════════════════════ */
html {
  scroll-behavior: smooth;
  max-width: 100%;
  overflow-x: hidden;
}

body {
  font-family: var(--sans);
  color: var(--text);
  min-height: 100vh;
  font-size:var(--fs-title-sm);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;

  background-color: var(--page-bg);
  background-image:
    radial-gradient(circle at 20% 10%, rgba(0,64,161,.06) 0%, transparent 50%),
    radial-gradient(circle at 80% 90%, rgba(0,174,239,.05) 0%, transparent 50%),
    radial-gradient(circle at 60% 40%, rgba(0,108,71,.04) 0%, transparent 40%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Ccircle cx='1' cy='1' r='1' fill='%230040a1' fill-opacity='0.04'/%3E%3C/svg%3E");
  background-attachment: fixed;
}

/* Hapus monospace/Courier di seluruh aplikasi */
.mono-text,
.tbl-rx, .tbl-jatuh-tempo, .tbl-hp, .tbl-ip,
.device-meta-item, .device-ip,
.form-input.mono, .field-input.mono {
  font-family: var(--sans) !important;
}


/* ══════════════════════════════════════════════════════════
   4. HEADER
══════════════════════════════════════════════════════════ */
.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  height: var(--header-h);
  background: var(--header-bg);
  border-bottom: 1px solid var(--header-border);
  box-shadow: 0 2px 20px rgba(0,0,0,.25);
  overflow: visible;
  background-image:
    radial-gradient(ellipse 80% 60% at 15% 50%, rgba(0,174,239,.12) 0%, transparent 70%),
    radial-gradient(ellipse 50% 90% at 85% 20%, rgba(205,220,240,.10) 0%, transparent 60%),
    linear-gradient(135deg, #001f3f 0%, #003f88 45%, #00254d 100%);
}

.header::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.07) 1px, transparent 1px),
    linear-gradient(180deg, rgba(255,255,255,.10) 0%, transparent 55%);
  background-size: 26px 26px, 26px 26px, 100% 100%;
  opacity: .6;
  pointer-events: none;
  z-index: 0;
}

.header::after {
  content: '';
  position: absolute;
  top: -40%; left: -10%;
  width: 60%; height: 200%;
  background: radial-gradient(ellipse, rgba(0,174,239,.08) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
  clip-path: inset(0);
  mix-blend-mode: screen;
  animation: headerBlobFloat 7s ease-in-out infinite alternate;
}

/* EFFECT 3: kilau diagonal yang menyapu header (lihat initHeaderFx di global.js) */
.header-shine {
  position: absolute;
  top: 0; left: -150%;
  width: 60%; height: 100%;
  background: linear-gradient(115deg, transparent, rgba(170,195,230,.20), rgba(255,255,255,.32), rgba(170,195,230,.20), transparent);
  transform: skewX(-18deg);
  animation: headerShineSweep 4.5s ease-in-out infinite;
  pointer-events: none;
  z-index: 1;
  clip-path: inset(0);
}

/* EFFECT 2: garis aksen bergerak di tepi bawah header */
.header-accent {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, #5b7fae 30%, #e8edf5 50%, #5b7fae 70%, transparent);
  background-size: 200% 100%;
  animation: headerAccentSlide 2.5s linear infinite;
  pointer-events: none;
  z-index: 1;
}

.header-canvas {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .88;
  z-index: 1;
}

.header-fiber {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  z-index: 1;
}

.header-inner {
  position: relative; z-index: 2;
  max-width: 100%; margin: 0 auto;
  padding: 0 32px;
  height: var(--header-h);
  display: flex; align-items: center;
  justify-content: space-between; gap: 16px;
}

.header-brand {
  display: flex; align-items: center;
  gap: 10px; flex-shrink: 0;
}

.brand-logo {
  width: 44px; height: 44px; border-radius: 11px;
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.22);
  display: flex; align-items: center; justify-content: center;
  color: #fff; overflow: hidden;
  box-shadow: 0 2px 10px rgba(0,0,0,.3);
  flex-shrink: 0;
  backdrop-filter: blur(4px);
}
.brand-logo img { width: 38px; height: 38px; object-fit: contain; border-radius: 8px; }
.brand-logo .material-symbols-outlined { font-size: 21px; }

.brand-name {
  font-size:var(--fs-title-sm); font-weight: 700;
  font-family: var(--heading);
  color: var(--header-active); letter-spacing: -.02em;
  line-height: 1.2;
}
.brand-sub {
  font-size:var(--fs-small); color: var(--header-sub); margin-top: 1px;
}


/* ══════════════════════════════════════════════════════════
   5. TOPBAR NAV
══════════════════════════════════════════════════════════ */
.topbar-nav {
  display: flex; align-items: center; gap: 2px;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: var(--r-md);
  padding: 4px;
  backdrop-filter: blur(4px);
}
.topbar-nav a {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 14px; border-radius: var(--r-sm);
  font-size:var(--fs-body); font-weight: 600;
  color: var(--header-item);
  text-decoration: none;
  transition: background .15s, color .15s, box-shadow .15s;
  white-space: nowrap;
}
.topbar-nav a .material-symbols-outlined { font-size: 16px; }
.topbar-nav a:hover {
  background: rgba(255,255,255,.12);
  color: var(--header-active);
}
.topbar-nav a.active {
  background: rgba(255,255,255,.20);
  color: var(--header-active);
  font-weight: 700;
  box-shadow: 0 1px 4px rgba(0,0,0,.2);
}

.topbar-nav .nav-perangkat { position: relative; }
.topbar-nav .nav-perangkat:hover .perangkat-dropdown,
.topbar-nav .nav-perangkat:focus-within .perangkat-dropdown {
  display: block;
}

.perangkat-dropdown {
  display: none;
  position: absolute;
  top: calc(100% + 8px); left: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  min-width: 220px;
  z-index: 1000;
  overflow: hidden;
  animation: fadeDown .18s ease;
}
.perangkat-dropdown a {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px;
  font-size:var(--fs-body); font-weight: 500;
  color: var(--text-muted); text-decoration: none;
  transition: background .12s, color .12s;
  border-radius: 0;
  background: none;
}
.perangkat-dropdown a:hover {
  background: var(--surface); color: var(--text);
}
.perangkat-dropdown a .material-symbols-outlined {
  font-size: 18px; color: var(--primary);
}


/* ══════════════════════════════════════════════════════════
   6. HEADER ACTIONS — icon-btn, avatar, profile dropdown
══════════════════════════════════════════════════════════ */
.header-actions {
  display: flex; align-items: center;
  gap: 8px; flex-shrink: 0;
}

.icon-btn {
  width: 38px; height: 38px; border-radius: 10px;
  border: 1px solid rgba(255,255,255,.2);
  background: rgba(255,255,255,.10);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--header-item);
  transition: background .15s, border-color .15s, color .15s;
  backdrop-filter: blur(4px);
}
.icon-btn:hover {
  background: rgba(255,255,255,.18);
  border-color: rgba(255,255,255,.35);
  color: var(--header-active);
}
.icon-btn .material-symbols-outlined { font-size: 20px; }

.avatar-circle {
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(255,255,255,.20);
  border: 2px solid rgba(255,255,255,.40);
  color: #fff; font-size:var(--fs-caption); font-weight: 700;
  font-family: var(--heading);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; letter-spacing: .04em;
  transition: background .15s, transform .1s;
}
.avatar-circle:hover {
  background: rgba(255,255,255,.30);
  transform: scale(1.06);
}

.profile-wrap { position: relative; }

.profile-btn {
  display: flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.20);
  border-radius: var(--r-md); padding: 4px 10px 4px 4px;
  cursor: pointer;
  transition: background .15s, border-color .15s;
  backdrop-filter: blur(4px);
}
.profile-btn:hover {
  background: rgba(255,255,255,.18);
  border-color: rgba(255,255,255,.35);
}

.profile-username {
  font-size:var(--fs-body); font-weight: 600;
  color: var(--header-active); font-family: var(--sans);
  max-width: 100px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.profile-chevron {
  font-size:var(--fs-title-sm); color: var(--header-item);
  transition: transform .2s;
}

.profile-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  min-width: 210px; z-index: 1000;
  display: none; overflow: hidden;
  animation: fadeDown .18s ease;
}
.profile-dropdown.open { display: block; }

.profile-menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px; font-size:var(--fs-body); font-weight: 500;
  color: var(--text-muted); text-decoration: none;
  transition: background .12s, color .12s;
}
.profile-menu-item .material-symbols-outlined { font-size: 18px; color: var(--text-dim); }
.profile-menu-item:hover { background: var(--surface); color: var(--text); }
.profile-menu-item:hover .material-symbols-outlined { color: var(--primary); }
.profile-menu-item.logout:hover { background: var(--red-bg); color: var(--red); }
.profile-menu-item.logout:hover .material-symbols-outlined { color: var(--red); }
.profile-menu-divider { height: 1px; background: var(--border); margin: 4px 0; }


/* ══════════════════════════════════════════════════════════
   7. BOTTOM NAVBAR — MOBILE ONLY
══════════════════════════════════════════════════════════ */
.bottom-nav {
  display: none;
  position: fixed; bottom: 0; left: 0; right: 0;
  z-index: 600;
  background: var(--bnav-bg);
  box-shadow: 0 -2px 16px rgba(0,0,0,.22);
  border-top: 1px solid rgba(255,255,255,.06);
  height: var(--bnav-h);
  overflow: hidden;
}

/* Garis aksen mengalir di tepi atas — sisipkan via initBottomNav() di
   global.js, reuse keyframe headerAccentSlide (lihat .header-accent). */
.bottom-nav-accent {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, #5b7fae 30%, #e8edf5 50%, #5b7fae 70%, transparent);
  background-size: 200% 100%;
  animation: headerAccentSlide 2.5s linear infinite;
  pointer-events: none;
  z-index: 1;
}

/* Sembunyikan saat keyboard virtual terbuka — dideteksi via visualViewport
   di global.js. Tanpa ini, navbar fixed-bottom melayang di atas keyboard
   pada banyak WebView Android (bug klasik resize viewport). */
body.keyboard-open .bottom-nav { display: none !important; }

/* Ganti animasi canvas (RAF terus-menerus, berat) dengan shimmer
   CSS murni — cuma animasi background-position, jauh lebih ringan. */
.bottom-nav::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    transparent 20%, rgba(0,174,239,.14) 50%, transparent 80%);
  background-size: 250% 100%;
  animation: bnavShimmer 6s ease-in-out infinite;
  pointer-events: none;
  z-index: 0;
}

.bottom-nav-inner {
  display: flex;
  justify-content: space-around;
  align-items: stretch;
  height: var(--bnav-h);
  position: relative;
  z-index: 1;
}

.bottom-nav-item {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 4px; flex: 1;
  padding: 8px 4px 6px;
  text-decoration: none;
  color: var(--bnav-inactive);
  font-size:var(--fs-small); font-weight: 600;
  font-family: var(--sans);
  border: none; background: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  position: relative; overflow: hidden;
  min-width: 0;
  transition: color .22s ease;
}

.bottom-nav-icon {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  transition: transform .32s cubic-bezier(.34,1.5,.64,1), opacity .22s ease, filter .25s ease;
}
.bottom-nav-item .material-symbols-outlined {
  font-size: 22px; display: block;
  transition: font-variation-settings .25s ease, color .22s ease;
  font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
}

.bottom-nav-label {
  max-width: 60px;
  overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; line-height: 1.2;
  letter-spacing: .01em;
  transition: color .22s ease, font-weight .22s ease;
}

.bottom-nav-item.active { color: var(--bnav-active); }
.bottom-nav-item.active .bottom-nav-label { font-weight: 700; }
.bottom-nav-item.active .bottom-nav-icon {
  transform: translateY(-1px) scale(1.1);
}
.bottom-nav-item.active .material-symbols-outlined {
  font-variation-settings: 'FILL' 1, 'wght' 600, 'GRAD' 0, 'opsz' 24;
}
.bottom-nav-item:not(.active) .material-symbols-outlined {
  font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
}
.bottom-nav-item:not(.active):hover { color: rgba(255,255,255,.80); }
.bottom-nav-item:not(.active):hover .bottom-nav-icon { transform: translateY(-1px) scale(1.06); }


/* ══════════════════════════════════════════════════════════
   8. PAGE WRAPPER
══════════════════════════════════════════════════════════ */
.page {
  max-width: 100%; margin: 0 auto;
  padding: calc(var(--header-h) + 14px) 32px 60px;
  width: 100%; box-sizing: border-box;
}

.page-top {
  display: flex; align-items: flex-start;
  justify-content: space-between; gap: 16px;
  margin-bottom: var(--space-xl); flex-wrap: wrap;
}

.page-title {
  font-size: var(--fs-title-lg); font-weight: 700;
  font-family: var(--heading);
  color: var(--text); letter-spacing: -.03em;
}

.page-sub {
  font-size:var(--fs-body); color: var(--text-muted); margin-top: 2px;
}

.page-top-actions {
  display: flex; align-items: center; gap: 10px;
}


/* ══════════════════════════════════════════════════════════
   9. TOMBOL UMUM — seragam semua halaman
══════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 16px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--bg);
  color: var(--text-muted);
  font-size:var(--fs-body); font-weight: 600;
  cursor: pointer; font-family: var(--sans);
  white-space: nowrap; box-shadow: var(--shadow-xs);
  transition: background .15s, border-color .15s, box-shadow .15s, transform .1s, color .15s;
}
.btn .material-symbols-outlined, .btn i { font-size: 16px; }
.btn:hover {
  background: var(--surface); border-color: var(--border-2);
  color: var(--text); box-shadow: var(--shadow-sm);
}
.btn:active { transform: scale(.97); }
.btn:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }

.btn-primary {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--primary); color: #fff;
  border: none; border-radius: var(--r-md);
  padding: 10px 18px; font-size:var(--fs-body); font-weight: 600;
  cursor: pointer; font-family: var(--sans);
  box-shadow: 0 2px 8px rgba(0,64,161,.28);
  transition: background .15s, box-shadow .15s, transform .1s;
  white-space: nowrap;
}
.btn-primary .material-symbols-outlined, .btn-primary i { font-size: 18px; }
.btn-primary:hover {
  background: var(--primary-dark);
  box-shadow: 0 4px 14px rgba(0,64,161,.36);
}
.btn-primary:active { transform: scale(.97); }
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }

/* ── btn-secondary: tombol aksi sekunder (sejajar btn-primary) ── */
.btn-secondary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 16px; border-radius: var(--r-md);
  border: 1.5px solid var(--border); background: var(--bg);
  color: var(--text-muted); font-size:var(--fs-body); font-weight: 600;
  cursor: pointer; font-family: var(--sans); white-space: nowrap;
  box-shadow: var(--shadow-xs);
  transition: background .15s, border-color .15s, color .15s, box-shadow .15s, transform .1s;
}
.btn-secondary .material-symbols-outlined, .btn-secondary i { font-size: 17px; }
.btn-secondary:hover {
  background: var(--surface); border-color: var(--primary);
  color: var(--primary); box-shadow: var(--shadow-sm);
}
.btn-secondary:active { transform: scale(.97); }
.btn-secondary:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }

.btn-blue  { background: var(--blue-bg);  border-color: var(--blue-border);  color: var(--blue); }
.btn-blue:hover  { background: #dbeafe; border-color: #93c5fd; color: var(--blue); }

.btn-green { background: var(--green-bg); border-color: var(--green-border); color: var(--green); }
.btn-green:hover { background: #cceedd; border-color: var(--green); color: var(--green); }

.btn-amber { background: var(--amber-bg); border-color: var(--amber-border); color: var(--amber); }
.btn-amber:hover { background: #fef3c7; border-color: #fcd34d; color: var(--amber); }

.btn-red   { background: var(--red-bg);   border-color: var(--red-border);   color: var(--red); }
.btn-red:hover   { background: #fee2e2; border-color: #fca5a5; color: var(--red); }

.btn-sm { padding: 5px 11px; font-size:var(--fs-caption); }
.btn-sm .material-symbols-outlined, .btn-sm i { font-size: 14px; }

.btn-hapus { background: var(--red-bg); color: var(--red); border: 1px solid var(--red-border); }
.btn-hapus .material-symbols-outlined { font-size: 17px; }
.btn-hapus:hover { background: #fbd4d4; border-color: var(--red); }

.btn-tbl {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--bg);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-dim);
  transition: background .12s, border-color .12s, color .12s;
  font-family: inherit;
}
.btn-tbl .material-symbols-outlined { font-size: 16px; }
.btn-tbl:hover { background: var(--surface); border-color: var(--border-2); color: var(--text); }
.btn-tbl.edit:hover   { background: var(--blue-bg);  border-color: var(--blue-border);  color: var(--blue); }
.btn-tbl.hapus:hover  { background: var(--red-bg);   border-color: var(--red-border);   color: var(--red); }
.btn-tbl.detail:hover { background: var(--amber-bg); border-color: var(--amber-border); color: var(--amber); }

.btn-save   { background: var(--primary); color: #fff; border: none; box-shadow: 0 2px 8px rgba(0,64,161,.25); }
.btn-save:hover { background: var(--primary-dark); }
.btn-cancel { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
.btn-cancel:hover { background: var(--surface); border-color: var(--border-2); }
.btn-retry  { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); margin-top: 12px; }
.btn-retry:hover { background: var(--surface); }

.icon-btn-sm {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-dim); flex-shrink: 0;
  transition: background .15s, color .15s;
}
.icon-btn-sm:hover {
  background: var(--primary-light); color: var(--primary);
  border-color: rgba(0,64,161,.2);
}
.icon-btn-sm .material-symbols-outlined { font-size: 18px; }


/* ══════════════════════════════════════════════════════════
   10. STAT CARDS
══════════════════════════════════════════════════════════ */
.stat-row,
.stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px; margin-bottom: 22px;
}

.stat-row .stat-card:nth-child(n+4),
.stats-row .stat-card:nth-child(n+4) { display: none; }

.stat-row-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px; margin-bottom: 22px;
}
.stat-row-4 .stat-card:nth-child(n+4) { display: flex; }

/* ── 5-kolom — dashboard kolektor ─────────────────────── */
.stat-row-5 {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px; margin-bottom: 22px;
}
.stat-row-5 .stat-card { padding: 16px 14px; }
.stat-row-5 .stat-card .stat-num { font-size:var(--fs-title-lg); }
.stat-row-5 .stat-card .stat-label { font-size:var(--fs-small); }
@media (max-width: 1100px) {
  .stat-row-5 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .stat-row,
  .stats-row,
  .stat-row-4,
  .stat-row-5 { grid-template-columns: 1fr !important; }
  /* Tampilkan semua card yang tersembunyi saat 1-kolom */
  .stat-row .stat-card:nth-child(n+4),
  .stats-row .stat-card:nth-child(n+4) { display: flex !important; }
}

/* Warna tiap card di stat-row-5 berdasarkan class eksplisit */
.stat-c-blue   { background: var(--card-1-bg); border-color: var(--card-1-border); box-shadow: 0 4px 18px var(--card-1-shadow); color: #fff; }
.stat-c-teal   { background: var(--card-2-bg); border-color: var(--card-2-border); box-shadow: 0 4px 18px var(--card-2-shadow); color: #fff; }
.stat-c-amber  { background: linear-gradient(135deg,#92400e 0%,#d97706 100%); border-color: rgba(255,255,255,.15); box-shadow: 0 4px 18px rgba(217,119,6,.28); color: #fff; }
.stat-c-red    { background: linear-gradient(135deg,#7f1d1d 0%,#dc2626 100%); border-color: rgba(255,255,255,.15); box-shadow: 0 4px 18px rgba(220,38,38,.28); color: #fff; }
.stat-c-purple { background: var(--card-4-bg); border-color: var(--card-4-border); box-shadow: 0 4px 18px var(--card-4-shadow); color: #fff; }
.stat-c-green  { background: var(--card-5-bg); border-color: var(--card-5-border); box-shadow: 0 4px 18px var(--card-5-shadow); color: #fff; }

/* Text putih untuk semua child di card berwarna */
.stat-c-blue .stat-num, .stat-c-blue .stat-label,
.stat-c-teal .stat-num, .stat-c-teal .stat-label,
.stat-c-amber .stat-num, .stat-c-amber .stat-label,
.stat-c-red .stat-num, .stat-c-red .stat-label,
.stat-c-purple .stat-num, .stat-c-purple .stat-label,
.stat-c-green .stat-num, .stat-c-green .stat-label { color: #fff; }

/* Sub-nilai di bawah stat-num (nominal, dll) — putih di card berwarna */
.stat-sub-val { font-size:var(--fs-small); font-weight: 700; margin-top: 3px; color: rgba(255,255,255,.80); }

.stat-c-blue:hover   { box-shadow: 0 10px 32px var(--card-1-shadow); transform: translateY(-3px); }
.stat-c-teal:hover   { box-shadow: 0 10px 32px var(--card-2-shadow); transform: translateY(-3px); }
.stat-c-amber:hover  { box-shadow: 0 10px 32px rgba(217,119,6,.38);  transform: translateY(-3px); }
.stat-c-red:hover    { box-shadow: 0 10px 32px rgba(220,38,38,.38);   transform: translateY(-3px); }
.stat-c-purple:hover { box-shadow: 0 10px 32px var(--card-4-shadow); transform: translateY(-3px); }
.stat-c-green:hover  { box-shadow: 0 10px 32px var(--card-5-shadow); transform: translateY(-3px); }

/* Ikon di dalam card berwarna */
.stat-c-blue .stat-icon,   .stat-c-teal .stat-icon,
.stat-c-amber .stat-icon,  .stat-c-red .stat-icon,
.stat-c-purple .stat-icon, .stat-c-green .stat-icon {
  background: rgba(255,255,255,.18) !important;
  color: #fff !important;
}

/* Tabel kolektor — kolom di desktop */
.kol-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size:var(--fs-body); }
.kol-table thead th {
  background: var(--header-bg); color: rgba(255,255,255,.88);
  font-size:var(--fs-small); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  padding: 11px 14px; border-bottom: 1px solid rgba(255,255,255,.12); text-align: left; white-space: nowrap;
  position: sticky; top: 0; z-index: 2;
}
.kol-table tbody td { padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.kol-table tbody tr:last-child td { border-bottom: none; }
.kol-table tbody tr:hover td { background: var(--surface); }
.kol-table .kol-nama { font-weight: 700; font-size:var(--fs-body); }
.kol-table .kol-sub  { font-size:var(--fs-small); color: var(--text-dim); }
.kol-table .kol-num  { font-weight: 700; }
.kol-table .kol-dim  { color: var(--text-muted); font-size:var(--fs-caption); }
.kol-wrap { overflow-x: auto; }
.kol-wrap::-webkit-scrollbar { height: 4px; }
.kol-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

/* Card wrap tabel kolektor */
.kol-card-wrap {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm); overflow: hidden; margin-bottom: 20px;
}
.kol-card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  font-weight: 800; font-size:var(--fs-body); color: var(--text);
  background: var(--surface);
}
.kol-card-head .material-symbols-outlined { font-size: 20px; color: var(--primary); }

.stat-card {
  border-radius: 16px;
  padding: 20px 22px;
  display: flex; align-items: center; gap: 16px;
  border: 1px solid;
  position: relative; overflow: hidden;
  opacity: 0;
  transform: translateY(14px);
  animation: cardSlideUp .4s cubic-bezier(.22,1,.36,1) forwards;
  transition: transform .2s cubic-bezier(.34,1.4,.64,1), box-shadow .2s ease;
}
.stat-card:nth-child(1) { animation-delay: .04s; }
.stat-card:nth-child(2) { animation-delay: .10s; }
.stat-card:nth-child(3) { animation-delay: .16s; }
.stat-card:nth-child(4) { animation-delay: .22s; }
.stat-card:nth-child(5) { animation-delay: .28s; }

.stat-card::before { display: none; }
.stat-card::after  { display: none; }

.stat-row .stat-card:nth-child(1),
.stats-row .stat-card:nth-child(1),
.stat-row-4 .stat-card:nth-child(1),
.stat-row-5 .stat-card:nth-child(1) {
  background: var(--card-1-bg); border-color: var(--card-1-border);
  box-shadow: 0 4px 20px var(--card-1-shadow);
}
.stat-row .stat-card:nth-child(2),
.stats-row .stat-card:nth-child(2),
.stat-row-4 .stat-card:nth-child(2),
.stat-row-5 .stat-card:nth-child(2) {
  background: var(--card-2-bg); border-color: var(--card-2-border);
  box-shadow: 0 4px 20px var(--card-2-shadow);
}
.stat-row .stat-card:nth-child(3),
.stats-row .stat-card:nth-child(3),
.stat-row-4 .stat-card:nth-child(3),
.stat-row-5 .stat-card:nth-child(3) {
  background: var(--card-3-bg); border-color: var(--card-3-border);
  box-shadow: 0 4px 20px var(--card-3-shadow);
}
.stat-row-4 .stat-card:nth-child(4),
.stat-row-5 .stat-card:nth-child(4) {
  background: var(--card-4-bg); border-color: var(--card-4-border);
  box-shadow: 0 4px 20px var(--card-4-shadow);
}
.stat-row-5 .stat-card:nth-child(5) {
  background: linear-gradient(135deg, #6d28d9 0%, #a855f7 100%);
  border-color: rgba(255,255,255,.15);
  box-shadow: 0 4px 20px rgba(124,58,237,.28);
}

.stat-card:hover {
  transform: translateY(-3px);
}
.stat-row .stat-card:nth-child(1):hover, .stats-row .stat-card:nth-child(1):hover,
.stat-row-4 .stat-card:nth-child(1):hover,
.stat-row-5 .stat-card:nth-child(1):hover { box-shadow: 0 10px 36px var(--card-1-shadow); }
.stat-row .stat-card:nth-child(2):hover, .stats-row .stat-card:nth-child(2):hover,
.stat-row-4 .stat-card:nth-child(2):hover,
.stat-row-5 .stat-card:nth-child(2):hover { box-shadow: 0 10px 36px var(--card-2-shadow); }
.stat-row .stat-card:nth-child(3):hover, .stats-row .stat-card:nth-child(3):hover,
.stat-row-4 .stat-card:nth-child(3):hover,
.stat-row-5 .stat-card:nth-child(3):hover { box-shadow: 0 10px 36px var(--card-3-shadow); }
.stat-row-4 .stat-card:nth-child(4):hover,
.stat-row-5 .stat-card:nth-child(4):hover { box-shadow: 0 10px 36px var(--card-4-shadow); }
.stat-row-5 .stat-card:nth-child(5):hover { box-shadow: 0 10px 36px rgba(124,58,237,.35); }

.stat-icon {
  width: 48px; height: 48px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  transition: transform .2s cubic-bezier(.34,1.5,.64,1);
}
.stat-card:hover .stat-icon { transform: scale(1.08) rotate(-3deg); }
.stat-icon .material-symbols-outlined { font-size: 22px; }
.stat-icon.blue, .stat-icon.green, .stat-icon.red,
.stat-icon.amber, .stat-icon.primary, .stat-icon.pink {
  background: rgba(255,255,255,.18); color: #ffffff;
  box-shadow: 0 1px 0 rgba(255,255,255,.3) inset;
}

/* Icon per card */
.stat-row .stat-card .stat-icon,
.stats-row .stat-card .stat-icon,
.stat-row-4 .stat-card .stat-icon,
.stat-row-5 .stat-card .stat-icon {
  background: rgba(255,255,255,.18); color: #ffffff;
  box-shadow: 0 1px 0 rgba(255,255,255,.25) inset;
}

.stat-body { flex: 1; min-width: 0; }

.stat-num {
  font-size:var(--fs-hero); font-weight: 800;
  font-family: var(--heading);
  letter-spacing: -.04em; line-height: 1;
  animation: countUp .5s cubic-bezier(.22,1,.36,1) both;
  animation-delay: inherit;
}
.stat-row .stat-card .stat-num,
.stats-row .stat-card .stat-num,
.stat-row-4 .stat-card .stat-num,
.stat-row-5 .stat-card .stat-num { color: #ffffff; }

.stat-label {
  font-size:var(--fs-caption); color: var(--text-muted);
  margin-top: 4px; font-weight: 500;
}
.stat-row .stat-card .stat-label,
.stats-row .stat-card .stat-label,
.stat-row-4 .stat-card .stat-label,
.stat-row-5 .stat-card .stat-label { color: rgba(255,255,255,.75); }

.stat-trend {
  display: inline-flex; align-items: center; gap: 4px;
  font-size:var(--fs-small); font-weight: 600;
  margin-top: 6px; padding: 2px 8px; border-radius: 20px;
}
.stat-trend .material-symbols-outlined { font-size: 13px; }
.stat-trend.up      { background: var(--green-bg);    color: var(--green); }
.stat-trend.warn    { background: var(--red-bg);      color: var(--red); }
.stat-trend.neutral { background: var(--primary-light); color: var(--primary); }


/* ══════════════════════════════════════════════════════════
   11. BADGE & STATUS
══════════════════════════════════════════════════════════ */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size:var(--fs-small); font-weight: 600;
  padding: 3px 10px; border-radius: 99px; border: 1px solid;
  white-space: nowrap; letter-spacing: .01em;
}
.badge-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
}

.badge.connected            { background: var(--green-bg);  color: var(--green);    border-color: var(--green-border); }
.badge.connected .badge-dot { background: var(--green); }
.badge.failed               { background: var(--red-bg);    color: var(--red);      border-color: var(--red-border); }
.badge.failed .badge-dot    { background: var(--red); animation: pulseRed 1.2s infinite; }
.badge.pending              { background: var(--surface);   color: var(--text-dim); border-color: var(--border); }
.badge.pending .badge-dot   { background: var(--text-dim); }
.badge.warning              { background: var(--amber-bg);  color: var(--amber);    border-color: var(--amber-border); }
.badge.warning .badge-dot   { background: var(--amber); animation: pulseAmber 1.2s infinite; }
.badge.syncing              { background: var(--blue-bg);   color: var(--blue);     border-color: var(--blue-border); }
.badge.syncing .badge-dot   { background: var(--blue); animation: pulseBlue .8s infinite; }

.badge-status {
  display: inline-flex; align-items: center; gap: 5px;
  font-size:var(--fs-small); font-weight: 600;
  padding: 3px 10px; border-radius: 99px; border: 1px solid;
  white-space: nowrap;
}
.badge-status.online   { background: var(--green-bg); color: var(--green); border-color: var(--green-border); }
.badge-status.online   .badge-dot { background: var(--green); animation: pulseGreen .9s infinite; }
.badge-status.aktif    { background: var(--green-bg); color: var(--green); border-color: var(--green-border); }
.badge-status.aktif    .badge-dot { background: var(--green); }
.badge-status.nonaktif { background: var(--red-bg);   color: var(--red);   border-color: var(--red-border); }
.badge-status.nonaktif .badge-dot { background: var(--red); animation: pulseRed 1.2s infinite; }

.badge-profil {
  display: inline-block;
  background: var(--primary-light); color: var(--primary);
  border: 1px solid rgba(0,64,161,.2);
  font-size:var(--fs-small); font-weight: 600;
  padding: 2px 9px; border-radius: 99px; white-space: nowrap;
}

.device-tipe-badge {
  font-size:var(--fs-small); font-weight: 600;
  padding: 2px 8px; border-radius: 99px;
  background: var(--primary-light); color: var(--primary);
  border: 1px solid rgba(0,64,161,.2);
  white-space: nowrap;
}

@keyframes pulseRed   { 0%,100%{opacity:1} 50%{opacity:.3} }
@keyframes pulseAmber { 0%,100%{opacity:1} 50%{opacity:.4} }
@keyframes pulseBlue  { 0%,100%{opacity:1} 50%{opacity:.4} }
@keyframes pulseGreen { 0%,100%{opacity:1} 50%{opacity:.4} }


/* ══════════════════════════════════════════════════════════
   12. MODAL
══════════════════════════════════════════════════════════ */
.modal-overlay {
  position: fixed;
  top: var(--header-h);
  left: 0; right: 0;
  bottom: var(--bnav-h);
  background: rgba(15,23,42,.45);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  z-index: 80;
  display: none; align-items: center; justify-content: center;
}
/* Desktop (>768px): bottom-nav disembunyikan (display:none), tapi overlay
   masih nyisain ruang bottom: var(--bnav-h) — bagian itu jadi TIDAK ikut
   diblur/digelapkan. Di atas breakpoint ini, overlay full sampai bawah. */
@media (min-width: 769px) {
  .modal-overlay { bottom: 0; }
}
.modal-overlay.open { display: flex; }
.modal-overlay.modal-sheet-style { align-items: flex-end; }

.modal-sheet {
  background: var(--bg);
  border-radius: var(--r-xl);
  border: 1px solid var(--border);
  padding: 28px 24px;
  width: auto; min-width: 300px; max-width: 520px;
  box-shadow: var(--shadow-lg);
  animation: popIn .22s cubic-bezier(.22,1,.36,1);
  max-height: 92dvh; overflow-y: auto;
}
.modal-sheet.small { max-width: 380px; }
.modal-sheet.large { max-width: 640px; }

.modal {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 24px;
  width: 420px;
  max-width: calc(100vw - 32px);
  max-height: 92dvh; overflow-y: auto;
  box-shadow: var(--shadow-lg);
  animation: popIn .22s cubic-bezier(.22,1,.36,1);
}

.form-modal {
  background: var(--bg);
  border: 1.5px solid var(--primary);
  border-radius: var(--r-xl);
  padding: 24px 28px;
  width: 540px;
  max-width: calc(100vw - 32px);
  max-height: 90dvh; overflow-y: auto;
  box-shadow: 0 0 0 4px var(--primary-ring), var(--shadow-lg);
  animation: popIn .22s cubic-bezier(.22,1,.36,1);
}

.modal-handle {
  display: none;
  width: 40px; height: 4px; border-radius: 99px;
  background: var(--border-2); margin: 0 auto 20px;
}
.modal-head {
  display: flex; align-items: flex-start;
  justify-content: space-between; gap: 12px; margin-bottom: 20px;
}
.modal-head-left { display: flex; align-items: center; gap: 12px; }
.modal-head-icon {
  width: 40px; height: 40px; border-radius: var(--r-md);
  background: var(--primary-light); color: var(--primary);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.modal-head-icon .material-symbols-outlined { font-size: 20px; }

.modal-title  { font-size:var(--fs-title-sm); font-weight: 700; font-family: var(--heading); color: var(--text); display: flex; align-items: center; gap: 8px; }
.modal-title i { font-size:var(--fs-title-lg); }
.modal-sub    { font-size:var(--fs-caption); color: var(--text-dim); margin-top: 2px; }
.modal-body   { font-size:var(--fs-body); color: var(--text-muted); margin-bottom: 20px; line-height: 1.7; }

/* Alias .modal-header → .modal-head (backward compat) */
.modal-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 20px; }

.modal-close {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-dim); flex-shrink: 0;
  transition: background .15s, color .15s;
}
.modal-close:hover { background: var(--surface); color: var(--text); }
.modal-close .material-symbols-outlined { font-size: 18px; }

.modal-fields  { display: flex; flex-direction: column; gap: 14px; }
.modal-footer  { display: flex; justify-content: flex-end; gap: 10px; margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border); }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; }

.hapus-icon-wrap {
  display: flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--red-bg); margin: 0 auto 14px;
}
.hapus-icon  { font-size: 26px; color: var(--red); }
.hapus-title { font-size:var(--fs-title-sm); font-weight: 700; font-family: var(--heading); text-align: center; color: var(--text); margin-bottom: 8px; }
.hapus-sub   { font-size:var(--fs-body); color: var(--text-muted); text-align: center; line-height: 1.6; margin-bottom: 4px; }

/* Modal bottom-sheet universal */
.modal-bs { align-items: center; justify-content: center; }
.modal-bs-sheet { border-radius: var(--r-xl); }


/* ══════════════════════════════════════════════════════════
   13. TOAST NOTIFICATION
══════════════════════════════════════════════════════════ */
#toast {
  position: fixed; bottom: 24px; right: 24px;
  font-size:var(--fs-body); font-weight: 600;
  padding: 12px 18px; border-radius: var(--r-md);
  display: flex; align-items: center; gap: 8px;
  z-index: 999; pointer-events: none;
  transition: opacity .3s, transform .3s;
  border: 1px solid; box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(10px);
}
#toast.show    { opacity: 1; transform: translateY(0); }
#toast.hidden  { opacity: 0; transform: translateY(10px); }
#toast.success { background: var(--green-bg);  color: var(--green);  border-color: var(--green-border); }
#toast.danger  { background: var(--red-bg);    color: var(--red);    border-color: var(--red-border); }
#toast.info    { background: var(--blue-bg);   color: var(--blue);   border-color: var(--blue-border); }
#toast.warning { background: var(--amber-bg);  color: var(--amber);  border-color: var(--amber-border); }
#toast .material-symbols-outlined, #toast i { font-size: 17px; }


/* ══════════════════════════════════════════════════════════
   14. SPINNER / LOADING
══════════════════════════════════════════════════════════ */
.spinner {
  width: 32px; height: 32px; border-radius: 50%;
  border: 3px solid var(--primary-light);
  border-top-color: var(--primary);
  animation: spin .8s linear infinite;
}
.spinner-ring {
  width: 36px; height: 36px; border-radius: 50%;
  border: 3px solid var(--blue-bg);
  border-top-color: var(--blue);
  animation: spin .8s linear infinite;
}

.state-box {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 48px 24px; gap: 12px; text-align: center;
}
.state-icon  { font-size: 40px; color: var(--text-dim); }
.error-icon  { color: var(--red) !important; }
.state-title { font-size:var(--fs-title-sm); font-weight: 600; color: var(--text); }
.state-sub   { font-size:var(--fs-body); color: var(--text-muted); }

.spin     { animation: spin .8s linear infinite; display: inline-block; }
.spinning { animation: spin .8s linear infinite; display: inline-block; }


/* ══════════════════════════════════════════════════════════
   15. FORM INPUT — SERAGAM semua halaman
══════════════════════════════════════════════════════════ */
.form-card {
  background: var(--bg);
  border: 1.5px solid var(--primary);
  border-radius: var(--r-xl);
  padding: 20px 24px; margin-bottom: 22px;
  box-shadow: 0 0 0 3px var(--primary-ring), var(--shadow-md);
  animation: slideDown .22s cubic-bezier(.22,1,.36,1);
}

.card-head {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--card-head-border);
  font-family: var(--heading);
  font-size:var(--fs-body); font-weight: 800;
  color: var(--card-head-text);
  background: var(--card-head-bg);
}
.card-head .material-symbols-outlined { font-size: 18px; color: var(--card-head-icon); }

.form-card-title {
  font-size: var(--fs-title-sm); font-weight: 700; font-family: var(--heading);
  color: var(--text); letter-spacing: -.01em; margin-bottom: 20px;
  display: flex; align-items: center; gap: 12px;
}
.form-card-title i,
.form-card-title .material-symbols-outlined { font-size: 20px; color: var(--primary); }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.form-group      { display: flex; flex-direction: column; gap: 5px; }
.form-group.full { grid-column: 1 / -1; }

.form-label {
  font-size:var(--fs-caption); font-weight: 600;
  color: var(--text-muted); letter-spacing: .01em;
}
.req { color: var(--red); margin-left: 2px; }

.form-input {
  height: var(--dd-h);
  padding: 0 var(--dd-pad-h);
  border: var(--dd-border);
  border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  font-size: var(--dd-font-size);
  font-family: var(--sans);
  width: 100%; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.form-input:focus {
  border-color: var(--primary);
  box-shadow: var(--dd-focus-ring);
  background: var(--bg);
}
.form-input::placeholder { color: var(--text-dim); }
.form-input.mono { font-family: var(--sans); font-size:var(--fs-body); }
.form-input[readonly] { background: var(--bg); color: var(--text-dim); cursor: not-allowed; }
.form-input[readonly]:focus { box-shadow: none; border-color: var(--border); }

/* Normalisasi <input type="number"> — tanpa ini, browser mobile menampilkan
   spinner bawaan yang menyempitkan area teks & membuat field terasa lebih
   kecil/tidak konsisten dibanding .form-input teks biasa (mis. kolom Port). */
.form-input[type="number"] { -moz-appearance: textfield; }
.form-input[type="number"]::-webkit-outer-spin-button,
.form-input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

textarea.form-input {
  height: auto; padding: 10px 12px;
  resize: none; line-height: 1.6;
}

select.form-input {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a96a8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
  padding-right: 32px; cursor: pointer;
}

/* IP & Port sebaris — IP melebar (flex:1), Port lebar tetap 90px. */
.ip-port-row                  { display: flex; flex-direction: row; gap: 8px; }
.ip-port-row .form-input      { flex: 1; min-width: 0; }
.ip-port-row .form-input.port { flex: 0 0 90px; text-align: left; }

/* Pasangan field generik (mis. Username+Password) — selalu sebaris,
   tidak ikut collapse ke 1 kolom seperti .form-grid di mobile (≤480px),
   karena flex ini berdiri sendiri di dalam 1 sel .form-group.full. */
.dual-field-row { display: flex; gap: 8px; align-items: flex-start; }
.dual-field      { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }

/* ── Input kalender (date / month / datetime-local) ─────────── */
input[type="date"],
input[type="month"],
input[type="datetime-local"] {
  height: 40px; padding: 0 36px 0 12px;
  border: 1.5px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); color: var(--text);
  font-size:var(--fs-body); font-family: var(--sans); font-weight: 600;
  cursor: pointer; outline: none; position: relative;
  transition: border-color .15s, box-shadow .15s;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230040a1' stroke-width='2'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
}
input[type="date"]:focus,
input[type="month"]:focus,
input[type="datetime-local"]:focus {
  border-color: var(--primary);
}
input[type="date"]:hover,
input[type="month"]:hover,
input[type="datetime-local"]:hover { border-color: var(--primary); }
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  opacity: 0; width: 28px; height: 28px; cursor: pointer; position: absolute; right: 8px;
}
/* filter-select[type=month/date] — override agar pakai ikon kalender bukan chevron */
.filter-select[type="month"],
.filter-select[type="date"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230040a1' stroke-width='2'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  color: var(--text); font-weight: 600;
}

.form-pwd-wrap { position: relative; display: flex; align-items: center; }
.form-pwd-wrap .form-input { padding-right: 40px; }
.form-pwd-toggle {
  position: absolute; right: 10px;
  background: none; border: none; cursor: pointer;
  color: var(--text-dim); display: flex; align-items: center;
  transition: color .15s; padding: 0;
}
.form-pwd-toggle:hover { color: var(--primary); }
.form-pwd-toggle .material-symbols-outlined { font-size: 18px; }

.form-hint    { font-size:var(--fs-small); color: var(--text-dim); margin-top: 3px; }
.form-actions {
  display: flex; justify-content: flex-end; gap: 10px;
  margin-top: 24px; padding-top: 16px;
  border-top: 1px solid var(--border);
}

/* Alias field-* → form-* (backward compat) */
.field-group  { display: flex; flex-direction: column; gap: 6px; }
.field-row    { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field-label  { font-size:var(--fs-caption); font-weight: 600; color: var(--text-muted); letter-spacing: .01em; }
.field-input  {
  height: var(--dd-h); padding: 0 var(--dd-pad-h);
  border: var(--dd-border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  font-size: var(--dd-font-size); font-family: var(--sans);
  width: 100%; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.field-input:focus {
  border-color: var(--primary);
  box-shadow: var(--dd-focus-ring);
  background: var(--bg);
}
.field-input::placeholder { color: var(--text-dim); }
select.field-input {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a96a8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
  padding-right: 32px; cursor: pointer;
}

.pwd-wrap { position: relative; }
.pwd-wrap .field-input { padding-right: 40px; }
.pwd-toggle {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer;
  color: var(--text-dim); padding: 4px; transition: color .15s;
}
.pwd-toggle:hover { color: var(--text-muted); }
.pwd-toggle .material-symbols-outlined { font-size: 18px; }

/* pwd-wrap alias untuk dashboard */
.pwd-wrap .form-input { padding-right: 44px; }
.pwd-eye {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer; padding: 4px;
  color: var(--text-dim); display: flex; align-items: center;
}
.pwd-eye .material-symbols-outlined { font-size: 18px; }


/* ══════════════════════════════════════════════════════════
   16. EMPTY STATE
══════════════════════════════════════════════════════════ */
.empty-state {
  text-align: center; padding: 56px 24px;
  background: var(--bg);
  border: 2px dashed var(--border);
  border-radius: var(--r-xl);
  color: var(--text-muted);
}
.empty-state .material-symbols-outlined, .empty-state i {
  font-size: 40px; color: var(--text-dim);
  display: block; margin-bottom: 14px;
}
.empty-state p { font-size:var(--fs-body); line-height: 1.7; }


/* ══════════════════════════════════════════════════════════
   17. DATE BADGE
══════════════════════════════════════════════════════════ */
.date-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 6px 14px;
  font-size:var(--fs-body); font-weight: 600;
  color: var(--text-muted); box-shadow: var(--shadow-xs);
  white-space: nowrap;
}
.date-badge .material-symbols-outlined { font-size: 16px; color: var(--primary); }


/* ══════════════════════════════════════════════════════════
   18. LIST HEADER
══════════════════════════════════════════════════════════ */
.list-header {
  display: flex; align-items: center;
  justify-content: space-between; margin-bottom: 12px;
}
.list-title {
  font-size: var(--tbl-head-size); font-weight: var(--tbl-head-weight);
  color: var(--text-dim); text-transform: var(--tbl-head-case);
  letter-spacing: var(--tbl-head-spacing);
}
#device-count, #odp-count, #odc-count, #olt-count { font-size:var(--fs-caption); color: var(--text-dim); }


/* ══════════════════════════════════════════════════════════
   19. DEVICE CARD
══════════════════════════════════════════════════════════ */
.device-card {
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 16px 18px; margin-bottom: 10px;
  display: flex; align-items: center; gap: 14px;
  box-shadow: var(--shadow-sm);
  transition: border-color .2s, box-shadow .2s, transform .15s;
  animation: fadeUp .2s ease both;
}
.device-card:hover { border-color: var(--border-2); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.device-card.status-connected { border-left: 3px solid var(--green); }
.device-card.status-failed    { border-left: 3px solid var(--red); }
.device-card.status-pending   { border-left: 3px solid var(--amber); }

.device-icon {
  width: 42px; height: 42px; border-radius: var(--r-md);
  background: var(--primary-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--primary); flex-shrink: 0;
}
.device-info    { flex: 1; min-width: 0; }
.device-top     { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; flex-wrap: wrap; }
.device-top > .badge { margin-left: auto; }
.device-name    { font-size:var(--fs-body); font-weight: 700; color: var(--text); }
.device-meta    { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.device-meta-item {
  display: flex; align-items: center; gap: 5px;
  font-size:var(--fs-caption); color: var(--text-muted);
  font-family: var(--sans);
}
.device-meta-item i,
.device-meta-item .material-symbols-outlined { font-size: 13px; color: var(--text-dim); }
.device-keterangan { font-size:var(--fs-small); color: var(--text-dim); margin-top: 5px; font-style: italic; }
.device-actions { display: flex; gap: 5px; flex-shrink: 0; flex-wrap: nowrap; justify-content: flex-end; }
.device-bottom-row {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px; width: 100%; margin-top: 6px;
}
/* Label tombol panjang (mis. "Remote ONU", "Isolir Redirect") otomatis
   memendek di mobile supaya tetap muat satu baris — lihat penggunaan
   di input_mikrotik.js (btn-label-full/btn-label-short). */
.btn-label-short { display: none; }
@media (max-width: 639px) {
  .btn-label-full  { display: none; }
  .btn-label-short { display: inline; }
}


/* ══════════════════════════════════════════════════════════
   20. UTILITY CLASSES
══════════════════════════════════════════════════════════ */
.d-none     { display: none !important; }
.d-flex     { display: flex; }
.d-grid     { display: grid; }
.hidden     { display: none; }

.text-primary { color: var(--primary); }
.text-muted   { color: var(--text-muted); }
.text-dim     { color: var(--text-dim); }
.text-green   { color: var(--green); }
.text-red     { color: var(--red); }
.text-amber   { color: var(--amber); }

.fw-400  { font-weight: 400; }
.fw-600  { font-weight: 600; }
.fw-700  { font-weight: 700; }
.fw-bold { font-weight: 700; }
.text-center { text-align: center; }
.text-right  { text-align: right; }

.mt-4  { margin-top: 4px; }
.mt-8  { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.mb-8  { margin-bottom: 8px; }
.mb-16 { margin-bottom: 16px; }
.mb-24 { margin-bottom: 24px; }

.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.divider  { height: 1px; background: var(--border); margin: 16px 0; }
.mono-text { font-family: var(--sans); font-size:var(--fs-caption); font-weight: 600; color: var(--text-muted); }

/* ── TBL CELL ── */
.tbl-user-cell { display: flex; align-items: center; gap: 8px; }

.user-avatar {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--primary-light); color: var(--primary);
  font-size:var(--fs-small); font-weight: 700; font-family: var(--heading);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; letter-spacing: .04em;
  border: 1.5px solid rgba(0,64,161,.15);
}

.tbl-rx {
  font-family: var(--sans);
  font-size:var(--fs-caption); font-weight: 700;
  padding: 2px 8px; border-radius: var(--r-sm);
  display: inline-block; white-space: nowrap;
}
.tbl-rx.rx-ok   { color: var(--green);    background: var(--green-bg);  border: 1px solid var(--green-border); }
.tbl-rx.rx-warn { color: var(--amber);    background: var(--amber-bg);  border: 1px solid var(--amber-border); }
.tbl-rx.rx-bad  { color: var(--red);      background: var(--red-bg);    border: 1px solid var(--red-border); }
.tbl-rx.rx-none { color: var(--text-dim); background: var(--surface);   border: 1px solid var(--border); font-weight: 400; }

.tbl-empty-msg {
  text-align: center; color: var(--text-dim);
  padding: 24px; font-size:var(--fs-body);
}

.tbl-username {
  font-weight: 700; color: var(--text);
  font-family: var(--sans); font-size: var(--tbl-cell-size);
  white-space: normal; word-break: break-all; line-height: 1.4;
}

.tbl-tagihan      { font-weight: 700; color: var(--text); font-size: var(--tbl-cell-size); }
.tbl-jatuh-tempo  { font-weight: 600; color: var(--amber); font-size:var(--fs-caption); font-family: var(--sans); }
.tbl-wilayah      { font-size: var(--tbl-cell-size); color: var(--text-muted); }
.tbl-hp           { font-size:var(--fs-caption); color: var(--text-muted); font-family: var(--sans); }


/* ══════════════════════════════════════════════════════════
   20b. ZEBRA STRIPING GLOBAL
══════════════════════════════════════════════════════════ */
tbody tr:nth-child(odd) td  { background-color: #ffffff; }
tbody tr:nth-child(even) td { background-color: #f0f5ff; }
tbody tr:hover td           { background-color: #e0eaff !important; transition: background-color .15s ease; }

tbody tr:nth-child(odd) td.sticky-col-1,
tbody tr:nth-child(odd) td.sticky-col-2  { background-color: #ffffff; }
tbody tr:nth-child(even) td.sticky-col-1,
tbody tr:nth-child(even) td.sticky-col-2 { background-color: #f0f5ff; }
tbody tr:hover td.sticky-col-1,
tbody tr:hover td.sticky-col-2           { background-color: #e0eaff !important; }

.info-row:nth-child(odd)  { background: #ffffff; }
.info-row:nth-child(even) { background: #f0f5ff; }
.info-row:hover           { background: #e0eaff; transition: background .15s ease; }


/* ══════════════════════════════════════════════════════════
   21. ANIMASI GLOBAL
══════════════════════════════════════════════════════════ */
@keyframes slideUp   { from{transform:translateY(100%);opacity:0} to{transform:translateY(0);opacity:1} }
@keyframes slideDown { from{opacity:0;transform:translateY(-6px)} to{opacity:1;transform:translateY(0)} }
@keyframes fadeIn    { from{opacity:0} to{opacity:1} }
@keyframes fadeDown  { from{opacity:0;transform:translateY(-6px)} to{opacity:1;transform:translateY(0)} }
@keyframes fadeUp    { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
@keyframes popIn     { from{opacity:0;transform:scale(.94) translateY(8px)} to{opacity:1;transform:scale(1) translateY(0)} }
@keyframes spin      { to{transform:rotate(360deg)} }
@keyframes spinAnim  { to{transform:rotate(360deg)} }
@keyframes bnavShimmer { 0%,100%{background-position:100% 0} 50%{background-position:0% 0} }

@keyframes headerGridPulse {
  0%, 100% { opacity: .6; }
  50%       { opacity: 1; }
}
@keyframes headerRadialPulse {
  0%   { transform: scale(1) translateX(0); opacity: .8; }
  100% { transform: scale(1.15) translateX(3%); opacity: 1; }
}

/* EFFECT 4: blob cahaya melayang di .header::after */
@keyframes headerBlobFloat {
  0%   { transform: translate(0,0) scale(1); opacity: .8; }
  50%  { transform: translate(-32px,26px) scale(1.35); opacity: 1; }
  100% { transform: translate(14px,-18px) scale(.9); opacity: .7; }
}
/* EFFECT 3: kilau sweep diagonal di .header-shine */
@keyframes headerShineSweep {
  0%, 55% { left: -150%; }
  100%    { left: 150%; }
}
/* EFFECT 2: garis aksen bergerak di .header-accent */
@keyframes headerAccentSlide {
  0%   { background-position: 0% 0; }
  100% { background-position: 200% 0; }
}

/* ── Stat Card Animations ── */
@keyframes cardSlideUp {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes countUp {
  from { opacity: 0; transform: translateY(6px) scale(.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.stat-num {
  animation: countUp .5s cubic-bezier(.22,1,.36,1) both;
  animation-delay: inherit;
}
@keyframes pulseSignal {
  0%,100% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  50%     { box-shadow: 0 0 0 5px transparent; opacity: .7; }
}
/* Dot sinyal di stat-label area (online/offline) */
.stat-signal-dot {
  display: inline-block;
  width: 7px; height: 7px; border-radius: 50%;
  margin-right: 5px; vertical-align: middle;
  animation: pulseSignal 1.6s ease-in-out infinite;
}
.stat-signal-dot.online  { color: var(--card-2-accent); background: var(--card-2-accent); }
.stat-signal-dot.offline { color: var(--card-3-accent); background: var(--card-3-accent); }


/* ══════════════════════════════════════════════════════════
   22. PERANGKAT BOTTOM SHEET (psheet)
══════════════════════════════════════════════════════════ */
.psheet-overlay {
  display: none; position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 499;
  background: rgba(0,0,0,.48);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  animation: fadeIn .2s ease;
}
.psheet-overlay.open { display: block; }

.psheet {
  position: fixed;
  bottom: 0; left: 0; right: 0; top: auto; width: 100%;
  max-height: 92vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  z-index: 500;
  background: var(--bg);
  border-radius: 24px 24px 0 0;
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 80px);
  box-shadow: 0 -8px 32px rgba(0,0,0,.18);
  display: none; flex-direction: column;
  transform: translateY(100%);
  transition: transform .3s cubic-bezier(.22,1,.36,1);
}
.psheet.open { display: flex; transform: translateY(0); }

@media (min-width: 769px) {
  .psheet-overlay { display: none !important; }
  .psheet {
    position: fixed;
    top: calc(var(--header-h) + env(safe-area-inset-top) + 6px);
    left: auto; right: auto; bottom: auto;
    width: 320px;
    max-height: calc(100vh - var(--header-h) - 40px);
    border-radius: var(--r-xl);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    padding-bottom: 8px;
    transform: translateY(-8px); opacity: 0;
    transition: transform .2s cubic-bezier(.22,1,.36,1), opacity .18s ease;
    overflow-y: auto; overflow-x: hidden;
  }
  .psheet.open { transform: translateY(0); opacity: 1; display: flex; }
  .psheet-handle { display: none; }
}

.psheet-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px 10px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.psheet-eyebrow {
  font-size:var(--fs-small); font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--primary); opacity: .8; margin-bottom: 2px;
}
.psheet-title {
  font-family: var(--heading); font-size:var(--fs-title-sm); font-weight: 800;
  color: var(--text); letter-spacing: -.02em; line-height: 1.2;
}
.psheet-close {
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--surface);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-muted);
  transition: background .15s, border-color .15s, color .15s; flex-shrink: 0;
}
.psheet-close:hover { background: var(--red-bg); border-color: var(--red-border); color: var(--red); }
.psheet-close .material-symbols-outlined { font-size: 17px; }

.psheet-list { padding: 8px 10px 4px; display: flex; flex-direction: column; gap: 4px; }

.psheet-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 10px; border-radius: var(--r-lg);
  border: 1.5px solid transparent;
  text-decoration: none;
  transition: background .16s, border-color .16s, transform .12s, box-shadow .16s;
  position: relative;
}
.psheet-item:active { transform: scale(.98); }

.psheet-item-icon {
  width: 44px; height: 44px; border-radius: 13px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: transform .18s;
}
.psheet-item-icon .material-symbols-outlined { font-size: 22px; }
.psheet-item:hover .psheet-item-icon { transform: scale(1.08); }

.psheet-item-body { flex: 1; min-width: 0; }
.psheet-item-name {
  font-size:var(--fs-body); font-weight: 700; font-family: var(--heading);
  color: var(--text); letter-spacing: -.01em; line-height: 1.3; margin-bottom: 2px;
}
.psheet-item-desc {
  font-size:var(--fs-small); color: var(--text-muted); line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.psheet-item-badge {
  font-size:var(--fs-small); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 20px; flex-shrink: 0; white-space: nowrap;
}
.psheet-item-arrow {
  font-size:var(--fs-title-sm); color: var(--text-dim); flex-shrink: 0;
  transition: transform .18s, color .18s;
}
.psheet-item:hover .psheet-item-arrow { transform: translateX(3px); }

.psheet-mikrotik { background: var(--primary-light); border-color: rgba(0,64,161,.12); }
.psheet-mikrotik .psheet-item-icon  { background: rgba(0,64,161,.12); color: var(--primary); }
.psheet-mikrotik .psheet-item-badge { background: var(--primary); color: #fff; }
.psheet-mikrotik .psheet-item-arrow { color: rgba(0,64,161,.40); }
.psheet-mikrotik:hover { background: #d4e2ff; border-color: rgba(0,64,161,.25); box-shadow: 0 2px 10px rgba(0,64,161,.10); }
.psheet-mikrotik:hover .psheet-item-arrow { color: var(--primary); }

.psheet-olt { background: var(--green-bg); border-color: rgba(0,108,71,.15); }
.psheet-olt .psheet-item-icon  { background: rgba(0,108,71,.12); color: var(--green); }
.psheet-olt .psheet-item-badge { background: var(--green); color: #fff; }
.psheet-olt .psheet-item-arrow { color: rgba(0,108,71,.40); }
.psheet-olt:hover { background: #c3ecd8; border-color: var(--green-border); box-shadow: 0 2px 10px rgba(0,108,71,.10); }
.psheet-olt:hover .psheet-item-arrow { color: var(--green); }

.psheet-odc { background: #e8f4f8; border-color: rgba(0,80,120,.12); }
.psheet-odc .psheet-item-icon  { background: rgba(0,80,120,.10); color: #006994; }
.psheet-odc .psheet-item-badge { background: #006994; color: #fff; }
.psheet-odc .psheet-item-arrow { color: rgba(0,80,120,.35); }
.psheet-odc:hover { background: #d0e8f0; border-color: rgba(0,80,120,.25); box-shadow: 0 2px 10px rgba(0,80,120,.10); }
.psheet-odc:hover .psheet-item-arrow { color: #006994; }

.psheet-odp { background: var(--amber-bg); border-color: rgba(180,83,9,.12); }
.psheet-odp .psheet-item-icon  { background: rgba(180,83,9,.10); color: var(--amber); }
.psheet-odp .psheet-item-badge { background: var(--amber); color: #fff; }
.psheet-odp .psheet-item-arrow { color: rgba(180,83,9,.40); }
.psheet-odp:hover { background: #fde8c0; border-color: var(--amber-border); box-shadow: 0 2px 10px rgba(180,83,9,.10); }
.psheet-odp:hover .psheet-item-arrow { color: var(--amber); }

.psheet-diagnostik { background: var(--blue-bg); border-color: rgba(29,78,216,.12); }
.psheet-diagnostik .psheet-item-icon  { background: rgba(29,78,216,.10); color: var(--blue); }
.psheet-diagnostik .psheet-item-badge { background: var(--blue); color: #fff; }
.psheet-diagnostik .psheet-item-arrow { color: rgba(29,78,216,.35); }
.psheet-diagnostik:hover { background: #dbe8ff; border-color: var(--blue-border); box-shadow: 0 2px 10px rgba(29,78,216,.10); }
.psheet-diagnostik:hover .psheet-item-arrow { color: var(--blue); }

.psheet-problems { background: var(--red-bg); border-color: rgba(186,26,26,.12); }
.psheet-problems .psheet-item-icon  { background: rgba(186,26,26,.10); color: var(--red); }
.psheet-problems .psheet-item-badge { background: var(--red); color: #fff; }
.psheet-problems .psheet-item-arrow { color: rgba(186,26,26,.35); }
.psheet-problems:hover { background: #fde2e2; border-color: var(--red-border); box-shadow: 0 2px 10px rgba(186,26,26,.10); }
.psheet-problems:hover .psheet-item-arrow { color: var(--red); }

.psheet-onu { background: #edf7f0; border-color: rgba(16,124,65,.12); }
.psheet-onu .psheet-item-icon  { background: rgba(16,124,65,.10); color: #107c41; }
.psheet-onu .psheet-item-badge { background: #107c41; color: #fff; }
.psheet-onu .psheet-item-arrow { color: rgba(16,124,65,.35); }
.psheet-onu:hover { background: #d4eddc; border-color: rgba(16,124,65,.28); box-shadow: 0 2px 10px rgba(16,124,65,.10); }
.psheet-onu:hover .psheet-item-arrow { color: #107c41; }

.psheet.open .psheet-item { animation: fadeUp .25s cubic-bezier(.22,1,.36,1) both; }
.psheet.open .psheet-item:nth-child(1) { animation-delay: .04s; }
.psheet.open .psheet-item:nth-child(2) { animation-delay: .09s; }
.psheet.open .psheet-item:nth-child(3) { animation-delay: .14s; }
.psheet.open .psheet-item:nth-child(4) { animation-delay: .19s; }
.psheet.open .psheet-item:nth-child(5) { animation-delay: .24s; }
.psheet.open .psheet-item:nth-child(6) { animation-delay: .29s; }
/* Diperpanjang sampai nth-child(10) — 19 Agt 2026: sheet Keuangan &
   Perangkat sudah sampai 9 item (Mitra, Riwayat Gangguan dst), item
   ke-7 dst sebelumnya tidak kebagian delay bertahap sama sekali (ketauan
   dari laporan user "belum ikut efek animasinya"), jadi masuk barengan
   dgn item pertama alih2 menyusul berurutan. */
.psheet.open .psheet-item:nth-child(7)  { animation-delay: .34s; }
.psheet.open .psheet-item:nth-child(8)  { animation-delay: .39s; }
.psheet.open .psheet-item:nth-child(9)  { animation-delay: .44s; }
.psheet.open .psheet-item:nth-child(10) { animation-delay: .49s; }

/* Keuangan sheet items */
.psheet-keuangan { background: #eaf0fb; border-color: rgba(0,64,161,.12); }
.psheet-keuangan .psheet-item-icon  { background: rgba(0,64,161,.10); color: var(--primary); }
.psheet-keuangan .psheet-item-badge { background: var(--primary); color: #fff; }
.psheet-keuangan .psheet-item-arrow { color: rgba(0,64,161,.35); }
.psheet-keuangan:hover { background: #d4e2ff; border-color: rgba(0,64,161,.25); }
.psheet-keuangan:hover .psheet-item-arrow { color: var(--primary); }

.psheet-tagihan { background: #f0f7ee; border-color: rgba(0,108,71,.12); }
.psheet-tagihan .psheet-item-icon  { background: rgba(0,108,71,.10); color: var(--green); }
.psheet-tagihan .psheet-item-badge { background: var(--green); color: #fff; }
.psheet-tagihan .psheet-item-arrow { color: rgba(0,108,71,.35); }
.psheet-tagihan:hover { background: #c3ecd8; border-color: var(--green-border); }
.psheet-tagihan:hover .psheet-item-arrow { color: var(--green); }

.psheet-loket { background: #fef3e2; border-color: rgba(180,83,9,.12); }
.psheet-loket .psheet-item-icon  { background: rgba(180,83,9,.10); color: var(--amber); }
.psheet-loket .psheet-item-badge { background: var(--amber); color: #fff; }
.psheet-loket .psheet-item-arrow { color: rgba(180,83,9,.35); }
.psheet-loket:hover { background: #fde8c0; border-color: var(--amber-border); }
.psheet-loket:hover .psheet-item-arrow { color: var(--amber); }

.psheet-wa { background: #e8f8f0; border-color: rgba(37,211,102,.2); }
.psheet-wa .psheet-item-icon  { background: rgba(37,211,102,.15); color: #128C7E; }
.psheet-wa .psheet-item-badge { background: #128C7E; color: #fff; }
.psheet-wa .psheet-item-arrow { color: rgba(37,211,102,.45); }
.psheet-wa:hover { background: #d0f0e0; border-color: rgba(37,211,102,.35); }
.psheet-wa:hover .psheet-item-arrow { color: #128C7E; }

.psheet-payment { background: #f5eefb; border-color: rgba(124,58,237,.15); }
.psheet-payment .psheet-item-icon  { background: rgba(124,58,237,.10); color: #7c3aed; }
.psheet-payment .psheet-item-badge { background: #7c3aed; color: #fff; }
.psheet-payment .psheet-item-arrow { color: rgba(124,58,237,.35); }
.psheet-payment:hover { background: #ede0fa; border-color: rgba(124,58,237,.28); }
.psheet-payment:hover .psheet-item-arrow { color: #7c3aed; }

.psheet-tiket { background: var(--red-bg); border-color: var(--red-border); }
.psheet-tiket .psheet-item-icon  { background: rgba(186,26,26,.10); color: var(--red); }
.psheet-tiket .psheet-item-badge { background: var(--red); color: #fff; }
.psheet-tiket .psheet-item-arrow { color: rgba(186,26,26,.35); }
.psheet-tiket:hover { background: #fbd4d4; border-color: var(--red-border); }
.psheet-tiket:hover .psheet-item-arrow { color: var(--red); }

.psheet-wo { background: #e0f7fa; border-color: rgba(8,145,178,.15); }
.psheet-wo .psheet-item-icon  { background: rgba(8,145,178,.14); color: #0891b2; }
.psheet-wo .psheet-item-badge { background: #0891b2; color: #fff; }
.psheet-wo .psheet-item-arrow { color: rgba(8,145,178,.40); }
.psheet-wo:hover { background: #b2ebf2; border-color: rgba(8,145,178,.30); }
.psheet-wo:hover .psheet-item-arrow { color: #0891b2; }
.psheet-topologi { background: #ede9fe; border-color: rgba(109,40,217,.15); }
.psheet-topologi .psheet-item-icon  { background: rgba(109,40,217,.12); color: #7c3aed; }
.psheet-topologi .psheet-item-badge { background: #7c3aed; color: #fff; }
.psheet-topologi .psheet-item-arrow { color: rgba(109,40,217,.35); }
.psheet-topologi:hover { background: #ddd6fe; border-color: rgba(109,40,217,.30); }
.psheet-topologi:hover .psheet-item-arrow { color: #7c3aed; }
.psheet-profit { background: #f0fdf4; border-color: rgba(0,108,71,.15); }
.psheet-profit .psheet-item-icon  { background: rgba(0,108,71,.10); color: var(--green); }
.psheet-profit .psheet-item-badge { background: var(--green); color: #fff; }
.psheet-profit .psheet-item-arrow { color: rgba(0,108,71,.35); }
.psheet-profit:hover { background: #dcfce7; border-color: rgba(0,108,71,.30); }
.psheet-profit:hover .psheet-item-arrow { color: var(--green); }

/* Mitra & Riwayat Gangguan — dulu belum punya blok warna sendiri di sini
   sama sekali (cuma kepakai class-nya di HTML), jadi badge-nya tampil
   polos tanpa background/warna spt yg lain (ketauan dari laporan user).
   19 Agt 2026. */
.psheet-mitra { background: #fce7f3; border-color: rgba(190,24,93,.15); }
.psheet-mitra .psheet-item-icon  { background: rgba(190,24,93,.10); color: #be185d; }
.psheet-mitra .psheet-item-badge { background: #be185d; color: #fff; }
.psheet-mitra .psheet-item-arrow { color: rgba(190,24,93,.35); }
.psheet-mitra:hover { background: #f9c9e0; border-color: rgba(190,24,93,.30); }
.psheet-mitra:hover .psheet-item-arrow { color: #be185d; }

.psheet-riwayat-gangguan { background: #e9e8fb; border-color: rgba(67,56,202,.15); }
.psheet-riwayat-gangguan .psheet-item-icon  { background: rgba(67,56,202,.10); color: #4338ca; }
.psheet-riwayat-gangguan .psheet-item-badge { background: #4338ca; color: #fff; }
.psheet-riwayat-gangguan .psheet-item-arrow { color: rgba(67,56,202,.35); }
.psheet-riwayat-gangguan:hover { background: #d4d1f7; border-color: rgba(67,56,202,.30); }
.psheet-riwayat-gangguan:hover .psheet-item-arrow { color: #4338ca; }

.psheet-kesehatan-olt { background: #ccfbf1; border-color: rgba(13,148,136,.15); }
.psheet-kesehatan-olt .psheet-item-icon  { background: rgba(13,148,136,.10); color: #0d9488; }
.psheet-kesehatan-olt .psheet-item-badge { background: #0d9488; color: #fff; }
.psheet-kesehatan-olt .psheet-item-arrow { color: rgba(13,148,136,.35); }
.psheet-kesehatan-olt:hover { background: #99f6e4; border-color: rgba(13,148,136,.30); }
.psheet-kesehatan-olt:hover .psheet-item-arrow { color: #0d9488; }


/* ══════════════════════════════════════════════════════════
   23. DROPDOWN GLOBAL — standar semua halaman
   ─────────────────────────────────────────────────────────
   Gunakan class .g-select (global select) untuk dropdown
   yang harus identik di Dashboard, Pelanggan, Detail.
   Wrapper .g-select-wrap untuk icon chevron absolut.
══════════════════════════════════════════════════════════ */
.g-select-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* Select standar global */
.g-select,
.filter-select {
  appearance: none;
  -webkit-appearance: none;
  height: var(--dd-h);
  padding: 0 var(--dd-pad-h); /* simetris kiri-kanan, tanpa chevron tidak perlu reservasi ruang ikon */
  border: var(--dd-border);
  border-radius: var(--dd-radius);
  background: var(--bg);
  color: var(--text-muted);
  font-size: var(--dd-font-size);
  font-weight: var(--dd-font-weight);
  font-family: var(--sans);
  cursor: pointer;
  min-width: 140px;
  transition: border-color .18s, box-shadow .18s, background .15s;

  /* Chevron SVG bawaan (fallback tanpa wrapper) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236a82a8' stroke-width='2.2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
}

.g-select:focus,
.filter-select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--dd-focus-ring);
  background-color: var(--bg);
}

/* Ikon chevron dropdown DIHILANGKAN secara global — sesuai keputusan,
   kotak select (border+background) sendiri sudah jadi sinyal visual
   "bisa diklik", tidak perlu ikon panah tambahan. Konsisten dgn
   .tf-sel-chevron yg juga disembunyikan di custom-select. */
.g-select-icon { display: none !important; }
select { background-image: none !important; }

/* Varian: primary (seperti selector MikroTik di dashboard) */
.g-select.primary {
  background-color: var(--primary-light);
  border-color: rgba(0,64,161,.20);
  color: var(--primary);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230040a1' stroke-width='2.2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
.g-select.primary:focus {
  border-color: var(--primary);
  box-shadow: var(--dd-focus-ring);
}

/* Varian: surface (filter halus di tabel/panel) */
.g-select.surface {
  background-color: var(--surface);
  border-color: var(--border);
  color: var(--text-muted);
}


/* ══════════════════════════════════════════════════════════
   23b. DEVICE BAR — komponen global (dipindah dari dashboard.css
   supaya dashboard, pelanggan & profile_pppoe pakai satu bentuk
   yang sama persis: icon box, dropdown .g-select, status dot
   animasi & badge sync — bukan masing-masing versi sendiri)
══════════════════════════════════════════════════════════ */
.dash-device-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 14px 18px;
  margin-bottom: var(--section-gap);
  box-shadow: var(--shadow-sm);
  flex-wrap: wrap;
}

.dash-device-bar-left {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  min-width: 0;
}

.dash-device-icon {
  width: 48px; height: 48px;
  border-radius: var(--r-md);
  background: var(--primary-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--primary); flex-shrink: 0;
}
.dash-device-icon .material-symbols-outlined { font-size: 22px; }

.dash-device-info { display: flex; flex-direction: column; gap: 2px; }

.dash-device-label {
  font-size:var(--fs-small); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-dim);
}

.dash-device-bar-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

/* Badge sync kecil di sisi kanan device bar */
.sync-badge {
  font-size:var(--fs-small); font-weight: 600;
  padding: 2px 8px; border-radius: 99px;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-dim); white-space: nowrap;
  transition: background .2s, color .2s;
}
.sync-badge.syncing { background: var(--blue-bg);  color: var(--blue);  border-color: var(--blue-border); }
.sync-badge.ok      { background: var(--green-bg); color: var(--green); border-color: var(--green-border); }
.sync-badge.error   { background: var(--red-bg);   color: var(--red);   border-color: var(--red-border); }

/* Ikon statis .g-select-icon selalu duplikat dengan chevron hasil enhance JS
   (.tf-sel-chevron) pada SEMUA dropdown ter-enhance — sembunyikan global */
.g-select-icon { display: none; }

/* Modifier: tampilan "sumber data" — gradient gelap seperti stat-card
   #1 (Total Pelanggan), warna dibedakan. Dipakai di Dashboard & Pelanggan
   untuk card device bar pilih perangkat MikroTik. */
.dash-device-bar--source {
  background: linear-gradient(135deg, #170655 0%, #003f88 100%);
  border-color: rgba(255,255,255,.15);
  box-shadow: 0 4px 20px rgba(0,63,136,.22);
  position: relative;
  /* z-index:1 - animation transform (cardSlideUp) membuat elemen ini
     stacking context sendiri; tanpa z-index eksplisit, seluruh context
     ini (termasuk .tf-pop dropdown #select-device, z-index:30 di
     dalamnya) jatuh sejajar dgn .stat-card lain (z-index:auto) dan
     tertutup .stat-row yang urutan DOM-nya setelah bar ini. */
  z-index: 1;
  animation: cardSlideUp .4s cubic-bezier(.22,1,.36,1) forwards;
}
/* Kilauan tipis melintas - sama seperti efek di bottom-nav, dipasang
   di belakang konten (z-index negatif) supaya teks/ikon tetap terbaca.
   border-radius sendiri (bukan overflow:hidden di parent) supaya panel
   dropdown #select-device (position:absolute, meluas ke luar card ini)
   tidak ikut terpotong. */
.dash-device-bar--source::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(100deg,
    transparent 20%, rgba(255,255,255,.18) 50%, transparent 80%);
  background-size: 250% 100%;
  animation: bnavShimmer 6s ease-in-out infinite;
  pointer-events: none;
  z-index: -1;
}
.dash-device-bar--source .dash-device-icon {
  background: rgba(255,255,255,.18);
  color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,.25) inset;
}
.dash-device-bar--source .dash-device-label {
  color: rgba(255,255,255,.75);
}
.dash-device-bar--source .sync-badge {
  background: rgba(255,255,255,.18) !important;
  border-color: transparent !important;
  color: rgba(255,255,255,.92) !important;
}
.dash-device-bar--source .tf-sel-trigger {
  background-color: rgba(255,255,255,.14) !important;
  border-color: rgba(255,255,255,.22) !important;
  color: #fff !important;
}


/* ══════════════════════════════════════════════════════════
   24. SECTION CARD GLOBAL — wrapper konten standar
   ─────────────────────────────────────────────────────────
   Identik dengan .dp-card di detail_pelanggan dan
   .dash-section di dashboard. Gunakan .g-section di
   halaman baru; backward-compat class juga disupport.
══════════════════════════════════════════════════════════ */

/* Base section card */
.g-section,
.dash-section,
.dp-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin-bottom: var(--section-gap);
}

/* Section head — konsisten dengan card-head */
.g-section-head,
.dash-section-head,
.dp-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px var(--section-pad-h);
  background: var(--card-head-bg);
  border-bottom: 1px solid var(--card-head-border);
  flex-wrap: wrap;
  /* wajib: text putih di atas background biru gelap */
  color: var(--card-head-text);
  font-family: var(--heading);
  font-size:var(--fs-body);
  font-weight: 800;
}
.dp-card-head .material-symbols-outlined { font-size: 18px; color: var(--card-head-icon, rgba(255,255,255,.8)); }

.g-section-title,
.dash-section-title,
.dp-card-title {
  font-family: var(--heading);
  font-size: var(--fs-title-sm);
  font-weight: 800;
  color: var(--card-head-text);
  display: flex;
  align-items: center;
  gap: 8px;
  letter-spacing: -.01em;
  line-height: 1.3;
}
.g-section-title .material-symbols-outlined,
.dash-section-title .material-symbols-outlined,
.dp-card-title .material-symbols-outlined {
  font-size: 18px;
  color: var(--card-head-icon);
}

.g-section-sub,
.dash-section-sub,
.dp-card-sub {
  font-size:var(--fs-small);
  color: rgba(255,255,255,.65);
  margin-top: 2px;
}

/* Section body padding */
.g-section-body,
.dash-section-body,
.dp-card-body {
  padding: var(--section-pad-v) var(--section-pad-h);
}

/* Tabel di dalam section: fullbleed, tanpa padding wrapper */
.g-section-table,
.dash-section-table,
.dp-card-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--tbl-cell-size);
}

.g-section-table th,
.dash-section-table th,
.dp-card-table th {
  padding: 10px 14px;
  text-align: left;
  font-size: var(--tbl-head-size);
  font-weight: var(--tbl-head-weight);
  text-transform: var(--tbl-head-case);
  letter-spacing: var(--tbl-head-spacing);
  color: var(--text-dim);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  user-select: none;
}

.g-section-table td,
.dash-section-table td,
.dp-card-table td {
  padding: 10px 14px;
  vertical-align: middle;
  border-bottom: 1px solid var(--border);
  line-height: 1.5;
}

.g-section-table tr:last-child td,
.dash-section-table tr:last-child td,
.dp-card-table tr:last-child td { border-bottom: none; }

/* Wrapper scroll tabel — scrollbar disembunyikan, scroll tetap aktif
   (mouse/trackpad/swipe) supaya tampilan lebih bersih */
.table-scroll,
#table-scroll,
#profile-table-wrap {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.table-scroll::-webkit-scrollbar,
#table-scroll::-webkit-scrollbar,
#profile-table-wrap::-webkit-scrollbar {
  display: none;
}


/* ══════════════════════════════════════════════════════════
   25. SKELETON LOADER GLOBAL
   ─────────────────────────────────────────────────────────
   Konsisten dengan detail_pelanggan. Gunakan class .skel
   di elemen placeholder saat data sedang dimuat.
   Helper class .skel-* untuk ukuran umum.
══════════════════════════════════════════════════════════ */
.skel {
  background: linear-gradient(
    90deg,
    var(--skel-base)  25%,
    var(--skel-shine) 50%,
    var(--skel-base)  75%
  );
  background-size: 200% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
  border-radius: 6px;
  display: block;
}

@keyframes skelShimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Ukuran preset — teks satu baris */
.skel-line { height: 14px; border-radius: 4px; }
.skel-line.sm { height: 12px; }
.skel-line.lg { height: 18px; }

/* Stat number placeholder */
.skel-num { height: 32px; width: 80px; border-radius: 6px; }

/* Baris tabel placeholder */
.skel-row { height: var(--tbl-row-h); width: 100%; border-radius: 0; }

/* Avatar circle placeholder */
.skel-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
}

/* Card section placeholder */
.skel-card {
  height: 80px;
  border-radius: var(--r-lg);
  width: 100%;
}

/* Stack helper — gunakan di dalam container flex-column */
.skel-stack { display: flex; flex-direction: column; gap: 8px; }
.skel-stack .skel-line { width: 70%; }
.skel-stack .skel-line:first-child { width: 50%; }
.skel-stack .skel-line:last-child  { width: 85%; }

/* Stat card skeleton (3 kolom) */
.skel-stat-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 22px;
}
.skel-stat-card {
  height: 96px;
  border-radius: var(--r-lg);
}

/* Tabel skeleton body */
.skel-tbody tr td { padding: 0; border: none; background: transparent !important; }
.skel-tbody .skel-row { margin: 2px 0; }


/* ══════════════════════════════════════════════════════════
   26. PROFILE DROPDOWN — Header sesi & item tambahan
══════════════════════════════════════════════════════════ */
.profile-menu-header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px 10px;
}
.profile-menu-avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--primary-light); color: var(--primary);
  font-size:var(--fs-body); font-weight: 700; font-family: var(--heading);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; letter-spacing: .04em;
}
.profile-menu-identity { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.profile-menu-name {
  font-size:var(--fs-body); font-weight: 700; font-family: var(--heading);
  color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.profile-menu-role {
  font-size:var(--fs-small); font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; padding: 1px 7px; border-radius: 20px;
  background: var(--primary-light); color: var(--primary);
  border: 1px solid rgba(0,64,161,.15); width: fit-content;
}
.profile-menu-role.teknisi {
  background: var(--amber-bg); color: var(--amber); border-color: var(--amber-border);
}


/* ══════════════════════════════════════════════════════════
   27. RESPONSIVE GLOBAL
══════════════════════════════════════════════════════════ */

/* Tablet landscape (≤1024px) */
@media (max-width: 1024px) {
  .header-inner   { padding: 0 20px; }
  .page           { padding-left: 20px; padding-right: 20px; }
  .topbar-nav a   { padding: 6px 10px; font-size:var(--fs-caption); }
  .stat-row-4     { grid-template-columns: repeat(2, 1fr); }
  .skel-stat-row  { grid-template-columns: repeat(2, 1fr); }
}

/* Tablet portrait (≤768px) */
@media (max-width: 768px) {
  .header-inner   { padding: 0 16px; }
  .page {
    padding-left: 16px; padding-right: 16px;
    padding-bottom: calc(var(--bnav-h) + 16px);
  }

  .topbar-nav     { display: none; }
  .brand-sub      { display: none; }
  .bottom-nav     { display: block; }

  .profile-username { display: none; }
  .profile-chevron  { display: none; }

  .stat-row .stat-card:nth-child(n+4),
  .stats-row .stat-card:nth-child(n+4),
  .stat-row-4 .stat-card:nth-child(n+4) { display: flex; }

  .stat-row, .stats-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  .stat-row-4            { grid-template-columns: 1fr 1fr; gap: 10px; }
  .skel-stat-row         { grid-template-columns: 1fr 1fr; gap: 10px; }

  .field-row      { grid-template-columns: 1fr; }
  .modal          { max-width: 100%; }

  .device-card    { flex-wrap: wrap; }
  .device-actions { width: 100%; justify-content: flex-end; margin-top: 6px; flex-wrap: wrap; }

  /* Device bar lebih ramping: dropdown + status sejajar label, badge sync sejajar judul.
     margin-bottom disamakan dengan gap antar stat-card (768px: 10px) supaya jarak
     device-bar ke card di bawahnya tidak terasa lebih lebar dari jarak antar card. */
  .dash-device-bar {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "icon   label  sync"
      "icon   select .";
    align-items: center;
    gap: 4px 10px;
    margin-bottom: 10px;
  }
  .dash-device-bar-left,
  .dash-device-info,
  .dash-device-bar-right { display: contents; }
  .dash-device-icon  { grid-area: icon; align-self: start; }
  .dash-device-label { grid-area: label; }
  .dash-device-info .g-select-wrap { grid-area: select; min-width: 0; }
  /* Badge sync sebaris dengan label (baris atas) - posisi konsisten di
     semua halaman, tidak ikut turun mengikuti tinggi area select/dropdown */
  .dash-device-bar-right .sync-badge { grid-area: sync; justify-self: end; align-self: center; }

  /* Dropdown perangkat sering punya min-width inline (style="min-width:240px")
     yang dibawa enhanceSelect() ke .tf-select — di mobile itu memaksa
     .dash-device-bar melebar sampai badge "Terhubung"/"Memperbarui..." keluar
     dari kartu. Paksa menyusut & biarkan teks terpotong (...) */
  .dash-device-info .g-select-wrap .tf-select {
    min-width: 0 !important;
    max-width: 100% !important;
    width: 100%;
  }

  #toast { bottom: calc(var(--bnav-h) + 12px); }

  .modal-overlay {
    top: var(--header-h);
    bottom: var(--bnav-h);
  }

  .modal-bs { align-items: flex-end; justify-content: center; }
  .modal-bs-sheet {
    max-width: 100% !important; width: 100%;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    padding-bottom: env(safe-area-inset-bottom, 8px);
    animation: slideUp .28s cubic-bezier(.22,1,.36,1);
  }

  /* Semua modal-sheet & modal biasa → bottom sheet di mobile */
  .modal-overlay { align-items: flex-end; justify-content: center; }
  .modal-sheet {
    width: 100% !important; max-width: 100% !important; min-width: unset;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    border: none; border-top: 1px solid var(--border);
    box-shadow: none;
    animation: slideUp .28s cubic-bezier(.22,1,.36,1);
    padding-bottom: env(safe-area-inset-bottom, 24px);
  }
  .modal-handle { display: block; }
  /* .modal (bukan .modal-sheet) di dalam overlay → bottom sheet juga.
     max-height presisi (header & bottom-nav) — tanpa ini, modal berisi
     form panjang (mis. Atur Gateway WA) meluap ke atas menutupi header. */
  .modal-overlay .modal {
    max-width: 100% !important; width: 100%;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    border: none; border-top: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    max-height: calc(100vh - var(--header-h) - var(--bnav-h) - 16px) !important;
    max-height: calc(100dvh - var(--header-h) - var(--bnav-h) - 16px) !important;
    overflow-y: auto;
    animation: slideUp .28s cubic-bezier(.22,1,.36,1);
  }

  /* Form tambah/edit (kartu perangkat, pelanggan, dll) → bottom sheet di mobile */
  #modal-form-overlay {
    align-items: flex-end; justify-content: center;
  }
  #modal-form-overlay .form-modal,
  #modal-form-overlay .modal {
    width: 100%; max-width: 100% !important;
    border: none; border-top: 1.5px solid var(--primary);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    box-shadow: var(--shadow-lg);
    /* Batasi sesuai ruang yang BENAR-BENAR tersedia di antara header & bottom-nav
       (bukan persentase layar) — supaya sheet tidak meluap menutupi header
       saat kontennya panjang. Baris vh sebagai fallback utk WebView tanpa dukungan dvh. */
    max-height: calc(100vh - var(--header-h) - var(--bnav-h) - 16px) !important;
    max-height: calc(100dvh - var(--header-h) - var(--bnav-h) - 16px) !important;
    overflow-y: auto;
    /* contain+translateZ: cegah konten/header sticky "bocor" keluar
       sudut membulat — bug rendering overflow+border-radius+sticky */
    contain: paint;
    padding: 20px 18px calc(env(safe-area-inset-bottom, 0px) + 24px) !important;
    animation: slideUp .28s cubic-bezier(.22,1,.36,1);
  }
  /* Handle drag jadi ::before milik HEADER (bukan container) & posisinya absolute
     supaya: (1) ikut menempel sticky bersama judul — tidak tergulir terpisah,
     (2) tidak ikut jadi flex-item di baris header (header ber-display:flex).
     Header yang sticky (position!=static) jadi containing block utk absolute ini. */
  #modal-form-overlay .form-modal > div:first-child::before,
  #modal-form-overlay .modal > div:first-child::before {
    content: '';
    position: absolute;
    top: -13px; left: 50%;
    transform: translateX(-50%);
    width: 40px; height: 4px; border-radius: 99px;
    background: var(--border-2);
  }
  /* Header/judul form tetap diam di atas — tidak ikut tergulir bersama isi.
     margin-bottom inline diubah jadi padding-bottom (di-!important-kan) supaya
     tertutup latar header itu sendiri — kalau dibiarkan margin, isi yang
     digulir bisa "mengintip" lewat celah transparan di bawah header sticky. */
  #modal-form-overlay .form-modal > div:first-child,
  #modal-form-overlay .modal > div:first-child {
    position: sticky; top: 0; z-index: 2;
    background: var(--bg);
    margin: 0 !important;
    padding-bottom: 16px !important;
    border-bottom: 1px solid var(--border);
  }
  /* Modal konfirmasi (icon bundar + judul + teks, dibuka via openModalForm)
     pakai .hapus-icon-wrap sebagai anak pertama, BUKAN header form — jangan
     ikut diberi treatment sticky-header di atas (yang merusak margin:auto
     peng-tengah ikon jadi rata kiri, dan menambah border-bottom yang tidak
     relevan untuk lingkaran ikon). */
  #modal-form-overlay .form-modal > .hapus-icon-wrap:first-child,
  #modal-form-overlay .modal > .hapus-icon-wrap:first-child {
    position: static !important;
    margin: 0 auto 14px !important;
    padding-bottom: 0 !important;
    border-bottom: none !important;
  }

  .g-section-head, .dash-section-head { flex-direction: column; align-items: flex-start; }
}

/* Mobile (≤480px) */
@media (max-width: 480px) {
  :root { --header-h: 84px; }

  .header-inner   { padding: 0 14px; }
  .page           { padding-left: 12px; padding-right: 12px; padding-bottom: 92px; }

  .stat-row, .stats-row, .stat-row-4 { grid-template-columns: 1fr; gap: 8px; }
  .skel-stat-row                     { grid-template-columns: 1fr; }

  .stat-card      { padding: 12px 14px; }
  .stat-num       { font-size:var(--fs-title-lg); }

  .page-title     { font-size:var(--fs-title-sm); }
  .page-top       { flex-direction: column; align-items: stretch; gap: 10px; }
  .page-top-actions { flex-direction: column; align-items: stretch; gap: 8px; width: 100%; }
  .page-top-actions .btn-primary,
  .page-top-actions .btn-secondary { width: 100%; justify-content: center; }
  .page-top-actions .date-badge { align-self: flex-start; }
  .btn-primary    { justify-content: center; }

  /* Persis 2 item (date-badge + tombol, atau 2 tombol) -> sebelahan, lebar sama */
  .page-top-actions:has(> :nth-child(2):last-child) { flex-direction: row; }
  .page-top-actions:has(> :nth-child(2):last-child) > * {
    flex: 1 1 0; width: auto; min-width: 0;
  }
  .page-top-actions:has(> :nth-child(2):last-child) .date-badge {
    align-self: stretch; justify-content: center;
  }

  /* Persis 3 tombol (tanpa date-badge/input) -> 2 per baris */
  .page-top-actions:has(> :nth-child(3):last-child):not(:has(.date-badge)):not(:has(input)) {
    flex-direction: row; flex-wrap: wrap;
  }
  .page-top-actions:has(> :nth-child(3):last-child):not(:has(.date-badge)):not(:has(input)) > * {
    flex: 1 1 calc(50% - 4px); width: auto; min-width: 0;
  }

  .form-grid      { grid-template-columns: 1fr; }
  .form-group.full{ grid-column: 1; }

  .dash-device-bar { padding: 12px 14px; margin-bottom: 8px; }

  .btn-sm         { font-size:var(--fs-small); padding: 4px 9px; }

  #toast {
    width: calc(100% - 24px); right: 12px;
    bottom: calc(var(--bnav-h) + 12px);
    text-align: center; justify-content: center;
  }

  .bottom-nav-item                            { font-size:var(--fs-small); }
  .bottom-nav-item .material-symbols-outlined { font-size: 20px; }
  .bottom-nav-icon                            { width: 24px; height: 24px; }

  /* Section pada mobile: kurangi padding */
  .g-section-head, .dash-section-head {
    padding: 11px var(--space-md);
  }
  .g-section-body, .dash-section-body {
    padding: var(--space-md);
  }
  .g-section-table th,
  .g-section-table td,
  .dash-section-table th,
  .dash-section-table td {
    padding: 8px 10px;
  }
}

/* HP sangat kecil (≤360px) */
@media (max-width: 360px) {
  .brand-name       { font-size:var(--fs-body); }
  .stat-num         { font-size:var(--fs-title-lg); }
  .page-title       { font-size:var(--fs-title-sm); }
  .bottom-nav-label { display: none; }
  .bottom-nav-item  { padding: 10px 4px; }
  .bottom-nav-icon  { width: 26px; height: 26px; }
  .stat-row, .stats-row, .stat-row-4 { grid-template-columns: 1fr; }
  .device-card      { padding: 12px 14px; }
  .device-icon      { width: 36px; height: 36px; font-size: 18px; }
  .modal            { width: calc(100vw - 32px); }
}

/* ══════════════════════════════════════════════════════════
   SHARED COMPONENTS — Input Perangkat
   Dipindahkan dari input_mikrotik.css & input_olt.css
   v2.2 — konsolidasi duplikasi CSS
   ⚠ Berlaku untuk semua halaman input_perangkat/*
══════════════════════════════════════════════════════════ */

/* ── Tombol warna ─────────────────────────────────────────── */
.btn-blue  { background: var(--blue-bg);  border-color: var(--blue-border);  color: var(--blue); }
.btn-amber { background: var(--amber-bg); border-color: var(--amber-border); color: var(--amber); }
.btn-red   { background: var(--red-bg);   border-color: var(--red-border);   color: var(--red); }
.btn-green { background: var(--green-bg); border-color: var(--green-border); color: var(--green); }

.btn-blue:hover  { background: #dbeafe; border-color: #93c5fd; }
.btn-amber:hover { background: #fef3c7; border-color: #fcd34d; }
.btn-red:hover   { background: #fee2e2; border-color: #fca5a5; }
.btn-green:hover { background: #dcfce7; border-color: #86efac; }

/* ── Form card (panel tambah/edit perangkat) ──────────────── */
.form-card {
  background: var(--bg);
  border: 1.5px solid var(--primary);
  border-radius: var(--r-xl);
  padding: 20px 24px;
  margin-bottom: 22px;
  box-shadow: 0 0 0 3px var(--primary-ring), var(--shadow-md);
  animation: slideDown .22s cubic-bezier(.22,1,.36,1);
}
.form-card-title {
  font-size: var(--fs-title-sm); font-weight: 700;
  font-family: var(--heading);
  color: var(--text); letter-spacing: -.01em;
  margin-bottom: 20px;
  display: flex; align-items: center; gap: 12px;
}
.form-card-title .material-symbols-outlined,
.form-card-title i { font-size: 20px; color: var(--primary); }

/* ── Form grid & groups ───────────────────────────────────── */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.form-group      { display: flex; flex-direction: column; gap: 5px; }
.form-group.full { grid-column: 1 / -1; }
.form-label { font-size:var(--fs-caption); font-weight: 600; color: var(--text-muted); letter-spacing: .01em; }
.form-hint  { font-size:var(--fs-small); color: var(--text-dim); margin-top: 3px; }

.form-input {
  height: 40px; padding: 0 12px;
  border: 1.5px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  font-size:var(--fs-body); font-family: var(--sans);
  width: 100%; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.form-input:focus {
  border-color: var(--primary);
  background: var(--bg);
}
.form-input::placeholder { color: var(--text-dim); }
.form-input.mono { font-family: var(--sans); font-weight: 600; font-size:var(--fs-caption); }
textarea.form-input { height: auto; padding: 10px 12px; resize: none; line-height: 1.6; }
select.form-input {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a96a8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
  padding-right: 32px; cursor: pointer;
}

/* IP + Port row — lihat definisi pertama (.ip-port-row) */

/* Password toggle */
.form-pwd-wrap { position: relative; display: flex; align-items: center; }
.form-pwd-wrap .form-input { padding-right: 40px; }
.form-pwd-toggle {
  position: absolute; right: 10px;
  background: none; border: none; cursor: pointer;
  color: var(--text-dim); display: flex; align-items: center;
  transition: color .15s; padding: 0;
}
.form-pwd-toggle:hover { color: var(--primary); }
.form-pwd-toggle .material-symbols-outlined { font-size: 18px; }

.form-actions {
  display: flex; justify-content: flex-end; gap: 10px;
  margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border);
}

/* ── Koordinat row + preview ──────────────────────────────── */
/* Koordinat: input + tombol Deteksi bersebelahan (pola sama dgn SN + Scan SN). */
.koordinat-row { display: flex; flex-direction: row; gap: 8px; align-items: center; }
.koordinat-row .form-input { width: auto; flex: 1; }
.koordinat-btn {
  height: 40px; padding: 0 14px;
  border: 1.5px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--primary);
  font-size:var(--fs-caption); font-weight: 600; font-family: var(--sans);
  cursor: pointer; white-space: nowrap; flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 5px;
  transition: background .15s, border-color .15s;
}
.koordinat-btn:hover { background: var(--primary-light); border-color: var(--primary); }
.koordinat-btn .material-symbols-outlined { font-size: 15px; }

.koordinat-preview {
  margin-top: 6px; border: 1px solid var(--border);
  border-radius: var(--r-sm); overflow: hidden;
  height: 120px; background: var(--surface); display: none;
}
.koordinat-preview.show { display: block; }
.koordinat-preview iframe { width: 100%; height: 100%; border: none; }

/* Badge koordinat di card */
.koordinat-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size:var(--fs-small); color: var(--text-dim);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 99px; padding: 2px 8px;
  text-decoration: none; cursor: pointer;
  transition: background .15s, color .15s;
  max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.koordinat-badge:hover { background: var(--primary-light); color: var(--primary); }
.koordinat-badge .material-symbols-outlined { font-size: 12px; flex-shrink: 0; }

/* ── List header ──────────────────────────────────────────── */
.list-header {
  display: flex; align-items: center;
  justify-content: space-between; margin-bottom: 12px;
}
.list-title {
  font-size:var(--fs-small); font-weight: 700;
  color: var(--text-dim); text-transform: uppercase; letter-spacing: .06em;
}

/* ── Device card — base layout ────────────────────────────── */
.device-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  margin-bottom: 10px;
  display: flex; align-items: center; gap: 14px;
  box-shadow: var(--shadow-sm);
  transition: border-color .2s, box-shadow .2s, transform .15s;
  animation: fadeUp .2s ease both;
}
.device-card:hover {
  border-color: var(--border-2);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.device-card.status-connected { border-left: 3px solid var(--green); }
.device-card.status-failed    { border-left: 3px solid var(--red); }
.device-card.status-pending   { border-left: 3px solid var(--amber); }

.device-icon {
  width: 44px; height: 44px; border-radius: var(--r-md);
  background: var(--primary-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--primary); flex-shrink: 0;
}
.device-info  { flex: 1; min-width: 0; }
.device-top   { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; flex-wrap: wrap; }
.device-top > .badge { margin-left: auto; }
.device-name  { font-size:var(--fs-body); font-weight: 700; color: var(--text); }
.device-meta  { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.device-meta-item {
  display: flex; align-items: center; gap: 4px;
  font-size:var(--fs-caption); color: var(--text-muted);
}
.device-meta-item .material-symbols-outlined,
.device-meta-item i { font-size: 13px; color: var(--text-dim); }
.device-keterangan { font-size:var(--fs-small); color: var(--text-dim); margin-top: 5px; font-style: italic; }
.device-actions { display: flex; gap: 5px; flex-shrink: 0; flex-wrap: nowrap; justify-content: flex-end; }
.device-bottom-row {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px; width: 100%; margin-top: 6px;
}
/* Label tombol panjang (mis. "Remote ONU", "Isolir Redirect") otomatis
   memendek di mobile supaya tetap muat satu baris — lihat penggunaan
   di input_mikrotik.js (btn-label-full/btn-label-short). */
.btn-label-short { display: none; }
@media (max-width: 639px) {
  .btn-label-full  { display: none; }
  .btn-label-short { display: inline; }
}
.device-profile-row { margin-top: 7px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* Badge tipe (ZTE, Huawei, dll) */
.device-tipe-badge {
  font-size:var(--fs-small); font-weight: 600;
  padding: 2px 8px; border-radius: 99px;
  background: var(--primary-light); color: var(--primary);
  border: 1px solid rgba(0,64,161,.2); white-space: nowrap;
}

/* ── Empty state ──────────────────────────────────────────── */
.empty-state {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 48px 24px; text-align: center;
  color: var(--text-muted);
  background: var(--bg);
  border: 1px dashed var(--border);
  border-radius: var(--r-lg); gap: 8px;
}
.empty-state p { margin: 0; font-size:var(--fs-body); line-height: 1.6; }
.empty-state .material-symbols-outlined { font-size: 40px; color: var(--text-dim); }

/* ── Stats row 4 kolom ────────────────────────────────────── */
.stats-row-4 { grid-template-columns: repeat(4, 1fr); }

/* ── Responsive — input perangkat ────────────────────────── */
@media (max-width: 768px) {
  .device-card    { flex-wrap: wrap; }
  .device-actions { width: 100%; justify-content: flex-end; margin-top: 6px; flex-wrap: wrap; }
  .stats-row-4    { grid-template-columns: repeat(2, 1fr); gap: 10px; }
}
@media (max-width: 480px) {
  .form-grid      { grid-template-columns: 1fr; }
  .form-group.full{ grid-column: 1; }
  .btn-sm         { font-size:var(--fs-small); padding: 4px 9px; }
  .stats-row-4    { grid-template-columns: 1fr 1fr; }
}
/* -- Tabel Kolektor Dashboard -------------------------------- */
.kol-table { width:100%; border-collapse:separate; border-spacing:0; font-size:var(--fs-body); font-family:var(--sans); min-width:700px; }
.kol-table thead th { background:var(--header-bg); color:rgba(255,255,255,.85); font-size:var(--fs-small); font-weight:700; text-transform:uppercase; letter-spacing:.06em; padding:10px 14px; border-bottom:1px solid rgba(255,255,255,.12); text-align:left; white-space:nowrap; }
.kol-table tbody td { padding:10px 14px; border-bottom:1px solid var(--border); color:var(--text); vertical-align:middle; }
.kol-table tbody tr:last-child td { border-bottom:none; }
.kol-table tbody tr:hover td { background:var(--surface); }
.kol-bayar-item { display:flex; align-items:center; gap:10px; padding:10px 12px; border:1.5px solid var(--border); border-radius:var(--r-md); cursor:pointer; transition:border-color .15s,background .15s; font-size:var(--fs-body); }
.kol-bayar-item:hover { border-color:var(--primary); background:var(--primary-light); }
.kol-bayar-item input { width:16px; height:16px; accent-color:var(--primary); flex-shrink:0; }

/* -- Modal khusus kolektor dashboard (scoped agar tidak bocor) */
.kol-modal-overlay { display:none; position:fixed; inset:0; background:rgba(15,23,42,.5); backdrop-filter:blur(2px); z-index:90; }
.kol-modal-overlay.show { display:block; }
.kol-modal { display:none; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); width:min(480px,calc(100vw - 32px)); background:var(--bg); border-radius:var(--r-lg); box-shadow:0 20px 60px rgba(0,0,0,.25); z-index:91; max-height:90vh; overflow-y:auto; }
.kol-modal.show { display:block; }

/* -- Tagihan badge di Maps card ONU ----------------------------- */
.dcx-tagihan-badge { display:inline-block; padding:2px 8px; border-radius:99px; font-size:var(--fs-small); font-weight:700; margin-top:3px; }
.dcx-tbadge-belum { background:rgba(220,38,38,.2); color:#dc2626; }
.dcx-tbadge-lunas { background:rgba(22,163,74,.2); color:#16a34a; }
.dcx-btn-amber { background:#d97706; color:#fff; }
.dcx-btn-amber:hover { background:#b45309; }

/* ══════════════════════════════════════════════════════════
   SHARED PAGINATION — dipakai di tagihan, loket, dll
══════════════════════════════════════════════════════════ */
.pagination {
  display: flex; align-items: center; gap: 4px;
  justify-content: center; flex-wrap: wrap;
}
.page-btn {
  min-width: 34px; height: 34px; padding: 0 10px;
  border-radius: var(--r-sm); border: 1.5px solid var(--border);
  background: var(--bg); color: var(--text-muted);
  font-size:var(--fs-body); font-weight: 600; font-family: var(--sans);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: background .14s, border-color .14s, color .14s;
  white-space: nowrap;
}
.page-btn:hover    { background: var(--surface); border-color: var(--border-2); color: var(--text); }
.page-btn.active   { background: var(--primary); color: #fff; border-color: var(--primary); }
.page-btn:disabled { opacity: .4; cursor: not-allowed; pointer-events: none; }
.page-btn.ellipsis { border-color: transparent; background: none; cursor: default; color: var(--text-dim); }

/* ══════════════════════════════════════════════════════════════
   GLOBAL ENHANCEMENTS v45+
══════════════════════════════════════════════════════════════ */

/* ── Page fade-in on load ── */
@keyframes pageIn { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:translateY(0)} }
.page-wrap, .main-content, .content-area { animation: pageIn .3s ease both; }

/* ── Cross-document View Transitions (native browser API) — transisi
   antar-halaman tanpa SPA, tanpa delay JS buatan. Browser yang support
   (Chrome/Edge 126+) coordinate snapshot lama→baru sendiri; browser lain
   (Firefox/Safari saat ini) abaikan rule ini & reload normal tanpa efek,
   jadi tidak ada risiko. header/bottom-nav dikasih view-transition-name
   sendiri supaya dianggap "elemen yang sama" lintas halaman (krn isinya
   identik di semua halaman) — hasilnya terlihat diam, cuma konten yg
   crossfade. ── */
@view-transition { navigation: auto; }

.header     { view-transition-name: tf-header; }
.bottom-nav { view-transition-name: tf-bottom-nav; }

::view-transition-old(root),
::view-transition-new(root) { animation-duration: .18s; }

/* ── Table row — left accent on hover ── */
.tbl-main tbody tr { transition: background .1s; }
.tbl-main tbody tr:hover > td:first-child {
  box-shadow: inset 3px 0 0 var(--primary);
  padding-left: 13px;
}

/* ── Badge status improvement — bigger pulse ring ── */
@keyframes pulseGreen {
  0%,100% { box-shadow: 0 0 0 0 rgba(34,197,94,.6); }
  50%      { box-shadow: 0 0 0 5px rgba(34,197,94,0); }
}
@keyframes pulseRed {
  0%,100% { box-shadow: 0 0 0 0 rgba(239,68,68,.5); }
  50%      { box-shadow: 0 0 0 4px rgba(239,68,68,0); }
}

/* ── Stat card shimmer on hover ── */
.stat-card::after {
  display: block;
  content: '';
  position: absolute;
  top: -60%; left: -60%;
  width: 60%; height: 200%;
  background: linear-gradient(105deg, transparent 40%, rgba(255,255,255,.07) 50%, transparent 60%);
  transform: skewX(-15deg);
  transition: left .4s ease;
  pointer-events: none;
}
.stat-card:hover::after { left: 110%; }

/* ── Better mobile toast ── */
@media (max-width: 600px) {
  #toast {
    bottom: 72px !important;
    left: 12px !important;
    right: 12px !important;
    width: auto !important;
    transform: none !important;
  }
}

/* ── Scrollbar global thin ── */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,.15); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.3); }

/* ── Filter bar gap uniform ── */
.filter-bar { gap: 10px; }

/* ── Table empty state ── */
.tbl-empty {
  text-align: center;
  padding: 56px 20px !important;
  color: var(--text-dim);
}
.tbl-empty .material-symbols-outlined { font-size: 40px; opacity: .4; display: block; margin-bottom: 10px; }
.tbl-empty p { font-size:var(--fs-body); margin-top: 6px; }


/* ── Feature lock (fitur terkunci sesuai paket langganan) ──── */
.tf-locked {
  position: relative !important;
  opacity: .5;
  filter: grayscale(.35);
  cursor: not-allowed !important;
  pointer-events: none;
}
.tf-lockbadge {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--amber);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  cursor: pointer;
  z-index: 2;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
.tf-lockbadge .material-symbols-outlined {
  font-size: 9px;
  color: #fff;
}

/* ════════════════════════════════════════════════════════════
   CUSTOM DROPDOWN & DATE/MONTH PICKER
   Ganti tampilan <select> & <input type="date"/"month"> bawaan
   browser/device (termasuk picker mobile) dengan UI premium yang
   konsisten. Elemen asli disembunyikan visual (.tf-native-hidden)
   tapi tetap ada di DOM untuk value/onchange — lihat global.js.
══════════════════════════════════════════════════════════════ */
.tf-native-hidden {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: 0 !important; border: none !important;
  opacity: 0 !important; overflow: hidden !important; pointer-events: none !important;
}

/* Panel dibuka INLINE (position:static), tepat di bawah trigger lewat
   urutan DOM normal — bukan overlay absolute/fixed. Jadi posisinya selalu
   benar di manapun trigger berada (toolbar, dalam modal yg discroll, dll)
   tanpa perlu hitung containing-block atau JS positioning. */
.tf-pop {
  position: static; width: 100%; box-sizing: border-box;
  margin-top: 0; max-height: 0; overflow: hidden;
  background: var(--bg); border: 1px solid transparent;
  border-radius: var(--r-md); box-shadow: none;
  padding: 6px;
  opacity: 0;
  transition: max-height .2s ease, opacity .15s ease, margin-top .2s ease,
    border-color .2s ease, box-shadow .2s ease;
}
.tf-pop.open {
  margin-top: 6px; max-height: 200px; overflow-y: auto;
  opacity: 1; border-color: var(--border); box-shadow: var(--shadow-lg);
}

/* ── Custom select ──────────────────────────────────────── */
.tf-select { position: relative; display: inline-block; }
.tf-select.tf-block { display: block; width: 100%; }

/* Dropdown compact (filter, picker perangkat, dll - bukan field
   full-width di card tambah/edit): panel tampil sebagai overlay
   melayang menempel trigger, tidak mendorong layout saat dibuka -
   sama seperti dropdown pilih perangkat. Lebar panel minimal
   selebar trigger, tapi BOLEH lebih lebar kalau teks opsi
   lebih panjang (tidak dipotong ikut lebar trigger).
   Catatan: width:auto pada elemen absolute "shrink-to-fit" tetap
   dibatasi lebar trigger (containing block) walau ada min-width;
   max-content tidak ikut batas itu, jadi panel benar2 menyesuaikan
   teks opsi terlebar - dibatasi max-width agar tidak meluber. */
.tf-select:not(.tf-block) .tf-pop {
  position: absolute; top: 100%; left: 0;
  width: max-content; min-width: 100%; max-width: 280px;
  z-index: 30; margin-top: 0;
}
.tf-select:not(.tf-block) .tf-pop.open { margin-top: 4px; }
/* Kalau trigger dekat tepi kanan layar, panel (bisa lebih lebar dari
   trigger) ditambahkan class ini lewat JS (lihat openPop di global.js)
   supaya rata-kanan & tumbuh ke kiri, tidak meluber keluar viewport. */
.tf-select:not(.tf-block) .tf-pop.tf-pop-end { left: auto; right: 0; }

.tf-sel-trigger {
  display: flex; align-items: center; gap: 8px; width: 100%;
  text-align: left; cursor: pointer; background-image: none !important;
  padding-right: var(--dd-pad-h) !important; /* simetris kiri-kanan tanpa chevron */
}
.tf-sel-trigger-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ikon chevron dropdown disembunyikan di semua custom-select (global) */
.tf-sel-chevron { display: none; }
.tf-sel-trigger:disabled { opacity: .55; cursor: not-allowed; }

.tf-sel-panel .tf-sel-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 11px; border-radius: var(--r-sm); font-size:var(--fs-body); color: var(--text);
  cursor: pointer; transition: background .12s ease;
}
.tf-sel-panel .tf-sel-opt:hover { background: var(--surface-2); }
.tf-sel-panel .tf-sel-opt.selected { background: var(--primary-light); color: var(--primary); font-weight: 600; }
.tf-sel-panel .tf-sel-opt[aria-disabled="true"] { opacity: .4; pointer-events: none; }
/* Ikon centang opsi terpilih disembunyikan di semua dropdown (global) */
.tf-sel-panel .tf-sel-check { display: none; }
.tf-sel-empty { padding: 14px 11px; font-size:var(--fs-caption); color: var(--text-dim); text-align: center; }

/* ── Custom date / month picker ────────────────────────────── */
.tf-dp { position: relative; display: inline-block; }
.tf-dp.tf-dp-block { display: block; width: 100%; }

/* Picker tanggal/bulan compact (filter, bukan field di card
   tambah/edit): panel kalender overlay melayang menempel trigger
   (tidak mendorong layout) - sama seperti dropdown pilih perangkat.
   Lebar TIDAK dipaksa ikut trigger (beda dgn .tf-select) karena
   grid kalender 7 kolom butuh lebar sendiri (lihat .tf-dp-panel). */
.tf-dp:not(.tf-dp-block) .tf-pop {
  position: absolute; top: 100%; left: 0; width: auto;
  z-index: 30; margin-top: 0;
}
.tf-dp:not(.tf-dp-block) .tf-pop.open { margin-top: 4px; }
/* Sama seperti .tf-select di atas - cegah panel kalender meluber
   keluar tepi kanan layar (lihat openPop di global.js). */
.tf-dp:not(.tf-dp-block) .tf-pop.tf-pop-end { left: auto; right: 0; }

.tf-dp-trigger {
  display: flex; align-items: center; gap: 8px; width: 100%;
  text-align: left; cursor: pointer; background-image: none !important;
}
.tf-dp-icon { font-size: 17px; color: var(--primary); flex-shrink: 0; }
.tf-dp-trigger-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf-dp-trigger:disabled { opacity: .55; cursor: not-allowed; }

.tf-dp-panel { padding: 6px; max-width: 240px; }
.tf-dp-panel.open { max-height: 280px; }

.tf-dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.tf-dp-label { font-weight: 700; font-size:var(--fs-caption); color: var(--text); font-family: var(--heading); }
.tf-dp-nav {
  width: 24px; height: 24px; border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: background .15s ease, color .15s ease;
}
.tf-dp-nav:hover { background: var(--primary-light); color: var(--primary); }
.tf-dp-nav .material-symbols-outlined { font-size: 15px; }

.tf-dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.tf-dp-dow {
  text-align: center; font-size:var(--fs-small); font-weight: 700; color: var(--text-dim);
  text-transform: uppercase; padding: 2px 0;
}
.tf-dp-day {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border: none; background: none; border-radius: var(--r-sm); font-size:var(--fs-small); color: var(--text);
  cursor: pointer; transition: background .12s ease, color .12s ease;
}
.tf-dp-day:hover { background: var(--surface-2); }
.tf-dp-day.tf-dp-out { color: var(--text-dim); opacity: .4; cursor: default; }
.tf-dp-day.tf-dp-out:hover { background: none; }
.tf-dp-day.tf-dp-today { color: var(--primary); font-weight: 700; box-shadow: inset 0 0 0 1.5px var(--primary); }
.tf-dp-day.tf-dp-selected { background: var(--primary); color: #fff; font-weight: 700; }

.tf-dp-mgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.tf-dp-month {
  padding: 7px 4px; border: none; background: var(--surface); border-radius: var(--r-sm);
  font-size:var(--fs-small); font-weight: 600; color: var(--text); cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.tf-dp-month:hover { background: var(--primary-light); color: var(--primary); }
.tf-dp-month.tf-dp-today { box-shadow: inset 0 0 0 1.5px var(--primary); color: var(--primary); }
.tf-dp-month.tf-dp-selected { background: var(--primary); color: #fff; }

.tf-dp-foot { display: flex; justify-content: flex-end; margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--border); }
.tf-dp-today-btn {
  font-size:var(--fs-small); font-weight: 700; color: var(--primary); background: var(--primary-light);
  border: none; border-radius: var(--r-sm); padding: 4px 10px; cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.tf-dp-today-btn:hover { background: var(--primary); color: #fff; }
