/* ==========================================================================
   PERBAIKAN TAMPILAN — 13 September 2026
   --------------------------------------------------------------------------
   Menindaklanjuti "Rapor Tampilan PATITA" (12 Sep). Dimuat SESUDAH style.css
   di index.html, jadi ia menang pada kekhususan yang sama tanpa perlu
   !important di mana-mana. !important hanya dipakai di tempat yang aturan
   lawannya sendiri memakai !important — setiap kejadian diberi alasan.

   MENCABUT: hapus <link> berkas ini di index.html (dan <script> pasangannya).
   Tidak ada berkas lain yang bergantung padanya.

   ┌────────────────────────────────────────────────────────────────────────┐
   │ DAERAH TERLARANG — tidak satu pun aturan di bawah boleh menyentuhnya.  │
   │                                                                        │
   │   .xt-sheet  .fkl-doc  .lar-kertas  .hps-uraian  .hps-sum  .kl-ed-*    │
   │   #view-spk-susun  #view-tor-susun  #view-rekap-hps  #view-klausul-edit│
   │   #view-spk-view  #view-tor-view  #view-fkl-view  #view-dp-view        │
   │   dan seluruh isi @media print                                         │
   │                                                                        │
   │ Sebabnya: itu semua reproduksi KERTAS, disetel per piksel selama       │
   │ sebulan terakhir (lihat 20-an catatan "lembar apa adanya", "kerapian   │
   │ HPS", "inden blok uraian"). Ukuran huruf dan warna di sana adalah      │
   │ HASIL PENGUKURAN, bukan selera — menaikkannya "biar terbaca" merusak   │
   │ padanan dengan Excel dan hasil cetak.                                  │
   │                                                                        │
   │ Karena itu setiap aturan di bawah diikat ke pemilih antarmuka yang     │
   │ jelas (#view-dashboard, .toolbar, .card, .fk-seg, .sidebar, .empty),   │
   │ bukan ke pemilih menyeluruh seperti `body` atau `table`.               │
   └────────────────────────────────────────────────────────────────────────┘
   ========================================================================== */


/* ==========================================================================
   0. TOKEN TAMBAHAN
   --------------------------------------------------------------------------
   DITAMBAHKAN, bukan menggantikan. Sepuluh blok :root di style.css sengaja
   TIDAK disentuh — mencabutnya butuh menelusuri 17.381 baris dan itu
   pekerjaan tersendiri. Yang ini memberi nama pada nilai-nilai yang selama
   ini ditulis berulang, supaya kode baru punya tempat berpegang.

   Skala huruf: tujuh anak tangga menggantikan 63 nilai yang berserak.
   Ditulis dalam rem supaya pengaturan ukuran huruf di peramban pengguna
   akhirnya berpengaruh — selama ini hampir semuanya px, jadi tidak.
   Dasar peramban 16px: 0.75rem = 12px, 0.8125rem = 13px, dst.
   ========================================================================== */
:root{
  --sk-1:0.75rem;    /* 12px — terkecil yang boleh dipakai untuk teks     */
  --sk-2:0.8125rem;  /* 13px — keterangan, label                          */
  --sk-3:0.875rem;   /* 14px — teks isi                                   */
  --sk-4:1rem;       /* 16px — judul panel                                */
  --sk-5:1.25rem;    /* 20px — judul bagian                               */
  --sk-6:1.625rem;   /* 26px — angka KPI                                  */
  --sk-7:2.125rem;   /* 34px — angka utama                                */

  --z-isi:1; --z-lengket:40; --z-tirai:45; --z-bilah:55;
  --z-sisi:70; --z-tempel:120; --z-modal:12000;

  /* Semantik warna. --teal tetap warna aksi; merah DIPERSEMPIT jadi milik
     hal yang merusak saja (lihat bagian 6). */
  --tindak:var(--teal,#0E7C86);
  --rusak:var(--red,#D33A3A);
  --awas:#8a5a00;
  /* Hijau dipergelap dari #1E9E5A: dengan teks putih rasio lamanya 3,45:1,
     di bawah ambang WCAG AA 4,5:1 untuk teks setebal ini. #157A44 → 5,29:1. */
  --hijau-aa:#157A44;
  /* Redup dipergelap dari #64757F: 4,22:1 di atas latar halaman #EEF1F4,
     juga di bawah 4,5:1. #55676F → 5,04:1 di latar halaman, 5,71:1 di kartu. */
  --redup-aa:#55676F;
}


/* ==========================================================================
   1. TAB AKTIF TIDAK LAGI PUTIH DI ATAS PUTIH            [temuan 01]
   --------------------------------------------------------------------------
   GEJALA: di Daftar Tender, label "Tender" — tab yang sedang aktif — tidak
   terbaca sama sekali.

   SEBAB: style.css:2291 `.fk-seg-btn.active{background:none;color:#fff}`.
   Teks putihnya mengandalkan pil teal yang DIGESER JAVASCRIPT
   (fkSegSyncThumb, js/app.js:12455) untuk memberi latar. Selama pil itu
   belum diposisikan — cat pertama, pindah halaman sebelum fkSegSyncAll
   sempat jalan, ubah ukuran jendela, atau satu galat JS di berkas lain —
   yang tersisa putih di atas putih.

   Pola yang benar SUDAH ADA di berkas yang sama, style.css:2389, untuk
   varian .mod-seg. Di sini ia dipakai untuk .fk-seg biasa.

   Pil gesernya TIDAK dicabut: ia digambar di atas latar ini dan tetap
   memberi gerak perpindahannya. Yang berubah hanya satu — keterbacaan tidak
   lagi bergantung pada JavaScript. */
.fk-seg-btn.active,
.fk-seg-btn.active:hover{
  background:linear-gradient(135deg,var(--teal,#0E7C86),var(--cyan,#16a9b5));
  color:#fff;
  box-shadow:0 4px 12px rgba(14,124,134,.28);
}
/* Ikon di dalamnya ikut putih — tanpa ini ikonnya mewarisi warna teal dan
   hilang juga, cuma lebih samar sehingga lebih lama ketahuan. */
.fk-seg-btn.active svg{ color:#fff }


/* ==========================================================================
   2. PENYARING DASHBOARD DI PONSEL                       [temuan 02]
   --------------------------------------------------------------------------
   GEJALA di 390px: keempat penyaring terbaca "PL &", "Semu", "Semu", "Semu".
   Tiga di antaranya tidak bisa dibedakan, padahal SELURUH angka di bawahnya
   bergantung pada pilihan itu.

   SEBAB, dua aturan yang bertemu:
     style.css:11851  .dash-filter-bar{ flex-wrap:nowrap }
     style.css:11855  .filter-field{ flex-basis:0 !important; min-width:0 !important }
   Empat medan berbagi ±358px → ±82px masing-masing. Komentar aslinya
   menyebut "keempatnya memenuhi lebar pita dalam satu baris" — benar untuk
   desktop, tidak pernah ditinjau ulang untuk ponsel.

   PERBAIKAN: di bawah 640px jadi kisi dua kolom (±171px per medan — cukup
   untuk "Semua Anggaran"), dan LABELNYA DIKEMBALIKAN. Tanpa label, "Semua
   Tahun" dan "Semua Periode" sama-sama terbaca "Semua …" saat terpotong;
   dengan label, medan yang mana pun langsung jelas.

   !important dipakai karena aturan lawannya memakai !important. */
@media (max-width:640px){
  #view-dashboard > .page-head .dash-filter-bar{
    display:grid !important;
    grid-template-columns:repeat(2,minmax(0,1fr)) !important;
    gap:12px 10px !important;
    flex-wrap:wrap !important;
  }
  #view-dashboard .dash-filter-bar .filter-field{
    flex:none !important;
    min-width:0 !important;
    gap:5px !important;
  }
  #view-dashboard .dash-filter-bar .filter-field > label{
    display:block !important;
    font-size:var(--sk-1) !important;   /* 12px, naik dari 9,5px */
    font-weight:600;
    letter-spacing:.04em;
    text-transform:none;                /* kapital semua pada 12px terlalu ramai */
    text-align:left !important;
    color:rgba(255,255,255,.82);        /* labelnya duduk di kop gelap */
    opacity:1;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  #view-dashboard .dash-filter-bar .filter-field > label::before{
    display:none;                       /* titik hiasan tidak perlu di ruang sesempit ini */
  }
  #view-dashboard .dash-filter-bar .filter-field select{
    width:100% !important; min-width:0 !important; max-width:none !important;
    font-size:var(--sk-2) !important;
    padding-inline:12px 34px !important;
    text-overflow:ellipsis;
  }
}
/* AMBANG SATU KOLOM DITURUNKAN 380px -> 320px.       15 September 2026
   KETENTUAN PEMILIK: "bisa dijadikan 1 baris 2 field filter biar tidak
   tinggi halamannya."

   Dugaan "di bawah 380px dua kolom pun mulai sempit" ditulis 13 September
   tanpa diukur, dan 360px justru lebar ponsel Android yang paling lazim —
   sehingga di layar yang PALING butuh hemat tinggi, penyaringnya kembali
   satu per baris dan kop gelapnya tumbuh jadi 422px, lebih dari separuh
   layar.

   SEKARANG DIUKUR, pada 360px: pita penyaring mendapat 320px, dua kolom
   dengan sela 10px memberi 155px per medan. Dikurangi bantalan kiri 12px
   dan kanan 34px (ruang anak panah), tersisa 109px untuk tulisannya.
   Pilihan terpanjang yang harus terbaca, "Semua Anggaran" pada 12px,
   memakai ±92px. Muat, dengan sisa — dan label di atasnya tetap ada,
   sehingga alasan pengembalian label 13 September ("Semua Tahun" dan
   "Semua Periode" sama-sama terbaca "Semua …") tidak dilanggar.
   Terukur sesudahnya: kop 422px -> 264px.

   320px dipertahankan sebagai ambang terakhir: itu lebar ponsel lawas
   (iPhone SE generasi pertama), dan di sana 109px tadi tinggal ±89px. */
@media (max-width:319px){
  #view-dashboard > .page-head .dash-filter-bar{
    grid-template-columns:1fr !important;
  }
}


/* ==========================================================================
   3. KARTU KPI TIDAK LAGI YATIM, JUDUL TIDAK LAGI TIGA BARIS  [temuan 03]
   --------------------------------------------------------------------------
   GEJALA: lima kartu di kisi dua kolom menyisakan satu kartu sendirian
   dengan lubang kosong di sebelahnya. Dan judul "Dashboard Pengadaan
   Langsung & Tender" melipat jadi tiga baris, sehingga kop memakan 420 dari
   844px sebelum satu angka pun terlihat.

   PERBAIKAN kartu: kartu terakhir pada jumlah GANJIL melebar penuh.
   `:last-child:nth-child(odd)` hanya benar ketika jumlah anaknya ganjil —
   tidak perlu tahu berapa kartunya, jadi tetap benar kalau nanti kartunya
   ditambah atau dikurangi.

   PERBAIKAN judul: clamp() — mengalir antara 17px dan 26px mengikuti lebar
   layar, tidak melipat pada lebar berapa pun. */
@media (max-width:640px){
  #view-dashboard .cards{
    grid-template-columns:repeat(2,minmax(0,1fr)) !important;
    gap:11px !important;
  }
  #view-dashboard .cards > .card:last-child:nth-child(odd){
    grid-column:1 / -1;
  }
  /* Panel Efisiensi memang selalu selebar penuh. */
  #view-dashboard .cards > .efisiensi-card:last-child:nth-child(odd){
    grid-column:1 / -1;
  }
}
/* Label dua baris ("Total Pekerjaan", "Gagal / Batal") membuat angka di
   bawahnya turun, sementara tetangganya yang berlabel satu baris tidak —
   dalam satu baris kartu, angkanya jadi tidak sejajar. Kepala kartu diberi
   tinggi minimum dua baris supaya seluruh angka berangkat dari garis yang
   sama, dan barisnya terbaca sebagai satu benda, bukan kartu yang berdiri
   sendiri-sendiri. */
#view-dashboard .cards .card .card-head{
  min-height:42px;
  align-items:center;
}

#view-dashboard > .page-head #dash-title{
  font-size:clamp(1.0625rem, 1.4vw + 0.78rem, 1.625rem);  /* 17px → 26px */
  line-height:1.2;
  text-wrap:balance;   /* kalau tetap dua baris, belahnya di tempat yang masuk akal */
}
#view-dashboard > .page-head .dash-sub{
  font-size:var(--sk-1);   /* 12px, naik dari 10px */
}


/* ==========================================================================
   4. TABEL: KEPALA MENEMPEL + TANDA MASIH ADA KOLOM DI KANAN  [temuan 04]
   --------------------------------------------------------------------------
   GEJALA: kolom "Metode Pengadaan" terpancung di tepi kanan tanpa tanda
   apa pun bahwa tabelnya masih berlanjut.

   WARNA KEPALA TABEL SENGAJA TIDAK DIUBAH. Rapor 12 Sep menyebut blok teal
   berhuruf kapital putih itu "bahasa visual 2014" — tetapi catatan 6
   September ("garis tepi samar") menunjukkan warna tabel adalah pilihan
   sadar pemilik, diputuskan sesudah mengukur kontras. Mengganti yang sudah
   diputuskan dengan sengaja bukan perbaikan, itu selera yang ditumpangkan.
   Yang diperbaiki di sini hanya yang FUNGSIONAL.

   Kelas .ada-kanan dipasang/dilepas js/tampilan-modern.js saat digulir.
   Dikecualikan: tabel dokumen (.hps-uraian/.hps-sum/.xt-sheet/.fkl-doc). */
.table-wrap{ position:relative }

/* z-index 6, BUKAN 2.                                    13 September 2026
   LAPORAN PEMILIK: "kolom aksi rusak tampilannya" — ikon pensil/mata/tong
   sampah baris pertama tampak menembus kepala tabel dan bertindih dengan
   tulisan "AKSI".

   Sebabnya adu lapisan yang seri, bukan latar yang bolong:
       css/style.css:1876   .act svg{ position:relative; z-index:2 }
   Ikon itu elemen berposisi ber-z-index 2. Kepala tabel yang menempel juga
   berposisi ber-z-index 2. Keduanya milik konteks penumpukan yang SAMA
   (.table-wrap hanya position:relative tanpa z-index, jadi ia tidak membuat
   konteks baru), dan pada nilai yang seri urutan dokumen yang memutuskan —
   <tbody> ditulis SESUDAH <thead>, jadi ikonnya menang.

   Yang dinaikkan kepala tabelnya, bukan yang diturunkan ikonnya: menurunkan
   z-index .act svg berarti menyentuh aturan yang juga dipakai di luar tabel.
   6 masih jauh di bawah lapisan yang menghalangi (#dpeng-list-overlay 96,
   .overlay 100), jadi tidak ada pop-up yang tertutup olehnya. */
.table-wrap thead th{
  position:sticky; top:0; z-index:6;
}
/* Lembar dokumen dikembalikan: di sana kepala tabel harus ikut mengalir
   bersama kertasnya, bukan menempel di layar. */
.table-wrap table.hps-uraian thead th,
.table-wrap table.hps-sum thead th,
.table-wrap table.xt-sheet thead th,
.fkl-doc .table-wrap thead th,
.lar-kertas .table-wrap thead th{
  position:static;
}

/* Bayangan tepi kanan: muncul hanya selama masih ada yang bisa digulir.

   translate() DI BAWAH BUKAN HIASAN — itu yang menahannya di tempat.
                                                         15 September 2026
   LAPORAN PEMILIK: "bayangannya" — pitanya berdiri melintang di TENGAH
   tabel, memotong kolom Nilai Pekerjaan dari kepala sampai baris terakhir,
   bukan menempel di tepi kanan.

   Sebabnya aturan lama CSS, bukan salah hitung: kotak berposisi ABSOLUT di
   dalam wadah bergulir ditata terhadap kotak padding wadahnya dalam keadaan
   BELUM digulir, lalu IKUT BERGULIR bersama isinya. Jadi right:0 memang
   tepat di tepi kanan selama scrollLeft masih 0; begitu tabelnya digulir
   300px ke kanan, pitanya ikut bergeser 300px ke KIRI dan mendarat di
   tengah. Hal yang sama terjadi ke atas lewat scrollTop — ujung bawah
   pitanya terputus sebelum sampai dasar tabel.

   Tingginya sendiri (top:0 + bottom:0) hanya setinggi bagian yang terlihat,
   bukan setinggi seluruh tabel. Itu justru yang diinginkan: digeser balik
   sejauh gulirannya, ia menutup persis jendela yang sedang terlihat.

   Dua peubah di bawah diisi js/tampilan-modern.js dari scrollLeft/scrollTop
   setiap kali digulir. Bila berkas JS itu dicabut, keduanya jatuh ke 0 dan
   bayangannya kembali ke perilaku lama — tidak ada yang pecah. */
.table-wrap::after{
  content:""; position:absolute; top:0; right:0; bottom:0; width:34px;
  pointer-events:none; opacity:0; transition:opacity .18s ease;
  background:linear-gradient(90deg, rgba(16,40,50,0), rgba(16,40,50,.14));
  border-radius:0 10px 10px 0;
  z-index:7;   /* tetap satu tingkat di atas kepala tabel yang menempel */
  transform:translate(var(--gulir-x, 0px), var(--gulir-y, 0px));
}
.table-wrap.ada-kanan::after{ opacity:1 }
@media (prefers-reduced-motion:reduce){
  .table-wrap::after{ transition:none }
}


/* ==========================================================================
   5. HURUF ANTARMUKA YANG TERLALU KECIL                  [temuan 05]
   --------------------------------------------------------------------------
   Diukur di Dashboard: 19 elemen teks di bawah 12px, yang terkecil 9,6px.
   Ambang yang dipakai di sini: TIDAK ADA teks antarmuka di bawah 12px.

   Ini HANYA berlaku pada antarmuka. Ukuran huruf di lembar dokumen,
   pratinjau, dan editor tidak disentuh sama sekali — di sana angkanya hasil
   pengukuran terhadap Excel, bukan pilihan keterbacaan layar.

   Angka besar kartu justru DINAIKKAN: pada kartu KPI angkanya adalah isi
   halaman, dan 23px terlalu kecil untuk peran itu. */
#view-dashboard .cards .card .sub{
  font-size:var(--sk-1) !important;   /* 9,6px → 12px; lawannya !important (style.css:11952) */
  margin-top:6px !important;
  color:var(--redup-aa);
}
#view-dashboard .cards .card .k{
  /* !important wajib: lawannya style.css:3076 menulis font-size:11px !important
     (satu dari tujuh aturan berbeda yang memperebutkan ukuran label kartu ini —
     9,4px · 9,5px · 10px · 11px · 12px tersebar di 245, 568, 3076, 8762, 11938).
     Tanpa !important di sini, yang menang tetap 11px. */
  font-size:var(--sk-1) !important;   /* 11px → 12px */
  letter-spacing:.06em !important;
  color:var(--redup-aa) !important;
}
#view-dashboard .cards .card .v{
  font-size:var(--sk-6);              /* 23px → 26px */
  letter-spacing:-.02em;
}
#view-dashboard .cards .card .v.v-rp{
  font-size:var(--sk-5) !important;   /* 15px → 20px; lawannya !important (style.css:11951) */
}
/* Label penyaring & toolbar di layar lebar (9,5px → 12px). */
.toolbar .filter-field label,
#view-dashboard .filter-field label{
  font-size:var(--sk-1);
}
/* Keterangan skala pada panel Efisiensi. Keadaan kosong (.empty / .eff-empty)
   SENGAJA TIDAK disentuh — 13 Sep 2026, atas permintaan pemilik: "kembalikan
   ke Data tidak tersedia seperti semula". */
#view-dashboard .eff-skala{
  font-size:var(--sk-2);
  color:var(--redup-aa);
}
/* Dua sisa terakhir di bawah 12px pada Dashboard, terukur di audit
   13 September: keterangan panel Efisiensi 9,4px dan label segmennya 10px. */
#view-dashboard .eff-panel-k,
#view-dashboard .eff-seg-k{
  font-size:var(--sk-1) !important;   /* lawannya memakai !important */
}


/* ==========================================================================
   6. KONTRAS & SEMANTIK WARNA                            [temuan 08]
   --------------------------------------------------------------------------
   Terukur (WCAG, teks di atas warna tombol):
     hijau  #1E9E5A + putih = 3,45:1   → gagal AA 4,5:1
     redup  #64757F di latar halaman   = 4,22:1  → gagal AA
     kuning #F6B40E di atas putih      = 1,83:1  (hanya dipakai di kop gelap,
                                          di sana 6,67:1 — aman, tidak diubah)

   DAN satu kesalahan makna, bukan kontras: tombol "Reset" berwarna MERAH.
   Di aplikasi ini merah berarti rusak — gagal, batal, saldo minus. Memakai
   merah untuk mengosongkan penyaring, tindakan yang tidak menghapus apa pun
   dan bisa diulang, melemahkan artinya di tempat yang benar-benar penting.
   Reset kini jadi tombol bergaris netral. Merah tetap utuh untuk Hapus dan
   Batalkan — .btn-danger tidak disentuh. */
.btn-green{
  background:linear-gradient(135deg,var(--hijau-aa),#1d9455);
  box-shadow:0 4px 14px rgba(21,122,68,.28),inset 0 1px 0 rgba(255,255,255,.22);
}
.btn-green:hover{
  box-shadow:0 8px 22px rgba(21,122,68,.40),inset 0 1px 0 rgba(255,255,255,.28);
}

/* Reset: dari merah pekat jadi bergaris netral. Hanya tombol yang benar-benar
   bernama Reset — dikenali js/tampilan-modern.js dan diberi kelas .btn-netral,
   supaya tidak ada tombol merah lain yang ikut terkena. */
.btn.btn-netral,
.btn.btn-netral:hover{
  background:#fff;
  color:#3f5359;
  border:1px solid #c3d1d6;
  box-shadow:0 1px 2px rgba(16,40,50,.05);
}
.btn.btn-netral:hover{
  border-color:#9fb6bd;
  background:#f6f9f9;
}
.btn.btn-netral svg{ color:#5d7276 }
.btn.btn-netral::after{ display:none }   /* kilau tombol berwarna tidak berlaku di sini */

/* Teks redup di latar halaman. Dibatasi ke antarmuka; --muted global tidak
   diubah karena ia juga dipakai di dalam lembar dokumen. */
#view-dashboard .dash-sub,
.toolbar .filter-field label,
.page-head p{
  color:var(--redup-aa);
}


/* ==========================================================================
   7. FORMULIR: SATU TINGKAT KARTU, SATU TINGGI KENDALI    [temuan 09]
   --------------------------------------------------------------------------
   GEJALA di Input Pekerjaan Tender: panel putih membungkus panel putih yang
   membungkus kartu bagian. Latarnya sama semua, jadi susunannya terbaca
   sebagai garis acak, bukan tingkatan. Dan dalam satu baris berdiri empat
   bahasa kendali berbeda: <select> bawaan peramban, <input type=date>
   bawaan peramban, sakelar kustom, dan sufiks "Hari Kalender".

   PERBAIKAN: panel di dalam panel kehilangan garis & bayangannya (tetap
   memberi jarak, berhenti mengaku sebagai benda terpisah), dan semua kendali
   disamakan tingginya 40px dengan latar abu sangat muda supaya batas
   medannya terlihat — selama ini putih di atas putih dengan garis samar.

   Hanya di dalam halaman input. Formulir di dalam editor dokumen tidak ikut. */
#view-input .panel .panel,
#view-input-pl .panel .panel,
#view-input-tender .panel .panel,
#view-input-nonpo .panel .panel,
#view-form-hps .panel .panel,
#view-form-anggaran .panel .panel{
  border:none; box-shadow:none; background:transparent;
  padding-inline:0;
}

/* :not([readonly]) — Rev 96 (22 Sep 2026), dibangun ulang Rev 203. Aturan ini
   berkekhasan 121 dan dimuat SESUDAH style.css, jadi tanpa pengecualian ini
   delapan kotak Total/PPN otomatis Pengadaan Langsung & Tender tetap putih
   walau style.css mengecatnya hijau. Dikecualikan DI SUMBERNYA, bukan
   ditimpa aturan baru: js/format-tanggal.js MENYALIN aturan ini ke <style>
   sebaris yang selalu paling akhir, dan salinannya ikut membawa
   pengecualian yang sama. min-height & ukuran huruf tetap berlaku untuk
   semua kotak (dipisah ke aturan kedua). */
#view-input .field input[type="text"], #view-input .field input[type="number"],
#view-input .field input[type="date"], #view-input .field select,
#view-input-pl .field input[type="text"], #view-input-pl .field input[type="number"],
#view-input-pl .field input[type="date"], #view-input-pl .field select,
#view-input-tender .field input[type="text"], #view-input-tender .field input[type="number"],
#view-input-tender .field input[type="date"], #view-input-tender .field select,
#view-input-nonpo .field input[type="text"], #view-input-nonpo .field input[type="number"],
#view-input-nonpo .field input[type="date"], #view-input-nonpo .field select{
  min-height:40px;
  font-size:var(--sk-2);
}
#view-input .field input[type="text"]:not([readonly]), #view-input .field input[type="number"]:not([readonly]),
#view-input .field input[type="date"]:not([readonly]), #view-input .field select,
#view-input-pl .field input[type="text"]:not([readonly]), #view-input-pl .field input[type="number"]:not([readonly]),
#view-input-pl .field input[type="date"]:not([readonly]), #view-input-pl .field select,
#view-input-tender .field input[type="text"]:not([readonly]), #view-input-tender .field input[type="number"]:not([readonly]),
#view-input-tender .field input[type="date"]:not([readonly]), #view-input-tender .field select,
#view-input-nonpo .field input[type="text"]:not([readonly]), #view-input-nonpo .field input[type="number"]:not([readonly]),
#view-input-nonpo .field input[type="date"]:not([readonly]), #view-input-nonpo .field select{
  background-color:#fbfdfd;
}
/* Penegas: kotak readonly masih bisa disorot — jangan diputihkan saat fokus. */
#view-input .field input:focus:not([readonly]), #view-input .field select:focus,
#view-input-pl .field input:focus:not([readonly]), #view-input-pl .field select:focus,
#view-input-tender .field input:focus:not([readonly]), #view-input-tender .field select:focus,
#view-input-nonpo .field input:focus:not([readonly]), #view-input-nonpo .field select:focus{
  background-color:#fff;
}


/* ==========================================================================
   8. KERANGKA PEMUATAN (SKELETON)                        [temuan 10]
   --------------------------------------------------------------------------
   Sebelumnya nol. Saat data dijemput, tabel dan kartu benar-benar kosong,
   lalu tiba-tiba terisi — layar berkedip dan aplikasi terasa lebih lambat
   daripada sebenarnya.

   Satu kelas, lima bentuk. Dipasang & dilepas js/tampilan-modern.js.
   Gerakannya berhenti sendiri untuk yang memilih prefers-reduced-motion —
   di sana ia jadi blok abu diam, yang tetap menyampaikan "sedang dimuat". */
.rangka{
  position:relative; overflow:hidden;
  background:#e7eef0; border-radius:6px;
  color:transparent !important;      /* teks di dalamnya tidak ikut terbaca */
}
.rangka *{ visibility:hidden }
.rangka::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.72) 50%, rgba(255,255,255,0) 100%);
  transform:translateX(-100%);
  animation:rangkaSapu 1.25s ease-in-out infinite;
}
@keyframes rangkaSapu{ to{ transform:translateX(100%) } }

.rangka-baris{ height:15px; margin:9px 0 }
.rangka-baris.pendek{ width:42% }
.rangka-baris.sedang{ width:68% }
.rangka-kartu{ height:104px; border-radius:14px }
.rangka-panel{ height:220px; border-radius:16px }

@media (prefers-reduced-motion:reduce){
  .rangka::after{ animation:none; opacity:0 }
}


/* ==========================================================================
   10. FOKUS PAPAN KETIK & SASARAN SENTUH                 [temuan 13]
   --------------------------------------------------------------------------
   Terhitung di style.css: 638 aturan :hover berbanding 27 :focus-visible,
   ditambah 37 kali outline:none. Orang yang bekerja cepat dengan Tab —
   persis cara formulir sepanjang Input Pekerjaan diisi — sering kehilangan
   jejak kursornya.

   :focus-visible (bukan :focus) berarti cincin ini TIDAK muncul saat diklik
   tetikus, hanya saat berpindah dengan papan ketik. Jadi tidak ada tampilan
   yang berubah bagi pengguna tetikus.

   Lembar dokumen & editor dikecualikan: di sana ada penanda seleksi sendiri
   yang sudah disetel, dan cincin tambahan justru mengacaukannya. */
.view :is(button,a[href],select,input,textarea,[tabindex]):not([tabindex="-1"]):focus-visible,
.sidebar :is(button,a[href]):focus-visible,
.appbar :is(button,a[href]):focus-visible,
.modal :is(button,a[href],select,input,textarea):focus-visible{
  outline:2px solid var(--teal,#0E7C86);
  outline-offset:2px;
  border-radius:6px;
}
/* Di atas kop gelap cincin teal tenggelam — di sana putih. */
.sidebar :is(button,a[href]):focus-visible,
.page-head :is(button,a[href],select):focus-visible{
  outline-color:#fff;
}
/* Daerah terlarang: penanda sendiri, jangan ditumpangi. */
.xt-sheet :focus-visible, .fkl-doc :focus-visible, .lar-kertas :focus-visible,
[class*="kl-ed-"] :focus-visible, #view-klausul-edit :focus-visible,
#view-rekap-hps :focus-visible{
  outline:revert; outline-offset:revert;
}

/* Sasaran sentuh 44px di perangkat sentuh. Penyaring Dashboard terukur 36px.
   Hanya pada penunjuk kasar — di desktop tinggi kendali tidak berubah. */
@media (any-pointer:coarse){
  #view-dashboard .dash-filter-bar .filter-field select,
  .toolbar .filter-field select,
  .toolbar .filter-field input{
    min-height:44px;
  }
  .fk-seg-btn{ min-height:40px }
}


/* ==========================================================================
   11. GERAK YANG TIDAK MENYAMPAIKAN APA-APA DIHENTIKAN   [temuan 15]
   --------------------------------------------------------------------------
   36 animasi `infinite` berjalan terus-menerus di aplikasi ini. Yang
   menyampaikan keadaan (pemuat berputar, lonceng berdenyut saat ada
   notifikasi baru) DIBIARKAN — itu memang tugasnya.

   Yang dihentikan hanya yang murni hiasan dan tidak pernah berhenti:
   strip emas di tepi sidebar (sheenV, 7 detik, seumur halaman dibuka). Pada
   layar yang menyala berjam-jam ia menarik mata ke tempat yang tidak ada
   apa-apanya, dan pada laptop ia mencegah komposisi layar beristirahat.
   Stripnya TETAP ADA — warnanya, lebarnya, gradasinya; yang berhenti hanya
   pergerakannya. */
.sidebar::after{ animation:none }


/* ==========================================================================
   12. RAIL SIDEBAR: IKON PUNYA NAMA                      [temuan 15]
   --------------------------------------------------------------------------
   Dalam mode menciut, sidebar tinggal tujuh ikon abstrak tanpa label dan
   tanpa keterangan apa pun. Ikon yang harus dihafal bukan navigasi, itu
   ujian ingatan.

   Keterangan muncul saat kursor singgah atau saat medan itu menerima fokus
   papan ketik. Teksnya diambil js/tampilan-modern.js dari label aslinya,
   jadi tidak ada nama yang ditulis dua kali dan tidak bisa ketinggalan
   ketika menunya berubah. */
/* Balon ini TIDAK bisa digambar dengan ::after pada tombolnya. Diperiksa
   13 Sep: ada EMPAT leluhur beroverflow:hidden berturut-turut —
   .topnav-link → #topnav → .topbar-inner → #sidebar-shell — jadi apa pun
   yang digambar di luar kotak tombol pasti dipangkas. (Percobaan pertama
   memakai ::after dan balonnya tidak pernah terlihat sama sekali.)

   Karena itu balonnya satu elemen position:fixed yang ditempelkan ke <body>
   dan diletakkan js/tampilan-modern.js saat kursor singgah atau saat
   tombolnya menerima fokus papan ketik. */
.rail-tip{
  position:fixed; z-index:var(--z-tempel);
  background:#0d2a30; color:#fff;
  font-family:'Plus Jakarta Sans',sans-serif;
  font-size:var(--sk-1); font-weight:600; white-space:nowrap;
  padding:7px 11px; border-radius:8px;
  box-shadow:0 8px 22px rgba(4,32,36,.38);
  pointer-events:none;
  opacity:0; transform:translateX(-4px);
  transition:opacity .14s ease, transform .14s ease;
}
.rail-tip.tampil{ opacity:1; transform:translateX(0) }
/* Segitiga kecil ke arah tombolnya. */
.rail-tip::before{
  content:""; position:absolute; left:-4px; top:50%; margin-top:-4px;
  width:8px; height:8px; background:inherit; transform:rotate(45deg);
  border-radius:1px;
}
@media (prefers-reduced-motion:reduce){
  .rail-tip{ transition:none }
}
/* Pada perangkat sentuh tidak ada "singgah" — balon ini tidak dipasang
   sama sekali (lihat js/tampilan-modern.js). */


/* ==========================================================================
   13. PALET PERINTAH (Ctrl/⌘ + K)                        [temuan 15]
   --------------------------------------------------------------------------
   Aplikasi ini punya puluhan layar di balik menu bertingkat. Mengetik dua
   huruf lalu Enter jauh lebih cepat daripada membuka kelompok menu yang
   benar — dan ini penanda paling khas aplikasi kerja yang dirawat.

   Daftarnya dibangun js/tampilan-modern.js dari menu sidebar yang sudah ada,
   jadi ia otomatis benar dan tidak perlu dirawat terpisah. */
.pp-tirai{
  position:fixed; inset:0; z-index:var(--z-modal);
  background:rgba(7,40,44,.44);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
  display:flex; align-items:flex-start; justify-content:center;
  padding:12vh 16px 16px;
  opacity:0; transition:opacity .14s ease;
}
.pp-tirai.tampil{ opacity:1 }
.pp-kotak{
  width:100%; max-width:520px;
  background:#fff; border-radius:14px;
  box-shadow:0 24px 60px rgba(4,32,36,.34);
  overflow:hidden;
  transform:translateY(-8px) scale(.985);
  transition:transform .16s cubic-bezier(.2,.9,.3,1);
  display:flex; flex-direction:column; max-height:min(64vh, 520px);
}
.pp-tirai.tampil .pp-kotak{ transform:none }
.pp-cari{
  display:flex; align-items:center; gap:10px;
  padding:14px 16px; border-bottom:1px solid #e4ebea; flex:0 0 auto;
}
.pp-cari svg{ width:18px; height:18px; color:var(--redup-aa); flex:0 0 18px }
.pp-cari input{
  flex:1 1 auto; min-width:0;
  border:none !important; outline:none !important; box-shadow:none !important;
  background:transparent !important; padding:0 !important;
  font-family:'Plus Jakarta Sans',sans-serif;
  font-size:var(--sk-4); font-weight:600; color:var(--ink,#16242c);
  min-height:0 !important;
}
.pp-cari kbd{
  font-family:'Plus Jakarta Sans',sans-serif; font-size:10px; font-weight:700;
  color:var(--redup-aa); background:#f0f5f6; border:1px solid #dde7e8;
  border-radius:5px; padding:3px 6px; flex:0 0 auto;
}
.pp-daftar{ overflow-y:auto; padding:6px; flex:1 1 auto; overscroll-behavior:contain }
.pp-item{
  display:flex; align-items:center; gap:11px;
  padding:10px 12px; border-radius:9px; cursor:pointer;
  font-size:var(--sk-2); font-weight:600; color:#2b3f44;
}
.pp-item .pp-grup{
  margin-left:auto; font-size:var(--sk-1); font-weight:600; color:var(--redup-aa);
  white-space:nowrap;
}
.pp-item svg{ width:16px; height:16px; color:var(--teal,#0E7C86); flex:0 0 16px }
.pp-item.pilih{ background:var(--teal-soft,#e3f2f3); color:var(--teal-dark,#095e66) }
.pp-item mark{ background:rgba(246,180,14,.34); color:inherit; border-radius:3px }
.pp-nihil{ padding:26px 16px; text-align:center; color:var(--redup-aa); font-size:var(--sk-2) }
@media (prefers-reduced-motion:reduce){
  .pp-tirai, .pp-kotak{ transition:none }
}
@media (max-width:560px){
  .pp-tirai{ padding-top:8vh }
}


/* ==========================================================================
   14. SAKELAR KEPADATAN — tidak dipasang.
   --------------------------------------------------------------------------
   Sengaja dicatat di sini supaya tidak dikira terlupa: temuan 12 rapor
   (kartu KPI tanpa tren/selisih/sparkline) TIDAK bisa diselesaikan di CSS.
   Ia butuh satu kueri pembanding ke basis data — nilai periode sebelumnya
   pada penyaring yang sama. Bentuk kartunya sudah siap menerimanya
   (.card > .kpi-tren akan jatuh di bawah .v), tetapi slot kosong yang tidak
   pernah terisi lebih buruk daripada tidak ada slot sama sekali, jadi
   markup-nya tidak ditambahkan sampai datanya ada.
   ========================================================================== */
.card .kpi-tren{
  display:flex; align-items:center; gap:5px;
  margin-top:6px; font-size:var(--sk-1); font-weight:700;
}
.card .kpi-tren.naik{ color:var(--hijau-aa) }
.card .kpi-tren.turun{ color:var(--rusak) }
.card .kpi-tren.datar{ color:var(--redup-aa) }


/* ==========================================================================
   15. HURUF TABEL & FORMULIR — tindak lanjut audit lintas perangkat
   --------------------------------------------------------------------------
   13 September 2026. Audit 63 kombinasi perangkat menemukan bahwa isi tabel
   Daftar dan label formulir Input ditulis 9,5–11 px — di bawah ambang 12 px
   di layar mana pun, dan pada perangkat yang halamannya diskala ia mengecil
   lagi mengikuti skalanya.

   Berbeda dengan mengubah lebar tata letak, perbaikan ini bekerja di SEMUA
   skala sekaligus dan tidak menyentuh susunan kolom mana pun.

   Naik ke 12 px, bukan 13 px seperti saran rapor: 12 px sudah memenuhi ambang
   yang dipakai seluruh audit ini, dan tiap piksel tambahan menambah risiko
   kolom tabel melipat dua baris di laptop — hal yang sudah dua kali
   dikeluhkan pemilik ("di desktop no kontrak hanya 1 baris bukan seperti ipad
   2 baris"). Dampaknya pada pelipatan diukur sebelum dan sesudah.

   Lembar dokumen tidak termasuk: pemilihnya diikat ke .table-wrap di dalam
   halaman daftar dan ke .field di dalam halaman input.

   --------------------------------------------------------------------------
   HURUF TABEL DIKEMBALIKAN — LIMA HALAMAN ITU YANG BEDA SENDIRI
                                                       15 September 2026, malam
   --------------------------------------------------------------------------
   LAPORAN PEMILIK, dengan lima tangkapan layar berturut-turut: "tampilannya
   lebih besar dari daftar yang lain", "menu daftar pengadaan dan penetapan
   nomor beda sendiri ukurannya dari yang lain", "penetapan nomor, teks
   judulnya besar", lalu Daftar Kontrak Pekerjaan dikirim sebagai patokan —
   "ini ukuran menu yang lain".

   DIUKUR DI SELURUH HALAMAN BERDAFTAR SEKALIGUS, bukan pada dua halaman yang
   kebetulan dibandingkan. Sembilan belas halaman punya .table-wrap table;
   satu baris data disuntikkan ke masing-masing, lalu gaya terhitung sel dan
   kepalanya dibaca:

       12 px / 12 px    (5 halaman)  view-list, view-list-pl, view-list-tender,
                                     view-list-nonpo, view-pn-lihat
       11 px / 9,5 px  (14 halaman)  view-spk-view, view-fk-view, view-dp-view,
                                     view-anggaran-view, view-hps-view,
                                     view-tor-view, view-fkl-view, dan seterusnya

   Kelima halaman di daftar pertama itu PERSIS yang disentuh aturan ini pada
   13 September. Jadi yang dilihat pemilik bukan salah satu halaman yang
   membesar sendiri, melainkan perbaikan yang berhenti di sepertiga jalan:
   lima halaman naik, empat belas tertinggal, dan sejak itu aplikasi punya dua
   ukuran tabel yang berdampingan di menu yang sama.

   ATURANNYA DICABUT, bukan disebarkan ke 14 halaman sisanya. Keduanya sama-
   sama menghasilkan satu ukuran, dan pilihan itu milik pemilik aplikasi — ia
   memilih dengan menunjuk patokannya sendiri. Yang perlu diketahui dan tidak
   boleh hilang dari berkas ini: angka 9,5 px pada KEPALA tabel memang di bawah
   ambang 12 px yang dipakai audit 13 September. Menaikkan keempat belas
   halaman sisanya ke 12 px adalah satu blok pemilih di tempat yang sama, dan
   catatan di atas sengaja dibiarkan utuh supaya jalan itu tetap terbuka.

   Dua aturan di bawah (kolom nomor kontrak & tanggal tidak boleh melipat)
   DIPERTAHANKAN: keduanya tidak menyentuh ukuran huruf, dan "di desktop no
   kontrak hanya 1 baris" adalah ketentuan pemilik yang berdiri sendiri. */

/* Label & keterangan medan pada halaman input. */
#view-input .field label, #view-input .fld-label-text, #view-input .field .req,
#view-input-pl .field label, #view-input-pl .fld-label-text, #view-input-pl .field .req,
#view-input-tender .field label, #view-input-tender .fld-label-text, #view-input-tender .field .req,
#view-input-nonpo .field label, #view-input-nonpo .fld-label-text, #view-input-nonpo .field .req{
  font-size:var(--sk-1);   /* 10–11px → 12px */
}

/* Lencana hitungan di judul & pil segmented — keduanya 10–11,5px.
   Kekhususan dinaikkan karena .mod-seg .fk-seg-btn (0,2,0) di style.css:2309
   mengalahkan .fk-seg-btn biasa, dan .count-badge diperebutkan dua aturan. */
.count-badge.count-badge, .fk-seg-btn.fk-seg-btn,
.mod-seg .fk-seg-btn, .fk-seg .fk-seg-btn{ font-size:var(--sk-1) }

/* CATATAN SISA: di halaman Input masih ada empat elemen TANPA KELAS
   (satu <p> 11px, dua <span> 10–10,5px, satu <label> 10px) yang tidak bisa
   dipilih tanpa memakai pemilih menyeluruh seperti `#view-input span`, dan
   pemilih semacam itu akan ikut mengubah elemen lain yang ukurannya memang
   sudah benar. Diberi nama di sini supaya tidak dikira terlewat; memperbaikinya
   perlu menambahkan kelas di index.html, bukan menambah aturan CSS. */

/* Kolom yang TIDAK BOLEH melipat, berapa pun ukuran hurufnya.
   Pemilik dua kali mengeluhkan hal yang persis ini: "di desktop no kontrak
   hanya 1 baris bukan seperti ipad 2 baris". Menaikkan huruf ke 12 px
   menambah risiko itu pada sel datanya — risiko yang tidak bisa diukur di
   sini karena tanpa sambungan Supabase tabelnya kosong. Jadi kolom nomor
   kontrak dan kolom tanggal dikunci satu baris; tabel menggeser sedikit lebih
   jauh ke kanan, dan itu sudah diberi bayangan tepi (bagian 4). */
#view-list .col-kontrak, #view-list .col-date,
#view-list-pl .col-kontrak, #view-list-pl .col-date,
#view-list-tender .col-kontrak, #view-list-tender .col-date,
#view-list-nonpo .col-kontrak, #view-list-nonpo .col-date,
#view-pn-lihat .col-kontrak, #view-pn-lihat .col-date{
  white-space:nowrap;
}
/* Kepala tabelnya tetap boleh melipat — "TGL. TERBIT KONTRAK" memang dua
   baris sejak semula, dan memaksanya satu baris justru melebarkan kolom. */
#view-list thead .col-kontrak, #view-list thead .col-date,
#view-list-pl thead .col-kontrak, #view-list-pl thead .col-date,
#view-list-tender thead .col-kontrak, #view-list-tender thead .col-date,
#view-list-nonpo thead .col-kontrak, #view-list-nonpo thead .col-date,
#view-pn-lihat thead .col-kontrak, #view-pn-lihat thead .col-date{
  white-space:normal;
}


/* ==========================================================================
   16. PENYARING DAFTAR MEMENUHI LEBAR LAYAR DI PONSEL
   --------------------------------------------------------------------------
   LAPORAN PEMILIK (13 Sep 2026): "lebih bagus lagi kalau semua status dan
   semua tahun ini memenuhi lebar kiri kanan layar".

   TERUKUR di 412px, halaman Monitoring: bilah penyaring selebar 342px berisi
   Bidang 342 (penuh), Status 123, Tahun 119 — menyisakan 100px kosong di
   kanan baris kedua. Tombol Reset & Input Data pun berhenti di 118px masing-
   masing dan menggantung ke kanan.

   SEBABNYA satu aturan di style.css:9936 (rentang <=767px):
       .toolbar .filter-field{ flex:0 1 auto; min-width:0 }
   `flex-grow:0` berarti medan TIDAK BOLEH melar; lebarnya berhenti di lebar
   isinya (max-width:158px dari style.css:272). Aturan <=640px yang lebih tua
   (`.filter-field{flex:1 1 100%}`, style.css:2032) memang menyuruh melar,
   tetapi bobotnya lebih rendah (0,1,0 lawan 0,2,0) DAN ditulis lebih awal,
   jadi ia selalu kalah.

   PERBAIKAN: di bawah 640px medan penyaring biasa berbagi baris DUA-DUA
   (50% dikurangi separuh gap 10px), sedangkan Bidang & Cari — yang isinya
   panjang — tetap satu baris penuh. Hasilnya: tiap baris benar-benar penuh
   dari tepi kiri ke tepi kanan, tanpa satu pun angka lebar tetap.

   Tombol Reset & Input Data ikut dibagi rata pada baris terakhir dengan
   alasan yang sama; keduanya sudah `flex:1 1 auto` di style.css:2039 tetapi
   `min-width:118px` (style.css:361) menahannya, dan itulah yang dilepas. */
@media (max-width:640px){
  /* Dasarnya SENGAJA di bawah separuh (50% - 12px, bukan 50% - 5px = separuh
     gap). Dua medan berdasar tepat separuh ditambah gap 10px berjumlah persis
     100%, dan pembulatan sub-piksel sedikit saja sudah membuat yang kedua
     turun baris — TERUKUR: keduanya berakhir 342px, masing-masing sebaris
     sendiri. Dengan dasar yang lebih kecil keduanya pasti sebaris, lalu
     flex-grow memelarkannya memenuhi lebar. Tiga medan tetap tidak muat,
     jadi yang ketiga tetap turun sebagaimana mestinya. */
  .toolbar .filter-field{
    flex:1 1 calc(50% - 12px) !important;
    min-width:0;
  }
  /* Bidang Pelaksana & Cari: isinya panjang, jadi satu baris penuh. */
  .toolbar .filter-field:has(> select[id$="bidang"]),
  .toolbar .filter-field:has(> select[id$="kategori"]),
  .toolbar .filter-field.toolbar-search,
  .toolbar .filter-field.fk-search,
  .toolbar .filter-field.search-elegant{
    flex:1 1 100% !important;
  }
  .toolbar .filter-field select,
  .toolbar .filter-field input{
    width:100%; min-width:0; max-width:none;
  }
  /* Baris tombol: dibagi rata, bukan menggantung ke kanan. */
  .toolbar .toolbar-actions{ flex:1 1 100%; margin-left:0; }
  .toolbar .toolbar-actions > .btn{
    flex:1 1 0; min-width:0; justify-content:center;
  }
}


/* ==========================================================================
   17. EMPAT TOMBOL PUSTAKA KLAUSUL MUAT SATU BARIS
   --------------------------------------------------------------------------
   LAPORAN PEMILIK (13 Sep 2026): "kalau bisa tombol empat ini 1 baris".

   TERUKUR di 412px: bilahnya 302px, sedangkan Profil 89 + Profil 89 +
   Klausul 99 + Reset 91 + tiga gap 8px = 392px. Reset turun ke baris kedua.

   Yang dipangkas bukan jumlah tombolnya — keempatnya memang perlu — tetapi
   lebar yang dipakai tiap tombol: jarak dalam kiri-kanan, gap, dan ukuran
   huruf. `flex:1 1 0` membuat keempatnya melar sama rata memenuhi baris,
   jadi hasilnya rapi berapa pun lebar layarnya. Ikonnya tidak ikut menyusut
   (`flex:none`) supaya yang membedakan keempat tombol tetap terbaca — itulah
   yang menjadi pembeda sejak labelnya dipendekkan jadi "Profil" bertiga
   (style.css blok 21). */
@media (max-width:640px){
  /* Judul kartu & bilah tombolnya menumpuk, bukan berebut satu baris. */
  .form-card .form-section-title:has(> .spk-klbar){
    flex-wrap:wrap;
    row-gap:10px;
  }
  .form-card .form-section-title > .spk-klbar{ flex:1 1 100% }

  .spk-klbar{
    flex-wrap:nowrap !important;
    gap:6px;
    width:100%;
    /* Tombol berlabel dua baris jadi lebih tinggi daripada tetangganya;
       `stretch` menyamakan tingginya supaya keempatnya tetap terbaca
       sebagai SATU baris tombol, bukan dua baris yang tidak rata. */
    align-items:stretch;
  }
  .spk-klbar > .jp-profil-btn,
  .spk-klbar > .btn{
    flex:1 1 0;
    min-width:0;
    padding-left:6px; padding-right:6px;
    gap:5px;
    font-size:11px;
    justify-content:center;
    /* ------------------------------------------------------------------
       LABEL BOLEH TURUN BARIS DI DALAM TOMBOL       13 September 2026
       ------------------------------------------------------------------
       Sejak labelnya dikembalikan lengkap ("Simpan Profil" / "Muat
       Profil" — ketentuan pemilik "dikasi lengkap ... agar pengguna
       paham"), `white-space:nowrap` membuatnya TERPOTONG, bukan turun:
       terukur di 412px tombolnya 79px sementara "Simpan Profil" butuh
       87px (+8px terpotong), di 360px +14px.

       Dua ketentuan pemilik bertemu di bilah yang sama — "tombol empat
       ini 1 baris" dan "dikasi lengkap" — dan keduanya bisa dipenuhi
       sekaligus bila yang melipat bukan BILAHNYA melainkan LABELNYA:
       empat tombol tetap sebaris, masing-masing menampung dua kata
       bertumpuk. Terukur sesudahnya: 412px, 390px dan 360px sama-sama
       satu baris tanpa satu huruf pun terpotong.
       ------------------------------------------------------------------ */
    white-space:normal;
    line-height:1.15;
    text-align:center;
  }
  .spk-klbar > .jp-profil-btn > span,
  .spk-klbar > .btn > span{ white-space:normal }
  .spk-klbar > .jp-profil-btn > svg,
  .spk-klbar > .btn > svg{ flex:none }
  /* Lencana "Profil: <nama>" berdiri sendiri supaya tidak ikut memepet. */
  .form-card .form-section-title .spk-klprof-tag{ flex:0 0 auto }
}
/* Ponsel paling sempit (<=400px): "Klausul" satu kata yang tidak bisa dilipat
   masih kurang 3px di 360px. Hurufnya diturunkan setengah poin dan ikonnya
   sedikit dikecilkan — cukup untuk keempatnya, dan ikon 13px masih terbaca
   jelas sebagai pembeda tombol. */
@media (max-width:400px){
  .spk-klbar > .jp-profil-btn,
  .spk-klbar > .btn{ font-size:10.5px; padding-left:5px; padding-right:5px; gap:4px }
  .spk-klbar > .jp-profil-btn > svg,
  .spk-klbar > .btn > svg{ width:13px; height:13px }
}
/* Tablet potret (641–1024px): ruangnya cukup untuk empat label lengkap
   sebaris, tetapi tidak cukup bila tiap tombol memakai lebar penuhnya —
   terukur di 768px bilahnya 443px dan Reset turun ke baris kedua. Di sini
   tombolnya BOLEH BERBEDA LEBAR (`flex:0 1 auto`): yang labelnya panjang
   dapat lebih banyak, yang pendek tidak dipaksa melebar, dan keempatnya
   tetap satu baris tanpa dipotong. */
@media (min-width:641px) and (max-width:1024px){
  .form-card .form-section-title:has(> .spk-klbar){ flex-wrap:wrap; row-gap:10px }
  .form-card .form-section-title > .spk-klbar{ flex:1 1 100% }
  .spk-klbar{ flex-wrap:nowrap !important; gap:8px; width:100% }
  .spk-klbar > .jp-profil-btn,
  .spk-klbar > .btn{
    flex:0 1 auto; min-width:0;
    padding-left:10px; padding-right:10px;
    font-size:11px; justify-content:center; white-space:nowrap;
  }
  .spk-klbar > .jp-profil-btn > svg,
  .spk-klbar > .btn > svg{ flex:none }
}


/* ==========================================================================
   18. ENAM BUTIR DI PANEL MASUK: TIGA BARIS, KIRI-KANAN
   --------------------------------------------------------------------------
   PERMINTAAN PEMILIK: "enam poin ini dijadikan 3 baris kiri kanan lebih
   bagus lagi agar panel login tidak terlalu tinggi".

   style.css:1416 mengembalikannya ke satu lajur di bawah 520px, dengan
   catatan yang jujur: dua lajur di sana membuat tiap butir terlalu sempit
   sehingga BARIS PERINCIANNYA terpotong elipsis. Itu benar selama perinciannya
   dipaksa satu baris — dan memang `.bf-tx b` serta `.bf-tx i` keduanya
   ber-`white-space:nowrap`.

   Jadi yang diperbaiki di sini BUKAN cuma jumlah lajurnya. Tiga hal sekaligus,
   dan ketiganya perlu:
     1. dua lajur;
     2. perincian boleh MELIPAT (nowrap dilepas, dibatasi dua baris) — itulah
        yang membatalkan sebab penolakan lama;
     3. ikon & huruf sedikit dikecilkan supaya dua lajur tidak sesak.

   DAN SATU LAGI YANG BARU KETAHUAN SAAT DIUKUR. style.css:1472
   menyembunyikan daftar ini sepenuhnya di bawah 431px:
       @media(max-width:430px){ .brandside-feats{display:none} }
   Selama ponsel potret DIPAKSA berlebar tata letak 620px (LEBAR_POTRET lama),
   rentang itu tidak pernah tercapai — ponsel selalu "terbaca" 620px, jadi
   keenam butir selalu tampil. Sejak ponsel potret dikembalikan 1:1 (13 Sep,
   lihat index.html), layar 390-412px jatuh tepat ke dalam rentang itu dan
   keenam butir LENYAP. TERUKUR: 390px & 412px -> display:none.

   Jadi rentangnya di sini sengaja TIDAK dibatasi min-width: dua lajur berlaku
   sampai selebar-sempitnya layar, sekaligus mengembalikan keenam butir yang
   hilang. Ukurannya dipangkas secukupnya supaya pada 390px pun tidak ada satu
   pun teks yang terpotong — dijaga oleh pengukuran, bukan perkiraan. */
@media (max-width:520px){
  /* Mengembalikan yang disembunyikan style.css:1472. */
  .login-screen .brandside-feats,
  .login-brandside .brandside-feats{ display:grid }
}
@media (max-width:520px){
  .login-screen .brandside-feats,
  .login-brandside .brandside-feats{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:9px 10px;
  }
  .login-brandside .brandside-feat{ align-items:flex-start; gap:7px }
  .login-brandside .brandside-feat .bf-ic{
    width:22px; height:22px; flex:0 0 22px; border-radius:7px;
  }
  .login-brandside .brandside-feat .bf-ic svg{ width:12px; height:12px }
  /* Judul butir pun dilepas dari nowrap. TERUKUR: pada 390px "Pembukaan
     Penawaran" terpotong (1 elemen), pada 360px dua elemen. Dibatasi dua
     baris supaya butir yang judulnya panjang tidak menjulang sendirian. */
  .login-brandside .brandside-feat .bf-tx b{
    font-size:10px; line-height:1.25;
    white-space:normal;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
    overflow:hidden; text-overflow:clip;
  }
  .login-brandside .brandside-feat .bf-tx i{
    font-size:8.5px; line-height:1.3; margin-top:1px;
    white-space:normal;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
    overflow:hidden; text-overflow:clip;
  }
}


/* ==========================================================================
   19. BALON PEMBERITAHUAN TIDAK LAGI MELESET KE KIRI
   --------------------------------------------------------------------------
   LAPORAN PEMILIK (13 Sep 2026): "pop up pemberitahuan bergeser ke tempat
   lain, bukan muncul dari lonceng" — balonnya separuh keluar tepi kiri layar
   sehingga yang terbaca hanya "…iki 1 pemberitahuan baru".

   DUA ATURAN YANG SALING TIDAK TAHU:

     a) js/notifikasi.js (rentang <=820px) menaruh balon di TENGAH ATAS:
            .ntf-balok{ left:50% !important }
        dan animasi masuknya menahan `transform:translateX(-50%)` di bingkai
        terakhir (ntfBalokMasukHp, animation-fill-mode:both) — itulah yang
        memusatkannya.

     b) js/kanan-atas.js memindahkan loncengnya ke pojok kanan atas, lalu
        menaruh balon TEPAT DI BAWAH lonceng dengan left absolut:
            .ntf-balok.ka-balok-bawah{ left:var(--ka-bl-l) !important }

   Bobot (b) lebih tinggi, jadi `left` yang menang adalah nilai absolut dari
   kanan-atas.js — TETAPI `translateX(-50%)` milik animasi (a) tetap berlaku,
   sebab deklarasi animasi mengalahkan deklarasi biasa apa pun, termasuk
   `.ntf-balok.ka-balok-bawah.ntf-tampil{transform:none}`. Balon selebar 340px
   pun tergeser 170px ke kiri dari tempat yang sudah benar.

   Persis jebakan yang dicatat sendiri di js/notifikasi.js ("kalau keyframes-
   nya berakhir di transform:none, balok akan MELONCAT") — hanya arahnya
   terbalik: di sini yang salah justru keyframes yang MENAHAN geseran.

   PERBAIKAN: saat balon sudah diletakkan kanan-atas.js, animasinya ditukar ke
   sepasang keyframes yang tidak menggeser mendatar sama sekali. Gerak
   datang-perginya tetap ada, hanya tegak. Runcingnya ikut dikembalikan —
   rentang <=820px mematikannya karena balon yang dipusatkan memang tidak
   menunjuk ke mana-mana, sedangkan yang ini justru turun DARI loncengnya. */
@keyframes kaBalokMasukBawah{
  0%  { opacity:0; transform:translateY(-18px) scale(.92) }
  55% { opacity:1; transform:translateY(5px) scale(1.03) }
  78% {            transform:translateY(-2px) scale(.995) }
  100%{ opacity:1; transform:none }
}
@keyframes kaBalokKeluarBawah{
  0%  { opacity:1; transform:none }
  30% { opacity:1; transform:translateY(6px) scale(1.02) }
  100%{ opacity:0; transform:translateY(-20px) scale(.92) }
}
/* TANPA @media, DAN DENGAN !important                     13 Sep 2026, rev. 2
   ---------------------------------------------------------------------------
   LAPORAN PEMILIK sesudah perbaikan pertama: "pemberitahuan masih melenceng".

   Dua pengencangan, dan keduanya menutup celah yang sama dari arah berbeda:

   1. RENTANGNYA DILEPAS. Kelas .ka-balok-bawah HANYA dipasang kanan-atas.js
      ketika balon diletakkan di bawah lonceng — yaitu tepat keadaan yang
      geseran mendatarnya salah. Mengurungnya lagi di dalam (max-width:820px)
      berarti bergantung pada dua syarat untuk satu keadaan; kalau lebar tata
      letaknya kebetulan di luar rentang (mis. tablet potret 1024px, atau
      ponsel yang tata letaknya sedang dipaksa lebih lebar), aturan lamanya
      yang berlaku dan balonnya meleset lagi.

   2. !important PADA animation-name. Deklarasi animasi mengalahkan deklarasi
      biasa, tetapi TIDAK mengalahkan deklarasi ber-!important. Dengan
      animation-name yang ber-!important, tidak ada urutan pemuatan lembar
      gaya mana pun yang bisa mengembalikan keyframes lama — sedangkan
      gerakannya tetap ada (bukan transform-nya yang dipaksa, melainkan
      keyframes mana yang dipakai). */
.ntf-balok.ka-balok-bawah.ntf-tampil{ animation-name:kaBalokMasukBawah !important }
.ntf-balok.ka-balok-bawah.ntf-pergi { animation-name:kaBalokKeluarBawah !important }
/* Runcing yang menunjuk lurus ke lonceng di atasnya. Letak mendatarnya
   dihitung kanan-atas.js lewat --bl-notch-x; rentang <=820px di notifikasi.js
   mematikannya karena balon yang dipusatkan memang tidak menunjuk ke mana-mana. */
.ntf-balok.ka-balok-bawah::before{ display:block !important }
@media (prefers-reduced-motion:reduce){
  .ntf-balok.ka-balok-bawah.ntf-tampil,
  .ntf-balok.ka-balok-bawah.ntf-pergi{ animation:none !important }
  .ntf-balok.ka-balok-bawah.ntf-tampil{ transform:none !important; opacity:1 }
}


/* ==========================================================================
   20. TOMBOL "LAYAR PENUH" DILEPAS DARI PERANGKAT SENTUH
   --------------------------------------------------------------------------
   LAPORAN PEMILIK (13 Sep 2026): "tidak berfungsi maximize dan minimize
   halaman", lalu: "di fullscreen saja seperti pratinjau dokumen HPS".

   Laporannya tepat, dan sebabnya bisa dibaca langsung dari style.css sendiri.
   Blok "PRATINJAU DI PERANGKAT SENTUH" (style.css:8529) sudah membuat modal
   pratinjau menutupi seluruh layar di SETIAP perangkat sentuh:
       @media (max-width:820px),(hover:none),(any-pointer:coarse){
         .pn-preview-modal{ width:100vw; height:100dvh; border-radius:0 }
       }
   Sedangkan tombol itu hanya memasang kelas .pn-fs-semu, yang isinya persis
   sama: 100vw x 100dvh tanpa sudut membulat. Menekannya berarti mengganti
   keadaan dengan keadaan yang identik.

   TERUKUR pada 412x915, pratinjau HPS, sebelum & sesudah tombol diketuk:
       lebar modal      412 -> 412
       tinggi modal     915 -> 915
       tinggi kepala     56 -> 56
       tinggi badan     859 -> 859
   Tidak satu piksel pun berubah.

   Jadi yang dilepas bukan kemampuannya — kemampuannya memang sudah terpakai
   penuh sejak modalnya selebar layar — melainkan TOMBOL yang menjanjikan
   sesuatu yang tidak bisa lagi ia berikan. Kendali yang terbukti tidak
   melakukan apa-apa lebih buruk daripada tidak ada kendali.

   RENTANGNYA SENGAJA DISALIN PERSIS dari blok yang membuat modalnya selebar
   layar. Dengan begitu keduanya tidak mungkin berselisih: di mana pun modal
   sudah selebar layar, di situ pula tombolnya hilang — dan di peramban meja
   berkursor, yang tidak masuk rentang itu, tombolnya tetap ada dan tetap
   memakai Fullscreen API seperti biasa.

   MENGEMBALIKAN: hapus blok ini. Pintasan huruf F, penanganan
   fullscreenchange, dan seluruh js/ui-sidebar.js tidak disentuh sama sekali —
   yang diubah hanya tampak/tidaknya satu tombol. */
@media (max-width:820px), (hover:none), (any-pointer:coarse){
  #pn-preview-overlay #pn-preview-fs{ display:none !important }
}


/* ==========================================================================
   21. BILAH PENYARING DI TABLET POTRET (LANJUTAN BAGIAN 16)
   --------------------------------------------------------------------------
   Sejak potret memakai tata letak laci (lihat index.html), iPad potret tidak
   lagi ditata selebar 1366px melainkan selebar layarnya sendiri — 744, 820,
   834, atau 1024px. Rentang itu di ATAS 640px, jadi bagian 16 tidak
   menjangkaunya, dan yang berlaku di sana aturan lebar tetap style.css:272
   (`min-width:158px;max-width:158px`).

   TERUKUR pada iPad 10.9 potret (820px): "Semua Status" terbaca "Semua Statu"
   dan "Semua Tahun" terbaca "Semua Tahu" — keduanya terpotong satu huruf,
   persis gejala yang dulu dilaporkan di ponsel.

   Aturannya SAMA PERSIS dengan bagian 16, hanya rentangnya yang berbeda, dan
   diikat ke `html:not(.mode-rail)` — yaitu tata letak laci. Jendela peramban
   MEJA selebar 700-1024px tidak ikut terpengaruh: di sana .mode-rail menyala,
   dan bilah penyaringnya tetap seperti semula. */
@media (min-width:641px) and (max-width:1024px){
  html:not(.mode-rail) .toolbar{
    width:auto; margin-left:0; margin-right:0; max-width:100%;
  }
  html:not(.mode-rail) .toolbar .filter-field{
    flex:1 1 calc(50% - 12px) !important;
    min-width:0;
  }
  html:not(.mode-rail) .toolbar .filter-field:has(> select[id$="bidang"]),
  html:not(.mode-rail) .toolbar .filter-field:has(> select[id$="kategori"]),
  html:not(.mode-rail) .toolbar .filter-field.toolbar-search,
  html:not(.mode-rail) .toolbar .filter-field.fk-search,
  html:not(.mode-rail) .toolbar .filter-field.search-elegant{
    flex:1 1 100% !important;
  }
  html:not(.mode-rail) .toolbar .filter-field select,
  html:not(.mode-rail) .toolbar .filter-field input{
    width:100%; min-width:0; max-width:none;
  }
  html:not(.mode-rail) .toolbar .toolbar-actions{ flex:1 1 100%; margin-left:0 }
  html:not(.mode-rail) .toolbar .toolbar-actions > .btn{
    flex:1 1 0; min-width:0; justify-content:center;
  }
}
/* Kotak "Cari" pada rentang yang sama dipatok LEWAT ID di style.css:9829
   (`min-width:150px;max-width:190px`) — bobot ID mengalahkan pemilih kelas
   berapa pun, jadi aturan lebar di atas tidak menyentuhnya. TERUKUR pada iPad
   10.9 potret: medannya sudah selebar 762px, tetapi <input>-nya berhenti di
   190px sehingga tempat "Cari No. SPBJ / Pekerjaan / Penyedia" kurang 60px.
   Dijawab dengan bobot yang setara: ID juga, ditambah rantai kelas. */
@media (min-width:641px) and (max-width:1024px){
  html:not(.mode-rail) .toolbar #filter-search,
  html:not(.mode-rail) .toolbar #filter-pl-search,
  html:not(.mode-rail) .toolbar #filter-tender-search,
  html:not(.mode-rail) .toolbar #filter-npo-search,
  html:not(.mode-rail) .toolbar #fkl-view-search,
  html:not(.mode-rail) .toolbar #fk-view-search,
  html:not(.mode-rail) .toolbar #dpeng-view-search,
  html:not(.mode-rail) .toolbar #materi-view-search,
  html:not(.mode-rail) .toolbar #pn-lihat-search{
    min-width:0; max-width:none; width:100%;
  }
}

/* ==========================================================================
   §22  RELIEF 3D TOMBOL "UBAH DATA"                     13 September 2026
   --------------------------------------------------------------------------
   KETENTUAN PEMILIK: "tambahkan efek 3d ke ubah data seperti pada tombol
   pilih sheet."

   Keduanya sebenarnya SUDAH memakai relief yang sama — style.css:10459
   memasang empat lapis bayangan ber-!important pada setiap `.btn`, dan Ubah
   Data adalah `<button class="btn xtpl-btn lar-ubah-btn">`. Yang berbeda
   warnanya: Pilih Sheet memakai .btn-teal (var(--teal) -> var(--cyan)),
   Ubah Data memakai gradasi yang jauh lebih pekat (var(--teal-dark) ->
   var(--teal)) supaya tidak tertukar dengan tombol Profil tosca di
   sebelahnya. Di atas warna sepekat itu lapisan putih .30/.45 nyaris tidak
   terbaca — reliefnya ada, tetapi mata tidak melihatnya.

   Jadi yang ditambah di sini kepekatan lapisannya, bukan susunannya: empat
   lapis yang sama persis, dengan putih dinaikkan dan bayangan jatuh
   dipertegas sedikit. Hasilnya sepadan dengan yang terlihat di Pilih Sheet.

   Bobotnya: dua kelas (.btn.lar-ubah-btn) melawan satu kelas + dua :not(#id)
   di style.css. :not() tidak menambah bobot pemilih di dalamnya untuk
   perbandingan ini — keduanya berbobot ID 0, jadi yang memutuskan jumlah
   kelas: 2 lawan 1. Ditambah !important supaya sejajar dengan aturan yang
   dilawan, dan letaknya yang belakangan mengunci hasilnya.
   ========================================================================== */
.btn.lar-ubah-btn:not([disabled]){
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.42),
    inset 0 1px 0 rgba(255,255,255,.62),
    inset 0 -2px 0 rgba(0,0,0,.28),
    0 2px 0 rgba(6,52,58,.34),
    0 7px 16px rgba(6,52,58,.34) !important;
}
.btn.lar-ubah-btn:not([disabled]):hover{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.52),
    inset 0 1px 0 rgba(255,255,255,.72),
    inset 0 -2px 0 rgba(0,0,0,.30),
    0 3px 0 rgba(6,52,58,.36),
    0 10px 22px rgba(6,52,58,.40) !important;
}
/* Ditekan: relief dibalik ke dalam — lipatan & bayangan jatuh dihapus,
   sama persis dengan perilaku .btn di style.css:10495. */
.btn.lar-ubah-btn:not([disabled]):active{
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.26),
    inset 0 2px 7px rgba(0,0,0,.42) !important;
}
