/* VALE DIGITAL TWIN — bahasa visual.
 *
 * Palet berasal dari lambang korporat pada kop Scope of Work REV.0/2026:
 * Vale-Green #007E7A dan Vale-Blue #3CB5E5; kuning tidak ada di palet.
 *
 * Bentuknya mengikuti bahasa rupa Apple, atas permintaan klien. Yang berubah
 * bukan sekadar sudut dan warna, melainkan cara panel berlaku terhadap apa
 * yang ada di belakangnya:
 *
 *   · LATAR NETRAL, bukan gelap bersemu toska. Warna merek dipakai sebagai
 *     aksen, tidak sebagai suasana. Di ruang kendali, latar yang ikut
 *     berwarna membuat penanda berwarna kehilangan artinya.
 *   · PERMUKAAN TEMBUS dengan buram tebal dan saturasi dinaikkan. Panel
 *     mengambil warna dari medan 3D di belakangnya, jadi ia terasa melayang
 *     di atas kawasan alih-alih menutupinya.
 *   · SUDUT BESAR dan garis serambut. Garis 1 px bersemu neon diganti garis
 *     putih nyaris tak terlihat; yang memisahkan panel dari latar sekarang
 *     bayangannya, bukan garisnya.
 *   · HURUF SISTEM, bukan monospace. Monospace tetap dipakai untuk ANGKA —
 *     kolom yang sejajar bisa dibandingkan sekilas — tetapi teks biasa dalam
 *     huruf monospace membaca seperti terminal, bukan seperti perkakas.
 *   · UKURAN NAIK, KAPITAL TURUN. Label 8,5 px berhuruf kapital ber-tracking
 *     lebar adalah kebiasaan dasbor teknis; ia padat tetapi melelahkan.
 *     Diganti huruf kalimat berukuran wajar.
 *
 * Warna tetap dipakai hemat: toska untuk keadaan normal dan penanda aktif,
 * kuning untuk peringatan, merah untuk alarm. Di luar itu abu-abu. Ruang
 * kendali yang penuh warna membuat yang genting tidak lagi menonjol.
 */
/* DUA TEMA, SATU PALET.
 *
 * Panduan merek menyebut latar harus Vale-Green, Vale-Blue, atau putih, dan
 * teks memakai Vale-Dark-Gray. Itu identitas yang TERANG, dan karena itulah
 * terang yang jadi bawaan di sini.
 *
 * Gelap tetap ada, dan bukan sebagai selera. Panel aplikasi ini melayang di
 * atas medan 3D yang menggambarkan siang dan malam sungguhan; pada pukul dua
 * pagi, antarmuka putih terang di ruang kendali menyilaukan orang yang harus
 * menatapnya semalaman. Yang memilih bukan pengguna lewat saklar melainkan
 * sistem operasinya — sama seperti seluruh aplikasi lain di perangkat itu.
 *
 * Semua warna di lembar ini melewati token. Itu yang membuat dua tema mungkin
 * tanpa menulis dua lembar gaya: yang berganti hanya nilainya, bukan
 * aturannya.
 */
:root {
  /* ---- PALET RESMI — dari vale_color.pptx, tab Theme Colours.
   *
   * Nilai-nilai ini SALINAN, bukan turunan. Sebelumnya sebagian ditebak dari
   * kop surat SOW; yang paling meleset kuning #EAAA14, yang ternyata tidak
   * ada sama sekali di palet Vale, padahal dipakai sebagai warna judul setiap
   * kotak dan penanda peringatan di seluruh aplikasi.
   *
   * Aturan pemakaian dari slide 4: Vale-Green, Vale-Blue, dan White untuk
   * LATAR; Vale-Dark-Gray untuk TEKS; sisanya untuk grafik. */
  --vale-green:      #007E7A;
  --vale-blue:       #3CB5E5;
  --vale-dark-gray:  #555555;
  --vale-gray:       #747678;
  --vale-dark-blue:  #2626D1;
  --vale-dark-green: #034944;
  --vale-mid-gray:   #BCBEC0;
  --vale-light-gray: #E6E7E8;

  /* Nama lama dipertahankan supaya seluruh lembar tidak perlu ditulis ulang
     sekaligus; nilainya kini yang resmi. */
  --vale-teal:        var(--vale-green);
  --vale-teal-terang: #19B3A6;
  --vale-teal-neon:   var(--vale-green);

  /* ---- TERANG (bawaan, sesuai panduan) */
  --ground:      #FFFFFF;
  --ground-2:    #F4F5F6;
  --permukaan:   rgba(255, 255, 255, .74);
  --permukaan-2: rgba(255, 255, 255, .90);
  --garis:       rgba(0, 0, 0, .10);
  --garis-kuat:  rgba(0, 0, 0, .18);
  --kilau:       rgba(0, 0, 0, .05);

  --isi-halus:   rgba(0, 0, 0, .04);
  --isi:         rgba(0, 0, 0, .07);
  --isi-kuat:    rgba(0, 0, 0, .12);

  --teks:   var(--vale-dark-gray);
  /* Teks redup dan samar DIUKUR, bukan ditebak.
   *
   * Nilai pertama saya — alfa 0,70 dan 0,46 — memberi 3,54:1 dan 2,15:1 di
   * atas putih; keduanya di bawah ambang WCAG AA. Teks abu muda di atas latar
   * putih adalah kegagalan aksesibilitas yang paling sering lolos karena ia
   * tampak "halus" bagi mata yang sehat di layar yang baik. */
  --redup:  rgba(60, 60, 60, .86);
  --samar:  rgba(60, 60, 60, .64);
  /* Vale-Blue adalah warna LATAR menurut panduan, bukan warna teks: di atas
     putih ia hanya 2,35:1. Untuk teks beraksen di tema terang yang dipakai
     Vale-Green; birunya tetap boleh mengisi bidang. */
  --biru-teks: var(--vale-dark-blue);

  /* Warna di atas isian pekat — tombol utama dan lencana berlatar warna. */
  --atas-warna: #FFFFFF;

  --bayang-1: 0 1px 2px rgba(0, 0, 0, .07), 0 4px 12px rgba(0, 0, 0, .06);
  --bayang-2: 0 2px 6px rgba(0, 0, 0, .09), 0 12px 32px rgba(0, 0, 0, .10);
  --bayang-3: 0 8px 20px rgba(0, 0, 0, .12), 0 28px 68px rgba(0, 0, 0, .16);

  /* ---- STATUS.
   *
   * Palet merek tidak memuat warna peringatan maupun bahaya — ia palet
   * presentasi, dan presentasi tidak punya alarm. Keduanya karena itu warna
   * FUNGSIONAL, sengaja dipilih di luar palet supaya tidak pernah tertukar
   * dengan warna korporat. */
  --ok:     var(--vale-green);
  --warn:   #B4690E;
  --alarm:  #C7362B;
  --diam:   var(--vale-gray);

  /* ---- HURUF.
   *
   * Vale Sans lebih dulu. Berkasnya belum ada di project ini, jadi mesin yang
   * tidak memilikinya jatuh ke huruf sistem — SF di Apple, Segoe di Windows.
   * Bila berkasnya tersedia kelak, cukup satu @font-face di sini dan seluruh
   * aplikasi ikut tanpa perubahan lain. */
  --sans: 'Vale Sans Light', 'Vale Sans', -apple-system, BlinkMacSystemFont,
          'SF Pro Text', 'Inter', 'Segoe UI Variable Text', 'Segoe UI',
          system-ui, sans-serif;
  --sans-tebal: 'Vale Sans Medium', 'Vale Sans', -apple-system,
          BlinkMacSystemFont, 'SF Pro Display', 'Inter', 'Segoe UI', system-ui, sans-serif;
  --mono: 'SF Mono', 'JetBrains Mono', 'Cascadia Mono', ui-monospace, Consolas, monospace;

  --buram: saturate(180%) blur(30px);

  --bar-h:   56px;
  --panel-w: 300px;
  --radius:    12px;
  --radius-sm:  9px;
  --radius-lg: 18px;
}

/* ---- GELAP.
 *
 * Bertumpu pada Vale-Dark-Green, bukan hitam netral: hitam bukan warna merek,
 * dan panel tembus di atasnya kehilangan warna yang seharusnya diambilnya
 * dari Vale. Aksen bergeser ke Vale-Blue karena Vale-Green kehilangan
 * keterbacaannya di atas latar yang juga hijau. */
@media (prefers-color-scheme: dark) {
  :root {
    --vale-teal-neon: var(--vale-blue);

    --ground:      #021E1C;
    --ground-2:    #04302C;
    --permukaan:   rgba(3, 73, 68, .62);
    --permukaan-2: rgba(4, 58, 54, .80);
    --garis:       rgba(255, 255, 255, .10);
    --garis-kuat:  rgba(255, 255, 255, .18);
    --kilau:       rgba(255, 255, 255, .08);

    --isi-halus:   rgba(255, 255, 255, .045);
    --isi:         rgba(255, 255, 255, .09);
    --isi-kuat:    rgba(255, 255, 255, .16);

    --teks:   #FFFFFF;
    --redup:  rgba(255, 255, 255, .70);
    --samar:  rgba(255, 255, 255, .48);
    --biru-teks: var(--vale-blue);
    --atas-warna: #FFFFFF;

    --warn:   #F5A524;
    --alarm:  #FF453A;

    --bayang-1: 0 1px 2px rgba(0, 0, 0, .28), 0 4px 12px rgba(0, 0, 0, .22);
    --bayang-2: 0 2px 6px rgba(0, 0, 0, .32), 0 12px 32px rgba(0, 0, 0, .34);
    --bayang-3: 0 8px 20px rgba(0, 0, 0, .40), 0 28px 68px rgba(0, 0, 0, .46);
  }
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* Dokumen ini TIDAK PERNAH menggulung.
 *
 * Seluruh cangkang diletakkan absolut di dalam satu layar penuh; yang boleh
 * menggulung hanya isinya sendiri (.halaman, .isi-panel, .belah-kiri). Tanpa
 * kunci ini, satu elemen hias yang menonjol sedikit saja — cincin menu alat
 * yang melebar melewati tepi kanan, misalnya — langsung memunculkan bilah
 * gulung di sekeliling peta. */
html, body { width: 100%; height: 100%; overflow: hidden; }
html { font-family: var(--sans); -webkit-font-smoothing: antialiased;
       -moz-osx-font-smoothing: grayscale; }
body {
  background: var(--ground);
  color: var(--teks);
  /* Huruf sistem, SF lebih dulu. Urutannya penting: -apple-system harus
     mendahului 'Segoe UI', kalau tidak mesin Windows yang kebetulan punya
     keduanya akan memilih yang salah — dan seluruh nada rupanya berubah
     hanya karena satu urutan. */
  font: 14px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
}

/* Kisi latar tipis — memberi kedalaman pada halaman tanpa peta dan menandai
   bahwa ini ruang teknis. Sangat samar supaya tidak mengganggu bacaan. */
body::before {
  /* Kilau lembut, bukan kisi teknis.
   *
   * Latar berpola titik adalah kiasan perkakas rekayasa. Yang
   * menggantikannya di sini satu sapuan cahaya yang nyaris tak terlihat —
   * cukup untuk membuat layar hitam tidak terasa mati, tidak cukup untuk
   * bersaing dengan apa pun yang digambar di atasnya. */
  background:
    radial-gradient(ellipse 120% 80% at 50% -10%, rgba(47, 212, 196, .07), transparent 60%),
    radial-gradient(ellipse 90% 60% at 85% 100%, var(--isi-halus), transparent 65%);
}

.angka, table.tabel td.angka, .kpi-nilai {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  letter-spacing: -.1px;
}

/* ---------------------------------------------------------- bilah atas */

.bar {
  position: absolute; inset: 0 0 auto 0; height: var(--bar-h); z-index: 40;
  display: flex; align-items: center; gap: 14px; padding: 0 16px;
  /* Tembus pandang dengan buram tebal — bilah mengambil warna dari apa yang
     lewat di bawahnya, seperti bilah menu yang melayang di atas jendela. */
  background: var(--permukaan-2);
  -webkit-backdrop-filter: var(--buram); backdrop-filter: var(--buram);
  border-bottom: 1px solid var(--garis);
  box-shadow: none;
}
.bar .merek { display: flex; align-items: center; gap: 12px; min-width: 0; flex: none; }
.bar .merek img { width: 30px; height: 26px; flex: none; }
.bar .merek .judul { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.bar .merek .judul b {
  font-size: 15px; font-weight: 600; letter-spacing: -.35px; white-space: nowrap;
}
.bar .merek .judul b em { color: var(--vale-teal-neon); font-style: normal; }
.bar .merek .judul span {
  font-size: 11.5px; color: var(--samar); letter-spacing: 0; text-transform: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bar .kanan {
  margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none;
}

/* Menu yang menyusut, bukan yang mendorong.
 *
 * Bilah ini tidak boleh melebar melewati layar: kalau melebar, grup kanan —
 * termasuk tombol Keluar — terdorong keluar dan tidak bisa disentuh sama
 * sekali, dan sejak dokumen mengunci overflow ia hilang tanpa jejak. Merek dan
 * grup kanan karena itu tidak boleh menyusut; yang mengalah adalah menunya,
 * yang boleh digulung mendatar bila layarnya memang sempit.
 *
 * Bilah gulungnya sendiri disembunyikan — di bilah setinggi 54 px ia memakan
 * ruang yang tidak ada, dan menunya sudah bisa digulung dengan roda maupun
 * sentuhan. */
.nav {
  display: flex; align-items: stretch; height: 100%; margin-left: 20px;
  min-width: 0; overflow-x: auto; scrollbar-width: none;
}
.nav::-webkit-scrollbar { display: none; }
.nav-item { flex: none; }

/* Layar sempit: jam adalah yang paling tidak penting di antara isi grup
   kanan — sistem operasi sudah menampilkannya. */
@media (max-width: 1100px) {
  #jam { display: none; }
}
/* Menu berisi TOMBOL, bukan tautan: berpindah tampilan tidak pernah menuju
   alamat lain, jadi tidak ada href yang bisa ditulis di sini. Gaya bawaan
   tombol dilucuti supaya bentuknya tetap sama seperti sebelumnya. */
.nav-item {
  display: flex; align-items: center; padding: 0 15px; height: 100%;
  color: var(--redup); text-decoration: none; position: relative;
  font: 600 12.5px/1 inherit; letter-spacing: 0; text-transform: none;
  white-space: nowrap;
  background: none; border: 0; cursor: pointer; font-family: inherit;
}
.nav-item:hover { color: var(--teks); background: var(--kilau); }
.nav-item.aktif { color: var(--vale-teal-neon); background: var(--kilau); }
.nav-item.aktif::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--vale-teal-neon); box-shadow: 0 0 10px var(--vale-teal-neon);
}
.nav-item .lonceng {
  margin-left: 7px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 980px; background: var(--alarm); color: var(--atas-warna);
  font: 700 11.5px/16px var(--mono); text-align: center;
}

#akun { display: flex; flex-direction: column; line-height: 1.25; text-align: right; }
#akun b { font-size: 13px; font-weight: 600; }
#akun span { font-size: 11.5px; color: var(--samar); letter-spacing: 0; text-transform: none; }

#jam {
  font: 600 13.5px/1 var(--mono); color: var(--vale-teal-neon);
  letter-spacing: 0; padding-right: 4px;
}
#pilih-project { width: auto; max-width: 210px; font-size: 13px; padding: 6px 9px; }

/* Titik denyut untuk keadaan langsung */
.denyut {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--ok); box-shadow: 0 0 0 0 rgba(25, 179, 166, .7);
  animation: denyut 2.4s infinite;
}
.denyut.warn  { background: var(--warn);  animation-name: denyut-warn; }
.denyut.alarm { background: var(--alarm); animation-name: denyut-alarm; animation-duration: 1.2s; }
.denyut.diam, .denyut.kosong, .denyut.nonaktif { background: var(--diam); animation: none; }
@keyframes denyut       { 70% { box-shadow: 0 0 0 7px rgba(25, 179, 166, 0); } }
@keyframes denyut-warn  { 70% { box-shadow: 0 0 0 7px rgba(245, 165, 36, 0); } }
@keyframes denyut-alarm { 70% { box-shadow: 0 0 0 8px rgba(255, 90, 78, 0); } }

/* ---------------------------------------------------------- tombol */

.tbl {
  /* Tombol tanpa garis tepi. Yang membedakannya dari latar adalah ISIANNYA,
     bukan bingkainya — garis tepi pada setiap tombol membuat panel penuh
     kotak-kotak, dan yang penting jadi tidak lagi menonjol. */
  font: 590 13.5px/1 inherit; letter-spacing: -.1px;
  padding: 9px 16px; border-radius: 980px; cursor: pointer;
  border: 0; background: var(--isi);
  color: var(--teks);
  transition: background .18s cubic-bezier(.32, .72, 0, 1),
              transform .12s cubic-bezier(.32, .72, 0, 1), opacity .18s;
}
.tbl:hover:not(:disabled) { background: var(--isi-kuat); }
/* Tekanan dibalas seketika dengan penyusutan kecil. Umpan balik sentuh
   membuat tombol terasa ditekan, bukan sekadar diklik. */
.tbl:active:not(:disabled) { transform: scale(.97); }
.tbl:disabled { opacity: .32; cursor: not-allowed; }
.tbl.utama { background: var(--vale-green); color: var(--atas-warna); }
.tbl.utama:hover:not(:disabled) { background: var(--vale-teal-terang); }
.tbl.awas  { background: var(--alarm); color: var(--atas-warna); }
.tbl.awas:hover:not(:disabled) { background: color-mix(in srgb, var(--alarm) 85%, white); }
.tbl.polos { background: none; color: var(--vale-teal-neon); padding-left: 10px; padding-right: 10px; }
.tbl.polos:hover { background: var(--isi); }
.tbl.penuh { width: 100%; padding: 11px 0; margin-top: 10px; }
.tbl.mini { padding: 5px 12px; font-size: 12.5px; }

/* ---------------------------------------------------------- halaman data */

/* Lapisan isi.
 *
 * Tampilan selain peta digambar DI ATAS peta, yang tetap hidup di belakangnya.
 * Ketika lapisan ini kosong, ia tidak digambar sama sekali dan peta terlihat
 * utuh — itulah yang membuat kembali ke peta tidak memakan waktu: tidak ada
 * yang dimuat ulang, hanya satu lapisan yang berhenti ditampilkan. */
.lapis { position: absolute; inset: var(--bar-h) 0 0 0; z-index: 20; display: none; }
.lapis.tampil { display: block; background: var(--ground); }

/* Saat memilih titik: lapisan isi disembunyikan tanpa dikosongkan, sehingga
   peta terlihat dan formulir di dalamnya tetap utuh untuk diisi sesudahnya. */
.lapis.tampil.disembunyikan { display: none; }

.bilah-pilih {
  position: absolute; left: 50%; top: calc(var(--bar-h) + 14px);
  transform: translateX(-50%) translateY(-8px);
  z-index: 38; display: none; align-items: center; gap: 14px;
  padding: 10px 12px 10px 16px;
  background: var(--permukaan); border: 1px solid var(--vale-teal-neon);
  border-radius: var(--radius); backdrop-filter: blur(12px);
  box-shadow: var(--bayang-3);
  opacity: 0; transition: opacity .16s, transform .16s;
}
.bilah-pilih.tampil { display: flex; opacity: 1; transform: translateX(-50%) translateY(0); }
.bilah-pilih .pilih-judul {
  font: 700 12px/1 inherit; letter-spacing: 0; text-transform: none;
  color: var(--vale-teal-neon);
}
.bilah-pilih .pilih-petunjuk { font-size: 13px; color: var(--redup); }

/* Saat memilih titik, kursor di atas peta menyatakan bahwa klik akan diambil. */
body.memilih-titik #viewer { cursor: crosshair; }

/* Perkakas peta ikut menyingkir saat lapisan isi terbuka.
 *
 * Panel, rail alat, HUD dan kartu alarm duduk di z-index yang lebih tinggi
 * daripada lapisan isi — tanpa aturan ini semuanya tetap terlihat menempel di
 * atas Sumber Data atau Katalog, seolah-olah tersangkut di sana. Peta sendiri
 * (#viewer) tidak di-display:none: kanvas WebGL yang dikecilkan ke nol harus
 * disiapkan ulang saat kembali, dan lapisan yang legap sudah menutupinya.
 *
 * Jendela tayangan SENGAJA dikecualikan: tayangan CCTV dibuka dari daftar
 * Sumber Data, jadi ia harus tetap terlihat justru ketika lapisan sedang
 * terbuka. */
body.lapis-terbuka .panel,
body.lapis-terbuka .rail,
body.lapis-terbuka .hud-atas,
body.lapis-terbuka .pembuka,
body.lapis-terbuka .tumpuk-alarm,
body.lapis-terbuka .peta-saja { display: none; }

.halaman {
  position: absolute; inset: 0; overflow: auto;
  padding: 26px 30px 48px; z-index: 1;
}
.halaman::-webkit-scrollbar { width: 9px; }
.halaman::-webkit-scrollbar-thumb { background: var(--garis-kuat); border-radius: 5px; }
.halaman-dalam { max-width: 1240px; margin: 0 auto; }

/* Pemilih peta dasar bergambar.
 *
 * Kartu, bukan daftar pilihan: perbedaan antara satu penyedia citra dan yang
 * lain tidak bisa dijelaskan oleh namanya. Kisi menyesuaikan lebar wadahnya,
 * jadi kendali yang sama muat di halaman lebar maupun di panel alat 288 px. */
.grid-basemap {
  display: grid; gap: 8px; margin-top: 4px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
}
.basemap-kartu {
  position: relative; padding: 0; cursor: pointer; overflow: hidden;
  background: var(--kilau); border: 1px solid var(--garis);
  border-radius: var(--radius); aspect-ratio: 4 / 3;
  display: block; font: inherit; color: var(--teks);
}
.basemap-kartu img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  /* Ubin dari penyedia berbeda punya kecerahan berbeda-beda; sedikit diredam
     supaya labelnya tetap terbaca di atas semuanya. */
  filter: saturate(.92) brightness(.92);
}
.basemap-kartu span {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 5px 7px;
  font: 600 12px/1 inherit; letter-spacing: 0; text-transform: none;
  background: linear-gradient(transparent, rgba(4, 16, 21, .92));
  text-align: left;
}
.basemap-kartu:hover { border-color: var(--garis-kuat); }
.basemap-kartu.aktif {
  border-color: var(--vale-teal-neon);
  box-shadow: 0 0 0 3px rgba(47, 212, 196, .55), var(--bayang-2);
}
.basemap-kartu.aktif span { color: var(--vale-teal-neon); }
/* Penyedia yang ubinnya tidak terambil: kartunya tetap bisa dipilih. */
.basemap-kartu.tanpa-pratinjau {
  display: grid; place-items: center; aspect-ratio: 4 / 3;
}
.basemap-kartu.tanpa-pratinjau span {
  position: static; background: none; text-align: center;
  color: var(--redup); padding: 0 6px;
}

/* Panel pada halaman Konfigurasi Mesin: hanya satu yang tampil. */
.panel-mesin { display: none; }
.panel-mesin.tampil { display: block; }

/* ------------------------------------------------------------- sub-tab */

/* Deret tab di dalam satu tampilan. Bentuknya sengaja lebih ringan daripada
   menu bilah atas: ini perpindahan DI DALAM satu tempat, bukan berpindah
   tempat, dan bobot visual yang sama akan membuat keduanya bersaing. */
.sub-tabs {
  display: flex; align-items: center; gap: 2px; margin: 6px 0 18px;
  border-bottom: 1px solid var(--garis); padding-bottom: 0;
  overflow-x: auto; scrollbar-width: none;
}
.sub-tabs::-webkit-scrollbar { display: none; }

.sub-tab {
  flex: none; display: flex; align-items: center; gap: 6px;
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 9px 13px; margin-bottom: -1px; cursor: pointer;
  color: var(--redup); font: 600 12px/1 inherit; font-family: inherit;
  letter-spacing: 0; text-transform: none; white-space: nowrap;
}
.sub-tab:hover { color: var(--teks); }
.sub-tab.aktif { color: var(--vale-teal-neon); border-bottom-color: var(--vale-teal-neon); }

/* Jumlah dataset per jenis. Ditulis di tabnya supaya orang tahu ada isinya
   sebelum membukanya. */
.sub-tab .jml {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
  background: var(--kilau); color: var(--redup);
  font: 700 11.5px/17px var(--mono); text-align: center;
}
.sub-tab.aktif .jml { background: rgba(53, 232, 213, .16); color: var(--vale-teal-neon); }

/* Kategori yang belum ada isinya tetap ditampilkan — itu yang memberi tahu apa
   saja yang bisa disimpan di sini — tetapi diredupkan supaya tidak bersaing
   dengan yang benar-benar berisi. */
.sub-tab.kosong { color: var(--samar); }
.sub-tab.kosong .jml { background: transparent; color: var(--samar); }
.sub-tab.kosong:hover, .sub-tab.kosong.aktif { color: var(--teks); }
.sub-tab.kosong.aktif .jml { color: var(--teks); }

/* Pemisah antara tab jenis data dan tab pekerjaan (unggah, periksa). */
/* ------------------------------------------------------- pohon katalog */

/* Terrain sebagai induk, berkas penyusunnya sebagai anak.
 *
 * Indentasi saja tidak cukup: pada tabel selebar layar, jarak 20 px di kolom
 * pertama tidak terbaca sebagai "milik baris di atasnya". Karena itu ada garis
 * cabang yang benar-benar digambar — itulah yang membuat susunannya terbaca
 * sebagai pohon, bukan sebagai daftar yang kebetulan menjorok. */
table.tabel tr.induk td {
  padding-top: 13px; padding-bottom: 9px;
  font: 700 12px/1.2 inherit; letter-spacing: 0; text-transform: none;
  color: var(--vale-teal-neon);
  background: var(--isi-halus);
  border-top: 1px solid var(--garis);
  border-bottom: 1px solid var(--garis);
}
table.tabel tr.induk td .denyut { margin: 0 8px 0 2px; }
table.tabel tr.induk td .tipis { text-transform: none; letter-spacing: .3px; }

/* Tombol lipat. Segitiga digambar dengan border, bukan karakter — glif
   segitiga termasuk yang kerap tidak ada di fon bawaan. */
.lipat {
  background: none; border: 0; cursor: pointer; padding: 0;
  width: 16px; height: 16px; vertical-align: middle; position: relative;
}
.lipat::before {
  content: ''; position: absolute; left: 4px; top: 50%;
  border: 5px solid transparent; border-left-color: var(--vale-teal-neon);
  transform-origin: 2px 0; transform: translateY(-5px) rotate(90deg);
  transition: transform .16s;
}
tbody.pohon.tutup .lipat::before { transform: translateY(-5px) rotate(0deg); }
.lipat:hover::before { border-left-color: var(--teks); }

/* Anak: menjorok, dengan garis cabang yang menghubungkannya ke induk. */
table.tabel tr.anak-pohon td:first-child { padding-left: 40px; position: relative; }
table.tabel tr.anak-pohon .cabang {
  position: absolute; left: 17px; top: 0; bottom: 0; width: 14px;
  pointer-events: none;
}
/* Batang tegak menyambung dari baris ke baris… */
table.tabel tr.anak-pohon .cabang::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0;
  border-left: 1px solid var(--garis-kuat);
}
/* …dan siku yang menunjuk ke barisnya sendiri. */
table.tabel tr.anak-pohon .cabang::after {
  content: ''; position: absolute; left: 0; top: 50%; width: 12px;
  border-top: 1px solid var(--garis-kuat);
}
/* Anak terakhir: batangnya berhenti di siku, tidak menggantung ke bawah. */
table.tabel tr.anak-pohon:last-child .cabang::before { bottom: 50%; }

/* Versi berada satu tingkat lebih dalam lagi. */
table.tabel tr.anak-versi td:first-child { padding-left: 64px; }
table.tabel tr.anak-versi .cabang { left: 41px; }

/* Induk yang terlipat tidak menampilkan anaknya sama sekali. */
tbody.pohon.tutup tr.anak-pohon { display: none; }

.sub-tab-pisah {
  flex: none; width: 1px; height: 16px; margin: 0 8px;
  background: var(--garis-kuat);
}

.judul-halaman { display: flex; align-items: center; gap: 10px; margin-bottom: 3px; }
.judul-halaman h1 {
  font-size: 17px; font-weight: 600; letter-spacing: 0; text-transform: none;
}
.judul-halaman .aksi-kanan { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.sub-halaman {
  font-size: 13px; color: var(--redup); margin-bottom: 22px;
  font-family: var(--mono); letter-spacing: .2px;
}

.judul-halaman + .ket { display: none; }
.judul-halaman + .ket.buka {
  display: block; margin: 6px 0 18px; padding: 12px 14px; max-width: 760px;
  background: var(--kilau); border-left: 2px solid var(--vale-teal-neon);
  font-size: 13px; color: var(--redup); line-height: 1.7;
}

/* Kartu — sudut bertakik, bukan membulat: bahasa panel instrumen. */
.kotak {
  /* Kartu, bukan panel bertakik. Sudut bertakik adalah kiasan antarmuka
     teknis; yang menggantikannya di sini kedalaman — permukaan sedikit lebih
     terang dari latar, ditambah bayangan lembut. */
  position: relative; background: var(--permukaan);
  border: 1px solid var(--garis); border-radius: var(--radius-lg);
  padding: 22px 24px; margin-bottom: 20px;
  -webkit-backdrop-filter: var(--buram); backdrop-filter: var(--buram);
  box-shadow: var(--bayang-1);
}
.kotak > h2 {
  font-family: var(--sans-tebal);
  font-size: 17px; font-weight: 600; letter-spacing: -.4px;
  color: var(--teks); margin-bottom: 16px;
  padding-bottom: 0; border-bottom: 0;
  display: flex; align-items: center; gap: 8px;
}
.kotak > h2 .kanan-h2 { margin-left: auto; color: var(--samar); font-weight: 600; letter-spacing: 0; }

.kisi { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.kisi.dua { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }

/* Ubin KPI */
.kpi-baris {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr));
  gap: 12px; margin-bottom: 18px;
}
.kpi {
  position: relative; padding: 14px 16px; background: var(--permukaan);
  border: 1px solid var(--garis); border-left: 2px solid var(--vale-teal-terang);
  border-radius: var(--radius); backdrop-filter: blur(8px);
}
.kpi.warn  { border-left-color: var(--warn); }
.kpi.alarm { border-left-color: var(--alarm); }
.kpi .kpi-label {
  font-size: 11px; letter-spacing: 0; text-transform: none;
  color: var(--samar); margin-bottom: 7px;
}
.kpi .kpi-nilai { font-size: 25px; font-weight: 600; line-height: 1; }
.kpi.warn  .kpi-nilai { color: var(--warn); }
.kpi.alarm .kpi-nilai { color: var(--alarm); }
.kpi .kpi-satuan { font-size: 13px; color: var(--samar); margin-left: 4px; font-weight: 400; }
.kpi .kpi-kaki { font-size: 12px; color: var(--samar); margin-top: 6px; }

/* Tabel */
.tabel-bungkus { overflow-x: auto; }
table.tabel { width: 100%; border-collapse: collapse; font-size: 13px; }
table.tabel th {
  text-align: left; font-size: 11px; font-weight: 700; letter-spacing: 0;
  text-transform: none; color: var(--samar); white-space: nowrap;
  padding: 0 12px 10px 0; border-bottom: 1px solid var(--garis-kuat);
}
table.tabel td {
  padding: 10px 12px 10px 0; border-bottom: 1px solid var(--isi-halus);
  vertical-align: middle;
}
table.tabel tr:hover td { background: rgba(25, 179, 166, .055); }
table.tabel td.utama { font-weight: 600; }
table.tabel td.angka { white-space: nowrap; }
table.tabel td.tipis { color: var(--redup); }
table.tabel td.aksi { text-align: right; white-space: nowrap; }
table.tabel .anak td { background: var(--isi-halus); }
table.tabel .anak td:first-child { padding-left: 22px; }

/* Lencana status */
.lenc {
  font-size: 11.5px; font-weight: 590; letter-spacing: -.05px;
  padding: 3px 9px; border-radius: 980px; white-space: nowrap;
  border: 1px solid transparent;
}
.lenc.uploaded  { background: rgba(220, 238, 240, .08); color: var(--redup); }
/* Perangkat bawaan mesin: bukan tahapan daur hidup data, jadi tidak memakai
   warna tahapan. Ia tidak menunggu diverifikasi maupun diterbitkan — ia
   memang sudah siap sejak ada. */
.lenc.bawaan    { background: color-mix(in srgb, var(--vale-blue) 16%, transparent);
                  color: var(--biru-teks);
                  border: 1px solid color-mix(in srgb, var(--vale-blue) 34%, transparent); }
.lenc.verified  { background: rgba(245, 165, 36, .14);  color: var(--warn);
                  border-color: rgba(245, 165, 36, .35); }
.lenc.published,
.lenc.ok        { background: rgba(25, 179, 166, .15);  color: var(--vale-teal-neon);
                  border-color: rgba(25, 179, 166, .4); }
.lenc.warn      { background: rgba(245, 165, 36, .16);  color: var(--warn);
                  border-color: rgba(245, 165, 36, .42); }
.lenc.alarm,
.lenc.restricted{ background: rgba(255, 90, 78, .16);   color: var(--alarm);
                  border-color: rgba(255, 90, 78, .45); }
.lenc.diam, .lenc.kosong, .lenc.nonaktif {
                  background: rgba(107, 126, 134, .16); color: var(--diam);
                  border-color: rgba(107, 126, 134, .38); }

/* ---------------------------------------------------------- halaman belah */

.belah { position: absolute; inset: 0; display: flex; z-index: 1; }
.belah-kiri {
  width: 392px; flex: none; overflow: auto; padding: 22px 22px 44px;
  border-right: 1px solid var(--garis-kuat); background: rgba(4, 14, 19, .72);
}
.belah-kiri::-webkit-scrollbar { width: 8px; }
.belah-kiri::-webkit-scrollbar-thumb { background: var(--garis-kuat); border-radius: 4px; }
.belah-kiri .kotak { padding: 15px 16px; }
.belah-kanan { flex: 1; position: relative; min-width: 0; }
.belah-kanan #tr-viewer { position: absolute; inset: 0; top: 0; }
.belah-kanan .pembuka { inset: 0; }

@media (max-width: 900px) {
  .belah { flex-direction: column; }
  .belah-kiri { width: 100%; border-right: 0; border-bottom: 1px solid var(--garis-kuat); }
  .belah-kanan { min-height: 320px; }
}

/* ---------------------------------------------------------- panel peta */

/* Wadah peta mengurung isinya sendiri.
 *
 * Mesin menggambar beberapa hal lebih besar daripada kotak yang terlihat —
 * peta-dalam minimap dibuat 1,45x lalu di-mask jadi lingkaran supaya sudutnya
 * tidak kosong saat berputar. Yang terlihat sudah benar, tetapi kotak tata
 * letaknya tetap menjulur ke bawah layar. Dikurung di sini, bukan di html,
 * supaya yang membereskannya adalah bagian yang memang memilikinya. */
#viewer {
  position: absolute; left: 0; right: 0; top: var(--bar-h); bottom: 0;
  overflow: hidden;
}

.panel {
  position: absolute; top: calc(var(--bar-h) + 12px); z-index: 30;
  width: var(--panel-w); max-height: calc(100% - var(--bar-h) - 24px);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--permukaan); border: 1px solid var(--garis);
  border-radius: var(--radius-lg);
  -webkit-backdrop-filter: var(--buram); backdrop-filter: var(--buram);
  box-shadow: var(--bayang-3);
  transition: transform .16s ease, opacity .16s ease;
}
.panel.kiri  { left: 12px; }
body.panel-tutup .panel.kiri {
  transform: translateX(calc(-1 * var(--panel-w) - 24px)); opacity: 0;
}

.kepala-panel, .kepala-jendela {
  display: flex; align-items: center; gap: 8px; padding: 13px 14px 13px 16px;
  border-bottom: 1px solid var(--garis); background: none;
}
.kepala-panel h3, .kepala-jendela h3, .kepala-jendela b {
  flex: 1; font-size: 14px; font-weight: 590; letter-spacing: -.2px;
  color: var(--teks);
}
.kepala-panel .tutup, .kepala-jendela .tutup {
  background: none; border: 0; color: var(--samar); cursor: pointer;
  font-size: 16px; line-height: 1; padding: 0 2px;
}
.kepala-panel .tutup:hover, .kepala-jendela .tutup:hover { color: var(--teks); }

.panel .isi-panel, .jendela .isi-panel { overflow: auto; padding: 12px 14px 16px; }
.panel .isi-panel::-webkit-scrollbar,
.jendela .isi-panel::-webkit-scrollbar { width: 6px; }
.panel .isi-panel::-webkit-scrollbar-thumb,
.jendela .isi-panel::-webkit-scrollbar-thumb {
  background: var(--garis-kuat); border-radius: 3px;
}
/* -------------------------------------------------- jendela mengambang */

/* Wadahnya menutupi seluruh area peta tetapi TIDAK menangkap tetikus, supaya
   peta di sela-sela jendela tetap bisa diputar. Urutan tumpukan diatur di
   dalam wadah ini, jadi jendela tidak pernah bisa naik menutupi bilah menu
   berapa kali pun ia diangkat. */
.jendela-wadah {
  position: absolute; inset: var(--bar-h) 0 0 0; z-index: 30;
  pointer-events: none;
}

.jendela {
  position: absolute; left: 0; top: 0; pointer-events: auto;
  width: var(--panel-w); max-height: calc(100% - 12px);
  display: none; flex-direction: column; overflow: hidden;
  background: var(--permukaan); border: 1px solid var(--garis-kuat);
  border-radius: var(--radius); backdrop-filter: blur(14px);
  box-shadow: var(--bayang-3);
}
.jendela.tampil { display: flex; }

/* Kepala jendela adalah pegangan seretnya. Kursor menyatakan itu sebelum
   dicoba, dan pemilihan teks dimatikan supaya menyeret tidak berubah jadi
   menyorot judul. */
.kepala-jendela { cursor: move; user-select: none; -webkit-user-select: none; }
.kepala-jendela .tutup { cursor: pointer; }

/* Jendela alat ikut menyingkir saat tampilan lain dibuka. Jendela TAYANGAN
   tidak — ia dibuka dari daftar Sumber Data, jadi justru harus terlihat
   ketika lapisan isi sedang terbuka. */
body.lapis-terbuka .jendela[data-alat].tampil { display: none; }

.ket-alat { display: none; }
.ket-alat.buka {
  display: block; margin: 10px 14px 0; padding: 10px 12px;
  background: var(--kilau); border-left: 2px solid var(--vale-teal-neon);
  font-size: 12px; color: var(--redup); line-height: 1.65;
}

/* Deretan alat di tepi kanan */
/* ------------------------------------------------- menu alat melingkar */

/* Satu tombol, alatnya mekar melingkarinya saat disentuh kursor.
 *
 * Wadahnya berukuran nol dan diletakkan tepat di titik pusat lingkaran;
 * semua tombol diposisikan relatif terhadap titik itu lewat --x/--y yang
 * dihitung peta.js. Dengan begitu jumlah alat boleh berubah tanpa satu pun
 * angka di berkas ini ikut diubah. */
.rail {
  position: absolute; right: 46px; top: 50%; z-index: 31;
  width: 0; height: 0;
}

.rail .ik {
  width: 21px; height: 21px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}

.radial-utama {
  position: absolute; left: 0; top: 0; width: 54px; height: 54px;
  margin: -27px 0 0 -27px; border-radius: 50%; cursor: pointer;
  background: var(--permukaan); border: 1px solid var(--garis-kuat);
  color: var(--vale-teal-neon); display: grid; place-items: center;
  backdrop-filter: blur(12px); transition: all .18s;
  box-shadow: var(--bayang-2);
}
.radial-utama .ik { width: 24px; height: 24px; }
.radial-utama:hover { border-color: var(--vale-teal-neon); }

/* Tidak ada cincin hias di sekeliling menu.
 *
 * Sempat ada, dan itu keliru: lingkaran 336 px berpusat 46 px dari tepi kanan
 * menjulur 124 px keluar layar dan memunculkan bilah gulung di sekeliling
 * peta. Keadaan terbuka sudah cukup terbaca dari tombol utama yang menyala
 * dan tombol-tombol yang mekar; hiasan yang harus dipotong supaya muat tidak
 * menambah apa pun. */
.rail.mekar .radial-utama {
  color: var(--atas-warna); background: var(--vale-green);
  border-color: var(--vale-teal-neon);
  box-shadow: var(--bayang-2);
}
.rail.mekar .radial-utama .ik { transform: rotate(90deg); }
.radial-utama .ik { transition: transform .28s cubic-bezier(.2, .8, .3, 1); }

.radial-item {
  position: absolute; left: 0; top: 0; width: 44px; height: 44px;
  margin: -22px 0 0 -22px; border-radius: 50%; cursor: pointer;
  background: var(--permukaan); border: 1px solid var(--garis);
  color: var(--redup); display: grid; place-items: center;
  backdrop-filter: blur(12px);
  transform: scale(.3); opacity: 0; pointer-events: none;
  transition: transform .3s cubic-bezier(.2, .9, .3, 1.15), opacity .18s,
              color .12s, border-color .12s, background .12s;
}
.rail.mekar .radial-item {
  transform: translate(var(--x), var(--y)) scale(1);
  opacity: 1; pointer-events: auto;
  transition-delay: var(--tunda), var(--tunda), 0s, 0s, 0s;
}
.radial-item:hover {
  color: var(--vale-teal-neon); border-color: var(--vale-teal-neon);
  background: var(--isi);
}
.radial-item.aktif {
  color: var(--atas-warna); background: var(--vale-green);
  border-color: var(--vale-teal-neon); box-shadow: var(--bayang-2);
}

/* Nama alat muncul di bawah tombolnya, hanya saat kursor menyentuhnya —
   sembilan label sekaligus akan meramaikan layar tanpa menambah kejelasan. */
.radial-item span {
  position: absolute; top: 50px; left: 50%; transform: translateX(-50%);
  white-space: nowrap; opacity: 0; pointer-events: none;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0; text-transform: none;
  background: rgba(4, 16, 21, .97); border: 1px solid var(--garis-kuat);
  border-radius: 3px; padding: 5px 9px; transition: opacity .12s;
}
.radial-item:hover span, .radial-item:focus-visible span { opacity: 1; }

.radial-item .titik-alarm, .rail button .titik-alarm {
  position: absolute; top: 3px; right: 3px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--alarm);
  box-shadow: 0 0 8px var(--alarm);
}

/* Gerak dimatikan bila pengguna memintanya lewat setelan sistem. */
@media (prefers-reduced-motion: reduce) {
  .radial-item, .radial-utama .ik { transition: none; }
  .rail.mekar .radial-item { transition-delay: 0s; }
}

.hud-atas {
  position: absolute; top: calc(var(--bar-h) + 12px); left: 50%;
  transform: translateX(-50%); z-index: 29;
  display: flex; gap: 1px; background: var(--garis-kuat);
  border: 1px solid var(--garis-kuat); border-radius: var(--radius);
  overflow: hidden; backdrop-filter: blur(14px);
  box-shadow: var(--bayang-2);
}
.hud-atas .sel { background: rgba(4, 16, 21, .9); padding: 8px 16px; text-align: center; }
.hud-atas .sel .l {
  font-size: 8px; letter-spacing: 0; text-transform: none;
  color: var(--samar); margin-bottom: 3px;
}
.hud-atas .sel .v { font: 600 15px/1 var(--mono); font-variant-numeric: tabular-nums; }
.hud-atas .sel .v small { font-size: 12px; color: var(--samar); margin-left: 3px; }
.hud-atas .sel.warn  .v { color: var(--warn); }
.hud-atas .sel.alarm .v { color: var(--alarm); }
@media (max-width: 1100px) { .hud-atas { display: none; } }

/* Jendela tayangan video: melayang di atas peta, bisa digeser ke sudut lain.
   Ditaruh di kiri-bawah karena kanan sudah dipakai rail alat dan alarm. */
/* Tayangan adalah jendela biasa; yang berbeda hanya lebarnya, karena isinya
   video dengan rasio tetap. Letak, seretan, dan tumpukannya sama persis. */
.tayangan { width: 372px; }
.tayangan video, .tayangan img { display: block; width: 100%; background: #000; }
.tayangan .kaki-tayang {
  padding: 7px 12px; font-size: 12px; color: var(--samar);
  font-family: var(--mono); display: flex; align-items: center; gap: 7px;
}
.tayangan .kosong { padding: 14px 12px; }
@media (max-width: 760px) { .tayangan { width: calc(100vw - 24px); } }

/* Tumpukan pesan alarm di kanan bawah */
.tumpuk-alarm {
  position: absolute; right: 68px; bottom: 12px; z-index: 35;
  display: flex; flex-direction: column-reverse; gap: 8px; max-width: 320px;
}
.pesan-alarm {
  background: rgba(28, 8, 6, .95); border: 1px solid var(--alarm);
  border-left-width: 3px; border-radius: var(--radius); padding: 10px 13px;
  backdrop-filter: var(--buram); box-shadow: var(--bayang-2);
  animation: masuk-kanan .22s ease; cursor: pointer;
}
.pesan-alarm.warn { background: rgba(30, 22, 4, .95); border-color: var(--warn); }
.pesan-alarm b { font-size: 13px; display: block; margin-bottom: 3px; }
.pesan-alarm span { font-size: 12px; color: var(--redup); font-family: var(--mono); }
@keyframes masuk-kanan { from { opacity: 0; transform: translateX(18px); } }

/* ---------------------------------------------------------- kendali */

.sub {
  font-size: 11px; letter-spacing: 0; text-transform: none;
  color: var(--warn); margin: 15px 0 5px; padding-bottom: 5px;
  border-bottom: 1px solid rgba(245, 165, 36, .18);
}
.sub:first-child { margin-top: 2px; }
label {
  display: block; font-size: 12px; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--samar); margin: 10px 0 4px;
}

select, input[type=text], input[type=number], input[type=password],
input[type=date], input[type=file], textarea {
  width: 100%; background: var(--isi);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--teks); padding: 10px 12px; font: inherit; font-size: 13.5px;
  transition: background .16s, box-shadow .16s;
}
/* Cincin fokus, bukan garis tepi berwarna. Garis tepi menggeser tata letak
   sepersekian piksel saat isian difokus; cincin tidak menyentuh aliran sama
   sekali. */
select:focus, input:focus, textarea:focus {
  outline: none; background: var(--isi);
  box-shadow: 0 0 0 3.5px rgba(47, 212, 196, .28);
}
select option { background: var(--ground-2); color: var(--teks); }
input[type=file] { padding: 7px; font-size: 12.5px; }
.duo { display: flex; gap: 6px; }
.duo > * { flex: 1; }

.baris {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px;
  padding: 7px 0; border-bottom: 1px solid var(--isi-halus);
}

.baris .nama { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.baris .kecil {
  color: var(--samar); font-size: 12px; white-space: nowrap; font-family: var(--mono);
}
.kosong { font-size: 12.5px; color: var(--samar); padding: 12px 0; }

.hasil {
  font-size: 13.5px; color: var(--teks); margin-top: 10px; line-height: 1.65;
}
/* Angka tetap monospace bertabular walau teks di sekelilingnya tidak — kolom
   yang sejajar bisa dibandingkan sekilas. */
.hasil b { color: var(--teks); font-weight: 590;
           font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* Keterangan — tertutup sampai ikon "i" ditekan */
.info {
  width: 15px; height: 15px; flex: none; border-radius: 50%;
  border: 1px solid var(--garis-kuat); color: var(--redup);
  font: 700 11.5px/13px Georgia, serif; font-style: italic;
  text-align: center; cursor: pointer; text-transform: none; letter-spacing: 0;
}
.info:hover { color: var(--warn); border-color: var(--warn); }

/* Grafik garis kecil di dalam tabel */
.spark { display: block; width: 92px; height: 22px; }
.spark path.garis { fill: none; stroke: var(--vale-teal-terang); stroke-width: 1.4; }
.spark.warn  path.garis { stroke: var(--warn); }
.spark.alarm path.garis { stroke: var(--alarm); }
.spark path.isi { fill: rgba(25, 179, 166, .14); stroke: none; }

/* Grafik besar (profil melintang, deret sensor) */
.grafik { width: 100%; display: block; }
.grafik .sumbu { stroke: var(--garis-kuat); stroke-width: 1; }
.grafik .kisi-g { stroke: var(--isi-halus); stroke-width: 1; }
.grafik .garis { fill: none; stroke: var(--vale-teal-neon); stroke-width: 1.6; }
.grafik .isi { fill: rgba(25, 179, 166, .14); stroke: none; }
.grafik .ambang-warn  { stroke: var(--warn);  stroke-width: 1; stroke-dasharray: 4 3; }
.grafik .ambang-alarm { stroke: var(--alarm); stroke-width: 1; stroke-dasharray: 4 3; }
.grafik text { fill: var(--samar); font: 9px var(--mono); }

/* Dialog konfirmasi. Dibuat sendiri, bukan confirm() bawaan peramban:
   dialog bawaan tidak bisa diberi gaya, memblokir seluruh halaman, dan
   tampilannya berbeda-beda antar peramban — tidak pantas untuk tindakan
   sepenting menghapus riwayat pengukuran. */
.tirai {
  position: fixed; inset: 0; z-index: 60; display: none;
  background: rgba(2, 8, 11, .72); backdrop-filter: blur(3px);
  align-items: center; justify-content: center; padding: 20px;
}
.tirai.tampil { display: flex; }
.dialog {
  position: relative; width: 100%; max-width: 380px; padding: 26px 24px 20px;
  background: var(--permukaan-2); border: 1px solid var(--garis);
  border-radius: 20px; box-shadow: var(--bayang-3);
  -webkit-backdrop-filter: var(--buram); backdrop-filter: var(--buram);
  text-align: center;
}
.dialog h3 {
  font-size: 13.5px; font-weight: 700; letter-spacing: 0;
  text-transform: none; margin-bottom: 10px; color: var(--vale-teal-neon);
}
.dialog.bahaya h3 { color: var(--alarm); }
.dialog p { font-size: 13.5px; color: var(--redup); line-height: 1.7; }
.dialog .tombol-dialog {
  display: flex; gap: 8px; justify-content: flex-end; margin-top: 20px;
}

/* ---------------------------------------------------------- status */

/* Sudut kiri bawah dipegang minimap; yang lain menggeser ke kanannya sejauh
   lebar minimap yang sedang dipakai (diumumkan alat Peta Dasar). */
:root { --minimap: 180px; }

.status {
  position: absolute; left: calc(var(--minimap) + 24px); bottom: 12px; z-index: 25;
  display: flex; gap: 8px; align-items: center; pointer-events: none;
}
/* Kotak yang tidak berisi apa-apa tidak digambar. Bilah pesan kosong hampir
   sepanjang waktu, dan bingkai kosong di sudut layar hanya terbaca sebagai
   cacat tampilan. */
.status > div:empty { display: none; }
.status > div {
  background: rgba(4, 16, 21, .9); border: 1px solid var(--garis);
  border-radius: var(--radius); padding: 6px 12px; font-size: 12px;
  color: var(--redup); font-family: var(--mono);
}
#koordinat { display: none; }

/* ---------------------------------------------------------- layar penuh */

.tengah {
  position: absolute; inset: 0; display: grid; place-items: center;
  background:
    radial-gradient(1200px 680px at 50% 30%, rgba(0, 126, 122, .26) 0%, transparent 62%),
    var(--ground);
}
.kartu {
  position: relative; width: 100%; max-width: 380px; padding: 32px 32px 28px;
  background: var(--permukaan); border: 1px solid var(--garis-kuat);
  border-radius: var(--radius); backdrop-filter: blur(14px);
  box-shadow: var(--bayang-3);
}
.kartu::before, .kartu::after {
  content: ''; position: absolute; width: 14px; height: 14px;
  border-color: var(--vale-teal-neon); border-style: solid;
}
.kartu::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.kartu::after  { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }
.kartu .merek-besar { display: flex; align-items: center; gap: 14px; margin-bottom: 6px; }
.kartu .merek-besar img { width: 44px; height: 38px; }
.kartu h1 { font-size: 14px; letter-spacing: 0; font-weight: 700; }
.kartu h1 em { color: var(--vale-teal-neon); font-style: normal; }
.kartu .sub-judul {
  font-size: 12px; color: var(--samar); margin-bottom: 24px;
  letter-spacing: 0; text-transform: none;
}
.pesan-galat {
  display: none; margin-top: 14px; padding: 10px 12px; border-radius: var(--radius);
  background: rgba(255, 90, 78, .1); border: 1px solid rgba(255, 90, 78, .45);
  color: var(--alarm); font-size: 13px;
}
.pesan-galat.tampil { display: block; }

.pembuka {
  position: absolute; inset: var(--bar-h) 0 0 0; z-index: 20;
  display: grid; place-items: center; text-align: center;
  background:
    radial-gradient(980px 560px at 50% 40%, rgba(0, 126, 122, .22) 0%, transparent 60%),
    var(--ground);
}
.pembuka.selesai { display: none; }
.pembuka h1 { font-size: 19px; letter-spacing: 0; font-weight: 300; }
.pembuka h1 b { color: var(--vale-teal-neon); font-weight: 700; }
.pembuka p { margin-top: 12px; font-size: 13px; color: var(--redup); font-family: var(--mono); }
.putar {
  width: 34px; height: 34px; margin: 24px auto 0; border-radius: 50%;
  border: 2px solid var(--isi); border-top-color: var(--vale-teal-neon);
  animation: putar 1s linear infinite;
}
@keyframes putar { to { transform: rotate(360deg); } }

@media (max-width: 760px) {
  :root { --panel-w: calc(100vw - 24px); }
  .bar .merek .judul span { display: none; }
  .nav { margin-left: 8px; }
  .nav-item { padding: 0 10px; }
}

/* Tombol yang tampil sebagai teks biasa di dalam tabel — dipakai untuk
   membuka tayangan tanpa meninggalkan aplikasi. */
.tbl-teks {
  background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
  color: var(--vale-teal-neon); text-decoration: none;
}
.tbl-teks:hover { text-decoration: underline; }
.tbl-teks.tipis { color: var(--redup); }

/* Singkatan zona di samping jam. Tanpa ini jam situs tidak bisa dibedakan dari
   jam peramban, dan perbedaan satu jam justru paling mudah tidak disadari. */
.zona-nama { font-size: 12px; letter-spacing: .1em; color: var(--redup);
             margin-left: -4px; }

/* ═══════════════════════════════════════════════════════════ KENDALI
 *
 * Sakelar, penggeser, pemilih, kalender, dan modal.
 *
 * Kendali bawaan peramban tampak berbeda di tiap sistem operasi, dan tak satu
 * pun cocok dengan sisa antarmuka ini. Yang digambar ulang di sini hanya
 * RUPANYA — elemen aslinya tetap <input>, jadi papan ketik, pembaca layar,
 * dan pengisian otomatis tetap bekerja. Kendali yang dibangun dari <div>
 * terlihat sama tetapi kehilangan semua itu.
 */

/* ---------------------------------------------------------- sakelar
 *
 * Kotak centang menjadi sakelar geser. Bukan sekadar rupa: kotak centang
 * berarti "pilih beberapa dari daftar", sakelar berarti "hidupkan atau
 * matikan satu hal" — dan yang ada di panel ini semuanya jenis kedua. */
.baris input[type=checkbox],
input[type=checkbox].sakelar {
  appearance: none; -webkit-appearance: none;
  position: relative; flex: none;
  width: 42px; height: 25px; border-radius: 980px;
  background: var(--isi-kuat); border: 0; cursor: pointer;
  transition: background .22s cubic-bezier(.32, .72, 0, 1);
}
.baris input[type=checkbox]::after,
input[type=checkbox].sakelar::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 21px; height: 21px; border-radius: 50%;
  background: #FFFFFF;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .28), 0 0 0 .5px rgba(0, 0, 0, .06);
  transition: transform .22s cubic-bezier(.32, .72, 0, 1);
}
.baris input[type=checkbox]:checked,
input[type=checkbox].sakelar:checked { background: var(--vale-green); }
.baris input[type=checkbox]:checked::after,
input[type=checkbox].sakelar:checked::after { transform: translateX(17px); }
.baris input[type=checkbox]:focus-visible,
input[type=checkbox].sakelar:focus-visible {
  outline: none; box-shadow: 0 0 0 3.5px color-mix(in srgb, var(--vale-green) 40%, transparent);
}

/* ---------------------------------------------------------- penggeser
 *
 * Jalur tipis, kenop bulat timbul. Bagian jalur yang sudah dilewati TIDAK
 * diwarnai: peramban tidak menyediakannya lintas mesin tanpa skrip, dan jalur
 * yang setengah berwarna di satu peramban dan polos di peramban lain lebih
 * buruk daripada jalur yang sama di mana-mana. */
input[type=range] {
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 26px; background: none; cursor: pointer;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 980px; background: var(--isi-kuat);
}
input[type=range]::-moz-range-track {
  height: 4px; border-radius: 980px; background: var(--isi-kuat);
}
input[type=range]::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 22px; height: 22px; margin-top: -9px; border-radius: 50%;
  background: #FFFFFF; border: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .30), 0 0 0 .5px rgba(0, 0, 0, .08);
  transition: transform .12s cubic-bezier(.32, .72, 0, 1);
}
input[type=range]::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: #FFFFFF; border: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .30), 0 0 0 .5px rgba(0, 0, 0, .08);
}
input[type=range]:active::-webkit-slider-thumb { transform: scale(1.12); }
input[type=range]:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3.5px color-mix(in srgb, var(--vale-green) 40%, transparent),
              0 1px 4px rgba(0, 0, 0, .30);
}

/* ---------------------------------------------------------- pemilih
 *
 * Tanda panah digambar sendiri. Panah bawaan berbeda bentuk di tiap sistem,
 * dan yang di Windows menempel pada kotak abu yang tidak bisa diwarnai. */
select {
  appearance: none; -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) calc(50% + 2px), calc(100% - 12px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
}

/* ---------------------------------------------------------- kalender
 *
 * Isian tanggal bawaan menyisakan satu hal yang tidak bisa digaya: ikon
 * kalendernya. Yang bisa dikerjakan membalik warnanya di tema gelap supaya ia
 * tidak jadi kotak hitam di atas permukaan gelap, dan menaruhnya rapi di
 * tepi kanan. */
input[type=date] { position: relative; }
input[type=date]::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .55; padding: 2px; border-radius: 5px;
  transition: opacity .15s, background .15s;
}
input[type=date]::-webkit-calendar-picker-indicator:hover {
  opacity: 1; background: var(--isi);
}
/* Satu baris yang mengurus seluruh kendali BAWAAN peramban: panel kalender,
 * daftar pilihan, bilah gulung, dan ikon di dalam isian tanggal semuanya ikut
 * tema yang sedang berlaku.
 *
 * Sebelumnya saya menulis dua aturan terpisah dan menaruh yang terang SESUDAH
 * blok gelap — jadi yang terang selalu menang, dan di tema gelap panel
 * kalender tetap terbuka putih menyilaukan di atas antarmuka gelap.
 * Menyebut kedua skema sekaligus membuat peramban yang memilih, dan urutan
 * aturan tidak lagi bisa merusaknya. */
:root { color-scheme: light dark; }

/* ---------------------------------------------------------- berkas */
input[type=file] { cursor: pointer; }
/* DUA aturan terpisah, sengaja tidak digabung dalam satu daftar selektor.
 *
 * Daftar selektor yang memuat pseudo-elemen vendor akan GUGUR SELURUHNYA di
 * mesin yang tidak mengenal salah satunya — bukan sebagian, semuanya. Digabung,
 * tombol ini tetap memakai rupa bawaan di mana-mana; dan itu justru tidak
 * terlihat sebagai galat, hanya sebagai satu tombol yang bentuknya lain
 * sendiri. */
input[type=file]::-webkit-file-upload-button {
  appearance: none; -webkit-appearance: none;
  font: 590 13px/1 var(--sans); letter-spacing: -.1px;
  padding: 7px 14px; margin-right: 12px;
  border: 0; border-radius: 980px; cursor: pointer;
  background: var(--isi-kuat); color: var(--teks);
  transition: background .18s;
}
input[type=file]::-webkit-file-upload-button:hover { background: var(--garis-kuat); }

input[type=file]::file-selector-button {
  appearance: none;
  font: 590 13px/1 var(--sans); letter-spacing: -.1px;
  padding: 7px 14px; margin-right: 12px;
  border: 0; border-radius: 980px; cursor: pointer;
  background: var(--isi-kuat); color: var(--teks);
  transition: background .18s;
}
input[type=file]::file-selector-button:hover { background: var(--garis-kuat); }

/* ---------------------------------------------------------- modal
 *
 * Tirai memburamkan seluruh layar, bukan sekadar menggelapkannya. Yang di
 * belakang tetap terlihat bentuknya — orang tidak kehilangan tempatnya —
 * tetapi tidak lagi bisa dibaca, jadi perhatian tidak terbagi. */
#tirai-dialog, .tirai {
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  backdrop-filter: blur(20px) saturate(140%);
  background: color-mix(in srgb, var(--ground) 34%, transparent);
}
.dialog {
  animation: dialog-masuk .26s cubic-bezier(.32, .72, 0, 1);
}
/* Muncul dengan membesar sedikit dari 96%, bukan dari nol. Dari nol ia terasa
   melompat; dari 96% ia terasa mendekat. */
@keyframes dialog-masuk {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}
.dialog h3 { font-family: var(--sans-tebal); font-size: 17px; font-weight: 600;
             letter-spacing: -.4px; margin-bottom: 6px; }
.dialog p  { font-size: 13.5px; color: var(--redup); line-height: 1.5; }
/* Tombol dialog membentang penuh dan berdampingan — bentuk peringatan yang
   sudah dikenal orang, dan target sentuh yang jauh lebih besar. */
.dialog .baris-tombol, .dialog .aksi-dialog {
  display: flex; gap: 10px; margin-top: 20px;
}
.dialog .baris-tombol .tbl, .dialog .aksi-dialog .tbl { flex: 1; padding: 11px 0; }

/* ---------------------------------------------------------- tab tersegmen
 *
 * Sub-tab menjadi kendali tersegmen: satu bidang bergaris, penanda pilihan
 * meluncur di dalamnya. Bentuk ini menyatakan "pilih SATU dari beberapa" jauh
 * lebih jelas daripada deretan tombol yang salah satunya kebetulan menyala. */
.sub-tabs {
  display: flex; gap: 2px; padding: 2px;
  background: var(--isi-halus); border-radius: 11px;
  border: 0; width: fit-content; max-width: 100%; overflow-x: auto;
}
.sub-tab {
  border: 0; border-radius: 9px; padding: 7px 14px;
  font: 590 13px/1 var(--sans); letter-spacing: -.1px;
  color: var(--redup); background: none; cursor: pointer; white-space: nowrap;
  transition: background .18s, color .18s;
}
.sub-tab:hover { color: var(--teks); }
.sub-tab.aktif {
  background: var(--permukaan-2); color: var(--teks);
  box-shadow: var(--bayang-1);
}

/* ---------------------------------------------------------- gulung
 *
 * Bilah gulung tipis yang menyingkir. Yang bawaan di Windows selebar tujuh
 * belas piksel dan berwarna abu terang — di panel gelap ia jadi garis putih
 * yang lebih menonjol daripada isinya. */
* { scrollbar-width: thin; scrollbar-color: var(--garis-kuat) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: none; }
::-webkit-scrollbar-thumb {
  background: var(--garis-kuat); border-radius: 980px;
  border: 2px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--samar); background-clip: content-box; }

/* ---------------------------------------------------------- gerak
 *
 * Yang meminta gerakan dikurangi mendapat antarmuka tanpa gerakan. Ini bukan
 * kesopanan: bagi sebagian orang animasi meluncur memicu pusing dan mual. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
