/* ==========================================================================
   ARG — SHELL APLIKASI: sidebar, topbar, layout 3 zona, dashboard
   ========================================================================== */

/* ── Kerangka ─────────────────────────────────────────────────────────── */
#app{display:grid; grid-template-columns:var(--sidebar-w) minmax(0,1fr); min-height:100vh; transition:grid-template-columns .18s ease}

/* ══════════════════ SIDEBAR ══════════════════
   TERANG, bukan gelap. Sidebar navy membelah aplikasi jadi dua bidang yang
   saling berebut perhatian; yang membedakan menu aktif seharusnya warna
   AKSEN, bukan kontras hitam-putih.

   Tiga keadaan, dan hanya satu yang menggeser konten:
   • LEBAR    — bawaan; ikon + label; konten bergeser.
   • CIUT     — ikon saja; konten bergeser. Dikunci pengguna lewat tombol pin.
   • FLYOUT   — sementara melebar saat kursor masuk, MENUMPUK di atas konten.
                Konten tidak ikut bergeser: menggeser seluruh halaman hanya
                karena kursor lewat membuat teks melompat saat sedang dibaca.

   Flyout hanya untuk penunjuk yang benar-benar bisa hover. Pada layar sentuh
   `hover:hover` tidak terpenuhi, jadi sidebar dibuka lewat ketuk. */
.sidebar{
  background:var(--sidebar); color:var(--ink-2);
  display:flex; flex-direction:column;
  position:sticky; top:0; height:100vh; overflow:visible;
  z-index:var(--lapis-sidebar);
  border-right:1px solid var(--line);
  width:var(--sidebar-w);
  transition:width var(--gerak) var(--lengkung);
}
body.sb-collapsed{--sidebar-w:var(--sidebar-ciut)}

/* Flyout: lebar penuh kembali TANPA menggeser kolom konten. Yang melebar
   hanya elemen sidebar-nya; grid #app tetap memakai --sidebar-w yang ciut. */
body.sb-collapsed .sidebar.sb-flyout{
  width:250px; box-shadow:var(--shadow-2); border-right-color:var(--line-2);
}
body.sb-collapsed .sidebar.sb-flyout .sb-label,
body.sb-collapsed .sidebar.sb-flyout .sb-caption,
body.sb-collapsed .sidebar.sb-flyout .sb-brand-txt,
body.sb-collapsed .sidebar.sb-flyout .sb-user-txt,
body.sb-collapsed .sidebar.sb-flyout .sb-toggle .chev,
body.sb-collapsed .sidebar.sb-flyout .sb-badge,
body.sb-collapsed .sidebar.sb-flyout .sb-cari-bung,
body.sb-collapsed .sidebar.sb-flyout #btnKeluar{display:flex}
body.sb-collapsed .sidebar.sb-flyout .sb-label,
body.sb-collapsed .sidebar.sb-flyout .sb-caption,
body.sb-collapsed .sidebar.sb-flyout .sb-user-txt span,
body.sb-collapsed .sidebar.sb-flyout .sb-user-txt b{display:block}
body.sb-collapsed .sidebar.sb-flyout .sb-item,
body.sb-collapsed .sidebar.sb-flyout .sb-toggle{justify-content:flex-start;padding-left:15px;padding-right:14px}
body.sb-collapsed .sidebar.sb-flyout .sb-group.open .sb-sub{display:block}
body.sb-collapsed .sidebar.sb-flyout .sb-brand{justify-content:flex-start;padding:12px 14px}
body.sb-collapsed .sidebar.sb-flyout .sb-user{justify-content:flex-start}
/* Tooltip tidak perlu saat seluruh sidebar sudah melebar — labelnya sudah
   terbaca, dan dua keterangan sekaligus hanya saling menutupi. */
body.sb-collapsed .sidebar.sb-flyout .sb-item[data-tip]:hover::after,
body.sb-collapsed .sidebar.sb-flyout .sb-toggle[data-tip]:hover::after{display:none}

.sb-brand{
  display:flex; align-items:center; gap:11px; padding:12px 14px; min-height:var(--topbar-h);
  border-bottom:1px solid var(--line); flex:none; background:var(--sidebar-2);
}
.sb-logo{width:34px;height:34px;border-radius:var(--r-sm);flex:none;background:#fff;
  padding:3px;object-fit:contain;border:1px solid var(--line)}
.sb-brand-txt{min-width:0; overflow:hidden}
.sb-brand-txt b{display:block;font-family:var(--font-display);font-size:14px;font-weight:800;
  letter-spacing:-.01em;white-space:nowrap;color:var(--ink)}
.sb-brand-txt span{display:block;font-size:10.5px;color:var(--ink-3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

/* Pencarian menu. Pada 17 halaman ini masih bisa ditelusuri mata, tetapi
   mengetik dua huruf tetap lebih cepat daripada memindai dua grup. */
.sb-cari-bung{position:relative;padding:9px 11px 4px;flex:none}
.sb-cari{width:100%;height:32px;padding:0 10px 0 30px;font-size:12.5px;
  border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--card-2);color:var(--ink)}
.sb-cari::placeholder{color:var(--ink-3)}
.sb-cari-ico{position:absolute;left:20px;top:50%;transform:translateY(-3px);
  width:14px;height:14px;color:var(--ink-3);pointer-events:none}
.sb-kosong{padding:14px 16px;font-size:12px;color:var(--ink-3);line-height:1.5}

.sb-scroll{
  flex:1; overflow-y:auto; overflow-x:hidden; padding:6px 0 14px;
  scrollbar-width:thin;
  scrollbar-color:var(--line-2) transparent;
}
.sb-scroll::-webkit-scrollbar{width:8px}
.sb-scroll::-webkit-scrollbar-thumb{background:var(--line-2); border-radius:var(--r-pil);
  border:2px solid var(--sidebar)}
.sb-scroll::-webkit-scrollbar-track{background:transparent}

.sb-group{margin-bottom:2px}
.sb-caption{
  padding:11px 16px 5px; font-size:9.5px; font-weight:800; letter-spacing:.11em;
  text-transform:uppercase; color:var(--ink-3); white-space:nowrap;
}
.sb-toggle{
  display:flex; align-items:center; gap:11px; width:100%;
  padding:9px 14px 9px 15px; background:none; border:none; cursor:pointer;
  color:var(--ink-2); font-size:12.5px; font-weight:700; text-align:left;
  border-radius:0; transition:background var(--gerak-cepat), color var(--gerak-cepat);
}
.sb-toggle:hover{background:var(--hover); color:var(--blue)}
.sb-toggle .chev{margin-left:auto; transition:transform var(--gerak) var(--lengkung);
  flex:none; opacity:.55}
.sb-group.open .sb-toggle .chev{transform:rotate(90deg)}
/* Akordeon: submenu tumbuh, tidak muncul-hilang mendadak. max-height dipakai
   karena tinggi isinya tidak diketahui sebelum digambar. */
.sb-sub{max-height:0; overflow:hidden; padding:0;
  transition:max-height var(--gerak-lambat) var(--lengkung)}
.sb-group.open .sb-sub{max-height:520px; padding:1px 0 5px}

.sb-item{
  display:flex; align-items:center; gap:11px; width:100%;
  padding:8px 14px 8px 15px; background:none; border:none; cursor:pointer;
  color:var(--ink-2); font-size:13px; font-weight:500;
  /* Menu ini <a> sungguhan (supaya bisa dibuka di tab baru dan dibaca
     pembaca layar sebagai tautan), jadi garis bawah bawaan browser berlaku
     kalau tidak dimatikan — dan tujuh belas menu bergaris bawah terbaca
     sebagai dinding tautan, bukan navigasi. */
  text-decoration:none;
  text-align:left; position:relative;
  transition:background var(--gerak-cepat), color var(--gerak-cepat);
}
.sb-item:hover{background:var(--hover); color:var(--blue)}
.sb-item:active{background:var(--tekan)}
/* Menu aktif: warna aksen + garis tebal di tepi + tebal huruf. Tiga penanda
   sekaligus, supaya tidak bergantung pada warna saja. */
.sb-item[aria-current="page"]{background:var(--blue-soft); color:var(--blue); font-weight:700}
.sb-item[aria-current="page"]::before{
  content:''; position:absolute; left:0; top:5px; bottom:5px; width:3px;
  border-radius:0 3px 3px 0; background:var(--blue);
}
.sb-sub .sb-item{padding-left:44px; font-size:12.5px}
.sb-dot{width:6px;height:6px;border-radius:var(--r-pil);flex:none;background:currentColor;opacity:.42}
.sb-sub .sb-item[aria-current="page"] .sb-dot{opacity:1}
.sb-ico{width:18px;height:18px;flex:none;opacity:.72}
.sb-item[aria-current="page"] .sb-ico,
.sb-item:hover .sb-ico,
.sb-toggle:hover .sb-ico{opacity:1}
.sb-label{white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.sb-badge{
  margin-left:auto; flex:none; min-width:19px; height:19px; padding:0 6px;
  border-radius:var(--r-pil); background:var(--blue); color:var(--on-accent);
  font-size:10.5px; font-weight:800; display:grid; place-items:center;
  font-variant-numeric:tabular-nums;
}

.sb-foot{flex:none; border-top:1px solid var(--line); padding:9px; background:var(--sidebar-2)}
.sb-user{display:flex; align-items:center; gap:10px; padding:5px 4px; min-width:0}
.sb-avatar{
  width:31px;height:31px;border-radius:var(--r-sm);flex:none;display:grid;place-items:center;
  background:var(--blue); color:var(--on-accent); font-weight:800; font-size:12.5px;
  font-family:var(--font-display);
}
.sb-user-txt{min-width:0;overflow:hidden;flex:1}
.sb-user-txt b{display:block;font-size:12.5px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:var(--ink)}
.sb-user-txt span{display:block;font-size:10.5px;color:var(--ink-3);white-space:nowrap}
#btnKeluar{flex:none;width:30px;height:30px;padding:0;color:var(--ink-3)}
#btnKeluar:hover{color:var(--bad);background:var(--bad-bg)}
#btnKeluar svg{width:16px;height:16px}
body.sb-collapsed #btnKeluar{display:none}

/* Tombol pin: mengunci sidebar tetap ciut atau tetap lebar. Tanpa ini,
   pengguna yang memilih ciut akan terus-menerus membukanya tanpa sengaja
   setiap kali kursor lewat. */
.sb-pin{
  flex:none; width:26px; height:26px; padding:0; margin-left:auto;
  border:1px solid transparent; border-radius:var(--r-xs); background:none;
  color:var(--ink-3); cursor:pointer; display:grid; place-items:center;
  transition:background var(--gerak-cepat), color var(--gerak-cepat);
}
.sb-pin:hover{background:var(--hover); color:var(--blue)}
.sb-pin[aria-pressed="true"]{color:var(--blue); background:var(--blue-soft); border-color:var(--blue-soft-2)}
.sb-pin svg{width:14px;height:14px}
body.sb-collapsed .sb-pin{display:none}
body.sb-collapsed .sidebar.sb-flyout .sb-pin{display:grid}

/* Mode ciut: sembunyikan teks, pusatkan ikon */
body.sb-collapsed .sb-label,
body.sb-collapsed .sb-caption,
body.sb-collapsed .sb-brand-txt,
body.sb-collapsed .sb-user-txt,
body.sb-collapsed .sb-toggle .chev,
body.sb-collapsed .sb-cari-bung,
body.sb-collapsed .sb-badge{display:none}
body.sb-collapsed .sb-item,
body.sb-collapsed .sb-toggle{justify-content:center; padding-left:0; padding-right:0}
body.sb-collapsed .sb-sub{max-height:0!important; padding:0}
body.sb-collapsed .sb-brand{justify-content:center; padding:12px 6px}
body.sb-collapsed .sb-user{justify-content:center}

/* Tooltip saat ciut — hanya bila penunjuknya memang bisa hover. */
@media (hover:hover){
  body.sb-collapsed .sb-item[data-tip]:hover::after,
  body.sb-collapsed .sb-toggle[data-tip]:hover::after{
    content:attr(data-tip); position:absolute; left:calc(100% + 10px); top:50%;
    transform:translateY(-50%); background:var(--navy); color:#fff;
    padding:6px 10px; border-radius:var(--r-xs); font-size:12px; white-space:nowrap;
    box-shadow:var(--shadow-2); z-index:var(--lapis-flyout); font-weight:600;
    pointer-events:none;
  }
}

/* ══════════════════ TOPBAR ══════════════════ */
.main{min-width:0; display:flex; flex-direction:column}
.topbar{
  display:flex; align-items:center; gap:13px; min-height:var(--topbar-h);
  padding:9px 18px; background:var(--card); border-bottom:1px solid var(--line);
  position:sticky; top:0; z-index:var(--lapis-topbar);
}
.crumb{display:flex; align-items:center; gap:7px; font-size:13px; color:var(--ink-3);
  min-width:0; flex-wrap:nowrap; overflow:hidden}
.crumb b{color:var(--ink); font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/* Tingkat di atas bisa diklik untuk kembali; halaman yang sedang dibuka
   tidak — menautkan halaman ke dirinya sendiri hanya membingungkan. */
.crumb a{color:var(--ink-3); text-decoration:none; white-space:nowrap;
  border-radius:var(--r-xs); padding:1px 3px}
.crumb a:hover{color:var(--blue); background:var(--hover)}
.crumb span[aria-hidden]{opacity:.5; flex:none}
@media(max-width:700px){
  /* Di layar sempit hanya halaman aktif yang bertahan: tingkat di atas
     sudah terwakili sidebar, dan remah yang terpotong di tengah lebih
     menyesatkan daripada tidak ada sama sekali. */
  .crumb > :not(b){display:none}
}
/* Bilah tombol di topbar.
   `min-width:0` dan `overflow-x:auto` berlaku di SEMUA lebar, bukan hanya di
   layar HP. Diukur: pada lebar 800–1000 px bilah ini butuh 539 px sementara
   sisa ruangnya kurang — dan tanpa dua sifat itu ia MENDORONG halaman jadi
   bisa digeser mendatar, sampai 91 px. Perbaikan sebelumnya hanya dipasang
   di dalam @media (max-width:760px), jadi pita di antaranya tidak terjaga
   sama sekali.

   Di layar lebar keduanya tidak berpengaruh: isinya muat, jadi tidak ada
   yang digulir dan tidak ada yang menyusut. */
.top-act{
  margin-left:auto; display:flex; align-items:center; gap:9px;
  min-width:0; overflow-x:auto; scrollbar-width:none;
}
.top-act::-webkit-scrollbar{display:none}
/* Tombol tidak boleh ikut menyusut. Tanpa ini flexbox memampatkan tulisan
   "Publikasikan ke Purchasing" jadi dua baris terpotong alih-alih
   menggulirkan bilahnya — dan tombol yang terpotong terbaca sebagai rusak,
   bukan sebagai tanda ada yang perlu digeser. */
.top-act > *{flex:none}

/* Tanda bahwa masih ada isi di samping — scrollbar-nya sengaja disembunyikan,
   jadi tanpa ini tidak ada apa pun yang memberi tahu bilahnya bisa digeser.
   Dua lapis pertama berjangkar `local` sehingga MENUTUPI bayangan begitu
   gulirannya mentok; lapis bayangan berjangkar `scroll`, menempel pada
   kotaknya. Tanpa satu baris JavaScript. */
.top-act{
  background:
    linear-gradient(to right, var(--card) 60%, rgba(255,255,255,0)) left center / 26px 100% no-repeat local,
    linear-gradient(to left,  var(--card) 60%, rgba(255,255,255,0)) right center / 26px 100% no-repeat local,
    linear-gradient(to right, var(--line-2), rgba(255,255,255,0)) left center / 13px 100% no-repeat scroll,
    linear-gradient(to left,  var(--line-2), rgba(255,255,255,0)) right center / 13px 100% no-repeat scroll;
}

/* Kotak cari di topbar. Bukan input sungguhan melainkan TOMBOL yang membuka
   palet: satu kotak untuk berpindah halaman dan menjalankan perintah lebih
   berguna daripada dua kotak cari yang mirip tapi berbeda isinya. */
.tb-cari{display:flex;align-items:center;gap:8px;height:34px;padding:0 10px;margin-left:14px;
  border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--card-2);
  color:var(--ink-3);font-size:12.5px;cursor:pointer;min-width:190px;
  transition:border-color var(--gerak-cepat), background var(--gerak-cepat)}
.tb-cari:hover{border-color:var(--blue);background:var(--card);color:var(--ink-2)}
.tb-cari svg{width:15px;height:15px;flex:none}
.tb-cari-teks{flex:1;text-align:left}
.tb-kbd{font-family:var(--font-mono);font-size:10px;font-weight:600;color:var(--ink-3);
  border:1px solid var(--line-2);border-radius:var(--r-xs);padding:1px 5px;background:var(--card);
  flex:none}
@media(max-width:900px){
  /* Di layar sempit tombolnya menyusut jadi ikon: judul halaman lebih
     berhak atas lebar yang tersisa. */
  .tb-cari{min-width:0;margin-left:8px;padding:0 9px}
  .tb-cari-teks,.tb-kbd{display:none}
}

/* ══════════════════ HALAMAN ══════════════════ */
.page{padding:18px 20px 44px; display:none}
.page.active{display:block}
.page-head{display:flex; align-items:flex-end; gap:14px; margin-bottom:16px; flex-wrap:wrap}
/* Tombol Bantuan didorong ke ujung KANAN kepala halaman, tempat yang sama di
   seluruh halaman. margin-left:auto, bukan justify-content pada induknya —
   induknya juga memuat judul dan keterangan yang harus tetap rapat di kiri. */
.pd-kepala{margin-left:auto; flex:none; align-self:center}

/* ── Tombol Urungkan / Ulangi di kepala halaman ───────────────────────
   Rumahnya sama dengan tombol Bantuan, dan alasannya sama: bilah aksi
   atas DITIMPA setiap kali form menggambar ulang tombolnya, dan pada
   halaman tanpa dokumen ia memang kosong sama sekali. Kepala halaman
   selalu ada dan tempatnya sama di seluruh halaman.

   Yang mengambil sisa ruang adalah blok undo, dan tombol Bantuan menempel
   di sebelahnya. Kalau keduanya sama-sama memakai margin-left:auto, sisa
   ruangnya DIBAGI DUA dan muncul jarak menganga di antara keduanya —
   dua kelompok tombol yang terlihat tidak berhubungan padahal keduanya
   milik kepala halaman yang sama. */
.undo-kepala{margin-left:auto; flex:none; align-self:center;
  display:inline-flex; gap:6px}
.undo-kepala + .pd-kepala{margin-left:0}
/* Tombol mati harus TERLIHAT mati. Tanpa ini ia tetap tampak bisa ditekan,
   dan orang menekannya berulang kali menunggu sesuatu terjadi. */
.undo-kepala .btn:disabled{opacity:.38; cursor:not-allowed}
.undo-kepala .btn svg{width:17px; height:17px}
/* WAJIB, dan diukur: tanpa ini blok judul memakai lebar aslinya (min-width
   bawaan flex item adalah `auto`, yaitu selebar isinya), jadi pada 360 px
   tombol Bantuan terdorong keluar sampai 87 px di halaman LPJ yang
   keterangannya panjang. Dengan min-width:0 blok judulnya yang mengalah. */
.page-head > div{min-width:0; flex:1 1 auto}
/* MENCOLOK, bukan lembut (permintaan MRI, 4 Sep 2026). Tombol ini harus
   ditemukan oleh orang yang sedang bingung — dan orang yang sedang bingung
   memindai layar mencari sesuatu yang menonjol, bukan sesuatu yang serasi.
   Lime, bukan biru: biru sudah dipakai seluruh tombol utama di aplikasi ini,
   jadi tombol biru kelima di layar yang sama tidak menonjol sama sekali.
   Teks navy di atas lime — aturan lime di tokens.css, tidak pernah putih. */
.pd-bantuan{display:inline-flex; align-items:center; gap:6px;
  background:var(--lime); border-color:var(--lime-dark); color:var(--on-lime);
  font-weight:800; box-shadow:0 1px 3px rgba(15,23,51,.12)}
.pd-bantuan:hover{background:var(--lime-dark); border-color:var(--lime-dark);
  color:var(--on-lime)}
.pd-bantuan svg{width:15px; height:15px; flex:none}
@media(max-width:560px){
  /* Di layar sempit kepala halaman sudah memuat judul dua baris. Tulisannya
     disembunyikan, ikonnya tetap — aria-label-nya tetap menerangkan. */
  .pd-bantuan span{display:none}
}
.page-head h1{font-size:20px; font-weight:800; letter-spacing:-.01em}
/* ── Keterangan di bawah judul halaman: 100 KARAKTER per baris ─────────
   Permintaan MRI, 8 Sep 2026. Keterangan halaman Project berjalan sekitar
   200 karakter dalam satu baris selebar layar, dan baris sepanjang itu
   membuat mata kehilangan tempat saat berpindah ke awal baris berikutnya —
   sebabnya jarak lompatannya jauh melebihi yang bisa dilacak sekali gerak.

   `ch` dipakai karena satuannya memang KARAKTER: 100ch berarti selebar
   seratus angka nol pada font yang berlaku. Menuliskannya dalam piksel
   berarti menebak, dan tebakannya meleset begitu ukuran fontnya berubah.
   Yang lebih pendek dari itu tetap satu baris — batas ini menahan, bukan
   memaksa. */
.page-head p{margin:2px 0 0; font-size:12.5px; color:var(--ink-3);
  max-width:100ch; line-height:1.55}
.page-head .spacer{margin-left:auto}

/* Layout 3 zona (dipakai semua form) */
.shell3{display:grid; grid-template-columns:262px minmax(0,1fr) 288px; gap:16px; align-items:start}
@media (max-width:1340px){.shell3{grid-template-columns:238px minmax(0,1fr)} .zona-kanan{display:none}}
@media (max-width:1000px){.shell3{grid-template-columns:minmax(0,1fr)} .zona-kiri{display:none}}
.zona-kiri,.zona-kanan{position:sticky; top:calc(var(--topbar-h) + 14px); display:flex; flex-direction:column; gap:14px}
.zona-tengah{display:flex; flex-direction:column; gap:16px; min-width:0}

/* Daftar dokumen di zona kiri */
.cari{width:100%; height:36px; padding:0 11px; border:1px solid var(--line-2); border-radius:var(--r-sm); background:var(--card-2)}
.cari::placeholder{color:var(--ink-3)}
.dok-list{display:flex; flex-direction:column; gap:5px; padding:8px; max-height:calc(100vh - 260px); overflow-y:auto}
.dok{
  display:grid; grid-template-columns:1fr auto; gap:3px 8px; width:100%;
  padding:9px 11px; border-radius:10px; border:1px solid transparent;
  background:transparent; text-align:left; cursor:pointer; transition:background .13s;
}
.dok:hover{background:var(--card-2)}
.dok[aria-current="true"]{background:var(--blue-soft); border-color:var(--blue)}
.dok-nama{font-weight:600; font-size:12.5px; line-height:1.35; grid-column:1}
.dok-meta{grid-column:1/-1; font-family:var(--font-mono); font-size:10px; color:var(--ink-3); font-variant-numeric:tabular-nums}
.dok .pil{grid-column:2; grid-row:1; align-self:start}
/* KEADAAN KOSONG. "Belum ada data" memberi tahu apa yang TIDAK ada, tetapi
   tidak memberi tahu apa yang harus dilakukan. Bentuk yang berguna: ikon,
   satu kalimat penjelas, dan jalan keluarnya. Form yang belum memberi teks
   panjang tetap tampil rapi karena hanya barisnya yang dipakai. */
.kosong{padding:26px 16px; text-align:center; font-size:12.5px; color:var(--ink-3);
  line-height:1.6; display:flex; flex-direction:column; align-items:center; gap:3px}
.kosong-ikon{font-size:26px; line-height:1; opacity:.55; margin-bottom:3px}
.kosong b{display:block; font-size:13.5px; color:var(--ink-2); font-weight:700}
.kosong .btn{margin-top:9px}

/* SKELETON. Lebih baik daripada pemutar di tengah layar: bentuknya sudah
   menyerupai isi yang akan datang, jadi mata tidak perlu menyesuaikan ulang
   ketika datanya tiba. */
.skel{background:linear-gradient(90deg,var(--sunk) 25%,var(--card-2) 37%,var(--sunk) 63%);
  background-size:400% 100%; animation:skelGeser 1.3s ease-in-out infinite;
  border-radius:var(--r-xs)}
@keyframes skelGeser{from{background-position:100% 0}to{background-position:0 0}}
.skel-baris{height:13px;margin:9px 0}
.skel-baris:nth-child(3n){width:72%}
.skel-baris:nth-child(3n+1){width:92%}
/* Rangka halaman saat modulnya masih diunduh. Ukurannya sengaja mendekati
   tata letak sungguhan — judul, lalu panel daftar, lalu panel area kerja —
   supaya isinya tidak melompat begitu tiba. */
.skel-hal{padding:2px 0}
.skel-judul{height:26px;width:230px;margin-bottom:20px}
.skel-panel{height:172px;margin-bottom:15px;border-radius:var(--r)}
.skel-panel-2{height:330px}

/* ══════════════════ DASHBOARD ══════════════════ */
.kpi-row{display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:13px; margin-bottom:18px}
.kpi{
  background:var(--card); border:1px solid var(--line); border-radius:var(--r);
  padding:14px 15px; box-shadow:var(--shadow-1); position:relative; overflow:hidden;
}
.kpi::before{content:''; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--kpi-c,var(--blue))}
.kpi-lbl{font-size:10.5px; font-weight:800; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3)}
.kpi-val{font-family:var(--font-display); font-size:24px; font-weight:800; margin-top:5px; font-variant-numeric:tabular-nums; letter-spacing:-.02em}
.kpi-sub{font-size:11.5px; color:var(--ink-3); margin-top:2px}
.kpi-sub b{color:var(--ink-2)}

.dash-grid{display:grid; grid-template-columns:minmax(0,1.55fr) minmax(0,1fr); gap:16px; align-items:start}
@media (max-width:1080px){.dash-grid{grid-template-columns:minmax(0,1fr)}}

/* Baris "perlu tindakan" */
.aksi-list{display:flex; flex-direction:column}
.aksi{
  display:flex; align-items:center; gap:11px; padding:11px 15px;
  border-bottom:1px solid var(--line); cursor:pointer; background:none;
  border-left:none; border-right:none; border-top:none; width:100%; text-align:left;
}
.aksi:last-child{border-bottom:none}
.aksi:hover{background:var(--card-2)}
.aksi-ico{
  width:32px;height:32px;border-radius:9px;flex:none;display:grid;place-items:center;
  background:var(--blue-soft); color:var(--blue);
}
.aksi-txt{flex:1; min-width:0}
.aksi-txt b{display:block; font-size:13px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.aksi-txt span{display:block; font-size:11.5px; color:var(--ink-3)}
.aksi-umur{flex:none; font-family:var(--font-mono); font-size:11.5px; font-variant-numeric:tabular-nums; color:var(--ink-3)}
.aksi-umur.tua{color:var(--bad); font-weight:700}

/* Log aktivitas ringkas */
.log-list{display:flex; flex-direction:column; gap:0}
.log-row{display:flex; gap:10px; padding:9px 15px; border-bottom:1px solid var(--line); font-size:12.5px}
.log-row:last-child{border-bottom:none}
.log-ava{
  width:24px;height:24px;border-radius:7px;flex:none;display:grid;place-items:center;
  background:var(--sunk); color:var(--ink-2); font-size:10.5px; font-weight:800;
}
.log-txt{flex:1; min-width:0; line-height:1.45}
.log-txt b{font-weight:700}
.log-txt .kode{font-family:var(--font-mono); font-size:11.5px; color:var(--blue)}
.log-wkt{flex:none; font-size:11px; color:var(--ink-3); font-family:var(--font-mono); white-space:nowrap}

/* ── Muka A4 (pratinjau cetak di dalam form) ──────────────────────────── */
.muka{background:var(--card); border:1px solid var(--line-2); border-radius:var(--r); padding:20px 22px 16px; box-shadow:var(--shadow-2)}
.muka-kop{display:flex; align-items:flex-start; gap:12px; padding-bottom:11px; border-bottom:2px solid var(--blue)}
.muka-kop img{width:34px;height:34px;object-fit:contain;flex:none}
.kop-teks{min-width:0;flex:1}
.kop-nama{font-family:var(--font-display); font-weight:800; font-size:11.5px; color:var(--blue)}
.kop-alamat{font-size:9px; color:var(--ink-3); line-height:1.45}
.kop-ref{font-family:var(--font-mono); font-size:9.5px; color:var(--ink-3); white-space:nowrap; padding-top:2px; text-align:right}
.muka-judul{text-align:center; font-family:var(--font-display); font-weight:800; font-size:15px; color:var(--blue); letter-spacing:.04em; margin:13px 0 15px}
.meta2{display:grid; grid-template-columns:1fr 1fr; gap:5px 26px; margin-bottom:15px}
@media (max-width:700px){.meta2{grid-template-columns:1fr}}
.meta-sel{display:grid; grid-template-columns:96px minmax(0,1fr); gap:8px; font-size:12px; margin:0}
.meta-sel dt{font-weight:700; color:var(--ink-2)}
.meta-sel dd{margin:0; color:var(--ink); overflow:hidden; text-overflow:ellipsis}

/* ── Ringkasan zona kanan ─────────────────────────────────────────────── */
.ringkas{display:flex; flex-direction:column; gap:8px; margin:0}
.ring-baris{display:flex; align-items:center; justify-content:space-between; gap:10px; font-size:12.5px}
.ring-baris dt{color:var(--ink-2)}
.ring-baris dd{margin:0; font-family:var(--font-mono); font-weight:600; font-variant-numeric:tabular-nums}
.ring-total{border-top:1px solid var(--line); padding-top:9px; margin-top:3px}
.ring-total dt{font-weight:800; color:var(--ink)}
.ring-total dd{font-size:15px; font-weight:800; color:var(--blue)}
.bar{height:6px; border-radius:99px; background:var(--sunk); overflow:hidden; margin-top:4px}
.bar i{display:block; height:100%; border-radius:99px; background:var(--blue)}

/* ── Layar login ──────────────────────────────────────────────────────── */
#login{position:fixed; inset:0; z-index:var(--lapis-login); display:grid; place-items:center; padding:20px;
  background:linear-gradient(135deg,var(--navy),var(--blue-2) 55%,var(--blue))}
#login.hide{display:none}
.login-card{background:var(--card); border-radius:var(--r-lg); box-shadow:var(--shadow-2); width:100%; max-width:380px; overflow:hidden}
.login-head{padding:26px 26px 20px; text-align:center; border-bottom:1px solid var(--line)}
.login-head img{width:52px;height:52px;object-fit:contain;margin-bottom:11px}
.login-head h1{font-size:17px; font-weight:800}
.login-head p{margin:4px 0 0; font-size:12px; color:var(--ink-3)}
.login-body{padding:20px 26px 26px; display:flex; flex-direction:column; gap:13px}

/* Kotak ID+domain di layar masuk. Domainnya (`.id-domain`) TEKS BIASA, bukan
   bagian dari nilai isian — itu bedanya dengan kotak yang mencegat
   Backspace supaya domainnya "kelihatan tidak bisa dihapus": cara itu
   rapuh pada paste dan kursor yang digeser tangan; teks tetap yang memang
   bukan bagian isian tidak bisa rusak sama sekali. Dibungkus supaya terlihat
   SATU kotak — batas & latar dipindah ke pembungkusnya, input di dalamnya
   polos tanpa batas sendiri. */
.id-gab{
  display:flex; align-items:center; height:38px;
  border:1px solid var(--line-in); border-radius:var(--r-sm); background:var(--card-2);
  padding-right:11px;
}
.id-gab input{
  flex:1; min-width:0; height:100%; padding:0 3px 0 11px;
  border:0; border-radius:var(--r-sm) 0 0 var(--r-sm); background:transparent;
}
/* TIDAK menekan outline bawaan input — cincin fokus global
   (:where(...):focus-visible di core/base.css) tetap dipakai apa adanya,
   supaya navigasi keyboard tidak kehilangan tandanya di kotak ini saja. */
.id-domain{font-size:13.5px; color:var(--ink-3); white-space:nowrap; user-select:none}
.role-pick{display:flex; flex-direction:column; gap:7px}
.role-opt{
  display:flex; align-items:center; gap:11px; padding:11px 13px; cursor:pointer;
  border:1.5px solid var(--line-2); border-radius:10px; background:var(--card-2);
  transition:border-color .13s, background .13s;
}
.role-opt:hover{border-color:var(--line-in)}
.role-opt.sel{border-color:var(--blue); background:var(--blue-soft)}
.role-opt b{font-size:13px; display:block}
.role-opt span{font-size:11.5px; color:var(--ink-3)}
.role-ava{width:32px;height:32px;border-radius:9px;flex:none;display:grid;place-items:center;background:var(--blue);color:#fff;font-weight:800;font-size:13px}

/* ── Cetak ────────────────────────────────────────────────────────────── */
@media print{
  .sidebar,.topbar,#toastWrap,.zona-kiri,.zona-kanan,.no-print,#login{display:none!important}
  /* Wadah bergulir tata dua kolom dilepas saat mencetak — kalau tidak, isi
     yang berada di luar layar ikut terpotong dari kertas. */
  [data-tata="dua"] .tata-2,
  [data-tata="dua"] .tata-kiri,
  [data-tata="dua"] .tata-kanan{height:auto!important;overflow:visible!important}
  #app{grid-template-columns:1fr}
  .shell3{grid-template-columns:1fr}
  .page{padding:0}
  .muka{box-shadow:none;border:none}
}

/* ── Kwitansi: kepala 3 kolom × 3 baris ──────────────────────────────
   Kolom 1 dan 2 memuat enam isian pendek. Kolom 3 ditempati dua bidang teks
   bebas: "Untuk Pembayaran" di baris pertama, lalu "Catatan" yang menjulur
   dua baris ke bawah supaya tingginya sejajar dengan sisa kolom di kirinya —
   tanpa itu, kolom 3 berakhir sepertiga lebih pendek dan sudut kanan-bawah
   panel menganga kosong. */
.kw-header .kw-bayar{grid-column:3;grid-row:1}
.kw-header .kw-catatan{grid-column:3;grid-row:2 / span 2;display:flex;flex-direction:column}
.kw-header .kw-catatan textarea{flex:1;min-height:96px;resize:vertical}
@media (max-width:700px){
  /* Di bawah 700px .grid-3 sudah turun jadi satu kolom (core/base.css),
     jadi penempatan kolom/baris di atas harus dilepas — kalau tidak, kedua
     bidang itu tetap dipaksa ke kolom 3 yang sudah tidak ada. */
  .kw-header .kw-bayar,
  .kw-header .kw-catatan{grid-column:auto;grid-row:auto}
}

/* ── Data Master: bilah cari, halaman, penanda ────────────────────────
   Tabel master Barang berisi 105.602 baris. Yang digambar dibatasi satu
   halaman; penyaringannya tetap atas seluruh data. */
.mstr-bar{display:flex;align-items:center;gap:10px;margin-bottom:11px;flex-wrap:wrap}
.mstr-cari{flex:1 1 240px;max-width:340px;height:32px}
.mstr-jml{font-size:12.5px;color:var(--ink-3);white-space:nowrap}
.mstr-nav{display:flex;align-items:center;justify-content:center;gap:4px;margin-top:0}

/* ── Tabel Data Master dirapikan (permintaan MRI, 8 Sep 2026) ──────────
   SELURUH gayanya dilingkupi `.tbl-master`. Kelas `.tbl` yang polos dipakai
   14 form dokumen; merapikannya di sana berarti mengubah tampilan setiap
   pengajuan, PO, dan BAP yang pernah dibuka — perubahan yang tidak diminta
   siapa pun dan tidak akan ada yang menghubungkannya dengan permintaan ini.

   Yang bisa dicapai lewat CSS dikerjakan lewat CSS: sel tabel master berupa
   <input> terkunci, dan menggantinya dengan <span> akan merembet ke jalur
   sunting, pencarian, dan uji yang membacanya. */
.mstr-judul{display:flex;align-items:baseline;gap:9px;min-width:0}
.mstr-judul b{font-size:15px;color:var(--ink)}

/* Kepala tabel: bidang berwarna, bukan sekadar garis bawah. Pada tabel
   selebar ini kepala yang menyatu dengan isinya membuat mata kehilangan
   patokan begitu halaman digulir. */
/* ── PERMUKAAN LENGKET WAJIB LEGAP (16 Sep 2026) ──────────────────────
   Dilaporkan MRI: kepala tabel Data Master terlihat menumpuk di atas baris
   datanya. Sebabnya bukan z-index dan bukan sticky-nya, melainkan LATARNYA
   yang tembus pandang: sejak palet v3 (commit 13c0e8c, 15 Sep 2026)

       --card-2    #FAFCFE  ->  #8338EC0A   (legap  ->   4% kelegapan)
       --blue-soft          ->  #8338EC1C   (            11% kelegapan)

   Kepala tabel karena itu 89-96% tembus pandang, dan setiap baris yang
   bergulir di bawahnya terlihat menembusnya. Tidak ada satu pun galat;
   yang berubah cuma arti sebuah token.

   TOKENNYA TIDAK BOLEH DIBUAT LEGAP. Satu token dipakai dua maksud yang
   berlawanan: `th` yang lengket butuh legap, sedangkan belang baris
   (`tr:nth-child(even)`) justru HARUS tembus pandang — ia memang cuma
   cucuran warna di atas kartu putih, dan di sana nilai ber-alfa itu benar.

   Jadi yang dilegapkan PEMAKAIANNYA, bukan tokennya: warna kartu sebagai
   alas, lalu cucuran yang sama ditumpuk di atasnya lewat background-image.
   Rupanya sama persis dengan yang dimaksudkan, tetapi tidak bisa ditembus.
   Satu sumber kebenaran untuk warnanya tetap token itu sendiri — tidak ada
   nilai kedua yang bisa menyimpang. */
.tbl-master thead th{
  background:var(--card);
  background-image:linear-gradient(var(--blue-soft),var(--blue-soft));
  border-bottom:1px solid var(--line-2);
  padding:0;white-space:nowrap}
.tbl-master thead th.mstr-no,
.tbl-master thead th.mstr-aksi-kol{padding:9px 12px;font-size:12px;color:var(--ink-2)}
.mstr-no{width:52px;text-align:center;color:var(--ink-3);font-size:12.5px}
.mstr-aksi-kol{width:auto;text-align:left}

/* Kepala kolom adalah TOMBOL, bukan teks yang kebetulan bisa diklik:
   ia dapat fokus keyboard dan terbaca pembaca layar sebagai tindakan. */
.mstr-urut{display:flex;align-items:center;gap:6px;width:100%;
  padding:9px 12px;border:0;background:none;cursor:pointer;
  font:inherit;font-size:12px;font-weight:600;color:var(--ink-2);text-align:left}
.mstr-urut:hover{background:var(--blue-soft-2);color:var(--ink)}
.mstr-urut:focus-visible{outline:2px solid var(--fokus);outline-offset:-2px}
.mstr-urut.aktif{color:var(--blue)}
/* Panahnya diredupkan sampai kolomnya dipakai — delapan panah pekat di
   satu baris terbaca seperti hiasan, dan yang sedang aktif ikut hilang. */
.mstr-urut-ikon{font-size:10px;color:var(--ink-3);flex:none}
.mstr-urut.aktif .mstr-urut-ikon{color:var(--blue)}

/* Belang tipis + sorotan baris: pada tabel selebar ini mata mudah pindah
   baris di tengah jalan, dan angka harga yang terbaca dari baris lain
   adalah kekeliruan yang tidak memberi tanda apa pun. */
.tbl-master tbody tr:nth-child(even){background:var(--blue-soft-2)}
.tbl-master tbody tr:hover{background:var(--hover)}
.tbl-master tbody tr:hover .mstr-no{color:var(--ink-2)}

/* Kode dibaca sebagai penanda, bukan sebagai kalimat. */
.tbl-master td input[data-k="kode"]{background:var(--blue-soft)!important;
  color:var(--blue);font-weight:600;font-size:12px;border-radius:999px;
  text-align:center;min-width:0}

/* Tombol aksi: bidang lembut berwarna, bukan garis. Tiga ikon berdempetan
   dengan garis tepi masing-masing menghasilkan pagar yang menarik mata
   lebih daripada datanya. Merahnya HANYA untuk hapus — warna yang dipakai
   di dua tempat berbeda berhenti berarti apa-apa. */
/* 34 px, bukan 30. Uji 24 menjaga SETIAP sasaran sentuh tetap >= 32 px:
   di layar sentuh, tombol 30 px berdampingan dengan dua tombol lain berarti
   ibu jari mengenai tetangganya — dan tetangga tombol Edit di sini adalah
   tombol Hapus. Diukur seluruh kotaknya, jadi lebarnya yang menentukan. */
.tbl-master td .btn-icon,
.tbl-master td .btn-sm{border:0;border-radius:9px;background:var(--blue-soft);
  color:var(--blue);min-width:34px;height:34px;padding:0 9px;font-size:13px}
.tbl-master td .btn-icon:hover,
.tbl-master td .btn-sm:hover{background:var(--blue-soft-2);color:var(--blue-hi)}
.tbl-master td .btn-hapus,
.tbl-master td .btn-danger{background:var(--bad-bg);color:var(--bad)}

/* ── Kaki tabel ───────────────────────────────────────────────────────
   Keterangan di kiri, halaman di tengah-kanan, jumlah baris di ujung.
   Dijadikan satu baris supaya "menampilkan 1–50 dari 105.609" dan tombol
   halamannya terbaca sebagai satu keterangan, bukan dua yang terpisah. */
.mstr-kaki{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin-top:12px;padding-top:11px;border-top:1px solid var(--line)}
.mstr-kaki-ket{font-size:12.5px;color:var(--ink-3)}
.mstr-hal-btn{min-width:32px;height:32px;padding:0 9px;border:1px solid var(--line);
  border-radius:9px;background:var(--card);color:var(--ink-2);cursor:pointer;
  font:inherit;font-size:12.5px}
.mstr-hal-btn:hover:not(:disabled){background:var(--hover);color:var(--ink)}
.mstr-hal-btn:disabled{opacity:.42;cursor:default}
.mstr-hal-btn.aktif{background:var(--blue);border-color:var(--blue);color:var(--on-accent);font-weight:600}
.mstr-hal-sela{padding:0 3px;color:var(--ink-3)}
.mstr-perhal{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ink-3)}
.mstr-perhal select{height:32px;padding:0 7px}

@media(max-width:640px){
  .mstr-kaki{justify-content:center}
  .mstr-kaki-ket{width:100%;text-align:center}
  .mstr-perhal{display:none}
}
.mstr-hal{font-size:12.5px;color:var(--ink-3);white-space:nowrap}
.mstr-hal b{color:var(--ink);font-size:13.5px}
.mstr-hal-ket{color:var(--ink-3)}
@media(max-width:640px){ .mstr-hal-ket{display:none} }
/* Kolom yang dibuat sistem (kode, ID) — terlihat, tapi jelas tidak diketik. */
.mstr-ro{background:var(--sunk)!important;color:var(--ink-2);cursor:default}
/* Kolom turunan: dihitung dari kolom lain, bukan disimpan sendiri. */
.mstr-turunan{font-size:12px;color:var(--ink-2);white-space:nowrap}
/* Baris berharga mencurigakan menurut sumber datanya. Beberapa harga di CSV
   jelas keliru — baterai genset seharga gensetnya. Tanpa penanda, angka
   seperti itu terlihat sama meyakinkannya dengan yang benar. */
.mstr-curiga td:first-child{box-shadow:inset 3px 0 0 var(--bad)}
.mstr-curiga input{color:var(--bad)}

/* ── Ragam fokus halaman form ──────────────────────────────────────────
   Ditentukan formPage lewat [data-fokus]. Tabel butuh selebar mungkin;
   formulir justru lebih mudah dibaca bila dibatasi; dokumen ditampilkan
   seperti lembar kertas supaya terasa sebagai halaman, bukan daftar. */
[data-fokus="formulir"] .panel-body > .grid-2{max-width:900px}
[data-fokus="dokumen"] .panel-body{background:var(--sunk);padding:18px 15px}
/* Latar --sunk sengaja dipertahankan supaya area isian terbaca sebagai
   bidang tersendiri, bukan lanjutan bilah judul. Yang diperbaiki adalah
   KONTRASNYA: kolom isian bawaannya --card-2 (#F8FAFC), hanya beda tipis
   dari --sunk (#E4ECF4), sehingga kolomnya nyaris tidak terlihat. Di dalam
   panel ini kolom dibuat putih penuh. */
[data-fokus="dokumen"] .panel-body input,
[data-fokus="dokumen"] .panel-body select,
[data-fokus="dokumen"] .panel-body textarea{background:var(--card)}
/* Lebar lembar sengaja dibatasi ~780px: dengan dua foto berdampingan, itu
   memberi tiap foto sekitar 360px — cukup jelas untuk diperiksa, dan empat
   baris masih terasa sebagai SATU halaman, bukan gulungan tanpa ujung. */
[data-fokus="dokumen"] .lembar{
  background:#fff;border:1px solid var(--line-2);border-radius:10px;
  padding:20px 22px;margin:0 auto 16px;max-width:700px;
  box-shadow:0 1px 3px rgba(15,23,51,.06);
}
[data-fokus="dokumen"] .lembar-kepala{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding-bottom:11px;margin-bottom:13px;border-bottom:1px solid var(--line-2);
}
[data-fokus="dokumen"] .lembar-kepala h3{margin:0;font-size:13.5px;color:var(--navy)}
[data-fokus="dokumen"] .lembar-kepala .no{font-size:11.5px;color:var(--ink-3)}

/* Sepasang tombol mode di atas tabel (Input Manual / Input Otomatis) */
.mode-input{display:flex;gap:7px;margin-bottom:11px;flex-wrap:wrap}
.mode-input .btn{display:inline-flex;align-items:center;gap:6px}

/* ── Tata letak dua kolom (dipakai BAP) ────────────────────────────────
   Bawaannya SATU kolom: pembungkus .tata-2 hanya menjadi grid bila halaman
   memintanya lewat [data-tata="dua"]. Dengan begitu 13 form lain sama sekali
   tidak berubah meski memakai kerangka yang sama. */
.tata-2{display:block}
[data-tata="dua"] .tata-2{display:block}
@media(min-width:1180px){
  [data-tata="dua"] .tata-2{
    display:grid;
    grid-template-columns:minmax(320px,400px) minmax(0,1fr);
    gap:16px;
    align-items:start;
  }
  /* GULIR TERPISAH. Tiap kolom menggulung di dalam wadahnya sendiri, sehingga
     menggulung di daftar BAP tidak menggeser lembar laporan, dan sebaliknya.

     Tingginya DIHITUNG, bukan 100vh: topbar punya tinggi sendiri, dan
     memakai 100vh membuat kolom menembus ke bawah layar sehingga ujung
     lembar tidak pernah bisa dicapai.

     Aturan ini sengaja dikurung di [data-tata="dua"] — hanya BAP yang
     memakainya. 13 form lain tetap menggulung seperti biasa; wadah bergulir
     bertinggi tetap bisa memotong isi pada cetak-dari-browser. */
  [data-tata="dua"] .tata-2{
    height:calc(100vh - var(--topbar-h) - 34px);
    overflow:hidden;
  }
  [data-tata="dua"] .tata-kiri,
  [data-tata="dua"] .tata-kanan{
    height:100%; overflow-y:auto; overflow-x:hidden;
    padding-right:4px;               /* ruang agar batang gulir tidak menimpa isi */
    scrollbar-width:thin;
  }
  [data-tata="dua"] .tata-kiri .switcher{margin-bottom:16px}

  /* ── KEPALA PANEL & BILAH ALAT MENEMPEL SAAT DIGULIR ─────────────────
     Lembar BAP lebih tinggi daripada kolomnya — pada 100% baris keempat ada
     di luar pandangan. Tanpa ini, menggulir ke sana membuang seluruh bilah
     alat dari layar: pindah halaman, unggah, rapatkan, dan perbesaran
     semuanya tertinggal di atas, jadi SETIAP tindakan menuntut menggulir
     balik lebih dulu.

     Hanya di tata dua kolom, dan itu memang satu-satunya yang perlu: di
     sini wadah bergulirnya .tata-kanan, sebuah kotak dengan puncak yang
     jelas. Di layar sempit yang bergulir halamannya sendiri, `top:0`
     menempelkan bilah ini ke puncak VIEWPORT — tepat di bawah topbar yang
     melayang, jadi ia mendarat di belakangnya. */
  [data-tata="dua"] .panel-head{
    position:sticky; top:0; z-index:7;
    background:var(--card);
    border-radius:var(--r) var(--r) 0 0;
  }
  /* Bilah alat menempel PERSIS di bawah kepala panel. Tingginya diukur saat
     berjalan oleh pasangLengket() di forms/bap.js dan dituliskan sebagai
     --bap-kepala-h: nota di kepala panel bisa membungkus jadi dua baris,
     dan angka yang ditulis di sini akan benar hari ini lalu meleset diam-
     diam pada hari notanya memanjang. Cadangannya 44px supaya bilahnya
     tetap masuk akal seandainya pengukurannya belum sempat berjalan. */
  [data-tata="dua"] .bap-nav{
    position:sticky; top:var(--bap-kepala-h, 44px); z-index:6;
    /* BERLATAR, bukan putih polos (permintaan MRI, 4 Sep 2026). Bilah ini
       menempel di puncak kolom sementara lembar putih bergulir di bawahnya;
       dengan latar putih yang sama, batas antara "alat" dan "kertas" hanya
       ditandai satu garis 1 px — dan begitu foto pertama menyentuh garis itu,
       bilahnya terlihat seperti bagian dari lembarnya.

       LEGAP sejak 16 Sep 2026, sebab yang sama dengan kepala tabel: dengan
       --card-2 polos (alfa 4%) kalimat di atas ini menjanjikan sesuatu yang
       tidak dikerjakannya sama sekali — foto lembar bergulir menembusnya.
       Ditemukan saat menelusuri laporan MRI soal kepala tabel, bukan
       dilaporkan sendiri. */
    background:var(--card);
    background-image:linear-gradient(var(--card-2),var(--card-2));
    /* Menembus padding .panel-body supaya isi yang lewat di bawahnya
       tertutup sampai ke tepi panel — bilah yang menyisakan celah 15 px di
       kiri-kanannya memperlihatkan foto yang menyelinap di sampingnya. */
    margin:-13px -15px 13px; padding:11px 15px;
    border-bottom:1px solid var(--line-2);
    box-shadow:0 1px 0 rgba(15,23,51,.04);
  }
}

/* Di kolom kiri yang sempit, kartu mendatar tidak muat — daftarnya berubah
   menjadi menurun. Panah geser kiri/kanan ikut disembunyikan karena tidak
   lagi ada yang digeser. */
@media(min-width:1180px){
  /* .sw-area bawaannya dibatasi 170px (untuk animasi lipat). Dengan kartu
     menurun, isinya jauh lebih tinggi dan akan menembus keluar menimpa bilah
     konteks di bawahnya — jadi batasnya dilonggarkan khusus tata ini. */
  [data-tata="dua"] .switcher:not(.lipat) .sw-area{max-height:52vh}
  [data-tata="dua"] .sw-kartu-area{
    flex-direction:column; overflow-x:hidden; overflow-y:auto; max-height:46vh;
  }
  [data-tata="dua"] .sw-kartu{flex:none;width:100%;min-height:auto}
  [data-tata="dua"] .sw-panah{display:none}
  [data-tata="dua"] .sw-bar{grid-template-columns:1fr 1fr}
}

/* Pagination lembar BAP */
/* Bilah ini menampung banyak hal: pagination, unggah massal, tambah halaman,
   dan pengaturan. Tanpa flex:none pada tombolnya, flexbox akan memampatkan
   isinya sampai teks saling tindih ketika ruang menyempit — dan itu yang
   sempat terjadi. Sekarang tombol menolak dimampatkan dan barisnya melipat. */
/* Bilah satu baris. Dropdown pemilih halaman sudah dibuang — melompat jauh
   dilakukan lewat laci Konteks BAP → tab Halaman, yang memuat daftar halaman
   yang bisa diklik langsung. */
.bap-nav{display:flex;align-items:center;gap:8px;margin-bottom:13px;flex-wrap:wrap;
  /* Di luar tata dua kolom bilah ini berdiri sendiri, jadi ia diberi bidangnya
     sendiri: kotak bertepi lembut, bukan deretan tombol yang mengambang di
     atas latar putih tanpa batas. */
  padding:9px 11px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--card-2)}
/* KELOMPOK DIPISAH GARIS, bukan sekadar jarak. Bilah ini menjawab empat
   pertanyaan berbeda — halaman mana, susun apa, sebesar apa, lalu tindakan —
   dan jarak 8 px yang sama di antara semuanya membuat keempatnya terbaca
   sebagai satu deretan panjang tanpa bentuk. */
/* Pemisahnya JARAK, bukan garis pada tombolnya: tombol punya tepinya sendiri,
   dan menambah garis di salah satu sisinya membuat satu tombol terlihat cacat
   dibanding tetangganya. */
.bap-nav [data-tambah-hal]{margin-left:9px}
.bap-nav [data-unggah-massal]{margin-left:9px}
.bap-nav [data-hapus-hal]{margin-left:auto}
.bap-nav > .btn{flex:none}
/* Panah pindah halaman: WARNA SENDIRI, berbeda dari tombol tindakan di
   sebelahnya (permintaan MRI, 4 Sep 2026). Keduanya menjawab pertanyaan yang
   berbeda — "halaman mana" versus "lakukan apa" — dan sejak tulisannya
   dilepas, satu-satunya yang tersisa untuk membedakannya adalah warnanya.
   Yang mati diberi warna redup, bukan sekadar disamarkan: panah yang terlihat
   sama hidupnya lalu tidak melakukan apa-apa terbaca sebagai aplikasi rusak. */
.bap-hal-nav{background:var(--blue-soft); border-color:var(--info-line);
  color:var(--blue-2); font-weight:800; font-size:15px; line-height:1}
.bap-hal-nav:hover:not(:disabled){background:var(--blue-soft-2); border-color:var(--blue)}
.bap-hal-nav:disabled{background:var(--sunk); border-color:var(--line);
  color:var(--ink-3); opacity:.75}
.bap-nav-ket{font-size:11.5px;color:var(--ink-3);white-space:nowrap;flex:none;
  padding:0 2px}
.bap-nav-ket b{font-size:13px;color:var(--ink)}
@media(max-width:640px){
  /* Di layar sempit enam elemen tidak muat sebaris. Yang dikorbankan lebih
     dulu adalah keterangan jumlah foto — angkanya masih terbaca di strip
     daftar dan di laci konteks. */
  .bap-nav-ket-foto{display:none}
  .bap-nav{gap:6px}
}
/* Di tata dua kolom, lembar memakai lebar kolom kanan sepenuhnya */
@media(min-width:1180px){
  [data-tata="dua"][data-fokus="dokumen"] .lembar{max-width:100%}
}

/* ── BAP: pengatur halaman (di luar lembar) ────────────────────────────── */
.bap-atur{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin-bottom:12px;
  padding:11px 12px;background:var(--card-2);border:1px solid var(--line);border-radius:var(--r-sm)}
.bap-atur .f{margin:0;flex:1;min-width:150px}
.bap-atur .f label{font-size:10.5px}
.bap-atur .f input,.bap-atur .f select{height:32px;font-size:12.5px}
.bap-atur .btn{flex:none}

/* Pembungkus lembar. Tidak membatasi tinggi: lembar tampil pada ukuran asli
   dan halaman digulir seperti biasa. */
.lembar-panggung{overflow:visible}
[data-fokus="dokumen"] .lembar-panggung .lembar{margin-bottom:0}

/* Penanda "bisa diperbesar" di pojok foto */
.slot-perbesar{position:absolute;left:6px;bottom:6px;z-index:1;font-size:12px;line-height:1;
  color:#fff;background:rgba(15,23,51,.55);border-radius:5px;padding:3px 5px;pointer-events:none}

/* ── Pratinjau foto ukuran penuh ───────────────────────────────────────── */
.foto-pratinjau{position:fixed;inset:0;z-index:var(--lapis-pratinjau);background:rgba(15,23,51,.88);
  display:flex;align-items:center;justify-content:center;gap:10px;padding:22px}
.foto-pratinjau .fp-isi{margin:0;display:flex;flex-direction:column;align-items:center;gap:11px;
  max-width:min(1100px,88vw);max-height:88vh}
.foto-pratinjau img{max-width:100%;max-height:78vh;object-fit:contain;border-radius:10px;
  background:#fff;box-shadow:0 18px 48px rgba(0,0,0,.4)}
.foto-pratinjau figcaption{color:#fff;font-size:12.5px;text-align:center;line-height:1.5;
  background:rgba(255,255,255,.1);padding:7px 13px;border-radius:8px}
.foto-pratinjau .fp-nav,.foto-pratinjau .fp-tutup{
  border:0;background:rgba(255,255,255,.14);color:#fff;cursor:pointer;border-radius:10px;
  width:44px;height:44px;font-size:22px;line-height:1;flex:none;display:grid;place-items:center}
.foto-pratinjau .fp-nav:hover:not(:disabled),.foto-pratinjau .fp-tutup:hover{background:rgba(255,255,255,.26)}
.foto-pratinjau .fp-nav:disabled{opacity:.25;cursor:not-allowed}
.foto-pratinjau .fp-tutup{position:absolute;top:16px;right:18px;width:38px;height:38px;font-size:17px}
@media(max-width:700px){
  .foto-pratinjau{padding:12px;gap:5px}
  .foto-pratinjau .fp-nav{width:34px;height:34px;font-size:18px}
}
.bap-atur.tutup{display:none}
/* Kotak centang di panel pengaturan. Dibuat sejajar dengan kolom lain,
   tetapi labelnya boleh dua baris karena keterangannya penting: pilihan ini
   berlaku untuk seluruh dokumen, bukan halaman yang sedang dibuka. */
/* Kekhususan sengaja dinaikkan (.bap-atur di depan): tanpa itu `.bap-atur .f`
   yang menang, kolomnya menyusut jadi 150px, dan tulisan "Pakai tanggal
   setiap 2 foto" membungkus jadi dua baris di samping kotak centang. */
.bap-atur .bap-atur-cek{flex:1 1 260px;min-width:230px;display:flex;align-items:flex-start;
  /* WAJIB. `.f` di base.css menyetel flex-direction:column supaya label
     duduk di ATAS isiannya — benar untuk kotak isian, salah untuk kotak
     centang. Tanpa baris ini centangnya menumpuk di atas tulisannya dan
     seluruh baris pengaturan terlihat acak-acakan. Tidak ada galat; hanya
     satu sifat yang diwarisi dari tempat lain. */
  flex-direction:row;
  gap:8px;cursor:pointer;margin:0;padding-bottom:2px}
.bap-atur-cek input{width:16px;height:16px;flex:none;margin-top:2px;cursor:pointer}
.bap-atur-cek span{font-size:12.5px;line-height:1.35}
.bap-atur-cek small{display:block;font-size:10.5px;color:var(--ink-3);margin-top:1px}

/* ── BAP: pemindahan foto ──────────────────────────────────────────────── */
.slot-pindah{position:absolute;top:6px;left:6px;z-index:3;border:0;cursor:grab;
  width:26px;height:26px;border-radius:7px;background:rgba(15,23,51,.62);color:#fff;
  font-size:13px;line-height:1;display:grid;place-items:center}
.slot-pindah:hover{background:var(--blue)}
/* Tombol sampah, sepasang dengan tombol pindah di seberangnya. Sebelum ini
   tempatnya diisi tombol bertuliskan "Ganti" yang sebenarnya MENGHAPUS —
   nama yang menjanjikan pertukaran padahal yang terjadi kehilangan.
   Bentuknya disamakan dengan .slot-pindah supaya keduanya terbaca sebagai
   satu pasang alat pada foto, bukan dua benda yang kebetulan berdekatan. */
.slot-hapus{position:absolute;top:6px;right:6px;z-index:3;border:0;cursor:pointer;
  width:26px;height:26px;border-radius:7px;background:rgba(15,23,51,.62);color:#fff;
  font-size:13px;line-height:1;display:grid;place-items:center}
.slot-hapus:hover{background:var(--bad)}
/* GANTI di pojok kanan BAWAH, jauh dari sampah di pojok kanan atas.
   Berdempetan, keduanya jadi sepasang tombol kecil yang bedanya cuma ikon —
   dan yang satu tidak bisa diurungkan dengan mudah sedangkan yang lain
   mengganti isi. Jarak diagonal penuh adalah pengaman yang paling murah. */
.slot-ganti{position:absolute;right:6px;bottom:6px;z-index:3;border:0;cursor:pointer;
  padding:3px 9px;border-radius:7px;background:rgba(15,23,51,.62);color:#fff;
  font-size:11px;font-weight:700;line-height:1.4}
.slot-ganti:hover{background:var(--blue)}
[data-slot].slot-diangkat{outline:3px solid var(--blue);outline-offset:-3px}
[data-slot].slot-diangkat::before{content:"Diangkat";position:absolute;inset:auto 0 0 0;z-index:2;
  background:var(--blue);color:#fff;font-size:10.5px;font-weight:700;text-align:center;padding:3px 0}
[data-slot].slot-sasaran{outline:2px dashed var(--blue);outline-offset:-2px;background:var(--blue-soft)}
[data-slot].slot-diseret{opacity:.4}
.bap-angkat{display:flex;align-items:center;justify-content:space-between;gap:11px;flex-wrap:wrap;
  margin-bottom:11px;padding:9px 12px;border-radius:var(--r-sm);
  background:var(--blue-soft);border:1px solid var(--info-line);font-size:12.5px;color:var(--ink)}

/* ── BAP: kartu foto ───────────────────────────────────────────────────
   Bidang foto dan keterangannya adalah DUA kotak bersudut membulat yang
   ditumpuk, bukan satu kotak yang dibagi garis. Bentuk ini sengaja disamakan
   persis dengan hasil cetaknya, supaya yang terlihat di layar benar-benar
   mewakili PDF-nya. */
/* Nomor baris — dulu ditulis inline bersama kotak tanggal; sejak tanggal
   pindah ke tengah pasangan, yang tersisa di sini hanya penanda urutan. */
.bap-baris-no{
  font-size:11px;color:var(--ink-3);text-align:center;margin-bottom:8px;
}
.bap-pasangan{display:grid;grid-template-columns:1fr 1fr;gap:11px}
/* Kolom tengah untuk lencana tanggal. Lebarnya TETAP (150 px) supaya kedua
   kolom foto tetap sama lebar; kolom tengah yang ikut melar akan membuat
   foto kiri dan kanan berbeda ukuran begitu tanggalnya panjang. */
.bap-pasangan-tgl{grid-template-columns:1fr 150px 1fr;align-items:center}
.bap-lencana{display:flex;justify-content:center}
.bap-lencana .cal-bung,.bap-lencana>span{width:100%}

/* Foto dan keterangannya SATU kartu, bukan dua kotak berjarak — mengikuti
   desain Figma MRI, tempat kartu keterangan digambar di belakang foto
   sehingga sudut membulatnya menyatu dengan dasar foto. Di layar hal yang
   sama dicapai dengan menghapus jaraknya dan membulatkan sudut luarnya
   saja. */
.kartu-foto{display:flex;flex-direction:column;gap:0;background:transparent}
.kartu-foto-slot{
  /* Rasio slot CETAK, bukan 4:3.
     Bedanya cuma 2%, dan selama foto dipotong tengah otomatis itu tidak
     pernah terasa. Sejak tampilannya bisa DIATUR sendiri, bingkai di layar
     adalah alat ukurnya — bingkai yang bentuknya berbeda dari kertas
     membuat orang memilih bagian yang tidak persis sama dengan yang
     tercetak, tanpa satu pun tanda. Angkanya dari SPEK-BAP.md. */
  position:relative;aspect-ratio:51.08/39.06;background:var(--sunk);
  border:1px solid var(--line-2);border-radius:12px 12px 0 0;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
}
.kartu-foto-slot img{border-radius:11px 11px 0 0}
.kartu-foto-cap{
  border:1px solid var(--line-2)!important;border-top:0!important;
  border-radius:0 0 10px 10px!important;
  width:100%;text-align:center;font-size:12px;background:var(--card);
  /* DUA BARIS, setinggi kartunya di kertas. resize:none dan overflow
     tersembunyi: yang melebihi dua baris memang tidak ikut tercetak, jadi
     layar harus memotongnya di tempat yang sama — kotak yang bisa digulir
     akan memperlihatkan teks yang tidak akan pernah keluar dari printer. */
  height:44px;line-height:1.35;padding:5px 8px;resize:none;overflow:hidden;
  font-family:inherit;
}
.kartu-foto-cap:focus{border-color:var(--blue-hi)!important}
/* Penanda dan tombol ikut membulat mengikuti sudut kartunya */
/* Tombol tangan — TENGAH BAWAH setiap foto (permintaan MRI, 8 Sep 2026).
   Menyalakan mode geser. Selama mati, foto berperilaku persis seperti
   sebelum pengaturan tampilan ada: sekali klik membuka ukuran penuh.
   Maksud yang DIKATAKAN, bukan ditebak dari jarak gerakan tangan. */
.slot-geser{position:absolute;left:50%;bottom:6px;transform:translateX(-50%);
  z-index:3;border:0;cursor:pointer;font-size:12px;line-height:1;
  padding:4px 9px;border-radius:999px;color:#fff;background:rgba(15,23,51,.55);
  transition:background .15s,box-shadow .15s}
.slot-geser:hover{background:rgba(15,23,51,.78)}
/* Menyala: warnanya jelas berbeda, bukan sekadar sedikit lebih gelap —
   pengguna harus bisa tahu foto mana yang sedang bisa digeser tanpa
   mencobanya lebih dulu. */
.slot-geser.aktif{background:var(--blue);color:var(--on-accent);box-shadow:0 0 0 2px var(--card)}
.kartu-foto-slot.geser-aktif{outline:2px solid var(--blue);outline-offset:-2px}
.kartu-foto-slot .slot-geser{bottom:8px}

/* ── Sakelar sumber alamat di dialog Project ───────────────────────────
   Dua tombol berdampingan, bukan kotak centang: "alamat baru" dan "pakai
   alamat client" sama-sama pilihan sah, sedangkan kotak centang menjadikan
   salah satunya keadaan bawaan yang tidak pernah dikatakan.
   Ditaruh di ATAS isiannya supaya terbaca sebelum orang mulai mengetik —
   di bawah, ia baru ditemukan sesudah alamatnya terlanjur diketik ulang. */
.prj-alamat-sakelar{display:inline-flex;gap:0;margin-bottom:5px;
  border:1px solid var(--line-2);border-radius:999px;overflow:hidden;
  background:var(--card);width:fit-content}
.prj-sakelar{border:0;background:none;cursor:pointer;font:inherit;
  font-size:11.5px;padding:4px 11px;color:var(--ink-2);white-space:nowrap}
.prj-sakelar:hover:not(.aktif){background:var(--hover);color:var(--ink)}
.prj-sakelar.aktif{background:var(--blue);color:var(--on-accent);font-weight:600}
/* Alamat yang disalin dari client TIDAK bisa diketik — kalau bisa, angka
   yang terlihat "dari client" sebenarnya sudah bukan alamat client lagi,
   dan tidak ada yang memberi tahu. */
.prj-f input[readonly]{background:var(--sunk);color:var(--ink-2);cursor:default}

/* Kendali tanggal massal di bilah pilihan. Berdiri di sebelah angka
   "N item dipilih" karena itulah yang menentukan sasarannya — dipisah dari
   angka itu, orang menekannya tanpa mencentang apa pun lalu mengira
   tombolnya rusak. */
.it-bulk-tgl{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap}
.it-bulk-tgl-label{font-size:11.5px;color:var(--ink-3);white-space:nowrap}
.it-bulk-tgl .cal-wrap{min-width:150px}

/* ── Kepala KATEGORI di dalam tabel item (BOQ) ─────────────────────────
   Membentang seluruh kolom, seperti baris rincian. Dibuat sebagai BARIS
   tabel, bukan tabel terpisah per kategori: satu tabel berarti satu bilah
   tindakan, satu penomoran, dan satu tempat yang menggambar semuanya —
   sedangkan tabel per kategori menggandakan toolbar dan membuat kolomnya
   tidak lagi sejajar antar kategori. */
.it-kategori > td{background:var(--blue-soft);padding:0}
.it-kategori-kotak{display:flex;align-items:center;gap:9px;padding:8px 10px}
.it-kategori-huruf{font-weight:800;font-size:13px;color:var(--blue);flex:none;
  min-width:22px}
/* Nama kategori sengaja tampil seperti JUDUL, bukan seperti isian: ia
   memang bisa diketik, tetapi yang dibaca orang saat menelusuri BOQ adalah
   namanya — bukan kotaknya. Garisnya baru muncul saat disentuh. */
.it-kategori-nama{flex:1;min-width:0;border:1px solid transparent;background:none;
  font:inherit;font-size:13px;font-weight:800;letter-spacing:.02em;
  text-transform:uppercase;color:var(--ink);padding:5px 7px;border-radius:6px}
.it-kategori-nama:hover:not([readonly]){border-color:var(--line-2);background:var(--card)}
.it-kategori-nama:focus{border-color:var(--blue-hi);background:var(--card);outline:none}
.it-kategori-tambah{flex:none}
.it-kategori-hapus{flex:none;color:var(--bad)}

/* Penanda bahwa tampilan foto ini sudah diatur sendiri.
   Pengaturan yang tidak terlihat akan dikira hilang oleh orang berikutnya
   yang membuka dokumen itu — lalu ia mengaturnya ulang. */
.slot-crop-tanda{position:absolute;right:6px;bottom:6px;z-index:1;font-size:11px;
  line-height:1;color:#fff;background:rgba(15,23,51,.55);border-radius:5px;
  padding:3px 5px;pointer-events:none}
.kartu-foto-slot .slot-crop-tanda{right:8px;bottom:8px}
.kartu-foto-slot .slot-perbesar{left:8px;bottom:8px}
.kartu-foto-slot .slot-pindah{top:8px;left:8px}
.kartu-foto-slot .slot-hapus{top:8px;right:8px}
.kartu-foto-slot .slot-ganti{right:8px;bottom:8px}
[data-slot].slot-diangkat{outline-offset:-3px;border-radius:12px}

/* ══════════════════ LAYAR HP ══════════════════
   Sampai putaran ini aplikasi tidak punya tata letak HP sama sekali: #app
   selalu grid dua kolom dengan sidebar 250 px, sehingga di layar 360 px
   hanya tersisa 110 px untuk isinya, dan baris tombol topbar yang menolak
   membungkus melebarkan seluruh dokumen sampai 899 px. Diukur, bukan
   diperkirakan.

   Ambang 760 px, bukan 700: pada 700–760 px sidebar 250 px masih memakan
   sepertiga layar, dan tabel barang sudah mulai menggulir mendatar padahal
   ruangnya sebenarnya cukup kalau sidebar disingkirkan.

   Sidebar jadi LACI: keluar dari alur, menumpuk di atas isi, dengan tirai
   di belakangnya. Bukan ciut-jadi-ikon — rel ikon 66 px tetap memakan
   seperlima layar 360 px demi menu yang labelnya justru tidak terbaca. */
/* Tirai laci HP. Disembunyikan di sini — DI LUAR dan DI ATAS media query
   yang menghidupkannya.

   Dua hal yang gampang salah dan keduanya sudah pernah salah:

   1. Elemennya selalu ada di DOM (dibuat sekali supaya transisinya punya
      keadaan awal untuk dianimasikan). Kalau SELURUH gayanya ditaruh di
      dalam @media, pada layar lebar ia kehilangan gaya sama sekali dan
      tergambar apa adanya: <button> kosong 16x6 px di dasar tiap halaman.
   2. Aturan penyembunyinya harus berada DI ATAS @media. Media query tidak
      menambah kekhususan, jadi kalau ia ditulis di bawah, ia menang lewat
      urutan sumber dan mematikan tirainya di HP juga — dan gejalanya diam:
      opacity dan pointer-events tetap benar, hanya elemennya yang tidak
      pernah tergambar. */
.sb-tirai{display:none}

@media (max-width:760px){
  #app{grid-template-columns:minmax(0,1fr)}

  .sidebar{
    position:fixed; left:0; top:0; height:100dvh; width:min(286px,84vw);
    transform:translateX(-100%); box-shadow:none;
    transition:transform var(--gerak) var(--lengkung);
  }
  body.sb-hp .sidebar{transform:none; box-shadow:var(--shadow-3)}

  /* Tirai — bentuk sebenarnya ada di luar media query ini, lihat catatan di
     bawah blok. Di sini ia hanya dihidupkan. */
  .sb-tirai{
    display:block; position:fixed; inset:0; z-index:calc(var(--lapis-sidebar) - 1);
    background:rgba(21,38,66,.42); border:0; padding:0; margin:0;
    opacity:0; pointer-events:none; transition:opacity var(--gerak);
  }
  body.sb-hp .sb-tirai{opacity:1; pointer-events:auto}

  /* Tombol pin tidak ada gunanya di sini: laci selalu menumpuk, tidak pernah
     mendorong, jadi tidak ada lebar yang bisa dikunci. */
  .sb-pin{display:none}

  /* Topbar jadi dua baris. Tombol aksi tidak boleh dipaksa muat — memampatkan
     "Publikasikan ke Purchasing" jadi tiga huruf menghilangkan justru
     keterangan yang membuatnya aman ditekan. Ia digulir mendatar di barisnya
     sendiri, dan karena punya overflow sendiri ia berhenti melebarkan
     dokumen. */
  .topbar{flex-wrap:wrap; gap:9px; row-gap:8px; padding:8px 12px; min-height:0}
  /* Yang khas HP hanya ini: bilahnya turun jadi baris sendiri selebar layar.
     Sifat menggulir, menyembunyikan scrollbar, dan bayangan tepinya sudah
     berlaku di SEMUA lebar — lihat catatannya di definisi .top-act. */
  .top-act{ order:3; width:100%; margin-left:0; flex-wrap:nowrap; padding-bottom:1px; }
  .tb-cari{margin-left:auto}

  /* Satu tombol saja tidak layak memakan satu baris penuh — di Dashboard
     baris aksi hanya berisi ikon "?" dan barisnya jadi hampir seluruhnya
     kosong. Ditulis sebagai PENGECUALIAN ber-:has(), bukan sebaliknya:
     kalau peramban tidak mengenal :has() seluruh aturan ini diabaikan dan
     yang tersisa adalah tata letak dua baris yang aman. Kebalikannya —
     memaksa satu baris lalu memperbaikinya dengan :has() — akan
     mengembalikan dokumen yang meluber mendatar pada peramban lama. */
  .topbar:has(.top-act > :only-child) .top-act{
    width:auto; order:0; margin-left:auto; overflow:visible;
  }

  /* ── SASARAN SENTUH ────────────────────────────────────────────────
     `.btn-sm` setinggi 31 px cukup untuk kursor tetikus dan terlalu kecil
     untuk jempol. Diukur di layar 390 px: tab Data Master, tombol Buka di
     Daftar Project, "Input Manual", "‹ Sebelumnya" — semuanya 31 px.
     Panduan sentuh yang lazim 44 px; 36 px dipilih sebagai kompromi karena
     bilah tab Data Master memuat tujuh tombol berdampingan dan 44 px
     membuatnya membungkus jadi tiga baris.

     `min-height`, bukan `height`: tombol yang teksnya membungkus tetap boleh
     tumbuh, dan tombol yang tingginya sudah cukup tidak berubah sama sekali. */
  .btn-sm{min-height:36px}
  .btn-icon.btn-sm{min-width:36px}

  /* Aksi utama didahulukan. Bilah aksi di HP menggulir mendatar, dan pada
     BOQ isinya 790 px di dalam kotak 366 px — "Publikasikan ke Purchasing"
     berada di luar layar, tanpa satu pun tanda bahwa ia ada. Yang paling
     mahal dari itu bukan gulirnya, melainkan bahwa tombol yang paling
     dicari justru yang tersembunyi. Diurutkan lewat `order`, bukan dengan
     mengubah urutan sumbernya: di layar lebar urutan aslinya tetap berlaku,
     dan tombol berbahaya tetap di ujung kanan. */
  .top-act > .btn-lime, .top-act > .btn-primary{ order:-1 }


  .page{padding:14px 12px 40px}
  .page-head h1{font-size:18px}

  /* Pegangan laci konteks & kartu strip TIDAK diatur dari sini — gayanya
     disuntik saat berjalan oleh core/context-drawer.js dan
     core/record-switcher.js, dan suntikan itu masuk ke <head> sesudah
     berkas ini sehingga selalu menang pada kekhususan yang sama. Aturan
     HP-nya ada di masing-masing berkas komponen. */
}

/* Layar sangat sempit (≤380 px). Tombol ikon-saja tetap 36 px — di bawah itu
   sasaran sentuhnya lebih kecil daripada ujung jari orang dewasa. */
@media (max-width:380px){
  .topbar{padding:8px 10px; gap:7px}
  .page{padding:12px 10px 36px}
}

/* ══════════════════ DATA MASTER: hanya isi tabel yang bergulir ══════════
   Kepala tabel SUDAH `position:sticky; top:0` di core/base.css. Yang dulu
   kurang bukan aturan sticky-nya, melainkan WADAH YANG MENGGULIR: sticky
   menempel pada scrollport terdekat, dan `.tbl-wrap` hanya punya
   overflow-x tanpa batas tinggi — jadi tabelnya tumbuh setinggi isinya,
   yang menggulir adalah halaman, dan kepala tabel menempel dengan patuh
   pada wadah yang tidak pernah bergerak.

   Perbaikannya bukan max-height bernilai tebakan (angka begitu meleset
   begitu topbar berubah tinggi atau bar cari membungkus), melainkan rantai
   flex setinggi layar: tiap lapis meneruskan tingginya ke bawah, dan
   `.tbl-wrap` mengambil sisanya.

   `min-height:0` di tiap lapis WAJIB. Tanpa itu isi flex menolak menyusut
   di bawah tinggi kontennya, tinggi yang diteruskan jadi tak berbatas, dan
   tidak ada satu pun wadah yang benar-benar menggulir.

   Hanya di atas 760 px — ambang HP yang sama dengan sisa aplikasi. Di HP
   halaman tetap menggulir seperti biasa: gulir bersarang di layar sentuh
   sering membuat jari menggerakkan halaman padahal maksudnya tabel. */
@media (min-width:761px){
  .page[data-master]{
    height:calc(100dvh - var(--topbar-h));
    padding-bottom:14px;
    display:flex; flex-direction:column; min-height:0; overflow:hidden;
  }
  .page[data-master] .panel{
    flex:1; display:flex; flex-direction:column; min-height:0; margin-bottom:0;
  }
  .page[data-master] .panel-head{flex:none}
  .page[data-master] .panel-body{
    flex:1; display:flex; flex-direction:column; min-height:0; overflow:hidden;
  }
  .page[data-master] .mstr-bar,
  .page[data-master] .mstr-nav{flex:none}
  /* Inilah satu-satunya yang bergulir. overflow:auto dua arah: tabel Barang
     sepuluh kolom, dan kepala tabel harus ikut bergeser ke kanan bersama
     isinya — ia menempel hanya secara VERTIKAL. */
  .page[data-master] .tbl-wrap{flex:1; min-height:0; overflow:auto}
}

/* Pesan galat di dalam modal tambah data master. */
.mstr-galat{
  margin:11px 0 0; padding:8px 11px; font-size:12.5px; line-height:1.5;
  color:var(--bad); background:var(--bad-bg);
  border:1px solid var(--bad-line); border-radius:var(--r-sm);
}

/* Keterangan saat sebuah tab Data Master tidak boleh diubah peran ini.
   Menyembunyikan tombolnya saja meninggalkan orang menebak kenapa; kalimat
   pendek ini yang membedakan "tidak boleh" dari "rusak". */
.mstr-kunci{
  font-size:12px; color:var(--ink-3); padding:4px 2px; line-height:1.5;
}

/* Baris master yang dinonaktifkan. Tetap terlihat — kalau disembunyikan,
   tidak ada jalan mengaktifkannya kembali — tetapi jelas berbeda supaya
   tidak tertukar dengan barang yang masih dipakai. */
.mstr-nonaktif{opacity:.5}
.mstr-nonaktif input{text-decoration:line-through}

/* Log Aktivitas — pemisahan DEV.
   Tindakan DEV punya tabnya sendiri, tetapi TETAP ditandai per baris: kalau
   suatu saat kedua daftar digabungkan lagi, tandanya sudah ada dan tidak
   perlu diingat ulang. */
.log-tab{display:flex; gap:6px}
.log-jml{display:inline-block; min-width:18px; padding:0 5px; margin-left:5px;
  border-radius:9px; background:var(--sunk); color:var(--ink-2);
  font-size:10.5px; font-weight:800; line-height:16px; text-align:center}
.log-tab .btn-primary .log-jml{background:rgba(255,255,255,.24); color:#fff}
.log-peran{display:inline-block; margin:0 5px 0 2px; padding:0 6px;
  border:1px solid var(--line-2); border-radius:var(--r-xs);
  font-size:9.5px; font-weight:800; letter-spacing:.04em; color:var(--ink-3)}
.log-row.log-dev{background:var(--warn-bg)}
.log-row.log-dev .log-peran{border-color:var(--warn-line); color:var(--warn)}

/* ── Menu Project ────────────────────────────────────────────────────────
   Corong tahap: tujuh sel berjajar, membungkus di layar sempit. Bukan
   grafik — ini hitungan, dan hitungan yang dibaca sekilas lebih baik
   berbentuk angka besar daripada batang yang harus ditaksir. */
.prj-corong{display:flex; gap:9px; flex-wrap:wrap}
.prj-corong-sel{flex:1 1 132px; min-width:132px; display:flex; flex-direction:column;
  align-items:flex-start; gap:6px; padding:11px 12px;
  border:1px solid var(--line-2); border-radius:10px; background:var(--card-2)}
.prj-corong-sel b{font-size:21px; line-height:1; font-variant-numeric:tabular-nums}

.prj-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:11px}
.prj-f{display:flex; flex-direction:column; gap:5px}
.prj-f>span{font-size:11px; font-weight:700; color:var(--ink-2)}
.prj-f input{height:36px; padding:0 10px; border:1px solid var(--line-in);
  border-radius:8px; background:var(--card); font:inherit; color:inherit; width:100%}
.prj-f input[readonly]{background:var(--sunk); color:var(--ink-2)}

.prj-tahap-bar{display:flex; align-items:center; gap:7px; flex-wrap:wrap;
  margin-top:14px; padding:11px; border:1px solid var(--line-2);
  border-radius:10px; background:var(--card-2)}
.prj-tahap-bar b{font-size:12.5px; white-space:nowrap}

/* Dua gerbang ditampilkan sebagai keadaan, bukan sebagai galat. Yang belum
   terpenuhi bukan kesalahan — ia sekadar belum terjadi, dan menandainya
   merah membuat pekerjaan yang normal terlihat seperti kerusakan. */
.prj-gerbang{margin-top:13px; display:flex; flex-direction:column; gap:7px}
.prj-gerbang-baris{display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  padding:9px 11px; border:1px solid var(--line-2); border-radius:9px;
  background:var(--sunk); font-size:12.5px}
.prj-gerbang-baris.lolos{background:var(--ok-bg); border-color:var(--ok-line)}
.prj-gerbang-baris span:last-child{color:var(--ink-2)}

/* Tanda project yang tahapnya dipindah lewat kode DEV. Sengaja mencolok:
   gunanya justru supaya terlihat mana yang tidak lewat jalur normal. */
/* Tombol lipat panel header. Di kanan kepala panel, sesudah keterangan
   nomornya — urutan yang sama dengan "Tutup Daftar" di strip dokumen, supaya
   dua benda yang melakukan hal sama duduk di tempat yang sama. */
.hdr-lipat{margin-left:8px; flex:none}
/* Keterangan nomor di kepala panel MENGALAH, bukan mendorong. Ia satu-satunya
   isi kepala panel yang panjangnya tidak terbatas ("Nomor terbit saat
   diterbitkan → 001/ARG/LPJ/IX/2026"), dan tanpa batas ini ia mendorong
   tombol Sembunyikan keluar layar sejauh 87 px pada 360 px — diukur, bukan
   diperkirakan.
   ...dan MELIPAT, bukan dipotong sebaris. Dipotong, yang tersisa cuma
   "Nomor terbit saat diterbitkan → 001/ARG/BAP/I" — diukur 172 px terpakai
   dari 336 px yang dibutuhkan, jadi separuh keterangannya hilang justru di
   bagian yang menyebut nomornya.

   Melipat juga LEBIH AMAN daripada nowrap+elipsis untuk tombol Sembunyikan:
   teks yang melipat tidak bisa melebarkan kotaknya sama sekali, jadi ia
   tidak mungkin mendorong tombol itu keluar layar pada lebar berapa pun.
   Tiga baris karena panel header memang sempit — diukur 394 px, dan
   sesudah judul serta tombolnya tersisa 172 px untuk keterangan ini. */
.panel-head .count{min-width:0; overflow:hidden; line-height:1.35;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
  /* "001/ARG/BAP/IX/2026" tidak punya spasi, jadi peramban tidak boleh
     memenggalnya kecuali disuruh — dan tanpa izin itu ia melebar melewati
     kotaknya pada 375 px, tepat pada bagian yang menyebut nomornya. */
  overflow-wrap:anywhere}
/* Di layar HP keterangan ini turun ke BARISNYA SENDIRI.
   Diukur pada 375 px: dijejalkan sebaris dengan judul dan tombol, ia cuma
   kebagian 74-103 px — tiga baris pun tidak cukup, dan yang terpotong lagi-
   lagi nomornya. Membiarkan kepala panel melipat memberinya lebar penuh,
   dan judul serta tombolnya tetap berdampingan di baris pertama. */
@media(max-width:640px){
  .panel-head{flex-wrap:wrap}
  /* Urutannya ditukar supaya tombolnya tetap di kanan JUDUL, bukan
     terlempar ke baris ketiga: tanpa ini, keterangan yang mengambil lebar
     penuh menyisipkan pemisah di antara judul dan tombolnya, dan tombol
     Sembunyikan mendarat sendirian di bawah — tempat yang tidak dicari
     siapa pun. */
  .panel-head .hdr-lipat{order:1; margin-left:auto}
  /* TANPA batas baris di sini. Batas baris ada untuk melindungi tata letak
     dari teks yang panjangnya tidak terbatas — dan begitu keterangan ini
     mendapat barisnya sendiri selebar panel, ia tidak bisa mendesak apa pun
     lagi. Yang tersisa dari membatasinya cuma satu: menyembunyikan nomor
     dokumen pada layar yang paling sering dipakai di lapangan. */
  .panel-head .count{order:2; flex:1 0 100%; margin-top:2px;
    display:block; -webkit-line-clamp:none}
}
.panel.hdr-tutup .panel-head{border-bottom:0}

/* ── Isian panjang mengambil LEBAR PENUH kisi header ───────────────────
   Panel header BAP diukur 354 px; dibagi dua kolom, isian Project cuma
   kebagian sekitar 170 px — dan Project justru isian dengan isi terpanjang
   di seluruh formulir, jadi namanya terpotong di tengah.

   Yang dilebarkan HANYA yang isinya memang panjang.
   Bukan semuanya dilebarkan: kolom Tanggal selebar panel hanya memindahkan
   masalahnya jadi ruang kosong, dan formulir yang tiap isiannya satu baris
   penuh menuntut gulir lebih jauh untuk pekerjaan yang sama. */
/* Lebar penuh hanya kalau separuh baris memang TERLALU SEMPIT.
   Aturan ini lahir untuk panel header BAP yang lebarnya 354 px — di sana
   separuh kisi cuma 168 px dan nama project terpotong di tengah. Tetapi
   Pengajuan memakai panel selebar 1080 px, dan di sana lebar penuh justru
   MEMECAH kisi dua kolomnya: isian pendek berjajar sendirian di baris yang
   separuhnya kosong, dan formulirnya menuntut gulir dua kali lebih jauh.
   Dilaporkan MRI, 8 Sep 2026.

   Container query, bukan media query: yang menentukan lebar PANELNYA, dan
   panel yang sama bisa sempit di layar lebar (dua panel berdampingan)
   maupun lebar di layar sempit. Mengukur layar berarti mengukur yang
   salah. Peramban yang belum mengenalnya jatuh ke dua kolom — keadaan
   sebelum aturan ini ada, bukan keadaan yang rusak. */
[data-hgrid].grid-2, [data-kgrid].grid-2{container-type:inline-size}
@container (max-width:560px){
  [data-hgrid] .f-lebar, [data-kgrid] .f-lebar{grid-column:1/-1}
}

/* ── Jenis project: lencana baris & kelompok tombol saringan ──────────
   Sejak Project dan Project Maintenance jadi SATU daftar, jenisnya harus
   terbaca sambil menelusuri — tanpa itu petunjuknya cuma awalan ID tiga
   huruf di kolom paling kiri, dan itu bukan sesuatu yang tertangkap mata
   saat sedang mencari nama. */
.prj-jenis{display:inline-flex; align-items:center; padding:2px 9px;
  border:1px solid var(--line-2); border-radius:999px;
  background:var(--sunk); color:var(--ink-2);
  font-size:10.5px; font-weight:800; letter-spacing:.02em; white-space:nowrap}
.prj-jenis-mtn{background:var(--blue-soft); border-color:var(--info-line); color:var(--blue-2)}
.prj-grup-jenis{display:inline-flex; gap:5px; flex-wrap:wrap}
.prj-grup-jenis .btn{flex:none}

/* Kartu pilihan jenis pada langkah pertama "Project Baru". Kartu, bukan
   sepasang tombol: keduanya perlu membawa keterangan dan contoh ID-nya, dan
   itu tidak muat di dalam tombol. */
.prj-pilih-jenis{display:grid; grid-template-columns:1fr 1fr; gap:11px}
@media(max-width:560px){ .prj-pilih-jenis{grid-template-columns:1fr} }
.prj-kartu-jenis{display:flex; flex-direction:column; gap:5px; text-align:left;
  padding:14px 15px; border:1.5px solid var(--line-2); border-radius:var(--r);
  background:var(--card); cursor:pointer; font:inherit; color:inherit;
  transition:border-color .14s, background .14s, transform .14s}
.prj-kartu-jenis:hover{border-color:var(--blue); background:var(--card-2);
  transform:translateY(-1px)}
.prj-kartu-jenis.terpilih{border-color:var(--blue); background:var(--blue-soft)}
.prj-kartu-jenis b{font-size:13.5px; font-weight:800}
.prj-kartu-jenis span{font-size:11.5px; color:var(--ink-3); line-height:1.5}
.prj-kartu-jenis i{font-style:normal; font-family:var(--font-mono); font-size:11px;
  color:var(--blue-2); font-weight:700}

.prj-tanda{display:inline-block; margin-left:6px; padding:1px 7px;
  border:1px solid var(--warn-line); border-radius:var(--r-xs);
  background:var(--warn-bg); color:var(--warn);
  font-size:10px; font-weight:800; letter-spacing:.03em}

.prj-aktif{background:var(--blue-soft)}
.prj-pilih{display:flex; align-items:flex-start; gap:9px; padding:10px 11px;
  border:1px solid var(--line-2); border-radius:9px; margin-bottom:8px; cursor:pointer}
.prj-pilih small{color:var(--ink-3)}

@media (max-width:640px){
  .prj-corong-sel{flex:1 1 100%}
  .prj-tahap-bar{flex-direction:column; align-items:stretch}
}

/* Kartu dokumen terkait di halaman Project. Angka besar di tengah karena
   pertanyaan yang dibawa orang ke sini adalah "ada berapa", bukan "apa
   saja" — daftar isinya ada di halaman jenisnya masing-masing. */
.prj-dok{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:10px}
.prj-dok-kartu{display:flex; flex-direction:column; gap:3px; padding:11px 12px;
  border:1px solid var(--line-2); border-radius:10px; background:var(--card-2);
  text-decoration:none; color:inherit; transition:border-color .15s, transform .15s}
.prj-dok-kartu:hover{border-color:var(--blue); transform:translateY(-1px)}
.prj-dok-kartu b{font-size:12px; color:var(--ink-2)}
.prj-dok-n{font-size:20px; font-weight:800; line-height:1.1;
  font-variant-numeric:tabular-nums; color:var(--blue)}
.prj-dok-kartu small{font-size:10.5px; color:var(--ink-3)}

.prj-tagih{display:flex; flex-direction:column; gap:2px; font-size:11px; color:var(--ink-2)}
.prj-tagih b{font-variant-numeric:tabular-nums}

/* ── Data Master: kolom cukup lebar, tabel bergulir mendatar ───────────
   Kolom yang dipersempit paksa agar semuanya muat membuat isinya terpotong
   di tengah kata — dan yang terpotong justru yang perlu dibaca: alamat
   lengkap, nomor rekening, nama project. Lebih baik tabelnya lebih lebar
   daripada kertasnya lalu bisa digulir mendatar; menggulir adalah gerakan
   yang orang sudah tahu, menebak isi yang terpotong tidak. */
.page[data-master] .tbl-wrap{overflow-x:auto}
.page[data-master] table.tbl{min-width:1080px}
.page[data-master] table.tbl th,
.page[data-master] table.tbl td{white-space:nowrap}
.page[data-master] table.tbl input{min-width:140px}
/* Kolom yang isinya memang panjang diberi ruang lebih dari yang lain. */
.page[data-master] table.tbl td input[data-k="alamat"],
.page[data-master] table.tbl td input[data-k="deskripsi"],
.page[data-master] table.tbl td input[data-k="keterangan"],
.page[data-master] table.tbl td input[data-k="nama"]{min-width:220px}

/* Baris yang sedang dibuka untuk disunting — dibedakan supaya tidak ada
   keraguan baris mana yang sedang bisa diubah. */
.mstr-sunting > td{background:var(--blue-soft)}
.mstr-sunting input:not(.mstr-ro){border-color:var(--blue)}


/* ══════════════════ HALAMAN PROJECT SENDIRI ══════════════════
   Sejak satu project punya alamatnya sendiri (#/project/prj-123), detailnya
   berdiri sebagai halaman penuh — bukan lagi panel yang menggantung di bawah
   daftar. Tiga gaya di bawah yang menyusul dari perubahan itu. */
.prj-balik{margin-bottom:12px}
.prj-balik a{
  font-size:12.5px;color:var(--ink-2);text-decoration:none;
  display:inline-flex;align-items:center;gap:6px;
  padding:6px 11px;border:1px solid var(--line-2);border-radius:8px;background:var(--card);
}
.prj-balik a:hover{border-color:var(--blue-hi);color:var(--blue-hi)}

/* Nama project di tabel jadi tautan sungguhan — bisa dibuka di tab baru,
   bisa disalin alamatnya. Tombol "Buka" di ujung baris tetap ada: yang satu
   untuk yang menyasar namanya, yang satu untuk yang menyasar barisnya. */
/* Nama project di daftar adalah TAUTAN, jadi ia sasaran sentuh — dan
   sebagai teks sebaris tingginya cuma setinggi hurufnya: diukur 16 px,
   separuh dari batas 32 px yang dijaga uji 24. Di layar sentuh, tautan
   setipis itu menuntut ketepatan yang tidak dimiliki ibu jari, dan yang
   di bawahnya adalah baris project LAIN.

   Dibuat block + padding tegak, bukan diberi tinggi tetap: nama panjang
   sudah melipat dua baris di daftar, dan tinggi tetap akan memotongnya. */
.prj-tautan{color:var(--ink-1);text-decoration:none;
  display:block;padding:8px 0;min-height:32px}
.prj-tautan:hover{color:var(--blue-hi);text-decoration:underline}

/* Jenis dokumen yang BELUM ada tetap tampil, tetapi diredupkan. Panel yang
   hanya menampilkan yang sudah ada tidak menjawab "sudah sampai mana" —
   justru yang kosong itulah jawabannya. */
.prj-dok-kosong{opacity:.5}
.prj-dok-kosong .prj-dok-n{color:var(--ink-3)}


/* Tombol yang berupa TAUTAN, bukan kotak. Dipakai di layar masuk ("Lupa
   kata sandi?", "Kembali ke halaman masuk"): keduanya perpindahan layar,
   bukan tindakan — dan tombol bergaya kotak di sebelah tombol Masuk yang
   sungguhan membuat keduanya tampak setara padahal tidak.

   Tetap `<button>`, bukan `<a href="#">`: ia tidak menuju alamat mana pun,
   dan `<a>` tanpa tujuan tidak bisa dijangkau papan ketik dengan benar
   maupun dibacakan pembaca layar sebagaimana mestinya. */
.tautan-teks{
  border:0; background:none; padding:2px 4px; margin:0;
  font:inherit; font-size:11px; color:var(--blue); cursor:pointer;
  text-decoration:underline; text-underline-offset:2px; border-radius:6px;
}
.tautan-teks:hover{color:var(--blue-hi)}
.tautan-teks:focus-visible{outline:2px solid var(--blue); outline-offset:1px}


/* ══════════════════ PERBESARAN LEMBAR BAP ══════════════════
   Dipisahkan dari tombol navigasi halaman dengan garis tipis: keduanya ada
   di bilah yang sama tetapi menjawab pertanyaan yang berbeda — yang satu
   "halaman mana", yang lain "seberapa besar". */
/* Satu baris keterangan di tab Caption: label kecil di atas isiannya, bukan
   di sebelahnya. Laci konteks lebarnya ~320 px — label sejajar isian di sana
   menyisakan ~200 px untuk mengetik, dan keterangan foto memang kalimat,
   bukan satu kata. */
.bap-cap-baris{display:flex;flex-direction:column;gap:3px;margin-bottom:9px;
  padding:5px 6px;border:1px solid transparent;border-radius:var(--r-sm)}
.bap-cap-kepala{display:flex;align-items:center;gap:6px;
  font-size:10.5px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-3)}
/* Pegangan seret. Kotak teksnya sendiri TIDAK bisa menyeret barisnya -- di
   sana seret berarti menyorot lalu memindahkan sebagian kalimat, perilaku
   bawaan yang memang diharapkan. */
.bap-cap-seret{cursor:grab;font-size:13px;line-height:1;color:var(--ink-3)}
.bap-cap-baris:hover{border-color:var(--line-2);background:var(--card-2)}
.bap-cap-baris.bap-cap-diseret{opacity:.45}
.bap-cap-baris.bap-cap-sasaran{border-color:var(--blue);background:var(--blue-soft)}
.bap-cap-baris input{width:100%;height:32px;padding:0 9px;font-size:12.5px;
  border:1px solid var(--line-in);border-radius:var(--r-sm);background:var(--card)}

.bap-zoom{
  display:inline-flex;align-items:center;gap:4px;
  padding-left:9px;border-left:1px solid var(--line);
}
/* TANPA `margin-left:auto`. Dengan itu, begitu bilahnya membungkus, kelompok
   zoom mendarat sendirian di baris kedua dan didorong ke kanan — satu
   gerombolan tombol mengambang dengan ruang kosong selebar setengah panel di
   kirinya. Tanpa itu ia mengalir langsung sesudah tombol terakhir: sebaris
   kalau muat, dan kalau membungkus ia mulai dari tepi kiri yang sama seperti
   baris di atasnya — terbaca sebagai lanjutan, bukan sebagai pulau. */
.bap-zoom b{
  font-size:11.5px;font-weight:700;color:var(--ink-2);
  /* Lebar tetap dan angka bertabular: tanpa keduanya seluruh bilah bergeser
     setiap kali angkanya berpindah dari 90% ke 100%, dan tombol yang
     bergerak sendiri di bawah jari adalah tombol yang salah tekan. */
  min-width:38px;text-align:center;font-variant-numeric:tabular-nums;
}


/* ══════════════════ NOTA DI KEPALA PANEL ══════════════════
   Dipakai form yang area kerjanya sudah padat (BAP). Satu baris nota di
   bawah kepala panel mendorong bilah alat dan lembar fotonya turun sejauh
   40 px — mahal di layar yang tingginya memang sudah kurang.

   Dibatasi SATU BARIS dengan elipsis: nota yang membungkus akan mengubah
   tinggi kepala panel, dan kepala yang tingginya berubah-ubah membuat
   seluruh isi di bawahnya melompat setiap kali status dokumen berganti. */
.nota-kepala{
  flex:1 1 auto; min-width:0; margin:0 4px;
  font-size:11.5px; line-height:1.4; color:var(--ink-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.nota-kepala b{font-weight:700; color:var(--ink)}
/* Warnanya mengikuti jenis nota, tetapi HANYA lewat warna teks. Kelas
   `.nota-warn` dan kawan-kawannya membawa latar, garis tepi, dan padding
   sendiri — di dalam kepala panel itu jadi pita berwarna melintang yang
   bersaing perhatian dengan judulnya, dan tinggi kepalanya ikut berubah.
   Kekhususan dua kelas dipakai supaya menang tanpa !important. */
.nota-kepala.nota-warn, .nota-kepala.nota-bad,
.nota-kepala.nota-ok,   .nota-kepala.nota-info{
  background:none; border:0; padding:0; border-radius:0; gap:0;
}
.nota-kepala.nota-warn b{color:var(--warn-ink, #92400E)}
.nota-kepala.nota-bad  b{color:var(--bad)}
.nota-kepala.nota-ok   b{color:var(--ok)}
.nota-kepala svg{display:none}

@media(max-width:760px){
  /* Di layar sempit kepala panel sudah sesak oleh judul dan hitungannya.
     Notanya turun jadi baris sendiri di dalam kepala yang sama — masih di
     kepala, tetapi tidak lagi berebut lebar dengan keduanya. */
  .nota-kepala{flex-basis:100%; white-space:normal; margin:2px 0 0}
}


/* ── Jendela "Lihat detail" Data Master ────────────────────────────────
   Daftar label–nilai, bukan tabel: isinya empat sampai sepuluh baris dan
   selalu dua kolom, jadi tabel hanya menambah garis tanpa menambah kejelasan.
   Nilai boleh membungkus — spesifikasi barang kadang satu kalimat penuh, dan
   memotongnya di sini akan mengulang persis masalah yang membuat jendela ini
   ada. */
.mstr-detail{display:flex; flex-direction:column; gap:0}
.mstr-detail > div{display:grid; grid-template-columns:150px 1fr; gap:10px;
  padding:8px 0; border-bottom:1px solid var(--line)}
.mstr-detail > div:last-child{border-bottom:0}
.mstr-detail span{font-size:11.5px; font-weight:700; color:var(--ink-3);
  letter-spacing:.02em}
.mstr-detail b{font-size:12.5px; color:var(--ink); font-weight:600;
  word-break:break-word; line-height:1.5}
@media(max-width:560px){
  .mstr-detail > div{grid-template-columns:1fr; gap:2px}
}


/* ══════════════ BATANG JADWAL (GANTT) ══════════════
   Nama pekerjaannya di KIRI sebagai HTML biasa, batangnya di kanan sebagai
   SVG. Dipisah dengan sengaja: SVG-nya memakai preserveAspectRatio="none"
   supaya batang meregang mengikuti lebar layar, dan huruf yang ikut
   diregangkan jadi tulisan pipih yang sulit dibaca.

   Tinggi barisnya HARUS sama persis dengan TINGGI_LAJUR + JARAK_LAJUR di
   core/gantt.js. Kalau menyimpang, label dan batangnya bergeser makin jauh
   ke bawah — baris kelima masih terlihat wajar, baris ketiga puluh sudah
   menunjuk pekerjaan yang salah, dan tidak ada satu pun galat. */
.gantt-wrap{display:flex; gap:0; align-items:flex-start; overflow-x:auto}
/* 264 px, DIUKUR: label terpanjang pada data ARG sungguhan ("Bongkar
   plafon & rapikan kabel lama") butuh 251 px. Pada 240 px ia terpotong
   elipsis tepat di kata terakhir — dan yang terpotong justru bagian yang
   membedakan satu pekerjaan dari pekerjaan lain di project yang sama. */
.gantt-sisi{flex:none; width:264px; padding-top:30px}  /* 30 = TINGGI_SUMBU */
.gantt-isi{flex:1 1 auto; min-width:420px}
.gantt-label{height:26px; margin-bottom:6px; display:flex; align-items:center;
  gap:6px; font-size:12px; color:var(--ink-2); white-space:nowrap;
  overflow:hidden; padding-right:10px}
/* `text-overflow` TIDAK bekerja pada wadah flex — ia hanya berlaku pada
   kotak yang isinya teks. Ditaruh di wadahnya, nama pekerjaan terpotong
   keras tanpa satu pun tanda bahwa ia terpotong, dan di layar HP itu
   berarti dua pekerjaan yang awalannya sama terlihat persis serupa.
   `min-width:0` wajib: bawaan flex item adalah `auto`, yaitu selebar
   isinya, jadi tanpa itu ia tidak pernah menyusut dan tidak pernah
   memotong. */
.gantt-nama{overflow:hidden; text-overflow:ellipsis; min-width:0}
/* Nama project berdiri di lajurnya SENDIRI, bukan menumpang baris
   pekerjaan pertama. Menumpang membuat pekerjaan itu kehilangan namanya:
   lajurnya cuma setinggi satu baris, dan yang muat tinggal nama
   projectnya. Batangnya tetap tergambar, jadi tidak ada yang terlihat
   rusak — hanya satu pekerjaan per project yang tidak bisa dibaca. */
.gantt-label-grup{font-weight:800; color:var(--ink); font-size:12px;
  padding-right:10px; align-items:flex-end; padding-bottom:2px}
.gantt-label-grup b{overflow:hidden; text-overflow:ellipsis; font-weight:800}
.gantt-svg{display:block; border-left:1px solid var(--line-2)}
.gantt-legenda{display:flex; gap:14px; flex-wrap:wrap; margin-top:12px;
  font-size:11.5px; color:var(--ink-3)}
.gantt-legenda span{display:inline-flex; align-items:center; gap:6px}
.gantt-legenda i{width:12px; height:12px; border-radius:3px; display:inline-block}
.gantt-legenda i.gantt-kini{width:2px; height:14px; border-radius:0;
  background:var(--blue)}
@media (max-width:760px){
  .gantt-sisi{width:150px}
  .gantt-label{font-size:11px}
}
/* Kelompok tombol saringan status di Schedule Pekerjaan. WAJIB melipat:
   enam tombol dalam satu baris yang tidak bisa dipotong meluber keluar
   layar 360 px dan mendorong seluruh halaman bergulir mendatar. */
.jd-saring-status{display:inline-flex; gap:4px; flex-wrap:wrap}
/* Kotak saring project ikut mengalah di layar sempit — min-width 180px
   yang dipertahankan pada 360 px menyisakan terlalu sedikit untuk tombol
   di sebelahnya. */
@media (max-width:520px){
  #jdSaring{min-width:0; flex:1 1 130px}
}
/* ══════════════════ SCHEDULE: BOBOT, PROGRES, KURVA-S ══════════════════
   Ditambahkan 16 Sep 2026 (PROMPT Schedule dari MRI).
   Warna hanya lewat token — tidak ada satu pun heks di blok ini. */
.jd-ringkas{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px}
.jd-r-angka{font-family:var(--font-display); font-weight:800; font-size:26px;
  line-height:1.1; font-variant-numeric:tabular-nums; margin:0}
.jd-r-judul{font-size:12px; color:var(--ink-3); margin:4px 0 0}
/* Merah HANYA untuk yang benar-benar buruk — warna yang dipakai di dua
   tempat berbeda berhenti berarti apa-apa. */
.jd-buruk{color:var(--bad)}
.jd-kosong{color:var(--ink-3)}

/* Induk ditebalkan, anaknya menjorok. Tanpa itu tiga tingkat tidak
   terbedakan sama sekali di layar. */
.tbl-jadwal .jd-induk{font-weight:700}
.tbl-jadwal .jd-thead td{font-weight:800}
.tbl-jadwal tr.jd-telat td{background:var(--bad-bg)}
/* Tanda timpaan manual, pola ✎ yang sama dengan harga material BOQ. */
.jd-timpa{color:var(--warn); cursor:help}

.jd-deviasi{font-size:14px; font-weight:600; margin:0 0 10px}
.jd-legenda{display:flex; gap:14px; flex-wrap:wrap; margin-top:10px;
  font-size:12px; color:var(--ink-3)}
.jd-legenda span{display:inline-flex; align-items:center; gap:6px}
.jd-legenda i{width:18px; height:3px; border-radius:2px; display:inline-block}
.jd-l-base{background:var(--ink-3)}
.jd-l-rencana{background:var(--blue)}
.jd-l-real{background:var(--lime)}

.jd-warn{margin:0; padding-left:18px; font-size:13px; line-height:1.7}
.jd-riwayat{margin-top:10px; padding:10px 12px; background:var(--card-2);
  border:1px solid var(--line); border-radius:var(--r-sm); font-size:12.5px}
.jd-riwayat div{margin-top:4px; color:var(--ink-3)}
.jd-boq{display:inline-flex; gap:6px; flex-wrap:wrap}

@media (max-width:760px){
  .jd-ringkas{grid-template-columns:repeat(2,minmax(0,1fr))}
}
