/* PKPT — gaya tampilan.
 *
 * ATURAN PALING ATAS, JANGAN DIHAPUS.
 * Seluruh navigasi aplikasi ini bergantung pada atribut `hidden`. Aturan
 * bawaan browser `[hidden]{display:none}` KALAH spesifisitas dari selektor id
 * atau kelas mana pun yang menyetel `display`, jadi satu baris
 * `#panel { display: flex }` sudah cukup membuat panel form terpampang
 * permanen sebagai lapisan transparan setinggi layar — dan menelan setiap
 * ketukan, sehingga aplikasi tampak mati total di HP. Ini pernah terjadi di
 * NERACA.
 */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
   TEMA — SEKARANG DATANG DARI /css/tokens.css
   (jembatan dipasang 24 Agustus 2026)

   Nilai warna tidak lagi ditulis di berkas ini. Ia datang dari token design
   system yang ditautkan SEBELUM style.css di index.html. Yang tersisa di sini
   hanya jembatan di bawah: tiga nama lama yang dipakai 49 kali di berkas ini
   dan TIDAK ADA di kosakata token.

   Aksen tetap BIRU, bukan hijau atau teal. Hijau dipakai untuk "sesuai/aman"
   dan merah untuk "melampaui"; aksen yang masuk rumpun hijau akan terbaca
   sebagai penanda status oleh mata deuteranopia (~6% pria). Token
   `--aksen: #3a4f9e` mempertahankan aturan itu — ia biru merek lembaga yang
   digelapkan sampai lolos AA, bukan warna baru.

   YANG BERUBAH BAWAANNYA. Dulu `:root` telanjang berarti GELAP di sini;
   di token ia berarti TERANG. Itu aman, dan hanya karena satu hal: js/tema.js
   selalu menyetel data-tema ke 'gelap' atau 'terang' sebelum stylesheet
   melukis, jadi `:root` telanjang tidak pernah benar-benar berlaku. Kalau
   suatu saat tema.js dihapus dari <head>, aplikasi akan terbuka TERANG, bukan
   gelap. Itu perubahan yang disengaja, bukan kelalaian.

   Tetap tidak ada varian "auto" — keadaan ikut-sistem tetap urusan tema.js,
   dan CSS cukup mengenal dua keadaan.
--------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   JEMBATAN NAMA LAMA → TOKEN

   Tiga nama ini hidup di seluruh berkas dan tidak punya padanan di token:

     --latar-2   permukaan kartu/panel/kepala tabel lengket   (24 pemakaian)
     --latar-3   isian mundur: hover baris, jalur batang
                 kosong, baris sub, tombol nav aktif          (21 pemakaian)
     --bayang    bayangan panel & modal                       ( 4 pemakaian)

   Tanpa blok ini ketiganya menjadi custom property yang TIDAK TERDEFINISI.
   Dan `background: var(--latar-2)` yang tak terdefinisi tidak melempar galat
   dan tidak jatuh ke warna aman — deklarasinya menjadi tidak sah, latarnya
   kembali transparan, dan 24 permukaan kartu menghilang sekaligus sementara
   teksnya tetap tergambar di atas apa pun yang kebetulan ada di belakangnya.
   Persis jenis cacat yang tidak bergalat.

   --latar-3 SENGAJA DIPETAKAN BERBEDA DI TIAP TEMA, dan itu bukan
   inkonsistensi. Arah kontrasnya memang terbalik di kode lama: pada tema
   terang #eef2f7 lebih GELAP dari kartunya (#ffffff), pada tema gelap #1b2431
   lebih TERANG dari kartunya (#131a23). Satu token tidak bisa menjadi keduanya.
   Jadi terang mengambil --latar (meja kertas hangat, mundur ke belakang
   lembar) dan gelap mengambil --sel (naik ke depan lembar). Memaksakan satu
   nama untuk keduanya akan membuat hover baris di salah satu tema tidak
   terlihat sama sekali.
--------------------------------------------------------------------------- */
:root {
  --latar-2: var(--lembar);
  --latar-3: var(--latar);
  --bayang:  var(--bayang-panel);

  /* --- BATAS YANG MEMISAHKAN WILAYAH, BUKAN SEKADAR KISI (§131.14) --------
   *
   * `--garis` adalah tepi lembar: lembut dengan sengaja, dan tepat untuk kisi
   * tabel yang tidak boleh berteriak. Ia TIDAK cukup ketika yang dipisahkan
   * adalah WILAYAH — tabel di dalam tabel, atau kotak yang punya gulirnya
   * sendiri di dalam panel yang juga menggulir. Diukur, bukan ditaksir:
   *
   *              vs permukaannya     terang   gelap
   *   --garis                          1,40    1,34
   *   beda latar antar permukaan       1,15    1,08
   *   --teks-lemah 80%                 3,52    4,62   <- dipakai
   *
   * Dua baris pertama itu yang dilaporkan pemilik sebagai "tidak kelihatan,
   * sulit membedakan yang digulir tabel luar atau dalam" — dan angkanya
   * membenarkannya: beda LATAR saja tidak akan pernah cukup di palet ini,
   * pada tema mana pun. 80% dipilih sebagai yang pertama melewati 3:1 di
   * KEDUA tema; 100% terbaca sebagai garis kendali, bukan batas wilayah.
   *
   * `color-mix` baru ada di peramban yang cukup baru. Yang belum
   * mengenalnya memakai `--garis` lewat deklarasi `border` di atasnya —
   * keadaan sebelum pasal ini, bukan keadaan rusak. */
  --batas-tegas: color-mix(in srgb, var(--teks-lemah) 80%, transparent);
}

:root[data-tema="gelap"] {
  --latar-3: var(--sel);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--latar);
  color: var(--teks);
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

#app { max-width: 1100px; margin: 0 auto; padding: 16px 14px 88px; }

/* --- tipografi ----------------------------------------------------------- */
h1 { font-size: 1.4rem; margin: 0; letter-spacing: -.01em; }
h2 { font-size: 1.05rem; margin: 22px 0 8px; }
h3 { font-size: .95rem; margin: 14px 0 6px; }
p  { margin: 6px 0; }

/* WARNA TAUTAN TIDAK BOLEH DISERAHKAN KE BAWAAN PERAMBAN (§13.8).
 *
 * Sampai 14 Agustus 2026 berkas ini tidak memuat satu pun aturan untuk `a`,
 * sehingga tautan memakai bawaan peramban: #0000EE, dan yang sudah dikunjungi
 * #551A8B. Di atas kartu gelap keduanya menghasilkan kontras 1,86 dan 1,59 —
 * praktis tak terbaca. Yang kena justru tautan yang paling perlu terbaca:
 * `/pkpt/diagnosa.html` di Pengaturan, yaitu alamat yang disebutkan kepada
 * orang yang TIDAK BISA MASUK sama sekali.
 *
 * Tema gelap tidak pernah diberi tahu tentang warna bawaan itu, dan tidak ada
 * yang melihatnya karena kontras tidak pernah diukur.
 *
 * --aksen: 6,88 di kartu gelap, 6,70 di kartu terang. `:visited` disamakan
 * dengan sengaja — riwayat kunjungan tidak menambah apa pun di aplikasi
 * setebal ini, dan ungu bawaan hanya menambah satu pasangan warna lagi yang
 * harus diukur.
 */
a, a:visited { color: var(--aksen); }
a:hover, a:focus-visible { text-decoration-thickness: 2px; }

/* Setiap `summary` adalah sasaran sentuh (§13.9), bukan hanya yang kebetulan
   berada di dalam `.rincian` atau `.tindak`. Dua kali dalam satu hari
   ditemukan `summary` 22–32px yang luput karena kelasnya berbeda: aturan yang
   dipasang per kelas menjaga yang sudah ada, bukan yang ditambahkan besok.
   Yang sulit dibuka sama saja dengan yang disembunyikan. */
summary { min-height: 44px; }

/* Kop cetakan: tidak pernah terlihat di layar (§13.11). */
.kop-cetak { display: none; }
/* Keterangan yang hanya berarti di atas kertas — pembaca cetakan tidak
   pernah melihat tombol kerapatan yang menghasilkan gambar itu. */
.hanya-cetak { display: none; }
/* Bungkus pengganti `<details>` saat mencetak — lihat pasangCetakPeta(). */
.cetak-terbuka { display: none; }

.lemah { color: var(--teks-lemah); }
.kecil { font-size: .84rem; }
/* `.mono` menandai TOKEN MESIN — kode rekening, kode sub-kegiatan, nama kolom
   tempel, bentuk tanggal, nomor ST. Ia karena itu `nowrap`, sepola dengan
   `.kode-kecil`/`.kode-sisip` di bawah dan dengan `.angka-ringkas` (§13).

   Cacatnya lebih tua daripada seluruh pekerjaan hari ini dan tetap luput
   karena bentuknya kecil: `<span class="mono">…0003</span>` di halaman Pedoman
   pecah menjadi "…" (9px) lalu "0003" (35px) pada 320px dan 375px. Titik-tiga
   U+2026 adalah tempat peramban BOLEH memutus baris, jadi kode yang diawali
   elipsis punya celah yang tidak dipunyai kode penuh — dan ia justru bentuk
   yang dipakai menjelaskan beda `…0001` dengan `…0003`, dua kode yang seluruh
   halaman itu ada untuk membedakannya.

   Diperbaiki di KELASNYA, bukan di kedua pemanggilnya: penyebutan ketiga yang
   ditulis bulan depan akan pecah lagi, dan tidak ada yang akan menyadarinya —
   persis riwayat aturan yang sama di `uang.js`. */
.mono  { font-variant-numeric: tabular-nums; font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
         white-space: nowrap; }
.angka { font-variant-numeric: tabular-nums; }

.baik  { color: var(--baik); }
.buruk { color: var(--buruk); }
.hati  { color: var(--hati); }

.baris-judul {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 10px; flex-wrap: wrap;
}
.alat-judul { display: flex; gap: 8px; align-items: center; }

/* --- pemilih wajah beranda (kanan atas) ---------------------------------- */
/* Sisi kanan baris judul Beranda: pemilih wajah + petak alat. `flex-wrap`
   supaya pada 375px keduanya melipat KE BAWAH judul, bukan memeras judulnya
   sampai "Beranda" pecah baris. `max-width: 100%` menjaga sisa kanan HALAMAN,
   bukan sekadar sisa di dalam kotaknya — pelajaran halaman Pedoman. */
.judul-kanan {
  display: flex; gap: 8px; align-items: center;
  flex-wrap: wrap; justify-content: flex-end; max-width: 100%;
}
/* Petak kosong tetap sebuah anak flex, dan `gap` tetap dihitung untuknya —
   jarak 8px yang tidak memisahkan apa pun. */
#beranda-wajah:empty, #beranda-alat:empty { display: none; }

.pilih-wajah { display: flex; gap: 6px; align-items: center; max-width: 100%; }
.pilih-wajah label {
  font-size: .85rem; color: var(--teks-lemah); white-space: nowrap;
}
/* Sasaran sentuhnya datang dari `input, select, textarea { min-height: 44px }`
   di bawah — tidak ada perkecualian §13.9 yang perlu ditandai di sini. */
.pilih-wajah select { max-width: 100%; }
/* Akun berperan lebih dari satu: pemilihnya DISOROT (§117.5) — tepi beraksen
   dan label tebal, supaya kotak kecil di kanan atas itu terbaca sebagai
   kendali, bukan hiasan. Yang menyalakannya kelas `rangkap`, yang hanya
   diberikan saat daftarnya lebih dari satu. */
.pilih-wajah.rangkap label { color: var(--teks); font-weight: 600; }
.pilih-wajah.rangkap select { border-color: var(--hati); box-shadow: 0 0 0 2px color-mix(in srgb, var(--hati) 25%, transparent); }
.sadar-peran p { margin: 0 0 6px; }
.sadar-peran .baris-tombol { margin: 6px 0 0; }

/* --- kartu --------------------------------------------------------------- */
.kartu {
  background: var(--latar-2);
  border: 1px solid var(--garis);
  border-radius: 12px;
  padding: 14px;
  margin: 10px 0;
}
.kartu-rapat { padding: 10px 12px; }

/* Lebar minimum kolom 210px, BUKAN 160px.
 *
 * Pada 160px, layar 375px memuat dua kolom selebar ~168px — dan
 * "Rp 5.128.422.000" tidak muat, sehingga "Rp" terlempar ke baris sendiri.
 * Itu persis cacat yang §13.4 larang, hanya pada kartu ringkasan alih-alih
 * pada daftar. Dengan 210px, layar HP memberi satu kolom penuh dan angkanya
 * utuh; layar 440px ke atas kembali dua kolom dengan sendirinya. */
.kisi { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

/* Kartu di dalam kisi memakai jarak dari `gap`, bukan dari margin sendiri.
   Keduanya sekaligus membuat tiap kartu berjarak 30px dari tetangganya, dan
   pada layar HP — tempat kisi menjadi satu kolom — enam kartu ringkasan
   mendorong papan pemeriksaan sejauh satu setengah layar ke bawah. */
.kisi > .kartu { margin: 0; }
.kisi > .kartu .angka-besar { margin: 2px 0; }

/* `clamp` menyusutkan angka pada layar sempit alih-alih memecahnya. Nominal
   yang mengecil masih terbaca; nominal yang terbelah dua baris tidak. */
.angka-besar {
  font-size: clamp(1.15rem, 5.2vw, 1.5rem);
  font-weight: 650; letter-spacing: -.02em;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* Angka yang BELUM ADA (SPEC-rev2 §13.1). Dibedakan dari nominal supaya tidak
   terbaca sebagai garis penghubung yang tercecer. */
.angka-besar.lemah { color: var(--teks-lemah); font-weight: 500; }

/* Baris keterangan KEDUA pada kartu ringkas — dipakai `label_tampilan` milik
   SPJ, yang ditampilkan apa adanya dan karena itu panjang (§51.4). Ukurannya
   diperkecil dan spasinya dirapatkan supaya kartunya tidak tumbuh melebihi
   ketiga tetangganya; kalau ia tetap lebih tinggi, yang bertumbuh grid-nya,
   bukan kalimatnya yang dipotong. */
   TANPA `opacity`. Meredupkan dengan opacity menjatuhkan kontras di bawah
   token yang sudah diaudit, dan auditnya BUTA terhadapnya — ia membaca warna,
   bukan hasil komposisinya. Warnanya sudah datang dari `.lemah`
   (`--teks-lemah`), yang memang sudah lolos ambang. */
.kartu-asal { margin-top: 2px; font-size: .68rem; line-height: 1.3; }
.label { font-size: .78rem; color: var(--teks-lemah); text-transform: uppercase; letter-spacing: .04em; }

/* --- tombol -------------------------------------------------------------- */
button, .tombol {
  font: inherit;
  border-radius: 10px;
  border: 1px solid var(--garis);
  background: var(--latar-3);
  color: var(--teks);
  padding: 9px 14px;
  cursor: pointer;
  /* 44px adalah ambang sasaran sentuh yang bisa ditekan dengan yakin sambil
     berdiri. Aplikasi ini juga dibuka dari HP saat rapat. */
  min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  text-decoration: none;
}
button:hover, .tombol:hover { border-color: var(--aksen); }
button:disabled { opacity: .45; cursor: not-allowed; }
button.utama { background: var(--aksen); color: var(--aksen-teks); border-color: var(--aksen); font-weight: 600; }
button.ghost { background: transparent; }
/* "Kecil" berlaku pada padding dan ukuran huruf, TIDAK pada tingginya (§13.9).
   Sampai 14 Agustus 2026 kelas ini menyetel 38px — dan karena "Setujui yang
   dipilih" serta "Tolak…" memakainya, dua tombol yang menentukan seluruh alur
   §20 berada di bawah ambang yang ditetapkan sepuluh baris di atas. Ambang yang
   dibatalkan oleh satu kelas pembantu, tanpa keputusan, bukan ambang. */
button.kecil, .kecil.tombol { padding: 6px 12px; min-height: 44px; font-size: .9rem; }
button.lebar, .lebar { width: 100%; }
button.bahaya { color: var(--buruk); border-color: var(--buruk); background: transparent; }

.baris-tombol { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
/* Sel tabel yang memakai kelas ini TETAP sel tabel. `display: flex` membuat
   `<td>` keluar dari barisnya: garis bawahnya tidak sejajar dengan sel lain,
   dan margin 10px mendorong tombolnya turun. Terlihat di Atur → Kalender,
   Atur → Obyek, dan Laporan → PPBR pada ketiga lebar. */
td.baris-tombol { display: table-cell; margin: 0; }
td.baris-tombol > button { margin: 0 0 4px; vertical-align: top; }
td.baris-tombol > button:not(:last-child) { margin-right: 4px; }

/* Isian berawalan tetap — nomor surat tugas (SPEC-rev2 §23.1).
   Awalannya kode klasifikasi yang baku; yang diketik hanya nomor urutnya.
   Ditulis sebagai teks, bukan sebagai isi kotak, supaya ia tidak punya
   kesempatan terhapus atau salah ketik. `flex-shrink: 0` menjaganya tetap utuh
   pada 375px — awalan yang terpotong menjadi "800.1.1…" akan membuat orang
   mengira nomornya yang salah. */
.baris-isian { display: flex; align-items: stretch; gap: 0; }
.baris-isian .awalan {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  padding: 10px 10px;
  border: 1px solid var(--garis);
  border-right: 0;
  border-radius: 8px 0 0 8px;
  background: var(--latar-3);
  color: var(--teks-lemah);
}
.baris-isian input { border-radius: 0 8px 8px 0; }

/* --- masukan ------------------------------------------------------------- */
input, select, textarea {
  font: inherit;
  width: 100%;
  padding: 10px 12px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid var(--garis);
  background: var(--latar-2);
  color: var(--teks);
}
textarea { min-height: 140px; resize: vertical; font-family: ui-monospace, Consolas, monospace; font-size: .88rem; }
input:focus, select:focus, textarea:focus, button:focus-visible {
  outline: 2px solid var(--aksen); outline-offset: 1px;
}
label { display: block; font-size: .86rem; color: var(--teks-lemah); margin: 10px 0 4px; }
.tumpuk { display: block; }
.tumpuk button { margin-top: 14px; width: 100%; }

.baris-saring { display: flex; gap: 8px; margin: 8px 0 12px; }
.baris-saring input { flex: 2; }
.baris-saring select { flex: 1; }
/* Pemilih unit per baris di Atur → Unit (§133.5). Dengan `width: 100%` bawaan,
   kolomnya diperas ke lebar nama unit terpendek, dan "— tanpa unit —"
   terpotong pada 375 dan 768px. Selebar opsi terpanjangnya; tabelnya sudah
   menggulir di dalam `.gulir`. */
select[data-unit-pilih] { width: auto; }

/* Bilah saring Penugasan: tiga kendali, bukan dua (SPEC-rev2 §78).
 *
 * Pemanggil bilah posisi ikut berdiri di baris ini. Pada 375px ketiganya tidak
 * muat berdampingan — kotak pencarian akan tersisa selebar dua aksara — jadi
 * barisnya BOLEH melipat, dan yang melipat turun adalah pemanggilnya.
 * `flex-basis` diberikan supaya lipatannya terjadi karena kesempitan, bukan
 * karena `flex: 2 / 1` yang berpangkal nol dan karena itu SELALU muat — tiga
 * kendali dalam satu baris 375px berarti kotak pencarian selebar dua aksara.
 *
 * Angka 200/100 bukan sembarang: pada 375px ia memulangkan lebar yang PERSIS
 * sama dengan `flex: 2 / 1` sebelum §78 (226,2px dan 113,1px). Pemanggilnya
 * yang turun ke baris kedua; bilah pencarian yang sudah dipakai orang tidak
 * berubah sedikit pun.
 *
 * Dilingkupi id, bukan `.baris-saring` telanjang: kelas itu dipakai juga oleh
 * bilah saring jejak audit yang hanya punya dua kendali dan sudah muat. */
#penugasan-saring { flex-wrap: wrap; }
#penugasan-saring input  { flex: 2 1 200px; }
#penugasan-saring select { flex: 1 1 100px; }
#penugasan-saring #penugasan-posisi-buka { flex: 0 0 auto; white-space: nowrap; }

/* --- tab ----------------------------------------------------------------- */
/* Bilah tab yang lebih lebar dari wadahnya HARUS mengatakannya.
 *
 * Terukur pada audit 20 Agustus 2026, halaman Pedoman di 375px: bilahnya 887px
 * di dalam wadah 347px, dan tab KETIGA mulai di x=369 — sepenuhnya di luar
 * layar. Tidak ada mask, tidak ada bayangan, tidak ada batang gulir; satu-
 * satunya petunjuk bahwa ada isi di kanan adalah tab kedua yang kebetulan
 * terpotong di tengah kata. Tiga dari lima tabnya tidak terlihat sama sekali.
 *
 * Yang membuatnya mahal: Pedoman adalah satu-satunya halaman yang dibaca orang
 * SEBELUM ia tahu cara memakai aplikasinya — dan sejak 20 Agustus pembacanya
 * bertambah 126.
 *
 * `mask-image` dipilih, bukan gradasi latar: ia bekerja di atas latar apa pun
 * sehingga tidak perlu dua nilai untuk dua tema. Dipasang lewat variabel
 * supaya bisa dimatikan pada lebar yang memang memuat seluruh tabnya. */
.tab {
  display: flex; gap: 6px; overflow-x: auto; margin: 4px 0 12px; padding-bottom: 2px;
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
@media (min-width: 700px) { .tab { mask-image: none; } }
.tab button { white-space: nowrap; min-height: 44px; padding: 7px 14px; }
.tab button.aktif { background: var(--aksen); color: var(--aksen-teks); border-color: var(--aksen); font-weight: 600; }
/* Sakelar jenis di atas bilah tab Anggaran (§103.10): dua bilah bertumpuk, yang atas lebih rapat. */
.tab.tab-jenis { margin-bottom: 4px; }
.tab.tab-jenis button { min-height: 44px; font-size: .92em; }

/* --- ATUR → AKUN: SUB-TAB TINGKAT KEDUA (§82.1) --------------------------

   Bilahnya memakai kelas `.tab` yang SUDAH ADA — gulir mendatar, mask-image,
   dan `min-height: 44px` per tombol datang dari sana tanpa satu baris
   tambahan. Yang ditambahkan di bawah hanya yang membedakan TINGKAT: dua
   bilah tab yang tampak persis sama, bertumpuk, terbaca sebagai satu bilah
   panjang yang terpotong — dan orang akan mencari "Keamanan" di sebelah
   kanan "Pengawasan".

   Pembedanya BUKAN warna aksen kedua (yang akan bertabrakan dengan tombol
   aktif) melainkan garis penambat di kiri dan tombol yang sedikit lebih
   rendah bobotnya. Tingginya TIDAK diturunkan: 44px berlaku di setiap
   tingkat, dan sasaran sentuh bukan tempat menghemat ruang. */
.tab#atur-akun-tab {
  margin-top: -4px;
  padding-left: 10px;
  border-left: 3px solid var(--garis);
}
.tab#atur-akun-tab button { font-size: .9rem; }

/* Pita §59, di ATAS bilah sub-tab dan karena itu terlihat dari bagian mana
   pun. Kosong ia tidak memakan ruang sama sekali — `:empty` menutup jarak
   yang kalau tidak akan menyisakan celah tak terjelaskan di atas tab. */
#atur-akun-pita:empty { display: none; }
#atur-akun-pita { margin-bottom: 10px; }

/* LAYAR SATU BAGIAN, KERTAS KEEMPATNYA (§82.4).

   Sepola `.periksa-lipat` (§74.3), dan dengan sebab yang sama persis: kalau
   tiga bagian yang tidak aktif dihapus dari DOM, Ctrl+P dari "Keamanan"
   menghasilkan seperempat halaman Pengaturan SAMBIL TERLIHAT UTUH. Yang
   memilih satu bagian adalah kelas ini; @media print di bawah
   membatalkannya. */
.atur-lipat { display: none; }

/* Hanya untuk kertas. Di layar nama bagiannya sudah terbaca di bilah tab,
   dan judul kedua tepat di bawah tab yang sama hanya mengulang. */
.atur-kepala-cetak { display: none; }

/* --- PPBR: kepanjangannya di judul (§82.7) --------------------------------
   Namanya dan kepanjangannya satu blok, tetapi BUKAN satu ukuran: yang
   dicari mata adalah singkatannya, yang dibaca sekali adalah kepanjangannya.
   Di 375px keduanya membungkus ke dua baris — karena itu `display: block`
   pada kepanjangannya, bukan mengandalkan spasi. */
.ppbr-judul { margin-bottom: 12px; }
.ppbr-judul .lemah {
  display: block;
  font-size: .9rem;
  font-weight: 400;
}

/* --- tabel --------------------------------------------------------------- */
.gulir { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { border-collapse: collapse; width: 100%; font-size: .88rem; }
th, td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--garis); vertical-align: top; }
th { color: var(--teks-lemah); font-weight: 600; font-size: .78rem; text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; }
td.kanan, th.kanan { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Baris aksi Kelola akun (§159.6) menempel ke baris akun di atasnya: garis
   pemisahnya pindah ke bawah baris aksi, supaya tombolnya terbaca milik akun
   itu dan bukan milik akun berikutnya. */
tr:has(+ tr.kl-aksi) > td { border-bottom: none; }
tr.kl-aksi > td { padding-top: 0; }
tbody tr:hover { background: var(--latar-3); }
/* …KECUALI baris yang MEMUAT tabel lain di dalamnya (§131.14).
   `tbody tr:hover` adalah selektor keturunan, jadi menyorot satu baris tabel
   dalam ikut menyalakan baris tabel LUAR yang menampungnya — dua baris
   menyala untuk satu tunjuk, dan yang membacanya tidak tahu mana yang sedang
   ia tunjuk. Yang dipadamkan barisnya yang luar: ia hanya wadah, dan tidak
   ada tindakan apa pun yang melekat padanya. */
tbody tr:has(table):hover { background: transparent; }

/* --- pengesahan: dokumen batal & pemilih isi lampiran (SPEC-rev2 §34) ----- */

/* Dokumen yang DIBATALKAN tetap ditampilkan (§34.5) — yang berubah hanya
   bobotnya di mata. Dipudarkan, BUKAN dicoret: teks bergaris coret di dalam
   tabel padat sudah terbukti sulit dibaca pada 375px, dan yang justru perlu
   dibaca di baris ini adalah sebab pembatalannya. */
.baris-batal > td { opacity: .62; }
.baris-batal .lencana.buruk { opacity: 1; }

/* Daftar 274 penugasan di dalam panel HARUS punya batas tinggi sendiri.
   Tanpa ini panelnya menjadi setinggi 274 baris, tombol Simpan terdorong ke
   ujung bawah, dan orang yang sudah memilih barisnya harus menggulir seluruh
   daftar untuk menemukannya — kelas cacat "tombol yang tak terjangkau" yang
   sudah pernah ditambal di layar lain. */
.gulir-tinggi { max-height: 46vh; overflow-y: auto; }

/* --- tabel rencana → realisasi (SPEC-rev2 §32.7) ------------------------- */

/* LIMA KOLOM PADA 375px BERGULIR, TIDAK DIPERAS.
 *
 * Gulirnya ada di dalam `.gulir`, tidak pernah di halaman (§17.4). Lebar
 * minimum kolom uang bukan selera: 120px adalah lebar yang masih memuat
 * "Rp 108,2 jt" dalam satu baris. Nominal yang pecah dua baris sudah pernah
 * menjadi cacat yang harus diperbaiki (§13.4) — dan di tabel berkolom empat
 * ia pecah empat kali sekaligus, pada baris yang sama.
 *
 * Kolom nama sengaja `white-space: normal`: nama penugasan panjang, dan
 * memaksanya satu baris melebarkan tabel sampai kolom uangnya tidak pernah
 * terlihat bersamaan — padahal membandingkan keempatnya pada satu baris
 * justru satu-satunya alasan tabel ini ada. */
.tabel-empat { min-width: 720px; }
.tabel-empat th:first-child,
.tabel-empat td:first-child { min-width: 230px; white-space: normal; }
.tabel-empat th.kanan, .tabel-empat td.kanan { min-width: 120px; }
.tabel-empat tfoot th {
  color: var(--teks); font-size: .85rem; border-top: 2px solid var(--garis);
}

/* ---------------------------------------------------------------------------
 * KEPALA, KOLOM NAMA, DAN BARIS JUMLAH DIPATOK (§56)
 *
 * Keluhan pemilik, 21 Agustus 2026: menggulir tabel ini ke kanan membuat judul
 * kolom dan nama penugasannya hilang bersamaan — dan pada empat kolom uang
 * berdampingan, "kolom keberapa ini" adalah pertanyaan yang jawabannya
 * menentukan apakah angkanya dibaca sebagai rencana atau sebagai bayaran.
 *
 * PELAJARANNYA SUDAH ADA DI BERKAS INI, dua kali, dan keduanya dipakai:
 *
 *   1. `.gulir-tim` — tabel harus menggulir DI DALAM kotaknya sendiri. Panel
 *      modal yang menggulir keseluruhan membuat `top: 0` menempel pada panel,
 *      bukan pada tabelnya, sehingga kepalanya tetap hanyut. Karena itu ada
 *      `max-height` di bawah; tanpa itu seluruh blok ini tidak berbuat apa-apa.
 *   2. `.peta-nama` — urutan `z-index` menentukan siapa menimpa siapa saat
 *      keduanya hanyut. Kolom nama harus menang atas isi baris, dan kepala
 *      harus menang atas kolom nama; sudut kiri-atas menang atas keduanya.
 *      Pada tingkat yang sama, yang belakangan di DOM menang — dan itu sudah
 *      pernah membuat penanda menimpa nama orangnya.
 *
 * Urutannya, dan ketiganya harus dibaca bersama:
 *     kolom pertama   2   nama penugasan menang atas kolom uang
 *     thead / tfoot   3   kepala dan jumlah menang atas kolom nama
 *     sudut keduanya  4   perpotongannya menang atas semuanya
 *
 * LATARNYA WAJIB PADAT. Sel `sticky` yang latarnya bening membiarkan baris di
 * bawahnya lewat menembusnya — dan angka yang saling menimpa lebih buruk
 * daripada angka yang hanyut, sebab yang pertama masih terbaca sebagai angka.
 * ------------------------------------------------------------------------- */
.gulir-empat {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  max-height: min(58vh, 560px);
}
.gulir-empat .tabel-empat thead th {
  position: sticky; top: 0; z-index: 3;
  background: var(--latar-2);
  box-shadow: 0 1px 0 var(--garis);
}
/* Baris JUMLAH ikut dipatok di DASAR, dan itu bukan hiasan: ia satu-satunya
   angka di tabel ini yang menjawab "berapa seluruhnya", dan pada 96 baris ia
   berada sembilan layar di bawah — sehingga tidak pernah terlihat bersamaan
   dengan baris mana pun yang sedang dibaca. */
.gulir-empat .tabel-empat tfoot th {
  position: sticky; bottom: 0; z-index: 3;
  background: var(--latar-2);
  box-shadow: 0 -1px 0 var(--garis);
}
.gulir-empat .tabel-empat th:first-child,
.gulir-empat .tabel-empat td:first-child {
  position: sticky; left: 0; z-index: 2;
  background: var(--latar);
  border-right: 1px solid var(--garis);
}
/* Sudut kiri-atas dan kiri-bawah: keduanya sekaligus kepala DAN kolom nama,
   jadi keduanya harus menang atas dua-duanya. */
.gulir-empat .tabel-empat thead th:first-child,
.gulir-empat .tabel-empat tfoot th:first-child {
  z-index: 4; background: var(--latar-2);
}
/* Kolom yang DISOROT (§32.7) tidak pernah kolom pertama — `k()` hanya
   memasangnya pada keempat kolom uang — jadi sorotan dan pematokan tidak
   pernah berebut latar pada sel yang sama. Kalau suatu hari kolom pertama ikut
   bisa disorot, aturan di atas harus dikecualikan untuknya. */

/* Kolom yang tadi diketuk di beranda (§32.7).
 *
 * LATAR, bukan warna teks. Warna teks di kolom uang sudah dipakai naik/turun,
 * dan dua makna pada satu penanda adalah penanda yang tidak bermakna. Sorotan
 * dipasang di kepala DAN di seluruh selnya: kepala saja tidak terlihat lagi
 * begitu tabelnya digulir melewati baris pertama. */
.sorot-kolom { background: color-mix(in srgb, var(--aksen) 12%, transparent); }
tbody tr:hover .sorot-kolom { background: color-mix(in srgb, var(--aksen) 20%, transparent); }

/* --- daftar penugasan ---------------------------------------------------- */
.item {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--garis); border-radius: 12px;
  background: var(--latar-2); margin-bottom: 8px; width: 100%; text-align: left;
  min-height: 44px;
}
.item:hover { border-color: var(--aksen); }
/* Baris daftar penugasan yang bisa DIPILIH untuk diajukan/disetujui (tahap 4).
   Kotaknya berdiri di luar tombol barisnya — `<input>` di dalam `<button>`
   tidak sah — dan menempati kolom 44px sendiri. Baris yang tidak bisa
   ditindak mendapat ruang kosong selebar itu supaya kolomnya tetap sejajar.
   `.item` di dalamnya tetap selebar sisa baris, tidak menyusut di bawah
   isinya (`min-width: 0` membiarkan namanya membungkus). */
.item-pilih { display: flex; align-items: flex-start; gap: 4px; }
.item-pilih > .item { flex: 1 1 auto; min-width: 0; }
.item-pilih > .pilih-baris { flex: 0 0 44px; justify-content: center; min-height: 44px; }

/* TAHAP PENUGASAN SEBAGAI ALUR (tahap 4). Lima tahap berderet dan MEMBUNGKUS
   di layar sempit — bukan menggulir mendatar: yang dicari mata adalah tahap
   yang sekarang, dan tahap yang tersembunyi di balik tepi tidak menjawabnya.
   Yang sekarang ditandai isian + tebal, yang sudah lewat bercentang, yang
   belum lemah — tiga keadaan, tiga bentuk, bukan hanya tiga warna (dicetak). */
.alur-tahap {
  list-style: none; margin: 4px 0 6px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 4px; font-size: .78rem;
}
.alur-tahap li {
  padding: 2px 9px; border-radius: 999px; border: 1px solid var(--garis);
  color: var(--teks-lemah); white-space: nowrap;
}
.alur-tahap li.lewat { color: var(--teks); }
.alur-tahap li.lewat::before { content: "\2713\00A0"; color: var(--baik); }
.alur-tahap li.kini {
  background: var(--aksen); border-color: var(--aksen); color: var(--aksen-teks); font-weight: 700;
}
.alur-tahap.berhenti li { text-decoration: line-through; opacity: .7; }
.alur-langkah { margin: 0 0 6px; }

/* PANEL BANTUAN (tahap 4). Tombolnya satu aksara "?", jadi lebarnya DIPASANG —
   ambang §13.9 punya dua sumbu, dan lebar tombol satu aksara hanya terjadi,
   tidak tertulis (§145.7, panah bulan Kalender 31×44). */
#tombol-bantuan { min-width: 44px; font-weight: 700; }
.bantuan-daftar { list-style: none; margin: 8px 0; padding: 0; display: grid; gap: 10px; }
.bantuan-daftar li {
  border: 1px solid var(--garis); border-radius: 10px; padding: 10px 12px;
  background: var(--latar);
}
.bantuan-daftar li p { margin: 4px 0 6px; }
/* Sorotan sesaat pada elemen yang DITUNJUKKAN — cincin, bukan warna isian,
   supaya terbaca di kedua tema dan tidak menimpa warna status di dalamnya. */
.sorot-bantuan {
  outline: 3px solid var(--aksen); outline-offset: 3px;
  box-shadow: 0 0 0 8px color-mix(in srgb, var(--aksen) 22%, transparent);
  transition: outline-color .3s;
}

/* FORMULIR BERTAHAP (tahap 4): deret langkah bernomor di kepala formulir
   panjang. Membungkus, tidak menggulir mendatar; tiap langkah tombol ringan
   44px (§13.9) yang membawa mata ke bagiannya — bagiannya tidak disembunyikan
   (lihat `langkahFormHtml()` di app.js untuk sebabnya). */
.langkah-form {
  list-style: none; margin: 6px 0 10px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 4px;
}
.langkah-form button b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%; margin-right: 4px;
  background: var(--aksen); color: var(--aksen-teks); font-size: .72rem;
}
/* Ringkasan tepat di atas Simpan: "yang akan tersimpan", dengan yang wajib
   dan masih kosong ditulis berwarna hati. */
.ringkas-simpan {
  margin: 4px 0 8px; padding: 8px 10px; border-radius: 8px;
  border: 1px dashed var(--garis); background: var(--latar);
}
.alur-tombol { margin: 0 0 8px; }
/* `display: block` pada keduanya, BUKAN inline.
 *
 * Sebagai span sebaris, nama penugasan dan keterangannya mengalir menjadi satu
 * paragraf: "Pendampingan Opname Kas dan Persediaan selesai januari — tanggal
 * belum ditetapkan". Judul dan keterangan yang menyambung begitu menuntut
 * dibaca sampai habis untuk tahu di mana judulnya berakhir. */
.item-kiri { min-width: 0; display: block; }
.item-nama { font-weight: 600; display: block; line-height: 1.35; }
.item-meta { font-size: .8rem; color: var(--teks-lemah); margin-top: 3px; display: block; }

/* NOMINAL TIDAK PERNAH MENYUSUT DAN TIDAK PERNAH PECAH BARIS (SPEC-rev2 §13.4).
 *
 * `.item` adalah flex dan `.item-kiri` boleh menyusut (min-width: 0). Tanpa dua
 * aturan di bawah, flex memeras kolom angka sampai 27,5px di lebar HP dan
 * "Rp 30,9 jt" terbelah menjadi tiga baris: "Rp" / "30,9" / "jt". Masih terbaca
 * oleh yang menulisnya, tidak oleh orang yang membacanya sekali di rapat. */
/* Nilai tunggal (tanggal/nominal) di dalam kalimat diff §66.1 — aturan §13
 * yang sama: nilai yang terbelah dua baris berhenti terbaca sebagai satu
 * nilai. Tertangkap sapu-ukur 375px pada 25 Agu 2026 ("19 Feb 2026" pecah). */
.nilai-utuh { white-space: nowrap; }
.item > .angka {
  flex: 0 0 auto;
  white-space: nowrap;
  text-align: right;
  font-weight: 600;
  padding-left: 4px;
}

/* --- yang bisa ditekan --------------------------------------------------- */
/* Angka ringkasan dan baris tabel yang menyimpan rincian di baliknya. Tanda
   visualnya sengaja jelas: rincian yang ada tapi tidak terlihat bisa dibuka
   sama saja dengan rincian yang tidak ada. */
.kartu-buka {
  width: 100%; text-align: left; font: inherit; color: inherit;
  min-height: 0; display: block; cursor: pointer;
}
.kartu-buka:hover { border-color: var(--aksen); }
/* Kartu penyaring yang sedang aktif (Pegawai §25.1) — batasnya menyala supaya
   daftar yang menyusut di bawahnya bisa dilacak sebabnya. */
.kartu-buka.aktif { border-color: var(--aksen); box-shadow: inset 0 0 0 1px var(--aksen); }
.kartu-buka .angka-besar { text-align: left; }

tr.klik { cursor: pointer; }
tr.klik:hover { background: var(--latar-3); }
tr.klik:hover td:first-child { box-shadow: inset 3px 0 0 var(--aksen); }

#lapis-kembali { margin-bottom: 4px; }

/* --- lencana ------------------------------------------------------------- */
.lencana {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: .74rem; font-weight: 600; border: 1px solid var(--garis);
  white-space: nowrap;
}
.lencana.baik  { color: var(--baik);  border-color: var(--baik); }
.lencana.buruk { color: var(--buruk); border-color: var(--buruk); }
.lencana.hati  { color: var(--hati);  border-color: var(--hati); }
.lencana.aksen { color: var(--aksen); border-color: var(--aksen); }

/* --- pekerjaan Anda (SPEC-rev2 §144) — pola daftar tugas ----------------- */
.tugas-daftar { list-style: none; margin: 0; padding: 0; }
.tugas-daftar > li + li { border-top: 1px solid var(--garis); }
.tugas-baris {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 44px; padding: 10px 4px; text-align: left;
  background: none; border: 0; border-radius: 0; color: inherit; font: inherit;
}
button.tugas-baris { cursor: pointer; }
button.tugas-baris:hover { background: var(--latar-lembut, rgba(0,0,0,.03)); }
.tugas-angka { flex: 0 0 auto; min-width: 2.2em; text-align: right; font-weight: 700;
  font-size: 1.15rem; white-space: nowrap; }
.tugas-isi { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tugas-baris > .lencana { flex: 0 0 auto; }
@media (max-width: 520px) {
  .tugas-baris { flex-wrap: wrap; }
  .tugas-baris > .lencana { margin-left: calc(2.2em + 12px); }
}

/* --- keadaan data terkini (SPEC-rev2 §143.2) ------------------------------ */
.keadaan-daftar { list-style: none; margin: 0; padding: 0; }
.keadaan-butir { padding: 6px 0; border-top: 1px solid var(--garis); }
.keadaan-butir:first-child { border-top: 0; }
.keadaan-butir > div + div { margin-top: 2px; }

/* --- lencana UNIT: siapa pemiliknya (SPEC-rev2 §13.6) ---------------------
 *
 * BENTUKNYA SENGAJA BERBEDA dari lencana status: unit diisi penuh (padat),
 * status hanya bergaris. Pemisahan bentuk itu yang membuat warnanya tidak
 * saling mengacaukan — mata membaca "kotak padat = milik siapa" dan "kotak
 * bergaris = ada apa", tanpa perlu menghafal peta warna.
 *
 * Alasannya penggunaan: Inspektur membuka daftar penugasan untuk menjawab
 * "ini tugas Irban mana" lebih dulu. Sebelum ini, jawaban itu ditulis dengan
 * ukuran, warna, dan berat yang sama persis dengan "selesai februari (tanggal
 * belum ditetapkan)" — sementara yang menonjol justru "tanpa tim", yaitu hal
 * yang paling jarang ditanyakan.
 *
 * Lima warna sengaja menjauhi hijau dan merah, yang sudah punya arti tetap
 * (sesuai / melampaui) di seluruh aplikasi ini.
 */
.lencana-unit {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: .74rem; font-weight: 700; letter-spacing: .01em;
  white-space: nowrap; color: #fff; border: 1px solid transparent;
  background: var(--unit, #475569);
}
.unit-1 { --unit: #4f46e5; }   /* indigo  */
.unit-2 { --unit: #0e7490; }   /* teal    */
.unit-3 { --unit: #7c3aed; }   /* ungu    */
.unit-4 { --unit: #b45309; }   /* tembaga */
.unit-5 { --unit: #475569; }   /* batu    */

/* TEMA GELAP ADALAH PALET KEDUA, DAN IA PUNYA MASALAHNYA SENDIRI (§13.8).
 *
 * Isian di sini sengaja LEBIH TERANG daripada tema terang, supaya lencananya
 * tidak melebur ke kartu gelap. Sampai 14 Agustus 2026 teksnya tetap putih —
 * dan putih di atas isian yang dicerahkan kehilangan kontras: 4,47 · 3,61 ·
 * 4,23 · 3,74 · 4,76, empat dari lima di bawah ambang AA 4,5 untuk huruf
 * 11,84px. Cacatnya berdiri sejak tema gelap lahir dan tidak pernah terlihat,
 * karena kontras tidak pernah diukur; mata hanya mengira "agak pucat", dan
 * "agak pucat" tidak pernah menjadi laporan.
 *
 * Jalan keluarnya bukan menggelapkan isiannya — itu memindahkan cacat ke sisi
 * lain, yaitu lencana yang melebur ke kartu dan §13.6 batal. Yang dibalik
 * TEKSNYA. `--aksen-teks` memang ada untuk keperluan ini: teks di atas isian
 * berwarna.
 *
 * Sesudah dibalik: 4,61 · 5,28 · 4,61 · 5,10 · 4,61 terhadap teksnya, dan
 * 4,23–4,85 terhadap kartu. Tiga isian digeser terangnya sedikit (unit-1, 3, 5)
 * supaya seluruhnya lewat ambang; dua lainnya tidak perlu diubah.
 *
 * Angkanya dijaga uji statis di tools/test-api.js — termasuk untuk lencana
 * keenam yang ditambahkan orang yang tidak pernah membaca catatan ini.
 */
:root[data-tema="gelap"] .lencana-unit { color: var(--aksen-teks); }
:root[data-tema="gelap"] .unit-1 { --unit: #6a6df2; }
:root[data-tema="gelap"] .unit-2 { --unit: #0e93b0; }
:root[data-tema="gelap"] .unit-3 { --unit: #8d5ef6; }
:root[data-tema="gelap"] .unit-4 { --unit: #c2700f; }
:root[data-tema="gelap"] .unit-5 { --unit: #6d7e96; }

/* Lokasi. Luar kota ditandai lebih tegas DENGAN SENGAJA: tarifnya Rp360 ribu
   berbanding Rp140 ribu ditambah penginapan, jadi ia hampir selalu menjadi
   sebab utama sebuah penugasan mahal. */
.lencana-lokasi {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: .72rem; font-weight: 600; white-space: nowrap;
  border: 1px solid var(--garis); color: var(--teks-lemah);
}
.lencana-lokasi.luar {
  border-color: var(--aksen); color: var(--aksen); font-weight: 700;
}

/* Baris lencana di kepala tiap penugasan. */
.item-tanda { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 3px; }

/* --- papan pemeriksaan --------------------------------------------------- */
/*
 * EMPAT KEADAAN, BUKAN DUA (SPEC-rev2 §7.1).
 *
 * Versi sebelumnya hanya mengenal "ada temuan" dan "aman". Akibatnya P1, P5,
 * P6, dan P7 — yang seluruhnya BELUM BISA DIJALANKAN karena tanggal dan kisi
 * tim belum diisi — digambar hijau dengan angka 0, dan hijau-dengan-nol
 * terbaca sebagai "sudah diperiksa, bersih".
 *
 * Keadaan `mati` sengaja dibuat paling sepi warnanya dan angkanya diganti "—".
 * Nol adalah jawaban; garis pisah adalah pertanyaan. Menukar keduanya membuat
 * orang berhenti bertanya.
 */
.papan { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.papan-sel {
  border: 1px solid var(--garis); border-radius: 12px; padding: 10px 12px;
  background: var(--latar-2); text-align: left; min-height: 44px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
}
.papan-sel .kode { font-size: .74rem; color: var(--teks-lemah); letter-spacing: .06em; }
.papan-sel .jml  { font-size: 1.3rem; font-weight: 700; line-height: 1.15; }
.papan-sel .jdl  { font-size: .84rem; font-weight: 600; line-height: 1.3; }
.papan-sel .pra  { font-size: .72rem; margin-top: 3px; }

/* --- kode sebagai keterangan, bukan judul (SPEC-rev2 §13.7) --------------
   Kode rekening dan kode sub-kegiatan TETAP di layar — ia kunci mesin dan
   satu-satunya cara mencocokkan baris di aplikasi dengan baris di DPA. Yang
   diubah hanya urutan membacanya: nama lebih dulu, kode menyusul kecil.
   `nowrap` supaya kode tidak pernah terpecah dua baris di 375px — kode yang
   patah di tengah tidak bisa dibandingkan dengan DPA sama sekali. */
.kode-kecil {
  display: inline-block;
  font-size: .72rem;
  color: var(--teks-lemah);
  letter-spacing: .02em;
  white-space: nowrap;
}
.kode-sisip {
  font-size: .72rem;
  color: var(--teks-lemah);
  white-space: nowrap;
}
h2 .kode-kecil { font-weight: 400; margin-left: 6px; vertical-align: middle; }

/* --- SATU PEMERIKSAAN SATU HALAMAN (SPEC-rev2 §74) ------------------------
 *
 * Kedelapan kartu SELALU dirakit ke DOM; yang memilih satu halaman hanyalah
 * kelas ini. Bukan kerapian yang jadi alasannya melainkan KERTAS: aturan
 * @media print di bawah membatalkan `.periksa-lipat`, sehingga Ctrl+P dari
 * halaman P3 tetap menghasilkan kedelapan pemeriksaan.
 *
 * Kalau tujuh sisanya dihapus dari DOM, cetakan itu memuat seperdelapan papan
 * pemeriksaan SAMBIL TERLIHAT UTUH — tidak ada halaman yang hilang dan tidak
 * ada baris terpotong. Kertas yang kehilangan isinya adalah kegagalan yang
 * berulang di aplikasi ini, dan ia tidak pernah terlihat sebagai kegagalan.
 */
.periksa-lipat { display: none; }

/* Hanya untuk kertas. Di layar ia tidak ada sama sekali. */
.periksa-kepala-cetak { display: none; }

/* Angka temuan di tombol sub-tab.
 *
 * Warnanya warna status, KECUALI di tombol yang sedang aktif: latarnya di sana
 * `--aksen`, dan `--buruk`/`--hati`/`--baik` tidak lolos ambang kontras di
 * atasnya pada kedua tema. Di tombol aktif ia mewarisi warna teks tombolnya,
 * yang memang sudah dipilih untuk latar itu.
 *
 * `.mati` memakai warna teks lemah dan BUKAN `--baik` — pemeriksaan yang belum
 * bisa dijalankan menampilkan "—", dan tanda hubung berwarna hijau terbaca
 * sebagai kabar baik atas keadaan yang belum diperiksa sama sekali. */
.tab .tab-jml {
  margin-left: 6px;
  font-size: .78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.tab .tab-jml.buruk { color: var(--buruk); }
.tab .tab-jml.hati  { color: var(--hati); }
.tab .tab-jml.baik  { color: var(--baik); }
.tab .tab-jml.mati  { color: var(--teks-lemah); }
.tab button.aktif .tab-jml { color: inherit; }

.papan-sel.ada      { border-color: var(--hati); }
.papan-sel.aman     { border-color: var(--baik); }
.papan-sel.sebagian { border-color: var(--hati); border-style: dashed; }
.papan-sel.mati {
  border-style: dashed;
  border-color: var(--garis);
  background: transparent;
  opacity: .82;
}
.papan-sel.mati .jml { color: var(--teks-lemah); font-weight: 600; }

/* --- batang perbandingan ------------------------------------------------- */
/* Lebar disetel lewat CSSOM (element.style.width) di app.js, BUKAN atribut
   style di markup — CSP `style-src 'self'` memblokir atribut style yang
   berasal dari HTML, sementara perubahan lewat CSSOM tidak diblokir. */
.batang { height: 8px; border-radius: 999px; background: var(--latar-3); overflow: hidden; margin-top: 6px; }
.batang > i { display: block; height: 100%; background: var(--aksen); }
.batang > i.buruk { background: var(--buruk); }
.batang > i.baik  { background: var(--baik); }

/* Batang KOMPOSISI (§26.1): beberapa ruas dalam satu batang. Latar batangnya
   sendiri = sisa pagu — sisa tidak digambar sebagai ruas supaya pembulatan
   tiga persentase tidak pernah menjulurkan batang melewati 100%. */
.batang-susun { display: flex; height: 12px; margin-top: 8px; }
.batang-susun > i { display: block; height: 100%; flex-shrink: 0; }
.batang-susun > i.ruas-saya { background: var(--aksen); }
.batang-susun > i.ruas-lain { background: color-mix(in srgb, var(--aksen) 38%, var(--latar-3)); }
.batang-susun > i.ruas-lebih { background: var(--buruk); }
.batang-susun > i.ruas-diajukan { background: var(--hati); }
.batang-susun > i.ruas-disetujui { background: var(--baik); }
.kunci-ruas { display: flex; flex-wrap: wrap; gap: 10px 14px; margin-top: 6px; color: var(--teks-lemah); align-items: center; }
.kunci-ruas span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
/* Ruas yang berangka DI ATAS NOL adalah pintu (§129) — bentuknya mengikuti
   `span` di sebelahnya supaya barisnya tidak bergeser, hanya rupa tautannya
   yang membedakan. Yang nol tetap `span`: pintu yang membuka daftar kosong
   sekelas dengan kotak centang yang tidak menuju tombol apa pun (§20.1). */
.kunci-ruas button.tautan-data {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  /* sentuh-kecil: butir kunci batang, bukan kendali utama — sasaran sentuhnya
     seluruh baris teks pada bilah yang tingginya mengikuti hurufnya, dan
     menaikkannya ke 44px akan memecah kunci batang menjadi tiga baris tinggi
     yang menutupi batang yang justru ia jelaskan. Pintu yang sama tersedia
     sebagai kartu 44px tepat di atasnya. */
  min-height: 0; padding: 0;
}
.kunci-ruas .kunci-kotak.ruas-saya { background: var(--aksen); }
.kunci-ruas .kunci-kotak.ruas-lain { background: color-mix(in srgb, var(--aksen) 38%, var(--latar-3)); }
.kunci-ruas .kunci-kotak.ruas-sisa { background: var(--latar-3); border: 1px solid var(--garis); }
.kunci-ruas .kunci-kotak.ruas-lebih { background: var(--buruk); }
.kunci-ruas .kunci-kotak.ruas-diajukan { background: var(--hati); }
.kunci-ruas .kunci-kotak.ruas-disetujui { background: var(--baik); }
.kunci-ruas .kunci-kotak.ruas-rencana { background: var(--latar-3); border: 1px solid var(--garis); }
/* Batang mini di dalam sel tabel Anggaran — tanpa margin kartu. */
td .batang-susun { margin-top: 4px; height: 8px; border-radius: 999px; overflow: hidden; background: var(--latar-3); min-width: 90px; }

/* Matriks rekap bulanan (§26.7) — bentuk sheet "Rekap": kolom nama MENETAP
   saat 24 kolom bulan digulir, alasan yang sama dengan kolom nama peta
   kalender: matriks tanpa nama yang menetap hanya menunjukkan bahwa ADA
   angka, bukan angka milik siapa. */
.rekap-bulanan th, .rekap-bulanan td { white-space: nowrap; }
.rekap-bulanan .rekap-nama,
.rekap-bulanan thead th:first-child,
.rekap-bulanan tfoot td:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--latar-2);
  max-width: 260px; min-width: 180px;
  white-space: normal;
}
.rekap-bulanan thead th { position: sticky; top: 0; background: var(--latar-2); }
.rekap-bulanan thead th:first-child { z-index: 2; }

/* Daftar tanpa peluru — "di lapangan hari ini" pada beranda Inspektur. */
.daftar-polos { list-style: none; margin: 4px 0 0; padding: 0; }
.daftar-polos li { padding: 4px 0; border-bottom: 1px solid var(--garis); }
.daftar-polos li:last-child { border-bottom: none; }

/* --- peringatan ---------------------------------------------------------- */
.peringatan {
  border: 1px solid var(--buruk); color: var(--buruk);
  border-radius: 10px; padding: 9px 12px; margin: 10px 0; font-size: .88rem;
}
.catatan {
  border: 1px solid var(--hati); color: var(--hati);
  border-radius: 10px; padding: 9px 12px; margin: 10px 0; font-size: .88rem;
}
.info {
  border: 1px solid var(--garis); background: var(--latar-3);
  border-radius: 10px; padding: 10px 12px; margin: 10px 0; font-size: .88rem;
}

/* --- layar kosong: TIGA SEBAB, TIGA TAMPILAN (SPEC-rev2 §13.3) -------------
 * Datanya belum ada / di luar kewenangan / prasyarat belum terpenuhi.
 * Satu kalimat "tidak ada data" untuk ketiganya adalah cacat, bukan
 * penyederhanaan: yang pertama menuntut pengisian, yang kedua menuntut
 * permintaan akses, yang ketiga menuntut data lain sama sekali. */
.kosong {
  border: 1px dashed var(--garis); border-radius: 12px;
  padding: 22px 16px; margin: 12px 0; text-align: center;
}
.kosong .ikon { font-size: 1.6rem; line-height: 1; }
.kosong .judul { font-weight: 650; margin-top: 8px; }
.kosong .sebab { color: var(--teks-lemah); font-size: .86rem; margin-top: 4px; }
.kosong.terkunci { border-color: var(--hati); }
.kosong.terkunci .judul { color: var(--hati); }

/* --- jenjang rincian (SPEC-rev2 §13.2) ------------------------------------
 * Jejak lapisan selalu terlihat, supaya orang yang sudah turun empat lapis
 * tahu ia sedang berada di mana dan angka yang dilihatnya konteksnya apa. */
.jenjang {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: .78rem; color: var(--teks-lemah);
  margin: 2px 0 10px; padding-bottom: 8px; border-bottom: 1px solid var(--garis);
}
.jenjang .kini { color: var(--teks); font-weight: 600; }
.jenjang .pisah { opacity: .5; }

/* Petunjuk bahwa sebuah angka menyimpan rincian di baliknya. Tanda visualnya
   sengaja jelas: rincian yang ada tapi tidak terlihat sama saja dengan
   rincian yang tidak ada. */
.kartu-buka .lemah::after { content: ''; }
.kartu-buka { position: relative; transition: border-color .12s, transform .12s; }
.kartu-buka:hover { transform: translateY(-1px); }
.kartu-buka:active { transform: none; }
.kartu-buka::after {
  content: '›';
  position: absolute; top: 12px; right: 12px;
  color: var(--teks-lemah); font-size: 1.15rem; line-height: 1;
}
/* Label diberi ruang supaya tidak tertimpa tanda panah di sudut. */
.kartu-buka .label { padding-right: 16px; }

/* --- asal-usul angka (SPEC-rev2 §13.1) ------------------------------------
 * Setiap nominal membawa jenisnya: dihitung, dari spreadsheet Rencana Kerja,
 * atau belum ada.
 * Tanpa penanda ini "Rp 1,2 M" dari kisi tim dan "Rp 1,2 M" dari tulisan
 * tangan terlihat sama persis, padahal keduanya menuntut tindakan berbeda. */
.asal {
  display: inline-block; font-size: .7rem; letter-spacing: .02em;
  padding: 1px 6px; border-radius: 999px; border: 1px solid var(--garis);
  color: var(--teks-lemah); white-space: nowrap; vertical-align: middle;
}
.asal.sheet { border-color: var(--hati); color: var(--hati); }
.asal.tim   { border-color: var(--baik); color: var(--baik); }
.asal.kosong { border-style: dashed; }

/* --- layar masuk --------------------------------------------------------- */
.layar-tengah { min-height: 88vh; display: flex; align-items: center; justify-content: center; }
.kartu-masuk {
  width: 100%; max-width: 380px; background: var(--latar-2);
  border: 1px solid var(--garis); border-radius: 16px; padding: 26px 22px;
  box-shadow: var(--bayang); text-align: center;
}
/* ---------- layar pembuka ----------
   Memakai ulang `.kartu-masuk`; hanya pemutar dan daftar langkahnya yang baru. */

/* Pemutar. TANPA keadaan awal yang menyembunyikan — ia hanya BERPUTAR, tidak
   memudar dan tidak menyusut. Apa pun yang membekukan animasi (penghemat
   baterai, halaman tidak dikomposit) tidak boleh menghapus isi layar; kalau jam
   animasinya mati, cincin ini tetap terlihat, hanya diam. */
.boot-putar {
  width: 32px; height: 32px; margin: 14px auto 4px;
  border-radius: 50%;
  border: 3px solid var(--garis);
  border-top-color: var(--aksen);
  animation: boot-putar 900ms linear infinite;
}
@keyframes boot-putar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .boot-putar { animation: none; } }

/* Langkah bernomor: rata kiri walau kartunya rata tengah — daftar tindakan yang
   rata tengah jauh lebih sulit dibaca berurutan. */
.boot-langkah {
  text-align: left;
  margin: 14px 0 2px;
  padding-left: 20px;
  display: grid;
  gap: 11px;
  line-height: 1.45;
}
.boot-langkah u { text-decoration: none; color: var(--aksen); font-weight: 650; }
.kartu-masuk .boot-langkah { text-align: left; }

/* Alamat publik pada layar putus-sambungan (§85) — satu-satunya tautan di layar
   itu, dan ia disentuh dari HP: `min-height` + padding menegakkan 44px bahkan
   saat alamatnya cukup pendek untuk muat satu baris.

   `overflow-wrap: anywhere` bukan kerapian: alamat tailnet berikut wilayahnya
   melewati 322px yang tersisa pada layar 375px, dan tautan yang tidak boleh
   melipat akan mendorong SELURUH halaman menggulir mendatar. */
.boot-alamat {
  display: block;
  min-height: 44px;
  padding: 11px 0;
  color: var(--aksen);
  font-weight: 650;
  overflow-wrap: anywhere;
}

.kartu-masuk h1 { font-size: 1.1rem; margin: 8px 0 2px; }
.kartu-masuk form { text-align: left; margin-top: 16px; }
.kartu-masuk .peringatan { text-align: left; }
/* Kredit pencipta: di kartu masuk dan di kartu "Tentang aplikasi" (Atur ›
   Aplikasi). Nama dan panah dijaga nowrap supaya panahnya tidak jatuh sendirian
   ke baris baru pada 375px. */
.kredit-pengembang { margin: 18px 0 0; }
.kartu .kredit-pengembang { margin: 6px 0 2px; }
.kredit-pengembang a { color: inherit; white-space: nowrap; text-underline-offset: 2px; }
.lambang {
  font-size: 1.4rem; font-weight: 800; letter-spacing: .08em;
  color: var(--aksen);
}

/* --- pemilih personil yang bisa dicari ------------------------------------
 * Daftar personil berisi 194 orang dengan banyak nama yang mirip. Menggulir
 * sampai ketemu bukan sekadar lambat — ia rawan salah pilih, dan satu tautan
 * personil yang keliru membuat jejak audit menunjuk ke orang yang salah. */
.cari-personil { margin-bottom: 6px; }
.pilih-panjang {
  width: 100%;
  font: inherit;
  padding: 4px;
  background: var(--latar-2);
  color: var(--teks);
  border: 1px solid var(--garis);
  border-radius: 10px;
}
.pilih-panjang option { padding: 7px 8px; border-radius: 6px; }
.pilih-panjang option:checked { background: var(--aksen); color: var(--aksen-teks); }

/* --- kisi tim ------------------------------------------------------------ */
/* Penyaring di atas kisi tim. Untuk Irban dengan 28 personil, menggulir sambil
   mencocokkan nama masih memungkinkan tetapi tidak nyaman; untuk super admin
   yang melihat seluruh unit, tidak. */
.saring-tim { margin: 6px 0 10px; }

/* Kisi tim menggulir DI DALAM kotaknya sendiri supaya kepala tabelnya bisa
   sticky. Panel modal yang menggulir keseluruhan membuat header PERSONIL/
   PERAN/HARI/MALAM/ORANG/BIAYA lenyap begitu daftar 31 orang digulir — dan
   pada lima kotak angka berdampingan, lupa "kolom keberapa hari" berujung
   salah isi yang tidak bergalat. */
.gulir-tim { max-height: min(56vh, 520px); overflow: auto; }
.gulir-tim thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--latar-2);
  box-shadow: 0 1px 0 var(--garis);
}
.kisi-tim tr[hidden] { display: none; }
/* Baris luar-Irban pada mode lintas: cukup lencana asal, tanpa warna baris —
   warna baris sudah dipakai `mati` (tidak dicentang). */
.kisi-tim .lencana-irban-kecil { font-size: .62rem; }
.kisi-tim th, .kisi-tim td { padding: 6px 8px; }
.kisi-tim input, .kisi-tim select { min-height: 38px; padding: 6px 8px; }
/* Kotak angka berlebar TETAP, dan kolom nama punya lebar minimum.
 *
 * Bukan selera. Kisi tim realisasi semula tanpa aturan ini: pada 375px kotak
 * "Hari" terperas menjadi 30px, dan nilai 10 terpotong menjadi terbaca "1" —
 * angka yang SALAH DIBACA, bukan sekadar sempit, tepat pada kolom yang memang
 * ada untuk disesuaikan. Kelas kegagalan yang sama dengan "Rp 30,9 jt" yang
 * pecah tiga baris (§13.4), hanya lebih berbahaya karena hasilnya tetap
 * terlihat seperti angka yang masuk akal.
 *
 * Konsekuensinya tabel ini lebih lebar daripada 375px — dan itu benar:
 * gulir mendatarnya ada DI DALAM .gulir, tidak pernah di halaman (§17.4). */
.kisi-tim input[type="number"],
.kisi-tim input[inputmode="numeric"] { width: 76px; text-align: right; flex-shrink: 0; }
/* Rupiah kuitansi bisa tujuh digit — 76px memotong "770000" menjadi "70000",
   persis kelas cacat "10 terbaca 1" yang pernah terjadi pada kotak Hari. */
.kisi-tim input.inap-kuitansi { width: 116px; }
.kisi-tim select { min-width: 84px; }
.kisi-tim td:first-child select { min-width: 148px; }
.kisi-tim .biaya { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
.kisi-tim tr.mati { opacity: .45; }

/* --- geser jadwal berantai (§66.3, TODO-MERGE nomor pasal) ---------------
 * Kotak "berapa hari" per baris memuat maksimal 4 aksara ("-366") — 76px
 * mengikuti ukuran kotak angka kisi tim di atas, alasannya sama: kotak
 * bawaan number selebar kolom akan memerkosa tabelnya di 375px, dan tabel
 * ini pun bergulir DI DALAM .gulir, tidak pernah di halaman (§17.4). */
input.gj-hari { width: 76px; text-align: right; flex-shrink: 0; }
/* Pratinjau tanggal tidak boleh pecah baris DI DALAM satu rentang — rentang
 * "12 Jan – 26 Jan" yang terbelah dua baris terbaca sebagai dua tanggal. */
.gj-pratinjau b { white-space: nowrap; }

/* --- pratinjau tempel ---------------------------------------------------- */
.pratinjau td { font-size: .82rem; }
.pratinjau tr.siap       td:first-child { border-left: 3px solid var(--baik); }
.pratinjau tr.peringatan td:first-child { border-left: 3px solid var(--hati); }
.pratinjau tr.ditolak    td:first-child { border-left: 3px solid var(--buruk); }
.pratinjau .sebab { color: var(--teks-lemah); font-size: .78rem; }

/* --- panel form ---------------------------------------------------------- */
.panel { position: fixed; inset: 0; z-index: 40; }
.panel-latar { position: absolute; inset: 0; background: rgba(0,0,0,.55); }
.panel-isi {
  position: absolute; left: 0; right: 0; bottom: 0;
  max-height: 92vh; overflow-y: auto;
  background: var(--latar-2); border-top: 1px solid var(--garis);
  border-radius: 16px 16px 0 0; padding: 16px 14px calc(20px + env(safe-area-inset-bottom));
  box-shadow: var(--bayang);
}
@media (min-width: 760px) {
  .panel-isi {
    left: 50%; right: auto; bottom: auto; top: 50%;
    transform: translate(-50%, -50%);
    width: min(680px, 92vw); border-radius: 16px; border: 1px solid var(--garis);
    max-height: 88vh;
  }
}
.panel-kepala { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.panel-kepala h2 { margin: 0; }

/* PANEL GABUNGAN "Ubah penugasan & tim" (tahap 4). Halamannya panjang — itu
   harga yang pemilik timbang sendiri — dan yang TIDAK boleh adalah tombol
   Simpan yang hilang di bawah lipatan. Kakinya menempel di dasar `.panel-isi`
   (wadah yang menggulir), berlatar sama dengan panelnya supaya isi yang
   lewat di belakangnya tidak tembus. Kalimat "yang akan disimpan" ikut
   menempel: ia yang menjawab "tombol ini mengirim apa". */
.ug-kaki {
  position: sticky; bottom: calc(-20px - env(safe-area-inset-bottom));
  margin: 16px -14px 0; padding: 10px 14px calc(12px + env(safe-area-inset-bottom));
  background: var(--latar-2); border-top: 1px solid var(--garis);
}
.ug-kaki p { margin: 0 0 6px; }
.ug-kaki .baris-tombol { margin: 0; }
#ug-h-kepala, #ug-h-tim { margin-top: 18px; padding-top: 10px; border-top: 1px solid var(--garis); }
#ug-h-kepala { margin-top: 4px; border-top: 0; padding-top: 0; }

/* --- navigasi ------------------------------------------------------------ */
nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex; justify-content: space-around;
  background: var(--latar-2); border-top: 1px solid var(--garis);
  padding: 4px 2px calc(4px + env(safe-area-inset-bottom));
  overflow-x: auto;
}
nav button {
  flex: 1 1 0; min-width: 0; flex-direction: column; gap: 1px;
  border: none; background: none; border-radius: 10px;
  padding: 6px 2px; font-size: 1.1rem; color: var(--teks-lemah); min-height: 52px;
}
/* `flex: 1 1 0` dengan `min-width: 0` membuat kedelapan menu berbagi lebar
   layar, bukan memaksakan lebar minimum lalu mendorong yang terakhir ke luar.
   Sebelumnya menu "Atur" — satu-satunya jalan ke pengaturan dan keluar —
   berada di luar layar pada 375px, dan hanya bisa dijangkau dengan menggeser
   bilah menu ke samping, gerakan yang tidak ada tandanya sama sekali. */
nav button span {
  font-size: .58rem; letter-spacing: -.01em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
nav button.aktif { color: var(--aksen); }

/* --- MENU PER PERAN: laci "Lainnya" (§145.3) -----------------------------
   Bilah bawah memuat paling banyak LIMA tombol; sisanya diberi kelas
   `nav-lain` oleh `susunMenu()` dan tinggal di balik tombol "Lainnya".

   Yang memutuskan TEMPATNYA di sini CSS, bukan JavaScript yang membaca lebar
   layar: satu susunan DOM untuk kedua lebar, jadi tidak ada pendengar
   `resize` yang bisa tertinggal, dan memutar HP tidak pernah meninggalkan
   bilah yang susunannya milik lebar sebelumnya.

   `display: inline-flex`, bukan `flex` — itu nilai bawaan `button` di berkas
   ini (lihat aturan `button, .tombol` di atas), dan `flex` akan mengubah
   lebar tombolnya pada lebar desktop. Aturan `[hidden] { display: none
   !important }` di kepala berkas tetap menang atas keduanya: menu yang
   TERTUTUP untuk sebuah peran tidak pernah muncul di laci. */
nav button.nav-lain { display: none; }
/* `flex-start`, bukan `space-around` yang berlaku saat tertutup: baris
   terakhir laci hampir selalu tidak penuh, dan `space-around` memusatkan
   satu tombol yang tersisa di tengah layar — tombol yang tidak sekolom
   dengan tombol mana pun di atasnya terbaca sebagai tombol yang lain
   jenisnya. */
nav[data-lain="buka"] { flex-wrap: wrap; align-content: flex-end; justify-content: flex-start; }
/* Basis 20% membuat laci yang terbuka menjadi baris-baris berisi lima, bukan
   satu baris yang menyempit sampai di bawah sasaran sentuh. `flex: 1 1 0`
   yang berlaku di luar keadaan ini sengaja tidak diubah — catatan di atas
   menjelaskan kenapa ia ada. */
nav[data-lain="buka"] button { flex: 0 0 20%; }
nav[data-lain="buka"] button.nav-lain { display: inline-flex; }

/* Kolom yang boleh menghilang di layar sempit.
   Dipakai untuk keterangan pelengkap saja — JANGAN untuk kolom yang memuat
   angka anggaran atau tombol tindakan. Yang hilang di HP harus benar-benar
   tidak dibutuhkan di HP, bukan sekadar yang paling mudah dibuang. */
@media (max-width: 560px) {
  .sempit-sembunyi { display: none; }
}

/* Kolom TINDAKAN tidak boleh menjadi kolom yang terpotong.
 *
 * Aturan di atas melarang tombol tindakan disembunyikan di layar sempit, dan
 * itu memang tidak dilakukan — tetapi tombolnya tetap tidak terjangkau lewat
 * jalan lain. Diukur pada 375px, audit 20 Agustus 2026: wadah `.gulir` daftar
 * akun berakhir di x=361 sementara tombol "Kelola" berdiri di x=354–418, jadi
 * 8px dari 64px yang terlihat — dan `document.elementFromPoint` di titik
 * tengahnya mengembalikan `null`, yaitu di luar layar.
 *
 * `.gulir` memang `overflow-x: auto`, jadi barisnya BISA digeser. Yang tidak
 * ada adalah tanda bahwa ia bisa digeser: tanpa mask, tanpa bayangan, tanpa
 * batang gulir. Jadi setiap tindakan atas 136 akun menuntut satu geseran
 * mendatar yang tidak diberitahukan lebih dulu.
 *
 * Yang dipilih: kolom terakhir dipakukan ke tepi kanan, bukan tabelnya
 * dipersempit. Mempersempit kolom lain akan memindahkan pemotongan ke nama
 * orang — dan nama yang terpotong pada daftar 136 baris lebih buruk daripada
 * tombol yang perlu digeser.
 *
 * Bayangan menggantikan garis tepi: `border-collapse: collapse` tidak
 * menggambar tepi sel yang dipakukan secara andal di semua peramban.
 * Dibatasi ≤560px supaya `tbody tr:hover` di desktop tidak menjadi belang —
 * sel yang dipakukan membawa latarnya sendiri dan tidak ikut berubah saat
 * baris disorot.
 *
 * DUA PERLUASAN, 28 September 2026 (audit tampilan menu Atur):
 *
 * - Daftar akun BERLINGKUP milik Irban (`table.kl-akun-lingkup`, §159) TIDAK
 *   ikut. Kolom terakhirnya Keadaan, bukan tindakan — tombolnya berdiri di
 *   baris sendiri selebar tabel. Dipakukan, lencana Keadaan menutupi kolom
 *   Peran pada 375px sampai terbaca "P".
 * - Daftar Faktor kedua (`#kelola-2fa`) IKUT. Alasannya sama persis dengan
 *   daftar akun: 153 baris, tombol Buka pendaftaran/Reset di kolom terakhir,
 *   dan pada 375px tombolnya terpotong di tepi penggulir menjadi "Bu".
 *
 * DUA PERLUASAN LAGI, 29 September 2026 (tindak lanjut audit yang sama):
 *
 * - Tabel dasar Pengesahan (`table.tabel-dasar`) IKUT pada ≤560px. Pada 375px
 *   "+ Penugasan…" terlihat 87 dari 105px dan "Batalkan…" terpotong 3px di
 *   tepi penggulir. Kolom terakhirnya memang kolom tindakan.
 * - Daftar akun super admin dipakukan sampai 899px, bukan 560px. Tabelnya
 *   757px di wadah 740px pada 768px, jadi 6px kanan SELURUH 153 tombol
 *   Kelola terpotong. 899px adalah batas bilah bawah (bilah sisi
 *   mulai 900px): di bawahnya layar dipakai dengan jari. Pada 900px ke atas
 *   tabelnya muat (diukur 900, 1024, 1280), jadi tidak dipakukan.
 *
 * Sorotan baris ikut ke sel yang dipakukan (aturan `:hover` di bawah), jadi
 * tablet bertetikus di rentang 561–899px tidak mendapat baris belang — alasan
 * batas 560px semula. */
@media (max-width: 899px) {
  #kelola-akun .gulir table:not(.kl-akun-lingkup) th:last-child,
  #kelola-akun .gulir table:not(.kl-akun-lingkup) td:last-child {
    position: sticky;
    right: 0;
    background: var(--latar-2);
    box-shadow: -8px 0 8px -8px rgb(0 0 0 / .45);
  }
  #kelola-akun .gulir table:not(.kl-akun-lingkup) tbody tr:hover > td:last-child {
    background: var(--latar-3);
  }
}
@media (max-width: 560px) {
  #kelola-2fa .gulir th:last-child,
  #kelola-2fa .gulir td:last-child,
  .gulir table.tabel-dasar th:last-child,
  .gulir table.tabel-dasar td:last-child {
    position: sticky;
    right: 0;
    background: var(--latar-2);
    box-shadow: -8px 0 8px -8px rgb(0 0 0 / .45);
  }
  #kelola-2fa .gulir tbody tr:hover > td:last-child,
  .gulir table.tabel-dasar tbody tr:hover > td:last-child {
    background: var(--latar-3);
  }
}

/* --- bilah atas ---------------------------------------------------------- */
#bar-atas {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  /* Margin negatif menutup celah padding #app di atasnya. Tanpa ini, isi
     halaman yang tergulir terlihat lewat di antara tepi layar dan bilah yang
     sedang menempel — pemilih tahun tampak melayang di atas angka anggaran. */
  margin: -16px 0 4px;
  padding: 16px 0 10px;
  background: var(--latar);
  border-bottom: 1px solid var(--garis);
}
/* --- LOMPAT KE BAGIAN (SPEC-rev2 §127) ------------------------------------
 *
 * Bilah yang mengisi ruang kosong di kanan bilah atas. Ia memakai kelas `.tab`
 * yang SUDAH ADA, dan itu memberinya tiga hal tanpa satu baris tambahan:
 * gulir mendatar, `min-height: 44px` per tombol (§13.9), dan penyembunyian
 * saat mencetak. Yang ditulis di bawah hanya yang membedakannya dari tab biasa.
 *
 * DISEMBUNYIKAN DI BAWAH 900px. Bilah menu pada 375px sudah menyisakan 41px
 * per tombol, dan bilah kedua yang menggulir sendiri di bawahnya memakan baris
 * tetap kedua pada layar yang ruangnya paling sempit. Menggulir di layar
 * sempit juga murah — jempol sudah di sana. Ini keputusan yang paling pantas
 * ditinjau ulang bila riset lapangan berkata lain.
 */
#lompat-bagian {
  margin: 0;
  /* Menyusut lebih dulu ketika ruangnya kurang: pemilih tahun dan tombol tema
     tidak boleh terdorong keluar oleh navigasi yang sifatnya membantu. */
  min-width: 0; flex: 1 1 auto;
  /* ── RATA KIRI, DAN INI KOREKSI (§127.9) ────────────────────────────────
     Percobaan pertama merata-kanankan isinya supaya "menempel di kanan atas".
     Pada wajah yang butirnya banyak — Irban punya belasan — bilah yang
     merata-kanan MULAI TERGULIR: butir PERTAMA hilang di balik tepi kiri, dan
     yang tampak potongan label di tengah daftar. Pemilik melihatnya sebagai
     "jelek sekali dan ketutup", dan ia benar. Peta yang menyembunyikan
     awalnya bukan peta. */
  justify-content: flex-start;
  gap: 2px;
  /* …dan pudarnya ikut berbalik ke KANAN, tempat lanjutannya sekarang berada.
     Pudar di sisi yang salah menandai yang sudah lewat, bukan yang belum. */
  mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent);
}
#lompat-bagian:empty { display: none; }

/* ── RUPA: TEKS BERGARIS BAWAH, BUKAN DERET TOMBOL ────────────────────────
 *
 * Percobaan pertama memakai rupa `.tab` apa adanya — kotak berbingkai, sama
 * dengan bilah tab di dalam halaman. Dua akibatnya terlihat sekaligus di
 * layar: bilahnya terbaca sebagai BILAH MENU KEDUA yang bersaing dengan menu
 * di kiri, dan padding kotaknya memakan ruang sehingga lebih sedikit butir
 * yang muat — dua kerugian dari satu keputusan.
 *
 * Yang dipakai sekarang bentuk yang pemilik tunjukkan sendiri sebagai contoh:
 * teks tenang, yang aktif ditandai GARIS BAWAH. Sasaran sentuhnya TIDAK
 * diturunkan — 44px tetap (§13.9), hanya kotaknya yang hilang. Tinggi yang
 * dipertahankan tanpa bingkai adalah cara membuat rupa ringan tanpa membayar
 * dengan sasaran yang mengecil.
 */
#lompat-bagian button {
  min-height: 44px;
  padding: 6px 9px;
  font-size: .8rem;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--teks-lemah);
  font-weight: 500;
}
#lompat-bagian button:hover { color: var(--teks); background: none; }
#lompat-bagian button.aktif {
  background: none;
  color: var(--aksen);
  border-color: var(--aksen);
  font-weight: 600;
}
@media (max-width: 899px) { #lompat-bagian { display: none; } }

/* Judul bagian berhenti DI BAWAH bilah atas yang menempel, bukan di baliknya.
   Tanpa ini setiap lompatan mendarat pada judul yang tertutup bilahnya sendiri
   — dan yang terlihat adalah lompatan yang meleset satu judul. */
#view-beranda h2 { scroll-margin-top: 92px; }

/* ── CINCIN FOKUS PADA JUDUL: HANYA UNTUK KEYBOARD (§127.9) ───────────────
 *
 * Melompat memindahkan fokus ke judulnya (§127.6) — itu wajib, sebab tanpanya
 * Tab berikutnya melempar pembaca kembali ke tempat ia berangkat. Tetapi judul
 * yang difokuskan menerima cincin fokus bawaan peramban, dan pada tekanan
 * TETIKUS ia muncul sebagai kotak hitam tebal mengelilingi judul — terlihat
 * seperti kerusakan, dan itulah yang pemilik lihat.
 *
 * `:focus-visible` memisahkan keduanya: pemakai tetikus tidak melihat apa pun,
 * pemakai keyboard tetap melihat di mana fokusnya berada. Membuang cincinnya
 * dengan `outline: none` saja akan melanggar WCAG 2.4.7 dan mengambil satu-
 * satunya petunjuk yang dimiliki pemakai keyboard.
 */
#view-beranda h2:focus { outline: none; }
#view-beranda h2:focus-visible {
  outline: 2px solid var(--aksen);
  outline-offset: 4px;
  border-radius: 3px;
}

/* --- kunci merek: logo lembaga + logo aplikasi (SPEC-rev2 §60) ------------
 *
 * URUTANNYA MENGIKAT: lembaga di KIRI, aplikasi di kanan. Kiri menjawab "milik
 * siapa", kanan menjawab "ini apa" — dan yang di kiri sama di seluruh aplikasi
 * di mesin ini, jadi ia jangkar yang tidak bergerak. Nama aplikasinya karena
 * itu selalu mendarat di titik yang sama, dan justru itu yang membuat bedanya
 * cepat tertangkap. Membalik urutannya memindahkan jangkarnya ke bagian yang
 * berubah-ubah, yaitu kebalikan dari yang dicari.
 *
 * Wordmark lembaga ("Inspektorat Aceh" di bawah marknya) SENGAJA DIPOTONG dari
 * berkas gambarnya: pada tinggi 22–24px ia menjadi noda, bukan kata — dan noda
 * yang menyerupai teks lebih buruk daripada tidak ada teks sama sekali.
 *
 * Bobotnya tidak sama, dan itu disengaja: wordmark aplikasi tetap yang paling
 * tebal. Kepemilikan adalah konteks; identitas aplikasi adalah pertanyaan yang
 * sedang dijawab layar ini.
 */
.merek, .nav-merek { align-items: center; gap: 8px; min-width: 0; }
.merek-lembaga, .merek-app, .merek-pisah { flex: 0 0 auto; }
.merek-lembaga { width: auto; }
.merek-app { border-radius: 5px; }
.merek-pisah { width: 1px; height: 20px; background: var(--garis); }
.merek b, .nav-merek b { color: var(--aksen); font-weight: 800; white-space: nowrap; }

#bar-atas .merek { display: flex; }
#bar-atas .merek b { letter-spacing: .08em; font-size: .95rem; }
#bar-atas .merek-lembaga { height: 24px; }
#bar-atas .merek-app { width: 22px; height: 22px; }

.nav-merek { display: none; }

/* ---------------------------------------------------------------------------
   TATA LETAK DESKTOP
   Navigasi berpindah dari bilah bawah menjadi bilah sisi kiri.

   Ambangnya 900px, bukan 768px: pada tablet melintang, jempol masih menjangkau
   tepi bawah layar dan bilah bawah tetap lebih mudah ditekan. Bilah sisi baru
   menang ketika alatnya benar-benar dipakai dengan tetikus — dan di situlah
   ruang mendatar yang menganggur mulai terasa mahal, karena tabel selisih pagu
   punya enam kolom yang semuanya perlu terbaca sekaligus.
--------------------------------------------------------------------------- */
@media (min-width: 900px) {
  /* 180px, bukan 208px. Dipersempit 14 Agustus 2026 atas laporan pemilik dari
     desktop: tabel Renwas kurang 63px dari lebar wadahnya pada layar 1280 CSS
     px, sehingga kolom Jumlah — kolom yang justru dibaca lebih dulu — terpotong
     dan harus digeser tangan. Ruang yang dilepaskan bilah sisi ini berlaku
     untuk SETIAP tabel lebar (Renwas, Pegawai, jejak audit, peta kalender),
     bukan hanya untuk yang dilaporkan. Label terpanjang "Penugasan" tetap muat
     tanpa terpotong. */
  nav {
    top: 0; bottom: 0; right: auto;
    width: 180px;
    flex-direction: column; justify-content: flex-start; gap: 2px;
    border-top: none; border-right: 1px solid var(--garis);
    padding: 16px 10px calc(16px + env(safe-area-inset-bottom));
    overflow-y: auto; overflow-x: hidden;
  }
  nav button {
    flex: 0 0 auto; width: 100%;
    flex-direction: row; justify-content: flex-start; gap: 10px;
    padding: 9px 12px; font-size: 1.05rem; min-height: 44px;
  }
  nav button span { font-size: .92rem; letter-spacing: 0; }
  nav button.aktif { background: var(--latar-3); }

  /* LACI "LAINNYA" TIDAK ADA DI BILAH SISI (§145.3). Bilah sisi bergulir
     tegak dan tidak pernah kehabisan petak, jadi seluruh menu berdiri
     sekaligus — laci menjawab sempitnya bilah BAWAH, bukan banyaknya menu.
     Menyembunyikan menu di desktop hanya akan menambah satu ketukan pada
     layar yang tidak membutuhkannya. */
  nav button.nav-lain { display: inline-flex; }
  nav button[data-menu="lainnya"] { display: none; }
  nav[data-lain="buka"] { flex-wrap: nowrap; }
  nav[data-lain="buka"] button { flex: 0 0 auto; }

  /* Susunannya SAMA dengan bilah atas HP — mendatar, bukan bertumpuk. Bilah
     sisi 180px menyisakan 147px di dalam paddingnya, dan kunci mereknya
     memakai 116px; sisa 31px. Diukur, bukan dikira: percobaan pertama
     menumpuknya ke bawah atas dugaan tidak muat, dan dugaan itu keliru. */
  .nav-merek {
    display: flex;
    padding: 6px 12px 16px;
  }
  .nav-merek b { letter-spacing: .09em; font-size: 1rem; }
  .nav-merek .merek-lembaga { height: 22px; }
  .nav-merek .merek-app { width: 22px; height: 22px; }

  /* Ruang untuk bilah sisi. #app tetap terpusat supaya pada layar sangat lebar
     barisnya tidak menjadi terlalu panjang untuk dibaca. */
  #app {
    max-width: 1360px;
    padding: 18px 20px 40px 200px;
  }

  /* Layar masuk dan ganti sandi tidak punya bilah sisi — tanpa ini kartunya
     tergeser ke kanan dan terlihat seperti salah pasang. Kelasnya disetel
     tampil() di app.js, bukan ditebak dari :has(). */
  #app.publik { padding-left: 28px; }

  #bar-atas { margin: -18px 0 6px; padding: 18px 0 12px; }
  #bar-atas .merek { display: none; }   /* sudah ada di bilah sisi */

  .toast { left: calc(50% + 104px); bottom: 28px; }

  /* Kartu angka utama diberi lebar minimum lebih besar: pada layar lebar,
     enam kolom sempit membuat "Rp 708.500.000" terpotong justru di layar yang
     ruangnya paling banyak. */
  .kisi { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
  .papan { grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); }

  h1 { font-size: 1.55rem; }
  table { font-size: .9rem; }
}

/* TIDAK ADA BATAS LEBAR KHUSUS UNTUK PEDOMAN — dan itu keputusan pemilik,
   13 Agustus 2026, sesudah dua percobaan yang keduanya salah.

   Percobaan pertama membatasi PARAGRAFNYA (`#view-pedoman .kartu p`,
   max-width 76ch) di atas 1200px. Kartunya tetap membentang penuh, sehingga
   teks berhenti di 865px sementara kotaknya berlanjut sampai 1237px: 371px
   ruang kosong di dalam kotak yang batasnya terlihat. Dilaporkan dari tablet
   lanskap sebagai "tertahan, tidak lanjut ke kanan".

   Percobaan kedua memindahkan batas itu ke KARTUNYA supaya tepi kotak dan tepi
   teks berakhir bersamaan. Tepinya memang jadi sepadan, dan gejalanya tidak
   hilang — hanya berpindah: sekarang kartunya sendiri yang berhenti di sekitar
   dua pertiga halaman, dan sisi kanan tetap kosong.

   Pelajarannya: masalahnya bukan letak `max-width`-nya, melainkan ADANYA batas
   itu pada layar selebar tablet. Pemilik membaca halaman ini di tablet lanskap
   dan menghendakinya mengisi lebar yang tersedia. Kekhawatiran semula — baris
   panjang memaksa mata melompat balik — nyata pada monitor 1600px+, tetapi
   itu bukan alat yang dipakai membaca halaman ini, dan mengoptimalkan untuk
   layar yang tidak dipakai dengan mengorbankan layar yang dipakai adalah
   pertukaran yang salah arah.

   Bila kelak halaman ini banyak dibaca di monitor lebar dan barisnya terasa
   terlalu panjang, yang dinaikkan adalah `#app { max-width }` untuk SELURUH
   halaman — bukan batas khusus yang membuat satu halaman berperilaku berbeda
   dari delapan lainnya. */

/* --- toast --------------------------------------------------------------- */
.toast {
  position: fixed; left: 50%; bottom: 78px; transform: translateX(-50%);
  background: var(--latar-3); color: var(--teks); border: 1px solid var(--garis);
  border-radius: 10px; padding: 10px 16px; z-index: 60; box-shadow: var(--bayang);
  max-width: 90vw; font-size: .9rem;
}

/* --- bilah versi baru (§149) ----------------------------------------------
   Di tepi ATAS, bukan bawah: bilah menu HP dan toast sudah menempati tepi
   bawah. z-index 65 berada di atas panel (40), sebab yang paling perlu
   membacanya justru orang yang sedang di tengah formulir; juga di atas toast
   (60) yang hanya sesaat, dan di bawah kartu istilah (70) yang dibuka
   dengan sengaja. */
.versi-baru {
  position: fixed; left: 50%; transform: translateX(-50%);
  top: calc(8px + env(safe-area-inset-top, 0px));
  width: min(560px, calc(100vw - 24px)); z-index: 65;
  background: var(--latar-2); color: var(--teks);
  border: 2px solid var(--aksen); border-radius: 12px;
  padding: 12px 14px; box-shadow: var(--bayang);
}
.versi-baru p { margin: 0 0 4px; }
.versi-baru .baris-tombol { margin: 8px 0 0; }

/* --- animasi -------------------------------------------------------------
   Keadaan awal setiap @keyframes TIDAK BOLEH opacity:0 atau scaleY(0).
   `animation: … both` menahan keadaan awal tanpa batas waktu, jadi apa pun
   yang membekukan jam animasi — penghemat baterai, halaman tidak dikomposit,
   kebijakan browser — akan MENGHAPUS isi layar kalau keadaan awalnya nol.
   Angka anggaran yang hilang jauh lebih mahal daripada animasi yang kurang
   dramatis. Pelajaran dari grafik arus kas NERACA yang pernah kosong total.
--------------------------------------------------------------------------- */
@keyframes muncul { from { opacity: .55; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.view { animation: muncul .16s ease-out both; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --- laporan Renwas (SPEC-rev2 §16) -------------------------------------- */
.saring-baris {
  display: flex; flex-wrap: wrap; align-items: end; gap: 10px; margin-bottom: 10px;
}
.saring-baris label { margin: 0; }
.saring-baris select { min-width: 160px; }

/* Sebelas kolom pada satu tabel — 2px per sisi berarti 44px untuk seluruh
   barisnya, dan 44px itulah selisih antara "kolom Jumlah terbaca" dan "kolom
   Jumlah harus digeser tangan". Dipersempit hanya untuk tabel ini; tabel lain
   tidak sepadat ini dan tidak perlu membayar kerapatannya. */
table.renwas th, table.renwas td { padding-left: 8px; padding-right: 8px; }
table.renwas th { font-size: .74rem; letter-spacing: .02em; }
table.renwas td { vertical-align: top; }
.renwas-sub > td { background: var(--latar-3); font-weight: 600; }
.renwas-pen > td { border-top: 2px solid var(--garis); }
.renwas-tim > td { padding-top: 2px; padding-bottom: 2px; font-size: .84rem; color: var(--teks-lemah); }
.renwas-orang { padding-left: 14px; }
.renwas-no {
  display: inline-block; min-width: 18px; text-align: right;
  color: var(--teks-lemah); margin-right: 4px;
}

/* --- peta kalender (SPEC-rev2 §17) ---------------------------------------
   Tanpa pustaka grafik: CSS grid. Lebar sel dan jumlah kolom disetel lewat
   CSSOM di app.js (`setLebar`), bukan atribut style — `style-src 'self'`
   memblokir yang kedua.

   `overflow-x: auto` berada DI SINI, di wadah petanya sendiri. 365 kolom tidak
   akan pernah muat di 375px, tetapi HALAMANNYA tidak boleh ikut menggulir
   mendatar: gulir mendatar di tingkat halaman memindahkan seluruh antarmuka,
   termasuk bilah menu, dan pengguna kehilangan jalan kembali. */
.peta {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--garis);
  border-radius: 12px;
  background: var(--latar-2);
  margin: 10px 0;
  max-height: 70vh;
  overflow-y: auto;
}
/* `width: max-content` WAJIB. Baris blok berlebar bawaan hanya selebar wadah
   `.peta`, sementara jalurnya menjulur jauh melewatinya — dan `position:
   sticky` berhenti di tepi kanan KOTAK INDUKNYA. Akibat nyatanya: pada
   kerapatan harian kolom nama menetap sampai ±akhir Februari lalu ikut hanyut,
   dan seluruh baris kehilangan identitasnya justru di sepuluh bulan sisanya.
   min-width menjaga baris pendek tetap selebar wadah pada kerapatan bulan. */
.peta-baris { display: flex; align-items: stretch; border-bottom: 1px solid var(--garis); width: max-content; min-width: 100%; }
.peta-baris:last-child { border-bottom: none; }
.peta-baris-kosong .peta-nama-teks { color: var(--teks-lemah); }

/* Kolom nama DIPATOK. Tanpa ini, menggulir ke November membuat seluruh baris
   kehilangan identitasnya — peta 365 kolom tanpa nama yang menetap hanya
   menunjukkan bahwa ADA sesuatu, bukan pada siapa.

   TINGKATNYA HARUS DI ATAS SELURUH ISI JALUR (SPEC-rev2 §33.1).
   Sampai 20 Agustus 2026 kolom ini berbagi `z-index: 2` dengan `.btg-tumpuk`.
   Pada tingkat yang sama, yang belakangan di DOM menang — dan penanda
   bertumpuk memang digambar paling akhir supaya berdiri di atas batangnya.
   Akibatnya: menggulir ke kanan membuat penanda itu HANYUT MENIMPA NAMA
   ORANGNYA, bukan lewat di bawahnya seperti batang biasa (yang ber-z-index 1
   dan karena itu benar sejak awal). Terukur pada data hidup: 31 penanda
   menimpa kolom nama di ujung gulir, dan `elementFromPoint` di titik
   irisannya mengembalikan penandanya — jadi kliknya pun ikut dirampas.

   Urutannya sekarang, dan ketiganya harus dibaca bersama:
     .btg-peta   1   batang lewat DI BAWAH kolom nama
     .btg-tumpuk 2   penanda di atas batang, tetap di bawah kolom nama
     .peta-nama  4   kolom nama menang atas seluruh isi jalur
     .peta-kepala 5  kepala tetap menang atas kolom nama saat gulir tegak
   Ada uji statis yang menjaga urutan ini. */
.peta-nama {
  position: sticky; left: 0; z-index: 4;
  flex: 0 0 168px; width: 168px;
  background: var(--latar-2);
  border-right: 1px solid var(--garis);
  padding: 5px 8px;
  display: flex; flex-direction: column; gap: 2px;
  font-size: .76rem; line-height: 1.25;
}
.peta-nama-teks {
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.peta-jalur {
  display: grid;
  grid-auto-rows: minmax(34px, auto);
  align-items: center;
  position: relative;
}
.peta-jalur > * { grid-row: 1; }

/* Satu tingkat DI ATAS kolom nama — lihat tabel urutan di `.peta-nama`.
   Kolom nama dinaikkan ke 4, jadi kepala yang tertinggal di 3 akan tertimpa
   nama baris pertama begitu petanya digulir tegak: cacat yang sama persis,
   hanya berputar 90 derajat. */
.peta-kepala { position: sticky; top: 0; z-index: 5; background: var(--latar-2); }
.peta-kepala .peta-jalur { grid-auto-rows: 20px; }
.peta-kepala-tik { top: 20px; border-bottom: 1px solid var(--garis); }

/* Nama bulan MEMBENTANG selebar bulannya, bukan selebar satu kolom. Versi
   pertama menandainya di satu kolom saja, sehingga "Feb" tampak menandai satu
   hari alih-alih satu bulan. */
.peta-bulan {
  font-size: .72rem; font-weight: 600; color: var(--teks);
  border-left: 1px solid var(--garis);
  padding-left: 4px; white-space: nowrap; overflow: hidden;
  display: flex; align-items: center;
}
.peta-tik {
  font-size: .62rem; color: var(--teks-lemah);
  border-left: 1px solid var(--garis);
  display: flex; align-items: center; justify-content: center;
  white-space: nowrap; overflow: hidden;
}
.peta-tik.pekan { color: var(--buruk); }

/* KISI YANG TERLIHAT SEBAGAI KISI (SPEC-rev2 §18.1).
   Tanpa garis per sel, dua batang yang berselisih satu hari tampak bersambung,
   dan kolom kosong tidak bisa dihitung — hanya dilihat. */
.peta-sel {
  align-self: stretch;
  border-left: 1px solid var(--garis);
  opacity: .55;
}
/* Akhir pekan dan hari libur berlatar BERBEDA, supaya kolom kosong bisa dibaca
   sebagai "kosong karena libur" atau "kosong karena memang tidak ada
   penugasan". Dua sebab yang berbeda tidak boleh terlihat sama (§13.3). */
.peta-sel.sel-pekan { background: var(--latar-3); }
.peta-sel.sel-libur { background: var(--buruk); opacity: .22; }
.peta-sel.sel-ada-libur { border-left-color: var(--buruk); }
.peta-sel.tersorot { background: var(--aksen); opacity: .28; }

.peta-libur { background: var(--buruk); opacity: .16; align-self: stretch; }
/* BATANG DAN PENANDA HARUS BERADA DI ATAS SEL LATAR (SPEC-rev2 §29.20).
   `.peta-sel` memakai `opacity: .55`, dan opacity < 1 MEMBUAT KONTEKS
   PENUMPUKAN — akibatnya sel latar dilukis pada tahap yang datang SESUDAH isi
   biasa, meski ia lebih dulu di DOM. Dua akibatnya sekaligus:

     1. batang penugasan tampak berpita terang di kolom akhir pekan, seolah
        penugasannya terputus-putus padahal ia utuh;
     2. dan yang jauh lebih mahal — `document.elementFromPoint` di tengah
        penanda bertumpuk mengembalikan `.peta-sel`, sehingga KLIK TIDAK
        PERNAH SAMPAI. Diuji 19 Agustus 2026: 12 dari 12 penanda tertutup.

   Cacat ini lolos dari uji karena uji memanggil `el.click()`, yang MELEWATI
   uji-tumpuk peramban. Pemilik yang menemukannya, dengan jari.

   Diperbaiki dengan menaikkannya ke lapis ber-z-index, bukan dengan
   `pointer-events: none` pada selnya: sel latar membawa `title` berisi tanggal
   dan keterangan liburnya, dan mematikan pointer akan ikut mematikan itu. */
.btg-peta {
  height: 20px; border-radius: 4px; min-width: 3px;
  display: flex; align-items: center; overflow: hidden;
  padding: 0 4px; font-size: .66rem; color: #fff;
  position: relative; z-index: 1;
}
.btg-peta > b { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.btg-dalam { background: #2563eb; }
.btg-luar  { background: #b45309; }

/* Tumpang tindih dibedakan POLA, bukan hanya rona (§17.3). Peta yang hanya
   mengandalkan warna tidak terbaca oleh sebagian orang, dan tidak terbaca
   sama sekali saat dicetak hitam-putih — dan laporan ini memang dicetak. */
.btg-tumpuk {
  height: 26px; align-self: center; border-radius: 3px;
  background: repeating-linear-gradient(45deg,
    var(--buruk) 0 3px, transparent 3px 6px);
  outline: 1px solid var(--buruk);
  cursor: pointer;
  /* Satu tingkat DI ATAS batang: penanda bertumpuk selalu berdiri tepat di
     atas batang yang ditumpuknya, dan ia yang harus menerima kliknya. */
  position: relative; z-index: 2;
}
.btg-peta[data-rinci] { cursor: pointer; }
/* Lencana "N hari bertumpuk" pernah menjadi TOMBOL (§26.4) dan sekarang
   TIDAK lagi (§29.20): pintunya satu, yaitu kotak bergaris di kalender.
   Aturannya dibuang bersama tombolnya — aturan gaya yang tidak lagi punya
   elemen akan dipakai lagi oleh orang berikutnya yang mengira ia masih hidup. */

.peta-kunci { display: flex; flex-wrap: wrap; gap: 12px; margin: 6px 0 2px; color: var(--teks-lemah); }
.peta-kunci span { display: inline-flex; align-items: center; gap: 5px; }
.kunci-kotak { width: 14px; height: 12px; border-radius: 3px; display: inline-block; }
.peta-libur-contoh { background: var(--buruk); opacity: .3; }

:root[data-tema="terang"] .btg-dalam { background: #1d4ed8; }
:root[data-tema="terang"] .btg-luar  { background: #92400e; }

/* Lencana di dalam kolom nama tidak boleh melebar melewati kolomnya. Pada
   375px kolom itu hanya 118px, dan "13 hari bertumpuk" — justru penanda yang
   paling perlu terbaca — terpotong di tengah kata. Dibiarkan membungkus, bukan
   dipendekkan: singkatan yang harus ditebak sama saja dengan terpotong. */
.peta-nama .lencana {
  white-space: normal;
  max-width: 100%;
  line-height: 1.15;
  padding: 1px 5px;
  align-self: flex-start;
}

@media (max-width: 560px) {
  .peta-nama { flex-basis: 118px; width: 118px; font-size: .7rem; }
  .peta-nama .lencana { font-size: .62rem; }
  .peta { max-height: 62vh; }
}

/* --- rincian batang peta (SPEC-rev2 §18.3) -------------------------------- */
.peta-detail {
  border: 1px solid var(--aksen);
  border-radius: 12px;
  background: var(--latar-2);
  padding: 12px 14px;
  margin: 10px 0;
}
.peta-detail h3 { margin: 0; }
.peta-rinci {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 4px 14px; margin: 10px 0 0; font-size: .88rem;
}
.peta-rinci dt { color: var(--teks-lemah); }
.peta-rinci dd { margin: 0; }
.peta-rinci ul { margin: 4px 0 0; padding-left: 18px; }

/* Anggota paket di kartu banding (§29.9): digandengkan dengan garis tepi,
   supaya dua baris bernama sama persis terbaca sebagai satu kesatuan dan
   bukan sebagai kembaran yang tidak dijelaskan. */
.banding-anggota {
  margin: 4px 0 0; padding-left: 10px;
  border-left: 2px solid var(--garis);
}
.banding-anggota li { margin: 2px 0; }
.banding-porsi {
  margin: 4px 0 0; padding-left: 10px;
  border-left: 2px dotted var(--garis);
}
.banding-porsi > div { margin: 2px 0; }
.banding-paket { margin-bottom: 8px; }

/* Gandengan anggota paket di laporan bulanan (§29.9). Garis tepi kiri, bukan
   warna latar: latar berwarna akan bertabrakan dengan penanda status usulan
   yang sudah memakai warna, dan cetakan hitam-putih menghapusnya sama sekali. */
tr.renwas-pen.paket-awal   > td:first-child { border-left: 3px solid var(--aksen); }
tr.renwas-pen.paket-tengah > td:first-child { border-left: 3px solid var(--aksen); }
tr.renwas-pen.paket-akhir  > td:first-child { border-left: 3px solid var(--aksen); }
tr.renwas-pen.paket-awal   > td { border-top: 1px solid var(--aksen); }
tr.renwas-pen.paket-akhir  > td { border-bottom: 1px solid var(--aksen); }

.btg-peta { cursor: pointer; }
.btg-peta:focus-visible { outline: 2px solid var(--aksen); outline-offset: 1px; }
.btg-peta.terpilih { outline: 2px solid var(--teks); outline-offset: 1px; }

/* Batang penugasan HARUS terlihat bisa ditekan (§29.4). Sebelum ini ia hanya
   berubah kursor — dan kursor tidak ada di layar sentuh, sehingga seluruh
   kalender terasa gambar mati sampai seseorang tidak sengaja menekannya. */
.btg-peta:hover, .btg-tumpuk:hover {
  outline: 2px solid var(--aksen); outline-offset: 1px; filter: brightness(1.08);
}
.btg-tumpuk { cursor: pointer; }
.btg-tumpuk:focus-visible { outline: 2px solid var(--aksen); outline-offset: 1px; }
.btg-tumpuk.terpilih { outline: 2px solid var(--teks); outline-offset: 1px; }

@media (max-width: 560px) {
  .peta-rinci { grid-template-columns: 1fr; gap: 0 0; }
  .peta-rinci dt { margin-top: 6px; font-size: .78rem; }
}

/* --- tindak lanjut temuan (SPEC-rev2 §19) --------------------------------- */
.tindak {
  margin-top: 10px; border: 1px solid var(--garis); border-radius: 10px;
  padding: 8px 12px; background: var(--latar-3);
}
/* 44px, sama seperti `.rincian > summary` (§13.9). Keduanya satu-satunya jalan
   membuka isinya; yang sulit dibuka sama saja dengan yang disembunyikan. Yang
   satu sudah diperbaiki 13 Agustus, yang ini tertinggal — dan tertinggalnya
   baru ketahuan ketika ambangnya dijaga mesin, bukan diingat orang. */
.tindak > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; }
.tindak ol { margin: 6px 0; padding-left: 20px; }
.tindak li { margin: 3px 0; }

/* --- kelas kedua pemeriksaan: dicatat, tidak dituduh (SPEC §7.2, §24.5) --- */
.rincian {
  margin-top: 10px; border: 1px solid var(--garis); border-radius: 10px;
  padding: 4px 12px; background: var(--latar-3);
}
/*
 * 44px, bukan selera. Versi pertama memakai <summary> telanjang dan hasilnya
 * 23px pada 375px — separuh anjuran, pada satu-satunya elemen yang HARUS
 * disentuh untuk membuka kelompok "belum bisa dipastikan". Kelompok yang
 * sulit dibuka sama saja dengan kelompok yang disembunyikan, dan §24.5 ada
 * justru supaya ia tidak tersembunyi.
 */
.rincian > summary {
  cursor: pointer; min-height: 44px;
  display: flex; align-items: center; gap: 6px;
  padding: 4px 0;
}
.rincian table { margin-top: 4px; }

/* --- pilih massal & status (SPEC-rev2 §20) -------------------------------- */
.aksi-massal {
  position: sticky; top: 0; z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  background: var(--latar-2); border: 1px solid var(--garis);
  border-radius: 10px; padding: 8px 12px; margin: 10px 0;
}
/* Label pembungkus, bukan kotak telanjang: kotak centang bawaan hanya 13px,
   jauh di bawah 44px, dan pada tabel serapat ini ia nyaris tidak bisa ditekan
   dengan jempol. Labelnya memperluas sasaran sentuh tanpa memperbesar kotaknya. */
/* 44px pada KEDUA sisi (§13.9). `min-height` saja menghasilkan label 31×44 di
   kolom nomor daftar usulan — tinggi cukup, lebar tidak, dan uji statis tidak
   bisa melihatnya karena lebarnya datang dari tata letak, bukan dari CSS. Sel
   kolomnya sendiri sudah 59px, jadi 44px muat tanpa menggeser apa pun. */
.pilih {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0; min-height: 44px; min-width: 44px; cursor: pointer; color: var(--teks);
}
.pilih input {
  width: 18px; height: 18px; margin: 0; flex: 0 0 auto;
  /* sentuh-kecil: kotak centang bawaan peramban 13-18px, dan memperbesarnya
     membuatnya terlihat seperti kotak isian angka. Sasaran sentuhnya adalah
     `.pilih` di atas — label setinggi 44px yang membungkusnya (§13.9). */
  min-height: 18px;
}

/* Daftar tempat penugasan (§114): kotak centang 23 kabupaten/kota, boleh
   lebih dari satu. Kisi yang menyesuaikan lebar — satu kolom di 375px, dua
   sampai tiga di desktop — dan bergulir DI DALAM wadahnya sendiri: 23 baris
   × 44px adalah 1.000px, dan modal formulir yang memanjang sejauh itu
   menyembunyikan tombol Simpan. Sasaran sentuh tiap barisnya `.pilih` (44px). */
.label-kelompok { display: block; font-size: .86rem; color: var(--teks-lemah); margin: 10px 0 4px; }
.tempat-daftar {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 0 12px; max-height: min(44vh, 400px); overflow-y: auto;
  border: 1px solid var(--garis); border-radius: 8px; padding: 4px 10px;
  background: var(--latar-2);
}
.tempat-pilih { font-size: .92rem; width: 100%; }
.tempat-pilih > span { line-height: 1.25; }
.baris-tempat-bebas {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 44px; padding: 2px 10px; margin-top: 6px;
  border: 1px solid var(--garis); border-radius: 8px; font-size: .92rem;
}
.tempat-lain .baris-tombol { margin: 4px 0 2px; align-items: center; }
.tempat-lain .baris-tombol input { flex: 1 1 200px; margin: 0; }
/* Formulirnya `.tumpuk`, yang melebarkan SETIAP tombol menjadi 100%. Kedua
   tombol di sini berdampingan dengan teks/isian, jadi lebarnya dikembalikan
   ke isinya — tanpa ini "Buang" selebar baris dan nama tempatnya terdesak
   menjadi dua baris. */
.tumpuk .baris-tempat-bebas button,
.tumpuk .tempat-lain .baris-tombol button { width: auto; margin-top: 0; flex: 0 0 auto; }
#fp-lokasi-ringkas { margin: 6px 0 2px; }

/* Tabel berjenjang (Per program & panel belanja): baris kepala kelompok +
   baris anak yang menjorok. Nama induk ditulis SEKALI. */
tr.baris-kelompok td {
  background: var(--latar-3);
  border-top: 1px solid var(--garis);
  padding-top: 8px; padding-bottom: 6px;
}
td.sel-anak { padding-left: 22px; }

/* Angka ringkas yang membawa angka pastinya. Kursor desktop membaca `title`;
   HP memakai penanda ⓘ di sampingnya yang membuka kartu (bertahan sampai
   ditutup, bisa disalin). nowrap menjaga nominal tak pecah baris (§13.4). */
.angka-ringkas { white-space: nowrap; cursor: help; }
/* Nominal yang mengikuti nama panjang (contoh pembanding beranda): namanya
   boleh melipat, "— Rp 39.210.000"-nya tidak (§13.4) — tertangkap sapu-ukur
   pada 375px, 15 Agustus 2026. */
.nilai-rapat { white-space: nowrap; }

/* --- penyaring status Renwas (§25.9 butir 1) ------------------------------ */
/* Hitungan status adalah tombol penyaring. Bentuknya tetap kalimat — yang
   berubah hanya kursornya dan garis bawah titik-titik, supaya terbaca bisa
   ditekan tanpa mengubah wajah laporan. */
button.saring-status {
  background: none; border: 0; padding: 4px 2px; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  min-height: 44px; display: inline-flex; align-items: center; gap: 4px;
  border-bottom: 1px dotted var(--teks-lemah);
}
button.saring-status.aktif {
  border-bottom: 2px solid var(--aksen);
  background: var(--latar-3);
}
/* CSS yang menyaring, CETAK yang mengembalikan: kertas selalu laporan penuh
   (§13.12). Aturan pengembaliannya hidup DI DALAM blok @media print utama di
   bawah berkas ini — blok print kedua yang berdiri sendiri mengecoh uji
   statis CSS cetak, yang membaca satu blok print sebagai satu kesatuan. */
.renwas-saring tr.saring-luput { display: none; }
.renwas-saring tr.renwas-sub,
.renwas-saring table.renwas tfoot,
.renwas-saring .renwas-total { display: none; }

/* --- glosarium (§25.9 butir 4) -------------------------------------------- */
.glos-item { border-bottom: 1px solid var(--garis); padding: 4px 0; }
.glos-item summary {
  cursor: pointer; font-weight: 600; padding: 8px 0;
  min-height: 44px; display: flex; align-items: center;
}
.glos-item > div { padding: 0 0 10px 14px; }
#glos-usul { flex: 1; min-width: 160px; }
.angka-i {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 4px; margin-left: 1px;
  color: var(--aksen); font-size: .8em; line-height: 1;
  vertical-align: super; cursor: pointer; user-select: none;
  /* sentuh-kecil: penanda ⓘ sebaris di samping nominal — 44px memecah baris
     angkanya, dan kartunya sendiri sudah menjadi sasaran 44px yang membuka
     panel berisi angka penuh yang sama.

     Penandanya DIULANG di sini, bukan hanya di `.angka-i-sentuh` di bawah:
     yang berukuran kecil adalah kelas INI, dan sapuan runtime
     (`tools/reviu-tablet.js`) memungut pengecualian dari kelas di selektor
     aturan yang memuat penandanya. Keputusan yang tertulis di sebelah kelas
     yang salah sama saja dengan keputusan yang tidak tertulis. */
}
.angka-i:hover { color: var(--teks); }
/* Penanda ⓘ yang berdiri DI DALAM sebuah tombol (§77.1). Ia tidak ber-tabindex
   dan tidak ber-`role` — isi `<button>` dilarang memuat keduanya — jadi yang
   tersisa hanya sasaran sentuh/tetikus, dan sasaran itu harus benar-benar
   berada DI ATAS lapisan tombolnya supaya `document.elementFromPoint`
   memulangkan penandanya, bukan tombol di belakangnya.

   sentuh-kecil: penanda sebaris di samping nominal, sama alasannya dengan
   `.istilah-i` — 44px memecah baris angkanya, dan kartunya sendiri sudah
   menjadi sasaran 44px yang membuka panel berisi angka penuh yang sama. */
.angka-i-sentuh { position: relative; z-index: 1; }

/* Kamus istilah (SPEC-rev2 §25.5): penanda ⓘ sebaris + kartu penjelasan. */
button.istilah-i {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 3px; border: 0; background: none; color: var(--aksen);
  font: inherit; font-size: .85em; line-height: 1; cursor: help;
  vertical-align: super;
  /* sentuh-kecil: penanda kamus sebaris di samping istilah — 44px memecah
     baris kalimatnya. Kartu yang dibukanya punya tombol Tutup berukuran
     penuh, dan penandanya sendiri berdiri di samping teks yang bisa dibaca
     tanpa menyentuh apa pun. */
  min-height: 0;
}
.istilah-kartu {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  width: min(520px, calc(100vw - 24px)); z-index: 70;
  background: var(--latar-2); border: 1px solid var(--garis);
  border-radius: 12px; padding: 12px 14px; box-shadow: var(--bayang);
}
.istilah-kartu h3 { margin: 0 0 4px; font-size: 1rem; }

/* Tautan-dalam: nama orang/penugasan di dalam kalimat atau tabel yang membuka
   resumenya (SPEC-rev2 §25). Bentuknya tautan, elemennya button — supaya CSP
   tetap tanpa handler sebaris dan pembaca layar mendengar tombol. */
button.tautan-data {
  display: inline; padding: 0; border: 0; background: none;
  font: inherit; text-align: inherit; white-space: normal;
  color: var(--aksen); text-decoration: underline; cursor: pointer;
  /* sentuh-kecil: tautan sebaris di tengah kalimat temuan dan sel tabel;
     memaksanya 44px memecah baris teks di sekelilingnya. Sasaran sentuh
     efektifnya baris/sel yang memuatnya, sama seperti tautan `a` biasa. */
  min-height: 0;
}
button.tautan-data:hover { color: var(--teks); }

/* Nomor ST di Lembar rekap adalah pintu ke ISI SURAT di register (§116.8),
   dan di baris yang sama ada pintu lain — nama penugasan — yang membuka hal
   berbeda. Dua pintu yang tampak sama akan ditekan bergantian sampai salah
   satu berhenti ditekan, jadi yang ini bergaris putus-putus dan berpenanda
   pensil. Mono-nya diwarisi dari sel. */
button.tautan-data.tautan-register {
  text-decoration-style: dashed; text-underline-offset: 3px;
}
button.tautan-data.tautan-register::after {
  content: ' ✎'; font-size: 0.85em; opacity: 0.75; text-decoration: none; display: inline-block;
}

.item-tanda { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 2px; }
.renwas-pen .item-tanda { margin-top: 2px; }

/* ===========================================================================
   CETAK — media kedua, dan ia punya aturannya sendiri (SPEC-rev2 §13.12)

   `CLAUDE.md` menyatakan "laporan ini dicetak" sejak §17 lahir, dan pernyataan
   itu membeli satu keputusan mahal: tumpang tindih di peta dibedakan POLA,
   bukan hanya warna. Tetapi sampai 14 Agustus 2026 berkas ini tidak memuat satu
   pun aturan cetak — keputusan itu berdiri di atas jalur yang tidak pernah
   disiapkan maupun diperiksa.

   Diuji dengan mencetak halaman Laporan ke PDF: 34 halaman, dan kolom JUMLAH —
   nominal yang menjadi alasan laporan ini ada — tidak muncul SATU KALI PUN.
   PENGINAPAN juga nol. UANG HARIAN muncul tetapi nilainya terpenggal:
   "Rp 700 r" sebanyak 169 kali. Tanpa pesan, tanpa tanda potong; kertasnya
   hanya berhenti.

   Sebabnya justru aturan yang BENAR untuk layar: tabel berada di dalam wadah
   `overflow-x: auto` (§17), dan di kertas tidak ada gulir. Yang tidak terlihat
   tidak tercetak. Aturan yang benar pada satu media menjadi kehilangan data
   pada media lain.
   =========================================================================== */

/* --- panel pengawasan (SPEC-rev2 §58) ------------------------------------
 *
 * Tiga kotak pilihan berdampingan. `input, select, textarea` bawaan memakai
 * `width: 100%`, yang di dalam baris lentur membuat SETIAP kotak memakan satu
 * baris penuh — tiga penyaring bertumpuk setinggi layar pada lebar berapa pun,
 * termasuk desktop.
 *
 * `flex: 1 1 180px` yang menjawab keduanya sekaligus: pada 375px dua kotak
 * selebar 180px tidak muat berdampingan sehingga ia membungkus sendiri, dan
 * pada desktop ketiganya berbagi satu baris. Angka 180px bukan selera — ia
 * lebar terkecil yang masih memuat nama aksi terpanjang yang ada
 * (`usul_nama_diajukan`) tanpa terpotong menjadi teka-teki.
 *
 * `min-height: 44px` bawaan TIDAK diganggu (§13.9): kotak pilihan adalah
 * sasaran sentuh seperti tombol, dan ia satu-satunya kendali di panel ini yang
 * dipakai berulang-ulang.
 *
 * `max-width: 100%` MENUTUP GULIR MENDATAR 20px PADA 375px (§165). Butir
 * lentur tidak pernah menyusut di bawah lebar isinya, dan lebar isi kotak
 * pilihan ditentukan OPSI TERPANJANGNYA, dipilih atau tidak: *"Semua perubahan
 * data (bukan peristiwa pintu masuk)"* membuat `#awas-aksi` selebar 366px di
 * wadah 317px, sebelum penyaring apa pun dipasang. Batas atas itu ikut
 * menjepit batas bawah otomatisnya (min(isi, wadah)), jadi pada layar lebar
 * kotaknya tetap selebar opsinya; hanya di bawah itu teks terpilih terpotong
 * di dalam kotak, dan daftar opsinya tetap utuh. Bukan `min-width: 0`: yang
 * itu membuat kotak di desktop menyusut di bawah teksnya begitu tombol
 * *Bersihkan penyaring* ikut di baris yang sama. */
.awas-saring { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.awas-saring select { flex: 1 1 180px; width: auto; max-width: 100%; }
.awas-saring button { flex: 0 0 auto; }

/* Pemilih jendela hari duduk DI DALAM baris judul, jadi ia tidak boleh
   melebar memenuhi barisnya dan mendorong judulnya turun. */
.awas-jendela { width: auto; flex: 0 0 auto; min-width: 116px; }

/* Penanda jendela waktu daftar jejak (§68) — "sejak 25/08/2026 09.14".
   Ia KETERANGAN, bukan kendali: yang melepasnya tombol di sebelahnya, jadi
   §13.9 tidak berlaku padanya dan ia tidak butuh perkecualian sentuh-kecil.
   `align-self: center` supaya ia sejajar tengah dengan kotak pilihan setinggi
   44px alih-alih meregang setinggi itu — lencana setinggi tombol terbaca
   sebagai tombol, dan tombol yang tidak bisa ditekan terbaca sebagai kerusakan. */
.awas-jendela-tanda { align-self: center; flex: 0 0 auto; }
@media print {
  /* Kertas tidak bisa ditekan. Seluruhnya sempat ikut tercetak di atas kertas
     resmi: sembilan menu navigasi, bilah tahun, tab, tombol Ekspor, dan bilah
     "Pilih semua · Ajukan ke Inspektur · Setujui yang dipilih · Tolak…". */
  nav, #bar-atas, .tab, .aksi-massal, .baris-tombol,
  button, .tombol, #panel, .toast { display: none !important; }

  /* PERKECUALIAN YANG BUKAN KENDALI: tautan-dalam (§25) adalah ISI — nama
     penugasan di kolom Renwas dan nama orang di baris tim dirender sebagai
     <button class="tautan-data">. Ikut menyembunyikannya berarti mencetak
     laporan yang kehilangan seluruh NAMANYA — kelas kegagalan yang sama
     dengan kolom Jumlah yang dulu tidak pernah tercetak. Di kertas ia teks
     biasa: tanpa warna tautan, tanpa garis bawah. */
  button.tautan-data {
    display: inline !important;
    color: inherit !important; text-decoration: none !important;
  }

  /* PERKECUALIAN KEDUA, DAN SEBABNYA SAMA: KARTU YANG MENJADI TOMBOL.

     Sejak §75 kartu KPI Beranda pantau LAHIR sebagai <button>, dan sejak
     §77 corong usulan serta baris legenda ikut. Aturan `button { display:none }`
     di atas benar untuk KENDALI — tetapi kelima kartu itu ADALAH angkanya,
     bukan tombol di sebelah angkanya. Tanpa perkecualian ini, mencetak Beranda
     menghasilkan kertas yang kehilangan seluruh kartu KPI, keenam tahap corong,
     dan nilai tiap potong donat sekaligus — tanpa satu pun galat, dan hanya
     terlihat oleh yang membandingkan kertasnya dengan layarnya.

     Di kertas ia ISI, bukan kendali: tanpa kursor, tanpa tanda `›`, dan tanpa
     tinggi sasaran sentuh yang di sana tidak berarti apa-apa. */
  .kartu-buka, .pt-corong-btn, .g-legenda-btn {
    display: block !important; cursor: auto !important;
    min-height: 0 !important; transform: none !important;
  }
  .g-legenda-btn { display: inline-flex !important; }
  .kartu-buka::after { content: '' !important; }

  /* Chip bulan (§77.2) TIDAK dikecualikan: ia kendali murni — dua belas nama
     bulan tanpa satu angka pun, yang di kertas hanya deretan kata. */

  /* PENYARING STATUS RENWAS (§25.9 butir 1): layar boleh tersaring, kertas
     TIDAK PERNAH. Baris yang disembunyikan penyaring dikembalikan di sini —
     tanpa aturan ini, mencetak selagi penyaring aktif menghasilkan laporan
     sepotong yang tampak resmi. Kendali penyaringnya sendiri ikut aturan
     `button { display:none }` di atas. */
  .renwas-saring tr.saring-luput { display: table-row !important; }
  .renwas-saring tr.renwas-sub { display: table-row !important; }
  .renwas-saring table.renwas tfoot { display: table-footer-group !important; }
  .renwas-saring .renwas-total { display: block !important; }
  #renwas-saring-info { display: none !important; }
  /* PAPAN PEMERIKSAAN: LAYAR SATU P, KERTAS KEDELAPANNYA (§74.3).
     Sepola perkecualian penyaring Renwas di atas, dan dengan sebab yang sama —
     layar boleh terpilih, kertas tidak pernah. Tanpa aturan ini, mencetak dari
     halaman P3 menghasilkan satu kartu di atas kertas resmi tanpa satu tanda
     pun bahwa tujuh lainnya tidak ikut.
     `.periksa-cetak-nota` adalah kalimat untuk PEMBACA LAYAR ("mencetak
     halaman ini menghasilkan kedelapannya"); di atas kertas ia sudah tidak
     menjelaskan apa-apa, jadi ia yang justru disembunyikan. */
  .periksa-lipat { display: block !important; }
  /* PENGATURAN → AKUN: LAYAR SATU BAGIAN, KERTAS KEEMPATNYA (§82.4).
     Keputusannya sadar, dan sama dengan §74.3 di atas — bukan aturan kedua
     untuk hal yang sama. Yang dipertimbangkan dan DITOLAK: mencetak hanya
     bagian yang aktif dan membubuhkan catatan "tiga bagian lain tidak ikut".
     Catatan seperti itu benar tetapi tidak menolong — yang memegang kertasnya
     tetap tidak punya isinya, dan pasal ini justru lahir karena isi yang
     hilang tanpa tanda sudah berulang di aplikasi ini.
     `.atur-kepala-cetak` sebaliknya: TIDAK ADA di layar, WAJIB di kertas —
     bilah tabnya sendiri tidak tercetak, dan empat bagian tanpa judul kembali
     menjadi satu gulir panjang. */
  .atur-lipat { display: block !important; }
  .atur-kepala-cetak { display: block !important; margin: 14px 0 8px; }
  .atur-bagian { break-inside: auto; }
  /* Pita §59 IKUT TERCETAK. Ia satu-satunya bagian halaman ini yang
     memberitahu bahwa orang lain menyentuh akun pemiliknya, dan kertas yang
     dibawa ke meja pengelola justru kertas yang paling perlu memuatnya. */
  #atur-akun-pita { display: block !important; }
  .periksa-kepala-cetak { display: block !important; margin-bottom: 10px; }
  .periksa-cetak-nota { display: none !important; }
  /* Tiap pemeriksaan mulai di halaman kertasnya sendiri kalau memang tidak
     muat — kartu yang terbelah di antara dua lembar kehilangan judulnya pada
     lembar kedua, dan lembar tanpa judul tidak bisa dirujuk di rapat. */
  .periksa-hal { break-inside: avoid-page; }


  /* CETAK PANEL (tombol "🖨 Cetak resume", §25). Ctrl+P biasa mencetak
     HALAMAN — panel di atasnya justru disembunyikan aturan cetak. Saat
     tombolnya menyalakan kelas cetak-panel di <body>, arahnya dibalik:
     halaman di belakang disembunyikan, panel dibentang statis, dan setiap
     wadah gulirnya dilepas — kertas tidak punya gulir, ke arah mana pun. */
  /* #panel adalah ANAK #app — menyembunyikan #app utuh ikut menelan panelnya
     (cetakan pertama: halaman kosong 1.269 byte). Yang disembunyikan saudara-
     saudaranya saja. */
  body.cetak-panel #app > :not(#panel) { display: none !important; }
  body.cetak-panel #panel { display: block !important; position: static; }
  body.cetak-panel .panel-latar { display: none !important; }
  body.cetak-panel .panel-isi {
    position: static !important;
    /* transform layar (translate -50%,-50% pada lebar >=760px) menggeser isi
       keluar kertas pada posisi statis — cetakan pertamanya halaman kosong. */
    transform: none !important;
    width: 100% !important; max-width: none !important;
    max-height: none !important; height: auto !important;
    overflow: visible !important;
    box-shadow: none !important; border: 0 !important; border-radius: 0 !important;
    padding: 0 !important; background: #fff !important;
  }
  body.cetak-panel .panel-isi .gulir {
    overflow: visible !important; max-height: none !important;
  }
  /* Baris "Istilah: …" adalah pembuka kamus di layar; di kertas kamusnya
     tidak bisa dibuka, jadi barisnya hanya bising. */
  .istilah-baris { display: none !important; }

  /* Penanda ⓘ angka pasti adalah undangan menyentuh; kertas tidak bisa
     disentuh, dan ⓘ di samping setiap nominal terbaca seperti catatan kaki
     yang tidak pernah ada isinya. */
  .angka-i { display: none !important; }

  /* Ruang bilah sisi ikut dilepas — tanpa ini tepi kiri setiap halaman kosong
     selebar 180px. */
  #app { max-width: none !important; padding: 0 !important; margin: 0 !important; }

  /* INI YANG MENGHILANGKAN KOLOM JUMLAH. Wadah gulir dilepas supaya seluruh
     kolom mengalir; yang tidak muat diselesaikan oleh orientasi lanskap di
     bawah, bukan dengan memotong diam-diam. */
  /* ANIMASI DIMATIKAN — DAN INILAH SEBAB CETAKAN TERPOTONG SELAMA EMPAT
     PERCOBAAN.

     `.view { animation: muncul .16s both }` memberi setiap halaman gerakan
     muncul yang manis di layar. `animation-fill-mode: both` membuat nilai
     animasinya MENETAP sesudah selesai — dan meski keyframe terakhirnya
     berbunyi `transform: none`, yang tercatat pada elemennya adalah sebuah
     MATRIKS (`matrix(1, 0, 0, 1, 0, 0)`), bukan `none`.

     Elemen bertransform tidak bisa dipenggal antar halaman: bagi mesin cetak
     ia satu kotak utuh yang tidak boleh dipotong, jadi yang tidak muat
     dibuang. Halaman Pemeriksaan setinggi 23.341px karena itu selalu
     berhenti di angka yang sama — 9 halaman — apa pun yang saya ubah di
     dalamnya: melepas overflow, membongkar wadah, memecah tabel. Keempatnya
     memperbaiki hal yang memang perlu diperbaiki, dan tidak satu pun
     menyentuh sebabnya.

     Pelajarannya: yang menghentikan cetakan bukan isi halaman, melainkan
     SATU SIFAT pada elemen yang membungkus seluruh isinya. Empat percobaan
     saya menggeledah isi kotak, sementara yang salah kotaknya. */
  .view, .kartu, .cetak-terbuka {
    animation: none !important;
    transform: none !important;
  }

  .gulir { overflow: visible !important; }

  /* …DAN WADAH PETA, YANG PUNYA BATAS TINGGI SENDIRI.

     Cetakan 14 Agustus 2026 pukul 17.09 membuktikan bahwa melepas `.gulir`
     saja tidak cukup: petanya benar setahun penuh mendatar, tetapi hanya
     LIMA dari 32 orang yang tercetak. `.peta` memakai `max-height: 70vh` +
     `overflow-y: auto`, dan di kertas tidak ada gulir menegak sebagaimana
     tidak ada gulir mendatar — 27 orang hilang tanpa satu pun tanda.

     Kegagalan yang sama persis dengan kolom Jumlah, hanya berputar 90
     derajat. Setiap batas ukuran yang ada demi LAYAR wajib dilepas untuk
     kertas; yang tersisa di layar hanyalah gulir, dan kertas tidak punya
     gulir ke arah mana pun. */
  .peta {
    max-height: none !important; overflow: visible !important;
    border: 1px solid #999 !important;
  }
  .peta-baris { break-inside: avoid; }

  @page { size: A4 landscape; margin: 10mm; }

  /* Palet layar tidak dibawa ke kertas: teks hitam di atas putih, apa pun tema
     yang sedang dipakai. Tokennya TIDAK disalin ulang di sini — salinan ketiga
     sebuah palet adalah salinan yang pasti terlupakan saat satu warna diganti
     (lihat catatan tema di bagian atas berkas ini). */
  html, body, .kartu, table, th, td {
    background: #fff !important; color: #000 !important;
  }
  /* `break-inside: avoid` SENGAJA TIDAK DIPAKAI DI SINI, dan itu koreksi
     14 Agustus 2026 pukul 17.27.

     Kartu papan pemeriksaan bisa setinggi 17.290px — sekitar 24 halaman A4
     lanskap — karena `<details>` "69 pasangan belum bisa dipastikan" dibuka
     saat mencetak. Kotak yang lebih tinggi daripada satu halaman TIDAK BISA
     dihormati permintaannya untuk tidak dipenggal; peramban memenggalnya
     dengan cara memotong, dan isi yang lewat batas halaman HILANG bersama
     apa pun yang menyusul. Pada cetakan uji, P6, P7, dan P8 tidak pernah
     tercetak sama sekali.

     Aturannya: `break-inside: avoid` hanya untuk kotak yang PASTI lebih
     pendek daripada satu halaman — baris tabel dan baris peta. Kerapian yang
     dibeli dengan kehilangan isi bukan kerapian. */
  .kartu { border: 1px solid #999 !important; box-shadow: none !important; }
  .lemah, .kecil { color: #333 !important; }
  .lencana, .lencana-unit, .lencana-lokasi {
    color: #000 !important; background: #fff !important; border: 1px solid #555 !important;
  }

  /* Peta TETAP mencetak warnanya. Pola membedakan tumpang tindih (§17.3), tetapi
     panjang batang adalah durasi — dan durasi tanpa warna tidak terbaca sebagai
     apa pun. `print-color-adjust` mencegah peramban "menghemat tinta" dengan
     membuang latar yang justru memuat isinya. */
  .btg-peta, .btg-tumpuk, .peta-sel, .peta-libur, .peta-batang {
    print-color-adjust: exact; -webkit-print-color-adjust: exact;
  }

  /* Tiga puluh empat halaman angka tanpa nama kolom bukan laporan. */
  thead { display: table-header-group; }
  tr { break-inside: avoid; }
  table { font-size: 8.5pt; }
  th, td { border-bottom: 1px solid #bbb !important; }

  /* Alamat halaman diagnosa tetap berguna di atas kertas; sisanya tidak. */
  a[href^="/"]::after { content: " (" attr(href) ")"; font-size: .85em; color: #333; }

  /* KOP: dokumen menyebut dirinya sendiri. Sebelum ini kertasnya dimulai
     dengan label penyaring "Irban / Lingkup saya" — sisa antarmuka, bukan
     judul dokumen. Penyaringnya sendiri ikut disembunyikan di bawah. */
  .kop-cetak {
    display: block !important;
    border-bottom: 2px solid #000 !important;
    padding-bottom: 6pt; margin-bottom: 10pt;
    break-after: avoid;
  }
  .kop-judul { font-size: 13pt; font-weight: 700; }
  .kop-baris { font-size: 8.5pt; color: #222 !important; }

  /* Penyaring, panel rincian yang hanya hidup saat ditekan, dan tombol
     ekspor tidak punya arti di atas kertas. */
  .saring-baris, .peta-detail { display: none !important; }
  .hanya-cetak { display: block !important; margin: 0 0 6pt; }
  .cetak-terbuka { display: block !important; }
  .cetak-terbuka-judul { font-weight: 700; margin: 6pt 0 3pt; }

  /* Sub-judul tidak boleh menjadi baris terakhir halaman: pembacanya
     membalik halaman lalu menemukan angka tanpa tahu angka apa. */
  .renwas-sub > td, h2, h3 { break-after: avoid; }

  /* Keterangan warna peta WAJIB ikut — peta tanpa keterangannya hanya gambar
     berwarna. Ia satu-satunya bagian antarmuka yang justru harus tercetak. */
  .peta-kunci { display: flex !important; gap: 10pt; margin-bottom: 6pt; }
}

/* ===========================================================================
   CORONG POSISI PENUGASAN (SPEC-rev2 §35)

   Setiap tahap adalah TOMBOL, bukan angka mati — ia menekan ke daftar
   Penugasan yang sudah tersaring. Karena itu ia tunduk pada ambang sasaran
   sentuh §13.9: min-height 44px, tanpa perkecualian dan tanpa `button.kecil`.

   `auto-fit` dengan minimum 96px, bukan tiga kolom tetap: pada 375px tiga
   kolom menyisakan ~105px per tahap, dan label "Belum berangkat" terbelah tiga
   baris. Yang menyempit dibiarkan turun, bukan diperas.
   =========================================================================== */
.corong-judul { margin: 10px 0 4px; text-transform: uppercase; letter-spacing: .04em; }

.corong {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
}

.tahap {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 44px; padding: 8px 10px;
  background: var(--latar-3); color: var(--teks);
  border: 1px solid var(--garis); border-radius: 10px;
  text-align: left; cursor: pointer;
}
.tahap:hover { border-color: var(--aksen); }

/* Nominal tidak pernah pecah baris (§13.2) — berlaku juga pada angka kecil di
   bawah label, tempat "Rp 1,2 jt" paling mudah terbelah pada kolom sempit. */
.tahap-n {
  font-size: 1.25rem; font-weight: 650; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.tahap-label { font-size: .82rem; line-height: 1.25; }
.tahap-rp { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Warna menandai ARTI tahapnya, bukan besar angkanya: `baik` untuk yang sudah
   maju, `hati` untuk yang masih tertahan di awal rantai. Yang kosong memakai
   `lemah` — nol yang pudar terbaca sebagai "belum sampai sini", bukan sebagai
   nol yang sudah dipastikan. */
.tahap.baik .tahap-n { color: var(--baik); }
.tahap.hati .tahap-n { color: var(--hati); }
.tahap.lemah { opacity: .72; }
.tahap.lemah .tahap-n { color: var(--teks-lemah); font-weight: 500; }

/* --- kalender pribadi pegawai (SPEC-rev2 §37) ----------------------------- */

.kal-kepala {
  display: flex; align-items: center; gap: 8px; margin: 4px 0 10px;
}
.kal-kepala b { flex: 1 1 auto; text-align: center; }
/* AMBANG 44px PUNYA DUA SUMBU, dan sampai 23 September 2026 hanya satu yang
   pernah diperiksa. Panah bulan `‹` dan `›` memakai `button.kecil`
   (padding 6px 12px, min-height 44px) dan berisi SATU aksara: tingginya 44px,
   lebarnya 31px.

   Uji statis §13.9 di `tools/test-api.js` tidak bisa melihatnya — ia membaca
   `min-height` yang DIDEKLARASIKAN, sedangkan yang kurang di sini lebar yang
   DIHASILKAN. Yang menemukannya sapuan runtime `tools/reviu-tablet.js`, dan
   ia satu-satunya yang bisa: lebar sebuah tombol tidak tertulis di mana pun,
   ia hanya terjadi. */
.kal-kepala button { flex: 0 0 auto; min-width: 44px; }

/* Tujuh kolom SELALU, pada lebar berapa pun. Kalender yang kolomnya berkurang
   di layar sempit berhenti menjadi kalender — pola mingguannya yang justru
   dibaca orang, bukan tanggalnya satu per satu. */
.kal-bulan {
  display: grid; gap: 2px;
  border: 1px solid var(--garis); border-radius: 10px; padding: 4px;
  background: var(--latar-2);
  /* `minmax(0, 1fr)`, BUKAN `1fr`. `1fr` berarti `minmax(auto, 1fr)`, dan
     `auto` tidak pernah lebih kecil daripada isi terlebar di dalamnya — jadi
     satu nama hari libur ber-`nowrap` cukup untuk membuat kolomnya 177px
     sementara lima kolom lain terperas menjadi 26px. Terukur di layar sebelum
     naik: `grid-template-columns` terhitung
     "177px 177px 26px 30px 28px 25px 27px" pada lebar 375px.
     Ini kerabat §13.1 (nominal yang pecah baris): keduanya kolom yang
     lebarnya ditentukan isinya, bukan oleh keputusan. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
}
.kal-nama-hari {
  text-align: center; color: var(--teks-lemah); font-weight: 600;
  padding: 4px 0; text-transform: uppercase; letter-spacing: .03em;
}
.kal-sel {
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  /* 56px, DI ATAS ambang 44px (§13.9): selnya sendiri yang menjadi sasaran
     sentuh, sehingga tidak ada satu pun perkecualian sentuh-kecil di sini. */
  min-height: 56px; padding: 3px; border-radius: 6px;
  background: var(--latar); border: 1px solid transparent;
  font: inherit; color: inherit; text-align: left;
  /* Ikut menjaga trek tetap sama lebar: tanpa ini isi sel yang panjang
     mendorong kolomnya sendiri melebar walau treknya sudah minmax(0,1fr). */
  min-width: 0; overflow: hidden;
}
.kal-luar { background: none; border-color: transparent; min-height: 0; }
.kal-akhir { background: var(--latar-3); }
/* HARI LIBUR DITANDAI GARIS, BUKAN HANYA RONA (§13.8).
   Terukur di tema gelap sebelum naik: `color-mix(--buruk 12%, --latar)` di atas
   #0b0f14 menghasilkan rasio 1,09:1 terhadap sel biasa — yaitu tidak terlihat
   sama sekali, sementara di tema terang ia cukup. Tema gelap adalah palet
   KEDUA dan punya cacatnya sendiri; ini kejadian yang sama dengan lencana
   Irban yang empat dari lima di bawah ambang sejak tema itu lahir.
   Yang membawa isyaratnya sekarang garis tepi ber-`--buruk` penuh — terbaca di
   kedua tema, terbaca hitam-putih, dan terbaca oleh yang tidak membedakan
   merah. Latarnya tinggal hiasan. */
.kal-libur {
  background: color-mix(in srgb, var(--buruk) 18%, var(--latar));
  box-shadow: inset 3px 0 0 var(--buruk);
}
.kal-kini { border-color: var(--aksen); }
.kal-ada { cursor: pointer; }
.kal-ada:hover { border-color: var(--aksen); }
.kal-tanggal { font-size: .78rem; font-variant-numeric: tabular-nums; }
.kal-ket {
  color: var(--teks-lemah); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: .6rem;
}

/* Balok TIDAK bisa ditekan — `<span>`, bukan `<button>`. Yang ditekan harinya.
   Bedanya pola, bukan hanya rona (§17.3): kalender ini ikut tercetak, dan
   perbedaan yang hanya rona hilang di mesin fotokopi. */
.kal-balok { height: 6px; border-radius: 2px; background: var(--aksen); }
.kal-kira {
  background: repeating-linear-gradient(45deg,
    var(--aksen) 0 3px, transparent 3px 6px);
  outline: 1px solid var(--aksen);
}
/* CATATAN PRIBADI: BULATAN, BUKAN BALOK (SPEC-rev2 §40.3).
   Bedanya BENTUK, dan itu disengaja. Balok yang membentang adalah kosakata
   visual penugasan; catatan berbentuk balok akan terbaca sebagai penugasan
   berapa pun bedanya rona — terutama pada sel 47px di layar 375px, dan
   terutama di kertas fotokopi. §37.5a menyebut ini bahaya terbesar fitur
   tersebut: kalender yang tidak lagi bisa menjawab "mana yang resmi".
   Ronanya sengaja NETRAL (`--teks-lemah`), bukan salah satu rona status —
   catatan pribadi bukan baik, bukan buruk, dan bukan perlu diperiksa. */
.kal-catatan {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  align-self: flex-start; background: var(--teks-lemah);
}
.kal-contoh-catatan { border-radius: 50%; background: var(--teks-lemah); }

.kal-jml {
  margin-top: auto; align-self: flex-end; color: var(--teks-lemah);
  font-variant-numeric: tabular-nums; font-size: .6rem;
}

/* Baris catatan di panel hari dan di agenda. Diberi garis tepi kiri netral
   supaya ia terbaca sebagai KELAS LAIN dari baris penugasan di sebelahnya,
   bukan sebagai penugasan yang kebetulan berbeda rona. */
.catatan-baris {
  border-left: 3px solid var(--teks-lemah);
  padding: 6px 8px; border-radius: 0 6px 6px 0;
  background: var(--latar-3, var(--latar));
  white-space: pre-wrap; overflow-wrap: anywhere;
}

.kal-contoh-pasti { background: var(--aksen); }
.kal-contoh-kira {
  background: repeating-linear-gradient(45deg,
    var(--aksen) 0 3px, transparent 3px 6px);
  outline: 1px solid var(--aksen);
}
/* Kunci peta wajib memakai isyarat yang SAMA dengan yang dijelaskannya —
   kalau contohnya rona penuh sementara selnya bergaris tepi, kuncinya
   menjelaskan tanda yang tidak ada di kalender. */
.kal-contoh-libur {
  background: color-mix(in srgb, var(--buruk) 18%, var(--latar));
  box-shadow: inset 3px 0 0 var(--buruk);
}

/* --- agenda --------------------------------------------------------------- */

.agenda { display: flex; flex-direction: column; gap: 6px; margin: 8px 0 16px; }
.agenda-baris {
  display: flex; flex-direction: column; gap: 2px; align-items: stretch;
  width: 100%; min-height: 56px; padding: 10px 12px; border-radius: 10px;
  background: var(--latar-2); border: 1px solid var(--garis);
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.agenda-baris:hover { border-color: var(--aksen); }
.agenda-tgl { color: var(--aksen); font-weight: 600; }
.agenda-nama { font-weight: 600; }
.agenda-ket { color: var(--teks-lemah); }
.agenda-lampau { margin: 12px 0; }
.agenda-lampau summary { min-height: 44px; display: flex; align-items: center; }

/* --- corong pribadi: rencana -> berjalan -> dibayar (SPEC-rev2 §52) -------- */

/* TIGA TAHAP MENDATAR di layar lebar, MENURUN di HP.
   Bukan sekadar selera: anak panah antar-tahap yang dipaksa mendatar pada
   375px menyisakan ~100px per tahap, dan "Rp 1.680.000" tidak muat di
   dalamnya tanpa pecah baris — yaitu §13.1, aturan yang paling sering bocor
   justru di tempat yang tidak punya wadah sendiri. Di bawah 560px anak
   panahnya diputar menjadi menurun. */
.corong-bayar {
  display: flex; align-items: stretch; gap: 6px; flex-wrap: nowrap;
  margin: 8px 0 4px;
}
.corong-tahap {
  flex: 1 1 0; min-width: 0;
  padding: 8px 10px; border-radius: 10px;
  background: var(--latar); border: 1px solid var(--garis);
}
/* Tahap terakhir DIBEDAKAN GARIS TEPI, bukan hanya rona (§13.8, §17.3).
   Ia satu-satunya tahap yang angkanya rupiah dan satu-satunya yang datanya
   dipinjam dari aplikasi lain; keduanya alasan yang cukup untuk membuatnya
   terbaca berbeda di kertas fotokopi juga. */
.corong-bayar-akhir {
  border-color: var(--baik);
  box-shadow: inset 3px 0 0 var(--baik);
}
.corong-angka {
  font-size: 1.05rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
  /* Nominal tidak pernah pecah baris (§13.1). Di sini wadahnya sempit dan
     isinya rupiah, jadi aturannya dipasang pada wadahnya sendiri. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.corong-nama {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .03em;
  color: var(--teks-lemah); font-weight: 600;
}
.corong-panah {
  align-self: center; color: var(--teks-lemah); flex: 0 0 auto;
  font-size: 1rem; line-height: 1;
}

@media (max-width: 560px) {
  .corong-bayar { flex-direction: column; }
  .corong-panah { transform: rotate(90deg); align-self: center; }
}

/* --- kalender: keadaan pembayaran pada baris agenda & panel hari ---------- */

/* Penanda kecil di dalam kalimat, bukan lencana penuh: ia mendampingi nama
   penugasan, dan lencana sebesar nama akan mengambil alih barisnya.
   Ketiganya dibedakan RONA DAN GARIS TEPI sekaligus — rona saja hilang di
   fotokopi, dan halaman kalender ikut dicetak (§17.3). */
.tanda-bayar {
  display: inline-block; border: 1px solid currentColor; border-radius: 999px;
  padding: 0 6px; font-size: .68rem; line-height: 1.6; white-space: nowrap;
  vertical-align: baseline;
}
.tanda-bayar.sudah    { color: var(--baik); }
.tanda-bayar.diproses { color: var(--hati); border-style: dashed; }
.tanda-bayar.belum    { color: var(--teks-lemah); border-style: dotted; }

/* --- penjelas terlipat "Kenapa?" (tahap 4, RANCANGAN-UI-UX §4.4) ---------- */

/* Latar aturan di bawah kolom formulir, dilipat. Ringan dengan sengaja: ia
   bukan kendali utama, dan kotak berbingkai di bawah setiap kolom akan
   membuat formulirnya terbaca sebagai tumpukan kartu. Ringkasannya tetap
   bersasaran sentuh 44px dari aturan `summary` di kepala berkas; yang dipakai
   hanya selebar teksnya, jadi ia tidak memanjang menjadi baris yang bisa
   tertekan tanpa sengaja. */
.kenapa { margin: -2px 0 8px; }
.kenapa > summary {
  display: inline-flex; align-items: center; cursor: pointer;
  min-width: 44px; padding: 0 4px;
  color: var(--aksen); font-size: .8rem; font-weight: 600;
}
.kenapa > div { padding: 2px 0 4px; }
.kenapa > div p { margin: 0 0 6px; }

/* --- kalender: penjelasan arti warna (SPEC-rev2 §52.6) -------------------- */

/* Penjelasan yang bisa DITUTUP, bukan paragraf tetap.
   Kalimat §37.4 selama ini berdiri sebagai satu blok `catatan` di bawah
   kalender dan tetap tidak terbaca — pemilik melaporkan orang masih bingung.
   Yang berubah bukan panjangnya melainkan TEMPATNYA: ia naik ke sebelah
   kuncinya, tempat pertanyaannya muncul. */
.kal-jelas {
  margin: 8px 0 4px; border: 1px solid var(--garis); border-radius: 10px;
  background: var(--latar-2); padding: 0;
}
.kal-jelas > summary {
  cursor: pointer; padding: 8px 12px; font-size: .82rem; font-weight: 600;
  /* Sasaran sentuh 44px (§13.9) — summary bawaan peramban hanya setinggi
     barisnya, dan ia satu-satunya kendali di blok ini. */
  min-height: 44px; display: flex; align-items: center;
}
.kal-jelas > div { padding: 0 12px 10px; }
.kal-jelas dl { margin: 0; }
.kal-jelas dt {
  display: flex; align-items: center; gap: 8px;
  font-weight: 600; font-size: .82rem; margin-top: 8px;
}
.kal-jelas dd {
  margin: 2px 0 0 0; color: var(--teks-lemah); font-size: .78rem;
}

/* Contoh di dalam penjelasan memakai TANDA YANG SAMA PERSIS dengan yang ada di
   kalendernya. Kunci yang menggambarkan tanda yang tidak ada di layar adalah
   kunci yang menyesatkan — pelajaran yang sudah ditulis untuk .kal-contoh-libur
   dan berlaku lagi di sini. */
.kal-jelas .kunci-kotak { flex: 0 0 auto; }

/* Tabel penugasan di resume orang: EMPAT kolom pada 375px sesudah §52
   (Penugasan, Hari, Nilai, Dibayar). Terukur: dengan lapik baku 8px 10px ia
   365px di wadah 347px, sehingga tepi kanan kolom Dibayar terpotong — dan
   kolom itu justru yang baru ditambahkan. Lapiknya dipersempit HANYA pada
   tabel ini dan HANYA di layar sempit; mempersempit `td` global akan
   memindahkan keputusan ini ke belasan tabel yang tidak memintanya. */
@media (max-width: 560px) {
  .tabel-orang th, .tabel-orang td { padding-left: 5px; padding-right: 5px; }
}

/* Tanggal PASTI yang dibayar (SPEC-rev2 §53): CENTANG, bukan balok dan bukan
   rona.

   §52.7 melarang memberi rona pembayaran di petak bulanan, dan alasannya tetap
   berlaku utuh: rona sepanjang rentang menyatakan setiap hari di dalamnya
   dibayar. Yang berubah bukan aturannya melainkan BAHANNYA — sejak §53 SPJ
   mengirim tanggalnya satu per satu, jadi yang ditandai HARI ITU SENDIRI.

   Bentuknya centang karena ketiga kosakata lain sudah terpakai dan masing-masing
   punya alasannya: balok = rentang, bulatan = catatan pribadi (§40.3), garis
   tepi = hari libur. Centang juga satu-satunya di antara keempatnya yang
   terbaca tanpa rona sama sekali — dan halaman ini ikut dicetak (§17.3). */
.kal-bayar {
  color: var(--baik); font-weight: 700; margin-left: 3px;
  /* Tidak boleh memperlebar sel: petaknya minmax(0,1fr) dan satu aksara yang
     ikut menghitung lebar akan memeras kolom lain (pelajaran .kal-bulan). */
  font-size: .78rem; line-height: 1;
}

/* Di dalam kunci dan penjelasan, centangnya diberi kotak sepadan dengan
   `.kunci-kotak` supaya barisnya sejajar dengan butir lain. */
.peta-kunci .kal-bayar, .kal-jelas .kal-bayar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; margin-left: 0;
}

/* --- FAKTOR KEDUA (SPEC-rev2 §57.9) --------------------------------------
 *
 * Seluruhnya memakai token; tidak ada satu pun nilai warna literal di sini.
 * Yang perlu diingat saat menambah warna di blok ini: rasionya diukur terhadap
 * `--latar` (meja), BUKAN hanya terhadap `--lembar` — meja lebih gelap, dan di
 * situlah token pertama gagal saat sapuan kontras 24 Agustus 2026.
 */

/* Kotak enam angka. SATU kotak, bukan enam (lihat catatan di index.html):
 * enam kotak terpisah mematikan tempel dan pengisian otomatis `one-time-code`.
 * Jaraknya yang dilebarkan, bukan kotaknya yang dipecah. */
.kotak-kode {
  font-family: var(--angka);
  font-size: var(--uk-angka-besar);
  letter-spacing: .4em;
  /* Padding kiri mengimbangi `letter-spacing`, yang menambahkan jarak SESUDAH
   * aksara terakhir juga — tanpa ini angkanya terlihat miring ke kiri. */
  text-align: center;
  padding-left: .4em;
  min-height: var(--sentuh);
}

/* Langkah pendaftaran. Nomornya bawaan <ol>; yang diatur hanya jaraknya. */
.langkah-2fa { margin: var(--sela-3) 0 0; padding-left: var(--sela-5); }
.langkah-2fa > li { margin-bottom: var(--sela-5); }
.langkah-2fa > li::marker { color: var(--teks-lemah); font-weight: 700; }

/* QR. Lebarnya dibatasi supaya ia tidak memenuhi layar HP — pemindai butuh
 * simbol yang UTUH dalam bingkainya, dan simbol selebar layar justru menuntut
 * orang menjauhkan HP-nya. Latarnya putih apa adanya (dari SVG-nya sendiri),
 * jadi kotaknya diberi tepi supaya ia tidak melayang di atas kertas terang. */
.qr-2fa {
  margin: var(--sela-3) 0;
  max-width: 260px;
  border: 1px solid var(--garis);
  border-radius: var(--bulat);
  overflow: hidden;
  line-height: 0;
}
.qr-2fa svg { width: 100%; height: auto; display: block; }

/* Kunci manual. Dipecah empat-empat oleh app.js; di sini hanya dibuat mudah
 * dibaca dan mudah disorot. `user-select: all` supaya satu ketukan menyorot
 * seluruhnya — menyorot 32 aksara base32 dengan jempol nyaris mustahil. */
.kunci-2fa {
  background: var(--sel);
  border: 1px solid var(--garis-halus);
  border-radius: var(--bulat);
  padding: var(--pad-isian);
  margin: var(--sela-2) 0;
  font-size: var(--uk-kecil);
  letter-spacing: .08em;
  /* PERKECUALIAN BERTANDA atas `nowrap` milik `.mono`: yang ini BUKAN kode
     yang dibandingkan dengan dokumen lain, melainkan rahasia 32 aksara yang
     disalin ke aplikasi autentikator. Ia memang harus melipat — `nowrap` di
     sini melebarkan halaman melewati 320px, dan gulir mendatar pada layar
     pendaftaran faktor kedua adalah tempat paling buruk untuk menemukannya. */
  white-space: normal;
  word-break: break-all;
  user-select: all;
}

/* Sepuluh kode pemulihan, dicetak sekali. Dua lajur di layar lebar, satu di HP.
 * `user-select: all` per kode: yang menyalinnya satu per satu ke kertas justru
 * tidak boleh keliru satu aksara. */
.daftar-kode {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sela-2);
  margin: var(--sela-4) 0;
}
.daftar-kode span {
  background: var(--sel);
  border: 1px solid var(--garis-halus);
  border-radius: var(--bulat);
  padding: var(--pad-isian);
  text-align: center;
  font-size: var(--uk-badan);
  letter-spacing: .06em;
  user-select: all;
}

/* Halaman kode pemulihan ikut dicetak (tombol Cetak di kartunya). Saat dicetak,
 * yang tersisa harus kodenya — bukan bilah navigasi dan bukan tombolnya. Aturan
 * cetak umum di §17.3 sudah menyembunyikan tombol; ini hanya memastikan kisinya
 * tidak terpotong di tengah kode. */
@media print {
  .daftar-kode { grid-template-columns: repeat(2, 1fr); }
  .daftar-kode span { break-inside: avoid; }
}

/* --- RIWAYAT AKUN SENDIRI (SPEC-rev2 §59) --------------------------------
 *
 * Kolom waktu tidak boleh pecah baris. "24 Agu 2026, 11.04" yang terbelah dua
 * baris membuat tabel dua kolom terlihat seperti tabel empat baris, dan pada
 * 375px itu satu-satunya kolom yang lebarnya bisa diprediksi. Sepola dengan
 * aturan nominal §13.2 — hanya bahannya yang berbeda.
 */
.nowrap { white-space: nowrap; }

/* ===========================================================================
   PUSTAKA GRAFIK — SPEC-rev2 §69, rancangan monitoring §6 & §6B
   ===========================================================================

   SELURUH WARNA DI SINI DATANG DARI TOKEN, dan itu satu-satunya sebab grafik
   ini lolos dua tema tanpa satu baris pun kode tema: `public/js/grafik.js`
   tidak pernah menulis warna, ia hanya menulis KELAS. Yang berubah antara
   terang dan gelap adalah nilai tokennya, bukan markupnya.

   TIDAK ADA SATU PUN `fill`/`stroke` YANG DISETEL PADA KELAS YANG JUGA DIPAKAI
   ELEMEN BER-ATRIBUT `fill`. CSS mengalahkan atribut presentasi SVG: satu
   aturan `.g-belum { fill: … }` akan menimpa `fill="url(#…-arsir)"` pada
   rect-nya dan menghapus seluruh arsir "belum bisa dihitung" tanpa galat.
   Karena itu aturan chip di bawah SELALU berpagar `.g-chip`.
   ------------------------------------------------------------------------ */

:root {
  /* Rencana = langkah TERANG dari rona aksen (validator dataviz 24 Agu 2026).
     Kontrasnya terhadap lembar 2,38:1 — WARN, diterima hanya karena grafik.js
     wajib menulis label nilai langsung di batangnya. Jangan pakai token ini
     untuk TEKS. */
  --seri-rencana: #93a5d6;
  --seri-lainnya: #8b93a4;
}

:root[data-tema="gelap"] {
  /* Di tema gelap langkah "terang" justru harus lebih GELAP dari --aksen
     (#8aa3ec): terang di sini berarti dekat ke latar, bukan dekat ke putih.
     #5570b5 memberi 3,48:1 di atas --lembar — lolos ambang 3:1 untuk objek
     grafis, sementara jarak dua langkahnya tetap 1,96:1 seperti di tema
     terang, yaitu WARN yang sama dan syarat label yang sama. */
  --seri-rencana: #5570b5;
  --seri-lainnya: #9aa1ad;
}

/* --- kartu & kepala ------------------------------------------------------- */

.g-kartu {
  margin: 0;
  padding: 14px 18px;
  background: var(--lembar);
  border: 1px solid var(--garis);
  border-radius: 3px;
}

.g-kepala {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
}

.g-judul {
  font-size: var(--uk-pita);
  font-weight: var(--berat-tebal);
  letter-spacing: var(--renggang-pita);
  text-transform: uppercase;
  color: var(--tinta);
}

/* SELURUH TEKS DI KARTU GRAFIK MEMAKAI --teks-lemah, tidak ada yang lebih
   pudar dari itu. Diukur di peramban 25 Agu 2026: --teks-samar memberi 3,01:1
   di atas --lembar tema terang — gagal AA untuk teks kecil. Di tempat lain ia
   benar karena yang ditulisnya memang keterangan sampingan; DI SINI tidak ada
   teks hiasan. Angka sumbu adalah data, kalimat asal-usul adalah syarat §13.1,
   dan kalimat "belum bisa dihitung" adalah §7.1 itu sendiri. */
.g-catatan { font-size: var(--uk-mikro); color: var(--teks-lemah); margin-top: 6px; }
.g-belum-teks { font-size: var(--uk-mikro); color: var(--teks-lemah); }
.g-asal { font-size: var(--uk-mikro); color: var(--teks-lemah); margin-top: 6px; }
.g-padanan { font-size: var(--uk-mikro); display: inline-block; margin-top: 4px; }

/* --- legenda: chip + NAMA, tidak pernah warna saja ------------------------ */

.g-legenda { display: flex; flex-wrap: wrap; list-style: none; margin: 0; padding: 0; gap: 0 16px; }

/* 44px — sasaran sentuh, aturan yang sama dengan tinggi sasaran sentuh di
   berkas ini. Legenda grafik kelak bisa diketuk untuk menyaring; tingginya
   ditetapkan sekarang supaya tata letaknya tidak berubah saat itu terjadi. */
.g-legenda-butir {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  font-size: var(--uk-mikro);
  color: var(--teks-lemah);
}

.g-chip { width: 11px; height: 11px; flex: 0 0 auto; border-radius: 2px; display: inline-block; }
.g-chip.g-rencana   { background: var(--seri-rencana); }
.g-chip.g-realisasi { background: var(--aksen); }
.g-chip.g-unit-1    { background: var(--unit-1); }
.g-chip.g-unit-2    { background: var(--unit-2); }
.g-chip.g-unit-3    { background: var(--unit-3); }
.g-chip.g-unit-4    { background: var(--unit-4); }
.g-chip.g-unit-5    { background: var(--unit-5); }
.g-chip.g-lainnya   { background: var(--seri-lainnya); }
.g-chip.g-netral    { background: var(--garis); }
.g-chip.g-belum {
  background: repeating-linear-gradient(45deg,
    var(--lembar) 0 2px, var(--teks-samar) 2px 4px);
  border: 1px solid var(--garis);
}

.g-legenda-nama { color: var(--teks); }

/* BARIS LEGENDA SEBAGAI PINTU (§77.5). Tombolnya MENGISI barisnya, bukan
   berdiri di dalamnya: sasaran sentuh yang lebih kecil daripada baris yang
   terlihat bisa ditekan adalah baris yang gagal ditekan tanpa sebab yang
   kelihatan. Gaya tombol bawaan peramban dilucuti — legenda yang tiba-tiba
   bertepi dan berlatar abu terbaca sebagai kerusakan, bukan sebagai kendali. */
.g-legenda-btn {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 6px; margin: 0 -6px;
  border: 0; background: none; font: inherit; color: inherit;
  border-radius: 6px; cursor: pointer; text-align: left;
}
.g-legenda-btn:hover { background: var(--latar-3); }
.g-legenda-btn:hover .g-legenda-nama { color: var(--aksen); }
.g-legenda-nilai { font-variant-numeric: var(--angka); white-space: nowrap; color: var(--teks-lemah); }

/* --- kanvas SVG ----------------------------------------------------------- */

/* Lebar 100% + viewBox = luwes tanpa satu perhitungan JS pun. Inilah sebab
   grafik.js tidak butuh CSSOM untuk SVG-nya. */
.g-svg { display: block; width: 100%; height: auto; margin: 4px 0; }
.g-svg-donat { max-width: 480px; margin-inline: auto; }
.g-svg text { font-family: var(--font-inti); font-variant-numeric: var(--angka); }

/* UKURAN HURUF DI DALAM SVG ADALAH UKURAN TERBITNYA (SPEC-rev2 §72.2), sebab
   `.g-svg` di bawah menahan lebar minimum sebesar viewBox-nya dan skalanya
   karena itu tidak pernah turun di bawah 1,0. Sebelum aturan itu ada, angka di
   sini adalah angka SEBELUM diskalakan: 10px pada bidang 977px untuk viewBox
   1170 terbit sebagai 8,4px — di bawah `--uk-mikro` (11,5px), yaitu di bawah
   teks terkecil yang aplikasi ini akui masih terbaca.

   Angka-angka ini DICERMINKAN di `UK` pada grafik.js, yang memakainya untuk
   menghitung apakah dua label bertindih. Keduanya diuji sepadan: ukuran yang
   bergeser sendiri di salah satu sisi menghasilkan tata letak yang dihitung
   dengan ukuran yang bukan ukuran yang tergambar. */
.g-sumbu { stroke: var(--garis); stroke-width: 1; }
.g-kisi  { stroke: var(--garis-halus); stroke-width: 1; }
.g-skala { fill: var(--teks-lemah); font-size: 11.5px; }
.g-sumbu-label { fill: var(--teks-lemah); font-size: 12px; }

/* isian batang — dua langkah satu rona */
rect.g-rencana   { fill: var(--seri-rencana); }
rect.g-realisasi { fill: var(--aksen); }

/* nol SUNGGUHAN: garis setebal 3 di dasar, bukan ketiadaan */
line.g-nol-rencana   { stroke: var(--seri-rencana); }
line.g-nol-realisasi { stroke: var(--aksen); }

/* LABEL NILAI — syarat keras rancangan §6B, bukan hiasan. Sejak §72.1 ia
   berdiri di DUA BARIS TETAP di atas bidang gambar, bukan menempel di puncak
   batangnya: dua label rupiah pada dua batang yang berjarak 26 satuan mustahil
   tidak bertindih, dan bertindih persis membatalkan sebab label itu ada. */
.g-nilai-rencana   { fill: var(--teks-lemah); font-size: 12px; }
.g-nilai-realisasi { fill: var(--aksen); font-size: 12px; font-weight: 700; }
/* "—" MEMAKAI WARNA TEKS BIASA, bukan --teks-kosong.
   Diukur di peramban 25 Agu 2026: --teks-kosong memberi 2,52:1 di atas
   --lembar tema gelap — gagal AA. Di tempat lain token itu benar, karena di
   sana ia menandai sel yang memang kosong. DI SINI ia menyampaikan pernyataan
   terpenting seluruh pustaka ini — "belum bisa dihitung" — dan pernyataan itu
   tidak boleh lebih pudar daripada angka di sebelahnya. Yang membedakannya
   dari sebuah nilai adalah ARSIRNYA, bukan pudarnya. */
.g-nilai-belum     { fill: var(--teks-lemah); font-size: 12px; }

/* arsir "belum bisa dihitung" — pola, bukan warna */
.g-arsir-latar { fill: var(--lembar); }
/* 3,01:1 di tema terang dan 4,32:1 di gelap — arsir yang lebih pudar dari itu
   terbaca sebagai kotak kosong, bukan sebagai pola. */
.g-arsir-garis { stroke: var(--teks-samar); }

/* --- kurva kumulatif ------------------------------------------------------ */

.g-garis-rencana   { stroke: var(--seri-rencana); }
.g-garis-realisasi { stroke: var(--aksen); }
.g-titik-rencana   { fill: var(--seri-rencana); stroke: var(--lembar); stroke-width: 1.5; }
.g-titik-realisasi { fill: var(--aksen); stroke: var(--lembar); stroke-width: 1.5; }

/* DEVIASI NETRAL. Mockup menggambarnya merah; prinsip §2.3 rancangan menang:
   penyimpangan rencana bukan temuan, dan yang merah hanya yang P1-P8
   nyatakan temuan. Merah di sini akan membuat setiap awal tahun terlihat
   seperti pelanggaran. */
.g-deviasi-garis { stroke: var(--teks-samar); }
.g-deviasi-teks  { fill: var(--teks-lemah); font-size: 12px; }

/* --- donat ---------------------------------------------------------------- */

path.g-isi-rencana   { fill: var(--seri-rencana); }
path.g-isi-realisasi { fill: var(--aksen); }
path.g-isi-unit-1    { fill: var(--unit-1); }
path.g-isi-unit-2    { fill: var(--unit-2); }
path.g-isi-unit-3    { fill: var(--unit-3); }
path.g-isi-unit-4    { fill: var(--unit-4); }
path.g-isi-unit-5    { fill: var(--unit-5); }
path.g-isi-lainnya   { fill: var(--seri-lainnya); }
path.g-isi-netral    { fill: var(--garis); }

circle.g-cincin-rencana   { stroke: var(--seri-rencana); }
circle.g-cincin-realisasi { stroke: var(--aksen); }
circle.g-cincin-unit-1    { stroke: var(--unit-1); }
circle.g-cincin-unit-2    { stroke: var(--unit-2); }
circle.g-cincin-unit-3    { stroke: var(--unit-3); }
circle.g-cincin-unit-4    { stroke: var(--unit-4); }
circle.g-cincin-unit-5    { stroke: var(--unit-5); }
circle.g-cincin-lainnya   { stroke: var(--seri-lainnya); }
circle.g-cincin-netral    { stroke: var(--garis); }
circle.g-cincin-kosong    { stroke: var(--garis-halus); }

.g-label-luar  { fill: var(--teks-lemah); font-size: 12px; }
.g-pusat-angka {
  fill: var(--tinta);
  font-family: var(--font-tampilan);
  font-weight: var(--berat-tampilan);
  font-size: 26px;
  letter-spacing: var(--renggang-angka);
}
.g-pusat-label { fill: var(--teks-lemah); font-size: 12px; }

/* --- kartu KPI ------------------------------------------------------------ */

.g-papan { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }

.g-kpi {
  background: var(--lembar);
  border: 1px solid var(--garis);
  border-radius: 3px;
  padding: 12px 16px;
}
/* Penghematan adalah CAPAIAN, bukan kegagalan (rancangan §2.2) — satu-satunya
   tempat warna status boleh memimpin sebuah kartu, dan ia dinyatakan sadar
   oleh pemanggil lewat `nada`, tidak pernah disimpulkan grafiknya sendiri. */
.g-kpi--baik  { border-color: var(--baik);  background: var(--latar-baik); }
.g-kpi--hati  { border-color: var(--hati);  background: var(--latar-hati); }
.g-kpi--buruk { border-color: var(--buruk); background: var(--latar-buruk); }

.g-kpi-label {
  font-size: var(--uk-label);
  letter-spacing: var(--renggang-label);
  text-transform: uppercase;
  font-weight: var(--berat-lencana);
  color: var(--teks-lemah);
}
.g-kpi--baik  .g-kpi-label { color: var(--baik); }
.g-kpi--hati  .g-kpi-label { color: var(--hati); }
.g-kpi--buruk .g-kpi-label { color: var(--buruk); }

.g-kpi-nilai {
  font-family: var(--font-tampilan);
  font-weight: var(--berat-tampilan);
  font-size: var(--uk-angka-besar);
  letter-spacing: var(--renggang-angka);
  color: var(--tinta);
  font-variant-numeric: var(--angka);
  white-space: nowrap;      /* nominal tidak pernah pecah baris */
}
.g-kpi--baik  .g-kpi-nilai { color: var(--baik); }
.g-kpi--buruk .g-kpi-nilai { color: var(--buruk); }
/* Nilai yang BELUM ADA diredupkan SATU langkah, tidak lebih.
   Sepola .g-nilai-belum dan dengan alasan yang sama: --teks-kosong memberi
   1,92:1 di atas --lembar tema terang, dan pada 29px sebuah "—" seterang itu
   terbaca sebagai kerusakan penggambaran, bukan sebagai pernyataan. Yang
   membedakannya dari sebuah angka adalah LABEL DI BAWAHNYA, bukan pudarnya. */
.g-kpi-nilai.g-kosong { color: var(--teks-lemah); }

.g-kpi-satuan {
  font-family: var(--font-inti);
  font-size: var(--uk-kecil);
  font-weight: 400;
  color: var(--teks-lemah);
  margin-left: 4px;
}

.g-kpi-delta { font-size: var(--uk-mikro); color: var(--teks-lemah); }
.g-kpi-panah { color: var(--teks-lemah); }
.g-kpi--baik  .g-kpi-delta, .g-kpi--baik  .g-kpi-panah { color: var(--baik); }
.g-kpi--hati  .g-kpi-delta, .g-kpi--hati  .g-kpi-panah { color: var(--hati); }
.g-kpi--buruk .g-kpi-delta, .g-kpi--buruk .g-kpi-panah { color: var(--buruk); }

.g-kpi-catatan, .g-kpi-batang-teks { font-size: var(--uk-mikro); color: var(--teks-lemah); }

/* Isian batang KPI. Selektornya menyertakan `.batang > i` dengan sengaja:
   aturan lama `.batang > i { background: var(--aksen) }` lebih spesifik
   daripada satu kelas, dan tanpa pagar ini seluruh nada di bawah kalah. */
.batang > i.g-nada-baik   { background: var(--baik); }
.batang > i.g-nada-hati   { background: var(--hati); }
.batang > i.g-nada-buruk  { background: var(--buruk); }
.batang > i.g-nada-netral { background: var(--aksen); }

/* `min-width: 0` BUKAN kerapian. Butir grid bawaannya tidak boleh menyusut di
   bawah lebar min-content isinya, dan sejak grafik menahan lebar minimumnya
   sendiri (§72.2) lebar itu 480–940px. Tanpa baris ini butirnya melebar
   sampai 517px di layar 375px dan yang menggulir HALAMANNYA, bukan bidang
   grafiknya — persis cacat yang `.g-bidang` ada untuk mencegahnya. */
.g-tumpuk { display: grid; gap: 12px; }
.g-tumpuk > * { min-width: 0; }

/* Kelompok bulan dan potong donat membawa `<title>`-nya sendiri sebagai
   tooltip. Kursor tanya adalah satu-satunya petunjuk bahwa ada yang bisa
   dibaca di sana — tanpanya tooltip itu hanya ditemukan tidak sengaja. */
.g-kelompok, .g-potong { cursor: help; }

/* Varian per komponen. Dipakai pemanggil untuk menempatkan grafik di tata
   letaknya sendiri, dan dipakai di sini untuk hal yang memang berbeda per
   bentuk: batang dan kurva melebar sepenuh induknya, sementara legenda donat
   berdiri di tengah mengikuti cincinnya. */
.g-batang-bulanan, .g-kurva { width: 100%; }
.g-donat .g-legenda { justify-content: center; }

/* Nada netral: kartu KPI tanpa penilaian. Ditulis terang-terangan supaya
   "tanpa nada" menjadi keadaan yang DIPILIH, bukan keadaan yang terlupakan —
   dan supaya kartu netral tidak diam-diam mewarisi tepi berwarna. */
.g-kpi--netral { border-color: var(--garis); }

/* Penanda asal di bawah grafik BOLEH pecah baris, dan hanya di sini.
   Aturan umum `.asal { white-space: nowrap }` benar untuk lencana pendek
   ("dihitung dari kisi tim") yang berdiri di dalam sel tabel. Kalimat asal
   sebuah grafik lebih panjang — "andaian Rp600rb/malam — bukan angka
   terukur" terukur 264px, dan di dalam kartu KPI selebar 220px ia MENDORONG
   seluruh halaman melebar 12px. Cacat itu hanya terlihat sebagai bilah gulir
   mendatar tipis, yang tidak dilihat siapa pun sampai ia membuka di HP. */
.g-asal .asal { white-space: normal; }
.g-kpi, .g-kartu { min-width: 0; }

/* BIDANG BERGULIR untuk grafik lebar. Dua belas bulan pada viewBox selebar
   1170 yang dipaksa muat di 380px membuat setiap label nilai menjadi 3px —
   yaitu menghapus syarat "label nilai wajib tertulis" tanpa menghapus satu
   baris kode pun. Di layar sempit grafiknya menahan lebar minimumnya dan
   bidang inilah yang bergulir; donat tidak ikut, karena ia memang muat. */
.g-bidang { overflow-x: auto; min-width: 0; }

/* KOREKSI 25 AGUSTUS 2026 (SPEC-rev2 §72.2): AMBANGNYA DICABUT, BUKAN DIGESER.
   Sampai revisi ini min-width hanya berlaku di bawah 760px, dan di atas ambang
   itu tidak ada yang menahan apa pun. Akibatnya terukur di peramban: bidang
   grafik di kartu Beranda 977px pada jendela 1280px dan 1073px pada 1680px,
   untuk viewBox 1170 — skala 0,83 dan 0,92, dan label nilai 10px terbit
   sebagai 8,4px dan 9,2px. Keduanya di bawah `--uk-mikro` (11,5px), yaitu di
   bawah teks terkecil yang aplikasi ini akui masih terbaca. Ambang 760px tidak
   pernah menyentuh kasus itu, dan tidak bisa: lebar JENDELA tidak menentukan
   lebar KARTU yang memuat grafiknya.

   Yang berlaku sekarang tidak berambang. Lebar minimum = lebar viewBox, jadi
   skalanya ≥ 1,0 di setiap wadah, dan setiap ukuran huruf di grafik.js berarti
   persis seperti yang tertulis di sana. viewBox-nya sendiri diperkecil menjadi
   940 supaya kartu Beranda desktop (977px) memuatnya tanpa menggulir sama
   sekali; yang tersisa menggulir hanya wadah yang memang lebih sempit dari itu
   — dan itu memang pola aplikasi ini untuk isi lebar (`.tabel-empat`
   min-width 720px), bukan perkecualian baru.

   Donat ikut, dan itu koreksi tersendiri: ia "muat" di 281px dengan mengecil
   menjadi skala 0,57, sehingga label luarnya terbit 6,3px. Muat bukan
   terbaca. */
.g-batang-bulanan .g-svg, .g-kurva .g-svg { min-width: 940px; }
.g-svg-donat { min-width: 480px; }

/* ==========================================================================
   BERANDA PANTAU (SPEC-rev2 §71)
   ==========================================================================
   Bentuk grafiknya seluruhnya milik `.g-*` di atas; yang lahir di sini hanya
   perabot di sekelilingnya — sakelar dimensi, catatan kaki grafik, corong
   usulan, dan daftar "perlu perhatian". Tidak ada satu warna seri pun di
   bawah ini: warna seri hidup di satu tempat saja (§69.4). */

/* TEMPATNYA DIPESAN SELAGI KOSONG (SPEC-rev2 §80.1).
 *
 * `muatBeranda()` menggambar beranda lama lebih dulu lalu memanggil
 * `muatPantau()` TANPA menunggunya — dan itu benar, lihat alasannya di sana.
 * Akibatnya ruang pantau tiba ±400 ms kemudian dan disisipkan DI ATAS isi yang
 * sudah tergambar, sehingga seluruh halaman terdorong ke bawah tepat saat mata
 * mulai membaca. Terukur di peramban, muat pertama tiap sesi: 4.144 px
 * (Inspektur, 1280px) · 8.428 px (Inspektur, 375px) · 4.662 px (Irban, 1280px)
 * · 10.431 px (Irban, 375px), CLS 0,66–0,76.
 *
 * ANGKANYA SATU LAYAR, DAN ITU DIPILIH DARI HASIL UKUR DI ATAS, BUKAN DIKARANG.
 * Memesan tinggi PENUH mustahil: keempat angkanya berbeda 2,5 kali lipat antar
 * peran dan lebar, dan kartu terbesarnya masih berubah bentuk. Yang menentukan
 * bukan tinggi bloknya melainkan tinggi LAYARNYA — pergeseran yang seluruhnya
 * terjadi di bawah lipatan tidak pernah dilihat siapa pun, dan memang tidak
 * dihitung CLS. Karena blok sungguhannya SELALU lebih tinggi daripada satu
 * layar (yang terpendek 4.144 px pada layar 900 px, yaitu 4,6 kali), satu layar
 * tidak pernah menjadi pemesanan yang KELEBIHAN — jadi tidak ada lubang kosong
 * yang tersisa saat isinya tiba, hanya sisa tinggi yang tumbuh ke bawah.
 *
 * `:empty` yang MELEPASKANNYA, bukan JavaScript: begitu `ruangPantau()`
 * menempel, pemesanannya batal pada putaran gambar yang sama. Dan `.pt-memesan`
 * yang MEMASANGNYA, sebab wadah ini juga dikosongkan untuk beranda pegawai
 * (§4.3) yang memang tidak pernah menggambar ruang pantau — tanpa kelas itu
 * mereka mendapat satu layar kosong yang tidak menunggu apa pun. Kelasnya
 * dicabut `muatBeranda()` begitu `muatPantau()` selesai, termasuk saat ia
 * pulang diam-diam karena rutenya gagal.
 *
 * Isinya SENGAJA tidak ada — bukan `0`, bukan `Rp 0`, bukan angka contoh, dan
 * bukan pula tulisan yang bisa dibaca sebagai data. Yang belum dihitung bukan
 * nol, dan aturan itu berlaku pada penampungnya juga. */
#beranda-pantau.pt-memesan:empty { min-height: 100vh; min-height: 100svh; }

/* Sakelar dimensi & bentuk. Tinggi 44px TANPA perkecualian (§13.9): ini
   kendali yang paling sering diketuk di seluruh aplikasi — tiga dimensi kali
   dua bentuk, dari HP, sambil berdiri. Bilahnya bergulir mendatar SENDIRI
   supaya halamannya tidak; `mask-image` sepola `.tab` menandakan ada lagi di
   kanan tanpa menuntut dua nilai untuk dua tema. */
.pt-sakelar-baris {
  display: flex; flex-wrap: wrap; gap: 8px 24px; align-items: flex-end;
  margin: 4px 0 12px;
}

/* DUA KELOMPOK YANG BERBEDA PEKERJAANNYA, DAN MATA HARUS MELIHATNYA (§75.4).
 *
 * Keluhan pemiliknya, 25 Agustus 2026: "filternya dan tombolnya kan ada 2 jenis
 * apakah tidak diberikan jarak untuk pilihannya berbeda satu memilih isi data
 * dan satu memilih bentuk datanya."
 *
 * `role="group"` sudah ada sejak §71 — tetapi ia hanya terdengar oleh pembaca
 * layar. Yang terlihat adalah lima tombol berjarak sama, dan jarak yang sama
 * berarti satu daftar. Karena itu jarak ANTAR kelompok (24px) dibuat empat kali
 * jarak DI DALAM kelompok (6px), dan tiap kelompok diberi judul yang tertulis —
 * bukan hanya `aria-label`. Angkanya bukan selera: di bawah 16px dua kelompok
 * masih terbaca sebagai satu deret, dan 6px adalah jarak antar tombol sekelompok
 * yang sudah dipakai sejak §71. */
.pt-set { display: flex; flex-direction: column; gap: 3px; min-width: 0; max-width: 100%; }
.pt-set-judul {
  font-size: var(--uk-label); letter-spacing: var(--renggang-label);
  text-transform: uppercase; font-weight: var(--berat-lencana);
  color: var(--teks-lemah);
}
.pt-set-dasar { margin: 2px 0 10px; }

.pt-kelompok {
  display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px;
  mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
  max-width: 100%;
}
@media (min-width: 700px) { .pt-kelompok { mask-image: none; } }
.pt-sakelar {
  white-space: nowrap; min-height: 44px; padding: 7px 14px;
}
.pt-sakelar.aktif {
  background: var(--aksen); color: var(--aksen-teks);
  border-color: var(--aksen); font-weight: 600;
}
.pt-saring { display: flex; align-items: center; gap: 6px; }
.pt-saring select { min-height: 44px; }

/* Catatan kaki grafik. Ia BUKAN hiasan — di dalamnya berdiri cakupan dua
   sumber bulan (§70.2), ketidaklengkapan sebuah total (§70.3), keranjang
   "tanpa bulan", dan ketiga seri rencana berdampingan (§70.4). Karena itu
   warnanya `--teks-lemah`, bukan yang lebih pudar: pada tema terang
   `--teks-samar` hanya 3,01:1 dan `--teks-kosong` 1,92:1, dan kalimat yang
   menjaga sebuah angka tidak boleh lebih sulit dibaca daripada angkanya. */
.pt-catatan {
  margin: 0; padding-left: 18px;
  font-size: var(--uk-mikro); color: var(--teks-lemah);
}
.pt-catatan li { margin: 2px 0; }

/* Corong usulan — satu baris visual (rancangan §4.2). Ia daftar berurut,
   bukan tabel: tiap tahap adalah BAGIAN dari tahap sebelumnya. */
.pt-corong {
  display: flex; flex-wrap: wrap; gap: 10px; list-style: none; margin: 8px 0 4px; padding: 0;
  counter-reset: none;
}
.pt-corong > li {
  flex: 1 1 130px; min-width: 0;
  border: 1px solid var(--garis); border-radius: 8px; padding: 8px 10px;
  background: var(--latar);
}
.pt-corong-angka {
  display: block; font-family: var(--font-tampilan);
  font-size: var(--uk-angka); font-weight: var(--berat-tampilan);
  letter-spacing: var(--renggang-angka);
  font-variant-numeric: var(--angka); white-space: nowrap;
}
.pt-corong-nama { display: block; font-size: var(--uk-kecil); color: var(--teks); }

/* Daftar "perlu perhatian". Angka di kiri, kalimat di kanan — dan angkanya
   `—` bila prasyaratnya mati, tidak pernah `0` berwarna hijau (§7.1). */
.pt-awas-daftar { list-style: none; margin: 8px 0 4px; padding: 0; }
.pt-awas {
  display: flex; gap: 12px; align-items: baseline;
  padding: 8px 0; border-bottom: 1px solid var(--garis-halus);
}
.pt-awas:last-child { border-bottom: 0; }
.pt-awas-angka {
  flex: 0 0 auto; min-width: 46px; text-align: right;
  font-variant-numeric: var(--angka); white-space: nowrap;
  font-size: var(--uk-angka); font-weight: var(--berat-tampilan);
  font-family: var(--font-tampilan); letter-spacing: var(--renggang-angka);
}
.pt-awas-teks { flex: 1 1 auto; min-width: 0; font-size: var(--uk-kecil); }

/* Kartu penghematan: satu-satunya kartu bernada di ruang pantau, dan nadanya
   CAPAIAN (rancangan §2.2). Tepinya hijau; isinya tidak diwarnai, supaya
   kalimat andai-andainya tetap terbaca sebagai keterangan. */
.kartu-hemat { border-color: var(--baik); }

/* ── SATU BARIS KPI, BUKAN EMPAT DITAMBAH SATU (§75.3) ─────────────────────
 *
 * Keluhan pemiliknya: "usulan menunggu keputusan itu … sayang sekali hanya dia
 * sendiri kenapa tidak dinaikkan saja sekalian yang lainnya ke atas?".
 *
 * Kelima kartu memang sudah satu `.g-papan`; yang memisahkan yang kelima adalah
 * `auto-fit, minmax(220px, 1fr)` — pada lebar meja ia memuat empat kolom dan
 * melempar sisanya ke baris kedua sendirian. `auto-fit` tidak bisa diberi tahu
 * "muatkan semuanya", jadi jumlah kartunya yang diberitahukan, lewat
 * `data-kartu` dari `papanKpi()`. Tidak ada `style=` di mana pun (§11.2).
 *
 * Ambangnya 1000px, bukan 700px: lima kolom pada 760px memberi 136px per kartu,
 * dan "Rp411,23 jt" pada `--uk-angka-besar` tidak muat di sana — memaksanya
 * satu baris hanya menukar satu kartu terlempar dengan lima angka terpotong.
 * Di bawah ambang itu `auto-fit` bawaan tetap yang bekerja, dan pada HP kelima
 * kartunya memang bertumpuk satu kolom seperti sebelumnya. */
@media (min-width: 1000px) {
  .pt-papan[data-kartu="5"] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .pt-papan[data-kartu="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .pt-papan[data-kartu="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Kartu KPI yang menjadi PINTU (§75.1). Ia `<button>` sekarang, jadi bawaan
   tombol (latar, tepi, sudut, padding) harus mundur ke `.g-kpi` — kalau tidak
   yang tergambar adalah kartu di dalam kartu. Tanda panah `›` datang dari
   `.kartu-buka`, dan labelnya diberi ruang supaya tidak tertimpa. */
.pt-papan .kartu-buka.g-kpi {
  padding: 12px 16px; border-radius: 3px; background: var(--lembar);
}
.pt-papan .kartu-buka.g-kpi--baik  { background: var(--latar-baik); }
.pt-papan .kartu-buka.g-kpi--hati  { background: var(--latar-hati); }
.pt-papan .kartu-buka.g-kpi--buruk { background: var(--latar-buruk); }
.pt-papan .kartu-buka .g-kpi-label { padding-right: 18px; }

/* ── P1–P8 SEBAGAI DELAPAN KARTU TERPISAH (§75.9) ──────────────────────────
   Sebelumnya satu daftar dengan SATU tombol di bawahnya, sehingga yang menekan
   "P5: 41" mendarat di papan berisi delapan pemeriksaan dan mencari P5 lagi.
   Sekarang tiap kartu menaut ke sub-tabnya sendiri. */
.pt-p-papan {
  display: grid; gap: 10px; margin-top: 8px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.pt-p-papan > .pt-p { margin: 0; }
.pt-p .angka-besar { margin: 2px 0; }
.pt-p .angka-besar.baik  { color: var(--baik); }
.pt-p .angka-besar.buruk { color: var(--buruk); }
.pt-p .angka-besar.lemah { color: var(--teks-lemah); }
.pt-p-judul { color: var(--teks); }

/* Tiga dasar beban berdampingan di Beranda Irban (§75.7). Bentuknya `.kisi`,
   tetapi dengan minimum yang lebih sempit: isinya tiga, bukan enam. */
.pt-dasar-baris {
  display: grid; gap: 10px; margin: 8px 0 4px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.pt-dasar-baris > .pt-dasar { margin: 0; }

/* Kartu "Lokasi" (§81.2) — DUA angka di dalam satu kartu, bukan satu.
   Keduanya berbagi lebar supaya tidak ada yang terbaca sebagai angka utama;
   di lebar 375px kartunya sendiri sudah satu kolom penuh, jadi dua angka
   berdampingan tetap muat tanpa gulir mendatar. */
.pt-lokasi-pasang { display: flex; gap: 14px; flex-wrap: wrap; }
.pt-lokasi-sisi { display: block; min-width: 0; }
.pt-lokasi-sisi > .angka-besar { display: block; }

/* Kalimat "sudah final / belum final" pada kartu kisi tim. Ia baris KEDUA di
   bawah kalimat himpunan, dan sengaja tidak diberi warna: yang membedakannya
   isinya, bukan nadanya — kartu ini bukan rapor. */
.pt-final { margin-top: 2px; }

/* Belahan dilanjutkan / tidak dilanjutkan (§81.3). Tabel biasa; `caption`
   di kiri seperti tabel skenario, supaya dua tabel keterangan di aplikasi ini
   tidak berbeda bentuk. */
.pt-pisah caption { text-align: left; padding-bottom: 6px; }

/* Dua daftar lokasi (§81.2). Judul kelompok memakai `h3` supaya pembaca layar
   bisa melompatinya; angkanya menempel di judul, bukan berdiri sendiri di
   kolom yang jauh. Panel laporan per sub-kegiatan TIDAK lagi memakainya sejak
   §84 — di sana barisnya sendiri yang menjadi judul sekaligus kendali. */
.pt-sk-judul { margin: 12px 0 2px; font-size: 14px; }
.pt-lapor-daftar { list-style: none; margin: 0 0 4px; padding: 0; }
.pt-lapor-daftar > li {
  padding: 4px 0; border-bottom: 1px solid var(--garis-halus);
  font-size: var(--uk-kecil);
}
.pt-lapor-daftar > li:last-child { border-bottom: 0; }

/* --- BARIS SUB-KEGIATAN ADALAH PINTU (SPEC-rev2 §84) ---------------------- */

/* Bentuknya tabel dan ia BUKAN `<table>`, karena tiap baris harus bisa
   membentangkan isinya DI TEMPAT dan `<tr>` tidak boleh memuat `<details>`.
   Kolomnya digambar `grid` dengan template yang SAMA untuk baris kepala,
   kesembilan baris, dan baris jumlah — satu tempat, satu kebenaran, sebab tiga
   template akan berbeda pendapat pada suatu hari.

   Kolom pertama selebar segitiga penanda: pada baris yang bisa dibentangkan ia
   `::before` (yang ikut menjadi butir grid), pada baris kepala dan baris jumlah
   tempatnya diisi span kosong supaya ketiganya benar-benar sejajar. */
.pt-sk-lipat { margin: 10px 0 6px; }
.pt-sk-kepala, .pt-sk-baris, .pt-sk-jumlah {
  display: grid;
  grid-template-columns: 1.1em minmax(0, 1fr) max-content max-content;
  column-gap: 10px;
  align-items: baseline;
}
.pt-sk-kepala { padding: 0 2px 4px; border-bottom: 1px solid var(--garis); }
.pt-sk-jumlah { margin: 0; padding: 8px 2px 0; border-top: 1px solid var(--garis); }

/* SASARAN SENTUH 44px (§13.9). `summary { min-height: 44px }` di kepala berkas
   ini sudah menjaminnya untuk setiap kepala lipatan, termasuk yang ditambahkan
   besok — tetapi `display: grid` mengganti tata letak bawaannya, jadi isinya
   dipusatkan supaya baris pendek tetap setinggi 44px, bukan setinggi teksnya. */
.pt-sk-baris {
  min-height: 44px; align-content: center;
  padding: 6px 2px; cursor: pointer;
  border-bottom: 1px solid var(--garis-halus);
  list-style: none;
}
.pt-sk-baris::-webkit-details-marker { display: none; }
/* Segitiga penanda digambar sendiri: kepala lipatan yang bukan `display:
   list-item` kehilangan penanda bawaan peramban, dan pintu tanpa tanda tidak
   terbaca sebagai pintu — persis keluhan yang §84 jawab. */
.pt-sk-baris::before { content: "\25B8"; color: var(--teks-lemah); }
.pt-sk[open] > .pt-sk-baris::before { content: "\25BE"; }
.pt-sk-baris:hover { background: var(--latar-3); }
.pt-sk-baris:focus-visible { outline: 2px solid var(--aksen); outline-offset: -2px; }
.pt-sk-nama { min-width: 0; overflow-wrap: anywhere; }
.pt-sk-sebab { display: block; }
.pt-sk-angka { white-space: nowrap; }

/* NAMA KOLOM YANG IKUT TIAP BARIS, TERSEMBUNYI DARI MATA SAJA.
 *
 * Bukan `display: none`, dan bedanya bukan gaya: yang `display: none` hilang
 * pula dari pohon aksesibilitas DAN dari `textContent` — dan `textContent`
 * baris inilah yang dipakai `pasangCetakPeta()` menjadi judul di atas kertas.
 * Tanpa aturan ini kertasnya berbunyi "…3440": dua angka menempel tanpa nama.
 *
 * Di bawah 520px ia justru DIPAKAI. Baris kepala tidak muat berdampingan dengan
 * nama sub-kegiatan yang panjang, jadi kolomnya dinamai di tempat angkanya. */
.pt-sk-unit {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}
@media (max-width: 520px) {
  .pt-sk-kepala { display: none; }
  .pt-sk-unit {
    position: static; width: auto; height: auto;
    margin: 0; overflow: visible; clip-path: none;
  }
}

/* Isi yang terbentang menggantung sejajar dengan judul barisnya, bukan rata
   kiri panel — yang rata kiri terbaca sebagai daftar yang berdiri sendiri,
   persis bentuk yang §84 hapus. */
.pt-sk > .pt-lapor-daftar { padding-left: calc(1.1em + 10px); padding-bottom: 6px; }

/* HUBUNGAN PAKET–ANGGOTA DIKATAKAN, BUKAN DIISYARATKAN (§84). Sampai §84 yang
   membedakan nama paket dari nama anggotanya hanya tebal hurufnya — dan pada
   data nyata ketiganya bernama sama persis, sehingga pembacanya tidak punya
   cara tahu bahwa ia satu laporan dan bukan tiga. Paket tetap BUKAN pintu: ia
   tidak punya halaman resume sendiri, dan tombol yang tidak menuju ke
   mana-mana lebih buruk daripada teks. */
.pt-lapor-paket { margin: 0; font-weight: 600; }
.pt-lapor-tanda {
  display: inline-block; margin-right: 6px; padding: 0 6px;
  border: 1px solid var(--garis); border-radius: 999px;
  background: var(--latar-3); color: var(--teks-lemah);
  font-size: .72rem; font-weight: 600; white-space: nowrap;
}
.pt-lapor-hubung { margin: 0 0 3px; }
.pt-lapor-lintas { margin: 3px 0 0; }
.pt-lapor-anggota {
  list-style: none; margin: 0; padding: 0 0 0 10px;
  border-left: 2px solid var(--garis);
}
.pt-lapor-anggota > li { padding: 2px 0; }

/* Tabel skenario penghematan (§75.2). Baris yang menjadi andaian kartu KPI
   ditandai — supaya "angka mana yang di muka" tidak perlu ditebak. */
.pt-skenario caption { text-align: left; padding-bottom: 6px; }
.pt-skenario-bawaan > td { background: var(--latar-3); }

/* Penghematan dari PELAKSANAAN (§76.2) — bagian bawah kartu penghematan, dan
   ia menjawab pertanyaan yang berbeda dari bagian atasnya: yang sudah terjadi,
   bukan yang diandaikan. Garis pemisah di atasnya ada supaya kedua pertanyaan
   itu tidak terbaca sebagai satu daftar yang panjang. */
.pt-hemat-nyata {
  margin-top: 14px; padding-top: 10px;
  border-top: 1px solid var(--garis);
}
.pt-hemat-nyata h3 { margin: 0 0 4px; font-size: 15px; }
.pt-arah caption { text-align: left; padding-bottom: 6px; }
/* Baris sebab di panel per-surat-tugas: ia menempel pada baris di atasnya,
   jadi tepi atasnya dibuang supaya keduanya terbaca sebagai satu baris. */
.pt-sebab > td { border-top: 0; padding-top: 0; }

/* Petunjuk geser. Grafik dua belas bulan digambar 1180px di dalam bidang
   selebar 281px pada layar 375px, dan bilah gulir Android baru tergambar saat
   jari menyentuhnya — jadi tanpa kalimat ini yang membuka dari HP melihat
   grafik yang tampaknya berhenti di April dan tidak punya alasan mencoba
   menggesernya. Ia MATI di atas 760px, tempat grafiknya memang muat. */
.pt-geser { display: none; margin: 0 0 6px; }
@media (max-width: 760px) { .pt-geser { display: block; } }

/* --- SATU BULAN ADALAH PINTU (SPEC-rev2 §77.2) ---------------------------- */

/* PITA SENTUH SELEBAR SATU BULAN, di dalam SVG. `fill: transparent` — BUKAN
   `fill: none`: keduanya sama-sama tak terlihat, dan hanya yang pertama
   menerima ketukan. Bedanya tidak bisa dilihat di layar, hanya diuji dengan
   `document.elementFromPoint`.

   Lebarnya satu slot bulan = 71,8 satuan viewBox, dan karena `.g-svg` menahan
   lebar minimum sebesar viewBox-nya (§72.2) satu satuan tidak pernah lebih
   kecil dari satu piksel. Jadi sasaran sentuhnya ≥71×236px di lebar mana pun —
   §13.9 terpenuhi tanpa perkecualian. Yang TIDAK dipenuhi pita ini adalah
   keterjangkauannya di layar sempit; itu tugas `.pt-bulan` di bawah. */
.g-pita { fill: transparent; stroke: none; }
.g-bulan-pintu { cursor: pointer; }
.g-bulan-pintu:hover .g-pita,
.g-bulan-pintu:focus-visible .g-pita { stroke: var(--aksen); stroke-width: 2; }
/* Fokus digambar pada PITANYA, bukan sebagai `outline` pada `<g>`: kotak
   fokus bawaan pada sebuah grup SVG digambar mengelilingi kotak pembatas
   seluruh isinya, yang di sini termasuk label nilai di baris atas — jadi
   kotaknya melebar ke bulan sebelah dan tidak menunjuk apa pun. */
.g-bulan-pintu:focus-visible { outline: none; }
.g-bulan-pintu:focus-visible .g-pita { stroke-dasharray: none; }

/* JALAN KEDUA — chip bulan di bawah grafik. Bentuknya sengaja sama dengan
   barisan chip bulan di Laporan › Usulan per bulan; dua barisan chip bulan yang
   berbeda bentuk pada satu aplikasi terbaca sebagai dua hal yang berbeda. */
.pt-bulan-baris { margin: 10px 0 4px; }
.pt-bulan-kelompok { display: flex; flex-wrap: wrap; gap: 6px; margin: 3px 0 4px; }
.pt-bulan {
  min-height: 44px; min-width: 44px; padding: 6px 12px;
  white-space: nowrap; font-variant-numeric: var(--angka);
}
.pt-bulan[disabled] { cursor: not-allowed; }

/* CORONG USULAN SEBAGAI PINTU (§77.4). Tombolnya MENGISI seluruh butir daftar,
   bukan berdiri di dalamnya: sasaran sentuh yang lebih kecil daripada kotak
   yang terlihat bisa ditekan adalah kotak yang gagal ditekan tanpa sebab yang
   kelihatan. Tepi dan latarnya karena itu pindah dari `li` ke tombolnya. */
.pt-corong > li { padding: 0; border: 0; background: none; }
.pt-corong-btn {
  width: 100%; min-height: 44px; padding: 8px 26px 8px 10px;
  border: 1px solid var(--garis); border-radius: 8px; background: var(--latar);
  text-align: left; font: inherit; color: inherit; cursor: pointer;
}

/* Kolom RENTANG tabel skenario penghematan (§76.2).
   Ia BUKAN satu angka melainkan sepasang, jadi rata kanan membuat kata
   "sampai" jatuh di tempat berbeda pada setiap baris dan pasangannya
   berhenti terbaca sebagai satu rentang. Dilaporkan pemilik 25 Agu 2026.
   Rata tengah menyejajarkan porosnya; angkanya sendiri tetap tabular-nums.

   PEMILIHNYA `td.rentang-sel`, BUKAN `.rentang-sel` (§83). Bentuk yang lebih
   pendek ditulis lebih dulu dan TIDAK PERNAH BERLAKU: `<td>` yang sama masih
   memegang kelas `.kanan`, dan `td.kanan` di atas berbobot (0,1,1) sementara
   `.rentang-sel` hanya (0,1,0) — jadi rata kanan menang berapa pun urutannya.
   Cacat yang mustahil terlihat dari membaca berkas ini saja, dan mustahil
   dipastikan dengan mata: yang membuktikannya `getComputedStyle().textAlign`.
   Bobotnya kini sepadan (0,1,1) dan aturan ini berdiri LEBIH BAWAH, jadi ia
   yang menang — tanpa `!important`, yang hanya memindahkan pertanyaannya. */
td.rentang-sel, th.rentang-sel { text-align: center; }

/* --- ARAH BIAYA: TIAP BARISNYA PINTU (§83) -------------------------------- */

/* Bentuknya SENGAJA bukan tabel. Sampai §83 panel ini memuat dua tabel yang
   berbentuk sama untuk dua pertanyaan yang berbeda — arah biaya rencana↔kisi
   realisasi, dan arah biaya kisi realisasi↔SPJ — dan kemiripan bentuk itulah
   yang membuat yang satu terbaca sebagai yang lain selama beberapa revisi.
   Yang tersisa di panel ini hanya SATU pertanyaan, dan ia berbentuk daftar
   yang bisa dibuka; peringatan mutu data di bawahnya berbentuk catatan.

   Satuan ("penugasan", "orang-hari") ditulis di dalam markup, bukan sebagai
   kepala kolom. Kepala kolom menuntut kolomnya sejajar pada lebar berapa pun —
   dan pada 375px kolom itu harus dilipat, sehingga kepalanya berhenti menunjuk
   apa pun sementara pembaca layar tidak pernah mendapat kaitannya sama sekali. */
.pt-arah-daftar { margin: 8px 0; }
.pt-arah-pintu {
  border-top: 1px solid var(--garis);
  font-size: 13px;
}
.pt-arah-pintu:last-child { border-bottom: 1px solid var(--garis); }

/* `summary` sudah bersasaran sentuh 44px lewat aturan menyeluruh di kepala
   berkas ini (§13.9); yang ditambahkan di sini hanya tata letaknya. */
.pt-arah-pintu > summary,
.pt-arah-diam {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  align-items: center;
  padding: 8px 4px;
  min-height: 44px;
}
.pt-arah-pintu > summary { cursor: pointer; }

/* PENANDA BUKA/TUTUP DIGAMBAR SENDIRI, dan itu WAJIB — bukan hiasan.
   `display: grid` pada sebuah <summary> MENGHAPUS segitiga bawaan peramban
   (bawaannya `display: list-item`, dan mengubahnya membuang markernya).
   Terlihat di layar 375px: keempat barisnya tampak seperti teks mati, dan
   pintu yang tidak terlihat sebagai pintu tidak pernah ditekan siapa pun.
   Bentuknya mengikuti keadaan `[open]`, jadi ia juga menyatakan sedang
   terbuka — bukan sekadar "bisa dibuka". */
.pt-arah-pintu > summary::-webkit-details-marker { display: none; }
.pt-arah-pintu > summary { list-style: none; }
/* Penandanya di DEPAN nama, bukan di belakangnya. Di belakang ia menempel pada
   kata terakhir, dan pada label sepanjang "Naik — bukan penghematan, dan tetap
   perlu terlihat" di layar 375px kata itu jatuh ke baris berikutnya sendirian
   sehingga penandanya berdiri di baris kosong (terukur 25 Agu 2026). Di depan
   ia menempel pada kata pertama, yang tidak pernah pindah baris. */
.pt-arah-pintu > summary .pt-arah-nama::before {
  content: "\25B8\00A0"; color: var(--aksen); font-weight: 700;
}
.pt-arah-pintu[open] > summary .pt-arah-nama::before { content: "\25BE\00A0"; }
.pt-arah-diam { color: var(--teks-lemah); }
.pt-arah-nama { min-width: 0; }
.pt-arah-angka {
  display: flex; flex-wrap: wrap; gap: 2px 14px; justify-content: flex-end;
  font-variant-numeric: var(--angka);
}
.pt-arah-angka > span { white-space: nowrap; }
.pt-arah-isi { padding: 0 4px 10px; }

/* 375px: angkanya turun ke barisnya sendiri dan rata kiri. Menggulir mendatar
   bukan pilihan di sini — gulir milik tabel di balik pintunya, dan pintu yang
   harus digeser dulu sebelum bisa dibaca berhenti menjadi pintu (§17.4). */
@media (max-width: 560px) {
  .pt-arah-pintu > summary,
  .pt-arah-diam { grid-template-columns: minmax(0, 1fr); }
  .pt-arah-angka { justify-content: flex-start; }
}

/* Peringatan mutu data — perbandingan rencana↔kisi realisasi yang turun pangkat
   dari tabel menjadi catatan (§83). Tepi kiri membedakannya dari catatan lain
   di kartu yang sama tanpa memakai merah: ia bukan temuan pemeriksaan. */
.pt-mutu { border-left: 3px solid var(--garis); }

   Rata tengah menyejajarkan porosnya; angkanya sendiri tetap tabular-nums. */
.rentang-sel { text-align: center; }

/* ===========================================================================
   KUITANSI PERJALANAN DINAS — BERANDA TIGA MEJA

   Pasangan `wajahKuitansi()` di `public/js/pantau.js`. Tidak ada satu pun
   aturan di bawah yang menyetel tinggi tombol: tombol di aplikasi ini sudah
   `min-height: 44px` sejak aturan dasarnya, dan blok ini SENGAJA tidak
   menyentuhnya. Ambang sasaran sentuh yang bisa dibatalkan oleh satu kelas
   pembantu bukan ambang — itu pelajaran yang sudah dibayar `button.kecil`.

   Bentuk barisnya KARTU, bukan tabel. Antrean kuitansi dibaca dari HP sambil
   berdiri, dan tabel enam kolom pada 375px hanya bisa dibaca dengan menggeser
   — sementara tombol keputusannya justru berada di kolom terakhir, yaitu
   kolom yang tidak pernah terlihat tanpa digeser lebih dulu.
   =========================================================================== */

.kui-kepala h2 { margin: 0 0 2px; }

/* CORONG LIMA TAHAP (§99) — menggantikan kisi lima kartu.

   Bentuknya `.pt-corong` milik beranda Irban, dipakai ulang apa adanya: ia
   satu-satunya komponen di aplikasi ini yang memang menggambarkan TAHAPAN
   BERURUT, dan butirnya melar (`flex: 1 1 130px`), sehingga baris terakhir
   mengisi sisa ruang di lebar berapa pun. Kisi `.kisi` tidak bisa: jumlah
   kolomnya ikut lebar jendela, dan lima butir pada empat kolom meninggalkan
   satu butir yatim dengan tiga petak kosong. */
.kui-corong { margin: 10px 0 4px; }
.kui-tahap-rp { display: block; font-variant-numeric: var(--angka); margin-top: 2px; }

/* MEJA SENDIRI vs MEJA ORANG LAIN.
   Bedanya dibuat pada BOBOT, bukan pada palet status (baik/hati/buruk): tidak
   ada yang buruk pada kuitansi yang sedang berada di meja orang lain, dan warna
   status akan membacanya sebagai peringatan. */
.kui-tahap-saya > .pt-corong-btn {
  border-color: var(--aksen); box-shadow: inset 3px 0 0 var(--aksen);
}
.kui-tahap-saya .pt-corong-nama { color: var(--aksen); font-weight: 600; }

/* Yang bukan mejanya DIPELANKAN, bukan disembunyikan — ia tetap pintu, tetap
   ber-`›`, tetap bisa dibuka.

   Angkanya TIDAK diberi `--teks-lemah`: itu warna yang dipakai "—" untuk
   sesuatu yang belum bisa dihitung (§7.1), dan angka sungguhan yang memakai
   warna itu akan terbaca sebagai angka yang belum ada. */
.kui-tahap-lain .pt-corong-angka { opacity: .8; }
.kui-tahap-lain .pt-corong-nama { color: var(--teks-lemah); }

/* Tahap yang isinya nol BUKAN pintu (§20.1), jadi ia bukan `<button>`. Kotaknya
   tetap sama supaya barisnya tidak bergerigi; yang hilang hanya kursor, hover,
   dan tanda `›`. Padding kanannya ikut turun — ruang yang disediakan untuk tanda
   itu tidak perlu dikosongkan pada kotak yang tidak memilikinya. */
.kui-tahap-mati { padding-right: 10px; cursor: default; }

.kui-daftar { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 10px; }

.kui-baris, .kui-pagu {
  border: 1px solid var(--garis);
  border-radius: 10px;
  padding: 10px 12px;
  background: var(--latar);
}
/* Nama penugasan adalah PINTU, dan pintu yang dipakai sambil berdiri butuh
   44px. `.tautan-data` bawaan sengaja ber-`min-height: 0` supaya tautan yang
   berdiri di TENGAH KALIMAT tidak memecah baris di sekelilingnya — di sini ia
   bukan itu: ia judul barisnya sendiri, satu-satunya jalan membuka kuitansi
   ini, jadi tinggi yang ditanggalkan di sana dikembalikan di sini.

   Yang menyediakan ruangnya `.kui-judul`. Tanpa itu, sasaran sentuh dua baris
   bertetangga saling tindih dan yang tertekan bukan yang dituju — cacat yang
   tidak kelihatan sama sekali dari tetikus. */
.kui-judul {
  font-weight: 600; line-height: 1.35;
  min-height: 44px; display: flex; align-items: center;
}
.kui-judul button.tautan-data { padding: 12px 0; }

/* Meta dipisah TITIK TENGAH lewat `::before`, bukan lewat karakter yang ikut
   tersalin ketika baris ini disalin ke berkas lain. Pemisah yang ikut tersalin
   berakhir di dalam nomor surat tugas orang lain. */
.kui-meta { display: flex; flex-wrap: wrap; gap: 0 10px; margin-top: 3px; }
.kui-meta > span + span::before { content: "\00B7\00A0"; color: var(--teks-lemah); }

/* Rincian surat tugas di kotak "Surat tugas menunggu penugasannya" (tahap 4):
   label di kiri, isi di kanan. Kolom pertamanya `auto`, bukan lebar tetap —
   label terpanjang ("Tanggal surat") yang menentukan, dan pada 375px isinya
   tetap membungkus di kolom kedua, bukan mendorong halaman melebar. */
.surat-rinci {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 12px;
  margin: 4px 0 8px;
}
.surat-rinci dt { color: var(--teks-lemah); }
.surat-rinci dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.kui-angka {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px 10px; margin-top: 8px;
  font-variant-numeric: var(--angka);
}
/* Nominal didorong ke ujung kanan supaya kolom angka sejajar antar-baris tanpa
   tabel. Pada layar sempit `flex-wrap` menurunkannya, dan `margin-left: auto`
   pada baris sendiri tidak berbahaya. */
.kui-jumlah { margin-left: auto; font-size: 1.05rem; white-space: nowrap; }

.kui-kembali, .kui-minus { margin: 8px 0 0; }
.kui-tombol { margin: 10px 0 0; }

/* Pagu: ketiga angka berdampingan, masing-masing dengan namanya di atasnya.
   Nama di ATAS, bukan di samping — "Terpakai Rp 3.130.000" yang membelah baris
   di tengahnya membuat nama dan angkanya terbaca sebagai dua hal berbeda. */
.kui-pagu-angka { gap: 8px 18px; }
.kui-pagu-angka > span { white-space: nowrap; }
.kui-pagu-angka .label { display: block; }
.kui-pagu .batang { margin-top: 8px; }

/* 375px: nominalnya turun ke barisnya sendiri dan rata kiri. Menggulir
   mendatar bukan pilihan — nominal yang harus digeser dulu sebelum terbaca
   adalah nominal yang tidak diperiksa siapa pun. */
@media (max-width: 480px) {
  .kui-jumlah { margin-left: 0; flex-basis: 100%; }
}

/* ===========================================================================
   KALENDER HARI YANG DIBAYAR — kuitansi perjalanan dinas
   ===========================================================================

   Layar pertama modul kuitansi meminta orang MENGETIK tanggal satu per satu.
   Pemilik mencobanya 31 Agustus 2026: "sulit sekali dan ribet di pembuat
   kuitansinya". Kuitansi delapan hari untuk lima orang berarti empat puluh
   kali mengetik tanggal — dan empat puluh kesempatan salah ketik.

   Yang menggantikannya kisi tanggal yang tinggal dicentang. Dua hal di sini
   yang TIDAK ada di layar SPJ, dan keduanya sengaja:

     1. NAMA HARI tertulis di tiap tanggal. Yang memeriksa kuitansi memeriksa
        "apakah benar berangkat Senin sampai Rabu", bukan "apakah benar
        tanggal 2 sampai 4".
     2. AKHIR PEKAN DITANDAI, sehingga hari yang biasanya tidak dibayar
        terlihat SEBELUM dicentang. Ia ditandai, bukan dilarang — perjalanan
        dinas yang memang berlangsung Sabtu tetap bisa dipilih.
   ------------------------------------------------------------------------ */

.kt-kalender {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0;
}

/* 56px, bukan 44px: tiga baris teks di dalam satu sasaran sentuh. Ambang
   §13.9 adalah lantai, dan sasaran yang tepat di lantainya dengan tiga baris
   di dalamnya menjadi tiga baris yang berimpit. */
.kt-hari {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  min-width: 54px;
  min-height: 56px;
  padding: 4px 6px;
  line-height: 1.1;
  background: var(--sel);
  color: var(--teks);
  border: 1px solid var(--garis);
  border-radius: 8px;
  cursor: pointer;
}

.kt-hari-nama { font-size: .7rem; letter-spacing: .04em; color: var(--teks-lemah); }
.kt-hari-tgl  { font-size: 1.05rem; font-weight: 700; }
.kt-hari-bln  { font-size: .68rem; color: var(--teks-samar); }

.kt-hari.kt-akhir { border-color: var(--latar-buruk); }
.kt-hari.kt-akhir .kt-hari-nama { color: var(--buruk); }

/* HARI LIBUR NASIONAL & CUTI BERSAMA — DAN IA BUKAN AKHIR PEKAN.
 *
 * Pemilik, 1 September 2026: "Tanggal 16 Januari isra mi'raj kenapa tidak
 * tanggal merah atau tidak ditandai bukan hari kerja". Daftarnya sudah ada di
 * tabel `hari_libur` dan sudah dipakai peta kalender (§17.4); kalender
 * kuitansi tidak pernah membacanya.
 *
 * WARNANYA BERBEDA DARI AKHIR PEKAN, dan itu bukan selera. Dua kolom yang
 * kosong karena sebab yang berbeda tidak boleh terlihat sama — aturan yang
 * sudah dipegang peta kalender sejak awal. Akhir pekan memakai rumpun
 * `--buruk` (merah), hari libur memakai `--hati` (amber): yang pertama
 * berulang setiap minggu dan bisa diperkirakan sendiri, yang kedua DIPUTUSKAN
 * pemerintah dan hanya bisa diketahui dari daftarnya.
 *
 * SESUDAH aturan akhir pekan dan SEBELUM `.terpilih`, dengan alasan yang sama
 * yang sudah ditulis di bawah: kekhususan ketiganya sama, jadi urutannya yang
 * menentukan. Hari libur yang jatuh pada Sabtu memakai penanda hari libur —
 * itu sebab yang lebih kuat.
 *
 * KONTRAS (§13.8), DIUKUR DI PERAMBAN pada kartu tempat ia benar-benar
 * berdiri (`--lembar`), bukan dihitung dari warna yang dikira:
 *   terang — teks #9b5a0e di atas isian #fdf6e6 = 5,05:1 (≥ 4,5) ·
 *            tepi #9b5a0e terhadap kartu #fdfcfa = 5,30:1 (≥ 3)
 *   gelap  — teks #e0a63f di atas isian #302716 = 6,79:1 ·
 *            tepi #e0a63f terhadap kartu #1b1e24 = 7,71:1
 * Isiannya sendiri memang lunak terhadap kartu; yang memikul pembedaan adalah
 * TEPI dan TEKSNYA, sepola dengan akhir pekan di atas — dan di sebelahnya
 * berdiri penanda "•" pada nama harinya, sehingga tandanya tidak bersandar
 * pada warna saja.
 */
.kt-hari.kt-libur {
  background: var(--latar-hati);
  border-color: var(--hati);
}
.kt-hari.kt-libur .kt-hari-nama,
.kt-hari.kt-libur .kt-hari-bln { color: var(--hati); }

/* SESUDAH aturan akhir pekan, dan urutannya yang menentukan: kekhususan
   keduanya sama persis, jadi yang belakangan menang. Dibalik, nama hari Sabtu
   yang terpilih tetap merah di atas latar aksen — kontras 1,7:1, tidak
   terbaca, dan tidak berbunyi galat. */
.kt-hari.terpilih {
  background: var(--aksen);
  border-color: var(--aksen);
  color: var(--aksen-teks);
}
.kt-hari.terpilih .kt-hari-nama,
.kt-hari.terpilih .kt-hari-bln { color: var(--aksen-teks); }

/* "BELUM DISIMPAN". Warnanya --hati, bukan --buruk: yang terjadi bukan
   kesalahan melainkan pekerjaan yang belum selesai. */
.kt-belum { color: var(--hati); font-weight: 700; }

/* ===========================================================================
   LEMBAR HOTEL — SATU BARIS PER LEMBAR TAGIHAN
   ===========================================================================

   Pemilik, 1 September 2026: "bill hotel penginapan bisa lebih dari satu dan
   ditambahkan karena bisa pindah hotel dan tarif berbeda diinput manual satu
   per satu saja per billnya."

   GRID, BUKAN FLEX, dan itu bukan selera: empat kotak yang lebarnya diatur
   flex akan berbeda lebar dari baris ke baris begitu salah satu isinya lebih
   panjang, dan kolom rupiah yang bergeser-geser membuat dua lembar yang
   nilainya berdekatan sulit dibandingkan dengan mata. Kolom nama hotel yang
   melar (1fr) dan tiga kolom sisanya tetap.

   375px: nama hotel naik ke barisnya sendiri, lalu malam + rupiah + tombol
   buang berbagi baris di bawahnya. Yang TIDAK dilakukan: menggulir mendatar —
   angka yang harus digeser dulu sebelum terbaca adalah angka yang tidak
   diperiksa siapa pun (§13, sama alasannya dengan `.kui-jumlah`).
   ------------------------------------------------------------------------ */

.kt-inap { margin: 8px 0; }

.kt-inap-baris {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5.5rem 9rem auto;
  gap: 6px;
  margin-bottom: 6px;
  align-items: center;
}

/* Nominal tidak pernah pecah baris (§13), dan kotak isian rupiah punya
   bentuknya sendiri: rata kanan supaya titik ribuannya berbaris antar lembar,
   dan `mono` supaya lebar angkanya sama — "111" dan "999" yang berbeda lebar
   membuat dua lembar terlihat berbeda besarnya padahal tidak. */
.kt-inap-malam,
.kt-inap-rp {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.kt-inap-buang { justify-self: end; }

@media (max-width: 480px) {
  .kt-inap-baris {
    grid-template-columns: minmax(0, 4.5rem) minmax(0, 1fr) auto;
  }
  /* Nama hotel memakai seluruh baris pertama — ia satu-satunya kolom yang
     isinya teks bebas, dan 4,5rem tidak cukup untuk membedakan dua hotel yang
     namanya berawalan sama. */
  .kt-inap-hotel { grid-column: 1 / -1; }
}

/* ===========================================================================
   NAMA ORANG YANG MENGISI SEBUAH SLOT — kisi tim REALISASI
   ===========================================================================

   Baris "Supir" tidak bernama saat direncanakan, dan kuitansi MENCETAK NAMA.
   Kolom ini yang menghubungkan keduanya (§102.3).

   YANG PADAM TETAP TERBACA. `:disabled` bawaan peramban meredupkan teksnya
   sampai di bawah ambang, dan pada baris bernama kotak ini memang selalu
   padam — sehingga kolomnya terlihat rusak, bukan tidak berlaku. Yang dipakai
   di sini: latar `--latar-3` (permukaan mundur yang sudah dipakai baris sub
   dan jalur batang kosong) tanpa menyentuh warna teksnya, ditambah kursor
   "tidak untuk Anda". Isinya memang selalu kosong pada baris bernama, jadi
   yang harus terbaca hanya bentuk kotaknya.
   ------------------------------------------------------------------------ */

.kisi-tim .nama-slot:disabled {
  background: var(--latar-3);
  cursor: not-allowed;
  opacity: 1;
}

/* ---------------------------------------------------------------------------
   FAKTA YANG SUDAH TERCATAT — ditampilkan, tidak diketik ulang (§110.27)

   Formulir nomor surat tugas dan formulir register ST menanyakan pekerjaan
   yang sama dengan mata pemakainya, dan berbeda jauh di layar: yang satu
   meminta uraian dan tempat, yang lain tidak menyebutnya sama sekali —
   padahal keduanya ADA, sudah ditulis saat rencananya disusun. Yang kurang
   bukan medannya melainkan tampilannya.

   Resepnya DISALIN dari `.nama-slot:disabled` di atas, dan alasannya sama
   persis: `:disabled` bawaan peramban meredupkan teks sampai di bawah ambang
   kontras, sehingga kotaknya terlihat RUSAK, bukan tidak berlaku. Latar
   `--latar-3` menyatakan "bukan untuk Anda isi" tanpa menyentuh warna
   teksnya — dan di sini isinya justru yang harus terbaca.
   ------------------------------------------------------------------------ */

.isian-tetap:disabled,
textarea.isian-tetap:disabled {
  background: var(--latar-3);
  cursor: default;
  opacity: 1;
}

/* Textarea di aplikasi ini ber-`min-height: 140px` — ukuran yang benar untuk
   kotak yang akan DIKETIK, dan salah untuk kotak yang hanya dibaca: judul
   penugasan satu baris menyisakan 118px abu-abu kosong, yang terbaca sebagai
   kotak isian yang menunggu diisi. Diukur, bukan ditaksir. `resize` ikut mati:
   tidak ada yang perlu dilebarkan pada kotak yang tidak bisa diketik. */
textarea.isian-tetap {
  min-height: 0;
  resize: none;
}

/* Kotak angka sempit — bobot PPBR dan jarak audit.
   Ia ADA karena CSP: `style-src 'self'` tanpa `unsafe-inline` memblokir atribut
   `style=`, dan sampai 1 September 2026 tiga kotak isian di `app.js` memakainya
   (`style="width:4.5rem"`). Ketiganya lolos berbulan-bulan sebab penjaga statis
   §11.2 hanya menyapu dua potongan HTML tertentu, bukan seluruh berkas — jadi
   yang menjaganya bukan lubang di CSP melainkan lubang di penjaganya. Lebarnya
   tetap 4,5rem; yang berubah dari mana ia datang. */
.angka-sempit { width: 4.5rem; }

/* ===========================================================================
   PENOMORAN SURAT TUGAS (SPEC-rev2 §110)
   =========================================================================== */

/* Bilah alat wajah Penomoran. Ia membungkus di 375px alih-alih meluber —
   bilah tab meluber sudah pernah terjadi di dua tempat sekaligus. */
.pn-alat { flex-wrap: wrap; align-items: center; }
.pn-alat select { flex: 0 1 auto; }
.pn-alat button { flex: 0 0 auto; }

/* Kotak centang: sasaran sentuhnya LABELNYA, dan itu satu-satunya
   perkecualian 44px yang tertulis (§13.9). */
.pn-centang {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; margin: 4px 0;
}
.pn-centang input { width: 20px; height: 20px; flex-shrink: 0; }

/* Lembar rekap: garis pemisah ANTAR SURAT, bukan antar baris.
   Satu surat memuat beberapa nama, dan tanpa garis ini pembacanya tidak bisa
   melihat di mana satu surat berakhir — persis yang dilakukan sel tergabung
   di lembar Excel aslinya. */
.rekap-st tr.rekap-awal td { border-top: 2px solid var(--garis-tebal, #888); }
.rekap-st td { vertical-align: top; }
/* Nominal dan nomor tidak pernah pecah baris (§13). Kolom NO dan TANGGAL ST
   di sini keduanya bisa terperas di 375px. */
.rekap-st td.nowrap, .rekap-st td.mono { white-space: nowrap; }

/* Kolom PENUGASAN pada surat berpaket (§120.6): nama paket sebagai
   KETERANGAN, lalu satu pintu per kaki. Berbaris ke bawah, bukan
   berdampingan — dua pintu bersebelahan pada sel sesempit ini terbaca
   sebagai satu kalimat yang terpotong, dan yang menekannya tidak tahu ia
   menekan yang mana. */
.rekap-st .rekap-paket { display: block; margin-bottom: 2px; }
.rekap-st .rekap-kaki { display: block; }
.rekap-st .rekap-kaki + .rekap-kaki { margin-top: 2px; }

/* Kotak saring per kolom di baris kedua thead (§116.3). `th` mewarisi
   uppercase + letter-spacing ke input di dalamnya; dikembalikan supaya yang
   diketik terbaca apa adanya. Lebar minimum supaya kolom sempit (NO, HARI)
   tidak menghasilkan kotak yang hanya memuat dua aksara. */
.rekap-st tr.rekap-saring th { padding: 4px 6px; }
.rekap-st tr.rekap-saring input[type="search"] {
  text-transform: none; letter-spacing: 0; font-size: .9rem; font-weight: 400;
  min-width: 6.5rem; padding: 6px 10px;
}
.rekap-cakupan {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  margin: 6px 0 8px;
}

/* `.angka-sempit` yang sudah ada (4,5rem) DIPAKAI APA ADANYA, tidak
   dipersempit di sini. Lebar itu sudah pernah diukur dan lulus; menimpanya
   dengan angka yang "terlihat cukup" adalah cara paling murah menghidupkan
   kembali kotak 30px yang membuat "10" terbaca "1". */

/* Pencarian nama per baris di formulir register ST (§116.4).
   Daftar hasilnya berdiri DI BAWAH kotak, bukan melayang: di dalam tabel yang
   digulir mendatar, kotak melayang terpotong tepi wadahnya dan hasilnya tidak
   bisa disentuh. Tiap butir tombol penuh — sasaran sentuh 44px, terjangkau
   papan ketik — dengan nama di baris pertama dan jabatan · unit di bawahnya. */
.pn-cari { min-width: 14rem; }
.pn-cari-kotak { display: flex; gap: 6px; align-items: stretch; margin-bottom: 4px; }
.pn-cari-kotak .cari-personil { margin-bottom: 0; flex: 1 1 auto; min-width: 0; }
.pn-cari-kotak button.kecil { flex: 0 0 auto; padding: 6px 10px; }
.pn-cari-hasil {
  list-style: none; margin: 0 0 6px; padding: 4px;
  border: 1px solid var(--garis); border-radius: 10px; background: var(--latar-2);
  display: grid; gap: 2px;
}
.pn-cari-hasil button {
  width: 100%; min-height: 44px; padding: 6px 10px;
  border: 0; border-radius: 8px; background: transparent;
  display: flex; flex-direction: column; align-items: flex-start; gap: 0;
  text-align: left; line-height: 1.3;
}
.pn-cari-hasil button:hover, .pn-cari-hasil button:focus-visible { background: var(--latar-3); }
.pn-cari-kosong { padding: 8px 10px; }
/* Kotak peran teks + tombol Pakai jabatan sebaris; tombolnya tidak menyusut
   supaya labelnya tidak pecah menjadi dua baris di sel yang sempit. */
.pn-peran-alat { display: flex; gap: 6px; align-items: stretch; margin-top: 4px; }
.pn-peran-alat input { flex: 1 1 auto; min-width: 8rem; }
.pn-peran-alat button.kecil { flex: 0 0 auto; white-space: nowrap; }

/* Gema tanggal di bawah kotak <input type="date"> (lihat gemaTanggal() di
   app.js): urutan kotaknya milik bahasa peramban, gemanya milik kita. */
.gema-tanggal { display: block; margin-top: 2px; min-height: 1em; }
.gema-peringatan { margin: 0 0 8px; }

/* Dua tombol penghitung di bawah kotak HARI formulir register (§119.6),
   sebentuk `.pn-peran-alat` di kolom sebelahnya. Membungkus di 375px: dua
   tombol berdampingan pada kolom selebar 4,5rem akan meluber keluar tabel. */
.pn-hari-alat { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.pn-hari-alat button.kecil { flex: 0 0 auto; white-space: nowrap; }

/* Sebab padamnya tombol penghitung hari (§119.7) — satu baris penuh di bawah
   kedua tombol, bukan di sampingnya: kolom HARI sempit, dan teks yang berbagi
   baris dengan tombol akan memerasnya. */
.pn-hari-sebab { flex: 1 0 100%; margin-top: 2px; line-height: 1.3; }

/* Satu pertanyaan meja laporan kepada satu unit (SPEC-rev2 §123.2). Beberapa
   pertanyaan bisa berdiri di satu kartu, dan tanpa pemisah yang terlihat
   tombol jawaban pertanyaan pertama tampak milik pertanyaan kedua. */
.kotak-usul { border-top: 1px solid var(--garis); padding-top: 10px; margin-top: 10px; }
.kotak-usul:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }

/* --- pratinjau impor lembar rekap luring (SPEC-rev2 §131.4) ---------------

   DELAPAN KOLOM YANG ENAM DI ANTARANYA BISA DISUNTING. Ia dibaca sambil
   menyandingkannya dengan lembar Excel yang terbuka di sebelahnya, jadi
   kolomnya tidak boleh diperas sampai isinya pecah baris: yang membandingkan
   dua kolom URAIAN di dua layar tidak bisa melakukannya bila salah satunya
   terpotong. Gulirnya di dalam wadahnya sendiri, tidak pernah di halaman
   (§17.4).

   Kepala tabel dipatok supaya nama kolom tetap terlihat pada berkas berisi
   dua puluh surat — sebab yang disunting di sini adalah SEL, dan sel tanpa
   nama kolom di layar hanyalah kotak berisi tanggal. */
/* PANELNYA MELEBAR HANYA UNTUK TABEL INI.
   Panel form biasa dibatasi 680px dan itu benar untuk formulir satu kolom;
   pada tabel delapan kolom ia memaksa gulir mendatar sampai kolom UNIT —
   kolom yang justru harus diisi lebih dulu — jatuh di luar layar. Dipilih
   lewat `:has()` supaya tidak ada kelas yang harus dipasang dan DIBERSIHKAN
   di panel berikutnya; peramban yang belum mengenalnya tetap mendapat panel
   680px, yaitu keadaan sebelumnya. */
@media (min-width: 760px) {
  .panel-isi:has(.imp-tabel) { width: min(1180px, 96vw); }
  /* Formulir surat tugas (register, dan sejak §151 juga Isi nomor surat
     tugas) sama alasannya: tabel nama-namanya lima kolom — nama berikut
     kotak luar daftar, peran berikut Pakai jabatan, hari berikut dua tombol
     penghitung, dan ✕. Di 680px kolom ✕ terdorong ke luar dan tabelnya
     harus digeser (keluhan pemilik 24 Sep 2026, §151.8). Diukur buku
     panduan pada layar 1280px. */
  .panel-isi:has(#pnf-tabel) { width: min(1180px, 96vw); }
  /* Kisi tim — ketiga penyuntingnya: panel Tim, formulir Isi realisasi, dan
     kisi realisasi. Tabel realisasinya delapan kolom (orang, nama slot, peran,
     hari, malam, org, inap/mlm, ✕), dan di 680px separuhnya harus digeser
     sampai ✕ tidak terlihat sama sekali (keluhan pemilik 24 Sep 2026,
     §153.1). Dipasang pada KELASNYA, bukan satu id: ketiga panel memakai
     tabel yang sama, dan yang dibetulkan satu per satu menunggu keluhan yang
     sama dua kali lagi (§131.14). */
  .panel-isi:has(.kisi-tim) { width: min(1180px, 96vw); }
}
/* --- WILAYAH GULIR YANG TERLIHAT BATASNYA (§131.14) -----------------------

   Panel ini punya DUA wilayah gulir bersarang: `.panel-isi` menggulir seluruh
   panelnya, dan `.imp-gulir` menggulir tabelnya sendiri. Keduanya sah — tabel
   tujuh kolom berisi puluhan surat harus punya batas tingginya sendiri, kalau
   tidak tombol Simpan terdorong sejauh puluhan baris. Yang TIDAK sah adalah
   membiarkan keduanya tidak bisa dibedakan: dua bilah gulir muncul
   berdampingan di tepi kanan, dan yang menggulir tidak tahu mana yang sedang
   ia gerakkan. Dilaporkan pemilik, 16 September 2026.

   Jadi wilayahnya DIGAMBAR: bergaris penuh, bersudut, dan berlatar sendiri —
   sebuah kotak, bukan potongan halaman yang kebetulan berhenti. */
/* KEEMPATNYA, bukan hanya yang dilaporkan. Penelusuran 16 September 2026
   menemukan EMPAT wilayah gulir menegak yang hidup DI DALAM `.panel-isi` —
   yang juga menggulir menegak — dan hanya satu yang kebetulan sedang dibuka
   pemilik:

     .imp-gulir     pratinjau impor rekap
     .gulir-tim     panel Tim, formulir realisasi, kisi realisasi (3 panel)
     .gulir-empat   lapis Rencana → Realisasi
     .gulir-tinggi  panel Lampiran pengesahan

   Menambal satu dan membiarkan tiga berarti menunggu keluhan yang sama tiga
   kali lagi. Resepnya sendiri bukan hal baru di berkas ini — `.tempat-daftar`
   dan `.peta` sudah memakainya bertahun-tahun; yang dikerjakan di sini hanya
   menyamakan yang tertinggal. */
.imp-gulir,
.gulir-tim,
.gulir-empat,
.gulir-tinggi {
  border: 1px solid var(--garis);
  border-color: var(--batas-tegas);
  border-radius: 10px;
  /* LATARNYA SENGAJA TIDAK DIUBAH. Isi ketiga wilayah ini memuat kepala tabel
     dan kolom pertama yang DIPATOK LENGKET, dan yang dipatok wajib berlatar
     pekat supaya baris di bawahnya tidak tembus — `.gulir-empat` memakai
     `--latar` untuk kolom pertamanya. Memberi wilayahnya latar yang sama
     membuat kolom itu melebur tepat ketika ia paling dibutuhkan, yaitu saat
     tabelnya digulir mendatar. Yang memisahkan wilayah di sini GARISNYA. */
  /* Bayangan dalam di tepi atas dan bawah: pada tabel yang tergulir setengah,
     inilah satu-satunya tanda bahwa MASIH ADA baris di luar pandangan. Garis
     saja tidak mengatakannya. */
  box-shadow: inset 0 6px 6px -6px rgba(0,0,0,.18),
              inset 0 -6px 6px -6px rgba(0,0,0,.18);
}
.imp-gulir { max-height: min(56vh, 560px); overflow: auto; }
/* Tujuh kolom, dan lebarnya dipilih supaya SELURUHNYA muat di panel lebar
   tanpa gulir mendatar: 44 + 200 + nomor + 110 + 240 + 120 + 118 ≈ 930.
   Angka ini berpasangan dengan `width: min(1180px, 96vw)` di atas — kalau
   salah satunya berubah, yang lain ikut. */
.imp-tabel { min-width: 940px; }
/* Kolom UNIT berdiri KEDUA, dan lebarnya dijaga: nama kepala unit panjang
   ("Muthmainna, SE, M.Si, Ak, CA, CRMP, CGCAE"), dan pemilih yang terperas
   memotongnya justru pada bagian yang membedakan satu unit dari yang lain. */
.imp-tabel .imp-sel-unit { min-width: 200px; }
.imp-tabel .imp-sel-unit select { width: 100%; }

/* --- YANG WAJIB DIISI TERLIHAT WAJIB (§131.13) ----------------------------
   DUA warna dengan DUA arti, dan jangan disatukan:
     --hati  (perhatian) : belum diisi. Itu bukan kesalahan — suratnya memang
                           tidak menyebut PPJ, dan orangnyalah yang memutuskan.
     --buruk (penolakan) : baru saja mencoba mencentangnya. Yang terjadi bukan
                           lagi "belum", melainkan "ditolak, dan inilah
                           sebabnya".
   Menyeragamkan keduanya menjadi merah membuat setiap berkas yang memuat satu
   surat tanpa PPJ terbuka dengan layar penuh alarm, dan alarm yang menyala
   pada keadaan yang normal mengajari orang mengabaikannya. */
.imp-tabel select.imp-unit-wajib {
  border-color: var(--hati); background: var(--latar-hati);
}
.imp-tabel select.imp-unit-tolak {
  border-color: var(--buruk); background: var(--latar-buruk);
}
/* Garis tebal di kiri sel: warnanya saja tidak cukup pada layar kecil, dan
   tidak semua orang membedakan kuning dari jingga (§13.8 — pembedaan tidak
   pernah hanya oleh warna). */
.imp-tabel .imp-sel-unit:has(.imp-unit-wajib) { box-shadow: inset 3px 0 0 var(--hati); }
.imp-tabel .imp-sel-unit:has(.imp-unit-tolak) { box-shadow: inset 3px 0 0 var(--buruk); }
.imp-wajib-teks {
  font-size: .72rem; margin-top: 3px; color: var(--hati); font-weight: 600;
}
.imp-wajib-teks.imp-wajib-keras { color: var(--buruk); }
/* Baris catatan di bawah bilah aksi saat "Pilih semua" meninggalkan sebagian. */
.peringatan-lunak {
  border: 1px solid var(--hati); background: var(--latar-hati);
  border-radius: 10px; padding: 8px 12px; margin: 8px 0;
}
/* Rentang pelaksanaan: DUA tanggal, ditumpuk. Berdampingan keduanya menuntut
   220px dan kolom terakhirlah yang membayar — ia terpotong di tepi panel. */
.imp-tabel .imp-sel-rentang { min-width: 118px; }
.imp-tabel .imp-sel-rentang input { display: block; }
.imp-tabel .imp-sel-rentang input + input { margin-top: 4px; }
/* Susunan tim TURUN ke barisnya sendiri di bawah surat itu. Sebagai kolom ia
   terperas menjadi selebar empat huruf; ia juga satu-satunya kolom yang tidak
   disunting, jadi ia tidak perlu sejajar dengan kotak-kotak isian. Garis
   bawahnya dihapus supaya ia terbaca menyatu dengan baris di atasnya —
   keduanya satu surat, bukan dua. */
.imp-tabel > tbody > tr:not(.imp-baris-tim) > td { border-bottom: 0; }
.imp-tabel > tbody > tr.imp-baris-tim > td { padding-top: 0; }
/* Rincian orang: tertutup secara bawaan supaya satu surat tetap setinggi dua
   baris, dan dibuka saat harinya perlu dipastikan terhadap lembarnya.
   `<summary>` bawaan sudah bersasaran sentuh 44px lewat aturan di bagian atas
   berkas ini; yang ditambahkan di sini hanya rupa. */
.imp-tim > summary { cursor: pointer; padding: 4px 0; }
.imp-tim > summary:hover { color: var(--aksen); }

/* --- TABEL DI DALAM TABEL: BATASNYA DIGAMBAR (§131.14) --------------------

   Rumusan pertamanya hanya satu garis tipis di kiri. Di dalam sel sebuah
   tabel lain itu tidak cukup: garisnya terbaca sebagai batas kolom, bukan
   sebagai batas tabel, sehingga yang membacanya tidak tahu di mana tabel
   dalam mulai dan tabel luar berhenti — dan pada layar bergulir ia tidak tahu
   pula mana yang sedang ia gulirkan.

   Yang membuatnya terbaca sebagai KOTAK TERSENDIRI ada tiga, dan ketiganya
   perlu: garis penuh, sudut membulat, dan latar yang berbeda dari barisnya.
   Satu saja dari ketiganya tidak cukup — garis penuh tanpa beda latar masih
   melebur ke dalam kisi tabel luarnya. */
.tabel-dalam {
  width: auto; min-width: 0;
  margin: 6px 0 8px;
  border: 1px solid var(--garis);
  border-color: var(--batas-tegas);
  border-radius: 8px;
  background: var(--latar-2);
  overflow: hidden;            /* supaya sudutnya benar-benar membulat */
}
.tabel-dalam > thead > tr > th {
  font-size: .68rem;
  background: var(--latar-3);
  border-bottom: 1px solid var(--garis);
  border-bottom-color: var(--batas-tegas);
  /* Kepala tabel LUAR dipatok lengket; yang di dalam TIDAK — sebuah kepala
     yang ikut menempel di puncak wilayah gulir akan berdiri di atas kepala
     tabel luarnya, dan yang terbaca dua judul untuk satu tabel. */
  position: static;
}
.tabel-dalam > tbody > tr > td,
.tabel-dalam > thead > tr > th {
  padding: 4px 12px; vertical-align: top;
}
/* Garis antarbaris memakai `--garis` yang sama dengan tabel luarnya — yang
   memisahkan keduanya sudah dikerjakan kotak di atas (garis penuh + sudut +
   latar), bukan ketebalan garisnya. Warna garis ketiga yang lebih lembut
   sempat dipertimbangkan dan dibatalkan: token itu tidak ada, dan
   menambahkannya menyentuh palet yang dipakai seluruh aplikasi demi satu
   tabel. Baris terakhir tanpa garis supaya tidak ada garis ganda di tepi
   bawah kotaknya. */
.tabel-dalam > tbody > tr:not(:last-child) > td {
  border-bottom: 1px solid var(--garis);
}
.tabel-dalam > tbody > tr:last-child > td { border-bottom: 0; }
.imp-tabel > thead > tr > th {
  position: sticky; top: 0; z-index: 2;
  background: var(--latar-2);
  box-shadow: 0 1px 0 var(--garis);
}
.imp-tabel > thead > tr > th, .imp-tabel > tbody > tr > td { padding: 6px 8px; }
/* Kotak isian di dalam sel: sasaran sentuhnya TETAP 44px (§13.9) — yang
   dirapatkan hanya padding mendatarnya, bukan tingginya. Baris yang lebih
   rapat di sini akan menghemat satu layar dan membayar dengan salah ketuk
   pada kolom tanggal, yaitu tepat kolom yang paling sering diperbaiki. */
.imp-tabel input[type="text"], .imp-tabel select { padding: 6px 8px; border-radius: 8px; }
.imp-tabel .imp-tgl { min-width: 104px; }
.imp-tabel .imp-sedang { min-width: 120px; }
/* URAIAN — kolom KELIMA sejak UNIT pindah ke kiri. Nomor urut di selektor ini
   sudah pernah menunjuk kolom yang salah begitu urutannya berubah; kalau ia
   berubah lagi, yang ikut berubah harus baris ini juga. */
.imp-tabel > tbody > tr > td:nth-child(5) { min-width: 240px; }
/* KOTAK CENTANG KECIL, SASARAN SENTUH TETAP 44px (§13.9).
   Kotaknya sendiri 20px — 44px akan meninggikan setiap baris tabel — tetapi
   yang diketuk adalah LABEL yang membungkusnya dan mengisi selnya penuh.
   Sel yang sekadar dilebarkan tidak cukup: mengetuk sel kosong di sebelah
   kotak tidak mencentang apa pun, jadi sasaran sentuhnya tetap 20px sementara
   kodenya terbaca seolah 44px. Terlihat dengan mengukurnya di 375px,
   bukan dengan membaca CSS-nya. */
.imp-tabel > tbody > tr > td:first-child { width: 44px; min-width: 44px; text-align: center; padding: 0; }
.imp-ketuk {
  display: flex; align-items: center; justify-content: center;
  min-height: 44px; margin: 0; cursor: pointer;
}
.imp-tabel input[type="checkbox"] { width: 20px; height: 20px; min-height: 20px; }
/* Baris yang TIDAK bisa dipilih tetap terbaca, hanya mundur satu langkah.
   Menyamarkannya lebih jauh membuat sebab yang tertulis di bawahnya ikut
   hilang — dan sebab itulah satu-satunya yang dipunyai baris tersebut. */
.baris-lemah td { color: var(--teks-lemah); background: var(--latar-3); }
