/* ══════════════════════════════════════════════════════════════════════
   JARING · lembar gaya bersama
   ──────────────────────────────────────────────────────────────────────
   Prototipe di proto-*.html masing-masing menyalin CSS-nya sendiri, dan
   salinan itu menyimpang: 22 ukuran huruf, 27 nilai spasi, 10 radius —
   sebagian beda setengah piksel dan tidak terbedakan mata, tapi tiap
   nilai tambahan adalah satu keputusan yang harus diambil ulang di layar
   berikutnya.

   Berkas ini kebalikannya: satu sumber, dan setiap layar menunjuk ke
   sini. Skalanya diturunkan dari nilai yang MEMANG dipakai, bukan dari
   sistem yang rapi di atas kertas — supaya memindahkan layar ke sini
   berupa pergeseran satu-dua piksel, bukan perancangan ulang.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1 · WARNA ─────────────────────────────────────────────────────────
   Tiga blok, bukan dua: :root memuat palet terang lengkap, media query
   menimpanya untuk tema sistem gelap, dan [data-theme] menimpa keduanya
   supaya pengalih manual menang di kedua arah. Tidak ada warna yang
   definisinya cuma ada di dalam media query.

   KEDUA BLOK GELAP DIBATASI KE `screen`. `prefers-color-scheme` tidak
   terbatas pada layar, dan `[data-theme]` jelas tidak — jadi tanpa batas
   itu, mencetak dari mesin bertema gelap menghasilkan teks putih di atas
   kertas putih. Palet terang di :root sekaligus jadi palet cetak, tanpa
   satu pun nilai warna ditulis dua kali. Lihat bagian 17.

   TIGA WARNA PER KEADAAN, DAN ITU BUKAN KERAPIAN. `ok` sejak awal punya
   tiga — dasar, `-ink` untuk teks, `-soft` untuk latar — sementara `warn`
   dan `bad` cuma punya dua. Lima belas berkas terlanjur menulis
   `var(--warn-ink)` dan sepuluh menulis `var(--bad-ink)` seolah keduanya
   ada. Token yang tidak ada TIDAK melempar galat: deklarasinya dibuang,
   dan `color` yang dibuang jatuh ke warna warisan. Di beranda.html itu
   membuat "tenggat 2 hari" dan "lewat 3 hari" terbit dengan warna yang
   sama persis — dua keadaan berbeda, satu rupa. Melengkapi tripletnya
   menutup 38 deklarasi sekaligus, di ketiga blok.                      */
:root{
  --ground:#FBFBFC; --surface:#FFFFFF; --surface-2:#F1F3F5; --surface-3:#E7EAEE;
  --line:#DDE1E6; --line-strong:#C3C9D0;
  --text:#16191F; --dim:#3C4652; --mute:#5F6A76;
  --accent:#C8551F; --accent-ink:#8E3A12; --accent-soft:#FAEAE1;
  --tenant-mark:#4A3C93;
  --btn-bg:#8E3A12; --btn-fg:#FFFFFF; --btn-hover:#71290C;
  --ok:#1F6F6B; --ok-ink:#134A47; --ok-soft:#DFEDEC;
  --warn:#7A4E08; --warn-ink:#5C3A05; --warn-soft:#F6EBD8;
  --bad:#8E1E22; --bad-ink:#74191D; --bad-soft:#F6E3E3;
  --idle:#4C555E; --idle-soft:#ECEEF1;
  --seq-1:#F2D2BC; --seq-2:#E0A575; --seq-3:#C8551F; --seq-4:#9E4118; --seq-5:#6B2A0C;
  /* Rampa NETRAL Meja Sinyal (F2-E, peta bacaan): bacaan bukan cakupan, jadi
     tidak memakai rona Operasi (C.6). Divalidasi --ordinal (satu rona, L
     menurun, ujung terang >= 2:1 terhadap permukaan), terang dan gelap. */
  --neu-1:#BDB29B; --neu-2:#A09580; --neu-3:#827866; --neu-4:#645C4D; --neu-5:#463F34;
  --stage:#22272E; --stage-ink:#C3CBD4; --stage-line:#39424C;
  --shadow:0 1px 2px rgba(22,25,31,.06), 0 10px 30px -14px rgba(22,25,31,.22);
}
@media screen and (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ground:#0D1014; --surface:#171B21; --surface-2:#1E232A; --surface-3:#262C34;
    --line:#2C333C; --line-strong:#414B56;
    --text:#F2F4F7; --dim:#C2CAD4; --mute:#98A2AE;
    --accent:#E2743E; --accent-ink:#F3AE85; --accent-soft:#2E1D14; --tenant-mark:#A79BF0;
    --btn-bg:#F0996A; --btn-fg:#1A0E06; --btn-hover:#F6C0A0;
    --ok:#57B3AC; --ok-ink:#8FD2CC; --ok-soft:#142624;
    --warn:#DCA95C; --warn-ink:#E9BE75; --warn-soft:#2A2114;
    --bad:#E08084; --bad-ink:#F0A9AC; --bad-soft:#2B1618;
    --idle:#98A2AE; --idle-soft:#22272E;
    --seq-1:#4A2A1A; --seq-2:#80452A; --seq-3:#CC6A36; --seq-4:#E8834D; --seq-5:#F6BC94;
    --neu-1:#5A5245; --neu-2:#746A5A; --neu-3:#918672; --neu-4:#B0A48D; --neu-5:#D2C7B0;
    --stage:#080A0D; --stage-ink:#9AA4B0; --stage-line:#242A32;
    --shadow:0 1px 2px rgba(0,0,0,.5), 0 10px 30px -14px rgba(0,0,0,.8);
  }
}
@media screen{ :root[data-theme="dark"]{
  --ground:#0D1014; --surface:#171B21; --surface-2:#1E232A; --surface-3:#262C34;
  --line:#2C333C; --line-strong:#414B56;
  --text:#F2F4F7; --dim:#C2CAD4; --mute:#98A2AE;
  --accent:#E2743E; --accent-ink:#F3AE85; --accent-soft:#2E1D14; --tenant-mark:#A79BF0;
  --btn-bg:#F0996A; --btn-fg:#1A0E06; --btn-hover:#F6C0A0;
  --ok:#57B3AC; --ok-ink:#8FD2CC; --ok-soft:#142624;
  --warn:#DCA95C; --warn-ink:#E9BE75; --warn-soft:#2A2114;
  --bad:#E08084; --bad-ink:#F0A9AC; --bad-soft:#2B1618;
  --idle:#98A2AE; --idle-soft:#22272E;
  --seq-1:#4A2A1A; --seq-2:#80452A; --seq-3:#CC6A36; --seq-4:#E8834D; --seq-5:#F6BC94;
  --neu-1:#5A5245; --neu-2:#746A5A; --neu-3:#918672; --neu-4:#B0A48D; --neu-5:#D2C7B0;
  --stage:#080A0D; --stage-ink:#9AA4B0; --stage-line:#242A32;
  --shadow:0 1px 2px rgba(0,0,0,.5), 0 10px 30px -14px rgba(0,0,0,.8);
} }

/* ── 2 · SKALA ─────────────────────────────────────────────────────────
   Huruf: sembilan langkah, dari dua puluh dua. Yang digabung adalah yang
   memang tidak terbedakan — 13/13.5, 14/14.5, 12/12.5, 10/10.5 — dan
   16/18 yang dua-duanya dipakai sebagai subjudul di layar berbeda.

   Spasi: delapan langkah berbasis empat. Nilai ganjil yang banyak dipakai
   (7, 9, 11, 13) bergeser paling jauh satu piksel.

   Radius: empat, dari sepuluh. Sudut 1–3px tidak terbaca sebagai sudut
   membulat; ia cuma menghaluskan aliasing.                            */
:root{
  --t-kicker:10px;   /* mono, huruf besar, jarak lebar — label bagian     */
  --t-chip:11px;     /* isi chip                                          */
  --t-kecil:12px;    /* keterangan, catatan kaki                          */
  --t-dua:13px;      /* teks sekunder                                     */
  --t-badan:14px;    /* teks utama                                        */
  --t-baca:16px;     /* teks bacaan layar ber-brand (brand.css, §04)       */
  --t-tegas:15px;    /* penekanan — TIDAK untuk isian, lihat --t-isian    */
  --t-isian:16px;    /* isian, dan 16 bukan pilihan gaya: Safari iOS
                        MEMPERBESAR viewport begitu input di bawah 16px
                        menerima fokus, lalu pengguna harus mengecilkan
                        lagi untuk melihat tombol kirimnya. Ia LANTAI,
                        sebangun dengan --t-hitung: alasannya dari luar
                        tangga, jadi ia tidak ikut tangga. Menaikkan
                        --t-tegas juga akan membesarkan tombol dan teks
                        panel yang tidak punya masalah ini.            */
  --t-sub:17px;      /* subjudul                                          */
  --t-hitung:24px;   /* angka hitungan di HP — G.2 menyebut angkanya, dan
                        itu LANTAI keterbacaan di bawah matahari, bukan
                        pilihan gaya. Ia di luar tangga yang diturunkan
                        dari pemakaian justru karena alasannya dari luar. */
  --t-judul:22px;    /* judul layar                                       */
  --t-angka:30px;    /* angka besar                                       */

  --s-1:2px;  --s-2:4px;  --s-3:8px;  --s-4:12px;
  --s-5:16px; --s-6:20px; --s-7:24px; --s-8:32px;

  --lebar-jendela:1060px;
  --lebar-catatan:var(--lebar-jendela);   /* layar HP menyempitkannya ke
                        lebar bingkai telepon, sementara panel fasilitator
                        tetap selebar layar — dua lebar, satu kerangka. */

  --r-halus:2px;   /* chip, sudut yang cuma menghaluskan aliasing         */
  --r-kotak:4px;   /* kotak, tombol, isian                                */
  --r-besar:8px;   /* jendela aplikasi, kartu besar                       */
  --r-bulat:999px; /* lencana                                             */

  --w-biasa:400; --w-medium:500; --w-tebal:600; --w-berat:700;

  --font:"IBM Plex Sans","Helvetica Neue",Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
}

/* ── 2b · TITIK PUTUS ─────────────────────────────────────────────────
   Satu-satunya skala di berkas ini yang TIDAK BISA jadi token: `@media`
   tidak membaca custom property, jadi tiap angka harus ditulis ulang di
   tempatnya. Yang bisa dilakukan cuma menyepakati daftarnya di sini dan
   memilih dari daftar, bukan menambah angka baru tiap layar.

     1280   jendela lebar → sempit. Kolom tabel yang boleh runtuh ke dalam
            sel pertama. Dipakai B-01 dan B-02.
     1120   pita catatan prototipe menyempit. Bukan bagian produk.
     1024   dua kolom → satu. Titik putus utama, delapan layar.
      900   bilah samping runtuh ke atas isinya.
      768   kerangka desktop terakhir yang masih masuk akal.
      520   bingkai HP jadi penuh layar.
      360   HP paling sempit yang masih dilayani.

   PASANGKAN SEBAGAI N-1 / N. `max-width:899px` berpasangan dengan
   `min-width:900px`; menulis keduanya 900 membuat lebar 900 tepat menyala
   di dua sisi sekaligus. Spesifikasi menulisnya "≥900px … <900px", dan
   hanya pasangan yang bergeser satu piksel yang menepatinya.

   DAFTAR SIMPANGANNYA SENDIRI PERNAH SALAH. Catatan ini dulu menyebut
   "640, 700, 760, 359" sebagai angka di luar daftar. Disapu ulang:

     359   BUKAN simpangan — ia pasangan N-1 dari 360, persis aturan yang
           ditulis di paragraf atas. Ia daftar ini yang sedang dipatuhi.
     640   dua kemunculan, dan cuma SATU titik putus: `@media` di K-04.
           Yang satunya `.panel{max-width:640px}` di K-08 — ukuran komponen,
           bukan titik putus, dan tidak pernah membelah tata letak.
     760   sama: `@media` di K-01, sementara `table{min-width:760px}` di
           K-03 lebar tabel. Dua hal berbeda dengan angka yang sama.
     700   dua-duanya titik putus sungguhan: K-06 dan K-07.

   Jadi simpangan yang sebenarnya TIGA aturan media, bukan empat angka.
   Menghitung lebar komponen sebagai titik putus membuat daftar ini terlihat
   lebih berantakan dari keadaannya, dan yang membacanya akan merapikan hal
   yang tidak perlu dirapikan.

   Ketiganya sudah dicoba diturunkan dari geometri — kolomnya dipaksa tetap
   banyak lalu lebarnya diturunkan sampai 414px, dan TIDAK ADA yang luber.
   Ketiganya runtuh demi KETERBACAAN, bukan demi muat: "kolomnya jadi
   terlalu sempit untuk dibaca" adalah penilaian, dan itu memang yang
   ASUMSI 7 tunggu datanya. Dicatat, bukan ditebak.

   Yang justru BISA diukur sudah diukur: 768 adalah lebar terakhir di mana
   kerangka desktop B-01 tidak memotong bilah sampingnya yang sudah runtuh
   (768 utuh, 700 terpotong 54px oleh `.app{overflow:hidden}`). Angka itu
   bukan tebakan lagi. */

/* ── 3 · DASAR ────────────────────────────────────────────────────────── */
*{box-sizing:border-box}
html,body{margin:0; padding:0}
body{background:var(--stage); color:var(--text); font-family:var(--font);
  -webkit-font-smoothing:antialiased; min-height:100vh}
button{font:inherit; color:inherit}
/* `hidden` HARUS berarti tersembunyi. Aturan bawaan browser hanya
   `[hidden]{display:none}` dengan kekhususan 0,1,0 — jadi setiap
   `.menu{display:flex}` atau `.kaki{display:flex}` diam-diam
   mengalahkannya, dan elemen yang menurut JS sudah disembunyikan tetap
   terlihat. Enam belas tempat di prototipe ini sudah menambalnya satu
   per satu; yang ketujuh belas ketahuan di P-02, saat bilah samping dan
   kaki tabel bertahan di layar yang seharusnya sudah tidak ada.
   `!important` di sini disengaja: CSS khas layar dimuat SESUDAH berkas
   ini, jadi tanpa itu tambalannya kalah lagi. */
[hidden]{display:none !important}
:focus-visible{outline:3px solid var(--accent); outline-offset:2px; border-radius:var(--r-kotak)}
@media (prefers-reduced-motion: reduce){ *{animation:none !important; transition:none !important} }
.sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}

/* TAUTAN LOMPAT. Tiap layar aplikasi memasang bilah atas yang sama —
   nama tenant, siklus, lencana antrean — jadi tanpa ini pengguna keyboard
   dan pembaca layar menyusuri kepala yang identik di SETIAP perpindahan
   layar sebelum sampai ke isinya. Ia disembunyikan sampai difokus, bukan
   dengan display:none (yang membuatnya hilang dari urutan Tab juga). */
.lompat{position:absolute; left:-9999px; top:8px; z-index:50;
  background:var(--text); color:var(--ground); padding:10px 14px;
  border-radius:var(--r-kotak); font-size:var(--t-dua); text-decoration:none}
.lompat:focus{left:8px}

/* ── 4 · KERANGKA APLIKASI ────────────────────────────────────────────── */
/* Lebarnya dari --lebar-jendela, tapi sisinya TIDAK dari titik putus.
   Sebelumnya ada `@media (max-width:1120px){ margin:16px }` — angka yang
   diwarisi dari jendela 1060px. Begitu --lebar-jendela jadi variabel,
   titik putusnya tidak ikut: layar 860px berhenti memusat pada 1120px,
   dan duduk melekat di kiri sepanjang 260px yang seharusnya memusat.
   `width:calc(100% - 32px)` menjamin sela 16px di segala ukuran tanpa
   titik putus sama sekali, jadi ia benar untuk lebar jendela mana pun. */
/* `position:relative` BUKAN untuk menata apa pun: ia menutup sisa kontrak
   T-06. `overflow` tidak memotong turunan ber-`position:absolute` yang blok
   penampungnya di luar sini, jadi satu `.sr` di dalam elemen lebar bisa
   menggeser seluruh halaman ke samping — 355px di Cakupan, 13 Sep. Pembungkus
   tabel sudah ditutup (#550); ini kulit terluarnya. */
.app{max-width:var(--lebar-jendela); width:calc(100% - var(--s-8));
  margin:var(--s-7) auto var(--s-8); background:var(--ground);
  border:1px solid var(--line); border-radius:var(--r-besar); overflow:hidden;
  position:relative; box-shadow:var(--shadow)}
@media (max-width:600px){ .app{border-radius:6px} }

.top{display:flex; align-items:center; gap:var(--s-5); flex-wrap:wrap;
  padding:var(--s-4) var(--s-5); background:var(--surface); border-bottom:1px solid var(--line)}
.merek{font-family:var(--mono); font-size:var(--t-kecil); font-weight:var(--w-berat);
  letter-spacing:.16em}
/* Merek di kepala /app jadi tautan ke layar pertama jabatan sesudah akun
   dikenal (app/akun.js, pasangMerek). Rupanya tetap wordmark — bukan teks
   biru bergaris bawah — dan sasaran sentuhnya ±45 px walau hurufnya 21.
   Sasarannya diperbesar lewat ::after, BUKAN min-height: min-height:44px
   menumbuhkan baris pertama kepala ponsel dari 120 ke 143 px di 390 px,
   padahal tata letaknya tidak perlu berubah sepiksel pun. */
a.merek{color:inherit; text-decoration:none; position:relative}
a.merek::after{content:''; position:absolute; inset:-12px -6px}
a.merek:hover{text-decoration:underline; text-decoration-thickness:2px; text-underline-offset:4px}
/* Jalan kembali ke daftar kerja (Fase 1b): hanya di layar yang dibuka dari
   baris Beranda (?dari=beranda; app/akun.js, pasangKembali). Sasaran
   sentuhnya diperbesar lewat ::after, seperti merek di sebelahnya, supaya
   baris pertama kepala ponsel tidak ikut tumbuh. */
.top .kembali-kerja{position:relative; font-size:var(--t-dua); font-weight:var(--w-tebal);
  color:var(--ok); text-decoration:none; white-space:nowrap}
.top .kembali-kerja::after{content:''; position:absolute; inset:-12px -6px}
.top .kembali-kerja:hover{text-decoration:underline}
/* PALET ⌘K (Fase 1c; app/akun.js pasangPalet, app/palet.js). Pencarian
   terikat meja (ia-alur.md G.8): isinya menu meja layar ini dan, di Meja
   Operasi, daftar kerja hari ini. Tombolnya di kepala, sebelum akun; di
   ponsel tanpa petunjuk papan ketik, dan setinggi lantai sentuh. */
.palet-buka{display:inline-flex; align-items:center; gap:8px; min-height:34px; padding:0 10px;
  border:1px solid var(--line-strong); border-radius:var(--r-kotak); background:var(--surface);
  color:var(--mute); font:inherit; font-size:var(--t-dua); cursor:pointer; white-space:nowrap}
.palet-buka:hover{background:var(--surface-2); color:var(--text)}
.palet-buka kbd{font-family:var(--mono); font-size:var(--t-kecil); color:var(--dim);
  border:1px solid var(--line); border-radius:4px; padding:1px 5px; background:var(--surface-2)}
@media (pointer:coarse), (max-width:600px){
  .palet-buka{min-height:44px}
  .palet-buka kbd{display:none}
}
.palet-latar{position:fixed; inset:0; z-index:70; display:flex; justify-content:center;
  align-items:flex-start; padding:10vh var(--s-5) var(--s-5); background:rgba(12,20,16,.46)}
.palet-latar[hidden]{display:none}
html.palet-terbuka{overflow:hidden}

/* ══ MODE LEMBAR (Fase 1d) ═══════════════════════════════════════════
   LAYAR DI DALAM LEMBAR (html.dalam-lembar, app/lembar-sisip.js): satu
   pekerjaan, tanpa kepala, menu meja, pita, dan bingkai jendela — yang
   itu semua milik Beranda di sekelilingnya. */
html.dalam-lembar body{background:var(--ground)}
html.dalam-lembar .top, html.dalam-lembar .sisi, html.dalam-lembar .lompat, html.dalam-lembar .pita-atas,
html.dalam-lembar .ajak-penanda, html.dalam-lembar .b-ruang{display:none !important}
html.dalam-lembar .app{max-width:none; width:100%; margin:0; border:0; border-radius:0; box-shadow:none}
html.dalam-lembar .badan{grid-template-columns:minmax(0,1fr)}

/* LEMBAR DI JENDELA INDUK (app/lembar.js): menempel di kanan, selebar
   kira-kira satu layar kerja; di ponsel selebar layar. Bingkainya mengisi
   sisa tinggi, dan layar di dalamnya menggulung sendiri.
   Namanya .lembar-panel, BUKAN .lembar: hibah.html punya .lembar sendiri
   (dialog pernyataan), dan aturan di sini berlaku di tiap layar. Kelas mode
   di <html> layar yang dibingkai pun .dalam-lembar, bukan .lembar — kalau
   sama, panel selebar 66vw ini menjepit layar di dalamnya. Dijaga uji J
   alat/uji-lembar-browser.mjs. */
.lembar-latar{position:fixed; inset:0; z-index:65; display:flex; justify-content:flex-end;
  background:rgba(12,20,16,.40)}
.lembar-latar[hidden]{display:none}
html.lembar-terbuka{overflow:hidden}
.lembar-panel{width:min(820px,66vw); height:100%; display:flex; flex-direction:column;
  background:var(--surface); border-left:1px solid var(--line-strong); box-shadow:var(--shadow)}
.lembar-hd{display:flex; align-items:center; gap:10px; padding:8px 10px 8px 20px;
  border-bottom:1px solid var(--line)}
.lembar-hd h2{flex:1; min-width:0; margin:0; font-size:var(--t-tegas); font-weight:var(--w-berat);
  overflow-wrap:anywhere}
.lembar-penuh{display:inline-flex; align-items:center; min-height:36px; padding:0 10px;
  color:var(--ok); font-size:var(--t-dua); font-weight:var(--w-tebal); text-decoration:none; white-space:nowrap}
.lembar-penuh:hover{text-decoration:underline}
.lembar-tutup{min-height:36px; padding:0 12px; border:1px solid var(--line-strong); border-radius:var(--r-kotak);
  background:var(--surface); color:var(--text); font:inherit; font-size:var(--t-dua); cursor:pointer}
.lembar-tutup:hover{background:var(--surface-2)}
.lembar-bingkai{flex:1; width:100%; border:0; background:var(--ground)}
@media (max-width:760px){
  .lembar-panel{width:100%; border-left:0}
  .lembar-hd{padding-left:14px}
  .lembar-penuh,.lembar-tutup{min-height:44px}
}
.palet{width:min(640px,100%); max-height:76vh; display:flex; flex-direction:column;
  background:var(--surface); color:var(--text); border:1px solid var(--line-strong);
  border-radius:var(--r-besar); box-shadow:var(--shadow); overflow:hidden}
.palet-hd{display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:8px 8px 0 16px}
.palet-judul{margin:0; font:var(--w-tebal) var(--t-kicker)/1.5 var(--mono);
  letter-spacing:.12em; text-transform:uppercase; color:var(--mute)}
.palet-tutup{min-height:36px; padding:0 12px; border:0; border-radius:var(--r-kotak); background:none;
  color:var(--mute); font:inherit; font-size:var(--t-dua); cursor:pointer}
.palet-tutup:hover{background:var(--surface-2); color:var(--text)}
#palet-cari{margin:8px 12px 10px; min-height:44px; padding:8px 12px; font:inherit; font-size:16px;
  color:var(--text); background:var(--surface-2); border:1px solid var(--line-strong);
  border-radius:var(--r-kotak)}
#palet-daftar{list-style:none; margin:0; padding:0 6px 8px; overflow:auto; min-height:0}
.palet-gol{padding:10px 10px 4px; font:var(--w-tebal) var(--t-kicker)/1.5 var(--mono);
  letter-spacing:.12em; text-transform:uppercase; color:var(--mute)}
.palet-status{padding:8px 10px; color:var(--mute); font-size:var(--t-dua)}
#palet-daftar [role=option] a{display:flex; align-items:center; justify-content:space-between;
  gap:12px; min-height:44px; padding:8px 10px; border-radius:var(--r-kotak);
  color:var(--text); text-decoration:none}
#palet-daftar [role=option] .l{min-width:0; overflow-wrap:anywhere}
#palet-daftar [role=option] .k{flex:none; max-width:55%; color:var(--mute); font-size:var(--t-dua);
  text-align:right}
#palet-daftar [role=option][aria-selected=true] a{background:var(--accent-soft); color:var(--accent-ink)}
#palet-daftar [role=option][aria-current=page] .l::after{content:' \00b7  layar ini'; color:var(--mute);
  font-size:var(--t-dua)}
.palet-kaki{margin:0; padding:8px 16px; border-top:1px solid var(--line); color:var(--mute);
  font-size:var(--t-kecil)}
@media (pointer:coarse){ .palet-kunci{display:none} }
@media (max-width:600px){
  .palet-tutup{min-height:44px}
  .palet-latar{padding:0; align-items:stretch}
  .palet{max-height:none; height:100%; border-radius:0; border:0}
  #palet-daftar [role=option] a{flex-wrap:wrap}
  #palet-daftar [role=option] .k{max-width:none; text-align:left; flex:1 1 100%}
}
.konteks{font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase; color:var(--mute);
  border:1px solid var(--line-strong); border-radius:var(--r-halus); padding:5px 10px}
/* Slot siklus yang tidak terisi TIDAK tampil. Kotak berbingkai yang
   kosong terbaca seperti data yang gagal dimuat (studi kesesuaian 25 Sep:
   26 dari 48 layar). Diisi app/akun.js dari siklus ruang kerja. */
.konteks:empty,[data-siklus-kepala]:empty{display:none}
/* LINGKUP WILAYAH di kepala (ia-alur.md H.1), dipasang app/akun.js dari
   lingkup sesi. Bentuknya sekeluarga dengan slot siklus di sebelahnya, dan
   yang terkunci — koordinator desa — membawa gembok, bukan warna. */
.kpl-lingkup{display:inline-flex; align-items:center; gap:6px;
  font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase; color:var(--mute);
  border:1px dashed var(--line-strong); border-radius:var(--r-halus); padding:5px 10px}
.kpl-lingkup .b-ikon{width:13px; height:13px}
/* YANG BISA DIPILIH — rute layar ini menghormati `?wilayah=` (LINGKUP_LIHAT
   di functions/api/_middleware.js). Garis PEJAL dan ▾: putus-putus berarti
   "diberikan", pejal berarti "bisa diganti". Panah itu tidak pernah muncul
   di layar yang isinya tidak akan menyempit. Tiap pilihan tautan biasa,
   44px, karena ia juga disentuh di ponsel. */
details.kpl-lingkup{position:relative; border-style:solid; padding:0}
details.kpl-lingkup>summary{display:inline-flex; align-items:center; gap:6px; min-height:30px;
  padding:5px 10px; cursor:pointer; list-style:none}
details.kpl-lingkup>summary::-webkit-details-marker{display:none}
details.kpl-lingkup>summary::after{content:"\25BE"; letter-spacing:0}
details.kpl-lingkup[open]>summary{background:var(--surface-2)}
.kpl-pilih{position:absolute; top:calc(100% + 6px); left:0; z-index:30; min-width:260px;
  max-height:min(60vh, 460px); overflow:auto; padding:var(--s-2) 0;
  background:var(--surface); border:1px solid var(--line-strong); border-radius:var(--r-kotak);
  box-shadow:var(--shadow); font-family:var(--font); font-size:var(--t-dua); font-weight:var(--w-biasa);
  letter-spacing:0; text-transform:none; color:var(--text)}
.kpl-pilih p{margin:var(--s-2) var(--s-4); font-family:var(--mono); font-size:var(--t-kicker);
  font-weight:var(--w-tebal); letter-spacing:.13em; text-transform:uppercase; color:var(--mute)}
.kpl-pilih ul{margin:0; padding:0; list-style:none}
.kpl-pilih a{display:flex; align-items:center; min-height:44px; padding:0 var(--s-4);
  color:var(--text); text-decoration:none}
.kpl-pilih a:hover,.kpl-pilih a:focus-visible{background:var(--surface-2)}
.kpl-pilih .naik a{color:var(--dim)}
.kpl-pilih .naik+li:not(.naik){border-top:1px solid var(--line)}
@media (max-width:599px){
  details.kpl-lingkup>summary{min-height:44px}
  .kpl-pilih{position:fixed; left:var(--s-4); right:var(--s-4); top:auto; min-width:0}
}

/* REMAH WILAYAH (ia-alur.md H.2) — satu gaya untuk tiap layar, dirakit
   Akun.remah(). Dulu lima salinan identik di lima <style> layar, dan satu
   yang lain sendiri. Pemisah dan penanda "di sini" milik lembar ini. */
.remah{display:flex; align-items:baseline; gap:var(--s-3); flex-wrap:wrap;
  margin:0 0 var(--s-5); font-size:var(--t-dua); color:var(--mute)}
.remah ol{display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--s-2);
  margin:0; padding:0; list-style:none}
.remah li{display:inline-flex; align-items:baseline; gap:var(--s-2)}
.remah li+li::before{content:"\203A"; color:var(--line-strong)}
.remah a{color:var(--dim); text-decoration:none}
.remah a:hover{color:var(--accent-ink); text-decoration:underline}
.remah li[aria-current]{color:var(--text); font-weight:var(--w-tebal)}
.remah-siklus{margin-left:auto; font-family:var(--mono); font-size:var(--t-kicker);
  letter-spacing:.1em; text-transform:uppercase; color:var(--mute)}
/* Tombol ▾ di simpul terdalam membuka pemilih wilayah di kepala — hanya
   di ponsel, tempat simpul lain disembunyikan (H.2 aturan 5). */
.remah-pilih{display:none}
/* Di ponsel remah runtuh ke simpul terdalam (H.2 aturan 5). */
@media (max-width:599px){
  .remah li:not([aria-current]){display:none}
  .remah li+li::before{content:none}
  .remah-pilih{display:inline-flex; align-items:center; justify-content:center;
    min-width:44px; min-height:44px; margin:-12px 0; padding:0; border:0;
    background:none; color:var(--dim); font:inherit; cursor:pointer}
}
.akun{margin-left:auto; font-size:var(--t-dua); color:var(--dim)}
.akun b{color:var(--text); font-weight:var(--w-tebal)}

/* PENANDA TENANT (M3) — konteks mati, bukan kontrol. Bilah pejal = partai,
   bilah berongga 8px = kampanye. Luminans violet dan biru berdekatan, jadi
   bentuk dan inisial yang menanggung pembedaan — bukan warna. */
.penanda-tenant{display:inline-flex; align-items:center; gap:7px; cursor:default}
.pt-bilah{width:4px; height:18px; border-radius:1px; background:var(--tenant-mark); flex:0 0 auto}
.pt-bilah.rongga{width:8px; background:transparent; border:1.5px solid var(--tenant-mark)}
.pt-inisial{font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-berat);
  letter-spacing:.08em; color:var(--tenant-mark); border:1px solid var(--tenant-mark);
  border-radius:var(--r-halus); padding:2px 5px; line-height:1}
.pt-nama{font-size:var(--t-dua); font-weight:var(--w-tebal); letter-spacing:.01em}

/* Disempitkan ke main.isi, dan itu bukan kerapian melainkan perbaikan.
   Sebagai `.isi` telanjang ia mengenai SETIAP elemen berkelas isi — dan
   K-08 memakai <span class="isi"> di dalam baris kader dan baris TPS.
   Akibatnya tiap span itu mewarisi padding 22/24/28px: baris kader jadi
   71px tinggi, namanya terdorong menjauh dari kotak centangnya, dan tetap
   terlihat seperti tata letak yang disengaja. Seluruh layar memakai
   <main class="isi">, jadi menyempitkannya tidak mengubah apa pun kecuali
   menutup tabrakan itu — dan mencegahnya terulang. */
main.isi{padding:var(--s-6) var(--s-7) var(--s-8)}
@media (max-width:600px){ main.isi{padding:var(--s-5) var(--s-5) var(--s-7)} }

/* ── 4b · KERANGKA BERSISI ─────────────────────────────────────────────
   Tujuh layar memakai kerangka yang sama: pengalih ruang di kepala, bilah
   samping berisi menu, isi di kanan. B-01, B-02, dan B-03 dipindahkan ke
   lembar ini dengan markup kerangkanya utuh tapi aturannya tidak ikut ke
   mana pun — bilah sampingnya runtuh jadi deretan tombol polos, dan
   TETAP TERLIHAT MASUK AKAL, jadi lolos pemeriksaan. Pelajarannya: layar
   yang dipindahkan harus dibandingkan dengan aslinya, bukan cuma dicek
   apakah tokennya terbaca.

   Lebar jendela sebelumnya tujuh nilai berbeda (1060…1240) tanpa alasan
   yang bisa dijelaskan. Sekarang dua, lewat --lebar-jendela: 1060 biasa,
   1240 untuk yang berbilah samping (216px bilah menyisakan ~1024px isi).
   Satu variabel, karena lebarnya dipakai tiga tempat — .app, .fasil-in,
   dan .catatan — dan kalau ketiganya tidak seiring, catatan fasilitator
   jadi lebih sempit dari jendelanya. Layar berbilah samping cukup menulis
   satu baris di blok khasnya: :root{ --lebar-jendela:1240px }         */

.ruang{display:flex; border:1px solid var(--line-strong);
  border-radius:3px; overflow:hidden}
.ruang button{appearance:none; background:var(--surface); border:0;
  border-right:1px solid var(--line); padding:var(--s-3) var(--s-5); min-height:40px;
  cursor:pointer; color:var(--mute); font-family:var(--mono);
  font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase}
.ruang button:last-child{border-right:0}
.ruang button[aria-pressed="true"]{background:var(--accent-soft); color:var(--accent-ink)}
/* Ruang Sinyal ditandai bentuk, bukan warna (C.6): garis bawah tebal dan
   latar netral, bukan terracotta milik Ruang Operasi. */
.ruang button[data-ruang="sinyal"][aria-pressed="true"]{background:var(--surface-2);
  color:var(--text); box-shadow:inset 0 -3px 0 0 var(--line-strong)}
/* PENGALIH MEJA DI APLIKASI — komponen yang sama, dengan TAUTAN.
   Hi-fi menggambarnya sebagai tombol karena prototipe tidak punya halaman
   tujuan; di app tiap meja adalah halaman sungguhan, jadi ia <a> dan yang
   sedang dibuka ditandai aria-current, bukan aria-pressed. Dirakit
   alat/rakit-menu.mjs dari alat/meja.mjs (Lima Meja, keputusan 25 Sep). */
.ruang a{display:flex; align-items:center; background:var(--surface);
  border-right:1px solid var(--line); padding:var(--s-3) var(--s-5); min-height:40px;
  color:var(--mute); text-decoration:none; font-family:var(--mono);
  font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase}
.ruang a:last-child{border-right:0}
.ruang a:hover{background:var(--surface-2); color:var(--text)}
.ruang a[aria-current="true"]{background:var(--accent-soft); color:var(--accent-ink)}
.ruang a[data-meja="sinyal"][aria-current="true"]{background:var(--surface-2);
  color:var(--text); box-shadow:inset 0 -3px 0 0 var(--line-strong)}
/* Di ponsel pengalih turun ke barisnya sendiri dan bisa digeser; memecah
   nama meja jadi dua baris membuat tiga butir terbaca seperti enam. */
@media (max-width:599px){
  .mj-pengalih{order:5; flex-basis:100%; overflow-x:auto}
  .mj-pengalih a{flex:1 0 auto; justify-content:center; min-height:44px}
}
/* Judul kelompok di dalam satu meja (Lima Meja: "Menetapkan", "Orang",
   "Bukti", …). Lebih kecil dari judul meja, dan tidak pernah dibaca
   sebagai meja lain. */
.sisi p.mj-gol{margin:var(--s-5) 0 var(--s-2); padding:0 11px;
  font:var(--w-tebal) var(--t-chip)/1.5 var(--mono); letter-spacing:.1em;
  text-transform:uppercase; color:var(--mute)}

.badan{display:grid; grid-template-columns:216px minmax(0,1fr)}
.sisi{background:var(--surface-2); border-right:1px solid var(--line);
  padding:var(--s-5) var(--s-4)}
/* 899, bukan 900. `max-width:900px` dan `min-width:900px` dua-duanya
   menyala di lebar 900 tepat: bilah sampingnya runtuh sementara aturan
   lain di lembar ini menganggap 900 masih lebar (lihat .akibat). Spesifikasi
   menulisnya "≥900px … <900px", dan hanya pasangan 899/900 yang menepati
   itu. Pasangan 1023/1024 dan 1279/1280 sudah benar sejak awal; yang ini
   terlewat. */
/* `minmax(0,1fr)`, BUKAN `1fr`, dan bedanya bukan gaya. Track `1fr` punya
   batas bawah `auto` — selebar isi terlebarnya — jadi satu tabel lebar
   memekarkan seluruh kolom isi melewati layar, dan pembungkus bergulirnya
   ikut memekar alih-alih menggulir. Desktop di atas sudah memakai
   `minmax(0,1fr)`; di sini dulu tidak. Di 400px Cakupan per kecamatan
   jadi 792px lebarnya, dan kolom Kurang — alasan layar itu ada — tidak
   pernah terlihat di ponsel (audit 15 Sep 2026, UX-06). */
@media (max-width:899px){
  .badan{grid-template-columns:minmax(0,1fr)}
  .sisi{border-right:0; border-bottom:1px solid var(--line)}
}
/* PITA DI DALAM .badan. 38 layar menaruh `#pita` di antara `nav.sisi` dan
   `main`, dan grid tanpa penempatan mengisi sel menurut urutan. Selama
   pita tersembunyi yang tersisa cuma bilah dan isi, jadi rapi. Begitu
   Pita.galat() menampilkannya, pita mengambil baris 1 kolom 2 dan `main`
   jatuh ke baris 2 KOLOM 1, jalur bilah yang 216px. Diukur 26 Sep 2026 di
   berkas-dana 1280px: #isi dari x=327 lebar 842 jadi x=111 lebar 216, dan
   pitanya sendiri melar setinggi bilah (387px untuk satu baris kalimat).
   Tiap galat di desktop merusak halaman yang sedang dilaporkannya.

   BIDANG BERNAMA, bukan `grid-row:span 2` pada bilah. Tiga cara yang lebih
   pendek sudah diukur: bilah span 2; bilah span 2 plus anak lain di kolom
   2; bidang bernama tanpa baris `1fr`. Ketiganya mengembalikan #isi ke
   kolom 2, tapi membagi sisa tinggi bilah ke DUA baris auto. Saat bilah
   lebih tinggi dari isinya (35 dari 38 layar dengan isi tiruan), pita satu
   baris jadi 136–187px. Saat pita TERSEMBUNYI pun ada akibatnya. Dua cara
   span membuat #isi berhenti memanjang setinggi bilah di 48 dari 50 layar.
   Bidang tanpa 1fr lebih parah: baris pita yang kosong menelan sisanya dan
   mendorong #isi turun di 47 dari 50 layar, di titik sampai 1325px.
   `auto 1fr` memberi seluruh sisa ke baris isi.
   Pitanya setinggi teksnya, dan tanpa pita baris 1 kosong setinggi 0,
   jadi ke-50 layar ber-.badan terukur sama persis dengan sebelumnya.

   `1fr` di sini BARIS, dan batas bawah `auto` yang ditolak untuk kolom di
   atas justru yang dicari: baris isi tidak pernah lebih pendek dari isinya.

   Hanya ≥900px. Di bawahnya satu kolom dengan urutan DOM — laci, bilah,
   pita, isi — dan itu memang urutan yang benar: pita tepat di atas isi
   yang dilaporkannya. Aturan ini tidak menyentuhnya sama sekali.
   Dijaga alat/uji-pita-kolom-browser.mjs. */
@media (min-width:900px){
  .badan{grid-template-rows:auto 1fr; grid-template-areas:"sisi pita" "sisi isi"}
  .badan > .sisi{grid-area:sisi}
  .badan > .pita-atas{grid-area:pita}
  .badan > main{grid-area:isi}
}
.sisi p.hd{margin:0 0 var(--s-3); font-family:var(--mono); font-size:var(--t-kicker);
  font-weight:var(--w-tebal); letter-spacing:.15em; text-transform:uppercase; color:var(--mute)}
.sisi .catat{margin:var(--s-4) 0 0; font-family:var(--font); font-size:var(--t-kecil);
  font-weight:var(--w-biasa); letter-spacing:0; text-transform:none;
  color:var(--mute); line-height:1.5}

/* SATU aturan untuk semua glif yang dirakit ikon(), bukan satu aturan per
   pemakainya — dan di LEMBAR BERSAMA, bukan di satu layar. Aturan ini
   pernah hanya ada di app/beranda.html: di sana panah laci ponsel terbit
   17×17, sementara di 45 layar lain SVG yang sama terbit 0×0 — pembuka
   menu tanpa panah, dan tak seorang pun melihat glif yang tidak ada.

   Mockup tidak bisa menangkap ini: di sana tiap SVG ditulis tangan lengkap
   dengan width, height, dan fill. Yang merakit glif dari fungsi justru
   layar sungguhan, dan di situlah lubangnya. (UX-07, audit 15 Sep.) */
.b-ikon{width:17px; height:17px; flex:none; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}

/* Menu menerima button dan a — P-01 memakai tautan sungguhan karena tiap
   butirnya memang halaman tersendiri. */
.menu{display:flex; flex-direction:column; gap:3px}
.menu button,.menu a{display:block; width:100%; text-align:left; background:none; border:0;
  cursor:pointer; padding:10px 11px; border-radius:var(--r-kotak);
  font-size:var(--t-badan); color:var(--dim); text-decoration:none}
.menu button:hover,.menu a:hover{background:var(--surface-3)}
.menu button[aria-current="page"],.menu a[aria-current="page"]{background:var(--accent-soft);
  color:var(--accent-ink); font-weight:var(--w-tebal)}
/* Butir yang menunjuk ke Ruang Sinyal, dan seluruh menu saat berada di
   sana: netral dengan garis tepi, tidak pernah terracotta.

   `a` IKUT DISEBUT, dan itu bukan kerapian. Aturan ini ditulis hanya
   untuk `button` saat C.6 disusun, lalu tidak pernah dipakai — dan saat
   akhirnya dipakai, kedua pemakainya ternyata memakai TAUTAN: K-14 sudah
   lama begitu, dan P-04 memang halaman tersendiri. Selama `a` tidak
   disebut, butir "sedang di sini" di Ruang Sinyal jatuh ke aturan umum
   di atas dan tampil terracotta — persis yang kalimat ini larang. */
.sisi.sinyal .menu button[aria-current="page"],
.sisi.sinyal .menu a[aria-current="page"],
.menu button.sinyal,
.menu a.sinyal{background:var(--surface-3); color:var(--text);
  box-shadow:inset 3px 0 0 0 var(--line-strong); border-radius:var(--r-kotak)}

/* ── 4c · KERANGKA HP ──────────────────────────────────────────────────
   Layar saksi memakai bingkai telepon, bukan jendela desktop. Dinaikkan
   ke sini setelah S-06 jadi pemakai kedua; S-01 lebih dulu memilikinya
   sendiri, dan keduanya persis sama begitu S-01 ditokenkan.

   Yang TIDAK ikut naik: `body{display:flex}` yang memusatkan bingkainya.
   Itu pilihan tingkat halaman, bukan komponen, dan menyiarkannya akan
   mengubah tata letak setiap layar desktop.                             */
.frame{width:100%; max-width:400px; margin:var(--s-7) auto 30px;
  background:var(--ground); border-radius:22px; box-shadow:var(--shadow);
  overflow:hidden; position:relative; display:flex; flex-direction:column;
  min-height:660px; border:1px solid var(--line)}
@media (max-width:520px){
  .frame{max-width:none; margin:0; border-radius:0; border:0;
    min-height:calc(100vh - 120px)}
}

.appbar{display:flex; align-items:center; justify-content:space-between;
  gap:var(--s-3); padding:var(--s-4); background:var(--surface);
  border-bottom:1px solid var(--line)}
.siklus{font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase; color:var(--mute)}
.ab-kiri{display:flex; flex-direction:column; align-items:flex-start; gap:4px; min-width:0}
/* Lencana antrean 48px: satu-satunya jalan melihat apa yang belum
   terkirim, dan ditekan satu tangan sambil berdiri (G.1). */
.badge{appearance:none; background:var(--surface-2); border:1px solid var(--line-strong);
  border-radius:var(--r-bulat); min-height:48px; padding:0 var(--s-5); cursor:pointer;
  display:inline-flex; align-items:center; gap:7px; font-family:var(--mono);
  font-size:var(--t-kecil); font-weight:var(--w-tebal); color:var(--dim)}
.badge[data-n="0"]{opacity:.55}
.badge b{color:var(--accent-ink); font-weight:var(--w-berat)}

/* Bilah menempel di bawah kepala aplikasi — bukan .pita yang bermargin
   dan bersudut. Dua hal berbeda, dua nama berbeda. */
/* white-space:pre-line supaya ringkasan berbaris — impor mutasi melaporkan
   "sekian masuk / sekian dilewati / baris ke-N tidak terbaca" sebagai
   beberapa baris, dan sebelumnya itu satu-satunya alasan ia memakai
   alert(). Varian .galat memakai palet bad, bukan warn: gagal dan
   peringatan tidak boleh berupa yang sama. */
.pita-atas{padding:9px var(--s-4); font-size:var(--t-dua); line-height:1.45;
  white-space:pre-line;
  background:var(--warn-soft); color:var(--warn); border-bottom:1px solid var(--line)}
.pita-atas.galat{background:var(--bad-soft); color:var(--bad)}
.pita-atas[hidden]{display:none}
/* KEADAAN MUAT (app/keadaan.js, R6). Pita di bawah kepala: luring memakai
   palet warn — data masih terbaca, cuma lama — dan galat memakai bad. Tombol
   Coba lagi duduk di dalam kalimatnya, 44px karena ia juga disentuh di ponsel. */
.pita-keadaan{display:flex; flex-wrap:wrap; align-items:center; gap:var(--s-2) var(--s-3)}
.pita-keadaan .btn{min-height:44px; padding:0 var(--s-4)}
.petak-keadaan.gagal-muat{display:flex; flex-direction:column; align-items:flex-start; gap:var(--s-3)}
.petak-keadaan.gagal-muat p{margin:0}
/* Aksi yang dimatikan karena luring: redup, dan tautan bergaya tombol tidak
   bisa diketuk — tombol dan isian sudah `disabled`. */
[data-luring-mati]{opacity:.45; cursor:default}
a[data-luring-mati]{pointer-events:none}

.scr{flex:1; overflow-y:auto; position:relative; padding:var(--s-5) var(--s-4) 26px;
  display:flex; flex-direction:column; gap:var(--s-5)}
.scr[hidden]{display:none}
.scr .kicker{margin:0}
/* h1 IKUT, karena judul layar memang h1 — bukan h2 di bawah h1 yang tidak
   pernah ada. Selektornya tetap disebut per elemen supaya .judul pada div
   dan span di layar lain tidak ikut berubah ukuran. */
h1.judul, h2.judul{margin:0; font-size:19px; font-weight:var(--w-tebal); letter-spacing:-.01em}

/* Tautan kembali, bukan tombol aksi: tanpa latar, tanpa garis, warna
   redup. 44px karena ia tetap disentuh ibu jari sambil berdiri — itu
   lantai sentuh, bukan bobot visual.

   Dinaikkan setelah S-10 jadi pemakai kedua di antara layar high
   fidelity. Kedua salinannya sama persis sampai spasi, jadi
   pemindahannya tidak mengubah satu piksel pun — dan itu diperiksa,
   bukan diandaikan. `proto-saksi.html` juga memuatnya dan SENGAJA tidak
   ikut: prototipe lama tidak menunjuk ke lembar bersama, dan E.1 sudah
   mengecualikannya. */
.kembali{appearance:none; background:none; border:0; padding:6px 2px; cursor:pointer;
  align-self:flex-start; font-size:var(--t-badan); color:var(--dim);
  min-height:44px; display:flex; align-items:center; gap:7px;
  /* Satu baris, tidak menyusut: di 320 px "‹ Tugas saya" dipatahkan jadi
     "‹ Tugas / saya" oleh lencana antrean di sebelahnya (Laporkan masalah,
     lalu tiga bingkai yang mendapat tautan pulang di R5). Yang boleh patah
     nama Dasbor di kiri, bukan tautan pulangnya. */
  white-space:nowrap; flex:none}

/* Aksi primer di HP: 56px penuh-lebar, sepertiga bawah layar adalah zona
   ibu jari (G.1). Bukan .btn 48px milik layar desktop. */
.tombol{appearance:none; width:100%; min-height:56px; border-radius:var(--r-kotak);
  cursor:pointer; background:var(--btn-bg); color:var(--btn-fg);
  border:1px solid var(--btn-bg); font-size:16px; font-weight:var(--w-tebal);
  letter-spacing:.01em}
.tombol:hover{background:var(--btn-hover)}
.tombol[disabled]{opacity:.45; cursor:default}
.tombol[disabled]:hover{background:var(--btn-bg)}
.tombol.kedua{background:var(--surface); color:var(--text); border-color:var(--line-strong)}
.tombol.kedua:hover{background:var(--surface-2)}

/* ── 5 · TIPOGRAFI ────────────────────────────────────────────────────── */
h2{margin:0 0 var(--s-2); font-size:var(--t-judul); font-weight:var(--w-tebal);
  letter-spacing:-.015em}
h3{margin:0 0 var(--s-4); font-size:var(--t-sub); font-weight:var(--w-tebal)}
.sub{margin:0 0 var(--s-6); font-size:var(--t-badan); color:var(--mute); line-height:1.55}
.kicker{margin:0 0 var(--s-3); font-family:var(--mono); font-size:var(--t-kicker);
  font-weight:var(--w-tebal); letter-spacing:.15em; text-transform:uppercase; color:var(--mute)}
.bantu{margin:0; font-size:var(--t-kecil); color:var(--mute); line-height:1.5}
.galat{margin:0; font-size:var(--t-dua); color:var(--bad); font-weight:var(--w-tebal); line-height:1.5}

/* Angka jalur uang: tabular, rata kanan, sudut tegas — kebalikan jalur
   sinyal. Perataannya sendiri salah satu dari empat isyarat C.6. */
.angka{font-family:var(--mono); font-variant-numeric:tabular-nums; text-align:right;
  font-weight:var(--w-berat); color:var(--text); white-space:nowrap}
/* Keadaan hitungan — "kosong bukan nol" (C.6). Yang membedakan BENTUKNYA:
   kurang dan lebih tebal; pas biasa; tanya dan belum berganti rupa huruf
   sekalian, supaya "tidak ada angkanya" tidak pernah terbaca sebagai
   angka kecil.
   Berlebih memakai KUNING, bukan merah. G.3 melarang merah/hijau untuk
   kurang-vs-lebih — katanya sudah dibawa kata "kurang"/"lebih" — dan
   merah di produk ini milik bahaya: bayar ganda, rekening kembar. K-01
   sempat memakai merah; K-03 kuning. Kuning yang menang.
   Basisnya sengaja TIDAK menyetel rupa huruf maupun ukuran: di K-03 sel
   `td.ang` sudah monospace, dan memaksakan ukuran di sini akan membesarkan
   angka tabelnya. Keadaan di basis, skala di tempatnya dipakai. */
.kurang{font-weight:var(--w-berat); font-variant-numeric:tabular-nums; color:var(--text)}
.kurang.pas{font-weight:var(--w-biasa); color:var(--dim)}
.kurang.lebih{color:var(--warn)}
.kurang.tanya,.kurang.belum{font-family:var(--font); font-size:var(--t-dua);
  font-weight:var(--w-biasa); color:var(--mute)}
.kurang .kata{font-family:var(--font); font-weight:var(--w-biasa);
  font-size:var(--t-dua); color:var(--mute); margin-right:6px}

.angka-besar{font-family:var(--mono); font-size:var(--t-angka); font-weight:var(--w-berat);
  font-variant-numeric:tabular-nums; line-height:1.1; color:var(--text)}

/* ── 6 · PITA ─────────────────────────────────────────────────────────── */
/* Basisnya bermakna sendiri: pita keterangan netral. Sebelumnya ia
   `border-left:3px solid` tanpa warna, jadi varian yang lupa ditulis
   tampil transparan bergaris putih — dan TETAP TERLIHAT SENGAJA, persis
   jebakan yang membuat bilah samping hilang tanpa ketahuan. Sekarang
   pita tanpa varian terbaca sebagai keterangan, bukan sebagai rusak. */
.pita{padding:var(--s-4) var(--s-5); border-radius:var(--r-kotak); margin:0 0 var(--s-5);
  font-size:var(--t-dua); line-height:1.55; background:var(--surface-2);
  color:var(--dim); border-left:3px solid var(--line-strong)}
.pita.mati { background:var(--idle-soft); color:var(--idle); border-left-color:var(--line-strong) }
.pita.awas { background:var(--warn-soft); color:var(--warn); border-left-color:var(--warn) }
.pita.bahaya{background:var(--bad-soft);  color:var(--bad);  border-left-color:var(--bad) }
.pita.baik { background:var(--ok-soft);   color:var(--ok-ink); border-left-color:var(--ok) }
.pita b{color:var(--text)}
.pita.awas b,.pita.bahaya b,.pita.baik b{color:inherit}

/* Pita hasil — muncul setelah sesuatu berhasil ditetapkan. Beda dari
   .pita.baik: ia menyatakan APA yang barusan terjadi, bukan keadaan yang
   sedang berlaku, jadi ia hidup di bawah aksinya dan bisa disembunyikan.
   Tujuh layar memakainya. */
.hasil{margin:var(--s-6) 0 0; padding:var(--s-5); border-radius:var(--r-kotak);
  background:var(--ok-soft); color:var(--ok-ink); border-left:3px solid var(--ok);
  font-size:var(--t-badan); line-height:1.6}
.hasil[hidden]{display:none}
.hasil b{font-family:var(--mono); font-weight:var(--w-berat)}
.hasil ul{margin:var(--s-3) 0 0; padding-left:18px}
.hasil li{margin:0 0 5px}
/* Varian jalur sinyal: putus-putus dan sudut membulat, supaya hasil di
   Ruang Sinyal tidak pernah terbaca seperti hasil di jalur uang (C.6). */
.hasil.sinyal{border-left-style:dashed; border-radius:0 var(--r-besar) var(--r-besar) 0}

/* ── 7 · CHIP ─────────────────────────────────────────────────────────── */
.chip{display:inline-flex; align-items:center; padding:3px 9px; border-radius:var(--r-halus);
  font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.1em; text-transform:uppercase; white-space:nowrap;
  background:var(--surface-3); color:var(--dim)}
.chip.uang  { background:var(--ok-soft);   color:var(--ok-ink); box-shadow:inset 2px 0 0 var(--ok) }
.chip.awas  { background:var(--warn-soft); color:var(--warn);   box-shadow:inset 2px 0 0 var(--warn) }
.chip.bahaya{ background:var(--bad-soft);  color:var(--bad);    box-shadow:inset 2px 0 0 var(--bad) }
.chip.diam  { background:var(--idle-soft); color:var(--idle);   box-shadow:inset 2px 0 0 var(--line-strong) }
/* Hijau TANPA bilah. Yang bertanda jalur uang adalah .chip.uang — hijau
   PLUS bilah teal — dan tak ada yang lain boleh menyerupainya, supaya
   penanda jalur tidak muncul di layar yang bukan jalur uang. Keadaan
   positif biasa memakai ini: "diwarisi" di K-05, "diterima" di K-06.
   K-06 aslinya memakai bilah teal untuk "diterima"; itu diperbaiki. */
.chip.baik  { background:var(--ok-soft);   color:var(--ok-ink) }
/* Beraksen, dan satu-satunya chip beraksen di produk ini. Ia bukan
   severity melainkan GILIRAN — ada orang yang sedang memegangnya. Naik
   setelah S-06 jadi pemakai kedua sesudah K-10. */
.chip.ditinjau{background:var(--accent-soft); color:var(--accent-ink);
  box-shadow:inset 2px 0 0 var(--accent)}

/* ChipProvenance (E.1 memetakannya ke .chip-sumber). Lima keadaan di spek:
   resmi-kpu · resmi-big · turunan · simulasi · lapangan. Ia menempel pada
   ANGKA, bukan pada halaman, dan sengaja bukan .chip.uang — hijau di sana
   berarti jalur uang, bukan sumber tepercaya; memakainya di sini akan
   menaruh penanda uang di layar jalur sinyal.
   SEVERITY, diputuskan saat K-03 dipindahkan. Spek sendiri yang menjawab:
   `turunan`/`simulasi` "memblokir ekspor ke laporan pemodal & dana
   kampanye" — itu BATAS, bukan bahaya. Merah di produk ini dipakai untuk
   bayar ganda dan rekening kembar; menaruh ekspor terblokir di tingkat
   yang sama akan mengencerkan merahnya. Jadi kuning, dan C-01 yang harus
   pindah dari merah — bukan sebaliknya. */
.chip-sumber{display:inline-flex; align-items:center; padding:3px 9px;
  border-radius:var(--r-halus); font-family:var(--mono); font-size:var(--t-kicker);
  font-weight:var(--w-tebal); letter-spacing:.1em; text-transform:uppercase;
  white-space:nowrap; background:var(--ok-soft); color:var(--ok-ink);
  box-shadow:inset 2px 0 0 var(--ok)}
.chip-sumber.tak-sah{background:var(--warn-soft); color:var(--warn);
  box-shadow:inset 2px 0 0 var(--warn)}
/* Belum ada sumbernya sama sekali — bukan sumber yang buruk. Sejalan
   "kosong bukan nol": yang membedakan kata di dalamnya, bukan warnanya. */
.chip-sumber.kosong{background:var(--idle-soft); color:var(--mute);
  box-shadow:inset 2px 0 0 var(--line-strong)}
/* Varian netral untuk baris yang JUGA membawa chip jalur uang. Di C-01
   tiap baris berkas punya keduanya, dan dua chip hijau bersebelahan akan
   mengaburkan penanda jalurnya — hijau di sana harus tetap berarti uang.
   Jadi bedanya konteks, bukan drift. */
.chip-sumber.diam{background:var(--surface-3); color:var(--dim); box-shadow:none}
/* Jalur sinyal: garis putus-putus dan sudut bulat, supaya terbaca beda
   tanpa warna sama sekali (C.6). */
/* align-self supaya chip tidak melar jadi bilah selebar induk saat ia
   berada di dalam kolom flex — kartu klaim K-01 justru begitu. */
.chip-jalur{display:inline-flex; align-self:flex-start; align-items:center;
  gap:7px; padding:5px 11px;
  border-radius:var(--r-bulat); border:1px dashed var(--accent); background:transparent;
  font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-berat);
  letter-spacing:.14em; text-transform:uppercase; color:var(--accent-ink)}
/* Varian netral. Spek menyebut satu komponen ChipJalur, tapi rupanya dua:
   C-01 memakai yang beraksen, K-01 dan P-02 yang netral. Bentuk putus-
   putusnya sama, jadi keduanya lulus C.6 — yang belum diputus warnanya.
   Diputuskan saat C-01 dan P-01 dipindahkan, bukan ditebak sekarang.  */
.chip-jalur.diam{border-color:var(--line-strong); background:var(--surface-2);
  color:var(--mute)}

/* ── 8 · TOMBOL ───────────────────────────────────────────────────────── */
.btn{appearance:none; min-height:48px; padding:0 18px; border-radius:var(--r-kotak);
  cursor:pointer; background:var(--btn-bg); color:var(--btn-fg); border:1px solid var(--btn-bg);
  font-size:var(--t-tegas); font-weight:var(--w-tebal)}
.btn:hover{background:var(--btn-hover)}
.btn[disabled]{opacity:.45; cursor:default}
.btn[disabled]:hover{background:var(--btn-bg)}
.btn.halus{background:var(--surface); color:var(--text); border-color:var(--line-strong);
  font-weight:var(--w-medium)}
.btn.halus:hover{background:var(--surface-2)}
.btn.halus[disabled]:hover{background:var(--surface)}
/* Tiga tinggi, tiga peran. Prototipe sempat memakai TUJUH — 40 · 44 · 46
   · 48 · 50 · 52 · 60 — dan 44/46/50 cuma derau di antara 40 dan 52.
     kecil  40  aksi di dalam baris tabel atau daftar
     (asal) 48  aksi biasa di layar; minimum aksi sekunder G.1
     besar  52  aksi yang menutup atau menetapkan sesuatu di layar itu
   Layar saksi memakai 56 karena G.1 menyebutnya untuk aksi primer di HP;
   dua prototipe saksi kini 60 dan harus turun saat dipindahkan. */
.btn.kecil{min-height:40px; padding:0 14px; font-size:var(--t-dua)}
.btn.besar{min-height:52px; padding:0 var(--s-7); font-size:var(--t-tegas)}
/* Alasan terkunci selalu menyertai tombol mati. Tombol mati tanpa alasan
   mengundang orang mencari jalan memutarnya. */
.sebab{margin:var(--s-1) 0 0; font-size:var(--t-dua); color:var(--mute); line-height:1.55;
  max-width:62ch}
.aksi{display:flex; gap:var(--s-4); align-items:center; flex-wrap:wrap; margin:var(--s-5) 0 0}

/* ── 8b · ISIAN ───────────────────────────────────────────────────────── */
/* Tinggi 48px mengikuti minimum aksi sekunder G.1. Layar saksi memakai
   56px karena ia aksi primer di HP, satu tangan — itu override yang sah,
   bukan penyimpangan. */
.form{display:flex; flex-direction:column; gap:var(--s-5)}
/* align-items:flex-start supaya kendali menyandang lebarnya sendiri.
   Sebagai kolom flex biasa ia meregangkan SEMUA anaknya, dan isian
   tanggal pun jadi selebar kolom — padahal tanggal punya lebar alami.
   Yang memang perlu penuh menyebutkannya sendiri, di bawah ini. */
.field{display:flex; flex-direction:column; align-items:flex-start; gap:7px}
.field label{font-size:var(--t-badan); color:var(--dim)}
.field input,.field select,.field textarea{min-height:48px; padding:9px var(--s-4);
  border-radius:var(--r-kotak); border:1px solid var(--line-strong);
  background:var(--surface); color:var(--text); font:inherit; font-size:var(--t-isian)}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent)}
.field textarea{min-height:80px; resize:vertical; width:100%}
/* Isian teks bebas mengisi lebar; select dan tanggal tidak. */
.field input[type=text]:not([class]),.field input[type=email],.field input[type=tel]{width:100%}
/* Isian angka: monospace dan tabular-nums, supaya angka yang diketik
   terbaca sebagai angka — dan sempit, karena lebar field ikut menyatakan
   berapa digit yang diharapkan. */
.field input[type=text]{font-family:var(--mono); font-size:var(--t-sub);
  font-weight:var(--w-tebal); font-variant-numeric:tabular-nums; max-width:140px}
.field.salah input{border-color:var(--bad)}

/* Isian alasan. Yang NAIK cuma isinya — textarea, bilah tombol, penghitung
   sisa — karena kotaknya memang beda maksud di tiap layar: B-02 kuning
   (mutasi kembar), B-03 merah (selisih diterima), K-04 tanpa kotak sama
   sekali (alasan baris daftar periksa). Satu nama, tiga hal; yang sama
   disatukan, yang beda dibiarkan beda. */
.alasan textarea{width:100%; min-height:76px; padding:9px 11px;
  border-radius:var(--r-kotak); border:1px solid var(--line-strong);
  background:var(--surface); color:var(--text); font:inherit;
  font-size:var(--t-badan); resize:vertical}
.alasan textarea:focus{border-color:var(--accent)}
.alasan .bar{display:flex; gap:9px; margin-top:9px; align-items:center; flex-wrap:wrap}
.alasan .sisa{font-size:var(--t-kecil); color:var(--mute); font-variant-numeric:tabular-nums}

/* Dua kolom setara. Layar yang kolom kirinya lebih berat memakai .berat-kiri. */
.dua{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:var(--s-7); align-items:start}
.dua.berat-kiri{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
/* `minmax(0,1fr)` untuk alasan yang sama dengan `.badan` di atas: Rakit
   laporan menaruh tabelnya di kolom `.dua`. */
@media (max-width:1023px){ .dua,.dua.berat-kiri{grid-template-columns:minmax(0,1fr); gap:var(--s-6)} }

/* ── 9 · TAB ANTREAN ──────────────────────────────────────────────────── */
.tab-antrean{display:flex; border:1px solid var(--line-strong); border-radius:3px;
  overflow:hidden; margin:0 0 var(--s-6); width:max-content; max-width:100%; flex-wrap:wrap}
.tab-antrean button{appearance:none; background:var(--surface); border:0;
  border-right:1px solid var(--line); padding:11px 17px; min-height:46px; cursor:pointer;
  color:var(--mute); font-size:var(--t-badan)}
.tab-antrean button:last-child{border-right:0}
/* Menerima dua penanda terpilih, dan itu BUKAN cuma utang — keduanya sah,
   tergantung apa yang dikendalikan.
     aria-selected (role="tablist")  kendalinya MEMBELAH isi jadi bagian
       yang saling lepas; tiap baris ada di tepat satu bagian. B-01, B-05,
       K-09, K-10.
     aria-pressed (role="group")     kendalinya MENYARING satu daftar; satu
       pilihan memuat pilihan lain. B-06 "Perlu diperiksa" vs "Semua".
   Menyebut penyaring sebagai tab berbohong kepada pembaca layar: ia
   mengumumkan "tab 2 dari 2" seolah keduanya alternatif, padahal yang satu
   cuma mempersempit yang lain. Yang masih berutang tinggal B-05, K-09, dan
   K-10 — ketiganya membelah, jadi ketiganya harus pakai aria-selected.  */
.tab-antrean button[aria-pressed="true"],
.tab-antrean button[aria-selected="true"]{background:var(--accent-soft);
  color:var(--accent-ink); font-weight:var(--w-tebal)}
/* Lencana angka di dalam tab. */
.tab-antrean .n{font-family:var(--mono); font-size:var(--t-kecil); font-weight:var(--w-berat);
  font-variant-numeric:tabular-nums; background:var(--surface-3); border-radius:var(--r-bulat);
  padding:2px 8px; color:var(--dim); margin-left:7px}
.tab-antrean button[aria-selected="true"] .n,
.tab-antrean button[aria-pressed="true"] .n{background:var(--accent); color:var(--btn-fg)}
/* Angka di tab dimuat lebih dulu dari isinya, supaya beban kerja terbaca
   sebelum daftarnya siap. */
.tab-antrean b{font-family:var(--mono); font-variant-numeric:tabular-nums;
  margin-left:7px; font-weight:var(--w-berat)}
.tab-antrean b.nol{font-weight:var(--w-biasa); opacity:.6}

/* ── 10 · TABEL & DAFTAR ──────────────────────────────────────────────── */
.tabel{width:100%; border-collapse:collapse; font-size:var(--t-dua)}
.tabel th{text-align:left; padding:9px var(--s-4) 9px 0; border-bottom:1px solid var(--line-strong);
  font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.13em; text-transform:uppercase; color:var(--mute); white-space:nowrap}
.tabel td{padding:var(--s-4) var(--s-4) var(--s-4) 0; border-bottom:1px solid var(--line);
  vertical-align:top; line-height:1.55; color:var(--dim)}
.tabel tr:last-child td{border-bottom:0}
.tabel th:last-child,.tabel td:last-child{padding-right:0}
.tabel .utama{color:var(--text); font-weight:var(--w-tebal)}
.tabel .kecil{display:block; margin-top:3px; font-size:var(--t-kecil); color:var(--mute);
  line-height:1.5}

/* Pembungkus tabel lebar: menggeser tabelnya sendiri, bukan halamannya.
   Dipakai B-01, B-03, K-03, P-01 — aturannya sudah tersalin identik di
   dua layar yang lebih dulu dipindahkan. */
.bungkus{border:1px solid var(--line); border-radius:var(--r-kotak);
  overflow-x:auto; background:var(--surface)}
/* Pembungkus yang sama tanpa bingkai, untuk tabel yang sudah punya
   bingkainya sendiri atau memang tidak berbingkai — kisi sembilan kotak
   Medan, tabel banding Bawa. Tabel tanpa pembungkus bergulir ditolak
   alat/uji-ux-statis.mjs: di layar sempit ia memekarkan halamannya. */
.gulir-x{overflow-x:auto}
/* KEDUANYA CONTAINING BLOCK, dan tanpa itu guliran bocor. `overflow`
   tidak memotong turunan ber-`position:absolute` yang containing block-nya
   di luar pembungkus. `.sr` di kepala kolom Rumus Cakupan per kecamatan
   duduk di x=726 di dalam tabel selebar 760px, lolos dari guliran
   pembungkusnya, dan memperlebar dokumen jadi 727px di layar 400px — kolom
   isinya sudah muat, tapi halamannya masih bisa digeser ke ruang kosong. */
.bungkus,.gulir-x{position:relative}

.kotak{border:1px solid var(--line-strong); border-radius:var(--r-kotak);
  background:var(--surface); overflow:hidden}
/* Daftar di dalam kotak selalu berupa baris rancangan sendiri, tidak
   pernah daftar bertitik. Tanpa ini, kotak yang isinya <ul> memunculkan
   bullet di tiap baris — dan itu terlihat seperti gaya, bukan kelalaian. */
.kotak ul{list-style:none; margin:0; padding:0}
.kotak > .hd{margin:0; padding:var(--s-4) var(--s-5); background:var(--surface-2);
  border-bottom:1px solid var(--line-strong); font-family:var(--mono);
  font-size:var(--t-kicker); font-weight:var(--w-tebal); letter-spacing:.15em;
  text-transform:uppercase; color:var(--mute)}

/* Keadaan kosong: tiga jenis yang tidak boleh tertukar dibedakan lewat
   kalimatnya, dan glif — bukan warna. */
.petak-keadaan{padding:var(--s-8) var(--s-6); text-align:center;
  border:1px dashed var(--line-strong); border-radius:var(--r-kotak);
  background:var(--surface-2)}
.petak-keadaan p{margin:0; font-size:var(--t-tegas); color:var(--mute); line-height:1.6}
/* Kosong bersebab (app/keadaan.js, Keadaan.kosong — R6b). Empat sebab,
   dibedakan LABEL dan GLIF: — belum ditetapkan · ? belum ada data ·
   0 tidak ada · ⊂ disaring. Warnanya sama untuk keempatnya. */
.petak-keadaan.kosong{display:flex; flex-direction:column; align-items:center; gap:var(--s-3)}
.petak-keadaan.kosong .kosong-label{display:inline-flex; align-items:center; gap:var(--s-2);
  font-family:var(--mono); font-size:var(--t-kicker); font-weight:var(--w-tebal);
  letter-spacing:.12em; text-transform:uppercase; color:var(--dim)}
.kosong-glif{display:inline-grid; place-items:center; width:22px; height:22px; border-radius:50%;
  border:1px solid var(--line-strong); background:var(--surface); font-size:12px; letter-spacing:0;
  color:var(--text)}
.petak-keadaan.kosong .kosong-kalimat{color:var(--text)}
.petak-keadaan.kosong .kosong-ket{font-size:var(--t-dua); max-width:62ch}
/* Tindakan lanjutannya TAUTAN (ia pindah halaman), bergaya tombol
   sekunder. `.btn` dirancang untuk <button>; tanpa ini <a> di kolom flex
   memanjang setinggi min-height dengan teks menempel di atas. */
.petak-keadaan.kosong .btn{margin-top:var(--s-2); display:inline-flex; align-items:center;
  justify-content:center; text-decoration:none}
.petak-keadaan.kosong.ringkas{padding:var(--s-5); align-items:flex-start; text-align:left;
  border-style:solid; background:transparent}

/* LangkahRantai (app/rantai.js; adendum rencana menang C.10) — satu baris
   di puncak isi keenam layar rantai. Glif statusnya sama dengan keadaan
   kosong: ✓ selesai · — belum ditetapkan · ? belum ada data. Yang sedang
   dibuka ditebalkan dan bergaris bawah, tidak diwarnai. */
.langkah-rantai{margin:0 0 var(--s-5); padding:var(--s-3) var(--s-4); border:1px solid var(--line);
  border-radius:var(--r-kotak); background:var(--surface); font-size:var(--t-dua)}
.langkah-rantai[hidden]{display:none}
.langkah-rantai ol{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap;
  gap:4px var(--s-3); align-items:baseline}
.langkah-rantai li{display:inline-flex; align-items:baseline; gap:6px}
/* Pemisah di AKHIR langkah, bukan di awal berikutnya: saat membungkus di
   layar sempit, "·" yang tergantung jatuh di ujung baris, bukan membuka
   baris kedua. */
.langkah-rantai li:not(:last-child)::after{content:"·"; color:var(--mute); margin-left:var(--s-2)}
.langkah-rantai a{color:var(--text); text-decoration:none}
.langkah-rantai a:hover{text-decoration:underline; text-underline-offset:3px}
.langkah-rantai li[aria-current] a{font-weight:var(--w-tebal); text-decoration:underline;
  text-underline-offset:3px}
.langkah-rantai .langkah-st{font-family:var(--mono); font-size:var(--t-kicker); color:var(--mute);
  white-space:nowrap}
.langkah-rantai li.langkah-selesai .langkah-st{color:var(--ok-ink)}
.langkah-rantai .langkah-cabang{margin:var(--s-2) 0 0; color:var(--dim)}
.langkah-rantai .langkah-cabang a{color:var(--accent-ink); text-decoration:underline; text-underline-offset:3px}

/* ── 11 · PANEL & TIRAI ───────────────────────────────────────────────── */
.tirai{position:fixed; inset:0; background:rgba(8,10,13,.62); display:flex;
  align-items:center; justify-content:center; padding:var(--s-6); z-index:40}
.tirai[hidden]{display:none}
.panel{background:var(--surface); border:1px solid var(--line-strong);
  border-radius:7px; box-shadow:var(--shadow); max-width:560px; width:100%;
  max-height:100%; overflow:auto; padding:var(--s-7) 25px 21px}
@media (max-width:1023px){
  .tirai{padding:0; align-items:stretch}
  .panel{max-width:none; border-radius:0; border:0; padding:26px var(--s-6)}
}
/* Enam prototipe memberi panelnya judul, di bawah LIMA nama berbeda —
   .panel-alasan · .panel-bungkam · .panel-tinjau · .panel-putusan. Satu
   komponen; namanya .panel, dan judul serta galatnya ikut di sini. */
.panel h3{margin:0 0 var(--s-4); font-size:var(--t-sub); font-weight:var(--w-tebal)}
.panel > p{margin:0 0 var(--s-5); font-size:var(--t-tegas); color:var(--dim); line-height:1.6}
.panel .galat{margin:var(--s-3) 0 0; font-size:var(--t-dua); color:var(--bad);
  font-weight:var(--w-tebal)}
.panel textarea{width:100%; min-height:92px; padding:11px var(--s-4);
  border-radius:var(--r-kotak); border:1px solid var(--line-strong);
  background:var(--surface); color:var(--text); font:inherit; font-size:var(--t-isian);
  resize:vertical}
.panel textarea:focus{border-color:var(--accent)}
.panel .aksi{justify-content:flex-end}

/* ── 12 · PANEL RUMUS ─────────────────────────────────────────────────── */
/* Isi wajib: rumus · nilai tiap suku · sumber tiap suku · siapa menetapkan
   · kapan dihitung. Panelnya hidup di tempat angkanya jadi pokok bahasan,
   bukan di setiap layar yang menyebutnya. */
/* Tombol ungkap: bergaya tautan, membuka penjelasan di tempat. Sempat
   bernama .rumusbtn — nama yang diambil dari satu pemakaiannya saja,
   padahal K-05 memakai bentuk yang persis sama untuk "kenapa?". Empat
   layar, satu bentuk; namanya sekarang menyebut apa yang ia lakukan. */
.ungkap{appearance:none; background:none; border:0; cursor:pointer; padding:var(--s-2) 0;
  color:var(--accent-ink); font-size:var(--t-dua); text-decoration:underline;
  text-underline-offset:3px}
.ungkap:hover{color:var(--accent)}
.panel-rumus{margin:var(--s-4) 0 0; padding:var(--s-5); border-radius:var(--r-kotak);
  border:1px dashed var(--line-strong); background:var(--surface-2)}
.panel-rumus[hidden]{display:none}
.panel-rumus dl{margin:0; display:grid; grid-template-columns:minmax(0,max-content) minmax(0,1fr);
  gap:7px var(--s-5); font-family:var(--mono); font-size:var(--t-dua)}
.panel-rumus dt{color:var(--mute)}
.panel-rumus dd{margin:0; color:var(--text); font-variant-numeric:tabular-nums}
.panel-rumus dd .asal{display:block; margin-top:3px; font-family:var(--font);
  font-size:var(--t-kecil); color:var(--mute); line-height:1.5}
.panel-rumus .kapan{margin:11px 0 0; font-family:var(--font); font-size:var(--t-kecil);
  color:var(--mute)}
/* app/rumus.js (R6b) — tiga cara menghadirkan isi yang sama.
   Baris hasil dipisah garis; nilai yang tidak dikirim "? belum ada data"
   dalam huruf teks, supaya tidak terbaca sebagai angka kecil. */
.panel-rumus dt.rumus-hasil, .panel-rumus dd.rumus-hasil{padding-top:7px; border-top:1px solid var(--line);
  font-weight:var(--w-tebal)}
.panel-rumus .tak-tahu{font-family:var(--font); color:var(--mute)}
.panel-rumus .rumus-catatan{margin:11px 0 0; font-family:var(--font); font-size:var(--t-kecil);
  color:var(--dim); line-height:1.55}
.panel-rumus.terbuka{margin:0}
/* Sempit: label di atas nilainya. Dua kolom di 390 px memberi label mono
   yang panjang ("Koordinator Relawan per TPS") seluruh lebarnya, dan
   nilainya terpotong di tepi panel. */
@media (max-width:600px){
  .panel-rumus dl{grid-template-columns:minmax(0,1fr); gap:2px}
  .panel-rumus dd{margin-bottom:var(--s-3)}
  .panel-rumus dt.rumus-hasil{padding-top:9px}
  .panel-rumus dd.rumus-hasil{padding-top:0; border-top:0}
}
.panel-rumus .langkah-hitung{margin:11px 0 0; padding:11px 0 0; list-style:none;
  border-top:1px solid var(--line); font-family:var(--mono); font-size:var(--t-dua);
  color:var(--dim); line-height:1.7; word-break:break-word}
/* Lipat: <details>. Penanda segitiga bawaan dibuang — "buka rumus" sudah
   kata kerjanya — dan panelnya menempel di bawah pemicunya. */
.rumus-lipat{margin:var(--s-3) 0 0}
.rumus-lipat > summary{list-style:none; display:inline-block}
.rumus-lipat > summary::-webkit-details-marker{display:none}
.rumus-lipat > .panel-rumus{margin-top:var(--s-2)}
/* Tombol ikon ⓘ di baris tabel (K-03): bulat, tanpa garis bawah. */
.ungkap.ikon{width:28px; height:28px; padding:0; border:1px solid var(--line-strong);
  border-radius:var(--r-bulat); text-decoration:none; color:var(--dim); line-height:1;
  display:inline-flex; align-items:center; justify-content:center}
.ungkap.ikon:hover{border-color:var(--accent)}
.ungkap.ikon[aria-expanded="true"]{border-color:var(--accent); color:var(--accent-ink)}

/* ── 13 · KARTU MASA BERLAKU ──────────────────────────────────────────
   Kartu untuk pemberian yang WAJIB BERAKHIR dan bisa dicabut lebih awal.
   Dua tabel di skema berbentuk sama persis — `pembungkaman_penanda`
   (K-09) dan `kapasitas_penyetuju` (C-04): append-only, `berakhir_pada`
   not null, mencabut berarti baris baru. Kartunya karena itu juga sama,
   dan ia harus memperlihatkan tiga hal sekaligus: apa yang diberikan,
   sampai kapan, dan atas alasan apa.

   Sisa waktu duduk di kanan kepala, ditulis sebagai TANGGAL + JUMLAH
   HARI. Tanggal saja menuntut pembacanya menghitung sendiri; jumlah hari
   saja menghilangkan patokan yang bisa dicek. Judul kartunya diserahkan
   ke layar masing-masing — di K-09 nama aturan (mono), di C-04 nama
   orang (bukan mono) — karena yang sama adalah kerangkanya, bukan
   isinya.                                                             */
.kartu-masa{border:1px solid var(--line-strong); border-radius:var(--r-kotak);
  background:var(--surface); padding:var(--s-5); margin:0 0 var(--s-4)}
.kartu-masa .kepala{display:flex; align-items:baseline; gap:13px;
  flex-wrap:wrap; margin:0 0 var(--s-3)}
.kartu-masa .sisa{margin-left:auto; font-size:var(--t-dua); color:var(--mute); white-space:nowrap}
.kartu-masa .sisa.dekat{color:var(--warn); font-weight:var(--w-tebal)}
.kartu-masa .alasan{margin:0 0 var(--s-3); font-size:var(--t-dua);
  color:var(--dim); line-height:1.6}
.kartu-masa .kaki{display:flex; align-items:center; gap:13px; flex-wrap:wrap;
  font-size:var(--t-kecil); color:var(--mute)}
/* Tombol pertama yang didorong ke kanan, bukan tiap tombol: kartu
   dengan dua aksi (C-04: perbarui, cabut) kalau tidak akan
   menyebarkannya ke dua ujung seolah keduanya tak berhubungan. */
.kartu-masa .kaki .btn:first-of-type{margin-left:auto}

/* ── 14 · DAFTAR AKIBAT ───────────────────────────────────────────────
   Sepasang daftar yang HARUS dibaca bersama: apa yang berhenti, dan apa
   yang tetap ada. Naik ke sini saat C-03 jadi pemakai kedua sesudah S-09,
   dan bentuknya sama karena kesalahannya sama: orang yang menarik
   persetujuan mengira datanya terhapus, orang yang menyetujui penghapusan
   mengira jejaknya ikut hilang. Menampilkan satu kolom saja membiarkan
   dugaan itu berdiri — dan ia baru ketahuan salah saat sudah terlambat.

   Warnanya menandai, bukan memberi tahu: judul kolomnya sudah menyebut
   apa isinya, jadi dicetak hitam-putih pun bedanya bertahan (C.6). */
.akibat{display:flex; flex-direction:column; gap:var(--s-5)}
.akibat .grup > .hd{margin:0 0 7px; font-family:var(--mono); font-size:var(--t-kicker);
  font-weight:var(--w-tebal); letter-spacing:.13em; text-transform:uppercase}
.akibat .berhenti > .hd{color:var(--warn)}
.akibat .tetap > .hd{color:var(--ok-ink)}
.akibat ul{margin:0; padding-left:19px; display:flex; flex-direction:column; gap:6px}
.akibat li{font-size:var(--t-dua); color:var(--dim); line-height:1.55}
/* Di layar lebar keduanya berdampingan; di HP bertumpuk. Yang tidak boleh
   terjadi: salah satunya berada di luar layar saat yang lain terbaca. */
@media (min-width:900px){
  .akibat{flex-direction:row; gap:var(--s-7)}
  .akibat .grup{flex:1; min-width:0}
}

/* Baris aksi di bawah daftar: tombolnya dan kalimat yang menyebut apa
   yang wajib diisi sebelum menekannya. */
.aksi-bawah{margin:var(--s-6) 0 0; display:flex; gap:var(--s-4);
  align-items:center; flex-wrap:wrap}


/* ── 17 · CETAK ────────────────────────────────────────────────────────
   C.6 menyebut "cetak hitam-putih" sebagai uji sebelum handoff di empat
   tempat berbeda di spek, dan sampai 5 Sep 2026 tidak ada satu pun aturan
   `@media print` di seluruh proyek — ujinya tidak pernah bisa dijalankan
   sebagaimana ia ditulis. Keluaran cetak termasuk penanda yang tidak
   terlihat saat layarnya diperiksa: setiap tinjauan melihat jendelanya,
   dan kertas tidak pernah ikut ditinjau.

   Yang dijalankan ujinya adalah MEMBUANG WARNA, bukan membuang isyarat.
   Browser secara bawaan tidak mencetak latar maupun bayangan, dan itu
   membuang dua hal sekaligus: warnanya (memang disengaja) DAN bilah kiri
   chip (tidak disengaja) — karena bilah itu digambar `box-shadow:inset`,
   bukan `border`. Tanpa blok ini, cetakannya menghapus lapis "garis" C.6
   diam-diam, lalu terlihat lulus dengan tiga lapis padahal diklaim empat.
   Bilahnya karena itu digambar ulang sebagai border di sini.

   Yang TIDAK dilakukan blok ini: memaksa `print-color-adjust:exact`.
   Warna memang harus hilang — itu seluruh isi ujinya.                 */
@media print{
  /* Panel fasilitator bukan bagian produk, dan mencetaknya membuat
     halaman pertama tiap cetakan berisi alat peraga. */
  .fasil{display:none !important}

  /* Bayangan tidak tercetak; menyatakannya di sini supaya tata letaknya
     tidak bergeser antara layar dan kertas. */
  *{box-shadow:none !important; text-shadow:none !important}

  /* Bilah jalur chip, digambar ulang sebagai border supaya ia SAMPAI di
     kertas. Lebar dan warnanya sama; yang berubah cuma cara menggambar. */
  .chip{border-left:2px solid transparent}
  .chip.uang  {border-left-color:var(--ok)}
  .chip.awas  {border-left-color:var(--warn)}
  .chip.bahaya{border-left-color:var(--bad)}
  .chip.diam  {border-left-color:var(--line-strong)}
  /* Ditemukan pemeriksanya sendiri, bukan mata: varian kelima yang
     terlewat saat blok ini ditulis tangan. */
  .chip.ditinjau{border-left-color:var(--accent)}
  /* .chip-jalur TIDAK disebut di sini, dan justru itu isi temuannya: ia
     sudah memakai `border` sungguhan, jadi ia sampai di kertas tanpa
     dibantu. Chip jalur uang tidak. Kedua penanda jalur digambar dengan
     dua cara yang berbeda, dan bedanya tak terlihat sama sekali di layar
     — ia baru muncul di media yang tidak pernah diperiksa siapa pun. */

  /* TIDAK ada aturan yang menambahkan garis ke kartu dan panel di sini,
     meski versi pertama blok ini punya. Ternyata semuanya sudah bergaris
     sendiri — .app, .kartu-*, .panel-rumus, .petak-keadaan — dan yang dua
     terakhir bergaris PUTUS-PUTUS dengan sengaja. Menimpanya dengan garis
     padat "supaya batasnya tidak hilang" justru menghapus perbedaan yang
     garis itu bawa, tepat di kertas tempat warna sudah tidak ada.
     Aturan yang menyelesaikan masalah yang tidak ada tetap punya akibat.

     Kertas tidak punya gulir. `.bungkus` menggulir mendatar dan `.panel`
     menegak; yang di balik gulir akan terpotong tanpa jejak kalau tidak
     dibuka di sini. */
  .bungkus,.gulir-x,.panel{overflow:visible !important; max-height:none !important}

  /* Di kertas, kerangka muat adalah janji yang tidak pernah ditepati: tidak
     ada apa pun yang akan datang mengisinya. Diganti satu baris jujur. */
  .kerangka-muat{display:none}
  .kerangka-muat + .kerangka-ket{display:block}
}

/* ─────────────────────────────────────────────────────────────────────
   MEMUAT dan GAGAL MUAT
   Dua keadaan yang selama ini cuma ada di tabel State dan tidak pernah
   ada di layar, karena tidak satu pun prototipe punya cara mencobanya.
   Ditaruh di sini, bukan di tiap layar, supaya keduanya tidak lahir
   sepuluh versi berbeda.

   Namanya .kerangka-muat, bukan .kerangka. Kata "kerangka" sudah dipakai
   lembar ini untuk kerangka TATA LETAK — dua lebar, satu kerangka — dan
   dua arti yang sama namanya di satu berkas adalah cara memastikan
   seseorang kelak menghapus yang salah.
   ───────────────────────────────────────────────────────────────────── */

/* Kerangka, BUKAN pemintal. Spek menyebutnya begitu di lima layar, dan
   alasannya bukan selera: pemintal tidak memberi tahu berapa banyak yang
   akan datang, jadi halaman melompat begitu isinya tiba. Kerangka dengan
   JUMLAH BARIS YANG BENAR membuat tinggi halaman sudah betul sebelum
   satu angka pun ada. Itu sebabnya penolongnya menuntut n. */
.kerangka-muat{display:flex; flex-direction:column; gap:var(--s-3); margin:0 0 var(--s-5)}
.kerangka-muat > i{display:block; height:var(--tinggi-tulang,44px); border-radius:var(--r-kotak);
  background:var(--surface-2); border:1px solid var(--line);
  position:relative; overflow:hidden}
.kerangka-muat.baris > i{--tinggi-tulang:44px}
.kerangka-muat.kartu > i{--tinggi-tulang:96px}
.kerangka-muat.tabel > i{--tinggi-tulang:38px; border-radius:0; border-left:0; border-right:0}
.kerangka-muat > i::after{content:""; position:absolute; inset:0;
  background:linear-gradient(90deg, transparent, var(--surface), transparent);
  transform:translateX(-100%); animation:tulang-lewat 1.15s ease-in-out infinite}

@keyframes tulang-lewat{ to{ transform:translateX(100%) } }

/* Gerak yang berulang tanpa henti adalah gerak yang paling mengganggu
   orang yang memintanya berhenti. Tanpa gerakan, tulangnya tetap
   terbaca — yang hilang cuma kilaunya. */
@media (prefers-reduced-motion: reduce){
  .kerangka-muat > i::after{ animation:none }
}

/* .kerangka-ket cuma terlihat di kertas — aturannya ada di blok @media
   print bagian 17, bukan di sini, karena satu berkas sebaiknya punya SATU
   bagian cetak. Blok cetak kedua tidak salah secara CSS, tapi ia memecah
   tempat orang mencari, dan periksa.py sempat membaca yang terakhir saja. */
.kerangka-ket{display:none; color:var(--mute); font-size:var(--t-dua)}

/* Pita gagal muat. Ia BERTAMBAH di atas isi, tidak menggantikannya —
   itu inti keadaannya di lima spek sekaligus: "daftar terakhir tetap
   terbaca", "tabel terakhir tetap terbaca", "angka lama + gagal
   menyegarkan". Kegagalan menyegarkan bukan alasan untuk menghapus apa
   yang sudah ada di tangan. */
.pita.gagal{background:var(--bad-soft); color:var(--bad); border-left-color:var(--bad);
  display:flex; flex-wrap:wrap; gap:var(--s-3) var(--s-4); align-items:baseline}
.pita.gagal .pesan{flex:1 1 18em}
.pita.gagal button{appearance:none; background:transparent; border:1px solid currentColor;
  border-radius:var(--r-kotak); color:inherit; padding:5px 12px; cursor:pointer;
  font:inherit; font-size:var(--t-dua)}
.pita.gagal button:hover{background:var(--bad); color:var(--surface)}

/* ═══════════════════════════════════════════════════════════════════════
   LACI NAVIGASI PONSEL — milik seluruh layar bersisi, bukan satu
   ═══════════════════════════════════════════════════════════════════════
   Pola ini lahir di app/beranda.html dan tinggal di sana sendirian: 38
   layar bersisi lain merender navigasinya memanjang di dalam halaman.
   Diukur di 375 px — app/tutup.html menaruh navigasi setinggi 403 px
   dengan delapan tautan sebelum satu baris isi pun mulai, jadi isinya baru
   dimulai di 567 px dari 812 px yang ada. Tujuh puluh persen layar
   pertama habis sebelum orangnya melihat apa yang ia datangi.

   Dipindahkan ke sini utuh, dan tombolnya dibangun app/akun.js untuk tiap
   layar yang punya `.sisi` — sama seperti penanda tenant mobile yang juga
   dibangun di sana. Satu tempat, bukan tiga puluh sembilan yang harus
   diingat satu-satu.
   ═══════════════════════════════════════════════════════════════════════ */
/* WARNA DI LUAR MEDIA QUERY, tata letak di dalamnya. Sebelumnya keduanya
   di dalam, jadi di desktop tombol ini — walau display:none — mewarisi
   warna bawaan browser. Begitu halaman menyatakan color-scheme "light
   dark", bawaan itu jadi abu gelap, dan sapuan kontras menemukannya
   sebagai teks 4,36:1 di atas #6B6B6B. Tidak terlihat siapa pun karena
   tersembunyi — tapi elemen yang benar hanya selama ia tak terlihat
   adalah elemen yang menunggu giliran untuk salah. */
.b-ruang{display:none; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-kotak); color:var(--text); font-size:var(--t-badan);
  text-align:left; cursor:pointer}
@media (max-width:899px){
  .b-ruang{display:flex; align-items:center; gap:10px; width:calc(100% - var(--s-5)*2);
    margin:var(--s-5) var(--s-5) 0; padding:0 14px; min-height:48px}
  .b-ruang .tag{font:var(--w-tebal) var(--t-chip)/1 var(--mono); letter-spacing:.1em;
    text-transform:uppercase; color:var(--ok); background:var(--ok-soft);
    border-radius:3px; padding:5px 7px}
  .b-ruang .chev{margin-left:auto; display:flex; color:var(--mute);
    transition:transform .15s}
  .b-ruang[aria-expanded="true"] .chev{transform:rotate(180deg)}
  .b-ruang[aria-expanded="true"]{background:var(--surface-2)}
  /* Butir menu di dalam laci adalah sasaran JARI. Tanpa lantai ini
     tingginya 36-37px — di bawah 44px, dan di bawah tinggi pembukanya
     sendiri (48px). Beranda memberi dirinya aturan ini; 45 layar lain
     tidak. (UX-07, audit 15 Sep.) */
  .menu button,.menu a{min-height:44px}
  /* Tertutup secara bawaan DI MARKUP, bukan oleh skrip: kalau skripnya
     gagal dimuat, yang tersisa harus navigasi yang TERLIHAT — bukan menu
     yang hilang tanpa ada yang bisa membukanya. Karena itu yang menyembunyikan
     adalah kelas yang DIPASANG skrip, dan bukan sebaliknya. */
  .sisi.b-tutup{display:none}
}
