/* ============================================================
   style.css — gabungan seluruh gaya UI aplikasi
   Urutan blok dipertahankan persis seperti file asli:
     1. Gaya utama            2. rho-ui-css
     3. hps-ui-css            4. table-unify-css
     5. spk-style
   CATATAN: blok <style id="fkl-doc-css"> SENGAJA TIDAK dipindah ke sini.
   Blok itu dibaca ulang oleh JS (fklDocBaseCss / hpscAllCss) memakai
   .textContent untuk membangun dokumen Cetak/PDF, jadi harus tetap
   berupa <style> di dalam index.html.
   ============================================================ */

/* ===== 1. GAYA UTAMA ===== */
:root{
  --teal:#0E7C86; --teal-dark:#095e66; --teal-soft:#e3f2f3; --cyan:#16a9b5;
  --yellow:#F6B40E; --green:#1E9E5A; --green-dark:#157a44;
  --red:#D33A3A; --red-dark:#b22a2a;
  --bg:#eef1f4; --surface:#ffffff; --ink:#16242c; --muted:#64757f;
  --line:#dce3e8; --radius:14px;
  --shadow:0 1px 2px rgba(16,40,50,.06),0 4px 14px rgba(16,40,50,.05);
  --shadow-md:0 2px 6px rgba(16,40,50,.07),0 12px 32px rgba(16,40,50,.09);
  --shadow-lg:0 8px 24px rgba(9,94,102,.12),0 24px 60px rgba(9,94,102,.10);
  --ring:0 0 0 3px var(--teal-soft);
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Plus Jakarta Sans',sans-serif;color:var(--ink);font-size:12px;line-height:1.5;
  background:
    radial-gradient(900px 420px at 88% -8%, rgba(22,169,181,.10), transparent 60%),
    radial-gradient(700px 360px at -6% 4%, rgba(14,124,134,.08), transparent 55%),
    linear-gradient(180deg,#f1f5f7,#eaeef1 60%,#e8edf0);
  background-attachment:fixed;}
h1,h2,h3,.brand,.nav-link,.btn{font-family:'Plus Jakarta Sans',sans-serif}
button{cursor:pointer;font-family:inherit}
a{color:inherit}
::selection{background:rgba(14,124,134,.18)}

/* ---------- App shell (sidebar layout) ---------- */
.app-shell{display:flex;min-height:100vh;align-items:stretch}
.sidebar{width:258px;flex:0 0 258px;background:linear-gradient(165deg,#073f45 0%,var(--teal-dark) 44%,var(--teal) 100%);color:#fff;display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;z-index:60;box-shadow:6px 0 24px rgba(7,63,69,.18)}
.sidebar::after{content:"";position:absolute;top:0;bottom:0;right:0;width:3px;background:linear-gradient(180deg,var(--yellow),var(--cyan),var(--yellow));background-size:100% 200%;animation:sheenV 7s linear infinite;opacity:.85}
@keyframes sheenV{to{background-position:0 200%}}
.sidebar-brand{display:flex;align-items:center;gap:12px;padding:20px 18px 18px;border-bottom:1px solid rgba(255,255,255,.12)}
.logo{width:42px;height:42px;flex:0 0 42px;background:transparent;border-radius:12px;display:grid;place-items:center;box-shadow:none}
.logo svg{width:23px;height:23px;filter:drop-shadow(0 1px 1px rgba(0,0,0,.15))}
.logo .logo-img{width:100%;height:100%;object-fit:contain;padding:0;border-radius:inherit;display:block;image-rendering:auto}
.brandside-logo .logo-img,.topbar-brand .logo .logo-img{width:100%;height:100%;object-fit:contain;padding:0;border-radius:inherit;display:block}
.brandside-logo .logo-img{padding:0}
.brand h1{font-size:13.5px;font-weight:800;letter-spacing:.3px;line-height:1.2;color:#fff}
.brand span{font-size:9px;opacity:.85;font-weight:500;letter-spacing:1.5px;text-transform:uppercase;color:#dff3f4}

/* ---------- Sidebar nav ---------- */
.side-nav{display:flex;flex-direction:column;gap:3px;padding:14px 12px;flex:1 1 auto}
.nav-section-label{font-size:9px;font-weight:700;letter-spacing:1.3px;text-transform:uppercase;color:rgba(255,255,255,.42);padding:14px 14px 5px}
.nav-link{appearance:none;width:100%;background:none;border:none;padding:11px 13px;font-family:'Plus Jakarta Sans';font-size:12.5px;font-weight:600;color:rgba(255,255,255,.82);display:flex;align-items:center;gap:11px;border-radius:10px;text-align:left;cursor:pointer;transition:background .15s,color .15s}
.nav-link svg{width:18px;height:18px;flex:0 0 auto;transition:transform .2s}
.nav-link:hover{background:rgba(255,255,255,.10);color:#fff}
.nav-link.active{background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45;font-weight:800;box-shadow:0 4px 14px rgba(246,180,14,.32)}
.nav-link.active svg{color:#073f45}
/* ---- Sidebar groups (accordion) ---- */
.nav-group{display:flex;flex-direction:column}
.nav-toggle{appearance:none;width:100%;background:none;border:none;padding:11px 13px;font-family:'Plus Jakarta Sans';font-size:12.5px;font-weight:600;color:rgba(255,255,255,.82);display:flex;align-items:center;gap:11px;border-radius:10px;text-align:left;cursor:pointer;transition:background .15s,color .15s}
.nav-toggle > svg:first-of-type{width:18px;height:18px;flex:0 0 auto}
.nav-toggle:hover{background:rgba(255,255,255,.10);color:#fff}
.nav-toggle .caret{width:14px;height:14px;margin-left:auto;transition:transform .25s;flex:0 0 auto}
.nav-group.open .nav-toggle .caret{transform:rotate(180deg)}
.nav-group.has-active .nav-toggle{color:#fff}
.nav-menu{display:none;flex-direction:column;gap:2px;padding:2px 0 6px 8px}
.nav-group.open .nav-menu{display:flex}
.nav-item{appearance:none;width:100%;background:none;border:none;text-align:left;padding:9px 12px;margin-left:8px;font-family:'Plus Jakarta Sans';font-size:11.5px;font-weight:600;color:rgba(255,255,255,.72);border-left:2px solid rgba(255,255,255,.16);border-radius:0 9px 9px 0;display:flex;align-items:center;gap:9px;cursor:pointer;transition:background .15s,color .15s,border-color .15s}
.nav-item svg{width:15px;height:15px;color:rgba(255,255,255,.58);flex:0 0 auto}
.nav-item:hover{background:rgba(255,255,255,.10);color:#fff}
.nav-item.active{background:rgba(255,255,255,.15);color:#fff;border-left-color:var(--yellow);font-weight:700}
.nav-item.active svg{color:var(--yellow)}

/* ---------- Main column ---------- */
.app-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.mobile-topbar{display:none}
.sidebar-overlay{display:none}
.wrap{max-width:1180px;width:100%;margin:0 auto;padding:24px}
.view{display:none}
/* #11: Transisi perpindahan halaman yang lebih memukau — reveal halus
   (fade + naik + skala + blur mengurai) disertai stagger pada judul & konten. */
.view.active{display:block;animation:pageReveal .62s cubic-bezier(.16,1,.3,1) both;will-change:opacity,transform,filter}
@keyframes pageReveal{
  0%{opacity:0;transform:translateY(22px) scale(.985);filter:blur(6px)}
  55%{filter:blur(0)}
  100%{opacity:1;transform:none;filter:blur(0)}
}
.view.active>.page-head{animation:pageRise .6s .06s cubic-bezier(.16,1,.3,1) both}
.view.active>.page-head+*{animation:pageRise .6s .14s cubic-bezier(.16,1,.3,1) both}
@keyframes pageRise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  .view.active,.view.active>.page-head,.view.active>.page-head+*{animation:fade .2s ease both}
}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.page-head{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.page-head h2{font-size:19px;font-weight:800;position:relative;padding-left:14px}
.page-head h2::before{content:"";position:absolute;left:0;top:3px;bottom:3px;width:5px;border-radius:3px;background:linear-gradient(180deg,var(--teal),var(--cyan))}
.page-head p{color:var(--muted);font-size:11px;margin-top:4px}
/* Judul + jumlah data, lalu jarak 30px, lalu tombol Export Data (dikelompokkan di kiri) */
.head-export-row{display:flex;align-items:center;gap:20px;flex-wrap:wrap;justify-content:space-between;width:100%}
.head-export-row h2{margin:0}

/* ---------- Cards ---------- */
.cards{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}
.cards-5{grid-template-columns:repeat(5,1fr)}   /* baris atas saat memuat 5 kartu */
.card{background:linear-gradient(180deg,#ffffff,#fbfdfd);border:1px solid var(--line);border-radius:var(--radius);padding:18px 18px 18px 22px;box-shadow:var(--shadow);position:relative;overflow:hidden;transition:transform .22s ease,box-shadow .22s ease,border-color .22s ease}
.card:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);border-color:#cfdde0}
.card .accent{position:absolute;left:0;top:0;bottom:0;width:5px;border-radius:0 4px 4px 0}
.card::after{content:"";position:absolute;right:-30px;top:-30px;width:90px;height:90px;border-radius:50%;background:radial-gradient(circle,rgba(14,124,134,.07),transparent 70%);pointer-events:none}
.card .k{font-size:10px;color:var(--muted);font-weight:700;text-transform:uppercase;letter-spacing:.6px}
.card .v{font-size:28px;font-weight:800;font-family:'Plus Jakarta Sans';margin-top:8px;line-height:1;color:var(--ink)}
.card .sub{font-size:10px;color:var(--muted);margin-top:8px}
/* ---- Baris nilai & kartu Efisiensi Kontrak vs HPS ---- */
.dash-nilai{margin-top:-8px}
/* Baris nilai kini memuat 5 kartu (3 nilai + 2 efisiensi: RAB lalu HPS) */
.dash-nilai{grid-template-columns:repeat(5,1fr)}
.efisiensi-card{background:linear-gradient(160deg,#f2fbf6,#ffffff 60%);border-color:#c7ead6;display:flex;flex-direction:column}
.efisiensi-card::after{background:radial-gradient(circle,rgba(30,158,90,.10),transparent 70%)}
.efisiensi-card .k{color:var(--green-dark)}
.eff-pct{font-family:'Plus Jakarta Sans';font-weight:800;font-size:30px;line-height:1;color:var(--green-dark);margin-top:8px}
.eff-pct span{font-size:15px;font-weight:700;margin-left:2px}
.eff-bar{height:9px;background:#e2f0e8;border-radius:6px;overflow:hidden;margin:11px 0 10px;box-shadow:inset 0 1px 2px rgba(16,40,50,.06)}
.eff-bar-fill{height:100%;border-radius:6px;background:linear-gradient(90deg,var(--green),#3fce86);box-shadow:0 1px 5px rgba(30,158,90,.45);width:0;animation:effGrow .7s cubic-bezier(.2,.8,.2,1) both}
@keyframes effGrow{from{width:0}}
.eff-rp{font-family:'Plus Jakarta Sans';font-weight:800;font-size:15px;color:var(--ink);line-height:1.15;word-break:break-word}
.eff-rp small{display:block;font-family:'Plus Jakarta Sans';font-weight:500;font-size:9.5px;color:var(--muted);margin-top:3px;letter-spacing:.2px}
.eff-empty{font-size:10.5px;color:var(--muted);margin-top:14px;line-height:1.5}
#view-dashboard .eff-pct{font-size:32px}
#view-dashboard .eff-rp{font-size:16px}
#view-dashboard .eff-rp small{font-size:11px}
#view-dashboard .eff-empty{font-size:12px}
/* ---- Transisi perpindahan Jenis Data pada Dashboard ---- */
#dash-content{transition:opacity .26s ease, transform .26s ease}
#dash-content.dash-out{opacity:0;transform:translateY(12px) scale(.994)}
#dash-content.dash-in{animation:dashIn .46s cubic-bezier(.2,.8,.2,1)}
@keyframes dashIn{from{opacity:0;transform:translateY(16px) scale(.99)}to{opacity:1;transform:none}}
#dash-content.dash-in .card{animation:cardRise .5s cubic-bezier(.2,.8,.2,1) both}
#dash-content.dash-in #dash-cards .card:nth-child(2){animation-delay:.04s}
#dash-content.dash-in #dash-cards .card:nth-child(3){animation-delay:.08s}
#dash-content.dash-in #dash-cards .card:nth-child(4){animation-delay:.12s}
#dash-content.dash-in #dash-cards .card:nth-child(5){animation-delay:.16s}
#dash-content.dash-in #dash-nilai .card:nth-child(1){animation-delay:.06s}
#dash-content.dash-in #dash-nilai .card:nth-child(2){animation-delay:.10s}
#dash-content.dash-in #dash-nilai .card:nth-child(3){animation-delay:.14s}
#dash-content.dash-in #dash-nilai .card:nth-child(4){animation-delay:.18s}
#dash-content.dash-in #dash-nilai .card:nth-child(5){animation-delay:.22s}
@keyframes cardRise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ✦✦✦ GRAND ENTRANCE — animasi masuk dashboard megah (khusus setelah login) ✦✦✦ */
#dash-content.dash-grand{animation:dashGrand .95s cubic-bezier(.16,1,.3,1) both}
@keyframes dashGrand{
  0%{opacity:0;transform:translateY(28px) scale(.965);filter:blur(10px)}
  55%{opacity:1;filter:blur(0)}
  100%{opacity:1;transform:none;filter:blur(0)}
}
/* Baris judul dashboard turun lembut */
#view-dashboard.dash-grand-on .page-head{animation:grandRise .8s .1s cubic-bezier(.16,1,.3,1) both}
/* Baris filter muncul setelah judul */
#view-dashboard.dash-grand-on .dash-filter-bar{animation:grandRise .8s .18s cubic-bezier(.16,1,.3,1) both}
/* Kartu statistik naik & membesar bertahap (cascade) */
#dash-content.dash-grand #dash-cards .card{animation:grandCard .8s cubic-bezier(.16,1,.3,1) both}
#dash-content.dash-grand #dash-cards .card:nth-child(1){animation-delay:.26s}
#dash-content.dash-grand #dash-cards .card:nth-child(2){animation-delay:.34s}
#dash-content.dash-grand #dash-cards .card:nth-child(3){animation-delay:.42s}
#dash-content.dash-grand #dash-cards .card:nth-child(4){animation-delay:.50s}
#dash-content.dash-grand #dash-nilai .card{animation:grandCard .8s cubic-bezier(.16,1,.3,1) both}
#dash-content.dash-grand #dash-nilai .card:nth-child(1){animation-delay:.40s}
#dash-content.dash-grand #dash-nilai .card:nth-child(2){animation-delay:.48s}
#dash-content.dash-grand #dash-nilai .card:nth-child(3){animation-delay:.56s}
#dash-content.dash-grand #dash-nilai .card:nth-child(4){animation-delay:.64s}
/* Panel grafik muncul terakhir, meluncur naik */
#dash-content.dash-grand .split .panel,
#dash-content.dash-grand > .panel{animation:grandPanel .9s .58s cubic-bezier(.16,1,.3,1) both}
#dash-content.dash-grand .split .panel:nth-child(2){animation-delay:.68s}
@keyframes grandRise{from{opacity:0;transform:translateY(-14px)}to{opacity:1;transform:none}}
@keyframes grandCard{
  0%{opacity:0;transform:translateY(30px) scale(.92)}
  60%{opacity:1}
  100%{opacity:1;transform:none}
}
@keyframes grandPanel{from{opacity:0;transform:translateY(26px) scale(.98)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  #dash-content.dash-grand,
  #view-dashboard.dash-grand-on .page-head,
  #view-dashboard.dash-grand-on .dash-filter-bar,
  #dash-content.dash-grand #dash-cards .card,
  #dash-content.dash-grand #dash-nilai .card,
  #dash-content.dash-grand .split .panel,
  #dash-content.dash-grand > .panel{animation:fade .4s ease both;filter:none}
}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden}
.panel-head{padding:15px 20px;border-bottom:1px solid var(--line);font-weight:700;font-family:'Plus Jakarta Sans';display:flex;align-items:center;gap:9px;background:linear-gradient(180deg,#fafcfc,#f4f8f9);color:var(--teal-dark)}
.panel-head::before{content:"";width:8px;height:8px;border-radius:50%;background:linear-gradient(135deg,var(--teal),var(--cyan));box-shadow:0 0 0 3px rgba(14,124,134,.12)}
.panel-body{padding:20px}
.split{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.bar-row{display:flex;flex-wrap:wrap;align-items:center;gap:5px 12px;margin-bottom:12px}
.bar-row .lbl{flex:1 1 100%;font-size:11px;color:var(--ink);white-space:normal;overflow:visible;text-overflow:clip;word-break:break-word;line-height:1.35}
.bar-track{flex:1 1 auto;min-width:60px;height:10px;background:#eef3f4;border-radius:6px;overflow:hidden;box-shadow:inset 0 1px 2px rgba(16,40,50,.06)}
/* Transisi lebar dipakai dashAnimasiIsi() (app.js) untuk mengisi bar dari nol
   sampai ke angkanya — setiap kali dashboard digambar ulang maupun tombol
   penyaring dipindah. Kurvanya melambat di ujung supaya bar terasa "mendarat"
   di angkanya, bukan berhenti mendadak. */
.bar-fill{height:100%;background:linear-gradient(90deg,var(--teal),var(--cyan));border-radius:6px;box-shadow:0 1px 4px rgba(14,124,134,.4);transition:width .9s cubic-bezier(.22,1,.36,1)}
@media (prefers-reduced-motion:reduce){ .bar-fill{transition:none} }
.bar-row .num{flex:0 0 auto;min-width:34px;text-align:right;font-weight:700;font-size:11px}
.bar-row .num.num-rp{width:auto;min-width:120px;white-space:nowrap;font-size:11px}

/* #3: Perkecil sedikit keseluruhan tampilan pada Dashboard agar lebih ringkas & elegan
   (hanya berlaku di #view-dashboard; tabel monitoring tidak terpengaruh). */
#view-dashboard .page-head{margin-bottom:14px}
#view-dashboard .page-head h2{
  font-size:22px;font-weight:800;letter-spacing:.2px;line-height:1.15;
  padding-left:18px;
  background:linear-gradient(100deg,var(--ink) 0%,var(--teal-dark) 46%,var(--teal) 72%,var(--cyan) 100%);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
#view-dashboard .page-head h2::before{
  content:"";position:absolute;left:0;top:1px;bottom:1px;width:6px;border-radius:6px;
  background:linear-gradient(180deg,var(--cyan),var(--teal),var(--teal-dark));
  box-shadow:0 0 0 3px rgba(22,169,181,.12),0 4px 12px rgba(14,124,134,.35);
}
#view-dashboard .page-head p{font-size:10.5px}
#view-dashboard .cards{gap:13px;margin-bottom:18px}
#view-dashboard .card{padding:15px 15px 15px 18px}
#view-dashboard .card .k{font-size:9.5px;letter-spacing:.5px}
#view-dashboard .card .v{font-size:23px;margin-top:6px}
#view-dashboard .card .sub{font-size:9.5px;margin-top:6px}
#view-dashboard .card-ic{transform:scale(.9)}
#view-dashboard .dash-nilai{margin-top:-6px}
#view-dashboard .split{gap:13px}
#view-dashboard .panel-head{padding:12px 16px;font-size:12px}
#view-dashboard .panel-body{padding:16px}
#view-dashboard .bar-row{gap:5px 10px;margin-bottom:10px}
#view-dashboard .bar-row .lbl{flex-basis:100%;font-size:10.5px}
#view-dashboard .bar-track{height:9px}
#view-dashboard .bar-row .num{font-size:10.5px}
#view-dashboard .bar-row .num.num-rp{min-width:110px;font-size:10.5px}
#view-dashboard .filter-field label{font-size:10px}
#view-dashboard .eff-pct{font-size:27px !important}
#view-dashboard .eff-rp{font-size:14px !important}
@media(max-width:640px){ #view-dashboard .bar-row .lbl{flex-basis:100%} }

/* ---------- Toolbar / Filters ---------- */
.toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-bottom:16px;margin-left:auto;margin-right:0;width:fit-content;max-width:100%;background:linear-gradient(135deg,#eef8f9 0%,#e0f1f3 100%);border:1px solid #cbe4e7;border-radius:var(--radius);padding:16px;box-shadow:0 4px 14px rgba(14,124,134,.12),inset 0 1px 0 rgba(255,255,255,.7)}
.filter-field{display:flex;flex-direction:column;gap:5px}
.filter-field label{font-size:9.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.filter-field select,.filter-field input{min-width:180px;max-width:180px}
/* Sembunyikan JUDUL filter (Bidang Pelaksana, Status, Tahun, dan juga Cari) di semua toolbar.
   Kotak input & ikon pencarian tetap tampil. */
.toolbar .filter-field>label{display:none}
/* Monitoring: perkecil sedikit agar tombol Reset & Hapus Semua sejajar satu baris dengan filter */
.toolbar .filter-field select,.toolbar .filter-field input{min-width:158px;max-width:158px}
/* ---- FILTER BIDANG: SELEBAR PILIHAN TERPANJANG (7 Agu 2026) ----
   Batas 158px di atas memenggal daftar bidang: pilihan terpanjang
   ("Keselamatan, Kesehatan Kerja, Lingkungan dan Keamanan") jauh lebih lebar
   daripada kotaknya, sehingga daftar yang terbuka menjulur keluar melewati
   kotak dan menutupi kolom tabel di bawahnya.

   `width:max-content` memakai LEBAR INTRINSIK <select>, yang menurut spesifikasi
   diambil dari <option> TERLEBAR — jadi kotaknya menyesuaikan sendiri bila
   daftar bidang bertambah/berubah, tanpa angka ajaib yang harus dipelihara.
   min-width & max-width bawaan wajib dinolkan lebih dulu; keduanya lebih kuat
   daripada width.

   Batas atas 100% dipasang sebagai pengaman di layar sempit supaya kotaknya
   tidak pernah mendorong tombol Reset & Tambah Data keluar dari baris. */
.toolbar .filter-field:has(> select[id$="bidang"]){flex:0 0 auto}
.toolbar .filter-field > select[id$="bidang"]{
  min-width:0;max-width:100%;width:max-content}
/* Kolom "Cari" diperlebar ~1,5x dari ukuran sebelumnya (200–260px → 300–390px) */
/* Batas 390px DILEPAS: kolom Cari-lah yang menyerap sisa lebar bilah, supaya
   tidak ada ruang mati di antara filter dan tombol aksi. 300px dipertahankan
   sebagai lebar MINIMUM, jadi pada layar sempit tampilannya tidak berubah. */
.toolbar #filter-search,.toolbar #filter-pl-search,.toolbar #filter-tender-search{min-width:300px;max-width:none;width:100%}
#filter-search,#filter-pl-search,#filter-tender-search{min-width:300px;max-width:390px}
.toolbar .spacer{flex:0 0 0;width:0;margin:0}
/* Kolom Cari tetap mengalir bersama filter di kiri */
/* KOLOM CARI MENYERAP SISA LEBAR (7 Agu 2026) — permintaan "Reset mentok ke
   tombol Input Data". Sebelumnya kotak Cari dipatok maksimal 390px, sehingga
   pada layar lebar ada ruang mati di tengah bilah: filter berkumpul di kiri,
   tombol aksi terdorong ke kanan oleh `margin-left:auto`, dan celah kosong
   menganga di antaranya.

   Yang dilebarkan adalah kolom CARI, bukan kolom Bidang: Bidang sudah punya
   aturannya sendiri (selebar pilihan terpanjang) dan meregangkannya lagi akan
   membatalkan aturan itu. Kotak pencarian justru satu-satunya isian yang
   memang selalu untung dari ruang tambahan.

   flex-basis 300px = lebar minimum lamanya, jadi pada layar sempit perilakunya
   tidak berubah sama sekali. */
.toolbar .toolbar-search{flex:1 1 300px;min-width:0}
.toolbar .toolbar-search .search-elegant-box{width:100%}
.toolbar .toolbar-search input{max-width:none;width:100%}
/* Reset & Hapus Semua didorong ke pojok kanan toolbar */
.toolbar .toolbar-actions{display:flex;align-items:flex-end;gap:12px;flex-wrap:nowrap;margin-left:auto}
.toolbar .toolbar-actions>.btn{margin:0;flex:0 0 auto}
/* Penetapan Nomor: kolom Cari dipindah ke kanan & diperbesar 2x (158px → 316px) */
.toolbar .toolbar-search.pn-search-right{margin-left:auto}
.toolbar #pn-lihat-search{min-width:316px;max-width:316px}
/* Kotak Cari yang dipindah sejajar dengan judul (di dalam page-head) */
.page-head .pn-head-search{flex:0 0 auto;margin-left:auto}
/* Tombol "Tambah Data" di pojok kanan atas page-head; kotak Cari bergeser ke kiri */
.page-head .head-add-btn{flex:0 0 auto;margin-left:12px;align-self:center}
.page-head .pn-head-search input{min-width:316px;max-width:316px}
@media(max-width:640px){
  .page-head .pn-head-search{flex:1 1 100%;margin-left:0}
  .page-head .head-add-btn{margin-left:0;width:100%;justify-content:center}
  .page-head .pn-head-search input{min-width:0;max-width:none;width:100%}
}
/* Kelengkapan Dokumen — Lihat Data: samakan lebar kotak Cari dengan Monitoring (300–390px) */
.toolbar #fkl-view-search{min-width:300px;max-width:390px}
/* ===== Kotak "Cari" elegan (Kelengkapan — Lihat Data & File Kontrak — Lihat Kontrak) ===== */
.filter-field.search-elegant{
  background:transparent;
  border:none;border-radius:0;padding:0;
  box-shadow:none
}
.filter-field.search-elegant label{color:var(--teal-dark);font-weight:800;opacity:1}
.search-elegant-box{position:relative;display:flex;align-items:center}
.search-elegant-box .search-elegant-ic{position:absolute;left:12px;width:16px;height:16px;color:var(--teal);pointer-events:none}
.filter-field.search-elegant input{
  padding-left:36px;background:#ffffff;border-color:#b6dde1;
  box-shadow:0 1px 2px rgba(16,40,50,.05), inset 0 1px 0 rgba(255,255,255,.6)
}
.filter-field.search-elegant input:focus{border-color:var(--teal);box-shadow:0 0 0 3px var(--teal-soft),0 3px 10px rgba(14,124,134,.16)}
/* File Kontrak — Lihat Kontrak: lebar kotak Cari disamakan dengan Monitoring (300–390px) */
@media(min-width:641px){
  .toolbar.fk-toolbar .fk-search.search-elegant input{min-width:300px!important;max-width:390px!important;width:auto!important}
}
/* Kolom Lokasi Pekerjaan pada tabel Kelengkapan — Lihat Data */
#view-fkl-view th.fkl-col-lokasi,#view-fkl-view td.fkl-col-lokasi{white-space:normal;min-width:170px;max-width:240px;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
/* Kolom Metode + badge pada tabel Penetapan — Lihat Nomor (gabungan PL & Tender) */
.pn-col-metode{text-align:center;white-space:nowrap;vertical-align:middle}
.pn-metode-badge{display:inline-block;padding:4px 10px;border-radius:20px;font-size:9.5px;font-weight:800;letter-spacing:.2px;white-space:nowrap;line-height:1.3}
.pn-badge-pl{background:#e0f2f4;color:#0b6b74;box-shadow:inset 0 0 0 1px rgba(14,124,134,.22)}
.pn-badge-tender{background:#e7e3fb;color:#4531a3;box-shadow:inset 0 0 0 1px rgba(69,49,163,.20)}
/* Toolbar Lihat Nomor / Lihat Data: ikut background gabungan hijau, lebar mengikuti isi */
.toolbar.pn-toolbar-bare{margin-bottom:16px;background:transparent;border:none;box-shadow:none;padding:0}
.toolbar.pn-toolbar-bare .pn-search-right{margin-left:0}
/* Samakan ukuran tombol Reset & Hapus Semua */
.toolbar .toolbar-actions>.btn-red,.toolbar .toolbar-actions>.btn-danger{min-width:118px;justify-content:center}
/* ===== File Kontrak — toolbar: Cari 2× lebar tombol Reset, dan Reset menempel di kanan Cari ===== */
/* Toolbar melebar penuh mengikuti lebar tabel di bawah, rata kiri; tombol Reset ikut bergeser ke kiri */
.toolbar.fk-toolbar{width:100%;margin-left:0;margin-right:0}
.toolbar.fk-toolbar .fk-search{flex:0 0 auto}
.toolbar.fk-toolbar .fk-search input{min-width:236px!important;max-width:236px!important;width:236px!important}
.toolbar.fk-toolbar .fk-actions-inline{margin-left:0;flex:1 1 auto}
/* Dropdown "Bidang Pelaksana": lebar +50% (180px -> 270px) dan SAMA persis
   antara Daftar Perjanjian/Kontrak dan Dokumen Pengadaan */
.toolbar.fk-toolbar .filter-field:has(#fk-view-bidang),
.toolbar.fk-toolbar .filter-field:has(#dpeng-view-bidang),
.toolbar.fk-toolbar .filter-field:has(#materi-view-kategori){flex:0 0 auto}
.toolbar.fk-toolbar #fk-view-bidang,
.toolbar.fk-toolbar #dpeng-view-bidang{min-width:270px!important;max-width:270px!important;width:270px!important}
/* Kategori pada Materi & Peraturan: lebih ringkas daripada Bidang Pelaksana,
   cukup untuk memuat "Standar Operasional Prosedur (SOP)". */
.toolbar.fk-toolbar #materi-view-kategori{min-width:230px!important;max-width:230px!important;width:230px!important}
/* Tombol pojok ("Tambah Data" / "Tambah Dokumen" / "Tambah Peraturan") didorong
   ke pojok kanan toolbar, Reset tetap menempel di kanan Cari */
.toolbar.fk-toolbar .fk-actions-inline > .fk-corner-btn,
.toolbar.fk-toolbar .fk-actions-inline > .dpeng-corner-btn,
.toolbar.fk-toolbar .fk-actions-inline > .materi-corner-btn{margin-left:auto}
@media(max-width:640px){
  .toolbar.fk-toolbar .fk-search{flex:1 1 100%}
  .toolbar.fk-toolbar .fk-search input{min-width:0!important;max-width:none!important;width:100%!important}
  .toolbar.fk-toolbar .filter-field:has(#fk-view-bidang),
  .toolbar.fk-toolbar .filter-field:has(#dpeng-view-bidang),
  .toolbar.fk-toolbar .filter-field:has(#materi-view-kategori){flex:1 1 100%}
  .toolbar.fk-toolbar #fk-view-bidang,
  .toolbar.fk-toolbar #dpeng-view-bidang,
  .toolbar.fk-toolbar #materi-view-kategori{min-width:0!important;max-width:none!important;width:100%!important}
  .toolbar.fk-toolbar .fk-actions-inline{flex:1 1 100%;margin-left:0}
  .toolbar.fk-toolbar .fk-actions-inline > .fk-corner-btn,
  .toolbar.fk-toolbar .fk-actions-inline > .dpeng-corner-btn,
  .toolbar.fk-toolbar .fk-actions-inline > .materi-corner-btn{margin-left:0}
}
select,input,textarea{font-family:'Plus Jakarta Sans';font-size:12px;padding:9px 11px;border:1px solid #cdd9de;border-radius:10px;background:linear-gradient(180deg,#ffffff,#fbfdfe);color:var(--ink);width:100%;transition:border .15s,box-shadow .15s,background .15s;box-shadow:0 1px 2px rgba(16,40,50,.05),inset 0 1px 0 rgba(255,255,255,.6)}
select:hover,input:hover{border-color:#a7bec5;box-shadow:0 2px 6px rgba(16,40,50,.08),inset 0 1px 0 rgba(255,255,255,.6)}
select:focus,input:focus,textarea:focus{outline:none;border-color:var(--teal);background:#fff;box-shadow:0 0 0 3px var(--teal-soft),0 3px 10px rgba(14,124,134,.16)}
select:disabled,input:disabled,textarea:disabled,input[readonly]{background:linear-gradient(180deg,#f1f5f6,#eef3f4);box-shadow:none}

/* ---------- Buttons ---------- */
.btn{border:none;border-radius:12px;padding:10px 17px;font-weight:700;font-size:11.5px;display:inline-flex;align-items:center;gap:8px;transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .22s ease,filter .2s ease;white-space:nowrap;letter-spacing:.2px;position:relative;isolation:isolate}
.btn svg{width:16px;height:16px}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(0) scale(.98)}
.btn:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(255,255,255,.6),0 0 0 5px var(--teal)}
.btn-teal{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;box-shadow:0 4px 14px rgba(14,124,134,.32),inset 0 1px 0 rgba(255,255,255,.25)}.btn-teal:hover{box-shadow:0 8px 22px rgba(14,124,134,.44),inset 0 1px 0 rgba(255,255,255,.3);filter:brightness(1.04)}
.btn-green{background:linear-gradient(135deg,var(--green),#27b569);color:#fff;box-shadow:0 4px 14px rgba(30,158,90,.30),inset 0 1px 0 rgba(255,255,255,.25)}.btn-green:hover{box-shadow:0 8px 22px rgba(30,158,90,.44),inset 0 1px 0 rgba(255,255,255,.3);filter:brightness(1.04)}
.btn-red{background:linear-gradient(135deg,var(--red),#e25151);color:#fff;box-shadow:0 4px 14px rgba(211,58,58,.28),inset 0 1px 0 rgba(255,255,255,.22)}.btn-red:hover{box-shadow:0 8px 22px rgba(211,58,58,.42),inset 0 1px 0 rgba(255,255,255,.28);filter:brightness(1.04)}
.btn-danger{background:linear-gradient(135deg,var(--red-dark),#c23636);color:#fff;box-shadow:0 4px 14px rgba(178,42,42,.34),inset 0 1px 0 rgba(255,255,255,.18)}.btn-danger:hover{box-shadow:0 8px 22px rgba(178,42,42,.5),inset 0 1px 0 rgba(255,255,255,.24);filter:brightness(1.05)}
.btn-ghost{background:linear-gradient(180deg,#fff,#f7fafb);color:var(--ink);border:1px solid var(--line);box-shadow:0 2px 6px rgba(16,40,50,.06)}.btn-ghost:hover{border-color:var(--teal);color:var(--teal);box-shadow:0 4px 14px rgba(14,124,134,.16)}
.btn-amber{background:linear-gradient(135deg,var(--yellow),#ffca3a);color:#5a3d00;box-shadow:0 4px 14px rgba(246,180,14,.32),inset 0 1px 0 rgba(255,255,255,.4)}.btn-amber:hover{box-shadow:0 8px 22px rgba(246,180,14,.48),inset 0 1px 0 rgba(255,255,255,.5);filter:brightness(1.04)}
.btn-indigo{background:linear-gradient(135deg,#3a56d4,#5b8def);color:#fff;box-shadow:0 4px 14px rgba(58,86,212,.30),inset 0 1px 0 rgba(255,255,255,.25)}.btn-indigo:hover{box-shadow:0 8px 22px rgba(58,86,212,.46),inset 0 1px 0 rgba(255,255,255,.3);filter:brightness(1.05)}
.btn-sm{padding:7px 12px;font-size:10.5px;border-radius:9px}

/* ---------- Table ---------- */
.table-wrap{overflow:auto;max-height:calc(100vh - 250px);min-height:300px;border-radius:14px;border:6px solid #fff;outline:1px solid #dbe7ea;outline-offset:0;background:#fff;box-shadow:0 6px 22px rgba(16,40,50,.10)}
table{border-collapse:collapse;width:100%;min-width:980px}
th,td{padding:2px 4px;text-align:left;font-size:11px;border:1px solid #fff;white-space:nowrap}
th{background:var(--teal);font-weight:700;color:#fff;font-size:9.5px;text-transform:uppercase;letter-spacing:.5px;text-align:center;position:sticky;top:0;z-index:6;border-color:#fff;white-space:normal;line-height:1.28;vertical-align:middle;min-width:82px}
/* Semua JUDUL kolom tabel rata tengah */
.table-wrap thead th{text-align:center!important}
tbody tr{transition:background .15s}
tbody tr:nth-child(even){background:#f5f9fa}
tbody tr:hover{background:var(--teal-soft)}
td.wrap-cell{white-space:normal;min-width:280px}
td.wrap-penyedia{white-space:normal;min-width:225px}
/* Kolom Bidang Pelaksana pada tabel monitoring: lebar tetap 200px, teks di-wrap (tidak melebar mengikuti isi) */
th.col-bidang,td.col-bidang{width:200px;min-width:200px;max-width:200px;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
/* Kolom Penyedia pada tabel monitoring: lebar tetap 210px, teks di-wrap */
th.col-penyedia,td.col-penyedia{width:200px;min-width:200px;max-width:200px;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
.stack-line{display:block;padding:2px 0;line-height:1.35}
.stack-line+.stack-line{border-top:1px dashed var(--line);margin-top:2px}
.stack-no{display:inline-block;min-width:16px;color:var(--teal-dark);font-weight:800;font-size:10px}
td.cell-center{text-align:center}
.action-cell{display:flex;gap:6px;justify-content:center}
.act{border:none;border-radius:8px;width:30px;height:30px;display:grid;place-items:center;color:#fff;transition:transform .15s,box-shadow .2s}
.act svg{width:15px;height:15px}
.act-edit{background:linear-gradient(135deg,var(--yellow),#ffca3a);color:#5a3d00}.act-view{background:linear-gradient(135deg,var(--teal),var(--cyan))}.act-del{background:linear-gradient(135deg,var(--red),#e25151)}
.act:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(16,40,50,.22)}
.pill{display:inline-block;padding:4px 11px;border-radius:20px;font-size:9.5px;font-weight:700;letter-spacing:.2px}
.pill-prog{background:#fff3d6;color:#9a6b00;box-shadow:inset 0 0 0 1px rgba(154,107,0,.18)}
.pill-kontrak{background:#d8f0e3;color:#157a44;box-shadow:inset 0 0 0 1px rgba(21,122,68,.18)}
/* Tandatangan Kontrak: biru + teks 2 baris (dipecah <br> di tahapanPill) */
.pill-ttd{background:#ffe4cc;color:#b3560c;box-shadow:inset 0 0 0 1px rgba(179,86,12,.22)}
.pill.pill-ttd{white-space:normal;text-align:center;line-height:1.25;padding-top:3px;padding-bottom:3px}
.pill-batal{background:#fbe0e0;color:#b22a2a;box-shadow:inset 0 0 0 1px rgba(178,42,42,.18)}
/* Freeze horizontal (pane) : kolom "No." + "Nama Pekerjaan" dibekukan di kiri,
   sehingga tetap terlihat saat tabel digulir ke kanan. */
.table-wrap thead th:first-child{position:sticky;top:0;z-index:8;background:var(--teal)}
/* #4: Kolom No. dipersempit agar pas dengan angka baris (mis. 1–2 digit) — dibekukan di kiri (left:0) */
.table-wrap th.col-no,.table-wrap td.col-no{width:34px;min-width:34px;max-width:40px;text-align:center;padding-left:4px;padding-right:4px;white-space:nowrap}

/* #3: Kolom "Nama Pekerjaan" — freeze pane horizontal, menempel tepat setelah kolom No. (left:34px) */
.table-wrap th.col-nama-freeze,.table-wrap td.col-nama-freeze{white-space:normal;min-width:240px;max-width:300px;word-break:break-word;overflow-wrap:break-word;line-height:1.3}

/* Isi latar penuh via pseudo-element agar tidak ada celah tembus (bug border-collapse
   pada sel sticky). Pseudo diletakkan DI DALAM garis border (inset 1px) agar tidak
   menutupi garis border atas/bawah/kanan pada kolom No. & Nama Pekerjaan. */

/* ===== Freeze pane horizontal — HANYA menu Monitoring (Daftar Pekerjaan) =====
   Berlaku eksklusif di #view-list (Kontrak Rinci), #view-list-pl (Pengadaan Langsung),
   dan #view-list-tender (Tender). Menu lain memakai aturan dasar di atas: kolom
   mengalir normal (tidak dibekukan ke kiri); baris judul tetap menempel di atas. */
#view-list .table-wrap thead th:first-child,
#view-list-pl .table-wrap thead th:first-child,
#view-list-tender .table-wrap thead th:first-child{left:0;z-index:8}
#view-list .table-wrap th.col-no,#view-list .table-wrap td.col-no,
#view-list-pl .table-wrap th.col-no,#view-list-pl .table-wrap td.col-no,
#view-list-tender .table-wrap th.col-no,#view-list-tender .table-wrap td.col-no{
  position:sticky;left:0;z-index:4}
#view-list .table-wrap th.col-nama-freeze,#view-list .table-wrap td.col-nama-freeze,
#view-list-pl .table-wrap th.col-nama-freeze,#view-list-pl .table-wrap td.col-nama-freeze,
#view-list-tender .table-wrap th.col-nama-freeze,#view-list-tender .table-wrap td.col-nama-freeze{
  position:sticky;left:34px;z-index:4}
#view-list .table-wrap thead th.col-no,#view-list .table-wrap thead th.col-nama-freeze,
#view-list-pl .table-wrap thead th.col-no,#view-list-pl .table-wrap thead th.col-nama-freeze,
#view-list-tender .table-wrap thead th.col-no,#view-list-tender .table-wrap thead th.col-nama-freeze{
  z-index:8}
/* Isi latar penuh via pseudo-element agar tidak ada celah tembus (bug border-collapse
   pada sel sticky). Pseudo diletakkan DI DALAM garis border (inset 1px). */
#view-list .table-wrap td.col-no,#view-list .table-wrap td.col-nama-freeze,
#view-list-pl .table-wrap td.col-no,#view-list-pl .table-wrap td.col-nama-freeze,
#view-list-tender .table-wrap td.col-no,#view-list-tender .table-wrap td.col-nama-freeze{
  background-clip:padding-box}
#view-list .table-wrap td.col-no::before,#view-list .table-wrap td.col-nama-freeze::before,
#view-list-pl .table-wrap td.col-no::before,#view-list-pl .table-wrap td.col-nama-freeze::before,
#view-list-tender .table-wrap td.col-no::before,#view-list-tender .table-wrap td.col-nama-freeze::before{
  content:"";position:absolute;top:0;bottom:0;left:1px;right:1px;background:inherit;z-index:-1}
/* Sel sticky kehilangan garis border-collapse saat digulir, jadi garis dipalsukan
   lewat inset box-shadow + latar solid. HANYA dipakai di Monitoring; di menu lain
   sel tidak sticky sehingga border asli tabel sudah tampil normal. */
#view-list .table-wrap thead th.col-no,#view-list .table-wrap thead th.col-nama-freeze,
#view-list-pl .table-wrap thead th.col-no,#view-list-pl .table-wrap thead th.col-nama-freeze,
#view-list-tender .table-wrap thead th.col-no,#view-list-tender .table-wrap thead th.col-nama-freeze{
  background:var(--teal);box-shadow:inset 1px 0 0 #fff, inset -1px 0 0 #fff, inset 0 -1px 0 #fff}
#view-list .table-wrap tbody td.col-no,#view-list .table-wrap tbody td.col-nama-freeze,
#view-list-pl .table-wrap tbody td.col-no,#view-list-pl .table-wrap tbody td.col-nama-freeze,
#view-list-tender .table-wrap tbody td.col-no,#view-list-tender .table-wrap tbody td.col-nama-freeze{
  background:#eef4f6;box-shadow:inset 1px 0 0 #fff, inset -1px 0 0 #fff, inset 0 -1px 0 #fff, inset 0 1px 0 #fff}
#view-list .table-wrap tbody tr:nth-child(even) td.col-no,#view-list .table-wrap tbody tr:nth-child(even) td.col-nama-freeze,
#view-list-pl .table-wrap tbody tr:nth-child(even) td.col-no,#view-list-pl .table-wrap tbody tr:nth-child(even) td.col-nama-freeze,
#view-list-tender .table-wrap tbody tr:nth-child(even) td.col-no,#view-list-tender .table-wrap tbody tr:nth-child(even) td.col-nama-freeze{
  background:#e6eef1}
#view-list .table-wrap tbody tr:hover td.col-no,#view-list .table-wrap tbody tr:hover td.col-nama-freeze,
#view-list-pl .table-wrap tbody tr:hover td.col-no,#view-list-pl .table-wrap tbody tr:hover td.col-nama-freeze,
#view-list-tender .table-wrap tbody tr:hover td.col-no,#view-list-tender .table-wrap tbody tr:hover td.col-nama-freeze{
  background:#dceaed}
/* Kolom Tgl. Terbit & Berakhir Kontrak — dilebarkan & judul dibungkus agar muat 2 baris */
.table-wrap th.col-date,.table-wrap td.col-date{min-width:118px!important;width:118px!important;max-width:124px!important;padding-left:4px;padding-right:4px}
.table-wrap th.col-date{white-space:normal;line-height:1.28;text-align:center;vertical-align:middle}
.table-wrap td.col-date{white-space:nowrap;text-align:center}
/* ---------------------------------------------------------------------
   Daftar Surat Perintah Kerja: kolom TANGGAL & NILAI selebar isi
   terpanjangnya, bukan lebar tetap. Caranya width:1% + white-space:nowrap —
   pada tabel table-layout:auto, kolom yang diminta selebar 1% akan menyusut
   sampai sesempit isinya yang tidak boleh terpotong, dan sisa ruang jatuh ke
   kolom Nama Pekerjaan yang memang paling butuh tempat.
   Aturan .col-date umum di atas memakai !important, jadi penimpaannya di sini
   juga harus !important. Ruang lingkupnya dibatasi #view-spk-view supaya
   tabel Monitoring lain tetap memakai lebar tanggal yang seragam. */
#view-spk-view .table-wrap th.col-date,
#view-spk-view .table-wrap td.col-date{
  width:1%!important;min-width:0!important;max-width:none!important;
  white-space:nowrap!important;padding-left:16px;padding-right:16px}
#view-spk-view .table-wrap th.col-nilai,
#view-spk-view .table-wrap td.col-nilai{
  width:1%;min-width:0;white-space:nowrap;text-align:right;
  padding-left:16px;padding-right:16px}
/* Kolom No. Kontrak/SPBJ — menyesuaikan lebar isi data (tampil utuh, tidak terpotong) */
.table-wrap th.col-kontrak,.table-wrap td.col-kontrak{white-space:nowrap;min-width:150px;width:1%}
.table-wrap td.col-kontrak.wrap-penyedia{white-space:normal}
/* Kolom Nilai Pekerjaan — lebar MENYUSUT mengikuti nominal terpanjang yang tampil
   (tanpa lebar minimum tetap; tiap nominal tetap satu baris utuh) */
.table-wrap th.col-nilai,.table-wrap td.col-nilai{white-space:nowrap;width:1%;min-width:0;text-align:right}
.table-wrap td.col-nilai.wrap-penyedia{white-space:nowrap;width:1%;min-width:0;text-align:left}
.table-wrap td.col-nilai.wrap-penyedia .stack-line{white-space:nowrap}
.table-wrap tbody td:first-child{font-weight:700;color:var(--teal-dark)}
.table-wrap tbody tr:nth-child(even) td:first-child{background:#f5f9fa}
.table-wrap tbody tr:hover td:first-child{background:var(--teal-soft)}
.empty{padding:56px 20px;text-align:center;color:var(--muted);display:flex;flex-direction:column;align-items:center;gap:2px}
.empty svg{width:30px;height:30px;opacity:.9;margin:0 0 14px;color:var(--teal);
  padding:15px;box-sizing:content-box;border-radius:50%;
  background:linear-gradient(180deg,#f1fafb,#e6f4f5);
  box-shadow:inset 0 0 0 1px rgba(14,124,134,.14),0 8px 20px rgba(14,124,134,.10)}
.empty>div{font-family:'Plus Jakarta Sans';font-weight:700;font-size:12.5px;color:#5b6d76}
.pagination{display:flex;justify-content:flex-end;align-items:center;gap:6px;flex-wrap:wrap;padding:14px 16px;border-top:1px solid var(--line)}
.pg-btn{border:1px solid var(--line);background:#fff;color:var(--ink);border-radius:8px;padding:7px 12px;font-size:11px;font-weight:600;font-family:'Plus Jakarta Sans'}
.pg-btn:hover:not(:disabled):not(.active){border-color:var(--teal);color:var(--teal)}
.pg-btn:disabled{opacity:.4;cursor:default}
.pg-num{min-width:36px;padding:7px 0;text-align:center}
.pg-btn.active{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;border-color:var(--teal);box-shadow:0 4px 12px rgba(14,124,134,.32)}
.pg-ellipsis{padding:0 4px;color:var(--muted)}
@media(max-width:640px){ .pagination{justify-content:center} }

/* Dashboard: ukuran font dinaikkan 2px */
#view-dashboard .page-head h2{font-size:21px}
#view-dashboard .page-head p{font-size:13px}
#view-dashboard .filter-field label{font-size:11.5px;text-align:center;align-self:stretch}
#view-dashboard .filter-field select{font-size:14px}
#view-dashboard .card .k{font-size:12px}
#view-dashboard .card .v{font-size:30px}
#view-dashboard .card .sub{font-size:12px}
#view-dashboard .panel-head{font-size:14px}
#view-dashboard .bar-row .lbl{font-size:13px}
#view-dashboard .bar-row .num{font-size:13px}
.empty svg{width:30px;height:30px;opacity:.9;margin:0 0 14px}
.count-badge{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;font-weight:700;font-size:10px;padding:3px 11px;border-radius:20px;margin-left:8px;box-shadow:0 3px 10px rgba(14,124,134,.28);vertical-align:middle}

/* ===== Halaman berbasis tabel (Monitoring, File Kontrak, Penetapan, Kelengkapan) — lebih elegan & profesional ===== */
#view-list .panel,#view-list-pl .panel,#view-list-tender .panel,
#view-fk-input .panel,#view-fk-view .panel,#view-pn-lihat .panel,#view-fkl-view .panel{
  border-radius:18px;border-color:#dbe8ea;
  box-shadow:0 1px 2px rgba(16,40,50,.05),0 16px 40px rgba(16,40,50,.07)
}
/* Header tabel: gradasi teal lebih dalam + garis cahaya tipis di bawah judul */
#view-list .table-wrap thead th,#view-list-pl .table-wrap thead th,#view-list-tender .table-wrap thead th,
#view-fk-input .table-wrap thead th,#view-fk-view .table-wrap thead th,#view-pn-lihat .table-wrap thead th,#view-fkl-view .table-wrap thead th,
#view-list .table-wrap thead th:first-child,#view-list-pl .table-wrap thead th:first-child,#view-list-tender .table-wrap thead th:first-child,
#view-fk-input .table-wrap thead th:first-child,#view-fk-view .table-wrap thead th:first-child,#view-pn-lihat .table-wrap thead th:first-child,#view-fkl-view .table-wrap thead th:first-child,
#view-list .table-wrap thead th.col-no,#view-list-pl .table-wrap thead th.col-no,#view-list-tender .table-wrap thead th.col-no,
#view-fk-input .table-wrap thead th.col-no,#view-fk-view .table-wrap thead th.col-no,#view-pn-lihat .table-wrap thead th.col-no,#view-fkl-view .table-wrap thead th.col-no,
#view-list .table-wrap thead th.col-nama-freeze,#view-list-pl .table-wrap thead th.col-nama-freeze,#view-list-tender .table-wrap thead th.col-nama-freeze,
#view-fk-input .table-wrap thead th.col-nama-freeze,#view-fk-view .table-wrap thead th.col-nama-freeze,#view-pn-lihat .table-wrap thead th.col-nama-freeze,#view-fkl-view .table-wrap thead th.col-nama-freeze{
  background:#0E7C86;
  letter-spacing:.6px
}
#view-list .table-wrap thead th,#view-list-pl .table-wrap thead th,#view-list-tender .table-wrap thead th,
#view-fk-input .table-wrap thead th,#view-fk-view .table-wrap thead th,#view-pn-lihat .table-wrap thead th,#view-fkl-view .table-wrap thead th{
  border-bottom:2px solid rgba(255,255,255,.10)
}
/* Badge jumlah data sedikit lebih menonjol */
#view-list .count-badge,#view-list-pl .count-badge,#view-list-tender .count-badge,
#view-fk-input .count-badge,#view-fk-view .count-badge,#view-pn-lihat .count-badge,#view-fkl-view .count-badge{
  font-size:10.5px;padding:4px 12px;
  box-shadow:0 4px 12px rgba(14,124,134,.34),inset 0 1px 0 rgba(255,255,255,.35)
}
/* Judul halaman: garis aksen kiri sedikit bercahaya */
#view-list .page-head h2::before,#view-list-pl .page-head h2::before,#view-list-tender .page-head h2::before,
#view-fk-input .page-head h2::before,#view-fk-view .page-head h2::before,#view-pn-lihat .page-head h2::before,#view-fkl-view .page-head h2::before{
  box-shadow:0 3px 12px rgba(14,124,134,.4)
}
/* Baris data: transisi hover lebih halus */
#view-list tbody tr,#view-list-pl tbody tr,#view-list-tender tbody tr,
#view-fk-input tbody tr,#view-fk-view tbody tr,#view-pn-lihat tbody tr,#view-fkl-view tbody tr{transition:background .16s ease}
/* Toolbar filter: sedikit lebih "mengambang" agar terpisah rapi dari tabel */
#view-list .toolbar,#view-list-pl .toolbar,#view-list-tender .toolbar,
#view-fk-input .toolbar,#view-fk-view .toolbar,#view-pn-lihat .toolbar,#view-fkl-view .toolbar{
  box-shadow:0 6px 20px rgba(14,124,134,.12),inset 0 1px 0 rgba(255,255,255,.8)
}
/* Toolbar "bare" (Penetapan & Kelengkapan) tidak punya latar → jangan beri bayangan */
#view-pn-lihat .toolbar.pn-toolbar-bare,#view-fkl-view .toolbar.pn-toolbar-bare{box-shadow:none}
/* Penetapan Nomor (menu tunggal): field Cari & tombol "Ambil Nomor" sejajar
   dengan judul pada baris page-head (ukuran Cari mengikuti .pn-head-search). */
#view-pn-lihat .page-head .head-add-btn{flex:0 0 auto;margin-left:12px}

/* ===== Penetapan Nomor / Kelengkapan — Lihat: header rapi & kotak Cari lebih premium ===== */
#view-pn-lihat .page-head{
  align-items:center;
  margin-bottom:18px
}
/* Kelengkapan — Lihat Data: jarak judul ke tabel disamakan dengan Data Pekerjaan */
#view-fkl-view .page-head{align-items:center}
#view-pn-lihat .page-head p,#view-fkl-view .page-head p{
  font-size:11.5px;color:#5b6d76;margin-top:5px
}
/* Kotak Cari: sedikit terangkat & membulat agar terasa elegan */
#view-pn-lihat .filter-field.search-elegant input,#view-fkl-view .filter-field.search-elegant input{
  border-radius:12px;border-color:#b6dde1;
  box-shadow:0 4px 14px rgba(14,124,134,.10),inset 0 1px 0 rgba(255,255,255,.7)
}
#view-pn-lihat .filter-field.search-elegant input:focus,#view-fkl-view .filter-field.search-elegant input:focus{
  box-shadow:0 0 0 3px var(--teal-soft),0 6px 16px rgba(14,124,134,.16)
}

/* ---------- Form ---------- */
.form-section{margin-bottom:8px}
.form-section-title{font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;color:var(--teal-dark);display:flex;align-items:center;gap:9px;margin:24px 0 16px;padding-bottom:9px;border-bottom:2px solid;border-image:linear-gradient(90deg,var(--teal),var(--cyan),transparent) 1;letter-spacing:.3px}
.form-section-title:first-child{margin-top:0}
/* #2: Kartu pembatas per kelompok data pada form Input Pekerjaan */
.form-card{position:relative;background:linear-gradient(180deg,#ffffff,#fbfdfe);border:1px solid #d8e4e7;
  border-radius:16px;padding:8px 22px 22px;margin-bottom:20px;
  box-shadow:0 2px 6px rgba(16,40,50,.05),0 14px 34px rgba(16,40,50,.06);
  transition:box-shadow .25s ease,border-color .25s ease,transform .25s ease}
.form-card::before{content:"";position:absolute;left:0;top:20px;bottom:20px;width:4px;border-radius:0 4px 4px 0;
  background:linear-gradient(180deg,var(--teal),var(--cyan));box-shadow:2px 0 10px rgba(14,124,134,.25)}
.form-card:hover{border-color:#bcd6d9;box-shadow:0 4px 10px rgba(16,40,50,.07),0 20px 46px rgba(16,40,50,.09)}
.form-card:last-child{margin-bottom:0}
/* Reveal halus untuk data yang muncul setelah tombol "Pilih Data Pekerjaan"
   ditekan — konten keluar perlahan (fade + naik + mengembang) hingga penuh,
   dengan sedikit jeda bertingkat antar-bagian agar terasa mengalir. */
@keyframes dpReveal{
  0%{opacity:0;transform:translateY(14px) scale(.975);filter:blur(4px)}
  55%{filter:blur(0)}
  100%{opacity:1;transform:none;filter:blur(0)}
}
.dp-reveal{animation:dpReveal .58s cubic-bezier(.16,1,.3,1) both;will-change:opacity,transform,filter}
.dp-reveal.dp-reveal-d1{animation-delay:.06s}
.dp-reveal.dp-reveal-d2{animation-delay:.16s}
.dp-reveal.dp-reveal-d3{animation-delay:.26s}
@media(prefers-reduced-motion:reduce){ .dp-reveal{animation-duration:.01s!important;animation-delay:0s!important} }
.form-card .form-section-title{margin:0 0 18px;padding:14px 0 11px}
.dp-pick-btn{appearance:none;border:none;cursor:pointer;display:inline-flex;align-items:center;gap:7px;background:linear-gradient(135deg,#12a3ad,#0E7C86);color:#fff;font-family:'Plus Jakarta Sans';font-weight:800;font-size:10.5px;letter-spacing:.5px;text-transform:uppercase;padding:9px 15px;border-radius:10px;box-shadow:0 4px 12px rgba(11,61,66,.22);transition:transform .15s ease,box-shadow .2s ease;white-space:nowrap}
.dp-pick-btn:hover{transform:translateY(-1px);box-shadow:0 7px 16px rgba(11,61,66,.3)}
.dp-pick-btn:active{transform:translateY(0) scale(.97)}
.dp-pick-btn svg{width:15px;height:15px;flex:0 0 auto}
.dp-pick-wrap{margin-left:auto;display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.dp-unpick-btn{appearance:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;background:#fff;color:#b02626;border:1.5px solid #edbcbc;font-family:'Plus Jakarta Sans';font-weight:800;font-size:10.5px;letter-spacing:.5px;text-transform:uppercase;padding:8px 13px;border-radius:10px;transition:transform .15s ease,background .2s ease;white-space:nowrap}
.dp-unpick-btn:hover{background:#fce4e4;transform:translateY(-1px)}
.dp-unpick-btn:active{transform:translateY(0) scale(.97)}
.dp-unpick-btn svg{width:14px;height:14px;flex:0 0 auto}
.hps-pick-row{display:flex;gap:14px;align-items:flex-end;flex-wrap:wrap;margin-top:6px}
.hps-pick-row .field{flex:1 1 360px;min-width:240px;margin:0}
.hps-pick-btn{flex:0 0 auto;height:46px;align-self:flex-end}
.form-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px 30px}
/* Baris Kontrak Rinci: Tgl Terbit & Tgl Berakhir = 1/3 Nama Penyedia, Nilai = 1/2 Nama Penyedia */
.grid-kr{display:grid;grid-template-columns:2fr 2fr 3fr 6fr;gap:10px 30px;margin-top:16px}
.field{display:flex;flex-direction:column;gap:6px}
.field.col-2{grid-column:span 2}
.field.col-3{grid-column:span 3}
/* ===== Model lebar-px + jumlah kolom bidang (Penyesuaian) ===== */
/* Container "flow": field mengalir kiri-atas -> kanan-bawah, membungkus otomatis.
   --cols menentukan jumlah kolom bidang; field tanpa lebar px mengisi 1 kolom. */
.form-flow{display:flex;flex-wrap:wrap;gap:10px 30px;align-items:flex-end}
.form-flow>.field{flex:0 1 calc((100% - (var(--cols) - 1) * 30px) / var(--cols));min-width:0}
.form-flow>.field.has-pxw{flex:0 0 auto}
/* #3: Bidang/Sub Bidang — lebar 1,5× kolom biasa */
.form-flow>.field.field-wide15{flex:0 1 calc(1.5 * ((100% - (var(--cols) - 1) * 30px) / var(--cols)) + 15px)}
@media(max-width:640px){ .form-flow>.field.field-wide15{flex:1 1 100% !important} }
.form-flow>.field input,.form-flow>.field select{width:100%}
@media(max-width:640px){ .form-flow>.field{flex:1 1 100% !important;width:100% !important} }
/* Kelompok yang memuat field multi-nilai (Bidang / Sub Bidang) — rata ATAS.
   .form-flow bawaannya align-items:flex-end supaya kotak isian sebaris. Namun
   pada kelompok yang memuat .indep-field, tiap penambahan baris membuat field
   lain (Jenis Pengadaan, Jenis Perjanjian/Kontrak) ikut terdorong ke bawah
   mengikuti isian terakhir. Di sini perataannya dibalik ke atas sehingga field
   lain tetap di posisi semula meski daftar memanjang.
   :has() dipakai agar HANYA kelompok tsb yang berubah — kelompok form lain
   (termasuk .hl-add-flow yang butuh rata bawah) tidak ikut terpengaruh. */
.form-flow:has(> .indep-field){align-items:flex-start;align-content:flex-start}
.form-flow:has(> .indep-field)>.field{align-self:flex-start;justify-content:flex-start;margin-bottom:auto}
/* Cadangan manual bila peramban belum mendukung :has() — tambahkan kelas
   .flow-top pada container .form-flow yang bersangkutan. */
.form-flow.flow-top{align-items:flex-start;align-content:flex-start}
.form-flow.flow-top>.field{align-self:flex-start;justify-content:flex-start;margin-bottom:auto}
/* Tombol "Tambah Tanggal" sejajar (rata bawah) dengan field Tanggal & Keterangan.
   .form-flow sudah align-items:flex-end, jadi tombol otomatis sebaris dengan input. */
.hl-add-btn-field{display:flex;align-items:flex-end}
.hl-add-btn-field .btn{white-space:nowrap}
@media(max-width:640px){ .hl-add-btn-field .btn{width:100%;justify-content:center} }
/* Baris "Informasi Umum" dengan lebar tetap — HANYA di form Input SPBJ/Kontrak Rinci */
#view-input .grid-umum{display:grid;grid-template-columns:180px 280px 120px 270px;gap:10px 30px}
#view-input .grid-umum + .form-grid{margin-top:10px}
@media(max-width:1160px){ #view-input .grid-umum{grid-template-columns:1fr 1fr} }
@media(max-width:640px){ #view-input .grid-umum{grid-template-columns:1fr} }
.field label{font-size:10.5px;font-weight:600;color:var(--ink)}
.field label .req{color:var(--red)}
/* Field wajib yang belum diisi saat simpan */
.field.field-error label{color:var(--red)}
.field.field-error input,.field.field-error select{border-color:var(--red)!important;background:#fdecec}
.field.field-error input:focus,.field.field-error select:focus{box-shadow:0 0 0 3px rgba(211,58,58,.15)}
.field .hint{font-size:9px;color:var(--muted)}
.form-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:26px;padding-top:20px;border-top:1px solid var(--line)}
.form-actions .btn{padding:12px 26px;font-size:12px}

/* ===== Penyesuaian (form builder) ===== */
.mode-banner.penyesuaian{background:#fff4dc;color:#7a5300;border-color:#f2d38a}
.pyn-help{font-size:10.5px;color:var(--muted);background:#f4f8f9;border:1px dashed #c8dee0;border-radius:10px;padding:10px 14px;margin-bottom:16px;line-height:1.5}
.pyn-help b{color:var(--teal-dark)}
.pyn-group{border:1px solid var(--line);border-radius:12px;padding:14px 16px 16px;margin-bottom:16px;background:linear-gradient(180deg,#fafcfc,#fff)}
.pyn-group-head{display:flex;align-items:center;gap:9px;margin-bottom:12px}
.pyn-group-head>svg{width:16px;height:16px;color:var(--teal);flex:0 0 auto}
.pyn-gtitle{flex:1;min-width:0;font-family:'Plus Jakarta Sans',sans-serif;font-weight:800;font-size:12px;color:var(--teal-dark);border:1px solid var(--line);border-radius:8px;padding:8px 11px;background:#fff}
.pyn-count{flex:0 0 auto;font-size:9.5px;font-weight:700;color:var(--muted);background:#eef5f5;padding:3px 9px;border-radius:20px;white-space:nowrap}
.pyn-gdel{flex:0 0 auto;border:none;background:#fbe0e0;color:var(--red-dark);border-radius:8px;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}
.pyn-gdel:hover{background:#f6c9c9}.pyn-gdel svg{width:14px;height:14px}
.pyn-fields{display:flex;flex-direction:column;gap:8px}
.pyn-field{background:#fff;border:1px solid var(--line);border-radius:9px;padding:8px 10px}
.pyn-frow{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pyn-label{flex:1 1 220px;min-width:150px;font-size:11px;font-weight:600;border:1px solid var(--line);border-radius:7px;padding:7px 10px}
.pyn-width{flex:0 0 auto;font-size:10.5px;border:1px solid var(--line);border-radius:7px;padding:7px 8px;background:#fff}
.pyn-typesel{flex:0 0 auto;font-size:10.5px;border:1px solid var(--line);border-radius:7px;padding:7px 8px;background:#fff}
.pyn-type{flex:0 0 auto;font-size:9.5px;font-weight:700;color:var(--teal-dark);background:var(--teal-soft);padding:4px 9px;border-radius:20px;white-space:nowrap}
.pyn-opts{flex:1 1 180px;min-width:140px;font-size:10.5px;border:1px solid var(--line);border-radius:7px;padding:7px 10px}
.pyn-custom-badge{flex:0 0 auto;font-size:9px;font-weight:700;color:#7a5300;background:#fff4dc;border:1px solid #f2d38a;padding:3px 8px;border-radius:20px}
.pyn-del{flex:0 0 auto;border:none;background:#fbe0e0;color:var(--red-dark);border-radius:7px;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}
.pyn-del:hover{background:#f6c9c9}.pyn-del svg{width:15px;height:15px}
.pyn-lock{flex:0 0 auto;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted);font-size:13px}
.pyn-add{margin-top:10px;border:1px dashed var(--teal);background:var(--teal-soft);color:var(--teal-dark);border-radius:8px;padding:8px 14px;font-size:10.5px;font-weight:700;display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif}
.pyn-add:hover{background:#d3ebec}.pyn-add svg{width:14px;height:14px}
.pyn-toolbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px}
.pyn-tool{border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 14px;font-size:10.5px;font-weight:700;display:inline-flex;align-items:center;gap:6px;cursor:pointer;color:var(--ink);font-family:'Plus Jakarta Sans',sans-serif}
.pyn-tool:hover{border-color:var(--teal);color:var(--teal)}.pyn-tool svg{width:14px;height:14px}
/* ==== Penyesuaian: kontrol kolom bidang, lebar px, drag & drop ==== */
.pyn-cols{flex:0 0 auto;display:flex;align-items:center;gap:6px;font-size:9.5px;font-weight:700;color:var(--muted)}
.pyn-cols select{font-size:10.5px;border:1px solid var(--line);border-radius:7px;padding:6px 8px;background:#fff;font-weight:700;color:var(--ink)}
.pyn-grip{flex:0 0 auto;width:26px;height:30px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted);cursor:grab;border-radius:6px}
.pyn-grip:hover{background:#eef5f5;color:var(--teal-dark)}
.pyn-grip:active{cursor:grabbing}
.pyn-grip svg{width:15px;height:15px;pointer-events:none}
.pyn-pxwrap{flex:0 0 auto;display:flex;align-items:center;gap:5px;font-size:9.5px;font-weight:700;color:var(--muted);white-space:nowrap}
.pyn-pxw{width:74px;font-size:10.5px;border:1px solid var(--line);border-radius:7px;padding:7px 8px;text-align:right}
.pyn-pxw::placeholder{color:#b6c4cb;font-weight:500}
.pyn-field.dragging{opacity:.45;border-color:var(--teal);border-style:dashed;background:var(--teal-soft)}
.pyn-fields.drag-over{outline:2px dashed var(--teal);outline-offset:2px;border-radius:9px}
.pyn-field.drop-before{box-shadow:0 -3px 0 0 var(--teal)}
.pyn-field.drop-after{box-shadow:0 3px 0 0 var(--teal)}
.pyn-fields.empty-drop{min-height:44px;border:1px dashed var(--line);border-radius:9px;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:10px}
.pyn-fields.empty-drop::after{content:"Tarik field ke sini"}

/* mode banner */
.mode-banner{display:flex;align-items:center;gap:10px;background:var(--teal-soft);color:var(--teal-dark);border:1px solid #bfe0e2;border-radius:10px;padding:10px 16px;font-size:11px;font-weight:600;margin-bottom:18px}
/* Banner "Mode Ubah Data" (ikon + teks) dihilangkan pada mode edit */
#edit-banner,#edit-banner-pl,#edit-banner-tender{display:none!important}

/* upload box */
/* Bar tombol Template: container ringkas & cantik yang membungkus kedua tombol saja */
.io-row{display:flex;gap:12px;flex-wrap:wrap;align-items:center;justify-content:flex-end;margin:0 0 16px 0;width:auto;max-width:100%;
  background:linear-gradient(135deg,#f4fbfb 0%,#eaf6f7 55%,#f6fbf3 100%);
  border:1px solid #d3e7e9;border-radius:16px;padding:12px 14px;
  box-shadow:0 1px 2px rgba(16,40,50,.05),0 10px 26px rgba(14,124,134,.10),inset 0 1px 0 rgba(255,255,255,.7)}
/* Sembunyikan ikon & label "Template Pengisian Data" — sisakan tombol saja */
.io-row>svg{display:none}
.io-row .io-txt{display:none}

/* ---------- Modal ---------- */
.overlay{position:fixed;inset:0;background:radial-gradient(1200px 600px at 50% -10%,rgba(14,124,134,.28),rgba(16,36,44,.55) 60%);display:none;align-items:center;justify-content:center;z-index:100;padding:20px;backdrop-filter:blur(6px) saturate(1.05);-webkit-backdrop-filter:blur(6px) saturate(1.05)}
.overlay.show{display:flex;animation:ovFade .28s ease}
@keyframes ovFade{from{opacity:0}to{opacity:1}}
.modal{position:relative;background:linear-gradient(180deg,#ffffff,#fbfdfe);border-radius:20px;max-width:440px;width:100%;box-shadow:0 30px 80px rgba(9,63,69,.34),0 6px 22px rgba(9,63,69,.18),inset 0 0 0 1px rgba(255,255,255,.7);overflow:hidden;animation:pop .42s cubic-bezier(.16,1,.3,1)}
.modal::before{content:"";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--yellow),var(--cyan),var(--teal),var(--yellow));background-size:200% 100%;animation:sheenH 6s linear infinite}
@keyframes pop{0%{transform:scale(.9) translateY(14px);opacity:0}60%{transform:scale(1.012) translateY(0);opacity:1}100%{transform:scale(1) translateY(0);opacity:1}}
.modal-icon{width:64px;height:64px;border-radius:50%;display:grid;place-items:center;margin:28px auto 0;position:relative;box-shadow:0 8px 22px rgba(16,40,50,.14),inset 0 0 0 1px rgba(255,255,255,.6);animation:iconPop .5s .1s both cubic-bezier(.16,1,.3,1)}
.modal-icon::after{content:"";position:absolute;inset:-6px;border-radius:50%;border:2px solid var(--teal);opacity:.12;animation:iconRing 1.8s ease-out infinite}
@keyframes iconPop{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes iconRing{0%{transform:scale(.85);opacity:.35}70%{opacity:0}100%{transform:scale(1.35);opacity:0}}
/* Field pada modal Ganti Kata Sandi */
.cp-field{text-align:left;margin-bottom:12px}
.cp-field label{display:block;font-size:11px;font-weight:700;color:var(--ink);margin-bottom:6px;letter-spacing:.2px}
.cp-field input{width:100%;border:1px solid var(--line);border-radius:11px;padding:11px 13px;font-family:'Plus Jakarta Sans';font-size:13px;color:var(--ink);background:#fff;transition:border-color .18s,box-shadow .18s}
.cp-field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 4px rgba(14,124,134,.14)}
.bk-field{text-align:left;margin-bottom:12px}
.bk-field label{display:block;font-size:11px;font-weight:700;color:var(--ink);margin-bottom:6px;letter-spacing:.2px}
.bk-field select{width:100%;border:1px solid var(--line);border-radius:11px;padding:11px 13px;font-family:'Plus Jakarta Sans';font-size:13px;color:var(--ink);background:#fff;transition:border-color .18s,box-shadow .18s;cursor:pointer}
.bk-field select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 4px rgba(14,124,134,.14)}
.modal-icon svg{width:30px;height:30px}
.modal-body{padding:20px 32px 8px;text-align:center;animation:fade .4s .12s both}
.modal-body h3{font-family:'Plus Jakarta Sans',sans-serif;font-size:21px;font-weight:800;letter-spacing:-.4px;line-height:1.2;margin-bottom:10px;color:var(--teal-dark);background:linear-gradient(120deg,var(--teal-dark),var(--teal) 55%,var(--cyan));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.modal-body p{font-family:'Plus Jakarta Sans',sans-serif;color:#5a6b76;font-size:13.5px;line-height:1.7;letter-spacing:.1px;max-width:32ch;margin:0 auto;font-weight:450;text-wrap:balance}
.modal-body p b,.modal-body p strong{color:var(--ink);font-weight:700}
.modal-actions{display:flex;gap:12px;padding:22px 30px 30px;animation:fade .4s .18s both}
.modal-actions .btn{flex:1;justify-content:center;padding:13px;border-radius:12px;font-family:'Plus Jakarta Sans',sans-serif;font-size:13.5px;font-weight:700;letter-spacing:.3px;transition:transform .14s ease,box-shadow .18s ease,filter .18s ease}
.modal-actions .btn:hover{transform:translateY(-1px);filter:brightness(1.03)}
.modal-actions .btn:active{transform:translateY(0) scale(.99)}
/* Konfirmasi (Hapus/Simpan/Keluar/Batalkan): dua opsi teks kecil di kanan bawah —
   Ya (hijau) dan Tidak (merah). */
/* KOTAK KONFIRMASI SELALU PALING DEPAN (7 Agu 2026).
   `.overlay` ber-z-index 100, sedangkan konfirmasi ini justru paling sering
   dipanggil DARI DALAM panel lain yang jauh lebih tinggi — Kelola Akun (6000),
   Pustaka Klausul & Profil (9999), editor klausul (10000). Akibatnya "Reset
   Kata Sandi" terbit di BELAKANG panel Kelola Akun: pertanyaannya tidak
   terlihat, tombol Ya/Batal tidak terjangkau, dan alurnya buntu.
   Nilainya sengaja di atas seluruh lapisan yang ada: kotak konfirmasi tidak
   pernah menjadi latar bagi apa pun — ia selalu langkah terakhir yang menunggu
   jawaban. */
#confirm-overlay{ z-index:10050; }
#confirm-overlay .modal-actions{justify-content:flex-end;gap:10px;padding:14px 26px 22px}
#confirm-overlay .modal-actions .btn.cf-icon{flex:0 0 auto;min-width:0;width:auto;padding:7px 16px;border-radius:9px;font-size:12px;font-weight:700;letter-spacing:.3px}

/* detail modal */
.modal.wide{max-width:720px}
.detail-head{background:linear-gradient(100deg,var(--teal-dark),var(--teal));color:#fff;padding:20px 26px;display:flex;justify-content:space-between;align-items:center}
.detail-head h3{font-family:'Plus Jakarta Sans',sans-serif;font-size:15.5px;font-weight:800;letter-spacing:.2px}
/* ============================================================================
   TOMBOL TUTUP BAKU SELURUH POP-UP                                — 8 Agu 2026
   ----------------------------------------------------------------------------
   Bentuknya DISAMAKAN dengan tombol tutup pada pemilih Dokumen TOR/KAK
   (`.tor-dk-hd .x`, disuntikkan torEnsureStyle() di susun-dokumen.js):
   keping merah bergradasi 32x32, sudut 9px, ikon silang SVG putih 15px.

   Kenapa MERAH, bukan kotak putih transparan seperti sebelumnya: di seluruh
   aplikasi merah sudah berarti "mengakhiri" (tombol Hapus di tabel, tombol
   Batal, tombol tutup pratinjau). Kotak putih .2 di atas kepala teal nyaris
   tidak terlihat — itulah yang membuat tombol tutup mudah terlewat, dan
   sekarang menjadi SATU-SATUNYA jalan keluar dari pop-up (klik di latar tidak
   lagi menutup, lihat pasangTolakTutup di app.js). Jalan keluar tunggal wajib
   mencolok.

   Kenapa ikonnya SVG, bukan karakter &times;: sisi kosong &times; berbeda-beda
   menurut muka huruf sehingga silangnya tidak pernah benar-benar di tengah
   kotak. `font-size:0` tetap dipasang sebagai jaring pengaman — kalau kelak
   ada tombol baru yang masih memakai &times;, karakternya tersembunyi dan
   yang tampak hanya keping merahnya (bukan silang melenceng).      */
.detail-close{
  -webkit-appearance:none;appearance:none;
  flex:0 0 32px;width:32px;height:32px;min-width:32px;min-height:32px;
  padding:0;border:0;border-radius:9px;line-height:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  font-size:0;
  background:linear-gradient(135deg,#D33A3A,#e25151);color:#fff;
  box-shadow:0 2px 6px rgba(6,30,36,.30);
  transition:filter .15s ease,box-shadow .2s ease}
/* Warna ikon diwarisi dari tombolnya lewat currentColor — satu-satunya tempat
   warna ditentukan adalah properti `color` di atas. */
.detail-close svg{width:15px;height:15px;display:block;
  stroke:currentColor;fill:none;stroke-width:2}
.detail-close:hover{filter:brightness(1.08);box-shadow:0 4px 10px rgba(6,30,36,.36)}
.detail-close:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* KEPALA MERAH -> KEPING DIBALIK.
   Pop-up "Hasil Unggah Template" mewarnai kepalanya menurut hasil: hijau
   (semua masuk), kuning (sebagian), MERAH (tidak ada yang masuk). Keping merah
   di atas kepala merah praktis lenyap. Pelajaran yang sama sudah didapat saat
   menggarap pop-up TOR/KAK: warna yang bagus di atas satu latar belum tentu
   bagus di atas latar lain. Maka pada kepala merah keping & ikonnya ditukar —
   keping putih, ikon merah. Bahasa warnanya tetap sama. */
.detail-head.tone-err .detail-close{
  background:#fff;color:#D33A3A;box-shadow:0 2px 6px rgba(6,30,36,.22)}
.detail-body{padding:18px 26px 26px;max-height:66vh;overflow-y:auto;background:#f6f9fa}
/* #5: setiap kelompok tampil sebagai tabel ber-border; judul = header ter-mark */
.detail-group{margin-bottom:18px;border-radius:12px;box-shadow:0 3px 12px rgba(16,40,50,.06);overflow:hidden}
.detail-group:last-child{margin-bottom:0}
.detail-grp-title{font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;color:#fff;
  margin:0;padding:12px 16px;text-transform:uppercase;letter-spacing:.6px;
  background:linear-gradient(100deg,var(--teal-dark),var(--teal));
  border:1px solid var(--teal-dark);border-bottom:none;
  display:flex;align-items:center;gap:9px}
.detail-grp-title::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--yellow);box-shadow:0 0 0 3px rgba(246,180,14,.28)}
/* Baris data: sel label & sel nilai, ber-border seperti tabel */
.detail-row{display:grid;grid-template-columns:250px 1fr;gap:0;font-size:11.5px;
  border-left:1px solid #d8e4e7;border-right:1px solid #d8e4e7;border-bottom:1px solid #d8e4e7;background:#fff}
.detail-row .dk{color:var(--teal-dark);font-weight:700;padding:10px 16px;
  background:linear-gradient(180deg,#f2f8f9,#eaf3f4);border-right:1px solid #d8e4e7;
  display:flex;align-items:center}
.detail-row .dv{font-weight:500;color:var(--ink);padding:10px 16px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:0;word-break:break-word}
.detail-row .dv .stack-line{width:100%}
/* Penomoran (1. 2. 3.) pada baris detail disamakan dengan teks nilai di sebelah kanannya
   (warna, ketebalan, dan ukuran mengikuti .dv). Penomoran di tabel monitoring tidak terpengaruh. */
.detail-row .dv .stack-no{color:var(--ink);font-weight:500;font-size:inherit}
.detail-row:nth-of-type(odd) .dv{background:#fbfdfd}
/* Baris penanda "Penyedia N" pada Tender */
.detail-row.detail-penyedia{grid-template-columns:1fr}
.detail-row.detail-penyedia .dk{background:linear-gradient(90deg,var(--teal-soft),#eef7f8);color:var(--teal-dark);font-weight:800;border-right:none;letter-spacing:.4px;text-transform:uppercase;font-size:10px}
.detail-row.detail-penyedia .dv{display:none}

/* toast */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(120px);background:var(--ink);color:#fff;padding:13px 22px;border-radius:12px;font-family:'Plus Jakarta Sans',sans-serif;font-weight:700;font-size:12px;letter-spacing:.2px;box-shadow:0 10px 30px rgba(0,0,0,.25);z-index:200;transition:transform .3s;display:flex;align-items:center;gap:9px}
.toast.toast-ok{background:linear-gradient(135deg,#1a9152,#25b566);box-shadow:0 12px 30px rgba(30,158,90,.4)}
.toast.toast-warn{background:linear-gradient(135deg,#c4870a,#e0a413);box-shadow:0 12px 30px rgba(214,150,10,.4)}
.toast.toast-err{background:linear-gradient(135deg,#c62f2f,#e04b4b);box-shadow:0 12px 30px rgba(211,58,58,.42)}
.toast.show{transform:translateX(-50%) translateY(0)}
.toast svg{width:18px;height:18px;flex:0 0 auto}
/* Pesan lebih dari satu baris (mis. hasil unggah template): tiap kalimat
   turun ke barisnya sendiri, ikon disejajarkan dengan baris PERTAMA dan
   antar baris diberi sedikit jarak agar mudah dibaca. */
.toast.toast-multi{align-items:flex-start}
.toast.toast-multi svg{margin-top:1px}
.toast.toast-multi span{line-height:1.55}

@media(max-width:980px){
  .cards{grid-template-columns:repeat(2,1fr)}
  .form-grid{grid-template-columns:1fr 1fr}
  .split{grid-template-columns:1fr}
}
@media(max-width:900px){
  .sidebar{position:fixed;left:0;top:0;transform:translateX(-100%);transition:transform .28s ease;box-shadow:0 0 50px rgba(0,0,0,.45)}
  .sidebar.open{transform:translateX(0)}
  .sidebar-overlay{display:block;position:fixed;inset:0;background:rgba(7,40,44,.5);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .25s;z-index:45}
  .sidebar-overlay.show{opacity:1;visibility:visible;pointer-events:auto}
  .mobile-topbar{display:flex;align-items:center;gap:12px;padding:11px 16px;background:linear-gradient(115deg,#073f45,var(--teal));color:#fff;position:sticky;top:0;z-index:50;box-shadow:0 4px 16px rgba(7,63,69,.25)}
  .mobile-topbar .brand h1{font-size:12px}
  .mobile-topbar .brand span{font-size:8.5px}
  .hamburger{appearance:none;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);color:#fff;width:38px;height:38px;flex:0 0 38px;border-radius:10px;display:grid;place-items:center;cursor:pointer}
  .hamburger svg{width:20px;height:20px}
}
@media(max-width:640px){
  .cards{grid-template-columns:1fr}
  .form-grid{grid-template-columns:1fr}
  .grid-kr{grid-template-columns:1fr}
  .field.col-2,.field.col-3{grid-column:span 1}
  .brand h1{font-size:12px}
  .detail-row{grid-template-columns:1fr}
  .table-wrap{max-height:calc(100vh - 200px);min-height:260px}
}
/* ---------- Animasi Logout ---------- */
.logout-anim{position:fixed;inset:0;z-index:400;display:none;align-items:center;justify-content:center;color:#fff;overflow:hidden;
  background:
    radial-gradient(900px 500px at 85% -10%, rgba(22,169,181,.35), transparent 60%),
    radial-gradient(700px 480px at -8% 8%, rgba(246,180,14,.18), transparent 55%),
    linear-gradient(135deg,#073f45,#095e66 45%,#0E7C86 100%);}
.logout-anim.show{display:flex;animation:loIn .42s ease}
.logout-anim.fade-out{animation:loOut .45s ease forwards}
@keyframes loIn{from{opacity:0}to{opacity:1}}
@keyframes loOut{to{opacity:0}}
.logout-anim::before{content:"";position:absolute;inset:0;opacity:.5;background-image:radial-gradient(rgba(255,255,255,.10) 1px,transparent 1px);background-size:22px 22px;pointer-events:none}
.logout-anim::after{content:"";position:absolute;width:520px;height:520px;border-radius:50%;background:radial-gradient(circle,rgba(255,255,255,.10),transparent 62%);animation:loRipple 2.4s ease-out infinite}
@keyframes loRipple{0%{transform:scale(.35);opacity:.55}70%{opacity:0}100%{transform:scale(1.35);opacity:0}}

.lo-box{position:relative;display:flex;flex-direction:column;align-items:center;gap:22px;text-align:center;animation:loRise .55s cubic-bezier(.2,.85,.25,1) both}
@keyframes loRise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
.lo-ring{position:relative;width:124px;height:124px;display:grid;place-items:center}
.lo-spin{position:absolute;inset:0;width:124px;height:124px;animation:rl-rotate 1.05s cubic-bezier(.6,.15,.4,.85) infinite;filter:drop-shadow(0 0 8px rgba(246,180,14,.35))}
.lo-spin circle{fill:none;stroke:rgba(255,255,255,.16);stroke-width:4}
.lo-spin .lo-arc{stroke:var(--yellow);stroke-linecap:round;stroke-dasharray:72 220}
.lo-ring::before{content:"";position:absolute;inset:14px;border-radius:50%;border:2px solid transparent;
  border-top-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.22);
  animation:rl-rotate 1.7s linear infinite reverse}
.lo-badge{width:80px;height:80px;border-radius:50%;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.32);display:grid;place-items:center;box-shadow:0 12px 34px rgba(0,0,0,.32),inset 0 0 0 1px rgba(255,255,255,.12);animation:loPop .55s cubic-bezier(.2,.9,.3,1.35) both,loBadgeGlow 2s ease-in-out infinite}
@keyframes loPop{from{transform:scale(.35);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes loBadgeGlow{0%,100%{box-shadow:0 12px 34px rgba(0,0,0,.32),inset 0 0 0 1px rgba(255,255,255,.12),0 0 0 0 rgba(255,255,255,.12)}50%{box-shadow:0 12px 40px rgba(0,0,0,.36),inset 0 0 0 1px rgba(255,255,255,.2),0 0 0 10px rgba(255,255,255,.05)}}
.lo-badge svg{width:38px;height:38px;color:#fff;animation:loWave 1.5s ease-in-out infinite}
@keyframes loWave{0%,100%{transform:translateX(0)}50%{transform:translateX(4px)}}
.lo-title{font-family:'Plus Jakarta Sans';font-weight:800;font-size:19px;letter-spacing:.4px}
.lo-sub{font-size:11.5px;opacity:.85;letter-spacing:2px;text-transform:uppercase;font-weight:600;margin-top:5px}
.lo-dots::after{content:'';animation:rl-dots 1.4s steps(4,end) infinite}

/* ---------- Animasi Login — KEMBAR PERSIS DENGAN ANIMASI LOGOUT ----------
   KETENTUAN 8 Agu 2026: "animasi saat keluar sangat bagus, harusnya animasi
   saat login persis seperti itu tapi dengan arah panah kebalikan".

   Sebelumnya keduanya hanya MIRIP: login memakai latar yang sedikit lebih
   terang, animasi masuk berskala (liIn/liOut), lencana petir yang berganti
   menjadi centang, judul bergradasi berkilau, dan enam percikan yang melayang.
   Logout tidak punya satu pun dari itu. Hasilnya dua momen yang seharusnya
   berpasangan justru terasa berasal dari dua aplikasi berbeda.

   Sekarang seluruh nilainya disamakan dengan .logout-anim; yang membedakan
   HANYA ikon di dalam lencana (lihat markup di index.html) — pintu di kanan
   dengan panah masuk, cermin dari pintu di kiri dengan panah keluar.
   Aturan .li-* (percikan, petir/centang, judul berkilau) DIHAPUS karena tidak
   ada lagi elemen yang memakainya. z-index tetap 410 supaya lapisan masuk
   selalu di atas lapisan keluar bila keduanya sempat bertumpuk. */
.login-anim{position:fixed;inset:0;z-index:410;display:none;align-items:center;justify-content:center;color:#fff;overflow:hidden;
  background:
    radial-gradient(900px 500px at 85% -10%, rgba(22,169,181,.35), transparent 60%),
    radial-gradient(700px 480px at -8% 8%, rgba(246,180,14,.18), transparent 55%),
    linear-gradient(135deg,#073f45,#095e66 45%,#0E7C86 100%);}
.login-anim.show{display:flex;animation:loIn .42s ease}
.login-anim.fade-out{animation:loOut .45s ease forwards}
.login-anim::before{content:"";position:absolute;inset:0;opacity:.5;background-image:radial-gradient(rgba(255,255,255,.10) 1px,transparent 1px);background-size:22px 22px;pointer-events:none}
.login-anim::after{content:"";position:absolute;width:520px;height:520px;border-radius:50%;background:radial-gradient(circle,rgba(255,255,255,.10),transparent 62%);animation:loRipple 2.4s ease-out infinite}


/* ---------- Route Loader (transisi antar menu) — elegan ---------- */
.route-loader{position:fixed;inset:0;z-index:120;display:flex;align-items:center;justify-content:center;
  background:radial-gradient(600px 400px at 50% 45%, rgba(227,242,243,.72), rgba(238,244,246,.9));
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .32s ease}
.route-loader.show{opacity:1;visibility:visible;pointer-events:auto;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.route-loader.show .rl-box{animation:rl-in .4s cubic-bezier(.2,.85,.25,1) both}
@keyframes rl-in{from{opacity:0;transform:translateY(10px) scale(.94)}to{opacity:1;transform:none}}
.rl-box{display:flex;flex-direction:column;align-items:center;gap:22px}
.rl-spin{position:relative;width:96px;height:96px;display:grid;place-items:center}

/* Cincin orbit ganda dengan busur gradien */
.rl-orbit{position:absolute;border-radius:50%;border-style:solid;border-color:transparent}
.rl-orbit-1{inset:0;border-width:3px;border-top-color:var(--teal);border-right-color:var(--cyan);
  animation:rl-rotate 1.15s cubic-bezier(.6,.15,.4,.85) infinite;
  filter:drop-shadow(0 0 6px rgba(22,169,181,.35))}
.rl-orbit-2{inset:13px;border-width:3px;border-bottom-color:var(--yellow);border-left-color:#ffd35a;
  animation:rl-rotate 1.5s linear infinite reverse;opacity:.9}
.rl-orbit-3{inset:26px;border-width:2px;border-top-color:rgba(14,124,134,.35);border-right-color:rgba(22,169,181,.25);
  animation:rl-rotate 2.1s linear infinite}

/* Titik-titik yang mengorbit */
.rl-dot{position:absolute;top:50%;left:50%;width:96px;height:96px;margin:-48px 0 0 -48px;animation:rl-rotate 1.6s linear infinite}
.rl-dot::before{content:"";position:absolute;top:-3px;left:50%;width:7px;height:7px;margin-left:-3.5px;border-radius:50%;
  background:var(--teal);box-shadow:0 0 8px 1px rgba(22,169,181,.6)}
.rl-dot-1{animation-duration:1.6s}
.rl-dot-2{animation-duration:1.6s;animation-delay:-.53s}
.rl-dot-2::before{background:var(--yellow);box-shadow:0 0 8px 1px rgba(246,180,14,.6)}
.rl-dot-3{animation-duration:1.6s;animation-delay:-1.06s}
.rl-dot-3::before{background:var(--cyan);box-shadow:0 0 8px 1px rgba(92,195,255,.55)}

/* Inti logo yang berdenyut lembut */
.rl-core{position:relative;width:46px;height:46px;border-radius:15px;display:grid;place-items:center;
  background:linear-gradient(160deg,#ffffff,#eaf6f7);
  box-shadow:0 8px 20px rgba(9,94,102,.22),inset 0 0 0 1px rgba(255,255,255,.8);
  animation:rl-breathe 1.6s ease-in-out infinite}
.rl-core::after{content:"";position:absolute;inset:-6px;border-radius:20px;
  background:radial-gradient(circle,rgba(22,169,181,.28),transparent 70%);opacity:.7;
  animation:rl-glow 1.6s ease-in-out infinite;z-index:-1}
@keyframes rl-breathe{0%,100%{transform:scale(.94)}50%{transform:scale(1.06)}}
@keyframes rl-glow{0%,100%{opacity:.4;transform:scale(.9)}50%{opacity:.85;transform:scale(1.15)}}
.rl-bolt{width:24px;height:26px}
.rl-bolt path{fill:var(--yellow);stroke:var(--teal);stroke-width:1.2;stroke-linejoin:round}

.rl-text{font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;letter-spacing:3px;text-transform:uppercase;
  background:linear-gradient(90deg,var(--teal-dark),var(--cyan),var(--teal-dark));background-size:200% 100%;
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;
  animation:rl-sheen 2s linear infinite}
@keyframes rl-sheen{to{background-position:200% 0}}
.rl-text::after{content:'';animation:rl-dots 1.4s steps(4,end) infinite;-webkit-text-fill-color:var(--teal-dark)}
@keyframes rl-rotate{to{transform:rotate(360deg)}}
@keyframes rl-dots{0%{content:''}25%{content:'.'}50%{content:'..'}75%{content:'...'}}
/* Reveal halus baris tabel saat data (halaman baru) selesai dimuat */
tbody.tbody-reveal>tr{animation:rowReveal .5s cubic-bezier(.16,1,.3,1) both}
tbody.tbody-reveal>tr:nth-child(1){animation-delay:.02s}
tbody.tbody-reveal>tr:nth-child(2){animation-delay:.05s}
tbody.tbody-reveal>tr:nth-child(3){animation-delay:.08s}
tbody.tbody-reveal>tr:nth-child(4){animation-delay:.11s}
tbody.tbody-reveal>tr:nth-child(5){animation-delay:.14s}
tbody.tbody-reveal>tr:nth-child(6){animation-delay:.17s}
tbody.tbody-reveal>tr:nth-child(7){animation-delay:.20s}
tbody.tbody-reveal>tr:nth-child(8){animation-delay:.23s}
tbody.tbody-reveal>tr:nth-child(9){animation-delay:.26s}
tbody.tbody-reveal>tr:nth-child(10){animation-delay:.29s}
@keyframes rowReveal{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important}
}

/* ---------- Topbar user / logout ---------- */
.sidebar-user{margin-top:auto;padding:14px 16px 18px;border-top:1px solid rgba(255,255,255,.12);display:flex;flex-direction:column;align-items:stretch;gap:10px}
.user-chip{display:flex;align-items:center;gap:8px;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);padding:8px 13px;border-radius:30px;font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;color:#fff}
.logout-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.25);color:#fff;font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;padding:9px 13px;border-radius:10px;cursor:pointer;transition:background .2s,transform .15s}
.logout-btn svg{width:15px;height:15px}
.logout-btn:hover{background:rgba(255,255,255,.24);transform:translateY(-1px)}

/* ---------- Login screen (elegan) ---------- */
.login-screen{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:24px;overflow:auto;
  background:
    radial-gradient(1100px 620px at 82% -14%, rgba(22,169,181,.42), transparent 58%),
    radial-gradient(820px 560px at -10% 12%, rgba(246,180,14,.20), transparent 55%),
    radial-gradient(700px 700px at 50% 120%, rgba(30,158,90,.16), transparent 60%),
    linear-gradient(135deg,#052f34,#073f45 34%,#095e66 68%,#0E7C86 100%);}
/* butiran halus */
.login-screen::before{content:"";position:absolute;inset:0;opacity:.45;
  background-image:radial-gradient(rgba(255,255,255,.09) 1px,transparent 1px);background-size:24px 24px;
  mask-image:radial-gradient(circle at 50% 42%, #000 30%, transparent 78%);
  -webkit-mask-image:radial-gradient(circle at 50% 42%, #000 30%, transparent 78%);pointer-events:none}
/* orb mengambang */
.login-orbs{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.login-orbs span{position:absolute;border-radius:50%;filter:blur(2px);opacity:.55;mix-blend-mode:screen;animation:orbFloat 16s ease-in-out infinite}
.login-orbs span:nth-child(1){width:230px;height:230px;left:-60px;top:14%;background:radial-gradient(circle,rgba(22,169,181,.55),transparent 68%);animation-duration:19s}
.login-orbs span:nth-child(2){width:180px;height:180px;right:-40px;top:8%;background:radial-gradient(circle,rgba(246,180,14,.42),transparent 68%);animation-duration:22s;animation-delay:-4s}
.login-orbs span:nth-child(3){width:300px;height:300px;right:6%;bottom:-120px;background:radial-gradient(circle,rgba(30,158,90,.38),transparent 68%);animation-duration:26s;animation-delay:-8s}
.login-orbs span:nth-child(4){width:150px;height:150px;left:16%;bottom:-40px;background:radial-gradient(circle,rgba(92,195,255,.34),transparent 68%);animation-duration:20s;animation-delay:-2s}
@keyframes orbFloat{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(18px,-26px) scale(1.08)}}
@media (prefers-reduced-motion:reduce){.login-orbs span{animation:none}}

/* Kartu: dua panel (brand + form) */
.login-card{position:relative;z-index:2;width:100%;max-width:840px;display:grid;grid-template-columns:1.02fr 1fr;
  background:rgba(255,255,255,.14);border-radius:26px;overflow:hidden;
  box-shadow:0 40px 100px rgba(2,26,29,.55),0 8px 30px rgba(2,26,29,.35),inset 0 0 0 1px rgba(255,255,255,.22);
  backdrop-filter:blur(22px) saturate(140%);-webkit-backdrop-filter:blur(22px) saturate(140%);
  animation:loginZoomOut .85s cubic-bezier(.16,1,.3,1) both}
/* Efek zoom-out: kartu login muncul dari ukuran kecil lalu membesar perlahan ke ukuran normal.
   Class .replay dipakai untuk memicu ulang animasi (mis. setelah logout). */

/* ============================================================================
   NOMOR VERSI DI LAYAR MASUK (12 Agu 2026)
   ----------------------------------------------------------------------------
   Ditempel pada .login-card yang sudah position:relative, jadi ia tetap di
   pojok kartu — bukan di pojok LAYAR — dan ikut miring bersama kartunya saat
   login-tilt bekerja.

   z-index:3 dengan sengaja: .login-card memberi anak-anaknya z-index 2, dan
   pada nilai yang sama panel kanan akan menutupi nomor ini di layar sempit.

   pointer-events:none — ia sekadar keterangan. Tanpa ini, sudut kanan atas
   kartu berhenti bisa diseret untuk memiringkan tampilan, dan tidak ada yang
   akan menduga penyebabnya adalah tulisan sekecil ini.
   ============================================================================ */
.login-ver{position:absolute;top:13px;right:16px;z-index:3;pointer-events:none;
  font-size:9.5px;font-weight:800;letter-spacing:1.1px;text-transform:uppercase;
  /* Keping BERLATAR SENDIRI, bukan tembus pandang.
     Pojok kanan atas kartu ditempati panel kanan yang PUTIH pada layar lebar,
     tetapi berpindah ke panel kiri yang TEAL saat kartunya menumpuk di layar
     sempit. Teks putih tembus pandang terbaca di satu keadaan dan lenyap di
     keadaan lain — persis yang terjadi pada rancangan pertama keping ini.
     Latar terang + tulisan teal terbaca di KEDUANYA. */
  color:#0b5c63;background:#eaf4f5;
  border:1px solid rgba(14,124,134,.22);border-radius:20px;padding:4px 11px;
  box-shadow:0 2px 6px rgba(6,40,44,.10);
  font-variant-numeric:tabular-nums;user-select:none}
@media (max-width:700px){
  .login-ver{top:10px;right:12px;font-size:9px;padding:3px 9px;letter-spacing:1px}
}
.login-card.replay{animation:none}
.login-card.replay.go{animation:loginZoomOut .85s cubic-bezier(.16,1,.3,1) both}
@keyframes loginZoomOut{
  0%{opacity:0;transform:scale(.55)}
  60%{opacity:1}
  100%{opacity:1;transform:scale(1)}
}
@media (prefers-reduced-motion:reduce){
  .login-card,.login-card.replay.go{animation:loginFadeOnly .4s ease both}
}
@keyframes loginFadeOnly{from{opacity:0}to{opacity:1}}

/* ---------- Efek 3D interaktif kartu login ----------
   Kartu memiringkan diri mengikuti kursor (parallax perspektif) + kilau yang
   mengikuti arah cahaya + float 3D lembut saat idle. Transform tilt diberikan ke
   pembungkus .login-tilt (via JS) supaya TIDAK bentrok dengan animasi masuk
   (loginZoomOut) yang tetap berjalan pada .login-card di dalamnya. */
.login-screen{perspective:1600px;perspective-origin:50% 42%}
.login-tilt{position:relative;z-index:2;width:100%;max-width:840px;transform-style:preserve-3d;will-change:transform}
.login-tilt .login-card{width:100%;max-width:none;z-index:auto}
/* Kilau (glare) yang bergerak mengikuti kursor — tampak menonjol di panel gelap */
.login-card::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:4;
  background:radial-gradient(440px circle at var(--gx,50%) var(--gy,38%),rgba(255,255,255,.22),rgba(255,255,255,.06) 32%,transparent 62%);
  opacity:0;transition:opacity .45s ease;mix-blend-mode:screen}
.login-tilt.is-hot .login-card::after{opacity:1}
@media (prefers-reduced-motion:reduce){
  .login-tilt{transform:none!important}
  .login-card::after{display:none}
}
@media(max-width:760px){ .login-tilt{max-width:430px} }

/* ---- Panel kiri: branding ----
   Padding & jarak dirapatkan setelah tombol "Masuk sebagai Tamu" dihapus.
   Tinggi kartu ditentukan panel yang paling tinggi; karena panel form kini
   satu tombol lebih pendek, panel kiri ikut dirapatkan supaya tinggi kartu
   benar-benar menurun dan tetap seimbang antara kedua sisi. */
.login-brandside{position:relative;padding:38px 36px;color:#eafafb;display:flex;flex-direction:column;justify-content:space-between;
  background:
    radial-gradient(520px 320px at 12% 0%, rgba(22,169,181,.55), transparent 62%),
    linear-gradient(158deg,rgba(7,63,69,.92),rgba(9,94,102,.88) 55%,rgba(14,124,134,.86));
  overflow:hidden}
.login-brandside::after{content:"";position:absolute;top:-40%;right:-30%;width:120%;height:120%;
  background:conic-gradient(from 200deg at 70% 30%, rgba(246,180,14,.16),transparent 30%,rgba(92,195,255,.14),transparent 70%);
  animation:brandSpin 26s linear infinite;pointer-events:none}
@keyframes brandSpin{to{transform:rotate(360deg)}}
.brandside-top{position:relative;z-index:2;display:flex;align-items:center;gap:13px}
/* ---- UKURAN LOGO PLN DISELARASKAN DENGAN TEKSNYA (8 Agu 2026) ----
   56px membuat logo hampir DUA KALI tinggi blok teks di sebelahnya
   ("MONITORING PENGADAAN" 13px + "PT PLN (PERSERO) UP3 MASOHI" 8,5px
   = ±27px). Karena .brandside-top memakai align-items:center, kelebihan
   tinggi itu menjulur ±15px ke atas DAN ke bawah teks, sehingga logo
   terbaca lebih dominan daripada nama aplikasinya sendiri.

   46px menyisakan tonjolan ±9px di tiap sisi — logo tetap menjadi
   jangkar visual, tetapi tidak lagi menenggelamkan teksnya.
   border-radius & ukuran svg ikut diperkecil dengan rasio yang sama
   (16→13, 32→26) supaya lengkung sudut dan isi lambangnya tidak
   berubah proporsi, hanya skalanya.

   Efek sampingnya sengaja: .brandside-top ikut memendek 10px, jadi
   tinggi kartu login kembali menyusut sedikit — searah dengan
   permintaan sebelumnya. */
.brandside-logo{width:46px;height:46px;flex:0 0 46px;border-radius:13px;display:grid;place-items:center;
  background:transparent;box-shadow:none}
.brandside-logo svg{width:26px;height:26px;filter:drop-shadow(0 1px 1px rgba(0,0,0,.15))}
.brandside-top .bt-txt h3{font-family:'Plus Jakarta Sans';font-weight:800;font-size:13px;letter-spacing:.4px;line-height:1.2;color:#fff}
.brandside-top .bt-txt span{font-size:8.5px;font-weight:600;letter-spacing:1.8px;text-transform:uppercase;color:rgba(223,243,244,.85)}
.brandside-mid{position:relative;z-index:2;margin:20px 0}
.brandside-mid h2{font-family:'Plus Jakarta Sans';font-weight:800;font-size:26px;line-height:1.2;letter-spacing:.2px;color:#fff}
.brandside-mid h2 b{color:var(--yellow);font-weight:800}
.brandside-mid p{margin-top:12px;font-size:12px;line-height:1.65;color:rgba(223,243,244,.82);max-width:300px}
.brandside-feats{position:relative;z-index:2;display:flex;flex-direction:column;gap:10px}
/* ---- DAFTAR FITUR (diperbarui 9 Agu 2026) ----
   Dulu tiga butir umum ("Dashboard/Input/Monitoring") yang sudah tidak
   menggambarkan aplikasi ini lagi. Kini enam butir yang masing-masing
   menyebut kelompok menu yang benar-benar ada, dengan baris kedua sebagai
   perinciannya - jadi orang tahu isinya sebelum masuk.
   Karena butirnya bertambah dua kali lipat, ukurannya dirapatkan: ubin ikon
   28->26px, jarak antar butir dipatok 9px, dan tulisannya dibuat dua tingkat
   (judul tegas, perincian tipis) supaya tetap terbaca tanpa memakan tinggi. */
/* DUA LAJUR, TIGA BARIS (9 Agu 2026). Enam butir bertumpuk membuat kartu masuk
   memanjang ke bawah - di layar pendek bagian bawahnya terpotong. Disusun dua
   lajur, tingginya langsung menjadi separuh tanpa satu butir pun dihilangkan.
   Teksnya ikut dipendekkan di index.html supaya muat pada lajur yang separuh
   lebih sempit; perinciannya tetap dipotong elipsis sebagai pengaman terakhir. */
.brandside-feats{
  display:grid; grid-template-columns:1fr 1fr; gap:11px 16px;
}
.brandside-feat{display:flex;align-items:center;gap:9px;margin-bottom:0;min-width:0;
  font-size:11.5px;font-weight:600;color:rgba(234,250,251,.92);line-height:1.3}
.brandside-feat .bf-ic{width:26px;height:26px;flex:0 0 26px;border-radius:8px;display:grid;place-items:center;
  background:rgba(255,255,255,.13);border:1px solid rgba(255,255,255,.18)}
.brandside-feat .bf-ic svg{width:14px;height:14px;color:var(--yellow)}
.brandside-feat .bf-tx{min-width:0}
.brandside-feat .bf-tx b{display:block;font-weight:700;font-size:11.5px;color:#fff}
.brandside-feat .bf-tx b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.brandside-feat .bf-tx i{display:block;font-style:normal;font-weight:500;font-size:9.5px;
  color:rgba(223,243,244,.68);margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Layar sempit: kembali satu lajur - dua lajur di lebar <520px justru membuat
   tiap butir terlalu sempit dan seluruh perinciannya terpotong elipsis. */
@media (max-width:520px){
  .brandside-feats{ grid-template-columns:1fr; gap:9px }
}

/* ---- Panel kanan: form ---- */
.login-formside{position:relative;padding:34px 40px 28px;background:rgba(255,255,255,.98);
  display:flex;flex-direction:column;justify-content:center}
.login-logo{display:none} /* logo lama tak dipakai di layout baru */
.login-title{text-align:left;font-family:'Plus Jakarta Sans';font-weight:800;font-size:19px;color:var(--ink);letter-spacing:.1px;line-height:1.25}
/* #2: Judul "Halaman Login" — font sama seperti teks lain, tegak, ukuran ringkas */
.login-title-hero{font-style:normal;font-weight:800;font-size:22px;letter-spacing:.1px;line-height:1.2;margin-bottom:12px;color:var(--teal-dark);display:block}
@media(max-width:760px){.login-title-hero{font-size:20px}}
.login-sub{text-align:left;color:var(--teal-dark);font-size:10.5px;margin-top:6px;letter-spacing:1.4px;text-transform:uppercase;font-weight:700}
.login-divider{display:flex;align-items:center;gap:10px;margin:22px 0 16px;color:var(--muted);font-size:9.5px;font-weight:700;letter-spacing:1px;text-transform:uppercase}
.login-divider::before,.login-divider::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,transparent,var(--line),transparent)}

.role-tabs{position:relative;display:flex;gap:6px;background:#eef3f4;padding:5px;border-radius:14px;margin-bottom:18px;
  box-shadow:inset 0 1px 3px rgba(16,40,50,.08)}
.role-tab{flex:1;border:none;background:transparent;border-radius:10px;padding:10px 6px;font-family:'Plus Jakarta Sans';font-weight:700;font-size:12px;color:var(--muted);display:flex;align-items:center;justify-content:center;gap:7px;cursor:pointer;transition:color .2s,transform .12s;position:relative;z-index:2}
.role-tab svg{width:16px;height:16px;transition:transform .2s}
.role-tab:hover{color:var(--teal-dark)}
.role-tab:hover svg{transform:scale(1.1)}
.role-tab.active{color:#fff}
.role-tab.active svg{color:#fff}
/* pil geser di belakang tab aktif */
.role-tabs .role-pill{position:absolute;top:5px;left:5px;height:calc(100% - 10px);border-radius:10px;
  background:linear-gradient(135deg,var(--teal),var(--cyan));box-shadow:0 6px 16px rgba(14,124,134,.4);
  transition:transform .28s cubic-bezier(.4,1.2,.5,1),width .28s cubic-bezier(.4,1.2,.5,1);z-index:1}

.login-field{margin-bottom:14px}
.login-field label{display:block;font-size:11px;font-weight:700;color:var(--ink);margin-bottom:7px;letter-spacing:.2px}
.login-pass-wrap{position:relative}
.login-lead-ic{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:18px;height:18px;color:var(--muted);pointer-events:none;display:grid;place-items:center}
.login-lead-ic svg{width:18px;height:18px}
.login-pass-wrap input.has-lead{padding-left:40px}
.login-pass-wrap input:focus + .login-eye,.login-pass-wrap input.has-lead:focus ~ .login-lead-ic{color:var(--teal)}
.login-pass-wrap input{padding-right:44px;transition:border-color .18s,box-shadow .18s,background .18s}
.login-pass-wrap input:focus{border-color:var(--teal);box-shadow:0 0 0 4px rgba(14,124,134,.14);background:#fff}
.login-eye{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--muted);width:32px;height:32px;display:grid;place-items:center;border-radius:8px;cursor:pointer;transition:.15s}
.login-eye:hover{color:var(--teal);background:var(--teal-soft)}
.login-eye svg{width:18px;height:18px}
.login-error{color:var(--red);font-size:11px;font-weight:600;margin:-4px 0 12px;min-height:14px;display:flex;align-items:center;gap:6px}
.login-error:not(:empty)::before{content:"!";display:inline-grid;place-items:center;width:15px;height:15px;border-radius:50%;background:var(--red);color:#fff;font-size:10px;font-weight:800;flex:0 0 15px}

.login-btn{width:100%;border:none;border-radius:13px;padding:14px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:13px;color:#fff;display:flex;align-items:center;justify-content:center;gap:9px;position:relative;overflow:hidden;
  background:linear-gradient(135deg,var(--teal),var(--cyan));box-shadow:0 10px 26px rgba(14,124,134,.4);transition:transform .15s,box-shadow .2s;letter-spacing:.3px;cursor:pointer}
.login-btn::after{content:"";position:absolute;top:0;left:-120%;width:70%;height:100%;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.35),transparent);transform:skewX(-18deg);transition:left .55s ease}
.login-btn:hover{transform:translateY(-2px);box-shadow:0 16px 34px rgba(14,124,134,.5)}
.login-btn:hover::after{left:130%}
.login-btn:active{transform:translateY(0)}
.login-btn svg{width:18px;height:18px;position:relative;z-index:1}
/* Gaya .login-btn.guest & .login-guest-note DIHAPUS bersama tombol
   "Masuk sebagai Tamu" — tidak ada lagi elemen yang memakainya. */
.login-foot{text-align:center;color:var(--muted);font-size:9.5px;margin-top:16px;letter-spacing:.3px;opacity:.9}
.role-pane{display:none}.role-pane.active{display:block;animation:paneFade .28s ease}
@keyframes paneFade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

@media(max-width:760px){
  .login-card{grid-template-columns:1fr;max-width:430px}
  .login-brandside{padding:30px 30px 26px}
  .brandside-mid{margin:18px 0}
  .brandside-mid h2{font-size:22px}
  .brandside-mid p{display:none}
  .brandside-feats{flex-direction:row;flex-wrap:wrap;gap:8px 16px}
  .brandside-feat{font-size:10.5px}
  .login-formside{padding:30px 26px 24px}
}
@media(max-width:430px){
  .login-formside{padding:26px 20px 22px}
  .brandside-feats{display:none}
}

/* ============================================================
   ================  TOP NAVIGATION BAR  ======================
   (menggantikan sidebar kiri — posisi menu di atas)
   ============================================================ */
.app-shell{display:block;min-height:100vh}
.topbar{position:sticky;top:0;z-index:60;background:linear-gradient(115deg,#073f45 0%,var(--teal-dark) 46%,var(--teal) 100%);color:#fff;box-shadow:0 4px 22px rgba(7,63,69,.22)}
.topbar::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;background:linear-gradient(90deg,var(--yellow),var(--cyan),var(--yellow));background-size:200% 100%;animation:sheenH 7s linear infinite;opacity:.9}
@keyframes sheenH{to{background-position:200% 0}}
.topbar-inner{max-width:1180px;margin:0 auto;display:flex;align-items:center;gap:18px;padding:10px 24px}
.topbar-brand{display:flex;align-items:center;gap:11px;flex:0 0 auto}
.topbar-brand .logo{width:40px;height:40px;flex:0 0 40px;background:transparent;border-radius:12px;display:grid;place-items:center;box-shadow:none;position:relative;overflow:visible}
.topbar-brand .logo::after{content:none}
.topbar-brand .logo svg{width:23px;height:23px;position:relative;z-index:1;filter:drop-shadow(0 1px 1.5px rgba(3,30,34,.22))}
.topbar-brand .brand h1{font-size:13px;font-weight:800;letter-spacing:.3px;line-height:1.15;color:#fff}
.topbar-brand .brand span{font-size:8.5px;opacity:.85;font-weight:600;letter-spacing:1.6px;text-transform:uppercase;color:#dff3f4}

.topnav{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.topnav-link{appearance:none;background:none;border:none;padding:9px 16px;font-family:'Plus Jakarta Sans';font-size:12.5px;font-weight:600;color:rgba(255,255,255,.85);display:flex;align-items:center;gap:8px;border-radius:12px;cursor:pointer;transition:background .25s ease,color .25s ease,transform .18s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease;white-space:nowrap;position:relative;overflow:hidden;isolation:isolate}
.topnav-link svg{width:17px;height:17px;flex:0 0 auto;transition:transform .28s cubic-bezier(.34,1.56,.64,1)}
/* Kilau menyapu saat hover */
.topnav-link::before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(120deg,transparent 25%,rgba(255,255,255,.22) 50%,transparent 75%);transform:translateX(-130%);transition:transform .6s cubic-bezier(.22,1,.36,1)}
.topnav-link:hover::before{transform:translateX(130%)}
/* Indikator garis bawah beranimasi */
.topnav-link::after{content:"";position:absolute;left:50%;right:50%;bottom:5px;height:2.5px;border-radius:3px;background:linear-gradient(90deg,var(--yellow),#ffe08a);transition:left .28s cubic-bezier(.22,1,.36,1),right .28s cubic-bezier(.22,1,.36,1);opacity:.9}
.topnav-link:hover{background:rgba(255,255,255,.16);color:#fff;transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.16)}
.topnav-link:hover svg{transform:scale(1.16) rotate(-4deg)}
.topnav-link:hover::after{left:14px;right:14px}
.topnav-link:active{transform:translateY(0) scale(.95);transition-duration:.08s}
.topnav-link.active{background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45;font-weight:800;box-shadow:0 6px 18px rgba(246,180,14,.45),inset 0 1px 0 rgba(255,255,255,.5);transform:translateY(-1px)}
.topnav-link.active svg{color:#073f45}
.topnav-link.active::after{left:50%;right:50%}

.topnav-group{position:relative}
/* #1: Tombol Input Pekerjaan & Monitoring dibuat polos (tanpa border/kotak) seperti
   Dashboard; saat dipilih/dibuka berubah kuning sama seperti Dashboard aktif. */
.topnav-trigger{appearance:none;border:none;padding:9px 16px;font-family:'Plus Jakarta Sans';font-size:12.5px;font-weight:600;color:rgba(255,255,255,.85);display:flex;align-items:center;gap:8px;border-radius:12px;cursor:pointer;transition:background .25s ease,color .25s ease,transform .18s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease;white-space:nowrap;background:none;position:relative;overflow:hidden;isolation:isolate}
.topnav-trigger svg:first-of-type{width:17px;height:17px;flex:0 0 auto;transition:transform .28s cubic-bezier(.34,1.56,.64,1)}
.topnav-trigger .caret{width:13px;height:13px;margin-left:1px;transition:transform .28s cubic-bezier(.34,1.56,.64,1);opacity:.85}
.topnav-trigger::before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(120deg,transparent 25%,rgba(255,255,255,.22) 50%,transparent 75%);transform:translateX(-130%);transition:transform .6s cubic-bezier(.22,1,.36,1)}
.topnav-trigger:hover::before{transform:translateX(130%)}
.topnav-trigger::after{content:"";position:absolute;left:50%;right:50%;bottom:5px;height:2.5px;border-radius:3px;background:linear-gradient(90deg,var(--yellow),#ffe08a);transition:left .28s cubic-bezier(.22,1,.36,1),right .28s cubic-bezier(.22,1,.36,1);opacity:.9}
.topnav-trigger:hover{background:rgba(255,255,255,.16);color:#fff;transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.16)}
.topnav-trigger:hover svg:first-of-type{transform:scale(1.16) rotate(-4deg)}
.topnav-trigger:hover::after{left:14px;right:14px}
.topnav-trigger:active{transform:translateY(0) scale(.95);transition-duration:.08s}
/* Kuning HANYA menandai HALAMAN yang sedang aktif (bukan menu yang diklik/dibuka).
   Grup menjadi kuning bila salah satu sub-menunya adalah view yang aktif (has-active). */
.topnav-group.has-active .topnav-trigger{background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45;font-weight:800;box-shadow:0 6px 18px rgba(246,180,14,.45),inset 0 1px 0 rgba(255,255,255,.5);transform:translateY(-1px)}
.topnav-group.has-active .topnav-trigger svg:first-of-type{color:#073f45}
.topnav-group.has-active .topnav-trigger::after{left:50%;right:50%}
/* Saat dropdown dibuka tetapi halaman aktif bukan di grup ini → umpan balik halus (bukan kuning) */
.topnav-group.open:not(.has-active) .topnav-trigger{background:rgba(255,255,255,.16);color:#fff}
.topnav-group.open:not(.has-active) .topnav-trigger svg:first-of-type{color:currentColor}
.topnav-group.open .topnav-trigger .caret{transform:rotate(180deg)}

.topnav-dropdown{position:absolute;top:calc(100% + 9px);left:0;min-width:232px;background:linear-gradient(180deg,#ffffff,#fbfdfe);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-lg);padding:8px;display:none;flex-direction:column;gap:3px;z-index:80;animation:dropIn .2s cubic-bezier(.16,1,.3,1)}
@keyframes dropIn{from{opacity:0;transform:translateY(-8px) scale(.98)}to{opacity:1;transform:none}}
/* Denyut halus pada menu aktif (kuning) agar menonjol */
@keyframes navGlow{0%,100%{box-shadow:0 6px 18px rgba(246,180,14,.42),inset 0 1px 0 rgba(255,255,255,.5)}50%{box-shadow:0 8px 26px rgba(246,180,14,.62),inset 0 1px 0 rgba(255,255,255,.6)}}
.topnav-link.active,.topnav-group.has-active .topnav-trigger{animation:navGlow 2.6s ease-in-out infinite}
.topnav-group.open .topnav-dropdown{display:flex}
.topnav-dropdown::before{content:"";position:absolute;top:-6px;left:22px;width:11px;height:11px;background:#fff;border-left:1px solid var(--line);border-top:1px solid var(--line);transform:rotate(45deg)}
.topnav-item{appearance:none;width:100%;background:none;border:none;text-align:left;padding:10px 12px;font-family:'Plus Jakarta Sans';font-size:12px;font-weight:600;color:var(--ink);display:flex;align-items:center;gap:11px;border-radius:10px;cursor:pointer;transition:background .16s ease,color .16s ease,transform .14s ease}
.topnav-item svg{width:16px;height:16px;color:var(--teal);flex:0 0 auto;transition:transform .16s ease}
.topnav-item:hover{background:var(--teal-soft);color:var(--teal-dark);transform:translateX(2px)}
.topnav-item:hover svg{transform:scale(1.1)}
.topnav-item.active{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;box-shadow:0 4px 12px rgba(14,124,134,.28)}
.topnav-item.active svg{color:#fff}

.topbar-user{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;gap:10px}
.topbar-user .user-chip{display:flex;align-items:center;gap:9px;background:linear-gradient(180deg,rgba(255,255,255,.20),rgba(255,255,255,.10));border:1px solid rgba(255,255,255,.28);padding:7px 14px 7px 9px;border-radius:30px;font-size:11.5px;font-weight:700;color:#fff;box-shadow:0 3px 12px rgba(0,0,0,.14),inset 0 1px 0 rgba(255,255,255,.25);backdrop-filter:blur(4px)}
.user-role-ic{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background:rgba(255,255,255,.18);box-shadow:inset 0 0 0 1px rgba(255,255,255,.25)}
.user-role-ic svg{width:14px;height:14px;color:#fff;display:block}
.user-role-ic.admin{background:linear-gradient(135deg,rgba(246,180,14,.5),rgba(246,180,14,.22))}.user-role-ic.admin svg{color:#ffe08a}
.topbar-user .logout-btn{display:inline-flex;align-items:center;gap:7px;background:linear-gradient(180deg,rgba(255,255,255,.14),rgba(255,255,255,.06));color:#fff;border:1px solid rgba(255,255,255,.22);padding:8px 15px;border-radius:11px;font-family:'Plus Jakarta Sans';font-size:11.5px;font-weight:700;cursor:pointer;transition:background .18s ease,border-color .18s ease,transform .16s cubic-bezier(.16,1,.3,1),box-shadow .2s ease;box-shadow:inset 0 1px 0 rgba(255,255,255,.2)}
.topbar-user .logout-btn:hover{background:linear-gradient(135deg,var(--red),#e25151);border-color:transparent;transform:translateY(-2px);box-shadow:0 6px 18px rgba(211,58,58,.4)}
.topbar-user .logout-btn:active{transform:translateY(0) scale(.98)}
.topbar-user .logout-btn svg{width:15px;height:15px}
/* ---- Menu Pengaturan (gear) ---- */
.settings-wrap{position:relative;display:inline-flex}
.settings-gear{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:11px;background:linear-gradient(180deg,rgba(255,255,255,.16),rgba(255,255,255,.07));border:1px solid rgba(255,255,255,.24);color:#fff;cursor:pointer;box-shadow:inset 0 1px 0 rgba(255,255,255,.2);transition:background .18s ease,transform .3s cubic-bezier(.16,1,.3,1),box-shadow .2s ease}
.settings-gear svg{width:19px;height:19px;transition:transform .4s cubic-bezier(.16,1,.3,1)}
.settings-gear:hover{background:linear-gradient(180deg,rgba(255,255,255,.26),rgba(255,255,255,.12));transform:translateY(-1px)}
.settings-gear:hover svg{transform:rotate(60deg)}
.settings-wrap.open .settings-gear{background:linear-gradient(135deg,var(--teal),var(--cyan));border-color:transparent;box-shadow:0 6px 18px rgba(14,124,134,.4)}
.settings-wrap.open .settings-gear svg{transform:rotate(120deg)}
.settings-menu{position:absolute;top:calc(100% + 10px);right:0;min-width:230px;background:#fff;border:1px solid rgba(20,50,60,.1);border-radius:14px;box-shadow:0 18px 44px rgba(20,50,60,.22),0 3px 10px rgba(20,50,60,.1);padding:8px;z-index:120;opacity:0;visibility:hidden;transform:translateY(-8px) scale(.97);transform-origin:top right;transition:opacity .18s ease,transform .2s cubic-bezier(.16,1,.3,1),visibility .18s}
.settings-wrap.open .settings-menu{opacity:1;visibility:visible;transform:translateY(0) scale(1)}
.settings-account{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 11px 10px;border-radius:10px;background:linear-gradient(180deg,#f4fafb,#eef6f7)}
.settings-account-lbl{font-family:'Plus Jakarta Sans';font-size:11px;font-weight:700;color:#54666c;letter-spacing:.2px}
.settings-account .user-chip{background:linear-gradient(135deg,var(--teal),var(--cyan));border:none;color:#fff;padding:5px 12px 5px 6px;font-size:11.5px;box-shadow:0 3px 10px rgba(14,124,134,.28)}
.settings-account .user-role-ic{width:22px;height:22px;background:rgba(255,255,255,.22);box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}
.settings-account .user-role-ic svg{color:#fff}
.settings-account .user-role-ic.admin svg{color:#fff}
.settings-sep{height:1px;background:linear-gradient(90deg,transparent,rgba(20,50,60,.1),transparent);margin:7px 4px}
.settings-item{display:flex;align-items:center;gap:11px;width:100%;padding:10px 11px;border:none;background:none;border-radius:10px;font-family:'Plus Jakarta Sans';font-size:12.5px;font-weight:700;color:#22343a;cursor:pointer;text-align:left;transition:background .15s ease,color .15s ease}
.settings-item svg{width:17px;height:17px;flex:0 0 auto;color:#54666c;transition:color .15s ease}
.settings-item:hover{background:var(--teal-soft);color:var(--teal-dark)}
.settings-item:hover svg{color:var(--teal-dark)}
.settings-item.danger:hover{background:#fdecec;color:var(--red)}
.settings-item.danger:hover svg{color:var(--red)}

/* ===== Perbaikan iPad / layar sentuh =====
   a) Ikon gear tidak boleh menyusut/terpotong walau topbar sesak.
   b) Rentang 1025-1200px (iPad Air landscape, laptop kecil): navigasi & area akun
      dipadatkan supaya seluruh isi topbar muat tanpa terdorong keluar.
   c) Perangkat sentuh: efek hover (ikon berputar & tombol bergeser) dimatikan
      karena state hover "nyangkut" setelah disentuh -> ikon tampak tidak presisi. */
.settings-gear{flex:0 0 40px}
.topbar-inner{min-width:0}
@media (min-width:1025px) and (max-width:1200px){
  .topbar-inner{gap:10px;padding:10px 14px}
  .topnav{gap:2px}
  .topnav-link,.topnav-trigger{padding:8px 9px;font-size:11.5px;gap:6px}
  .topnav-link svg,.topnav-trigger svg{width:15px;height:15px}
  .topbar-user{gap:8px}
  .topbar-user .user-chip{padding:6px 11px 6px 8px;font-size:10.5px}
  .topbar-user .logout-btn{padding:7px 11px;font-size:10.5px}
}
@media (hover:none), (any-pointer:coarse){
  .settings-gear:hover{transform:none;background:linear-gradient(180deg,rgba(255,255,255,.16),rgba(255,255,255,.07))}
  .settings-gear:hover svg{transform:none}
  .topbar-user .logout-btn:hover{transform:none;background:linear-gradient(180deg,rgba(255,255,255,.14),rgba(255,255,255,.06));border-color:rgba(255,255,255,.22);box-shadow:inset 0 1px 0 rgba(255,255,255,.2)}
  .topnav-link:hover{transform:none}
}
.nav-burger{display:none;appearance:none;background:rgba(255,255,255,.12);border:none;color:#fff;width:38px;height:38px;border-radius:10px;cursor:pointer;align-items:center;justify-content:center}
.nav-burger svg{width:20px;height:20px}
.topnav-backdrop{display:none}

@media (max-width:1024px){
  .topbar-inner{flex-wrap:wrap;padding:10px 16px;gap:12px}
  .nav-burger{display:inline-flex}
  .topbar-user{order:2}
  /* Scrim menu mobile HARUS di bawah topbar (z-index topbar = 60) agar menu
     yang berada di dalam topbar tidak ikut ter-blur & tetap bisa diklik */
  .topnav-backdrop{position:fixed;inset:0;background:rgba(7,40,44,.5);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .25s;z-index:50}
  .topnav-backdrop.show{display:block;opacity:1;visibility:visible;pointer-events:auto}
  .topnav{position:fixed;top:0;left:0;bottom:0;width:280px;max-width:86vw;flex-direction:column;align-items:stretch;gap:3px;background:linear-gradient(165deg,#073f45,var(--teal-dark) 55%,var(--teal));padding:18px 14px;transform:translateX(-100%);transition:transform .28s ease;z-index:90;overflow-y:auto;-webkit-overflow-scrolling:touch;box-shadow:0 0 50px rgba(0,0,0,.45)}
  .topnav.open{transform:translateX(0)}
  .topnav-link,.topnav-trigger{width:100%;justify-content:flex-start}
  .topnav-link::after,.topnav-trigger::after{display:none}
  .topnav-link.active,.topnav-group.has-active .topnav-trigger{animation:none}
  .topnav-trigger .caret{margin-left:auto}
  .topnav-group{position:static}
  .topnav-group.has-active .topnav-trigger::after{display:none}
  .topnav-dropdown{position:static;min-width:0;box-shadow:none;border:none;background:rgba(255,255,255,.06);margin:2px 0 4px 8px;padding:4px}
  .topnav-dropdown::before{display:none}
  .topnav-item{color:rgba(255,255,255,.86)}
  .topnav-item svg{color:rgba(255,255,255,.6)}
  .topnav-item:hover{background:rgba(255,255,255,.12);color:#fff}
}

/* ---- field terkunci otomatis (conditional lock) Tender ---- */
.field.locked label{color:var(--muted)}
.field.locked input,.field.locked select{background:#f1f4f6;color:#9aa7ad;cursor:not-allowed;border-style:dashed}
.field .lock-note{font-size:8.5px;color:#b08400;font-weight:600;display:none;align-items:center;gap:3px}
.field.locked .lock-note{display:flex}
/* Field terkunci: TIDAK lagi menampilkan overlay "Data terkunci". Cukup kotak
   input abu-abu bergaris putus-putus dengan kursor not-allowed (lihat aturan
   .field.locked input,.field.locked select di atas). */
.field.locked{position:relative}
.lock-overlay{display:none}
.field.locked .lock-overlay{
  display:none;align-items:center;justify-content:center;gap:5px;
  position:absolute;left:0;right:0;bottom:0;box-sizing:border-box;
  line-height:18px;padding:10px 12px;
  border:1px dashed #d3b25a;border-radius:11px;
  background:linear-gradient(180deg,#f1f5f6,#eef3f4);
  color:#b08400;font-weight:700;font-size:10.5px;letter-spacing:.2px;
  white-space:nowrap;overflow:hidden;pointer-events:none;z-index:2}
.field.locked .lock-overlay svg{width:11px;height:11px;flex:0 0 auto}
/* Field data terkunci / otomatis pada form Input Data (Monitoring, Pengadaan
   Langsung, Tender): setiap kolom yang tidak dapat diisi (readonly / disabled —
   mis. total otomatis Barang+Jasa, PPN) ditampilkan tidak dapat diinput dengan
   kursor "not-allowed" & tampilan abu-abu terkunci. */
#work-form-fields input[readonly], #work-form-fields textarea[readonly],
#work-form-fields input:disabled, #work-form-fields select:disabled, #work-form-fields textarea:disabled,
#form-pl-fields input[readonly], #form-pl-fields textarea[readonly],
#form-pl-fields input:disabled, #form-pl-fields select:disabled, #form-pl-fields textarea:disabled,
#form-tender-fields input[readonly], #form-tender-fields textarea[readonly],
#form-tender-fields input:disabled, #form-tender-fields select:disabled, #form-tender-fields textarea:disabled{
  cursor:not-allowed;background:#f1f4f6;color:#6b7a80;border-style:dashed;
}
/* Chip KODE placeholder pada label field mail-merge SPK */
.spk-code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;font-weight:600;color:#0E7C86;background:#e6f4f5;border:1px solid #cfe8ea;border-radius:5px;padding:1px 5px;margin-left:6px;cursor:pointer;white-space:nowrap;vertical-align:middle;transition:background .12s}
.spk-code:hover{background:#d3ecee}

/* ---- Penawaran Harga: layer multi-penyedia ---- */
.pnw-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:-4px 0 14px;padding:8px 12px;background:linear-gradient(180deg,#f3fafb,#eef6f7);border:1px solid var(--line);border-radius:11px}
.pnw-bar-label{font-family:'Plus Jakarta Sans';font-weight:800;font-size:10px;letter-spacing:.3px;text-transform:uppercase;color:var(--teal-dark)}
.jp-control{margin-left:auto;display:inline-flex;align-items:center;gap:8px}
.jp-control label{margin:0;font-family:'Plus Jakarta Sans';font-weight:700;font-size:10px;letter-spacing:.2px;text-transform:none;color:var(--teal-dark);white-space:nowrap}
.jp-control select{height:32px;padding:0 10px;border:1px solid var(--line);border-radius:8px;background:#fff;font-family:'Plus Jakarta Sans';font-weight:700;font-size:12px;color:var(--ink);cursor:pointer;min-width:120px}
.jp-control select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px var(--teal-soft)}
/* Wrapper kontrol di kanan atas baris judul (Tahun, dan Jumlah Penyedia pada Tender) */
.title-controls{margin-left:auto;display:inline-flex;align-items:center;gap:30px}
.title-controls .jp-control{margin-left:0}
.year-control{display:inline-flex;align-items:center;gap:8px}
.year-control label{margin:0;font-family:'Plus Jakarta Sans';font-weight:700;font-size:10px;letter-spacing:.2px;text-transform:none;color:var(--teal-dark);white-space:nowrap}
.year-control select{height:32px;padding:0 10px;border:1px solid var(--line);border-radius:8px;background:#fff;font-family:'Plus Jakarta Sans';font-weight:700;font-size:12px;color:var(--ink);cursor:pointer;min-width:120px}
.year-control select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px var(--teal-soft)}
.stack-input-no{flex:0 0 auto;align-self:center;min-width:18px;color:var(--teal-dark);font-weight:800;font-size:11px;margin-right:7px}
.indep-list .indep-row .stack-input-no+input{flex:1 1 auto}
.pnw-tabs{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pnw-tab{appearance:none;border:1px solid var(--line);background:#fff;color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;min-width:30px;height:30px;padding:0 11px;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:all .15s}
.pnw-tab:hover{border-color:var(--teal);background:var(--teal-soft)}
.pnw-tab.active{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;border-color:transparent;box-shadow:0 3px 10px rgba(14,124,134,.28)}
.pnw-tab .pnw-no{font-size:13px;font-weight:800}
.pnw-actions{display:flex;align-items:center;gap:7px}
.pnw-add{appearance:none;border:none;background:linear-gradient(135deg,var(--green),var(--green-dark));color:#fff;font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;height:30px;padding:0 13px;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;box-shadow:0 3px 10px rgba(30,158,90,.25);transition:filter .15s}
.pnw-add:hover{filter:brightness(1.07)}
.pnw-add svg{width:15px;height:15px}
.pnw-del{appearance:none;border:1px solid var(--line);background:#fff;color:var(--red);width:30px;height:30px;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:all .15s}
.pnw-del:hover{background:var(--red);color:#fff;border-color:transparent}
.pnw-del svg{width:15px;height:15px}
.pp-tag{margin-left:auto;font-size:8.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#fff;background:linear-gradient(135deg,var(--teal),var(--cyan));padding:3px 9px;border-radius:20px;box-shadow:0 2px 7px rgba(14,124,134,.28)}
.pp-badge{display:inline-flex;align-items:center;font-size:8px;font-weight:700;letter-spacing:.3px;text-transform:uppercase;color:var(--teal-dark);background:var(--teal-soft);border:1px solid #bfe2e5;padding:1px 6px;border-radius:20px;margin-left:6px;vertical-align:middle}
.field.per-penyedia{position:relative}
.field.per-penyedia input,.field.per-penyedia select{border-color:#bfe2e5;background:linear-gradient(180deg,#fbfeff,#f3fafb)}
/* ---- Field multi-nilai independen (Bidang/Sub Bidang, No. SPPBJ) ----
   TOMBOL TAMBAH/HAPUS MELAYANG (11 Agu 2026).
   Sebelumnya baris judul field ini berisi label + dua tombol setinggi 26px,
   sehingga tingginya jauh melebihi judul field tetangga (<label> biasa, ~15px).
   Akibatnya kotak isian field ini turun ~11px dan tidak lagi sebaris dengan
   field di kiri-kanannya. Kini tombolnya dipasang MELAYANG di sudut kanan atas
   field, jadi tidak menyumbang tinggi sama sekali. Pola ini disalin dari
   .tor-ml-act pada Penyusunan Dokumen Pengadaan, yang tata letaknya sudah benar.
   Berlaku untuk SEMUA pemakainya: Pengadaan Langsung & Tender. */
.indep-field{position:relative}
/* Pembungkus .indep-head sudah DIBUANG dari markup (11 Agu 2026) - <label> kini
   anak langsung .field, persis seperti field biasa, sehingga tinggi baris
   judulnya identik. Aturan di bawah dipertahankan sebagai jaring pengaman bila
   masih ada markup lama yang belum ikut diperbarui. */
.indep-field .indep-head{display:contents}
.indep-field>label{margin:0}
.indep-actions{position:absolute;top:-2px;right:0;display:flex;align-items:center;gap:6px;z-index:2}
.indep-add,.indep-del-btn{appearance:none;border:none;font-family:'Plus Jakarta Sans';font-weight:800;font-size:10.5px;height:20px;padding:0 8px;border-radius:6px;cursor:pointer;display:inline-flex;align-items:center;gap:4px;line-height:1;transition:filter .15s,background .15s,color .15s}
.indep-add svg,.indep-del-btn svg{width:11px;height:11px}
.indep-add{background:linear-gradient(135deg,var(--green),var(--green-dark));color:#fff;box-shadow:0 2px 8px rgba(30,158,90,.25)}
.indep-add:hover{filter:brightness(1.07)}
.indep-del-btn{background:#fff;border:1px solid var(--line);color:var(--red)}
.indep-del-btn:hover:not(:disabled){background:var(--red);color:#fff;border-color:transparent}
.indep-del-btn:disabled{opacity:.45;cursor:not-allowed}
/* Tiap field DIPATOK ke sisi atas barisnya. Tanpa ini, begitu daftar
   multi-nilai memanjang ke bawah, seluruh field pada baris yang sama ikut
   diregangkan setinggi field terpanjang lalu isinya menempel di bawah. */
.form-flow{align-items:flex-start}
.form-flow>.field{align-self:flex-start}
.indep-list{display:flex;flex-direction:column;gap:7px}
.indep-row{display:flex;align-items:center}
.indep-row input{flex:1 1 auto;width:100%;min-width:0}

/* ============================================================
   #6 · POLISH VISUAL — penyempurnaan tampilan profesional
   (ditempatkan di akhir agar meng-override dengan aman)
   ============================================================ */
:root{
  --shadow:0 1px 2px rgba(16,40,50,.05),0 6px 18px rgba(16,40,50,.06);
  --shadow-md:0 3px 8px rgba(16,40,50,.07),0 16px 40px rgba(16,40,50,.10);
  --shadow-lg:0 10px 30px rgba(9,94,102,.14),0 30px 70px rgba(9,94,102,.12);
}
/* Kartu ringkasan: gradient halus + garis aksen kiri lebih halus + angka lebih tegas */
.card{border-radius:16px;transition:transform .25s cubic-bezier(.2,.8,.2,1),box-shadow .25s ease,border-color .25s ease}
.card:hover{transform:translateY(-4px)}
.card .accent{width:4px;border-radius:0 6px 6px 0;box-shadow:2px 0 10px rgba(16,40,50,.08)}
.card .v{letter-spacing:-.5px}
.card::before{content:"";position:absolute;left:0;right:0;top:0;height:3px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.6),transparent);opacity:.7}

/* Panel & header: sudut lebih lembut, header sedikit lebih hidup */
.panel{border-radius:16px}
.panel-head{letter-spacing:.2px;font-size:12.5px}

/* Toolbar filter: latar hijau lembut & bayangan lebih premium */
.toolbar{border-radius:16px;background:linear-gradient(135deg,#eef8f9 0%,#e0f1f3 100%);border-color:#cbe4e7;box-shadow:0 4px 14px rgba(14,124,134,.12),inset 0 1px 0 rgba(255,255,255,.7)}
.filter-field label{color:var(--teal-dark);opacity:.9}

/* Kontrol input: fokus lebih elegan */
select:hover,input:hover,textarea:hover{border-color:#9fc6cc}
select:focus,input:focus,textarea:focus{box-shadow:0 0 0 3px rgba(14,124,134,.16);border-color:var(--teal)}

/* Tombol: bayangan lebih dalam saat hover, sudut konsisten */
.btn{border-radius:11px}
.btn:hover{transform:translateY(-1.5px)}
.btn-teal,.btn-green,.btn-red,.btn-amber,.btn-danger{position:relative;overflow:hidden}
.btn-teal::after,.btn-green::after,.btn-red::after,.btn-amber::after,.btn-danger::after{content:"";position:absolute;inset:0;background:linear-gradient(120deg,transparent 30%,rgba(255,255,255,.22) 50%,transparent 70%);transform:translateX(-120%);transition:transform .5s ease}
.btn-teal:hover::after,.btn-green:hover::after,.btn-red:hover::after,.btn-amber:hover::after,.btn-danger:hover::after{transform:translateX(120%)}

/* Tabel: header lebih premium, baris lebih lega & hover lebih jelas */
.table-wrap{border-radius:14px}
th{font-size:9.5px;letter-spacing:.7px;background:var(--teal)}
th:first-child{border-top-left-radius:2px}
tbody tr{transition:background .18s ease,box-shadow .18s ease}
tbody tr:hover{background:#e9f6f7}
td{padding:2px 4px}

/* Pil status: lebih halus & modern */
.pill{padding:5px 12px;border-radius:20px;font-weight:800;letter-spacing:.3px;font-size:9.5px}
.pill-prog{background:linear-gradient(135deg,#fff4d8,#ffe9b0);color:#946400}
.pill-kontrak{background:linear-gradient(135deg,#d7f2e3,#c3ead4);color:#137a44}
.pill-ttd{background:linear-gradient(135deg,#ffe7d3,#ffd6b5);color:#ad5309}
.pill-batal{background:linear-gradient(135deg,#fbe0e0,#f6cccc);color:#b22a2a}

/* Badge jumlah & count: sedikit lebih menonjol */
.count-badge{box-shadow:0 4px 12px rgba(14,124,134,.3)}

/* Judul halaman: aksen kiri lebih tebal-lembut */
.page-head h2::before{width:5px;border-radius:4px;background:linear-gradient(180deg,var(--teal),var(--cyan));box-shadow:0 2px 8px rgba(14,124,134,.35)}

/* Tombol aksi tabel: lingkaran lebih halus */
.act{border-radius:9px;box-shadow:0 2px 6px rgba(16,40,50,.12)}
.act:hover{transform:translateY(-2px) scale(1.04)}

/* Topbar: garis bawah gradasi sedikit lebih tegas */
.topbar{box-shadow:0 6px 26px rgba(7,63,69,.24)}

/* Section title form: aksen lebih rapi */
.form-section-title{letter-spacing:.4px}

/* ============================================================
   BATANG GULIR TABEL — KEMBALI KE BATANG BAWAAN PERAMBAN (8 Agu 2026)
   ------------------------------------------------------------
   GEJALA: menyeret batang gulir tabel (mendatar maupun tegak) tersendat,
   PADAHAL menggulir dengan roda tetikus di tabel yang sama mulus.

   Asimetri itulah petunjuknya, dan penyebabnya ada di empat baris di bawah
   komentar ini — bukan di JavaScript.

   Begitu sebuah penggulir diberi aturan ::-webkit-scrollbar, Chromium
   berhenti memakai batang gulir BAWAAN SISTEM dan menggambar sendiri batang
   "custom" itu. Konsekuensinya bukan sekadar tampilan:

     - Roda tetikus digulirkan oleh COMPOSITOR THREAD. Ia tidak menunggu
       thread utama, jadi tetap mulus walau thread utama sedang sibuk —
       persis yang Anda alami.
     - Menyeret batang gulir CUSTOM harus ditangani THREAD UTAMA: tiap gerakan
       tetikus dihitung, batangnya digambar ulang, lalu isi tabel dicat ulang,
       semuanya dalam satu frame. Batang bawaan tidak begitu; Chromium bisa
       menyeretnya di compositor.

   Beratnya cat ulang itu memperparah keadaan, dan tabel Monitoring adalah
   kasus terberat di aplikasi ini: baris judul menempel di atas (th sticky),
   kolom No. & Nama Pekerjaan menempel di kiri (sticky), masing-masing dengan
   empat inset box-shadow pemalsu garis dan satu pseudo-element ::before
   ber-z-index -1 sebagai latar. Semua itu harus dicat ulang tiap frame seretan.

   Karena itu penggayaannya dipindah ke properti BAKU — scrollbar-width &
   scrollbar-color. Keduanya hanya MENIPISKAN dan MEWARNAI batang bawaan;
   batangnya tetap batang sistem, jadi jalur cepat compositor tidak hilang.
   Warnanya sengaja diambil dari gradasi lama (#a9cace di atas #f0f5f6) supaya
   tampilannya nyaris tidak berubah. Yang hilang hanya gradasi, sudut membulat,
   dan efek sorot pada batang — tiga hal yang tidak sebanding dengan gulir
   yang tersendat.

   Peramban lama yang belum mengenal kedua properti ini akan menampilkan batang
   gulir bawaan apa adanya: tetap benar, tetap cepat, hanya tanpa warna.

   CATATAN: #topnav (bagian 7250) juga memakai ::-webkit-scrollbar, tetapi
   SENGAJA dibiarkan — daftar menu pendek, isinya ringan, dan batangnya nyaris
   tidak pernah diseret. Yang bermasalah hanya penggulir yang isinya berat.
   ============================================================ */
.table-wrap{scrollbar-width:thin;scrollbar-color:#a9cace #f0f5f6}

/* ============================================================
   #4 · ANIMASI TOMBOL AKSI (Edit / Lihat / Hapus)
   ============================================================ */
.action-cell{gap:7px}
.act{position:relative;overflow:visible;width:32px;height:32px;border-radius:10px;
  transition:transform .28s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease,filter .2s ease}
.act svg{transition:transform .3s cubic-bezier(.34,1.56,.64,1);position:relative;z-index:2}
/* Cincin cahaya yang memancar saat hover */
.act::before{content:"";position:absolute;inset:0;border-radius:inherit;z-index:1;
  box-shadow:0 0 0 0 rgba(14,124,134,.45);transition:box-shadow .35s ease;pointer-events:none}
.act::after{content:"";position:absolute;inset:-3px;border-radius:12px;z-index:0;opacity:0;
  background:radial-gradient(circle,rgba(255,255,255,.55),transparent 70%);
  transform:scale(.4);transition:opacity .3s ease,transform .3s ease;pointer-events:none}
.act:hover{transform:translateY(-3px) scale(1.12)}
.act:hover::after{opacity:1;transform:scale(1)}
.act:active{transform:translateY(-1px) scale(.94)}
/* Riak saat ditekan */
.act:active::before{box-shadow:0 0 0 8px rgba(14,124,134,0);transition:box-shadow .01s}

/* Edit → pensil bergoyang menulis */
.act-edit:hover{box-shadow:0 8px 20px rgba(246,180,14,.5)}
.act-edit:hover::before{box-shadow:0 0 0 4px rgba(246,180,14,.25)}
.act-edit:hover svg{animation:actEdit .55s ease-in-out}
@keyframes actEdit{0%{transform:rotate(0)}25%{transform:rotate(-16deg) translate(-1px,1px)}55%{transform:rotate(12deg) translate(1px,-1px)}80%{transform:rotate(-6deg)}100%{transform:rotate(0)}}

/* Lihat → mata mengedip/zoom */
.act-view:hover{box-shadow:0 8px 20px rgba(14,124,134,.5)}
.act-view:hover::before{box-shadow:0 0 0 4px rgba(14,124,134,.28)}
.act-view:hover svg{animation:actView .6s ease-in-out}
@keyframes actView{0%{transform:scale(1)}30%{transform:scale(1.25)}50%{transform:scaleY(.4) scaleX(1.1)}70%{transform:scale(1.15)}100%{transform:scale(1)}}

/* Hapus → tutup tempat sampah bergetar */
.act-del:hover{box-shadow:0 8px 20px rgba(211,58,58,.5)}
.act-del:hover::before{box-shadow:0 0 0 4px rgba(211,58,58,.28)}
.act-del:hover svg{animation:actDel .5s ease-in-out}
@keyframes actDel{0%{transform:rotate(0)}20%{transform:rotate(-18deg)}40%{transform:rotate(14deg)}60%{transform:rotate(-10deg)}80%{transform:rotate(6deg)}100%{transform:rotate(0)}}

@media (prefers-reduced-motion: reduce){
  .act:hover svg{animation:none !important}
}
/* =====================================================================
   ✦ TASK 4 — DASHBOARD DIPERCANTIK (lebih elegan & profesional)
   ===================================================================== */
/* Kartu ringkasan: latar berlapis, sudut lembut, glow aksen, hover naik */
#view-dashboard .card{
  background:
    radial-gradient(120% 120% at 100% 0%, rgba(14,124,134,.05), transparent 42%),
    linear-gradient(180deg,#ffffff,#f8fcfc);
  border:1px solid #e2ecee;border-radius:18px;padding:20px 20px 20px 24px;
  box-shadow:0 1px 2px rgba(16,40,50,.04),0 10px 26px rgba(9,94,102,.06);
}
#view-dashboard .card::after{
  content:"";position:absolute;top:-40px;right:-40px;width:120px;height:120px;border-radius:50%;
  background:radial-gradient(circle,rgba(14,124,134,.06),transparent 70%);pointer-events:none;
}
#view-dashboard .card .accent{width:5px;border-radius:0 6px 6px 0;box-shadow:0 0 16px 1px rgba(16,40,50,.10)}
#view-dashboard .card .k{letter-spacing:.7px}
#view-dashboard .card .v{letter-spacing:-.6px;background:linear-gradient(180deg,#173139,#28434c);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
#view-dashboard .card:hover{transform:translateY(-4px);box-shadow:0 4px 10px rgba(16,40,50,.06),0 22px 46px rgba(9,94,102,.16);border-color:#cfe3e6}

/* Kartu Efisiensi: nuansa hijau lebih hidup */
#view-dashboard .efisiensi-card{
  background:
    radial-gradient(130% 130% at 100% 0%, rgba(30,158,90,.10), transparent 45%),
    linear-gradient(165deg,#eefbf3,#ffffff 62%);
  border-color:#c2e8d2;
}
#view-dashboard .efisiensi-card .v,#view-dashboard .eff-pct{-webkit-text-fill-color:initial;background:none;color:var(--green-dark)}
#view-dashboard .eff-bar{height:10px}

/* Panel grafik: kepala lebih tegas, isi sedikit lega */
#view-dashboard .panel{border-radius:18px;border-color:#e2ecee;box-shadow:0 1px 2px rgba(16,40,50,.04),0 12px 30px rgba(9,94,102,.07)}
#view-dashboard .panel-head{background:linear-gradient(180deg,#f4fafb,#ecf5f6);padding:16px 22px;letter-spacing:.3px}
#view-dashboard .panel-body{padding:22px}

/* Batang grafik tumbuh halus saat dashboard tampil / difilter */
#view-dashboard .bar-fill{transform-origin:left;animation:barGrow .85s cubic-bezier(.2,.85,.25,1) both}
@keyframes barGrow{from{transform:scaleX(0);opacity:.4}to{transform:scaleX(1);opacity:1}}
#view-dashboard .bar-track{height:11px;background:#eef4f5}
#view-dashboard .bar-row:hover .bar-fill{filter:brightness(1.06) saturate(1.1)}

/* Judul dashboard: sedikit lebih megah + garis pemisah halus di bawah header */
#view-dashboard .page-head{border-bottom:1px solid #e7eff0;padding-bottom:16px}
#view-dashboard .page-head h2{font-size:23px;letter-spacing:-.4px}

/* Filter dashboard: kapsul rapi */
#view-dashboard .filter-field select{border-radius:11px;font-weight:600}

/* ===== Filter Dashboard — tanpa background (transparan) ===== */
.dash-filter-bar{
  position:relative;
  display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end;
  padding:0;border-radius:0;
  background:transparent;border:none;box-shadow:none;
  backdrop-filter:none;-webkit-backdrop-filter:none
}
.dash-filter-bar .filter-field{gap:7px}
#view-dashboard .dash-filter-bar .filter-field label{
  display:none
}
#view-dashboard .dash-filter-bar .filter-field label::before{
  content:"";width:6px;height:6px;border-radius:50%;flex:0 0 6px;
  background:linear-gradient(135deg,var(--teal),var(--cyan));
  box-shadow:0 0 0 3px rgba(22,169,181,.14)
}
#view-dashboard .dash-filter-bar .filter-field select{
  appearance:none;-webkit-appearance:none;
  font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:600;
  color:var(--teal-dark);letter-spacing:.1px;
  width:auto;min-width:200px;max-width:none;
  padding:11px 38px 11px 15px;border-radius:12px;
  border:1px solid #cbe4e7;
  background-color:#fff;
  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='%230e7c86' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 13px center;
  box-shadow:0 2px 6px rgba(14,124,134,.08),inset 0 1px 0 rgba(255,255,255,.7);
  transition:border-color .18s ease,box-shadow .2s ease,transform .16s ease
}
/* Opsi dropdown tetap rata kiri saat menu terbuka (agar mudah dibaca) */
#view-dashboard .dash-filter-bar .filter-field select option{text-align:left}
#view-dashboard .dash-filter-bar .filter-field select:hover{
  border-color:var(--teal);transform:translateY(-1px);
  box-shadow:0 5px 14px rgba(14,124,134,.16),inset 0 1px 0 rgba(255,255,255,.7)
}
#view-dashboard .dash-filter-bar .filter-field select:focus{
  outline:none;border-color:var(--teal);
  box-shadow:0 0 0 3px var(--teal-soft),0 6px 16px rgba(14,124,134,.18)
}
/* Filter bar diletakkan pada baris DI BAWAH judul; ke-4 field dibuat lebar tetap
   yang sama — cukup untuk teks terpanjang ("SPBJ / Kontrak Rinci") sehingga tidak
   ada teks yang terpotong dan semua field seragam. */
#view-dashboard .page-head{flex-direction:column;align-items:flex-start;gap:20px}
/* Kelompok field filter rata kanan halaman (judul tetap di kiri) */
#view-dashboard .dash-filter-bar{align-self:flex-end}
/* Beri ruang di bawah judul agar ekor huruf (mis. 'g' pada "Langsung") tidak terpotong */
#view-dashboard .page-head h2{line-height:1.35;padding-bottom:4px}
.dash-filter-bar .filter-field{flex:0 0 auto;min-width:0}
#view-dashboard .dash-filter-bar .filter-field select{width:205px;min-width:205px;max-width:205px}
@media(max-width:640px){
  .dash-filter-bar{width:100%;padding:0}
  .dash-filter-bar .filter-field{flex:1 1 100%}
  #view-dashboard .dash-filter-bar .filter-field select{width:100%;min-width:0;max-width:none}
}

@media (prefers-reduced-motion: reduce){
  #view-dashboard .bar-fill{animation:none !important}
}
/* =====================================================================
   ✦ TASK 7 — PENYESUAIAN TAMPILAN MOBILE
   Menu kini tampil tajam & bisa diklik; tata letak dirapikan untuk layar kecil
   ===================================================================== */
body.nav-open{overflow:hidden}
@media(max-width:1024px){
  .topnav .topnav-link,.topnav .topnav-trigger{padding:12px 14px;font-size:13px;border-radius:11px}
  .topnav .topnav-item{padding:12px 12px;font-size:12.5px}
}
@media(max-width:640px){
  .wrap{padding:16px 14px}
  .page-head{flex-direction:column;align-items:stretch;gap:12px}
  .page-head h2{font-size:18px}
  #view-dashboard .page-head h2{font-size:20px}
  .toolbar{padding:13px;display:flex;width:auto;margin-left:0;margin-right:0}
  .filter-field{flex:1 1 100%}
  .filter-field select,.filter-field input{min-width:0;max-width:none;width:100%}
  .toolbar .spacer{display:none}
  .toolbar>.btn{flex:1 1 auto;justify-content:center}
  .toolbar .toolbar-actions{flex:1 1 100%;margin-left:0;gap:12px;flex-wrap:wrap}
  .toolbar .toolbar-search{flex:1 1 100%}
  .toolbar .toolbar-search input{min-width:0;max-width:none;width:100%}
  .toolbar .toolbar-actions>.btn{flex:1 1 auto;justify-content:center}
  #view-dashboard .page-head>div:last-child{width:100%;flex-wrap:wrap}
  #view-dashboard .filter-field{flex:1 1 100%}
  .act{width:34px;height:34px}
  .io-row{flex-wrap:wrap;text-align:center;justify-content:center;width:auto;margin-left:0}
  .io-row .btn{flex:1 1 auto;justify-content:center}
  .toast{left:14px;right:14px;transform:translateY(120px);bottom:16px}
  .toast.show{transform:translateY(0)}
}

/* ============================================================
   ===============  LAPISAN TAMPILAN ELEGAN  ==================
   (kosmetik saja — tidak mengubah struktur / fungsi)
   ============================================================ */

/* ---------- Judul halaman ---------- */
.page-head h2{letter-spacing:-.2px}
.page-head h2::before{background:linear-gradient(180deg,var(--yellow),var(--teal),var(--cyan));box-shadow:0 4px 14px rgba(14,124,134,.28)}

/* ---------- Kartu KPI Dashboard ---------- */
#view-dashboard .cards{gap:18px}
.card{background:linear-gradient(158deg,#ffffff 0%,#f9fdfd 60%,#f3fafb 100%);border-color:#e0eaec;
  box-shadow:0 1px 2px rgba(16,40,50,.05),0 10px 30px rgba(16,40,50,.06);border-radius:18px;
  padding:20px 20px 18px 24px}
.card::before{content:"";position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.7),transparent);opacity:.9}
.card:hover{transform:translateY(-4px);box-shadow:0 6px 16px rgba(16,40,50,.08),0 26px 54px rgba(16,40,50,.12);border-color:#c9dee1}
.card .accent{width:5px;border-radius:0 6px 6px 0;box-shadow:0 0 18px 1px rgba(16,40,50,.10)}
.card .k{color:var(--muted);letter-spacing:.7px}
.card .v{background:linear-gradient(180deg,var(--ink),#2f4a55);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-.6px}
.card .sub{display:inline-flex;align-items:center;gap:5px;color:var(--muted)}
.card .sub::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.55}
/* Ikon melayang di kanan-atas kartu */
.card-ic{position:absolute;top:16px;right:16px;width:40px;height:40px;border-radius:12px;display:grid;place-items:center;
  color:var(--ic,var(--teal));background:color-mix(in srgb,var(--ic,var(--teal)) 12%,#fff);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ic,var(--teal)) 22%,transparent);
  transition:transform .25s ease;z-index:2}
.card:hover .card-ic{transform:scale(1.08) rotate(-3deg)}
.card-ic svg{width:21px;height:21px}
.efisiensi-card .card-ic{color:var(--green);background:color-mix(in srgb,var(--green) 12%,#fff);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--green) 22%,transparent)}

/* ===== Kartu Dashboard — tampilan lebih elegan & profesional ===== */
#view-dashboard .card{
  --ca:var(--card-accent,var(--teal));
  background:
    linear-gradient(180deg, color-mix(in srgb,var(--ca) 6%,#fff) 0%, #ffffff 42%, #fbfdfd 100%);
  border:1px solid color-mix(in srgb,var(--ca) 16%,var(--line));
  border-radius:18px;
  box-shadow:
    0 1px 2px rgba(16,40,50,.05),
    0 10px 26px rgba(16,40,50,.06),
    inset 0 1px 0 rgba(255,255,255,.9);
}
/* Sinar warna aksen lembut di sudut kanan-atas (menggantikan radial teal statis) */
#view-dashboard .card::after{
  content:"";position:absolute;right:-34px;top:-34px;width:110px;height:110px;border-radius:50%;
  background:radial-gradient(circle, color-mix(in srgb,var(--ca) 20%,transparent), transparent 70%);
  opacity:.55;pointer-events:none;transition:opacity .25s ease,transform .25s ease}
#view-dashboard .card:hover{
  transform:translateY(-4px);
  border-color:color-mix(in srgb,var(--ca) 34%,var(--line));
  box-shadow:
    0 2px 4px rgba(16,40,50,.06),
    0 18px 40px color-mix(in srgb,var(--ca) 20%,rgba(16,40,50,.10)),
    inset 0 1px 0 rgba(255,255,255,.9);
}
#view-dashboard .card:hover::after{opacity:.85;transform:scale(1.08)}

/* ====== Transisi hover premium untuk kartu dashboard (tanpa animasi berputar) ====== */
#view-dashboard .card{
  isolation:isolate;
  transition:transform .34s cubic-bezier(.16,1,.3,1),
             box-shadow .38s cubic-bezier(.16,1,.3,1),
             border-color .3s ease;
}
/* Garis cahaya tipis di tepi atas yang menyapu masuk saat hover */
#view-dashboard .card>*{position:relative;z-index:2}
#view-dashboard .card:hover{
  transform:translateY(-6px);
  border-color:color-mix(in srgb,var(--ca) 40%,var(--line));
  box-shadow:
    0 2px 6px rgba(16,40,50,.06),
    0 20px 46px color-mix(in srgb,var(--ca) 22%,rgba(16,40,50,.12)),
    inset 0 1px 0 rgba(255,255,255,.9),
    inset 0 0 0 1px color-mix(in srgb,var(--ca) 22%,transparent);
}
/* Sinar aksen di pojok membesar & menguat saat hover (memanfaatkan ::after yang ada) */
#view-dashboard .card:hover::after{opacity:.95;transform:scale(1.15)}
/* Chip ikon ikut "hidup" saat hover */
#view-dashboard .card:hover .card-ic{
  transform:translateY(-1px) scale(1.06);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb,var(--ic,var(--teal)) 34%,transparent),
    0 8px 18px color-mix(in srgb,var(--ic,var(--teal)) 30%,transparent);
}
@media (prefers-reduced-motion: reduce){
  #view-dashboard .card:hover{transform:none}
}

/* Batang aksen kiri: sedikit lebih tebal & bercahaya sesuai warna kartu */
#view-dashboard .card .accent{
  width:5px;border-radius:0 6px 6px 0;
  box-shadow:0 0 16px 1px color-mix(in srgb,var(--ca) 45%,transparent);
}
/* Chip ikon: bayangan halus berwarna aksen agar terasa "premium" */
#view-dashboard .card-ic{
  width:42px;height:42px;border-radius:13px;
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb,var(--ic,var(--teal)) 24%,transparent),
    0 6px 14px color-mix(in srgb,var(--ic,var(--teal)) 22%,transparent);
}
#view-dashboard .card:hover .card-ic{transform:scale(1.08) rotate(-3deg)}
/* Ikon + judul dalam satu baris rapi (tidak lagi menumpuk) */
#view-dashboard .card-head{display:flex;align-items:center;gap:12px;margin-bottom:2px}
#view-dashboard .card-ic{position:static;top:auto;right:auto;flex:0 0 auto;transform:none}
#view-dashboard .card .k{padding-right:0;line-height:1.3;margin:0}
#view-dashboard .card .v,#view-dashboard .card .sub{padding-right:0}

/* ---------- Panel chart Dashboard ---------- */
#view-dashboard .panel{border-radius:18px;border-color:#e0eaec;box-shadow:0 1px 2px rgba(16,40,50,.05),0 12px 34px rgba(16,40,50,.06)}
#view-dashboard .panel-head{background:linear-gradient(180deg,#f7fbfb,#eef6f7);border-bottom-color:#e2edee;padding:16px 20px}
#view-dashboard .panel-head::before{width:9px;height:9px;box-shadow:0 0 0 4px rgba(14,124,134,.12)}
#view-dashboard .panel-body{padding:18px 20px 20px}

/* ===== Panel grafik "per Bidang Pelaksana" — lebih elegan & profesional ===== */
#view-dashboard .split .panel{
  overflow:hidden;
  background:linear-gradient(180deg,#ffffff, #fbfefe);
  box-shadow:0 1px 2px rgba(16,40,50,.05),0 14px 38px rgba(16,40,50,.07),inset 0 1px 0 rgba(255,255,255,.9);
  transition:box-shadow .25s ease,transform .25s ease
}
#view-dashboard .split .panel:hover{box-shadow:0 2px 4px rgba(16,40,50,.06),0 20px 46px rgba(14,124,134,.12),inset 0 1px 0 rgba(255,255,255,.9)}
#view-dashboard .split .panel-head{
  font-family:'Plus Jakarta Sans';font-weight:800;letter-spacing:.2px;font-size:13.5px;
  color:var(--teal-dark);padding:15px 20px;
  background:linear-gradient(180deg,#f4fbfb,#eaf6f7);border-bottom:1px solid #e2edee
}
/* Baris bar: sedikit lapang, garis pemisah halus, sorotan lembut saat hover */
#view-dashboard .split .bar-row{
  margin-bottom:0;padding:10px 8px;border-radius:10px;
  transition:background .18s ease
}
#view-dashboard .split .bar-row+.bar-row{border-top:1px solid #eef4f5}
#view-dashboard .split .bar-row:hover{background:color-mix(in srgb,var(--teal) 6%,#fff)}
#view-dashboard .split .bar-row .lbl{
  flex-basis:100%;font-weight:600;color:#243840
}
#view-dashboard .split .bar-track{
  height:12px;background:#eef4f5;border-radius:20px;
  box-shadow:inset 0 1px 2px rgba(16,40,50,.08)
}
#view-dashboard .split .bar-fill{
  border-radius:20px;
  background:linear-gradient(90deg,var(--teal),var(--cyan));
  box-shadow:0 1px 5px rgba(14,124,134,.35), inset 0 1px 0 rgba(255,255,255,.35)
}
#view-dashboard .split .bar-row .num{font-weight:800;color:var(--teal-dark)}
#view-dashboard .split .bar-row .num.num-rp{color:var(--ink)}
/* Empty state lebih rapi & profesional */
#view-dashboard .split .empty,#view-dashboard .split .panel-body>.empty{
  padding:40px 20px;color:var(--muted);font-size:12px;text-align:center;
  display:flex;align-items:center;justify-content:center;min-height:120px
}

/* ---------- Form Input Pekerjaan ---------- */
.form-card{border-radius:18px;border-color:#dde9eb;background:linear-gradient(180deg,#ffffff,#f9fdfe);
  box-shadow:0 1px 2px rgba(16,40,50,.04),0 12px 30px rgba(16,40,50,.06)}
.form-card::before{background:linear-gradient(180deg,var(--teal),var(--cyan))}
.form-card:hover{border-color:#bcd6d9;box-shadow:0 4px 12px rgba(16,40,50,.07),0 24px 54px rgba(16,40,50,.10)}
.form-section-title{font-size:12.5px;color:var(--teal-dark);border-image:linear-gradient(90deg,var(--teal),var(--cyan),transparent) 1}
/* Badge nomor otomatis di depan judul section (I, II, ...) */
.form-section-title svg{color:var(--teal);opacity:.9}
/* Ikon tombol Pilih/Ganti & Batalkan Pilihan tetap memakai warna tombolnya sendiri
   (putih / merah), jangan ikut diwarnai teal oleh aturan judul section di atas. */
.form-section-title .dp-pick-btn svg,.form-section-title .dp-unpick-btn svg{color:inherit;opacity:1}
.field label{font-size:11px;color:#2b3f48}
.field input,.field select,.field textarea{border-color:#cdd9de;background:linear-gradient(180deg,#ffffff,#fafdfe);border-radius:11px;padding:10px 12px;box-shadow:0 1px 2px rgba(16,40,50,.06),inset 0 1px 0 rgba(255,255,255,.6)}
.field input:hover,.field select:hover{border-color:#a7bec5;box-shadow:0 2px 7px rgba(16,40,50,.09),inset 0 1px 0 rgba(255,255,255,.6)}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.16),0 4px 12px rgba(14,124,134,.16);background:#fff}
.field input::placeholder{color:#9fb0b6}
/* Bintang wajib jadi lebih halus */
.field label .req{margin-left:3px;font-weight:800}

/* (Bar "Template Pengisian Data" kini tanpa kotak — hanya tombol) */

/* ---------- Toolbar filter Monitoring ---------- */
.toolbar{border-radius:18px;border-color:#cbe4e7;background:linear-gradient(135deg,#eef8f9 0%,#e0f1f3 100%);
  box-shadow:0 4px 14px rgba(14,124,134,.12),inset 0 1px 0 rgba(255,255,255,.7);padding:16px 18px;gap:12px}
.toolbar .filter-field label{color:var(--teal-dark);opacity:.85}
.filter-field select,.filter-field input{border-radius:11px;border-color:#dbe6e9}
.count-badge{padding:3px 12px;border-radius:20px}

/* ---------- Tabel Monitoring ---------- */
.panel{border-radius:18px;border-color:#e0eaec}
.table-wrap{border-radius:16px;border-color:#d3e2e4}
th{background:#0E7C86;letter-spacing:.6px;border-color:#0b6b74;padding:12px 14px}
.table-wrap thead th:first-child{background:#0E7C86}
/* Teks sel: weight 500 + warna --ink. Sebelumnya weight bawaan (400) pada
   Plus Jakarta Sans 11px membuat teks tampak tipis/berkabut, terutama pada
   baris genap yang berlatar #f6fafb. Kontras naik ke ~15:1 (WCAG AAA). */
td{border-color:#e4edef;padding:12px 14px;color:var(--ink);font-weight:500;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
tbody tr:nth-child(even){background:#f6fafb}
tbody tr:hover{background:#e9f6f7}
.table-wrap tbody tr:hover td:first-child{background:#e6f5f6}
/* Status pill lebih menonjol */
.pill{padding:5px 12px;border-radius:20px;font-size:9.5px;box-shadow:none}
.pill-prog{background:linear-gradient(180deg,#fff6e0,#ffeec6);color:#8a5f00;box-shadow:inset 0 0 0 1px rgba(154,107,0,.2)}
.pill-kontrak{background:linear-gradient(180deg,#e0f5ea,#d1efe0);color:#127a43;box-shadow:inset 0 0 0 1px rgba(21,122,68,.2)}
.pill-ttd{background:linear-gradient(180deg,#ffeade,#ffdcc2);color:#ad5309;box-shadow:inset 0 0 0 1px rgba(179,86,12,.24)}
.pill-batal{background:linear-gradient(180deg,#fce4e4,#f9d9d9);color:#b02626;box-shadow:inset 0 0 0 1px rgba(178,42,42,.2)}
/* Tombol aksi baris */
.act{border-radius:9px}
.act:hover{transform:translateY(-2px);box-shadow:0 5px 12px rgba(16,40,50,.24)}
/* Baris tabel muncul lembut */
tbody tr{animation:rowIn .3s ease both}
@keyframes rowIn{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){tbody tr{animation:none}}

/* ================= FILE KONTRAK ================= */
/* Submenu bertingkat (flyout ke KANAN, tak terbatas kedalamannya) — dibuka saat
   mouse berada di atas menu (hover), sekaligus tetap bisa diklik untuk mobile/sentuh. */
.topnav-sub{display:flex;flex-direction:column;position:relative}
.topnav-subtrigger{appearance:none;width:100%;background:none;border:none;text-align:left;padding:10px 12px;font-family:'Plus Jakarta Sans';font-size:12px;font-weight:700;color:var(--ink);display:flex;align-items:center;gap:11px;border-radius:10px;cursor:pointer;transition:background .16s ease,color .16s ease}
.topnav-subtrigger>svg:first-child{width:16px;height:16px;color:var(--teal);flex:0 0 auto;transition:transform .16s ease}
.topnav-subtrigger .sub-label{flex:1 1 auto}
.topnav-subtrigger .caret2{width:13px;height:13px;flex:0 0 auto;opacity:.8;transition:transform .22s cubic-bezier(.34,1.56,.64,1);transform:rotate(-90deg)}
.topnav-subtrigger:hover{background:var(--teal-soft);color:var(--teal-dark)}
.topnav-subtrigger:hover>svg:first-child{transform:scale(1.1)}
.topnav-sub.open>.topnav-subtrigger{background:var(--teal-soft);color:var(--teal-dark)}
.topnav-sub.open>.topnav-subtrigger .caret2{transform:rotate(0deg)}
.topnav-subdrop{display:none;flex-direction:column;gap:3px;position:absolute;top:-8px;left:calc(100% + 10px);min-width:222px;background:linear-gradient(180deg,#ffffff,#fbfdfe);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-lg);padding:8px;z-index:90;animation:dropIn .18s cubic-bezier(.16,1,.3,1)}
.topnav-sub.open>.topnav-subdrop{display:flex}
.topnav-subdrop::before{content:"";position:absolute;top:16px;left:-6px;width:11px;height:11px;background:#fff;border-left:1px solid var(--line);border-bottom:1px solid var(--line);transform:rotate(45deg)}
.topnav-subdrop.flip-left{left:auto;right:calc(100% + 10px)}
.topnav-subdrop.flip-left::before{left:auto;right:-6px;border-left:none;border-bottom:none;border-right:1px solid var(--line);border-top:1px solid var(--line)}
.topnav-subdrop .topnav-item{font-weight:600}
@media (max-width:1024px){
  .topnav-subtrigger{color:rgba(255,255,255,.9)}
  .topnav-subtrigger>svg:first-child{color:rgba(255,255,255,.65)}
  .topnav-subtrigger:hover,.topnav-sub.open>.topnav-subtrigger{background:rgba(255,255,255,.1);color:#fff}
}
@media (max-width:1024px){
  .topnav-sub{position:static}
  .topnav-subtrigger .caret2{transform:rotate(-90deg)}
  .topnav-sub.open>.topnav-subtrigger .caret2{transform:rotate(0deg)}
  .topnav-subdrop{position:static;min-width:0;box-shadow:none;border:none;background:rgba(255,255,255,.06);margin:2px 0 4px 8px;padding:4px;left:auto;right:auto;top:auto}
  .topnav-subdrop::before{display:none}
}
/* Segmented switcher (Jenis Pekerjaan) */
.fk-seg{display:inline-flex;gap:4px;padding:5px;background:linear-gradient(180deg,#ffffff,#f3f8f9);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);flex-wrap:wrap;position:relative}
.fk-seg-btn{appearance:none;border:none;background:none;font-family:'Plus Jakarta Sans';font-size:11.5px;font-weight:700;color:var(--muted);padding:9px 16px;border-radius:10px;cursor:pointer;display:inline-flex;align-items:center;gap:8px;transition:color .18s ease,transform .16s cubic-bezier(.16,1,.3,1);white-space:nowrap;position:relative;z-index:1}
.fk-seg-btn svg{width:15px;height:15px;flex:0 0 auto}
.fk-seg-btn:not(.active):hover{background:var(--teal-soft);color:var(--teal-dark)}
.fk-seg-btn.active{background:none;color:#fff}
.fk-seg-btn.active:hover{color:#fff}
.fk-seg-thumb{position:absolute;top:5px;bottom:5px;left:0;width:0;border-radius:10px;background:linear-gradient(135deg,var(--teal),var(--cyan));box-shadow:0 5px 14px rgba(14,124,134,.32);transition:transform .38s cubic-bezier(.16,1,.3,1),width .38s cubic-bezier(.16,1,.3,1),opacity .18s ease;z-index:0;pointer-events:none;opacity:0}
/* Pop 3D saat tab segmen dipilih: tombol terangkat & menekan dalam perspektif */
.fk-seg{perspective:720px}
@keyframes segPop{
  0%{transform:perspective(520px) translateZ(0) scale(1) rotateX(0)}
  32%{transform:perspective(520px) translateZ(20px) scale(1.10) rotateX(-9deg)}
  62%{transform:perspective(520px) translateZ(7px) scale(.975) rotateX(3.5deg)}
  100%{transform:perspective(520px) translateZ(0) scale(1) rotateX(0)}
}
.fk-seg-btn.seg-pop{animation:segPop .44s cubic-bezier(.22,1,.36,1);z-index:3}
.fk-seg-thumb.no-anim{transition:none}
/* Toggle modul di kanan atas tabel */
.head-right-tools{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:flex-end}
.head-left-tools{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.head-left-tools h2{margin:0}
.mod-seg{padding:4px;border-radius:12px}
.mod-seg .fk-seg-btn{font-size:11px;padding:7px 12px}
.mod-seg .fk-seg-btn svg{width:14px;height:14px}
.mod-seg .fk-seg-thumb{top:4px;bottom:4px}
/* Jadwal Pelaksanaan Pekerjaan (tabel tahapan pengadaan) — dirapikan & dipercantik */
.jp-table{border-left:4px solid var(--teal)}
.jp-table thead th{background:var(--teal);color:#fff;text-transform:uppercase;font-weight:800;font-size:10.5px;letter-spacing:.2px;border-color:#0b6b74}
tr.jp-row-hi td{background:#f2ecd9}
.jp-in-nama,.jp-in-ket{width:100%;border:1px solid var(--line);border-radius:8px;padding:6px 8px;font-family:'Plus Jakarta Sans';font-size:11.5px;transition:border-color .15s ease,box-shadow .15s ease}
.jp-in-nama:focus,.jp-in-ket:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px var(--teal-soft)}
/* Kolom TAHAPAN PENGADAAN diperlebar dengan ruang hasil pengecilan input Jam */
.jp-in-nama{min-width:255px}
/* Kolom Awal / Akhir: input Tanggal + Jam berdampingan */
.jp-dt{white-space:nowrap}
.jp-dt input{border:1px solid var(--line);border-radius:7px;padding:5px 7px;font-size:11px;background:#fff;width:auto;display:inline-block}
.jp-dt .jp-dt-tgl{width:108px;margin-right:4px}
.jp-dt .jp-dt-jam{width:86px;padding-left:6px;padding-right:4px}
.jp-awal-val{font-weight:700;color:#0d2a30;font-size:11.5px;white-space:nowrap}
.jp-aksi{display:flex;gap:4px;justify-content:center}
.jp-aksi button{border:none;background:var(--teal-soft);color:var(--teal-dark);border-radius:8px;width:26px;height:26px;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.jp-aksi button svg{width:14px;height:14px}
.jp-aksi button:hover{background:var(--teal);color:#fff}
/* Ringkasan jadwal (hero kecil di atas tabel) */
.jp-summary{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
.jp-summary-card{flex:1 1 160px;display:flex;align-items:center;gap:10px;background:linear-gradient(180deg,#ffffff,#f4fafb);border:1px solid var(--line);border-radius:14px;padding:12px 14px;box-shadow:var(--shadow)}
.jp-summary-card .ic{flex:0 0 auto;width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;background:var(--teal-soft);color:var(--teal-dark)}
.jp-summary-card .ic svg{width:18px;height:18px}
.jp-summary-card .txt b{display:block;font-size:12.5px;font-weight:800;color:#0d2a30;line-height:1.3}
.jp-summary-card .txt span{display:block;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;color:var(--muted)}
/* Kartu ke-3: tombol aksi Profil Jadwal (Simpan / Muat / Batalkan) */
/* Kartu 1 & 2 dipersempit agar kartu Profil muat 3 tombol dalam satu baris */
.jp-summary > .jp-summary-card:not(.jp-profil-card){flex:0 1 230px;min-width:0}
/* Kartu Profil tanpa kotak latar: hanya deretan tombol */
.jp-profil-card{flex:1 1 auto;min-width:0;gap:8px;flex-wrap:nowrap;justify-content:flex-end;background:none;border:none;box-shadow:none;padding:0 0 0 6px}
.jp-profil-btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:10px;padding:7px 11px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:10.5px;cursor:pointer;transition:.15s;background:#fff;color:#33454b;white-space:nowrap}
.jp-profil-btn svg{width:15px;height:15px;flex:0 0 auto}
.jp-profil-btn:hover{transform:translateY(-1px)}
.jp-profil-btn.is-save{background:linear-gradient(135deg,var(--yellow,#F6B40E),#ffd35a);border-color:#e2a70c;color:#5c4a00}
.jp-profil-btn.is-load{background:linear-gradient(135deg,var(--teal),var(--teal-dark));border-color:#0b6a73;color:#fff}
.jp-profil-btn.is-cancel{background:linear-gradient(135deg,#d33a3a,#e25151);border-color:#c33;color:#fff}
@media(max-width:1180px){.jp-profil-btn span{display:none}.jp-profil-btn{padding:8px 10px}}
@media(max-width:760px){.jp-summary > .jp-summary-card:not(.jp-profil-card){flex:1 1 100%}.jp-profil-card{flex:1 1 100%;flex-wrap:wrap}.jp-profil-btn span{display:inline}}
.jp-actions{margin-top:14px;display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-end}
/* Titik Mulai Jadwal — strip acuan awal jadwal di kartu Data Pekerjaan */
.jp-start-row{margin-top:14px;padding:13px 15px;border:1px solid #bfe3e6;border-radius:12px;background:linear-gradient(180deg,#f2fbfb,#e8f6f7);display:flex;flex-wrap:wrap;align-items:flex-end;gap:12px 18px}
.jp-start-lead{display:flex;align-items:center;gap:9px;flex:1 1 100%;font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;color:#0b5a62}
.jp-start-lead svg{width:17px;height:17px;flex:0 0 auto;color:var(--teal-dark)}
.jp-start-lead .tag{font-family:'Plus Jakarta Sans';font-weight:600;font-size:9.5px;letter-spacing:.2px;color:#fff;background:var(--teal);padding:3px 9px;border-radius:999px}
.jp-start-field{display:flex;flex-direction:column;gap:6px;flex:0 1 210px;min-width:150px}
.jp-start-field label{font-size:10.5px;font-weight:700;color:#0b5a62}
.jp-start-field input{width:100%;border:1px solid #bcd9dc;background:#fff;border-radius:11px;padding:10px 12px;font-family:inherit;font-size:12px;color:var(--ink);box-shadow:0 1px 2px rgba(16,40,50,.05)}
.jp-start-field input:hover{border-color:#95c7cc}
.jp-start-field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.16),0 4px 12px rgba(14,124,134,.14);background:#fff}
.jp-start-hint{flex:1 1 100%;font-size:11px;line-height:1.55;color:#3e6a6f;margin-top:2px}
.jp-start-hint b{color:#0b5a62}
@media(max-width:640px){.jp-start-field{flex:1 1 100%}}
/* Hari Libur — tabel & toolbar dirapikan */
tr.hl-weekend td{background:#f5f8fb}
.hl-toolbar{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap}
.hl-toolbar .field{flex:1 1 180px}
.hl-toolbar .btn{flex:0 0 auto;height:38px}
.hl-tpl-bar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:16px;margin-bottom:20px;
  background:linear-gradient(135deg,#f4fbfb 0%,#eaf6f7 55%,#f6fbf3 100%);
  border:1px solid #d3e7e9;border-radius:16px;padding:14px 18px;
  box-shadow:0 1px 2px rgba(16,40,50,.05),0 10px 26px rgba(14,124,134,.10),inset 0 1px 0 rgba(255,255,255,.7)}
.hl-tpl-icon{flex:0 0 auto;width:42px;height:42px;border-radius:12px;background:linear-gradient(135deg,var(--teal),var(--cyan));display:flex;align-items:center;justify-content:center;color:#fff;box-shadow:0 4px 12px rgba(14,124,134,.28)}
.hl-tpl-icon svg{width:22px;height:22px}
.hl-tpl-txt{flex:1 1 220px;display:flex;flex-direction:column;gap:2px;min-width:200px}
.hl-tpl-txt b{font-size:13px;color:#0d2a30;font-weight:800}
.hl-tpl-txt span{font-size:10.5px;color:var(--muted);font-weight:600;line-height:1.4}
.hl-tpl-actions{display:flex;gap:10px;flex-wrap:wrap;margin-left:auto}
@media(max-width:640px){
  .hl-tpl-bar{justify-content:center;text-align:center}
  .hl-tpl-actions{width:100%;margin-left:0}
  .hl-tpl-actions .btn{flex:1 1 auto;justify-content:center}
}
@media(max-width:900px){.head-right-tools{width:100%}.mod-seg{width:100%}.mod-seg .fk-seg-btn{flex:1 1 auto;justify-content:center}}
/* Mobile ≤640px: tab modul (SPBJ/Kontrak Rinci · Pengadaan Langsung · Tender)
   di-stack vertikal penuh agar tidak berdesakan/menumpuk. "Thumb" (pil geser
   absolut yang mengasumsikan satu baris) disembunyikan; tab aktif diberi latar
   teal langsung supaya tetap terlihat aktif. */
@media(max-width:640px){
  .mod-seg{flex-direction:column;align-items:stretch;flex-wrap:nowrap}
  .mod-seg .fk-seg-btn{width:100%;flex:0 0 auto;justify-content:center;padding:10px 12px}
  .mod-seg .fk-seg-thumb{display:none!important}
  .mod-seg .fk-seg-btn.active{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;box-shadow:0 5px 14px rgba(14,124,134,.32)}
}
/* Kolom & sel File Kontrak */
/* Kolom Bidang Pelaksana mengacu ukuran tabel Monitoring - Daftar Pekerjaan (col-bidang): lebar tetap 200px + wrap */
.fk-col-bidang{width:200px;min-width:200px;max-width:200px;text-align:center;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
#view-fk-input .table-wrap th.fk-col-bidang,
#view-fk-input .table-wrap td.fk-col-bidang,
#view-fk-view .table-wrap th.fk-col-bidang,
#view-fk-view .table-wrap td.fk-col-bidang{width:200px;min-width:200px;max-width:200px;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
/* Kolom Penyedia — mengikuti perlakuan Bidang Pelaksana (boleh turun baris) */
.fk-col-penyedia{width:220px;min-width:220px;max-width:220px;text-align:center;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
#view-fk-input .table-wrap th.fk-col-penyedia,
#view-fk-input .table-wrap td.fk-col-penyedia,
#view-fk-view .table-wrap th.fk-col-penyedia,
#view-fk-view .table-wrap td.fk-col-penyedia{width:220px;min-width:220px;max-width:220px;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3}
/* Tender: beberapa penyedia ditumpuk seperti kolom No. Kontrak */
.table-wrap td.fk-col-penyedia.wrap-penyedia{text-align:left}
.table-wrap td.fk-col-penyedia .stack-line{white-space:normal}
/* Nama Pekerjaan pada File Kontrak dilebarkan +60px (tanpa mengubah tabel Monitoring) */
#view-fk-input .table-wrap th.col-nama-freeze,#view-fk-input .table-wrap td.col-nama-freeze,
#view-fk-view .table-wrap th.col-nama-freeze,#view-fk-view .table-wrap td.col-nama-freeze{min-width:300px;max-width:360px}
/* Kolom No. & Nama Pekerjaan (freeze) — garis pemisah judul disamakan halus di semua tabel
   (File Kontrak, Penetapan, Kelengkapan): hanya garis bawah tipis, tanpa garis vertikal tebal. */
#view-fk-input .table-wrap thead th.col-no,#view-fk-view .table-wrap thead th.col-no,
#view-pn-lihat .table-wrap thead th.col-no,#view-fkl-view .table-wrap thead th.col-no,
#view-fk-input .table-wrap thead th.col-nama-freeze,#view-fk-view .table-wrap thead th.col-nama-freeze,
#view-pn-lihat .table-wrap thead th.col-nama-freeze,#view-fkl-view .table-wrap thead th.col-nama-freeze{
  box-shadow:inset 0 -1px 0 rgba(255,255,255,.10);
}
.fk-actions{display:flex;align-items:center;justify-content:center;gap:9px;flex-wrap:wrap}
.fk-act{border:none;border-radius:10px;padding:8px 14px;font-family:'Plus Jakarta Sans';font-size:11px;font-weight:700;letter-spacing:.2px;display:inline-flex;align-items:center;gap:7px;cursor:pointer;color:#fff;transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .22s ease,filter .2s ease;white-space:nowrap;box-shadow:0 3px 9px rgba(16,40,50,.14)}
.fk-act svg{width:14px;height:14px;flex:0 0 auto}
.fk-act:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(16,40,50,.22)}
.fk-act:active{transform:translateY(0) scale(.98)}
.fk-act-up{background:linear-gradient(135deg,var(--teal),var(--cyan))}
.fk-act-replace{background:linear-gradient(135deg,var(--yellow),#ffca3a);color:#5a3d00;box-shadow:0 3px 9px rgba(246,180,14,.3)}
.fk-act-dl{background:linear-gradient(135deg,var(--green),#28b466)}
.fk-act-view{background:linear-gradient(135deg,var(--teal),var(--cyan))}
.fk-act-del{background:linear-gradient(135deg,var(--red),#e25151)}
.fk-act[disabled]{background:linear-gradient(135deg,#c3ced4,#d6dee2);color:#fff;cursor:not-allowed;box-shadow:none;transform:none;filter:none;opacity:.85}
.fk-act.is-busy{cursor:progress;opacity:.75;pointer-events:none}
.fk-act-icon{padding:9px;width:36px;height:36px;justify-content:center;gap:0}
.fk-act-icon svg{width:16px;height:16px}
.fk-actcell{position:relative;transition:background .16s ease}
.fk-actcell.fk-drop-over{background:rgba(20,166,177,.14);outline:2px dashed var(--teal);outline-offset:-4px;border-radius:10px}
.fk-actcell.fk-drop-over .fk-act-up{transform:translateY(-2px) scale(1.04);box-shadow:0 8px 22px rgba(16,40,50,.3)}
/* Popup Unggah File Kontrak — kotak drag & drop / telusuri (efek 3D) */
.fk-upload-modal{max-width:460px}
.fk-up-body{padding:26px 24px 30px;perspective:900px}
.fk-dropzone{
  position:relative;border:2px dashed var(--teal);border-radius:18px;padding:36px 20px;text-align:center;cursor:pointer;
  background:linear-gradient(180deg,#f3fbfc,#e2f1f3);
  transform-style:preserve-3d;transform:translateZ(0);
  box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 -6px 14px rgba(14,124,134,.06) inset,
             0 14px 26px -10px rgba(14,90,100,.38),0 6px 10px -6px rgba(14,90,100,.26);
  transition:transform .22s cubic-bezier(.16,1,.3,1),box-shadow .22s ease,background .18s ease,border-color .18s ease;
  outline:none
}
.fk-dropzone:hover{
  background:linear-gradient(180deg,#f7fdfd,#dbeff1);
  transform:translateY(-4px) rotateX(6deg) scale(1.012);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset,0 -6px 14px rgba(14,124,134,.06) inset,
             0 28px 46px -14px rgba(14,90,100,.5),0 10px 16px -8px rgba(14,90,100,.3)
}
.fk-dropzone:focus-visible{box-shadow:0 0 0 3px rgba(20,166,177,.4),0 18px 32px -12px rgba(14,90,100,.45)}
.fk-dropzone.fk-dz-over{
  background:linear-gradient(180deg,#d2ebee,#c1e3e6);border-color:var(--teal-dark);
  transform:translateY(2px) rotateX(0) scale(.995);
  box-shadow:0 2px 0 rgba(255,255,255,.6) inset,0 12px 26px -12px rgba(14,90,100,.5) inset,
             0 5px 10px -8px rgba(14,90,100,.3)
}
.fk-dz-ic{transform:translateZ(30px)}
.fk-dz-ic svg{width:48px;height:48px;color:var(--teal-dark);filter:drop-shadow(0 8px 10px rgba(14,90,100,.28));transition:transform .22s cubic-bezier(.16,1,.3,1)}
.fk-dropzone:hover .fk-dz-ic svg{transform:translateY(-3px)}
.fk-dropzone.fk-dz-over .fk-dz-ic svg{transform:translateY(-6px) scale(1.08)}
.fk-dz-title{font-weight:800;color:#16242c;margin-top:12px;font-size:15px;text-shadow:0 1px 0 rgba(255,255,255,.7)}
.fk-dz-sub{color:#3d5560;margin-top:4px;font-size:13px}
.fk-dz-sub b{color:var(--teal-dark)}
.fk-dz-hint{color:#6f858e;margin-top:12px;font-size:12px}
/* Chip nama file terunggah */
.fk-file-chip{display:inline-flex;align-items:center;gap:7px;max-width:260px;padding:6px 11px;border-radius:9px;background:linear-gradient(180deg,#eef8f9,#e2f2f3);border:1px solid #bfe2e5;color:var(--teal-dark);font-size:11px;font-weight:700}
.fk-file-chip svg{width:14px;height:14px;flex:0 0 auto;color:var(--teal)}
.fk-file-chip .fk-file-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fk-file-chip .fk-file-size{font-weight:600;color:var(--muted);flex:0 0 auto}
.fk-none{display:inline-flex;align-items:center;gap:7px;color:var(--muted);font-size:11.5px;font-weight:600;font-style:italic}
.fk-none svg{width:14px;height:14px;opacity:.7}
.fk-namecell{font-weight:400;color:var(--ink)}
.fk-hint{color:var(--muted);font-size:12px;margin:-2px 0 0}
@media (max-width:720px){ .fk-file-chip{max-width:150px} }


/* ================= Penetapan Nomor ================= */
.pn-seg-wrap{display:flex;align-items:flex-end}
.pn-col-bidang{width:110px;min-width:110px;max-width:120px;text-align:center;white-space:normal;word-break:break-word}
.pn-col-jenis{width:180px;min-width:180px;max-width:180px;vertical-align:top;padding-top:0;padding-bottom:0}
.pn-col-nomor{width:300px;min-width:300px;max-width:300px;vertical-align:top;padding-top:0;padding-bottom:0}
.pn-col-tgl{width:104px;min-width:98px;max-width:112px;vertical-align:top;text-align:center;padding-top:0;padding-bottom:0}
.pn-col-aksi{width:150px;min-width:150px;max-width:160px;vertical-align:top;padding-top:0;padding-bottom:0}
/* Header kolom per-nomor tetap rata tengah (vertikal & horizontal) */
#view-pn-lihat .table-wrap thead th.pn-col-jenis,
#view-pn-lihat .table-wrap thead th.pn-col-nomor,
#view-pn-lihat .table-wrap thead th.pn-col-tgl,
#view-pn-lihat .table-wrap thead th.pn-col-aksi{vertical-align:middle;text-align:center;padding-top:11px;padding-bottom:11px}
#view-pn-lihat .table-wrap th.col-nama-freeze,#view-pn-lihat .table-wrap td.col-nama-freeze{min-width:210px;max-width:280px}
/* Nama Pekerjaan & No. — data tunggal diposisikan di tengah tinggi baris */
#view-pn-lihat .table-wrap td.col-no,#view-pn-lihat .table-wrap td.col-nama-freeze{vertical-align:middle}
/* ---- Lihat Nomor TENDER: kunci ukuran tabel & sesuaikan kolom ---- */
/* Layout auto agar kolom Jenis Dokumen menyusut PAS ke label terpanjang
   (tanpa sisa ruang). Kolom lain tetap terkunci lewat min/max-width. */
#view-pn-lihat.pn-modul-tender .table-wrap table{table-layout:auto;width:auto;min-width:100%}
/* Nama Pekerjaan: data rata kiri & vertikal tengah; JUDUL tetap rata tengah */
#view-pn-lihat.pn-modul-tender .table-wrap td.col-nama-freeze{
  text-align:left;vertical-align:middle;white-space:normal;
  word-break:break-word;overflow-wrap:break-word;
  width:260px;min-width:260px;max-width:260px}
#view-pn-lihat.pn-modul-tender .table-wrap th.col-nama-freeze{
  text-align:center;vertical-align:middle;white-space:normal;
  width:260px;min-width:260px;max-width:260px}
/* Jenis Dokumen: lebar mengikuti nama dokumen terpanjang (satu baris, pas ke isi) */
#view-pn-lihat.pn-modul-tender .table-wrap th.pn-col-jenis,
#view-pn-lihat.pn-modul-tender .table-wrap td.pn-col-jenis{
  width:1px;min-width:0;max-width:none;white-space:nowrap}
#view-pn-lihat.pn-modul-tender td.pn-col-jenis .pn-nomor-list{width:max-content}
#view-pn-lihat.pn-modul-tender td.pn-col-jenis .pn-nomor-item{width:100%;overflow:visible}
#view-pn-lihat.pn-modul-tender .pn-nomor-jenis{flex:0 0 auto;width:auto;white-space:nowrap;overflow:visible;text-overflow:clip}
/* Pertegas border vertikal antar kolom pada tabel Lihat Nomor */
#view-pn-lihat .table-wrap table{border-collapse:collapse}
#view-pn-lihat .table-wrap th,#view-pn-lihat .table-wrap td{border-left:1px solid #fff;border-right:1px solid #fff}
#view-pn-lihat .table-wrap thead th{border-left-color:#fff;border-right-color:#fff}
/* Garis pembatas antar pekerjaan (antar baris) — tipis */
#view-pn-lihat .table-wrap tbody td{border-top:1px solid #fff;border-bottom:1px solid #fff}
/* ==== Tabel Monitoring (Daftar Kontrak Rinci / Pengadaan Langsung / Tender)
   + File Kontrak & Kelengkapan — border kolom & baris disamakan (tipis, warna sama) ==== */
#view-list .table-wrap table,#view-list-pl .table-wrap table,#view-list-tender .table-wrap table,
#view-fk-input .table-wrap table,#view-fk-view .table-wrap table,#view-fkl-view .table-wrap table{border-collapse:collapse}
#view-list .table-wrap th,#view-list .table-wrap td,
#view-list-pl .table-wrap th,#view-list-pl .table-wrap td,
#view-list-tender .table-wrap th,#view-list-tender .table-wrap td,
#view-fk-input .table-wrap th,#view-fk-input .table-wrap td,
#view-fk-view .table-wrap th,#view-fk-view .table-wrap td,
#view-fkl-view .table-wrap th,#view-fkl-view .table-wrap td{border-left:1px solid #fff;border-right:1px solid #fff}
#view-list .table-wrap thead th,
#view-list-pl .table-wrap thead th,
#view-list-tender .table-wrap thead th,
#view-fk-input .table-wrap thead th,
#view-fk-view .table-wrap thead th,
#view-fkl-view .table-wrap thead th{border-left-color:#fff;border-right-color:#fff}
#view-list .table-wrap tbody td,
#view-list-pl .table-wrap tbody td,
#view-list-tender .table-wrap tbody td,
#view-fk-input .table-wrap tbody td,
#view-fk-view .table-wrap tbody td,
#view-fkl-view .table-wrap tbody td{border-top:1px solid #fff;border-bottom:1px solid #fff}
/* Daftar per masing-masing nomor dokumen — SATU BARIS per nomor (tanpa wrap),
   tinggi seragam & ringkas, data di tengah baris. */
.pn-nomor-list{display:flex;flex-direction:column;gap:0;padding:0}
.pn-nomor-item{display:flex;align-items:center;justify-content:flex-start;gap:8px;height:40px;min-height:40px;max-height:40px;flex:0 0 40px;padding:0;position:relative;box-sizing:border-box;overflow:hidden}
/* Garis pemisah elegan antar No. Dokumen */
.pn-nomor-item:not(:last-child)::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:linear-gradient(90deg,transparent,rgba(14,124,134,.28) 18%,rgba(14,124,134,.28) 82%,transparent)}
.pn-jenis-item{align-items:center}
.pn-tgl-item{justify-content:center}
.pn-aksi-item{align-items:center;justify-content:center}
/* Jenis & No. Dokumen — satu baris, dipotong halus (…) bila terlalu panjang */
.pn-nomor-jenis{flex:1 1 auto;width:100%;font-family:'Plus Jakarta Sans';font-size:11px;font-weight:700;color:var(--teal-dark);line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-nomor-val{font-family:'Plus Jakarta Sans',monospace;font-weight:600;font-size:11px;color:var(--ink);line-height:1.3;flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-tgl-val{font-family:'Plus Jakarta Sans';font-size:11px;color:var(--ink);white-space:nowrap}
.pn-copy{appearance:none;border:none;background:none;cursor:pointer;color:var(--muted);padding:2px;border-radius:6px;flex:0 0 auto;transition:background .15s,color .15s}
.pn-copy:hover{color:var(--teal);background:var(--teal-soft)}
.pn-copy.pn-copied{color:var(--green)}
.pn-copy svg{width:13px;height:13px;display:block}
.pn-actions{display:flex;align-items:center;justify-content:center;gap:6px;flex-wrap:wrap}
.pn-aksi-item .pn-actions{width:100%;flex-wrap:nowrap}
.pn-aksi-item .pn-actions .act{width:29px;height:29px}
.pn-aksi-item .pn-actions .act svg{width:15px;height:15px}
.pn-act-view{background:linear-gradient(135deg,#5a6b96,#7385ad)}
/* Tombol aksi ikon Penetapan Nomor */
.pn-actions .act.act-up{background:linear-gradient(135deg,#5a6b96,#7385ad)}
.pn-actions .act.act-dl{background:linear-gradient(135deg,var(--green),#28b466)}
.pn-actions .act[disabled]{background:linear-gradient(135deg,#c3ced4,#d6dee2)!important;color:#fff;cursor:not-allowed;box-shadow:none;transform:none;opacity:.7}
.pn-actions .act[disabled]:hover{transform:none;box-shadow:none}
.pn-actions .act.is-busy{cursor:progress;opacity:.7;pointer-events:none}
/* Pratinjau file (PDF/gambar) */
.pn-preview-modal{max-width:980px;width:min(980px,95vw);padding:0;display:flex;flex-direction:column;max-height:92vh}
.pn-preview-head-actions{display:flex;align-items:center;gap:10px}
.pn-preview-head-actions .btn{padding:8px 14px;font-size:11px}
.pn-preview-body{flex:1 1 auto;min-height:0;background:#eef2f4;overflow:auto;display:flex}
.pn-preview-body iframe{width:100%;height:74vh;border:none;background:#fff}
.pn-preview-body.has-tabs iframe{height:calc(74vh - 46px)}
.pn-preview-modal.is-max .pn-preview-body.has-tabs iframe{height:calc(100vh - 62px - 46px)}
/* Tab pemilih dokumen (Harga Satuan / Analisa Harga Satuan Pekerjaan) di modal pratinjau Konstruksi */
.ana-doc-tabs{display:flex;gap:8px;padding:12px 16px;background:#f3f7f8;border-bottom:1px solid #dde9eb}
.ana-doc-tab{border:1px solid #cdd9de;background:#fff;color:#5a6b70;font-size:11px;font-weight:700;padding:8px 16px;border-radius:20px;cursor:pointer;font-family:'Plus Jakarta Sans';transition:background .15s,color .15s,border-color .15s,box-shadow .15s,transform .1s}
.ana-doc-tab:hover{border-color:var(--teal);color:var(--teal-dark)}
.ana-doc-tab:active{transform:scale(.97)}
.ana-doc-tab.active{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;border-color:var(--teal);box-shadow:0 3px 10px rgba(14,124,134,.3)}
.pn-preview-body img{max-width:100%;max-height:74vh;margin:auto;display:block;object-fit:contain}
/* Mode layar penuh (maximize) */
.pn-preview-modal.is-max{max-width:100vw;width:100vw;height:100vh;max-height:100vh;border-radius:0}
.pn-preview-modal.is-max .pn-preview-body iframe{height:calc(100vh - 62px)}
.pn-preview-modal.is-max .pn-preview-body img{max-height:calc(100vh - 62px)}
.pn-preview-nofile{margin:auto;text-align:center;color:var(--muted);padding:52px 24px}
.pn-preview-nofile svg{width:46px;height:46px;opacity:.5}
.pn-preview-nofile .fn{font-weight:700;color:var(--ink);margin-top:12px;word-break:break-all;font-size:13px}
@media(max-width:640px){.pn-preview-body iframe,.pn-preview-body img{height:64vh;max-height:64vh}}
/* Ambil Nomor — hasil */
.pn-result{margin-top:16px;border-color:#cfe6e3;background:linear-gradient(180deg,#ffffff,#f4fbfa)}
/* Checklist dokumen Tender */
.pn-doc-bar{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-top:20px;padding-top:16px;border-top:1px solid var(--line);flex-wrap:wrap}
.pn-doc-toggle{position:relative}
.pn-doc-toggle svg:first-child{width:16px;height:16px}
.pn-doc-caret{width:15px!important;height:15px!important;transition:transform .3s cubic-bezier(.16,1,.3,1)}
.pn-doc-toggle.open .pn-doc-caret{transform:rotate(180deg)}
.pn-doc-count{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:20px;background:rgba(255,255,255,.28);font-size:11px;font-weight:800}
.pn-doc-save{margin-left:0}
/* Doc-bar dipindah ke dalam baris grid (menggantikan posisi Bidang Pelaksana) */
.pn-doc-bar-field{display:flex;flex-direction:column}
.pn-doc-bar-field .pn-doc-bar{margin-top:0;padding-top:0;border-top:none;justify-content:flex-start;flex-wrap:nowrap;gap:10px}
.pn-doc-bar-field .pn-doc-toggle,.pn-doc-bar-field .pn-doc-save{flex:1 1 0;min-width:0;justify-content:center}
/* Kolaps daftar dokumen */
.pn-doc-collapse{height:0;overflow:hidden;opacity:0;transform:translateY(-4px);transition:height .34s cubic-bezier(.16,1,.3,1),opacity .28s ease,transform .34s cubic-bezier(.16,1,.3,1)}
.pn-doc-collapse.open{opacity:1;transform:none}
.pn-doc-collapse-inner{padding-top:16px}
.pn-check-head{display:flex;align-items:center;gap:10px;margin:0 0 12px}
.pn-check-head small{color:var(--muted);font-size:11.5px;font-weight:500}
.pn-check-all{margin-left:auto;appearance:none;border:1px solid var(--teal);background:#fff;color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;padding:6px 14px;border-radius:9px;cursor:pointer;transition:background .16s,color .16s}
.pn-check-all:hover{background:var(--teal);color:#fff}
.pn-check-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 22px}
@media(max-width:760px){.pn-check-grid{grid-template-columns:1fr}}
/* #3: Checklist dokumen dikelompokkan (Bagian I. Pengadaan Langsung, II. Tender) */
.pn-doc-grouped{display:block}
.pn-doc-group+.pn-doc-group{margin-top:16px}
.pn-doc-group-title{display:flex;align-items:center;gap:9px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;color:var(--teal-dark);text-transform:uppercase;letter-spacing:.4px;margin:0 0 10px;padding-bottom:7px;border-bottom:1px solid var(--line)}
.pn-doc-group-title .pn-grp-badge{flex:0 0 auto;font-size:10px;font-weight:800;color:#fff;background:linear-gradient(135deg,var(--teal),var(--cyan));border-radius:7px;padding:3px 8px}
.pn-check-item{display:flex;align-items:flex-start;gap:10px;padding:9px 12px;border:1px solid var(--line);border-radius:11px;cursor:pointer;transition:border-color .16s,background .16s;background:#fff}
.pn-check-item:hover{border-color:var(--teal);background:var(--teal-soft)}
.pn-check-item input{position:absolute;opacity:0;width:0;height:0}
.pn-check-box{flex:0 0 auto;width:19px;height:19px;border-radius:6px;border:2px solid #c2d3d6;display:flex;align-items:center;justify-content:center;transition:background .16s,border-color .16s;margin-top:1px}
.pn-check-box svg{width:12px;height:12px;color:#fff;opacity:0;transition:opacity .14s}
.pn-check-item input:checked+.pn-check-box{background:linear-gradient(135deg,var(--teal),var(--cyan));border-color:var(--teal)}
.pn-check-item input:checked+.pn-check-box svg{opacity:1}
.pn-check-item input:checked~.pn-check-label{color:var(--ink)}
.pn-check-label{font-family:'Plus Jakarta Sans';font-size:12px;font-weight:600;color:#4b5b60;line-height:1.35}
/* Nomor & teks dipisah: label yang panjang membungkus dengan indentasi menggantung,
   sehingga baris ke-2 dst. sejajar dengan baris pertama SESUDAH nomor — bukan
   kembali ke bawah nomornya. Nomor rata kanan agar titiknya lurus antar-baris. */
.pn-check-label{display:flex;align-items:baseline;gap:5px}
.pn-check-no{flex:0 0 auto;min-width:1.7em;text-align:right;font-variant-numeric:tabular-nums}
.pn-check-txt{flex:1 1 auto;min-width:0}
.pn-check-label em{font-style:normal;font-weight:700;color:var(--teal-dark);font-size:11px}
/* ===== Modal pemilihan Dokumen (Ambil Nomor) ===== */
.pn-doc-modal{max-width:680px;text-align:left}
.pn-doc-modal-head{display:flex;align-items:center;gap:12px;padding:22px 26px 4px}
.pn-doc-modal-title{display:flex;align-items:center;gap:10px;font-family:'Plus Jakarta Sans';font-size:17px;font-weight:800;letter-spacing:-.2px;color:var(--teal-dark)}
.pn-doc-modal-title svg{width:20px;height:20px;color:var(--teal);flex:0 0 auto}
.pn-doc-modal-head .pn-check-all{margin-left:auto}
.pn-doc-modal-sub{padding:0 26px;margin:4px 0 0;color:var(--muted);font-size:12px;font-weight:500}
.pn-doc-modal-body{padding:16px 26px 4px;max-height:56vh;overflow:auto}
.pn-doc-modal-foot{display:flex;justify-content:flex-end;gap:10px;padding:16px 26px 22px}
.pn-doc-modal-foot .btn{flex:0 0 auto;padding:10px 22px;border-radius:11px;font-size:13px;font-weight:700;letter-spacing:.3px;transition:transform .14s ease,box-shadow .18s ease,filter .18s ease}
.pn-doc-modal-foot .btn:hover{transform:translateY(-1px);filter:brightness(1.03)}
.pn-doc-modal-foot .btn:active{transform:translateY(0) scale(.99)}
.pn-doc-modal-foot .btn svg{width:16px;height:16px}
/* Checkbox berada di sebelah kanan nama dokumen */
#pn-doc-modal-list .pn-check-item{align-items:flex-start}
#pn-doc-modal-list .pn-check-label{order:0;flex:1 1 auto}
#pn-doc-modal-list .pn-check-box{order:1;margin-top:1px}
/* Overlay progres unggah file */
.pn-upload-overlay{display:none;position:fixed;inset:0;z-index:200;background:rgba(7,63,69,.42);backdrop-filter:blur(3px);align-items:center;justify-content:center}
.pn-upload-overlay.show{display:flex}
.pn-upload-card{width:min(340px,90vw);background:#fff;border-radius:18px;padding:26px 24px 22px;box-shadow:0 24px 60px rgba(7,63,69,.32);text-align:center;animation:pnUpPop .28s cubic-bezier(.2,.9,.3,1.2)}
@keyframes pnUpPop{from{opacity:0;transform:translateY(10px) scale(.96)}to{opacity:1;transform:none}}
.pn-upload-anim{width:66px;height:66px;margin:0 auto 14px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 50% 40%,#e3f6f4,#cdeeea);position:relative}
.pn-upload-anim::after{content:"";position:absolute;inset:-4px;border-radius:50%;border:3px solid transparent;border-top-color:var(--teal);border-right-color:var(--teal);animation:pnUpSpin .9s linear infinite}
@keyframes pnUpSpin{to{transform:rotate(360deg)}}
.pn-upload-cloud{width:30px;height:30px;color:var(--teal-dark)}
.pn-upload-arrow{animation:pnUpArrow 1.1s ease-in-out infinite}
@keyframes pnUpArrow{0%,100%{transform:translateY(1.5px);opacity:.55}50%{transform:translateY(-1.5px);opacity:1}}
.pn-upload-title{font-family:'Plus Jakarta Sans';font-weight:700;font-size:14px;color:var(--ink)}
.pn-upload-fname{font-size:11.5px;color:var(--muted);margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-upload-barwrap{margin-top:16px;height:9px;border-radius:6px;background:#e6eff0;overflow:hidden;position:relative}
.pn-upload-bar{height:100%;width:0%;border-radius:6px;background:linear-gradient(90deg,var(--teal),var(--teal-dark));transition:width .18s ease;position:relative;overflow:hidden}
.pn-upload-bar::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.45),transparent);transform:translateX(-100%);animation:pnUpShine 1.2s ease-in-out infinite}
@keyframes pnUpShine{to{transform:translateX(100%)}}
.pn-upload-pct{margin-top:9px;font-family:'Plus Jakarta Sans';font-weight:700;font-size:13px;color:var(--teal-dark);letter-spacing:.3px}
/* Baris rincian unggahan: terkirim / total · kecepatan · perkiraan sisa waktu */
.pn-upload-stats{margin-top:6px;font-size:11px;font-weight:600;color:var(--muted);
  text-align:center;letter-spacing:.2px;line-height:1.5;min-height:16px}
.pn-result-sub{font-size:11px;color:var(--muted);margin:-6px 0 16px;line-height:1.6}
.pn-result-sub b{color:var(--ink)}
.pn-doc-card{border:1px solid var(--line);border-radius:12px;padding:12px 14px;display:flex;align-items:center;gap:12px;background:linear-gradient(180deg,#ffffff,#f8fcfc);margin-bottom:9px;box-shadow:var(--shadow)}
.pn-doc-card:last-child{margin-bottom:0}
.pn-doc-ic{width:34px;height:34px;flex:0 0 auto;border-radius:9px;display:grid;place-items:center;background:var(--teal-soft);color:var(--teal-dark)}
.pn-doc-ic svg{width:17px;height:17px}
.pn-doc-meta{flex:1 1 auto;min-width:0}
.pn-doc-label{font-size:10.5px;font-weight:600;color:var(--muted);margin-bottom:3px}
.pn-doc-no{font-family:'Plus Jakarta Sans',monospace;font-weight:700;font-size:13px;color:var(--teal-dark);word-break:break-all;line-height:1.4}
.pn-pending{padding:0}
.pn-pending .empty{padding:46px 24px}
.pn-pending-title{font-family:'Plus Jakarta Sans';font-weight:800;color:var(--ink);margin-top:6px;font-size:13px}
.pn-pending-desc{font-size:11px;color:var(--muted);max-width:460px;margin:8px auto 0;line-height:1.7}
@media(max-width:640px){
  .pn-seg-wrap{flex:1 1 100%}
  .pn-seg-wrap .fk-seg{width:100%}
  .pn-seg-wrap .fk-seg-btn{flex:1 1 auto;justify-content:center}
}

/* ================= FORM — KELENGKAPAN DOKUMEN PENGADAAN ================= */
/* ----- Stepper ----- */
.fkl-stepper{display:flex;align-items:center;gap:0;margin:2px 0 18px;flex-wrap:wrap}
.fkl-step{display:flex;align-items:center;gap:10px}
.fkl-step-dot{width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'Plus Jakarta Sans';font-weight:800;font-size:13px;background:#eef3f4;color:#9aabb0;border:1.5px solid var(--line);transition:.2s}
.fkl-step-dot svg{width:15px;height:15px}
.fkl-step-name{font-family:'Plus Jakarta Sans';font-size:12px;font-weight:700;color:#9aabb0;white-space:nowrap;transition:.2s}
.fkl-step.active .fkl-step-dot{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;border-color:var(--teal);box-shadow:0 4px 12px rgba(14,124,134,.32)}
.fkl-step.active .fkl-step-name{color:var(--ink)}
.fkl-step.done .fkl-step-dot{background:var(--teal-soft);color:var(--teal-dark);border-color:var(--teal)}
.fkl-step.done .fkl-step-name{color:var(--teal-dark)}
.fkl-step-line{flex:1 1 26px;min-width:22px;height:2px;background:var(--line);margin:0 10px;border-radius:2px}
.fkl-step-line.done{background:var(--teal)}
@media(max-width:640px){.fkl-step-name{display:none}.fkl-step-line{min-width:14px}}
/* ----- Grid pilihan dokumen ----- */
.fkl-hint{font-size:11.5px;color:var(--muted);margin:-2px 0 12px;line-height:1.5}
.fkl-hint b{color:var(--ink)}
.fkl-checkgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(var(--rows,9),auto);grid-auto-flow:column;gap:9px 20px}
@media(max-width:820px){.fkl-checkgrid{grid-template-columns:1fr;grid-template-rows:none;grid-auto-flow:row}}
.fkl-check{display:flex;align-items:center;gap:11px;padding:10px 13px;border:1px solid var(--line);border-radius:11px;cursor:pointer;background:#fff;transition:border-color .16s,background .16s}
.fkl-check:hover{border-color:var(--teal);background:var(--teal-soft)}
.fkl-check input{position:absolute;opacity:0;width:0;height:0}
.fkl-check .pn-check-box{margin-top:0}
.fkl-check .fkl-num{flex:0 0 auto;width:22px;height:22px;border-radius:7px;background:var(--teal-soft);color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;display:flex;align-items:center;justify-content:center}
.fkl-check input:checked~.fkl-num{background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff}
.fkl-check input:checked+.pn-check-box{background:linear-gradient(135deg,var(--teal),var(--cyan));border-color:var(--teal)}
.fkl-check input:checked+.pn-check-box svg{opacity:1}
.fkl-check .fkl-lbl{flex:1 1 auto;font-family:'Plus Jakarta Sans';font-size:11px;font-weight:600;color:#3d4d53;line-height:1.35}
.fkl-check input:checked~.fkl-lbl{color:var(--ink)}
.fkl-count-chip{margin-left:8px;font-family:'Plus Jakarta Sans';font-size:10.5px;font-weight:800;color:var(--teal-dark);background:var(--teal-soft);padding:3px 10px;border-radius:20px;vertical-align:middle}
.fkl-selall{display:flex;align-items:center;gap:10px;margin-top:12px}
.fkl-selall span{color:var(--line)}
.fkl-linkbtn{background:none;border:none;color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:700;font-size:11.5px;cursor:pointer;padding:0}
.fkl-linkbtn:hover{text-decoration:underline}
/* ----- Langkah 3: Ada / Tidak Ada ----- */
.fkl-empty-note{padding:16px 18px;border:1px dashed var(--line);border-radius:12px;background:#f8fbfc;color:var(--muted);font-size:12px;line-height:1.6}
.fkl-empty-note b{color:var(--ink)}
.fkl-ada-list{display:flex;flex-direction:column;gap:8px}
.fkl-ada-row{display:flex;align-items:center;gap:12px;padding:9px 12px 9px 10px;border:1px solid var(--line);border-radius:11px;background:#fff}
.fkl-ada-num{flex:0 0 auto;width:22px;height:22px;border-radius:7px;background:var(--teal-soft);color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;display:flex;align-items:center;justify-content:center}
.fkl-ada-name{flex:1 1 auto;font-family:'Plus Jakarta Sans';font-size:11px;font-weight:600;color:var(--ink);line-height:1.35}
.fkl-ada-opts{flex:0 0 auto;display:flex;gap:7px}
.fkl-ada-btn{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:9px;border:1.5px solid var(--line);background:#fff;color:#7c8a8f;font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;cursor:pointer;transition:.15s}
.fkl-ada-btn svg{width:13px;height:13px;opacity:.7}
.fkl-ada-btn:hover{border-color:#c4d2d5}
.fkl-ada-btn.ada.on{background:linear-gradient(180deg,#e0f5ea,#cdeedd);border-color:#69c493;color:#127a43}
.fkl-ada-btn.ada.on svg{opacity:1}
.fkl-ada-btn.no.on{background:linear-gradient(180deg,#fce4e4,#f7d6d6);border-color:#e79a9a;color:#b02626}
.fkl-ada-btn.no.on svg{opacity:1}
@media(max-width:600px){.fkl-ada-row{flex-wrap:wrap}.fkl-ada-opts{width:100%;justify-content:flex-end}}
/* Baris Tindak Lanjut (poin D) pada langkah 3 — memakai kerangka .fkl-ada-row
   supaya bentuknya persis sama dengan baris Ada/Tidak Ada di atasnya. */
.fkl-tl-row .fkl-ada-name{font-weight:700}
.fkl-tl-wajib{display:inline-block;margin-left:8px;padding:2px 8px;border-radius:20px;background:#fdecec;color:#b02626;font-family:'Plus Jakarta Sans';font-weight:800;font-size:9.5px;letter-spacing:.3px;text-transform:uppercase;vertical-align:middle;box-shadow:inset 0 0 0 1px rgba(178,42,42,.22)}
.fkl-tl-row.is-error{border-color:#e79a9a;background:linear-gradient(180deg,#fffafa,#fdf1f1);box-shadow:0 0 0 3px rgba(211,58,58,.10)}
/* ----- Ringkasan status ----- */
.fkl-status-card{display:flex;flex-wrap:wrap;align-items:center;gap:16px;padding:16px 18px;border-radius:14px;border:1px solid var(--line);background:linear-gradient(180deg,#ffffff,#f7fbfc)}
.fkl-status-badge{display:inline-flex;align-items:center;gap:9px;padding:9px 18px;border-radius:30px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:13px;letter-spacing:.3px}
.fkl-status-badge svg{width:17px;height:17px}
.fkl-status-badge.ok{background:linear-gradient(180deg,#e0f5ea,#cdeedd);color:#127a43;box-shadow:inset 0 0 0 1px rgba(21,122,68,.25)}
.fkl-status-badge.no{background:linear-gradient(180deg,#fce4e4,#f7d6d6);color:#b02626;box-shadow:inset 0 0 0 1px rgba(178,42,42,.25)}
.fkl-status-meta{font-size:11.5px;color:var(--muted);line-height:1.6}
.fkl-status-meta b{color:var(--ink)}
.fkl-prog{flex:1 1 180px;min-width:150px}
.fkl-prog-bar{height:9px;border-radius:6px;background:#e6eff0;overflow:hidden}
.fkl-prog-fill{height:100%;width:0;border-radius:6px;background:linear-gradient(90deg,var(--teal),var(--teal-dark));transition:width .28s ease}
.fkl-prog-txt{font-size:10.5px;color:var(--muted);margin-top:5px;font-weight:600}
/* ----- Action bar wizard ----- */
.fkl-actions{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:18px;flex-wrap:wrap}
.fkl-actions-left,.fkl-actions-right{display:flex;gap:10px;flex-wrap:wrap}
.fkl-actions-right{margin-left:auto}
/* ================== PEMBUKAAN PENAWARAN (WIZARD) ================== */
.pnw-hint-inline{font-weight:500;color:var(--muted);font-size:10.5px}
.fkl-check.is-locked{cursor:default;background:var(--teal-soft);border-color:var(--teal)}
.fkl-check.is-locked .fkl-lbl{color:var(--ink)}
.pnw-auto-badge{margin-left:auto;flex:0 0 auto;font-family:'Plus Jakarta Sans';font-size:9.5px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#0b6b74;background:#fff;border:1px solid var(--teal);border-radius:20px;padding:3px 9px}
.pnw-penyampaian-note{margin-top:14px;padding:10px 13px;border:1px dashed var(--line);border-radius:10px;background:#f8fbfc;color:var(--muted);font-size:11.5px;line-height:1.55}
.pnw-sampul-band{font-family:'Plus Jakarta Sans';font-weight:800;font-size:11.5px;letter-spacing:.4px;color:#0b3d42;background:linear-gradient(90deg,var(--teal-soft),#f2fafb);border:1px solid #bfe0e2;border-left:4px solid var(--teal);border-radius:8px;padding:8px 12px;margin:14px 0 12px;text-transform:uppercase}
.pnw-sampul-band:first-child{margin-top:0}
.pnw-kat-card{border:1px solid var(--line);border-radius:12px;padding:14px 15px;margin-bottom:14px;background:linear-gradient(180deg,#fff,#fbfdfe)}
.pnw-kat-card:last-child{margin-bottom:0}
/* Profil Persyaratan — tombol header + modal simpan/muat */
.pnw-syarat-title{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px}
.pnw-syarat-title-txt{display:flex;align-items:center;gap:8px}
.pnw-profil-bar{display:flex;gap:8px;flex-wrap:wrap}
.pnw-profil-btn{display:inline-flex;align-items:center;gap:7px;font-size:12px;padding:8px 13px}
.pnw-profil-btn svg{width:15px;height:15px}
/* Ikon tombol profil mengikuti warna teks tombol (bukan teal dari .form-section-title svg) */
.form-section-title .pnw-profil-btn svg{color:inherit;stroke:currentColor;opacity:1}
.pnw-profil-ov{display:none;position:fixed;inset:0;z-index:9999;background:rgba(16,40,50,.5);align-items:center;justify-content:center;padding:18px}
.pnw-profil-modal{width:100%;max-width:440px;background:#fff;border-radius:16px;box-shadow:0 20px 60px rgba(16,40,50,.35);padding:22px 22px 18px;max-height:86vh;overflow:auto}
.pnw-profil-head{display:flex;align-items:center;gap:9px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:16px;color:#0b3d42}
.pnw-profil-head svg{width:20px;height:20px;color:var(--teal-dark)}
.pnw-profil-sub{font-size:12.5px;color:#5a6b70;margin:8px 0 14px;line-height:1.5}
.pnw-profil-input{width:100%;box-sizing:border-box;height:42px;border:1px solid #cdd9de;border-radius:10px;padding:9px 13px;font-size:13px;font-family:inherit;color:var(--ink)}
.pnw-profil-input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
.pnw-profil-existing{font-size:11.5px;color:#7c8a8f;margin-top:10px;line-height:1.5}
.pnw-profil-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:18px}
.pnw-profil-list{display:flex;flex-direction:column;gap:9px;margin-bottom:4px}
.pnw-profil-item{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #e2ecee;border-radius:11px;padding:11px 13px;background:linear-gradient(180deg,#fff,#fafdfd)}
.pnw-profil-item-name{font-weight:700;font-size:13px;color:#233a41;word-break:break-word}
.pnw-profil-item-meta{font-size:11px;color:#8a99a0;margin-top:2px}
.pnw-profil-item-btns{display:flex;gap:6px;flex-shrink:0}
.pnw-profil-mini{padding:6px 12px;font-size:11.5px}
.pnw-kat-head{font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;color:var(--teal-dark);margin-bottom:8px;display:flex;align-items:center;gap:8px}
.pnw-kat-head::before{content:"";width:8px;height:8px;border-radius:3px;background:linear-gradient(135deg,var(--teal),var(--cyan))}
.pnw-lock-note{font-size:10.5px;color:var(--muted);margin:-2px 0 10px;line-height:1.5}
.pnw-syarat-list{display:flex;flex-direction:column;gap:8px}
.pnw-syarat-row{display:flex;align-items:center;gap:9px}
.pnw-syarat-no{flex:0 0 auto;width:22px;height:22px;border-radius:7px;background:var(--teal-soft);color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;display:flex;align-items:center;justify-content:center}
.pnw-syarat-row input{flex:1 1 auto;width:100%}
.pnw-syarat-row.locked input{background:#f4f7f8;color:#54666c;font-weight:600}
.pnw-lock-badge{flex:0 0 auto;font-family:'Plus Jakarta Sans';font-size:9.5px;font-weight:800;color:#8a6d00;background:#fff3d1;border:1px solid #f0d98a;border-radius:20px;padding:3px 9px;text-transform:uppercase;letter-spacing:.3px}
.pnw-syarat-del{flex:0 0 auto;width:32px;height:32px;border-radius:9px;border:1.5px solid var(--line);background:#fff;color:#b02626;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:.15s}
.pnw-syarat-del svg{width:15px;height:15px}
.pnw-syarat-del:hover{background:#fdf4f4;border-color:#e79a9a}
.pnw-syarat-add{margin-top:11px;display:inline-flex;align-items:center;gap:6px;font-family:'Plus Jakarta Sans';font-weight:700;font-size:11px;color:var(--teal-dark);background:var(--teal-soft);border:1px dashed var(--teal);border-radius:9px;padding:8px 13px;cursor:pointer;transition:.15s}
.pnw-syarat-add svg{width:14px;height:14px}
.pnw-syarat-add:hover{background:#d3ecee}
/* ===== Langkah 4: PANEL PEMERIKSAAN (mewah & profesional) ===== */
.pnw-panel{border:1px solid #d8e4e7;border-radius:18px;overflow:hidden;background:#fff;box-shadow:0 2px 8px rgba(16,40,50,.06),0 22px 50px rgba(9,94,102,.08)}
/* Hero header dengan gradasi teal gelap */
.pnw-hero{position:relative;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;
  padding:20px 24px;background:linear-gradient(120deg,#0b5d64 0%,#0E7C86 46%,#12a3ad 100%);color:#fff;overflow:hidden}
.pnw-hero-glow{position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(520px 220px at 88% -40%, rgba(246,180,14,.22), transparent 60%),radial-gradient(420px 200px at 8% 140%, rgba(255,255,255,.16), transparent 60%)}
.pnw-hero-main{position:relative;display:flex;align-items:center;gap:15px;min-width:0}
.pnw-hero-badge{flex:0 0 auto;width:46px;height:46px;border-radius:13px;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.30);display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)}
.pnw-hero-badge svg{width:24px;height:24px;color:#fff}
.pnw-hero-text{min-width:0}
.pnw-hero-kicker{font-family:'Plus Jakarta Sans';font-weight:700;font-size:10px;letter-spacing:1.4px;text-transform:uppercase;color:rgba(255,255,255,.82)}
.pnw-hero-title{font-family:'Plus Jakarta Sans';font-weight:800;font-size:18px;line-height:1.25;margin-top:3px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.12);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:44vw}
.pnw-hero-meta{display:flex;flex-wrap:wrap;gap:7px;margin-top:9px}
.pnw-hero-chip{font-family:'Plus Jakarta Sans';font-weight:700;font-size:10px;letter-spacing:.2px;color:#eafcfd;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.26);border-radius:20px;padding:4px 11px}
.pnw-hero-picker{position:relative;display:flex;flex-direction:column;gap:7px;min-width:230px}
.pnw-hero-picker .pnw-picker-lbl{color:rgba(255,255,255,.85)}
.pnw-picker-lbl{font-family:'Plus Jakarta Sans';font-weight:800;font-size:9.5px;text-transform:uppercase;letter-spacing:1px}
/* Dropdown penyedia */
.pnw-penyedia-select{position:relative;display:flex;align-items:center}
.pnw-penyedia-select .pnw-sel-ic{position:absolute;left:13px;width:17px;height:17px;color:var(--teal-dark);pointer-events:none}
.pnw-penyedia-select .pnw-sel-caret{position:absolute;right:12px;width:16px;height:16px;color:var(--teal-dark);pointer-events:none}
.pnw-penyedia-select select{appearance:none;-webkit-appearance:none;width:100%;font-family:'Plus Jakarta Sans';font-weight:700;font-size:12.5px;color:#0d2a30;
  background:#fff;border:1.5px solid rgba(255,255,255,.6);border-radius:11px;padding:11px 38px 11px 38px;cursor:pointer;
  box-shadow:0 6px 18px rgba(0,0,0,.14);transition:box-shadow .16s,border-color .16s}
.pnw-penyedia-select select:focus{outline:none;border-color:var(--yellow);box-shadow:0 0 0 3px rgba(246,180,14,.35)}
/* Sub-bar: judul sampul + nama penyedia aktif + progres */
.pnw-subbar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:14px 24px;background:linear-gradient(180deg,#f7fbfc,#f1f7f8);border-bottom:1px solid var(--line)}
.pnw-subbar-left{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.pnw-subbar-title{font-family:'Plus Jakarta Sans';font-weight:800;font-size:13px;color:var(--teal-dark)}
.pnw-active-penyedia{display:inline-flex;align-items:center;gap:7px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:11.5px;color:#0b3d42;background:#fff;border:1px solid #cfe3e5;border-radius:20px;padding:5px 13px 5px 10px}
.pnw-active-penyedia svg{width:14px;height:14px;color:var(--teal)}
.pnw-progress{display:flex;flex-direction:column;align-items:flex-end;gap:6px;min-width:220px}
.pnw-progress-stats{display:flex;gap:6px}
.pnw-pstat{font-family:'Plus Jakarta Sans';font-weight:800;font-size:10px;letter-spacing:.2px;border-radius:20px;padding:3px 10px;border:1px solid transparent}
.pnw-pstat.ada{color:var(--green-dark);background:#e7f6ee;border-color:#bfe6cf}
.pnw-pstat.no{color:var(--red-dark);background:#fbeaea;border-color:#f2c9c9}
.pnw-pstat.belum{color:#8a6d00;background:#fff6d9;border-color:#f0dc95}
.pnw-progress-bar{width:220px;max-width:46vw;height:7px;border-radius:20px;background:#e3edee;overflow:hidden}
.pnw-progress-fill{height:100%;border-radius:20px;background:linear-gradient(90deg,var(--teal),var(--cyan));transition:width .3s ease}
/* Tab sampul (di dalam panel) */
.pnw-sampul-tabs{display:flex;flex-wrap:wrap;gap:9px;padding:14px 24px 0}
.pnw-stab{display:inline-flex;align-items:center;gap:8px;font-family:'Plus Jakarta Sans';font-weight:700;font-size:11.5px;color:#54666c;background:#fff;border:1.5px solid var(--line);border-radius:11px;padding:9px 15px;cursor:pointer;transition:.15s}
.pnw-stab .pnw-stab-dot{width:8px;height:8px;border-radius:50%;background:#c2d3d6;transition:.15s}
.pnw-stab:hover{border-color:var(--teal);color:var(--teal-dark)}
.pnw-stab.on{background:linear-gradient(135deg,rgba(14,124,134,.10),rgba(18,169,181,.06));border-color:var(--teal);color:var(--teal-dark);box-shadow:inset 0 0 0 1px var(--teal)}
.pnw-stab.on .pnw-stab-dot{background:linear-gradient(135deg,var(--teal),var(--cyan))}
/* Tabel pemeriksaan */
.pnw-table-wrap{padding:16px 20px 20px;overflow-x:hidden}
.pnw-periksa-table{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0;font-size:11px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;border:1px solid #e6eef0;border-radius:12px;overflow:hidden}
.pnw-periksa-table th{background:#0E7C86;color:#eafcfd!important;font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;text-transform:uppercase;letter-spacing:.6px;padding:12px 13px;text-align:center;border:none;white-space:nowrap}
.pnw-periksa-table th.pnw-no{text-align:center;color:#eafcfd}
.pnw-periksa-table td{padding:11px 13px;border-bottom:1px solid #eef3f4;vertical-align:middle;background:#fff;transition:background .15s}
.pnw-periksa-table tbody tr:last-child td{border-bottom:none}
.pnw-periksa-table th.pnw-no,.pnw-periksa-table td.pnw-no{width:46px;min-width:42px;max-width:52px;text-align:center;font-weight:800;padding-left:6px;padding-right:6px}
.pnw-periksa-table td.pnw-no{color:var(--muted)}
.pnw-periksa-table th.pnw-uraian{text-align:left}
.pnw-periksa-table td.pnw-uraian{color:#233a41;font-weight:600;white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.4;text-align:left}
.pnw-periksa-table th.pnw-ck,.pnw-periksa-table td.pnw-ck{width:216px;min-width:216px;text-align:center}
/* Tombol Ada / Tidak Ada tetap satu baris (tidak wrap) */
.pnw-periksa-table td.pnw-ck .fkl-ada-opts{justify-content:center;flex-wrap:nowrap}
.pnw-periksa-table td.pnw-ck .fkl-ada-btn{white-space:nowrap;padding:6px 10px}
.pnw-periksa-table th.pnw-ket,.pnw-periksa-table td.pnw-ket{width:240px}
.pnw-periksa-table td.pnw-ket{text-align:left}
.pnw-periksa-table td.pnw-ket input{width:100%;box-sizing:border-box}
.pnw-periksa-table tr.is-ada td{background:#f4fbf7}
.pnw-periksa-table tr.is-no td{background:#fdf6f6}
.pnw-periksa-table tr.pnw-cat-row td{background:var(--teal-soft);padding:9px 13px;border-bottom:1px solid #d8e9ea}
.pnw-cat-idx{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:6px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;font-family:'Plus Jakarta Sans';font-weight:800;font-size:10.5px;margin-right:9px;vertical-align:middle}
.pnw-cat-name{font-family:'Plus Jakarta Sans';font-weight:800;font-size:11px;color:#0b3d42;text-transform:uppercase;letter-spacing:.4px;vertical-align:middle}
.pnw-jd-cell{font-weight:700;color:var(--teal-dark);white-space:nowrap}
@media(max-width:760px){
  .pnw-hero{padding:16px}.pnw-hero-title{max-width:100%;white-space:normal}
  .pnw-hero-picker{min-width:100%}.pnw-subbar{padding:12px 16px}
  .pnw-progress{align-items:flex-start;min-width:100%}.pnw-progress-bar{max-width:100%;width:100%}
  .pnw-sampul-tabs{padding:12px 16px 0}.pnw-table-wrap{padding:12px}
}
.btn.btn-ghost{background:#fff;border:1.5px solid var(--line);color:#7c8a8f}
.btn.btn-ghost:hover{border-color:#e79a9a;color:#b02626;background:#fdf4f4}
.btn.btn-light{background:#f1f6f7;border:1.5px solid var(--line);color:var(--teal-dark)}
.btn.btn-light:hover{background:var(--teal-soft);border-color:var(--teal)}

/* ================== PRATINJAU & CETAK DOKUMEN (ELEGAN) ================== */
#fkl-print-root{display:none}
/* Wadah pratinjau di dalam modal */
.pn-preview-body.fkl-preview-body{background:#e9eef1;padding:0;display:block;overflow:hidden}
.pn-preview-body.fkl-preview-body #fkl-preview-frame{width:100%;height:74vh;border:none;background:#e9eef1;display:block}
.pn-preview-modal.is-max .pn-preview-body.fkl-preview-body #fkl-preview-frame{height:calc(100vh - 62px)}
.fkl-doc-scroll{max-width:820px;margin:0 auto}
.fkl-preview-body .fkl-doc{background:#fff;box-shadow:0 18px 50px rgba(20,50,60,.22);border-radius:6px}
/* Dokumen */
.fkl-doc{font-family:'Plus Jakarta Sans','Segoe UI',sans-serif;color:#22343a;padding:34px 40px 30px;position:relative;overflow:hidden}
.fkl-doc-head{display:flex;align-items:center;gap:16px;padding-bottom:14px}
.fkl-doc-logo{flex:0 0 auto}
.fkl-doc-logo svg{width:52px;height:52px}
.fkl-doc-logo img{width:52px;height:auto;display:block}
.fkl-doc-org{flex:1 1 auto;line-height:1.3}
.fkl-doc-org .l1{font-weight:800;font-size:16px;letter-spacing:.5px;color:#0E7C86}
.fkl-doc-org .l2{font-weight:700;font-size:11px;color:#22343a;text-transform:uppercase;letter-spacing:.2px}
.fkl-doc-org .l3{font-size:10px;color:#7c8a8f;margin-top:2px}
.fkl-doc-band{height:3px;border-radius:3px;background:linear-gradient(90deg,#0E7C86,#12b3c0 55%,#F6B40E);margin-bottom:20px}
.fkl-doc-title{text-align:center;font-weight:800;font-size:19px;line-height:1.28;letter-spacing:.6px;color:#0d2a30;margin:0 0 10px;text-transform:uppercase}
/* Varian judul bergaris bawah + baris Nomor — HANYA dipakai dokumen HPS & Rekap HPS.
   display:table + margin auto membuat garis hanya selebar teks judul. */
.fkl-doc-title.has-rule{display:table;margin:0 auto 7px;padding-bottom:5px;border-bottom:2px solid #0d2a30;-webkit-print-color-adjust:exact;print-color-adjust:exact}
.fkl-doc-titlerule{display:none}
.fkl-doc-docno{text-align:center;font-weight:700;font-size:12px;letter-spacing:.35px;color:#0d2a30;margin:0}
.fkl-doc-titlegap{height:18px}
/* Judul section berhuruf A / B / C */
.fkl-sec-h{display:flex;align-items:center;gap:10px;font-weight:800;font-size:13px;color:#0d2a30;letter-spacing:.3px;text-transform:uppercase;margin:22px 0 10px}
.fkl-sec-h .rn{flex:0 0 auto;color:#0d2a30;font-weight:800;font-size:13px}
/* Tabel uraian pekerjaan */
.fkl-info{width:100%;border-collapse:collapse}
.fkl-info td{padding:5px 6px;vertical-align:top;font-size:12.5px}
.fkl-info td.k{width:34%;color:#54666c;font-weight:600}
.fkl-info td.s{width:16px;color:#54666c}
.fkl-info td.v{font-weight:700;color:#1a2b31}
/* Tabel kelengkapan dokumen */
.fkl-chk{width:100%;border-collapse:separate;border-spacing:0;margin-top:2px;border:1.5px solid #0b6a73;border-radius:9px;overflow:hidden;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.fkl-chk thead th{background:#0E7C86;color:#fff;font-size:11.5px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;padding:9px 12px;text-align:center;border-right:1px solid rgba(255,255,255,.3)}
.fkl-chk thead th:last-child{border-right:none}
.fkl-chk th.no,.fkl-chk td.no{width:44px;text-align:center}
.fkl-chk th.ck,.fkl-chk td.ck{width:190px;text-align:center}.fkl-chk th.ck{padding-top:7px;padding-bottom:7px}.fkl-chk th.ck .ck-main{display:block;line-height:1.2;white-space:nowrap}
.fkl-chk tbody td{padding:8px 12px;font-size:11.5px;font-weight:600;border-top:1px solid #bcd6d9;border-right:1px solid #bcd6d9;color:#22343a}
.fkl-chk tbody td:last-child{border-right:none}
.fkl-chk tbody tr:nth-child(even) td{background:#f6fafb}
.fkl-chk td.nm{font-weight:600}
.fkl-chk td.empty{text-align:center;color:#9aabb0;font-style:italic;padding:14px}
.fkl-chk .pill{display:inline-flex;align-items:center;justify-content:center;min-width:74px;padding:3px 12px;border-radius:20px;font-size:11.5px;font-weight:800;letter-spacing:.3px}
.fkl-chk .pill.ada{background:#e0f5ea;color:#127a43;border:1px solid #a8dcc0}
.fkl-chk .pill.no{background:#fce4e4;color:#b02626;border:1px solid #edbcbc}
.fkl-chk .pill.nn{background:#eef2f4;color:#98a6ab;border:1px solid #dde5e8}
/* Hasil pemeriksaan */
.fkl-doc .hasil{display:flex;align-items:center;gap:14px;padding:14px 18px;border-radius:11px;margin-top:2px}
.fkl-doc .hasil .hi{flex:0 0 auto;width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center}
.fkl-doc .hasil .hi svg{width:20px;height:20px}
.fkl-doc .hasil .ht{font-weight:800;font-size:14px;letter-spacing:.4px}
.fkl-doc .hasil .hs{font-size:11px;margin-top:1px}
.fkl-doc .hasil.ok{background:linear-gradient(180deg,#e6f8ee,#d5f1e0);border:1px solid #a8dcc0}
.fkl-doc .hasil.ok .hi{background:#127a43;color:#fff}
.fkl-doc .hasil.ok .ht{color:#0f6a3a}.fkl-doc .hasil.ok .hs{color:#3c7a58}
.fkl-doc .hasil.no{background:linear-gradient(180deg,#fdeaea,#f9dcdc);border:1px solid #edbcbc}
.fkl-doc .hasil.no .hi{background:#b02626;color:#fff}
.fkl-doc .hasil.no .ht{color:#9c2222}.fkl-doc .hasil.no .hs{color:#a15353}
/* Tanda terima */
.fkl-doc-foot{margin-top:26px}
.fkl-doc-foot .ttd-title{font-weight:800;font-size:12px;color:#0d2a30;text-transform:uppercase;letter-spacing:.3px;text-align:right}
.fkl-doc-foot .ttd-date{text-align:right;font-size:12px;color:#22343a;margin:4px 0 8px;font-weight:600}
.fkl-doc-foot .ttd{width:88%;margin-left:auto;border-collapse:collapse}
.fkl-doc-foot .ttd td{width:50%;text-align:center;vertical-align:top;padding:0 26px}
.fkl-doc-foot .ttd .role{font-size:12px;color:#22343a;font-weight:600}
.fkl-doc-foot .ttd .gap{height:72px}
.fkl-doc-foot .ttd .nm{font-weight:800;font-size:12.5px;color:#0d2a30;padding-top:5px;display:inline-block;min-width:150px;text-transform:uppercase}
.fkl-doc-foot .ttd .sub{font-size:10px;color:#7c8a8f;margin-top:2px}
/* ===== Print ===== (pencetakan dokumen kelengkapan memakai iframe terisolasi, lihat fklPrint) */

/* =================================================================
   ✦ LAPISAN "MEWAH": animasi & transisi halus di seluruh tampilan
   ================================================================= */

/* 1) Transisi umum yang lembut untuk elemen interaktif */
.btn,.nav-link,.nav-item,.topnav-link,.topnav-item,.card,.panel,
.field input,.field select,.filter-field input,.filter-field select,
.settings-item{
  transition:transform .28s cubic-bezier(.16,1,.3,1),
             box-shadow .3s cubic-bezier(.16,1,.3,1),
             background-color .25s ease,border-color .25s ease,color .2s ease,filter .25s ease;
}

/* 2) Kilau cahaya menyapu saat hover tombol (shine sweep) */
.btn{position:relative;overflow:hidden}
.btn::after{
  content:"";position:absolute;top:0;left:-140%;width:60%;height:100%;
  background:linear-gradient(120deg,transparent,rgba(255,255,255,.55),transparent);
  transform:skewX(-18deg);pointer-events:none;transition:none;opacity:0;
}
.btn:hover::after{animation:btnShine .8s cubic-bezier(.16,1,.3,1)}
@keyframes btnShine{0%{left:-140%;opacity:.9}100%{left:140%;opacity:0}}
.btn:active{transform:translateY(0) scale(.97)}

/* 3) Panel & kartu terangkat halus saat hover */
.panel{transition:transform .3s cubic-bezier(.16,1,.3,1),box-shadow .32s ease,border-color .25s ease}
.panel:hover{transform:translateY(-3px);box-shadow:0 10px 30px rgba(9,94,102,.14),0 3px 10px rgba(16,40,50,.08)}

/* 4) Baris tabel masuk bertahap (stagger) + hover terangkat lembut */
.table-wrap tbody tr{animation:rowFloatIn .5s cubic-bezier(.16,1,.3,1) both}
.table-wrap tbody tr:nth-child(1){animation-delay:.02s}
.table-wrap tbody tr:nth-child(2){animation-delay:.06s}
.table-wrap tbody tr:nth-child(3){animation-delay:.10s}
.table-wrap tbody tr:nth-child(4){animation-delay:.14s}
.table-wrap tbody tr:nth-child(5){animation-delay:.18s}
.table-wrap tbody tr:nth-child(6){animation-delay:.22s}
.table-wrap tbody tr:nth-child(7){animation-delay:.26s}
.table-wrap tbody tr:nth-child(8){animation-delay:.30s}
.table-wrap tbody tr:nth-child(n+9){animation-delay:.34s}
@keyframes rowFloatIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* 5) Input "mengangkat" halus saat fokus (selain glow yang sudah ada) */
.field input:focus,.field select:focus,.field textarea:focus,
.filter-field input:focus,.filter-field select:focus{
  transform:translateY(-1px);
}

/* 6) Item menu navigasi: geser halus & garis aksen saat hover */
.nav-link:hover,.nav-item:hover,.topnav-link:hover,.topnav-item:hover{transform:translateX(2px)}

/* 8) Angka besar di kartu dashboard: muncul dengan "count up" halus */
#dash-content.dash-in .card .v{animation:valueReveal .6s .12s cubic-bezier(.16,1,.3,1) both}
@keyframes valueReveal{from{opacity:0;transform:translateY(8px) scale(.96)}to{opacity:1;transform:none}}

/* 9) Badge jumlah (count-badge) berdenyut lembut sekali saat tampil */
.count-badge{animation:badgePop .5s cubic-bezier(.16,1,.3,1) both}
@keyframes badgePop{0%{transform:scale(.6);opacity:0}60%{transform:scale(1.08)}100%{transform:scale(1);opacity:1}}

/* 10) Toast meluncur masuk dengan lembut */
.toast{transition:transform .35s cubic-bezier(.16,1,.3,1),opacity .3s ease}

/* Hormati preferensi "kurangi gerak": matikan semua tambahan di atas */
@media (prefers-reduced-motion:reduce){
  .btn:hover::after{animation:none}
  .table-wrap tbody tr{animation:none}
  .panel:hover,
  .nav-link:hover,.nav-item:hover,.topnav-link:hover,.topnav-item:hover,
  .field input:focus,.field select:focus{transform:none}
  #dash-content.dash-in .card .v,.count-badge{animation:none}
}

/* =====================================================================
   ✦ PENYEMPURNAAN "KORPORAT BERSIH" — kosmetik saja, tanpa ubah tata letak
   Prioritas: Dashboard & kartu statistik agar tampak enterprise, rapi, minimal
   ===================================================================== */

/* — Palet & bayangan yang lebih tenang/presisi — */
:root{
  --line:#e3e8ec;
  --shadow:0 1px 2px rgba(16,40,50,.05),0 1px 3px rgba(16,40,50,.04);
  --shadow-md:0 1px 3px rgba(16,40,50,.06),0 6px 18px rgba(16,40,50,.07);
}

/* ---------- KARTU KPI DASHBOARD: permukaan bersih & flat ---------- */
#view-dashboard .card{
  background:#ffffff !important;              /* hilangkan gradasi ramai → putih bersih */
  border:1px solid #e6ebee !important;
  border-radius:14px !important;
  box-shadow:0 1px 2px rgba(16,40,50,.04),0 2px 8px rgba(16,40,50,.05) !important;
  padding:18px 20px !important;
}
/* Matikan glow pojok & garis dekoratif atas pada kartu dashboard */
#view-dashboard .card::after{display:none !important}
#view-dashboard .card::before{display:none !important}
/* Hover halus & terkendali (angkat tipis, tanpa warna berlebih) */
#view-dashboard .card:hover{
  transform:translateY(-2px) !important;
  border-color:#d5dee2 !important;
  box-shadow:0 2px 6px rgba(16,40,50,.06),0 10px 24px rgba(16,40,50,.08) !important;
}
/* Batang aksen kiri lebih tipis & tenang */
#view-dashboard .card .accent{
  width:3px !important;border-radius:0 3px 3px 0 !important;box-shadow:none !important;
  opacity:.9;
}
/* Judul kartu: huruf kapital rapi, warna netral */
#view-dashboard .card .k{
  color:#6a7a83 !important;font-size:11px !important;font-weight:700 !important;
  letter-spacing:.6px !important;
}
/* Angka besar: solid, tegas, tanpa gradient teks */
#view-dashboard .card .v{
  -webkit-text-fill-color:initial !important;background:none !important;
  color:#152a33 !important;font-weight:800 !important;letter-spacing:-.5px !important;
}
/* Sub-teks kartu: netral & ringan */
#view-dashboard .card .sub{color:#859299 !important;font-weight:500 !important}
/* Chip ikon: netral, bersih, tidak mencolok */
#view-dashboard .card-ic{
  background:#f3f6f7 !important;
  box-shadow:inset 0 0 0 1px #e5ebee !important;
  color:var(--ic,var(--teal)) !important;
}
#view-dashboard .card:hover .card-ic{
  transform:translateY(-1px) scale(1.04) !important;
  box-shadow:inset 0 0 0 1px #dbe3e6 !important;
}

/* ---------- PANEL GRAFIK DASHBOARD: header bersih ---------- */
#view-dashboard .panel{
  border:1px solid #e6ebee !important;border-radius:14px !important;
  box-shadow:0 1px 2px rgba(16,40,50,.04),0 2px 10px rgba(16,40,50,.05) !important;
}
#view-dashboard .panel-head{
  background:#fbfcfd !important;border-bottom:1px solid #eef2f4 !important;
  color:#243b43 !important;font-weight:700 !important;
}

/* ---------- JUDUL HALAMAN: aksen ramping & profesional (semua halaman) ---------- */
.page-head h2::before{
  background:var(--teal) !important;box-shadow:none !important;width:4px !important;border-radius:2px !important;
}
.page-head h2{color:#18313a !important;letter-spacing:-.2px}

/* ---------- BADGE JUMLAH: pill netral bersih ---------- */
.count-badge{
  background:#eef3f4 !important;color:var(--teal-dark) !important;
  box-shadow:inset 0 0 0 1px #dde7ea !important;font-weight:700 !important;
}

/* ---------- TABEL: garis lebih halus, baris genap lembut (semua halaman) ---------- */
.table-wrap{border-color:#e3e9ec !important}
tbody tr{background:#eef4f6}
tbody tr:nth-child(even){background:#e6eef1 !important}
tbody tr:hover{background:#dceaed !important}

/* ---------- TOMBOL: bayangan lebih tenang, tetap jelas ---------- */
.btn{box-shadow:0 1px 2px rgba(16,40,50,.08),0 2px 6px rgba(16,40,50,.06)}
.btn:hover{box-shadow:0 2px 4px rgba(16,40,50,.10),0 8px 18px rgba(16,40,50,.10)}

/* ---------- INPUT & SELECT: rapi, ring fokus konsisten ---------- */
.field input,.field select,.field textarea,
.filter-field input,.filter-field select{border-color:#d9e0e4}

/* ---------- PANEL UMUM (non-dashboard): bayangan halus & garis presisi ---------- */
.panel{border-color:#e6ebee}

/* ---------- Redam garis "sheen" berjalan → aksen statis tenang (korporat) ---------- */
.sidebar::after{animation:none !important;background:linear-gradient(180deg,var(--yellow),var(--cyan)) !important;opacity:.5 !important;width:2px !important}
.topbar::after{animation:none !important;background:var(--teal) !important;opacity:.35 !important;height:2px !important}
.modal::before{animation:none !important;background:linear-gradient(90deg,var(--teal),var(--cyan)) !important}

/* Hormati preferensi kurangi gerak sudah ditangani di atas */

/* ===== 2. rho-ui-css ===== */
/* ===================== Referensi Harga Online (UI) ===================== */
.rho-item-list{display:flex;flex-direction:column;gap:10px}
.rekap-static{padding:9px 12px;border:1px solid var(--line);border-radius:9px;background:#f4fafb;color:#0d2a30;font-weight:700;font-size:12px;min-height:16px}
.rho-ongkir-bar{display:flex;gap:14px;flex-wrap:wrap;justify-content:flex-end;margin:0 0 14px}
.rho-ongkir-bar .field{min-width:180px;margin:0}
input.rho-input-locked{background:#f1f4f6;color:#9aa7ad;cursor:not-allowed;border-style:dashed}
/* Berlaku juga untuk <select> yang terkunci (mis. Bidang Pelaksana pada
   Dokumen Pengadaan saat diisi otomatis dari menu Data Pekerjaan). */
select.rho-input-locked{background:#f1f4f6;color:#9aa7ad;cursor:not-allowed;border-style:dashed}
input.rho-input-locked[readonly]{color:#5d6b74}
.rho-item-row{display:flex;align-items:center;gap:12px;background:linear-gradient(180deg,#ffffff,#f6fbfc);border:1px solid #dbe7ea;border-radius:12px;padding:9px 12px}
.rho-item-row:hover{border-color:#bcd6d9;box-shadow:0 3px 10px rgba(16,40,50,.07)}
.rho-item-no{flex:0 0 auto;width:30px;height:30px;border-radius:8px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:12.5px;font-family:'Plus Jakarta Sans'}
.rho-item-row input{flex:1 1 auto;width:100%}
.rho-item-del{flex:0 0 auto;width:32px;height:32px;border-radius:8px;border:1px solid #f0d4d4;background:#fdf4f4;color:#c0392b;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;transition:.15s}
.rho-item-del svg{width:16px;height:16px}
.rho-item-del:hover{background:#b02626;border-color:#b02626;color:#fff;box-shadow:0 3px 10px rgba(176,38,38,.22)}
.rho-item-del:disabled{opacity:.4;cursor:not-allowed;background:#f4f6f7;border-color:#e2e8ea;color:#9aa7ad;box-shadow:none}
.rho-hint{font-size:10.5px;color:var(--muted);margin:2px 0 12px;line-height:1.6}

/* Panel pengisian referensi */
.rho-panel{display:flex;flex-direction:column;gap:16px}
.rho-item-card{background:#ffffff;border:1px solid #cfe0e3;border-radius:8px;overflow:hidden;box-shadow:0 1px 4px rgba(16,40,50,.05)}
.rho-item-head{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#e3f2f3;border-bottom:1px solid #bfe0e2;color:#0b3d42;text-transform:uppercase}
.rho-item-head .rho-h-no{flex:0 0 auto;width:24px;height:24px;border-radius:6px;background:#0E7C86;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:12px;letter-spacing:.2px}
.rho-item-head .rho-h-name{font-weight:800;font-size:12.5px;letter-spacing:.2px}
.rho-item-head .rho-h-tag{margin-left:auto;font-size:9.5px;font-weight:700;color:var(--teal-dark);background:#d3ebee;padding:3px 10px;border-radius:20px;text-transform:none}
.rho-matrix-wrap{overflow-x:auto;padding:10px 12px 12px}
table.rho-matrix{border-collapse:collapse;width:100%;min-width:560px}
table.rho-matrix th,table.rho-matrix td{border:1px solid #cfe0e3;padding:6px 8px;vertical-align:middle;font-size:12px}
table.rho-matrix thead th{background:#eef6f7;color:#0b3d42;font-weight:800;font-size:11px;text-transform:uppercase;letter-spacing:.3px;text-align:center;white-space:nowrap}
table.rho-matrix thead th.rho-c-lbl{text-align:left;min-width:150px;background:#e3f2f3}
table.rho-matrix td.rho-c-lbl{background:#f1f6f7;font-weight:700;color:#0b3d42;min-width:150px}
table.rho-matrix td.rho-c-lbl .rho-c-sub{display:block;font-weight:500;font-size:9.5px;color:#7c8a8f;margin-top:1px}
table.rho-matrix tr.rho-namarow td{background:#e8f4f5;color:#0b3d42;font-weight:800;font-size:12.5px;text-align:center}
table.rho-matrix tr.rho-autorow td:not(.rho-c-lbl){background:#fbfdf4}
table.rho-matrix tr.rho-totrow td{background:#eef8f1}
table.rho-matrix tr.rho-totrow td.rho-c-lbl{background:#e6f4ec;color:#0d7a3f}
table.rho-matrix input{width:100%;border:1px solid #cdd9de;border-radius:9px;padding:8px 9px;font-size:12px;background:#fff;font-family:inherit}
table.rho-matrix input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
.rho-auto-val{display:block;text-align:right;font-weight:800;color:#0b6a73;font-size:12.5px;white-space:nowrap}
.rho-total-val{color:#0d7a3f}

/* Sel foto: paste dari clipboard */
.rho-foto-cell{position:relative;width:150px;height:120px;margin:0 auto;border:2px dashed #b9d3d7;border-radius:11px;background:#f4fafb;display:flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;transition:.15s;outline:none}
.rho-foto-cell:hover{border-color:var(--teal);background:#edf7f8}
.rho-foto-cell:focus,.rho-foto-cell.is-focus{border-color:var(--teal);border-style:solid;box-shadow:0 0 0 3px rgba(14,124,134,.18);background:#fff}
.rho-foto-cell img{width:100%;height:100%;object-fit:contain;object-position:center;background:#fff;display:block}
.rho-foto-empty{display:flex;flex-direction:column;align-items:center;gap:5px;color:#7f9aa0;padding:6px;text-align:center;pointer-events:none}
.rho-foto-empty svg{width:26px;height:26px;opacity:.75}
.rho-foto-empty span{font-size:9.5px;font-weight:700;line-height:1.25}
.rho-foto-cell.is-focus .rho-foto-empty span{color:var(--teal-dark)}
.rho-foto-actions{position:absolute;top:5px;right:5px;display:flex;gap:5px;opacity:0;transition:.15s}
.rho-foto-cell:hover .rho-foto-actions,.rho-foto-cell.has-img .rho-foto-actions{opacity:1}
.rho-foto-actions button{width:24px;height:24px;border:none;border-radius:7px;background:rgba(9,40,45,.72);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.rho-foto-actions button svg{width:13px;height:13px}
.rho-foto-actions button:hover{background:#b02626}
.rho-ref-chip{display:inline-block;font-size:9px;font-weight:700;color:var(--teal-dark);background:var(--teal-soft);padding:2px 8px;border-radius:20px;margin-top:4px}

/* PDF foto dalam dokumen */
.rho-pdf-foto{width:100%;max-width:150px;height:96px;object-fit:contain;object-position:center;background:#fff;display:block;margin:0 auto;border:1px solid #e2eaec;border-radius:4px}
.rho-pdf-foto-empty{display:block;text-align:center;color:#9aabb0;font-style:italic;font-size:10px;padding:24px 4px}
@media(max-width:640px){
  .rho-foto-cell{width:120px;height:96px}
  table.rho-matrix{min-width:480px}
}

/* ===== 3. hps-ui-css ===== */
/* ===================== Harga Perkiraan Sendiri (UI) ===================== */
.hps-hint{font-size:10.5px;color:var(--muted);margin:2px 0 12px;line-height:1.6}
.menu-soon{margin-left:auto;font-size:8.5px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#9a6a00;background:#ffe9b8;padding:2px 7px;border-radius:20px}
/* Tombol Pilih Analisa di Data Pekerjaan */
.hps-analisa-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 16px;padding:12px 14px;background:linear-gradient(180deg,#f3fbfc,#e9f6f7);border:1px dashed #a9d3d8;border-radius:13px}
.hps-analisa-bar .ic{flex:0 0 auto;width:34px;height:34px;border-radius:9px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;display:flex;align-items:center;justify-content:center}
.hps-analisa-bar .ic svg{width:18px;height:18px}
.hps-analisa-bar .tx{flex:1 1 200px;min-width:0}
.hps-analisa-bar .tx b{display:block;font-size:12px;color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:800}
.hps-analisa-bar .tx span{font-size:10px;color:var(--muted)}
/* Tabel input Uraian Pekerjaan (langkah 2) — gaya RAB/HPS */
.hps-uraian-wrap{overflow-x:auto;border:1px solid #dde9eb;border-radius:14px;box-shadow:0 2px 8px rgba(16,40,50,.05)}
table.hps-uraian{border-collapse:separate;border-spacing:0;width:100%;min-width:940px}
table.hps-uraian thead th{background:#0E7C86;color:#fff;font-weight:800;font-size:10.5px;text-transform:uppercase;letter-spacing:.2px;padding:9px 8px;text-align:center;white-space:nowrap;vertical-align:middle}
/* Kolom Jumlah Total (Rp) dihapus pada tabel input HPS & Lampiran -> lebarnya
   dialihkan ke kolom Uraian Pekerjaan (td.c-ur tetap width:100%). */
table.hps-uraian thead th.c-ur{text-align:left;min-width:340px}
table.hps-uraian tbody td{border-bottom:1px solid #e8f0f1;padding:7px 8px;vertical-align:middle;font-size:12px}
table.hps-uraian tbody tr:last-child td{border-bottom:none}
table.hps-uraian tbody tr:nth-child(even){background:#f8fbfc}
/* Kolom NO cukup lebar untuk nomor tiga digit (mis. 100+) tanpa terlihat sempit */
table.hps-uraian th.c-no,table.hps-uraian td.c-no{text-align:center;font-weight:800;color:#0b6a73;width:62px;min-width:62px;max-width:62px;padding-left:6px;padding-right:6px;white-space:nowrap}
table.hps-uraian td.c-ur{width:100%}
table.hps-uraian textarea,table.hps-uraian input{width:100%;border:1px solid #cdd9de;border-radius:9px;padding:7px 8px;font-size:12px;background:#fff;font-family:inherit;color:var(--ink)}
table.hps-uraian textarea{resize:vertical;min-height:36px;line-height:1.45}
table.hps-uraian td.c-kel input{min-width:96px}
/* Judul? / Sub-Judul? — dropdown Ya/Tidak + kotak kecil (selebar 1 abjad) gaya penomoran */
/* Judul? / Sub-Judul? — saat "Ya", dropdown gaya penomoran (selebar 1 abjad) muncul
   DI DALAM lebar field itu sendiri: Ya/Tidak menyusut, kotak kecil menempati sisanya.
   Lebar total field tidak berubah, jadi tidak ada field lain yang bergeser. */
.js-judul-row{display:flex;align-items:center;gap:6px;width:100%}
/* Spesifisitas dinaikkan agar tidak dikalahkan `.field select{width:100%}` /
   `.ana-dp-rokinf .ana-tb-field select{width:100%}` */
.field > .js-judul-row > select,
.ana-tb-field > .js-judul-row > select{flex:1 1 auto;width:auto;min-width:0}
.field > .js-judul-row > select.js-numsel,
.ana-tb-field > .js-judul-row > select.js-numsel{flex:0 0 58px;width:58px;min-width:58px;text-align:center;font-weight:800;letter-spacing:.5px;padding-left:8px;padding-right:8px}
/* Kotak angka sempit (ROK 2 digit, Inflasi 4 digit) — juga dipotong dari lebar
   field induknya, sehingga tata letak kolom tidak bergeser saat dipilih "Ya". */
.field > .js-judul-row > input.js-numbox,
.ana-tb-field > .js-judul-row > input.js-numbox{flex:0 0 auto;text-align:center;font-weight:800;letter-spacing:.4px;padding-left:8px;padding-right:8px}
.field > .js-judul-row > input.js-num2,
.ana-tb-field > .js-judul-row > input.js-num2{width:56px;min-width:56px}
.field > .js-judul-row > input.js-num4,
.ana-tb-field > .js-judul-row > input.js-num4{width:80px;min-width:80px}
table.hps-uraian td.c-sat input{text-align:center;min-width:64px}
table.hps-uraian td.c-vol input{text-align:center;min-width:64px}
table.hps-uraian td.c-money input{text-align:right;min-width:120px}
table.hps-uraian textarea:focus,table.hps-uraian input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
table.hps-uraian td.c-calc{text-align:right;font-weight:800;color:#0b6a73;white-space:nowrap;background:#f2fafb;min-width:120px}
/* Panel ringkasan langsung di bawah tabel input */
.hps-sum-card{margin-top:16px;border:1px solid #dde9eb;border-radius:14px;overflow:hidden}
.hps-sum-head{display:flex;align-items:center;gap:9px;padding:11px 15px;background:linear-gradient(90deg,#0E7C86,#0b6a73);color:#fff;font-weight:800;font-size:12.5px}
.hps-sum-head svg{width:16px;height:16px}
table.hps-sum{width:100%;border-collapse:collapse}
table.hps-sum td{padding:9px 15px;font-size:12.5px;border-bottom:1px solid #eef4f5}
table.hps-sum tr:last-child td{border-bottom:none}
table.hps-sum td.lbl{color:#2b3f48;font-weight:700}
table.hps-sum td.val{text-align:right;font-weight:800;color:#0b3d42;white-space:nowrap;width:190px}
table.hps-sum tr.grand td{background:#eef8f1}
table.hps-sum tr.grand td.lbl{color:#0d7a3f}
table.hps-sum tr.grand td.val{color:#0d7a3f;font-size:13.5px}
.hps-terbilang{padding:11px 15px;font-size:11.5px;color:#2b3f48;background:#f6fafb;border-top:1px solid #eef4f5;line-height:1.55}
.hps-terbilang b{color:var(--teal-dark)}
@media(max-width:640px){ table.hps-uraian{min-width:860px} }
/* Sel tabel Uraian yang terkunci otomatis dari Analisa */
table.hps-uraian td.hps-cell-locked input,table.hps-uraian td.hps-cell-locked textarea{background:#eef4f5;color:#41565c;cursor:not-allowed;border-color:#d3e0e2}
.hps-lock-note{display:flex;align-items:flex-start;gap:7px;font-size:10.5px;color:#0b6a73;background:#eef8f9;border:1px dashed #a9d3d8;border-radius:10px;padding:8px 11px;margin:0 0 10px;line-height:1.55}
.hps-lock-note b{color:var(--teal-dark)}

/* ==================== ANALISA HARGA SATUAN ==================== */
/* Kotak input Sumber Referensi (jumlah menyesuaikan Jumlah Referensi) */
.ana-ref-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:10px;margin-top:4px}
.ana-ref-cell{display:flex;align-items:center;gap:8px;background:#f6fbfc;border:1px solid #dde9eb;border-radius:11px;padding:8px 10px}
.ana-ref-cell .rn{flex:0 0 auto;width:26px;height:26px;border-radius:7px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;font-family:'Plus Jakarta Sans'}
.ana-ref-cell input{flex:1 1 auto;min-width:0;border:1px solid #cdd9de;border-radius:8px;padding:6px 9px;font-size:12px;background:#fff;color:var(--ink)}
.ana-ref-cell input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}

/* Toolbar Analisa Harga Satuan (langkah 2): pemilih Referensi + Metode Perhitungan */
.ana-toolbar{display:flex;flex-wrap:wrap;align-items:flex-end;gap:12px;justify-content:stretch;margin:0 0 14px;background:linear-gradient(180deg,#f3fafb,#e9f5f6);border:1px solid #d4e6e9;border-radius:14px;padding:14px 16px;box-shadow:0 2px 8px rgba(16,40,50,.05)}
.ana-toolbar .ana-tb-field{display:flex;flex-direction:column;gap:5px;flex:1 1 0;min-width:150px}
.ana-toolbar .ana-tb-field label{font-size:10px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#7c8a8f}
.ana-toolbar .ana-tb-field select,.ana-toolbar .ana-tb-field input{width:100%;box-sizing:border-box;height:40px;border:1px solid #cdd9de;border-radius:9px;padding:8px 12px;font-size:12.5px;background:#fff;color:var(--ink);font-family:inherit}
.ana-toolbar .ana-tb-field select:focus,.ana-toolbar .ana-tb-field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
.ana-ref-pill{margin-right:auto;display:flex;align-items:center;gap:8px;background:linear-gradient(180deg,#f3fbfc,#e9f6f7);border:1px dashed #a9d3d8;border-radius:11px;padding:8px 12px;font-size:11px;color:var(--teal-dark);font-weight:700}
.ana-ref-pill b{font-family:'Plus Jakarta Sans';font-weight:800}
.ana-dp-rokinf{display:flex;gap:14px;flex-wrap:wrap;margin-top:16px;padding-top:14px;border-top:1px dashed #dbe6e9}
.ana-dp-rokinf .ana-tb-field{display:flex;flex-direction:column;gap:5px;flex:0 1 240px;min-width:190px}
.ana-dp-rokinf .ana-tb-field label{font-size:10px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#7c8a8f}
.ana-dp-rokinf .ana-tb-field select,.ana-dp-rokinf .ana-tb-field input{width:100%;box-sizing:border-box;height:40px;border:1px solid #cdd9de;border-radius:9px;padding:8px 12px;font-size:12.5px;background:#fff;color:var(--ink);font-family:inherit}
.ana-dp-rokinf .ana-tb-field select:focus,.ana-dp-rokinf .ana-tb-field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}

/* Tabel input analisa per-referensi */
.ana-uraian-wrap{overflow-x:auto;border:1px solid #dde9eb;border-radius:14px;box-shadow:0 2px 8px rgba(16,40,50,.05)}
table.ana-uraian{border-collapse:separate;border-spacing:0;width:100%;min-width:980px}
table.ana-uraian thead th{background:#0E7C86;color:#fff;font-weight:800;font-size:10.5px;text-transform:uppercase;letter-spacing:.2px;padding:9px 8px;text-align:center;white-space:nowrap;vertical-align:middle}
table.ana-uraian thead th.c-ur{text-align:center;min-width:300px}
table.ana-uraian tbody td{border-bottom:1px solid #e8f0f1;padding:7px 8px;vertical-align:middle;font-size:12px}
table.ana-uraian tbody tr:last-child td{border-bottom:none}
table.ana-uraian tbody tr:nth-child(even){background:#f8fbfc}
table.ana-uraian td.c-no,table.ana-uraian thead th.c-no{width:22px;min-width:22px;max-width:26px;padding-left:4px;padding-right:4px}
table.ana-uraian td.c-no{text-align:center;font-weight:800;color:#0b6a73}
table.ana-uraian textarea,table.ana-uraian input,table.ana-uraian select{width:100%;border:1px solid #cdd9de;border-radius:9px;padding:7px 8px;font-size:12px;background:#fff;font-family:inherit;color:var(--ink)}
table.ana-uraian textarea{resize:vertical;min-height:36px;line-height:1.45}
table.ana-uraian td.c-kel input{min-width:92px}
table.ana-uraian td.c-sat input{text-align:center;min-width:29px}
table.ana-uraian td.c-vol input{text-align:center;min-width:29px}
table.ana-uraian td.c-money input{text-align:right;min-width:118px}
table.ana-uraian td.c-method select{min-width:120px}
table.ana-uraian textarea:focus,table.ana-uraian input:focus,table.ana-uraian select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
table.ana-uraian td.c-calc{text-align:right;font-weight:800;color:#0b6a73;white-space:nowrap;background:#f2fafb;min-width:118px}

/* Kartu rekap hasil analisa (Rata-rata / Terendah antar referensi) */
.ana-res-card{margin-top:16px;border:1px solid #dde9eb;border-radius:14px;overflow:hidden}
.ana-res-head{display:flex;align-items:center;gap:9px;padding:11px 15px;background:linear-gradient(90deg,#0E7C86,#0b6a73);color:#fff;font-weight:800;font-size:12.5px}
.ana-res-head svg{width:16px;height:16px}
.ana-res td.c-mtd,.ana-res th.c-mtd{text-align:center;width:116px;min-width:106px;max-width:132px}
.ana-res th.c-mtd{white-space:normal;line-height:1.2}
.ana-res td.c-mtd{white-space:normal}
.ana-res td.c-rok,.ana-res th.c-rok{text-align:center;white-space:nowrap;width:74px;min-width:64px}
.ana-res td.c-rok{font-weight:700;color:#0b6a73}
.ana-res td.c-inf,.ana-res th.c-inf{text-align:center;width:98px;white-space:nowrap}
.ana-res td.c-inf input{width:54px;text-align:center;border:1px solid #cdd9de;border-radius:8px;padding:5px 6px;font-size:11.5px;font-family:inherit}
.ana-res td.c-inf input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
.ana-res td.c-inf .c-inf-suf{color:#9aa7ab;font-weight:700;margin-left:4px}
.ana-res-wrap{overflow-x:auto}
table.ana-res{width:100%;border-collapse:collapse;border-spacing:0;min-width:760px}
/* Desain mengikuti tabel input (ana-uraian): tanpa grid vertikal, hanya garis
   horizontal tipis antar baris + zebra lembut. */
table.ana-res th,table.ana-res td{border:none}
table.ana-res tbody td{border-bottom:1px solid #e8f0f1}
table.ana-res tbody tr:last-child td{border-bottom:none}
table.ana-res thead th{background:#0E7C86;color:#fff;font-weight:800;font-size:10px;text-transform:uppercase;letter-spacing:.3px;padding:9px 10px;text-align:center;white-space:normal;word-break:normal;overflow-wrap:break-word;line-height:1.25;vertical-align:middle}
table.ana-res thead th.c-ur{text-align:center}
table.ana-res thead th.c-no{text-align:center;width:46px;min-width:40px;max-width:52px}
table.ana-res tbody td.c-no{width:46px;min-width:40px;max-width:52px}
table.ana-res tbody td{padding:9px 10px;font-size:12px;text-align:right;white-space:nowrap;color:#2b3f48}
table.ana-res tbody tr:nth-child(even) td{background:#f8fbfc}
table.ana-res tbody td.c-no{text-align:center;font-weight:800;color:#0b6a73}
table.ana-res tbody td.c-ur{text-align:left;font-weight:600}
table.ana-res th.c-sat,table.ana-res td.c-sat,
table.ana-res th.c-vol,table.ana-res td.c-vol{width:1%;min-width:64px;text-align:center;white-space:nowrap}
table.ana-res td.c-vol{font-weight:600}
table.ana-res tbody td.c-res{font-weight:800;color:#0b3d42;background:#eef7f8}
/* Lebar kolom: Uraian Pekerjaan menyerap seluruh sisa ruang; kolom lain menyusut
   secukupnya (width:1% + nowrap) sehingga kolom harga tidak melebar berlebihan. */
table.ana-res th.c-ur,table.ana-res td.c-ur{width:100%}
table.ana-res td.c-mtd,
table.ana-res th.c-rok,table.ana-res td.c-rok,
table.ana-res th.c-inf,table.ana-res td.c-inf{width:1%;white-space:nowrap}
/* Header kolom "Metode Perhitungan" boleh turun ke dua baris (METODE / PERHITUNGAN)
   agar tidak terpotong; lebar kolom mengikuti aturan .c-mtd di atas. */
table.ana-res th.c-mtd{white-space:normal;word-break:normal;overflow-wrap:break-word;line-height:1.2}
table.ana-res th.c-money,table.ana-res td.c-money{width:1%;min-width:118px;white-space:nowrap}
.ana-res-hint{padding:10px 15px;font-size:11px;color:#5a6b70;background:#f6fafb;border-top:1px solid #eef4f5;line-height:1.55}
.ana-res-hint b{color:var(--teal-dark)}
.ana-method-chip{display:inline-block;font-size:9px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#0b6a73;background:#dff1f2;padding:2px 8px;border-radius:20px}
@media(max-width:640px){ table.ana-uraian{min-width:940px} .ana-toolbar{justify-content:flex-start} }

/* Selector Jenis Pekerjaan (kanan atas kartu Data Pekerjaan) */
.ana-jenis-top{display:flex;flex-direction:column;gap:4px;min-width:190px}
/* Cluster gabungan Jenis Pekerjaan + tombol Pilih Data Pekerjaan (satu layer, kanan atas) */
.ana-top-controls{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap;margin-left:auto}
.ana-top-controls .ana-jenis-top{min-width:180px}
.ana-top-dp{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end}
@media(max-width:640px){
  .ana-top-controls{width:100%}
  .ana-top-controls .ana-jenis-top{flex:1 1 100%;min-width:0}
  .ana-top-dp{width:100%}
  .ana-top-dp .btn{flex:1 1 auto;justify-content:center}
}
.ana-jenis-top label{font-size:10px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#7c8a8f}
.ana-jenis-top select{border:1px solid #cdd9de;border-radius:9px;padding:8px 10px;font-size:12px;background:#fff;color:var(--ink);font-family:inherit}
.ana-jenis-top select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}

/* Bagian 2 Konstruksi: kolom Inflasi & Koefisien pada tabel */
table.hps-uraian td.c-pct input,table.hps-uraian td.c-koef input{text-align:center;min-width:70px}
table.hps-uraian th.c-ref,table.hps-uraian td.c-ref{min-width:160px}
table.hps-uraian td.c-ref input{width:100%}

/* Bagian 3 Konstruksi: Analisa Harga Satuan Pekerjaan (AHSP) */
.ana-ahsp-head{display:flex;align-items:flex-end;justify-content:space-between;flex-wrap:wrap;gap:14px;margin-bottom:16px;padding-bottom:14px;border-bottom:1px dashed #dde9eb}
.ana-ahsp-head .tt{display:flex;align-items:center;gap:10px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:14px;color:var(--teal-dark);flex:1 1 240px}
.ana-ahsp-sec{margin-top:20px}
.ana-ahsp-sec-title{display:flex;align-items:center;justify-content:space-between;gap:10px;font-family:'Plus Jakarta Sans';font-weight:800;font-size:12px;color:#0b3d42;margin-bottom:9px;letter-spacing:.2px}
.ana-ahsp-sec-badge{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:7px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;font-size:11px;font-weight:800;margin-right:8px;box-shadow:0 2px 6px rgba(14,124,134,.28)}
.ana-ahsp-sec-title .ana-ahsp-sec-label{flex:1 1 auto;text-transform:uppercase;letter-spacing:.4px}
.ana-ahsp-add{border:1px solid var(--teal);background:#eef8f9;color:var(--teal-dark);font-size:10.5px;font-weight:800;padding:6px 13px;border-radius:20px;cursor:pointer;text-transform:none;letter-spacing:0;transition:background .15s,box-shadow .15s,transform .1s}
.ana-ahsp-add:hover{background:#dff1f2;box-shadow:0 3px 10px rgba(14,124,134,.18)}
.ana-ahsp-add:active{transform:scale(.97)}
.ana-ahsp-del{border:none;background:#fbeaea;color:#b23b3b;width:26px;height:26px;border-radius:8px;font-size:15px;line-height:1;cursor:pointer;transition:background .15s,transform .1s}
.ana-ahsp-del:hover{background:#f6d5d5}
.ana-ahsp-del:active{transform:scale(.94)}
table.ana-ahsp-table td.c-act{width:38px;text-align:center;padding:6px 4px}
table.ana-ahsp-table tbody tr:hover td{background:#f2fafb}
table.ana-ahsp-table tbody tr.grp:hover td,table.ana-ahsp-table tfoot tr:hover td{background:inherit}
table.ana-ahsp-table tfoot td{background:linear-gradient(180deg,#eefaf2,#e6f7ec);font-weight:800;color:#0d7a3f;padding:11px 12px;font-size:12.5px;border-top:2px solid #cfe9d8}
table.ana-ahsp-table tfoot td:first-child{text-transform:uppercase;letter-spacing:.3px;font-size:10.5px}
table.ana-ahsp-table tfoot tr td:last-child{border-radius:0 0 8px 0}
.ana-rok-chip{display:inline-block;color:#0b6a73;font-weight:800;background:#dff1f2;padding:2px 9px;border-radius:20px;font-size:11px;margin-left:6px;white-space:nowrap}
/* Layer AHSP (satu blok = satu analisa/pekerjaan) */
.ana-ahsp-layer{border:1px solid #dde9eb;border-radius:16px;padding:20px 22px;margin-bottom:18px;background:linear-gradient(180deg,#fdffff,#fbfeff);box-shadow:0 3px 14px rgba(20,60,70,.06);position:relative}
.ana-ahsp-layer::before{content:'';position:absolute;top:0;left:0;bottom:0;width:4px;border-radius:16px 0 0 16px;background:linear-gradient(180deg,var(--teal),var(--cyan))}
.ana-ahsp-no{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:8px;background:#eef8f9;color:var(--teal-dark);font-weight:800;font-size:12.5px}
.ana-ahsp-judul-input{flex:1 1 220px;min-width:180px;border:1px solid #cdd9de;border-radius:10px;padding:9px 12px;font-size:13.5px;font-family:'Plus Jakarta Sans';font-weight:700;color:var(--ink);background:#fff;transition:border-color .15s,box-shadow .15s}
.ana-ahsp-judul-input::placeholder{color:#a7b4b8;font-weight:600}
.ana-ahsp-judul-input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
/* Bar navigasi Bagian 3: paginasi (kiri) + Tambah/Hapus Analisa (kanan) */
.ana-ahsp-topbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;margin-bottom:18px;padding:12px 14px;background:#f6fafb;border:1px solid #e5eef0;border-radius:13px}
.ana-ahsp-topbar-pager{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.ana-ahsp-topbar-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ana-ahsp-onlylabel{font-size:11.5px;color:#5a6b70;font-weight:700}
.ana-ahsp-rok-field{flex:0 0 auto;width:150px}
.ana-ahsp-rok-btn{border:1.5px solid var(--teal);background:#eef8f9;color:var(--teal-dark);font-weight:800;font-size:12.5px;border-radius:10px;padding:9px 30px 9px 14px;cursor:pointer;font-family:'Plus Jakarta Sans';width:100%;transition:background .15s,box-shadow .15s;
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230b6a73' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;background-size:14px 14px}
.ana-ahsp-rok-btn:hover{background-color:#dff1f2;box-shadow:0 3px 10px rgba(14,124,134,.15)}
.ana-ahsp-rok-btn:focus{outline:none;box-shadow:0 0 0 3px rgba(14,124,134,.15)}
@media(max-width:640px){ .ana-ahsp-rok-field{width:100%} }
.ana-ahsp-hapus-analisa{border:1px solid #e2a9a9;background:#fbeaea;color:#b23b3b;font-size:10.5px;font-weight:800;padding:6px 14px;border-radius:20px;cursor:pointer;transition:background .15s,box-shadow .15s,transform .1s}
.ana-ahsp-hapus-analisa:hover{background:#f6d5d5;box-shadow:0 3px 10px rgba(178,59,59,.15)}
.ana-ahsp-hapus-analisa:active{transform:scale(.97)}
/* Tombol tambah/hapus baris per-baris pada tabel Harga Satuan (Konstruksi) */
table.hps-uraian td.c-act{width:64px;text-align:center;white-space:nowrap;padding:6px 4px}
.ana-row-add{width:26px;height:26px;padding:0;border-radius:8px;font-size:15px;line-height:1;margin-right:4px}

/* Daftar pilih analisa (modal) */
.hps-ana-list{display:flex;flex-direction:column;gap:9px;max-height:56vh;overflow-y:auto;padding:2px}
.hps-ana-item{display:flex;align-items:center;gap:12px;border:1px solid #dde9eb;border-radius:12px;padding:11px 13px;background:#fff;cursor:pointer;transition:.15s}
.hps-ana-item:hover{border-color:var(--teal);background:#f4fbfc;box-shadow:0 2px 8px rgba(14,124,134,.1)}
.hps-ana-item .ic{flex:0 0 auto;width:34px;height:34px;border-radius:9px;background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;display:flex;align-items:center;justify-content:center}
.hps-ana-item .ic svg{width:17px;height:17px}
.hps-ana-item .tx{flex:1 1 auto;min-width:0}
.hps-ana-item .tx b{display:block;font-size:12.5px;color:var(--teal-dark);font-family:'Plus Jakarta Sans';font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hps-ana-item .tx span{font-size:10.5px;color:var(--muted)}
.hps-ana-item .go{flex:0 0 auto;color:var(--teal)}
.hps-ana-item .go svg{width:18px;height:18px}
.hps-ana-empty{text-align:center;color:#9aa7ab;font-size:12px;padding:26px 10px}

/* Field terkunci (auto-terisi dari Analisa) */
.field.is-locked{position:relative}
.field.is-locked input,.field.is-locked select{background:#eef4f5;color:#41565c;cursor:not-allowed;border-color:#d3e0e2}
.field.is-locked .lock-badge{position:absolute;top:0;right:0;display:inline-flex;align-items:center;gap:3px;font-size:8.5px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;color:#0b6a73;background:#dff1f2;padding:2px 7px;border-radius:20px}
.field.is-locked .lock-badge svg{width:9px;height:9px}
.hps-analisa-bar .btn-unpick{background:#fff;color:#b23b3b;border:1px solid #e6b8b8}
.hps-analisa-bar .btn-unpick:hover{background:#fdf1f1}

/* ===== 4. table-unify-css ===== */
/* =================================================================
   Penyeragaman tampilan tabel INPUT & PENGISIAN DATA agar warna &
   garis (horizontal + vertikal) sama seperti tabel Monitoring —
   Daftar Pekerjaan: header gradient teal, grid penuh 1px #dce6e9,
   baris genap #f6fafb. Latar fungsional sel (kolom label, baris
   otomatis, sel terkunci) tetap dipertahankan.
   ================================================================= */
table.hps-uraian,
table.ana-uraian,
table.rho-matrix{ border-collapse:collapse; border-spacing:0; }

/* Garis grid horizontal + vertikal seragam pada semua sel */
table.hps-uraian th, table.hps-uraian td,
table.ana-uraian th, table.ana-uraian td,
table.rho-matrix th, table.rho-matrix td{ border:1px solid #dce6e9; }

/* Header: gradient teal 180° + teks putih (sama seperti Monitoring) */
table.hps-uraian thead th,
table.ana-uraian thead th{
  background:#0E7C86;
  color:#fff; border-color:#0b6b74;
}
/* RHO — samakan header input dengan tampilan dokumen/PDF (teal rata) */
table.rho-matrix thead th{
  background:#0E7C86;
  color:#fff; border-color:#0b6b74;
}
/* Kolom label pertama rho-matrix ikut header teal saat di baris thead */
table.rho-matrix thead th.rho-c-lbl{
  background:#0b6a73; color:#fff; text-align:center;
}

/* Baris genap diberi arsiran halus seperti Monitoring (untuk tabel baris-vertikal) */
table.hps-uraian tbody tr:nth-child(even),
table.ana-uraian tbody tr:nth-child(even){ background:#f6fafb; }
/* Pastikan garis bawah baris terakhir tetap tampil (grid penuh) */
table.hps-uraian tbody tr:last-child td,
table.ana-uraian tbody tr:last-child td{ border-bottom:1px solid #dce6e9; }

/* =================================================================
   Hilangkan BORDER PALING LUAR (atas/bawah/kiri/kanan) pada tabel —
   garis dalam (antar sel) tetap ada. Berlaku utk tabel grid & Hasil Analisa.
   ================================================================= */
.hps-uraian-wrap,.ana-uraian-wrap{ border:none; }
.ana-res-card{ border:none; }
table.hps-uraian,table.ana-uraian,table.rho-matrix,table.ana-res{ border:none; }
/* atas: buang border atas header */
table.hps-uraian thead th,table.ana-uraian thead th,table.rho-matrix thead th,table.ana-res thead th{ border-top:none; }
/* kiri: buang border kiri kolom pertama */
table.hps-uraian tr>*:first-child,table.ana-uraian tr>*:first-child,table.rho-matrix tr>*:first-child,table.ana-res tr>*:first-child{ border-left:none; }
/* kanan: buang border kanan kolom terakhir */
table.hps-uraian tr>*:last-child,table.ana-uraian tr>*:last-child,table.rho-matrix tr>*:last-child,table.ana-res tr>*:last-child{ border-right:none; }
/* bawah: buang border bawah baris terakhir */
table.hps-uraian tbody tr:last-child td,table.ana-uraian tbody tr:last-child td,table.rho-matrix tbody tr:last-child td,table.ana-res tbody tr:last-child td{ border-bottom:none; }

/* =================================================================
   Perjelas GARIS GRID (vertikal + horizontal) khusus tabel
   Pengisian Referensi (rho-matrix) agar tiap sel tegas & rapi
   saat diisi — badan tabel garis teal-abu jelas, pemisah kolom
   header terlihat tipis di atas latar teal.
   ================================================================= */
table.rho-matrix td{ border-color:#9bbfc5; }
table.rho-matrix thead th{ border-color:#3f9ba3; }

/* ===== 5. spk-style ===== */
.btn.btn-sm{padding:7px 12px;font-size:11.5px}
.spk-stepper{display:flex;align-items:center;gap:10px;margin:2px 2px 16px}
.spk-stp{display:inline-flex;align-items:center;gap:8px;border:1.5px solid #DfE4E9;background:#fff;color:#6B7885;font-weight:700;font-size:13px;padding:8px 15px;border-radius:30px;cursor:pointer;transition:.15s;font-family:inherit}
.spk-stp:hover{border-color:#0E7C86}
.spk-stp .spk-stp-no{width:22px;height:22px;flex:0 0 auto;border-radius:50%;background:#eef3f7;color:#6B7885;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:800}
.spk-stp.active{border-color:#0E7C86;background:#f0f8f9;color:#0E7C86}
.spk-stp.active .spk-stp-no{background:linear-gradient(135deg,#0E7C86,#12303f);color:#fff}
.spk-stp.done{color:#12303f;border-color:#bfe0e3}
.spk-stp.done .spk-stp-no{background:#0E7C86;color:#fff}
.spk-stp-line{flex:1;max-width:120px;height:2px;background:#DfE4E9;border-radius:2px}
@media(max-width:620px){.spk-stepper{flex-wrap:wrap}.spk-stp{font-size:12px;padding:7px 12px}.spk-stp-line{display:none}}
.spk-step{display:flex;align-items:center;gap:12px;margin:14px 2px 10px}
.spk-step-no{width:30px;height:30px;flex:0 0 auto;border-radius:50%;background:linear-gradient(135deg,#0E7C86,#12303f);color:#fff;font-weight:800;display:flex;align-items:center;justify-content:center;font-size:14px}
.spk-step-tx b{display:block;font-size:14px;color:#12303f}
.spk-step-tx span{display:block;font-size:12px;color:#6B7885}
.spk-kl-tools{display:flex;gap:6px}
.spk-kl-list{display:grid;grid-template-columns:1fr 1fr;gap:8px}
@media(max-width:760px){.spk-kl-list{grid-template-columns:1fr}}
.spk-narasi-hint{font-weight:400;color:#8A97A2;font-size:11px}
.spk-narasi-input{width:100%;font-family:inherit;line-height:1.5;resize:vertical;min-height:120px}
.spk-narasi-prevwrap{margin-top:10px}
.spk-narasi-prevlabel{font-size:10.5px;color:#6B7885;font-weight:800;letter-spacing:.04em;text-transform:uppercase;margin-bottom:5px}
/* --spk-lh = nilai CSS untuk "1,15 baris" gaya Word. Nilainya diukur ulang oleh JS
   (spkLHInit) dari tinggi baris tunggal font dokumen; 1.32 hanya nilai cadangan. */
:root{--spk-lh:1.32;--spk-kv-gap:4pt}
.spk-narasi-prev{font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:var(--spk-lh,1.32);color:#1c2733;background:#F8FAFB;border:1px solid #E2E7EB;border-radius:10px;padding:12px 15px;max-height:300px;overflow:auto}
.spk-narasi-prev p{margin:0 0 9px;text-align:justify;line-height:var(--spk-lh,1.32)}
.spk-narasi-prev p:last-child{margin-bottom:0}
/* Kisi cm mengikuti gaya paragraf template .docx (bukan em, agar tidak ikut
   mengecil/membesar oleh ukuran huruf pratinjau). */
.spk-narasi-prev p.klp{text-indent:.75cm}
.spk-narasi-prev p.klp1{margin-left:.75cm;text-indent:.75cm}
.spk-narasi-prev p.klp2{margin-left:1.5cm;text-indent:.75cm}
.spk-narasi-prev p.kl1{margin-left:.75cm;text-indent:-.75cm}
.spk-narasi-prev p.kl2{margin-left:1.5cm;text-indent:-.75cm}
.spk-narasi-prev p.kldesc{margin-left:.75cm;text-indent:0}
.spk-narasi-prev p .n{display:inline-block;box-sizing:border-box;text-indent:0;white-space:nowrap}
.spk-narasi-prev p .n:not([style]){min-width:.75cm}
.spk-narasi-prev p .n.m{display:inline-block;box-sizing:border-box;width:auto;min-width:1.5em;padding-right:.35em;text-indent:0;text-align:left}
.spk-narasi-prev i{font-style:italic}
.spk-narasi-prev b{font-weight:700}
.spk-narasi-empty{color:#9AA7B2;font-style:italic;font-family:inherit;font-size:12px}
/* Pemilihan klausul: tanpa animasi/geser (efek bergetar dihilangkan) */
.spk-kl-pick{display:flex;align-items:center;gap:10px;padding:9px 11px;border:1.5px solid #DfE4E9;border-radius:10px;cursor:pointer;background:#fff;transition:none;animation:none;transform:none;will-change:auto}
.spk-kl-pick:hover,.spk-kl-pick:active,.spk-kl-pick:focus,.spk-kl-pick:focus-within{border-color:#0E7C86;transform:none;animation:none;transition:none}
.spk-kl-pick *,.spk-kl-pick input{transition:none!important;animation:none!important;transform:none!important}
.spk-kl-pick.on{border-color:#0E7C86;background:#f0f8f9}
.spk-kl-pick input{width:17px;height:17px;accent-color:#0E7C86;flex:0 0 auto}
.spk-kl-no{width:22px;height:22px;flex:0 0 auto;border-radius:6px;background:#eef3f7;color:#12303f;font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center}
.spk-kl-judul{font-size:12.5px;font-weight:600;color:#233}
.spk-klx-list{display:flex;flex-direction:column;gap:8px}
.spk-klx{display:flex;align-items:center;gap:12px;padding:11px 13px;border:1.5px solid #DfE4E9;border-radius:11px;background:#fff}
.spk-klx.off{opacity:.6;background:#f7f8f9}
.spk-klx-no{width:26px;height:26px;flex:0 0 auto;border-radius:7px;background:#12303f;color:#fff;font-weight:800;display:flex;align-items:center;justify-content:center;font-size:12px}
.spk-klx-main{flex:1;min-width:0}
.spk-klx-judul{font-weight:700;font-size:13px;color:#12303f}
.spk-klx-prev{font-size:11.5px;color:#6B7885;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.spk-klx-act{display:flex;gap:5px;flex:0 0 auto}
.spk-badge-off{font-size:10px;background:#e0e5ea;color:#66707a;padding:1px 7px;border-radius:20px;font-weight:600;vertical-align:middle}
.spk-ov{position:fixed;inset:0;background:rgba(14,48,63,.5);display:none;align-items:center;justify-content:center;z-index:9999;padding:20px}
.spk-ov.show{display:flex}
.spk-ov-modal{background:#fff;border-radius:14px;width:min(920px,96vw);max-height:94vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 30px 80px -20px rgba(0,0,0,.5)}
.spk-ov-head{display:flex;align-items:center;justify-content:space-between;padding:13px 18px;border-bottom:1px solid #DfE4E9}
.spk-ov-title{font-weight:800;color:#12303f;font-size:15px}
.spk-ov-actions{display:flex;gap:8px}
.spk-ov-body{flex:1;overflow:auto;background:#eceff1}
.spk-ov-body iframe{width:100%;height:78vh;border:0;background:#fff;display:block}
.spk-ov-edit{width:min(820px,96vw)}
.spk-edit-body{padding:16px 18px;background:#fff}
.spk-edit-body textarea{width:100%;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;line-height:1.5}
.spk-edit-hint{font-size:11.5px;color:#6B7885;margin-top:8px}
.spk-ov-foot{padding:12px 18px;border-top:1px solid #DfE4E9;display:flex;justify-content:flex-end}
.spk-edit-body code,#spk-klausul-content code,.spk-klausul-host code{background:#eef3f7;color:#0E7C86;padding:1px 5px;border-radius:5px;font-size:11.5px}
/* ===== Editor WYSIWYG bergaya dokumen SPK ===== */
.spk-we-wrap{display:flex;flex-direction:column;background:#fff}
.spk-we-toolbar{background:#fff;border-bottom:1px solid #e5eaee;padding:7px 10px;position:sticky;top:0;z-index:5}
.spk-we-trow{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.spk-we-trow+.spk-we-trow{margin-top:6px}
.spk-we-grp{display:inline-flex;align-items:center;gap:3px;padding:1px}
.spk-we-sep{width:1px;height:22px;background:#e6e9ec;margin:0 3px}
.spk-we-toolbar button,.spk-we-toolbar select{height:31px;border:1px solid #e0e4e8;background:#fff;border-radius:6px;cursor:pointer;font-size:13px;color:#333;padding:0 8px;display:inline-flex;align-items:center;justify-content:center;transition:background .12s,border-color .12s;font-family:Arial,Helvetica,sans-serif}
.spk-we-toolbar button{min-width:32px}
.spk-we-toolbar button:hover,.spk-we-toolbar select:hover{background:#f4f6f8;border-color:#cdd3d9}
.spk-we-toolbar button:active{background:#e9edf0}
.spk-we-toolbar button.active{background:#e3f0ff;border-color:#9cc4f5;color:#1565c0}
.spk-we-clabel{display:inline-flex;align-items:center;gap:4px;cursor:pointer;font-size:12px;color:#333;height:31px;padding:0 6px;border:1px solid #e0e4e8;border-radius:6px;background:#fff}
.spk-we-clabel:hover{background:#f4f6f8;border-color:#cdd3d9}
.spk-we-clabel input[type=color]{width:22px;height:20px;padding:0;border:1px solid #e0e4e8;border-radius:4px;cursor:pointer;background:none}
.spk-we-check{display:inline-flex;align-items:center;gap:6px;height:31px;padding:0 9px;font-size:12px;color:#3d4a55;cursor:pointer;user-select:none;border:1px solid #e0e4e8;border-radius:6px;background:#fff}
.spk-we-check:hover{background:#f4f6f8;border-color:#cdd3d9}
.spk-we-check input{cursor:pointer;margin:0}
/* Ruler */
.spk-we-rulerwrap{background:#eef1f3;border-bottom:1px solid #e5eaee;padding:3px 0;user-select:none;display:flex;justify-content:center;overflow:hidden}
.spk-we-rulerwrap.hidden{display:none}
.spk-we-ruler{position:relative;height:34px;width:210mm;max-width:100%}
/* Penanda indentasi pada penggaris (dapat digeser, gaya Word) */
.spk-rm{cursor:default}
.spk-tab{cursor:pointer}
.spk-tab path{stroke:#12303f}
.spk-tab:hover path{stroke:#c0392b}
.spk-tabspace{display:inline-block}
.spk-rm polygon,.spk-rm rect{fill:#f3f6f8;stroke:#79848d;stroke-width:1;stroke-linejoin:round}
.spk-rm:hover polygon,.spk-rm:hover rect{fill:#1d9e75;stroke:#0f7a58}
.spk-rm.on polygon,.spk-rm.on rect{fill:#1d9e75;stroke:#0f7a58}
.spk-we-rulerwrap{position:relative}
.spk-we-ruletip{position:absolute;top:2px;right:10px;background:#12303f;color:#fff;font:11px Arial;padding:2px 8px;border-radius:5px;display:none;z-index:6;white-space:nowrap}
.spk-we-ruletip.show{display:block}
.spk-we-ruler svg{display:block;overflow:visible}
/* Area kertas A4 — Portrait, margin Normal (2,54 cm) persis seperti Microsoft Word */
.spk-we-pagearea{background:#e7eaed;padding:22px 14px 40px;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;overflow:auto;flex:1}
.spk-we-page{width:210mm;min-height:297mm;flex:0 0 auto;background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.16);padding:25.4mm;box-sizing:border-box;position:relative;
  /* garis bantu batas halaman: muncul tiap kelipatan tinggi A4 (297mm) */
  background-image:repeating-linear-gradient(to bottom,rgba(0,0,0,0) 0,rgba(0,0,0,0) calc(297mm - 2px),#c9d1d8 calc(297mm - 2px),#c9d1d8 297mm)}
/* Panduan margin disembunyikan — tampil sebagai kertas putih polos seperti Word.
   (Teks tetap dibatasi margin normal 25,4 mm pada .spk-we-page.) */
.spk-we-page::before{content:none}
.spk-we-page>*{position:relative;z-index:1}
/* Kanvas edit: samakan persis dengan .spk-cl dokumen (Arial 11pt, indent 0,75cm) */
/* Isi klausul pada dokumen SPK selalu menjorok 0,75cm (sejajar dengan huruf
   sesudah nomor klausul) -> kanvas editor dibuat sama persis. */
.spk-we-doc{outline:none;font-family:"Inter Local","Inter","Segoe UI",Arial,sans-serif;font-size:11pt;line-height:var(--spk-lh,1.32);color:#000;min-height:246.2mm;padding-left:.9cm}
/* Blok pertama editor tidak membawa spasi-sebelum (sejajar margin atas) */
.spk-we-doc > *:first-child{margin-top:0}
/* Baris judul klausul (pratinjau, tidak dapat diedit) */
/* Gaya Word "Klausul Judul": ind left=0,65cm hanging=0,65cm, spacing after 3pt,
   line 1,15. Nomor otomatis Word rata KIRI, kotaknya selebar gantungan; dipakai
   min-width agar nomor 2 digit mendorong judulnya seperti tab stop Word. */
.spk-we-clhead{font-family:"Inter Local","Inter","Segoe UI",Arial,sans-serif;font-size:11pt;font-weight:700;text-transform:uppercase;color:#000;line-height:var(--spk-lh,1.3915);
  margin:0 0 3pt;padding-left:.75cm;text-indent:-.75cm;user-select:none}
.spk-we-clhead .n{display:inline-block;box-sizing:border-box;min-width:.75cm;text-indent:0;text-align:right;padding-right:.18cm;white-space:nowrap}
.spk-we-clhead .ph{color:#9AA7B2;font-weight:700}
.spk-we-clhead-tag{font:10px Arial;color:#9AA7B2;text-transform:none;font-weight:400;margin-left:6px;letter-spacing:.02em}
.spk-we-doc:empty:before{content:attr(data-ph);color:#9AA7B2;font-style:italic}
.spk-we-doc p{margin:0 0 6pt;text-align:justify;line-height:var(--spk-lh,1.32)}
.spk-we-doc p.kl0{margin-left:0;text-indent:0}
.spk-we-doc p.klp{margin-left:0;text-indent:.75cm}
.spk-we-doc p.klp1{margin-left:.75cm;text-indent:.75cm}
.spk-we-doc p.klp2{margin-left:1.5cm;text-indent:.75cm}
.spk-we-doc p.kl1{margin-left:.75cm;text-indent:-.75cm}
.spk-we-doc p.kl2{margin-left:1.5cm;text-indent:-.5cm}
.spk-we-doc p.kldesc{margin-left:.75cm;text-indent:0}
.spk-we-doc p .n{display:inline-block;box-sizing:border-box;text-indent:0;text-align:left;white-space:nowrap}
.spk-we-doc p .n:not([style]){min-width:.75cm}
/* ---- Foto di dalam klausul TOR/KAK (editor) ----
   Tampilan di editor sengaja dibuat sedekat mungkin dengan hasil cetak: blok
   tersendiri, tak pernah melebihi lebar kertas, rasio asli terjaga, dan
   berjarak 6pt dari teks di atasnya. Angka pastinya (batas kiri mengikuti
   kolom teks paragraf di atasnya) dihitung ulang di dokumen oleh
   torFotoFitScript(); di sini nilai itu hanya disalin saat foto disisipkan. */
.spk-we-doc p.tor-foto{margin-top:6pt;text-indent:0;text-align:left}
.spk-we-doc p.tor-foto img{display:block;width:auto;height:auto;max-width:100%}
.spk-we-doc p.tor-foto span.n{display:none}
/* Sorotan tipis saat foto diklik supaya jelas ia satu blok yang bisa dihapus
   dengan satu kali Backspace. */
.spk-we-doc p.tor-foto img:hover{outline:2px solid rgba(11,106,115,.35);outline-offset:2px}
.spk-we-doc i{font-style:italic}
.spk-we-doc b{font-weight:700}
.spk-we-doc.fp-active{cursor:crosshair}
.spk-we-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:9px 14px;background:#fff;border-top:1px solid #e5eaee}
.spk-we-status{font-size:12px;color:#7a848d;display:flex;gap:14px}
/* Modal editor lebih lebar untuk memuat kertas A4 utuh (210mm + ruang scroll) */
.spk-ov-we{width:min(1060px,98vw);height:94vh;max-height:94vh}
.spk-ov-we .spk-ov-body{padding:0;background:#e7eaed;display:flex;flex-direction:column;min-height:0}
/* Iframe Lihat Klausul (dirender via spkClauseDocHtml, identik pratinjau SPK).
   flex:1 agar mengisi tinggi overlay; latar abu sama dengan pratinjau dokumen. */
#spk-klausul-view-frame{flex:1 1 auto;width:100%;min-height:0;border:0;background:#e7eaed;display:block}
/* ---- Title bar bergaya jendela: Minimize / Maximize / Close ---- */
.spk-we-head{background:#12303f;border-bottom:none;padding:0 0 0 16px;user-select:none;cursor:default}
.spk-we-head .spk-ov-title{color:#fff;font-size:14px;letter-spacing:.01em}
.spk-we-wbtns{display:flex;align-items:stretch;gap:0;margin-left:auto}
.spk-we-wbtn{width:46px;height:42px;border:0;background:transparent;color:#e7eef3;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:background .12s,color .12s}
.spk-we-wbtn svg{width:15px;height:15px;pointer-events:none}
.spk-we-wbtn:hover{background:rgba(255,255,255,.14);color:#fff}
.spk-we-wbtn.close:hover{background:#e53935;color:#fff}
/* ---- Maximized ---- */
.spk-ov.we-max{padding:0}
.spk-ov.we-max .spk-ov-we{width:100vw;height:100vh;max-height:100vh;border-radius:0}
/* ---- Minimized: menyusut jadi bilah di kanan bawah, isi editor tetap tersimpan ---- */
.spk-ov.we-min{background:transparent;align-items:flex-end;justify-content:flex-end;padding:0;pointer-events:none}
.spk-ov.we-min .spk-ov-we{pointer-events:auto;width:min(360px,90vw);height:auto;max-height:none;border-radius:10px 10px 0 0;margin:0 20px 0 0;box-shadow:0 -8px 28px -6px rgba(10,25,40,.45)}
.spk-ov.we-min .spk-ov-body,.spk-ov.we-min .spk-we-foot{display:none}
.spk-ov.we-min .spk-we-head{cursor:pointer}
.spk-ov.we-min .spk-we-head .spk-ov-title{max-width:190px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ---- Format Painter ---- */
.spk-we-toolbar button#spk-we-fp.sticky{background:#e6f7ef;border-color:#7fd3ae;color:#12805c}
.spk-we-doc.fp-active{cursor:cell}
.spk-we-hint{font-size:11px;color:#8a949c}
@media(max-width:820px){ .spk-we-hint{display:none} }
/* Dropdown pustaka penomoran (gaya Word) */
.spk-we-numwrap{position:relative;display:inline-flex}
.spk-we-numpop{position:absolute;top:calc(100% + 4px);left:0;z-index:60;background:#fff;border:1px solid #d5dbe0;border-radius:10px;box-shadow:0 18px 44px -12px rgba(10,25,40,.4);padding:12px;width:340px;max-height:420px;overflow:auto;display:none}
.spk-we-numpop.show{display:block}
.spk-we-numsec{font-size:11px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;color:#5a6773;margin:2px 2px 8px}
.spk-we-numsec+.spk-we-numgrid{margin-bottom:12px}
.spk-we-numgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.spk-we-numcell{border:1px solid #e2e7eb;border-radius:8px;background:#fff;cursor:pointer;padding:9px 8px;min-height:64px;display:flex;flex-direction:column;justify-content:center;gap:3px;transition:border-color .12s,background .12s}
.spk-we-numcell:hover{border-color:#1d9e75;background:#f2fbf7}
.spk-we-numcell.sel{border-color:#1d9e75;border-width:2px;background:#eafaf3}
.spk-we-numcell .ln{display:flex;align-items:center;gap:6px;font:12px/1.1 Arial,Helvetica,sans-serif;color:#2a3540}
.spk-we-numcell .ln .mk{color:#12303f;min-width:22px;font-weight:600}
.spk-we-numcell .ln .ba{flex:1;height:3px;background:#c7ced4;border-radius:2px}
.spk-we-numcell.none{align-items:center;justify-content:center;font:600 12px Arial;color:#3d4a55}
.spk-we-numdiv{height:1px;background:#e8ebee;margin:4px 0 12px}
.spk-we-numact{display:flex;flex-direction:column;gap:2px;margin-top:6px}
.spk-we-numactbtn{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:none;border:none;border-radius:7px;padding:9px 8px;cursor:pointer;font:13px Arial;color:#25303a}
.spk-we-numactbtn:hover{background:#f2f5f7}
.spk-we-numactbtn svg{width:16px;height:16px;flex:0 0 auto;color:#5a6773}
/* Modal 'Tetapkan Format Nomor Baru' */
.spk-we-nfmodal{position:fixed;inset:0;z-index:10000;background:rgba(14,48,63,.5);display:none;align-items:center;justify-content:center;padding:20px}
.spk-we-nfmodal.show{display:flex}
.spk-we-nfcard{background:#fff;border-radius:12px;width:min(430px,96vw);box-shadow:0 30px 80px -20px rgba(0,0,0,.5);overflow:hidden}
.spk-we-nfhead{display:flex;align-items:center;justify-content:space-between;padding:13px 16px;border-bottom:1px solid #e5eaee;font-weight:800;color:#12303f;font-size:14px}
.spk-we-nfbody{padding:14px 16px}
.spk-we-nfbody label{display:block;font-size:12px;font-weight:600;color:#3d4a55;margin:10px 0 5px}
.spk-we-nfbody label:first-child{margin-top:0}
.spk-we-nfbody select,.spk-we-nfbody input{width:100%;height:34px;border:1px solid #d5dbe0;border-radius:7px;padding:0 9px;font:13px Arial;color:#25303a;background:#fff}
.spk-we-nfprev{margin-top:12px;border:1px solid #e2e7eb;border-radius:8px;padding:12px;background:#f8fafb}
.spk-we-nfprev .pl{font-size:11px;color:#6b7885;font-weight:700;text-transform:uppercase;letter-spacing:.03em;margin-bottom:7px}
.spk-we-nfprev .rw{display:flex;align-items:center;gap:8px;margin:5px 0;font:13px Arial;color:#1c2733}
.spk-we-nfprev .rw .mk{min-width:32px;font-weight:600}
.spk-we-nfprev .rw .ba{flex:1;height:4px;background:#111;border-radius:2px}
.spk-we-nffoot{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid #e5eaee}
/* Dropdown spasi baris (gaya Word) */
.spk-we-lhwrap{position:relative;display:inline-flex}
.spk-we-lhpop{position:absolute;top:calc(100% + 4px);left:0;z-index:60;background:#fff;border:1px solid #d5dbe0;border-radius:10px;box-shadow:0 18px 44px -12px rgba(10,25,40,.4);padding:6px;width:250px;display:none}
.spk-we-lhpop.show{display:block}
.spk-we-lhitem{display:flex;align-items:center;gap:10px;width:100%;text-align:left;background:none;border:none;border-radius:7px;padding:9px 12px;cursor:pointer;font:13px Arial;color:#25303a}
.spk-we-lhitem:hover{background:#f2f5f7}
.spk-we-lhitem .ck{width:16px;flex:0 0 auto;color:#1d9e75;font-weight:700;visibility:hidden}
.spk-we-lhitem.on .ck{visibility:visible}
.spk-we-lhitem svg{width:16px;height:16px;flex:0 0 auto;color:#5a6773}
.spk-we-lhdiv{height:1px;background:#e8ebee;margin:5px 4px}
/* Dialog Paragraf */
.spk-we-pgprev .rw{height:6px;background:#c9ced3;border-radius:2px;margin:3px 0}
.spk-we-pgprev .rc{height:6px;background:#111;border-radius:2px;margin:3px auto}
.spk-we-nfbody .row2{display:flex;gap:12px}
.spk-we-nfbody .row2>div{flex:1}
.spk-we-nfcard.wide{width:min(560px,96vw)}
/* Dropdown pustaka poin (gaya Word) */
.spk-we-bulwrap{position:relative;display:inline-flex}
.spk-we-bulpop{position:absolute;top:calc(100% + 4px);left:0;z-index:60;background:#fff;border:1px solid #d5dbe0;border-radius:10px;box-shadow:0 18px 44px -12px rgba(10,25,40,.4);padding:12px;width:300px;max-height:420px;overflow:auto;display:none}
.spk-we-bulpop.show{display:block}
.spk-we-bulgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.spk-we-bulcell{border:1px solid #e2e7eb;border-radius:8px;background:#fff;cursor:pointer;min-height:56px;display:flex;align-items:center;justify-content:center;font:18px/1 Arial,Helvetica,sans-serif;color:#12303f;transition:border-color .12s,background .12s}
.spk-we-bulcell:hover{border-color:#1d9e75;background:#f2fbf7}
.spk-we-bulcell.none{font:600 11px Arial;color:#3d4a55;text-align:center;padding:4px}
.spk-we-bulcell.sel{border-color:#1d9e75;border-width:2px;background:#eafaf3}
/* Pratinjau klausul (mode Lihat) di halaman utama — samakan dengan dokumen */
/* 22 Jul 2026 — padding 0,75cm DIBUANG supaya Lihat Pustaka Klausul mulai di
   batas margin persis seperti dokumen cetak (.spk-clause .spk-cl{padding-left:0}).
   Inden tiap tingkat sepenuhnya diatur inline oleh spkPkIndentStd. */
/* CATATAN (tata ulang konsistensi): sejak "Lihat Klausul" dirender via IFRAME
   memakai spkClauseDocHtml() — CSS dokumen yang sama dengan Pratinjau SPK —
   aturan ".spk-we-page .spk-cl ..." di bawah TIDAK LAGI dipakai untuk Lihat
   Klausul dan menjadi inert (tak ada elemen .spk-we-page > .spk-cl di DOM utama).
   Dibiarkan agar tidak berisiko mengganggu selector gabungan; boleh dibersihkan
   di kemudian hari bila dipastikan tak ada modul lain yang memakainya. Kanvas
   EDITOR memakai ".spk-we-doc" (bukan ".spk-cl") dan tetap berlaku. */
.spk-we-page .spk-cl{font-family:"Inter Local","Inter","Segoe UI",Arial,sans-serif;font-size:11pt;color:#000;line-height:var(--spk-lh,1.3915);padding-left:0}
/* DIBATALKAN 23 Jul 2026 - isi klausul dari Word kini ikut dirapikan
   spkPkIndentStd (indennya dihitung dari MARGIN, bukan relatif BASE 0,90 cm),
   sama seperti pratinjau dokumen SPK. Dasar 0,90 cm di sini akan menggeser
   isinya dua kali sehingga Lihat Klausul tak lagi sama dengan pratinjau SPK. */
.spk-we-page .spk-cl:has(.spk-wx){padding-left:0}
.spk-we-page .spk-cl p{margin:0 0 6pt;text-align:justify;line-height:var(--spk-lh,1.32)}
/* Judul klausul di awal lembar: tanpa spasi sebelum/sesudah yang mendorongnya turun */
.spk-we-page .spk-cl-h:first-child,.spk-we-page .spk-clause:first-child > .spk-cl-h{margin-top:0;padding-top:0}
.spk-we-page .spk-cl p.kl0{margin-left:0;text-indent:0}
.spk-we-page .spk-cl p.klp{margin-left:0;text-indent:.75cm}
.spk-we-page .spk-cl p.klp1{margin-left:.75cm;text-indent:.75cm}
.spk-we-page .spk-cl p.klp2{margin-left:1.5cm;text-indent:.75cm}
.spk-we-page .spk-cl p.kl1{margin-left:.75cm;text-indent:-.75cm}
.spk-we-page .spk-cl p.kl2{margin-left:1.5cm;text-indent:-.5cm}
.spk-we-page .spk-cl p.kl1.spk-sl{margin-left:.75cm;text-indent:-.75cm;padding-left:0}
.spk-we-page .spk-cl p.kl2.spk-sl{margin-left:1.5cm;text-indent:-.5cm;padding-left:0}
.spk-we-page .spk-cl p.spk-sl .n{display:inline-block;box-sizing:border-box;text-indent:0;text-align:left;white-space:nowrap}
.spk-we-page .spk-cl p.spk-sl .n:not([style]){min-width:.75cm}
.spk-we-page .spk-cl p.kl2.spk-sl .n:not([style]){min-width:.5cm}
/* Label majemuk (5.1. / 3.1.1.) memakai kolom yang SAMA dengan butir
   tingkat-1 pada template .docx; kotak nomor hanya melebar bila perlu. */
.spk-we-page .spk-cl p.kl1.spk-ml{margin-left:.75cm;text-indent:-.75cm}
.spk-we-page .spk-cl p.kl2.spk-ml{margin-left:.75cm;text-indent:-.75cm}
.spk-we-page .spk-cl p.spk-ml .n.m{display:inline-block;box-sizing:border-box;text-indent:0;text-align:left;white-space:nowrap}
.spk-we-page .spk-cl p.spk-ml .n.m:not([style]){min-width:.75cm}
.spk-we-page .spk-cl p.kldesc{margin-left:.75cm;text-indent:0}
.spk-we-page .spk-cl p .n{display:inline-block;box-sizing:border-box;text-indent:0;text-align:left;white-space:nowrap}
.spk-we-page .spk-cl p .n:not([style]){min-width:.75cm}
/* Kop klausul SPK: gantungan 0,65 cm mengikuti gaya "Klausul Judul" template. */
.spk-we-page .spk-cl p.spk-cl-h{padding-left:.75cm;text-indent:-.75cm}
.spk-we-page .spk-cl p.spk-cl-h .n{min-width:.75cm;text-align:right;padding-right:.18cm}
.spk-we-page .spk-cl i{font-style:italic}
.spk-we-page .spk-cl b{font-weight:700}

/* ==========================================================================
   PRATINJAU HALAMAN A4 — BENTUK PERJANJIAN/KONTRAK SAJA (.spk-pk)
   Menyalin kisi tata letak "Lihat klausul — Perjanjian/Kontrak":
     isi klausul  : mulai TEPAT di batas margin kiri (bukan menjorok 0,75 cm)
     tingkat-1    : kotak nomor 0,46 cm, kolom teks 0,66 cm
     tingkat-2    : kotak huruf 0,40 cm, kolom teks 1,41 cm
     judul        : "PASAL n" rata tengah di baris pertama, nama pasal di bawah
   Tanpa kelas .spk-pk, seluruh aturan lama (bentuk Surat Perintah Kerja)
   tetap berlaku apa adanya.
   ========================================================================== */
.spk-we-page.spk-pk .spk-cl{padding-left:0}
.spk-we-page.spk-pk .spk-cl p.kl0{margin-left:0;text-indent:0}
.spk-we-page.spk-pk .spk-cl p.klp{margin-left:0;text-indent:.75cm}
.spk-we-page.spk-pk .spk-cl p.klp1{margin-left:.66cm;text-indent:.75cm}
.spk-we-page.spk-pk .spk-cl p.klp2{margin-left:1.41cm;text-indent:.75cm}
.spk-we-page.spk-pk .spk-cl p.kl1{margin-left:.66cm;text-indent:-.46cm}
.spk-we-page.spk-pk .spk-cl p.kl2{margin-left:1.41cm;text-indent:-.40cm}
.spk-we-page.spk-pk .spk-cl p.kl1.spk-sl{margin-left:.66cm;text-indent:-.46cm;padding-left:0}
.spk-we-page.spk-pk .spk-cl p.kl2.spk-sl{margin-left:1.41cm;text-indent:-.40cm;padding-left:0}
/* Template Perjanjian/Kontrak memakai DUA tab stop: tab KANAN di (kolom teks -
   jeda) lalu tab KIRI di kolom teks, sehingga titik penutup nomor lurus untuk
   1 maupun 2 digit. Di layar disamakan: kotak nomor rata KANAN + jeda 0,18 cm. */
.spk-we-page.spk-pk .spk-cl p.kl1.spk-sl .n{min-width:.46cm;width:auto;text-align:right;padding-right:.18cm;box-sizing:border-box}
.spk-we-page.spk-pk .spk-cl p.kl2.spk-sl .n{min-width:.40cm;width:auto;text-align:left;padding-right:.10cm;box-sizing:border-box}
.spk-we-page.spk-pk .spk-cl p.kldesc{margin-left:.66cm;text-indent:0}
.spk-we-page.spk-pk .spk-cl p .n{min-width:.46cm;width:auto;box-sizing:border-box}
/* KOP PASAL bukan kotak nomor butir.
   Kop klausul ditulis sebagai <p class="spk-cl-h">, sehingga ikut tersapu
   aturan ".spk-we-page .spk-cl p .n{width:.75cm}" di atas (dan .46cm pada PK).
   Akibatnya tulisan "PASAL 1" terjepit selebar kotak nomor lalu patah menjadi
   dua baris di tepi kiri. Di sini kop dikembalikan ke lebar alami dan rata
   tengah, sesuai tampilan dokumen Perjanjian/Kontrak. */
.spk-we-page.spk-pk .spk-cl p.spk-cl-h{text-align:center;padding-left:0;text-indent:0;margin-bottom:6pt}
.spk-we-page.spk-pk .spk-cl p.spk-cl-h .n{display:block;width:auto;min-width:0;
  text-align:center;padding-right:0;text-indent:0;margin:0;white-space:nowrap}
/* Kanvas edit ikut kisi yang sama supaya ketikan langsung tampak seperti hasilnya */
.spk-we-doc.spk-pk{padding-left:0}
.spk-we-doc.spk-pk p.kl0{margin-left:0;text-indent:0}
.spk-we-doc.spk-pk p.klp{margin-left:0;text-indent:.75cm}
.spk-we-doc.spk-pk p.klp1{margin-left:.66cm;text-indent:.75cm}
.spk-we-doc.spk-pk p.klp2{margin-left:1.41cm;text-indent:.75cm}
.spk-we-doc.spk-pk p.kl1{margin-left:.66cm;text-indent:-.46cm}
.spk-we-doc.spk-pk p.kl2{margin-left:1.41cm;text-indent:-.40cm}
.spk-we-doc.spk-pk p.kldesc{margin-left:.66cm;text-indent:0}
.spk-we-doc.spk-pk .n{min-width:.46cm;width:auto;text-align:right;padding-right:.18cm;box-sizing:border-box}
.spk-we-doc.spk-pk p.kl2 .n{min-width:.40cm;text-align:left;padding-right:.10cm}
/* Kop klausul: PASAL n rata tengah dua baris */
.spk-we-clhead.spk-pk{padding-left:0;text-indent:0;text-align:center}
.spk-we-clhead.spk-pk{margin-bottom:6pt}
.spk-we-clhead.spk-pk .n{display:block;width:auto;min-width:0;text-align:center;white-space:nowrap;margin:0;padding-right:0}
.spk-we-clhead.spk-pk .spk-we-clhead-tag{display:block;margin-left:0;text-align:center}
/* Pastikan SELURUH isi klausul (paragraf, blok pihak, baris label:nilai, daftar,
   dsb.) memakai jarak baris 1,15 di layar — sama seperti pengaturan di Word.
   Catch-all agar tidak ada elemen yang jatuh ke line-height default (~1). */
.spk-we-page .spk-cl,.spk-we-page .spk-cl *,
.spk-we-doc,.spk-we-doc *,
.spk-narasi-prev,.spk-narasi-prev *{line-height:var(--spk-lh,1.32)}
/* Contoh pengisian klausul (placeholder) di Pustaka Klausul: titik-titik sampai
   batas margin kanan, HURUF HITAM (bukan samar/transparan) agar keterangan
   "Isi Klausul ......" terbaca jelas. Blok bertanda .spk-ph tetap TIDAK PERNAH
   ikut tercetak — warnanya hanya soal keterbacaan di layar. */
.spk-cl p.spk-ph,.spk-we-page .spk-cl p.spk-ph{color:#000;white-space:nowrap;overflow:hidden;text-align:left}
/* Contoh pengisian pada EDITOR & pratinjau narasi: ikut hitam, boleh membungkus baris. */
.spk-we-doc p.spk-ph,.spk-narasi-prev p.spk-ph{color:#000}
.spk-we-toolbar button#spk-we-ph.active{background:#eef2f4;border-color:#b6c2cb;color:#5b6b78}
/* Kolom Judul Klausul yang dapat dimiringkan (contenteditable + tombol I) */
.spk-kldoc-jwrap{display:flex;align-items:stretch;gap:6px}
.spk-kldoc-jinput{flex:1 1 auto;min-height:42px;border:1px solid #cdd9de;border-radius:10px;padding:10px 13px;
  font-size:13px;font-family:inherit;color:var(--ink);background:#fff;outline:none;line-height:1.35;overflow-wrap:anywhere}
.spk-kldoc-jinput:focus{border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,124,134,.15)}
.spk-kldoc-jinput:empty:before{content:attr(data-ph);color:#9AA7B2}
.spk-kldoc-jinput i,.spk-kldoc-jinput em{font-style:italic}
/* Judul boleh diketik DI SINI maupun langsung di Word (sejak 8 Agu 2026 baris
   judul memakai content control berjenis teks biasa — lihat spkDocxTemplateBlob).
   Tata letak barisnya diatur ulang di bagian 39 pada akhir berkas ini. */
.spk-kldoc-jwrap{flex:1 1 240px;min-width:200px}
.spk-kldoc-tools .spk-kldoc-dl{flex:0 0 auto;margin-left:auto}
.spk-kldoc-jbtn i{font-style:italic;font-family:Georgia,"Times New Roman",serif}
.spk-kldoc-jbtn:hover{border-color:var(--teal);color:var(--teal)}
.spk-kldoc-jbtn{flex:0 0 auto;width:42px;border:1px solid #cdd9de;border-radius:10px;background:#fff;cursor:pointer;
  font-size:15px;color:#33454b}
.spk-kldoc-jbtn:hover{background:#f4f6f8;border-color:#0e7c86;color:#0e7c86}
/* Tombol Naik/Turun pada aksi klausul */
.spk-klx-act .act.act-mv{color:#0e7c86}
.spk-klx-act .act:disabled{opacity:.35;cursor:not-allowed;transform:none}
/* Bar tombol pada judul kartu Pustaka Klausul (Simpan/Muat/Batalkan Profil + Tambah) */
.spk-klbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.spk-klprof-tag{display:inline-flex;align-items:center;gap:6px;background:#e8f6f7;border:1px solid #bfe3e6;color:#0b5f66;border-radius:999px;padding:5px 10px;font-size:10.5px;font-weight:800}
/* Baris "Label : nilai" (spk-kv) — sejajar seperti Word. Aturan ini dulunya
   hanya ada di CSS dokumen (spkDocCss) sehingga di modal Lihat/pratinjau
   label:nilai tampak menyatu. Disamakan di sini agar tampilan konsisten. */
/* Angka tabular pada kotak nomor: digit '1' dan '2' sama lebar, sehingga '4.1.'
   dan '4.2.' berhenti di titik yang sama (seperti penomoran Word). */
.spk-cl .n,.spk-cl-h .n,.spk-clause .n,.spk-we-doc .n,.spk-we-page .n,.spk-narasi-prev .n{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1,"lnum" 1}
.spk-cl .spk-kv{display:flex;margin:0 0 var(--spk-kv-gap,4pt);line-height:var(--spk-lh,1.32)}
.spk-cl .spk-kv .k{flex:0 0 34%;max-width:34%}
.spk-cl .spk-kv .s{flex:0 0 auto;width:1.2em}
.spk-cl .spk-kv .v{flex:1;text-align:justify}
.spk-we-doc .spk-kv{display:flex;margin:0 0 var(--spk-kv-gap,4pt);line-height:var(--spk-lh,1.32)}
.spk-we-doc .spk-kv .k{flex:0 0 34%;max-width:34%}
.spk-we-doc .spk-kv .s{flex:0 0 auto;width:1.2em}
.spk-we-doc .spk-kv .v{flex:1;text-align:justify}
/* Grup baris "Label : nilai" (dibentuk spkKvGroup). Sebelumnya aturan ini HANYA
   ada di CSS dokumen, sehingga pratinjau memakai label lebar 34% tanpa indentasi
   sedangkan hasil cetak memakai grid ber-indentasi — dua tampilan yang berbeda
   untuk isi yang sama. Disamakan di sini.
   Tanpa indentasi tambahan: badan klausul sudah menjorok sendiri, sehingga
   label sejajar dengan teks judul butir di atasnya. */
.spk-cl .spk-kvgrp,.spk-we-doc .spk-kvgrp{display:grid;grid-template-columns:max-content max-content 1fr;row-gap:3pt;margin:0 0 6pt 0}
.spk-cl .spk-kvgrp .spk-kv,.spk-we-doc .spk-kvgrp .spk-kv{display:contents}
/* Jarak antar baris .spk-kv dipindah dari row-gap grid ke margin BUTIR GRID-nya
   (9 Agu 2026). Baris ber-display:contents tidak menghasilkan kotak, jadi
   margin-nya diabaikan - itu sebabnya w:spacing 6pt/12pt dari Word tampil sama
   saja. Peubah --kv-mt/--kv-mb tetap diwariskan melewati display:contents.
   Kembarannya ada di susun-kontrak.js (blok CSS pratinjau) - ubah berbarengan. */
.spk-cl .spk-kvgrp,.spk-we-doc .spk-kvgrp{row-gap:0}
.spk-cl .spk-kvgrp .spk-kv>*,
.spk-we-doc .spk-kvgrp .spk-kv>*{margin-top:var(--kv-mt,0);margin-bottom:var(--kv-mb,3pt)}
/* ---- Tabel data dari template Word (9 Agu 2026) ----
   Laporan "render klausul tidak membaca tabel": tabel 3 kolom di template
   dulu digabung kolomnya jadi satu paragraf. Kini dirender <table> sungguhan
   oleh spkWTblAsliHtml(); ini gaya tampilnya di dalam aplikasi. Blok kembaran
   untuk pratinjau & cetak ada di susun-kontrak.js (dekat .spk-cl .spk-kv) dan
   HARUS diubah berbarengan bila salah satunya disetel ulang.
   Garis tepi hanya muncul bila berkas Word memang menyetelnya (.bergaris). */
.spk-cl .spk-tbl,.spk-we-doc .spk-tbl{border-collapse:collapse;
  max-width:100%;margin:0 0 var(--spk-kv-gap,4pt);line-height:var(--spk-lh,1.32)}
.spk-cl .spk-tbl td,.spk-cl .spk-tbl th,
.spk-we-doc .spk-tbl td,.spk-we-doc .spk-tbl th{vertical-align:top;
  text-align:left;overflow-wrap:break-word}
.spk-cl .spk-tbl th,.spk-we-doc .spk-tbl th{font-weight:700}
.spk-cl .spk-tbl p,.spk-we-doc .spk-tbl p{margin:0}
.spk-cl .spk-kvgrp .spk-kv .k,.spk-we-doc .spk-kvgrp .spk-kv .k{flex:none;max-width:none;padding-right:.5cm}
.spk-cl .spk-kvgrp .spk-kv .s,.spk-we-doc .spk-kvgrp .spk-kv .s{flex:none;width:auto;padding-right:.3cm}
.spk-cl .spk-kvgrp .spk-kv .v,.spk-we-doc .spk-kvgrp .spk-kv .v{flex:none;text-align:justify}
/* ---- Pustaka Klausul: template Word (.docx) — pengganti editor teks ---- */
.spk-kldoc-top{padding:13px 16px 14px;background:#fff;border-bottom:1px solid #e5eaee}
.spk-kldoc-tools{display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin-top:11px}
.spk-kldoc-tools .btn svg{width:14px;height:14px}
.spk-kldoc-meta{font-size:12px;color:#6B7885}
.spk-kldoc-meta b{color:#12805c}
.spk-kldoc-note{margin-top:11px;background:#f2f7fa;border:1px solid #dbe6ee;border-radius:8px;padding:9px 11px;font-size:12px;color:#4a5a67;line-height:1.6}
.spk-kldoc-note b{color:#12303f}
.spk-kldoc-note code{background:#eef3f7;color:#0E7C86;padding:1px 5px;border-radius:5px;font-size:11.5px}
.spk-kldoc-hover{outline:3px dashed #1d9e75;outline-offset:-10px;background:#dff2ea}
.spk-we-page .spk-cl p.spk-kldoc-empty{color:#9AA7B2;font-style:italic;text-align:left}
/* Kotak unggah (Drag & Drop) — muncul saat tombol Upload Template ditekan */
/* Kotak drag & drop template klausul — tampilan seperti popup Unggah File + efek 3D */
.spk-kldoc-dz{display:none;position:relative;margin-top:12px;padding:30px 18px 26px;text-align:center;cursor:pointer;
  border:2px dashed #bcd8cd;border-radius:13px;
  background:linear-gradient(180deg,#f6fbf9,#e8f4ee);
  box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 -5px 12px rgba(29,158,117,.05) inset,
             0 12px 22px -10px rgba(20,90,70,.34),0 5px 9px -6px rgba(20,90,70,.22);
  transition:transform .22s cubic-bezier(.16,1,.3,1),border-color .16s,background .16s,box-shadow .22s ease}
.spk-kldoc-dz.show{display:block;animation:spkKlDzIn .16s ease-out}
@keyframes spkKlDzIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.spk-kldoc-dz:hover{border-color:#1d9e75;background:linear-gradient(180deg,#f4fcf8,#dff2ea);
  transform:perspective(760px) translateY(-4px) rotateX(6deg) scale(1.008);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset,0 -5px 12px rgba(29,158,117,.05) inset,
             0 24px 40px -14px rgba(20,90,70,.44),0 9px 15px -8px rgba(20,90,70,.26)}
.spk-kldoc-dz.drag{border-color:#1d9e75;background:linear-gradient(180deg,#d7efe5,#c7e8da);
  transform:perspective(760px) translateY(2px) scale(.995);
  box-shadow:0 2px 0 rgba(255,255,255,.6) inset,0 10px 22px -12px rgba(20,90,70,.45) inset,
             0 4px 9px -7px rgba(20,90,70,.28)}
.spk-kldoc-dzic{width:42px;height:42px;color:#6f9d8b;filter:drop-shadow(0 7px 9px rgba(20,90,70,.26));transition:color .14s,transform .22s cubic-bezier(.16,1,.3,1)}
.spk-kldoc-dz:hover .spk-kldoc-dzic,.spk-kldoc-dz.drag .spk-kldoc-dzic{color:#1d9e75}
.spk-kldoc-dz:hover .spk-kldoc-dzic{transform:translateY(-3px)}
.spk-kldoc-dz.drag .spk-kldoc-dzic{transform:translateY(-6px) scale(1.07)}
.spk-kldoc-dz .t{margin-top:10px;font-size:15px;font-weight:800;color:#16242c;text-shadow:0 1px 0 rgba(255,255,255,.7)}
.spk-kldoc-dz .s{margin-top:4px;font-size:13px;color:#3d5560}
.spk-kldoc-dz .s b{color:#12805c}
.spk-kldoc-dz .s2{margin-top:12px;font-size:12px;color:#7d929b}
.spk-kldoc-dzx{position:absolute;top:7px;right:7px;width:26px;height:26px;border:0;border-radius:7px;background:transparent;
  color:#8fa0ad;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}
.spk-kldoc-dzx svg{width:13px;height:13px}
.spk-kldoc-dzx:hover{background:#e8edf1;color:#3d4a55}


/* =========================================================================
   PENYERAGAMAN TOMBOL — Profil / Batalkan Pilihan / Pilih Pekerjaan
   Ukuran & gaya disamakan dengan tombol utama (.btn) seperti "Reset" &
   "Input Data": radius 12px, padding 10px 17px, font 11.5px, ikon 16px,
   gradien + bayangan, serta animasi angkat saat disorot.
   Blok ini sengaja diletakkan PALING BAWAH agar menimpa gaya lama.
   ========================================================================= */
.jp-profil-btn,
.dp-pick-btn,
.dp-unpick-btn{
  border:none;
  border-radius:12px;
  padding:10px 17px;
  font-family:'Plus Jakarta Sans',sans-serif;
  font-weight:700;
  font-size:11.5px;
  letter-spacing:.2px;
  text-transform:none;
  line-height:1.2;
  display:inline-flex;
  align-items:center;
  gap:8px;
  cursor:pointer;
  white-space:nowrap;
  position:relative;
  isolation:isolate;
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .22s ease,filter .2s ease;
}
.jp-profil-btn svg,
.dp-pick-btn svg,
.dp-unpick-btn svg{width:16px;height:16px;flex:0 0 auto}
.jp-profil-btn:hover,
.dp-pick-btn:hover,
.dp-unpick-btn:hover{transform:translateY(-2px)}
.jp-profil-btn:active,
.dp-pick-btn:active,
.dp-unpick-btn:active{transform:translateY(0) scale(.98)}

/* Simpan Profil -> kuning (setara .btn-amber) */
.jp-profil-btn.is-save{
  background:linear-gradient(135deg,var(--yellow),#ffca3a);
  color:#5a3d00;
  box-shadow:0 4px 14px rgba(246,180,14,.32),inset 0 1px 0 rgba(255,255,255,.4);
}
.jp-profil-btn.is-save:hover{box-shadow:0 8px 22px rgba(246,180,14,.48),inset 0 1px 0 rgba(255,255,255,.5);filter:brightness(1.04)}

/* Muat Profil & Pilih Pekerjaan -> teal (setara .btn-teal) */
.jp-profil-btn.is-load,
.dp-pick-btn{
  background:linear-gradient(135deg,var(--teal),var(--cyan));
  color:#fff;
  box-shadow:0 4px 14px rgba(14,124,134,.32),inset 0 1px 0 rgba(255,255,255,.25);
}
.jp-profil-btn.is-load:hover,
.dp-pick-btn:hover{box-shadow:0 8px 22px rgba(14,124,134,.44),inset 0 1px 0 rgba(255,255,255,.3);filter:brightness(1.04)}

/* Batalkan Profil / Batalkan Pilihan -> merah (setara .btn-red) */
.jp-profil-btn.is-cancel,
.dp-unpick-btn{
  background:linear-gradient(135deg,var(--red),#e25151);
  color:#fff;
  border:none;
  box-shadow:0 4px 14px rgba(211,58,58,.28),inset 0 1px 0 rgba(255,255,255,.22);
}
.jp-profil-btn.is-cancel:hover,
.dp-unpick-btn:hover{background:linear-gradient(135deg,var(--red),#e25151);box-shadow:0 8px 22px rgba(211,58,58,.42),inset 0 1px 0 rgba(255,255,255,.28);filter:brightness(1.04)}

/* Tombol profil pada menu Persyaratan (Pembukaan Penawaran) — sudah memakai
   kelas .btn, cukup dikembalikan ke ukuran tombol utama. */
.pnw-profil-btn{padding:10px 17px;font-size:11.5px;gap:8px}
.pnw-profil-btn svg{width:16px;height:16px}

/* Ikon di dalam judul kartu tidak ikut diwarnai teal oleh .form-section-title svg */
.form-section-title .jp-profil-btn svg,
.form-section-title .dp-pick-btn svg,
.form-section-title .dp-unpick-btn svg{color:inherit;stroke:currentColor;opacity:1}

/* Bar tombol pustaka klausul & tombol pilih pekerjaan: beri jarak seragam */
.spk-klbar{gap:10px}
.dp-pick-wrap{display:inline-flex;align-items:center;gap:10px}

/* Layar sempit: teks tombol tetap tampil, padding sedikit dirapatkan */
@media(max-width:1180px){
  .jp-profil-btn span{display:inline}
  .jp-profil-btn,.dp-pick-btn,.dp-unpick-btn{padding:9px 13px;font-size:11px}
}

/* Data Pekerjaan yang SUDAH DIGUNAKAN dokumen lain pada modul yang sama */
.hps-ana-item.is-used{opacity:.62;background:#faf7f7;border-color:#eccfcf}
.hps-ana-item.is-used:hover{border-color:#e0a8a8}
.hps-ana-item.is-used .ic{background:#c9cfd2;color:#fff}
.dp-used-tag{display:inline-flex;align-items:center;margin-left:8px;padding:2px 8px;border-radius:999px;background:#fbe6e6;color:#b02626;border:1px solid #eec5c5;font-family:'Plus Jakarta Sans',sans-serif;font-size:9.5px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;vertical-align:middle}

/* Ikon pada tombol di dalam judul kartu (mis. "+" Tambah Klausul) mengikuti warna
   teks tombol — jangan diwarnai teal oleh aturan .form-section-title svg */
.form-section-title .btn svg{color:inherit;stroke:currentColor;opacity:1}

/* Penanda "Sampul Dua belum diisi" pada tabel Lihat Hasil Pemeriksaan */
.pnw-s2-tag{display:inline-flex;align-items:center;margin-left:8px;padding:2px 8px;border-radius:999px;background:#fdf1dc;color:#8a5a06;border:1px solid #f0d59a;font-family:'Plus Jakarta Sans',sans-serif;font-size:9.5px;font-weight:800;letter-spacing:.3px;white-space:nowrap}

/* =========================================================================
   PENYERAGAMAN TABEL MENU — garis pemisah antar data yang halus namun tegas.
   Berlaku HANYA untuk tabel data di dalam menu (.table-wrap). Tidak menyentuh
   dokumen Susun Kontrak (SPK) maupun tampilan pratinjau/cetak.
   Hairline: #d5e1e4 (1px, lembut tetapi cukup memisahkan antar data).
   ========================================================================= */
.table-wrap tbody td{border:1px solid #d5e1e4}
.table-wrap thead th{border-color:#0b6b74}
.table-wrap tbody td:first-child{border-left:none}
.table-wrap tbody td:last-child{border-right:none}

/* Monitoring — kolom beku (No./Nama Pekerjaan): samakan garis "palsu"
   (inset box-shadow) dengan hairline di atas agar konsisten dgn kolom lain. */
#view-list .table-wrap tbody td.col-no,#view-list .table-wrap tbody td.col-nama-freeze,
#view-list-pl .table-wrap tbody td.col-no,#view-list-pl .table-wrap tbody td.col-nama-freeze,
#view-list-tender .table-wrap tbody td.col-no,#view-list-tender .table-wrap tbody td.col-nama-freeze{
  box-shadow:inset 1px 0 0 #d5e1e4, inset -1px 0 0 #d5e1e4, inset 0 -1px 0 #d5e1e4, inset 0 1px 0 #d5e1e4}
#view-list .table-wrap thead th.col-no,#view-list .table-wrap thead th.col-nama-freeze,
#view-list-pl .table-wrap thead th.col-no,#view-list-pl .table-wrap thead th.col-nama-freeze,
#view-list-tender .table-wrap thead th.col-no,#view-list-tender .table-wrap thead th.col-nama-freeze{
  box-shadow:inset 1px 0 0 #0b6b74, inset -1px 0 0 #0b6b74, inset 0 -1px 0 #0b6b74}

/* Sub-tabel lain di menu diselaraskan ke hairline yang sama */
.pnw-periksa-table td{border-bottom-color:#d5e1e4}
table.hps-sum td{border-bottom-color:#d5e1e4}

/* ===== Tabel pengisian Lampiran SPK =====
   Selaras dengan tabel Uraian HPS, dengan perapian khusus:
   - SEMUA judul kolom rata tengah & sewarna (thead HPS memberi text-align:left
     pada th.c-ur, sehingga "Uraian Pekerjaan" tadinya tidak sejajar);
   - "NO" tidak lagi tampak pudar (kolom c-no mewarisi warna teal, bukan putih);
   - lebar kolom stabil supaya field tidak melar/menyempit antar baris. */
table.hps-uraian.spk-lamp-tbl thead th{
  text-align:center;
  color:#fff;                     /* satu warna untuk semua judul kolom */
  vertical-align:middle;
  line-height:1.35;
  white-space:nowrap;
}
/* Menang atas `th.c-no{color:#0b6a73}` (baris 2578) yang membuat "NO" nyaris tak
   terbaca di atas latar teal, dan atas `thead th.c-ur{text-align:left}` (2573). */
table.hps-uraian.spk-lamp-tbl thead th.c-no,
table.hps-uraian.spk-lamp-tbl thead th.c-ur{
  color:#fff;
  text-align:center;
}
table.hps-uraian.spk-lamp-tbl thead th.c-ur{ min-width:260px }

/* Lebar kolom konsisten. Judul/Sub-Judul dilebarkan: pada 150px placeholder
   terpotong jadi "mis. JASA EDI1" dan isi asli sulit dibaca. */
table.hps-uraian.spk-lamp-tbl th.c-kel,
table.hps-uraian.spk-lamp-tbl td.c-kel{ width:172px;min-width:172px }
table.hps-uraian.spk-lamp-tbl td.c-kel input{ min-width:0 }
table.hps-uraian.spk-lamp-tbl th.c-sat,
table.hps-uraian.spk-lamp-tbl td.c-sat{ width:82px;min-width:82px }
table.hps-uraian.spk-lamp-tbl th.c-vol,
table.hps-uraian.spk-lamp-tbl td.c-vol{ width:88px;min-width:88px }
table.hps-uraian.spk-lamp-tbl th.c-money,
table.hps-uraian.spk-lamp-tbl td.c-money{ width:132px;min-width:132px }

/* Baris lebih lega + garis pemisah antar kolom yang halus */
table.hps-uraian.spk-lamp-tbl tbody td{ padding:8px 9px }
table.hps-uraian.spk-lamp-tbl tbody td + td{ border-left:1px solid #eef4f5 }
table.hps-uraian.spk-lamp-tbl tbody tr:hover td{ background:#f2fafb }

/* Sel Uraian: textarea tumbuh rapi tanpa scrollbar kembar */
table.hps-uraian.spk-lamp-tbl textarea{ min-height:38px }

/* Lebar kolom NO pada tabel Lampiran dihitung di JS (jsKolPx) mengikuti yang
   terpanjang antara judul "No" dan nomor baris terbesar, lalu dipasang sebagai
   inline style. Aturan lebar tetap 62px dari `table.hps-uraian th.c-no` (baris
   2578) dinetralkan di sini agar nilai hitungan itu tidak dilawan. */
table.hps-uraian.spk-lamp-tbl th.c-no,
table.hps-uraian.spk-lamp-tbl td.c-no{
  width:auto;min-width:0;max-width:none;
}

/* ============================================================
   EFEK 3D — TABEL DAFTAR DATA (.table-wrap)
   Hanya untuk tabel daftar/monitoring. Tabel pengisian (.hps-uraian,
   .ana-uraian) dan dokumen cetak (.fkl-doc) sengaja TIDAK disentuh.

   Kedalaman dibangun dari bayangan berlapis + gradien, BUKAN dari transform:
   `transform` pada elemen leluhur membuat position:sticky di dalamnya patah,
   sedangkan tabel ini mengandalkan sticky untuk header dan kolom beku
   (No. / Nama Pekerjaan). Perspektif/rotate juga akan mengaburkan teks 11px.
   ============================================================ */

/* Panel terangkat: bayangan berlapis (dekat = tajam, jauh = lembut) meniru
   cara benda nyata menjatuhkan bayangan, ditambah highlight tipis di tepi atas. */
.table-wrap{
  box-shadow:
    0 1px 1px rgba(16,40,50,.05),
    0 2px 4px rgba(16,40,50,.06),
    0 8px 16px rgba(16,40,50,.08),
    0 16px 32px rgba(16,40,50,.09),
    inset 0 1px 0 rgba(255,255,255,.9);
  transition:box-shadow .28s ease;
}
.table-wrap:hover{
  box-shadow:
    0 1px 1px rgba(16,40,50,.06),
    0 3px 6px rgba(16,40,50,.07),
    0 12px 24px rgba(16,40,50,.10),
    0 24px 48px rgba(16,40,50,.12),
    inset 0 1px 0 rgba(255,255,255,.9);
}

/* Header timbul: gradien terang→gelap memberi arah cahaya dari atas,
   bayangan bawah membuatnya seolah melayang di atas baris data. */
.table-wrap thead th{
  background-image:linear-gradient(180deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,0) 55%, rgba(0,0,0,.10) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    0 3px 6px rgba(16,40,50,.16);
  text-shadow:0 1px 1px rgba(0,0,0,.18);
}
/* Sel sticky (kolom beku) memakai latar via pseudo-element ::after — gradien
   header perlu ikut dipasang di situ, kalau tidak sel beku akan tampil rata
   sementara sel lain bergradien. */
.table-wrap thead th:first-child::after,
.table-wrap thead th.col-nama-freeze::after{
  background-image:linear-gradient(180deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,0) 55%, rgba(0,0,0,.10) 100%);
}

/* Baris: garis terang di atas + garis gelap tipis di bawah = kesan tebal/relief */
.table-wrap tbody tr{
  transition:background .15s, box-shadow .18s;
}
.table-wrap tbody tr:not(:last-child){
  box-shadow:inset 0 -1px 0 rgba(16,40,50,.07);
}
/* Baris disentuh: terangkat — bayangan di bawah + sedikit lebih terang di atas */
.table-wrap tbody tr:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.85),
    0 2px 6px rgba(16,40,50,.13);
  position:relative;
  z-index:2;
}

/* Tombol aksi: sudah punya angkat saat hover — dilengkapi relief agar
   terlihat sebagai tombol fisik, dan efek "tertekan" saat diklik. */
.table-wrap .act{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -1px 0 rgba(0,0,0,.14),
    0 1px 2px rgba(16,40,50,.20);
}
.table-wrap .act:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    0 4px 10px rgba(16,40,50,.26);
}
.table-wrap .act:active{
  transform:translateY(0);
  box-shadow:
    inset 0 2px 4px rgba(0,0,0,.24),
    0 1px 1px rgba(16,40,50,.14);
}

/* Pil status: sedikit timbul. Garis tepi tiap pil (.pill-prog/-kontrak/-batal)
   dibuat dengan `inset 0 0 0 1px` — sengaja TIDAK ditimpa: cukup tambahkan
   bayangan luar via drop-shadow agar warna tepi tiap status tetap utuh. */
.table-wrap .pill{
  filter:drop-shadow(0 1px 1.5px rgba(16,40,50,.18));
}

/* Aksesibilitas: hormati "kurangi animasi" pada sistem pengguna */
@media (prefers-reduced-motion:reduce){
  .table-wrap, .table-wrap tbody tr{ transition:none }
}

/* ============================================================
   EFEK 3D — DASHBOARD
   Berbeda dari tabel daftar: di sini `transform` AMAN dipakai karena tidak ada
   position:sticky di dalam kartu/panel (kartu bahkan sudah memakai translateY
   saat hover). Jadi kedalamannya nyata: kartu dimiringkan mengikuti kursor
   dengan rotateX/rotateY, bukan sekadar bayangan.
   ============================================================ */

/* Ruang 3D untuk tiap kartu. perspective di elemen induk (.cards) akan membuat
   semua kartu berbagi SATU titik hilang, sehingga kartu di tepi tampak miring
   walau tidak disentuh. Karena itu perspective dipasang per-kartu lewat
   transform sendiri (lihat .card.tilt-on). */
.cards{ perspective:none }

/* Bidang kartu & isinya berada di ruang 3D yang sama, supaya ikon/angka ikut
   terangkat saat kartu dimiringkan (parallax). */
#view-dashboard .card{
  transform-style:preserve-3d;
  will-change:transform;
}

/* Nilai default variabel tilt: 0 = datar. JS hanya mengubah angkanya. */
#view-dashboard .card{
  --rx:0deg;    /* rotateX — dari posisi kursor vertikal   */
  --ry:0deg;    /* rotateY — dari posisi kursor horizontal */
  --lift:0px;   /* angkat  */
  --gx:50%;     /* titik kilau  */
  --gy:50%;
}

/* Saat kursor di atas kartu: miring + terangkat.
   translateZ pada anak-anaknya memberi parallax berlapis. */
/* .card.card.tilt-on = spesifisitas dinaikkan (0,3,1) agar menang atas
   `#view-dashboard .card:hover{transform:translateY(-4px)}` (baris ~1515) yang
   spesifisitasnya sama (0,2,1) tetapi tertulis lebih belakang — tanpa ini
   transform tilt tidak pernah berlaku dan kartu hanya bergeser naik. */
#view-dashboard .card.card.tilt-on{
  /* !important wajib: `#view-dashboard .card:hover` (baris ~2414) memakai
     `transform:translateY(-2px) !important` yang akan mengalahkan aturan ini
     berapa pun spesifisitasnya. Tanpa !important, kartu hanya bergeser naik
     2px dan tilt tidak pernah terlihat. Hal yang sama berlaku untuk box-shadow
     & border-color di aturan itu. */
  transform:perspective(760px) rotateX(var(--rx)) rotateY(var(--ry)) translateY(var(--lift)) scale(1.018) !important;
  box-shadow:
    0 2px 4px rgba(16,40,50,.06),
    0 8px 16px rgba(16,40,50,.08),
    0 22px 44px rgba(16,40,50,.14),
    0 40px 80px rgba(9,94,102,.12) !important;
  border-color:#cfdde0 !important;
  z-index:3;
}
/* transition hanya saat kembali datar; ketika mengikuti kursor harus instan
   agar tidak terasa "molor" tertinggal dari gerakan mouse. */
#view-dashboard .card{ transition:transform .5s cubic-bezier(.2,.8,.2,1), box-shadow .3s ease, border-color .3s ease }
#view-dashboard .card.tilt-move{ transition:box-shadow .3s ease, border-color .3s ease }

/* Kilau (specular): titik terang lembut mengikuti kursor — inilah yang membuat
   permukaan terasa seperti kaca/logam, bukan kertas datar. */
/* `#view-dashboard .card::after{display:none !important}` (baris ~2410)
   mematikan pseudo ini, jadi display harus dinyalakan ulang dengan !important. */
#view-dashboard .card::after{
  content:"";
  display:block !important;
  position:absolute; inset:0;
  border-radius:inherit;
  background:radial-gradient(340px circle at var(--gx) var(--gy),
             rgba(255,255,255,.55), rgba(255,255,255,.12) 38%, transparent 62%);
  opacity:0;
  transition:opacity .3s ease;
  pointer-events:none;
}
#view-dashboard .card.tilt-on::after{ opacity:1 }

/* Parallax: makin "dekat" (translateZ besar), makin terasa melayang.
   Ikon sudah punya aturan hover `transform:translateY(-1px) scale(1.04)
   !important` (baris ~2442). transform tidak bertumpuk, jadi translateZ harus
   DIGABUNG dengan nilai itu — dan ikut memakai !important, kalau tidak aturan
   lama yang menang dan parallax ikon tidak muncul sama sekali. */
#view-dashboard .card .card-ic{ transition:transform .5s cubic-bezier(.2,.8,.2,1) }
#view-dashboard .card.tilt-on .card-ic{
  transform:translateY(-1px) scale(1.04) translateZ(38px) !important;
}
#view-dashboard .card .v{ transition:transform .5s cubic-bezier(.2,.8,.2,1) }
#view-dashboard .card.tilt-on .v{ transform:translateZ(26px) }
#view-dashboard .card.tilt-on .k,
#view-dashboard .card.tilt-on .sub{ transform:translateZ(14px) }
#view-dashboard .card .k,
#view-dashboard .card .sub{ transition:transform .5s cubic-bezier(.2,.8,.2,1) }
/* Garis aksen kiri ikut maju → terlihat setebal sisi kartu */
#view-dashboard .card .accent{ transition:transform .5s cubic-bezier(.2,.8,.2,1) }
#view-dashboard .card.tilt-on .accent{ transform:translateZ(20px) }

/* Panel grafik: kedalaman lebih kalem (isinya grafik, tidak boleh mengganggu
   keterbacaan) — hanya terangkat & bayangan berlapis, tanpa miring. */
#view-dashboard .split .panel{
  transition:transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s ease;
  box-shadow:
    0 1px 2px rgba(16,40,50,.05),
    0 4px 10px rgba(16,40,50,.05),
    0 12px 28px rgba(16,40,50,.07),
    inset 0 1px 0 rgba(255,255,255,.85);
}
#view-dashboard .split .panel:hover{
  transform:translateY(-4px);
  box-shadow:
    0 2px 4px rgba(16,40,50,.06),
    0 10px 22px rgba(16,40,50,.09),
    0 26px 56px rgba(16,40,50,.13),
    inset 0 1px 0 rgba(255,255,255,.85);
}
/* Judul panel timbul tipis */
#view-dashboard .panel-head{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9), 0 1px 0 rgba(16,40,50,.05);
}

/* Hormati "kurangi animasi": tilt & angkat dimatikan total. */
@media (prefers-reduced-motion:reduce){
  #view-dashboard .card.tilt-on{ transform:none; scale:1 }
  #view-dashboard .card.tilt-on .card-ic{ transform:scale(.9) }
  #view-dashboard .card.tilt-on .v,
  #view-dashboard .card.tilt-on .k,
  #view-dashboard .card.tilt-on .sub,
  #view-dashboard .card.tilt-on .accent{ transform:none }
  #view-dashboard .card::after{ display:none }
  #view-dashboard .split .panel:hover{ transform:none }
  #view-dashboard .card,#view-dashboard .split .panel{ transition:none }
}

/* ============================================================
   EFEK 3D — MENU INPUT & IKON
   Prinsip: makin sering dibaca, makin halus efeknya.
   - Field input  -> relief cekung tipis saja. Miring/melayang pada kotak isian
                     membuat teks yang sedang diketik ikut miring & melelahkan.
   - Kartu form   -> terangkat berlapis (kertas di atas meja).
   - Ikon & tombol-> boleh 3D nyata: kecil, tidak dibaca, jadi aman.
   Dokumen cetak (.fkl-doc) & tabel pengisian TIDAK disentuh.
   ============================================================ */

/* ---------- Kartu form: kertas terangkat ---------- */
.form-card{
  box-shadow:
    0 1px 2px rgba(16,40,50,.05),
    0 4px 10px rgba(16,40,50,.05),
    0 12px 28px rgba(16,40,50,.07),
    inset 0 1px 0 rgba(255,255,255,.9);
  transition:box-shadow .3s ease, transform .3s cubic-bezier(.2,.8,.2,1);
}
.form-card:hover{
  box-shadow:
    0 2px 4px rgba(16,40,50,.06),
    0 8px 18px rgba(16,40,50,.07),
    0 20px 44px rgba(16,40,50,.10),
    inset 0 1px 0 rgba(255,255,255,.9);
}

/* Judul seksi: sedikit timbul */
.form-section-title{ text-shadow:0 1px 0 rgba(255,255,255,.85) }

/* ---------- Field: cekung halus (inset), bukan melayang ----------
   Inset membuat kotak isian terasa "tenggelam" ke dalam kartu — arah kebalikan
   dari tombol yang timbul, sehingga hierarkinya terbaca tanpa mengganggu teks. */
.field input,.field select,.field textarea{
  box-shadow:
    inset 0 1px 2px rgba(16,40,50,.07),
    inset 0 0 0 1px rgba(255,255,255,.5),
    0 1px 0 rgba(255,255,255,.75);
  transition:box-shadow .2s ease, border-color .2s ease, transform .2s ease;
}
/* Saat diisi: cekungan dilepas & diberi cincin fokus supaya terasa "terangkat
   mendekat" ke pengguna. Aturan fokus lama tetap berlaku di bawahnya. */
.field input:focus,.field select:focus,.field textarea:focus{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 0 0 3px rgba(14,124,134,.15),
    0 4px 10px rgba(16,40,50,.10);
}
/* Field error: cekungan merah, senada aturan .field-error yang sudah ada */
.field.field-error input,.field.field-error select{
  box-shadow:
    inset 0 1px 3px rgba(211,58,58,.14),
    0 1px 0 rgba(255,255,255,.7);
}

/* ---------- Tombol: timbul & tertekan ---------- */
.btn{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -1px 0 rgba(0,0,0,.12),
    0 2px 5px rgba(16,40,50,.16);
}
.btn:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    0 6px 16px rgba(16,40,50,.22);
}
/* Tertekan: bergerak turun + bayangan dalam = terasa seperti tombol fisik */
.btn:active{
  transform:translateY(1px);
  box-shadow:
    inset 0 2px 5px rgba(0,0,0,.22),
    0 1px 1px rgba(16,40,50,.12);
}
.btn svg{ transition:transform .22s cubic-bezier(.34,1.56,.64,1) }
.btn:hover svg{ transform:translateZ(6px) scale(1.1) }

/* ---------- IKON ----------
   Ikon aksi (.act) sudah punya angkat+skala saat hover (baris ~1311); di sini
   hanya ditambah relief & efek tertekan. `[disabled]` dikecualikan karena
   aturan `.pn-actions .act[disabled]{transform:none!important}` (baris ~1929)
   sengaja mematikannya. */
.act:not([disabled]){
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    inset 0 -1px 0 rgba(0,0,0,.14),
    0 2px 6px rgba(16,40,50,.18);
}
.act:not([disabled]):active{
  transform:translateY(-1px) scale(1.04);
  box-shadow:
    inset 0 2px 5px rgba(0,0,0,.26),
    0 1px 2px rgba(16,40,50,.12);
}

/* Chip ikon pada kartu (.card-ic) di luar dashboard */
.card-ic{ transition:transform .3s cubic-bezier(.34,1.56,.64,1), box-shadow .3s ease }

/* Ikon menu atas: sedikit maju & memutar saat disentuh */
.topnav-link svg,.topnav-item svg,.topnav-trigger svg{
  transition:transform .28s cubic-bezier(.34,1.56,.64,1);
}
.topnav-link:hover svg,.topnav-item:hover svg,.topnav-trigger:hover svg{
  transform:translateZ(8px) scale(1.14) rotate(-4deg);
}
/* Ikon menu Pengaturan */
.settings-item:hover svg{ transform:scale(1.12) }
.settings-item svg{ transition:color .15s ease, transform .22s cubic-bezier(.34,1.56,.64,1) }
/* Animasi menu "Keluar": teks & panah bergeser ke kanan berulang (isyarat arah keluar) */
@keyframes lo-slide-right{ 0%{transform:translateX(0)} 55%{transform:translateX(6px)} 100%{transform:translateX(0)} }
.settings-logout .lo-word{ display:inline-block; animation:lo-slide-right 1.5s ease-in-out infinite }
.settings-logout svg{ animation:lo-slide-right 1.5s ease-in-out infinite }
.settings-logout .lo-word{ animation-delay:.07s } /* teks mengikuti panah sesaat */
/* Ikon panah "Keluar" dikendalikan animasi, jadi hover-scale umum tak berlaku di sini */
/* Tombol "Keluar" diberi aksen merah TETAP agar mudah dibedakan dari menu lain */
.settings-item.settings-logout{ background:#fdecec; color:var(--red); box-shadow:inset 0 0 0 1px rgba(211,58,58,.22) }
.settings-item.settings-logout svg{ color:var(--red) }
.settings-item.settings-logout:hover{ background:#f7d6d6; color:var(--red-dark); box-shadow:inset 0 0 0 1px rgba(211,58,58,.38) }
.settings-item.settings-logout:hover svg{ color:var(--red-dark) }
/* Gerigi berputar saat kursor mouse di atasnya — HANYA untuk perangkat bermouse.
   Di layar sentuh (iPad/HP) state hover "menempel" setelah di-tap sehingga tombol
   tertinggal dalam posisi miring 40 derajat -> tampak terpotong & tidak presisi. */
.settings-gear{ transition:transform .4s cubic-bezier(.34,1.56,.64,1) }
@media (hover:hover) and (pointer:fine){
  .settings-gear:hover{ transform:rotate(40deg) }
}

/* Ikon di judul seksi form & panel: timbul tipis */
.form-section-title svg,.fkl-sec-h svg{ filter:drop-shadow(0 1px 2px rgba(16,40,50,.22)) }

/* ---------- Hormati "kurangi animasi" ---------- */
@media (prefers-reduced-motion:reduce){
  .form-card,.form-card:hover,
  .btn:active,.act:not([disabled]):active{ transform:none }
  .btn:hover svg,
  .topnav-link:hover svg,.topnav-item:hover svg,.topnav-trigger:hover svg,
  .settings-item:hover svg,.settings-gear:hover{ transform:none }
  .settings-logout .lo-word,.settings-logout svg{ animation:none }
  .form-card,.field input,.field select,.field textarea,
  .btn,.btn svg,.act,.card-ic,.settings-gear{ transition:none }
}

/* ============================================================
   EFEK 3D — BRAND (LOGO + JUDUL) & MENU ATAS
   Catatan teknis: `.topbar` sendiri memakai position:sticky, jadi TIDAK boleh
   diberi transform (akan mematahkan sticky-nya). Transform hanya dipasang pada
   anak-anaknya (logo, judul, tombol menu) — di situ aman.
   ============================================================ */

/* ---------- Logo: kotak timbul dengan kilau ---------- */
.topbar-brand .logo{
  position:relative;
  border-radius:13px;
  background:linear-gradient(145deg, rgba(255,255,255,.22), rgba(255,255,255,.04));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),      /* highlight tepi atas */
    inset 0 -1px 0 rgba(0,0,0,.18),           /* bayangan tepi bawah */
    0 2px 4px rgba(0,0,0,.18),
    0 6px 14px rgba(0,0,0,.20);
  transform:translateZ(0);
  transition:transform .38s cubic-bezier(.34,1.56,.64,1), box-shadow .38s ease;
}
/* Kilau diagonal melintas saat disentuh */
.topbar-brand .logo::after{
  content:"";
  position:absolute; inset:0;
  border-radius:inherit;
  background:linear-gradient(115deg, transparent 30%, rgba(255,255,255,.42) 50%, transparent 70%);
  transform:translateX(-130%);
  transition:transform .7s cubic-bezier(.2,.8,.2,1);
  pointer-events:none;
}
.topbar-brand:hover .logo::after{ transform:translateX(130%) }
.topbar-brand:hover .logo{
  transform:perspective(420px) rotateY(-14deg) rotateX(6deg) scale(1.08);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    0 4px 8px rgba(0,0,0,.2),
    0 12px 26px rgba(0,0,0,.28);
}
/* Gambar logo sedikit maju agar terasa melayang di atas kotaknya */
.topbar-brand .logo .logo-img{
  transition:transform .38s cubic-bezier(.34,1.56,.64,1), filter .38s ease;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.3));
}
.topbar-brand:hover .logo .logo-img{
  transform:scale(1.06);
  filter:drop-shadow(0 3px 6px rgba(0,0,0,.4));
}

/* ---------- Judul: huruf timbul (embossed) ----------
   Bayangan gelap di bawah + garis terang tipis di atas = huruf terasa menonjol
   dari latar teal, bukan sekadar ditempel. */
.brand h1{
  text-shadow:
    0 1px 0 rgba(255,255,255,.28),            /* garis terang di puncak huruf */
    0 -1px 1px rgba(0,0,0,.22),
    0 2px 3px rgba(0,0,0,.30),
    0 4px 10px rgba(0,0,0,.22);
  transition:text-shadow .35s ease, transform .35s cubic-bezier(.34,1.56,.64,1);
}
.topbar-brand:hover .brand h1{
  text-shadow:
    0 1px 0 rgba(255,255,255,.36),
    0 -1px 1px rgba(0,0,0,.24),
    0 3px 5px rgba(0,0,0,.34),
    0 7px 16px rgba(0,0,0,.28);
  transform:translateY(-1px);
}
.brand span{
  text-shadow:0 1px 2px rgba(0,0,0,.28);
  transition:opacity .35s ease;
}
.topbar-brand:hover .brand span{ opacity:1 }

/* Beri ruang 3D pada blok brand & jadikan kursor petunjuk interaktif */
.topbar-brand{ perspective:600px; cursor:default }

/* ---------- Menu atas: tombol timbul ----------
   `.topnav-link:hover` (baris ~1051) sudah memberi translateY(-2px); di sini
   relief-nya dilengkapi agar terbaca sebagai tombol fisik. */
.topnav-link,.topnav-trigger{
  text-shadow:0 1px 2px rgba(0,0,0,.22);
}
.topnav-link:hover,.topnav-trigger:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.24),
    0 8px 20px rgba(0,0,0,.22);
}
/* Ditekan: turun & bayangan dalam */
.topnav-link:active,.topnav-trigger:active{
  box-shadow:inset 0 2px 6px rgba(0,0,0,.3);
}
/* Menu aktif: timbul lebih tegas, senada aksen kuning yang sudah ada */
.topnav-link.active{
  box-shadow:
    0 6px 18px rgba(246,180,14,.45),
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 -2px 0 rgba(150,100,0,.28);
  text-shadow:0 1px 0 rgba(255,255,255,.45);
}

/* Item dropdown: relief halus saat disentuh */
.topnav-item:hover{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7), 0 3px 8px rgba(16,40,50,.14);
}

/* ---------- Hormati "kurangi animasi" ---------- */
@media (prefers-reduced-motion:reduce){
  .topbar-brand:hover .logo,
  .topbar-brand:hover .logo .logo-img,
  .topbar-brand:hover .brand h1{ transform:none }
  .topbar-brand .logo::after{ display:none }
  .topbar-brand .logo,.topbar-brand .logo .logo-img,.brand h1{ transition:none }
}

/* ============================================================
   EFEK 3D & TRANSISI — POP-UP NOTIFIKASI (TOAST)
   Toast berada di posisi fixed dan TIDAK mengandung sticky, jadi transform 3D
   aman sepenuhnya di sini.

   PENTING: `.toast` memakai transform untuk MEMPOSISIKAN dirinya sendiri
   (translateX(-50%) agar center). Karena transform tidak bertumpuk, setiap
   nilai transform baru WAJIB menyertakan translateX(-50%) — kalau tidak, toast
   akan melompat ke kanan. Pada layar <=640px aturan lama memakai left/right
   sehingga TIDAK memakai translateX(-50%); kedua kondisi ditangani terpisah.
   ============================================================ */

/* Ruang 3D + kedalaman berlapis. Bayangan warna mengikuti jenis toast
   (ok/warn/err) sudah diatur aturan lama; di sini ditambah relief tepi. */
.toast{
  transform-style:preserve-3d;
  will-change:transform, opacity;
  opacity:0;                       /* keadaan tersembunyi */
  perspective:800px;
  border:1px solid rgba(255,255,255,.14);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),      /* highlight tepi atas */
    inset 0 -1px 0 rgba(0,0,0,.22),           /* bayangan tepi bawah */
    0 2px 4px rgba(0,0,0,.18),
    0 10px 24px rgba(0,0,0,.24),
    0 22px 48px rgba(0,0,0,.20);
}

/* --- Keadaan TERSEMBUNYI: jatuh ke bawah, mengecil, & miring ke belakang ---
   rotateX positif = tepi atas menjauh, seolah tergeletak di "lantai". */
.toast{
  transform:
    translateX(-50%) translateY(120px) translateZ(-120px)
    rotateX(38deg) scale(.86);
}

/* --- Keadaan TAMPIL: berdiri tegak menghadap pengguna ---
   Kurva pegas (overshoot) membuat toast terasa "mendarat" dengan bobot,
   bukan sekadar bergeser. */
.toast.show{
  transform:
    translateX(-50%) translateY(0) translateZ(0)
    rotateX(0deg) scale(1);
  opacity:1;
}

/* Transisi: masuk memakai pegas & agak lambat (terasa hidup);
   keluar lebih cepat & tanpa pegas (tidak menahan perhatian). */
.toast{
  transition:
    transform .34s cubic-bezier(.34,1.56,.64,1),
    opacity .26s ease,
    box-shadow .34s ease;
}
.toast:not(.show){
  transition:
    transform .26s cubic-bezier(.4,0,1,1),
    opacity .2s ease;
}

/* Ikon di dalam toast maju ke depan (parallax) & berputar masuk —
   memberi kesan isi toast punya kedalaman, bukan gambar rata. */
.toast svg{
  transform:translateZ(0) scale(.5) rotate(-45deg);
  opacity:0;
  transition:transform .4s cubic-bezier(.34,1.56,.64,1) .06s, opacity .3s ease .06s;
}
.toast.show svg{
  transform:translateZ(26px) scale(1) rotate(0deg);
  opacity:1;
}
/* Teks sedikit maju, tertunda halus setelah ikon */
.toast span{
  display:inline-block;
  transform:translateZ(0) translateX(-6px);
  opacity:0;
  transition:transform .36s cubic-bezier(.2,.8,.2,1) .1s, opacity .3s ease .1s;
}
.toast.show span{
  transform:translateZ(12px) translateX(0);
  opacity:1;
}

/* Kilau tipis melintas sekali saat toast muncul */
.toast::after{
  content:"";
  position:absolute; inset:0;
  border-radius:inherit;
  background:linear-gradient(115deg, transparent 34%, rgba(255,255,255,.26) 50%, transparent 66%);
  transform:translateX(-120%);
  pointer-events:none;
  opacity:0;
}
.toast.show::after{
  animation:toastSheen .9s cubic-bezier(.2,.8,.2,1) .16s 1;
}
@keyframes toastSheen{
  0%   { transform:translateX(-120%); opacity:0 }
  30%  { opacity:1 }
  100% { transform:translateX(120%);  opacity:0 }
}

/* --- Layar kecil (<=640px) ---
   Aturan lama memakai left/right sehingga TIDAK ada translateX(-50%).
   Nilai transform di sini karena itu ditulis ulang tanpa translateX. */
@media(max-width:640px){
  .toast{
    transform:translateY(120px) translateZ(-120px) rotateX(38deg) scale(.86);
  }
  .toast.show{
    transform:translateY(0) translateZ(0) rotateX(0deg) scale(1);
  }
}

/* --- Hormati "kurangi animasi": muncul/hilang tanpa gerak 3D --- */
@media (prefers-reduced-motion:reduce){
  .toast{ transform:translateX(-50%) translateY(120px); transition:opacity .2s ease }
  .toast.show{ transform:translateX(-50%) translateY(0) }
  .toast svg,.toast.show svg,
  .toast span,.toast.show span{ transform:none; opacity:1; transition:none }
  .toast.show::after{ animation:none }
  @media(max-width:640px){
    .toast{ transform:translateY(120px) }
    .toast.show{ transform:translateY(0) }
  }
}
/* ============================================================
   ==========  PUSAT KONTROL AKUN & AKSES (fitur baru)  =======
   ============================================================ */
/* Penyembunyian berbasis kapabilitas (di-toggle lewat kelas <body>) */
body.ac-no-input [onclick*="newRecord"],
body.ac-no-input [onclick*="openFkInput"],
body.ac-no-input .head-add-btn,
body.ac-no-input .fk-corner-btn{ display:none !important; }
body.ac-no-template #io-tpl-kr,
body.ac-no-template #io-tpl-pl,
body.ac-no-template #io-tpl-tender,
body.ac-no-template [onclick*="ownloadTemplate"]{ display:none !important; }
body.ac-no-bersih #btn-bersih-kontrak{ display:none !important; }
body.ac-no-gantisandi #btn-change-pass{ display:none !important; }

/* Overlay + panel */
.ac-ov{ position:fixed; inset:0; z-index:6000; display:none; align-items:flex-start; justify-content:center;
  background:rgba(12,34,38,.55); backdrop-filter:blur(3px); padding:28px 16px; overflow:auto; }
.ac-ov.show{ display:flex; animation:acFade .18s ease; }
@keyframes acFade{ from{opacity:0} to{opacity:1} }
.ac-panel{ width:min(940px,100%); background:#fff; border-radius:18px; box-shadow:0 24px 70px rgba(9,60,66,.35);
  overflow:hidden; animation:acPop .22s cubic-bezier(.2,.9,.3,1.2); }
@keyframes acPop{ from{transform:translateY(14px) scale(.985); opacity:0} to{transform:none; opacity:1} }
.ac-head{ display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:18px 22px; background:linear-gradient(135deg,#0E7C86,#0a5e66); color:#fff; }
.ac-head-t{ display:flex; align-items:center; gap:14px; }
.ac-head-t svg{ width:30px; height:30px; flex:none; opacity:.95; }
.ac-head-t h3{ margin:0; font-size:1.12rem; font-weight:800; letter-spacing:.2px; }
.ac-head-t p{ margin:2px 0 0; font-size:.8rem; opacity:.85; }
/* MERAH, SEPERTI TOMBOL TUTUP PRATINJAU TOR/KAK (7 Agu 2026).
   flex:none + min-width/min-height menahan ukurannya: tanpa itu, judul panel
   yang panjang meregangkan baris kepala dan tombolnya ikut menyusut/tergeser. */
/* DISAMAKAN PERSIS dengan tombol tutup TOR/KAK — 8 Agu 2026.
   Sebelumnya panel Akun & Penyimpanan memakai angkanya sendiri (34px, sudut
   10px, silang berupa KARAKTER &times; setinggi 1,4rem), sehingga dua panel ini
   satu-satunya yang berbeda dari seluruh pop-up lain. Sekarang: 32x32, sudut
   9px, ikon silang 15px.

   Ikonnya digambar lewat ::before + mask, BUKAN dengan mengubah markup:
   panel ini dibangun di app-lain.js, dan menggambar ikon dari CSS membuat
   perubahan ini berdiri sendiri di satu berkas. `font-size:0` menyembunyikan
   karakter &times; yang masih ada di markup — kalau dibiarkan, silangnya
   bertumpuk dua. Kalau kelak markup-nya diganti <svg>, aturan :has(svg) di
   bawah otomatis mematikan ::before dan memakai SVG itu. */
.ac-x{ background:linear-gradient(135deg,#D33A3A,#e25151); border:0; color:#fff;
  flex:none; min-width:32px; min-height:32px; width:32px; height:32px; border-radius:9px;
  padding:0; font-size:0; line-height:0; cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center;
  box-shadow:0 2px 6px rgba(6,30,36,.30);
  transition:filter .15s ease, box-shadow .2s ease; }
.ac-x::before{ content:""; width:15px; height:15px; flex:none;
  background-color:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center/15px 15px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center/15px 15px no-repeat; }
.ac-x:has(svg)::before{ display:none }
.ac-x svg{ width:15px; height:15px; display:block;
  stroke:currentColor; fill:none; stroke-width:2 }
.ac-x:hover{ filter:brightness(1.08); box-shadow:0 4px 10px rgba(6,30,36,.36); }
.ac-x:focus-visible{ outline:2px solid #fff; outline-offset:2px; }
/* Getaran "tutup dulu" — bahasa isyarat yang sama dengan pratinjau TOR/KAK.
   @keyframes-nya DIDEFINISIKAN DI SINI, bukan dipinjam dari torEnsureStyle():
   gaya TOR baru disuntikkan saat halaman TOR/KAK dibuka, sedangkan panel ini
   bisa dibuka tanpa pernah menyentuh halaman itu — animasinya akan diam-diam
   tidak berjalan. Namanya sengaja sama persis dan isinya identik, jadi kalau
   kelak keduanya termuat bersamaan hasilnya tetap satu gerakan yang sama. */
@keyframes tor-dk-getar{
  0%,100%{ transform:translateX(0) }
  15%{ transform:translateX(-6px) } 30%{ transform:translateX(6px) }
  45%{ transform:translateX(-4px) } 60%{ transform:translateX(4px) }
  75%{ transform:translateX(-2px) } 90%{ transform:translateX(2px) } }
@keyframes tor-dk-sorot{
  0%,100%{ box-shadow:0 2px 7px rgba(4,26,32,.30) }
  50%{ box-shadow:0 0 0 4px rgba(255,255,255,.75),0 2px 7px rgba(4,26,32,.30) } }
.ac-panel.menolak,.st-panel.menolak{ animation:tor-dk-getar .4s cubic-bezier(.36,.07,.19,.97) both; }
.ac-panel.menolak .ac-x,.st-panel.menolak .ac-x{ animation:tor-dk-sorot .4s ease-in-out 2; }
@media (prefers-reduced-motion:reduce){
  .ac-panel.menolak,.st-panel.menolak{ animation:none; }
  .ac-panel.menolak .ac-x,.st-panel.menolak .ac-x{ animation:tor-dk-sorot .5s ease-in-out 2; } }
/* --- Tombol aksi di kanan atas panel Akun & Kontrol ---
   Menggantikan bilah tab: halaman pertama panel kini Daftar Akun, dan kedua
   halaman lain dibuka dari sini. `margin-left:auto` yang mendorongnya ke kanan
   — .ac-head sudah flex, jadi tombol × tetap di ujung tanpa perubahan lain.
   Di layar sempit kelompok ini turun ke baris berikutnya (lihat blok
   @media di bawah) supaya judul panel tidak ikut terhimpit. */
.ac-head-act{ display:flex; align-items:center; gap:8px; margin-left:auto; }
.ac-hbtn{ background:rgba(255,255,255,.14); border:0; color:#fff; padding:8px 14px; border-radius:10px;
  font-size:.82rem; font-weight:700; line-height:1; cursor:pointer; white-space:nowrap;
  transition:background .15s, transform .12s; }
.ac-hbtn:hover{ background:rgba(255,255,255,.28); }
.ac-hbtn:active{ transform:translateY(1px); }
.ac-hbtn.active{ background:#fff; color:#0a5e66; }
/* Tombol kembali ke Daftar Akun, dipasang di atas halaman Buat Akun & Reset
   Sandi. Tanpa ini kedua halaman itu tidak punya jalan keluar sejak bilah tab
   dihapus — satu-satunya cara kembali adalah menutup seluruh panel. */
.ac-back{ display:inline-flex; align-items:center; gap:7px; background:transparent; border:0; cursor:pointer;
  color:#0E7C86; font-weight:700; font-size:.85rem; padding:2px 0 12px; }
.ac-back:hover{ color:#0a5e66; text-decoration:underline; }
.ac-back svg{ width:16px; height:16px; }
@media (max-width:640px){
  .ac-head{ flex-wrap:wrap; }
  .ac-head-act{ order:3; width:100%; margin-left:0; }
  .ac-hbtn{ flex:1; text-align:center; }
}
.ac-tabs{ display:flex; gap:4px; padding:10px 16px 0; background:#f2f7f8; border-bottom:1px solid #dfeaec; }
.ac-tab{ border:0; background:transparent; padding:10px 16px; font-weight:700; font-size:.86rem; color:#5b7176;
  cursor:pointer; border-radius:10px 10px 0 0; border-bottom:3px solid transparent; }
.ac-tab:hover{ color:#0E7C86; }
.ac-tab.active{ color:#0a5e66; background:#fff; border-bottom-color:#0E7C86; }
.ac-body{ padding:18px 22px 22px; max-height:66vh; overflow:auto; }
.ac-hint,.ac-note{ font-size:.82rem; color:#4a6065; background:#eef6f7; border:1px solid #d5e7e9;
  border-radius:10px; padding:10px 12px; margin-bottom:14px; line-height:1.5; }
.ac-note code{ background:#dcecee; padding:1px 6px; border-radius:5px; font-size:.78rem; }
.ac-empty{ text-align:center; color:#78898d; padding:26px; font-size:.9rem; }

/* Matrix */
.ac-tablewrap{ overflow:auto; border:1px solid #e2edee; border-radius:12px; }
table.ac-matrix{ border-collapse:collapse; width:100%; font-size:.82rem; }
table.ac-matrix th,table.ac-matrix td{ padding:9px 8px; text-align:center; border-bottom:1px solid #eef3f4; white-space:nowrap; }
table.ac-matrix thead th{ background:#0E7C86; color:#fff; font-weight:700; position:sticky; top:0; font-size:.76rem; }
table.ac-matrix thead th.ac-sticky{ left:0; z-index:3; }
table.ac-matrix th.ac-sticky,table.ac-matrix td.ac-sticky{ position:sticky; left:0; background:#fff; text-align:left;
  box-shadow:2px 0 0 #eef3f4; font-weight:700; color:#274046; }
table.ac-matrix tbody tr:nth-child(even) td{ background:#f7fbfb; }
table.ac-matrix tbody tr:nth-child(even) td.ac-sticky{ background:#f7fbfb; }
.ac-dbcol{ background:#fff6ec !important; }
.ac-role .ac-badge{ display:inline-block; font-size:.64rem; font-weight:800; color:#0a5e66; background:#d6ecee;
  padding:2px 7px; border-radius:20px; margin-left:6px; vertical-align:middle; }

/* Switch */
.ac-sw{ position:relative; display:inline-block; width:38px; height:22px; cursor:pointer; }
.ac-sw input{ opacity:0; width:0; height:0; position:absolute; }
.ac-sw span{ position:absolute; inset:0; background:#cdd8da; border-radius:20px; transition:.18s; }
.ac-sw span:before{ content:""; position:absolute; width:16px; height:16px; left:3px; top:3px; background:#fff;
  border-radius:50%; transition:.18s; box-shadow:0 1px 3px rgba(0,0,0,.25); }
.ac-sw input:checked + span{ background:#0E7C86; }
.ac-sw-db input:checked + span,.ac-dbcol .ac-sw input:checked + span{ background:#e08a1e; }
.ac-sw input:checked + span:before{ transform:translateX(16px); }
.ac-sw.dis,.ac-sw input:disabled + span{ opacity:.5; cursor:not-allowed; }

/* Form buat akun */
.ac-form .ac-row2{ display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:14px; }
.ac-fld{ display:flex; flex-direction:column; gap:6px; margin-bottom:6px; }
.ac-fld > label{ font-size:.78rem; font-weight:700; color:#3a5257; }
.ac-fld input[type=text],.ac-fld select{ padding:10px 12px; border:1px solid #cddcde; border-radius:10px; font-size:.9rem; background:#fff; }
.ac-fld input[readonly]{ background:#f2f5f6; color:#7b8b8f; }
.ac-toggle{ display:flex; align-items:center; gap:10px; cursor:pointer; padding:8px 0; }
.ac-toggle input{ opacity:0; width:0; height:0; position:absolute; }
.ac-toggle-tr{ position:relative; width:44px; height:24px; background:#cdd8da; border-radius:20px; transition:.18s; flex:none; }
.ac-toggle-tr:before{ content:""; position:absolute; width:18px; height:18px; left:3px; top:3px; background:#fff; border-radius:50%; transition:.18s; box-shadow:0 1px 3px rgba(0,0,0,.25); }
.ac-toggle input:checked + .ac-toggle-tr{ background:#e08a1e; }
.ac-toggle input:checked + .ac-toggle-tr:before{ transform:translateX(20px); }
.ac-toggle em{ font-style:normal; font-size:.82rem; color:#4a6065; font-weight:600; }
.ac-capgrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:8px 14px;
  border:1px solid #e2edee; border-radius:12px; padding:12px; background:#fafcfc; }
.ac-chk{ display:flex; align-items:center; gap:8px; font-size:.84rem; color:#33484d; cursor:pointer; }
.ac-chk input{ width:16px; height:16px; accent-color:#0E7C86; }
.ac-chk.dis{ opacity:.6; cursor:not-allowed; }

.ac-actions{ display:flex; justify-content:flex-end; gap:10px; margin-top:16px; }
.ac-actions .btn.ghost{ background:#eef3f4; color:#3a5257; border:1px solid #d7e3e5; }

/* Daftar akun */
/* Disamakan dengan tabel data utama (lihat aturan `th` global): kepala tabel
   teal pekat, huruf putih kapital berspasi, rata tengah. Sebelumnya kepala
   tabel di sini abu-abu muda dan rata kiri — terlihat seperti komponen dari
   aplikasi lain yang kebetulan menumpang di panel yang sama. */
table.ac-list{ border-collapse:collapse; width:100%; font-size:.84rem; }
table.ac-list th,table.ac-list td{ padding:11px 14px; vertical-align:middle; }
table.ac-list thead th{ background:var(--teal); color:#fff; font-weight:800; font-size:.7rem;
  text-transform:uppercase; letter-spacing:.5px; white-space:nowrap; text-align:center;
  border-right:1px solid rgba(255,255,255,.28); }
table.ac-list thead th:last-child{ border-right:0; }
table.ac-list tbody td{ border-top:1px solid #dfeaec; border-right:1px solid #eaf1f2;
  color:#22343a; text-align:center; }
table.ac-list tbody td:last-child{ border-right:0; }
table.ac-list tbody tr:nth-child(even) td{ background:#f6fafb; }
table.ac-list tbody tr{ transition:background .13s; }
table.ac-list tbody tr:hover td{ background:#eef7f8; }
/* Username = jangkar baris: rata kiri & lebih tebal supaya mata punya titik
   mulai yang tetap, sementara kolom lain rata tengah. */
table.ac-list td.ac-cell-user{ font-weight:800; color:#0a5e66; white-space:nowrap; text-align:left; }
table.ac-list td.ac-cell-ket{ color:#5b7176; font-size:.8rem; }
/* Kolom Aksi menyempit mengikuti isinya (tiga ikon) — `width:1%` membuat
   browser memberinya lebar seminimal mungkin, sehingga sisa ruang jatuh ke
   kolom data. */
table.ac-list th.ac-col-aksi,table.ac-list td.ac-col-aksi{ white-space:nowrap; width:1%; }

/* ---- Status Online ----
   Titik berwarna + teks. Warnanya bertingkat: hijau (sedang aktif), teal
   (dalam hitungan jam), abu (berhari-hari), merah pudar (setahun ke atas). */
.ac-stat{ display:inline-flex; align-items:center; gap:7px; font-weight:700; font-size:.78rem; white-space:nowrap; }
.ac-stat i{ width:8px; height:8px; border-radius:50%; flex:none; background:currentColor; }
.ac-stat.on{ color:#1E9E5A; }
.ac-stat.on i{ box-shadow:0 0 0 3px rgba(30,158,90,.18); animation:acPulse 1.8s ease-in-out infinite; }
/* KETENTUAN 7 Agu 2026: HANYA "Sedang aktif" yang berwarna. Semua status lain —
   berapa pun lamanya — memakai satu abu-abu kehitaman yang sama, supaya mata
   langsung menangkap siapa yang benar-benar sedang online alih-alih memilah
   empat tingkat warna. Titik mewarisi warna teksnya lewat
   `background:currentColor` pada .ac-stat i, jadi cukup satu deklarasi. */
.ac-stat.baru,.ac-stat.jeda,.ac-stat.lama,.ac-stat.never{ color:#5b6b70; }
/* "Belum pernah masuk" tetap dibedakan lewat BENTUK huruf (miring), bukan
   warna — keterangannya memang bukan rentang waktu seperti yang lain. */
.ac-stat.never{ font-style:italic; font-weight:600; }
@keyframes acPulse{ 0%,100%{ box-shadow:0 0 0 3px rgba(30,158,90,.18) } 50%{ box-shadow:0 0 0 6px rgba(30,158,90,.06) } }
@media (prefers-reduced-motion:reduce){ .ac-stat.on i{ animation:none } }

/* Reset kata sandi: kuning madu — bukan merah (tidak merusak apa pun) tetapi
   juga bukan netral, karena tetap mengubah kredensial orang lain. */
.act-reset{ background:linear-gradient(135deg,#C98A00,#e0a516); color:#fff; }
/* ============================================================================
   AKUN PENGGUNA — TOMBOL TULIS DISEMBUNYIKAN (12 Agu 2026)
   ----------------------------------------------------------------------------
   applyRole() di app.js menempelkan data-peran pada <body>. Aturan di bawah
   dipilih ketimbang menyembunyikan tiap tombol lewat JavaScript karena tabel
   di aplikasi ini digambar ULANG terus-menerus — saat difilter, dicari,
   berpindah halaman, atau setelah data disegarkan. Penyembunyian lewat JS
   hanya bertahan sampai render berikutnya; aturan CSS ikut berlaku pada tombol
   yang baru lahir sesudahnya.

   YANG TETAP TERLIHAT: .act-view (Lihat), .act-excel (Export Excel), dan
   seluruh tombol unduh/cetak — akun Pengguna memang boleh melihat, mengunduh,
   dan mencetak.

   INI BUKAN PENGAMANAN. CSS bisa dimatikan siapa saja dari alat pengembang.
   Yang menolak sungguhan adalah requireInput()/canInput() di app.js dan
   policy RLS boleh_tulis() di server (02_auth_akun.sql Bagian 7); aturan ini
   hanya menjaga agar layar tidak menawarkan tombol yang pasti ditolak.
   ============================================================================ */
body[data-peran="pengguna"] .act-edit,
body[data-peran="pengguna"] .act-del,
body[data-peran="pengguna"] .act-reset,
body[data-peran="pengguna"] .act-wa,
body[data-peran="pengguna"] .fk-act-up,
body[data-peran="pengguna"] .fk-act-del,
body[data-peran="pengguna"] .head-add-btn,
body[data-peran="pengguna"] #fk-view-tambah{ display:none !important; }

.ac-pill{ display:inline-block; font-size:.72rem; font-weight:800; padding:3px 9px; border-radius:20px; }
.ac-pill.dummy{ background:#e7eef0; color:#4a6065; }
.ac-pill.user{ background:#dcecff; color:#1c4e80; }
.ac-pill.admin{ background:#e5e0ff; color:#4b2a8a; }
/* Jenis "Pengguna" (hanya melihat). Hijau-teal, sengaja BUKAN biru milik
   .ac-pill.user: keduanya berdampingan di kolom yang sama, dan dua nada biru
   yang mirip akan terbaca sebagai satu jenis yang sama pada layar kecil. */
.ac-pill.lihat{ background:#d8f1ea; color:#175f4e; }
.ac-pill.on{ background:#fdecd6; color:#8a5a12; }
.ac-pill.off{ background:#e7eef0; color:#4a6065; }
.ac-rowact{ display:flex; gap:6px; justify-content:center; }
.ac-mini{ border:1px solid #cddcde; background:#fff; color:#2f484d; padding:5px 12px; border-radius:8px; font-size:.78rem; font-weight:700; cursor:pointer; }
.ac-mini:hover{ background:#f0f6f6; }
.ac-mini.danger{ border-color:#f0c9c6; color:#c0392b; }
.ac-mini.danger:hover{ background:#fdeeec; }

.ac-sql{ margin-top:18px; border-top:1px dashed #dbe6e7; padding-top:12px; }
.ac-sql summary{ cursor:pointer; font-weight:700; font-size:.82rem; color:#0a5e66; }
.ac-sql p{ font-size:.8rem; color:#4a6065; margin:8px 0 6px; }
.ac-sql pre{ background:#0f2b30; color:#d7f0f2; padding:12px 14px; border-radius:10px; font-size:.74rem;
  overflow:auto; line-height:1.5; }
.ac-sql small{ color:#78898d; }

@media (max-width:640px){
  .ac-form .ac-row2{ grid-template-columns:1fr; }
  .ac-body{ max-height:72vh; }
}

/* Reset Sandi (tab baru) */
.ac-sec-title{ font-size:.9rem; font-weight:800; color:#0a5e66; margin:4px 0 10px; }
input.ac-rpw{ padding:8px 10px; border:1px solid #cddcde; border-radius:8px; font-size:.85rem; width:170px; max-width:100%; }

/* ============================================================================
   AKUN & KONTROL — matrix granular, sesi aktif, dan panel Penyimpanan
   ============================================================================ */
.ac-panel{ width:min(1120px,100%); }

/* Matrix granular: header dua tingkat (grup + aksi) */
.ac-matrix-grp thead th.ac-grp-th{ background:#0a6a73; font-size:.72rem; letter-spacing:.2px;
  border-left:2px solid #fff; border-bottom:1px solid rgba(255,255,255,.22); white-space:normal; min-width:auto; }
.ac-matrix-grp thead th.ac-grp-th.alt{ background:#12888f; }
.ac-matrix-grp thead th.ac-act-th{ background:#0E7C86; font-size:.66rem; font-weight:700; text-transform:none;
  padding:5px 7px; letter-spacing:0; }
.ac-matrix-grp thead th.ac-act-th.alt{ background:#15959d; }
.ac-matrix-grp thead th.ac-act-view{ box-shadow:inset 0 3px 0 #16a9b5; }
.ac-matrix-grp thead th.ac-act-add{ box-shadow:inset 0 3px 0 #2fa36b; }
.ac-matrix-grp thead th.ac-act-edit{ box-shadow:inset 0 3px 0 #e6b800; }
.ac-matrix-grp thead th.ac-act-del{ box-shadow:inset 0 3px 0 #d9534f; }
.ac-matrix-grp thead th.ac-act-access{ box-shadow:inset 0 3px 0 #6b7bd6; }
.ac-matrix-grp td.ac-cell.alt{ background:#eef8f8 !important; }
.ac-matrix-grp tbody tr:nth-child(even) td.ac-cell.alt{ background:#e6f4f4 !important; }
.ac-matrix-grp td.ac-cell{ min-width:56px; }

/* Grid modul (form buat/ubah akun) — dikelompokkan per menu */
.ac-capgroups{ display:grid; grid-template-columns:repeat(auto-fill,minmax(238px,1fr)); gap:12px;
  border:1px solid #e2edee; border-radius:12px; padding:12px; background:#fafcfc; }
.ac-capgrp{ border:1px solid #e6eff0; border-radius:10px; background:#fff; overflow:hidden; }
.ac-capgrp-h{ font-size:.74rem; font-weight:800; color:#0a5e66; background:#eef6f7; padding:7px 11px;
  border-bottom:1px solid #e2edee; line-height:1.3; }
.ac-capgrp-body{ display:flex; flex-wrap:wrap; gap:7px 14px; padding:10px 12px; }

/* Ringkasan & sesi aktif */
.ac-active-wrap{ margin-bottom:14px; }
.ac-live-ic{ display:inline-block; width:8px; height:8px; border-radius:50%; background:#2fa36b; margin-right:7px;
  box-shadow:0 0 0 3px rgba(47,163,107,.18); vertical-align:middle; }
.ac-active{ display:flex; flex-direction:column; gap:6px; }
.ac-muted{ font-size:.82rem; color:#78898d; }
.ac-live{ display:flex; align-items:center; gap:9px; background:#f4faf9; border:1px solid #e0eeee;
  border-radius:10px; padding:8px 12px; font-size:.85rem; }
.ac-live.me{ background:#eafaf3; border-color:#bfe6d3; }
.ac-live b{ color:#274046; }
.ac-dot{ width:9px; height:9px; border-radius:50%; background:#2fa36b; box-shadow:0 0 0 3px rgba(47,163,107,.18);
  animation:acPulse 1.8s infinite; flex:none; }
@keyframes acPulse{ 0%,100%{opacity:1} 50%{opacity:.35} }
.ac-live-you{ font-size:.7rem; font-weight:800; color:#0a7a4a; background:#d5f3e3; padding:2px 8px; border-radius:20px; }
.ac-live-t{ margin-left:auto; font-size:.74rem; color:#78898d; white-space:nowrap; }
.ac-sum{ display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
.ac-sum-chip{ font-size:.8rem; color:#3a5257; background:#eef6f7; border:1px solid #d5e7e9; border-radius:20px; padding:5px 13px; }
.ac-sum-chip b{ color:#0a5e66; font-size:.92rem; }
.ac-sum-chip.user{ background:#dcecff; border-color:#bcd8f5; } .ac-sum-chip.user b{ color:#1c4e80; }
/* Ungu, disamakan dengan .ac-pill.admin supaya jenis akun dikenali dari warna
   yang sama di ringkasan maupun di dalam tabel. */
.ac-sum-chip.admin{ background:#e5e0ff; border-color:#cdc3f5; } .ac-sum-chip.admin b{ color:#4b2a8a; }
.ac-sum-chip.dummy{ background:#e7eef0; border-color:#d3dfe1; } .ac-sum-chip.dummy b{ color:#4a6065; }

/* ===== Panel Penyimpanan — kartu 3D ===== */
.st-panel{ width:min(760px,100%); }
.st-ov .ac-body{ background:linear-gradient(180deg,#f3f9f9,#eaf3f4); }
#st-pane{ overflow-x:hidden; }
.st-wrap{ display:block; }
.st-loading{ text-align:center; padding:56px 0; color:#5b7176; }
.st-loading p{ font-size:.86rem; }
.st-spin{ width:40px; height:40px; border:4px solid #d5e7e9; border-top-color:#0E7C86; border-radius:50%;
  margin:0 auto 14px; animation:acSpin .8s linear infinite; box-shadow:0 4px 12px rgba(14,124,134,.15); }
@keyframes acSpin{ to{ transform:rotate(360deg); } }

/* KPI tiles 3D */
.st-top{ display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:18px; }
.st-kpi{ position:relative; display:flex; align-items:center; gap:14px; border-radius:16px; padding:16px 18px; color:#fff; overflow:hidden;
  box-shadow:0 12px 26px rgba(9,60,66,.28), inset 0 1px 0 rgba(255,255,255,.32), inset 0 -4px 10px rgba(0,0,0,.16);
  transition:transform .18s ease, box-shadow .18s ease; }
.st-kpi:hover{ transform:translateY(-3px); box-shadow:0 18px 34px rgba(9,60,66,.34), inset 0 1px 0 rgba(255,255,255,.32), inset 0 -4px 10px rgba(0,0,0,.16); }
.st-kpi::after{ content:""; position:absolute; left:0; right:0; top:0; height:46%; background:linear-gradient(180deg,rgba(255,255,255,.20),transparent); pointer-events:none; }
.st-kpi-db{ background:linear-gradient(145deg,#12909b,#0a5e66); }
.st-kpi-st{ background:linear-gradient(145deg,#37b27e,#1c7a51); }
.st-kpi-ic{ width:48px; height:48px; border-radius:14px; flex:none; display:flex; align-items:center; justify-content:center;
  background:rgba(255,255,255,.16); box-shadow:inset 0 1px 0 rgba(255,255,255,.45), 0 5px 12px rgba(0,0,0,.18); }
.st-kpi-ic svg{ width:25px; height:25px; }
.st-kpi-txt{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.st-kpi-l{ font-size:.74rem; opacity:.9; }
.st-kpi-v{ font-size:1.7rem; font-weight:800; line-height:1.05; letter-spacing:.3px; text-shadow:0 1px 2px rgba(0,0,0,.18); }
.st-kpi-s{ font-size:.72rem; opacity:.85; }
.st-kpi-mini{ display:block; height:7px; border-radius:20px; background:rgba(255,255,255,.22); overflow:hidden;
  margin:8px 0 5px; box-shadow:inset 0 1px 2px rgba(0,0,0,.28), inset 0 -1px 0 rgba(255,255,255,.15); }
.st-kpi-mini span{ display:block; height:100%; border-radius:20px; background:linear-gradient(180deg,#ffffff,#dbf3f1);
  box-shadow:0 0 7px rgba(255,255,255,.55), inset 0 1px 0 rgba(255,255,255,.9); transition:width .6s cubic-bezier(.2,.9,.3,1); }
.st-kpi-mini.st span{ background:linear-gradient(180deg,#ffffff,#d5f5e2); }
.st-kpi-sub{ font-size:.73rem; opacity:.92; }
.st-kpi-sub b{ font-weight:800; }

/* Kartu 3D */
.st-card{ position:relative; border:1px solid #e2edee; border-radius:16px; padding:16px 18px; margin-bottom:16px;
  background:linear-gradient(180deg,#ffffff,#f6fbfb);
  box-shadow:0 10px 26px rgba(9,60,66,.09), inset 0 1px 0 rgba(255,255,255,.9); }
.st-card-h{ display:flex; align-items:center; gap:9px; font-size:.95rem; color:#274046; margin-bottom:14px; }
.st-card-h b{ color:#0a5e66; }
.st-card-h .st-muted{ margin-left:1px; }
.st-card-ic{ width:30px; height:30px; border-radius:9px; flex:none; display:flex; align-items:center; justify-content:center; color:#fff;
  box-shadow:0 5px 11px rgba(14,124,134,.30), inset 0 1px 0 rgba(255,255,255,.45); }
.st-card-ic svg{ width:17px; height:17px; }
.st-card-ic.db{ background:linear-gradient(145deg,#12909b,#0a5e66); }
.st-card-ic.st{ background:linear-gradient(145deg,#37b27e,#1c7a51); box-shadow:0 5px 11px rgba(31,125,84,.30), inset 0 1px 0 rgba(255,255,255,.45); }
.st-muted{ color:#78898d; font-size:.78rem; font-weight:500; }

/* Gauge 3D (track cekung + isian mengilap) */
.st-gauge{ margin-bottom:16px; }
.st-gauge-top{ display:flex; justify-content:space-between; align-items:baseline; margin-bottom:7px; }
.st-gauge-lbl{ font-weight:800; color:#0a5e66; font-size:.92rem; }
.st-gauge-pct{ font-size:.78rem; color:#5b7176; font-weight:700; }
.st-gauge-cap{ font-size:.72rem; color:#7e8f92; margin-top:6px; }
.st-hint{ font-size:.74rem; line-height:1.5; color:#5d7275; background:#f2f7f7; border:1px solid #dbe8e8;
  border-left:3px solid #1f8a80; border-radius:8px; padding:8px 10px; margin:10px 0 4px; }
.st-hint code{ background:#e4efef; border-radius:4px; padding:0 4px; font-size:.9em; }
.st-hint b{ color:#25545a; }
.st-track{ height:9px; border-radius:20px; background:#e6eef0; overflow:hidden;
  box-shadow:inset 0 2px 5px rgba(9,60,66,.20), inset 0 -1px 0 rgba(255,255,255,.65); }
.st-track.big{ height:15px; }
.st-fill{ display:block; height:100%; border-radius:20px; transition:width .6s cubic-bezier(.2,.9,.3,1);
  background:linear-gradient(180deg,#39aab3,#0E7C86 55%,#0a5e66);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5), 0 1px 3px rgba(14,124,134,.4); }
.st-fill.st{ background:linear-gradient(180deg,#63cf93,#2fa36b 55%,#1c7a51); box-shadow:inset 0 1px 0 rgba(255,255,255,.5), 0 1px 3px rgba(31,125,84,.4); }
.st-fill.warn{ background:linear-gradient(180deg,#f2c85c,#e0a52e); }
.st-fill.hot{ background:linear-gradient(180deg,#e57a76,#d9534f); }

/* Baris item (flex, anti-overflow) */
.st-list{ display:flex; flex-direction:column; gap:9px; }
.st-glabel{ align-self:stretch; font-size:.66rem; font-weight:800; letter-spacing:.5px; text-transform:uppercase; color:#0a5e66;
  padding:0 2px 9px; margin:26px 0 3px; border-bottom:1px dashed #d3e6e6; display:flex; align-items:center; gap:9px; }
.st-glabel::before{ content:""; width:9px; height:9px; border-radius:3px; flex:none;
  background:linear-gradient(145deg,#12909b,#0a5e66); box-shadow:0 2px 5px rgba(14,124,134,.35), inset 0 1px 0 rgba(255,255,255,.4); }
.st-list .st-glabel:first-child{ margin-top:4px; }
.st-item{ box-sizing:border-box; background:linear-gradient(180deg,#ffffff,#f3f9f9); border:1px solid #e6eff0; border-radius:12px;
  padding:11px 13px; box-shadow:0 2px 7px rgba(9,60,66,.05), inset 0 1px 0 rgba(255,255,255,.85); transition:transform .15s, box-shadow .15s, border-color .15s; }
.st-item:hover{ transform:translateY(-1px); box-shadow:0 7px 18px rgba(9,60,66,.11); border-color:#cbe4e4; }
.st-item-row{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:8px; }
.st-item-name{ font-size:.86rem; color:#33484d; font-weight:600; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.st-item-name code{ background:#eef3f4; padding:1px 7px; border-radius:6px; font-size:.72rem; color:#4a6065; font-weight:700; margin-left:5px; }
.st-item-val{ font-size:.92rem; font-weight:800; color:#0a5e66; white-space:nowrap; flex:none; }
.st-item-val em{ font-style:normal; font-weight:600; font-size:.74rem; color:#7e8f92; }
.st-na{ color:#a2adb0; font-weight:600; font-size:.74rem; }
.st-foot{ display:flex; align-items:center; justify-content:space-between; margin-top:10px; gap:12px; }
@media (max-width:640px){ .st-top{ grid-template-columns:1fr; } }

/* Enforcement per jenis pengadaan (disembunyikan bila aksi ditolak Admin) */
body.ac-no-add-kr #view-list button[onclick^="newRecord("]{ display:none !important; }
body.ac-no-edit-kr #view-list .act-edit{ display:none !important; }
body.ac-no-del-kr #view-list .act-del{ display:none !important; }
body.ac-no-add-pl #view-list-pl button[onclick^="newRecordPl("]{ display:none !important; }
body.ac-no-edit-pl #view-list-pl .act-edit{ display:none !important; }
body.ac-no-del-pl #view-list-pl .act-del{ display:none !important; }
body.ac-no-add-tender #view-list-tender button[onclick^="newRecordTender("]{ display:none !important; }
body.ac-no-edit-tender #view-list-tender .act-edit{ display:none !important; }
body.ac-no-del-tender #view-list-tender .act-del{ display:none !important; }
body.ac-no-fk-edit [onclick*="openFkInput"], body.ac-no-fk-edit .fk-corner-btn{ display:none !important; }
body.ac-no-fk-del [onclick^="fkDelete"]{ display:none !important; }

/* ============================================================================
   Efek 3D — Matriks Kontrol Akses & sakelar
   ============================================================================ */
.ac-tablewrap{ box-shadow:0 12px 30px rgba(9,60,66,.14), inset 0 1px 0 rgba(255,255,255,.7); border-radius:14px; }
.ac-matrix-grp thead th.ac-grp-th{ background:linear-gradient(180deg,#0f828c,#0a636c);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.20), inset 0 -3px 6px rgba(0,0,0,.20); text-shadow:0 1px 1px rgba(0,0,0,.28); }
.ac-matrix-grp thead th.ac-grp-th.alt{ background:linear-gradient(180deg,#138b93,#0d737b); }
.ac-matrix-grp thead th.ac-act-th{ background:linear-gradient(180deg,#0f818b,#0b6b73); text-shadow:0 1px 1px rgba(0,0,0,.22); }
.ac-matrix-grp thead th.ac-act-th.alt{ background:linear-gradient(180deg,#149098,#0e787f); }
.ac-matrix-grp thead th.ac-sticky{ background:linear-gradient(180deg,#0d737b,#0a5e66);
  box-shadow:3px 0 10px rgba(9,60,66,.22), inset 0 1px 0 rgba(255,255,255,.15); }
table.ac-matrix th.ac-sticky,table.ac-matrix td.ac-sticky{ box-shadow:4px 0 10px rgba(9,60,66,.10); }
table.ac-matrix tbody tr{ transition:background .15s; }
table.ac-matrix tbody tr:hover td{ background:#eafafa; }
table.ac-matrix tbody tr:hover td.ac-cell.alt{ background:#e0f4f4 !important; }
.ac-role .ac-badge{ box-shadow:0 2px 5px rgba(9,60,66,.12), inset 0 1px 0 rgba(255,255,255,.6); }
.ac-dbcol{ box-shadow:inset 0 0 0 1px rgba(224,138,30,.10); }

/* Sakelar 3D (track cekung, tombol timbul) */
.ac-sw span{ background:linear-gradient(180deg,#c2cfd1,#dae2e3);
  box-shadow:inset 0 2px 4px rgba(9,60,66,.24), inset 0 -1px 0 rgba(255,255,255,.55); }
.ac-sw span:before{ background:linear-gradient(180deg,#ffffff,#eef2f3);
  box-shadow:0 2px 4px rgba(0,0,0,.30), inset 0 1px 0 rgba(255,255,255,.95); }
.ac-sw input:checked + span{ background:linear-gradient(180deg,#17959f,#0a5e66);
  box-shadow:inset 0 2px 4px rgba(0,0,0,.22), 0 1px 3px rgba(14,124,134,.45); }
.ac-sw-db input:checked + span,.ac-dbcol .ac-sw input:checked + span{ background:linear-gradient(180deg,#efa53d,#c9761a);
  box-shadow:inset 0 2px 4px rgba(0,0,0,.20), 0 1px 3px rgba(201,118,26,.45); }
.ac-toggle-tr{ box-shadow:inset 0 2px 4px rgba(9,60,66,.22), inset 0 -1px 0 rgba(255,255,255,.55); }
.ac-toggle-tr:before{ box-shadow:0 2px 4px rgba(0,0,0,.30), inset 0 1px 0 rgba(255,255,255,.95); }
.ac-toggle input:checked + .ac-toggle-tr{ background:linear-gradient(180deg,#efa53d,#c9761a); }

/* Kelompok modul (form akun) sedikit terangkat */
.ac-capgrp{ box-shadow:0 4px 12px rgba(9,60,66,.07), inset 0 1px 0 rgba(255,255,255,.8); transition:transform .15s, box-shadow .15s; }
.ac-capgrp:hover{ transform:translateY(-1px); box-shadow:0 8px 20px rgba(9,60,66,.12); }

/* ============================================================================
   Efek 3D — Buat Akun, Daftar Akun, Reset Sandi
   ============================================================================ */
/* Kotak info (hint/note) — kartu terangkat + aksen kiri */
.ac-hint, .ac-note{ position:relative; background:linear-gradient(180deg,#f2fafb,#e8f4f5); border:1px solid #d4e8ea; border-radius:12px;
  box-shadow:0 6px 16px rgba(9,60,66,.07), inset 0 1px 0 rgba(255,255,255,.8); padding-left:17px; }
.ac-hint::before, .ac-note::before{ content:""; position:absolute; left:0; top:8px; bottom:8px; width:4px; border-radius:0 4px 4px 0;
  background:linear-gradient(180deg,#16a9b5,#0a5e66); box-shadow:1px 0 4px rgba(14,124,134,.40); }
.ac-note code{ box-shadow:inset 0 1px 2px rgba(9,60,66,.12); }

/* Input & select — cekung, fokus menyala */
.ac-fld input[type=text], .ac-fld select, input.ac-rpw{
  background:linear-gradient(180deg,#f7fbfb,#ffffff);
  box-shadow:inset 0 2px 4px rgba(9,60,66,.09), inset 0 -1px 0 rgba(255,255,255,.7); transition:box-shadow .15s, border-color .15s; }
.ac-fld input[type=text]:focus, .ac-fld select:focus, input.ac-rpw:focus{
  border-color:#0E7C86; box-shadow:inset 0 2px 4px rgba(9,60,66,.06), 0 0 0 3px rgba(14,124,134,.16), 0 5px 14px rgba(14,124,134,.15); }

/* Grid modul & kartu grup */
.ac-capgroups{ background:linear-gradient(180deg,#f2f9f9,#ecf4f5); box-shadow:inset 0 1px 3px rgba(9,60,66,.07); }
.ac-capgrp{ background:linear-gradient(180deg,#ffffff,#f6fbfb); }
.ac-capgrp-h{ background:linear-gradient(180deg,#eef6f7,#e1eff0); box-shadow:inset 0 1px 0 rgba(255,255,255,.75), 0 1px 0 rgba(9,60,66,.05); }
.ac-chk input{ width:17px; height:17px; border-radius:5px; }

/* Ringkasan chip 3D */
.ac-sum-chip{ background:linear-gradient(180deg,#f2f8f8,#e5f0f1); box-shadow:0 4px 10px rgba(9,60,66,.09), inset 0 1px 0 rgba(255,255,255,.8);
  transition:transform .15s, box-shadow .15s; }
.ac-sum-chip:hover{ transform:translateY(-1px); box-shadow:0 8px 17px rgba(9,60,66,.13); }
.ac-sum-chip.user{ background:linear-gradient(180deg,#e7f1ff,#d5e6fb); }
.ac-sum-chip.admin{ background:linear-gradient(180deg,#ece7ff,#ded5fb); }
.ac-sum-chip.dummy{ background:linear-gradient(180deg,#eef4f5,#dfe9eb); }

/* Panel "Sedang Aktif" + baris live */
.ac-active-wrap{ background:linear-gradient(180deg,#ffffff,#f4faf9); border:1px solid #e3eeee; border-radius:14px; padding:14px 16px 16px;
  box-shadow:0 9px 22px rgba(9,60,66,.07), inset 0 1px 0 rgba(255,255,255,.9); }
.ac-live-ic{ box-shadow:0 0 0 3px rgba(47,163,107,.18), 0 2px 5px rgba(31,125,84,.38); }
.ac-live{ background:linear-gradient(180deg,#ffffff,#f2f9f8); box-shadow:0 4px 11px rgba(9,60,66,.07), inset 0 1px 0 rgba(255,255,255,.9);
  transition:transform .15s, box-shadow .15s; }
.ac-live:hover{ transform:translateY(-1px); box-shadow:0 8px 18px rgba(9,60,66,.12); }
.ac-live.me{ background:linear-gradient(180deg,#eafaf2,#ddf5e9); box-shadow:0 6px 15px rgba(31,125,84,.13), inset 0 1px 0 rgba(255,255,255,.9); }
.ac-live .ac-pill{ box-shadow:0 2px 5px rgba(9,60,66,.12), inset 0 1px 0 rgba(255,255,255,.55); }
.ac-live-you{ box-shadow:0 2px 6px rgba(31,125,84,.24), inset 0 1px 0 rgba(255,255,255,.55); }
.ac-dot{ box-shadow:0 0 0 3px rgba(47,163,107,.18), 0 1px 3px rgba(31,125,84,.4); }

/* Judul seksi dengan penanda 3D (kecuali yang sudah punya titik "Sedang Aktif") */
.ac-sec-title{ display:flex; align-items:center; gap:10px; }
.ac-sec-title::before{ content:""; width:7px; height:17px; border-radius:4px; flex:none;
  background:linear-gradient(180deg,#16a9b5,#0a5e66); box-shadow:0 2px 5px rgba(14,124,134,.35), inset 0 1px 0 rgba(255,255,255,.4); }
.ac-active-wrap .ac-sec-title::before{ display:none; }

/* Kondisi kosong & tabel daftar akun */
.ac-empty{ background:linear-gradient(180deg,#fbfdfd,#f3f8f9); border:1px dashed #d7e3e5; border-radius:12px;
  box-shadow:inset 0 1px 3px rgba(9,60,66,.05); }
/* Kepala tabel Akun & Kontrol memakai teal pekat agar seragam dengan tabel
   data utama. Gradien terang yang dulu di sini SENGAJA tidak dipulihkan —
   ia datang belakangan di berkas ini dan menimpa aturan di atas, sehingga
   huruf putihnya jatuh di atas latar hampir putih dan judul kolom nyaris
   tidak terbaca. Yang tersisa hanya bayangan tipis di tepi bawahnya. */
table.ac-list thead th{ box-shadow:inset 0 -2px 0 rgba(0,0,0,.10); }
.ac-pill{ box-shadow:0 2px 5px rgba(9,60,66,.10), inset 0 1px 0 rgba(255,255,255,.55); }
.ac-mini{ background:linear-gradient(180deg,#ffffff,#f1f6f6); box-shadow:0 2px 6px rgba(9,60,66,.09), inset 0 1px 0 rgba(255,255,255,.8);
  transition:transform .15s, box-shadow .15s; }
.ac-mini:hover{ transform:translateY(-1px); box-shadow:0 6px 13px rgba(9,60,66,.15); }
.ac-mini.danger{ background:linear-gradient(180deg,#fff5f4,#fdeceb); }

/* Blok SQL sedikit terangkat */
.ac-sql pre{ box-shadow:0 8px 20px rgba(9,40,44,.28), inset 0 1px 0 rgba(255,255,255,.06); }

/* Judul grup matriks: maksimal 2 baris (kolom aksi tunggal dilebarkan) */
.ac-matrix-grp thead th.ac-grp-th{ font-size:.66rem; line-height:1.16; padding:7px 8px; word-break:normal; hyphens:none; }
.ac-matrix-grp th.ac-act-access, .ac-matrix-grp td.ac-act-access{ min-width:142px; }

/* ============================================================================
   Sorot pekerjaan pada tabel Penetapan Nomor — hindari salah salin No. Dokumen
   Saat kursor menunjuk satu pekerjaan, SELURUH selnya menyala oranye elegan.
   ============================================================================ */
#pn-lihat-body tr{ transition:background .12s ease; }
#pn-lihat-body tr:hover td,
#pn-lihat-body tr:hover td:first-child,
#pn-lihat-body tr:hover td.col-nama-freeze,
#pn-lihat-body tr:hover td.col-no{
  background:linear-gradient(180deg,#fff5e6,#ffe7c4) !important;
  color:#5a3d00;
}
#pn-lihat-body tr:hover td{ box-shadow:inset 0 -1px 0 rgba(201,118,26,.22); }
#pn-lihat-body tr:hover td:first-child{ box-shadow:inset 5px 0 0 #e08a1e, inset 0 -1px 0 rgba(201,118,26,.22); }
#pn-lihat-body tr:hover .pn-nomor-val{ color:#4a3200; }
#pn-lihat-body tr:hover .pn-nomor-jenis{ color:#9a5a12; }
#pn-lihat-body tr:hover .pn-tgl-val{ color:#6b4a10; }
#pn-lihat-body tr:hover .pn-copy{ border-color:#e6b678; color:#a9670f; background:#fff8ee; }
#pn-lihat-body tr:hover .pn-copy:hover{ background:#ffedd4; border-color:#d99a3c; }

/* ============================================================================
   Dialog Profil — 3D + tombol Unggah (kanan atas) & Unduh (per item)
   ============================================================================ */
.pnw-profil-modal{ position:relative; max-width:480px;
  background:linear-gradient(180deg,#ffffff,#f5fafb);
  box-shadow:0 28px 74px rgba(9,60,66,.42), inset 0 1px 0 rgba(255,255,255,.9); }
.pnw-profil-head{ padding-right:150px; min-height:36px; }
.pnw-profil-head svg{ filter:drop-shadow(0 2px 3px rgba(14,124,134,.3)); }

/* Tombol Unggah Profil (kanan atas) */
.pnw-profil-upload{ position:absolute; top:20px; right:20px; display:inline-flex; align-items:center; gap:7px;
  padding:8px 13px; font-size:11.5px; font-weight:800; color:#fff; border:0; border-radius:10px; cursor:pointer;
  background:linear-gradient(180deg,#37b27e,#1c7a51);
  box-shadow:0 6px 14px rgba(31,125,84,.34), inset 0 1px 0 rgba(255,255,255,.38); transition:transform .15s, box-shadow .15s; }
.pnw-profil-upload:hover{ transform:translateY(-1px); box-shadow:0 10px 20px rgba(31,125,84,.44), inset 0 1px 0 rgba(255,255,255,.38); }
.pnw-profil-upload:active{ transform:translateY(0); }
.pnw-profil-upload svg{ width:15px; height:15px; }

/* Item 3D + izinkan tombol turun ke bawah bila sempit */
.pnw-profil-item{ flex-wrap:wrap; background:linear-gradient(180deg,#ffffff,#f3f9fa);
  box-shadow:0 4px 12px rgba(9,60,66,.07), inset 0 1px 0 rgba(255,255,255,.9);
  transition:transform .15s, box-shadow .15s, border-color .15s; }
.pnw-profil-item:hover{ transform:translateY(-1px); box-shadow:0 9px 20px rgba(9,60,66,.13); border-color:#cfe6e6; }
.pnw-profil-item-info{ flex:1 1 150px; min-width:0; }
.pnw-profil-item-btns{ flex-wrap:wrap; justify-content:flex-end; }
.pnw-profil-mini{ box-shadow:0 3px 8px rgba(9,60,66,.14), inset 0 1px 0 rgba(255,255,255,.28); }
.pnw-profil-mini:active{ transform:translateY(1px); }
.pnw-profil-mini.pnw-mini-dl{ display:inline-flex; align-items:center; gap:5px; color:#0a5e66; }
.pnw-profil-mini.pnw-mini-dl svg{ width:13px; height:13px; }
.pnw-profil-mini.pnw-mini-dl:hover{ border-color:#0E7C86; color:#0E7C86; }
@media (max-width:520px){ .pnw-profil-head{ padding-right:120px; } .pnw-profil-upload span{ display:none; } .pnw-profil-upload{ padding:8px; } }

/* ============================================================================
   Tombol aksi profil sebagai IKON elegan (Muat / Hapus / Unduh / Unggah)
   ============================================================================ */
/* KEPALA DIALOG TIDAK LAGI MENYEDIAKAN RUANG UNTUK TOMBOL UNGGAH (9 Agu 2026):
   tombolnya sudah turun ke baris tindakan. Ruang kanan sekarang hanya dipakai
   tombol tutup (x) pada dialog Muat Profil, yang jauh lebih ramping. */
/* Ruang kanan kepala dialog: menampung tombol ikon Unggah Profil yang kembali
   ke pojok kanan atas (10 Agu 2026), dan tombol tutup (x) pada dialog Muat. */
.pnw-profil-head{ padding-right:96px !important; }
.pnw-profil-upload.pf-ic-up{ top:18px; right:20px; width:46px; height:46px; padding:0; gap:0; border-radius:14px; justify-content:center; }
.pnw-profil-upload.pf-ic-up svg{ width:20px; height:20px; }

.pnw-profil-item-btns{ gap:8px; }
.pf-ic{ width:42px; height:42px; flex:none; border-radius:12px; display:inline-flex; align-items:center; justify-content:center;
  border:1px solid #dbe6e7; background:linear-gradient(180deg,#ffffff,#f1f7f8); color:#3a5257; cursor:pointer;
  box-shadow:0 3px 8px rgba(9,60,66,.10), inset 0 1px 0 rgba(255,255,255,.85);
  transition:transform .14s ease, box-shadow .14s ease, background .14s ease, border-color .14s ease, color .14s ease; }
.pf-ic svg{ width:19px; height:19px; }
.pf-ic:hover{ transform:translateY(-2px); box-shadow:0 9px 18px rgba(9,60,66,.16); }
.pf-ic:active{ transform:translateY(0); box-shadow:0 2px 6px rgba(9,60,66,.14); }
/* Muat = utama (teal terisi) */
.pf-ic-load{ background:linear-gradient(180deg,#17959f,#0a5e66); border-color:#0a5e66; color:#fff;
  box-shadow:0 5px 13px rgba(14,124,134,.34), inset 0 1px 0 rgba(255,255,255,.38); }
.pf-ic-load:hover{ box-shadow:0 10px 20px rgba(14,124,134,.46), inset 0 1px 0 rgba(255,255,255,.38); }
/* Hapus = merah lembut */
.pf-ic-del{ color:#c0392b; }
.pf-ic-del:hover{ background:linear-gradient(180deg,#fff5f4,#fdece9); border-color:#f0c2bd; color:#b0301f; }
/* Unduh = teal outline */
.pf-ic-dl{ color:#0a5e66; }
.pf-ic-dl:hover{ background:linear-gradient(180deg,#edf7f8,#e2f0f1); border-color:#bfe0e2; color:#0E7C86; }

/* Penyesuaian: ikon aksi profil lebih kecil + ikon Unggah lebih tegas */
.pnw-profil-item-btns{ gap:7px; }
.pf-ic{ width:34px; height:34px; border-radius:10px; }
.pf-ic svg{ width:16px; height:16px; }
.pnw-profil-head{ padding-right:60px !important; }
.pnw-profil-upload.pf-ic-up{ width:40px; height:40px; border-radius:12px; top:18px; right:20px; }
.pnw-profil-upload.pf-ic-up svg{ width:19px; height:19px; }
.pnw-profil-upload.pf-ic-up svg *{ stroke-width:2.4; }
.pnw-profil-upload.pf-ic-up svg{ filter:drop-shadow(0 1px 2px rgba(0,0,0,.35)); }

/* Tombol Unggah = gaya sama dengan Unduh (putih, ikon teal), hanya beda ikon */
.pnw-profil-upload.pf-ic-up{
  top:19px; right:20px; width:38px; height:38px; border-radius:11px; padding:0; gap:0;
  background:linear-gradient(180deg,#ffffff,#f1f7f8);
  border:1px solid #dbe6e7; color:#0a5e66;
  box-shadow:0 3px 8px rgba(9,60,66,.10), inset 0 1px 0 rgba(255,255,255,.85);
}
.pnw-profil-upload.pf-ic-up:hover{
  transform:translateY(-2px);
  background:linear-gradient(180deg,#edf7f8,#e2f0f1);
  border-color:#bfe0e2; color:#0E7C86;
  box-shadow:0 9px 18px rgba(9,60,66,.16);
}
.pnw-profil-upload.pf-ic-up svg{ width:18px; height:18px; filter:none; }
.pnw-profil-upload.pf-ic-up svg *{ stroke-width:2; }

/* ============================================================================
   Logo PLN (brand): hilangkan efek KACA (shine/glass) & gerakan hover
   ============================================================================ */
.topbar-brand .logo{ background:transparent !important; box-shadow:none !important; transition:none !important; }
.topbar-brand .logo::after{ content:none !important; display:none !important; }
.topbar-brand:hover .logo{ transform:none !important; box-shadow:none !important; }
.topbar-brand:hover .logo .logo-img{ transform:none !important; filter:drop-shadow(0 1px 2px rgba(0,0,0,.3)) !important; }

/* =========================================================================
   TRACKING PENGADAAN — gaya elegan 3D (khusus halaman Tracking, prefix trk-)
   ========================================================================= */
.trk-scene{background:#ffffff;border:1px solid #ececec;border-radius:18px;padding:22px;box-shadow:0 10px 30px rgba(0,0,0,.05),0 2px 6px rgba(0,0,0,.03)}
.trk-scene *{box-sizing:border-box}
.trk-toolbar{margin-bottom:16px}
/* ---- KOTAK PILIH PEKERJAAN: LEBARNYA TIDAK BOLEH DITENTUKAN ISINYA ----
   Di Safari iPad, <select> ber-tampilan bawaan kadang menyusut mengikuti lebar
   teks pilihannya, bukan lebar wadahnya — meski sudah diberi width:100%.
   Pemicunya sizing "shrink-to-fit" pada kontrol native: selama elemennya masih
   inline-block, lebar isi ikut diperhitungkan.

   Tiga penegasan di bawah menutup jalan itu tanpa mengubah tampilan sama
   sekali (panah bawaan tetap dipakai, sama seperti seluruh dropdown lain di
   aplikasi ini):
     display:block      -> keluar dari perhitungan lebar-isi inline
     min-width:0        -> membatalkan lebar minimum bawaan kontrol
     max-width:100%     -> nama pekerjaan yang panjang tidak melebarkan kotak
     box-sizing         -> padding tidak menambah lebar (ditegaskan ulang di
                           sini; .trk-scene * sudah menyetelnya, tetapi aturan
                           ini harus tetap benar bila kotaknya dipindah)   */
.trk-pickbox{width:100%;min-width:0;display:block}
.trk-label{display:block;font-size:12.5px;color:#555;margin:0 0 6px;font-weight:600}
.trk-label-sub{font-weight:400;color:#999}
.trk-select{display:block;width:100%;min-width:0;max-width:100%;box-sizing:border-box;height:42px;border:1px solid #dcdedd;border-radius:12px;background:#ffffff;color:#222;font-size:14px;padding:0 12px;box-shadow:0 3px 8px rgba(0,0,0,.06),inset 0 1px 0 #fff;outline:none;appearance:auto;cursor:pointer}
.trk-select:focus{border-color:#18b394;box-shadow:0 0 0 3px rgba(24,179,148,.10),0 3px 8px rgba(0,0,0,.06)}
.trk-card{background:#ffffff;border:1px solid #eceded;border-radius:16px;box-shadow:0 10px 24px rgba(0,0,0,.07),0 2px 6px rgba(0,0,0,.04),inset 0 1px 0 #fff;padding:18px 20px;margin-bottom:16px}
.trk-card-t{margin:0 0 12px;font-size:14.5px;font-weight:700;color:#222}
.trk-card-s{font-weight:400;font-size:12px;color:#6b706f}
.trk-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:38px 20px;color:#6b706f;font-size:13.5px;text-align:center}
.trk-empty svg{width:44px;height:44px;color:#0f9d80;opacity:.75}
.trk-empty p{margin:0}
.trk-localnote{margin:10px 0 0;font-size:11.5px;color:#9a9e9d;font-style:italic}
.trk-hint{margin:10px 0 0;font-size:12.5px;color:#6b706f;line-height:1.55}
.trk-hint b{color:#333;font-weight:600}
/* ---- kepala kartu + badge status otomatis ---- */
.trk-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;padding-bottom:14px;border-bottom:1px solid #e7f0ee;margin-bottom:14px}
.trk-head-nama{margin:0;font-size:15.5px;font-weight:700;color:#222}
.trk-head-meta{margin:2px 0 0;font-size:12.5px;color:#6b706f}
.trk-pill{display:inline-block;font-size:12px;font-weight:700;padding:5px 14px;border-radius:99px;white-space:nowrap;box-shadow:0 2px 5px rgba(0,0,0,.08),inset 0 1px 0 rgba(255,255,255,.6)}
.trk-pill-proses{background:#e0eefa;color:#155e9c}
.trk-pill-kontrak{background:#e0f3ea;color:#0c6b52}
.trk-pill-gagal{background:#fbe7e3;color:#b02f22}
.trk-admin-badge{font-size:11px;background:#14a186;color:#fff;border-radius:99px;padding:3px 10px;vertical-align:3px;box-shadow:0 2px 5px rgba(0,0,0,.14)}
/* ---- timeline ---- */
.trk-timeline{padding-top:2px}
.trk-item{display:flex;gap:14px}
.trk-railcol{width:26px;display:flex;flex-direction:column;align-items:center;flex:none}
.trk-dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex:none}
.trk-dot svg{width:13px;height:13px}
.trk-rail{flex:1;width:3px;border-radius:2px;background:#e4e6e6;box-shadow:inset 0 1px 2px rgba(0,0,0,.08);min-height:14px}
.trk-body{flex:1;min-width:0;padding-bottom:18px}
.trk-item:last-child .trk-body{padding-bottom:2px}
.trk-nm{margin:2px 0 0;font-size:14px;font-weight:600;color:#222}
.trk-sub{margin:2px 0 0;font-size:12px;color:#6b706f}
.trk-done .trk-dot{background:#14a186;color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.14),inset 0 1px 1px rgba(255,255,255,.35)}
.trk-now  .trk-dot{background:#1d7fce;color:#fff;box-shadow:0 0 0 4px rgba(24,115,196,.12),0 3px 6px rgba(0,0,0,.14),inset 0 1px 1px rgba(255,255,255,.35)}
.trk-now  .trk-nm{color:#155e9c}
.trk-wait .trk-dot{background:#f2f3f3;box-shadow:inset 0 1px 2px rgba(0,0,0,.06),0 1px 0 #fff;border:2px solid #dcdedd}
.trk-wait .trk-nm{color:#9a9e9d;font-weight:500}
.trk-wait .trk-sub{color:#a8acab}

.trk-fail .trk-dot{background:#d3483a;color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.14),inset 0 1px 1px rgba(255,255,255,.35)}
.trk-fail .trk-nm{color:#b02f22}
.trk-redo .trk-dot{background:#e39b23;color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.14),inset 0 1px 1px rgba(255,255,255,.35)}
.trk-redo .trk-nm{color:#8a5a0a}
/* Jaring pengaman: bila app-lain.js versi LAMA masih tersimpan di cache
   peramban, ia tetap mencetak <div class="trk-ket"><svg>…. Tanpa batas ukuran,
   ikon balon obrolan itu membesar selebar kartu (lingkaran hitam raksasa).
   Aturan ini menjaganya tetap kecil sampai berkas barunya termuat. */
.trk-ket{margin-top:6px;font-size:12.5px;font-style:italic;color:#5a5f5e;display:flex;gap:7px;align-items:flex-start;line-height:1.5}
.trk-ket svg{width:15px;height:15px;flex:0 0 auto;margin-top:2px;color:#0f9d80}
.trk-ket-empty{display:none}
/* ---- keterangan tahapan: teks miring biasa di bawah jadwal (tanpa kotak) ---- */
.trk-note{margin:3px 0 0;font-size:12.5px;font-style:italic;color:#5a5f5e;line-height:1.5}
.trk-wait .trk-note{color:#a8acab}
.trk-fail .trk-note{color:#b0453a}
/* ---- chip penyedia ---- */
.trk-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;align-items:center}
.trk-chip{display:inline-flex;align-items:center;gap:5px;background:#ffffff;border:1px solid #dcdedd;border-radius:99px;padding:3px 10px;font-size:12px;color:#444;box-shadow:0 2px 4px rgba(0,0,0,.06),inset 0 1px 0 #fff}
.trk-chip svg{width:13px;height:13px}
.trk-chip-count{background:#f2f3f3;font-weight:600}
.trk-chip-x{border:none;background:none;color:#b02f22;font-size:14px;line-height:1;cursor:pointer;padding:0 0 0 2px}
/* ---- form admin ---- */
.trk-adm-grid{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(0,1fr);gap:12px;align-items:start}
.trk-adm-stat{display:flex;flex-direction:column;align-items:flex-start;gap:2px}
.trk-adm-stat .trk-pill{margin-top:4px}
.trk-in{width:100%;height:38px;border:1px solid #dcdedd;border-radius:10px;background:#ffffff;color:#222;font-size:13px;padding:0 10px;box-shadow:inset 0 1px 3px rgba(0,0,0,.06);outline:none;margin-top:8px}
.trk-in:focus{border-color:#18b394;box-shadow:0 0 0 3px rgba(24,179,148,.10),inset 0 1px 3px rgba(0,0,0,.06)}
.trk-in:disabled{opacity:.5;cursor:not-allowed}
.trk-alab{display:block;font-size:12px;color:#555;margin:10px 0 0;font-weight:600}
.trk-arow{border:1px solid #eceded;border-radius:12px;padding:10px 12px;margin-bottom:10px;background:#ffffff;box-shadow:0 3px 8px rgba(0,0,0,.05),inset 0 1px 0 #fff}
.trk-arow-on{border-color:#8fd0f0;box-shadow:0 0 0 3px rgba(24,115,196,.08),0 3px 8px rgba(0,0,0,.05)}
.trk-arow-top{display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap}
.trk-arow-t{margin:0;font-size:13px;font-weight:600;color:#222}
.trk-arow-src{font-size:11px;color:#9a9e9d;font-weight:400}
.trk-radio{font-size:12.5px;color:#555;display:flex;gap:6px;align-items:center;white-space:nowrap;cursor:pointer}
.trk-radio input{accent-color:#1873c4;cursor:pointer}
.trk-arow-on .trk-radio{color:#155e9c;font-weight:600}
.trk-pv-add{display:flex;gap:8px;margin-top:8px;align-items:flex-end}
.trk-pv-add .trk-in,.trk-pv-add .trk-select{margin-top:0;flex:1}
.trk-btn{height:38px;border:none;border-radius:10px;padding:0 16px;font-size:13px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:7px;box-shadow:0 4px 10px rgba(0,0,0,.14),inset 0 1px 0 rgba(255,255,255,.35);white-space:nowrap;transition:transform .12s ease,filter .12s ease,box-shadow .12s ease}
.trk-btn:hover{filter:brightness(1.05)}
.trk-btn:active{transform:translateY(1px) scale(.99);box-shadow:0 2px 5px rgba(0,0,0,.14),inset 0 1px 0 rgba(255,255,255,.35)}
.trk-btn svg{width:15px;height:15px}
.trk-btn-teal{background:#14a186;color:#fff}
.trk-btn-amber{background:#e39b23;color:#fff}
.trk-btn-ghost{background:#ffffff;color:#444;border:1px solid #dcdedd;box-shadow:0 3px 8px rgba(0,0,0,.08),inset 0 1px 0 #fff}
.trk-gcard{border:1px solid #f2d6d2;opacity:.55;transition:opacity .2s ease}
.trk-gcard-on{opacity:1;box-shadow:0 10px 24px rgba(201,58,44,.08),0 2px 6px rgba(0,0,0,.04),inset 0 1px 0 #fff}
.trk-gtop{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:6px}
.trk-gt{margin:0;color:#b02f22;display:flex;align-items:center;gap:7px}
.trk-gt svg{width:16px;height:16px}
.trk-gcard .trk-radio input{accent-color:#c93a2c}
.trk-ulang{margin-top:12px;border-top:1px dashed #f2d6d2;padding-top:4px}
.trk-hist{margin:6px 0 0;font-size:12.5px;color:#8a5a5a;background:#fdf6f5;border:1px solid #f2ddd9;border-radius:9px;padding:7px 10px}
.trk-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}
@media (max-width:720px){
  .trk-scene{padding:14px;border-radius:14px}
  .trk-adm-grid{grid-template-columns:1fr}
  .trk-head{flex-direction:column}
  .trk-actions{flex-direction:column-reverse}
  .trk-actions .trk-btn{justify-content:center}
  .trk-pv-add{flex-direction:column;align-items:stretch}
}
/* Tracking: grid keterangan + tanggal selesai (realisasi) per tahap */
.trk-arow-grid{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(0,.9fr);gap:10px;align-items:start}
.trk-tgl-note{margin:4px 0 0;font-size:10.5px;color:#9a9e9d;line-height:1.4}
@media (max-width:720px){ .trk-arow-grid{grid-template-columns:1fr} }
/* Tracking: chip status otomatis pada baris admin (pengganti radio Tahap Berjalan) */
.trk-stchip{font-size:11.5px;font-weight:700;padding:3px 11px;border-radius:99px;white-space:nowrap;box-shadow:0 2px 4px rgba(0,0,0,.07),inset 0 1px 0 rgba(255,255,255,.6)}
.trk-stchip-done{background:#e0f3ea;color:#0c6b52}
.trk-stchip-now{background:#e0eefa;color:#155e9c}
.trk-stchip-wait{background:#efefef;color:#8b8f8e}
/* Tracking: pasangan tanggal + jam untuk tahap manual */
.trk-tj{display:flex;gap:6px}
.trk-tj .trk-in{margin-top:8px}
.trk-in-jam{max-width:104px;flex:none}

/* =================================================================
   Samakan gaya tabel "Hasil Analisa Harga Satuan" (tabel 1)
   dengan tabel Lampiran / Susun Kontrak (tabel 2, .spk-lamp-tbl):
   kartu membulat + bayangan halus, grid penuh (garis horizontal &
   vertikal), zebra & padding seragam, serta efek hover baris.
   Ditaruh paling akhir agar menang atas aturan .ana-res sebelumnya.
   ================================================================= */
.ana-res-card{
  border:1px solid #dde9eb;
  border-radius:14px;
  overflow:hidden;
  box-shadow:0 2px 8px rgba(16,40,50,.05);
}
.ana-res-wrap{ overflow-x:auto; }
table.ana-res{ border-collapse:separate; border-spacing:0; }
/* Grid penuh horizontal + vertikal (sama seperti tabel Lampiran) */
table.ana-res th, table.ana-res td{ border:1px solid #dce6e9; }
/* Header teal rata + garis pemisah kolom senada */
table.ana-res thead th{
  background:#0E7C86; color:#fff; border-color:#0b6b74;
  font-size:10.5px; padding:9px 8px;
}
/* Padding baris & zebra seragam dengan tabel Lampiran */
table.ana-res tbody td{ padding:8px 9px; }
table.ana-res tbody tr:nth-child(even) td{ background:#f6fafb; }
table.ana-res tbody tr:hover td{ background:#f2fafb; }
/* Buang garis paling luar agar rapi mengikuti sudut membulat kartu */
table.ana-res thead th{ border-top:none; }
table.ana-res tr>*:first-child{ border-left:none; }
table.ana-res tr>*:last-child{ border-right:none; }
table.ana-res tbody tr:last-child td{ border-bottom:none; }

/* =================================================================
   SAKELAR (SWITCH) YA / TIDAK
   Pengganti dropdown "Ya/Tidak". Sakelar diletakkan di sebelah KANAN
   judul (label) field; ON = Ya, OFF = Tidak. Di bawah judul tetap ada
   kotak yang menampilkan nilai terpilih (atau kontrol pendamping,
   mis. gaya penomoran / kotak angka) supaya tinggi field tidak berubah
   dan sejajar dengan field lain di barisnya.
   ================================================================= */
.lbl-switch{display:flex;align-items:center;justify-content:space-between;
  gap:10px;width:100%;min-height:16px}
.lbl-switch>label{flex:1 1 auto;min-width:0}

button.js-switch{
  flex:0 0 auto;position:relative;display:inline-block;
  width:38px;height:20px;padding:0;border:0;border-radius:999px;
  /* PERBAIKAN LANJUTAN (11 Agu 2026) - RUPA DISAMAKAN DENGAN .tor-sw MILIK
     PENYUSUNAN DOKUMEN PENGADAAN, satu-satunya sakelar yang tidak pernah
     bergetar. Dua hal dibuang:

       1. box-shadow: inset 0 1px 3px  -> BAYANGAN DALAM. Pada rel setinggi
          20px, bayangan 3px menutupi hampir sepertiga tingginya; setiap
          penggambaran ulang (dan sakelar ini memang menggambar ulang formnya
          lewat applyLocks*) memaksa peramban menyusun ulang lapisan itu.
       2. linear-gradient pada keadaan ON (lihat .is-on di bawah) -> GRADASI
          TIDAK BISA DIINTERPOLASI. transition:background .24s ease karena itu
          tidak menganimasikan apa pun; ia MELOMPAT di tengah durasi, dan
          lompatan itulah yang terbaca sebagai getaran saat diklik.

     Sekarang: warna rata, tanpa bayangan, tanpa lingkar. Persis .tor-sw. */
  background:#CBD5E1;
  cursor:pointer;outline:none;overflow:visible;-webkit-appearance:none;appearance:none;
  -webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none;
  /* PERBAIKAN 5 Agu 2026 — sakelar hanya berpindah saat DIKLIK.
     'filter' dikeluarkan dari daftar transisi karena efek :hover yang dulu
     memakainya sudah dibuang (lihat catatan di bawah). */
  /* LANJUTAN PERBAIKAN (9 Agu 2026): 'box-shadow' IKUT DIKELUARKAN dari daftar
     transisi. Tambalan 5 Agu sudah membuang :hover filter & :active knob, tapi
     lingkar :hover di bawah masih dianimasikan 0,24 detik. Rel sakelar hanya
     38x20px - di ukuran sekecil itu gerak halus kursor di tepinya membuat
     :hover menyala-padam berkali-kali, dan tiap kali animasi 0,24 detik itu
     mulai dari awal tanpa pernah selesai. Yang terlihat: sakelar berkedip
     cepat seolah berpindah sendiri padahal nilainya tidak berubah.
     Kini hanya 'background' yang beranimasi, dan background hanya berubah oleh
     kelas .is-on - yang cuma dipasang jsSwitchToggle() saat benar-benar diklik. */
  transition:background .24s ease;
}
button.js-switch>.sw-knob{
  position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;
  background:#fff;box-shadow:0 1px 2px rgba(16,24,40,.25);
  /* LAPIS KEDUA (11 Agu 2026): knop tidak menerima peristiwa tetikus sama
     sekali. Dua akibatnya, keduanya dikehendaki:
       1. `:hover` TIDAK PERNAH cocok pada knop, jadi aturan menyeluruh apa pun
          yang memakai `*:hover` (blok 31) tak dapat menyentuhnya lagi.
       2. Klik di atas knop langsung menjadi klik pada <button> induknya -
          seluruh permukaan sakelar dapat diklik tanpa titik mati. */
  pointer-events:none;
  /* Lekukan pegas (.16,1,.3,1) diganti easing lurus: pada jarak 18px yang
     sependek ini, ujung lengkung yang melambat panjang terbaca sebagai knop
     bergeser dua kali. Durasi juga dipendekkan menyamai .tor-sw.

     AKAR MASALAH "KNOP MENGIKUTI KURSOR" (11 Agu 2026) - knop DIGESER DENGAN
     `left`, JANGAN `transform`. Blok 31 di bawah memasang aturan menyeluruh
     `.view ... *:hover{transform:none!important}` (untuk mematikan efek 3D).
     `.sw-knob` adalah <span> SUNGGUHAN sehingga ikut terpilih `*:hover`:
     begitu kursor menyentuh knop, translateX dibatalkan -> knop melompat ke
     kiri; kursor bergeser sedikit keluar knop -> transform hidup lagi -> knop
     melompat ke kanan. Dengan transisi .18s, itu terlihat persis seperti knop
     mengikuti gerak kursor padahal nilai sakelarnya tidak pernah berubah.
     `left` tidak disentuh aturan mana pun di blok 31.
     ATURAN TETAP: knop sakelar apa pun di berkas ini memakai left/right. */
  transition:left .18s ease;
}
button.js-switch.is-on{ background:var(--teal); }
/* 20px = lebar rel 38 - lebar knop 16 - tepi kiri 2 */
button.js-switch.is-on>.sw-knob{left:20px}
/* ---- SAKELAR TIDAK BOLEH "BERGERAK SENDIRI" (5 Agu 2026) ----
   Dua aturan lama dibuang karena keduanya MENGUBAH RUPA SAKELAR HANYA KARENA
   TERSENTUH/DITEKAN KURSOR, sehingga tampak seperti berpindah posisi padahal
   nilainya tidak berubah:

     button.js-switch:hover{filter:brightness(1.05)}
        -> mencerahkan seluruh rel. Pada keadaan ON (rel bergradasi teal->cyan)
           kecerahannya bergeser cukup jauh sehingga terbaca seperti ganti
           keadaan. Karena :hover menyala-padam mengikuti gerak halus kursor di
           tepi tombol, kesannya sakelar berkedip cepat selama kursor diam di
           atasnya.

     button.js-switch:active>.sw-knob{width:19px}
        -> knop MELEBAR 16px->19px selama tombol tetek. Knop diposisikan
           absolut dari kiri (left:2px + translateX(18px) saat ON), jadi
           penambahan lebar mendorong tepi kanannya keluar — terlihat persis
           seperti knop bergeser.

   Penggantinya: penanda fokus/sentuh yang TIDAK menggeser apa pun dan tidak
   menyentuh warna rel — hanya lingkar tipis di luar tombol. Dengan begitu satu-
   satunya hal yang memindahkan knop adalah kelas .is-on, dan .is-on hanya
   dipasang oleh jsSwitchToggle() saat tombol benar-benar diklik. */
/* LINGKAR :hover DIBUANG (9 Agu 2026). Pada keadaan OFF ia MEMUNCULKAN lingkar
   3px yang tadinya tidak ada, pada keadaan ON ia menaikkan pekatnya .13 -> .22.
   Dua-duanya mengubah rupa sakelar hanya karena tersentuh kursor - persis yang
   sudah dinyatakan tidak boleh terjadi di catatan 5 Agu, hanya lewat properti
   yang berbeda. Penanda arah kursor cukup diserahkan ke cursor:pointer.
   :focus-visible DIPERTAHANKAN: ia hanya menyala saat berpindah lewat papan
   ketik (Tab), bukan saat kursor lewat, jadi tidak pernah berkedip. */
button.js-switch:focus-visible{box-shadow:0 0 0 3px rgba(14,124,134,.30)}
button.js-switch[data-locked="1"]{opacity:.55;cursor:not-allowed}
button.js-switch:disabled{opacity:.55;cursor:not-allowed;filter:none}

/* [DIHAPUS 11 Agu 2026] seluruh aturan sakelar KHUSUS form Monitoring:
   aturan ber-awalan #view-input untuk .field.is-switch .sw-state,
   .field.locked .sw-state, .field.field-error .sw-state, dan .sw-row.
   PERINGATAN (11 Agu 2026): baris kedua catatan ini dahulu ditulis
   "#view-input" yang LANGSUNG DISUSUL tanda penutup komentar (bintang +
   garis-miring), sehingga komentarnya TERTUTUP di tengah kalimat. Sisa
   kalimatnya lalu terbaca sebagai SELEKTOR, menempel ke
   ".sw-state{" di bawahnya, sehingga SELURUH aturan .sw-state dibuang
   peramban - itulah sebabnya kotak nilai kehilangan garis luarnya saat
   sakelar OFF. JANGAN pernah mengetik tanda penutup komentar di dalam badan
   sebuah komentar - tulis kalimatnya ulang, jangan dikutip.
   Form Monitoring tidak lagi memakai .js-switch/.sw-state/.sw-row melainkan
   sakelar tersendiri .mon-sw — lihat blok "SAKELAR FORM MONITORING" di bawah.
   Aturan .lbl-switch / button.js-switch / .sw-state yang tersisa di atas &
   bawah TETAP DIPAKAI oleh Perhitungan HPS, Analisa Harga Satuan, dan Susun
   Kontrak, jadi jangan ikut dihapus. */

/* Kotak nilai — menggantikan tampilan dropdown lama */
.sw-state{
  display:flex;align-items:center;gap:7px;flex:1 1 auto;min-width:0;
  border:1px solid #cdd9de;border-radius:11px;padding:10px 12px;
  /* TINGGI DIKUNCI & TEKS TIDAK MEMBUNGKUS (11 Agu 2026).
     Inilah beda terakhir dengan .tor-sw-val di Penyusunan Dokumen Pengadaan,
     yang sejak awal memakai min-height:37px. Tanpa tinggi tetap, kotak ini
     memuai/mengempis mengikuti PANJANG LABELNYA: "Tidak Ada" lebih lebar
     daripada "Ada", dan pada Monitoring - satu-satunya form yang memakai kisi
     kolom lebar tetap (#view-input .grid-umum: 180/280/120/270px) - label
     panjang itu terpaksa membungkus ke baris kedua. Sekali membungkus,
     tinggi barisnya bertambah, seluruh field sebaris ikut diregangkan, lalu
     mengempis lagi saat sakelar dikembalikan. Gerakan naik-turun itulah yang
     terbaca sebagai getaran, dan hanya muncul di menu itu.
     box-sizing wajib: padding 10px atas-bawah sudah termasuk di dalam 40px. */
  box-sizing:border-box;min-height:40px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  /* Warna RATA, bukan gradasi (11 Agu 2026). Kotak nilai ini berpasangan dengan
     sakelar di atasnya dan ikut berubah warna saat diklik; gradasi tidak dapat
     diinterpolasi, jadi transition di bawah tidak menganimasikannya melainkan
     MELOMPAT di tengah durasi - terlihat sebagai kedipan tepat saat sakelar
     ditekan. Menyamai .tor-sw-val pada Penyusunan Dokumen Pengadaan. */
  background:#fff;
  color:#93a2aa;font-weight:700;font-size:12px;line-height:1.5;
  /* 'all' diganti daftar tegas (9 Agu 2026): dengan 'all', properti apa pun yang
     berubah - termasuk yang mempengaruhi ukuran - ikut dianimasikan, sehingga
     kotak nilai bisa tampak bergoyang mengikuti sakelarnya. */
  user-select:none;transition:background .24s ease,border-color .24s ease,color .24s ease;
}
.sw-state::before{content:"";width:7px;height:7px;border-radius:50%;
  background:#bcc8ce;flex:0 0 auto;transition:background .24s ease,box-shadow .24s ease}
.sw-state.is-on{border-color:#BCE0DA;color:var(--teal-dark);background:#EAF6F4}
.sw-state.is-on::before{background:var(--teal)}
.js-judul-row>.sw-state{flex:1 1 auto}

/* =================================================================
   SAKELAR FORM MONITORING — .mon-sw   (11 Agu 2026)
   =================================================================
   SALINAN PERSIS .tor-sw milik Penyusunan Dokumen Pengadaan (susun-dokumen.js,
   torEnsureStyle) — sakelar yang tidak pernah bereaksi terhadap gerak kursor.
   Sakelar lama form Monitoring (.js-switch[data-sw="1"] + .sw-state + .sw-row)
   sudah dihapus, bukan ditimpa.

   ATURAN YANG TIDAK BOLEH DITAMBAHKAN DI SINI, apa pun alasannya:
     - :hover / :active pada button.mon-sw maupun .mon-sw-val
       (mengubah rupa hanya karena tersentuh kursor = gejala "bergerak sendiri")
     - transition pada .mon-sw-val
       (kotak nilai ikut berubah ukuran saat labelnya berganti, dan animasi
        ukuran terbaca sebagai getaran)
     - box-shadow inset atau linear-gradient pada rel sakelar
       (gradasi tidak bisa diinterpolasi — transition-nya MELOMPAT di tengah
        durasi, dan lompatan itu terlihat seperti kedipan)
   Penanda arah kursor cukup diserahkan ke cursor:pointer; penanda papan ketik
   ke :focus-visible, yang hanya menyala saat berpindah lewat Tab. */
.field.mon-swf .mon-sw-head{display:flex;align-items:center;justify-content:space-between;
  gap:10px;width:100%;min-height:16px}
.field.mon-swf .mon-sw-head>label{flex:1 1 auto;min-width:0}
button.mon-sw{flex:0 0 auto;-webkit-appearance:none;appearance:none;position:relative;
  width:44px;height:22px;padding:0;margin:0;border:0;border-radius:999px;background:#CBD5E1;
  cursor:pointer;outline:none;-webkit-tap-highlight-color:transparent;
  user-select:none;-webkit-user-select:none;transition:background-color .18s ease}
button.mon-sw .kn{position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;
  background:#fff;box-shadow:0 1px 2px rgba(16,24,40,.25);transition:left .18s ease}
button.mon-sw.on{background:#2E8B84}
button.mon-sw.on .kn{left:25px}
button.mon-sw:disabled{opacity:.5;cursor:not-allowed}
button.mon-sw:focus-visible{box-shadow:0 0 0 3px rgba(14,124,134,.30)}

/* Kotak nilai di bawah judul — pengganti dropdown. Tinggi DIPATOK & teks tidak
   membungkus: pada kisi kolom lebar tetap milik Monitoring, label panjang
   ("Tidak Ada") dulu turun ke baris kedua, meregangkan tinggi seluruh baris,
   lalu mengempis lagi saat sakelar dikembalikan. */
.mon-sw-val{display:flex;align-items:center;gap:8px;width:100%;
  min-height:37px;padding:0 12px;box-sizing:border-box;
  border:1px solid #D9E1E7;border-radius:10px;background:#fff;
  font-size:12.5px;line-height:1.25;color:#98A2B3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  user-select:none;-webkit-user-select:none}
.mon-sw-val .dt{width:7px;height:7px;border-radius:50%;background:#C2CBD6;flex:0 0 auto}
.mon-sw-val.on{background:#EAF6F4;border-color:#BCE0DA;color:#1F5E58;font-weight:700}
.mon-sw-val.on .dt{background:#2E8B84}
/* Ikut aturan tampilan "terkunci" & "wajib diisi" seperti input/select biasa */
.field.locked .mon-sw-val{background:#f1f4f6;color:#9aa7ad;border-style:dashed}
.field.locked .mon-sw-val .dt{background:#c3ccd1}
.field.field-error .mon-sw-val{border-color:var(--red)!important;background:#fdecec}

/* Bila hanya tersisa SATU kontrol pendamping pada baris (karena dropdown
   Ya/Tidak sudah pindah ke samping judul), biarkan mengisi lebar field. */
.field > .js-judul-row > select.js-numsel:only-child,
.ana-tb-field > .js-judul-row > select.js-numsel:only-child{
  flex:1 1 auto;width:auto;min-width:58px}
.field > .js-judul-row > input.js-numbox:only-child,
.ana-tb-field > .js-judul-row > input.js-numbox:only-child{
  flex:1 1 auto;width:auto;min-width:56px}

/* =================================================================
   POP UP HASIL UNGGAH TEMPLATE
   Menampilkan rincian: berapa Data pekerjaan yang berhasil / tidak
   berhasil ditambahkan, lengkap dengan nama pekerjaannya. Bagian yang
   jumlahnya 0 tidak dirender sama sekali. Warna kepala pop up sama
   dengan nada notifikasi lama: hijau / kuning / merah.
   ================================================================= */
#imp-res-overlay{z-index:130}
.modal.imp-res-modal{max-width:640px}
.detail-head.tone-ok  {background:linear-gradient(100deg,#137a41,#25b566)}
.detail-head.tone-warn{background:linear-gradient(100deg,#a3700a,#e0a413)}
.detail-head.tone-err {background:linear-gradient(100deg,#a52727,#e04b4b)}

.imp-res-body{padding:18px 20px 22px;display:flex;flex-direction:column;gap:14px;
  max-height:min(66vh,540px);overflow:auto}
.imp-sec{border:1px solid var(--line);border-radius:14px;overflow:hidden;
  background:#fff;box-shadow:0 1px 2px rgba(16,40,50,.05)}
.imp-sec-h{display:flex;align-items:center;gap:9px;padding:11px 14px;
  font-weight:800;font-size:12.5px;line-height:1.4}
.imp-sec-h svg{width:17px;height:17px;flex:0 0 auto}
.imp-sec-h .imp-n{font-size:14px;font-weight:800}
.imp-ok  .imp-sec-h{background:#e9f7ef;color:#0f6a38;border-bottom:1px solid #cfeada}
.imp-dup .imp-sec-h{background:#fdf3e0;color:#8a5e05;border-bottom:1px solid #f2dcae}

.imp-list{list-style:none;margin:0;padding:4px 0;counter-reset:impn}
.imp-list li{position:relative;padding:9px 14px 9px 40px;font-size:12px;
  line-height:1.5;color:var(--ink);border-bottom:1px dashed #eef2f4;
  display:flex;flex-direction:column;gap:2px;word-break:break-word}
.imp-list li:last-child{border-bottom:none}
.imp-list li::before{counter-increment:impn;content:counter(impn) ".";
  position:absolute;left:14px;top:9px;width:20px;text-align:right;
  color:var(--muted);font-weight:700;font-variant-numeric:tabular-nums}
.imp-list li b{font-weight:700}
.imp-note{font-size:10.5px;font-weight:600;color:var(--muted)}
.imp-empty{padding:26px 14px;text-align:center;color:var(--muted);
  font-size:12px;font-weight:600}
@media(max-width:640px){
  .imp-res-body{padding:14px 14px 18px}
  .imp-list li{padding-left:36px}
}

/* ============================================================
   ✦ LATAR APLIKASI & KANVAS DASHBOARD
   ------------------------------------------------------------
   AKAR MASALAH “latar putih polos”: blok <style id="fkl-doc-css"> di
   index.html memuat aturan `html,body{background:#e9eef1}`. Blok itu
   WAJIB tetap inline (isinya dibaca JS untuk membangun dokumen
   Cetak/PDF), tetapi karena ia berada SETELAH style.css, aturannya
   ikut berlaku di halaman aplikasi dan menimpa gradasi latar yang
   sudah dirancang — seluruh halaman jadi rata #e9eef1.

   Di sini latar itu dikembalikan dengan pemilih ber-spesifisitas
   lebih tinggi (`html body`), jadi tidak perlu menyentuh blok
   dokumen cetak sama sekali — hasil Cetak/PDF tetap berlatar abu
   seperti semula.

   CATATAN PENTING (jangan diubah jadi pseudo-element):
   lapisan latar ini SENGAJA ditulis sebagai `background` milik body,
   bukan `body::before`. Pseudo-element ber-z-index:-1 digambar
   SEBELUM latar body, sehingga akan tertutup dan tidak pernah
   terlihat. Tekstur titik memakai `#view-dashboard::before` yang
   aman karena elemennya membentuk stacking context sendiri.
   ============================================================ */

/* ---------- Latar dasar seluruh halaman (mengembalikan rancangan awal) ---------- */
html body{
  background:
    radial-gradient(900px 420px at 88% -8%, rgba(22,169,181,.10), transparent 60%),
    radial-gradient(700px 360px at -6% 4%,  rgba(14,124,134,.08), transparent 55%),
    linear-gradient(180deg,#f1f5f7,#eaeef1 60%,#e8edf0);
  background-attachment:fixed;
}

/* ---------- Kanvas khusus Dashboard: “aurora siang” ----------
   Titik cahaya diletakkan pada posisi yang SAMA dengan layar Masuk
   (toska kanan-atas, emas kiri-atas, hijau bawah-tengah), hanya dalam
   nada terang — supaya aplikasi terasa satu keluarga dari layar Masuk
   sampai Dashboard. Bila peramban tidak mendukung :has(), aturan ini
   diabaikan dan latar kembali ke gradasi dasar di atas (tetap rapi). */
html body:has(#view-dashboard.active){
  background:
    radial-gradient(1100px 620px at 84% -12%, rgba(22,169,181,.22), transparent 58%),
    radial-gradient(820px 560px at -10% 6%,   rgba(246,180,14,.12), transparent 55%),
    radial-gradient(760px 700px at 50% 116%,  rgba(30,158,90,.10), transparent 60%),
    linear-gradient(160deg,#f3f8fa 0%,#e9f1f3 52%,#e3edef 100%);
  background-attachment:fixed;
}

/* Butiran titik halus — tekstur kertas yang memudar ke bawah agar
   angka & grafik tetap bersih. Dipasang pada #view-dashboard (bukan
   body) supaya digambar DI ATAS latar body. */
#view-dashboard{position:relative;isolation:isolate}
#view-dashboard::before{
  content:"";position:absolute;inset:-24px -24px -40px;z-index:-1;pointer-events:none;
  background-image:radial-gradient(rgba(9,94,102,.085) 1px, transparent 1.6px);
  background-size:26px 26px;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.5) 45%,transparent 86%);
          mask-image:linear-gradient(180deg,#000 0%,rgba(0,0,0,.5) 45%,transparent 86%);
}

/* ---------- Judul: garis pemisah jadi gradasi, bukan garis abu ---------- */
#view-dashboard .page-head{border-bottom:none;padding-bottom:18px}
#view-dashboard .page-head::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,
    rgba(9,94,102,.34) 0%,
    rgba(22,169,181,.20) 34%,
    rgba(246,180,14,.20) 62%,
    rgba(22,169,181,0) 100%);
}

/* ---------- Panel grafik: kaca buram tipis supaya kanvas terlihat ---------- */
#view-dashboard .split .panel,
#view-dashboard #dash-content > .panel{
  background:linear-gradient(180deg,rgba(255,255,255,.94) 0%,rgba(249,253,254,.88) 100%);
  -webkit-backdrop-filter:blur(12px) saturate(1.06);
          backdrop-filter:blur(12px) saturate(1.06);
  border-color:#d7e7ea;
}
#view-dashboard .panel-head{
  position:relative;
  background:linear-gradient(180deg,#f4fbfc,#e9f5f7);
  border-bottom-color:#dbebed;
}
/* Aksen pendek di bawah judul panel — penanda warna, bukan hiasan penuh */
#view-dashboard .panel-head::after{
  content:"";position:absolute;left:0;bottom:-1px;width:104px;height:2px;
  border-radius:0 3px 3px 0;
  background:linear-gradient(90deg,var(--teal),var(--cyan) 72%,rgba(22,169,181,0));
}

/* ---------- Batang grafik: alurnya ikut berwarna, bukan abu ---------- */
#view-dashboard .bar-track{
  background:linear-gradient(180deg,#e6f1f3,#dbe9eb);
  box-shadow:inset 0 1px 2px rgba(16,40,50,.07)
}

/* ---------- Kartu KPI: sedikit tembus pandang agar menyatu dengan kanvas ---------- */
#view-dashboard #dash-cards .card,
#view-dashboard #dash-nilai .card{
  background:
    linear-gradient(180deg,
      color-mix(in srgb,var(--ca,var(--teal)) 7%,rgba(255,255,255,.97)) 0%,
      rgba(255,255,255,.96) 44%,
      rgba(250,253,254,.94) 100%);
  -webkit-backdrop-filter:blur(10px) saturate(1.04);
          backdrop-filter:blur(10px) saturate(1.04);
}

/* ---------- Filter: kotak pilihan ikut kaca buram ---------- */
#view-dashboard .dash-filter-bar .filter-field select{
  background-color:rgba(255,255,255,.88);
  -webkit-backdrop-filter:blur(8px);
          backdrop-filter:blur(8px);
  border-color:#c6e0e4;
}

/* Layar kecil: titik butiran dirapatkan agar proporsinya tetap sama. */
@media(max-width:640px){
  #view-dashboard::before{background-size:20px 20px;inset:-14px -14px -30px}
}

/* ============================================================
   KARTU DASHBOARD — BINGKAI GRADIEN (Varian B)
   Permintaan 26 Jul 2026: kotak-kotak dashboard terlihat terlalu polos.
   Setiap kartu KPI kini dibungkus GARIS TEPI GRADIEN setebal 1,6px yang
   warnanya mengikuti warna status kartu (--card-accent: teal / hijau /
   kuning / merah), sementara isinya tetap putih bersih agar angka mudah
   dibaca. Bayangan kartu ikut diberi rona warna yang sama sehingga kartu
   terasa "melayang" berwarna, bukan abu-abu datar.

   Teknik: dua lapis background — `padding-box` untuk permukaan putih dan
   `border-box` untuk gradien — dengan border transparan. Cara ini membuat
   gradien hanya tampak di bidang border, sesuatu yang tidak bisa dicapai
   dengan `border-color` biasa (border-color tidak menerima gradient).

   !important dipakai karena blok "permukaan bersih & flat" di atas
   (#view-dashboard .card{background:#fff !important; border:… !important})
   memakai !important juga; tanpa ini aturan di bawah tidak pernah berlaku.
   ============================================================ */
#view-dashboard .card{
  --ca:var(--card-accent,var(--teal));
  border:1.6px solid transparent !important;
  border-radius:16px !important;
  padding:18px 20px !important;
  background:
    linear-gradient(180deg,#ffffff,#fdfeff) padding-box,
    linear-gradient(140deg,
      color-mix(in srgb,var(--ca) 78%,#fff) 0%,
      color-mix(in srgb,var(--ca) 24%,#fff) 40%,
      #e9f0f2 76%,
      color-mix(in srgb,var(--ca) 50%,#fff) 100%) border-box !important;
  box-shadow:
    0 2px 4px rgba(16,40,50,.04),
    0 14px 34px color-mix(in srgb,var(--ca) 16%,rgba(16,40,50,.07)) !important;
}
/* Batang aksen dipindah ke tepi BAWAH sebagai garis tipis yang memudar di
   kedua ujungnya — penegas warna status tanpa mengganggu bingkai gradien. */
#view-dashboard .card .accent{
  left:14px !important;right:14px !important;top:auto !important;bottom:0 !important;
  width:auto !important;height:3px !important;border-radius:3px 3px 0 0 !important;
  background:linear-gradient(90deg,transparent,var(--ca),transparent) !important;
  opacity:.9 !important;
}
/* Chip ikon ikut memakai rona warna kartunya (sebelumnya abu-abu netral). */
#view-dashboard .card-ic{
  background:color-mix(in srgb,var(--ca) 13%,#fff) !important;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ca) 28%,transparent) !important;
}
#view-dashboard .card:hover{
  box-shadow:
    0 3px 8px rgba(16,40,50,.05),
    0 22px 46px color-mix(in srgb,var(--ca) 24%,rgba(16,40,50,.09)) !important;
}
/* Peramban lama tanpa color-mix(): kembali ke bingkai polos, bukan hilang. */
@supports not (color:color-mix(in srgb,#000 50%,#fff)){
  #view-dashboard .card{
    border:1px solid #e6ebee !important;
    background:#ffffff !important;
  }
}

/* Panel grafik dibungkus bingkai gradien yang sama (rona teal) supaya kartu KPI
   dan panel di bawahnya terbaca sebagai satu keluarga, bukan dua gaya berbeda. */
#view-dashboard .panel{
  border:1.6px solid transparent !important;
  border-radius:16px !important;
  background:
    linear-gradient(180deg,#ffffff,#fdfeff) padding-box,
    linear-gradient(140deg,
      color-mix(in srgb,var(--teal) 62%,#fff) 0%,
      color-mix(in srgb,var(--teal) 20%,#fff) 42%,
      #e9f0f2 78%,
      color-mix(in srgb,var(--cyan) 40%,#fff) 100%) border-box !important;
  box-shadow:
    0 2px 4px rgba(16,40,50,.04),
    0 14px 34px color-mix(in srgb,var(--teal) 12%,rgba(16,40,50,.07)) !important;
}
@supports not (color:color-mix(in srgb,#000 50%,#fff)){
  #view-dashboard .panel{border:1px solid #e6ebee !important;background:#ffffff !important}
}

/* ============================================================
   LATAR HALAMAN PUTIH POLOS
   Permintaan 26 Jul 2026: latar aplikasi dibuat putih bersih agar
   sama rata dengan bidang tabel dan lebih enak dilihat.

   Semua lapisan hiasan latar dimatikan di sini — gradasi dasar
   `html body`, kanvas "aurora" khusus Dashboard, dan tekstur titik
   `#view-dashboard::before`. Ditulis di AKHIR berkas supaya menang
   atas ketiga blok tersebut tanpa perlu menghapusnya (kalau suatu saat
   ingin dikembalikan, cukup buang blok ini).

   TIDAK disentuh:
   - Layar Masuk (.login-screen) — punya latar sendiri & tetap berwarna.
   - Sidebar — tetap teal sebagai penanda navigasi.
   - Dokumen Cetak/PDF (#fkl-doc-css di index.html) — latar lembarnya
     diatur terpisah dan tetap seperti semula.
   ============================================================ */
html body,
html body:has(#view-dashboard.active){
  background:#ffffff !important;
  background-attachment:scroll !important;
}
/* Tekstur butiran titik pada Dashboard dimatikan */
#view-dashboard::before{display:none !important}

/* Panel & kartu tidak lagi perlu efek kaca (kanvas di belakangnya sudah
   putih polos); dibuat padat supaya tepinya bersih tanpa warna menumpuk. */
#view-dashboard .split .panel,
#view-dashboard #dash-content > .panel{
  background:linear-gradient(180deg,#ffffff,#fdfeff) !important;
  -webkit-backdrop-filter:none !important;
          backdrop-filter:none !important;
}
#view-dashboard #dash-cards .card,
#view-dashboard #dash-nilai .card{
  -webkit-backdrop-filter:none !important;
          backdrop-filter:none !important;
}
#view-dashboard .dash-filter-bar .filter-field select{
  background-color:#ffffff !important;
  -webkit-backdrop-filter:none !important;
          backdrop-filter:none !important;
}

/* ============================================================================
   SOROT BARIS TABEL — ORANYE ELEGAN (BERLAKU DI SELURUH MENU)
   Permintaan 26 Jul 2026: baris tabel yang disentuh kursor menyala oranye
   elegan, persis seperti pada menu Penetapan Nomor — bukan lagi biru-teal.

   Alasannya sama dengan di Penetapan: sorotan hangat yang jelas membuat mata
   tidak "melompat baris" saat membaca/menyalin data ke samping, terutama pada
   tabel lebar yang harus digulir.

   Cara kerja:
   - Warna disimpan sebagai variabel (--row-hi-*) agar cukup diubah di satu
     tempat kalau nuansanya mau digeser.
   - Latar dipasang pada <tr> DAN pada tiap <td>. Sel kolom beku (col-no,
     col-nama-freeze) punya latar sendiri, jadi harus ditimpa di tingkat sel;
     kalau hanya di <tr> kolom bekunya akan tetap kelabu.
   - !important dipakai karena beberapa aturan lama juga memakai !important
     (mis. `tbody tr:hover{background:#dceaed !important}`).
   - Blok ini ditulis di AKHIR berkas supaya menang tanpa perlu menghapus
     aturan lama; kalau suatu saat ingin kembali ke teal, cukup buang blok ini.

   TIDAK ikut disorot:
   - Baris judul grup (tr.grp) dan baris jumlah (tfoot) — bukan data.
   - Dokumen cetak/pratinjau (.fkl-doc) — lembar dokumen, bukan tabel data.
   ============================================================================ */
:root{
  --row-hi-top:#fff5e6;      /* puncak gradien - krem terang */
  --row-hi-bot:#ffe7c4;      /* dasar gradien - oranye lembut */
  --row-hi-bar:#e08a1e;      /* batang penanda di tepi kiri baris */
  --row-hi-line:rgba(201,118,26,.22);
  --row-hi-ink:#5a3d00;      /* teks utama di atas latar oranye */
  --row-hi-ink2:#9a5a12;     /* teks pendukung/nomor urut */
}

/* --- Latar baris --------------------------------------------------------- */
.table-wrap tbody tr:not(.grp):hover,
table tbody tr:not(.grp):hover{
  background:linear-gradient(180deg,var(--row-hi-top),var(--row-hi-bot)) !important;
}
.table-wrap tbody tr:not(.grp):hover td,
table tbody tr:not(.grp):hover td,
.table-wrap tbody tr:not(.grp):hover td:first-child,
.table-wrap tbody tr:not(.grp):hover td.col-no,
.table-wrap tbody tr:not(.grp):hover td.col-nama-freeze{
  background:linear-gradient(180deg,var(--row-hi-top),var(--row-hi-bot)) !important;
  color:var(--row-hi-ink);
}

/* --- Batang penanda di tepi kiri (sel pertama) ---------------------------- */
.table-wrap tbody tr:not(.grp):hover td:first-child{
  box-shadow:inset 5px 0 0 var(--row-hi-bar), inset 0 -1px 0 var(--row-hi-line);
}
/* Monitoring memakai kolom beku yang garis-garisnya dipalsukan lewat inset
   box-shadow; garis putih itu harus tetap ada, jadi batang penanda disisipkan
   ke dalam susunan bayangan yang sama, bukan menggantinya. */
#view-list .table-wrap tbody tr:hover td.col-no,
#view-list-pl .table-wrap tbody tr:hover td.col-no,
#view-list-tender .table-wrap tbody tr:hover td.col-no{
  box-shadow:inset 5px 0 0 var(--row-hi-bar), inset -1px 0 0 #fff,
             inset 0 -1px 0 #fff, inset 0 1px 0 #fff;
}
#view-list .table-wrap tbody tr:hover td.col-nama-freeze,
#view-list-pl .table-wrap tbody tr:hover td.col-nama-freeze,
#view-list-tender .table-wrap tbody tr:hover td.col-nama-freeze{
  box-shadow:inset 1px 0 0 #fff, inset -1px 0 0 #fff,
             inset 0 -1px 0 #fff, inset 0 1px 0 #fff;
}

/* --- Isi sel ikut menghangat supaya tidak ada warna dingin yang tertinggal - */
.table-wrap tbody tr:not(.grp):hover .stack-no,
table tbody tr:not(.grp):hover .stack-no{ color:var(--row-hi-ink2); }
.table-wrap tbody tr:not(.grp):hover .stack-line+.stack-line,
table tbody tr:not(.grp):hover .stack-line+.stack-line{
  border-top-color:rgba(201,118,26,.34);
}

/* --- Pengecualian -------------------------------------------------------- */
table.ana-ahsp-table tbody tr.grp:hover td,
table.ana-ahsp-table tfoot tr:hover td,
table tfoot tr:hover td{ background:inherit !important; color:inherit; }
/* Kelas ditulis dua kali (.fkl-doc.fkl-doc) semata-mata untuk menaikkan
   kekhususan agar menang atas aturan sorot di atas — bukan salah ketik. */
.fkl-doc.fkl-doc table tbody tr:hover,
.fkl-doc.fkl-doc table tbody tr:hover td{
  background:inherit !important; color:inherit; box-shadow:none;
}

/* ============ DOKUMEN PENGADAAN ============ */
.act-up{background:linear-gradient(135deg,var(--teal),var(--cyan))}
.act-dl{background:linear-gradient(135deg,#3b56c9,#5b73e0)}
.act-up:hover{box-shadow:0 8px 20px rgba(14,124,134,.5)}
.act-dl:hover{box-shadow:0 8px 20px rgba(59,86,201,.5)}
/* ===== Form Unggah Dokumen: satu baris horizontal =====
   Nama Pekerjaan | Bidang Pelaksana | Tgl. Terima Dokumen. Dua field kanan
   memakai width:max-content sehingga lebarnya = yang TERPANJANG antara judul
   field dan isi kontrolnya (untuk select: opsi terpanjang). Nama Pekerjaan
   memakai flex:1 sehingga mengisi seluruh sisa ruang. */
.dpeng-frow{display:flex;flex-wrap:wrap;gap:14px 22px;align-items:flex-start}
.dpeng-frow>.field{min-width:0;margin:0}
.dpeng-frow>.dpeng-f-nama{flex:1 1 240px;min-width:200px}
.dpeng-frow>.dpeng-f-nama input{width:100%}
.dpeng-frow>.dpeng-f-bidang,
.dpeng-frow>.dpeng-f-tgl{flex:0 0 auto;width:max-content;max-width:100%}
/* Tgl. Terima Dokumen dilebarkan sedikit; tambahannya diambil dari sisa ruang
   Nama Pekerjaan (yang memakai flex:1) sehingga baris tetap satu deret. */
.dpeng-frow>.dpeng-f-tgl{min-width:168px}
.dpeng-frow>.dpeng-f-bidang select,
.dpeng-frow>.dpeng-f-tgl input{width:100%}
.dpeng-f-dok{margin-top:16px}
/* Baris "Dokumen": label di kiri, tombol Pilih/Unggah/Kembali sebaris di kanan */
.dpeng-f-dok.dpeng-dok-row{display:flex;flex-direction:row;align-items:center;gap:14px;margin-top:20px;padding-top:16px;border-top:1px solid var(--line)}
.dpeng-f-dok.dpeng-dok-row>label{margin:0;flex:0 0 auto}
.dpeng-f-dok.dpeng-dok-row>.pn-doc-bar{margin-top:0;padding-top:0;border-top:none;margin-left:auto;flex-wrap:nowrap}
@media(max-width:720px){
  .dpeng-f-dok.dpeng-dok-row{flex-direction:column;align-items:stretch;gap:10px}
  .dpeng-f-dok.dpeng-dok-row>.pn-doc-bar{margin-left:0;flex-wrap:wrap;justify-content:flex-start}
}
@media(max-width:820px){
  .dpeng-frow>.field{flex:1 1 100%!important;width:100%!important}
}
.dpeng-hint{font-size:11.5px;color:var(--muted);margin-top:5px}
.dpeng-file-ok{display:inline-block;margin-left:8px;font-size:12px;font-weight:600;color:var(--green);
  max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
.dpeng-file-no{display:inline-block;margin-left:8px;font-size:12px;font-weight:600;color:#b08400}
/* ===== Judul panel Unggah Berkas ===== */
.dpeng-up-title{flex-wrap:wrap;gap:8px}
.dpeng-up-title > svg{flex:0 0 auto;width:16px;height:16px}
.dpeng-up-h{flex:0 0 auto}
.dpeng-up-sub{flex:1 1 auto;min-width:0;font-weight:700;font-size:11.5px;color:var(--ink);
  letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dpeng-up-prog{flex:0 0 auto;font-size:10.5px;font-weight:800;letter-spacing:.02em;
  padding:2px 9px;border-radius:999px;background:rgba(37,99,235,.10);color:#1d4ed8;
  border:1px solid rgba(37,99,235,.26)}
.dpeng-uphint{font-size:12.5px;color:var(--muted);margin:-2px 0 12px}
.dpeng-uplist{display:flex;flex-direction:column;gap:9px}
.dpeng-up-file{font-size:11.5px;font-weight:600;color:#1d4ed8;max-width:260px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dpeng-up-btn{white-space:nowrap}
.dpeng-uprow{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 14px;border:1px solid var(--line,#e3e8ec);border-radius:12px;background:#fff;
  transition:border-color .2s,box-shadow .2s}
.dpeng-uprow.done{border-color:rgba(30,158,90,.35);background:linear-gradient(0deg,rgba(30,158,90,.04),rgba(30,158,90,.04))}
.dpeng-uprow-l{display:flex;align-items:center;gap:10px;min-width:0;flex:1}
.dpeng-uprow-no{flex:none;width:24px;height:24px;border-radius:7px;display:grid;place-items:center;
  font-size:12px;font-weight:800;color:#fff;background:linear-gradient(135deg,var(--teal),var(--cyan))}
.dpeng-uprow-name{font-size:13.5px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dpeng-uprow-r{display:flex;align-items:center;gap:8px;flex:none;flex-wrap:wrap;justify-content:flex-end}
.dpeng-grp-tag{flex:none;font-size:10.5px;font-weight:800;letter-spacing:.03em;padding:2px 8px;border-radius:999px;color:#fff}
.dpeng-grp-pl{background:#0E7C86}
.dpeng-grp-tender{background:#3b56c9}
@media (max-width:640px){
  .dpeng-uprow{flex-direction:column;align-items:stretch;gap:8px}
  .dpeng-uprow-r{justify-content:flex-start}
  .dpeng-file-ok{max-width:100%}
}

/* ===== Daftar Dokumen Pengadaan: chip jumlah berkas pada kolom Nama Pekerjaan ===== */
.dpeng-count-chip{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:999px;
  font-size:11px;font-weight:800;letter-spacing:.02em;vertical-align:middle;
  background:rgba(120,132,140,.14);color:#5d6b74;border:1px solid rgba(120,132,140,.22)}
.dpeng-count-chip.ok{background:rgba(37,99,235,.10);color:#1d4ed8;border-color:rgba(37,99,235,.28)}

/* ===== POP UP "LIHAT DOKUMEN" =====
   Ditempatkan di bawah modal pratinjau (#pn-preview-overlay, z-index 100) agar
   pratinjau selalu muncul DI ATAS daftar dan daftar tetap terlihat di belakang. */
#dpeng-list-overlay{z-index:96}
.dpeng-list-modal{max-width:820px}
.dpeng-list-modal .detail-head{align-items:flex-start;gap:14px}
/* Tombol tutup: warna, ukuran, ikon, sorot, & cincin fokus SELURUHNYA datang
   dari aturan baku `.detail-close` (blok "TOMBOL TUTUP BAKU SELURUH POP-UP",
   ~baris 812) — 8 Agu 2026. Dulu semuanya ditulis ulang di sini dengan ukuran
   34px/sudut 10px, jadi tombol tutup pop-up ini SATU-SATUNYA yang berbeda
   sendiri dari pop-up lain. Yang masih perlu ditegaskan khusus di sini hanya
   larangan MENGECIL: judul yang melipat dua-tiga baris meregangkan baris
   kepala, dan tanpa `flex:none` tombolnya jadi korban pertama. */
.dpeng-list-modal .detail-close{flex:none}
/* Getarannya TIDAK didefinisikan ulang di sini: aturan umum
   `.overlay .modal.menolak` di index.html sudah mencakup kotak ini (kelasnya
   `modal wide dpeng-list-modal` di dalam `.overlay`), dan menulis aturan kembar
   hanya akan menimbulkan dua sumber kebenaran untuk gerakan yang sama. */
.dpeng-list-head-txt{min-width:0}
.dpeng-list-sub{margin-top:3px;font-size:11.5px;font-weight:600;color:rgba(255,255,255,.82);letter-spacing:.15px}
.dpeng-list-body{padding:16px 20px 20px;max-height:min(70vh,620px);overflow:auto;background:#f7fafb}
.dpeng-list-hint{font-size:12px;color:var(--muted,#6b7280);margin:0 2px 12px}
.dpeng-list-empty{padding:34px 10px;text-align:center;font-size:13px;color:var(--muted,#6b7280)}
.dpeng-list-items{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.dpeng-list-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:12px;
  border:1px solid rgba(16,40,50,.10);background:#fff;transition:transform .12s ease,box-shadow .16s ease,border-color .16s ease}
.dpeng-list-no{flex:none;width:26px;height:26px;border-radius:8px;display:grid;place-items:center;
  font-size:11.5px;font-weight:800;background:rgba(16,40,50,.06);color:#5d6b74}
.dpeng-list-main{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}
.dpeng-list-label{font-size:13.5px;font-weight:650;line-height:1.35;color:var(--ink,#22343a)}
.dpeng-list-file{font-size:11.5px;font-weight:600;color:var(--ink,#22343a);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dpeng-list-none{font-size:11.5px;font-weight:600;color:#98a4ac}
.dpeng-list-act{flex:none;display:flex;align-items:center;gap:6px}
/* Sudah ada berkas → SELURUH BARIS adalah sasaran klik (7 Agu 2026), meniru
   daftar dokumen TOR/KAK. Tanda panah di ujung kanan menyatakan "ada halaman di
   balik ini" bahkan sebelum kursor menyentuhnya — dulu satu-satunya isyarat
   adalah garis bawah biru yang baru muncul tepat di atas namanya. */
.dpeng-list-item.has-file{cursor:pointer;border-color:rgba(37,99,235,.34);
  background:linear-gradient(0deg,rgba(37,99,235,.05),rgba(37,99,235,.05)),#fff}
.dpeng-list-item.has-file .dpeng-list-label{color:var(--ink,#22343a)}
.dpeng-list-item.has-file .dpeng-list-file{color:var(--ink,#22343a)}
.dpeng-list-item.has-file .dpeng-list-no{background:rgba(37,99,235,.12);color:#1d4ed8}
.dpeng-list-go{flex:none;font-size:22px;line-height:1;color:#9fb2c4;
  transition:color .14s ease,transform .14s ease}
.dpeng-list-item.has-file:hover,
.dpeng-list-item.has-file:focus-visible{border-color:#2563eb;
  box-shadow:0 4px 14px rgba(37,99,235,.16);transform:translateY(-1px)}
.dpeng-list-item.has-file:hover .dpeng-list-label{color:#1d4ed8}
.dpeng-list-item.has-file:hover .dpeng-list-go{color:#1d4ed8;transform:translateX(2px)}
.dpeng-list-item.has-file:focus-visible{outline:2px solid rgba(37,99,235,.55);outline-offset:2px}
/* Belum ada berkas → redup & tidak dapat diklik */
.dpeng-list-item.no-file{opacity:.62;background:#fbfcfd}
.dpeng-list-item.no-file .dpeng-list-label{color:#6b7880;font-weight:600}
@media (max-width:640px){
  .dpeng-list-body{padding:12px 12px 16px;max-height:74vh}
  .dpeng-list-item{align-items:flex-start;flex-wrap:wrap}
  .dpeng-list-label{white-space:normal}
}


/* =========================================================================
   EFEK 3D — SELURUH ISI MENU "DOKUMEN"
   Berlaku pada: Perjanjian/Kontrak (#view-fk-view), Dokumen Pengadaan
   (#view-dpeng-view & #view-dpeng-unggah), Materi & Peraturan
   (#view-materi-view), serta pop up milik Dokumen Pengadaan.

   PENTING — kenapa memakai scale, bukan translate:
   Efek angkat yang memakai translateY MEMINDAHKAN elemen menjauh dari kursor.
   Bila kursor berada di tepi bawah tombol, elemennya kabur → hover lepas →
   elemen kembali → hover lagi, berulang puluhan kali per detik. Akibatnya
   kursor berkedip antara panah & tangan, dan klik bisa gagal karena mousedown
   dan mouseup mendarat di elemen yang berbeda. scale() membesarkan kotak ke
   segala arah, sehingga titik yang tadinya di dalam TIDAK PERNAH keluar.
   Karena itu: wadah (kartu/panel/toolbar) TIDAK ditransform sama sekali
   (isinya ikut bergeser & menggeser tombol di dalamnya), sedangkan elemen
   interaktif memakai scale.
   ========================================================================= */
#view-fk-view,#view-dpeng-view,#view-dpeng-unggah,#view-materi-view{
  perspective:1600px; perspective-origin:50% 0%;
}

/* ---------- Kartu utama: kedalaman lewat bayangan berlapis (tanpa transform) ---------- */
#view-fk-view .panel,#view-dpeng-view .panel,#view-materi-view .panel,
#view-fk-view .toolbar,#view-dpeng-view .toolbar,
#view-dpeng-unggah .form-card{
  border-radius:16px;
  transition:box-shadow .3s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 1px 2px rgba(16,40,50,.07),
    0 6px 12px rgba(16,40,50,.07),
    0 16px 28px rgba(16,40,50,.09),
    0 32px 56px rgba(16,40,50,.07);
}
#view-fk-view .panel:hover,#view-dpeng-view .panel:hover,#view-materi-view .panel:hover,
#view-dpeng-unggah .form-card:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 2px 4px rgba(16,40,50,.08),
    0 10px 20px rgba(16,40,50,.10),
    0 24px 44px rgba(16,40,50,.12),
    0 46px 78px rgba(16,40,50,.09);
}

/* ---------- Kepala tabel: menonjol di atas badan tabel ---------- */
#view-fk-view .panel thead th,#view-dpeng-view .panel thead th{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18),0 3px 8px rgba(16,40,50,.16);
  text-shadow:0 1px 1px rgba(9,63,69,.35);
}

/* ---------- Baris tabel: membesar tipis (bukan bergeser) saat disorot ---------- */
#view-fk-view .panel tbody tr,#view-dpeng-view .panel tbody tr{
  transition:transform .2s cubic-bezier(.16,1,.3,1),box-shadow .2s ease,background .2s ease;
}
#view-fk-view .panel tbody tr:hover,#view-dpeng-view .panel tbody tr:hover{
  transform:scale(1.006);
  box-shadow:0 6px 16px rgba(16,40,50,.13),0 1px 3px rgba(16,40,50,.08);
  position:relative; z-index:1;
}

/* ---------- Tombol aksi: tombol fisik yang bisa ditekan ---------- */
#view-fk-view .act,#view-dpeng-view .act,#view-dpeng-unggah .act,
#dpeng-list-overlay .act,
#view-fk-view .fk-act-icon,#view-fk-input .fk-act-icon{
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 3px 6px rgba(16,40,50,.20),
    0 1px 2px rgba(16,40,50,.14);
}
#view-fk-view .act:hover,#view-dpeng-view .act:hover,#view-dpeng-unggah .act:hover,
#dpeng-list-overlay .act:hover,
#view-fk-view .fk-act-icon:hover,#view-fk-input .fk-act-icon:hover{
  transform:scale(1.10);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.40),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 7px 14px rgba(16,40,50,.26),
    0 2px 4px rgba(16,40,50,.16);
  filter:brightness(1.05);
}
#view-fk-view .act:active,#view-dpeng-view .act:active,#view-dpeng-unggah .act:active,
#dpeng-list-overlay .act:active,
#view-fk-view .fk-act-icon:active,#view-fk-input .fk-act-icon:active{
  transform:scale(.94);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.26),0 1px 1px rgba(16,40,50,.14);
}

/* ---------- Tombol biasa (Pilih Dokumen, Unggah Dokumen, Reset, dll.) ----------
   scale menggantikan translateY bawaan .btn:hover — inilah yang menghilangkan
   kursor berkedip & klik yang gagal di tepi bawah tombol. */
#view-fk-view .btn,#view-dpeng-view .btn,#view-dpeng-unggah .btn,
#dpeng-doc-overlay .btn,#dpeng-list-overlay .btn,
#view-fk-view .dp-pick-btn,#view-dpeng-unggah .dp-pick-btn,
#view-fk-view .dp-unpick-btn,#view-dpeng-unggah .dp-unpick-btn{
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 4px 9px rgba(16,40,50,.18),
    0 1px 2px rgba(16,40,50,.12);
}
#view-fk-view .btn:hover,#view-dpeng-view .btn:hover,#view-dpeng-unggah .btn:hover,
#dpeng-doc-overlay .btn:hover,#dpeng-list-overlay .btn:hover,
#view-fk-view .dp-pick-btn:hover,#view-dpeng-unggah .dp-pick-btn:hover,
#view-fk-view .dp-unpick-btn:hover,#view-dpeng-unggah .dp-unpick-btn:hover{
  transform:scale(1.04);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 9px 18px rgba(16,40,50,.24),
    0 2px 5px rgba(16,40,50,.14);
}
#view-fk-view .btn:active,#view-dpeng-view .btn:active,#view-dpeng-unggah .btn:active,
#dpeng-doc-overlay .btn:active,#dpeng-list-overlay .btn:active,
#view-fk-view .dp-pick-btn:active,#view-dpeng-unggah .dp-pick-btn:active,
#view-fk-view .dp-unpick-btn:active,#view-dpeng-unggah .dp-unpick-btn:active{
  transform:scale(.97);
  box-shadow:inset 0 3px 7px rgba(0,0,0,.22),0 1px 1px rgba(16,40,50,.12);
}

/* ---------- Baris "Unggah Berkas" pada halaman unggah ---------- */
#view-dpeng-unggah .dpeng-uprow{
  transition:transform .22s cubic-bezier(.16,1,.3,1),box-shadow .22s ease;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 2px 5px rgba(16,40,50,.07),0 8px 16px rgba(16,40,50,.06);
}
#view-dpeng-unggah .dpeng-uprow:hover{
  transform:scale(1.008);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95),0 4px 9px rgba(16,40,50,.10),0 14px 26px rgba(16,40,50,.11);
}

/* ---------- Nomor & lencana: bulatan timbul ---------- */
#view-dpeng-unggah .dpeng-uprow-no,#dpeng-list-overlay .dpeng-list-no{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),inset 0 -2px 0 rgba(0,0,0,.14),0 2px 4px rgba(16,40,50,.20);
}
#view-dpeng-view .dpeng-count-chip,#view-dpeng-unggah .dpeng-up-prog{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),0 1px 2px rgba(16,40,50,.12);
}

/* ---------- Pop up milik Dokumen Pengadaan ---------- */
#dpeng-list-overlay .modal,#dpeng-doc-overlay .modal{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.6),
    0 4px 10px rgba(9,63,69,.18),
    0 22px 44px rgba(9,63,69,.26),
    0 48px 92px rgba(9,63,69,.30);
}
#dpeng-list-overlay .dpeng-list-item{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 2px 4px rgba(16,40,50,.07),0 7px 14px rgba(16,40,50,.06);
}
#dpeng-doc-overlay .pn-check-item{
  transition:transform .18s cubic-bezier(.16,1,.3,1),box-shadow .18s ease,border-color .18s ease;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 1px 2px rgba(16,40,50,.06),0 4px 9px rgba(16,40,50,.05);
}
#dpeng-doc-overlay .pn-check-item:hover{
  transform:scale(1.02);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95),0 3px 6px rgba(16,40,50,.09),0 10px 20px rgba(16,40,50,.09);
}
#dpeng-doc-overlay .pn-check-box{ box-shadow:inset 0 1px 2px rgba(16,40,50,.12) }
#dpeng-doc-overlay input:checked+.pn-check-box{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),0 2px 5px rgba(14,124,134,.35);
}

/* ---------- Judul: sedikit terangkat dari latar ---------- */
#view-fk-view .page-head h2,#view-dpeng-view .page-head h2,
#view-dpeng-unggah .page-head h2,#view-materi-view .page-head h2{
  text-shadow:0 1px 0 rgba(255,255,255,.9),0 2px 4px rgba(16,40,50,.12);
}
#view-dpeng-unggah .form-section-title,#view-fk-view .form-section-title{
  text-shadow:0 1px 0 rgba(255,255,255,.85);
}

/* ---------- Kolom isian: sedikit cekung agar kontras dgn kartu timbul ---------- */
#view-fk-view .filter-field input,#view-fk-view .filter-field select,
#view-dpeng-view .filter-field input,#view-dpeng-view .filter-field select,
#view-dpeng-unggah .field input,#view-dpeng-unggah .field select{
  box-shadow:inset 0 2px 4px rgba(16,40,50,.07),inset 0 -1px 0 rgba(255,255,255,.9);
}

/* Ikon di dalam tombol: jangan ikut melayang (translateZ bawaan bikin goyang) */
#view-fk-view .btn:hover svg,#view-dpeng-view .btn:hover svg,
#view-dpeng-unggah .btn:hover svg,#dpeng-doc-overlay .btn:hover svg,
#dpeng-list-overlay .btn:hover svg{ transform:scale(1.08) }

/* Hormati preferensi pengguna yang meminimalkan animasi */
@media (prefers-reduced-motion:reduce){
  #view-fk-view *,#view-dpeng-view *,#view-dpeng-unggah *,#view-materi-view *,
  #dpeng-list-overlay *,#dpeng-doc-overlay *{ transition:none!important;transform:none!important }
}

/* ===== Pratinjau Excel (Dokumen Pengadaan) =====
   Isi .xlsx dibaca SheetJS lalu dirender sebagai tabel. Kolom & baris dibuat
   ringkas agar BoQ yang lebar tetap terbaca; area tabel bergulir dua arah. */
/* `:not(.fkl-preview-body)` = pengaman: pratinjau DOKUMEN (HPS, Analisa,
   SPK, dsb.) selalu memasang .fkl-preview-body. Bila kelas Excel sempat
   tertinggal dari pratinjau sebelumnya, aturan ini otomatis mundur
   sehingga dokumennya tidak ikut memakai tata letak lembar kerja. */
.pn-preview-body.dpeng-xls-body:not(.fkl-preview-body){display:block;background:#eef2f4;padding:0;overflow:hidden}
.dpeng-xls-wrap{display:flex;flex-direction:column;height:74vh;min-height:0}
.pn-preview-modal.is-max .dpeng-xls-wrap{height:calc(100vh - 62px)}
@media(max-width:640px){ .dpeng-xls-wrap{height:64vh} }

.dpeng-xls-tabs{flex:0 0 auto;display:flex;gap:6px;padding:8px 10px 0;overflow-x:auto;
  background:linear-gradient(180deg,#e7edf0,#eef2f4);border-bottom:1px solid rgba(16,40,50,.10)}
.dpeng-xls-tab{flex:0 0 auto;border:1px solid rgba(16,40,50,.14);border-bottom:none;
  background:#f7fafb;color:#5d6b74;font-family:'Plus Jakarta Sans',sans-serif;
  font-size:11.5px;font-weight:700;letter-spacing:.15px;padding:7px 14px;
  border-radius:9px 9px 0 0;cursor:pointer;white-space:nowrap;
  transition:background .16s ease,color .16s ease,box-shadow .16s ease}
.dpeng-xls-tab:hover{background:#fff;color:var(--teal-dark,#0d2a30)}
.dpeng-xls-tab.active{background:#fff;color:var(--teal-dark,#0d2a30);
  box-shadow:inset 0 3px 0 var(--teal,#0E7C86),0 -2px 6px rgba(16,40,50,.06)}
.dpeng-xls-empty{font-weight:600;font-size:10px;color:#98a4ac;margin-left:5px}

.dpeng-xls-bar{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;
  gap:12px;padding:9px 14px;background:#fff;border-bottom:1px solid rgba(16,40,50,.10)}
.dpeng-xls-nama{font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:800;
  color:var(--teal-dark,#0d2a30);letter-spacing:.2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dpeng-xls-bar .btn{flex:0 0 auto}

.dpeng-xls-scroll{flex:1 1 auto;min-height:0;overflow:auto;background:#fff;padding:0}
.dpeng-xls-blank{padding:46px 16px;text-align:center;font-size:12.5px;color:var(--muted,#6b7280)}
.dpeng-xls-scroll table{border-collapse:collapse;width:max-content;min-width:100%;
  font-family:'Plus Jakarta Sans',system-ui,sans-serif;font-size:12px;color:#22343a}
.dpeng-xls-scroll td,.dpeng-xls-scroll th{border:1px solid #dbe3e8;padding:6px 10px;
  vertical-align:top;white-space:pre-wrap;max-width:420px;background:#fff}
.dpeng-xls-scroll tr:first-child td,.dpeng-xls-scroll th{
  background:linear-gradient(180deg,#f2f7f8,#e9f1f3);font-weight:800;color:#0d2a30;
  position:sticky;top:0;z-index:2}
.dpeng-xls-scroll tr:nth-child(even) td{background:#fbfdfe}
.dpeng-xls-scroll tr:nth-child(even) td:first-child{background:#f7fafb}

/* =========================================================================
   EFEK 3D — SELURUH MENU APLIKASI
   Menyamakan kedalaman seluruh halaman dengan menu "Dokumen → Dokumen
   Pengadaan". Blok ini adalah versi UMUM dari blok "EFEK 3D — SELURUH ISI
   MENU DOKUMEN" di atas: yang di sana dikunci ke #view-fk-view/#view-dpeng-*,
   di sini berlaku untuk SEMUA halaman lewat kelas `.view`.

   TIDAK DISENTUH — pratinjau & cetak/PDF:
   Seluruh dokumen pratinjau dan cetak (Kelengkapan, HPS, Analisa, Jadwal,
   RHO, Rekap, SPK/Perjanjian) dibangun sebagai dokumen HTML MANDIRI di dalam
   <iframe>/jendela baru (lihat fklDocShell/spkDocHtml). Berkas style.css ini
   tidak pernah dimuat di sana, jadi tampilan cetak & PDF otomatis bebas dari
   efek ini. Yang perlu dikecualikan secara manual hanyalah:
     - #pn-preview-overlay  -> pop up "Pratinjau File" (bingkai iframe/PDF)
     - .dpeng-xls-*         -> pratinjau isi Excel
     - .spk-narasi-prev     -> pratinjau kerapian di form Susun Kontrak
   Ditambah @media print di bawah yang mematikan bayangan & transform.

   PENTING — kenapa memakai scale, bukan translate (sama seperti blok Dokumen):
   translateY MEMINDAHKAN elemen menjauh dari kursor. Bila kursor ada di tepi
   bawah tombol, elemennya kabur -> hover lepas -> kembali -> hover lagi,
   puluhan kali per detik: kursor berkedip dan klik bisa gagal karena mousedown
   & mouseup mendarat di elemen berbeda. scale() membesarkan kotak ke segala
   arah sehingga titik yang tadinya di dalam TIDAK PERNAH keluar. Karena itu
   wadah (kartu/panel/toolbar) TIDAK ditransform sama sekali, hanya elemen
   interaktif yang memakai scale.
   ========================================================================= */

/* ---------- Ruang 3D tiap halaman ----------
   Aman: seluruh pop up layar-penuh (.overlay, .spk-ov, .pnw-profil-ov,
   .spk-we-nfmodal) ditempelkan ke <body>, bukan ke dalam .view, jadi
   position:fixed miliknya tidak ikut terikat ke halaman ini. */
.view{ perspective:1600px; perspective-origin:50% 0% }

/* ---------- Kartu utama: kedalaman lewat bayangan berlapis (tanpa transform) ----------
   Panel daftar memuat kolom beku & kepala tabel position:sticky. Transform pada
   leluhurnya akan mematahkan sticky, jadi kedalaman di sini murni bayangan.

   KENAPA `.view:not(#view-dashboard)` DAN BUKAN `.view` SAJA — dua tugas sekaligus:
   (a) PENGUAT SPESIFISITAS. Halaman berbasis tabel (baris ~499) menata panel &
       toolbar lewat pemilih ber-ID: `#view-list .panel, #view-list-pl .panel,
       #view-list-tender .panel, #view-fk-input .panel, #view-pn-lihat .panel,
       #view-fkl-view .panel` dengan bobot (1,1,0). Satu ID selalu menang atas
       pemilih berbasis kelas, BERAPA PUN banyak kelasnya — jadi `.view .panel`
       (0,2,0) tidak akan pernah berlaku di enam halaman itu. `:not(#…)` menyumbang
       bobot ID sehingga pemilih ini jadi (1,2,0) dan menang.
   (b) PENGECUALIAN DASHBOARD. Dashboard sudah punya rancangan 3D sendiri (kartu
       KPI miring mengikuti kursor + panel grafik kaca buram, lihat blok "EFEK 3D —
       DASHBOARD"). Menimpanya dengan bayangan umum ini akan merusak tampilan itu,
       jadi Dashboard sengaja dilewati. */
.view:not(#view-dashboard) .panel,
.view:not(#view-dashboard) .toolbar,
.view:not(#view-dashboard) .form-card,
.view:not(#view-dashboard) .hl-tpl-bar{
  border-radius:16px;
  transition:box-shadow .3s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 1px 2px rgba(16,40,50,.07),
    0 6px 12px rgba(16,40,50,.07),
    0 16px 28px rgba(16,40,50,.09),
    0 32px 56px rgba(16,40,50,.07);
}
.view:not(#view-dashboard) .panel:hover,
.view:not(#view-dashboard) .form-card:hover,
.view:not(#view-dashboard) .hl-tpl-bar:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 2px 4px rgba(16,40,50,.08),
    0 10px 20px rgba(16,40,50,.10),
    0 24px 44px rgba(16,40,50,.12),
    0 46px 78px rgba(16,40,50,.09);
}

/* ---------- Kepala tabel: menonjol di atas badan tabel ---------- */
.view:not(#view-dashboard) .table-wrap thead th{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.18),
    0 3px 8px rgba(16,40,50,.16);
  text-shadow:0 1px 1px rgba(9,63,69,.35);
}

/* ---------- Baris tabel: terangkat saat disorot ----------
   TEMUAN saat pengujian (Chromium 141): blok menu "Dokumen" memakai
   `transform:scale(1.006)` pada baris tabel, tetapi `transform` TIDAK BEKERJA
   pada elemen `display:table-row`. Diuji langsung: `transform:scale(1.05)` pada
   sebuah <tr> menghasilkan computed style `matrix(1,0,0,1,0,9.18)` — komponen
   skalanya dibuang, tersisa geseran. Jadi di menu Dokumen pun yang benar-benar
   terlihat adalah BAYANGANNYA, bukan pembesarannya. Karena itu di sini skala
   sengaja tidak dipakai: hasil akhirnya sama persis, tanpa geseran sisa yang
   tidak diinginkan. Kolom beku (td.col-nama-freeze, position:sticky) juga
   dipastikan tetap di tempatnya — diukur 40px dari tepi panel sebelum maupun
   saat baris disorot. */
.view:not(#view-dashboard) .table-wrap tbody tr{
  transition:box-shadow .2s ease,background .2s ease;
}
.view:not(#view-dashboard) .table-wrap tbody tr:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.85),
    0 6px 16px rgba(16,40,50,.13),
    0 1px 3px rgba(16,40,50,.08);
  position:relative;
  z-index:2;
}

/* ---------- Tombol aksi (ikon): tombol fisik yang bisa ditekan ---------- */
.view .act:not([disabled]),
.view .fk-act-icon:not([disabled]),
.overlay:not(#pn-preview-overlay) .act:not([disabled]){
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 3px 6px rgba(16,40,50,.20),
    0 1px 2px rgba(16,40,50,.14);
}
.view .act:not([disabled]):hover,
.view .fk-act-icon:not([disabled]):hover,
.overlay:not(#pn-preview-overlay) .act:not([disabled]):hover{
  transform:scale(1.10);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.40),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 7px 14px rgba(16,40,50,.26),
    0 2px 4px rgba(16,40,50,.16);
  filter:brightness(1.05);
}
.view .act:not([disabled]):active,
.view .fk-act-icon:not([disabled]):active,
.overlay:not(#pn-preview-overlay) .act:not([disabled]):active{
  transform:scale(.94);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.26),0 1px 1px rgba(16,40,50,.14);
}

/* ---------- Tombol biasa ----------
   scale menggantikan translateY bawaan .btn:hover — inilah yang menghilangkan
   kursor berkedip & klik yang gagal di tepi bawah tombol. */
.view .btn,
.overlay:not(#pn-preview-overlay) .btn{
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 4px 9px rgba(16,40,50,.18),
    0 1px 2px rgba(16,40,50,.12);
}
.view .btn:hover,
.overlay:not(#pn-preview-overlay) .btn:hover{
  transform:scale(1.04);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 9px 18px rgba(16,40,50,.24),
    0 2px 5px rgba(16,40,50,.14);
}
.view .btn:active,
.overlay:not(#pn-preview-overlay) .btn:active{
  transform:scale(.97);
  box-shadow:inset 0 3px 7px rgba(0,0,0,.22),0 1px 1px rgba(16,40,50,.12);
}
/* Ikon di dalam tombol: jangan ikut melayang (translateZ bawaan + perspective
   halaman membuatnya goyang saat tombolnya ikut membesar) */
.view .btn:hover svg,
.overlay:not(#pn-preview-overlay) .btn:hover svg{ transform:scale(1.08) }

/* ---------- Pop up: bayangan dalam agar terasa jauh di atas halaman ----------
   #pn-preview-overlay (Pratinjau File) sengaja dilewati. */
.overlay:not(#pn-preview-overlay) .modal{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.6),
    0 4px 10px rgba(9,63,69,.18),
    0 22px 44px rgba(9,63,69,.26),
    0 48px 92px rgba(9,63,69,.30);
}

/* ---------- Daftar centang dokumen (Penetapan, Kelengkapan, dll.) ---------- */
.view .pn-check-item,
.overlay:not(#pn-preview-overlay) .pn-check-item,
.view .fkl-check{
  transition:transform .18s cubic-bezier(.16,1,.3,1),box-shadow .18s ease,border-color .18s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 1px 2px rgba(16,40,50,.06),
    0 4px 9px rgba(16,40,50,.05);
}
.view .pn-check-item:hover,
.overlay:not(#pn-preview-overlay) .pn-check-item:hover,
.view .fkl-check:hover{
  transform:scale(1.02);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 3px 6px rgba(16,40,50,.09),
    0 10px 20px rgba(16,40,50,.09);
}
.view .pn-check-box,
.overlay:not(#pn-preview-overlay) .pn-check-box{ box-shadow:inset 0 1px 2px rgba(16,40,50,.12) }
.view input:checked+.pn-check-box,
.overlay:not(#pn-preview-overlay) input:checked+.pn-check-box{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),0 2px 5px rgba(14,124,134,.35);
}

/* ---------- Judul halaman & seksi: sedikit terangkat dari latar ----------
   JANGAN pasang text-shadow pada judul BERGRADASI. Judul Dashboard memakai
   `background-clip:text` + `-webkit-text-fill-color:transparent` (baris ~207):
   hurufnya sendiri TRANSPARAN dan warnanya datang dari gradasi latar di
   belakangnya. Bila diberi text-shadow, yang tampak justru bayangan putih itu
   MENEMBUS huruf — judul berubah jadi siluet pudar dan tidak terbaca
   (dilaporkan pada "Dashboard Kontrak Rinci"). Karena itu Dashboard dilewati,
   dan di bawahnya ada pengaman untuk seluruh teks bergradasi lain. */
.view:not(#view-dashboard) .page-head h2{ text-shadow:0 1px 0 rgba(255,255,255,.9),0 2px 4px rgba(16,40,50,.12) }
.view .form-section-title,
.view .panel-head{ text-shadow:0 1px 0 rgba(255,255,255,.85) }

/* Pengaman teks bergradasi — bobot ID/kelas dibuat lebih tinggi dari aturan di
   atas supaya tetap aman bila kelak ada judul bergradasi baru di halaman lain. */
#view-dashboard .page-head h2,
.view .page-head h2[style*="text-fill"],
.view .card .v,
.view .rl-text{ text-shadow:none }

/* ---------- Kolom isian: sedikit cekung agar kontras dgn kartu timbul ---------- */
.view .filter-field input,
.view .filter-field select{
  box-shadow:inset 0 2px 4px rgba(16,40,50,.07),inset 0 -1px 0 rgba(255,255,255,.9);
}
.view .filter-field input:focus,
.view .filter-field select:focus{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 0 0 3px rgba(14,124,134,.15),
    0 4px 10px rgba(16,40,50,.10);
}

/* ---------- PENGECUALIAN: area pratinjau di dalam halaman ----------
   Pratinjau isi Excel (Dokumen Pengadaan), pratinjau berkas, dan pratinjau
   kerapian narasi pada Susun Kontrak harus tampil DATAR seperti dokumen
   aslinya. Ketiganya berada di luar `.view` (di dalam pop up pratinjau) atau
   tidak memuat elemen yang disentuh blok ini, jadi aturan di bawah hanyalah
   pengaman bila kelak dipindah ke dalam halaman. */
.dpeng-xls-scroll tbody tr:hover,
.spk-narasi-prev tbody tr:hover,
.fkl-doc tbody tr:hover{
  transform:none;
  box-shadow:none;
}

/* ---------- Hormati preferensi pengguna yang meminimalkan animasi ---------- */
@media (prefers-reduced-motion:reduce){
  .view .act:not([disabled]):hover,
  .view .act:not([disabled]):active,
  .view .btn:hover,
  .view .btn:active,
  .view .btn:hover svg,
  .view .pn-check-item:hover,
  .view .fkl-check:hover,
  .overlay:not(#pn-preview-overlay) .act:not([disabled]):hover,
  .overlay:not(#pn-preview-overlay) .act:not([disabled]):active,
  .overlay:not(#pn-preview-overlay) .btn:hover,
  .overlay:not(#pn-preview-overlay) .btn:active,
  .overlay:not(#pn-preview-overlay) .btn:hover svg,
  .overlay:not(#pn-preview-overlay) .pn-check-item:hover{ transform:none }
  .view:not(#view-dashboard) .panel,.view:not(#view-dashboard) .toolbar,
  .view:not(#view-dashboard) .form-card,.view:not(#view-dashboard) .hl-tpl-bar,
  .view:not(#view-dashboard) .table-wrap tbody tr,
  .view .act,.view .btn,
  .view .pn-check-item,.view .fkl-check{ transition:none }
}

/* ---------- Cetak: seluruh efek dimatikan ----------
   Dokumen cetak sebenarnya berjalan di iframe terpisah, tetapi bila pengguna
   menekan Ctrl+P langsung dari halaman aplikasi, bayangan & transform tidak
   boleh ikut tercetak (boros tinta dan membuat teks buram). */
@media print{
  .view{ perspective:none }
  .view .panel,.view .toolbar,.view .form-card,.view .hl-tpl-bar,
  .view .table-wrap thead th,.view .table-wrap tbody tr,
  .view .act,.view .btn,.view .pn-check-item,.view .fkl-check,
  .view .filter-field input,.view .filter-field select,
  .overlay .modal,.overlay .btn,.overlay .act{
    box-shadow:none !important;
    transform:none !important;
    text-shadow:none !important;
    filter:none !important;
  }
}


/* ============================================================================
   ============================================================================
   TAMBALAN "TAJAM" — ditambahkan 28 Juli 2026
   Menghapus: pergeseran tabel naik-turun, seluruh efek 3D, dan sumber buram.
   Blok ini SENGAJA diletakkan paling bawah agar menimpa aturan di atasnya.
   Untuk mengembalikan tampilan lama: hapus semua yang ada di bawah garis ini.
   ============================================================================
   ============================================================================ */


/* ############################################################
   BAGIAN A — TABEL TIDAK LAGI BERGESER
   ############################################################ */

/* ------------------------------------------------------------
   A1. Sumber utama: style.css baris 2549
       .panel:hover{transform:translateY(-3px)}
   Setiap tabel dibungkus <div class="panel">. Begitu kursor masuk
   ke area panel, SELURUH tabel naik 3px; begitu keluar, turun lagi.
   Karena tepi panel dilewati berkali-kali saat membaca, tabel
   naik-turun terus — itu yang bikin pusing.
   Kedalaman tetap ada, tapi lewat bayangan saja (tidak bergerak).
   ------------------------------------------------------------ */
.panel:hover,
.panel:focus-within,
.split .panel:hover,
.form-card:hover,
.toolbar:hover{
  transform:none !important;
}
.panel{
  transition:box-shadow .3s ease, border-color .25s ease !important;
}

/* ------------------------------------------------------------
   A2. Baris tabel "melayang masuk" bertahap saat halaman dibuka
       (@keyframes rowFloatIn, style.css baris 2552-2562)
   Tiap baris naik 10px satu per satu. Pada tabel panjang ini
   terlihat seperti daftar yang bergelombang.
   ------------------------------------------------------------ */
.table-wrap tbody tr,
tbody tr{
  animation:none !important;
  opacity:1 !important;
  transform:none !important;
}

/* ------------------------------------------------------------
   A3. Isi baris tidak berubah bentuk saat di-hover.
   Penanda baris aktif tetap ada lewat warna latar (sudah diatur
   style.css) — itu sudah cukup terbaca tanpa gerakan.
   ------------------------------------------------------------ */
tbody tr:hover td,
tbody tr:hover th,
tr:hover .pn-nomor-val{
  transform:none !important;
  /* font-weight:inherit DIBUANG. Aturan itu justru sumber "goyang"-nya:
     sel tabel bertebal 500 dipaksa mewarisi 400 saat disentuh kursor,
     sehingga hurufnya menipis & melebar sedikit setiap kursor lewat.
     Sekarang tiap sel mempertahankan ketebalannya sendiri. */
}


/* ############################################################
   BAGIAN B — SELURUH EFEK 3D DIHAPUS
   ############################################################ */

/* ------------------------------------------------------------
   B1. Matikan ruang 3D secara global.
   perspective & transform-style adalah "panggung" tempat efek 3D
   hidup. Dimatikan di sini, tidak ada elemen yang bisa terlihat
   punya kedalaman. Ini tidak mengubah tata letak sama sekali.
   Menutup: .view, #view-fk-view dkk, .login-screen, .fk-seg,
   .fk-up-body, .topbar-brand, .toast, .cards, .card.
   ------------------------------------------------------------ */
*, *::before, *::after{
  perspective:none !important;
  transform-style:flat !important;
}

/* ------------------------------------------------------------
   B2. Kartu dashboard — tilt mengikuti kursor
       (style.css 3799-3877, digerakkan app.js 2232-2284)
   Kartu dimiringkan rotateX/rotateY mengikuti mouse. Ini juga
   penyebab teks kartu terlihat buram: huruf yang diputar harus
   digambar ulang oleh GPU dengan interpolasi.
   ------------------------------------------------------------ */
#view-dashboard .card{
  transform-style:flat !important;
  will-change:auto !important;
}
#view-dashboard .card.card.tilt-on{
  transform:none !important;            /* tanpa miring, tanpa naik */
}
#view-dashboard .card.tilt-on .v,
#view-dashboard .card.tilt-on .k,
#view-dashboard .card.tilt-on .sub,
#view-dashboard .card.tilt-on .accent,
#view-dashboard .card.tilt-on .card-ic{
  transform:none !important;            /* parallax translateZ mati */
}
/* Kilau putih yang mengikuti kursor — menurunkan kontras teks */
#view-dashboard .card.tilt-on::after{ opacity:0 !important }

/* ------------------------------------------------------------
   B3. Menu atas — tiap item menu memiringkan diri mengikuti kursor
       (app.js 2378-2399 menulis style.transform langsung)
   !important tetap menang atas inline style, jadi cukup dari CSS.
   ------------------------------------------------------------ */
.topnav-link, .topnav-trigger, .topnav-item, .topnav-subtrigger,
.topnav-link:hover, .topnav-trigger:hover,
.topnav-item:hover, .topnav-subtrigger:hover,
.nav-link:hover, .nav-item:hover{
  transform:none !important;
}
/* CATATAN: sebelumnya di sini ada tambahan `background` & `box-shadow` untuk
   penanda hover. Itu SALAH dan sudah dihapus — `.topnav-link:hover` punya
   bobot yang sama persis dengan `.topnav-link.active` (0,2,0), dan karena
   ditulis lebih belakang ia menang. Akibatnya pil kuning menu aktif berubah
   jadi kotak putih transparan saat disentuh. Aturan hover asli (baris 1132,
   1149, 1172) sudah bagus dan memang tidak pernah bermasalah — yang perlu
   dibuang hanya transform-nya. */

/* Ikon menu: translateZ(8px) & rotasi dibuang seluruhnya */
.topnav-link:hover svg,
.topnav-item:hover svg,
.topnav-trigger:hover svg{
  transform:none !important;
}

/* ------------------------------------------------------------
   B4. Toast (notifikasi) — masuk sambil berputar rotateX(38deg)
       dan melesat dari translateZ(-120px)  (style.css 4186-4281)
   Diganti geser vertikal biasa. translateX(-50%) WAJIB tetap ada,
   itu yang menempatkan toast di tengah layar.
   ------------------------------------------------------------ */
.toast{
  transform-style:flat !important;
  will-change:opacity !important;
  transform:translateX(-50%) translateY(16px) !important;
}
.toast.show{
  transform:translateX(-50%) translateY(0) !important;
}
.toast svg{        transform:scale(.85) !important }
.toast.show svg{   transform:none !important }
.toast span,
.toast.show span{  transform:none !important }
/* Layar kecil memakai left/right, jadi tanpa translateX(-50%) */
@media(max-width:640px){
  .toast{      transform:translateY(16px) !important }
  .toast.show{ transform:none !important }
}
/* Toast TIDAK BOLEH menangkap sentuhan.
   Keadaan tersembunyinya hanya opacity:0 + geser 16px — jadi kotaknya tetap
   berada di atas layar (z-index:200) walau tak terlihat. Di ponsel POTRET
   kotak itu membentang selebar layar tepat di jalur tombol "Keluar" pada laci
   navigasi, sehingga ketukan mendarat di toast tak kasatmata, bukan di tombol.
   Isi toast memang tidak pernah perlu diklik, maka dimatikan seluruhnya. */
.toast{ pointer-events:none !important }

/* ------------------------------------------------------------
   B5. Area unggah berkas (dropzone) — miring rotateX(6deg)
       (style.css 2002, 2009, 2013 & 3493, 3497)
   ------------------------------------------------------------ */
.fk-dropzone:hover,
.spk-kldoc-dz:hover{
  transform:none !important;
}
.fk-dropzone.fk-dz-over,
.spk-kldoc-dz.drag{
  transform:none !important;
}
.fk-dz-ic{ transform:none !important }   /* translateZ(30px) */

/* ------------------------------------------------------------
   B6. Tab segmen — animasi "pop" 3D saat dipilih
       (@keyframes segPop, style.css 1845-1850)
   Ditulis ulang tanpa perspective/translateZ/rotateX.
   ------------------------------------------------------------ */
@keyframes segPop{
  0%  { transform:scale(1) }
  38% { transform:scale(1.05) }
  100%{ transform:scale(1) }
}

/* ------------------------------------------------------------
   B7. Logo topbar — berputar rotateY(-14deg) rotateX(6deg)
       saat kursor mengenai area brand (style.css 4088-4090)
   ------------------------------------------------------------ */
.topbar-brand:hover .logo{
  transform:scale(1.05) !important;
}

/* ------------------------------------------------------------
   B8. Ikon di dalam tombol — translateZ(6px) (style.css 3990)
   ------------------------------------------------------------ */
.btn:hover svg{ transform:scale(1.08) !important }

/* ------------------------------------------------------------
   B9. Layar login — kartu login miring mengikuti kursor
       (style.css 997-998)
   ------------------------------------------------------------ */
.login-screen{ perspective:none !important }
.login-tilt{
  transform:none !important;
  transform-style:flat !important;
  will-change:auto !important;
}


/* ############################################################
   BAGIAN C — SUMBER BURAM (lanjutan dari v1)
   ############################################################ */

/* ------------------------------------------------------------
   C1. backdrop-filter:blur() di panel & kartu
       (style.css 5124, 5154, 5161, 1178, 2375)
   Memaksa teks di atasnya dirender dengan anti-alias grayscale —
   huruf terlihat lembek TERUS, bukan hanya saat hover.
   ------------------------------------------------------------ */
#view-dashboard .split .panel,
#view-dashboard #dash-content > .panel,
#view-dashboard #dash-cards .card,
#view-dashboard #dash-nilai .card,
#view-dashboard .dash-filter-bar .filter-field select,
.topbar-user .user-chip,
.pnw-hero-badge{
  -webkit-backdrop-filter:none !important;
          backdrop-filter:none !important;
}
#view-dashboard .split .panel,
#view-dashboard #dash-content > .panel{
  background:linear-gradient(180deg,#fff 0%,#f9fdfe 100%) !important;
}

/* ------------------------------------------------------------
   C2. filter:blur() pada animasi masuk halaman
       (@keyframes pageReveal 85-87, dpReveal 588-590)
   Ini buram harfiah ±0,3 detik setiap pindah halaman.
   ------------------------------------------------------------ */
@keyframes pageReveal{
  0%  { opacity:0; transform:translateY(14px) }
  100%{ opacity:1; transform:none }
}
@keyframes dpReveal{
  0%  { opacity:0; transform:translateY(10px) }
  100%{ opacity:1; transform:none }
}
.view.active, .dp-reveal{ will-change:auto !important }

/* ------------------------------------------------------------
   C3. Input naik 1px saat fokus (style.css 2565-2568)
   Geser 1px = teks mendarat di posisi subpiksel ganjil.
   Diganti cincin fokus yang justru lebih terbaca.
   ------------------------------------------------------------ */
.field input:focus,.field select:focus,.field textarea:focus,
.filter-field input:focus,.filter-field select:focus{
  transform:none !important;
  box-shadow:0 0 0 3px rgba(22,169,181,.22);
}

/* ------------------------------------------------------------
   C4. -webkit-font-smoothing:antialiased (baris 1787, 2416, 2485)
   Menipiskan huruf & mengurangi ketajaman, paling terasa di layar
   non-Retina. Dikembalikan ke penggambaran bawaan sistem.
   ------------------------------------------------------------ */
body,
.pnw-periksa-table,
.fkl-chk{
  -webkit-font-smoothing:auto !important;
  -moz-osx-font-smoothing:auto !important;
}


/* ============================================================
   PEMBUKAAN PENAWARAN — LEBAR KOLOM TABEL
   ============================================================ */

/* --- Kolom AKSI: selebar isinya saja, ikon tetap satu baris ---
   width:1% + white-space:nowrap pada tabel table-layout:auto membuat kolom
   menyusut sampai sesempit isinya yang tidak boleh terpotong. Sisa ruangnya
   jatuh ke kolom Nama Pekerjaan yang memang paling butuh tempat.
   Aturan lama memakai style="min-width:170px" langsung di <th>, jadi
   penimpaannya perlu !important. */
#view-pnw-view .table-wrap th.pnw-col-aksi,
#view-pnw-view .table-wrap td.pnw-col-aksi{
  width:1% !important;
  min-width:0 !important;
  max-width:none !important;
  white-space:nowrap !important;
  text-align:center;
  padding-left:12px; padding-right:12px;
}
/* Tiga tombol berjajar tanpa pernah turun baris */
#view-pnw-view .table-wrap td.pnw-col-aksi .action-cell{
  display:inline-flex;
  flex-wrap:nowrap;
  justify-content:center;
  white-space:nowrap;
}

/* --- Kolom TGL. PEMBUKAAN PENAWARAN ---
   Muat dua tanggal sekaligus ("27/07/2026 - 28/07/2026") dalam satu baris.
   .col-date umum memakai !important, jadi di sini juga harus !important. */
#view-pnw-view .table-wrap th.pnw-col-tgl,
#view-pnw-view .table-wrap td.pnw-col-tgl{
  width:1% !important;
  min-width:0 !important;
  max-width:none !important;
  white-space:nowrap !important;
  text-align:center;
  padding-left:14px; padding-right:14px;
}

/* --- Kolom METODE PENYAMPAIAN DOKUMEN ---
   Nilai terpanjang "1 Tahap 2 Sampul" tetap satu baris; judulnya boleh
   membungkus jadi dua baris agar kolom tidak melebar berlebihan. */
#view-pnw-view .table-wrap th.pnw-col-metode{
  white-space:normal;
  line-height:1.28;
  text-align:center;
  vertical-align:middle;
}
#view-pnw-view .table-wrap td.pnw-col-metode{
  width:1%;
  min-width:0;
  white-space:nowrap;
  text-align:center;
}
/* Penanda "Sampul Dua belum diisi" tetap turun ke baris kedua */
#view-pnw-view .table-wrap td.pnw-col-metode .pnw-s2-tag{
  display:block;
  white-space:normal;
  margin-top:3px;
}


/* ============================================================================
   TAMBALAN "TAJAM" — LANJUTAN
   Menghentikan getaran tabel & menghapus sisa efek 3D pada ikon/tombol.
   ============================================================================ */

/* ------------------------------------------------------------
   D1. PENYEBAB GETARAN — .act:hover{transform:translateY(-3px)}
       (style.css baris 1430)
   Persis yang diperingatkan komentar di baris 5508-5514 file ini:
   translateY MEMINDAHKAN tombol menjauh dari kursor. Kursor di tepi
   bawah tombol -> tombol kabur ke atas -> hover lepas -> tombol turun
   lagi -> hover lagi. Berulang puluhan kali per detik = bergetar.
   Karena kolom Aksi berisi tiga tombol berjajar dan kursor sering
   menyapunya naik-turun, getarannya terasa di seluruh baris.
   ------------------------------------------------------------ */
.act, .act:hover, .act:focus, .act:focus-visible, .act:active,
.act::before, .act::after{
  transform:none !important;
}
.act{ transition:box-shadow .2s ease, filter .2s ease !important }
/* Cincin cahaya yang memancar & membesar saat hover — ikut dimatikan */
.act::after{ opacity:0 !important }
.act:hover::before, .act:active::before{ box-shadow:none !important }

/* ------------------------------------------------------------
   D2. IKON TOMBOL AKSI BERGOYANG SENDIRI
       (style.css 1439-1452)
   Tiga animasi: pensil bergoyang (actEdit), mata mengedip (actView),
   dan tempat sampah BERGETAR (actDel — namanya memang begitu di
   komentar aslinya baris 1448). Semuanya jalan tiap kali kursor lewat.
   ------------------------------------------------------------ */
.act svg,
.act-edit:hover svg,
.act-view:hover svg,
.act-del:hover svg{
  animation:none !important;
  transform:none !important;
  transition:none !important;
}

/* ------------------------------------------------------------
   D3. SEMUA IKON BERHENTI MEMBESAR / BERPUTAR / MAJU
   Menutup: .btn svg (translateZ), .topnav-* svg (scale+rotate),
   .settings-gear svg (rotate 60deg), .card-ic (scale+rotate),
   .role-tab svg, .fk-dz-ic, .spk-kldoc-dzic, dan ikon di dalam pop up.
   ------------------------------------------------------------ */
.btn svg, .btn:hover svg,
.act svg,
.topnav-link svg, .topnav-link:hover svg,
.topnav-trigger svg, .topnav-trigger:hover svg,
.topnav-trigger:hover svg:first-of-type,
.topnav-item svg, .topnav-item:hover svg,
.topnav-subtrigger svg, .topnav-subtrigger:hover > svg:first-child,
.settings-gear svg, .settings-gear:hover svg,
.settings-item svg, .settings-item:hover svg,
.role-tab svg, .role-tab:hover svg,
.card-ic, .card:hover .card-ic,
#view-dashboard .card:hover .card-ic,
.fk-dz-ic, .fk-dz-ic svg, .fk-dropzone:hover .fk-dz-ic svg,
.spk-kldoc-dzic, .spk-kldoc-dz:hover .spk-kldoc-dzic,
#dpeng-list-overlay .btn:hover svg,
.overlay .btn:hover svg,
.topbar-brand:hover .logo,
.topbar-brand .logo svg,
.brandside-logo svg{
  transform:none !important;
  animation:none !important;
}

/* ------------------------------------------------------------
   D4. TOMBOL & KARTU TIDAK LAGI MELOMPAT SAAT DISENTUH
   Daftar ini SENGAJA berisi nama kelas, bukan pemilih universal:
   elemen yang memang butuh transform untuk berfungsi (toast yang
   dipusatkan translateX(-50%), penggeser .fk-seg-thumb, knop
   .ac-toggle-tr, pemutar .lo-spin) tidak ada di daftar ini,
   jadi tetap bekerja normal.
   ------------------------------------------------------------ */
.btn, .btn:hover, .btn:active, .btn:focus-visible,
.card, .card:hover,
.panel, .panel:hover,
.pg-btn, .pg-btn:hover, .pg-btn:active,
.act, .act:hover, .act:active,
.logout-btn:hover, .logout-btn:active,
.login-btn:hover, .login-btn:active,
.settings-gear:hover,
.role-tab:hover,
.nav-link:hover, .nav-item:hover,
.topnav-link:hover, .topnav-link:active,
.topnav-trigger:hover, .topnav-trigger:active,
.topnav-item:hover, .topnav-subtrigger:hover,
.jp-profil-btn:hover,
.fk-act:hover, .fk-act:active,
.fk-dropzone:hover, .fk-dropzone.fk-dz-over,
.spk-kldoc-dz:hover, .spk-kldoc-dz.drag,
.dp-pick-btn:hover, .dp-pick-btn:active,
.dp-unpick-btn:hover, .dp-unpick-btn:active,
.modal-actions .btn:hover, .modal-actions .btn:active,
.pn-doc-modal-foot .btn:hover, .pn-doc-modal-foot .btn:active,
.ana-doc-tab:active,
.ana-ahsp-add:active, .ana-ahsp-del:active, .ana-ahsp-hapus-analisa:active,
.st-kpi:hover, .st-item:hover,
.ac-capgrp:hover, .ac-sum-chip:hover, .ac-live:hover, .ac-mini:hover,
.pnw-profil-upload:hover, .pnw-profil-upload:active,
.pnw-profil-item:hover, .pnw-profil-mini:active,
.pf-ic:hover, .pf-ic:active,
.trk-btn:active,
.pn-copy:hover{
  transform:none !important;
}

/* ------------------------------------------------------------
   D5. KILAU YANG MENYAPU MELINTASI TOMBOL
       (@keyframes btnShine, style.css 2543-2544; .btn-*:hover::after
       dan .topnav-*:hover::before yang memakai translateX)
   Sorotan putih yang bergerak melintas juga terbaca sebagai getaran.
   ------------------------------------------------------------ */
.btn::after, .btn:hover::after,
.btn-teal:hover::after, .btn-green:hover::after, .btn-red:hover::after,
.btn-amber:hover::after, .btn-danger:hover::after,
.topnav-link:hover::before, .topnav-trigger:hover::before,
.topbar-brand:hover .logo::after{
  animation:none !important;
  transform:none !important;
  opacity:0 !important;
}

/* ------------------------------------------------------------
   D6. BARIS TABEL — pergantian warna dibuat seketika
   Transisi latar .18s membuat baris memudar masuk-keluar saat kursor
   menyapu cepat; berderet ke bawah, itu tampak seperti riak/getaran.
   Penanda baris aktif tetap ada, hanya muncul langsung.
   ------------------------------------------------------------ */
tbody tr, tbody tr td,
#pn-lihat-body tr,
table.ac-matrix tbody tr,
.pnw-periksa-table td{
  transition:none !important;
}


/* ============================================================================
   TAMBALAN "TAJAM" — BAGIAN E
   Meratakan efek 3D yang berasal dari BAYANGAN, bukan dari gerakan.
   Warna, gradasi, dan ukuran tidak diubah — hanya reliefnya yang dihapus.
   ============================================================================ */

/* ------------------------------------------------------------
   E1. Kenapa tombol masih terlihat timbul
   Pola bayangan di baris 5845-5849 (dan kembarannya di 5875-5879,
   3970-3987) menyusun tombol fisik secara harfiah:
     inset 0 1px 0 rgba(255,255,255,.34)  -> kilau di tepi ATAS
     inset 0 -2px 0 rgba(0,0,0,.16)       -> tepi BAWAH gelap = ketebalan
     0 3px 6px rgba(16,40,50,.20)         -> bayangan jatuh ke permukaan
   Tiga lapis itulah yang membuat mata membacanya sebagai benda 3D.
   Diganti satu bayangan datar tipis supaya tombol tetap terpisah dari
   latar tanpa terlihat menonjol.
   ------------------------------------------------------------ */

/* --- Tombol ikon aksi (Ubah / Lihat / Hapus) --- */
.act,
.view .act:not([disabled]),
.view .fk-act-icon:not([disabled]),
.overlay .act:not([disabled]),
.overlay:not(#pn-preview-overlay) .act:not([disabled]),
.table-wrap .act{
  box-shadow:0 1px 2px rgba(16,40,50,.10) !important;
}
.act:hover,
.view .act:not([disabled]):hover,
.view .fk-act-icon:not([disabled]):hover,
.overlay:not(#pn-preview-overlay) .act:not([disabled]):hover{
  box-shadow:0 2px 4px rgba(16,40,50,.16) !important;
}
.act:active,
.view .act:not([disabled]):active,
.overlay:not(#pn-preview-overlay) .act:not([disabled]):active{
  box-shadow:0 1px 2px rgba(16,40,50,.10) !important;
}

/* --- Tombol biasa (Buat Kontrak, Reset, Simpan, dll.) --- */
.btn,
.view .btn,
.overlay .btn,
.overlay:not(#pn-preview-overlay) .btn,
.btn-teal, .btn-green, .btn-red, .btn-danger, .btn-amber, .btn-indigo,
.modal-actions .btn, .pn-doc-modal-foot .btn,
.head-add-btn, .pg-btn{
  box-shadow:0 1px 2px rgba(16,40,50,.10) !important;
}
.btn:hover,
.view .btn:hover,
.overlay:not(#pn-preview-overlay) .btn:hover,
.btn-teal:hover, .btn-green:hover, .btn-red:hover,
.btn-danger:hover, .btn-amber:hover, .btn-indigo:hover,
.pg-btn:hover{
  box-shadow:0 2px 5px rgba(16,40,50,.14) !important;
}
.btn:active,
.view .btn:active,
.overlay:not(#pn-preview-overlay) .btn:active{
  box-shadow:0 1px 2px rgba(16,40,50,.10) !important;
}

/* --- Gerigi Pengaturan & chip pengguna di topbar --- */
.settings-gear, .settings-gear:hover,
.topbar-user .user-chip,
.topbar-user .logout-btn, .topbar-user .logout-btn:hover,
.logout-btn, .logout-btn:hover{
  box-shadow:none !important;
}

/* --- Daftar centang dokumen --- */
.view .pn-check-item, .view .fkl-check,
.overlay:not(#pn-preview-overlay) .pn-check-item,
.view .pn-check-item:hover, .view .fkl-check:hover,
.overlay:not(#pn-preview-overlay) .pn-check-item:hover{
  box-shadow:0 1px 2px rgba(16,40,50,.08) !important;
}

/* ------------------------------------------------------------
   E2. Ikon berhenti melayang di atas tombolnya
   drop-shadow pada SVG membuat ikon seolah mengambang beberapa
   milimeter di atas permukaan tombol — relief 3D yang paling kentara
   pada ikon kecil.
   ------------------------------------------------------------ */
.btn svg, .act svg, .fk-act-icon svg,
.logo svg, .topbar-brand .logo svg, .brandside-logo svg,
.topbar-brand .logo .logo-img,
.topbar-brand:hover .logo .logo-img,
.form-section-title svg, .fkl-sec-h svg,
.pnw-profil-head svg,
.pnw-profil-upload.pf-ic-up svg,
.fk-dz-ic svg, .spk-kldoc-dzic{
  filter:none !important;
}

/* ------------------------------------------------------------
   E3. Huruf timbul (embossed) dikembalikan jadi rata
   .brand h1 memakai empat lapis text-shadow: garis terang di puncak
   huruf + tiga bayangan gelap di bawahnya. Judul halaman & kepala
   panel memakai pola yang sama dengan versi lebih tipis.
   Kalau kamu justru suka judulnya sedikit timbul, hapus blok E3 saja.
   ------------------------------------------------------------ */
.brand h1, .topbar-brand:hover .brand h1,
.brand span,
.view:not(#view-dashboard) .page-head h2,
.view .panel-head,
.form-section-title,
.fk-dz-title, .spk-kldoc-dz .t,
.pnw-hero-title, .st-kpi-v,
.ac-matrix-grp thead th.ac-act-th{
  text-shadow:none !important;
}

/* ------------------------------------------------------------
   E4. Kilau di dalam menu aktif
   Pil kuning menu aktif memakai `inset 0 1px 0 rgba(255,255,255,.5)`
   sebagai garis kilau di tepi atas. Halo kuningnya DIPERTAHANKAN —
   itu penanda halaman mana yang sedang dibuka — hanya kilaunya rata.
   ------------------------------------------------------------ */
.topnav-link.active,
.topnav-group.has-active .topnav-trigger{
  box-shadow:0 2px 8px rgba(246,180,14,.38) !important;
  animation:none !important;   /* denyut navGlow ikut dihentikan */
}


/* ============================================================================
   TAMBALAN "TAJAM" — BAGIAN F
   Tombol Pengaturan diberi warna sendiri agar terbaca sebagai tombol.
   ============================================================================ */

/* ------------------------------------------------------------
   F1. Kenapa tadi nyaris tak terlihat
   Aturan asli (baris 1191) memberi latar putih transparan .16 di atas
   topbar yang di ujung kanan berwarna --teal (#0E7C86). Bedanya terlalu
   tipis; selama ini yang menolongnya justru bayangan timbul — dan itu
   sudah diratakan di blok E1. Jadi solusinya warna, bukan bayangan.
   Dipilih --cyan (#16a9b5): sewarna keluarga topbar, jelas lebih terang
   dari latarnya, dan TIDAK memakai kuning agar tidak tertukar dengan
   penanda "halaman yang sedang aktif".
   ------------------------------------------------------------ */
.settings-gear{
  background:var(--cyan) !important;
  border:1px solid rgba(255,255,255,.42) !important;
  color:#fff !important;
}
.settings-gear:hover{
  background:#1fbecb !important;
  border-color:rgba(255,255,255,.62) !important;
}
/* Menu terbuka: dibalik jadi terang — tidak perlu gerakan untuk terbaca */
.settings-wrap.open .settings-gear{
  background:#fff !important;
  border-color:#fff !important;
  color:var(--teal-dark) !important;
  box-shadow:none !important;
}
.settings-wrap.open .settings-gear svg{ color:var(--teal-dark) !important }

/* Fokus papan ketik tetap terlihat jelas */
.settings-gear:focus-visible{
  outline:2px solid #fff !important;
  outline-offset:2px !important;
}

/* =========================================================================
   MATERI & PERATURAN
   Struktur & rasa visualnya mengikuti Dokumen Pengadaan: toolbar filter +
   tabel berpaginasi pada halaman daftar (#view-materi-view), dan satu
   form-card pada halaman tambah/ubah (#view-materi-form).
   ========================================================================= */

/* ---------- Peringatan nama ganda (dipakai Dokumen Pengadaan & Materi) ----------
   Tampil di bawah kolom nama saat nama yang diketik sudah dipakai record lain.
   display diatur dari JS (none/'') sehingga di sini TIDAK boleh ada display
   pada state normal selain flex. */
.dpeng-dupe{
  display:flex;align-items:flex-start;gap:6px;margin-top:6px;
  padding:6px 9px;border-radius:9px;
  font-size:11.5px;font-weight:700;line-height:1.35;
  color:#9a2b2b;background:rgba(211,58,58,.08);
  border:1px solid rgba(211,58,58,.26);
}
.dpeng-dupe svg{flex:0 0 auto;width:14px;height:14px;margin-top:1px}

/* ---------- Kolom tabel ---------- */
.materi-col-kat{min-width:150px;max-width:220px}
/* Lencana jenis berkas di belakang Nama Materi / Peraturan */
.materi-file-chip{
  display:inline-block;margin-left:8px;padding:1px 8px;border-radius:999px;
  font-size:10.5px;font-weight:800;letter-spacing:.03em;vertical-align:middle;
  background:rgba(120,132,140,.14);color:#5d6b74;border:1px solid rgba(120,132,140,.22);
}
.materi-file-chip.ok{background:rgba(37,99,235,.10);color:#1d4ed8;border-color:rgba(37,99,235,.28)}

/* ---------- Formulir: satu baris horizontal ----------
   Kategori | Nama Materi / Peraturan | Tgl. Terbit. Kategori & Tgl. selebar
   isinya (opsi/judul terpanjang), Nama mengambil seluruh sisa ruang. */
.materi-frow{display:flex;flex-wrap:wrap;gap:14px 22px;align-items:flex-start}
.materi-frow>.field{min-width:0;margin:0}
.materi-frow>.materi-f-nama{flex:1 1 260px;min-width:220px}
.materi-frow>.materi-f-nama input{width:100%}
.materi-frow>.materi-f-kat,
.materi-frow>.materi-f-tgl{flex:0 0 auto;width:max-content;max-width:100%}
.materi-frow>.materi-f-tgl{min-width:168px}
.materi-frow>.materi-f-kat select,
.materi-frow>.materi-f-tgl input{width:100%}
@media(max-width:820px){
  .materi-frow>.field{flex:1 1 100%!important;width:100%!important}
}

/* ---------- Baris "Berkas": label di kiri, kontrol sebaris di kanan ---------- */
.materi-f-file.materi-file-row{
  display:flex;flex-direction:row;align-items:center;gap:14px;
  margin-top:20px;padding-top:16px;border-top:1px solid var(--line);
}
.materi-f-file.materi-file-row>label{margin:0;flex:0 0 auto}
.materi-file-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-left:auto;justify-content:flex-end}
.materi-file-ok{
  font-size:12px;font-weight:700;color:var(--green);
  max-width:420px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.materi-file-ok em{font-style:normal;font-weight:600;color:var(--muted)}
.materi-file-no{font-size:12px;font-weight:600;color:#b08400}
@media(max-width:720px){
  .materi-f-file.materi-file-row{flex-direction:column;align-items:stretch;gap:10px}
  .materi-file-bar{margin-left:0;justify-content:flex-start}
  .materi-file-ok{max-width:100%}
}

/* ---------- Baris tombol Simpan / Kembali ---------- */
.pn-doc-bar.materi-act-bar{margin-top:18px;padding-top:16px;border-top:1px solid var(--line);
  display:flex;gap:10px;flex-wrap:wrap}

/* =========================================================================
   EFEK 3D — menyamakan Materi & Peraturan dengan isi menu "Dokumen" lainnya.
   Catatan yang sama berlaku: wadah TIDAK ditransform (isinya ikut bergeser),
   elemen interaktif memakai scale() — bukan translateY — agar kursor tidak
   berkedip & klik tidak gagal di tepi bawah tombol.
   ========================================================================= */
#view-materi-form{ perspective:1600px; perspective-origin:50% 0% }

#view-materi-view .toolbar,#view-materi-form .form-card{
  border-radius:16px;
  transition:box-shadow .3s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 1px 2px rgba(16,40,50,.07),
    0 6px 12px rgba(16,40,50,.07),
    0 16px 28px rgba(16,40,50,.09),
    0 32px 56px rgba(16,40,50,.07);
}
#view-materi-form .form-card:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(16,40,50,.05),
    0 2px 4px rgba(16,40,50,.08),
    0 10px 20px rgba(16,40,50,.10),
    0 24px 44px rgba(16,40,50,.12),
    0 46px 78px rgba(16,40,50,.09);
}

/* Kepala & baris tabel */
#view-materi-view .panel thead th{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18),0 3px 8px rgba(16,40,50,.16);
  text-shadow:0 1px 1px rgba(9,63,69,.35);
}
#view-materi-view .panel tbody tr{
  transition:transform .2s cubic-bezier(.16,1,.3,1),box-shadow .2s ease,background .2s ease;
}
#view-materi-view .panel tbody tr:hover{
  transform:scale(1.006);
  box-shadow:0 6px 16px rgba(16,40,50,.13),0 1px 3px rgba(16,40,50,.08);
  position:relative; z-index:1;
}

/* Tombol aksi (ikon) */
#view-materi-view .act,#view-materi-form .act{
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 3px 6px rgba(16,40,50,.20),
    0 1px 2px rgba(16,40,50,.14);
}
#view-materi-view .act:hover,#view-materi-form .act:hover{
  transform:scale(1.10);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.40),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 7px 14px rgba(16,40,50,.26),
    0 2px 4px rgba(16,40,50,.16);
  filter:brightness(1.05);
}
#view-materi-view .act:active,#view-materi-form .act:active{
  transform:scale(.94);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.26),0 1px 1px rgba(16,40,50,.14);
}

/* Tombol biasa (Reset, Tambah Peraturan, Unggah Berkas, Simpan, Kembali) */
#view-materi-view .btn,#view-materi-form .btn{
  transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .16s ease,filter .16s ease;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 4px 9px rgba(16,40,50,.18),
    0 1px 2px rgba(16,40,50,.12);
}
#view-materi-view .btn:hover,#view-materi-form .btn:hover{
  transform:scale(1.04);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.34),
    inset 0 -2px 0 rgba(0,0,0,.14),
    0 9px 18px rgba(16,40,50,.24),
    0 2px 5px rgba(16,40,50,.14);
}
#view-materi-view .btn:active,#view-materi-form .btn:active{
  transform:scale(.97);
  box-shadow:inset 0 3px 7px rgba(0,0,0,.22),0 1px 1px rgba(16,40,50,.12);
}
#view-materi-view .btn:hover svg,#view-materi-form .btn:hover svg{ transform:scale(1.08) }

/* Judul & isian */
#view-materi-form .page-head h2{
  text-shadow:0 1px 0 rgba(255,255,255,.9),0 2px 4px rgba(16,40,50,.12);
}
#view-materi-form .form-section-title{ text-shadow:0 1px 0 rgba(255,255,255,.85) }
#view-materi-view .filter-field input,#view-materi-view .filter-field select,
#view-materi-form .field input,#view-materi-form .field select{
  box-shadow:inset 0 2px 4px rgba(16,40,50,.07),inset 0 -1px 0 rgba(255,255,255,.9);
}
#view-materi-view .materi-file-chip{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),0 1px 2px rgba(16,40,50,.12);
}

@media (prefers-reduced-motion:reduce){
  #view-materi-form *{ transition:none!important;transform:none!important }
}

/* ==================================================================
   MATERI & PERATURAN — KATEGORI DI SUDUT KANAN ATAS + ISIAN SEBARIS
   ------------------------------------------------------------------
   Perubahan susunan formulir Tambah/Ubah Peraturan:
   (a) dropdown Kategori dipindah ke sudut kanan atas kartu, menyatu dengan
       judul section, ditemani ikon Ubah Nama & Hapus kategori (ikon hanya
       digambar oleh app.js bila sudah ada kategori terpilih);
   (b) Nama Materi / Peraturan, Tgl. Terbit, dan Berkas kini SEBARIS.
   Blok ini ditaruh paling akhir supaya menimpa aturan .materi-* di atasnya.
   ================================================================== */
.materi-sec-title{ justify-content:space-between; flex-wrap:wrap; gap:10px 18px }
.materi-sec-txt{ display:flex; align-items:center; gap:9px; min-width:0 }

/* --- Bilah kategori (kanan atas) --- */
/* SATU BARIS: label + dropdown + ikon tidak boleh membungkus. Karena bilah ini
   rata KANAN (margin-left:auto), munculnya ikon Ubah/Hapus menggeser dropdown
   Kategori ke kiri — bukan menurunkannya ke baris kedua. */
.materi-kat-bar{ display:flex; align-items:center; gap:8px; flex-wrap:nowrap; margin-left:auto; min-width:0 }
.materi-kat-lbl{
  font-family:'Plus Jakarta Sans',sans-serif; font-weight:700; font-size:11px; letter-spacing:.2px;
  color:#2b3f48; white-space:nowrap; text-shadow:none; flex:0 0 auto;
}
.materi-kat-lbl .req{ color:var(--red); font-weight:800; margin-left:3px }
.materi-kat-sel{
  font-family:'Plus Jakarta Sans',sans-serif; font-weight:600; font-size:12.5px; letter-spacing:0;
  color:var(--ink); text-shadow:none;
  /* boleh menyusut bila ruang menyempit, supaya barisnya tetap utuh */
  flex:0 1 auto; width:250px; min-width:150px; max-width:320px; height:38px; box-sizing:border-box;
  border:1px solid #cdd9de; border-radius:11px; padding:0 11px;
  background:linear-gradient(180deg,#ffffff,#fafdfe);
  box-shadow:0 1px 2px rgba(16,40,50,.06),inset 0 1px 0 rgba(255,255,255,.6);
  transition:border-color .15s,box-shadow .2s;
}
.materi-kat-sel:hover{ border-color:#a7bec5; box-shadow:0 2px 7px rgba(16,40,50,.09),inset 0 1px 0 rgba(255,255,255,.6) }
.materi-kat-sel:focus{ outline:none; border-color:var(--teal); box-shadow:0 0 0 3px rgba(14,124,134,.16),0 4px 12px rgba(14,124,134,.16); background:#fff }
/* Ikon dibuat PERSEGI (31x31). Sebelumnya tingginya dipatok setinggi dropdown
   (38px) sehingga kotaknya memanjang & tampak gepeng; kini tingginya dikurangi
   agar sama dengan lebarnya, lalu diratakan tengah terhadap dropdown lewat
   align-items:center pada .materi-kat-bar. */
.materi-kat-bar .act{ width:31px; height:31px; border-radius:9px; flex:0 0 auto }
.materi-kat-bar .act svg{ width:14px; height:14px }
/* Ikon di bilah ini pakai warna tombolnya sendiri, jangan diwarnai teal oleh
   aturan .form-section-title svg. */
.form-section-title .materi-kat-bar .act svg{ color:inherit; stroke:currentColor; opacity:1 }

/* --- Nama Materi / Peraturan + Tgl. Terbit + Berkas jadi satu baris --- */
.materi-frow{ align-items:flex-start }
.materi-frow>.materi-f-nama{ flex:1 1 320px; min-width:230px }
.materi-frow>.materi-f-tgl{ flex:0 0 auto; width:max-content; min-width:168px }
.materi-frow>.materi-f-file{ flex:0 0 auto; width:max-content; max-width:100%; margin:0 }
.materi-frow>.materi-f-file .materi-file-bar{
  margin-left:0; justify-content:flex-start; min-height:42px; align-items:center;
}
.materi-frow>.materi-f-file .materi-file-ok{ max-width:320px }
@media (max-width:900px){
  .materi-kat-bar{ margin-left:0; width:100% }
  .materi-kat-sel{ flex:1 1 auto; width:auto; min-width:0; max-width:none }
  .materi-frow>.materi-f-file{ width:100%; max-width:none }
  .materi-frow>.materi-f-file .materi-file-ok{ max-width:100% }
}

/* --- Pop up Buat / Ubah Nama Kategori --- */
.materi-kat-ov{
  display:none; position:fixed; inset:0; z-index:10010;
  background:rgba(16,40,50,.5); align-items:center; justify-content:center; padding:18px;
  backdrop-filter:blur(2px);
}
.materi-kat-modal{
  width:100%; max-width:440px; background:#fff; border-radius:16px;
  box-shadow:0 22px 64px rgba(16,40,50,.38); padding:22px 22px 18px;
  max-height:86vh; overflow:auto; animation:materiKatIn .18s ease-out;
}
@keyframes materiKatIn{ from{ opacity:0; transform:translateY(10px) scale(.985) } to{ opacity:1; transform:none } }
.materi-kat-head{
  display:flex; align-items:center; gap:9px;
  font-family:'Plus Jakarta Sans',sans-serif; font-weight:800; font-size:16px; color:#0b3d42;
}
.materi-kat-head svg{ width:20px; height:20px; color:var(--teal-dark); flex:0 0 auto }
.materi-kat-sub{ font-size:12.5px; color:#5a6b70; margin:8px 0 14px; line-height:1.55 }
.materi-kat-flabel{ display:block; font-size:11px; font-weight:700; color:#2b3f48; margin-bottom:6px }
.materi-kat-input{
  width:100%; box-sizing:border-box; height:42px;
  border:1px solid #cdd9de; border-radius:11px; padding:9px 13px;
  font-size:13px; font-family:'Plus Jakarta Sans',sans-serif; color:var(--ink);
  background:linear-gradient(180deg,#ffffff,#fafdfe);
}
.materi-kat-input:focus{ outline:none; border-color:var(--teal); box-shadow:0 0 0 3px rgba(14,124,134,.16); background:#fff }
.materi-kat-actions{ display:flex; justify-content:flex-end; gap:9px; margin-top:18px; flex-wrap:wrap }
@media (prefers-reduced-motion:reduce){
  .materi-kat-modal{ animation:none }
}


/* ============================================================
   6. LAYOUT SIDEBAR (modern)
   ------------------------------------------------------------
   Menu dipindah dari atas ke samping kiri. Nama kelas .topnav-*
   SENGAJA dipertahankan agar seluruh logika lama di app.js tetap
   berjalan; blok ini hanya mengubah TATA LETAK & tampilannya:

     .topnav-group   -> akordeon (dulu dropdown melayang)
     .topnav-sub     -> akordeon tingkat 2 (dulu flyout ke kanan)
     .topbar-user    -> pindah ke bilah atas ramping (.appbar)

   Ada 2 keadaan sidebar:
     diam              rail ikon 76px
     kursor di atasnya melebar 268px (kelas .is-open), melayang di atas isi
   ============================================================ */
:root{
  --side-w:268px;         /* lebar sidebar terbuka */
  --side-rail:76px;       /* lebar sidebar menciut */
  --appbar-h:58px;        /* tinggi bilah atas ramping */
  --side-1:#052a2f; --side-2:#073f45; --side-3:#0a6067;
}

/* ---------- kerangka ---------- */
.app-shell{display:flex;min-height:100vh;align-items:stretch}
.app-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;margin-left:var(--side-rail)}
/* Ruang isi dilebarkan (dulu 1180px) — sisa ruang dari menu-atas dipakai tabel */
.wrap{max-width:1320px}

/* ---------- SIDEBAR ---------- */
/* Sidebar MELAYANG di atas isi halaman: lebarnya berubah tanpa menggeser
   konten sedikit pun. Keadaan diam = rail ikon; saat kursor menyentuhnya
   (kelas .is-open dari ui-sidebar.js) melebar penuh, lalu menciut sendiri. */
.sidebar-shell{
  position:fixed;top:0;left:0;bottom:0;
  width:var(--side-rail);height:100vh;
  display:flex;flex-direction:column;color:#fff;z-index:70;
  background:
    radial-gradient(420px 220px at 20% 0%, rgba(22,169,181,.30), transparent 62%),
    linear-gradient(168deg,var(--side-1) 0%,var(--side-2) 42%,var(--teal-dark) 76%,var(--side-3) 100%);
  box-shadow:6px 0 20px rgba(5,32,36,.16);
  transition:width .26s cubic-bezier(.16,1,.3,1),box-shadow .26s ease;
}
.sidebar-shell.is-open{width:var(--side-w);box-shadow:14px 0 44px rgba(5,32,36,.34)}
/* Garis aksen beranimasi di tepi kanan (memakai keyframes sheenV yang sudah ada) */
.sidebar-shell::after{
  content:"";position:absolute;top:0;bottom:0;right:0;width:3px;
  background:linear-gradient(180deg,var(--yellow),var(--cyan),var(--yellow));
  background-size:100% 200%;animation:sheenV 7s linear infinite;opacity:.85}
.sidebar-shell .topbar-inner{
  display:flex;flex-direction:column;align-items:stretch;
  /* flex-wrap:nowrap WAJIB. Aturan lama `.topbar-inner{flex-wrap:wrap}` (dipakai
     saat menu masih di atas) membuat kolom ini MEMBELAH JADI DUA KOLOM begitu
     isinya lebih tinggi dari layar — persis yang terjadi di ponsel posisi
     lanskap: merek di kolom kiri, daftar menu terlempar ke kolom kanan. */
  flex-wrap:nowrap;
  gap:0;height:100%;max-width:none;margin:0;padding:0;min-width:0;overflow:hidden}

/* --- kepala: logo + nama --- */
.sidebar-shell .topbar-brand{
  display:flex;align-items:center;gap:12px;flex:0 0 auto;
  padding:18px 18px 16px;border-bottom:1px solid rgba(255,255,255,.10)}
.sidebar-shell .topbar-brand .logo{width:42px;height:42px;flex:0 0 42px;border-radius:12px}
.sidebar-shell .brand{min-width:0;overflow:hidden}
.sidebar-shell .brand h1{font-size:12.5px;line-height:1.25;white-space:normal}
.sidebar-shell .brand span{font-size:8.5px;letter-spacing:1.4px;display:block;margin-top:2px}

/* --- daftar menu --- */
#topnav{
  display:flex;flex:1 1 auto;flex-direction:column;align-items:stretch;gap:2px;
  padding:14px 12px 18px;min-height:0;overflow-y:auto;overflow-x:hidden;
  scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.28) transparent}
#topnav::-webkit-scrollbar{width:6px}
#topnav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.24);border-radius:6px}
#topnav::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.4)}

/* Efek menu-atas yang tak relevan di sidebar dimatikan:
   miring 3D (transform inline dari app.js), garis bawah, dan denyut kuning. */
#topnav .topnav-link,#topnav .topnav-trigger,#topnav .topnav-item,#topnav .topnav-subtrigger{transform:none!important}
#topnav .topnav-link::after,#topnav .topnav-trigger::after,
#topnav .topnav-group.has-active .topnav-trigger::after{display:none}
#topnav .topnav-link.active,#topnav .topnav-group.has-active .topnav-trigger{animation:none}

#topnav .topnav-link,#topnav .topnav-trigger{
  width:100%;justify-content:flex-start;padding:10px 12px;border-radius:12px;
  font-size:12.5px;gap:12px;overflow:hidden;color:rgba(255,255,255,.96)}
#topnav .topnav-link svg,#topnav .topnav-trigger svg:first-of-type{width:18px;height:18px}
#topnav .topnav-link:hover,#topnav .topnav-trigger:hover{background:rgba(255,255,255,.10);box-shadow:none}
#topnav .topnav-link:hover svg,#topnav .topnav-trigger:hover svg:first-of-type{transform:none}
#topnav .topnav-trigger .caret{margin-left:auto;width:14px;height:14px}
#topnav .topnav-link.active,#topnav .topnav-group.has-active .topnav-trigger{
  background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45;
  box-shadow:0 5px 16px rgba(246,180,14,.34)}

/* --- akordeon tingkat 1 (dulu dropdown melayang) --- */
#topnav .topnav-group{position:static}
#topnav .topnav-dropdown{
  position:static;top:auto;left:auto;min-width:0;width:auto;z-index:auto;
  background:none;border:none;box-shadow:none;border-radius:0;
  padding:3px 0 7px 10px;margin:0;animation:sideOpen .22s cubic-bezier(.16,1,.3,1)}
#topnav .topnav-dropdown::before{display:none}
@keyframes sideOpen{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}
#topnav .topnav-item,#topnav .topnav-subtrigger{
  width:100%;text-align:left;padding:9px 12px;margin-left:8px;font-size:11.5px;gap:10px;
  color:rgba(255,255,255,.95);background:none;
  border-left:2px solid rgba(255,255,255,.16);border-radius:0 10px 10px 0}
#topnav .topnav-item svg,#topnav .topnav-subtrigger svg:first-of-type{width:15px;height:15px;color:rgba(255,255,255,.8)}
#topnav .topnav-item:hover,#topnav .topnav-subtrigger:hover{background:rgba(255,255,255,.10);color:#fff}
#topnav .topnav-item:hover svg{transform:none}
#topnav .topnav-item.active{
  background:rgba(255,255,255,.15);color:#fff;border-left-color:var(--yellow);
  font-weight:700;box-shadow:none}
#topnav .topnav-item.active svg{color:var(--yellow)}

/* --- akordeon tingkat 2: Harga Perkiraan Sendiri (dulu flyout ke kanan) --- */
#topnav .topnav-sub{position:static;display:flex;flex-direction:column}
#topnav .topnav-subtrigger .caret2{margin-left:auto;width:13px;height:13px;transition:transform .25s}
#topnav .topnav-sub.open>.topnav-subtrigger{color:#fff;background:rgba(255,255,255,.08)}
#topnav .topnav-sub.open>.topnav-subtrigger .caret2{transform:rotate(180deg)}
#topnav .topnav-subdrop{
  position:static!important;top:auto!important;left:auto!important;right:auto!important;
  min-width:0;width:auto;z-index:auto;background:none;border:none;box-shadow:none;
  border-radius:0;padding:2px 0 4px 12px;margin:0;
  animation:sideOpen .2s cubic-bezier(.16,1,.3,1)}
#topnav .topnav-subdrop .topnav-item{font-size:11px;margin-left:12px;color:rgba(255,255,255,.92)}

/* --- kaki sidebar --- */
/* Label pemisah bagian */
.side-sec{font-size:9px;font-weight:800;letter-spacing:1.4px;text-transform:uppercase;
  color:rgba(255,255,255,.62);padding:15px 14px 5px}
.side-sec:first-child{padding-top:4px}

.side-foot{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid rgba(255,255,255,.10)}
.side-foot .topbar-user{flex-direction:column;align-items:stretch;gap:8px;margin:0}
.side-acct{display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:rgba(255,255,255,.08);border-radius:11px;padding:7px 9px 7px 12px}
.side-acct-lbl{font-size:10.5px;font-weight:700;letter-spacing:.3px;color:rgba(255,255,255,.92);white-space:nowrap}
/* Lencana peran: PUTIH PEKAT + teks teal gelap. Kuning sengaja dihindari
   karena kuning sudah dipakai sebagai penanda "menu yang sedang aktif";
   memakainya di sini membuat dua hal berbeda terlihat sama. */
.side-foot .user-chip{display:inline-flex;align-items:center;gap:7px;padding:4px 12px 4px 5px;
  border-radius:30px;font-size:11px;font-weight:800;color:var(--teal-dark);border:none;
  background:#ffffff;box-shadow:0 2px 8px rgba(3,26,30,.24)}
.side-foot .user-role-ic{width:20px;height:20px;background:var(--teal-soft);box-shadow:none}
.side-foot .user-role-ic svg{width:12px;height:12px;color:var(--teal-dark)}
/* Tombol Keluar: merah pekat + teks putih. Versi transparan sebelumnya
   nyaris menyatu dengan latar teal sehingga sulit terbaca. */
/* Lebarnya secukupnya ikon + teks (bukan selebar sidebar), tetap rata tengah */
.side-logout{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  width:auto;align-self:center;
  padding:8px 18px;border:none;border-radius:11px;
  background:linear-gradient(135deg,var(--red),#e05555);color:#fff;cursor:pointer;
  font-family:'Plus Jakarta Sans';font-size:11.5px;font-weight:800;letter-spacing:.3px;
  box-shadow:0 4px 14px rgba(150,26,26,.38);
  transition:background .16s,box-shadow .18s}
.side-logout svg{width:16px;height:16px;flex:0 0 auto}
.side-logout:hover{background:linear-gradient(135deg,#b22a2a,var(--red));box-shadow:0 6px 18px rgba(150,26,26,.5)}
.side-logout:active{box-shadow:0 2px 8px rgba(150,26,26,.4)}
.side-acct{background:rgba(255,255,255,.11)}
.side-collapse{
  display:flex;align-items:center;gap:11px;width:100%;padding:9px 12px;border:none;
  background:rgba(255,255,255,.07);color:rgba(255,255,255,.8);border-radius:11px;
  font-family:'Plus Jakarta Sans';font-size:11.5px;font-weight:700;cursor:pointer;
  transition:background .16s,color .16s}
.side-collapse svg{width:17px;height:17px;flex:0 0 auto}
.side-collapse:hover{background:rgba(255,255,255,.14);color:#fff}
.side-ver{font-size:9px;font-weight:700;letter-spacing:1.1px;text-transform:uppercase;
  color:rgba(255,255,255,.5);text-align:center;padding-top:9px}

/* ---------- BILAH ATAS RAMPING ---------- */
.appbar{
  position:sticky;top:0;z-index:55;flex:0 0 auto;min-height:var(--appbar-h);
  display:flex;align-items:center;gap:14px;padding:9px 22px;
  background:rgba(255,255,255,.86);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--line);box-shadow:0 1px 3px rgba(16,40,50,.05)}
.appbar .nav-burger{
  display:inline-flex;flex:0 0 auto;width:36px;height:36px;border-radius:11px;
  background:#f4f9fa;border:1px solid var(--line);color:var(--teal-dark);
  transition:background .16s,color .16s,border-color .16s}
.appbar .nav-burger:hover{background:var(--teal-soft);border-color:#bfe0e3}
.appbar .nav-burger svg{width:18px;height:18px}
.appbar-crumb{min-width:0;display:flex;flex-direction:column;justify-content:center;line-height:1.25}
.crumb-path{font-size:10.5px;font-weight:600;color:var(--muted);letter-spacing:.2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.crumb-now{font-size:14px;font-weight:800;color:var(--ink);letter-spacing:-.2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.appbar .topbar-user{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;gap:10px}
/* Ikon gear semula putih di atas latar teal — di bilah putih dibalik warnanya */
/* ---------- KEADAAN MENCIUT (rail ikon) ----------
   HANYA untuk perangkat berkursor & layar lebar. Di layar sentuh sidebar
   selalu berupa laci geser penuh, jadi tak satu pun aturan rail boleh
   ikut berlaku di sana (dulu bocor: kotak "Jenis Akun" hilang dan tombol
   Keluar menyusut jadi ikon di dalam laci). */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) .brand,
  .sidebar-shell:not(.is-open) .side-sec,
  .sidebar-shell:not(.is-open) .side-ver{opacity:0;pointer-events:none}
  .sidebar-shell:not(.is-open) .brand,
  .sidebar-shell:not(.is-open) .side-ver{display:none}
  .sidebar-shell:not(.is-open) .side-sec{height:9px;padding:6px 0 0;overflow:hidden}
  .sidebar-shell:not(.is-open) .topbar-brand{justify-content:center;padding:18px 0 16px}
  .sidebar-shell:not(.is-open) #topnav{padding:14px 0;align-items:center;gap:5px;overflow:hidden}
  .sidebar-shell:not(.is-open) #topnav .topnav-link,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
    width:46px;height:44px;padding:0;justify-content:center;border-radius:13px;gap:0;
    font-size:0;letter-spacing:0;background:rgba(255,255,255,.07)}
  .sidebar-shell:not(.is-open) #topnav .topnav-link:hover,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger:hover{background:rgba(255,255,255,.16)}
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger{
    background:linear-gradient(135deg,var(--yellow),#ffd35a)}
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger .caret{display:none}
  .sidebar-shell:not(.is-open) #topnav .topnav-dropdown{display:none}
  .sidebar-shell:not(.is-open) .side-foot{padding:8px 0 10px}
  .sidebar-shell:not(.is-open) .side-acct{display:none}
  .sidebar-shell:not(.is-open) .side-logout-lbl{display:none}
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */

  /* Nama menu memudar masuk saat melebar — bukan muncul mendadak */
  .sidebar-shell #topnav .topnav-link,
  .sidebar-shell #topnav .topnav-trigger{transition:background .16s,color .16s,width .24s cubic-bezier(.16,1,.3,1)}
}

/* ---------- LAYAR KECIL & PERANGKAT SENTUH: sidebar = laci geser ----------
   `(hover:none)` SAJA TIDAK CUKUP UNTUK iPad (9 Agu 2026).
   Laporan: di iPad 11" lanskap sidebar tampil sebagai rel desktop yang menimpa
   isi dan "sering berkedip"; di potret pun diminta jadi tombol tiga garis
   seperti di ponsel.

   Sebabnya penanda perangkatnya. `hover` menjawab "alat penunjuk UTAMA bisa
   menggantung?" - dan iPadOS yang dipasangi papan ketik bertrackpad menjawab
   `hover:hover` + `pointer:fine`, persis seperti komputer. Akibatnya iPad
   lanskap (1194px, di atas ambang 1024px) jatuh ke mode desktop: rel sempit
   yang MELEBAR SAAT DISENTUH. Di layar sentuh keadaan :hover itu menyala-padam
   tak menentu, dan karena lebarnya beranimasi 0,26 detik, yang terlihat adalah
   sidebar berkedip melebar-menyempit sendiri.

   `any-pointer:coarse` menjawab pertanyaan yang benar: "ADA alat penunjuk kasar
   (layar sentuh)?" - selalu benar di iPad, dengan atau tanpa trackpad, dan
   selalu salah di komputer tanpa layar sentuh. Ditambahkan sebagai alternatif,
   bukan pengganti, supaya perangkat lama yang hanya mengenali `hover:none`
   tetap terlayani.

   Efeknya untuk ketiga keluhan sekaligus: lanskap tidak lagi memakai rel yang
   melebar saat disentuh (berkedip hilang), laci menutup penuh dari atas ke
   bawah (celah saat melenting hilang), dan potret memakai tombol tiga garis
   sama seperti ponsel. */
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  .sidebar-shell,.sidebar-shell.is-open{
    width:284px;max-width:86vw;transform:translateX(-100%);
    transition:transform .28s cubic-bezier(.16,1,.3,1);z-index:90;box-shadow:none}
  body.nav-open .sidebar-shell{transform:none;box-shadow:0 0 50px rgba(0,0,0,.45)}
  .app-main{margin-left:0;width:100%;min-width:0}
  #topnav{position:static;transform:none;background:none;box-shadow:none;width:auto;max-width:none;
    padding:14px 12px 18px;overflow-y:auto}
  .topnav-backdrop{z-index:80}
  .appbar{padding:9px 14px}
}
/* Tombol ☰ hanya untuk layar kecil — di desktop sidebar melebar sendiri */
.appbar .nav-burger{display:none}
@media (max-width:1024px), (hover:none), (any-pointer:coarse){ .appbar .nav-burger{display:inline-flex} }
@media (max-width:640px){
  .wrap{padding:16px}
  .crumb-path{display:none}
}

/* ---------- PRATINJAU FILE: LAYAR PENUH ---------- */
.pn-preview-head-actions .pn-fs-btn{
  background:linear-gradient(135deg,var(--teal),var(--cyan));color:#fff;border:none;
  box-shadow:0 4px 12px rgba(14,124,134,.28)}
.pn-preview-head-actions .pn-fs-btn:hover{filter:brightness(1.06)}
.pn-preview-head-actions .pn-fs-btn.is-on{
  background:linear-gradient(135deg,#0b5b63,#0e7c86);box-shadow:0 4px 12px rgba(11,91,99,.34)}
/* Saat benar-benar layar penuh: modal mengisi seluruh layar, isi ikut memanjang */
.pn-preview-modal:fullscreen,
.pn-preview-modal:-webkit-full-screen{
  width:100vw;max-width:100vw;height:100vh;max-height:100vh;border-radius:0;
  background:#fff;margin:0;animation:none}
.pn-preview-modal:fullscreen .pn-preview-body iframe,
.pn-preview-modal:-webkit-full-screen .pn-preview-body iframe{height:calc(100vh - 62px)}
.pn-preview-modal:fullscreen .pn-preview-body.has-tabs iframe,
.pn-preview-modal:-webkit-full-screen .pn-preview-body.has-tabs iframe{height:calc(100vh - 62px - 46px)}
.pn-preview-modal:fullscreen .pn-preview-body img,
.pn-preview-modal:-webkit-full-screen .pn-preview-body img{max-height:calc(100vh - 62px)}
@media(max-width:640px){
  .pn-preview-head-actions .btn{padding:7px 10px}
  .pn-preview-head-actions .pn-fs-btn span{display:none}
}


/* ============================================================
   7. TABEL "PEMBUKAAN PENAWARAN" — pembagian lebar kolom
   ------------------------------------------------------------
   Tujuan: seluruh kolom muat tanpa geser kiri-kanan.
     Lokasi Pekerjaan   : lebarnya dipangkas 20%, jatahnya
                          diberikan ke Nama Pekerjaan
     Tgl. Pembukaan     : selebar teks tanggalnya, judul boleh
                          membungkus sampai 2 baris
     Metode Penyampaian : judul dijaga 2 baris (bukan 3)
   ============================================================ */
/* Nama Pekerjaan: 240/300 + 20% jatah Lokasi (48px) */
#view-pnw-view .table-wrap th.col-nama-freeze,
#view-pnw-view .table-wrap td.col-nama-freeze{
  min-width:256px; max-width:348px;
}
/* Lokasi Pekerjaan: 170/240 dikurangi 20% -> 136/192, isinya boleh membungkus */
#view-pnw-view .table-wrap th.fkl-col-lokasi,
#view-pnw-view .table-wrap td.fkl-col-lokasi{
  white-space:normal;
  min-width:124px; max-width:192px;
  word-break:break-word; overflow-wrap:break-word; line-height:1.3;
}
/* Metode Pengadaan: secukupnya isi */
#view-pnw-view .table-wrap th.pnw-col-jenis,
#view-pnw-view .table-wrap td.pnw-col-jenis{width:1%; white-space:nowrap;}
/* Metode Penyampaian Dokumen: judul 2 baris ("METODE PENYAMPAIAN" / "DOKUMEN") */
#view-pnw-view .table-wrap th.pnw-col-metode,
#view-pnw-view .table-wrap td.pnw-col-metode{
  min-width:150px; width:1%;
}
/* Tgl. Pembukaan Penawaran: judul 2 baris, kolom menyusut mengikuti isinya.
   Aturan .col-date umum memakai !important, jadi di sini juga. */
#view-pnw-view .table-wrap th.pnw-col-tgl{
  white-space:normal !important;
  width:1% !important;
  min-width:96px !important;
  max-width:none !important;
}
#view-pnw-view .table-wrap td.pnw-col-tgl{ min-width:96px !important; }
/* Tabel mengikuti lebar panel, bukan lebar minimum global 980px */
#view-pnw-view .table-wrap table{ min-width:0; width:100%; }


/* ============================================================
   8. PRATINJAU LAYAR PENUH — kepala tetap tampil, isi penuh layar
   ------------------------------------------------------------
   Modal bawaan dibatasi max-height:92vh & lebar 980px. Batas itu
   harus dilepas saat benar-benar layar penuh, kalau tidak isinya
   berhenti di tengah layar dan sisanya kosong.
   ============================================================ */
.pn-preview-modal:fullscreen,
.pn-preview-modal:-webkit-full-screen{
  width:100vw; max-width:100vw;
  height:100vh; max-height:100vh;
  margin:0; border-radius:0; background:#fff;
  display:flex; flex-direction:column; animation:none;
}
.pn-preview-modal:fullscreen .detail-head,
.pn-preview-modal:-webkit-full-screen .detail-head{
  flex:0 0 auto; padding:12px 22px;
  background:linear-gradient(100deg,var(--teal-dark),var(--teal));
}
/* Sisa tinggi layar sepenuhnya milik isi dokumen */
.pn-preview-modal:fullscreen .pn-preview-body,
.pn-preview-modal:-webkit-full-screen .pn-preview-body{
  flex:1 1 auto; min-height:0; height:auto;
}
.pn-preview-modal:fullscreen .pn-preview-body iframe,
.pn-preview-modal:-webkit-full-screen .pn-preview-body iframe{
  height:100% !important; width:100%; border:none;
}
.pn-preview-modal:fullscreen .pn-preview-body.has-tabs iframe,
.pn-preview-modal:-webkit-full-screen .pn-preview-body.has-tabs iframe{
  height:calc(100% - 46px) !important;
}
.pn-preview-modal:fullscreen .pn-preview-body img,
.pn-preview-modal:-webkit-full-screen .pn-preview-body img{
  max-height:100%; max-width:100%; margin:auto;
}

/* ============================================================
   9. BILAH FILTER (.toolbar) — kotak penuh selebar halaman
   ------------------------------------------------------------
   Sebelumnya width:fit-content + margin-left:auto membuat seluruh
   bilah mengambang ke kanan dan menyisakan ruang kosong di kiri.
   ============================================================ */
.toolbar{
  width:100%;
  margin-left:0; margin-right:0;
  justify-content:flex-start;
}
/* RESET MENEMPEL KE INPUT DATA (7 Agu 2026).
   Aturan lama mendorong tombol TERAKHIR ke pojok kanan lewat `margin-left:auto`,
   sehingga sisa lebar halaman menumpuk sebagai celah kosong TEPAT DI ANTARA
   Reset dan Input Data — terukur 123px pada layar 1600px. Padahal keduanya
   sama-sama tombol aksi; memisahkannya sejauh itu membuat mereka terbaca
   seperti dua kelompok yang tidak berhubungan.
   Sekarang seluruh kelompok aksi didorong utuh ke kanan (`margin-left:auto`
   pada wadahnya), jaraknya kembali ke gap 12px milik wadah itu, dan sisa lebar
   diserap kolom Cari (lihat .toolbar .toolbar-search di bagian atas berkas). */
.toolbar .toolbar-actions{margin-left:auto; flex:0 0 auto; justify-content:flex-end}


/* ============================================================
   10. BILAH ATAS DIHILANGKAN DI LAYAR LEBAR
   ------------------------------------------------------------
   Isinya tinggal judul halaman, dan judul itu sudah ada di dalam
   halaman (h2 + lencana jumlah) — jadi hanya kembar. Di layar
   kecil bilah ini tetap ada karena memuat tombol ☰ pembuka laci.
   Jejak halaman tetap dihitung ui-sidebar.js untuk judul tab
   peramban (document.title).
   ============================================================ */
.appbar{display:none}
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  .appbar{display:flex}
}

/* Kontras teks sidebar: putih pudar sulit dibaca di atas gradien teal,
   terutama pada isi grup (mis. Pengaturan). Ditegaskan di sini. */
.sidebar-shell{-webkit-font-smoothing:antialiased}
#topnav .topnav-item,#topnav .topnav-subtrigger{font-weight:650}
#topnav .topnav-item{border-left-color:rgba(255,255,255,.28)}


/* ============================================================
   11. PENYESUAIAN PERANGKAT BERGERAK (iPhone / Android / iPad)
   ------------------------------------------------------------
   a) 100dvh menggantikan 100vh — di peramban ponsel, 100vh dihitung
      seolah bilah alamat selalu tersembunyi, sehingga kaki sidebar
      (Jenis Akun & Keluar) terdorong ke bawah layar.
   b) Safe area iPhone berponi: sidebar & isi halaman tidak masuk
      ke bawah poni saat lanskap, dan tidak tertutup batang beranda.
   c) Layar pendek (ponsel lanskap): kepala & kaki sidebar dipadatkan
      agar daftar menu tetap kebagian ruang.
   ============================================================ */
@supports (height:100dvh){
  .sidebar-shell{height:100dvh}
  .table-wrap{max-height:calc(100dvh - 250px)}
  .pn-preview-modal{max-height:92dvh}
  .pn-preview-modal:fullscreen,
  .pn-preview-modal:-webkit-full-screen{height:100dvh; max-height:100dvh}
}
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  /* a. Judul halaman di bilah atas juga kembar dengan judul di dalam
        halaman — cukup jejaknya saja yang tampil, kecil dan tidak menonjol. */
  .crumb-now{display:none}
  .crumb-path{display:block;font-size:11.5px;font-weight:700;color:var(--teal-dark)}
  .appbar{min-height:52px}

  /* b. Safe area */
  .sidebar-shell{padding-left:env(safe-area-inset-left)}
  .side-foot{padding-bottom:calc(12px + env(safe-area-inset-bottom))}
  .appbar{padding-left:calc(14px + env(safe-area-inset-left));
          padding-right:calc(14px + env(safe-area-inset-right))}
  .wrap{padding-left:calc(16px + env(safe-area-inset-left));
        padding-right:calc(16px + env(safe-area-inset-right));
        padding-bottom:calc(20px + env(safe-area-inset-bottom))}

  /* Sasaran sentuh minimal ±40px */
  #topnav .topnav-link,#topnav .topnav-trigger{padding:11px 12px}
  #topnav .topnav-item,#topnav .topnav-subtrigger{padding:10px 12px}
}

/* c. Ponsel dalam posisi lanskap: tinggi layar tinggal ±380-430px */
@media (max-height:520px) and (orientation:landscape){
  .sidebar-shell .topbar-brand{padding:10px 14px}
  .sidebar-shell .topbar-brand .logo{width:32px;height:32px;flex:0 0 32px}
  .sidebar-shell .brand h1{font-size:11px}
  .sidebar-shell .brand span{display:none}
  #topnav{padding:8px 10px}
  #topnav .topnav-link,#topnav .topnav-trigger{padding:8px 11px}
  .side-sec{padding:9px 13px 3px}
  .side-foot{padding:7px 10px calc(8px + env(safe-area-inset-bottom))}
  .side-acct{padding:5px 8px 5px 11px}
  .side-ver{display:none}
  .table-wrap{min-height:180px;max-height:calc(100dvh - 150px)}
  .appbar{min-height:46px;padding-top:6px;padding-bottom:6px}
}

/* Modal pratinjau di layar sempit: kepala tidak boleh terdorong keluar */
@media (max-width:820px){
  .pn-preview-modal{width:100vw;max-width:100vw;border-radius:0;max-height:100dvh;height:100dvh}
  .detail-head{padding:12px 14px;gap:10px}
  .pn-preview-modal .detail-head h3{font-size:12.5px;line-height:1.3;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .pn-preview-head-actions{gap:6px;flex:0 0 auto}
  .pn-preview-head-actions .btn{padding:8px 10px;font-size:10.5px}
  .pn-preview-body iframe,.pn-preview-body img{height:auto;max-height:none}
  .pn-preview-body{height:auto;flex:1 1 auto;min-height:0}
  .pn-preview-body iframe{height:100%}
}

/* Anak-anak daftar menu TIDAK BOLEH menyusut. Dalam flex-column yang tingginya
   terbatas (ponsel lanskap), bawaan flex-shrink:1 memampatkan tiap tombol
   sampai isinya saling tindih. Yang benar: ukurannya tetap, daftarnya digulir. */
#topnav>*{flex:0 0 auto}
#topnav .topnav-dropdown>*,#topnav .topnav-subdrop>*{flex:0 0 auto}
.sidebar-shell .topbar-brand,.sidebar-shell .side-foot{flex:0 0 auto}
.side-foot .topbar-user>*{flex:0 0 auto}


/* ============================================================
   12. PRATINJAU DI PERANGKAT SENTUH (iPad / iPhone / Android)
   ------------------------------------------------------------
   Fullscreen API di Safari iPad mudah terlepas: sedikit gulir ke
   atas sudah menutup mode layar penuh. Karena itu di perangkat
   sentuh dipakai "layar penuh semu" — modal dibuat menutupi
   seluruh viewport lewat CSS, bukan lewat Fullscreen API.
   ============================================================ */
.pn-preview-modal.pn-fs-semu{
  position:fixed; inset:0; z-index:200;
  width:100vw; max-width:100vw;
  height:100vh; max-height:100vh;
  margin:0; border-radius:0;
  display:flex; flex-direction:column;
}
@supports (height:100dvh){
  .pn-preview-modal.pn-fs-semu{height:100dvh; max-height:100dvh}
}
.pn-preview-modal.pn-fs-semu .detail-head{
  flex:0 0 auto;
  padding-top:calc(12px + env(safe-area-inset-top));
  padding-left:calc(14px + env(safe-area-inset-left));
  padding-right:calc(14px + env(safe-area-inset-right));
}
.pn-preview-modal.pn-fs-semu .pn-preview-body{flex:1 1 auto; min-height:0; height:auto}
.pn-preview-modal.pn-fs-semu .pn-preview-body iframe{height:100% !important; width:100%; border:none}
.pn-preview-modal.pn-fs-semu .pn-preview-body.has-tabs iframe{height:calc(100% - 46px) !important}
.pn-preview-modal.pn-fs-semu .pn-preview-body img{max-height:100%; max-width:100%; margin:auto}

/* Gulir tidak merembet ke halaman di belakangnya — inilah yang membuat
   pratinjau terasa "bisa ditarik ke bawah" dan layar penuh ikut terlepas. */
.overlay,
.pn-preview-body,
.pn-preview-body.fkl-preview-body{overscroll-behavior:contain}
.pn-preview-body{-webkit-overflow-scrolling:touch}
/* Halaman di belakang dikunci selama pratinjau terbuka */
body.pratinjau-terbuka{overflow:hidden}

/* Dokumen selalu di tengah bidang pratinjau */
.pn-preview-body.fkl-preview-body{text-align:center}
.pn-preview-body>img{margin-left:auto;margin-right:auto}


/* ============================================================
   13. PENANDA HALAMAN AKTIF — kuning menandai ITEM YANG DIPILIH
   ------------------------------------------------------------
   Sebelumnya kuning jatuh ke grup induk (mis. "Form"), padahal yang
   sedang dibuka adalah salah satu isinya. Sekarang kuning menandai
   sub menu / sub-sub menu yang benar-benar dipilih; induknya cukup
   diberi latar putih transparan sebagai petunjuk jalur.
   Halo kuning (box-shadow) dibuang — halo itulah yang membuat
   tulisan tampak berbayang / buram.
   ============================================================ */
#topnav .topnav-link.active,
#topnav .topnav-group.has-active .topnav-trigger,
#topnav .topnav-item.active{box-shadow:none !important; animation:none !important; text-shadow:none}

/* Induk dari halaman aktif: penanda jalur, bukan penanda halaman */
#topnav .topnav-group.has-active .topnav-trigger{
  background:rgba(255,255,255,.12);
  color:#fff;
  font-weight:700;
}
#topnav .topnav-group.has-active .topnav-trigger svg:first-of-type{color:#ffd76a}

/* Sub menu & sub-sub menu yang dipilih -> KUNING */
#topnav .topnav-item.active{
  background:linear-gradient(135deg,var(--yellow),#ffd35a);
  color:#073f45;
  font-weight:800;
  border-left-color:#ffe08a;
}
#topnav .topnav-item.active svg{color:#073f45}
#topnav .topnav-item.active:hover{background:linear-gradient(135deg,#ffc22b,#ffdc74);color:#073f45}

/* Induk sub-sub menu (mis. "Harga Perkiraan Sendiri") */
#topnav .topnav-sub.open>.topnav-subtrigger{
  background:rgba(255,255,255,.12); color:#fff; font-weight:700}
#topnav .topnav-sub.open>.topnav-subtrigger svg:first-of-type{color:#ffd76a}

/* Menu tunggal (Dashboard, Penetapan, Susun Kontrak) memang halamannya
   sendiri, jadi tetap kuning — hanya halonya yang dihapus. */
#topnav .topnav-link.active{background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45}


/* ============================================================
   14. TABEL "DATA PEKERJAAN" & "KELENGKAPAN DOKUMEN PENGADAAN"
   ------------------------------------------------------------
   a) Judul kolom boleh turun baris, TAPI maksimal 2 baris.
   b) Kolom Rencana Anggaran Biaya & Aksi menyusut mengikuti
      isinya (width:1% + nowrap = "shrink to fit"), bukan
      memakai lebar tetap yang menyisakan ruang kosong.
   c) Isian Metode Pengadaan rata tengah.
   d) Angka Rencana Anggaran Biaya TIDAK ditebalkan lagi supaya
      seragam dengan kolom lain.
   ============================================================ */

/* a. Judul kolom dibatasi 2 baris (sisanya dipotong dengan elipsis).
      Dibungkus <span> karena -webkit-box tidak boleh dipasang pada
      elemen <th> — itu akan merusak tata letak tabel. */
.table-wrap thead th .th-2l{
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;line-height:1.25;white-space:normal
}

/* Berlaku hanya untuk dua halaman ini agar tabel lain tidak ikut berubah */
#view-dp-view .table-wrap th.col-metode,
#view-dp-view .table-wrap td.col-metode,
#view-fkl-view .table-wrap th.col-metode,
#view-fkl-view .table-wrap td.col-metode{
  text-align:center;white-space:nowrap;padding-left:10px;padding-right:10px
}

/* b1. Rencana Anggaran Biaya — selebar data terpanjang; bila judulnya masih
       lebih lebar, judul yang mengalah (turun jadi 2 baris). */
#view-dp-view .table-wrap th.col-rab,
#view-fkl-view .table-wrap th.col-rab{
  width:1%;min-width:0;white-space:normal;text-align:center;
  padding-left:10px;padding-right:10px
}
#view-dp-view .table-wrap td.col-rab,
#view-fkl-view .table-wrap td.col-rab{
  width:1%;min-width:0;white-space:nowrap;text-align:right;
  font-weight:400;                    /* d. tanpa bold */
  padding-left:10px;padding-right:10px
}

/* b2. Kolom Aksi — persis selebar deretan tombolnya */
#view-dp-view .table-wrap th.col-aksi,
#view-dp-view .table-wrap td.col-aksi,
#view-fkl-view .table-wrap th.col-aksi,
#view-fkl-view .table-wrap td.col-aksi{
  width:1%;min-width:0;white-space:nowrap;text-align:center;
  padding-left:8px;padding-right:8px
}
#view-dp-view .table-wrap td.col-aksi .action-cell,
#view-fkl-view .table-wrap td.col-aksi .action-cell{justify-content:center}

/* Kolom Bidang Pelaksana: lebar tetap & teks di-wrap, sama seperti
   kolom sejenis pada tabel Monitoring. */
#view-dp-view .table-wrap th.col-bidang-pel,
#view-dp-view .table-wrap td.col-bidang-pel{
  width:180px;min-width:180px;max-width:180px;
  white-space:normal;word-break:break-word;overflow-wrap:break-word;line-height:1.3
}

/* Lokasi Pekerjaan di Data Pekerjaan mengikuti aturan yang sudah dipakai
   di Kelengkapan Dokumen (semula hanya berlaku di #view-fkl-view). */
#view-dp-view th.fkl-col-lokasi,#view-dp-view td.fkl-col-lokasi{
  white-space:normal;min-width:170px;max-width:240px;
  word-break:break-word;overflow-wrap:break-word;line-height:1.3
}

/* Layar sempit: tabel tetap utuh dan digulir mendatar (tidak dipampatkan),
   sehingga susunan kolomnya persis seperti di desktop. */
@media (max-width:1024px){
  #view-dp-view .table-wrap table,
  #view-fkl-view .table-wrap table{min-width:1040px}
}


/* ============================================================
   15. LACI NAVIGASI DI PERANGKAT SENTUH — TUTUP SAAT DIKETUK DI LUAR
   ------------------------------------------------------------
   Masalah: aturan lama yang menampilkan scrim (.topnav-backdrop.show)
   hanya hidup di dalam @media (max-width:1024px). Padahal laci geser
   sendiri sudah aktif untuk `(max-width:1024px) ATAU (hover:none), (any-pointer:coarse)`.
   Akibatnya di iPad LANSKAP (lebar 1194/1366 px, tetapi layar sentuh)
   laci tetap terbuka sementara scrim-nya tak pernah tampil — jadi
   ketukan di luar navigasi tidak mengenai apa pun dan menu baru
   tertutup setelah salah satu menu dipilih.
   Perbaikan: syarat scrim disamakan persis dengan syarat laci geser.
   ============================================================ */
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  .topnav-backdrop{
    display:block;position:fixed;inset:0;background:rgba(7,40,44,.5);
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .25s;z-index:80;
    -webkit-tap-highlight-color:transparent
  }
  /* Terlihat & bisa diketuk bila laci sedang terbuka. Dua penanda dipakai
     sekaligus (.show dari toggleMobileNav dan body.nav-open) supaya tetap
     benar walau salah satunya luput dipasang. */
  .topnav-backdrop.show,
  body.nav-open .topnav-backdrop{
    opacity:1;visibility:visible;pointer-events:auto
  }
}
/* Di layar besar non-sentuh scrim tidak pernah dipakai */
@media (min-width:1025px) and (hover:hover){
  .topnav-backdrop,.topnav-backdrop.show{display:none!important}
}


/* ============================================================
   16. PRATINJAU DOKUMEN DI PERAMBAN MOBILE — PRESISI SEPERTI DESKTOP
   ------------------------------------------------------------
   Tiga hal yang membuat pratinjau di HP/tablet tidak sama dengan
   di desktop, diperbaiki di sini:

   a) SATUAN TINGGI. Nilai 92vh / 74vh / 64vh dihitung peramban
      ponsel seolah bilah alamat selalu tersembunyi, sehingga tepi
      bawah dokumen (dan kadang tombol) terpotong keluar layar.
      Diganti dvh — tinggi yang benar-benar terlihat.

   b) SYARAT LAYAR SENTUH. Tata letak "menutupi layar" dulu hanya
      untuk lebar <= 820 px, padahal iPad potret 834 px dan iPad
      lanskap 1194/1366 px juga layar sentuh. Syaratnya disamakan
      dengan bagian lain: `(max-width:820px) ATAU (hover:none)`.

   c) KEPALA MODAL. Judul panjang mendorong tombol Layar Penuh &
      tombol tutup keluar layar. Sekarang judul yang mengalah.
   ============================================================ */

/* a. Satuan tinggi yang benar untuk peramban ponsel */
@supports (height:100dvh){
  .pn-preview-modal{max-height:92dvh}
  .pn-preview-body iframe{height:74dvh}
  .pn-preview-body.has-tabs iframe{height:calc(74dvh - 46px)}
  .pn-preview-body img{max-height:74dvh}
  .pn-preview-body.fkl-preview-body #fkl-preview-frame{height:74dvh}
  .pn-preview-modal.is-max{height:100dvh;max-height:100dvh}
  .pn-preview-modal.is-max .pn-preview-body iframe{height:calc(100dvh - 62px)}
  .pn-preview-modal.is-max .pn-preview-body.has-tabs iframe{height:calc(100dvh - 62px - 46px)}
  .pn-preview-modal.is-max .pn-preview-body img{max-height:calc(100dvh - 62px)}
  .pn-preview-modal.is-max .pn-preview-body.fkl-preview-body #fkl-preview-frame{height:calc(100dvh - 62px)}
}

/* b. Semua perangkat sentuh (termasuk iPad potret & lanskap) memakai
      pratinjau selebar layar — sama seperti yang sudah berlaku di ponsel. */
@media (max-width:820px), (hover:none), (any-pointer:coarse){
  .pn-preview-modal{
    width:100vw;max-width:100vw;border-radius:0;
    height:100vh;max-height:100vh;margin:0
  }
  .pn-preview-modal .detail-head{
    padding:12px 14px;gap:10px;flex:0 0 auto;
    padding-top:calc(12px + env(safe-area-inset-top));
    padding-left:calc(14px + env(safe-area-inset-left));
    padding-right:calc(14px + env(safe-area-inset-right))
  }
  /* c. Judul mengalah, tombol tidak pernah terdorong keluar */
  .pn-preview-modal .detail-head h3{
    flex:1 1 auto;min-width:0;font-size:12.5px;line-height:1.3;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden
  }
  .pn-preview-head-actions{flex:0 0 auto;gap:6px}
  .pn-preview-head-actions .btn{padding:8px 10px;font-size:10.5px}

  /* Badan pratinjau mengisi sisa ruang — tidak lagi memakai tinggi tetap
     (74vh/64vh) yang membuat dokumen terpotong atau menyisakan celah. */
  .pn-preview-body{flex:1 1 auto;min-height:0;height:auto;overflow:auto}
  .pn-preview-body iframe,
  .pn-preview-body.fkl-preview-body #fkl-preview-frame{height:100%;max-height:none}
  .pn-preview-body.has-tabs iframe{height:calc(100% - 46px)}
  .pn-preview-body img{height:auto;max-height:100%;max-width:100%;margin:auto}
  .pn-preview-body{padding-bottom:env(safe-area-inset-bottom)}
}
@supports (height:100dvh){
  @media (max-width:820px), (hover:none), (any-pointer:coarse){
    .pn-preview-modal{height:100dvh;max-height:100dvh}
  }
}

/* Dokumen A4 yang diperkecil agar muat (lihat fitDokumen di ui-sidebar.js)
   tetap berada di TENGAH bidang, bukan menempel ke kiri. */
@media (max-width:820px), (hover:none), (any-pointer:coarse){
  .pn-preview-body{display:flex;align-items:flex-start;justify-content:center}
  .pn-preview-body>iframe{flex:1 1 auto;align-self:stretch}
}

/* Lapisan pembungkus pop-up punya padding 20px. Di layar sentuh padding itu
   membuat pratinjau "selebar layar" tetap menyisakan bingkai abu-abu 20px di
   keempat sisi — dan tinggi 100dvh-nya jadi meluber keluar layar. */
@media (max-width:820px), (hover:none), (any-pointer:coarse){
  #pn-preview-overlay{padding:0}
}


/* ============================================================
   17. TABEL "JADWAL PELAKSANAAN PENGADAAN"
   ------------------------------------------------------------
   Kolom Lokasi Pekerjaan ditambahkan sesudah Nama Pekerjaan.
   Durasi Pengadaan & Aksi menyusut mengikuti isinya; judul
   Durasi Pengadaan boleh turun maksimal 2 baris.
   ============================================================ */
#view-jadwal-view .table-wrap th.col-durasi{
  width:1%;min-width:0;white-space:normal;text-align:center;
  padding-left:10px;padding-right:10px
}
#view-jadwal-view .table-wrap td.col-durasi{
  width:1%;min-width:0;white-space:nowrap;text-align:center;
  padding-left:10px;padding-right:10px
}
#view-jadwal-view .table-wrap th.col-aksi,
#view-jadwal-view .table-wrap td.col-aksi{
  width:1%;min-width:0;white-space:nowrap;text-align:center;
  padding-left:8px;padding-right:8px
}
#view-jadwal-view .table-wrap td.col-aksi .action-cell{justify-content:center}
#view-jadwal-view th.fkl-col-lokasi,#view-jadwal-view td.fkl-col-lokasi{
  white-space:normal;min-width:170px;max-width:240px;
  word-break:break-word;overflow-wrap:break-word;line-height:1.3
}
@media (max-width:1024px){
  #view-jadwal-view .table-wrap table{min-width:1040px}
}


/* ============================================================
   18. IKON MENU AKTIF DI SIDEBAR MENCIUT (RAIL) — JANGAN MENYAMAR
   ------------------------------------------------------------
   Gejala: saat sidebar masih berupa deretan ikon, menu bergrup
   (Monitoring, Form, Dokumen, Pengaturan) yang sedang dibuka
   memang mendapat kapsul KUNING — tetapi ikonnya tetap memakai
   warna kuning #ffd76a dari aturan "penanda jalur" di bagian 13.
   Kuning di atas kuning = ikonnya seolah menghilang. Hanya
   Dashboard yang terlihat benar karena ia .topnav-link.active
   yang warnanya sudah disetel gelap.

   Perbaikan: di dalam rail, SEMUA menu aktif — baik menu tunggal
   maupun menu bergrup — memakai kapsul kuning dengan ikon & teks
   biru-tua, persis seperti Dashboard.
   ============================================================ */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger{
    background:linear-gradient(135deg,var(--yellow),#ffd35a);
    color:#073f45
  }
  /* Ikon mengikuti warna teks (currentColor) — dipaksa gelap supaya
     kontrasnya sama dengan Dashboard. */
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active svg,
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active svg:first-of-type,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger svg,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger svg:first-of-type{
    color:#073f45
  }
  /* Menyentuh ikon yang sedang aktif tidak boleh mengembalikannya jadi
     kapsul putih transparan. */
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active:hover,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger:hover{
    background:linear-gradient(135deg,#ffc22b,#ffdc74);
    color:#073f45
  }
}


/* ============================================================
   19. JUDUL KOLOM 2 BARIS — UTUH, TIDAK DIPOTONG ELIPSIS
   ------------------------------------------------------------
   Cara lama (-webkit-line-clamp:2) memotong baris ketiga menjadi
   "RENCANA ANGGARAN…". Sekarang pemenggalannya ditentukan sendiri
   lewat <br> dan tiap barisnya dilarang membungkus (nowrap),
   sehingga:
     - judulnya PASTI 2 baris dan PASTI utuh;
     - kolomnya otomatis minimal selebar baris terpanjang judul.
   Bila datanya lebih lebar dari judul, data yang menentukan lebar.
   ============================================================ */
.table-wrap thead th.th-2b{
  white-space:nowrap;line-height:1.25;text-align:center;
  padding-left:10px;padding-right:10px
}
/* Kalibrasi ulang: lebar kolom = MAX(isian terpanjang, judul 2 baris) */
#view-dp-view .table-wrap th.col-rab,
#view-fkl-view .table-wrap th.col-rab,
#view-jadwal-view .table-wrap th.col-durasi{
  width:1%;min-width:0;white-space:nowrap
}

/* ============================================================
   20. PEMBAGIAN LEBAR: NAMA PEKERJAAN -> BIDANG PELAKSANA
   ------------------------------------------------------------
   Kolom Nama Pekerjaan menyerap hampir semua sisa ruang tabel,
   sementara Bidang Pelaksana yang isinya panjang (mis. "Keselamatan,
   Kesehatan Kerja, Lingkungan dan Keamanan") terjepit sampai 3 baris.
   Seperlima (20%) jatah Nama Pekerjaan dialihkan ke Bidang Pelaksana.
   ============================================================ */
#view-dp-view .table-wrap th.col-bidang-pel,
#view-dp-view .table-wrap td.col-bidang-pel{
  width:20%;min-width:200px;max-width:none
}
#view-dp-view .table-wrap th.col-nama-freeze,
#view-dp-view .table-wrap td.col-nama-freeze{
  max-width:none                /* sisa ruang tetap diserap Nama Pekerjaan */
}

/* Pengalihan 20% di atas harus diambil dari Nama Pekerjaan saja — kolom
   Lokasi Pekerjaan jangan ikut menyusut sampai isinya pecah dua baris. */
#view-dp-view .table-wrap th.fkl-col-lokasi,
#view-dp-view .table-wrap td.fkl-col-lokasi{min-width:210px;max-width:260px}


/* ============================================================
   21. PEMBUKAAN PENAWARAN — JUDUL KOLOM TEPAT 2 BARIS
   ------------------------------------------------------------
   "METODE PENYAMPAIAN DOKUMEN" dan "TGL. PEMBUKAAN PENAWARAN"
   sebelumnya pecah jadi 3 baris karena membungkus sendiri di kolom
   yang sempit. Pemenggalannya kini ditentukan lewat <br> dan tiap
   barisnya nowrap, jadi tepat 2 baris dan tidak pernah terpotong.
   Aturan lama di kedua kolom ini memakai !important, sehingga
   penimpaannya juga harus !important.
   ============================================================ */
#view-pnw-view .table-wrap th.pnw-col-metode.th-2b,
#view-pnw-view .table-wrap th.pnw-col-tgl.th-2b{
  white-space:nowrap !important;
  line-height:1.28;
  text-align:center;
  vertical-align:middle;
  padding-left:12px;padding-right:12px
}
/* Lebar kolom mengikuti MAX(isian, baris judul terpanjang) */
#view-pnw-view .table-wrap th.pnw-col-metode.th-2b{min-width:0;width:1%}
#view-pnw-view .table-wrap th.pnw-col-tgl.th-2b{min-width:0 !important;width:1% !important}


/* ============================================================
   22. KONSISTENSI TAMPILAN DESKTOP <-> MOBILE
   ============================================================
   22a. IDENTITAS DI BILAH ATAS (layar sentuh / kecil)
   ------------------------------------------------------------
   Di desktop logo & nama aplikasi selalu terlihat di sidebar. Di
   HP/tablet sidebar berupa laci tersembunyi, sehingga bilah atas
   hanya berisi tombol ☰ — terasa kosong dan tidak seragam.
   ============================================================ */
.appbar-brand{display:none}
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  .appbar-brand{
    display:flex;align-items:center;gap:10px;min-width:0;flex:1 1 auto
  }
  .appbar-logo{
    flex:0 0 auto;width:30px;height:30px;border-radius:9px;overflow:hidden;
    display:grid;place-items:center;background:#fff;
    box-shadow:0 2px 8px rgba(16,40,50,.14)
  }
  .appbar-logo img{width:100%;height:100%;object-fit:contain;display:block}
  .appbar-brand-txt{display:flex;flex-direction:column;min-width:0;line-height:1.2}
  .appbar-brand-txt b{
    font-size:11px;font-weight:800;color:var(--teal-dark);letter-spacing:.2px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis
  }
  .appbar-brand-txt>span{
    font-size:8.5px;font-weight:700;letter-spacing:1px;color:var(--muted);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis
  }
  /* Jejak halaman menepi ke kanan agar tidak berebut ruang dengan identitas */
  .appbar-crumb{margin-left:auto;flex:0 0 auto;align-items:flex-end;text-align:right}
}
/* Layar sangat sempit: cukup logo + nama, anak judulnya disembunyikan */
@media (max-width:430px){
  .appbar-brand-txt>span{display:none}
  .appbar-crumb{display:none}
}

/* ============================================================
   22b. KARTU DASHBOARD — 2 KOLOM DI HP (dulu 1 kolom)
   ------------------------------------------------------------
   Satu kartu per baris membuat halaman jadi sangat panjang dan
   iramanya jauh berbeda dari desktop yang bergrid.
   ============================================================ */
@media (max-width:640px){
  .cards,.cards-5,.dash-nilai{grid-template-columns:repeat(2,1fr)!important}
  #view-dashboard .cards{gap:10px}
  #view-dashboard .card .v{font-size:22px}
  #view-dashboard .card .k{font-size:10px}
  #view-dashboard .card .sub{font-size:9.5px}
}
@media (max-width:360px){
  .cards,.cards-5,.dash-nilai{grid-template-columns:1fr!important}
}

/* ============================================================
   22c. "CARI" & "TAMBAH DATA" TETAP SEBARIS DI HP
   ------------------------------------------------------------
   Di layar <=640px .page-head dipaksa flex-direction:column,
   sehingga judul, kotak Cari, dan tombol Tambah Data menumpuk
   ke bawah dan melebar penuh — iramanya jauh berbeda dari
   desktop yang menaruh keduanya sebaris di kanan.
   Sekarang: judul di baris sendiri, Cari + Tambah Data sebaris.
   Dashboard dikecualikan karena memang dirancang bertumpuk
   (judul di atas, deretan filter di bawahnya).
   ============================================================ */
@media (max-width:640px){
  .view:not(#view-dashboard)>.page-head{
    flex-direction:row;flex-wrap:wrap;align-items:center;
    justify-content:flex-start;gap:10px
  }
  /* Judul memakai satu baris penuh */
  .view:not(#view-dashboard)>.page-head>div:first-child{flex:1 1 100%;min-width:0}
  .page-head .pn-head-search{flex:1 1 auto;margin-left:0;min-width:0;width:auto}
  .page-head .pn-head-search input{min-width:0;max-width:none;width:100%}
  .page-head .head-add-btn{
    flex:0 0 auto;margin-left:0;width:auto;justify-content:center;
    padding:9px 13px;white-space:nowrap
  }
}
/* Di bawah 400px label tombol disembunyikan, sisakan ikon + agar tetap sebaris */
@media (max-width:400px){
  .page-head .head-add-btn{padding:9px 11px;font-size:0;gap:0}
  .page-head .head-add-btn svg{width:17px;height:17px}
}

/* ============================================================
   22d. ISYARAT GESER MENDATAR PADA TABEL
   ------------------------------------------------------------
   Di iPad potret & HP kolom kanan tabel terpotong tanpa tanda apa
   pun. Bayangan tipis muncul di sisi yang masih menyimpan kolom
   tersembunyi dan hilang begitu digeser sampai ujung.

   Bayangannya TIDAK boleh dipasang di dalam .table-wrap: elemen
   itu wadah gulir, sehingga anak absolut-nya ikut tergeser dan
   sel tabel yang berlatar solid menutupi bayangan inset. Karena
   itu bayangan dipasang pada .panel dan geometrinya (posisi &
   tinggi kotak tabel) dikirim ui-sidebar.js lewat variabel CSS.
   ============================================================ */
/* Hanya panel yang MEMUAT tabel yang dijadikan acuan posisi — kelas
   .panel-tabel dipasang ui-sidebar.js. Dengan begitu panel lain tidak
   berubah perilakunya sedikit pun. */
.panel.panel-tabel{position:relative}
.panel.panel-tabel::before,.panel.panel-tabel::after{
  content:"";position:absolute;pointer-events:none;z-index:9;
  top:var(--tw-top,0px);height:var(--tw-h,0px);width:26px;
  opacity:0;transition:opacity .18s ease
}
.panel.panel-tabel::before{
  left:var(--tw-inset,0px);
  background:linear-gradient(to right,rgba(16,40,50,.17),rgba(16,40,50,0))
}
.panel.panel-tabel::after{
  right:var(--tw-inset,0px);
  background:linear-gradient(to left,rgba(16,40,50,.17),rgba(16,40,50,0))
}
.panel.panel-tabel.x-kiri::before{opacity:1}
.panel.panel-tabel.x-kanan::after{opacity:1}
@media (prefers-reduced-motion:reduce){
  .panel.panel-tabel::before,.panel.panel-tabel::after{transition:none}
}


/* ============================================================
   23. TABLET SENTUH = TAMPILAN DESKTOP (SIDEBAR RAIL PERMANEN)
   ------------------------------------------------------------
   iPad (potret 834 px & lanskap 1194/1366 px) sebelumnya ikut
   aturan "layar sentuh" sehingga sidebar berubah jadi laci
   tersembunyi — tampilannya jauh berbeda dari desktop.

   Sekarang perangkat sentuh yang layarnya cukup besar memakai
   susunan yang persis sama dengan desktop: rail ikon 76 px yang
   selalu terlihat, isi halaman bergeser ke kanan, dan bilah atas
   ☰ disembunyikan. Karena layar sentuh tidak punya kursor,
   pelebaran rail dipicu KETUKAN (ui-sidebar.js memasang kelas
   .is-open), lalu menciut lagi saat mengetuk di luar.

   Penanda mode dipasang ui-sidebar.js: <html class="mode-rail">.
   Ambang batasnya: lebar >= 700px DAN tinggi >= 600px — supaya
   ponsel dalam posisi lanskap (tinggi ~400px) tetap memakai laci.
   ============================================================ */
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  position:fixed;top:0;left:0;bottom:0;height:100vh;
  transform:none!important;max-width:none;
  width:var(--side-rail);z-index:70;
  box-shadow:6px 0 20px rgba(5,32,36,.16);
  transition:width .26s cubic-bezier(.16,1,.3,1),box-shadow .26s ease
}
@supports (height:100dvh){ html.mode-rail .sidebar-shell{height:100dvh} }
html.mode-rail .sidebar-shell.is-open{
  width:var(--side-w);box-shadow:14px 0 44px rgba(5,32,36,.34)
}
html.mode-rail .app-main{margin-left:var(--side-rail);width:auto}
html.mode-rail .appbar{display:none}
html.mode-rail .topnav-backdrop,
html.mode-rail .topnav-backdrop.show{display:none!important}
html.mode-rail body.nav-open{overflow:auto}

/* --- Salinan aturan RAIL (aslinya hanya untuk (hover:hover) & >=1025px) --- */
html.mode-rail .sidebar-shell:not(.is-open) .brand,
html.mode-rail .sidebar-shell:not(.is-open) .side-sec,
html.mode-rail .sidebar-shell:not(.is-open) .side-ver{opacity:0;pointer-events:none}
html.mode-rail .sidebar-shell:not(.is-open) .brand,
html.mode-rail .sidebar-shell:not(.is-open) .side-ver{display:none}
html.mode-rail .sidebar-shell:not(.is-open) .side-sec{height:9px;padding:6px 0 0;overflow:hidden}
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand{justify-content:center;padding:18px 0 16px}
html.mode-rail .sidebar-shell:not(.is-open) #topnav{padding:14px 0;align-items:center;gap:5px;overflow:hidden}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  width:46px;height:44px;padding:0;justify-content:center;border-radius:13px;gap:0;
  font-size:0;letter-spacing:0;background:rgba(255,255,255,.07)}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link.active,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger{
  background:linear-gradient(135deg,var(--yellow),#ffd35a);color:#073f45}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link.active svg,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link.active svg:first-of-type,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger svg,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger svg:first-of-type{color:#073f45}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger .caret{display:none}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-dropdown{display:none}
html.mode-rail .sidebar-shell:not(.is-open) .side-foot{padding:8px 0 10px}
html.mode-rail .sidebar-shell:not(.is-open) .side-acct{display:none}
html.mode-rail .sidebar-shell:not(.is-open) .side-logout-lbl{display:none}
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */

/* Sasaran sentuh tetap nyaman walau memakai tata letak desktop */
html.mode-rail #topnav .topnav-link,
html.mode-rail #topnav .topnav-trigger{min-height:44px}
html.mode-rail.sentuh #topnav .topnav-item,
html.mode-rail.sentuh #topnav .topnav-subtrigger{padding:10px 12px}

/* Isi halaman: lebar & jarak sama persis dengan desktop */
html.mode-rail .wrap{
  max-width:1320px;
  padding-left:calc(24px + env(safe-area-inset-left));
  padding-right:calc(24px + env(safe-area-inset-right))
}
html.mode-rail .crumb-path{display:none}

/* --- PERBAIKAN TAMPILAN RAIL DI TABLET (iPad) ---------------------------
   a) Rail yang menciut dulu memakai overflow:hidden (menimpa overflow-y:auto
      milik aturan laci). iPad dalam posisi lanskap tingginya hanya ~820 px,
      sedangkan daftar menunya lebih panjang dari itu — akibatnya butir di
      bawah garis lipat TERPOTONG dan tidak ada cara menggulirnya sama sekali.
      Batang gulirnya disembunyikan supaya rail tetap bersih selebar 76 px.  */
html.mode-rail .sidebar-shell #topnav{
  flex:1 1 auto;min-height:0;
  overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;-ms-overflow-style:none}
html.mode-rail .sidebar-shell #topnav::-webkit-scrollbar{width:0;height:0}

/* b) Tinggi diambil dari inset (top:0 + bottom:0) yang memang sudah dipasang
      di atas — BUKAN dari 100vh/100dvh. Di Safari iPad nilai dvh berubah tiap
      bilah alat menyusut atau melebar, dan itulah yang membuat kaki sidebar
      (Jenis Akun & Keluar) melompat sendiri saat halaman digulir.
      Aturan ini WAJIB berada sesudah blok @supports (height:100dvh) di atas
      agar memenangkan urutan berkas. */
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{height:auto}


/* ============================================================
   24. PRATINJAU DI TABLET = PERSIS DESKTOP
   ------------------------------------------------------------
   Aturan bagian 16 membuat pratinjau menutupi seluruh layar di
   SEMUA perangkat sentuh. Karena tablet kini memakai susunan
   desktop (bagian 23), pratinjaunya pun dikembalikan ke jendela
   melayang 980px seperti desktop. Ponsel tetap layar penuh.
   Mode "Layar Penuh Semu" (.pn-fs-semu) dikecualikan supaya
   tombol Layar Penuh tetap berfungsi.
   ============================================================ */
html.mode-rail #pn-preview-overlay{padding:20px}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu){
  width:min(980px,95vw);max-width:980px;
  height:auto;max-height:92vh;margin:auto;border-radius:18px
}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .detail-head{
  padding:16px 20px;
  padding-top:calc(16px + env(safe-area-inset-top))
}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .detail-head h3{
  font-size:14px;-webkit-line-clamp:2
}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body{
  display:flex;height:auto;flex:1 1 auto;min-height:0
}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body iframe,
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body.fkl-preview-body #fkl-preview-frame{
  height:74vh;max-height:none
}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body.has-tabs iframe{height:calc(74vh - 46px)}
html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body img{max-height:74vh}
@supports (height:100dvh){
  html.mode-rail .pn-preview-modal:not(.pn-fs-semu){max-height:92dvh;height:auto}
  html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body iframe,
  html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body.fkl-preview-body #fkl-preview-frame{height:74dvh}
  html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body.has-tabs iframe{height:calc(74dvh - 46px)}
  html.mode-rail .pn-preview-modal:not(.pn-fs-semu) .pn-preview-body img{max-height:74dvh}
}

/* Filter dashboard: 2 per baris di HP (dulu 1 per baris) — iramanya jadi
   sejalan dengan kartu ringkasan yang juga 2 kolom. */
@media (max-width:640px){
  #view-dashboard .dash-filter-bar{flex-wrap:wrap;gap:10px}
  #view-dashboard .filter-field{flex:1 1 calc(50% - 5px);min-width:0}
  #view-dashboard .filter-field select{width:100%;min-width:0;font-size:12px}
}
@media (max-width:360px){
  #view-dashboard .filter-field{flex:1 1 100%}
}


/* ============================================================
   25. GARIS TABEL PUTIH & TEGAS UNTUK SEMUA HALAMAN DAFTAR
   ------------------------------------------------------------
   Aturan umum `td{border-color:#e4edef}` (bagian "Tabel Monitoring")
   membuat garis antar sel jadi abu-abu tipis. Perlakuan putih hanya
   pernah dipasang satu per satu untuk 7 halaman — sisanya tertinggal:
     Data Pekerjaan, Jadwal, Pembukaan Penawaran, Perhitungan HPS,
     Analisa Harga Satuan, SPK, Dokumen Pengadaan, Materi & Peraturan,
     dan Realisasi Harga Optimal.
   Karena itu warnanya tidak seragam antar halaman.

   Sekarang aturannya dipasang SATU KALI untuk semua tabel daftar
   sekaligus, sehingga halaman baru pun otomatis ikut seragam.
   Sasarannya `.table-wrap>table:not([class])` — hanya tabel daftar.
   Tabel khusus yang punya kelas sendiri (hps-uraian, ana-uraian,
   jp-table, pnw-periksa-table, fkl-info) sengaja tidak diikutkan
   karena gaya garisnya memang dirancang berbeda.
   ============================================================ */
.table-wrap>table:not([class]){border-collapse:collapse}
.table-wrap>table:not([class]) th,
.table-wrap>table:not([class]) td{
  border-left:1px solid #fff;border-right:1px solid #fff
}
.table-wrap>table:not([class]) thead th{
  border-left-color:#fff;border-right-color:#fff
}
.table-wrap>table:not([class]) tbody td{
  border-top:1px solid #fff;border-bottom:1px solid #fff
}


/* ============================================================
   26. KEHALUSAN RENDER (LAYAR 120 Hz)
   ------------------------------------------------------------
   Layar 120 Hz hanya punya 8,3 ms per frame (bukan 16,7 ms seperti
   60 Hz), jadi pekerjaan yang dulu "masih sempat" kini melewati
   tenggat dan terasa patah-patah. Empat sumber beban dibereskan:

   26a. Animasi tak terbatas yang MEMAKSA CAT ULANG
   ------------------------------------------------------------
   Garis aksen di tepi sidebar menganimasikan `background-position`.
   Properti itu tidak bisa ditangani compositor, jadi seluruh strip
   dicat ulang di thread utama setiap frame — selamanya, bahkan saat
   tidak ada interaksi. Diganti `transform:translate3d` yang murni
   berjalan di compositor (nol pekerjaan thread utama).
   ============================================================ */
.sidebar-shell{overflow:hidden}
.sidebar-shell::after{
  top:0;bottom:auto;height:200%;
  background:linear-gradient(180deg,var(--yellow),var(--cyan),var(--yellow),var(--cyan),var(--yellow));
  background-size:100% 100%;
  animation:sheenVT 7s linear infinite;
  will-change:transform;
  transform:translate3d(0,0,0)
}
@keyframes sheenVT{
  from{transform:translate3d(0,0,0)}
  to  {transform:translate3d(0,-50%,0)}
}

/* 26b. Lapisan "Memuat" yang tersembunyi TETAP menganimasi
   ------------------------------------------------------------
   .route-loader disembunyikan dengan opacity:0 + visibility:hidden.
   Keduanya TIDAK menghentikan animasi CSS — 10 animasi tak terbatas
   (3 orbit, 3 titik, denyut, cahaya, sheen, elipsis) terus berdetak
   sepanjang sesi walau tidak terlihat sama sekali. Dijeda saat
   tersembunyi; transisi pudar-keluarnya tetap utuh karena yang
   dijeda hanya animasi, bukan transisi. */
.route-loader:not(.show),
.route-loader:not(.show) *,
.route-loader:not(.show) *::before,
.route-loader:not(.show) *::after{
  animation-play-state:paused!important
}

/* 26c. Transisi lebar sidebar
   ------------------------------------------------------------
   Menganimasikan `width` memaksa hitung ulang tata letak seluruh isi
   sidebar tiap frame. Itu tidak bisa dihindari tanpa merombak
   strukturnya, tetapi biayanya bisa dikurung:
     - contain:layout style  -> perubahan di dalam sidebar tidak
       merembet ke perhitungan tata letak halaman.
     - scrollbar-gutter      -> batang gulir daftar menu tidak
       muncul/hilang di tengah animasi (memicu reflow tambahan).
     - transisi `width` pada TIAP tombol menu dilepas: tombolnya
       sudah width:100%, jadi otomatis mengikuti lebar induknya.
       Dulu 1 animasi induk + 10 animasi anak berjalan berbarengan. */
.sidebar-shell{contain:layout style}
.sidebar-shell #topnav{scrollbar-gutter:stable}
.sidebar-shell #topnav .topnav-link,
.sidebar-shell #topnav .topnav-trigger{
  transition:background .16s ease,color .16s ease
}

/* 26d. Bayangan berat saat hover
   ------------------------------------------------------------
   Transisi box-shadow memicu cat ulang; dipasangkan dengan transform
   agar bagian geraknya tetap ditangani compositor. */
.act,.btn{will-change:auto}
.act:hover,.btn:hover{will-change:transform}

/* 26e. Bayangan sidebar tidak ikut dianimasikan
   ------------------------------------------------------------
   Sidebar mentransisikan `width` DAN `box-shadow` bersamaan. Bayangan
   kabur setinggi layar penuh harus dicat ulang setiap frame selama
   260 ms — persis saat animasi lebar sedang berjalan, sehingga dua
   pekerjaan berat menumpuk di frame yang sama. Bayangannya kini
   berubah seketika (mata hampir tidak bisa membedakan), sementara
   lebarnya tetap beranimasi halus. */
.sidebar-shell,
.sidebar-shell.is-open,
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  /* 260 ms dengan easing berekor panjang (.16,1,.3,1) membuat sidebar terasa
     "masih menata diri" beberapa saat sesudah kursor sampai. Dipercepat jadi
     170 ms dengan ease-out kubik biasa: gerakannya selesai tegas, tanpa ekor. */
  transition:width .17s cubic-bezier(.22,.61,.36,1)
}
/* Di ponsel/tablet kecil sidebar bergeser (transform) — itu sudah
   ditangani compositor, jadi tetap dipertahankan. */
@media (max-width:1024px), (hover:none), (any-pointer:coarse){
  html:not(.mode-rail) .sidebar-shell,
  html:not(.mode-rail) .sidebar-shell.is-open{
    transition:transform .28s cubic-bezier(.16,1,.3,1)
  }
}


/* ============================================================
   27. TEKS SIDEBAR — PUTIH PENUH, LEBIH TAJAM
   ------------------------------------------------------------
   Semua tulisan di sidebar memakai putih SEMI-TRANSPARAN
   (rgba(255,255,255,.85) sampai .96). Dua akibatnya:
     1) kontrasnya turun — putih pudar di atas gradien teal;
     2) teks transparan TIDAK BISA dirender dengan subpixel
        anti-aliasing, browser terpaksa memakai grayscale AA,
        sehingga hurufnya terlihat lembek/berkabut.
   Sekarang seluruhnya opak (#fff), jadi kontras penuh dan
   rendering huruf kembali setajam mungkin.

   `-webkit-font-smoothing:antialiased` juga dilepas — setelan itu
   MEMAKSA grayscale AA (huruf jadi lebih tipis), padahal tujuan
   kita justru sebaliknya.
   ============================================================ */
.sidebar-shell{-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}

/* Menu utama & grup */
#topnav .topnav-link,
#topnav .topnav-trigger,
#topnav .topnav-item,
#topnav .topnav-subtrigger,
#topnav .topnav-subdrop .topnav-item{color:#fff}
/* Ikon menu ikut penuh agar setara dengan tulisannya */
#topnav .topnav-item svg,
#topnav .topnav-subtrigger svg:first-of-type,
#topnav .topnav-link svg,
#topnav .topnav-trigger svg:first-of-type{color:#fff}
/* Menu aktif yang latarnya KAPSUL KUNING tetap biru-tua (jangan ikut putih). */
#topnav .topnav-link.active,
#topnav .topnav-link.active svg,
#topnav .topnav-item.active,
#topnav .topnav-item.active svg{color:#073f45}
/* CATATAN: induk grup yang sedang aktif (mis. "Form") TIDAK boleh dibuat
   biru-tua di sini. Saat sidebar melebar, latarnya hanya putih transparan
   12% di atas gradien teal — teks biru-tua di atasnya nyaris tak terbaca.
   Kapsul kuningnya hanya muncul saat sidebar menciut jadi rail, dan kasus
   itu sudah ditangani bagian 18 dengan syarat .sidebar-shell:not(.is-open). */
/* Nama aplikasi & unit di kepala sidebar */
.sidebar-shell .brand h1,
.sidebar-shell .brand span{color:#fff}
/* Label akun */
.side-acct-lbl{color:#fff}
/* Label bagian & versi: tetap sekunder, TAPI warnanya dibuat OPAK
   (bukan putih transparan) supaya hurufnya ikut tajam. Kalau ingin
   ikut putih penuh juga, tinggal ganti kedua warna di bawah ke #fff. */
.side-sec{color:#bcd9dc}
.side-ver{color:#a6c6ca}


/* ============================================================
   28. GERAK KURSOR DI ATAS TABEL LEBIH RINGAN
   ------------------------------------------------------------
   Setiap kali kursor berpindah baris, DUA baris ikut menganimasikan
   latarnya (yang ditinggalkan & yang dimasuki) selama 150 ms. Tiap
   baris selebar tabel — pada tabel yang lebarnya >1000 px itu cat
   ulang yang lumayan besar, dan karena kotak tabel bukan lapisan
   tersendiri, pembatalan cat-nya merembet ke panel berikut bayangan
   besarnya.
     - contain:layout paint  -> perubahan di dalam kotak tabel tidak
       lagi membatalkan tata letak/cat di luarnya.
     - will-change:scroll-position -> kotak tabel dijadikan lapisan
       gulir tersendiri, jadi gulir mendatar/menegak ditangani
       compositor.
     - transisi disempitkan ke `background-color` saja (dulu
       `background` yang mencakup gambar, posisi, ukuran, dsb.).
   ============================================================ */
.table-wrap{contain:layout paint;will-change:scroll-position}
tbody tr{transition:background-color .14s linear}

/* Batalkan petunjuk will-change yang dipasang SAAT hover — memasang
   will-change tepat ketika animasi dimulai justru memaksa browser
   membuat lapisan baru di tengah gerakan, dan itu terasa tersendat. */
.act:hover,.btn:hover{will-change:auto}


/* ============================================================
   29. SISA EFEK 3D PADA IKON & TULISAN — DIHAPUS SELURUHNYA
   ------------------------------------------------------------
   Tambalan "TAJAM" (28 Jul) sudah membuang sebagian besar efek 3D,
   tetapi tiga sumber masih tertinggal dan kembali terlihat:

     a) HURUF TIMBUL (text-shadow). Bagian E3 hanya mematikan
        sebagian daftar; yang tersisa: kepala tabel (baris 3735,
        5557, 5820, 6767), tulisan menu sidebar (4131, 4160),
        matriks kontrol akses (4581), serta judul & label pada
        "Materi & Peraturan" (6826, 6828). Karena itu sebagian
        menu masih terlihat berhuruf timbul, sebagian rata.

     b) EFEK GETAR SAAT KURSOR MENGENAI TULISAN. Judul aplikasi di
        kepala sidebar memakai
           .topbar-brand:hover .brand h1{ transform:translateY(-1px) }
        dengan easing memantul cubic-bezier(.34,1.56,.64,1) — judul
        melompat lalu memantul balik setiap kali kursor menyentuhnya.
        Logonya pun ikut membesar (scale 1.05) & disapu kilau.

     c) MENU "MATERI & PERATURAN" (blok 30 Jul) ditulis SESUDAH
        tambalan tajam, jadi efek 3D-nya tidak tertimpa: baris tabel
        menskala saat disorot, tombol & ikon membesar/mengecil.

   Blok ini menutup ketiganya. Bayangan kotak pada wadah (panel,
   form-card, kepala tabel) SENGAJA dibiarkan — yang diminta dibuang
   hanya efek pada IKON dan TULISAN.
   ============================================================ */

/* --- 29a. Tidak ada lagi huruf timbul di mana pun --- */
*, *::before, *::after{ text-shadow:none !important }

/* --- 29b. Kepala sidebar: judul & logo diam total saat disorot --- */
.brand h1, .brand span,
.topbar-brand:hover .brand h1,
.topbar-brand:hover .brand span,
.topbar-brand .logo, .topbar-brand:hover .logo,
.topbar-brand .logo .logo-img,
.topbar-brand:hover .logo .logo-img,
.brandside-logo, .brandside-logo svg{
  transform:none !important;
  animation:none !important;
  transition:none !important;
}
/* Kilau diagonal yang menyapu logo ikut dimatikan */
.topbar-brand .logo::after,
.topbar-brand:hover .logo::after{ display:none !important }
.topbar-brand{ perspective:none !important; cursor:default }

/* --- 29c. Ikon & lencana berhenti melayang --- */
.table-wrap .pill, .pill,
.settings-gear svg, .settings-gear:hover svg,
.side-logout svg, .side-logout:hover svg,
.appbar .nav-burger svg, .appbar .nav-burger:hover svg{
  filter:none !important;
  transform:none !important;
  animation:none !important;
}

/* --- 29d. "Materi & Peraturan": baris, tombol, dan ikon tidak bergerak --- */
#view-materi-form{ perspective:none !important }
#view-materi-view .panel tbody tr,
#view-materi-view .panel tbody tr:hover,
#view-materi-view .act, #view-materi-view .act:hover, #view-materi-view .act:active,
#view-materi-form .act, #view-materi-form .act:hover, #view-materi-form .act:active,
#view-materi-view .btn, #view-materi-view .btn:hover, #view-materi-view .btn:active,
#view-materi-form .btn, #view-materi-form .btn:hover, #view-materi-form .btn:active,
#view-materi-view .act svg, #view-materi-form .act svg,
#view-materi-view .btn svg, #view-materi-view .btn:hover svg,
#view-materi-form .btn svg, #view-materi-form .btn:hover svg{
  transform:none !important;
  animation:none !important;
}
#view-materi-view .panel tbody tr{ transition:background-color .14s linear !important }
#view-materi-view .panel tbody tr:hover{ box-shadow:none !important }

/* --- 29e. Panah arah grup menu DIKEMBALIKAN ---
   Bagian D3 menutup `.topnav-subtrigger svg` dengan transform:none
   !important, sehingga panah kecil penunjuk "grup terbuka/tertutup"
   ikut berhenti berputar. Panah itu bukan hiasan 3D melainkan
   PENANDA KEADAAN, jadi dikembalikan di sini. */
#topnav .topnav-sub.open > .topnav-subtrigger .caret2{
  transform:rotate(180deg) !important;
  transition:transform .25s ease !important;
}


/* ============================================================
   30. RAIL SIDEBAR: IKON LEBIH KECIL
   ------------------------------------------------------------
   Meniru laci ikon tersembunyi di Android/iOS: rail menyempit
   76px -> 70px, kotak ikon 46x44 -> 34x34, dan gambar ikonnya
   sendiri 18px -> 15px. Kepala (logo) & tombol Keluar ikut
   mengecil supaya iramanya sama.

   (Ukuran itu dinaikkan lagi di bagian 33; lebar rail sendiri
   ditetapkan ulang jadi 72px di bagian 32.)

   Rail tidak memakai gagang/anak panah apa pun — satu-satunya
   cara melebarkannya adalah mendekatkan kursor (desktop) atau
   mengetuknya (tablet), lihat ui-sidebar.js bagian 1a & 1e.
   ============================================================ */
:root{ --side-rail:70px }


/* ---------- ukuran isi rail saat menciut ---------- */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav{ padding:12px 0 14px; gap:4px }
  .sidebar-shell:not(.is-open) #topnav .topnav-link,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
    width:34px; height:34px; border-radius:10px }
  .sidebar-shell:not(.is-open) #topnav .topnav-link svg,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger svg:first-of-type{
    width:15px; height:15px }
  .sidebar-shell:not(.is-open) .topbar-brand{ padding:14px 0 12px }
  .sidebar-shell:not(.is-open) .topbar-brand .logo{
    width:30px; height:30px; flex:0 0 30px; border-radius:9px }
  .sidebar-shell:not(.is-open) .side-foot{ padding:6px 0 8px }
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */
}
/* Salinan yang sama untuk mode-rail (dipakai desktop & tablet) */
html.mode-rail .sidebar-shell:not(.is-open) #topnav{ padding:12px 0 14px; gap:4px }
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  width:34px; height:34px; border-radius:10px }
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link svg,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger svg:first-of-type{
  width:15px; height:15px }
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand{ padding:14px 0 12px }
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand .logo{
  width:30px; height:30px; flex:0 0 30px; border-radius:9px }
html.mode-rail .sidebar-shell:not(.is-open) .side-foot{ padding:6px 0 8px }
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */

/* Sasaran sentuh 44px (bagian 23) SENGAJA dilepas pada perangkat
   berkursor — di sana tinggi 34px sudah nyaman & itulah yang
   membuat ikon terlihat mengecil. Layar sentuh tetap 44px. */
html.mode-rail:not(.sentuh) .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail:not(.sentuh) .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  min-height:0
}


/* ============================================================
   31. TIDAK ADA LAGI YANG MENONJOL SAAT KURSOR MENGENAINYA
   ------------------------------------------------------------
   Blok 29 membuang huruf timbul (text-shadow) & efek memantul,
   tetapi masih tersisa sumber ketiga: elemen berisi TULISAN yang
   MEMBESAR / TERANGKAT saat disorot. Tambalan "TAJAM" bagian D4
   dulu menutupnya lewat DAFTAR NAMA KELAS, dan daftar itu tidak
   pernah lengkap — setiap kelas baru yang dibuat sesudahnya lolos:

     .pn-check-item        scale(1.02)   baris 5664 & 5925
     .fkl-check            scale(1.02)   baris 5925
     .dpeng-uprow          scale(1.008)  baris 5636
     .fk-act-icon          scale(1.10)   baris 5580 & 5856
                           (D4 hanya menyebut `.fk-act`, bukan
                            `.fk-act-icon` — kelas yang berbeda)
     .filter-field select  translateY(-1px) baris 1542

   Karena itu pendekatannya DIBALIK: bukan lagi daftar nama kelas
   yang harus terus ditambah, melainkan aturan menyeluruh di dalam
   wadah isi halaman. Kelas baru apa pun otomatis ikut, tanpa perlu
   menambal lagi di kemudian hari.

   Yang SENGAJA tidak tersentuh (transform-nya memang fungsional,
   bukan hiasan):
     - .toast          -> ditempel ke <body>, di luar jangkauan
     - .fk-seg-thumb   -> pointer-events:none, tak pernah disorot
     - .ac-toggle-tr   -> geser knop ada di ::before (pseudo tidak
                          ikut terpilih oleh `*:hover`)
     - .login-screen   -> bukan `.view`, jadi di luar jangkauan
     - #pn-preview-overlay -> pratinjau & cetak tetap dikecualikan
     - .caret2 & panah gagang sidebar -> penanda keadaan, dikuatkan
       ulang di bawah supaya tidak ikut terhenti
   ============================================================ */
/* PENGUAT BOBOT `:not(#_a):not(#_b)` — pola yang sudah dipakai di
   file ini (lihat `.view:not(#view-dashboard)` pada blok EFEK 3D).
   Alasannya: sejumlah aturan lawan memakai ID, mis.
      #view-dashboard .card:hover          -> bobot (1,2,0)
      #view-dashboard .card:hover .card-ic -> bobot (1,3,0)
      #view-dpeng-unggah .dpeng-uprow:hover-> bobot (1,2,0)
   dan `!important` TIDAK membatalkan perhitungan bobot — ia hanya
   menaikkan lapisan. Tanpa penguat ini, `.view *:hover` yang cuma
   (0,2,0) tetap kalah dan kartu Dashboard masih terangkat 2px saat
   disorot (terbukti saat diuji: matrix(1,0,0,1,0,-1.98)). Dua
   `:not()` ber-ID palsu menaikkannya ke (2,2,0) sehingga menang
   atas semuanya, tanpa mengubah elemen mana pun yang terpilih. */
/* PENGAMAN GANDA (11 Agu 2026): knop sakelar dikeluarkan DI PEMILIHNYA
   (bukan lewat aturan tandingan ber-!important, supaya tidak ada perang
   lapisan). `.sw-knob` = knop .js-switch, `.kn` = knop .mon-sw / .tor-sw.
   Bobotnya naik (2,2,0) -> (2,4,0), jadi tetap menang atas aturan ber-ID
   lawan. Bila kelak ada sakelar baru, daftarkan kelas knopnya di sini. */
.view:not(#_a):not(#_b) *:hover:not(.sw-knob):not(.kn),
.modal:not(#_a):not(#_b) *:hover:not(.sw-knob):not(.kn),
.overlay:not(#pn-preview-overlay):not(#_b) *:hover:not(.sw-knob):not(.kn),
.sidebar-shell:not(#_a):not(#_b) *:hover:not(.sw-knob):not(.kn),
.appbar:not(#_a):not(#_b) *:hover:not(.sw-knob):not(.kn),
.view:not(#_a):not(#_b) .card:hover,
#view-dashboard:not(#_b) .card:hover{
  transform:none !important;
}

/* Baris & item bertulisan: bayangannya ikut diratakan supaya tidak
   terlihat "terangkat" walau sudah tidak membesar lagi. */
.view .pn-check-item:hover, .view .fkl-check:hover,
.overlay:not(#pn-preview-overlay) .pn-check-item:hover,
#dpeng-doc-overlay .pn-check-item:hover,
#view-dpeng-unggah .dpeng-uprow:hover,
#dpeng-list-overlay .dpeng-list-item:hover,
.view .table-wrap tbody tr:hover,
.view .panel tbody tr:hover{
  box-shadow:0 1px 2px rgba(16,40,50,.08) !important;
}

/* --- Penanda keadaan dikuatkan ulang ---
   Aturan menyeluruh di atas memakai !important, jadi penanda arah
   ini harus ikut !important agar tetap berputar saat kursor
   kebetulan berada tepat di atasnya. */
#topnav .topnav-sub.open > .topnav-subtrigger .caret2{
  transform:rotate(180deg) !important;
}


/* ============================================================
   32. RAIL: LOGO, IKON MENU, & TOMBOL KELUAR SATU GARIS
   ------------------------------------------------------------
   Diukur di Chromium, rail 70px:
       logo          x=20  lebar=30  titik tengah 35
       ikon menu     x=13  lebar=34  titik tengah 30   <-- meleset
       tombol Keluar x=18  lebar=34  titik tengah 35
   Jadi yang meleset justru IKON MENU-nya, bukan logo & Keluar.

   SEBABNYA `scrollbar-gutter:stable` pada #topnav (dipasang bagian
   26c supaya batang gulir tidak muncul-hilang di tengah animasi
   lebar). Gutter itu MEREBUT 10px di tepi kanan — terukur:
   #topnav lebar 70px tetapi clientWidth hanya 60px. Isinya lalu
   dipusatkan pada 60px itu, bukan pada 70px, sehingga seluruh ikon
   menu bergeser 5px ke kiri. `.topbar-brand` dan `.side-foot` tidak
   menggulir, jadi keduanya tetap terpusat pada 70px penuh.

   PERBAIKAN: saat menciut, rail TIDAK PERLU gutter sama sekali —
   isinya cuma ikon, dan batang gulirnya sendiri tidak pantas tampil
   di jalur selebar itu. Batang gulir disembunyikan (rodanya tetap
   bisa menggulir), gutter dilepas, sehingga ketiganya terpusat pada
   lebar rail penuh. Saat melebar, gutter kembali seperti semula.
   Cara ini juga lebih tahan banting daripada mengimbangi dengan
   padding: lebar gutter berbeda-beda antar peramban, jadi angka
   tetap apa pun pasti meleset di salah satunya.

   Kotak logo ikut disamakan 30px -> 34px supaya lebarnya sebaris
   dengan ikon menu & tombol Keluar.

   Rail 70px -> 72px supaya ikon yang sudah terpusat benar tetap
   berjarak wajar dari garis aksen 3px di tepi kanan. Lebar ini
   dipertahankan karena bagian 33 menaikkan kotak ikon jadi 38px.
   ============================================================ */
:root{ --side-rail:72px }

/* ---------- rail menciut: tanpa gutter, tanpa batang gulir ---------- */
.sidebar-shell:not(.is-open) #topnav,
html.mode-rail .sidebar-shell:not(.is-open) #topnav{
  scrollbar-gutter:auto;
  scrollbar-width:none;          /* Firefox */
  -ms-overflow-style:none;       /* Edge lama */
}
.sidebar-shell:not(.is-open) #topnav::-webkit-scrollbar,
html.mode-rail .sidebar-shell:not(.is-open) #topnav::-webkit-scrollbar{
  width:0; height:0;
}

/* ---------- kotak logo disamakan dengan kotak ikon ---------- */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) .topbar-brand .logo{
    width:34px; height:34px; flex:0 0 34px; border-radius:10px }
}
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand .logo{
  width:34px; height:34px; flex:0 0 34px; border-radius:10px }


/* ============================================================
   33. RAIL MENCIUT: IKON SEDIKIT DIPERBESAR
   ------------------------------------------------------------
   Bagian 30 mengecilkan isi rail (kotak 34px, gambar ikon 15px)
   ketika lebar rail masih 76px. Sesudah bagian 32 memperbaiki
   pemusatan dan melebarkan rail jadi 72px, ukuran itu terasa
   terlalu kecil — ikonnya "hilang" di tengah ruang kosong.

   Dinaikkan satu tingkat, bukan lebih:
       kotak ikon    34 -> 38   (gambar 15 -> 17)
       kotak logo    34 -> 38
       tombol Keluar 34 -> 38   (gambar 14 -> 16)

   Kenapa berhenti di 38: kotak selebar itu terpusat pada rail
   72px jatuh di x = 17..55, sedangkan garis aksen 3px ada di
   x = 69..72 — masih tersisa 14px ruang bernapas. Angka 40 akan
   menyisakan 12px dan mulai terasa sesak; 42 sudah bersinggungan
   dengan garis aksen.

   Ditulis untuk KEDUA jalur yang dipakai bagian 30 (media query
   perangkat berkursor DAN html.mode-rail untuk tablet sentuh),
   supaya desktop dan iPad tetap seragam.
   ============================================================ */

/* ---------- perangkat berkursor ---------- */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav .topnav-link,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
    width:38px; height:38px; border-radius:11px }
  .sidebar-shell:not(.is-open) #topnav .topnav-link svg,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger svg:first-of-type{
    width:17px; height:17px }
  .sidebar-shell:not(.is-open) .topbar-brand .logo{
    width:38px; height:38px; flex:0 0 38px; border-radius:11px }
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */
}

/* ---------- mode-rail (desktop & tablet sentuh) ---------- */
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  width:38px; height:38px; border-radius:11px }
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link svg,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger svg:first-of-type{
  width:17px; height:17px }
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand .logo{
  width:38px; height:38px; flex:0 0 38px; border-radius:11px }
  /* ukuran tombol Keluar saat menciut: lihat satu aturan di bagian 31 */

/* Kotak tumbuh 4px, jadi jarak antar tombol dirapatkan sedikit
   supaya daftar menu tidak jadi lebih tinggi dari sebelumnya dan
   tetap muat tanpa menggulir pada layar laptop 768px. */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav{ padding:10px 0 12px; gap:3px }
}
html.mode-rail .sidebar-shell:not(.is-open) #topnav{ padding:10px 0 12px; gap:3px }


/* ============================================================
   34. RAIL MENCIUT: ISYARAT "MASIH BISA DILEBARKAN"
   ------------------------------------------------------------
   Rail ikon yang diam tampak seperti tembok mati — tidak ada
   satu pun tanda bahwa ia menyimpan nama menu di baliknya.
   Percobaan sebelumnya memakai gagang anak panah MENONJOL di
   luar tepi rail; bentuk itu dibuang karena menempel seperti
   tempelan asing pada sidebar yang selebihnya rata.

   Penggantinya tiga isyarat halus, semuanya DI DALAM rail:

   34a. Pegangan tiga titik di tepi kanan
        Bahasa rupa yang sudah dikenal luas (pegangan geser di
        panel, baris yang bisa diseret). Selalu tampak saat rail
        menciut, tetapi sangat samar — dan bernapas pelan supaya
        mata sempat menangkapnya tanpa merasa diteriaki.
        Letaknya x = 61..64: bersih dari kotak ikon (berhenti di
        x = 55) maupun garis aksen (x = 69..72).

   34b. Bentuk kursor
        Rail memakai `e-resize` — panah dua arah mendatar. Ini
        isyarat paling jujur: kursornya sendiri yang mengatakan
        "benda ini melebar ke samping". Tombol menu tetap
        `pointer` supaya tidak ikut tertukar maknanya.

   34c. Ajakan sekali per sesi
        Sesudah halaman tenang, rail melebar sedikit lalu kembali
        — dua kali, seperti laci yang menyembul. Satu gerakan
        singkat mengajarkan lebih banyak daripada ikon apa pun,
        dan karena hanya sekali per sesi ia tidak pernah menjadi
        gangguan. Kelas .rail-ajak dipasang ui-sidebar.js.

   Ketiganya padam begitu sidebar terbuka, dan tidak berlaku pada
   mode laci geser (ponsel) yang memang punya tombol ☰ sendiri.
   ============================================================ */

/* ---------- 34a. pegangan tiga titik ---------- */
.sidebar-shell::before{
  content:"";
  position:absolute; right:8px; top:50%;
  width:3px; height:27px; margin-top:-13.5px;   /* 27 / 9 = tepat 3 titik */
  pointer-events:none; z-index:3;
  background-image:radial-gradient(circle at 50% 1.5px, rgba(255,255,255,.92) 1.4px, transparent 1.7px);
  background-size:3px 9px;
  background-repeat:repeat-y;
  opacity:.30;
  transition:opacity .22s ease;
  animation:railGripNapas 3.6s ease-in-out infinite;
}
@keyframes railGripNapas{
  0%,100%{ opacity:.26 }
  50%    { opacity:.58 }
}
/* Terbuka -> isyarat tidak diperlukan lagi */
.sidebar-shell.is-open::before{ opacity:0; animation:none }
/* Laci geser (ponsel) tidak memakai rail sama sekali */
html:not(.mode-rail) .sidebar-shell::before{ display:none }

/* ============================================================
   34d. MODE CIUT BERHENTI BERGERAK SENDIRI       15 Agustus 2026
   ------------------------------------------------------------
   LAPORANNYA: "gerakan secara terus menerus tombol keluar selama
   di mode ciut."

   YANG DIUKUR LEBIH DULU: tombolnya SENDIRI tidak bergerak. Kotak
   .side-logout direkam 96 bingkai selama 4 detik dalam mode ciut —
   kiri, atas, lebar, dan tinggi TIDAK berubah satu pun (tetap
   38x38 pada kiri 17). Jadi yang terlihat bergerak bukan tombolnya.

   YANG SEBENARNYA BERGERAK: dua animasi tak berkesudahan milik
   sidebar, keduanya menempel di TEPI KANAN —

     .sidebar-shell::before  railGripNapas 3.6s infinite
                             pegangan tiga titik, opasitas .26<->.58
     .sidebar-shell::after   sheenVT 7s linear infinite
                             pita gradasi kuning-cyan yang meluncur

   Saat sidebar TERBUKA lebarnya 256px, jadi keduanya jauh dari
   tombol dan tidak terbaca sebagai satu benda. Saat MENCIUT
   lebarnya tinggal 72px: tombol Keluar berdiri di kiri 17px,
   sementara pita dan pegangannya berkedip-luncur sekitar 17px di
   sebelah kanannya. Pada jarak sedekat itu mata menggabungkan
   keduanya, dan yang terbaca adalah tombolnya yang bergerak.
   Itulah kenapa gejalanya HANYA muncul di mode ciut — dan kenapa
   mengutak-atik CSS tombolnya tidak akan pernah menyelesaikannya.

   PERBAIKANNYA: di mode ciut, keduanya diam. Rupanya TIDAK hilang
   — pegangannya tetap terlihat dan pitanya tetap berwarna; yang
   dihentikan hanya geraknya. Nilai diam yang dipakai persis nilai
   yang sudah ditetapkan blok "kurangi gerak" di bawah, jadi tidak
   ada rupa baru yang dikarang di sini.

   Mode TERBUKA sengaja TIDAK disentuh: di sana geraknya tidak
   pernah dikeluhkan, dan mengubahnya berarti mengubah hal yang
   tidak diminta. Kalau kelak ingin diam di kedua keadaan, cukup
   buang bagian `:not(.is-open)` dari kedua pemilih di bawah.
   ============================================================ */
.sidebar-shell:not(.is-open)::before{ animation:none; opacity:.42 }
.sidebar-shell:not(.is-open)::after { animation:none }

/* ---------- 34b. kursor "melebar ke samping" ---------- */
html.mode-rail .sidebar-shell:not(.is-open){ cursor:e-resize }
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open){ cursor:e-resize }
}
/* Yang bisa diklik tetap bicara sebagai tombol */
.sidebar-shell #topnav .topnav-link,
.sidebar-shell #topnav .topnav-trigger,
.sidebar-shell .side-logout,
.sidebar-shell .topbar-brand{ cursor:pointer }

/* ---------- 34c. ajakan sekali per sesi ---------- */
@keyframes railAjak{
  0%  { width:var(--side-rail) }
  20% { width:calc(var(--side-rail) + 20px) }
  44% { width:var(--side-rail) }
  64% { width:calc(var(--side-rail) + 20px) }
  100%{ width:var(--side-rail) }
}
.sidebar-shell.rail-ajak:not(.is-open){
  animation:railAjak 1.9s cubic-bezier(.16,1,.3,1) both;
}
/* Selama mengajak, pegangannya ikut menyala supaya mata tertuju ke sana */
.sidebar-shell.rail-ajak:not(.is-open)::before{
  animation:none; opacity:.9;
}

/* ---------- hormati "kurangi gerak" ---------- */
@media (prefers-reduced-motion:reduce){
  .sidebar-shell::before{ animation:none; opacity:.42 }
  .sidebar-shell.rail-ajak:not(.is-open){ animation:none }
}


/* ============================================================
   36. TABLET SENTUH BENAR-BENAR SAMA DENGAN DESKTOP
   ------------------------------------------------------------
   KETENTUAN 6 Agu 2026: "di mobile view landscape seperti pada
   tablet dan iPad, tampilannya 100% seperti tampilan desktop".

   Mode rail-nya sendiri sudah ditangani bagian 23 (html.mode-rail)
   dan sekarang dipasang sebelum halaman digambar (lihat skrip
   #mode-rail-awal di index.html). Yang TERTINGGAL adalah aturan
   di dalam blok @media (max-width:1024px),(hover:none), (any-pointer:coarse) yang TIDAK
   punya penawar .mode-rail — semuanya tetap berlaku di iPad dan
   membuat tampilannya berbeda dari desktop:

     - .crumb-now disembunyikan, .crumb-path dimunculkan
     - .sidebar-shell diberi padding safe-area
     - sasaran sentuh menu diperbesar (padding 11px/10px)
     - .appbar diberi tinggi minimum & padding safe-area

   Di bawah ini semuanya dikembalikan ke nilai desktop KHUSUS saat
   html.mode-rail aktif. Ponsel (yang memang memakai laci geser)
   TIDAK tersentuh sama sekali, sebab kelas itu tidak ada di sana.

   Kenapa ditulis sebagai bagian baru di akhir berkas, bukan dengan
   menyunting blok aslinya: blok asli juga melayani ponsel. Menambah
   :not(.mode-rail) di sana berarti menyentuh puluhan pemilih yang
   sudah teruji; menuliskan penawarnya di sini lebih sedikit risiko
   dan langsung terlihat sebagai satu kesatuan ketentuan.
   ============================================================ */
html.mode-rail .crumb-now{display:block}
html.mode-rail .crumb-path{display:block;font-size:12px;font-weight:600;color:var(--muted)}
html.mode-rail .sidebar-shell{padding-left:0}
html.mode-rail #topnav .topnav-link,
html.mode-rail #topnav .topnav-trigger{padding:10px 12px}
html.mode-rail #topnav .topnav-item,
html.mode-rail #topnav .topnav-subtrigger{padding:9px 12px}
/* Bilah atas memang sudah display:none di mode rail (bagian 23); tinggi
   minimum & padding-nya dinolkan juga agar tidak menyisakan ruang bila
   suatu saat bilah itu ditampilkan lagi. */
html.mode-rail .appbar{min-height:0}
/* Isi halaman: padding kiri-kanan kembali seperti desktop. Safe-area hanya
   relevan pada ponsel berponi; iPad tidak punya poni di sisi layar. */
html.mode-rail .wrap{padding-left:24px;padding-right:24px}

/* ---- TINGGI SIDEBAR: TANPA RUANG KOSONG DI BAWAH ----
   Gejala "sidebar kadang ada yang kosong di bawahnya" berasal dari satuan
   tinggi. 100vh di peramban bergerak dihitung SEOLAH bilah alamat selalu
   tersembunyi, jadi sidebar dibuat lebih tinggi daripada layar yang terlihat;
   kaki sidebar (Jenis Akun & Keluar) terdorong keluar dan yang tersisa di
   bawah daftar menu hanyalah gradien latar — terbaca sebagai ruang kosong.

   100dvh sudah dipakai di bagian 11, tetapi hanya sebagai @supports terpisah
   sehingga pada beberapa peramban kalah oleh html.mode-rail .sidebar-shell
   yang menyebut height lagi. Di sini keduanya dipastikan: dvh bila didukung,
   dan `bottom:0` sebagai jangkar terakhir supaya sidebar mustahil melewati
   dasar layar berapa pun satuan yang menang. */
.sidebar-shell{bottom:0}
@supports (height:100dvh){
  .sidebar-shell,
  html.mode-rail .sidebar-shell{height:100dvh;max-height:100dvh}
}
/* Daftar menu yang isinya sedikit tidak boleh menyisakan lubang di antara
   menu terakhir dan kaki sidebar: kakinya didorong menempel ke dasar. */
.side-foot{margin-top:auto}


/* ============================================================
   37. TOOLBAR DAFTAR: SATU BARIS PADA LEBAR TABLET
   ------------------------------------------------------------
   KETENTUAN 6 Agu 2026: "di iPad, tombol seperti Reset harusnya
   jadi satu baris dengan field yang lain, malah beda baris".

   SEBABNYA aritmetika lebar, bukan aturan responsif. Toolbar
   memakai flex-wrap:wrap dengan lebar isi yang DIPATOK:
     kotak Cari      min-width 300px (bagian 3)
     tiap filter     min/max-width 158px
     Reset & Hapus   min-width 118px masing-masing
   Pada iPad lanskap, lebar yang tersisa untuk isi halaman kira-kira
   1024px dikurangi rail 76px dan padding 2x24px = ±876px. Dengan dua
   filter + Cari + dua tombol, jumlahnya sudah melewati angka itu,
   sehingga .toolbar-actions terlempar ke baris kedua.

   Pada rentang tablet, patokan itu dilonggarkan secukupnya sehingga
   semuanya kembali muat satu baris. Desktop (>1200px) dan ponsel
   (<768px, yang memang lebih enak bertumpuk) tidak tersentuh.
   ============================================================ */
@media (min-width:768px) and (max-width:1200px){
  .toolbar{padding:12px;gap:8px}
  .toolbar .filter-field select,
  .toolbar .filter-field input{min-width:126px;max-width:126px}
  .toolbar #filter-search,
  .toolbar #filter-pl-search,
  .toolbar #filter-tender-search,
  .toolbar #fkl-view-search{min-width:180px;max-width:240px}
  .toolbar #pn-lihat-search{min-width:180px;max-width:240px}
  .toolbar .toolbar-actions{gap:8px}
  .toolbar .toolbar-actions>.btn-red,
  .toolbar .toolbar-actions>.btn-danger{min-width:96px}
  .toolbar .toolbar-actions>.btn{padding-left:12px;padding-right:12px}
}
/* Lebar tablet SEMPIT (iPad potret 768/834px): tombol tetap sebaris dengan
   Cari, tetapi kotak Cari-nya yang mengalah — bukan tombolnya yang turun. */
@media (min-width:768px) and (max-width:900px){
  .toolbar .filter-field select,
  .toolbar .filter-field input{min-width:112px;max-width:112px}
  .toolbar #filter-search,
  .toolbar #filter-pl-search,
  .toolbar #filter-tender-search,
  .toolbar #fkl-view-search,
  .toolbar #pn-lihat-search{min-width:150px;max-width:190px}
}


/* ===== Getaran "tutup dulu" untuk pop-up di luar keluarga .overlay =====
   Profil (Jadwal, Penomoran, Klausul, Penyesuaian) dan Kategori Materi memakai
   pembungkusnya sendiri, sehingga aturan umum `.overlay .modal.menolak` di
   index.html tidak menjangkaunya. Gerakannya sengaja sama persis supaya
   "tidak bisa ditutup dari sini" terasa seragam di seluruh aplikasi. */
.pnw-profil-modal.menolak,.materi-kat-modal.menolak{
  animation:tor-dk-getar .4s cubic-bezier(.36,.07,.19,.97) both}
.pnw-profil-modal.menolak .pnw-profil-x,.materi-kat-modal.menolak .materi-kat-x{
  animation:tor-dk-sorot .4s ease-in-out 2}
@media (prefers-reduced-motion:reduce){
  .pnw-profil-modal.menolak,.materi-kat-modal.menolak{animation:none} }


/* ============================================================
   BILAH FILTER MONITORING — KEMBALI SATU BARIS (8 Agu 2026)
   ------------------------------------------------------------
   Gejala: Reset & Input Data terlempar ke baris kedua, menyisakan
   ruang kosong lebar di bawah deretan filter.

   Sebabnya bukan tombolnya, melainkan LEBAR DASAR dua isian di
   kirinya. Kolom Bidang memakai `width:max-content` — selebar
   pilihan terpanjang ("Keselamatan, Kesehatan Kerja, Lingkungan
   dan Keamanan", ±370px) — sementara kotak Cari dipatok minimal
   300px. Dijumlahkan dengan Status, Tahun, jarak antar-isian, dan
   kedua tombol, angkanya melewati lebar bilah; karena .toolbar
   memakai flex-wrap:wrap, kelompok tombol turun satu baris.

   Perbaikan: lebar DASAR Bidang dan Cari dipangkas ±30%
   (370→260px dan 300→210px). Yang dikurangi HANYA lebar minimum
   yang menentukan pembungkusan baris — kotak Cari tetap boleh
   memuai (flex-grow) mengisi sisa ruang, jadi tidak muncul celah
   kosong di tengah bilah dan tombol tetap mentok di kanan.

   Ada tiga rentang, karena angka yang muat di layar 1400px belum
   tentu muat di 1210px:
     >1300px  → pemangkasan 30% seperti diminta
     1201-1300px → dipangkas lebih dalam supaya tetap satu baris
     768-1200px  → hanya kolom Bidang yang dicegat; sisanya sudah
                   punya angkanya sendiri di bagian tablet di atas
   ============================================================ */
@media (min-width:1301px){
  .toolbar .filter-field > select[id$="bidang"]{
    min-width:0; width:max-content; max-width:260px}
  .toolbar #filter-search,
  .toolbar #filter-pl-search,
  .toolbar #filter-tender-search{min-width:210px}
  .toolbar .toolbar-search{flex:1 1 210px}
}
@media (min-width:1201px) and (max-width:1300px){
  .toolbar .filter-field > select[id$="bidang"]{
    min-width:0; width:max-content; max-width:220px}
  .toolbar .filter-field select,
  .toolbar .filter-field input{min-width:140px;max-width:140px}
  .toolbar #filter-search,
  .toolbar #filter-pl-search,
  .toolbar #filter-tender-search{min-width:170px;max-width:none;width:100%}
  .toolbar .toolbar-search{flex:1 1 170px}
}
@media (min-width:768px) and (max-width:1200px){
  /* Aturan tablet di bagian sebelumnya sudah mengecilkan Status, Tahun & Cari,
     tetapi TIDAK menyentuh Bidang — `width:max-content` miliknya lebih kuat.
     Tanpa batas ini, bilah tetap pecah dua baris di iPad. */
  .toolbar .filter-field > select[id$="bidang"]{
    min-width:0; width:max-content; max-width:180px}
}
/* Pilihan terpanjang kini lebih lebar daripada kotaknya — dipotong dengan
   elipsis, bukan dibiarkan terpenggal mentah di tengah huruf. */
@media (min-width:768px){
  .toolbar .filter-field > select[id$="bidang"]{
    text-overflow:ellipsis; overflow:hidden; white-space:nowrap}
}


/* ============================================================
   TOMBOL AKSI & KOLOM AKSI — SATU UKURAN UNTUK SELURUH APLIKASI
   (8 Agu 2026)
   ------------------------------------------------------------
   Dipasang PALING AKHIR agar menimpa angka-angka lama yang tersebar di
   banyak bagian berkas ini, tanpa harus membongkar tiap bagian itu.

   1) UKURAN TOMBOL — 32x32 px, ikon 15 px.
      Itu ukuran baku .act (bagian #4) dan yang dipakai di Monitoring.
      Yang menyimpang:
        .fk-act-icon  36x36 / ikon 16  -> File Kontrak & Dokumen Pengadaan;
                                          inilah "tombol yang terlalu besar".
        .pn-actions   29x29            -> Penetapan Nomor; menyimpang ke arah
                                          sebaliknya, tetap disamakan supaya
                                          benar-benar satu ukuran.
      Ponsel (<=640px) DIKECUALIKAN: di sana tombol tetap 34 px sebagai sasaran
      sentuh jari, bukan karena kelalaian.

   2) LEBAR KOLOM AKSI — "sepanjang deretan tombol ATAU sepanjang judulnya,
      mana yang lebih dulu tercapai".
      Itu persis perilaku `width:1%` + `white-space:nowrap` pada tabel
      table-layout:auto: peramban menyusutkan kolom sampai sesempit ISI
      TERLEBARNYA yang tidak boleh terpotong — dan sel judul ikut dihitung
      sebagai isi. Jadi kolomnya berhenti di deretan tombol bila tombolnya
      lebih lebar, atau di kata "Aksi" bila judulnya yang lebih lebar.

      Tiga hal harus dinolkan agar itu bekerja:
        - `th{min-width:82px}` (aturan dasar) memberi lantai 82 px; untuk kolom
          berisi satu tombol saja itu jauh terlalu lebar;
        - lebar tetap pada .pn-col-aksi (150 px);
        - min-width sebaris pada beberapa <th> Aksi — yang ini sudah dibereskan
          di sumbernya: seluruh <th>Aksi</th> kini memakai kelas .col-aksi,
          bukan style sebaris.

      Sel datanya dijangkau lewat :has(): banyak <td> aksi tidak berkelas, dan
      menambah kelas ke setiap pembuat baris di app.js/susun-*.js jauh lebih
      rapuh daripada satu selektor yang mengenali "sel yang isinya deretan
      tombol". Pola :has() sudah dipakai di berkas ini (lihat filter Bidang).
   ============================================================ */
.act,
.pn-aksi-item .pn-actions .act{width:32px;height:32px}
.act svg,
.pn-aksi-item .pn-actions .act svg{width:15px;height:15px}
/* .fk-act-icon menumpang kelas .fk-act (tombol berlabel). padding & border-radius
   miliknya harus ikut dinolkan/diselaraskan, kalau tidak kotaknya tetap terasa
   lebih besar & lebih tumpul daripada .act di sebelahnya. */
.fk-act-icon{width:32px;height:32px;padding:0;border-radius:10px;flex:0 0 auto;justify-content:center;gap:0}
.fk-act-icon svg{width:15px;height:15px}
/* Ponsel (<=640px): sasaran sentuh dikembalikan ke 34 px. Aturan aslinya ada di
   media query bagian atas berkas; karena blok ini berada JAUH di bawahnya dan
   bobot selektornya sama, tanpa pengulangan di sini aturan 32 px akan menang
   dan tombolnya ikut mengecil di ponsel — media query TIDAK menambah bobot,
   hanya urutan yang menentukan. */
@media(max-width:640px){
  .act,
  .pn-aksi-item .pn-actions .act,
  .fk-act-icon{width:34px;height:34px}
}

.table-wrap th.col-aksi,.table-wrap td.col-aksi,
.table-wrap th.pn-col-aksi,.table-wrap td.pn-col-aksi,
.table-wrap th.pnw-col-aksi,.table-wrap td.pnw-col-aksi,
.table-wrap th.col-spk-aksi,.table-wrap td.col-spk-aksi,
.table-wrap td:has(> .action-cell),
.table-wrap td:has(> .pn-actions){
  width:1%;min-width:0;max-width:none;
  white-space:nowrap;text-align:center;
  padding-left:10px;padding-right:10px;
}
/* Deretan tombol tidak pernah turun baris — kalau ia melipat, kolomnya justru
   menyempit di bawah lebar sebenarnya dan tombolnya menumpuk ke bawah. */
.table-wrap .action-cell,
.table-wrap .pn-actions{flex-wrap:nowrap}


/* ============================================================
   HASIL ANALISA HARGA SATUAN — GARIS PEMISAH PUTIH (8 Agu 2026)
   ------------------------------------------------------------
   Tabel ini satu-satunya yang tampil TANPA kisi: aturannya di bagian
   Analisa memang sengaja menghapusnya —

       table.ana-res th, table.ana-res td { border:none }
       table.ana-res tbody td { border-bottom:1px solid #e8f0f1 }

   — meniru tabel isian (ana-uraian) yang memang bergaya "hanya garis
   horizontal tipis". Untuk tabel HASIL pilihan itu keliru: ia dibaca
   berdampingan dengan tabel lain di aplikasi yang semuanya memakai kisi
   putih tegas, sehingga kolomnya terasa mengambang dan angka Harga Satuan
   Barang & Jasa sulit dipisahkan sekilas.

   Sekarang disamakan dengan tabel lain: border 1px putih pada seluruh sel,
   horizontal DAN vertikal. Warna putih terbaca karena baris tabel ini
   berlatar teduh (#eef4f6 / #f8fbfc) dan kepala tabel berlatar teal —
   sama persis dengan cara kisi putih bekerja di tabel Monitoring.

   Kepala kartu ("Hasil Analisa Harga Satuan") diberi garis putih di
   bawahnya, lalu border ATAS sel judul dihapus. Keduanya harus berpasangan:
   bila dua-duanya dipasang, garisnya menebal jadi 2 px dan terlihat seperti
   celah, bukan pemisah.
   ============================================================ */
.ana-res-head{border-bottom:1px solid #fff}
table.ana-res th,table.ana-res td,
table.ana-res tbody td,
table.ana-res tbody tr:last-child td{border:1px solid #fff}
table.ana-res thead th{border-top:none}

/* Bilah Kategori Materi ikut disamakan (8 Agu 2026). Bobot selektornya lebih
   tinggi daripada aturan .act di atas, jadi ia harus disebut sendiri —
   kalau tidak, satu-satunya tombol aksi yang tersisa 31px/ikon 14px justru
   ada di sini. */
.materi-kat-bar .act{width:32px;height:32px;border-radius:10px}
.materi-kat-bar .act svg{width:15px;height:15px}


/* ============================================================
   TOMBOL AKSI DIPERCANTIK + BALON PETUNJUK (8 Agu 2026)
   ------------------------------------------------------------
   Dua permintaan sekaligus:

   1) WARNA & TAMPILAN tombol Ubah/Lihat/Hapus dirapikan.
      Yang lama: satu gradasi dua-warna datar tanpa tepi, sehingga
      tombol kuning menyatu dengan latar baris terang dan ikonnya
      terlihat mengambang. Sekarang tiap tombol memakai gradasi
      TIGA titik (terang di kiri-atas -> warna inti -> lebih gelap
      di kanan-bawah), tepi tipis, dan kilau garis di sisi atas.
      Hasilnya bentuknya tegas di latar terang MAUPUN gelap.

      Warna Ubah digeser dari kuning murni (#F6B40E) ke amber yang
      lebih pekat. Kuning murni memaksa ikon berwarna cokelat tua
      supaya terbaca, dan cokelat-di-atas-kuning itu yang membuatnya
      terlihat kusam di sebelah teal & merah yang berikon putih.

      Selektornya `button.act`, BUKAN `.act`. Sebabnya `.act` juga
      dipakai sebagai nama pembungkus <div class="act"> pada kepala
      pop-up Dokumen (index.html & susun-dokumen.js); memakai .act
      polos akan memberi wadah itu warna & tepi yang tidak diminta.
      Bobot (0,1,1) sekaligus menang atas seluruh aturan .act lama
      yang tersebar di berkas ini tanpa perlu !important.

      TIDAK ADA transform di sini — blok 29 & 31 sudah meniadakan
      efek menonjol/getar saat kursor menyorot, dan itu memang
      diminta. Yang berubah saat disorot hanya warna & bayangan.

   2) BALON PETUNJUK menggantikan `title` bawaan peramban.
      Dikendalikan modul di app-lain.js; di sini hanya tampilannya.
      Ia `position:fixed` dan ditempel ke <body> — kalau dibuat
      sebagai ::after pada tombolnya, tepi .table-wrap yang
      ber-overflow:auto akan memotongnya di baris terakhir tabel.
      Karena berada di luar .view/.modal, aturan menyeluruh blok 31
      (`*:hover{transform:none}`) tidak menjangkaunya.
   ============================================================ */
button.act{
  border:1px solid rgba(255,255,255,.30);
  box-shadow:0 1px 2px rgba(16,40,50,.18), inset 0 1px 0 rgba(255,255,255,.34);
  transition:background .18s ease, box-shadow .2s ease, border-color .18s ease;
}
button.act-edit{background:linear-gradient(145deg,#FFD164,#F2A50A 52%,#DE8E00);color:#442D00}
button.act-view{background:linear-gradient(145deg,#26BAC0,#0E7C86 52%,#0A6772);color:#fff}
button.act-del {background:linear-gradient(145deg,#F58585,#D33A3A 52%,#B62B2B);color:#fff}

button.act-edit:hover{background:linear-gradient(145deg,#FFDA85,#F5AE1E 52%,#E59500);
  border-color:rgba(255,255,255,.5);
  box-shadow:0 3px 11px rgba(206,132,0,.42), inset 0 1px 0 rgba(255,255,255,.5)}
button.act-view:hover{background:linear-gradient(145deg,#38CBD1,#12909B 52%,#0C7B86);
  border-color:rgba(255,255,255,.5);
  box-shadow:0 3px 11px rgba(14,124,134,.42), inset 0 1px 0 rgba(255,255,255,.42)}
button.act-del:hover{background:linear-gradient(145deg,#FF9A9A,#DE4747 52%,#C43333);
  border-color:rgba(255,255,255,.5);
  box-shadow:0 3px 11px rgba(190,45,45,.42), inset 0 1px 0 rgba(255,255,255,.42)}

/* Ditekan: bayangan luar dimatikan & diganti bayangan DALAM, jadi tombolnya
   terasa masuk ke dalam tanpa perlu menggeser posisinya. */
button.act:active{box-shadow:inset 0 2px 5px rgba(0,0,0,.26)}

/* Ikon Ubah yang baru (lembar + pensil) punya garis lebih rapat daripada ikon
   mata & tempat sampah. Pada 15 px, stroke 2 membuat sudut kanan-atas lembar
   dan badan pensil hampir menyatu — 1.85 mengembalikan celahnya. */
button.act-edit svg{stroke-width:1.85}

/* Tombol nonaktif (mis. Naikkan/Turunkan pada klausul teratas) tidak boleh
   ikut berwarna: kalau ikut, tidak ada bedanya dengan tombol yang bisa ditekan. */
button.act[disabled],button.act[disabled]:hover{
  background:linear-gradient(145deg,#d6dee2,#c3ced4);color:#fff;
  border-color:rgba(255,255,255,.35);box-shadow:none;cursor:not-allowed;opacity:.75}

/* ---- Balon petunjuk ---- */
.act-tip{
  position:fixed; left:0; top:0; z-index:12000;
  max-width:230px; padding:6px 11px;
  border-radius:9px; white-space:nowrap;
  font-size:12px; font-weight:600; letter-spacing:.1px; line-height:1.3;
  color:#fff; background:#12414B;
  box-shadow:0 8px 20px rgba(9,32,38,.30), 0 1px 3px rgba(9,32,38,.22);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .14s ease, visibility .14s ease;
}
.act-tip.tampil{opacity:1; visibility:visible}
/* Anak panah. `--ax` diisi app-lain.js supaya menunjuk tengah TOMBOL, yang
   tidak selalu sama dengan tengah balon saat balon digeser dari tepi layar. */
.act-tip::after{
  content:""; position:absolute; left:var(--ax,50%); margin-left:-6px;
  border:6px solid transparent;
}
.act-tip::after{top:-12px; border-bottom-color:#12414B}
.act-tip.atas::after{top:auto; bottom:-12px; border-bottom-color:transparent; border-top-color:#12414B}

@media (prefers-reduced-motion: reduce){
  .act-tip{transition:none}
}
@media print{
  .act-tip{display:none !important}
}


/* ============================================================
   SIDEBAR — WARNA PENUH 100% + KESAN KACA (8 Agu 2026, revisi)
   ------------------------------------------------------------
   Versi sebelumnya menurunkan latar sidebar ke 80% alfa. Hasilnya
   memang tembus, tetapi warnanya ikut PUDAR: teal tua bercampur
   dengan halaman terang di belakangnya sampai terlihat kelabu.
   Permintaan sekarang: warnanya tetap 100%, tetapi masih terasa
   seperti kaca.

   Dua hal itu tidak bisa dipenuhi lewat jalan yang sama, karena
   memang saling meniadakan — begitu latar tembus, apa pun yang
   lewat di belakangnya IKUT menentukan warna yang terlihat.
   Maka pembagiannya:

     WARNA  -> kembali ke gradasi asli, tanpa alfa sama sekali.
               Teal tua tampil sepekat semula.
     KACA   -> dibangun dari CAHAYA, bukan dari tembus pandang:
               satu lapis sorotan putih tipis yang jatuh miring
               dari sudut kiri-atas, seperti pantulan pada
               permukaan kaca. Ditulis sebagai lapisan PERTAMA
               pada `background` (latar boleh bertumpuk), jadi
               tidak perlu elemen semu — ::before sudah dipakai
               pegangan tiga titik (blok 34a) dan ::after garis
               aksen kanan.

   backdrop-filter DILEPAS. Di balik latar yang tidak tembus,
   ia tidak menghasilkan apa pun yang terlihat — tetapi tetap
   memaksa peramban menghitung ulang kaburan tiap kali halaman
   di belakangnya bergulir. Beban tanpa hasil.
   ============================================================ */
.sidebar-shell{
  background:
    linear-gradient(135deg,
      rgba(255,255,255,.11) 0%,
      rgba(255,255,255,.05) 26%,
      rgba(255,255,255,.015) 48%,
      rgba(255,255,255,0) 66%),
    radial-gradient(420px 220px at 20% 0%, rgba(22,169,181,.30), transparent 62%),
    linear-gradient(168deg,
      var(--side-1) 0%,
      var(--side-2) 42%,
      var(--teal-dark) 76%,
      var(--side-3) 100%);
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
}


/* ============================================================
   SATU UKURAN UNTUK SEMUA TOMBOL UTAMA (8 Agu 2026)
   ------------------------------------------------------------
   Acuannya tombol "Batal" pada bilah langkah wizard: itu tombol
   .btn polos — padding 10px 17px, huruf 11.5px, sudut 11px,
   ikon 16px. Sebagian besar tombol aplikasi memang sudah memakai
   ukuran itu; yang menyimpang hanya beberapa, dan justru itu yang
   membuat halaman terasa tidak rata:

     .form-actions .btn   12px 26px / 12px   -> Simpan & Batal pada
                          form Input Data (SPBJ, Pengadaan Langsung,
                          Tender) — paling mencolok karena berdiri
                          sendiri di dasar form.
     .hps-pick-btn        height:46px        -> tinggi dipatok agar
                          sejajar kotak isian di sampingnya.
     .jp-profil-btn       8px 10px (<=1180)  -> mengecil di layar
                          sedang sementara tetangganya tidak.

   Tombol Pilih/Ganti Data Pekerjaan & Lepas Pilihan pada RHO, HPS,
   dan Analisa dulu memakai gaya SEBARIS (padding:8px 14px). Gaya
   sebaris tidak bisa dikalahkan aturan CSS mana pun tanpa
   !important, jadi kedelapan atribut itu dibuang langsung di
   app.js — bukan ditimpa dari sini.

   TINGGI DISAMAKAN LEWAT min-height, bukan padding saja. Sebabnya
   tombol berikon dan tombol tanpa ikon tidak pernah sama tinggi
   walau padding-nya identik: baris isinya setinggi ikon (16px)
   pada yang berikon, dan setinggi huruf (~14px) pada yang tidak —
   selisih 2px yang terlihat begitu keduanya berdampingan.

   .btn-sm SENGAJA DIKECUALIKAN. Ia dipakai di dalam baris tabel
   dan kartu sempit (mis. tombol pada daftar klausul); menyamakan
   ukurannya dengan tombol utama akan mendorong tinggi baris tabel.

   Lingkupnya `.view` — yaitu isi halaman. Tombol di dalam pop-up
   (modal konfirmasi, Pilih Dokumen, pratinjau) ditempel ke <body>
   di luar .view, dan ukurannya memang sengaja berbeda: di sana
   tombol berpasangan melebar penuh mengisi kaki modal.
   ============================================================ */
.view .form-actions .btn:not(.btn-sm),
.view .jp-profil-btn,
.view .dp-pick-btn,
.view .dp-unpick-btn,
.view .pnw-profil-btn{
  padding:10px 17px;
  font-size:11.5px;
  gap:8px;
}
.view .form-actions .btn:not(.btn-sm) svg,
.view .jp-profil-btn svg,
.view .dp-pick-btn svg,
.view .dp-unpick-btn svg,
.view .pnw-profil-btn svg{width:16px;height:16px}

/* Tinggi seragam untuk seluruh tombol utama di dalam halaman */
.view .btn:not(.btn-sm),
.view .jp-profil-btn,
.view .dp-pick-btn,
.view .dp-unpick-btn{min-height:36px}

/* Tinggi tetap 46px dilepas; tombol ini tetap sejajar kotak isian karena
   barisnya memakai align-items:flex-end. */
.view .hps-pick-btn{height:auto}

/* Label profil kini lengkap ("Simpan Profil" / "Muat Profil" /
   "Batalkan Profil"), jadi tiga tombol berdampingan bisa lebih lebar
   daripada kartunya. Dibiarkan turun baris, bukan meluber. */
.jp-profil-card{flex-wrap:wrap}

/* ---- Tombol "Kembali" diberi warna sendiri ----
   .btn-light dulu abu-kebiruan #f1f6f7 di atas kartu putih: nyaris
   sewarna latarnya sendiri, sehingga tombol Kembali sulit dikenali
   sebagai tombol. Sekarang grafit kebiruan — jelas terbaca di atas
   kartu terang, dan tidak tertukar dengan teal (Selanjutnya), merah
   (Batal), hijau (Simpan), atau kuning (Simpan Profil). */
.btn.btn-light{
  background:linear-gradient(135deg,#48606a,#6b848e);
  color:#fff;border:none;
  box-shadow:0 4px 14px rgba(45,70,79,.30),inset 0 1px 0 rgba(255,255,255,.22);
}
.btn.btn-light svg{color:#fff;stroke:currentColor}
.btn.btn-light:hover{
  background:linear-gradient(135deg,#526d78,#78939e);
  color:#fff;border-color:transparent;
  box-shadow:0 8px 22px rgba(45,70,79,.42),inset 0 1px 0 rgba(255,255,255,.28);
  filter:brightness(1.04);
}


/* ============================================================
   NAVIGASI HALAMAN (PAGINASI) DIBERI WARNA — 8 Agu 2026
   ------------------------------------------------------------
   Keluhan: tombolnya putih di atas panel putih, jadi "‹ Sebelumnya"
   dan "Berikutnya ›" nyaris tidak terlihat sebagai tombol — hanya
   tulisan mengambang di pojok kanan bawah tabel.

   Tiga peran dibedakan warnanya, memakai dua warna yang memang
   sudah jadi bahasa aplikasi ini (teal & kuning PLN):

     Sebelumnya / Berikutnya  -> BIRU indigo, tulisan putih.
        Ini tombol AKSI (berpindah halaman), jadi yang paling
        menonjol. Sempat kuning; diganti biru atas pilihan user.
        Yang penting bukan warnanya, melainkan tetap BERBEDA dari
        teal penanda halaman aktif di sebelahnya.

     Nomor halaman            -> kartu teal muda bertepi teal.
        Terbaca sebagai tombol, tetapi tenang — jumlahnya bisa
        banyak dan tidak boleh meramaikan dasar tabel.

     Nomor halaman AKTIF      -> teal pekat, tulisan putih (tetap
        seperti semula; sudah paling menonjol di antara nomor).

   Tanpa box-shadow: blok "bayangan diratakan" di atas memasang
   `box-shadow ... !important` pada .pg-btn, jadi bayangan apa pun
   yang ditulis di sini akan diabaikan. Keterbacaan dibangun dari
   warna isi & tepi — bukan bayangan.

   Keadaan MATI (halaman pertama/terakhir) tidak memakai opacity
   .4 lagi: warna yang dipudarkan menjadi kotor, apa pun warnanya.
   Diganti abu-abu rata yang jelas terbaca sebagai "tidak bisa
   ditekan".
   ============================================================ */
.pagination .pg-btn{
  font-weight:700;
  transition:background .18s ease,color .18s ease,border-color .18s ease;
}
/* --- nomor halaman --- */
.pagination .pg-btn.pg-num{
  background:linear-gradient(180deg,#f2fafb,#e2f1f3);
  border:1px solid #b7d7db;
  color:#0b5a63;
}
.pagination .pg-btn.pg-num:hover:not(:disabled):not(.active){
  background:linear-gradient(180deg,#dcf0f2,#c9e7ea);
  border-color:var(--teal);
  color:var(--teal-dark);
}
.pagination .pg-btn.pg-num.active{
  background:linear-gradient(135deg,var(--teal),var(--cyan));
  border-color:var(--teal);
  color:#fff;
}
/* --- Sebelumnya / Berikutnya ---
   RIWAYAT WARNA: kuning -> indigo -> WARNA JUDUL TABEL (8 Agu 2026, permintaan
   terakhir user: "jadikan warna biru tua seperti pada warna judul tabel").
   Nilainya diambil apa adanya dari aturan kepala tabel (~baris 1940):
       th{background:#0E7C86; border-color:#0b6b74}
   Sengaja ditulis sebagai angka yang sama persis, bukan var(--teal), supaya
   terbaca jelas bahwa sumbernya adalah kepala tabel — kalau kelak warna kepala
   tabel diubah, KEDUANYA harus diubah bersama.

   Karena kini sewarna dengan nomor halaman AKTIF, keduanya dibedakan dengan
   cara lain: nomor aktif memakai GRADASI teal->cyan (lebih terang & berkilau),
   sedangkan Sebelumnya/Berikutnya rata tanpa gradasi — persis kepala tabel di
   atasnya. Sisi rata vs berkilau itulah pembedanya, bukan lagi rona warna. */
.pagination .pg-btn:not(.pg-num){
  background:#0E7C86;
  border:1px solid #0b6b74;
  color:#fff;
}
.pagination .pg-btn:not(.pg-num):hover:not(:disabled){
  background:#0b6b74;
  border-color:#095e66;
  color:#fff;
}
.pagination .pg-btn:not(.pg-num):disabled{
  background:#eaeff1;
  border-color:#d8e1e4;
  color:#93a3aa;
  opacity:1;
  cursor:default;
}


/* ============================================================
   KOLOM AKSI FILE KONTRAK — TOMBOL TETAP SATU BARIS (8 Agu 2026)
   ------------------------------------------------------------
   Gejala: pada "Dokumen Perjanjian/Kontrak" tombol Lihat & Hapus
   bertumpuk ke bawah, sementara di menu lain berdampingan.

   Sebabnya kolom Aksi di sini memakai nama kelas yang BERBEDA.
   Blok "TOMBOL AKSI & KOLOM AKSI" di atas menyebut .action-cell
   dan .pn-actions; File Kontrak memakai `td.fk-actcell` berisi
   `div.fk-actions` — yang sejak awal ber-`flex-wrap:wrap`.

   Akibatnya lebar TERKECIL sel itu = satu tombol saja. Karena
   `th.col-aksi` menyuruh kolomnya sesempit mungkin (width:1%),
   peramban menurutinya sampai selebar satu tombol, lalu tombol
   kedua turun baris. Yang perlu diperbaiki bukan lebar kolomnya,
   melainkan izin melipat itu: begitu deretannya nowrap, lebar
   terkecilnya menjadi selebar KEDUA tombol dan kolomnya berhenti
   di situ.

   Ini pengingat yang sama seperti pada blok efek 3D: daftar nama
   kelas tidak pernah lengkap. Karena itu di sini dipakai juga
   `:has(> .fk-actions)` supaya sel aksi tetap terjaring walau
   kelas selnya kelak berganti.
   ============================================================ */
.table-wrap .fk-actions{flex-wrap:nowrap}
.table-wrap td.fk-actcell,
.table-wrap td:has(> .fk-actions){
  width:1%;min-width:0;max-width:none;
  white-space:nowrap;text-align:center;
  padding-left:10px;padding-right:10px;
}


/* ============================================================
   TOMBOL KEMBALI TIMBUL (RELIEF) — 8 Agu 2026
   ------------------------------------------------------------
   Permintaan: semua tombol diberi efek timbul seperti contoh
   (kotak berwarna dengan tepi atas mengilap, tepi bawah gelap,
   dan bayangan jatuh ke permukaan di bawahnya).

   Ini MEMBALIK "TAMBALAN TAJAM — BAGIAN E" (3 Agu 2026) yang
   dulu meratakan bayangan tombol menjadi satu lapis tipis.
   Pembalikannya SENGAJA dibatasi pada bayangan DIAM saja:
   yang dikeluhkan waktu itu adalah tulisan & ikon yang bergetar
   dan menonjol SAAT KURSOR MENGENAINYA. Blok 29 & 31 yang
   mematikan transform serta text-shadow TIDAK disentuh — tombol
   di sini timbul tanpa bergerak sedikit pun.

   Empat lapis penyusun reliefnya:
     inset 0 0 0 1px  putih  -> cincin tepi, memisahkan dari latar
     inset 0 1px 0    putih  -> kilau di bibir ATAS
     inset 0 -2px 0   hitam  -> bibir BAWAH gelap = ketebalan benda
     0 2px 0 + 0 6px 14px    -> lipatan & bayangan jatuh

   BOBOT PEMILIH — `:not(#_a):not(#_b)` WAJIB. Aturan pendataran
   di bagian E memakai !important, dan !important TIDAK
   membatalkan perhitungan bobot; ia hanya menaikkan lapisan.
   Lawan terberatnya `.overlay:not(#pn-preview-overlay) .act:not([disabled])`
   berbobot (1,3,0), jadi `.act` polos (0,1,0) — bahkan dengan
   !important — akan kalah. Dua `:not()` ber-ID palsu menaikkannya
   ke (2,1,0) tanpa mengubah elemen mana pun yang terpilih. Pola
   yang sama sudah dipakai di blok 31.

   Tombol MATI dikecualikan: benda yang tidak bisa ditekan tidak
   boleh terlihat menonjol. Saat DITEKAN reliefnya dibalik menjadi
   bayangan ke dalam — itu yang membuat tombol terasa masuk tanpa
   perlu digeser posisinya.
   ============================================================ */
.btn:not(#_a):not(#_b):not([disabled]),
button.act:not(#_a):not(#_b):not([disabled]),
.fk-act:not(#_a):not(#_b):not([disabled]),
.pg-btn:not(#_a):not(#_b):not(:disabled),
.jp-profil-btn:not(#_a):not(#_b),
.dp-pick-btn:not(#_a):not(#_b),
.dp-unpick-btn:not(#_a):not(#_b),
.login-btn:not(#_a):not(#_b),
.logout-btn:not(#_a):not(#_b){
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.30),
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -2px 0 rgba(0,0,0,.17),
    0 2px 0 rgba(16,40,50,.10),
    0 6px 14px rgba(16,40,50,.20) !important;
}
.btn:not(#_a):not(#_b):not([disabled]):hover,
button.act:not(#_a):not(#_b):not([disabled]):hover,
.fk-act:not(#_a):not(#_b):not([disabled]):hover,
.pg-btn:not(#_a):not(#_b):not(:disabled):hover,
.jp-profil-btn:not(#_a):not(#_b):hover,
.dp-pick-btn:not(#_a):not(#_b):hover,
.dp-unpick-btn:not(#_a):not(#_b):hover,
.login-btn:not(#_a):not(#_b):hover,
.logout-btn:not(#_a):not(#_b):hover{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.40),
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -2px 0 rgba(0,0,0,.19),
    0 3px 0 rgba(16,40,50,.12),
    0 9px 20px rgba(16,40,50,.26) !important;
}
/* Ditekan: relief dibalik ke dalam. Lipatan & bayangan jatuh dihapus supaya
   permukaannya benar-benar terbaca turun, bukan sekadar menggelap. */
.btn:not(#_a):not(#_b):not([disabled]):active,
button.act:not(#_a):not(#_b):not([disabled]):active,
.fk-act:not(#_a):not(#_b):not([disabled]):active,
.pg-btn:not(#_a):not(#_b):not(:disabled):active,
.jp-profil-btn:not(#_a):not(#_b):active,
.dp-pick-btn:not(#_a):not(#_b):active,
.dp-unpick-btn:not(#_a):not(#_b):active,
.login-btn:not(#_a):not(#_b):active,
.logout-btn:not(#_a):not(#_b):active{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.22),
    inset 0 2px 6px rgba(0,0,0,.30) !important;
}
/* Tombol mati tetap rata — tidak boleh mengundang ditekan. */
.btn[disabled]:not(#_a):not(#_b),
button.act[disabled]:not(#_a):not(#_b),
.fk-act[disabled]:not(#_a):not(#_b),
.pg-btn:disabled:not(#_a):not(#_b){
  box-shadow:none !important;
}
@media print{
  .btn:not(#_a),button.act:not(#_a),.fk-act:not(#_a),.pg-btn:not(#_a){box-shadow:none !important}
}


/* ============================================================
   SEGMEN SPBJ / PENGADAAN LANGSUNG / TENDER IKUT TIMBUL
   (8 Agu 2026)
   ------------------------------------------------------------
   Sebelumnya segmen ini SENGAJA dilewati saat relief dipasang ke
   tombol lain, karena bentuknya berbeda: yang berwarna bukan
   tombolnya, melainkan `.fk-seg-thumb` — satu kotak yang MELUNCUR
   di belakang tombol menuju segmen yang dipilih. Tombolnya sendiri
   (`.fk-seg-btn`) tidak berlatar sama sekali; yang aktif hanya
   berganti warna huruf menjadi putih.

   Karena itu reliefnya dipasang di dua tempat, bukan pada tombol:

     .fk-seg       -> talam/wadahnya. Diberi relief ke DALAM
                      (bibir atas gelap, dasar terang) supaya
                      terbaca sebagai cekungan tempat chip duduk.
     .fk-seg-thumb -> chip aktifnya. Diberi relief ke LUAR, sama
                      persis dengan tombol lain: cincin tepi,
                      kilau bibir atas, bibir bawah gelap, lalu
                      bayangan jatuh.

   Cekungan + benda menonjol di dalamnya = yang membuat mata
   membaca segmen aktif benar-benar timbul. Kalau keduanya sama-
   sama menonjol, chip-nya justru tenggelam.

   Bayangan chip IKUT DIANIMASIKAN bersama geserannya (transition
   di baris 1958 hanya menyebut transform/width/opacity), jadi
   reliefnya tidak berkedip saat berpindah segmen.

   Layar sempit (<=640px) tidak memakai chip peluncur sama sekali —
   `.mod-seg .fk-seg-thumb{display:none}` dan segmen aktif diberi
   latar sendiri. Relief yang sama diulang di sana, kalau tidak
   satu-satunya segmen yang datar justru ada di ponsel.
   ============================================================ */
.fk-seg{
  box-shadow:
    inset 0 1px 2px rgba(16,40,50,.16),
    inset 0 -1px 0 rgba(255,255,255,.85),
    0 1px 2px rgba(16,40,50,.08);
}
.fk-seg-thumb{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.30),
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -2px 0 rgba(0,0,0,.17),
    0 2px 0 rgba(11,90,99,.22),
    0 6px 14px rgba(14,124,134,.34);
  transition:
    transform .38s cubic-bezier(.16,1,.3,1),
    width .38s cubic-bezier(.16,1,.3,1),
    opacity .18s ease,
    box-shadow .18s ease;
}
/* Segmen yang belum dipilih: relief tipis saja saat disorot — kalau setebal
   chip aktif, tidak ada lagi bedanya antara "dipilih" dan "sekadar disorot". */
.fk-seg-btn:not(.active):hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.7),
    0 1px 2px rgba(16,40,50,.12);
}
@media(max-width:640px){
  .mod-seg .fk-seg-btn.active{
    box-shadow:
      inset 0 0 0 1px rgba(255,255,255,.30),
      inset 0 1px 0 rgba(255,255,255,.45),
      inset 0 -2px 0 rgba(0,0,0,.17),
      0 2px 0 rgba(11,90,99,.22),
      0 6px 14px rgba(14,124,134,.34);
  }
}
@media print{
  .fk-seg,.fk-seg-thumb,.fk-seg-btn{box-shadow:none !important}
}

/* ============================================================
   36. POP-UP DAFTAR DOKUMEN (.tor-dk-ov) — ATURAN DASAR
   ------------------------------------------------------------
   BUG: teks "Dokumen Kontrak" bocor di halaman, menempel persis
   di sisi kanan sidebar.

   Penyebabnya: markup #spk-dok-overlay ADA SEJAK AWAL di
   index.html dan memakai kelas .tor-dk-ov, sedangkan seluruh
   gaya .tor-dk-* baru DISUNTIKKAN oleh torEnsureStyle()
   (susun-dokumen.js) — dan itu hanya terjadi saat pop-up
   pertama kali dibuka. Sebelum itu kelasnya tidak berarti
   apa-apa, sehingga <div> pop-up tergambar sebagai blok biasa
   di dasar halaman dan judulnya (<b>Dokumen Kontrak</b>)
   muncul di x=0 — tertimpa sebagian oleh sidebar, menyisakan
   ekor "…ontrak" yang terlihat seperti teks nyasar.

   Aturan dasar di bawah membuat pop-up itu tersembunyi sejak
   halaman pertama kali dimuat. Gaya lengkapnya (latar gelap,
   posisi, dsb.) tetap datang dari torEnsureStyle() — karena
   disuntikkan belakangan, ia yang menang tanpa perlu !important.
   ============================================================ */
.tor-dk-ov{
  position:fixed;inset:0;z-index:9000;
  display:none;align-items:center;justify-content:center;
  background:rgba(12,28,38,.45);padding:20px;
}
.tor-dk-ov.show{display:flex}

/* ============================================================
   37. TIRAI SESI — .app-shell disembunyikan selama animasi masuk
   ------------------------------------------------------------
   BUG: Dashboard terlihat di balik lapisan "Selamat Datang" yang
   masih memudar masuk (±0,42 detik pertama sesudah menekan Masuk).

   #view-dashboard sudah ber-kelas "active" di index.html sejak
   halaman dimuat, jadi ia SELALU tergambar — selama ini hanya
   kebetulan tertutup layar login. Begitu layar login pergi lebih
   dulu daripada lapisan penggantinya menjadi pekat, isinya
   menyembul.

   Kelas ini dipasang & dilepas oleh sesiTirai() di app.js; lihat
   catatan panjang di sana untuk urutan waktunya.

   `visibility`, BUKAN `display`: kotak tata letaknya harus tetap
   ada supaya kartu & grafik Dashboard dapat mengukur lebarnya
   sendiri saat digambar di balik lapisan. Dengan display:none
   lebarnya terbaca 0 dan grafiknya lahir gepeng.

   Lapisan sesi (#login-anim, #login-screen, #logout-anim) berada
   DI LUAR .app-shell di index.html, jadi tidak ikut tersembunyi.
   ============================================================ */
body.sesi-tirai .app-shell{visibility:hidden}
/* ---- DOKUMEN DI BALIK TIRAI TIDAK BOLEH IKUT DIGULIR (9 Agu 2026) ----
   Laporan iPad 11": "di halaman login pun bagian bawah dashboard sudah
   kelihatan". Sebabnya perpaduan dua hal yang masing-masing benar:

     a) .app-shell disembunyikan dengan `visibility:hidden`, BUKAN
        `display:none` - disengaja, supaya kartu & grafik Dashboard tetap
        punya kotak tata letak dan bisa mengukur lebarnya sendiri (lihat
        catatan di atas). Konsekuensinya: tinggi dokumen tetap setinggi
        seluruh Dashboard, bukan setinggi layar;
     b) .login-screen `position:fixed; inset:0` - hanya menutup SATU tinggi
        viewport.

   Selama dokumennya masih bisa digulir, apa pun yang berada di bawah satu
   layar itu bisa muncul di celah antara tepi bawah lapisan tetap dan tepi
   bawah layar - dan di iOS celah itu memang terbuka saat bilah peramban
   berubah tinggi. Di desktop gejalanya tidak pernah tampak karena tidak ada
   perubahan tinggi bilah seperti itu.

   Perbaikannya bukan mengubah (a) maupun (b), melainkan mematikan gulir
   dokumen selama tirai terpasang: tidak ada yang bisa digulir, jadi tidak ada
   yang bisa tersingkap. Layar login punya `overflow:auto` sendiri, jadi kartu
   loginnya tetap bisa digulir bila layarnya pendek. */
html:has(body.sesi-tirai), body.sesi-tirai{ overflow:hidden; height:100% }
/* Cadangan untuk peramban tanpa :has() - kelas kembar dipasang JS di <html>. */
html.sesi-tirai{ overflow:hidden; height:100% }

/* ---- LUBANG YANG TERTINGGAL DARI PERBAIKAN 9 AGU (15 Agu 2026) ----
   Aturan di atas hanya berlaku selama `sesi-tirai` terpasang, dan kelas itu
   baru dipasang SESUDAH tombol Masuk ditekan. Sepanjang orangnya masih duduk
   di layar login - sebelum menekan apa pun - <body> tidak punya kelas apa pun,
   .app-shell tetap `visible`, dan dokumennya tetap bisa digulir.

   Terukur pada berkas aplikasi yang sebenarnya, iPad 834x1080: tinggi dokumen
   1330 px terhadap layar 1080 px, jadi ada 250 px yang bisa tersingkap - dan
   itu pada salinan lokal yang datanya KOSONG. Di situs sungguhan yang Daftar
   Pekerjaannya berisi puluhan baris, kelebihannya ribuan piksel.

   Kelas `layar-masuk` dipasang syncLayarMasukKelas() di app.js selama layar
   login tampil. Isinya sengaja SAMA PERSIS dengan sesi-tirai: kalau kelak
   salah satunya diubah, keduanya harus ikut - itulah alasan keduanya ditulis
   berdampingan di sini, bukan berjauhan. */
body.layar-masuk .app-shell{ visibility:hidden }
html:has(body.layar-masuk), body.layar-masuk{ overflow:hidden; height:100% }
html.layar-masuk{ overflow:hidden; height:100% }

/* ---- TEPI AMAN LAYAR LOGIN (15 Agu 2026) ----
   index.html memakai `viewport-fit=cover` bersama
   `apple-mobile-web-app-status-bar-style: black-translucent`, jadi di iPhone/
   iPad isi halaman memang MEMANJANG SAMPAI KE BAWAH jam & baterai - itu
   disengaja, dan bagian aplikasi lain sudah menambahkan env(safe-area-inset-*)
   sendiri (.appbar, .wrap, .side-foot, dan lainnya).

   .login-screen terlewat: paddingnya masih 24px rata. Selama kartunya cukup
   pendek ia terpusat dan tidak terasa, tetapi pada layar pendek - iPhone
   melintang, atau iPad terbagi dua - kartunya menyentuh tepi dan tepi atasnya
   masuk ke bawah bilah status. Angka 24px lama dipertahankan sebagai dasar;
   yang ditambahkan hanya tepi amannya, jadi di perangkat tanpa takik nilainya
   0 dan tidak ada yang berubah sama sekali. */
.login-screen{
  padding-top:calc(24px + env(safe-area-inset-top));
  padding-bottom:calc(24px + env(safe-area-inset-bottom));
  padding-left:calc(24px + env(safe-area-inset-left));
  padding-right:calc(24px + env(safe-area-inset-right));
}

/* ============================================================
   38. UKURAN TEKS TIDAK BOLEH DIKARANG PERAMBAN
   ------------------------------------------------------------
   Safari iOS & Chrome Android punya "penggelembungan teks
   otomatis": pada sebagian tata letak — paling sering setelah
   layar diputar ke lanskap — keduanya MEMBESARKAN sendiri huruf
   di dalam blok yang dianggap terlalu lebar, tanpa mengubah
   apa pun yang lain. Akibatnya tabel & kartu yang sama persis
   tampil dengan huruf lebih besar di tablet daripada di desktop,
   dan tata letaknya jadi berdesakan.

   Berkas ini tidak pernah menyetelnya, jadi nilainya `auto` —
   yaitu izin penuh bagi peramban untuk mengarang. Dikunci 100%
   di sini: satu-satunya penentu ukuran huruf adalah aturan CSS
   di berkas ini, sama di desktop maupun tablet.

   BUKAN pengganti `user-scalable=no` — pengguna tetap bebas
   mencubit-zoom; yang dilarang hanyalah penskalaan diam-diam
   yang tidak pernah diminta siapa pun.
   ============================================================ */
html{
  -webkit-text-size-adjust:100%;
     -moz-text-size-adjust:100%;
          text-size-adjust:100%;
}

/* ============================================================
   39. POP-UP "UNGGAH KLAUSUL KONTRAK" — BARIS ALAT
   ------------------------------------------------------------
   KETENTUAN 8 Agu 2026:
     - kotak Judul Klausul + tombol miring = SATU baris penuh,
     - tombol "Download Template (.docx)" TURUN ke baris bawah,
       menempel di kanan,
     - tinggi kotak judul sedikit diturunkan,
     - tombol miring dirapikan dengan ukuran presisi.

   Dipakai GRID, bukan flex-wrap. Alasannya: dengan flex-wrap,
   letak tiap tombol bergantung pada lebar sisa — keterangan
   "Berkas .docx tersimpan" yang panjangnya berubah-ubah bisa
   mendorong tombol Download naik atau turun sendiri. Grid dua
   kolom mengunci petanya: baris atas selalu milik judul, baris
   bawah selalu "keterangan di kiri, Download di kanan", berapa
   pun panjang keterangannya.

   Ditulis di akhir berkas supaya menang urutan atas aturan
   .spk-kldoc-* yang lebih awal, tanpa perlu !important.
   ============================================================ */
.spk-kldoc-tools{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:
    "judul judul"
    "meta  unduh";
  align-items:center;
  gap:10px 12px;
  margin-top:11px;
}
.spk-kldoc-tools .spk-kldoc-jwrap{grid-area:judul;min-width:0}
.spk-kldoc-tools .spk-kldoc-meta{grid-area:meta;min-width:0}
.spk-kldoc-tools .spk-kldoc-dl{grid-area:unduh;justify-self:end;margin-left:0}

/* Kotak judul: tinggi diturunkan 42 -> 38 px, padding ikut dirapatkan supaya
   teksnya tetap berada tepat di tengah tinggi barunya. */
.spk-kldoc-jwrap{gap:8px}
.spk-kldoc-jinput{
  min-height:38px;
  padding:8px 13px;
  line-height:1.4;
}

/* ---- Tombol MIRINGKAN (I) ----
   Persegi 38x38 — sama persis dengan tinggi kotak judul di sebelahnya, jadi
   kedua sisi baris berakhir di garis yang sama. Ukurannya dikunci lewat
   flex-basis + width + height sekaligus: flex-basis saja tidak cukup karena
   `align-items:stretch` pada pembungkusnya akan memanjangkannya mengikuti
   kotak judul yang tingginya boleh tumbuh saat judul memakai dua baris. */
.spk-kldoc-jbtn{
  flex:0 0 38px;width:38px;height:38px;align-self:flex-start;
  display:inline-flex;align-items:center;justify-content:center;
  padding:0;border:1px solid #cdd9de;border-radius:10px;
  background:linear-gradient(180deg,#ffffff,#f2f6f8);
  color:#33454b;cursor:pointer;
  box-shadow:0 1px 2px rgba(16,40,50,.07), inset 0 1px 0 #fff;
  transition:background .16s ease,border-color .16s ease,color .16s ease,
             box-shadow .18s ease,transform .12s ease;
}
/* `display:block` WAJIB: transform tidak berlaku pada elemen inline, dan tanpa
   pergeseran setengah piksel ini huruf "I" serif duduk sedikit terlalu rendah
   terhadap tengah tombol (garis dasar serif lebih berat di bawah). */
.spk-kldoc-jbtn i{
  display:block;font-style:italic;font-family:Georgia,"Times New Roman",serif;
  font-size:17px;font-weight:600;line-height:1;letter-spacing:.5px;
  transform:translateY(-.5px);
}
.spk-kldoc-jbtn:hover{
  background:linear-gradient(180deg,#f0f9fa,#e2f1f3);
  border-color:#0e7c86;color:#0e7c86;
  box-shadow:0 2px 7px rgba(14,124,134,.17), inset 0 1px 0 #fff;
}
.spk-kldoc-jbtn:active{
  transform:translateY(1px);
  box-shadow:0 1px 2px rgba(14,124,134,.16);
}
.spk-kldoc-jbtn:focus-visible{
  outline:none;border-color:var(--teal);
  box-shadow:0 0 0 3px rgba(14,124,134,.16);
}

/* Layar sempit: keterangan & tombol Download menumpuk, tombol tetap di kanan. */
@media (max-width:520px){
  .spk-kldoc-tools{grid-template-columns:minmax(0,1fr);
    grid-template-areas:"judul" "meta" "unduh"}
  .spk-kldoc-tools .spk-kldoc-dl{justify-self:stretch}
}

/* ============================================================
   40. POP-UP "UNGGAH KLAUSUL KONTRAK" — TOLAK TUTUP & TOMBOL X
   ------------------------------------------------------------
   KETENTUAN 8 Agu 2026: pop-up ini disamakan dengan pop-up lain —
   klik di latar TIDAK menutupnya, melainkan menggetarkan kotaknya
   sambil menyorot tombol tutup; dan tombol silangnya memakai
   bentuk yang sama dengan tombol Tutup pada pratinjau file/TOR
   (keping merah bersudut lengkung, ikon silang putih).

   Kenapa ini penting di sini, bukan sekadar konsistensi rasa:
   pop-up ini menyimpan pekerjaan yang belum tersimpan — judul
   yang sudah diketik dan berkas .docx yang sudah ditarik masuk.
   Dulu satu klik meleset di luar kotak membuang semuanya.

   Getarannya memakai keyframes tor-dk-getar / tor-dk-sorot yang
   sudah dipakai pop-up lain, jadi tidak ada gerak baru yang
   perlu dihafal mata.
   ============================================================ */
#spk-kldoc-ov .spk-ov-modal.menolak{
  animation:tor-dk-getar .4s cubic-bezier(.36,.07,.19,.97) both;
}
#spk-kldoc-ov .spk-ov-modal.menolak .spk-we-wbtn.close{
  animation:tor-dk-sorot .4s ease-in-out 2;
}
@media (prefers-reduced-motion:reduce){
  #spk-kldoc-ov .spk-ov-modal.menolak{animation:none}
  #spk-kldoc-ov .spk-ov-modal.menolak .spk-we-wbtn.close{
    animation:tor-dk-sorot .5s ease-in-out 2}
}

/* ---- Tombol Tutup: sama dengan kepala modal pratinjau ----
   Ukuran 32x32 dengan ikon 15px — angka yang sama persis dipakai
   #pn-preview-overlay, sehingga kedua pop-up terasa sekeluarga.
   Pembungkusnya (.spk-we-wbtns) diberi jarak kanan supaya keping
   merahnya tidak menempel di tepi kepala modal. */
#spk-kldoc-ov .spk-we-wbtns{align-items:center;padding-right:12px}
#spk-kldoc-ov .spk-we-wbtn.close{
  width:32px;height:32px;flex:0 0 32px;padding:0;
  border:none;border-radius:9px;line-height:0;
  background:linear-gradient(135deg,#D33A3A,#e25151);color:#fff;
  box-shadow:0 2px 6px rgba(6,30,36,.30);
  transition:filter .15s ease,box-shadow .2s ease;
}
#spk-kldoc-ov .spk-we-wbtn.close svg{
  width:15px;height:15px;display:block;
  stroke:currentColor;fill:none;stroke-width:2;
}
#spk-kldoc-ov .spk-we-wbtn.close:hover{
  background:linear-gradient(135deg,#D33A3A,#e25151);
  filter:brightness(1.08);
  box-shadow:0 4px 10px rgba(6,30,36,.36);
}
#spk-kldoc-ov .spk-we-wbtn.close:active{filter:brightness(.96)}
#spk-kldoc-ov .spk-we-wbtn.close:focus-visible{
  outline:none;
  box-shadow:0 0 0 3px rgba(255,255,255,.55),0 2px 6px rgba(6,30,36,.30);
}

/* ============================================================
   41. "UNGGAH KLAUSUL KONTRAK" — BINGKAI & KEPALA DISERAGAMKAN
   ------------------------------------------------------------
   KETENTUAN 8 Agu 2026: isinya tetap, tetapi bingkai & latar
   judulnya mengikuti pop-up pemilih dokumen (.tor-dk-*) —
   kepala bergradasi teal dengan judul putih tebal, sudut modal
   lebih membulat, bayangan lebih dalam.

   Angka-angkanya DISALIN PERSIS dari torEnsureStyle()
   (susun-dokumen.js), bukan dikira-kira:
     kepala    linear-gradient(90deg,#0E7C86,#12A0A8), padding 16/18
     modal     border-radius 16px, bayangan 0 24px 60px rgba(10,30,40,.28)
   Dengan begitu dua pop-up ini benar-benar sekeluarga, dan bila
   kelak warnanya diubah, satu-satunya tempat yang perlu dicari
   adalah kedua blok bersaudara ini.

   Kepala lamanya biru tua pekat (#12303f) — sisa dari masa
   pop-up ini bergaya "jendela editor" dengan tombol sepenuh
   tinggi kepala. Gaya itu sudah tidak dipakai di mana pun lagi.
   ============================================================ */
#spk-kldoc-ov .spk-ov-modal{
  border-radius:16px;
  box-shadow:0 24px 60px rgba(10,30,40,.28);
}
/* Tinggi kepala DITENTUKAN tombol X, bukan dikira-kira: 32px (tombol) + 10px
   atas + 10px bawah = 52px pas. Judulnya (14px x 1.35 = 19px) lebih pendek dari
   tombol, jadi ia yang menyesuaikan diri ke tengah — bukan sebaliknya.

   Padding kiri-kanan 16px, sama persis dengan .spk-kldoc-top di bawahnya:
   dengan begitu huruf pertama judul lurus dengan tepi kotak isian, dan tepi
   kanan tombol X lurus dengan tepi kanan tombol miring. Sebelumnya 18px —
   selisih 2px yang tidak kelihatan sendiri-sendiri, tetapi membuat kedua tepi
   modal ini tidak pernah benar-benar segaris. */
#spk-kldoc-ov .spk-ov-head.spk-we-head{
  background:linear-gradient(90deg,#0E7C86,#12A0A8);
  border-bottom:none;
  padding:10px 16px;
  align-items:center;
  gap:10px;
}
/* Judul MELIPAT, tombol tidak mengecil — pasangan min-width:0 +
   overflow-wrap:anywhere sama seperti .tor-dk-hd .jd: tanpa min-width:0
   satu kata panjang tanpa spasi akan mendorong tombol tutup keluar tepi. */
#spk-kldoc-ov .spk-we-head .spk-ov-title{
  flex:1 1 auto;min-width:0;
  color:#fff;font-weight:800;font-size:14px;line-height:1.35;
  letter-spacing:.01em;
  white-space:normal;overflow-wrap:anywhere;word-break:break-word;
}
#spk-kldoc-ov .spk-we-wbtns{
  flex:none;align-items:center;padding-right:0;margin-left:auto;
}
/* Cincin fokus putih — sama dengan .tor-dk-hd .x, dan lebih terbaca di atas
   kepala teal daripada bayangan putih yang dipakai sebelumnya. */
#spk-kldoc-ov .spk-we-wbtn.close:focus-visible{
  outline:2px solid #fff;outline-offset:2px;
  box-shadow:0 2px 6px rgba(6,30,36,.30);
}


/* ============================================================================
   LEBAR "BIDANG" & "CARI" DISERAGAMKAN SELURUH MENU            — 8 Agu 2026
   ----------------------------------------------------------------------------
   ACUAN = bilah filter Dokumen Perjanjian/Kontrak (#view-fk-view):
       Bidang Pelaksana  270 px
       Cari              300 px

   Sebelum ini ketiganya berbeda-beda menurut menu, sebagian karena tambalan
   yang ditulis di waktu berlainan:

     Monitoring (KR/PL/Tender)  Bidang `width:max-content` (LEBARNYA IKUT ISI —
                                jadi berubah-ubah), Cari 300px yang MEMUAI
     File Kontrak / Dok. Pengadaan   Bidang 270px, Cari 300–390px
     Materi & Peraturan         Kategori 230px
     Penetapan Nomor, Kelengkapan, Jadwal, TOR, SPK, RHO, HPS, Analisa, DP
                                Cari 316px (di dalam .page-head, bukan toolbar)

   Ketiganya dipatok mati (min = max = width) supaya benar-benar SAMA, bukan
   sekadar "kurang lebih sama": selama lebarnya masih boleh memuai/menyusut,
   dua menu dengan jumlah filter berbeda akan selalu tampil berbeda.

   ---- KENAPA AMBANGNYA 1325px, BUKAN 1301px SEPERTI BLOK SEBELUMNYA ----
   Bilah TERPADAT adalah Monitoring: Bidang 270 + Status 158 + Tahun 158 +
   Cari 300 + Reset 118 + Input Data ±118 = 1.122px, ditambah 5 jarak 10px dan
   padding bilah 2x16px = ±1.204px. Ruang isi halaman = min(1320, lebar layar
   − rail 72) − padding 2x24. Agar 1.204px itu muat, layar harus ≥ 1.325px.
   Di bawah itu aturan lama yang sudah ada (rentang 1201–1300 dan 768–1200)
   tetap berlaku — angka-angkanya memang disusun supaya bilah tidak pecah dua
   baris, dan menimpanya di sini akan mengulang persis bug yang baru diperbaiki
   pagi ini. Jadi keseragaman ini berlaku di layar desktop, tempat perbandingan
   antar-menu memang dilakukan.

   `!important` dipakai karena hampir semua aturan yang ditimpa juga memakainya
   (mis. `.toolbar.fk-toolbar #fk-view-bidang{...!important}`); pemilih di sini
   ditulis sama panjang atau lebih khusus supaya menang pada lapisan itu.
   ============================================================================ */
@media (min-width:1325px){

  /* ---- 1. Bidang Pelaksana / Kategori = 270px ---- */
  .toolbar .filter-field > select[id$="bidang"],
  .toolbar.fk-toolbar .filter-field > select[id$="bidang"],
  .toolbar.fk-toolbar #fk-view-bidang,
  .toolbar.fk-toolbar #fk-input-bidang,
  .toolbar.fk-toolbar #dpeng-view-bidang,
  .toolbar.fk-toolbar #materi-view-kategori{
    min-width:270px !important;
    max-width:270px !important;
    width:270px !important;
    /* Pilihan terpanjang ("Keselamatan, Kesehatan Kerja, Lingkungan dan
       Keamanan") masih lebih lebar daripada 270px — dipotong elipsis, bukan
       dibiarkan terpenggal di tengah huruf. Isi lengkapnya tetap terbaca saat
       daftarnya dibuka. */
    text-overflow:ellipsis; overflow:hidden; white-space:nowrap}

  /* ---- 2. Kotak Cari = 300px ----
     Tiga keluarga kotak Cari yang berbeda wadah, disebut semuanya:
       a. .toolbar .toolbar-search            -> Monitoring KR/PL/Tender
       b. .toolbar.fk-toolbar .fk-search      -> File Kontrak, Dok. Pengadaan,
                                                 Materi & Peraturan
       c. .page-head .pn-head-search          -> Penetapan Nomor, Kelengkapan,
                                                 Jadwal, TOR, SPK, RHO, HPS,
                                                 Analisa, Daftar Pekerjaan   */
  .toolbar .filter-field.toolbar-search input,
  .toolbar.fk-toolbar .filter-field.fk-search input,
  .toolbar.fk-toolbar .fk-search.search-elegant input,
  .page-head .pn-head-search input,
  .toolbar #filter-search,
  .toolbar #filter-pl-search,
  .toolbar #filter-tender-search,
  .toolbar #fkl-view-search,
  .toolbar #pn-lihat-search{
    min-width:300px !important;
    max-width:300px !important;
    width:300px !important}

  /* Kotaknya berhenti memuai. Tanpa ini, `flex:1 1 300px` (dipasang 7 Agu agar
     Cari menyerap sisa lebar bilah) tetap meregangkan pembungkusnya walau
     <input> di dalamnya sudah dipatok — hasilnya kotak 300px mengambang di
     tengah ruang kosong. Sisa lebar sekarang diserap kelompok tombol, yang
     memang sudah didorong ke kanan oleh `margin-left:auto`. */
  .toolbar .toolbar-search{flex:0 0 auto}
  .toolbar .toolbar-search .search-elegant-box{width:300px}
}

/* ============================================================================
   DIALOG SIMPAN PROFIL — SATU TAMPILAN UNTUK SEMUA MENU (8 Agu 2026)
   ----------------------------------------------------------------------------
   Keempat dialog Simpan Profil (Jadwal, Persyaratan, Klausul SPK/PK/TOR-KAK,
   Penyedia) memang sudah memakai satu susunan yang sama: .pnw-profil-head +
   .pnw-profil-sub + profilSaveBoxHtml() + .pnw-profil-actions. Yang belum
   seragam hanya SATU hal — lebar judulnya.

   Sebabnya: .pnw-profil-head menyisakan ruang di kanan (padding-right 150px,
   lalu ditimpa 70px, lalu 60px) untuk tombol Unggah Profil. Tombol itu HANYA
   ada di dialog MUAT Profil; di dialog SIMPAN ruang itu kosong dan justru
   memaksa judul panjang seperti "Simpan Profil Klausul TOR/KAK" atau
   "Simpan Profil Persyaratan" turun ke baris kedua, sedangkan
   "Simpan Profil Penyedia" yang lebih pendek tetap satu baris.

   Ruangnya kini hanya disisakan pada kepala dialog yang benar-benar memuat
   tombolnya, sehingga seluruh dialog Simpan Profil tampil persis sama.
   Peramban tanpa :has() mengabaikan aturan ini dan kembali ke perilaku lama —
   aman, tidak ada yang rusak.
   ============================================================================ */
.pnw-profil-head:not(:has(.pnw-profil-upload)){ padding-right:0 !important; }

/* ============================================================================
   KOTAK PILIHAN LEBAR PENUH (selx) — 8 Agu 2026
   ----------------------------------------------------------------------------
   Pasangan dari bagian 6 di ui-sidebar.js. Daftar pilihan sebuah <select>
   digambar oleh sistem operasi dan lebarnya tidak bisa disentuh CSS — di iPad
   ia muncul sebagai popover sempit sehingga nama pekerjaan yang panjang
   terpotong jadi tiga baris. Di sini disediakan penggantinya: <select> aslinya
   disembunyikan (TETAP ada di dokumen supaya kode lama tidak perlu diubah),
   tombol .selx-btn menirunya, dan .selx-panel menggambar daftarnya sendiri
   selebar tombol.

   .selx-btn sengaja tidak menyalin ulang tampilan .trk-select: kelas itu ikut
   dipasang oleh ui-sidebar.js, jadi warna, tinggi, sudut, dan bayangannya
   otomatis sama — kalau .trk-select diubah kelak, tombolnya ikut berubah
   sendiri. Di sini hanya ditulis yang khas tombol.
   ========================================================================== */
select.selx-asli{
  position:absolute !important;
  width:1px; height:1px; padding:0; margin:-1px;
  border:0; opacity:0; pointer-events:none;
  overflow:hidden; white-space:nowrap;
  clip:rect(0 0 0 0); clip-path:inset(50%);
}
.selx-btn{
  display:flex; align-items:center; gap:10px;
  text-align:left; font:inherit; font-size:14px; line-height:1.25;
  appearance:none; -webkit-appearance:none;
}
.selx-btn .selx-teks{
  flex:1 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.selx-btn .selx-caret{
  flex:0 0 auto; width:16px; height:16px; opacity:.5;
  transition:transform .18s ease;
}
.selx-btn.is-open .selx-caret{ transform:rotate(180deg); opacity:.9 }
.selx-btn.is-kosong .selx-teks{ color:#8a8f8e }
.selx-btn.is-open{
  border-color:#18b394;
  box-shadow:0 0 0 3px rgba(24,179,148,.10),0 3px 8px rgba(0,0,0,.06);
}
.selx-btn:disabled{ opacity:.6; cursor:not-allowed; background:#f4f6f6 }

/* Daftar pilihannya. position:fixed + penempatan dari JS supaya tidak pernah
   terpotong oleh induk yang overflow-nya tersembunyi (mis. .table-wrap). */
.selx-panel{
  position:fixed; z-index:12050;
  box-sizing:border-box;
  background:#fff; border:1px solid #dcdedd; border-radius:14px;
  box-shadow:0 18px 44px rgba(0,0,0,.16),0 2px 8px rgba(0,0,0,.08);
  padding:6px; overflow:auto; -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  opacity:0; transform:translateY(-6px);
  transition:opacity .14s ease, transform .14s ease;
}
.selx-panel.show{ opacity:1; transform:none }
.selx-opt{
  display:block; box-sizing:border-box; width:100%;
  position:relative;
  margin:0; padding:10px 12px 10px 34px;
  background:transparent; border:0; border-radius:10px;
  font:inherit; font-size:14px; line-height:1.45; color:#222;
  text-align:left; cursor:pointer;
  /* Inilah inti perbaikannya: nama pekerjaan yang panjang boleh turun baris
     dengan lega, bukan diperas ke dalam kotak sempit bawaan sistem. */
  white-space:normal; overflow-wrap:anywhere;
}
.selx-opt + .selx-opt{ margin-top:2px }
.selx-opt:hover, .selx-opt.is-fokus{ background:#eefaf7 }
.selx-opt.is-pilih{ background:#e3f6f1; color:#0d7f6a; font-weight:600 }
.selx-opt.is-pilih::before{
  content:'\2713';
  position:absolute; left:12px; top:10px;
  font-size:13px; font-weight:700; line-height:1.45;
}
.selx-opt:disabled{ opacity:.45; cursor:default; background:transparent }
.selx-kosong{ padding:14px 12px; text-align:center; color:#8a8f8e; font-size:13.5px }

/* Layar sentuh: sasaran jari dibuat lebih tinggi. */
@media (hover:none), (any-pointer:coarse){
  .selx-opt{ padding-top:12px; padding-bottom:12px }
  .selx-opt.is-pilih::before{ top:12px }
}

/* ============================================================
   12. SIDEBAR TIDAK IKUT MELENTING DI iPadOS / iOS (9 Agu 2026)
   ------------------------------------------------------------
   LAPORAN (iPad 11" lanskap): "saat scroll sampai bawah mentok, sidebar ikut
   bergeser dan memberi spasi; di desktop tetap tampil penuh."

   SEBABNYA BUKAN TINGGI SIDEBAR. `.sidebar-shell` sudah position:fixed dengan
   height:100dvh, dan itu memang sudah benar. Yang terjadi: di WebKit iOS,
   elemen position:fixed dipatok ke LAYOUT viewport, sedangkan lentingan
   (rubber-band) menggeser VISUAL viewport melewatinya. Selama lentingan itu
   elemen fixed ikut terseret bersama dokumen lalu menyisakan celah di sisi
   yang dilenting. Di macOS & Windows dokumennya juga melenting, tetapi di sana
   elemen fixed TETAP dipaku - karena itu gejalanya tidak pernah terlihat di
   desktop, persis seperti yang dilaporkan.

   Karena penyebabnya pergeseran viewport (bukan tinggi), mengganti satuan
   tinggi tidak akan menolong: 100vh, 100dvh, maupun 100svh sama-sama tetap
   bergeser. Yang harus dihentikan adalah lentingan DOKUMEN-nya sendiri.

   overscroll-behavior-y:none dipasang pada elemen penggulir dokumen (html, dan
   body sebagai cadangan bila kelak body yang menggulir). Didukung Safari
   iOS/iPadOS 16+; peramban lebih tua sekadar mengabaikan baris ini dan kembali
   ke perilaku lama - tidak ada yang rusak.

   DUA KONSEKUENSI YANG DISENGAJA:
     (a) tarik-untuk-muat-ulang mati DI DALAM aplikasi. Aplikasi ini punya
         tombol muat ulang datanya sendiri, dan gerakan itu justru sering tak
         sengaja terpicu saat menggulir tabel panjang;
     (b) gulir tidak lagi merambat dari penggulir dalam (tabel, modal,
         pratinjau) ke dokumen begitu mentok - memang itu yang diinginkan.

   DIBATASI KE PERANGKAT SENTUH (hover:none). Di desktop aturan ini percuma
   (lentingannya tidak pernah menggeser elemen fixed) sekaligus mematikan
   lentingan yang di sana terasa wajar, jadi tidak diusik.

   Mode POTRET tidak terpengaruh: di bawah 1024px sidebar berubah jadi tombol
   tiga garis + laci geser (lihat blok media (max-width:1024px)), dan laci itu
   memakai body.nav-open{overflow:hidden} sehingga dokumen memang tidak
   menggulir saat laci terbuka. */
@media (hover:none), (any-pointer:coarse){
  html{ overscroll-behavior-y:none }
  body{ overscroll-behavior-y:none }
}

/* ============================================================
   13. TABEL MUAT SATU LAYAR DI TABLET (9 Agu 2026)
   ------------------------------------------------------------
   LAPORAN: "di desktop tabel selain Monitoring - Daftar Pekerjaan tampil satu
   layar penuh; di iPad 11" dan iPad lain harus digeser kiri-kanan."

   HITUNGANNYA. Lebar isi = lebar layar - rel sidebar (76px) - jarak tepi
   halaman. iPad 11" lanskap 1194px menyisakan sekitar 1050px, sedangkan
   desktop 1920px menyisakan sekitar 1790px. Yang memakan ruang bukan satu
   aturan, melainkan tiga yang menumpuk:

     a) `table{min-width:980px}` - lantai global untuk SEMUA tabel;
     b) `.col-kontrak{white-space:nowrap}` - nomor kontrak seperti
        "0031.SPK/DAN.01.01/F17060000/2026" (33 aksara) dipaksa satu baris,
        jadi kolomnya menuntut ~230px, jauh di atas min-width 150px-nya;
     c) `.col-nama-freeze{min-width:240px}` di atas kolom penyedia, tanggal,
        nilai & aksi yang masing-masing punya lantainya sendiri.

   Jumlah lantainya melewati 1050px tapi masih di bawah 1790px - persis kenapa
   desktop muat dan tablet tidak.

   MONITORING - DAFTAR PEKERJAAN SENGAJA DIKECUALIKAN. Tabel itu memang lebar
   (kolomnya paling banyak) dan sudah memakai kolom beku Nomor + Nama yang
   menuntut geseran mendatar sebagai cara pakainya. Karena itu pengecualiannya
   ditulis dengan :not() pada ketiga tampilan daftarnya, bukan dengan mematikan
   aturan global - supaya tabel monitoring tetap persis seperti sekarang.

   Batasnya 1400px, jadi mencakup iPad 11" (1194) & iPad Pro 12,9" (1366)
   dalam lanskap, sekaligus jendela desktop yang dikecilkan. */
@media (max-width:1400px){
  /* a) lantai global dilepas - tabel menyesuaikan lebar layar */
  .view:not(#view-list):not(#view-list-pl):not(#view-list-tender) .table-wrap table{ min-width:0 }
  /* b) nomor kontrak boleh turun baris; pemenggalan hanya bila memang tak muat */
  .view:not(#view-list):not(#view-list-pl):not(#view-list-tender) .table-wrap th.col-kontrak,
  .view:not(#view-list):not(#view-list-pl):not(#view-list-tender) .table-wrap td.col-kontrak{
    white-space:normal; overflow-wrap:break-word; min-width:120px }
  /* c) kolom nama boleh menyempit; batas atasnya dilepas supaya sisa ruang
        dipakai kolom ini, bukan disebar rata ke kolom yang sudah cukup */
  .view:not(#view-list):not(#view-list-pl):not(#view-list-tender) .table-wrap th.col-nama-freeze,
  .view:not(#view-list):not(#view-list-pl):not(#view-list-tender) .table-wrap td.col-nama-freeze{
    min-width:170px; max-width:none }
}

/* ============================================================
   14. TOMBOL DIALOG PROFIL (9 Agu 2026)
   ------------------------------------------------------------
   (a) Tombol tutup (x) di pojok kanan atas dialog Muat Profil. Dialog itu
       isinya hanya daftar profil - tidak punya baris tindakan - sehingga tanpa
       tombol ini satu-satunya jalan keluar adalah Escape, karena klik latar
       sengaja ditolak (pasangTolakTutup). Bentuknya disamakan dengan tombol
       tutup pada daftar dokumen TOR/KAK.
   (b) Tombol "Unggah Profil" berlabel, sebaris dengan Batal & Simpan. Warna
       biru dipilih supaya ia terbaca sebagai tindakan yang BERBEDA dari Simpan
       (hijau) dan Batal (merah) - bukan sekadar tombol ketiga yang senada.
       Efek timbulnya (.btn-raise) memakai bayangan berlapis + geser 1px saat
       ditekan, jadi terasa benar-benar ditekan dan bukan cuma berubah warna. */
.pnw-profil-x{
  position:absolute; top:18px; right:18px; width:36px; height:36px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid #e2e8ea; border-radius:12px; background:#fff; color:#6b7b82;
  box-shadow:0 2px 6px rgba(16,40,50,.10);
  transition:background .18s ease,color .18s ease,box-shadow .18s ease;
}
/* Warna & ukuran ditulis tegas: aturan `.pnw-profil-head svg` di atas mengunci
   svg di dalam kepala dialog jadi 20px berwarna teal - termasuk tanda silang
   ini, yang seharusnya abu-abu dan lebih kecil. */
.pnw-profil-x svg{ width:18px; height:18px; color:inherit }
.pnw-profil-head .pnw-profil-x svg{ width:18px; height:18px; color:inherit }
.pnw-profil-x:hover{ background:#fdecec; color:var(--red); border-color:#f4c9c9;
  box-shadow:0 4px 12px rgba(211,58,58,.20) }
.pnw-profil-x:active{ transform:translateY(1px); box-shadow:0 1px 4px rgba(211,58,58,.18) }

.btn-blue{
  background:linear-gradient(135deg,#2f7fd1,#4aa3e8); color:#fff;
  box-shadow:0 4px 14px rgba(47,127,209,.30),inset 0 1px 0 rgba(255,255,255,.25);
}
.btn-blue:hover{ box-shadow:0 8px 22px rgba(47,127,209,.44),inset 0 1px 0 rgba(255,255,255,.3);
  filter:brightness(1.04) }
/* Efek timbul: naik sedikit saat disentuh, benar-benar turun saat ditekan. */
.btn-raise{ transition:transform .16s ease,box-shadow .16s ease,filter .16s ease }
.btn-raise:hover{ transform:translateY(-2px) }
.btn-raise:active{ transform:translateY(1px); box-shadow:0 2px 6px rgba(16,40,50,.22) }
.pnw-profil-actions .btn-blue svg{ width:17px; height:17px }

/* ============================================================
   15. LAPISAN PENUH-LAYAR DI iPad: TANPA backdrop-filter (9 Agu 2026)
   ------------------------------------------------------------
   Laporan berulang di iPad 11" lanskap: pratinjau tampil hanya satu halaman
   dan menempel ke kiri, sidebar tersisa tidak penuh, dan di bagian bawah layar
   terlihat potongan Dashboard yang mestinya tertutup.

   Ketiganya punya satu ciri sama: ada LAPISAN TETAP penuh-layar
   (`.overlay`, `.route-loader`, `.pn-upload-overlay`) yang seharusnya menutup
   segalanya, tetapi daerah catnya lebih pendek daripada layar yang terlihat.
   Lapisan-lapisan itu memakai `backdrop-filter: blur(...)`.

   Di WebKit iOS, backdrop-filter memaksa lapisan itu dirasterkan terpisah
   dengan ubin (tile) seukuran LAYOUT viewport. Begitu tinggi bilah peramban
   berubah - atau halaman di belakangnya digulir - ubin itu tidak selalu
   dirasterkan ulang, sehingga di luar batas ubin yang tampil adalah cat LAMA:
   isi halaman di belakangnya. Di macOS/Windows rasterisasinya mengikuti
   viewport yang terlihat, jadi gejalanya tidak pernah muncul - persis seperti
   yang kamu laporkan tentang desktop.

   Buram latar hanyalah hiasan; menutup layar adalah tugasnya. Karena itu di
   perangkat sentuh buramnya dimatikan dan latarnya dipekatkan sedikit sebagai
   gantinya, lalu tingginya dipatok ke viewport DINAMIS supaya ikut menyusut
   & memanjang bersama bilah peramban. Desktop tidak diusik sama sekali. */
@media (hover:none), (any-pointer:coarse){
  .overlay, .pn-upload-overlay, .route-loader.show, .login-screen{
    -webkit-backdrop-filter:none !important;
            backdrop-filter:none !important;
  }
  .overlay{
    background:radial-gradient(1200px 600px at 50% -10%,rgba(14,124,134,.42),rgba(16,36,44,.72) 60%);
  }
  .pn-upload-overlay{ background:rgba(7,63,69,.62) }
  /* Tinggi ikut viewport dinamis; `inset:0` saja tidak cukup karena ia
     mengacu ke layout viewport yang bisa lebih pendek dari layar terlihat. */
  .overlay, .pn-upload-overlay, .route-loader, .login-screen{
    height:100dvh; max-height:100dvh;
  }
}

/* ============================================================
   16. SENTUHAN KURSOR PADA SEMUA TOMBOL (9 Agu 2026)
   ------------------------------------------------------------
   Permintaan: "efek yang elegan saat kursor mengenai semua tombol - aksi,
   input data, tambah data, batal, simpan, selanjutnya, sebelumnya, dan
   lainnya."

   Sebagian sudah punya (.btn terangkat 2px + kilau menyapu), tetapi TOMBOL
   IKON di kolom Aksi, tombol halaman, tombol tutup modal, dan beberapa tombol
   lain memakai kelasnya sendiri sehingga tidak ikut - hasilnya terasa belang:
   tombol besar hidup, tombol kecil mati.

   Blok ini menyamakannya dengan satu perlakuan: naik sedikit, bayangan
   melebar, dan ikonnya membesar tipis. Tiga-tiganya properti yang dipercepat
   kartu grafis (transform & box-shadow), jadi tidak memicu perhitungan ulang
   tata letak - penting karena tombol aksi bisa puluhan dalam satu tabel.

   DIBATASI KE PERANGKAT BERKURSOR (hover:hover + pointer:fine). Di layar
   sentuh, keadaan :hover menempel sesudah diketuk dan tombolnya akan tampak
   terangkat terus - persis gejala sakelar berkedip yang sudah kita perbaiki.
   Juga dihormati prefers-reduced-motion bagi yang menyetel demikian. */
@media (hover:hover) and (pointer:fine){
  button.act, .act button, .icon-btn, .pg-btn, .detail-close,
  .tor-dk-hd .act button, .pnw-profil-x, .jp-aksi button{
    transition:transform .16s cubic-bezier(.16,1,.3,1),
               box-shadow .22s ease, background-color .18s ease, color .18s ease;
  }
  button.act:hover, .act button:hover, .icon-btn:hover, .pg-btn:hover,
  .detail-close:hover, .tor-dk-hd .act button:hover, .jp-aksi button:hover{
    transform:translateY(-2px);
    box-shadow:0 6px 16px rgba(16,40,50,.20);
  }
  button.act:active, .act button:active, .icon-btn:active, .pg-btn:active,
  .detail-close:active, .tor-dk-hd .act button:active, .jp-aksi button:active{
    transform:translateY(1px);
    box-shadow:0 1px 4px rgba(16,40,50,.18);
  }
  /* Ikon di dalam tombol ikut membesar tipis - cukup untuk terasa "hidup",
     tidak sampai menggeser apa pun di sekitarnya. */
  button.act svg, .act button svg, .icon-btn svg, .pg-btn svg, .detail-close svg{
    transition:transform .16s cubic-bezier(.16,1,.3,1);
  }
  /* Tombol AKSI tidak lagi sekadar membesar - tiap ikonnya punya gerakannya
     sendiri di blok 17 di bawah. Yang di sini hanya untuk tombol ikon lain. */
  .icon-btn:hover svg, .pg-btn:hover svg, .detail-close:hover svg{ transform:scale(1.10); }
  /* Tombol nonaktif tidak boleh ikut bereaksi - kalau ikut, ia terbaca
     seolah bisa ditekan. */
  .btn:disabled, .btn[disabled], .pg-btn:disabled,
  button.act:disabled, .act button:disabled, .icon-btn:disabled{
    transform:none !important; box-shadow:none !important; filter:none !important;
  }
}
@media (prefers-reduced-motion:reduce){
  .act button, .icon-btn, .pg-btn, .detail-close, .jp-aksi button{
    transition:none !important;
  }
  .act button:hover, .icon-btn:hover, .pg-btn:hover,
  .detail-close:hover, .jp-aksi button:hover{ transform:none !important; }
  .act button:hover svg, .icon-btn:hover svg,
  .pg-btn:hover svg, .detail-close:hover svg{ transform:none !important; }
}

/* ============================================================
   17. IKON TOMBOL AKSI BERGERAK SENDIRI-SENDIRI (9 Agu 2026)
   ------------------------------------------------------------
   Permintaan: "untuk hapus, tutup tempat sampah terbuka; untuk lihat, dari
   mata ke kaca pembesar bergerak; edit juga bergerak."

   Membesarkan seluruh ikon 10% terasa sama untuk semua tombol - tidak ada yang
   memberi tahu tombol itu akan MELAKUKAN apa. Di sini tiap ikon digerakkan pada
   bagian yang memang menjelaskan perbuatannya, dan HANYA bagian itu.

   Bagian ikon dipilih lewat nth-of-type, mengikuti urutan <path> pada
   DPENG_IC_DEL / VIEW / EDIT di app.js:
     Hapus : 1 badan, 2 batang tutup, 3 pegangan, 4 dua garis dalam
     Lihat : 1 kelopak mata, (circle) pupil, 2 gagang kaca pembesar
     Ubah  : 1 lembar, 2 badan pensil, 3 garis ujung pensil
   Kalau ikonnya kelak diganti, URUTAN INI IKUT BERUBAH - itu satu-satunya
   ketergantungan yang perlu diingat dari blok ini.

   transform-box:view-box dipakai supaya transform-origin bisa ditulis dalam
   satuan koordinat SVG (mis. tepi kiri batang tutup di x=4), bukan relatif
   terhadap kotak masing-masing garis yang letaknya berbeda-beda.

   Semuanya transform belaka - tidak ada properti yang memicu perhitungan ulang
   tata letak, penting karena satu tabel bisa memuat puluhan tombol ini. */
@media (hover:hover) and (pointer:fine){
  button.act svg *{
    transform-box:view-box; transform-origin:center;
    transition:transform .3s cubic-bezier(.2,.9,.25,1.15);
  }

  /* HAPUS — tutupnya terangkat membuka, badannya turun sedikit seolah
     menerima isi. Poros putarnya di ujung KIRI batang tutup, bukan di tengah,
     supaya gerakannya seperti engsel dan bukan seperti jungkat-jungkit. */
  button.act-del svg path:nth-of-type(2),
  button.act-del svg path:nth-of-type(3){ transform-origin:4px 7px; }
  button.act-del:hover svg path:nth-of-type(2),
  button.act-del:hover svg path:nth-of-type(3){ transform:rotate(-22deg); }
  button.act-del:hover svg path:nth-of-type(1){ transform:translateY(.7px); }
  button.act-del:hover svg path:nth-of-type(4){ transform:translateY(.4px); }

  /* LIHAT — kaca pembesarnya TURUN DARI ATAS ke arah mata (9 Agu 2026).
     Gagasan ikonnya memang mata + kaca pembesar, jadi gerakan yang menjelaskan
     perbuatannya adalah kacanya DIDEKATKAN ke mata, bukan pupilnya yang
     melirik-lirik. Gagang kaca (path ke-2) meluncur dari kiri-atas ke tempat
     diamnya, dan pupilnya membesar tipis seolah ikut terlihat lebih dekat. */
  button.act-view:hover svg path:nth-of-type(2){ animation:actKaca .55s cubic-bezier(.2,.9,.25,1.15) both; }
  button.act-view:hover svg circle{ transform:scale(1.14); }
  button.act-view:hover svg path:nth-of-type(1){ transform:scale(1.03); }

  /* UBAH — pensilnya DIANGKAT DULU, baru turun ke lembaran (9 Agu 2026).
     Urutan itu yang membuatnya terbaca sebagai "hendak menulis": alat tulis
     diangkat dari kertas, lalu didaratkan kembali. Kalau langsung bergeser,
     yang terbaca cuma ikon yang bergoyang. Lembarannya tetap diam. */
  button.act-edit:hover svg path:nth-of-type(2),
  button.act-edit:hover svg path:nth-of-type(3){ animation:actMenulis .72s cubic-bezier(.2,.9,.25,1.1) both; }

  /* UNGGAH & UNDUH — panahnya bergerak searah perbuatannya. */
  button.act-up:hover   svg path:nth-of-type(2),
  button.act-up:hover   svg path:nth-of-type(3){ animation:actNaik .6s ease both; }
  button.act-excel:hover svg path:nth-of-type(2),
  button.act-excel:hover svg path:nth-of-type(3){ animation:actTurun .6s ease both; }

  /* PINDAH URUTAN — bergeser sedikit ke arah pindahnya. */
  button.act-mv:hover svg *{ animation:actGeser .6s ease both; }
}
/* Kaca pembesar meluncur dari kiri-atas, lalu mendarat di tempatnya. */
@keyframes actKaca{
  0%  { transform:translate(-3.5px,-4.5px) scale(.82); opacity:.35 }
  60% { transform:translate(.6px,.6px) scale(1.06); opacity:1 }
  100%{ transform:translate(1.1px,1.1px) scale(1); opacity:1 }
}
/* Pensil: NAIK dulu (0-35%), baru turun mendarat di lembaran (35-100%). */
@keyframes actMenulis{
  0%  { transform:none }
  35% { transform:translate(.4px,-2.6px) rotate(-9deg) }
  70% { transform:translate(1.2px,-.2px) rotate(-3deg) }
  100%{ transform:none }
}
@keyframes actNaik{  0%,100%{transform:none} 45%{transform:translateY(-2px)} }
@keyframes actTurun{ 0%,100%{transform:none} 45%{transform:translateY(2px)} }
@keyframes actGeser{ 0%,100%{transform:none} 45%{transform:translateY(-1.6px)} }

/* Yang menyetel "kurangi gerak" tetap mendapat tampilan diam. */
@media (prefers-reduced-motion:reduce){
  button.act svg *{ transition:none !important; animation:none !important; transform:none !important }
}

/* ============================================================
   18. HALAMAN MASUK — SENTUHAN AKHIR (9 Agu 2026)
   ------------------------------------------------------------
   Permintaan: efek menarik pada tombol Masuk, efek terbaik pada ikon PLN,
   dan tulisan "Selamat Datang" bergerak dari kiri ke kanan seperti papan
   iklan.

   Semua gerakan di sini memakai transform & opacity saja - dua properti yang
   dikerjakan kartu grafis tanpa menghitung ulang tata letak. Halaman masuk
   adalah layar pertama yang dilihat pengguna; kalau ia tersendat, kesan
   pertamanya rusak sebelum aplikasinya sempat dipakai.

   Yang menyala terus dibuat SANGAT lambat & tipis (14-18 detik, kilau di
   bawah 30% pekat). Animasi yang cepat dan mencolok memang menarik pada
   detik pertama, tetapi layar masuk kerap dibiarkan terbuka lama - dan yang
   berkedip cepat di depan mata selama itu berubah jadi gangguan.

   prefers-reduced-motion dihormati penuh di akhir blok. */

/* ---- (a) "Selamat Datang": kilau menyapu kiri ke kanan ----
   Bukan tulisannya yang bergeser - yang bergerak CAHAYANYA. Menggeser
   tulisannya akan mendorong paragraf di bawahnya dan membuat seluruh sisi
   kiri bergoyang. Caranya: gradasi berjalan dipakai sebagai isi huruf lewat
   background-clip:text, jadi yang menyapu hanya warnanya. */
.brandside-mid h2{
  background-image:linear-gradient(100deg,
      #ffffff 0%, #ffffff 38%,
      var(--yellow, #ffd84d) 46%, #ffffff 54%,
      #ffffff 100%);
  background-size:280% 100%;
  background-position:120% 0;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:transparent;
  animation:sapuTeks 6.5s cubic-bezier(.5,0,.5,1) 1.1s infinite;
}
@keyframes sapuTeks{
  0%   { background-position:120% 0 }
  55%  { background-position:-40% 0 }
  100% { background-position:-40% 0 }   /* diam dulu sebelum menyapu lagi */
}

/* ---- (b) Ikon PLN: berdenyut halus + cincin cahaya ----
   Logo PLN adalah lambang resmi; ia tidak diputar, dimiringkan, atau
   dibalik. Yang bergerak hanya CINCIN CAHAYA di belakangnya dan denyut
   napas yang sangat tipis (2%) - jadi ia terasa hidup tanpa kehilangan
   wibawanya. */
.brandside-logo{ position:relative; isolation:isolate;
  animation:napasLogo 5.6s ease-in-out infinite }
.brandside-logo::before{
  content:""; position:absolute; inset:-7px; border-radius:20px; z-index:-1;
  background:radial-gradient(closest-side,rgba(255,216,77,.55),transparent 72%);
  opacity:.35; animation:cincinLogo 5.6s ease-in-out infinite;
}
.brandside-logo::after{      /* kilau tipis menyapu permukaan logo */
  content:""; position:absolute; inset:0; border-radius:inherit; z-index:1;
  pointer-events:none; overflow:hidden;
  background:linear-gradient(115deg,transparent 42%,rgba(255,255,255,.55) 50%,transparent 58%);
  background-size:260% 100%; background-position:130% 0;
  animation:kilauLogo 7.2s ease-in-out 2s infinite;
}
@keyframes napasLogo{ 0%,100%{transform:scale(1)} 50%{transform:scale(1.02)} }
@keyframes cincinLogo{ 0%,100%{opacity:.3;transform:scale(1)} 50%{opacity:.62;transform:scale(1.1)} }
@keyframes kilauLogo{ 0%{background-position:130% 0} 38%,100%{background-position:-60% 0} }

/* ---- (c) Tombol Masuk ----
   Tiga lapis yang saling melengkapi: kilau menyapu satu kali saat disentuh,
   terangkat + bayangan melebar, dan ikon panah maju sedikit ke arah yang ia
   tunjuk. Saat ditekan, tombol benar-benar turun. */
.login-btn{ transition:transform .18s cubic-bezier(.16,1,.3,1),
                        box-shadow .26s ease, filter .2s ease }
.login-btn svg{ transition:transform .22s cubic-bezier(.2,.9,.25,1.2) }
.login-btn::after{
  content:""; position:absolute; top:0; left:-150%; width:65%; height:100%;
  background:linear-gradient(120deg,transparent,rgba(255,255,255,.42),transparent);
  transform:skewX(-18deg); pointer-events:none; opacity:0;
}
@media (hover:hover) and (pointer:fine){
  .login-btn:hover{ transform:translateY(-2px);
    box-shadow:0 12px 30px rgba(14,124,134,.42), inset 0 1px 0 rgba(255,255,255,.32);
    filter:brightness(1.05) }
  .login-btn:hover::after{ animation:kilauMasuk .85s cubic-bezier(.16,1,.3,1) }
  .login-btn:hover svg{ transform:translateX(4px) }
}
.login-btn:active{ transform:translateY(1px) scale(.995);
  box-shadow:0 3px 10px rgba(14,124,134,.34) }
@keyframes kilauMasuk{ 0%{left:-150%;opacity:.85} 100%{left:150%;opacity:0} }

/* ---- (d) Daftar fitur di sisi kiri: muncul bertahap ----
   Ketiganya masuk berurutan supaya mata membacanya satu per satu, bukan
   sekaligus. Sekali jalan saat halaman dibuka - tidak berulang. */
.brandside-feat{ animation:masukFitur .62s cubic-bezier(.16,1,.3,1) both }
/* Enam butir, jeda dipersempit jadi 60 md supaya seluruh daftar sudah utuh
   dalam ~0,6 detik - kalau tetap 120 md, butir terakhir baru muncul setelah
   satu detik dan terasa lambat. */
.brandside-feat:nth-child(1){ animation-delay:.26s }
.brandside-feat:nth-child(2){ animation-delay:.32s }
.brandside-feat:nth-child(3){ animation-delay:.38s }
.brandside-feat:nth-child(4){ animation-delay:.44s }
.brandside-feat:nth-child(5){ animation-delay:.50s }
.brandside-feat:nth-child(6){ animation-delay:.56s }
@keyframes masukFitur{ from{opacity:0;transform:translateX(-14px)} to{opacity:1;transform:none} }
@media (hover:hover) and (pointer:fine){
  .brandside-feat{ transition:transform .2s ease }
  .brandside-feat:hover{ transform:translateX(4px) }
  .brandside-feat .bf-ic{ transition:transform .22s cubic-bezier(.2,.9,.25,1.2),
                                     background-color .22s ease }
  .brandside-feat:hover .bf-ic{ transform:scale(1.12) rotate(-4deg) }
}

/* ---- (e) Kartu masuk: naik lembut saat halaman dibuka ---- */
.login-card{ animation:naikKartu .7s cubic-bezier(.16,1,.3,1) both }
@keyframes naikKartu{ from{opacity:0;transform:translateY(16px) scale(.985)} to{opacity:1;transform:none} }

/* ---- (f) Kolom isian: cincin fokus yang menyala lembut ---- */
.login-field input{ transition:box-shadow .22s ease, border-color .22s ease }
.login-field input:focus{ box-shadow:0 0 0 4px rgba(14,124,134,.14) }
/* ---- IKON KIRI KOLOM ISIAN: JANGAN PERNAH DISENTUH transform-nya ----
   (diperbaiki 9 Agu 2026) Aturan sebelumnya memasang `transform:scale(1.1)`
   saat kolom difokus. `transform` BUKAN properti yang menumpuk - nilai baru
   MENGGANTI nilai lama, bukan menambahinya. Padahal ikon ini ditengahkan
   secara tegak dengan `top:50%` + `transform:translateY(-50%)`; begitu
   transform-nya ditimpa, penengahnya hilang dan ikonnya jatuh setengah
   tingginya setiap kali kolom diklik.

   Karena itu di sini transform TIDAK DIPAKAI sama sekali. Yang berubah saat
   fokus hanyalah rupa: tempat ikonnya menyala, warnanya berpindah ke teal,
   dan tebal guratannya menipis. Tidak ada satu pun yang mengubah posisi -
   jadi mustahil bergeser lagi.

   Ikonnya sendiri dipercantik dengan memberinya UBIN LEMBUT di belakangnya
   (bukan mengganti gambarnya, supaya index.html tidak perlu diubah): kotak
   membulat 26x26 dengan latar tipis, yang pada keadaan fokus menyala teal
   dengan cincin halus di sekelilingnya. */
.login-lead-ic{
  width:26px; height:26px; left:9px;         /* ubin, bukan hanya gambar */
  border-radius:9px;
  background:rgba(16,40,50,.045);
  color:var(--muted);
  transition:background-color .24s ease, color .24s ease, box-shadow .24s ease;
}
.login-lead-ic svg{
  width:16px; height:16px;
  stroke-width:1.9;                           /* guratan lebih halus & rapi */
  transition:stroke-width .24s ease;
}
.login-pass-wrap input.has-lead{ padding-left:44px }   /* ruang untuk ubin */

/* Keadaan fokus: ubinnya menyala, warnanya teal, guratannya menipis. */
.login-pass-wrap input.has-lead:focus ~ .login-lead-ic{
  background:rgba(14,124,134,.12);
  color:var(--teal);
  box-shadow:0 0 0 3px rgba(14,124,134,.10);
}
.login-pass-wrap input.has-lead:focus ~ .login-lead-ic svg{ stroke-width:2.1 }

/* Kolom yang SUDAH TERISI tetap bertanda, walau fokusnya sudah pindah -
   supaya sekilas terlihat mana yang sudah diisi. */
.login-pass-wrap input.has-lead:not(:placeholder-shown) ~ .login-lead-ic{
  background:rgba(14,124,134,.08); color:var(--teal-dark, #095E66);
}

/* Tombol mata: disamakan bentuknya dengan ubin di kiri supaya sepasang. */
.login-eye{ border-radius:9px }
.login-eye:hover{ box-shadow:0 0 0 3px rgba(14,124,134,.10) }

/* ---- Hormati "kurangi gerak" ---- */
@media (prefers-reduced-motion:reduce){
  .brandside-mid h2{ animation:none;
    -webkit-text-fill-color:#fff; color:#fff; background:none }
  .brandside-logo, .brandside-logo::before, .brandside-logo::after,
  .brandside-feat, .login-card, .login-btn::after{
    animation:none !important; transform:none !important }
  .login-btn:hover, .brandside-feat:hover{ transform:none !important }
}

/* ============================================================
   19. TINGGI LAPISAN PENUH-LAYAR MENGIKUTI LAYAR SEBENARNYA (9 Agu 2026)
   ------------------------------------------------------------
   Peubah --vvh ditulis app.js dari window.visualViewport pada setiap kejadian
   resize & scroll viewport - lihat catatan lengkapnya di fkTulisViewport().
   Bedanya dengan 100dvh: dvh baru diperbarui SESUDAH animasi bilah peramban
   selesai, sedangkan --vvh mengikutinya frame demi frame. Selama animasi
   itulah celah di bawah lapisan terbuka dan isi di belakangnya menyembul -
   persis gejala "bagian bawah dashboard bocor" yang berulang.

   Urutan cadangannya berlapis, dari yang paling tepat ke yang paling umum:
       var(--vvh, 100dvh)   -> peramban modern tanpa JS aktif
       100dvh               -> tetap lebih baik daripada 100vh
   Peramban yang tidak mengenal dvh akan mengabaikan seluruh deklarasi dan
   memakai baris 100vh sebelumnya. Karena itu 100vh SENGAJA dibiarkan sebagai
   deklarasi pertama di tiap aturan - ia jaring pengaman, bukan sisa lama.

   Berlaku untuk SEMUA perangkat, bukan hanya sentuh: di desktop --vvh sama
   dengan innerHeight sehingga hasilnya tidak berubah sedikit pun. */
/* SIDEBAR SENGAJA TIDAK IKUT DI SINI (11 Agu 2026).
   Dulu `.sidebar-shell` ada di baris ini juga. Itulah sumber "sidebar berkedip
   & terangkat saat gulir mentok ke bawah" di Safari iPad: --vvh ditulis ulang
   pada SETIAP kejadian scroll viewport, jadi tinggi sidebar dihitung ulang
   frame demi frame — dan begitu nilainya sesaat lebih pendek daripada layar,
   latar putih halaman menyembul di bawahnya.
   Untuk lapisan penuh-layar di bawah ini --vvh memang tepat: lapisan itu HARUS
   mengikuti daerah yang benar-benar terlihat supaya isinya terjangkau. Sidebar
   tidak punya kebutuhan itu — ia cukup dipatok ke DUA tepi (lihat bagian 23 di
   akhir berkas), yang nilainya tidak pernah berubah saat menggulir. */
.login-screen{ height:100vh; height:100dvh; height:var(--vvh, 100dvh) }
.overlay, .pn-upload-overlay, .route-loader{
  height:100vh; height:100dvh; height:var(--vvh, 100dvh);
  max-height:100vh; max-height:100dvh; max-height:var(--vvh, 100dvh);
}

/* ---- SIDEBAR TIDAK BOLEH TERPOTONG WALAU MENUNYA PANJANG ----
   Sebelumnya seluruh isi sidebar mengalir begitu saja; begitu daftar menunya
   lebih tinggi daripada layar - hal yang lumrah di iPad melintang maupun
   ponsel - bagian bawahnya (Jenis Akun & tombol Keluar) terpotong dan tidak
   ada cara mencapainya. Sekarang badannya dibagi tiga: kepala & kaki dipatok,
   dan HANYA daftar menunya yang menggulir. Dengan begitu tombol Keluar selalu
   terlihat, berapa pun panjang menunya dan seberapa pun pendek layarnya. */
/* Susunannya bertingkat: .sidebar-shell > .topbar-inner > (.topbar-brand,
   nav.topnav, .side-foot). Yang dijadikan kolom lentur adalah .topbar-inner,
   bukan .sidebar-shell - kalau salah tingkat, aturannya tidak mengenai apa pun. */
.sidebar-shell{ overflow:hidden }
.sidebar-shell > .topbar-inner{
  display:flex; flex-direction:column;
  height:100%; min-height:0; overflow:hidden;
}
.sidebar-shell > .topbar-inner > .topbar-brand,
.sidebar-shell > .topbar-inner > .side-foot{ flex:0 0 auto }
.sidebar-shell > .topbar-inner > nav.topnav{
  flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.28) transparent;
}
.sidebar-shell > .topbar-inner > nav.topnav::-webkit-scrollbar{ width:5px }
.sidebar-shell > .topbar-inner > nav.topnav::-webkit-scrollbar-thumb{
  background:rgba(255,255,255,.26); border-radius:99px }
.sidebar-shell > .topbar-inner > nav.topnav::-webkit-scrollbar-track{ background:transparent }

/* ---- PRATINJAU DOKUMEN: TINGGI IKUT LAYAR, BUKAN 74vh MATI ----
   74vh dihitung dari layout viewport, jadi di ponsel & iPad ia kerap melebihi
   layar yang benar-benar terlihat - akibatnya tepi bawah pratinjau (dan tombol
   di bawahnya) terdorong keluar layar dan dokumennya "tidak terbuka dengan
   baik". Sekarang tingginya dihitung dari --vvh dikurangi tinggi kepala modal
   dan jarak tepinya. */
.pn-preview-body iframe,
.pn-preview-body.fkl-preview-body #fkl-preview-frame{
  height:74vh;
  height:calc(var(--vvh, 100dvh) - 132px);
  max-height:calc(var(--vvh, 100dvh) - 132px);
}
.pn-preview-body.has-tabs iframe{
  height:calc(74vh - 46px);
  height:calc(var(--vvh, 100dvh) - 178px);
}
.pn-preview-modal.is-max .pn-preview-body.fkl-preview-body #fkl-preview-frame{
  height:calc(100vh - 62px);
  height:calc(var(--vvh, 100dvh) - 62px);
  max-height:calc(var(--vvh, 100dvh) - 62px);
}
.pn-preview-body img{
  max-height:74vh;
  max-height:calc(var(--vvh, 100dvh) - 132px);
}
@media (max-width:820px), (any-pointer:coarse){
  /* Di layar kecil kepala modalnya lebih ramping, jadi sisa ruangnya lebih
     banyak - dan pratinjau memang perlu setinggi mungkin di sana. */
  .pn-preview-body iframe,
  .pn-preview-body.fkl-preview-body #fkl-preview-frame{
    height:calc(var(--vvh, 100dvh) - 104px);
    max-height:calc(var(--vvh, 100dvh) - 104px);
  }
}

/* ============================================================
   20. DASHBOARD — KONSEP B "KOP GELAP" (9 Agu 2026)
   ------------------------------------------------------------
   Dipilih dari tiga rancangan yang diajukan. Enam hal yang diminta:
     a) bayangan / cahaya di sekitar kartu data DIHAPUS;
     b) judul dashboard punya pita berlatar sebagai pemisah;
     c) penyaring tidak lagi putih polos - ikut masuk ke dalam pita,
        sekaligus menghemat satu baris penuh;
     d) ikon jadi BULAT bercincin aksen, dan bergerak saat disentuh kursor;
     e) huruf dipertajam;
     f) bagian Bidang Pelaksana dirapatkan supaya gulirnya jauh berkurang.

   Semua diikat ke #view-dashboard supaya kartu & panel di menu lain tidak
   ikut berubah - .card dan .panel dipakai di banyak tempat. */

/* ---------- (b)(c) Kop gelap: judul + penyaring dalam satu pita ---------- */
#view-dashboard > .page-head{
  position:relative; overflow:hidden;
  margin:-18px -18px 18px; padding:20px 24px 16px;
  border-radius:0 0 20px 20px;
  background:linear-gradient(100deg,#0b4950,#187478 60%,#1d8a86);
  box-shadow:none;
  display:block;
}
/* Cahaya lembut di sudut kanan atas supaya bidangnya tidak terasa datar.
   pointer-events:none - ia hiasan, tidak boleh menghalangi penyaring. */
#view-dashboard > .page-head::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(560px 200px at 88% -40%,rgba(255,255,255,.26),transparent 72%);
}
#view-dashboard > .page-head > *{ position:relative; z-index:1 }
/* Judul lama diwarnai gradasi lewat `background-clip:text` +
   `-webkit-text-fill-color:transparent`. Di atas pita gelap gradasi teal itu
   nyaris tak terbaca, dan `color:#fff` SAJA tidak cukup - selama
   -webkit-text-fill-color masih transparan, ia yang menang atas `color`.
   Karena itu ketiganya dikembalikan sekaligus: isian teks, klip latar, dan
   latarnya sendiri. */
#view-dashboard > .page-head h2{
  background:none !important;
  -webkit-background-clip:border-box !important; background-clip:border-box !important;
  -webkit-text-fill-color:#fff !important; color:#fff !important;
  font-weight:800; letter-spacing:.1px; margin:0;
  /* (e) huruf dipertajam: bayangan teks dibuang, penghalusan disetel */
  text-shadow:none; -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
/* Batang penanda tetap memakai ::before mutlak yang sudah ada (padding-left-nya
   sudah disediakan aturan lama) - hanya warnanya diganti kuning agar terbaca di
   atas latar gelap, dan bayangan teal-nya dibuang. */
#view-dashboard > .page-head h2::before{
  background:var(--yellow,#ffd84d) !important;
  box-shadow:none !important;
  width:5px; border-radius:3px;
}
/* Anak judul: satu baris tipis di bawah judul, seperti pada konsep. */
#view-dashboard > .page-head .dash-sub{
  margin:5px 0 0 18px; font-size:10px; font-weight:500;
  color:rgba(198,229,231,.86); letter-spacing:.1px;
}
#view-dashboard > .page-head h2{ font-size:20px !important }
#view-dashboard > .page-head .dash-filter-bar{
  display:flex; gap:10px; flex-wrap:nowrap; margin-top:13px;
}
/* Keempat penyaing sama lebar dan tidak melipat - pada konsep keempatnya
   memenuhi lebar pita dalam satu baris. */
#view-dashboard .dash-filter-bar .filter-field{
  /* Longhand, bukan `flex:1 1 0`: aturan `.dash-filter-bar .filter-field{flex:0 0 auto}`
     di bagian lain berkas ini memakai properti ringkas, dan pada beberapa
     peramban properti ringkas yang datang belakangan dapat menimpa balik
     nilai ringkas sebelumnya secara utuh. Longkah longhand mengunci ketiganya. */
  flex-grow:1 !important; flex-shrink:1 !important; flex-basis:0 !important;
  min-width:0 !important;
  max-width:none !important }
/* Label penyaring disembunyikan: isinya sudah menjelaskan dirinya
   ("Semua Anggaran", "Semua Tahun"), dan tanpa label barisnya jadi satu tingkat. */
#view-dashboard .dash-filter-bar .filter-field > label{ display:none !important }
/* KEKHUSUSAN HARUS DISAMAKAN. Aturan lama memakai
   `#view-dashboard .dash-filter-bar .filter-field select` (1,2,1); pemilih yang
   lebih pendek akan KALAH walau ditulis belakangan. Karena itu bentuk pemilih
   di bawah dibuat sama persis, dan sifat yang harus menang diberi !important. */
#view-dashboard .dash-filter-bar .filter-field select{
  width:100% !important; min-width:0 !important; max-width:none !important;
  color:#fff !important; font-weight:600; font-size:12.5px;
  background-color:rgba(255,255,255,.14) !important;
  border:1px solid rgba(255,255,255,.30) !important;
  border-radius:11px !important; padding:9px 34px 9px 13px !important;
  box-shadow:none !important; transform:none !important;
  transition:background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
  /* Panah bawaan diganti agar warnanya terang di atas latar gelap. */
  -webkit-appearance:none; appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23cfe9ea' stroke-width='2.2' stroke-linecap='round'><path d='M6 9l6 6 6-6'/></svg>") !important;
  background-repeat:no-repeat !important; background-position:right 11px center !important;
  background-size:15px !important;
}
#view-dashboard .dash-filter-bar .filter-field select:hover{
  background-color:rgba(255,255,255,.22) !important;
  border-color:rgba(255,255,255,.46) !important;
  box-shadow:none !important; transform:none !important }
#view-dashboard .dash-filter-bar .filter-field select:focus{
  outline:none; border-color:rgba(255,255,255,.62) !important;
  box-shadow:0 0 0 3px rgba(255,255,255,.16) !important }
/* Daftar pilihannya digambar peramban dengan latar terang, jadi tulisannya
   harus dikembalikan gelap - kalau tidak, teksnya putih di atas putih. */
#view-dashboard .dash-filter-bar .filter-field select option{ color:var(--ink,#0b3d42); background:#fff }

/* ---------- (a) Kartu data: RATA, tanpa bayangan & cahaya ---------- */
/* Blok "bingkai gradasi + bayangan" di bagian lain berkas ini memakai
   !important pada border/background/padding/box-shadow. Konsep B menghendaki
   permukaan RATA, jadi keempatnya harus dilawan dengan !important pula -
   kekhususan saja tidak cukup melawan !important. */
#view-dashboard .cards .card{
  background:#fff !important;
  /* Ditulis LONGHAND dan tanpa var() di dalam shorthand: `border:1px solid
     var(--line)` gugur seluruhnya di peramban yang belum mengurai var() pada
     properti ringkas, dan kartu kembali memakai bingkai gradasi lama. */
  border-width:1px !important;
  border-style:solid !important;
  border-color:#e2e8ea !important;
  border-radius:14px !important;
  box-shadow:none !important;
  filter:none !important;
  padding:13px 15px 15px !important;
}
#view-dashboard .cards .card::before,
#view-dashboard .cards .card::after{ box-shadow:none !important; filter:none !important }
#view-dashboard .cards .card:hover{ box-shadow:none !important; transform:none !important;
  border-color:color-mix(in srgb, var(--card-accent,#0E7C86) 40%, #fff) !important }
/* Garis aksen tebal di tepi atas tidak dipakai lagi - warnanya sekarang
   dibawa cincin ikon, yang lebih terbaca dan tidak menambah tinggi kartu. */
#view-dashboard .cards .card > .accent{ display:none !important }
/* Titik bulat kecil sebelum keterangan dibuang: di konsep keterangannya polos,
   dan titik itu memakan lebar pada kartu yang sudah sempit. */
#view-dashboard .cards .card .sub::before{ display:none !important }
#view-dashboard .cards .card .sub{ display:block !important; gap:0 !important }

/* ---------- (d) Ikon BULAT bercincin aksen ---------- */
#view-dashboard .cards .card .card-head{ display:flex; align-items:center; gap:11px }
#view-dashboard .cards .card .card-ic{
  width:40px !important; height:40px !important; flex:0 0 40px !important;
  border-radius:50% !important;
  display:grid; place-items:center;
  color:var(--ic,var(--teal));
  background:color-mix(in srgb, var(--ic,#0E7C86) 12%, #fff) !important;
  border:1.5px solid color-mix(in srgb, var(--ic,#0E7C86) 34%, #fff) !important;
  box-shadow:none !important;
  position:relative;
}
#view-dashboard .cards .card .card-ic svg{ width:19px; height:19px }
#view-dashboard .cards .card .k{
  font-size:9.4px; font-weight:800; letter-spacing:.7px; text-transform:uppercase;
  color:var(--muted); line-height:1.3;
}
/* Ukuran angka & keterangan dipatok di sini agar sama dengan konsep. Aturan
   lama memakai 26px/12px yang membuat tiap kartu jauh lebih tinggi. */
#view-dashboard .cards .card .v{
  font-size:21px !important; line-height:1.15 !important; margin-top:9px !important;
  font-weight:800; letter-spacing:-.4px;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  text-shadow:none;
}
/* Nilai rupiah panjang diberi ukuran sendiri supaya tidak melipat dua baris. */
#view-dashboard .cards .card .v.v-rp{ font-size:15px !important }
#view-dashboard .cards .card .sub{ font-size:9.6px !important; margin-top:5px !important; color:var(--muted) }

/* Gerak saat kursor menyentuh - hanya di perangkat berkursor, karena di layar
   sentuh keadaan :hover menempel sesudah diketuk dan ikonnya akan membesar
   terus. Cincin luar melebar & memudar seperti riak; ikon di dalamnya berdenyut
   sedikit. transform & opacity saja, jadi tidak ada perhitungan ulang tata letak
   walau kartunya banyak. */
@media (hover:hover) and (pointer:fine){
  #view-dashboard .cards .card .card-ic{
    transition:transform .28s cubic-bezier(.2,.9,.25,1.15),
               background-color .28s ease, border-color .28s ease;
  }
  #view-dashboard .cards .card .card-ic::after{
    content:""; position:absolute; inset:-4px; border-radius:50%;
    border:1.5px solid var(--ic,#0E7C86); opacity:0; transform:scale(.86);
    transition:transform .45s cubic-bezier(.2,.9,.25,1.15), opacity .45s ease;
    pointer-events:none;
  }
  #view-dashboard .cards .card .card-ic svg{
    transition:transform .3s cubic-bezier(.2,.9,.25,1.2);
  }
  #view-dashboard .cards .card:hover .card-ic{
    transform:translateY(-2px);
    background:color-mix(in srgb, var(--ic,#0E7C86) 20%, #fff);
    border-color:color-mix(in srgb, var(--ic,#0E7C86) 55%, #fff);
  }
  #view-dashboard .cards .card:hover .card-ic::after{ opacity:.32; transform:scale(1.16) }
  #view-dashboard .cards .card:hover .card-ic svg{ transform:scale(1.12) }
}

/* ---------- Panel efisiensi: tiga cincin dalam satu kartu ---------- */
#view-dashboard .eff-panel{ grid-column:span 3; display:flex; flex-direction:column }
#view-dashboard .eff-panel .eff-panel-k{
  font-size:9.4px; font-weight:800; letter-spacing:.7px; text-transform:uppercase;
  color:var(--muted); margin-bottom:10px;
}
/* minmax(0,1fr) — BUKAN 1fr. Bawaan sebuah kolom grid adalah min-content,
   jadi segmen yang tulisannya lebih panjang menuntut kolom lebih lebar dan
   ketiganya berakhir tidak sama (217/211/197 px di iPad). */
#view-dashboard .eff-grid{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0; flex:1 1 auto;
}
#view-dashboard .eff-seg{ display:flex; align-items:center; gap:12px; padding:0 14px }
#view-dashboard .eff-seg + .eff-seg{ border-left:1px solid var(--line,#e2e8ea) }
#view-dashboard .eff-seg:first-child{ padding-left:0 }
#view-dashboard .eff-seg:last-child{ padding-right:0 }
/* Cincin dari conic-gradient; lubang tengahnya dibuat elemen putih di atasnya,
   bukan mask - supaya tetap tergambar di peramban tanpa dukungan mask. */
#view-dashboard .eff-ring{
  width:56px; height:56px; flex:0 0 56px; border-radius:50%;
  background:conic-gradient(var(--green,#0d7a3f) var(--deg,0%), #e9f0f1 0);
  display:grid; place-items:center;
}
#view-dashboard .eff-ring-in{
  width:44px; height:44px; border-radius:50%; background:#fff;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  line-height:1;
}
#view-dashboard .eff-ring-in b{ font-size:12.5px; font-weight:800; color:var(--green,#0d7a3f) }
#view-dashboard .eff-ring-in i{ font-style:normal; font-size:8px; color:var(--muted); margin-top:1px }
#view-dashboard .eff-seg-tx{ min-width:0 }
#view-dashboard .eff-seg-k{ font-size:10px; font-weight:700; color:var(--ink2,#0d2a30) }
#view-dashboard .eff-seg-v{ font-size:13px; font-weight:800; color:var(--ink,#0b3d42); margin-top:2px }
/* Keterangan kecil di bawah nilai. `white-space:nowrap` dibuang 15 Agu 2026:
   di desktop kolomnya 241px dan kalimatnya muat satu baris, tetapi di iPad
   hanya 197px sehingga ujungnya terpotong jadi "…terhadap HP…". Dibiarkan
   turun baris (paling banyak dua), tampilan desktop tidak berubah sedikit pun
   karena di sana ia memang tidak pernah sampai membungkus. */
#view-dashboard .eff-seg-s{
  font-size:9px; color:var(--muted); margin-top:2px; line-height:1.35;
  overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
}
@media (hover:hover) and (pointer:fine){
  #view-dashboard .eff-ring{ transition:transform .3s cubic-bezier(.2,.9,.25,1.2) }
  #view-dashboard .eff-seg:hover .eff-ring{ transform:scale(1.07) }
}

/* ---------- (f) Bidang Pelaksana dirapatkan ---------- */
#view-dashboard .split > .panel{
  box-shadow:none !important; filter:none !important;
  border:1px solid var(--line,#e2e8ea) !important; border-radius:16px !important;
  background:#fff !important;
}
/* Garis tebal bergradasi di bawah kepala panel diganti garis tipis biasa. */
#view-dashboard .split > .panel > .panel-h,
#view-dashboard .split > .panel > h3{
  border-bottom:1px solid var(--line,#e2e8ea) !important;
  box-shadow:none !important; background:none !important;
}
#view-dashboard .split > .panel > .panel-h::after,
#view-dashboard .split > .panel > h3::after{ display:none !important }
#view-dashboard .split > .panel:hover{ box-shadow:none !important }
/* Nama kelas mengikuti keluaran renderBars(): .bar-row > .lbl + .bar-track + .num
   (bukan .bar-lb / .bar-val - itu tebakan yang salah dan tidak mengenai apa pun). */
#view-dashboard .split .bar-row{ padding:6px 0 }
#view-dashboard .split .bar-row + .bar-row{ border-top:1px solid #f1f6f7 }
#view-dashboard .split .bar-row .lbl{
  font-size:10.5px; font-weight:600; margin-bottom:4px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
#view-dashboard .split .bar-row .bar-track{ height:7px; border-radius:99px }
#view-dashboard .split .bar-row .num{ font-size:10.5px; font-weight:800 }
#view-dashboard .split .bar-row .num.num-rp{ font-size:10px }

/* ---------- Layar sempit: pita tetap, penyaring melipat ---------- */
@media (max-width:820px), (any-pointer:coarse){
  #view-dashboard > .page-head{ margin:-12px -12px 14px; padding:16px 16px 14px }
  #view-dashboard .dash-filter-bar .filter-field{ flex:1 1 140px }
}

/* ---------- Panel Efisiensi: MELEBAR PENUH HANYA DI LAYAR SEMPIT ----------
   ⚠ DIPISAH DARI BLOK DI ATAS, 15 Agustus 2026.

   Keempat aturan ini dulu ikut di dalam blok yang sama, dan blok itu bertabir
   `(max-width:820px), (any-pointer:coarse)`. Tabir kedua itulah cacatnya:
   `any-pointer:coarse` benar untuk iPad PADA LEBAR BERAPA PUN — termasuk
   lanskap 1194px yang ruangnya berlimpah. Akibatnya panel Efisiensi di iPad
   selalu melebar penuh dan ketiga cincinnya bertumpuk ke bawah, sementara di
   desktop ia duduk sebaris dengan Nilai RAB & Nilai HPS.

   Yang menentukan muat-atau-tidak di sini memang LEBAR, bukan jenis penunjuk.
   Sentuhan tidak membuat layar menyempit. */
@media (max-width:820px){
  #view-dashboard .eff-panel{ grid-column:1 / -1 }
  #view-dashboard .eff-grid{ grid-template-columns:1fr }
  #view-dashboard .eff-seg{ padding:9px 0 }
  #view-dashboard .eff-seg + .eff-seg{ border-left:none; border-top:1px solid var(--line,#e2e8ea) }
}
@media (prefers-reduced-motion:reduce){
  #view-dashboard .cards .card .card-ic,
  #view-dashboard .cards .card .card-ic::after,
  #view-dashboard .cards .card .card-ic svg,
  #view-dashboard .eff-ring{ transition:none !important; transform:none !important }
}

/* ============================================================
   21. TOMBOL PROFIL: LABEL PENDEK, IKON YANG MEMBEDAKAN (9 Agu 2026)
   ------------------------------------------------------------
   Empat tombol berjajar yang tulisannya panjang-panjang ("Simpan Profil",
   "Muat Profil", "Batalkan Profil", "Reset Klausul") membuat bilahnya melipat
   ke baris kedua di layar sedang. Tulisannya dipendekkan jadi "Profil" bertiga
   dan "Reset", lalu yang MEMBEDAKAN diserahkan ke ikonnya: cakram simpan,
   panah muat ulang, tanda silang, dan panah muat ulang untuk Reset.

   Judul lengkapnya tetap ada di atribut title=, jadi arti tiap tombol masih
   bisa dipastikan dengan menggantungkan kursor - tidak ada keterangan yang
   benar-benar hilang. */

/* Tanda silang pada tombol Batalkan diberi LINGKARAN PUTIH di sekelilingnya.
   Tanpa lingkaran, silang polos di atas tombol merah mudah tertukar dengan
   tanda silang "tutup" yang ada di sudut modal. Lingkarannya dibuat dari
   border + border-radius pada svg-nya sendiri, bukan elemen tambahan, supaya
   markup tombolnya tidak perlu diubah sama sekali. */
.jp-profil-btn.is-cancel svg{
  border:1.6px solid currentColor;
  border-radius:50%;
  padding:2.5px;
  box-sizing:content-box;
  width:12px; height:12px;
}
@media (hover:hover) and (pointer:fine){
  .jp-profil-btn.is-cancel svg{ transition:transform .22s cubic-bezier(.2,.9,.25,1.2) }
  .jp-profil-btn.is-cancel:hover svg{ transform:rotate(90deg) }
}
/* Bilah tombolnya dirapatkan sedikit karena labelnya kini pendek. */
.spk-klbar{ display:flex; flex-wrap:wrap; gap:8px; align-items:center }

/* ============================================================
   22. (dikosongkan 10 Agu 2026)
   ------------------------------------------------------------
   Blok "Kop Gelap" untuk halaman Daftar (Kontrak Rinci / Pengadaan Langsung /
   Tender) DIBATALKAN atas permintaan; ketiganya kembali memakai tampilan
   bawaan: kepala biasa, bilah penyaring putih, dan tabel seperti semula.
   Pembungkus .list-kop di index.html ikut dicabut, jadi tidak ada sisa aturan
   yang menggantung di sini. */

/* ---- Baris tombol di dalam kartu formulir Ambil Nomor (10 Agu 2026) ----
   Garis tipis di atasnya memisahkan daerah tindakan dari daerah isian, dan
   jarak dalamnya mengikuti padding kartu supaya tombolnya lurus dengan tepi
   kolom isian - bukan menempel ke dinding kartu. */
.form-card .jp-actions.pn-card-actions{
  margin:16px -18px -16px; padding:14px 18px;
  border-top:1px solid var(--line,#e2e8ea);
  background:rgba(240,247,248,.6);
  border-radius:0 0 14px 14px;
  display:flex; gap:10px;
}


/* ============================================================
   23. SIDEBAR DIPATOK KE DUA TEPI LAYAR (11 Agu 2026)
   ------------------------------------------------------------
   LAPORAN (iPad 8" & 11"): "saat dashboard di-scroll sampai mentok bawah,
   sidebar berkedip / bergeser / terangkat sehingga background putih terlihat
   di bawahnya."

   SEBABNYA SATU: TINGGI SIDEBAR DIIKATKAN KE TINGGI VIEWPORT YANG BERUBAH-UBAH.
   Sepanjang berkas ini tinggi `.sidebar-shell` disebut berkali-kali, dan yang
   menang adalah yang paling belakang:

       baris 7884   .sidebar-shell{height:100dvh}
       baris 8514   html.mode-rail .sidebar-shell{height:100dvh}
       baris 9335   html.mode-rail .sidebar-shell{height:100dvh;max-height:100dvh}
       bagian 19    .sidebar-shell{height:var(--vvh, 100dvh)}

   Ketiga satuan itu — 100vh, 100dvh, dan --vvh — sama-sama BERGERAK di Safari
   iOS/iPadOS saat bilah peramban menyusut & memanjang mengikuti gulir. --vvh
   yang paling terasa karena ditulis ulang tiap frame (lihat bagian 19); dvh
   menyusul sesudah animasi bilah selesai. Karena sidebar dijangkarkan di
   `top:0` lalu diberi TINGGI, setiap kali angka itu sesaat lebih kecil daripada
   layar yang benar-benar terlihat, tepi bawahnya naik dan yang tampak di
   bawahnya adalah latar halaman — persis "terangkat, background putih terlihat".
   `max-height:100dvh` di baris 9335 membuatnya makin pasti: `bottom:0` yang
   sudah dipasang di bagian 36 pun tidak sempat meregangkannya kembali.

   Ada satu keganjilan lagi yang ikut terjawab: baris 8586
   (`html.mode-rail .sidebar-shell.is-open{height:auto}`) kekhususannya lebih
   tinggi daripada baris 9335, sehingga sidebar yang SEDANG MELEBAR memakai
   aturan tinggi yang berbeda dari sidebar yang menciut. Itu sebabnya kedipannya
   terasa tidak menentu — bergantung rail sedang terbuka atau tidak.

   PERBAIKANNYA: sidebar tidak lagi diberi TINGGI sama sekali, melainkan
   DIPATOK KE DUA TEPI (`top:0` + `bottom:0` + `height:auto`). Untuk elemen
   position:fixed, kotak acuannya adalah viewport tata letak — ukuran yang di
   WebKit iOS memang TIDAK ikut berubah saat bilah peramban bergerak maupun saat
   halaman melenting. Jadi tingginya tidak pernah dihitung ulang selama
   menggulir: tidak ada kedipan, dan mustahil ada celah di bawahnya. Di
   Windows/macOS hasilnya sama persis dengan sebelumnya (di sana kedua tepi itu
   memang tepi jendela), jadi tampilan desktop tidak berubah sedikit pun.

   Bagian 12 (overscroll-behavior-y:none) tetap dipertahankan: ia menghentikan
   lentingan dokumennya, sedangkan aturan di sini menghentikan perhitungan ulang
   tingginya. Keduanya menangani sisi yang berbeda dari gejala yang sama.
   ============================================================ */

/* Kekhususan sengaja disamakan dengan lawan terberatnya
   (`html.mode-rail .sidebar-shell.is-open`) supaya menang di SEMUA keadaan:
   rail menciut, rail melebar, maupun laci di ponsel. */
html .sidebar-shell,
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  top:0;
  bottom:0;
  height:auto;      /* tinggi lahir dari kedua tepi, bukan dari satuan viewport */
  max-height:none;  /* melepas max-height:100dvh baris 9335 yang mengunci regangan */
}

/* Kolom isi mengisi penuh tinggi itu. `height:100%` di sini sah karena tinggi
   induknya sudah pasti (lahir dari top+bottom), jadi kaki sidebar tetap
   menempel ke dasar layar seperti rancangan semula. */
html .sidebar-shell > .topbar-inner{ height:100%; min-height:0 }

/* PONSEL (laci geser) — pengecualian yang disengaja.
   Safari iPhone punya bilah alat di BAWAH layar; kalau sidebar dipatok sampai
   `bottom:0` viewport tata letak, tombol "Keluar" berakhir di balik bilah itu.
   Di sana dipakai 100svh: tinggi layar SAAT BILAH TERENTANG PENUH — nilainya
   TETAP, tidak ikut bergerak saat menggulir, jadi tidak menghidupkan kembali
   kedipan yang baru saja diperbaiki. Aman pula karena laci hanya muncul di atas
   halaman yang guliranya sudah dikunci (body.nav-open{overflow:hidden}).
   iPad tidak kena aturan ini: ia memakai mode rail, dan Safari iPad tidak punya
   bilah alat di bawah. */
@supports (height:100svh){
  html:not(.mode-rail) .sidebar-shell{
    bottom:auto;
    height:100svh;
    max-height:100svh;
  }
}


/* ============================================================
   24. SIDEBAR: SOROTAN TEGAS, JARAK PRESISI, GULIR YANG DIAM
   ------------------------------------------------------------
   Tiga keluhan, satu bagian — ketiganya menyangkut sidebar yang
   sama dan menaruhnya berjauhan hanya membuat yang satu tak
   sengaja membatalkan yang lain.

     a) sorotan saat kursor mengenai menu terlalu samar;
     b) jarak antar ikon dalam mode ciut tidak beraturan —
        label bagian yang dipangkas menyisakan dua titik yang
        terbaca sebagai kotoran layar, bukan sebagai pemisah;
     c) di iPad, menggulir dashboard sampai mentok membuat
        sidebar seperti TERANGKAT lalu turun lagi.

   Bagian ini ditulis PALING AKHIR supaya menang urutan berkas
   terhadap bagian 30, 33, dan 34 yang lebih dulu menetapkan
   ukuran rail. Kekhususan selektornya sengaja dibuat sama
   persis dengan yang di sana — bukan dinaikkan — agar yang
   menentukan cukup urutannya saja dan tetap mudah dilacak.
   ============================================================ */

/* ------------------------------------------------------------
   24a. SOROTAN HOVER
   Pseudo-elemen ::after pada menu sidebar dulu DIMATIKAN
   (bagian sidebar baris ~7630 mematikan garis bawah gaya
   menu-atas). Di sini ia dihidupkan kembali dengan tugas baru:
   BATANG KUNING di tepi kiri tombol. Bentuk itu dipilih karena
   ia satu-satunya penanda yang bekerja sama baiknya pada dua
   bentuk tombol yang jauh berbeda — baris selebar sidebar saat
   melebar, dan kotak 38px saat menciut.

   Yang bergerak hanya batangnya (scaleY), bukan tombolnya:
   #topnav memasang transform:none!important pada tombol, dan
   itu keputusan bagian 31 yang tidak boleh dibatalkan di sini.
   ------------------------------------------------------------ */
#topnav .topnav-link,
#topnav .topnav-trigger{
  transition:background .15s ease,color .15s ease,box-shadow .15s ease;
}
#topnav .topnav-link::after,
#topnav .topnav-trigger::after{
  display:block;content:"";
  position:absolute;left:0;top:50%;bottom:auto;right:auto;
  width:3px;height:58%;border-radius:0 3px 3px 0;
  background:linear-gradient(180deg,var(--yellow),#ffd35a);
  transform:translateY(-50%) scaleY(0);transform-origin:50% 50%;
  opacity:0;pointer-events:none;
  transition:transform .18s cubic-bezier(.16,1,.3,1),opacity .18s ease;
}
#topnav .topnav-link:hover::after,
#topnav .topnav-trigger:hover::after,
#topnav .topnav-link:focus-visible::after,
#topnav .topnav-trigger:focus-visible::after{
  transform:translateY(-50%) scaleY(1);opacity:1;
}
#topnav .topnav-link:hover,
#topnav .topnav-trigger:hover{
  background:rgba(255,255,255,.17);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.26),0 6px 18px rgba(2,26,30,.26);
  color:#fff;
}
#topnav .topnav-link:active,
#topnav .topnav-trigger:active{
  background:rgba(255,255,255,.24);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.34);
}
/* Menu yang SEDANG AKTIF sudah kuning penuh; batang kuning di
   atas latar kuning tidak menambah keterangan apa pun, jadi
   dilepas — sorotannya cukup lewat pendar yang menguat. */
#topnav .topnav-link.active::after,
#topnav .topnav-group.has-active .topnav-trigger::after{display:none}
#topnav .topnav-link.active:hover,
#topnav .topnav-group.has-active .topnav-trigger:hover{
  background:linear-gradient(135deg,#ffd85f,var(--yellow));
  box-shadow:0 6px 20px rgba(246,180,14,.5),inset 0 0 0 1px rgba(255,255,255,.55);
  color:#073f45;
}
/* Butir di dalam grup: garis tepi kirinya sendiri yang menguning.
   Ia sudah ada sebagai penanda hierarki, jadi tidak perlu
   penanda kedua. */
#topnav .topnav-item:hover,
#topnav .topnav-subtrigger:hover{
  background:rgba(255,255,255,.16);
  border-left-color:var(--yellow);
  color:#fff;
}
#topnav .topnav-item:active,
#topnav .topnav-subtrigger:active{background:rgba(255,255,255,.22)}

/* ------------------------------------------------------------
   24b. JARAK PRESISI DALAM MODE CIUT
   Irama tunggal: kotak 38px, jarak 6px, pemisah kelompok berupa
   GARIS 26px. Label bagian (.side-sec) tidak lagi dipangkas
   jadi 9px — potongan huruf itulah yang tampak seperti dua
   titik di sela ikon. Ia diubah menjadi garisnya sendiri:
   tulisannya benar-benar hilang (font-size:0), yang tersisa
   satu garis tipis dengan jarak atas-bawah yang sama.

   Ditulis dua kali — media query perangkat berkursor DAN
   html.mode-rail — mengikuti pola yang sudah dipakai bagian
   23, 30, dan 33. Satu salinan saja akan menyisakan salah satu
   perangkat memakai jarak lama.
   ------------------------------------------------------------ */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav{
    padding:12px 0 14px;gap:6px;align-items:center}
  .sidebar-shell:not(.is-open) #topnav .topnav-link,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
    margin:0;border-radius:12px}
  .sidebar-shell:not(.is-open) .side-sec{
    opacity:1;height:1px;width:26px;padding:0;margin:5px auto;
    font-size:0;line-height:0;overflow:hidden;
    background:rgba(255,255,255,.20);border-radius:1px;flex:0 0 auto}
  .sidebar-shell:not(.is-open) .side-sec:first-child{margin-top:0}
  .sidebar-shell:not(.is-open) .side-foot{padding:8px 0 10px}
}
html.mode-rail .sidebar-shell:not(.is-open) #topnav{
  padding:12px 0 14px;gap:6px;align-items:center}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  margin:0;border-radius:12px}
html.mode-rail .sidebar-shell:not(.is-open) .side-sec{
  opacity:1;height:1px;width:26px;padding:0;margin:5px auto;
  font-size:0;line-height:0;overflow:hidden;
  background:rgba(255,255,255,.20);border-radius:1px;flex:0 0 auto}
html.mode-rail .sidebar-shell:not(.is-open) .side-sec:first-child{margin-top:0}
html.mode-rail .sidebar-shell:not(.is-open) .side-foot{padding:8px 0 10px}

/* Kotak ikon dalam mode ciut: latar sedikit lebih hidup dan
   tepi dalam tipis, supaya ia terbaca sebagai TOMBOL — bukan
   ikon yang mengambang di atas gradien. */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav .topnav-link,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
    background:rgba(255,255,255,.08);
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.07)}
  .sidebar-shell:not(.is-open) #topnav .topnav-link:hover,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger:hover{
    background:rgba(255,255,255,.19);
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),0 5px 14px rgba(2,26,30,.3)}
  .sidebar-shell:not(.is-open) #topnav .topnav-link.active,
  .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger{
    box-shadow:0 5px 16px rgba(246,180,14,.42),inset 0 0 0 1px rgba(255,255,255,.4)}
}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger{
  background:rgba(255,255,255,.08);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.07)}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link:hover,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger:hover{
  background:rgba(255,255,255,.19);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),0 5px 14px rgba(2,26,30,.3)}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link.active,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-group.has-active .topnav-trigger{
  box-shadow:0 5px 16px rgba(246,180,14,.42),inset 0 0 0 1px rgba(255,255,255,.4)}

/* Batang kuning pada kotak 38px: dipendekkan supaya tidak
   menyentuh kedua sudut membulat. */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) #topnav .topnav-link::after,
  .sidebar-shell:not(.is-open) #topnav .topnav-trigger::after{height:52%;width:2.5px}
}
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-link::after,
html.mode-rail .sidebar-shell:not(.is-open) #topnav .topnav-trigger::after{height:52%;width:2.5px}

/* Kepala & kaki mengikuti irama yang sama: garis pemisah yang
   selebar garis kelompok, bukan selebar rail. */
@media (hover:hover) and (min-width:1025px){
  .sidebar-shell:not(.is-open) .topbar-brand{
    border-bottom-color:transparent;position:relative}
  .sidebar-shell:not(.is-open) .topbar-brand::after{
    content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);
    width:26px;height:1px;background:rgba(255,255,255,.20);border-radius:1px}
  .sidebar-shell:not(.is-open) .side-foot{
    border-top-color:transparent;position:relative}
  .sidebar-shell:not(.is-open) .side-foot::before{
    content:"";position:absolute;left:50%;top:0;transform:translateX(-50%);
    width:26px;height:1px;background:rgba(255,255,255,.20);border-radius:1px}
}
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand{
  border-bottom-color:transparent;position:relative}
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand::after{
  content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  width:26px;height:1px;background:rgba(255,255,255,.20);border-radius:1px}
html.mode-rail .sidebar-shell:not(.is-open) .side-foot{
  border-top-color:transparent;position:relative}
html.mode-rail .sidebar-shell:not(.is-open) .side-foot::before{
  content:"";position:absolute;left:50%;top:0;transform:translateX(-50%);
  width:26px;height:1px;background:rgba(255,255,255,.20);border-radius:1px}

/* ------------------------------------------------------------
   24c. GULIR PINDAH KE ISI HALAMAN (TABLET SENTUH)
   ------------------------------------------------------------
   Bagian 12 sudah mematikan lentingan dokumen dan bagian 23
   sudah memaku sidebar ke kedua tepi. Yang masih tersisa di
   iPad adalah gejala ketiga: menggulir dashboard sampai mentok
   membuat Safari MENYUSUTKAN lalu MEMBENTANGKAN kembali bilah
   alatnya. Setiap kali itu terjadi, tinggi viewport BERUBAH —
   dan elemen position:fixed yang dipatok ke dua tepi ikut
   berubah tinggi. Yang terlihat: sidebar terangkat sekejap
   lalu turun lagi.

   Tidak ada nilai CSS yang bisa memenangkan perlombaan itu,
   karena penyebabnya bukan satuan tinggi melainkan KEJADIAN
   menggulirnya dokumen. Maka dokumennya dibuat TIDAK PERNAH
   MENGGULIR: yang menggulir kini kolom isi (.app-main).
   Tanpa gulir dokumen, bilah alat Safari tidak pernah berubah
   keadaan, viewport tidak pernah berubah tinggi, dan sidebar
   berdiri diam.

   HANYA untuk mode rail di perangkat sentuh. Desktop tidak
   diusik sama sekali (di sana gejalanya memang tidak pernah
   ada), dan ponsel tetap memakai laci geser dengan gulir
   dokumen seperti biasa.

   Konsekuensi yang disengaja: bilah alat Safari tidak lagi
   menyusut saat menggulir, jadi layar terpakai sedikit lebih
   pendek — ditukar dengan sidebar yang tidak bergoyang. Untuk
   aplikasi yang dipakai berjam-jam, tukarnya menguntungkan.

   window.scrollTo() tetap bekerja: ui-sidebar.js membelokkan
   panggilannya ke kolom isi saat mode ini menyala.
   ------------------------------------------------------------ */
@media (any-pointer:coarse){
  html.mode-rail,
  html.mode-rail body{
    height:100%;max-height:100%;overflow:hidden;
    overscroll-behavior:none}
  html.mode-rail .app-shell{
    height:100%;min-height:0;overflow:hidden}
  html.mode-rail .app-main{
    height:100%;min-height:0;
    overflow-y:auto;overflow-x:hidden;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-y:contain}
  /* Batang gulirnya disembunyikan supaya tepi kanan tetap bersih
     seperti sebelumnya (di layar sentuh ia memang tak terpakai). */
  html.mode-rail .app-main{scrollbar-width:none;-ms-overflow-style:none}
  html.mode-rail .app-main::-webkit-scrollbar{width:0;height:0}
}

/* Gerak dimatikan bagi yang memintanya lewat setelan sistem. */
@media (prefers-reduced-motion:reduce){
  #topnav .topnav-link::after,
  #topnav .topnav-trigger::after{transition:none}
}


/* ============================================================
   25. "INGAT SAYA" DI HALAMAN LOGIN (15 Agustus 2026)
   ------------------------------------------------------------
   Kotak centang bawaan peramban tidak bisa diwarnai dengan
   layak dan ukurannya berbeda-beda di tiap sistem — di halaman
   login yang selebihnya tertata rapi ia terlihat seperti
   tempelan. Kotak aslinya karena itu DISEMBUNYIKAN (bukan
   dihapus: ia tetap elemen yang menerima klik, fokus papan
   ketik, dan pembaca layar), lalu digambar ulang lewat
   <span class="login-ingat-kotak">.

   Keterbacaan papan ketik dijaga: Tab tetap menyorotinya
   (:focus-visible -> cincin teal), dan Spasi tetap mencentang.
   ============================================================ */
.login-ingat{
  display:flex;align-items:center;gap:10px;cursor:pointer;
  margin:-2px 0 13px;padding:2px 0;user-select:none;
}
/* Kotak asli tetap ada — hanya tak terlihat. display:none akan
   mengeluarkannya dari urutan Tab dan mematikan pembaca layar. */
.login-ingat input{
  position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none;
}
.login-ingat-kotak{
  flex:0 0 auto;width:18px;height:18px;border-radius:6px;
  border:1.6px solid #cfdcdf;background:#fff;
  display:grid;place-items:center;color:#fff;
  transition:background .16s ease,border-color .16s ease,box-shadow .16s ease;
}
.login-ingat-kotak svg{width:12px;height:12px;opacity:0;transform:scale(.6);
  transition:opacity .14s ease,transform .16s cubic-bezier(.34,1.56,.64,1)}
.login-ingat:hover .login-ingat-kotak{border-color:var(--teal);background:#f2fbfb}
.login-ingat input:checked + .login-ingat-kotak{
  background:linear-gradient(135deg,var(--teal),var(--cyan));
  border-color:var(--teal);
  box-shadow:0 3px 9px rgba(14,124,134,.32);
}
.login-ingat input:checked + .login-ingat-kotak svg{opacity:1;transform:scale(1)}
.login-ingat input:focus-visible + .login-ingat-kotak{
  box-shadow:0 0 0 3px rgba(14,124,134,.24);border-color:var(--teal);
}
.login-ingat-teks{
  font-size:11.5px;font-weight:700;color:var(--ink);line-height:1.35;
}
/* Keterangan kecil di bawah labelnya DIHAPUS atas permintaan
   (15 Agu 2026, petang). Perilakunya tidak berubah — yang
   disimpan tetap username saja — hanya kalimat penjelasnya yang
   tidak lagi ditampilkan di layar. Penjelasannya tetap hidup di
   komentar app.js, tempat orang berikutnya akan mencarinya. */
@media (prefers-reduced-motion:reduce){
  .login-ingat-kotak,.login-ingat-kotak svg{transition:none}
}


/* ============================================================
   26. DAFTAR PEKERJAAN MUAT SATU LAYAR DI TABLET (15 Agu 2026)
   ------------------------------------------------------------
   LAPORAN: "di desktop tampilan 1 layar tanpa geser kiri kanan,
   di iPad malah tidak full dan harus geser kiri kanan."

   Bagian 13 sudah merapikan SELURUH tabel lain, tetapi TIGA
   daftar Monitoring (Kontrak Rinci · Pengadaan Langsung ·
   Tender) sengaja dikecualikan di sana. Alasannya sah pada
   masanya: tabel itu paling banyak kolomnya dan memakai kolom
   beku Nomor + Nama, sehingga geseran mendatar dianggap memang
   cara pakainya.

   Ternyata bukan itu yang terjadi. Di desktop ruang isinya
   1.272px dan tabelnya nyaris muat; di iPad 11" ruangnya hanya
   1.076px — 196px lebih sempit — dan selisih itulah yang
   memaksa menggeser. Bukan tabelnya yang berbeda, melainkan
   layarnya.

   HITUNGAN PENGHEMATANNYA (iPad 11" lanskap, perlu ±275px):

       Bidang Pelaksana   200 -> 124   =  76px
       Penyedia           200 -> 132   =  68px
       dua kolom tanggal  118 ->  96   =  44px
       Nama Pekerjaan     240 -> 186   =  54px
       No. Kontrak/SPBJ   boleh turun baris, 150 -> 112 = 38px
                                          ------------------
                                          jumlah  280px

   Tidak ada satu pun kolom yang disembunyikan dan tidak ada
   huruf yang diperkecil — yang berubah hanya lebar minimum,
   dan teks yang tadinya dipaksa satu baris kini boleh turun.

   HANYA TABLET. Ditulis di bawah `html.mode-rail` + tabir
   `any-pointer:coarse`, jadi tampilan desktop tidak tersentuh
   sama sekali.
   ============================================================ */
/* ⚠ BLOK INI DIMATIKAN — 16 Agustus 2026. Lihat bagian 37 di akhir berkas.
   Ringkasnya: pemadatan di bawah ini berangkat dari salah paham. Monitoring
   MEMANG dirancang untuk digeser mendatar — itu sebabnya kolom Nama Pekerjaan
   dibekukan — jadi memaksanya muat satu layar justru mengubah presisi kolom
   yang sudah benar. Syarat medianya diganti dengan yang tidak akan pernah
   cocok, sehingga seluruh isi blok tetap tersimpan utuh dan bisa dihidupkan
   lagi cukup dengan mengembalikan angka 0px menjadi 1400px. */
@media (any-pointer:coarse) and (max-width:0px){

  /* Lantai global 980px dilepas juga untuk ketiga daftar ini. */
  html.mode-rail #view-list .table-wrap table,
  html.mode-rail #view-list-pl .table-wrap table,
  html.mode-rail #view-list-tender .table-wrap table{ min-width:0 }

  /* Nomor kontrak/SPBJ boleh turun baris. Nomor seperti
     "0031.SPK/DAN.01.01/F17060000/2026" (33 aksara) yang dipaksa
     satu baris sendirian menuntut ±230px. */
  html.mode-rail #view-list .table-wrap th.col-kontrak,
  html.mode-rail #view-list .table-wrap td.col-kontrak,
  html.mode-rail #view-list-pl .table-wrap th.col-kontrak,
  html.mode-rail #view-list-pl .table-wrap td.col-kontrak,
  html.mode-rail #view-list-tender .table-wrap th.col-kontrak,
  html.mode-rail #view-list-tender .table-wrap td.col-kontrak{
    white-space:normal; overflow-wrap:anywhere; word-break:break-word;
    min-width:112px }

  /* Nama pekerjaan: batas bawah diturunkan, batas atas dilepas
     supaya sisa ruang jatuh ke kolom ini — bukan disebar rata ke
     kolom yang sudah cukup. */
  html.mode-rail #view-list .table-wrap th.col-nama-freeze,
  html.mode-rail #view-list .table-wrap td.col-nama-freeze,
  html.mode-rail #view-list-pl .table-wrap th.col-nama-freeze,
  html.mode-rail #view-list-pl .table-wrap td.col-nama-freeze,
  html.mode-rail #view-list-tender .table-wrap th.col-nama-freeze,
  html.mode-rail #view-list-tender .table-wrap td.col-nama-freeze{
    min-width:186px; max-width:none }

  /* Bidang & Penyedia sudah boleh turun baris sejak semula;
     yang mengunci lebarnya cuma width/min/max yang ditulis tegas. */
  html.mode-rail #view-list .table-wrap th.col-bidang,
  html.mode-rail #view-list .table-wrap td.col-bidang,
  html.mode-rail #view-list-pl .table-wrap th.col-bidang,
  html.mode-rail #view-list-pl .table-wrap td.col-bidang,
  html.mode-rail #view-list-tender .table-wrap th.col-bidang,
  html.mode-rail #view-list-tender .table-wrap td.col-bidang{
    width:124px; min-width:124px; max-width:124px }
  html.mode-rail #view-list .table-wrap th.col-penyedia,
  html.mode-rail #view-list .table-wrap td.col-penyedia,
  html.mode-rail #view-list-pl .table-wrap th.col-penyedia,
  html.mode-rail #view-list-pl .table-wrap td.col-penyedia,
  html.mode-rail #view-list-tender .table-wrap th.col-penyedia,
  html.mode-rail #view-list-tender .table-wrap td.col-penyedia{
    width:132px; min-width:132px; max-width:132px }

  /* Kolom tanggal memakai !important di aturan aslinya, jadi
     penggantinya wajib ikut !important — bukan gaya penulisan,
     melainkan satu-satunya cara menang. */
  html.mode-rail #view-list .table-wrap th.col-date,
  html.mode-rail #view-list .table-wrap td.col-date,
  html.mode-rail #view-list-pl .table-wrap th.col-date,
  html.mode-rail #view-list-pl .table-wrap td.col-date,
  html.mode-rail #view-list-tender .table-wrap th.col-date,
  html.mode-rail #view-list-tender .table-wrap td.col-date{
    width:96px!important; min-width:96px!important; max-width:96px!important }
}

/* --- Tender: satu kolom lebih banyak ------------------------
   Daftar Tender punya kolom "Metode Pengadaan" yang tidak ada
   pada dua daftar lain — 96px yang membuatnya tetap 69px lewat
   sesudah pemadatan di atas. Karena itu ia dipadatkan sedikit
   lebih jauh, dan judul kolom yang dipaksa satu baris (Nilai
   Pekerjaan, Metode Pengadaan) dibolehkan turun baris: yang
   melebarkan kolom itu memang JUDULNYA, bukan isinya.

   ⚠ IKUT DIMATIKAN 16 Agustus 2026 — lihat bagian 37. Blok ini lanjutan dari
   bagian 26 dan berangkat dari salah paham yang sama; syarat medianya diganti
   dengan yang tidak akan pernah cocok, isinya dibiarkan utuh. */
@media (any-pointer:coarse) and (max-width:0px){
  html.mode-rail #view-list-tender .table-wrap th.col-nama-freeze,
  html.mode-rail #view-list-tender .table-wrap td.col-nama-freeze{ min-width:160px }
  html.mode-rail #view-list-tender .table-wrap th.col-bidang,
  html.mode-rail #view-list-tender .table-wrap td.col-bidang{
    width:108px; min-width:108px; max-width:108px }
  html.mode-rail #view-list-tender .table-wrap th.col-penyedia,
  html.mode-rail #view-list-tender .table-wrap td.col-penyedia{
    width:116px; min-width:116px; max-width:116px }
  html.mode-rail #view-list-tender .table-wrap thead th{
    white-space:normal; line-height:1.28 }
}

/* ============================================================================
   27 · TOMBOL "RESET KATA SANDI" DI DIALOG GANTI KATA SANDI   13 Agustus 2026
   ----------------------------------------------------------------------------
   Lebarnya SENGAJA penuh — sepanjang Batal + Simpan digabung. Ia berdiri
   sendiri di bawah kolom sandi, bukan berjejer dengan keduanya: yang ini
   BUKAN penyelesaian dari formulir di atasnya, melainkan jalan lain ketika
   formulir itu tidak bisa diisi (sandi lamanya lupa). Menaruhnya sebaris
   dengan Simpan akan membuatnya terbaca sebagai pilihan ketiga yang setara.
   ============================================================================ */
.cp-reset-btn{
  width:100%; margin-top:14px; justify-content:center;
  border-style:dashed;                 /* garis putus = "hanya bila perlu" */
}
.cp-reset-btn:hover{ border-style:solid }

/* ============================================================================
   28 · "LUPA KATA SANDI?" & POP-UP RESET               13 Agu, ditulis ulang 14
   ============================================================================ */
/* Baris "Ingat saya" + "Lupa kata sandi?" berhadapan pada SATU baris. */
#login-screen .login-baris-ingat{
  display:flex; align-items:center; gap:12px; margin:-2px 0 13px;
}
#login-screen .login-baris-ingat .login-ingat{ margin:0; flex:0 0 auto }

/* ⚠ SELURUH SIFAT TOMBOL DIMATIKAN SATU PER SATU, TIDAK DIANGGAP MEWARISI.
   Versi pertama hanya menyetel warna & ukuran huruf, dan di layar asli ia
   tetap tampil sebagai KOTAK BERGARIS dengan huruf bawaan sistem — sebab
   <button> membawa border, background, padding, dan font-family sendiri yang
   TIDAK diwarisi dari induknya. Karena itu semuanya ditulis tegas di sini,
   dengan #login-screen di depan supaya tidak ada aturan tombol umum yang
   mengalahkannya. */
#login-screen .login-lupa,
.lupa-modal .login-lupa{
  margin-left:auto; flex:0 0 auto;
  appearance:none; -webkit-appearance:none;
  background:none; background-image:none; border:0; box-shadow:none;
  padding:2px 0; cursor:pointer; border-radius:0;
  font-family:'Plus Jakarta Sans',system-ui,sans-serif;
  font-size:12px; font-weight:700; line-height:1.2; letter-spacing:.01em;
  color:var(--teal); text-decoration:none;
  border-bottom:1.5px solid transparent; transition:color .16s ease,border-color .16s ease;
}
#login-screen .login-lupa:hover,
.lupa-modal .login-lupa:hover{ color:var(--teal-dark); border-bottom-color:var(--teal-dark) }
#login-screen .login-lupa:active,
.lupa-modal .login-lupa:active{ transform:translateY(1px) }
#login-screen .login-lupa:focus-visible,
.lupa-modal .login-lupa:focus-visible{ outline:2px solid var(--teal); outline-offset:3px; border-radius:4px }

/* ---- Tombol UTAMA pop-up: TEAL ----
   Riwayatnya tiga langkah, dan langkah terakhir yang benar:
     kuning  -> terbaca sebagai peringatan, bukan ajakan melanjutkan
     biru tua-> terlalu gelap dan mati berdampingan dengan Batal merah
     teal    -> warna aksi utama aplikasi ini

   Teal dipilih bukan karena paling cantik, melainkan karena SUDAH BERARTI
   sesuatu di sini: tombol Masuk, kepala tabel, dan tombol utama di seluruh
   menu memakainya. Orang yang sudah sehari memakai aplikasi ini mengenalinya
   sebagai "tekan ini untuk lanjut" tanpa perlu membaca tulisannya.

   Nama kelasnya tetap .btn-biru supaya tidak perlu menyentuh index.html dan
   app.js hanya untuk mengganti warna. */
.btn.btn-biru{
  background:linear-gradient(135deg,var(--teal),var(--cyan)); color:#fff;
  border:1px solid #0b6b74;
  box-shadow:0 4px 14px rgba(14,124,134,.34), inset 0 1px 0 rgba(255,255,255,.22);
}
.btn.btn-biru:hover{ filter:brightness(1.06); box-shadow:0 8px 22px rgba(14,124,134,.44), inset 0 1px 0 rgba(255,255,255,.28) }
.btn.btn-biru:disabled{ opacity:.55; cursor:default; box-shadow:none; filter:none }

/* Tombol KUNING — masih dipakai di tempat lain; jangan dihapus. */
.btn.btn-yellow{
  background:linear-gradient(180deg,#F6B40E,#e0a200); color:#3a2a00;
  border:1px solid #d79b00; box-shadow:0 3px 10px rgba(224,162,0,.32);
}
.btn.btn-yellow:hover{ filter:brightness(1.04); box-shadow:0 5px 16px rgba(224,162,0,.42) }
.btn.btn-yellow:disabled{ opacity:.55; cursor:default; box-shadow:none }

/* ---- Tombol HIJAU untuk langkah terakhir ----
   Hijau hanya muncul SETELAH kata sandi benar-benar berganti. Sepanjang alur
   tidak ada satu pun tombol hijau, jadi hijau di sini tidak bersaing dengan
   apa pun: ia hanya berarti "sudah selesai, dan berhasil". */
.btn.btn-hijau{
  background:linear-gradient(135deg,#1E9E5A,#157a44); color:#fff;
  border:1px solid #11693a;
  box-shadow:0 4px 14px rgba(30,158,90,.34), inset 0 1px 0 rgba(255,255,255,.2);
}
.btn.btn-hijau:hover{ filter:brightness(1.06); box-shadow:0 8px 22px rgba(30,158,90,.44) }

/* ---- Pop-up yang tidak bisa ditutup dari luar ---- */
.overlay.lupa-ov{ z-index:400 }   /* .login-screen ber-z-index 300 */
@keyframes lupaGoyang{
  0%,100%{ transform:translateX(0) }
  15%{ transform:translateX(-9px) }  30%{ transform:translateX(8px) }
  45%{ transform:translateX(-6px) }  60%{ transform:translateX(5px) }
  75%{ transform:translateX(-3px) }  90%{ transform:translateX(2px) }
}
.lupa-modal.lupa-goyang{ animation:lupaGoyang .5s cubic-bezier(.36,.07,.19,.97) both }
@keyframes lupaDenyut{
  0%,100%{ transform:scale(1);   box-shadow:0 3px 10px rgba(211,58,58,.30) }
  50%    { transform:scale(1.07); box-shadow:0 6px 20px rgba(211,58,58,.55) }
}
#lupa-batal.lupa-denyut{ animation:lupaDenyut .5s ease 2 }

/* ---- Kotak kode: ENAM KOTAK, satu angka per kotak ----
   Menggantikan satu kotak panjang berjarak-huruf (.lupa-kode-in, disimpan di
   bawah untuk pemakaian lain). Yang dikirim WhatsApp tetap "482913" utuh —
   yang dipecah hanya cara mengetiknya di layar.

   Pemisah "–" digambar oleh .otp-pisah, BUKAN oleh border kotak, supaya ia
   tidak ikut menebal saat kotak di sebelahnya sedang difokus. */
.otp-baris{
  display:flex; align-items:center; justify-content:center; gap:2px;
  margin-top:4px;
}
/* !important pada width: .cp-field input memasang width:100% dengan
   kekhususan yang sama, dan aturan itu berada LEBIH DULU di berkas — tanpa
   ini keenam kotak melar memenuhi barisnya. */
.cp-field .otp-baris .otp-sel,
.otp-sel{
  width:46px !important; height:56px; flex:0 0 auto; padding:0 !important;
  text-align:center; font-family:'Plus Jakarta Sans',sans-serif;
  font-size:24px !important; font-weight:800; color:var(--teal-dark);
  font-variant-numeric:tabular-nums;
  border:1.5px solid var(--line); border-radius:12px; background:#fff;
  transition:border-color .16s, box-shadow .16s, transform .16s;
}
.otp-sel:focus{
  outline:none; border-color:var(--teal);
  box-shadow:0 0 0 3px var(--teal-soft), 0 4px 12px rgba(14,124,134,.18);
  transform:translateY(-1px);
}
/* Kotak yang SUDAH terisi diberi latar tipis: dari sudut mata orang langsung
   melihat sudah berapa angka yang masuk tanpa membacanya satu per satu. */
.otp-sel.terisi{ border-color:var(--teal); background:#f6fbfb }
.otp-baris.salah .otp-sel{ border-color:var(--red); background:#fff6f6; color:var(--red) }
.otp-pisah{
  width:9px; height:2px; flex:0 0 auto; border-radius:2px;
  background:var(--line);
}
.otp-baris.salah .otp-pisah{ background:#f0b9b9 }
@media (max-width:400px){
  .otp-sel{ width:38px; height:48px; font-size:20px !important }
  .otp-pisah{ width:5px }
}

/* Kotak kode gaya lama — satu kotak, jarak huruf lebar. Tidak dipakai lagi di
   pop-up ini, disimpan karena masih dirujuk di tempat lain. */
.lupa-kode-in{
  text-align:center; letter-spacing:.55em; text-indent:.55em;
  font-size:22px !important; font-weight:800; font-variant-numeric:tabular-nums;
}
.lupa-timer{
  margin-top:10px; text-align:center; font-size:12px; font-weight:700;
  color:var(--muted); font-variant-numeric:tabular-nums;
}
.lupa-timer.habis{ color:var(--red) }
.lupa-modal .login-lupa.lupa-ulang{ display:block; margin:10px auto 0; margin-left:auto; margin-right:auto }

/* Kata sandi darurat — hanya tampil bila pengiriman WhatsApp GAGAL. */
.lupa-sandi{
  margin-top:12px; padding:12px 14px; border-radius:12px;
  background:#fff8f1; border:1.5px dashed #e0a200;
  font:800 20px/1.3 'Plus Jakarta Sans',monospace; letter-spacing:.12em;
  text-align:center; color:#7a5400; user-select:all;
}

@media (prefers-reduced-motion:reduce){
  .lupa-modal.lupa-goyang{ animation:none }
  #lupa-batal.lupa-denyut{ animation:none; box-shadow:0 0 0 3px rgba(211,58,58,.35) }
}

/* Tombol "Nomor WhatsApp" pada baris Kelola Akun (14 Agu 2026).
   Hijau WhatsApp — satu-satunya tempat warna itu dipakai di aplikasi ini,
   sehingga tombolnya dikenali sebelum dibaca. */
/* Tombol email di Kelola Akun. Semula hijau WhatsApp; diganti teal tema
   14 Agu 2026 saat jalur OTP pindah ke email korporat. Nama kelasnya
   dipertahankan supaya aturan penyembunyian per-peran di atas tetap
   berlaku tanpa perlu diubah di dua tempat. */
.act-wa{ background:linear-gradient(135deg,var(--teal),var(--cyan)); color:#fff }

/* ============================================================================
   29 · MENU "AKUN" — DATA SAYA SENDIRI                       14 Agustus 2026
   ============================================================================ */
.akun-form{ text-align:left }
.akun-form .cp-field{ margin-bottom:12px }
/* Kolom yang TIDAK bisa diubah dibuat terlihat mati sejak pandangan pertama —
   abu, tanpa bingkai fokus. Kotak yang tampak bisa diketik tetapi menolak
   ketikan jauh lebih menjengkelkan daripada kotak yang jelas terkunci. */
.akun-form input[readonly]{
  background:#f2f5f6; color:#5c757b; cursor:default; border-color:#e2e9ea;
}
.akun-form input[readonly]:focus{ box-shadow:none; border-color:#e2e9ea }
.akun-eye{
  position:absolute; right:10px; top:50%; transform:translateY(-50%);
  width:30px; height:30px; border:0; background:none; cursor:pointer;
  color:#8fa3a8; border-radius:8px; display:flex; align-items:center; justify-content:center;
}
.akun-eye:hover{ background:#f2f7f8; color:var(--teal) }
.akun-eye svg{ width:18px; height:18px }
.akun-bungkus{ position:relative }
.akun-bungkus input{ padding-right:44px }
.akun-cat{ font-size:11px; color:var(--muted); margin-top:-6px; margin-bottom:12px; line-height:1.5 }

/* ============================================================================
   30 · POP-UP BERTAHAP: GANTI EMAIL & GANTI KATA SANDI      14 Agustus 2026
   ----------------------------------------------------------------------------
   Keduanya memakai kerangka .lupa-modal yang sama dengan "Lupa kata sandi?" —
   ikon bulat, judul, satu kolom isian, dua tombol. Yang ditambahkan di sini
   hanya dua hal yang belum ada di sana.
   ========================================================================== */

/* Gema alamat: menampilkan kembali apa yang baru saja diketik pada langkah
   sebelumnya. Ada supaya langkah "ulangi" tidak berubah jadi tebak-tebakan —
   orang bisa MEMBANDINGKAN, bukan mengingat. */
.ge-echo{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-top:12px; padding:10px 13px; border-radius:10px;
  background:#f4f8f9; border:1px solid #d6e6e8;
}
.ge-echo span{ font-size:11px; font-weight:700; color:var(--muted); letter-spacing:.2px; flex:0 0 auto }
.ge-echo b{ font-size:12.5px; font-weight:800; color:var(--teal-dark); word-break:break-all; text-align:right }

.lupa-modal .ge-kecil{ font-size:11.5px; color:var(--muted); margin-top:10px }

/* Kotak sandi + tombol mata sebaris. Tombolnya di DALAM kotak supaya lebar
   isiannya sama persis dengan kotak lain di pop-up ini. */
.akun-sandi-baris{ position:relative }
.akun-sandi-baris input{ padding-right:42px !important }
.akun-eye{
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
  width:30px; height:30px; display:flex; align-items:center; justify-content:center;
  border:0; background:transparent; color:var(--muted); cursor:pointer; border-radius:8px;
}
.akun-eye:hover{ color:var(--teal); background:var(--teal-soft) }
.akun-eye svg{ width:17px; height:17px }

/* Enam kotak kode di dalam pop-up ini dipusatkan seperti di layar masuk. */
#ge-overlay .otp-baris{ justify-content:center }

/* ============================================================================
   31 · KEPALA SIDEBAR & TOMBOL KELUAR                       14 Agustus 2026
   ==========================================================================*/

/* ---- NOMOR VERSI PINDAH KE KEPALA SIDEBAR ----
   Dulu ia menggantung di dasar, di bawah tombol Keluar. Dua akibatnya:
   mata harus turun sampai ujung hanya untuk membaca tiga karakter, dan
   tombol Keluar naik-turun setiap kali sidebar menciut karena versi ikut
   menghilang. Di sini ia menempel pada identitas aplikasinya. */
.topbar-brand .brand{ position:relative }
.topbar-brand .brand .side-ver{
  display:block; padding:0; margin-top:3px;
  text-align:right;                 /* kanan bawah tulisan, sesuai permintaan */
  font-size:8.5px; font-weight:800; letter-spacing:1.1px; text-transform:uppercase;
  color:rgba(255,255,255,.42);
  transition:color .16s;
}
.topbar-brand:hover .brand .side-ver{ color:rgba(255,255,255,.66) }

/* Saat sidebar menciut, kepala brand-nya tinggal logo — versinya ikut hilang
   bersama tulisannya, dan itu memang yang diinginkan. */
.sidebar-shell:not(.is-open) .topbar-brand .brand .side-ver{ display:none }
html.mode-rail .sidebar-shell:not(.is-open) .topbar-brand .brand .side-ver{ display:none }

/* ---- TOMBOL KELUAR: TIDAK BERGESER, DAN LEBIH TENANG ----
   Masalahnya: .side-logout memakai `width:auto; align-self:center`, sehingga
   lebarnya mengikuti panjang tulisan. Begitu label "Keluar" disembunyikan
   saat menciut, lebarnya menyusut mendadak dan tombolnya seperti melompat ke
   tengah. Sekarang lebarnya SELALU penuh saat terbuka dan SELALU 46px saat
   menciut — dua keadaan tetap, tidak ada yang dihitung dari panjang teks.

   MERAH PADAT, PILIHAN ANDA — 14 Agu 2026 malam.
   Sempat saya turunkan menjadi kaca tipis agar "lebih elegan". Itu keliru:
   rgba(255,255,255,.07) di atas latar teal praktis TIDAK ADA BEDANYA dengan
   latarnya sendiri, sehingga tombolnya lenyap — terutama saat sidebar
   menciut dan tinggal ikonnya. Elegan tidak ada gunanya kalau tombolnya tidak
   terlihat. Kembali merah, tetapi merah yang lebih lembut daripada versi
   pertama: gradasi tenang dengan bayangan tipis, bukan merah pekat berbayang
   tebal. */
.side-foot .side-logout{
  display:flex; align-items:center; justify-content:center; gap:9px;
  box-sizing:border-box;

  /* ---- UKURAN: TETAP, TIDAK IKUT LEBAR SIDEBAR ----  14 Agu 2026, malam

     Dua keluhan, dan keduanya berakar pada satu baris: `width:100%`.

     (1) "dipaksa melebar hingga memenuhi UI sidebar". Memang. Lebar penuh
         itu warisan dari perbaikan sebelumnya, waktu masalahnya justru
         kebalikannya — lebarnya dulu mengikuti panjang tulisan, jadi ia
         menyusut mendadak saat label "Keluar" disembunyikan. Saya
         menyelesaikannya dengan memakukan lebar penuh. Itu menghentikan
         lompatannya, tetapi menukarnya dengan tombol sepanjang sidebar
         untuk sebuah kata berisi enam huruf.

     (2) "pada mode ciut tombol ini akan bergerak". Ini akibat langsung dari
         (1). Sidebar menciut dalam 0,26 detik; tombolnya berganti dari
         width:100% ke 46px SEKETIKA, tanpa transisi. Selama seperempat
         detik itu tombolnya berukuran salah relatif terhadap kotak yang
         sedang menyusut di sekelilingnya — dan itulah goyangan yang
         terlihat.

     Sekarang lebarnya ANGKA TETAP, bukan persentase. Ia tidak lagi
     bergantung pada lebar sidebar sama sekali, jadi tidak ada yang perlu
     dihitung ulang saat sidebar berubah. Tingginya pun disamakan 44px di
     kedua keadaan — sebelumnya 40px saat terbuka dan 44px saat menciut,
     dan 4px itu membuatnya tersentak naik-turun.

     Perpindahan lebarnya diberi transisi dengan lengkung dan durasi YANG
     SAMA PERSIS dengan sidebar. Keduanya bergerak sebagai satu benda. */
  width:132px; height:38px; align-self:center; padding:0 14px;

  border:1px solid rgba(255,255,255,.22);
  border-radius:12px;
  background:linear-gradient(135deg,#d34a4a,#b83232);
  color:#fff;
  font-family:'Plus Jakarta Sans'; font-size:11px; font-weight:700; letter-spacing:.3px;
  box-shadow:0 3px 11px rgba(120,20,20,.38);
  transition:width .26s cubic-bezier(.16,1,.3,1),
             background .18s, border-color .18s, color .18s, box-shadow .18s;
}
.side-foot .side-logout svg{ width:15px; height:15px; flex:0 0 auto; opacity:1 }
.side-foot .side-logout .side-logout-lbl{ white-space:nowrap }
/* Disentuh: sedikit lebih terang & bayangannya melebar. Bukan berubah warna —
   ia sudah merah; yang berubah cuma isyarat bahwa ia hidup. */
.side-foot .side-logout:hover{
  background:linear-gradient(135deg,#e05555,#c93a3a);
  border-color:rgba(255,255,255,.34);
  color:#fff;
  box-shadow:0 6px 20px rgba(150,26,26,.52);
}
.side-foot .side-logout:hover svg{ opacity:1 }
.side-foot .side-logout:active{ box-shadow:0 2px 8px rgba(150,26,26,.30) }
.side-foot .side-logout:focus-visible{
  outline:none; box-shadow:0 0 0 3px rgba(255,255,255,.28);
}

/* Menciut: LEBARNYA saja yang berubah, dari 150px ke 44px. Tinggi, radius,
   dan warna dibiarkan — makin sedikit yang berubah, makin sedikit yang bisa
   terlihat tersentak. Bentuk akhirnya bujur sangkar 44x44. */
/* ⚠ INILAH SATU-SATUNYA TEMPAT ukuran tombol Keluar saat menciut ditentukan.

   Sebelum hari ini ada ENAM aturan yang memperebutkannya, tersebar di
   berbagai media query dengan angka yang berbeda-beda: 46x44, 34x34, dan
   38x38. Yang menang bergantung pada lebar layar dan urutan berkas — dan
   itulah kenapa tingginya sempat terukur 38px padahal aturan yang saya
   tulis menyebut 44px. Keenamnya sudah dinetralkan; kalau kelak ukurannya
   perlu diubah, ubah DI SINI, dan jangan menambah aturan baru di tempat
   lain. */
.sidebar-shell:not(.is-open) .side-foot .side-logout,
.sidebar-shell:not(.is-open) .side-logout,
html.mode-rail .sidebar-shell:not(.is-open) .side-foot .side-logout,
html.mode-rail .sidebar-shell:not(.is-open) .side-logout{
  width:38px; padding:0; margin:0;
}
.sidebar-shell:not(.is-open) .side-logout svg,
html.mode-rail .sidebar-shell:not(.is-open) .side-logout svg{ width:16px; height:16px }

/* PEMBUNGKUSNYA TETAP `stretch`, DAN INI KELIRU SAYA.

   Saya sempat menulis `align-items:center` di sini untuk memusatkan tombol
   Keluar. Itu memang memusatkannya — tetapi align-items berlaku untuk
   SELURUH anak, dan anak yang satunya adalah kotak "Jenis Akun". Kotak itu
   ikut menyusut ke lebar isinya, jadi ia tidak lagi merentang dari tepi kiri
   ke tepi kanan sidebar.

   Yang dibutuhkan cuma satu anak yang dipusatkan, dan untuk itu ada
   align-self pada anaknya sendiri — sudah dipasang pada .side-logout.
   Memakai align-items berarti mengubah aturan bagi semua demi satu.

   Jarak antar keduanya dinaikkan 8px -> 13px: dengan tombol yang kini lebih
   kecil, 8px membuat keduanya terbaca seperti satu benda yang menempel. */
.side-foot .topbar-user{ align-items:stretch; gap:13px }

@media (prefers-reduced-motion:reduce){
  .side-foot .side-logout{ transition:background .18s, color .18s }
}

/* ---- POP-UP AKUN: LANTAI TINGGI DIBUANG ----   14 Agu 2026, malam

   Lantai 252px dipasang supaya tombol tidak berpindah tempat antar langkah.
   Diukur kembali hari ini, dan alasannya ternyata tidak bertahan:

       Lupa Kata Sandi   211 · 173 ·  78   (tidak pernah punya lantai)
       Ganti Email       256 · 252 · 309   (lantai terlampaui di langkah 3)
       Ganti Kata Sandi  227 · 474 · 100   (selisih 247px)

   Sejak daftar syarat kata sandi ditambahkan, langkah 2 pada Ganti Kata
   Sandi jauh lebih tinggi daripada lantai mana pun yang masuk akal. Lantai
   252 tidak lagi MENYAMAKAN apa-apa — ia hanya membuat langkah yang pendek
   menyeret ruang kosong, sementara tombolnya tetap berpindah karena langkah
   yang tinggi melampauinya. Menaikkan lantainya ke 474 akan lebih buruk
   lagi: langkah pertama yang cuma berisi satu kolom akan berdiri di kartu
   setinggi tiga perempat layar.

   Jadi lantainya dibuang, dan yang disamakan hal yang memang bisa disamakan:
   JARAK. Padding bawah isi dinolkan supaya hanya ada satu sumber jarak, lalu
   jarak isi ke tombol ditetapkan di satu tempat untuk ketiga pop-up. Kartunya
   sekarang setinggi isinya — tidak lebih, tidak kurang.
   ---------------------------------------------------------------------- */
#lupa-overlay .modal-body,
#ge-overlay   .modal-body,
#gs-overlay   .modal-body{ min-height:0; padding-bottom:0 }

/* SATU ANGKA UNTUK SELURUH LANGKAH, termasuk layar "Berhasil". Sebelumnya
   layar terakhir diberi angka sendiri yang lebih rapat; sesudah margin bawah
   dicabut, jaraknya sudah sama dengan sendirinya — jadi pengecualian itu
   tidak diperlukan lagi, dan satu aturan lebih sulit menyimpang daripada
   dua. Terukur: 36-37px dari dasar isi ke puncak tombol di SETIAP langkah,
   pada ketiga pop-up. */
#lupa-modal .modal-actions,
#ge-modal   .modal-actions,
#gs-modal   .modal-actions{ padding-top:14px }

/* Layar tunggu pop-up akun — lihat #ge-l di index.html. */
.ge-muat{
  display:flex; align-items:center; justify-content:center; gap:10px;
  min-height:96px; font-size:12.5px; color:var(--muted); font-weight:600;
}
.ge-spin{
  width:16px; height:16px; border-radius:50%; flex:0 0 auto;
  border:2.2px solid var(--teal-soft); border-top-color:var(--teal);
  animation:geSpin .7s linear infinite;
}
@keyframes geSpin{ to{ transform:rotate(360deg) } }
@media (prefers-reduced-motion:reduce){ .ge-spin{ animation-duration:2.4s } }


/* ---- DAFTAR SYARAT KATA SANDI ----
   Butir yang belum terpenuhi TIDAK dibuat merah. Merah berarti "Anda salah",
   padahal orang yang baru mengetik tiga huruf belum salah apa-apa — ia baru
   belum selesai. Abu-abu netral, lalu hijau saat terpenuhi. */
.syarat{ margin-top:14px; text-align:left }
.syarat-t{ font-size:11.5px; font-weight:700; color:var(--muted); margin-bottom:7px }
.syarat ul{ list-style:none; margin:0; padding:0; display:grid; gap:5px }
.syarat li{
  display:flex; align-items:center; gap:8px;
  font-size:11.5px; line-height:1.45; color:var(--muted);
  transition:color .18s;
}
.syarat-ic{
  width:15px; height:15px; flex:0 0 auto; border-radius:50%;
  background:#dbe3e8; position:relative; transition:background .18s;
}
/* Centangnya digambar CSS, bukan svg — enam butir berarti enam svg yang harus
   diganti isinya satu per satu; dua garis miring jauh lebih murah. */
.syarat-ic::before,.syarat-ic::after{
  content:""; position:absolute; background:#fff; border-radius:1px;
  transform-origin:left center;
}
.syarat-ic::before{ width:4px;  height:1.8px; left:3.4px; top:8px;  transform:rotate(45deg) }
.syarat-ic::after { width:7px;  height:1.8px; left:6px;   top:9.3px; transform:rotate(-52deg) }
.syarat li.ok{ color:var(--teal-dark); font-weight:600 }
.syarat li.ok .syarat-ic{ background:var(--green) }

/* Di panel Buat Akun daftarnya tinggal di dalam sel Kata Sandi. Dua kolom
   supaya lima butir tidak mendorong pemilih Jenis Akun jauh ke bawah, dan
   kembali satu kolom saat selnya menyempit. */
.syarat-ac{ margin:8px 0 0 }
.syarat-ac ul{ grid-template-columns:1fr 1fr; column-gap:14px }
@media (max-width:900px){ .syarat-ac ul{ grid-template-columns:1fr } }
/* Baris kedua panel ini punya margin-atas sendiri; tanpa ini jarak antara
   daftar dan "Jenis Akun" menjadi dua kali lipat. */
.ac-form .ac-row2:first-of-type{ margin-bottom:6px }

/* ---- BARIS GALAT PADA POP-UP AKUN: DIRATAKAN ----
   .login-error memakai align-items:center. Untuk pesan SATU baris itu benar;
   begitu pesannya memanjang jadi dua baris, lingkaran "!" melayang di tengah
   ketinggian kedua baris — tidak sejajar dengan baris mana pun. Ditambah
   teks yang dipusatkan mengikuti isi modal, tepi kirinya jadi bergerigi dan
   lingkarannya terlihat seperti tertinggal sendirian.

   Diperbaiki dengan tiga hal yang harus berjalan bersama:
     * align-items:flex-start  -> lingkaran naik ke baris PERTAMA
     * text-align:left         -> tepi kiri tulisan lurus, satu garis dengan
                                  yang lain, dan lingkarannya punya sesuatu
                                  untuk disejajarkan
     * margin-top pada lingkaran -> tinggi lingkaran (15px) berbeda dengan
                                  tinggi baris teks, jadi "sejajar" perlu
                                  digeser sedikit; tanpa ini ia duduk agak
                                  terlalu tinggi. */
#lupa-error, #ge-error, #gs-error{
  align-items:flex-start;
  text-align:left;
  line-height:1.55;
  gap:8px;
}
#lupa-error:not(:empty)::before,
#ge-error:not(:empty)::before,
#gs-error:not(:empty)::before{ margin-top:1.5px }

/* ---- LAYAR TERAKHIR BOLEH MENYUSUT ----
   #ge-overlay/.gs-overlay .modal-body punya lantai 252px supaya tombol tidak
   berpindah tempat saat orangnya bolak-balik antar langkah. Pada layar
   "Berhasil" isinya tinggal dua baris, dan lantai itu berubah fungsi: dari
   penjaga posisi tombol menjadi sejengkal ruang kosong yang menganggur.

   Lantainya dilepas HANYA di layar itu — di sana tidak ada yang perlu
   dijaga, karena tidak ada langkah sesudahnya. Jaraknya ke tombol diatur
   sendiri (22px), bukan dibiarkan menjadi sisa perhitungan. */
#lupa-modal.hal-akhir .modal-body,
#ge-modal.hal-akhir   .modal-body,
#gs-modal.hal-akhir   .modal-body{ min-height:0; padding-bottom:0 }

/* Jaraknya ke tombol DIUKUR, bukan disisakan. Dengan lantai tinggi dilepas,
   sisa jarak datang dari dua tempat: padding bawah isi dan padding atas baris
   tombol. Padding bawah dinolkan supaya hanya ada SATU sumber jarak, lalu
   padding atas baris tombol yang diatur — 14px menghasilkan 34px terukur dari
   dasar kalimat sampai puncak tombol. Cukup lapang untuk tidak terlihat
   berdesakan, cukup rapat untuk terbaca sebagai satu kesatuan. */
/* (Pengecualian hal-akhir untuk baris tombol DIHAPUS — angkanya kini sama.
   Kelas .hal-akhir tetap dipakai untuk melepas lantai tinggi.) */

/* ---- JARAK ISI KE TOMBOL: SATU ANGKA UNTUK SEMUA POP-UP ----  14 Agu 2026
   Diukur sebelum perbaikan ini: 47, 46, 42, 36 px — berbeda-beda menurut
   unsur apa yang kebetulan berada paling bawah pada tiap langkah (kolom
   isian, keterangan kecil, atau daftar syarat), karena masing-masing membawa
   margin bawahnya sendiri.

   Margin bawah unsur TERAKHIR di tiap langkah dinolkan, sehingga jaraknya
   tidak lagi ditentukan oleh isi yang kebetulan ada di sana, melainkan oleh
   satu angka: padding atas baris tombol. Ubah angka itu, seluruh pop-up ikut
   berubah bersama-sama. */
#lupa-modal .modal-body > div > :last-child,
#ge-modal   .modal-body > div > :last-child,
#gs-modal   .modal-body > div > :last-child{ margin-bottom:0 }

/* Aturan di atas saja belum cukup: pada langkah kode, unsur terakhir dalam
   susunan HTML adalah tautan "Kirim ulang kode" yang SEDANG DISEMBUNYIKAN.
   Margin yang dinolkan jatuh ke unsur tersembunyi itu, sementara kolom di
   atasnya tetap membawa margin bawahnya — dan jaraknya jadi 3px lebih besar
   daripada langkah lain. CSS tidak bisa memilih "anak terakhir yang
   terlihat", jadi sumber selisihnya yang dicabut: jarak antar-unsur di dalam
   pop-up ini seluruhnya diatur oleh margin ATAS, tidak ada satu pun yang
   mendorong dari bawah. */
#lupa-modal .cp-field,
#ge-modal   .cp-field,
#gs-modal   .cp-field{ margin-bottom:0 }


/* =========================================================================
   KOTAK ISIAN DUA BAGIAN                                  15 Agustus 2026
   -------------------------------------------------------------------------
   Dipakai kotak-satuan.js. Bentuknya: satu kotak yang dibagi dua —
   bagian depan diketik, bagian belakang satuan yang tetap.

       [ 3          | Referensi     ]
       [ 60         | Hari Kalender ]

   YANG BERGARIS DAN MENYALA ADALAH PEMBUNGKUSNYA, bukan input di dalamnya.
   Kalau bordernya tetap milik input, dua bagian itu akan terbaca sebagai dua
   kotak yang kebetulan bersebelahan — bukan satu kotak yang dibagi.
   ========================================================================= */
.ks-kk{
  display:flex; align-items:stretch; width:100%;
  /* Disalin dari aturan .field input di bagian 15 supaya kotak ini berdiri
     sejajar dengan kotak isian lain di form yang sama. */
  border:1px solid #cdd9de; border-radius:11px;
  background:linear-gradient(180deg,#ffffff,#fafdfe);
  box-shadow:0 1px 2px rgba(16,40,50,.06), inset 0 1px 0 rgba(255,255,255,.6);
  overflow:hidden;
  transition:transform .28s cubic-bezier(.16,1,.3,1),
             box-shadow .3s cubic-bezier(.16,1,.3,1),
             border-color .25s ease, background-color .25s ease;
}
.ks-kk:hover{ border-color:#a7bec5;
  box-shadow:0 2px 7px rgba(16,40,50,.09), inset 0 1px 0 rgba(255,255,255,.6) }

/* Fokus diteruskan dari input ke pembungkus. Tanpa :focus-within, cincin
   fokusnya hanya melingkari setengah kotak — dan setengah kotak yang menyala
   terbaca sebagai kerusakan, bukan sebagai fokus. */
.ks-kk:focus-within{
  border-color:var(--teal,#0E7C86);
  box-shadow:0 0 0 3px rgba(14,124,134,.16), 0 4px 12px rgba(14,124,134,.16);
  background:#fff;
  transform:translateY(-1px);
}

/* Bagian depan: tempat mengetik. */
.ks-kk .ks-isi{
  flex:1 1 auto; min-width:0; width:auto;
  border:0; outline:0; background:transparent;
  padding:10px 12px; margin:0;
  font-family:inherit; font-size:12.5px; font-weight:700; color:#0b3d43;
  /* Angka berlebar sama: saat nilainya berganti 9 -> 10 -> 100, lebar
     angkanya tidak ikut berdenyut. */
  font-variant-numeric:tabular-nums;
}
.ks-kk .ks-isi::placeholder{ color:#9fb0b6; font-weight:500 }

/* ⚠ CINCIN FOKUS GANDA — kotak ini berada DI DALAM .field, jadi aturan
   `.field input:focus` (bagian 15) dan `.field input:focus` (bagian 33,
   yang mengangkat 1px) ikut mengenainya. Akibatnya ada DUA cincin saat
   difokus: satu milik pembungkus, satu lagi melingkari setengah kotak di
   dalamnya. !important di sini menjawab aturan yang memang sudah ada. */
.ks-kk .ks-isi:focus,
.field .ks-kk .ks-isi:focus,
.filter-field .ks-kk .ks-isi:focus{
  box-shadow:none !important;
  transform:none !important;
  border:0 !important;
  background:transparent !important;
}
/* Panah naik-turun bawaan peramban: kotaknya type="text" jadi sebenarnya
   tidak muncul; aturan ini jaring bila kelak ada yang mengembalikannya. */
.ks-kk .ks-isi::-webkit-outer-spin-button,
.ks-kk .ks-isi::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0 }

/* Sekat: garis tipis, bukan blok warna. Ia hanya perlu mengatakan "sampai di
   sini yang Anda ketik"; apa pun yang lebih tebal bersaing dengan angkanya. */
.ks-sekat{ width:1px; background:#e2ebed; flex:0 0 auto }

/* Bagian belakang: satuan yang tetap.
   user-select:none supaya menyeret dari angka ke kanan tidak ikut menyorot
   satuannya — yang lalu ikut tersalin saat disalin. */
.ks-akhir{
  flex:0 0 auto; display:flex; align-items:center;
  padding:0 13px; background:#f4f8f9;
  font-family:'Plus Jakarta Sans',sans-serif;
  font-size:11.5px; font-weight:700; letter-spacing:.2px; color:#5b7376;
  user-select:none; -webkit-user-select:none; cursor:text;
  white-space:nowrap;
}
.ks-akhir span{ pointer-events:none }

.ks-kk.ks-mati{ background:#f5f8f9; opacity:.75 }
.ks-kk.ks-mati .ks-isi{ color:#7d9296 }
.ks-kk.ks-mati .ks-akhir{ background:#eef3f4 }

@media(max-width:640px){
  .ks-akhir{ padding:0 10px; font-size:10.5px }
  .ks-kk .ks-isi{ font-size:12px }
}

/* ============================================================================
   TAMBALAN iOS — PINTASAN LAYAR UTAMA (standalone)        15 Agustus 2026
   ----------------------------------------------------------------------------
   LETAKNYA DI SINI, DI BARIS PALING BAWAH, dan memang disengaja: blok ini
   MENUMPUK di akhir berkas, bukan menyunting aturan yang sudah ada.
   .side-logout dan .sidebar-shell punya belasan aturan bertingkat yang saling
   menimpa, dan menyentuhnya di tengah berkas berisiko membangunkan masalah
   lain. Kalau hasilnya tidak disukai, hapus blok ini
   dan tidak ada jejak yang tertinggal.

   DUA GEJALA YANG DIOBATI

   1. BILAH JAM & BATERAI iPad TERTUTUP TAMPILAN
      index.html:62 memasang
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
      Artinya iOS SENGAJA menaruh halaman web DI BAWAH bilah status — memang
      itu gunanya 'black-translucent'. Halaman lalu wajib menyisihkan sendiri
      ruang setinggi env(safe-area-inset-top) supaya isinya tidak menimpa jam.

      Di style.css, env(safe-area-inset-top) hanya dipakai .login-screen
      (baris 10342) dan .pn-preview-modal .detail-head. .sidebar-shell dan
      .topbar tidak pernah mendapatkannya — jadi begitu layar login lewat,
      seluruh aplikasi naik menutupi jam.

   2. GARIS PUTIH DI BAWAH, SIDEBAR TIDAK SAMPAI DASAR
      .sidebar-shell (baris 7585) berbunyi:
        position:fixed; top:0; left:0; bottom:0;
        width:var(--side-rail); height:100vh;
      `top`, `bottom`, DAN `height` diisi bersamaan. Aturan CSS: bila top dan
      height keduanya ada, `bottom` DIABAIKAN. Tingginya jadi dikunci 100vh —
      dan di aplikasi standalone iOS, 100vh tidak selalu sama dengan tinggi
      layar yang benar-benar terlihat. Selisihnya itulah yang tampak putih,
      karena yang menyembul di baliknya adalah latar <body>.

      Membuang `height` mengembalikan pasangan top:0 + bottom:0, yang
      meregang mengikuti viewport yang sesungguhnya — berapa pun tingginya,
      di perangkat apa pun, tanpa perlu satuan vh sama sekali.
   ============================================================================ */

/* ---- 1. Sidebar meregang ke viewport nyata, bukan dikunci 100vh ---- */
.sidebar-shell{
  height:auto;                     /* melepas kuncian 100vh di baris 7587 */
  top:0; bottom:0;                 /* dua ini yang kini menentukan tingginya */
}

/* ---- 2. Ruang aman atas & bawah ----
   padding, BUKAN margin: latar gradien sidebar tetap terlukis penuh sampai
   tepi layar, hanya ISINYA yang bergeser masuk. Kalau memakai margin, akan
   muncul garis kosong di atas dan di bawah sidebar — persis masalah yang
   sedang kita obati, cuma berpindah tempat.
   Di perangkat tanpa takik nilainya 0, jadi tampilan desktop tidak berubah
   sedikit pun. */
.sidebar-shell{
  padding-top:env(safe-area-inset-top);
  padding-bottom:env(safe-area-inset-bottom);
  box-sizing:border-box;
}

/* ---- 3. Topbar (tata letak sempit/tablet) juga turun di bawah jam ---- */
.topbar{
  padding-top:env(safe-area-inset-top);
}

/* ---- 4. Latar gelap sebagai jaring pengaman ----
   Bila masih tersisa secuil ruang yang tidak tertutupi — saat memantul
   overscroll, atau saat papan ketik muncul lalu pergi — yang menyembul kini
   berwarna gelap senada sidebar, bukan putih menyilaukan. Ini penambal
   terakhir, bukan pengganti tiga aturan di atas. */
html{ background:var(--side-1); }
body{ background:var(--side-1); }

/* ---- 5. Isi utama tidak ikut tertutup ----
   .app-main duduk di sebelah kanan sidebar dan punya penggulung sendiri. */
.app-main{
  padding-bottom:env(safe-area-inset-bottom);
}

/* ============================================================================
   32 · TAMPILAN APLIKASI TERPASANG (iOS/iPadOS) & TOMBOL KELUAR DI LACI
   16 Agustus 2026
   ----------------------------------------------------------------------------
   Bagian ini DITEMPELKAN DI PALING BAWAH style.css dan sengaja begitu: tiga
   gejala di bawah semuanya berupa aturan lama yang menang karena urutan atau
   spesifisitas, jadi penawarnya harus berada sesudah mereka.

   Tidak ada satu pun baris lama yang perlu dihapus.
   ==========================================================================*/


/* ============================================================================
   32.1 · JAM & BATERAI iPad MENEMPEL PADA HALAMAN
   ----------------------------------------------------------------------------
   Bagian 31 sudah mencoba mengobati ini, tetapi menyasar dua elemen yang
   keliru, jadi efeknya nol untuk isi halaman:

     * baris 12898  .sidebar-shell{padding-top:env(safe-area-inset-top)}
       BENAR, dan memang bekerja — rail kiri sudah turun di bawah jam.

     * baris 12905  .topbar{padding-top:env(safe-area-inset-top)}
       MATI. Kelas `.topbar` tidak ada di index.html; yang ada `.topbar-inner`,
       `.topbar-brand`, `.topbar-user` — ketiganya di DALAM sidebar. Bilah atas
       yang sebenarnya bernama `.appbar` (index.html baris 1030).

   Dan di iPad, `.appbar` pun bukan jawabannya, sebab baris 8613 berbunyi:

       html.mode-rail .appbar{display:none}

   iPad selalu masuk mode-rail (skrip di index.html baris 246-330), jadi bilah
   atasnya memang tidak ada. Elemen teratas di kolom kanan adalah `.wrap`, dan
   `.wrap` hanya pernah diberi safe-area KIRI dan KANAN (baris 8654-8655),
   tidak pernah ATAS. Karena itu kartu "Dashboard Pengadaan" naik sampai ke
   belakang jam.

   Dua hal dikerjakan di sini:
     a. isi halaman diturunkan setinggi safe-area;
     b. area jamnya DICAT gelap senada sidebar, supaya ada pemisah yang jelas —
        bukan sekadar ruang kosong yang mengambil warna kartu di bawahnya.

   Semuanya dikurung `display-mode:standalone`, jadi HANYA berlaku saat dibuka
   dari pintasan layar utama. Di Safari biasa dan di desktop, nilai
   env(safe-area-inset-top) tetap 0 dan tidak ada yang berubah sedikit pun.
   ==========================================================================*/

@media all and (display-mode:standalone){

  /* --- a. Pita gelap di belakang jam ---
     position:fixed supaya ia tidak ikut tergulir; z-index 200 supaya berada di
     atas sidebar (70/90) dan appbar (55). Tingginya persis safe-area, jadi di
     perangkat tanpa takik ia setinggi 0 px dan tak terlihat sama sekali.
     pointer-events:none supaya tidak pernah memakan sentuhan. */
  body::before{
    content:"";
    position:fixed; top:0; left:0; right:0;
    height:env(safe-area-inset-top);
    background:var(--side-1);
    z-index:200;
    pointer-events:none;
  }

  /* --- b1. iPad (mode rail, tanpa appbar): isi halaman turun ---
     24px adalah padding bawaan .wrap (baris 79); safe-area DITAMBAHKAN,
     bukan menggantikan, supaya jarak nyaman aslinya tidak hilang. */
  html.mode-rail .wrap{
    padding-top:calc(24px + env(safe-area-inset-top));
  }

  /* --- b2. Ponsel & tata letak sempit (appbar tampil): appbar yang turun ---
     .appbar sticky top:0, jadi dialah yang menyentuh jam. Tinggi minimumnya
     ikut ditambah, kalau tidak isinya berdesakan di sisa ruang. */
  html:not(.mode-rail) .appbar{
    padding-top:calc(9px + env(safe-area-inset-top));
    min-height:calc(52px + env(safe-area-inset-top));
  }

  /* Layar Masuk sudah punya safe-area sendiri (baris 10342). Tanpa
     pengecualian ini jaraknya jadi dua kali lipat. */
  .login-screen{ padding-top:calc(24px + env(safe-area-inset-top)) }
}


/* ============================================================================
   32.2 · DASAR LAYAR: ISI TERPOTONG & CELAH PUTIH
   ----------------------------------------------------------------------------
   Dua sebab yang menumpuk:

   1. `.app-shell{min-height:100vh}` (baris 7576 & 1299). Di aplikasi
      terpasang, 100vh dihitung dari tinggi layar UTUH — termasuk pita
      home-indicator yang tidak boleh diisi. Kerangkanya jadi sedikit lebih
      tinggi daripada yang benar-benar terlihat, dan selisih itu memotong
      baris terakhir. 100svh ("small viewport height") adalah nilai yang
      dijamin TIDAK PERNAH melebihi area terlihat.

   2. Jaring pengaman gelap di baris 12914 kalah spesifisitas:

          html body{background:...gradien terang...}   baris 5675  (0,0,0,2)
          body     {background:var(--side-1)}          baris 12914 (0,0,0,1)

      Urutan berkas tidak menolong kalau spesifisitasnya kalah. Jadi yang
      menyembul di celah bawah tetap gradien terang — itulah "bagian putih"
      yang terlihat. Di sini ditulis ulang dengan bobot yang cukup, dan hanya
      background-COLOR-nya, supaya gradien halaman di dalam body tidak ikut
      berubah.
   ==========================================================================*/

@supports (height:100svh){
  .app-shell{ min-height:100svh }
}

html,
html body{
  background-color:var(--side-1);
}

@media all and (display-mode:standalone){
  /* Ruang bawah untuk home-indicator. Ditambahkan pada .wrap di KEDUA tata
     letak; di mode rail aturan baris 7998 memang sudah memberinya, tetapi
     ditulis ulang di sini supaya tidak bergantung pada media query yang bisa
     berubah kelak. */
  .wrap,
  html.mode-rail .wrap{
    padding-bottom:calc(24px + env(safe-area-inset-bottom));
  }
}


/* ============================================================================
   32.3 · TOMBOL "KELUAR" BERANTAKAN DI LACI ANDROID / PONSEL
   ----------------------------------------------------------------------------
   INI YANG PALING PENTING, dan sebabnya bisa ditunjuk tepat.

   Aturan bagian 31 baris 12560-12565:

       .sidebar-shell:not(.is-open) .side-logout{ width:38px; padding:0 }

   TIDAK dikurung media query apa pun. Ia berlaku di mana saja selama
   `.sidebar-shell` tidak berkelas `is-open`.

   Sementara itu, laci ponsel TIDAK memakai `is-open` sama sekali. Lihat
   baris 7800-7803:

       .sidebar-shell,.sidebar-shell.is-open{transform:translateX(-100%)}
       body.nav-open .sidebar-shell{transform:none}

   Yang membuka laci adalah `body.nav-open`; `is-open` di sana justru disamakan
   dengan keadaan tertutup — ia memang milik rail desktop/tablet, bukan laci.

   Akibatnya, SELAMA LACI PONSEL TERBUKA, `.sidebar-shell` tetap tanpa
   `is-open`, dan tombol Keluar dipaksa selebar 38px. Padahal dua aturan yang
   seharusnya menemaninya — yang menyembunyikan label "Keluar" — dikurung
   gerbang yang sama sekali berbeda:

       baris 7767  di dalam @media (hover:hover) and (min-width:1025px)
       baris 8642  digerbangi kelas html.mode-rail

   Keduanya TIDAK berlaku di ponsel. Jadi kotaknya menyusut jadi 38px sementara
   isinya tetap ikon + tulisan "Keluar" (±62px). Karena `justify-content:center`,
   kelebihannya meluber SEIMBANG KE DUA SISI: ikon menyembul keluar di kiri,
   tulisan menyembul keluar di kanan, dan kotak merahnya tertinggal di tengah.
   Persis yang terlihat di layar.

   Komentar di baris 7742-7744 mencatat kebocoran yang sama pernah terjadi dan
   sudah ditambal untuk aturan-aturan rail lainnya — aturan bagian 31 ini
   ditulis belakangan dan luput dari tambalan itu.

   Penawarnya: kembalikan ukuran penuh KHUSUS di tata letak laci — yaitu saat
   perangkatnya sentuh/sempit DAN bukan mode-rail. Rail desktop (>=1025px
   berkursor) dan rail tablet (html.mode-rail) tidak disentuh sedikit pun,
   jadi penciutan 38px di sana tetap berlaku seperti rancangan bagian 31.
   ==========================================================================*/

@media (max-width:1024px), (hover:none), (any-pointer:coarse){

  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-foot .side-logout,
  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-logout{
    width:132px;
    height:38px;
    padding:0 14px;
    margin:0;
    align-self:center;
  }
  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-logout svg{
    width:15px; height:15px;
  }
  /* Label & kotak "Jenis Akun" memang harus tetap tampil di laci — ditegaskan
     di sini supaya kalau kelak ada aturan penciut baru yang bocor lagi, yang
     ini sudah lebih dulu berdiri. */
  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-logout-lbl{ display:inline }
  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-acct{ display:flex }
  html:not(.mode-rail) .sidebar-shell:not(.is-open) .side-foot{ padding:10px 12px 12px }
}

/* Kaki laci ikut menyisihkan ruang home-indicator saat terpasang di layar
   utama — sidebar sudah mendapatkannya di baris 12899, tetapi hanya lewat
   padding-bottom milik shell; kaki bagian dalamnya diberi jarak sendiri
   supaya tombol Keluar tidak duduk tepat di garis usap. */
@media all and (display-mode:standalone){
  html:not(.mode-rail) .side-foot{
    padding-bottom:calc(12px + env(safe-area-inset-bottom));
  }
}


/* ============================================================================
   33 · PENGAMAN LAYAR MASUK                                 16 Agustus 2026
   ----------------------------------------------------------------------------
   Baris 11293 memberi .login-screen tinggi dari var(--vvh) — nilai yang
   ditulis app.js frame demi frame dari window.visualViewport. Bila nilainya
   sesaat jauh lebih kecil daripada layar, lapisan login ikut menciut dan isi
   di belakangnya menyembul: "dashboard bocor sebelum masuk".

   Lantai 360px menghentikan kasus ekstremnya tanpa mengganggu penyusutan
   wajar saat papan ketik muncul (papan ketik tidak pernah menyisakan ruang
   sesempit itu).

   ⚠ INI PENGAMAN, BUKAN OBAT. Sebab utamanya ada di app.js: kelas
   `layar-masuk` — yang seharusnya menyembunyikan .app-shell dan mengunci gulir
   (lihat baris 10324-10326) — tidak selalu terpasang saat layar login tampil.
   Selama itu belum diperbaiki di syncLayarMasukKelas(), aturan di bawah hanya
   memperkecil peluang bocornya, tidak menutupnya.
   ==========================================================================*/
.login-screen{ height:max(var(--vvh, 100dvh), 360px) }


/* ============================================================================
   34 · PITA BAWAH: SISA PUTIH DI AREA HOME-INDICATOR        16 Agustus 2026
   ----------------------------------------------------------------------------
   Bagian 32.1 memasang pita di ATAS dan itu berhasil — jam & baterai sekarang
   duduk di atas warna gelap, terpisah dari halaman. Bawahnya belum diperlakukan
   sama, dan di situlah sisa putih itu.

   Kenapa muncul: dengan `viewport-fit=cover`, halaman memang MEMANJANG sampai
   ke bawah garis usap (home indicator). Tetapi yang mengisi jalur setinggi
   env(safe-area-inset-bottom) itu bukan sidebar dan bukan kartu — melainkan
   apa pun yang kebetulan tergambar paling belakang. Karena tidak ada yang
   ditugaskan mengecatnya, yang tampak adalah warna terang halaman, dan
   sidebar terlihat seperti berhenti sebelum tepi layar.

   Penawarnya kembar dengan pita atas: satu jalur position:fixed di dasar
   layar, setinggi safe-area, yang MENERUSKAN warna di atasnya — bukan satu
   warna rata. Itu sebabnya latarnya berupa gradien mendatar dua bagian:

       0 .. var(--side-rail)   warna dasar gradien sidebar  (var(--side-3))
       var(--side-rail) .. 100% warna dasar halaman         (#e8edf0)

   Dengan begitu jalur itu tidak terbaca sebagai pita tambahan, melainkan
   sebagai lanjutan dari sidebar dan halaman yang sudah ada di atasnya.

   Hanya berlaku saat dibuka dari pintasan layar utama; di Safari biasa dan di
   desktop nilai env-nya 0 sehingga tingginya 0 dan tidak ada yang berubah.
   ==========================================================================*/

@media all and (display-mode:standalone){

  /* --- Tata letak rail (iPad): dua bagian, mengikuti lebar rail --- */
  html.mode-rail body::after{
    content:"";
    position:fixed; left:0; right:0; bottom:0;
    height:env(safe-area-inset-bottom);
    background:linear-gradient(to right,
      var(--side-3) 0,
      var(--side-3) var(--side-rail),
      #e8edf0       var(--side-rail),
      #e8edf0       100%);
    z-index:200;
    pointer-events:none;
  }

  /* --- Tata letak laci (ponsel): sidebar tidak menempel di layar, jadi
         seluruh jalur memakai warna halaman saja. --- */
  html:not(.mode-rail) body::after{
    content:"";
    position:fixed; left:0; right:0; bottom:0;
    height:env(safe-area-inset-bottom);
    background:#e8edf0;
    z-index:200;
    pointer-events:none;
  }

  /* --- Sidebar ditegaskan meregang sampai tepi bawah layar ---
     Bagian 31 baris 12885 sudah melepas kuncian height:100vh, tetapi baris
     8602 (html.mode-rail) masih menuliskannya dengan bobot selektor yang lebih
     berat. Di sini ditegaskan ulang dengan bobot yang cukup, memakai pasangan
     top:0 + bottom:0 yang nilainya tidak pernah bergantung pada satuan vh. */
  html.mode-rail .sidebar-shell,
  html.mode-rail .sidebar-shell.is-open{
    top:0; bottom:0; height:auto;
  }

  /* Isi kaki sidebar tetap di atas garis usap — padding, bukan margin, supaya
     gradiennya tetap terlukis penuh sampai tepi. */
  .sidebar-shell{
    padding-bottom:env(safe-area-inset-bottom);
    box-sizing:border-box;
  }
}


/* ============================================================================
   35 · PITA TERANG DI DASAR LAYAR — SATUAN TINGGINYA YANG KELIRU
   16 Agustus 2026
   ----------------------------------------------------------------------------
   KEKELIRUAN SAYA SENDIRI, DI BAGIAN 32.2.

   Di sana .app-shell saya beri `min-height:100svh` dengan alasan "svh dijamin
   tidak pernah melebihi area terlihat". Kalimat itu benar, tetapi justru
   itulah yang salah untuk elemen ini.

   Ketiga satuan viewport berbeda arti:

       svh   tinggi layar saat bilah peramban SEDANG TAMPIL   (paling PENDEK)
       lvh   tinggi layar saat bilah peramban tersembunyi     (paling PANJANG)
       dvh   tinggi yang BENAR-BENAR terlihat saat ini        (mengikuti)

   .app-shell adalah kerangka yang tugasnya MENGISI layar. Untuk pengisi,
   satuan terpendek adalah pilihan terburuk: begitu bilah Safari menyusut atau
   tidak ada sama sekali, kerangkanya berhenti lebih tinggi daripada dasar
   layar — dan yang menyembul di bawahnya adalah gradien terang milik <body>.
   Persis pita terang yang terlihat. svh tepat untuk lapisan yang harus MUAT
   di dalam layar (mis. pop-up), bukan untuk yang harus MENUTUPI layar.

   Sekarang dipakai dvh, yang mengikuti tinggi terlihat frame demi frame, dengan
   100vh sebagai cadangan bagi peramban yang belum mengenalnya.
   ==========================================================================*/
.app-shell{ min-height:100vh }
@supports (height:100dvh){
  .app-shell{ min-height:100dvh }
}

/* ---- Sidebar meregang penuh DI SEMUA KEADAAN ----
   Bagian 34 sudah menegaskannya, tetapi terkurung di dalam
   @media (display-mode:standalone) — jadi di Safari biasa aturan baris 8602
   (height:100vh) tetap menang dan railnya berhenti sebelum tepi bawah.
   Pasangan top:0 + bottom:0 tidak bergantung pada satuan vh mana pun, jadi ia
   benar di kedua keadaan. */
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  top:0; bottom:0; height:auto;
}

/* ---- Jaring pengaman warna, tanpa kurungan display-mode ----
   Bila masih tersisa secuil ruang yang tidak tertutupi siapa pun, yang
   menyembul gelap senada sidebar, bukan terang. Ditulis dengan bobot `html
   body` supaya menang atas gradien terang di baris 5675 — bobot itulah yang
   kurang pada percobaan di baris 12914. */
html,
html body{ background-color:var(--side-1) }


/* ==========================================================================
   27. TITIK MULAI JADWAL — DUA ISIAN YANG SEJAJAR, BUKAN BERTUMPUK
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: "di Tentukan Jadwal, Tanggal Mulai dan Jam Mulai seperti bertumpuk
   dan tidak rapi."

   Barisnya selama ini flex: `.jp-start-row{display:flex;flex-wrap:wrap;gap:12px
   18px}` dengan `.jp-start-field{flex:0 1 210px;min-width:150px}`. Di mesin
   Blink hasilnya tepat 210 + 18 + 210. Tetapi lebar itu ditentukan oleh
   flex-basis yang MASIH BISA DIDORONG oleh lebar bawaan isinya: <input
   type="date"> dan <input type="time"> di iOS bukan kotak teks biasa
   melainkan kontrol bawaan sistem yang punya lebar minimum sendiri, dan
   min-width:150px hanya menetapkan lantai — bukan langit-langit. Begitu lebar
   bawaan kontrolnya melewati 210px, kedua kotak melar, jaraknya termakan, dan
   keduanya terbaca sebagai satu blok bertumpuk.

   Dua hal diperbaiki sekaligus:

   a) MEKANISMENYA DIGANTI KE GRID. Jalur grid dengan minmax(0,...) adalah satu-
      satunya cara menyatakan "selebar ini, TITIK" — ia tidak bisa didorong
      melar oleh lebar bawaan isinya, tidak di mesin mana pun. Jarak antar
      jalur pun dijamin: column-gap pada grid tidak pernah bisa dimakan isi.

   b) ANGKANYA DISELARASKAN DENGAN KISI DI ATASNYA. Dulu 210px + jarak 18px,
      sementara Data Pekerjaan tepat di atasnya memakai 4 kolom berjarak 30px
      (± 258px per isian). Dua irama berbeda dalam satu kartu — itulah "tidak
      rapi" yang kedua. Sekarang keduanya memakai 258px + jarak 30px, jadi
      Tanggal Mulai berdiri tepat di bawah Nama Pekerjaan dan Jam Mulai di
      bawah Lokasi Pekerjaan.

   Jalur ketiga `1fr` menampung sisa ruang supaya kedua isian tetap rata kiri
   dan tidak ikut melar saat kartunya melebar.
   ========================================================================== */
.jp-start-row{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,258px)) 1fr;
  column-gap:30px; row-gap:12px;
  align-items:end;
}
/* Judul baris & teks petunjuk tetap selebar penuh, seperti sebelumnya. */
.jp-start-row > .jp-start-lead,
.jp-start-row > .jp-start-hint{ grid-column:1 / -1 }
/* min-width:150px milik aturan lama harus dilepas: di dalam jalur grid ia
   justru menghidupkan kembali dorongan yang baru saja dimatikan. */
.jp-start-field{ min-width:0 }
.jp-start-field input{ width:100%; min-width:0 }

/* Layar sempit (ponsel potret): satu isian per baris, seperti sebelumnya. */
@media(max-width:640px){
  .jp-start-row{ grid-template-columns:1fr; column-gap:0 }
}


/* ==========================================================================
   28. JALUR AMAN BAWAH DILUKIS TANPA SYARAT               16 Agustus 2026
   --------------------------------------------------------------------------
   Bagian 33 memasang jalur pengisi di dasar layar, tetapi mengurungnya di
   dalam `@media all and (display-mode:standalone)`. Kurungan itu tidak
   dibutuhkan dan menambah satu titik gagal: tingginya sudah
   env(safe-area-inset-bottom), yang bernilai 0 di Safari biasa dan di desktop
   — jadi di luar mode layar utama aturan ini memang sudah tidak menggambar
   apa pun dengan sendirinya. Bila karena satu dan lain hal peramban tidak
   melaporkan display-mode standalone (mis. pintasan dibuka lewat jalur yang
   berbeda), aturan lamanya diam total dan pita terang itu muncul kembali.

   Ditulis ulang di sini tanpa kurungan, dengan isi yang sama persis. Aturan
   lama dibiarkan di tempatnya — keduanya identik, jadi mana pun yang menang
   hasilnya sama.

   CATATAN JUJUR: ini BUKAN pengganti pengukuran. Bila pitanya masih ada
   sesudah ini, artinya jalurnya berada DI LUAR kotak tata letak halaman dan
   tidak ada satu pun aturan CSS yang bisa menjangkaunya. Yang menjawabnya
   hanya pengukur di index.html (lihat "PENGUKUR TINGGI LAYAR").
   ========================================================================== */
html.mode-rail body::after{
  content:"";
  position:fixed; left:0; right:0; bottom:0;
  height:env(safe-area-inset-bottom, 0px);
  /* --lebar-sidebar-nyata, BUKAN --side-rail. Lihat bagian 33. */
  background:linear-gradient(to right,
    var(--side-3) 0,
    var(--side-3) var(--lebar-sidebar-nyata, var(--side-rail)),
    #e8edf0       var(--lebar-sidebar-nyata, var(--side-rail)),
    #e8edf0       100%);
  z-index:200;
  pointer-events:none;
}
html:not(.mode-rail) body::after{
  content:"";
  position:fixed; left:0; right:0; bottom:0;
  height:env(safe-area-inset-bottom, 0px);
  background:#e8edf0;
  z-index:200;
  pointer-events:none;
}


/* ==========================================================================
   29. POTONGAN PUTIH DI DASAR LAYAR — DIUKUR, BUKAN DITEBAK
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN (dengan tangkapan layar): "ada potongan putih di bawah yang membuat
   tampilan bawah website tidak penuh layar" — Safari, pintasan Layar Utama.

   TIGA FAKTA YANG DIKUMPULKAN LEBIH DULU, supaya ini tidak menjadi tambalan
   keempat yang memindahkan masalahnya:

   1. WARNANYA PUTIH, DAN ITU BUKAN KEBETULAN. Baris 5869 berbunyi
        html body, html body:has(#view-dashboard.active){
          background:#ffffff !important }
      Tanda !important itu mengalahkan jaring pengaman gelap di baris 13270
      (`html, html body{background-color:var(--side-1)}`) yang justru dipasang
      untuk keadaan ini. Jadi setiap jengkal yang tidak ditutupi elemen
      aplikasi akan tampil PUTIH — bukan senada sidebar seperti yang
      diharapkan bagian 31.

   2. YANG KURANG PANJANG ADALAH KERANGKANYA, BUKAN WARNANYA. .app-shell
      memakai min-height:100dvh dan sidebar bergantung pada pasangan
      top:0/bottom:0 yang keduanya diukur terhadap kotak tata letak. Di
      aplikasi standalone iOS kotak itu bisa lebih pendek daripada layar yang
      benar-benar terlihat — dan selisih itulah pitanya.

   3. SATUAN vh/dvh TIDAK BISA DIPERCAYA DI SINI. Riwayatnya sudah jelas:
      bagian 19, 31, dan 33 semuanya menambal dengan satuan viewport, dan
      pitanya selalu kembali. Karena itu di sini tidak dipakai satuan
      viewport sama sekali.

   PENAWARNYA: satu angka dari JavaScript, --tinggi-nyata, berisi nilai
   TERBESAR yang pernah terukur dari visualViewport.height / innerHeight untuk
   orientasi yang sedang berlaku (lihat skrip "TINGGI LAYAR YANG SESUNGGUHNYA"
   di index.html). Nilai terbesar dipilih supaya papan ketik dan cubit-zoom —
   yang hanya MENGECILKAN angka itu sesaat — tidak membuat sidebar ikut
   memendek setiap kali mengetik.

   Setiap aturan di bawah punya cadangan `100dvh`/`auto`, jadi bila skripnya
   gagal dimuat tampilannya kembali persis seperti sebelum bagian ini ada.

   CATATAN JUJUR: bila pitanya MASIH ada sesudah ini, artinya jalur itu berada
   di luar kotak tata letak halaman dan digambar iOS sendiri — tidak ada satu
   pun aturan CSS yang bisa menjangkaunya. Yang membedakan kedua kemungkinan
   itu hanya angka dari pengukur (ketuk lambang PLN 5x): bila baris `sidebar`
   lebih kecil daripada `visual`, penyebabnya ada di sini dan bagian ini
   menyembuhkannya; bila keduanya sama, penyebabnya di luar halaman.
   ========================================================================== */

/* --- 29a. (DIBATALKAN 16 Agu 2026 — lihat bagian 36) ---
   Aturan di sini dulu memaksa .app-shell dan .sidebar-shell setinggi
   --tinggi-nyata. Sudah tidak dipakai; yang tersisa hanya pasangan
   top:0 + bottom:0, yang sejak semula sudah berarti "setinggi persis layar". */
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  top:0; bottom:0; height:auto;
}

/* --- 29b. Jaring pengaman warna, kali ini cukup berat untuk menang ---
   Bukan mengganti latar putih halaman (itu memang disengaja bagian 14),
   melainkan memberi jalur setinggi apa pun di dasar layar warna yang benar:
   senada sidebar di 76px pertama, senada halaman sesudahnya. Dipasang pada
   ::after milik .app-shell — bukan body — supaya tidak bertabrakan dengan
   ::after milik bagian 28/33 yang tugasnya khusus ruang aman. */
html.mode-rail .app-shell::after{
  content:"";
  position:fixed; left:0; right:0; bottom:0;
  height:max(env(safe-area-inset-bottom, 0px), 0px);
  background:linear-gradient(to right,
    var(--side-3) 0,
    var(--side-3) var(--side-rail),
    #e8edf0       var(--side-rail),
    #e8edf0       100%);
  z-index:1; pointer-events:none;
}


/* ==========================================================================
   30. KONTROL TANGGAL BAWAAN TIDAK BOLEH MELUBER DARI KOLOMNYA
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: "jarak antar field harusnya sama dan sejajar, tetapi di iPad
   field-nya sedikit berantakan."

   DIUKUR: pada halaman Ubah Data Pekerjaan setiap kolom dijatah 258px oleh
   .form-flow. Kolom teks memang 258px. Kolom TANGGAL menjadi 280px — dan
   22px kelebihannya memakan jarak 30px antar kolom sampai tersisa 8px,
   sehingga "Tgl. Anggaran" terlihat menempel pada "Jenis Anggaran"
   sedangkan pasangan lain berjarak normal.

   Sebabnya bukan CSS halaman ini: <input type="date"> bawaan iOS adalah
   kontrol sistem yang punya lebar minimum sendiri, dan lebar itu tidak
   tunduk pada width:100% milik kotaknya.

   Penawar sesungguhnya ada di tempat lain — js/format-tanggal.js kini
   dimuat (lihat index.html), dan begitu tanggal menjadi kotak teks biasa
   masalahnya hilang dari akarnya. Bagian ini hanya JARING PENGAMAN untuk
   dua celah yang tersisa: sekejap sebelum skrip itu sempat berjalan, dan
   keadaan bila ia gagal dimuat sama sekali. Isinya sengaja tidak mengubah
   apa pun pada kotak yang sudah berupa teks.
   ========================================================================== */
.form-flow > .field > input[type="date"],
.form-flow > .field > input[type="time"],
.field > input[type="date"],
.field > input[type="time"],
.jp-start-field > input[type="date"],
.jp-start-field > input[type="time"]{
  max-width:100%;
  min-width:0;
  box-sizing:border-box;
}


/* ==========================================================================
   31. DASHBOARD DIPERCANTIK — CINCIN SVG, IKON DUA NADA, JUDUL EMAS
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   Permintaan: "percantik bagian dashboard efisiensi, apalagi pada lingkaran
   persennya dan logo-logo lainnya; judul Pengadaan Langsung & Tender beri
   warna emas."

   WARNANYA DIHITUNG, BUKAN DIPILIH DENGAN MATA. Setiap warna di bawah sudah
   diuji rasio kontrasnya (WCAG) terhadap latar tempat ia benar-benar duduk:

       #F6B40E  judul emas       di kop gelap #0b4950   5,50 : 1   lulus penuh
       #157A44  busur cincin     di putih                5,39 : 1   lulus
       #157A44  glif "baik"      di cakram #e6f4ec       4,75 : 1   lulus
       #9A6F04  glif "berjalan"  di cakram #fdf3d8       4,08 : 1   lulus
       #B22A2A  glif "gagal"     di cakram #fbe9e9       5,51 : 1   lulus
       #095e66  glif "nilai"     di cakram #e3f2f3       6,51 : 1   lulus

   CATATAN SOAL EMAS: #F6B40E di atas latar PUTIH hanya 1,83 : 1 — tidak
   terbaca, dan itu sebabnya emas cerah biasanya harus dikompromikan jadi
   coklat keemasan. Di sini tidak perlu: judul dashboard duduk di atas kop
   gelap, dan di ujung KIRI kop itu (tempat judulnya berada) warnanya paling
   gelap. Jadi emas cerahnya bisa dipakai apa adanya.
   ========================================================================== */

/* ---------- (a) Judul dashboard: nama modul berwarna emas ---------- */
#view-dashboard .page-head #dash-title .dash-t-emas{
  background:linear-gradient(92deg,#FFD35A,#F6B40E 55%,#e9a70a);
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  /* WAJIB. Judul kop memakai -webkit-text-fill-color:#fff, dan properti itu
     MENGALAHKAN `color` saat huruf dicat — tanpa baris ini huruf tetap putih
     dan gradien emasnya tidak pernah terlihat sama sekali. */
  -webkit-text-fill-color:transparent;
  /* Bayangan tipis: memisahkan huruf emas dari kop yang juga hangat di ujung
     kanan, tanpa mengubah warnanya. */
  text-shadow:0 1px 0 rgba(0,0,0,.10);
}
/* Peramban tanpa background-clip:text akan menampilkan teks transparan alias
   HILANG. Jaring pengamannya warna padat lebih dulu. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  #view-dashboard .page-head #dash-title .dash-t-emas{
    background:none; color:#FFD35A; -webkit-text-fill-color:#FFD35A; text-shadow:none;
  }
}

/* ---------- (b) Panel efisiensi: keterangan skala ---------- */
#view-dashboard .eff-panel .eff-panel-k{ display:flex; align-items:baseline; gap:9px; flex-wrap:wrap }
#view-dashboard .eff-panel .eff-skala{
  font-size:9px; font-weight:700; letter-spacing:.2px; text-transform:none; color:#93a6ad;
}

/* ---------- (c) Cincin efisiensi: SVG menggantikan conic-gradient ---------- */
#view-dashboard .eff-ring{
  position:relative; width:64px; height:64px; flex:0 0 64px;
  background:none;                 /* melepas conic-gradient aturan lama */
  display:block;
}
#view-dashboard .eff-ring svg{
  width:64px; height:64px; display:block; overflow:visible;
  transform:rotate(-90deg);        /* busur mulai dari puncak, searah jarum jam */
}
#view-dashboard .eff-ring .eff-jalur{ fill:none; stroke:#e7eef0; stroke-width:5.5 }
/* `stroke` SENGAJA TIDAK DITULIS di sini — lihat komentar di app.js. Aturan
   CSS mengalahkan atribut presentasi, dan gradien per-cincin akan lenyap. */
#view-dashboard .eff-ring .eff-arc{
  fill:none; stroke-width:5.5; stroke-linecap:round;
}
/* Tanda batas skala di puncak cincin: penanda "di sini 5%". */
#view-dashboard .eff-ring .eff-batas{ stroke:#b9cbd0; stroke-width:1.8; stroke-linecap:round }
/* Isi cincin kini LAPISAN di atas svg, bukan anak grid. */
#view-dashboard .eff-ring-in{
  position:absolute; inset:0; width:auto; height:auto; border-radius:0; background:none;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  line-height:1; pointer-events:none;
}
#view-dashboard .eff-ring-in b{
  font-size:15px; font-weight:800; color:#0d2a30;
  letter-spacing:-.02em; font-variant-numeric:tabular-nums;
}
#view-dashboard .eff-ring-in i{
  font-style:normal; font-size:8.5px; font-weight:700; color:#93a6ad;
  margin-top:2px; letter-spacing:.3px;
}
#view-dashboard .eff-seg{ gap:13px }

/* Busur tumbuh saat kartu muncul. Hanya bila pengguna tidak meminta
   pengurangan gerak. */
@media (prefers-reduced-motion:no-preference){
  #view-dashboard .eff-ring .eff-arc{
    transition:stroke-dashoffset 1s cubic-bezier(.16,1,.3,1);
  }
}

/* ---------- (d) Ikon kartu: cakram dua nada + cincin aksen ----------
   Bentuk & ukurannya tidak diubah sedikit pun — hanya isinya yang tadinya
   satu warna rata kini punya kedalaman: gradien halus dari sudut kiri atas,
   satu cincin tipis warna aksen di dalam tepinya, dan secercah cahaya di
   sisi atas. Warna aksennya tetap --ic yang sudah dikirim app.js per kartu,
   jadi tidak ada satu baris JavaScript pun yang perlu berubah. */
#view-dashboard .cards .card .card-ic{
  background:
    radial-gradient(120% 120% at 30% 18%,
      color-mix(in srgb, var(--ic,#0E7C86) 5%, #fff),
      color-mix(in srgb, var(--ic,#0E7C86) 16%, #fff)) !important;
  border:none !important;
  box-shadow:
    inset 0 0 0 1.5px color-mix(in srgb, var(--ic,#0E7C86) 24%, transparent),
    inset 0 2px 4px rgba(255,255,255,.9) !important;
}
#view-dashboard .cards .card .card-ic svg{
  stroke-width:2.1;
  /* Bayangan setipis rambut agar glif tidak menyatu dengan cakramnya. */
  filter:drop-shadow(0 1px 0 rgba(255,255,255,.55));
}

/* Layar sempit: cincin sedikit diperkecil supaya baris tidak melipat. */
@media (max-width:640px){
  #view-dashboard .eff-ring,
  #view-dashboard .eff-ring svg{ width:58px; height:58px }
  #view-dashboard .eff-ring{ flex:0 0 58px }
  #view-dashboard .eff-ring-in b{ font-size:14px }
}


/* ==========================================================================
   32. PITA TERANG DI DASAR LAYAR — CARA KELIMA, DAN YANG BERBEDA
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   Empat percobaan sebelumnya (bagian 19, 28, 29, dan 33) semuanya mencoba hal
   yang SAMA: membuat elemen aplikasi lebih panjang supaya menutupi jalur di
   dasar layar. Semuanya gagal, dan pola kegagalannya sendiri yang akhirnya
   memberi tahu jawabannya — kalau empat cara berbeda untuk memanjangkan
   elemen tidak berhasil, mungkin memang ada keadaan di mana elemennya TIDAK
   BISA sampai ke sana.

   Bagian ini berhenti melawan itu. Alih-alih memaksa elemen menutupi jalur,
   ia membuat jalur itu SUDAH BENAR WARNANYA sejak awal.

   YANG DIUKUR LEBIH DULU (lewat pengukur di index.html):

       latar html : rgb(233,238,241)  = #e9eef1
       latar body : rgb(255,255,255)  = putih

   #e9eef1 persis warna pita yang terlihat di foto. Jadi pitanya BUKAN
   gambaran iOS di luar jangkauan CSS — ia kanvas halaman ini sendiri, dan
   kanvas selalu bisa diwarnai. Yang salah cuma warnanya: satu abu-abu rata
   untuk seluruh lebar layar, padahal 76px pertama seharusnya segelap sidebar.

   Kanvas kini diberi dua nada:

       0 .. lebar sidebar     warna dasar sidebar (--side-1)
       lebar sidebar .. 100%  warna halaman        (#e9eef1)

   Lebar sidebarnya tidak ditulis sebagai angka mati — ia dikirim JavaScript
   lewat --lebar-sidebar-nyata dan ikut berubah saat rail melebar dari 76px ke
   258px. Dengan begitu jalur di dasar layar terbaca sebagai LANJUTAN dari
   sidebar dan halaman yang ada di atasnya, bukan sebagai pita asing —
   setinggi apa pun jalur itu, dan apa pun penyebabnya.

   `!important` DIPERLUKAN, bukan kemalasan: index.html baris 912 menulis
   `html,body{background:#e9eef1}` di dalam <style> yang letaknya SESUDAH
   <link> style.css, jadi tanpa !important aturan itu selalu menang.

   Hanya berlaku pada tata letak rail. Di tampilan laci (ponsel) sidebar tidak
   menempel di layar, jadi kanvas memang harus satu warna saja.
   ========================================================================== */
html.mode-rail{
  background:linear-gradient(to right,
    var(--side-1) 0,
    var(--side-1) var(--lebar-sidebar-nyata, var(--side-rail, 76px)),
    #e9eef1       var(--lebar-sidebar-nyata, var(--side-rail, 76px)),
    #e9eef1       100%) !important;
  background-attachment:fixed !important;
}


/* ==========================================================================
   33. AKHIRNYA DIUKUR — DAN PENYEBABNYA LEBAR, BUKAN TINGGI
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   Empat percobaan sebelumnya menebak bahwa kerangka aplikasi KURANG PANJANG.
   Pengukuran di iPad (mode Layar Utama, lanskap) membalik dugaan itu:

       layar     : 820 x 1180      (iOS selalu melapor posisi tegak)
       viewport  : width=1320   -> skala 1180/1320 = 0,894
       innerH / visual / client : 881
       aman-atas : 32       aman-bawah : 25
       sidebar   : 917  (sisa -36)
       app-shell : 917  (sisa -36)
       pita      : 25px            <-- body::after MEMANG tergambar
       body bg   : rgb(255,255,255)

   Tiga hal yang langsung terbaca dari angka-angka itu:

   1. TINGGINYA SUDAH CUKUP — bahkan KELEBIHAN 36px. Jadi pita terang itu
      tidak pernah disebabkan kerangka yang kurang panjang, dan empat tambalan
      tinggi sebelumnya memang tidak mungkin berhasil. (Kelebihan 36px itu
      ulah tambalan terakhir; sudah dibatalkan di index.html.)

   2. JALUR BAWAHNYA ADA DI DALAM HALAMAN, dan sudah dicat: `pita : 25px`
      membuktikan body::after benar-benar tergambar setinggi ruang aman.

   3. YANG SALAH LEBARNYA. Gradien pita itu berbunyi:

          gelap  0 .. var(--side-rail)      -> 76px
          terang var(--side-rail) .. 100%

      76px adalah lebar sidebar saat MENCIUT. Begitu rail dilebarkan menjadi
      258px, jalur dari 76px sampai 258px dicat #e8edf0 — abu-abu terang, tepat
      di bawah tombol Keluar. Itulah "garis tebal biru dan abu-abu di bawah
      tombol keluar" yang dilaporkan: birunya tepi bawah sidebar, abu-abunya
      jalur yang warnanya salah.

   Penawarnya satu kata: --side-rail diganti --lebar-sidebar-nyata, peubah yang
   diisi JavaScript dengan lebar sidebar yang BENAR-BENAR tergambar saat itu —
   76px ketika menciut, 258px ketika melebar, dan ikut berubah di tengah
   animasinya. Bagian 28 di atas ikut diperbaiki dengan cara yang sama.
   ========================================================================== */
@media all and (display-mode:standalone){
  html.mode-rail body::after{
    background:linear-gradient(to right,
      var(--side-3) 0,
      var(--side-3) var(--lebar-sidebar-nyata, var(--side-rail)),
      #e8edf0       var(--lebar-sidebar-nyata, var(--side-rail)),
      #e8edf0       100%) !important;
  }
}


/* ==========================================================================
   34. PITANYA BUKAN LUBANG — PITANYA CAT. JALUR ITU DIBUANG.
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   Bagian 33 sudah benar arahnya (lebar, bukan tinggi) tetapi masih setengah
   jalan. Angka dari pengukur, sekali lagi:

       innerH / visual / client : 881
       sidebar   : 917  (sisa -36)
       app-shell : 917  (sisa -36)
       pita      : 25px

   `sisa -36` berarti sidebar DAN kerangka aplikasi sudah menutupi seluruh
   tinggi yang terlihat, bahkan 36px lebih. Tidak ada satu jengkal pun di
   dasar layar yang tidak tertutupi elemen aplikasi.

   Maka pita terang itu MUSTAHIL berupa lubang yang tersingkap. Satu-satunya
   kemungkinan yang tersisa: ada yang MENGECATNYA di situ. Dan memang ada —
   body::after sendiri:

       position:fixed; bottom:0; height:env(safe-area-inset-bottom);
       z-index:200;
       background: gelap 0..76px , lalu #e8edf0 sampai 100%

   z-index 200 menaruhnya DI ATAS seluruh isi aplikasi (sidebar z-index 70,
   kartu jauh di bawah itu). Jadi jalur setinggi 25px di dasar layar dicat
   #e8edf0 menimpa apa pun yang ada di bawahnya — persis satu pita abu-abu
   terang membentang selebar layar. Bagian gelapnya pun cuma 76px, sehingga
   saat rail dilebarkan ke 258px, 182px berikutnya ikut jadi abu-abu tepat di
   bawah tombol Keluar.

   Jalur itu dipasang dahulu untuk menambal lubang yang — menurut
   pengukuran — tidak pernah ada. Ia bukan penawar; ia penyakitnya. Karena
   itu sekarang dimatikan, di ketiga tempat ia pernah ditulis.

   YANG MENGGANTIKANNYA sudah terpasang dan tidak mengecat apa pun di atas
   isi: kanvas dua nada di bagian 32. Kanvas berada di lapisan PALING BAWAH,
   jadi ia hanya terlihat pada jengkal yang memang tidak ditutupi siapa pun —
   dan bila memang tidak ada jengkal seperti itu, ia tidak terlihat sama
   sekali. Itulah bedanya menambal dengan cat dan menambal dengan latar.
   ========================================================================== */
html.mode-rail body::after,
html:not(.mode-rail) body::after{
  display:none !important;
  height:0 !important;
}
@media all and (display-mode:standalone){
  html.mode-rail body::after,
  html:not(.mode-rail) body::after{
    display:none !important;
    height:0 !important;
  }
}


/* ==========================================================================
   35. JALUR KEDUA — YANG SAYA BUAT SENDIRI DAN LUPA SAYA MATIKAN
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   Bagian 34 mematikan body::after dan pitanya TETAP ADA. Sebabnya sederhana
   dan memalukan: jalur di dasar layar itu ada DUA, dan yang kedua saya
   pasang sendiri di bagian 29b beberapa jam sebelumnya —

       html.mode-rail .app-shell::after{
         position:fixed; left:0; right:0; bottom:0;
         height:max(env(safe-area-inset-bottom,0px), 0px);
         background: gelap 0..var(--side-rail) , lalu #e8edf0 sampai 100%;
       }

   Isinya persis kembar dengan body::after: setinggi ruang aman (25px pada
   iPad), dicat #e8edf0 mulai dari 76px ke kanan, menimpa apa pun di bawahnya.
   Jadi mematikan yang satu tanpa yang lain sama saja tidak mematikan apa pun.

   CARA MENEMUKANNYA — dicatat supaya lain kali tidak perlu lima putaran:
   bukan dengan membaca ulang, melainkan dengan MENYARING SELURUH style.css
   memakai satu pertanyaan: "aturan mana saja yang position:fixed, menempel
   bottom:0, DAN punya background?" Tujuh aturan muncul, dan dua di antaranya
   jalur ini. Pertanyaan itu yang seharusnya diajukan sejak awal.

   Sekarang keduanya mati. Yang menutupi jalur bawah cukup elemen aplikasi
   sendiri — pengukuran sudah membuktikan sidebar & kerangka menutupi seluruh
   tinggi yang terlihat (sisa -36) — dengan kanvas dua nada bagian 32 sebagai
   lapisan paling bawah bila suatu saat ada jengkal yang benar-benar kosong.
   ========================================================================== */
html.mode-rail .app-shell::after,
html:not(.mode-rail) .app-shell::after{
  content:none !important;
  display:none !important;
  height:0 !important;
}


/* ==========================================================================
   36. SIDEBAR SATU HALAMAN PENUH, PERSIS SEPERTI DESKTOP
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: "sidebar seharusnya seperti di desktop — tampil satu halaman penuh
   tanpa geser atas-bawah; dari awal memang sudah fixed position, tombol Keluar
   pun terpaku di situ."

   Betul, dan memang begitu rancangannya sejak semula: .sidebar-shell itu
   position:fixed dengan top:0 DAN bottom:0. Pasangan itu sendiri sudah berarti
   "setinggi persis layar" — tidak ada angka yang perlu dihitung, tidak ada
   satuan vh yang perlu dipercaya.

   Yang merusaknya justru tambalan saya sendiri. Untuk menutupi pita terang di
   dasar layar, .sidebar-shell diberi min-height dari --tinggi-nyata. Di iPad
   angkanya 918px sementara tinggi yang benar-benar terlihat 881px:

       kotak sidebar   918px
       layar terlihat  881px
       selisih          37px   -> isinya melewati tepi bawah, jadi bisa digeser

   Di desktop selisih itu nol, jadi gejalanya tidak pernah muncul di sana —
   persis yang dilaporkan.

   Sekarang min-height itu dibuang, di CSS maupun di gaya sebaris yang dipasang
   JavaScript. Sidebar kembali mengikuti top:0 + bottom:0 saja. Alasan
   memasangnya pun sudah gugur: pita terang itu ternyata cat, bukan lubang
   (bagian 34 & 35), jadi tidak ada lagi yang perlu ditutupi.

   Dua penegasan di bawah bukan aturan baru — hanya memastikan tidak ada sisa
   min-height dari mana pun yang membuat sidebar lebih tinggi daripada layar.
   ========================================================================== */
html.mode-rail .sidebar-shell,
html.mode-rail .sidebar-shell.is-open{
  min-height:0 !important;
  max-height:none !important;
}
.app-shell{ min-height:100dvh }
@supports not (height:100dvh){ .app-shell{ min-height:100vh } }


/* ==========================================================================
   37. MONITORING MEMANG DIGESER — PEMADATANNYA DIBATALKAN
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   KOREKSI DARI PEMILIK APLIKASI: "menu Monitoring - Daftar Pekerjaan tidak
   perlu tampil satu halaman penuh tanpa geser kiri-kanan, karena menu ini
   memang dirancang untuk itu — makanya kolom Nama Pekerjaan dibekukan.
   Tampilannya harus presisi sama seperti desktop dan bisa digeser."

   Bagian 26 (15 Agu 2026) melakukan kebalikannya. Laporan yang memicunya —
   "di desktop tampilan 1 layar tanpa geser, di iPad harus geser" — dibaca
   sebagai keluhan tentang GESERANNYA. Padahal geseran itu memang cara pakai
   halaman ini; yang berbeda cuma ruang layarnya. Akibat salah baca itu enam
   kolom dipersempit khusus tablet:

       Bidang Pelaksana   200 -> 124px
       Penyedia           200 -> 132px
       Nama Pekerjaan     240 -> 186px
       No. Kontrak/SPBJ   150 -> 112px  (dan boleh turun baris)
       dua kolom tanggal  118 ->  96px
       lantai min-width 980px dilepas

   Hasilnya justru yang tidak diinginkan: tabel yang sama tampil dengan lebar
   kolom BERBEDA di tablet dan di desktop — hilang presisinya, dan nama
   penyedia yang panjang jadi melipat tiga baris.

   Blok itu kini dimatikan dengan menukar syarat medianya (max-width:1400px ->
   0px), bukan dihapus: seluruh alasan dan angkanya tetap tercatat di
   tempatnya, dan menghidupkannya kembali cukup satu angka. Sesudah ini
   ketiga daftar Monitoring memakai lebar kolom yang sama persis dengan
   desktop — termasuk lantai 980px dan kolom beku Nomor + Nama Pekerjaan —
   dan digeser mendatar sebagaimana mestinya.

   DUA BLOK, BUKAN SATU. Bagian 26 punya lanjutan tepat di bawahnya khusus
   Daftar Tender (kolom "Metode Pengadaan" membuatnya satu kolom lebih banyak):
   nama 240->160px, Bidang 200->108px, Penyedia 200->116px. Mematikan blok
   pertama saja menyisakan Tender tetap berbeda dari desktop — terbukti saat
   diukur: dua daftar sudah sama persis, Tender masih 1.353px lawan 1.617px.
   Keduanya kini dimatikan dengan cara yang sama.

   CATATAN: halaman lain TIDAK terpengaruh. Bagian 26 hanya pernah menyentuh
   #view-list, #view-list-pl, dan #view-list-tender.
   ========================================================================== */


/* ==========================================================================
   38. DI BAWAH TEPI HALAMAN, BUKAN DI ATAS ISINYA
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   PERTANYAAN PEMILIK: "masih menyisakan batas putih di bawah, apakah bawaan
   Safari seperti ini?"  Jawabannya: SEBAGIAN IYA — dan bagian yang bukan
   bawaan itulah yang diperbaiki di sini.

   YANG MEMANG BAWAAN. Di aplikasi Layar Utama, iOS tidak selalu memanjangkan
   KOTAK TATA LETAK halaman sampai tepi bawah layar, walaupun meta viewport
   sudah menulis viewport-fit=cover. Angka dari iPad ini membuktikannya:

       layar   : 820px fisik  = 917 satuan tata letak
       viewport: 881 satuan tata letak
       selisih :  36 satuan tata letak  = 32px fisik

   36 satuan itu PERSIS setinggi pita putih pada foto. Jadi jalur itu berada
   DI LUAR kotak tata letak: tidak ada elemen dalam aliran normal, dan tidak
   ada latar body maupun kanvas, yang bisa menjangkaunya.

   YANG BUKAN BAWAAN — dan ini kesalahan saya kemarin. Sebelum bagian 36,
   sidebar diberi min-height 917px. Angka itu membuatnya MENJULUR 36px
   melewati tepi bawah kotak tata letak, dan justru itulah yang menutupi jalur
   tersebut. Saya membuangnya untuk menyembuhkan sidebar yang bisa digeser —
   benar untuk gesernya, tetapi sekaligus mengembalikan pita putihnya.
   Dua gejala, satu tombol, arah berlawanan.

   PENAWARNYA: PISAHKAN KEDUANYA. Tinggi sidebar tetap sama dengan layar (jadi
   isinya tidak pernah lebih panjang daripada yang terlihat — tidak ada yang
   bisa digeser), tetapi ditambahkan satu jalur TERPISAH yang mulai TEPAT DI
   TEPI BAWAH kotak tata letak dan memanjang ke bawah:

       position:fixed;  top:100%;  height:120px;

   `top:100%` pada elemen fixed berarti "mulai dari tepi bawah viewport".
   Karena ia seluruhnya berada DI BAWAH tepi itu, ia MUSTAHIL menutupi isi
   aplikasi — beda mendasar dengan jalur lama (bagian 34 & 35) yang memakai
   `bottom:0` sehingga duduk DI DALAM viewport, di atas isi, dan justru
   menjadi pita abu-abu yang dikeluhkan.

   Warnanya dua nada mengikuti lebar sidebar yang sedang tergambar, sama
   seperti kanvas bagian 32, sehingga terbaca sebagai lanjutan sidebar dan
   halaman — bukan sebagai pita tambahan.

   Di desktop dan di Safari biasa tepi bawah viewport = tepi bawah layar, jadi
   jalur ini jatuh seluruhnya di luar layar dan tidak pernah terlihat.
   ========================================================================== */
html.mode-rail .app-shell::after{
  content:"" !important;
  display:block !important;
  position:fixed;
  left:0; right:0;
  top:100%;                 /* mulai persis di tepi bawah viewport */
  height:120px !important;  /* cukup untuk ruang aman terbesar mana pun */
  background:linear-gradient(to right,
    var(--side-1) 0,
    var(--side-1) var(--lebar-sidebar-nyata, var(--side-rail, 76px)),
    #e9eef1       var(--lebar-sidebar-nyata, var(--side-rail, 76px)),
    #e9eef1       100%);
  z-index:0;
  pointer-events:none;
}


/* ==========================================================================
   39. "MONITORING PENGADAAN" SELALU SATU BARIS
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: "tulisan Monitoring Pengadaan di tampilan desktop hanya 1 baris"
   — di iPad ia melipat menjadi dua.

   DIUKUR: pada sidebar melebar (268px), judul itu menuntut 173px sementara
   ruang yang tersedia untuknya juga 173px. Selisihnya NOL. Perbedaan sekecil
   satu piksel — pembulatan lebar logo, tebal huruf yang sedikit berbeda saat
   Plus Jakarta Sans belum selesai dimuat, atau pembulatan skala 0,894 di iPad
   — sudah cukup membuatnya melipat. Itu sebabnya gejalanya muncul di satu
   perangkat dan tidak di perangkat lain, padahal aturannya sama.

   Menambah lebar sidebar bukan jawabannya: yang salah bukan ukurannya,
   melainkan kenyataan bahwa judul ini DIIZINKAN melipat sama sekali. Nama
   aplikasi selalu dua kata dan tidak pernah berubah panjang, jadi tidak ada
   keadaan di mana melipat itu berguna.

   Tiga hal sekaligus, supaya tidak lagi bergantung pada satu piksel:
     a) white-space:nowrap  — melipat dimatikan.
     b) letter-spacing .3px -> .2px  — menghemat ±2px tanpa terlihat berbeda.
     c) min-width:0 pada .brand  — di dalam flex, bawaan sebuah anak adalah
        min-content; tanpa ini kotaknya bisa menuntut lebih lebar daripada
        jatahnya dan mendorong tata letak, bukan menyesuaikan diri.
   ========================================================================== */
.topbar-brand .brand{ min-width:0 }
.topbar-brand .brand h1{
  white-space:nowrap;
  letter-spacing:.2px;
  overflow:hidden;
  text-overflow:ellipsis;   /* jaring pengaman: kalau toh kurang, dipotong rapi
                               dengan titik-titik — bukan melipat dua baris */
}


/* ==========================================================================
   40. (DIBATALKAN 16 Agu 2026) — uji warna sementara sudah dicabut.
   Blok tiga jalur berwarna (merah/hijau/biru) dibuang karena aplikasi sedang
   tidak bisa dipakai; memulihkan login lebih mendesak daripada mengukur pita.
   Isinya bisa dibangun ulang kapan saja dari catatan di riwayat percakapan.
   ========================================================================== */


/* ==========================================================================
   41. HALAMAN TENTUKAN HARI LIBUR — DUA PERBAIKAN TATA LETAK
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   (a) TOMBOL "TAMBAH TANGGAL" TIDAK SEJAJAR DENGAN KOTAK ISIAN.
       Terukur: dasar kotak Tanggal & Keterangan di 865 px, dasar tombol di
       842 px — tombolnya 23 px terlalu tinggi.

       Sebabnya tabrakan dua aturan yang keduanya masih hidup:
           baris  667  .form-flow{align-items:flex-end}    <- niat aslinya
           baris 1541  .form-flow{align-items:flex-start}  <- menang, lebih akhir
       Baris 1541 dipasang untuk kelompok isian yang bisa memanjang ke bawah
       (Bidang/Sub Bidang), tetapi ditulis untuk SELURUH .form-flow, jadi baris
       Tambah Tanggal ikut terseret. Kotak isian punya <label> di atasnya dan
       tombol tidak, sehingga rata-atas membuat keduanya tidak pernah sebaris.

       Diperbaiki hanya untuk .hl-add-flow — satu-satunya baris yang memakai
       kelas itu — supaya kelompok isian lain tidak ikut berubah. Dua kelas
       mengalahkan satu kelas, jadi tidak perlu !important.

   (b) TOMBOL "KEMBALI" TAMPAK DI LUAR BINGKAI.
       Memang di luar: dulu ia berdiri sendiri di bawah kartu tabel, tanpa ada
       kartu yang memuatnya. Sekarang ia dipindah KE DALAM kartu (lihat
       renderHariLibur di app.js) dan memakai pola .pn-card-actions milik kartu
       Ambil Nomor. Aturan lama hanya mengenal .form-card sebagai induk; di sini
       induknya .panel, yang padding-nya nol dan sudutnya 16px — karena itu
       jarak dan lengkung sudutnya ditulis ulang, bukan menumpang begitu saja.
   ========================================================================== */
.form-flow.hl-add-flow{align-items:flex-end}
.form-flow.hl-add-flow>.field{align-self:flex-end}

.panel>.jp-actions.pn-card-actions{
  margin:0;
  padding:14px 20px;
  border-top:1px solid var(--line,#e2e8ea);
  background:rgba(240,247,248,.6);
  border-radius:0 0 16px 16px;
}


/* ==========================================================================
   41. KEPALA POP-UP PRATINJAU KETINGGIAN — SAFE-AREA DIPASANG DI TEMPAT YANG SALAH
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: bilah teal di atas pop-up pratinjau PDF tinggi sekali di Safari,
   jauh melebihi tulisan maupun tombolnya.

   SEBABNYA baris 8280 di dalam @media (hover:none):

       .pn-preview-modal .detail-head{ padding-top:calc(12px + env(safe-area-inset-top)) }

   Aturan itu benar untuk pop-up yang MENEMPEL KE TEPI ATAS LAYAR: di sana
   bilah judulnya berada di bawah kamera/jam, dan safe-area menjaganya tidak
   tertutup. Tetapi media query-nya berbunyi (hover:none) — cocok untuk SETIAP
   perangkat sentuh, termasuk iPad yang pop-upnya justru MENGAMBANG DI TENGAH
   layar dengan jarak lebar di atasnya. Di sana tidak ada yang perlu dihindari:
   env(safe-area-inset-top) (~24 px di iPad, dan lebih besar lagi sesudah
   dibagi skala 0,894) hanya menambah kekosongan.

   Ukuran yang benar untuk bilah ini ditentukan oleh isinya yang PALING TINGGI:

       tombol   32 px   <- ini yang menang
       judul    12,5 px x 1,3 = ~17 px

   Jadi 12 px atas + 32 px + 12 px bawah = 56 px. Itu tinggi yang seharusnya,
   dan itulah yang dikembalikan di sini.

   Safe-area TIDAK dibuang — ia dipindah ke tempat yang memang membutuhkannya:
   saat pop-up benar-benar memenuhi layar (.is-max, .pn-fs-semu, :fullscreen),
   bilah judulnya kembali menyentuh tepi atas dan padding itu jadi masuk akal.
   ========================================================================== */
.pn-preview-modal .detail-head{
  /* Atas & bawah dibuat SAMA supaya tombolnya benar-benar di tengah bilah.
     Sebelumnya bawah 16px sementara atas 40px — tidak seimbang, dan sudah
     terlihat miring bahkan sebelum safe-area menambahinya. */
  padding-top:12px !important;
  padding-bottom:12px !important;
  padding-left:14px !important;
  padding-right:14px !important;
}
.pn-preview-modal.is-max .detail-head,
.pn-preview-modal.pn-fs-semu .detail-head,
.pn-preview-modal:fullscreen .detail-head,
.pn-preview-modal:-webkit-full-screen .detail-head{
  padding-top:calc(12px + env(safe-area-inset-top)) !important;
  padding-left:calc(14px + env(safe-area-inset-left)) !important;
  padding-right:calc(14px + env(safe-area-inset-right)) !important;
}


/* ==========================================================================
   42. SIDEBAR TERANGKAT SAAT DIGULIR MENTOK BAWAH (ANDROID)
                                                        16 Agustus 2026
   --------------------------------------------------------------------------
   LAPORAN: "waktu scroll dashboard mentok bawah, ui sidebar tidak fix posisi
   dan terangkat."

   Sebabnya ada di bagian 23, dan hanya berupa satu selektor yang kurang:

       html.mode-rail .sidebar-shell,
       html.mode-rail .sidebar-shell.is-open{ ... height:100vh; }        (a)

       @supports (height:100dvh){
         html.mode-rail .sidebar-shell{ height:100dvh }                  (b)
       }

   Baris (b) memperbaiki tingginya — TETAPI hanya untuk sidebar yang sedang
   menyempit. Begitu sidebar-nya dibentangkan (kelas .is-open, yaitu keadaan
   pada tangkapan layar Android itu), ia tidak lagi tersentuh (b) dan kembali
   memakai 100vh dari (a).

   Bedanya nyata di ponsel: `vh` mengacu pada viewport BESAR — tinggi layar
   seolah bilah alamat sedang tersembunyi — sedangkan yang benar-benar terlihat
   saat bilah itu muncul lebih pendek. Sidebar setinggi 100vh karena itu
   menjulur ke bawah garis pandang; ketika halaman digulir sampai mentok, ujung
   bawahnya baru terlihat dan tampak seperti "terangkat" dari dasar layar.
   `dvh` mengacu pada viewport yang SEDANG terlihat, jadi tingginya ikut
   menyesuaikan saat bilah alamat muncul dan menghilang.

   Perbaikannya menyertakan .is-open pada aturan dvh — satu selektor, tidak
   ada nilai yang diubah. Ditulis di sini, bukan disunting di bagian 23, supaya
   riwayat aturan aslinya tetap terbaca utuh.
   ========================================================================== */
@supports (height:100dvh){
  html.mode-rail .sidebar-shell,
  html.mode-rail .sidebar-shell.is-open{ height:100dvh }
}


/* ==========================================================================
   43. RAIL SENTUH — MENU TIDAK BOLEH BISA DIKETUK SEBELUM RAIL DIAM
                                                        16 Agustus 2026, malam
   --------------------------------------------------------------------------
   LAPORAN: di iPad/tablet/ponsel, mengetuk rail kadang langsung memilih menu,
   padahal sidebar-nya baru mulai melebar.

   Dua hal terjadi bersamaan di satu ketukan:
     - di Safari iOS, preventDefault() pada 'pointerdown' tidak selalu
       membatalkan 'click' yang menyusul, jadi ketukan pembuka rail bisa ikut
       menjalankan menu di bawah jari;
     - selama animasi melebar (0,26 dtk), seluruh tautan sedang BERGERAK —
       jari yang mendarat di "Monitoring" bisa terangkat di atas "Dashboard".

   Menambal lewat pembatalan peristiwa tidak pernah tuntas; yang tuntas adalah
   membuat tautannya memang tidak bisa disentuh sampai rail benar-benar diam.

   `pointer-events:none` dipasang pada ISI sidebar, lalu dikembalikan pada
   CANGKANGNYA. Dengan begitu ketukan tetap diterima sidebar — ia masih bisa
   dibuka — tetapi tidak ada satu pun tautan yang bisa menerimanya.

   Berlaku pada dua keadaan:
     :not(.is-open)  rail masih menciut
     .sedang-buka    rail sedang melebar (dilepas oleh 'transitionend' di
                     ui-sidebar.js, dengan pengaman waktu 600 ms)

   Berpagar html.sentuh — perangkat berkursor tidak tersentuh sama sekali,
   karena di sana rail dibuka oleh hover dan tidak pernah ada ketukan yang
   mendarat di atas tautan yang sedang bergerak.

   Transisinya juga sedikit diperlambat KHUSUS di layar sentuh (0,26 -> 0,34
   dtk). Bukan demi keindahan: gerak yang lebih tenang memberi mata waktu
   membaca nama menu yang baru muncul, dan itu tepat yang diminta — "terbuka
   perlahan, jadi tidak ada lagi menu terklik".
   ========================================================================== */
html.mode-rail.sentuh .sidebar-shell:not(.is-open) *,
html.mode-rail.sentuh .sidebar-shell.sedang-buka *{
  pointer-events:none !important;
}
html.mode-rail.sentuh .sidebar-shell:not(.is-open),
html.mode-rail.sentuh .sidebar-shell.sedang-buka{
  pointer-events:auto !important;
}
html.mode-rail.sentuh .sidebar-shell,
html.mode-rail.sentuh .sidebar-shell.is-open{
  transition-duration:.34s;
}


/* ==========================================================================
   44. TOMBOL KELUAR MEMANGGIL PERHATIAN SAAT RAIL MENCIUT
                                                        16 Agustus 2026, malam
   --------------------------------------------------------------------------
   PERMINTAAN: "beri efek bergerak pada tombol keluar dalam mode ciut, seakan
   memberi petunjuk bahwa tombol keluar ada di sini."

   ⚠ CATATAN PENTING, JANGAN SAMPAI TERTUKAR DENGAN BAGIAN 34.
   Bagian 34 justru MENGHENTIKAN gerak di sekitar tombol ini, karena dulu
   dilaporkan "tombol keluar bergerak terus-menerus di mode ciut". Yang
   dihentikan di sana adalah gerak TAK DISENGAJA milik tetangganya —
   .sidebar-shell::before (pegangan tiga titik) dan ::after (pita gradasi) —
   yang pada lebar 72 px berdiri hanya ~17 px dari tombol sehingga mata
   menggabungkan keduanya. Gerak itu tidak punya maksud, terjadi selamanya,
   dan terbaca sebagai kegelisahan. Bagian 34 TIDAK dicabut dan tidak boleh
   dicabut.

   Yang ditambahkan di sini berbeda pada tiga hal, dan ketiganya disengaja:
     - yang bergerak TOMBOLNYA SENDIRI, jadi geraknya punya alamat yang jelas;
     - siklusnya LAMBAT (5,4 dtk) dengan sebagian besar waktu DIAM — denyutnya
       hanya menempati ~25% siklus, sisanya tenang. Ini beacon, bukan getaran;
     - yang berdenyut adalah CAHAYA (box-shadow) dan skala yang sangat kecil
       (1,06), bukan perpindahan tempat. Kotak tombol tidak bergeser sepiksel
       pun, jadi tidak ada yang terbaca sebagai "goyang".

   Berhenti sendiri ketika: rail dibuka (label "Keluar" sudah terbaca, tidak
   ada yang perlu ditunjuk lagi), jari/kursor menyentuhnya, atau pengguna
   memilih "kurangi gerak" di setelan perangkatnya.
   ========================================================================== */
@keyframes keluarDenyut{
  0%,  70%, 100% { transform:scale(1);    box-shadow:0 2px 10px rgba(150,26,26,.38) }
  80%            { transform:scale(1.06); box-shadow:0 0 0 6px rgba(211,58,58,.22), 0 6px 20px rgba(150,26,26,.55) }
  90%            { transform:scale(1);    box-shadow:0 0 0 11px rgba(211,58,58,0),  0 2px 10px rgba(150,26,26,.38) }
}
html.mode-rail .sidebar-shell:not(.is-open) .side-logout{
  animation:keluarDenyut 5.4s ease-in-out infinite;
  will-change:transform;
}
html.mode-rail .sidebar-shell:not(.is-open) .side-logout:hover,
html.mode-rail .sidebar-shell:not(.is-open) .side-logout:active,
html.mode-rail .sidebar-shell:not(.is-open) .side-logout:focus-visible{
  animation:none;
}
@media (prefers-reduced-motion:reduce){
  html.mode-rail .sidebar-shell:not(.is-open) .side-logout{ animation:none }
}
