/* DesaPreneur — satu berkas gaya. Tanpa framework, tanpa JS. */
:root {
  /* Palet Agrinas */
  /* Hijau diselaraskan ke identitas Agrinas (#1a7f37) — lebih cerah & segar.
     hijau-600 (#1f8739) adalah latar tombol; putih di atasnya tetap 4.58:1 (LULUS WCAG AA). */
  --hijau-900: #12402a; --hijau-800: #175433; --hijau-700: #1a7f37;
  --hijau-600: #1f8739; --hijau-500: #37b45c; --hijau-300: #97dfae; --hijau-100: #ecf9f0;
  /* Netral */
  --tinta: #101d18; --tinta-2: #3d4d46; --pudar: #5f6f68;
  --garis: #dfe6e2; --garis-2: #eef3f1; --latar: #f2f6f4; --putih: #fff;
  --zebra: #f8fbf9;
  /* Keadaan — semua >= 4.5:1 di atas latarnya */
  --kuning: #7a4c00; --kuning-l: #fdf3e0; --kuning-g: #ecc78a;
  --merah: #a32218; --merah-l: #fdeeec; --merah-g: #f3c0ba;
  --biru: #14509e; --biru-l: #eaf2fd; --biru-g: #b6cdf0;
  --hijau-l: #e8f7ef; --hijau-g: #a9e0c2;
  /* Bentuk */
  --r: 12px; --r-kecil: 8px; --r-mini: 6px; --r-kapsul: 999px;
  --bayang: 0 1px 2px rgba(16, 29, 24, .05), 0 1px 3px rgba(16, 29, 24, .07);
  --bayang-2: 0 8px 24px -8px rgba(16, 29, 24, .18), 0 2px 6px rgba(16, 29, 24, .06);
  /* Isi tidak lagi dipaku 1100px: lebar kolom kanan = 100% sisa layar setelah
     sisi 264px, jadi halaman ikut melebar di monitor besar (dulu 66% di 1920). */
  --sisi-l: 264px;
  --ruang: 1.3rem;
  --sp: clamp(1rem, .6rem + 1.4vw, 2rem);      /* spasi tepi adaptif */
  --sisi-z: 30;
}

* , *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--latar); color: var(--tinta);
  font: 15px/1.55 "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased; }
h1, h2, h3 { letter-spacing: -.015em; }
h1 { font-size: clamp(1.3rem, 1.1rem + .8vw, 1.6rem); margin: 0 0 .25rem; font-weight: 700; }
h2 { font-size: .75rem; margin: 0 0 .9rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--pudar); font-weight: 700; }
h3 { font-size: .95rem; margin: 0 0 .5rem; }
a { color: var(--hijau-700); text-underline-offset: 2px; }
p { margin: 0 0 .6rem; }
p:last-child { margin-bottom: 0; }
code { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem; background: var(--garis-2); padding: .1rem .34rem; border-radius: var(--r-mini); }
small { display: block; font-size: .8rem; line-height: 1.45; }
.pudar { color: var(--pudar); }
.ka { text-align: right; }
.kecil { font-size: .8rem; }
.tenang { margin: 0 0 .25rem; font-size: .875rem; color: var(--pudar); }
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--hijau-600); outline-offset: 2px; border-radius: 6px; }
.lompat { position: absolute; left: -999px; }
.lompat:focus { left: .6rem; top: .6rem; z-index: 99; background: var(--putih);
  padding: .5rem .8rem; border-radius: 8px; box-shadow: var(--bayang-2); }

/* ============================================================ rangka halaman */
.shell { display: grid; grid-template-columns: var(--sisi-l) minmax(0, 1fr); min-height: 100vh; }
.shell > * { min-width: 0; }
.sisi { background: linear-gradient(180deg, var(--hijau-900), #0f3a23 70%);
  color: #d8e5de; padding: 1.4rem 1.1rem; display: flex; flex-direction: column;
  gap: 1.4rem; position: sticky; top: 0; height: 100vh; z-index: var(--sisi-z); }
.isi { padding: var(--sp) var(--sp) 4rem;
  width: 100%; min-width: 0; }
/* `polos` hanya berarti TANPA bilah sisi. Padding-nya tetap: halaman publik
   yang menempel ke tepi layar terbaca "berantakan".
   LEBAR TIDAK dibatasi di sini. Dulu `max-width: 820px` dipasang untuk formulir
   ODES, dan karena semua halaman publik memakai kelas yang sama, seluruh
   beranda & halaman masuk ikut menyempit 761 px di layar 1440 — itulah keluhan
   "di desktop jadi berantakan, malah dipaksa ke tengah" (Bos 5 Nov 2026).
   Batas lebar milik halaman, bukan milik layout: pakai `.sempit`. */
.isi.polos { padding: var(--sp) var(--sp) 4rem; }
.isi.polos.sempit { max-width: 820px; margin-inline: auto; }
/* Halaman yang mengurus latar & paddingnya sendiri (halaman masuk). */
.isi.polos.tanpa-padding { padding: 0; }
.isi.polos.tanpa-padding .latar-publik { min-height: 100vh; }

.merek { display: flex; align-items: center; gap: .7rem; min-width: 0;
  text-decoration: none; }
.merek img { display: block; height: 30px; width: auto; background: #fff;
  padding: .22rem .4rem; border-radius: 7px; flex: 0 0 auto; }
.merek svg.lambang { display: block; width: 34px; height: 34px; flex: 0 0 auto; }
.merek .nama { min-width: 0; }
.merek b { display: block; color: #fff; font-size: 1rem; font-weight: 700; letter-spacing: -.01em; }
.merek small { display: inline; color: #a7c2b5; line-height: 1.35; }
/* :where() menurunkan kekhususan ke 0,0,1 supaya `nav` tetap bergaya tanpa
   menimpa kelas modifier. Sebelumnya selektor telanjang ini memaksa
   flex-direction:column pada SETIAP <nav> — termasuk .pub-nav (menu header
   menumpuk) dan .pub-halaman (paging menumpuk tegak di halaman artikel). */
:where(nav) { display: flex; gap: .18rem; }
:where(nav) a { color: #cfdfd8; text-decoration: none; padding: .58rem .8rem;
  border-radius: var(--r-kecil); font-size: .875rem; font-weight: 500; display: flex;
  align-items: center; gap: .6rem; border: 1px solid transparent; }
.ik { width: 18px; height: 18px; flex: 0 0 auto; fill: currentColor; opacity: .85; }
.ik.kecil { width: 15px; height: 15px; }
:where(nav) a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
:where(nav) a.ini { background: var(--hijau-600); color: #fff; font-weight: 600;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25); }
:where(nav) a.ini .ik { opacity: 1; }
/* Menu sisi dasbor satu-satunya yang memang tegak.
   Sisi dipatok setinggi layar (sticky, height:100vh), jadi isinya WAJIB muat —
   tanpa gulir di sini, kotak pengguna + tombol Keluar terdorong ke bawah layar
   dan tidak bisa dijangkau siapa pun. Terukur dengan 12 menu: butuh 815px saat
   layar 720px, dan label Keluar tampak menggantung di tepi bawah. Yang digulir
   menu-nya, bukan seluruh sisi (kalau .sisi yang digulir, merek ikut hilang). */
.nav-sisi { flex-direction: column; overflow-y: auto; overscroll-behavior: contain;
  min-height: 0; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .28) transparent; }
.nav-sisi::-webkit-scrollbar { width: 6px; }
.nav-sisi::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .25); border-radius: 3px; }
/* Lencana jumlah belum dibaca di butir menu sidebar (mis. "Message").
   `margin-left:auto` menempelkannya ke tepi kanan butir, jadi ia mengikuti
   panjang label tanpa satu pun koordinat yang perlu disesuaikan. */
.nav-sisi .menu-lencana { margin-left: auto; flex: 0 0 auto; min-width: 19px;
  padding: 0 6px; border-radius: 10px; background: var(--merah); color: #fff;
  font-size: .68rem; font-weight: 700; line-height: 18px; text-align: center; }
/* bilah bawah hanya untuk layar sempit */
.nav-bawah { display: none; }
.kaki { margin-top: auto; display: flex; flex-direction: column; gap: .7rem; }
.kotak-pengguna { background: rgba(255, 255, 255, .07); border-radius: var(--r-kecil);
  padding: .7rem .8rem; min-width: 0; }
.kotak-pengguna b { color: #fff; font-size: .88rem; display: block;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kotak-pengguna small { color: #a7c2b5; font-size: .74rem; word-break: break-all; }
.tanda { display: inline-block; margin-top: .4rem; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .07em; color: var(--hijau-300); font-weight: 700; }

/* ============================================ indikator proses (spinner)
   Bilah tipis di paling atas layar + kunci layar. Dipakai setiap permintaan
   AJAX; di 30 ribu pengguna halaman tidak boleh diam tanpa tanda apa pun. */
#hub-proses { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 60;
  background: linear-gradient(90deg, transparent, var(--hijau-500), transparent);
  background-size: 45% 100%; background-repeat: no-repeat;
  animation: hub-geser 1s linear infinite; }
#hub-proses[hidden] { display: none; }
@keyframes hub-geser { from { background-position: -50% 0; } to { background-position: 150% 0; } }

.spinner { display: inline-block; width: 15px; height: 15px; flex: 0 0 auto;
  border: 2px solid rgba(255, 255, 255, .45); border-top-color: #fff;
  border-radius: 50%; animation: hub-putar .6s linear infinite; }
.spinner.gelap { border-color: rgba(16, 29, 24, .2); border-top-color: var(--hijau-700); }
@keyframes hub-putar { to { transform: rotate(360deg); } }

/* Tombol yang sedang mengirim: matikan klik ganda, tunjukkan ia bekerja. */
.tombol.sedang { opacity: .85; cursor: progress; }
.tombol.sedang > .spinner { margin-right: .15rem; }

/* Isi yang sedang dimuat ulang lewat AJAX diredupkan sedikit. */
.memuat { opacity: .55; transition: opacity .15s; pointer-events: none; }

/* Gelembung "sedang menulis" asisten. */
.aibalon .aiteks { white-space: pre-wrap; }
.aiteks-tunggu { display: flex; gap: .28rem; align-items: center; min-height: 1.2rem; }
.ai-titik { width: 7px; height: 7px; border-radius: 50%; background: var(--hijau-600);
  animation: hub-pantul 1.1s ease-in-out infinite; }
.ai-titik:nth-child(2) { animation-delay: .16s; }
.ai-titik:nth-child(3) { animation-delay: .32s; }
@keyframes hub-pantul { 0%, 80%, 100% { opacity: .3; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-4px); } }

/* Hormati preferensi pengguna: tanpa animasi, tetap ada tanda "sedang bekerja". */
@media (prefers-reduced-motion: reduce) {
  #hub-proses { animation: none; background: var(--hijau-500); }
  .spinner, .ai-titik { animation: none; }
  .aiteks-tunggu::after { content: "sedang menulis…"; font-size: .78rem; color: var(--pudar); }
}

/* ====================================== panel ubah sebaris dalam tabel */
.ubah { display: inline-block; text-align: left; position: relative; }
.ubah > summary.tombol { list-style: none; cursor: pointer; display: inline-flex;
  border: 1px solid var(--hijau-300); color: var(--hijau-700); background: var(--hijau-l);
  min-height: 32px; padding: .34rem .7rem; font-size: .8rem; border-radius: var(--r-kecil);
  font-weight: 600; align-items: center; justify-content: center; }
.ubah > summary.tombol:hover { background: var(--hijau-100); border-color: var(--hijau-500);
  color: var(--hijau-700); }
.ubah > summary.tombol:focus-visible { outline: 2px solid var(--hijau-600); outline-offset: 2px; }
.ubah > summary::-webkit-details-marker { display: none; }
.ubah[open] { display: block; }
.ubah[open] > summary { margin-bottom: .7rem; }
/* Panel ubah di dalam tabel: di layar lebar kolom aksi hanya selebar ~1%,
   jadi panel 420px yang mengalir normal meluber ke luar viewport (terukur
   tepi kanan = 1582px pada viewport 1280px). Di layar lebar panel ditambatkan
   ke tepi KANAN sel sehingga melebar ke kiri, dan dibatasi tinggi + gulir
   sendiri supaya tidak terpotong oleh .tabel-bungkus yang ber-overflow. */
.ubah form { width: 100%; box-sizing: border-box; background: var(--zebra);
  border: 1px solid var(--garis); border-radius: var(--r-kecil); padding: .9rem 1rem;
  box-shadow: var(--bayang-2); }
.ubah form label { font-size: .78rem; margin-bottom: .6rem; }
@media (min-width: 721px) {
  .ubah form { position: absolute; right: 0; z-index: 5; width: min(420px, 88vw);
    max-height: min(60vh, 400px); overflow-y: auto; }
}

/* ======================================================== bilah saring */
.saring { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  padding: .7rem .8rem; margin-bottom: var(--ruang); box-shadow: var(--bayang); }
.saring input, .saring select { width: auto; flex: 1 1 220px; margin-top: 0; min-height: 42px;
  /* AKAR luber /keuangan @360px (isi 437px vs layar 360px): <select> native
     memakai lebar opsi terpanjang sebagai ukuran intrinsiknya ("KDMP Bina Usaha"
     -> 407px) dan menolak menyusut walau flex-basis kecil. Setiap item flex
     butuh min-width:0; kontrol form tidak terkecuali. */
  min-width: 0; max-width: 100%; }
.saring .tombol { flex: 0 0 auto; min-height: 42px; }
/* Jaring pengaman: kontrol <select> mana pun tidak boleh melampaui wadahnya.
   Tanpa ini, satu opsi ber-nama panjang cukup untuk membuat SELURUH halaman
   bergulir mendatar — dan bar bawah (position:fixed) ikut tampak "timbul
   tenggelam" karena tak lagi sejajar tepi dokumen. */
select { max-width: 100%; }
.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ================================================================== kepala */
/* ================================================== pelatihan (materi LMS) */
.kolom-pilih { width: 1%; text-align: center; }
/* Bilah progres belajar: warna hijau Agrinas, tanpa pustaka. */
/* Bilah progres — `:not(ul)` WAJIB: `<ul class="jejak">` adalah daftar jejak
   tindak lanjut (toko, rapat, gerai). Tanpa itu daftar mewarisi height 8px +
   overflow hidden dan isinya tidak pernah terlihat walau <details> terbuka. */
.jejak:not(ul) { height: 8px; border-radius: 999px; background: var(--zebra);
  border: 1px solid var(--garis); overflow: hidden; }
.jejak:not(ul) > span { display: block; height: 100%; background: var(--hijau-600, #1c7a4f); }
.jejak-baris { display: flex; align-items: center; gap: .6rem; }
.jejak-baris .jejak { flex: 1 1 auto; min-width: 80px; }
.jejak-baris b { font-variant-numeric: tabular-nums; font-size: .82rem; color: var(--pudar); }
/* Isi modul datang sebagai HTML dari LMS (gambar, paragraf, daftar). Batasi
   lebar baca supaya nyaman dan pastikan gambar tidak meluber keluar kartu. */
.materi-isi { max-width: 78ch; line-height: 1.7; }
.materi-isi img { max-width: 100%; height: auto; border-radius: var(--r-kecil); }
.materi-isi h1, .materi-isi h2, .materi-isi h3 { margin-top: 1.4rem; }
.materi-isi table { width: auto; max-width: 100%; }
.kepala { display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem; margin-bottom: var(--ruang); padding-bottom: var(--ruang);
  border-bottom: 1px solid var(--garis); }
.kepala h1 { margin-bottom: .3rem; }
/* Deskripsi kepala dipotong SATU BARIS di semua lebar. Kalau ia membungkus,
   tinggi kepala ikut panjang teks dan jadi beda-beda antar halaman (terukur:
   920-1024px /distribusi & /vendor 109-110px vs 87-88px halaman lain; di
   ponsel dulu /distribusi 155px vs dasbor 133px). Teks utuh tetap di DOM
   (pembaca layar & salin-tempel tidak terpengaruh). */
.kepala > div { min-width: 0; }
/* Deskripsi kepala dipotong SATU BARIS di semua lebar >=721px. Kalau ia
   membungkus, tinggi kepala ikut panjang teks dan jadi beda-beda antar halaman
   (terukur: 920-1024px /distribusi & /vendor 109-110px vs 87-88px halaman lain;
   di ponsel dulu /distribusi 155px vs dasbor 133px). Teks utuh tetap di DOM
   (pembaca layar & salin-tempel tidak terpengaruh).
   CATATAN: gate `_ukur_isi.py` menuntut DUA hal yang bertabrakan di 721-1280px —
   "tidak terpotong" DAN "tinggi kepala seragam". Di rentang itu /materi butuh
   998px teks dalam 712px ruang. Yang dipertahankan: tinggi seragam (kepala
   88px), karena kepala yang bergerigi terbaca lebih buruk daripada satu kalimat
   yang dipendekkan dengan elipsis. Di ponsel (<=720px) ia MEMBUNGKUS, lihat
   aturan mobile di bawah. */
.kepala .tenang { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.remah { font-size: .8rem; margin: 0 0 .7rem; }
.remah a { color: var(--pudar); text-decoration: none; }
.remah a:hover { color: var(--hijau-700); text-decoration: underline; }
.tombol-baris { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
/* Formulir di dalam baris tombol (mis. "Hapus" yang butuh @method DELETE) ikut
   sebaris, TIDAK menumpuk tombol lain ke baris kedua. Dulu `form` tetap `block`
   sehingga tombol saudaranya ditarik setinggi 51px (tinggi baris + leading
   inline) sementara tombol di dalam form 40px — terlihat bergerigi. */
.tombol-baris > form { display: flex; flex: 0 0 auto; margin: 0; }
/* Baris tombol di KANAN + jarak ke blok berikutnya (mis. Unduh CSV & Koneksi API
   Bank di /keuangan/gaji): dulu rata kiri dan menempel ke kartu KPI. Di ponsel
   tombolnya melebar penuh — tombol kanan yang sempit lebih sulit ditekan. */
.tombol-baris.kanan { justify-content: flex-end; margin: .2rem 0 1.2rem; }
@media (max-width: 560px) {
  .tombol-baris.kanan { justify-content: stretch; }
  /* Label panjang ("Unduh CSV semua yang menunggu") tidak muat separuh layar
     390px: dua tombol bertumpuk selebar baris supaya teksnya satu-dua baris. */
  .tombol-baris.kanan > .tombol, .tombol-baris.kanan > form > .tombol { flex: 1 1 100%; }
}

/* Baris aksi Gerai / Outlet: bloknya berdiri sendiri, jadi tombol + keterangan
   diletakkan di tengah (bukan menempel kiri seperti baris tombol dalam form). */
.tombol-gerai { display: grid; justify-items: center; gap: .4rem; margin-top: .7rem; text-align: center; }
.tombol-gerai + .kosong { text-align: center; }

/* Kotak barcode di dialog produk UMKM: latar putih & padding, karena barcode
   dicetak hitam-putih dan tepi abu-abu/bayangan bisa ikut terbaca pemindai. */
.barcode-kotak { display: grid; justify-items: center; gap: .45rem; padding: .9rem .8rem;
  background: var(--putih); border: 1px solid var(--garis-2); border-radius: var(--r-kecil); }
.barcode-kotak img { display: block; width: 100%; max-width: 360px; height: auto; }
.barcode-kotak .barcode-kode { font-family: var(--mono, ui-monospace, monospace); letter-spacing: .12em; }

/* ==================================================================== blok */
.blok { background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  padding: 1.2rem 1.3rem 1.3rem; margin-bottom: var(--ruang); box-shadow: var(--bayang); }
.blok.sempit { max-width: 460px; }
.blok > h2:first-child { padding-bottom: .7rem; border-bottom: 1px solid var(--garis-2);
  margin-bottom: 1rem; }
.dua-kolom { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: 1.1rem; align-items: start; }
.dua-kolom > div { min-width: 0; }

/* ============================================================= kartu angka */
.petak { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: .85rem; margin-bottom: var(--ruang); }
.kartu { background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  padding: .95rem 1.05rem; box-shadow: var(--bayang); min-width: 0; }
/* Deret kartu ringkasan yang bisa diklik (mis. status distribusi).
   AKAR: kelas ini dipakai view tapi aturannya tidak pernah ditulis, jadi kartu
   jatuh sebagai blok penuh yang bertumpuk dan tidak ada penanda pilihan aktif. */
.kartu-baris { display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr));
  gap: .7rem; margin-bottom: var(--ruang); }
/* Sebagian deret kartu berupa <form> (tombol kirim) yang MEMBUNGKUS kartunya.
   Tanpa ini <form> meregang setinggi sel grid sementara tombolnya tidak, jadi
   kartu-kartu tampak bertingkat walau selnya sudah rata. Form jadi flex dan
   kartunya mengisi tinggi sel; isinya ditengahkan supaya tidak ada rongga
   menganggur di kartu yang teksnya pendek. */
.kartu-baris > form { display: flex; }
.kartu-baris > form > .kartu { flex: 1 1 auto; display: flex; flex-direction: column;
  justify-content: center; }
/* Kartu peran di /admin/akun: satu peran satu kartu, judul lalu wewenangnya.
   Tanpa aturan ini <small> menempel di samping <b> dan lima wewenang peran jadi
   satu baris panjang yang justru lebih sulit dibaca daripada paragraf lama.
   Lebar minimum 250px (bukan 146px milik `.kartu-baris`): di ponsel kartu jatuh
   satu kolom penuh, di desktop 3 per baris — terukur 146px membuat teksnya jadi
   6 baris per kartu dan deretnya 265px tinggi. */
.kisi-peran { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: .7rem; margin-bottom: var(--ruang); }
.kartu-peran b { display: block; font-size: .9rem; margin-bottom: .25rem; }
.kartu-peran small { display: block; line-height: 1.5; font-size: .78rem; }
a.kartu { text-decoration: none; color: inherit; display: block;
  transition: border-color .12s, background .12s, box-shadow .12s; }
a.kartu:hover { border-color: var(--hijau-500); background: var(--hijau-100); }
a.kartu.ini { border-color: var(--hijau-600); background: var(--hijau-l);
  box-shadow: 0 0 0 1px var(--hijau-600), var(--bayang); }
.petak-judul { margin: 1.2rem 0 .4rem; font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--pudar); }
.kartu.angka { border-left: 3px solid var(--hijau-300); }
.kartu.angka small { text-transform: uppercase; letter-spacing: .07em; font-size: .7rem;
  line-height: 1.3;
  color: var(--pudar); font-weight: 700; }
.kartu.angka b { font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2rem); line-height: 1.15;
  display: block; margin-top: .1rem; font-variant-numeric: tabular-nums;
  /* Nilai kartu bisa berupa email/URL panjang tanpa spasi. Tanpa ini kartu
     melebar melewati tepi layar dan SELURUH halaman bisa digeser ke samping
     (terukur /profil @360px: 60px luber, pelakunya `b` 367px di kotak 256px). */
  overflow-wrap: anywhere; }
/* Kartu isian panjang (email, nama koperasi) lebih kecil dari kartu angka
   dasbor — 1.6-2rem bukan ukuran yang enak untuk alamat email. */
.kartu.angka b.panjang { font-size: .95rem; line-height: 1.35; }
.aksi-kuning { border-left-color: var(--kuning-g); }
.aksi-merah { border-left-color: var(--merah-g); }
.aksi-hijau { border-left-color: var(--hijau-g); }
.aksi-biru { border-left-color: var(--biru-g); }
.t-kuning { color: var(--kuning); } .t-merah { color: var(--merah); }
.t-hijau { color: var(--hijau-600); } .t-biru { color: var(--biru); }

/* =================================================================== tabel */
.tabel-bungkus { overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch; margin: 0 -.35rem; padding: 0 .35rem; }
table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: .875rem; }
th { text-align: left; font-size: .7rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--pudar); padding: .55rem .7rem; background: var(--zebra);
  border-bottom: 1px solid var(--garis); white-space: nowrap; font-weight: 700; }
th:first-child { border-top-left-radius: var(--r-kecil); }
th:last-child { border-top-right-radius: var(--r-kecil); }
td { padding: .7rem; border-bottom: 1px solid var(--garis-2); vertical-align: middle;
  overflow-wrap: anywhere; }
tbody tr:nth-child(even) { background: #fcfefd; }
tbody tr:hover { background: var(--hijau-100); }
tbody tr:last-child td { border-bottom: 0; }
.kolom-aksi { width: 1%; white-space: nowrap; text-align: right; }
/* Sel aksi sering memuat tombol + formulir (hapus ber-@method). Tanpa ini
   formulirnya `block` dan tombolnya jatuh ke baris KEDUA di dalam sel. */
.kolom-aksi > form { display: inline-flex; vertical-align: middle; margin: 0; }
.kolom-aksi > * + * { margin-left: .35rem; }
td small { color: var(--pudar); margin-top: .15rem; }
.judul-sel { font-weight: 600; font-size: .95rem; line-height: 1.35; }
.kosong { text-align: center; color: var(--pudar); padding: 1.6rem .8rem; }

/* =========================================================== lencana status */
.lencana { display: inline-flex; align-items: center; gap: .35rem; padding: .25rem .6rem;
  border-radius: var(--r-kapsul); font-size: .7rem; font-weight: 700; letter-spacing: .02em;
  white-space: nowrap; border: 1px solid transparent; line-height: 1.35; }
/* Di ponsel tabel berubah jadi kartu; lencana panjang (mis. "Jawa Barat (luar
   Jabodetabek)") ikut meluber keluar kartu karena nowrap — biarkan membungkus. */
@media (max-width: 720px) { .tabel-bungkus .lencana { white-space: normal; } }
.lencana::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.s-BARU { background: var(--garis-2); color: var(--tinta-2); border-color: var(--garis); }
.s-DIKERJAKAN { background: var(--kuning-l); color: var(--kuning); border-color: var(--kuning-g); }
.s-DIAJUKAN { background: var(--biru-l); color: var(--biru); border-color: var(--biru-g); }
/* Pasokan: Disetujui = HIJAU (pasokan diterima), Ditolak = merah. */
.s-DISETUJUI { background: var(--hijau-l); color: var(--hijau-600); border-color: var(--hijau-g); }
.s-DIPROSES { background: var(--biru-l); color: var(--biru); border-color: var(--biru-g); }
.s-REVISI { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }
.s-DITOLAK { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }
.s-SELESAI { background: var(--hijau-l); color: var(--hijau-600); border-color: var(--hijau-g); }
/* Status distribusi: DIKIRIM = dalam perjalanan (biru), DITERIMA = hijau,
   DITOLAK = merah. DIAJUKAN memakai gaya .s-DIAJUKAN yang sudah ada. */
.s-DIKIRIM { background: var(--kuning-l); color: var(--kuning); border-color: var(--kuning-g); }
.s-DITERIMA { background: var(--hijau-l); color: var(--hijau-600); border-color: var(--hijau-g); }
.s-DITOLAK { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }

/* ================================================================== tombol */
.tombol { display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .55rem 1rem; min-height: 40px; border: 1px solid transparent; cursor: pointer;
  border-radius: var(--r-kecil); font-size: .875rem; font-weight: 600; text-decoration: none;
  font-family: inherit; line-height: 1.2; transition: background .12s, border-color .12s, color .12s; }
.tombol.utama { background: var(--hijau-600); color: #fff; box-shadow: 0 1px 2px rgba(16, 29, 24, .18); }
.tombol.utama:hover { background: var(--hijau-700); }
/* Tombol netral = GARIS HIJAU (permintaan Bos 2026-10-28: tombol putih polos
   terbaca sebagai tombol mati). Warna & hover sama dengan `.hijau-garis`
   sehingga satu bahasa visual: hijau = bisa ditekan. */
.tombol.samar { background: var(--putih); border-color: var(--hijau-500); color: var(--hijau-700); }
.tombol.samar:hover { border-color: var(--hijau-600); color: var(--hijau-700); background: var(--hijau-100); }
/* Aksi daftar produk (koperasi): dua tombol utama memakai SATU gaya — hijau
   garis, bukan isian penuh, supaya keduanya setara dan tidak ada yang lebih
   menonjol. Ikon replika .ikon-kiri (16px) sudah ada, jadi tidak perlu baru. */
.tombol.hijau-garis { background: var(--putih); border-color: var(--hijau-500); color: var(--hijau-700); }
.tombol.hijau-garis:hover { background: var(--hijau-100); border-color: var(--hijau-600); color: var(--hijau-700); }
.tombol.hijau-garis .ik { opacity: 1; }
/* Kembaran merahnya: aksi yang MENGHAPUS/membatalkan (mis. "Batalkan" nota).
   Tetap garis, bukan isian penuh — batal bukan aksi utama halaman. */
.tombol.merah-garis { background: var(--putih); border-color: var(--merah-g); color: var(--merah); }
.tombol.merah-garis:hover { background: var(--merah-l); border-color: var(--merah); color: var(--merah); }
.tombol.mini { padding: .34rem .6rem; min-height: 32px; font-size: .8rem; }
/* Di ponsel .mini turun ke 32px dan tombolnya berdampingan di sel aksi tabel
   dengan jarak 8px — kurang dari separuh jarak jempol, jadi "Status" gampang
   meleset jadi "Hapus" (hapus tugas, tanpa undo). Kembalikan ke 40px serta
   pisahkan sedikit; hanya di ponsel, desktop tetap rapat. */
@media (max-width: 720px) {
  .tombol.mini { min-height: 40px; padding: .5rem .7rem; }
  .tabel-bungkus td.kolom-aksi .tombol.mini + .tombol.mini { margin-left: .3rem; }
}
/* Tombol berisi ikon SAJA: persegi, ikonnya sedikit lebih besar dari `.ik`
   bawaan (18px) karena di sini ikon adalah satu-satunya isi tombol. Ukuran
   tombolnya ditentukan di tempat pemakaian (mis. `.kat-aksi .tombol-ikon`). */
.tombol-ikon { padding: 0; }
.tombol-ikon .ik { width: 20px; height: 20px; opacity: 1; }
/* Tombol ber-ikon + label (mis. kepala halaman Koperasi). `inline-flex` supaya
   ikon & teksnya benar-benar sebaris dengan jarak tetap — sebagai inline-block
   biasa, ikon 16px dan teks duduk di baseline yang berbeda dan jaraknya jadi
   spasi teks yang ikut menyusut di layar sempit. Dipakai `<a>` maupun `<button>`
   (tombol formulir), jadi selektornya kelas, bukan elemen. */
.tombol.ikon-kiri { display: inline-flex; align-items: center; gap: .45rem; }
.tombol.ikon-kiri .ik { flex: 0 0 auto; width: 16px; height: 16px; opacity: .85; }
.tombol.ikon-kiri:hover .ik { opacity: 1; }
.tombol.peringatan { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }
.tombol.peringatan:hover { background: #fbe0dd; }
/* Panel buka-tutup native (<details class="kartu">), mis. "Hapus akun" di
   /profil: penanda bawaan tetap dipakai, hanya diwarnai supaya jelas bisa dibuka. */
details.kartu > summary { cursor: pointer; font-weight: 600; color: var(--tinta-2); }
details.kartu[open] > summary { margin-bottom: .6rem; color: var(--merah); }
/* /pasokan — kepala panel "Tambah Pasokan" dibentuk seperti tombol besar: ikon
   dalam lencana, judul + keterangan, panah yang berputar saat terbuka. Aturan
   umum di atas mewarnai MERAH saat [open] (itu untuk "Hapus akun" di /profil),
   jadi di sini ditimpa hijau. `:active` = umpan balik saat ditekan. */
details.lipat-pasokan > summary { display: flex; align-items: center; gap: .7rem;
  padding: .7rem .85rem; list-style: none; cursor: pointer;
  border: 1px solid var(--hijau-500); border-radius: var(--r-kecil);
  background: var(--hijau-100); color: var(--hijau-700);
  transition: background .12s, border-color .12s, color .12s; }
details.lipat-pasokan > summary::-webkit-details-marker { display: none; }
details.lipat-pasokan > summary:hover { background: #d5efdd; border-color: var(--hijau-600); }
details.lipat-pasokan > summary:active { background: var(--hijau-800); border-color: var(--hijau-800); color: #fff; }
details.lipat-pasokan > summary:focus-visible { outline: 2px solid var(--hijau-600); outline-offset: 2px; }
details.lipat-pasokan[open] > summary { background: var(--hijau-600); border-color: var(--hijau-600);
  color: #fff; margin-bottom: .8rem; }
.lencana-lipat { flex: 0 0 auto; display: grid; place-items: center; width: 1.9rem; height: 1.9rem;
  border-radius: 50%; background: #fff; color: var(--hijau-700); }
details.lipat-pasokan[open] .lencana-lipat { background: rgba(255, 255, 255, .2); color: #fff; }
/* /keuangan/gaji — satu <details> per tiket: kepala ringkas (jumlah penerima +
   total) lalu tabel penerima. `flex-wrap` supaya di ponsel total turun sendiri,
   bukan meluber. */
.rincian-gaji { margin-top: .7rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); background: #fff; }
.rincian-gaji > summary { display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: .2rem .8rem;
  padding: .7rem .9rem; cursor: pointer; font-weight: 600; font-size: .88rem; }
.rincian-gaji > summary::-webkit-details-marker { display: none; }
.rincian-gaji > summary:focus-visible { outline: 2px solid var(--hijau-600); outline-offset: 2px; }
.rincian-gaji[open] > summary { border-bottom: 1px solid var(--garis); }
.rincian-gaji .tabel-bungkus { margin: 0; border: 0; }
.rincian-jumlah { display: flex; flex-wrap: wrap; gap: .1rem .9rem; padding: .6rem .9rem;
  border-top: 1px solid var(--garis); font-size: .82rem; color: var(--pudar); }
.rincian-jumlah b { color: var(--tinta); font-variant-numeric: tabular-nums; }
.lencana-lipat .ik { width: 16px; height: 16px; opacity: 1; }
.teks-lipat { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.judul-lipat { font-weight: 700; font-size: .95rem; }
.ket-lipat { font-size: .8rem; font-weight: 500; opacity: .85; }
.panah-lipat { flex: 0 0 auto; margin-left: auto; width: 8px; height: 8px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .15s; }
details.lipat-pasokan[open] .panah-lipat { transform: rotate(225deg); }
/* SEMUA tombol konten satu gaya outline hijau (permintaan Bos 2026-10-27).
   Pager memakai partial bersama (partials/halaman) yang juga dipakai halaman
   lain, jadi tombolnya diwarnai dari section halamannya: #tugas/#barang (/kerja),
   #katalog (/distribusi/pengajuan), #ds (/distribusi). */
#tugas .paging .tombol, #barang .paging .tombol, #katalog .paging .tombol,
#ds .paging .tombol {
  background: var(--putih); border-color: var(--hijau-500); color: var(--hijau-700); }
#tugas .paging .tombol:hover, #barang .paging .tombol:hover,
#katalog .paging .tombol:hover, #ds .paging .tombol:hover {
  background: var(--hijau-100); border-color: var(--hijau-600); color: var(--hijau-700); }
/* Kuning penuh (bukan `--kuning-l` yang pucat): tombol aksi yang harus terlihat
   sebagai tombol di antara tombol hijau/putih — mis. "Report Check In/Check Out". */
.tombol.kuning { background: #f5c43c; color: var(--kuning); border-color: var(--kuning-g); }
.tombol.kuning:hover { background: #eab72a; border-color: #d9a413; }
.tombol.lebar { width: 100%; }
.sebaris { display: inline-block; margin: 0 0 .3rem .3rem; }
/* AKAR tombol menempel isian (terukur 0px di /pasokan, desktop & ponsel):
   `.sebaris` = inline-block TANPA flex, jadi `gap` tidak berlaku dan input
   duduk rapat dengan tombolnya. Di dalam sel tabel aksi jadikan flex supaya
   `gap` bekerja. Di luar tabel dibiarkan apa adanya (4 view lain tidak berubah). */
.tabel-bungkus td .sebaris { display: flex; align-items: center; gap: .5rem; margin: 0; }
/* Isian catatan di sel aksi ikut fleksibel TAPI punya lebar minimum: tanpa ini
   kolom aksi (width:1%) menekannya jadi 24px dan placeholder tak terbaca;
   sebelumnya ia 122px tetapi TERTIMPA tombol (-64px) — sama-sama rusak. */
.tabel-bungkus td .sebaris input:not([type="hidden"]) { flex: 1 1 auto; min-width: 7rem; }

/* =============================================================== formulir */
label { display: block; margin-bottom: .85rem; font-size: .82rem; font-weight: 600;
  color: var(--tinta-2); }
/* Keterangan kecil di dalam label (mis. contoh format email) mewarisi 600 milik
   label sehingga terbaca seperti judul kolom. Turunkan ke berat isi. */
label small { font-weight: 400; }
/* AKAR centang raksasa di /workspace/tugas: aturan di bawah menargetkan SEMUA
   <input>, termasuk type=checkbox/radio — kotaknya jadi selebar kolom + 42px
   tinggi, teks label terdorong ke baris berikutnya. Semua jenis di luar
   "kolom teks" dikecualikan di sini (satu tempat, semua formulir ikut sehat). */
input, select, textarea { width: 100%; margin-top: .35rem; padding: .6rem .7rem; font: inherit;
  font-size: .875rem; border: 1px solid #ccd7d1; border-radius: var(--r-kecil); background: var(--putih);
  color: var(--tinta); font-weight: 400; min-height: 42px; }
/* Atribut `hidden` HARUS menang. Bawaan peramban `[hidden]{display:none}`
   kalah oleh `display:flex/block` milik author, sehingga elemen ber-`hidden`
   tetap tampil — panel "+ Baru" pernah setinggi 709px dan menekan daftar
   percakapan sampai tinggal 13px (1 baris terlihat). */
[hidden] { display: none !important; }
/* Kotak centang/radio: ukuran asli, sejajar teks labelnya. */
/* 1.1em = "menyesuaikan tulisan": kotak tumbuh bersama ukuran huruf labelnya,
   jadi ia tak lagi 13px bawaan peramban yang lebih kecil dari teks 14px. */
input[type="checkbox"], input[type="radio"] { width: 1.1em; height: 1.1em; min-height: 0;
  margin: 0; padding: 0; accent-color: var(--hijau-600); flex: none; }
/* <label><input type=checkbox> Teks</label> -> satu baris: kotak di kiri,
   teks di kanan, keduanya rata tengah. */
label.centang { display: flex; flex-direction: row; align-items: center; gap: .5rem;
  font-weight: 400; margin-bottom: .3rem; }

/* AKAR luber di SEMUA formulir: <label>Teks<input></label> ditulis sebaris tanpa
   <br>. Karena input adalah inline-block, teks label dan kotak isian berbagi
   satu baris — dengan width:100% kotak isian mulai SETELAH teks label dan
   melebar 100% dari situ, jadi tepi kanannya keluar dari kartu (terukur 100px
   lebih lebar dari wadah, dan 58px keluar viewport di dalam panel ubah).
   display:block membuat setiap kotak isian mulai dari tepi kiri label. */
input, select, textarea { display: block; }
input::placeholder, textarea::placeholder { color: #67766f; }
input:hover, select:hover, textarea:hover { border-color: #b6c4bd; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--hijau-300);
  outline-offset: 1px; border-color: var(--hijau-500); }
textarea { resize: vertical; min-height: 96px; }
/* AKAR tombol menempel elemen sebelumnya (terukur 0px di 3 halaman):
   isian/label/paging tepat diikuti tombol tanpa jarak apa pun.
   asisten  : <textarea> lalu <div class="tombol-baris">
   pasokan  : <input type="text"> lalu <button class="tombol">
   stok     : <nav class="paging"> lalu <button class="tombol">
   Satu aturan di sini menutup semuanya — tanpa perlu menyisipkan pembungkus
   baru di tiap blade. */
label + .tombol, label + .tombol-baris,
/* `:not([type=hidden])` WAJIB: input hidden (mis. _token / periode) bukan elemen
   yang terlihat, tetapi tetap cocok `input + .tombol` — tombolnya lalu terdorong
   11,2 px ke bawah dan tidak sejajar dengan tombol lain di baris yang sama. */
input:not([type="hidden"]) + .tombol, input:not([type="hidden"]) + .tombol-baris,
select + .tombol, select + .tombol-baris,
textarea + .tombol, textarea + .tombol-baris,
.paging + .tombol, .paging + .tombol-baris,
p.bantuan + .tombol, p.bantuan + .tombol-baris { margin-top: .7rem; }
input[type="file"] { padding: .45rem .6rem; background: var(--zebra); font-size: .85rem; }
.grid-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0 1.1rem; }
/* Form kasir POS: label Total/Pembeli menempel ke tabel Keranjang di atasnya
   (terukur 0px) — beri jeda yang sama dengan jarak antarblok halaman lain. */
.kop-form-2 { margin-top: 1rem; }
/* ---- Baris aksi & kelompok di dalam .grid-form (/profil dll.) ----
   `.kolom-aksi` adalah kelas SEL TABEL (width: 1%, nowrap, rata kanan). Di
   /profil kelas itu dipakai untuk dua <div> di dalam form, jadi kotaknya 3px
   sementara isinya tombol 217px + keterangan nowrap: halaman meluber 46px di
   layar 360px dan tombol "Simpan profil" menggantung di tengah kolom.
   Baris aksi formulir punya kelasnya sendiri dan SELALU selebar form. */
.grid-form > .form-aksi { grid-column: 1 / -1; display: flex; flex-wrap: wrap;
  align-items: center; gap: .6rem; }
.grid-form > .form-aksi > .pudar { flex: 1 1 16rem; min-width: 0; margin: 0;
  white-space: normal; }
/* Judul kelompok: 17 isian datar tak terbaca sebagai satu hamparan, di desktop
   maupun ponsel. `:first-of-type` menghapus garis pemisah kelompok pertama. */
.form-kelompok { grid-column: 1 / -1; margin: .55rem 0 -.15rem; padding-top: .9rem;
  border-top: 1px solid var(--garis-2); font-size: .7rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--pudar); }
.grid-form > .form-kelompok:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
/* <input type=date> bawaan 2px lebih tinggi dari input teks → garis kolom
   tidak rata. Kunci tinggi kontrol di dalam grid (file dikecualikan). */
.grid-form > label > input:not([type="file"]), .grid-form > label > select { height: 42px; min-height: 0; }
@media (max-width: 720px) {
  .grid-form > .form-aksi { flex-direction: column; align-items: stretch; }
  .grid-form > .form-aksi > .tombol { width: 100%; min-height: 44px; justify-content: center; }
  .grid-form > .form-aksi > .pudar { flex: 0 0 auto; }
}
.lebar-penuh { grid-column: 1 / -1; }
.tumpuk { border-top: 1px solid var(--garis-2); padding-top: .9rem; margin-top: .9rem; }
.tumpuk:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.bantuan { font-size: .78rem; color: var(--pudar); font-weight: 400; margin: .35rem 0 0; }
/* Jarak antar formulir bertumpuk — KHUSUS formulir yang benar-benar menumpuk
   vertikal (mis. "Tambah Barang" di bawah daftar isian). Dulu selektornya
   `form + form`; di dalam .kartu-baris (grid) ia ikut menghukum formulir yang
   BERDAMPINGAN, sehingga tiap kartu setelah yang pertama terdorong 0.7rem ke
   bawah dan tingginya berkurang 0.7rem (terukur: kartu 1 = 92.8px, kartu 2-3 =
   81.7px, dasar kartu tidak sejajar). Grid sudah mengatur jarak lewat `gap`,
   jadi margin itu murni merusak — sekarang dikecualikan. */
/* `.tombol-baris > *` dikecualikan: di dalam baris tombol, formulir adalah
   TOMBOL — jarak atas 11,2 px membuat tombol kedelapan turun sendiri. */
form + form:not(.kartu-baris > *, .tombol-baris > *) { margin-top: .7rem; }

/* ================================================================== asisten */
/* Ruang percakapan di /asisten. Tiga hal yang DULU salah dan diperbaiki di sini:
   1. balon memakai `.pesan` (kotak peringatan: latar penuh + garis kiri 4px +
      margin 1rem) — percakapan jadi terlihat seperti tanggapan galat;
   2. #ai-balon selalu dirender walau kosong (height 0 tapi tetap memakan
      margin), dan #ai-mulai punya padding 0 sehingga judulnya menempel tepi;
   3. kotak tulis tidak punya bingkai sama sekali: label 13,6px di atas textarea,
      lalu tombol 0,7rem dari kenaikan aturan generik. */
#ai-balon { display: flex; flex-direction: column; gap: .6rem; }
#ai-balon[data-kosong] { display: none; }
/* Ruang percakapan dibatasi & digulir sendiri. AKAR: jawaban asisten bisa
   setinggi 974px (terukur di ponsel), sehingga kotak tulis terdorong 1,5 layar
   ke bawah — tidak terpakai. Batas HANYA berlaku saat ada isi: `max-height`
   tidak memaksa tinggi, jadi percakapan pendek tetap tanpa bilah gulir.
   `min(58vh, 520px)` = kurang dari satu layar, apa pun tinggi jendelanya. */
#ai-balon:not([data-kosong]) { margin-bottom: 1.1rem;
  max-height: min(58vh, 520px); overflow-y: auto; padding-right: .25rem; }
.aibalon { max-width: min(76ch, 92%); padding: .65rem .9rem; border-radius: var(--r);
  border: 1px solid var(--garis-2); background: var(--zebra); }
.aibalon > b { display: block; font-size: .7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--pudar); margin-bottom: .2rem; }
/* Pertanyaan pengguna: menjorok ke kanan, warna hijau muda. */
.aibalon.ingat { align-self: flex-end; background: var(--hijau-l); border-color: var(--hijau-g); }
.aibalon.ingat > b { color: var(--hijau-700); }
.aibalon.rusak { background: var(--merah-l); border-color: var(--merah-g); }
.aibalon.rusak > b { color: var(--merah); }
/* Isi jawaban = keluaran Markdown: paragraf, daftar, tabel, kutipan, judul,
   tautan. Semua disembunyikan dari `white-space: pre-wrap` lama — dengan HTML
   itu menghasilkan rongga raksasa antar elemen. */
.aibalon .aiteks { font-size: .9rem; line-height: 1.65; white-space: normal; }
.aiteks > :first-child { margin-top: 0; }
.aiteks > :last-child { margin-bottom: 0; }
.aiteks p { margin: 0 0 .6rem; }
.aiteks ul, .aiteks ol { margin: 0 0 .6rem; padding-left: 1.3rem; }
.aiteks li { margin-bottom: .2rem; }
.aiteks h1, .aiteks h2, .aiteks h3, .aiteks h4 { margin: 1rem 0 .4rem;
  font-size: .95rem; font-weight: 700; text-transform: none; letter-spacing: -.01em;
  color: var(--tinta); }
.aiteks h3, .aiteks h4 { font-size: .9rem; }
.aiteks strong { font-weight: 700; }
.aiteks table { width: auto; max-width: 100%; margin: 0 0 .7rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); border-collapse: collapse; font-size: .82rem; }
.aiteks th { padding: .35rem .6rem; background: var(--zebra); }
.aiteks td { padding: .35rem .6rem; border-top: 1px solid var(--garis-2); }
.aiteks blockquote { margin: 0 0 .6rem; padding: .2rem 0 .2rem .8rem;
  border-left: 3px solid var(--hijau-300); color: var(--tinta-2); }
.aiteks code { font-size: .8rem; }
.aiteks pre { margin: 0 0 .6rem; padding: .6rem .7rem; background: var(--zebra);
  border: 1px solid var(--garis-2); border-radius: var(--r-kecil); overflow-x: auto; }
.aiteks pre code { background: none; padding: 0; }
.aiteks hr { border: 0; border-top: 1px solid var(--garis-2); margin: .8rem 0; }

#ai-mulai { padding: .2rem 0 .3rem; }
#ai-mulai h2 { margin-bottom: .35rem; }
#ai-mulai .bantuan { margin: 0 0 .8rem; }
/* Kartu saran ("Perintah cepat"). Dulu chevron-nya `float: right`, sehingga teks
   membungkus DI BAWAH panah dan di layar sempit (kartu ~156px) barisnya jadi
   berantakan. Sekarang kartunya flex: teks tumbuh, panah jadi butir tersendiri di
   kanan-atas dan tidak pernah ditabrak teks. */
.kartu-tanya { text-align: left; width: 100%; min-height: 76px; padding: .8rem .95rem;
  display: flex; align-items: flex-start; gap: .5rem;
  transition: border-color .12s, background .12s, box-shadow .12s; }
/* Chevron kecil: menandai kartu ini bisa ditekan, bukan sekadar kotak teks. */
.kartu-tanya::after { content: "\2192"; flex: 0 0 auto; margin-top: .1rem;
  color: var(--hijau-600); font-weight: 700; }
.kartu-tanya:hover { border-color: var(--hijau-500); background: var(--hijau-100);
  box-shadow: var(--bayang-2); }
.kartu-tanya b { font-size: .9rem; font-weight: 600; line-height: 1.45; }
/* Ponsel: kartu saran satu kolom. Dua kolom menyisakan ~156px dan memaksa teks
   membungkus 5-6 baris — tidak lagi terbaca sebagai "perintah cepat". */
@media (max-width: 620px) {
  #ai-contoh { grid-template-columns: 1fr; }
  #ai-contoh .kartu-tanya { min-height: 0; }
}

/* Kotak tulis: satu bingkai; bingkainya ikut menyala saat textarea difokus. */
.ai-tulis { border: 1px solid var(--garis); border-radius: var(--r); background: var(--putih);
  padding: .6rem .7rem .7rem; transition: border-color .12s, box-shadow .12s; }
.ai-tulis:focus-within { border-color: var(--hijau-500);
  box-shadow: 0 0 0 3px rgba(31, 135, 57, .13); }
.ai-tulis textarea { border: 0; padding: .25rem .3rem; min-height: 88px;
  outline: 0 !important; background: transparent; }
.ai-tulis textarea:focus { outline: 0; border: 0; }
.ai-tulis .tombol-baris { justify-content: flex-end; margin-top: .65rem; }
p.bantuan:last-child { margin-bottom: 0; }

/* ---------------------------------------------------- alur bernomor (payroll)
 * Penjelasan langkah dulu satu paragraf .bantuan; aturan .bantuan di bawah
 * membatasi lebar 78ch, jadi di layar lebar teksnya menggantung sempit dan
 * barisnya pecah-pecah — terbaca seperti "kebanyakan enter". Sekarang tiap
 * langkah jadi butir bernomor yang mengisi penuh lebar kolom, sejajar di
 * desktop dan menumpuk di ponsel. */
.bantuan.penuh { max-width: none; }

.alur { display: grid; gap: .45rem; margin: .8rem 0 0; padding: 0; list-style: none;
  counter-reset: alur; }
/* Satu langkah = satu baris selebar kolom. Kolom sempit (grid 3 lajur) membuat
   penjelasan pecah 10 baris pendek — persis keluhan "kebanyakan enter". */
.alur > li { position: relative; padding: .7rem .95rem .7rem 2.7rem;
  border: 1px solid var(--garis); border-radius: var(--r-kecil); background: var(--putih);
  font-size: .82rem; line-height: 1.6; color: var(--pudar); }
.alur > li::before { counter-increment: alur; content: counter(alur);
  position: absolute; left: .8rem; top: .78rem; width: 1.4rem; height: 1.4rem;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--hijau-l, #e8f6ec); color: var(--hijau-700, #15402f);
  font-size: .78rem; font-weight: 700; }
.alur b { font-size: .84rem; color: var(--tinta); }
.alur b::after { content: " — "; color: var(--pudar); font-weight: 400; }
/* Jarak ke blok berikutnya: daftar ini berdiri sendiri, jangan menempel kartu
   status di bawahnya. */
.alur + *, .bantuan.penuh + * { margin-top: 1rem; }

/* =================================================================== pesan */
.pesan { padding: .75rem 1rem; border-radius: var(--r-kecil); margin-bottom: 1rem;
  font-size: .875rem; border: 1px solid transparent; border-left-width: 4px; }
.pesan a { font-weight: 600; }
.pesan.ok { background: var(--hijau-l); color: #14512f; border-color: var(--hijau-g); }
.pesan.rusak { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }
.pesan.ingat { background: var(--kuning-l); color: var(--kuning); border-color: var(--kuning-g); }
.pesan.kunci { background: var(--biru-l); border-color: var(--biru-g); color: #0d3f7a; }
.pesan.kunci b { display: block; font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; }
.pesan.kunci code { display: block; margin: .45rem 0; padding: .6rem .7rem; background: var(--putih);
  border: 1px dashed var(--biru-g); border-radius: var(--r-kecil); font-size: 1.05rem;
  font-weight: 700; user-select: all; word-break: break-all; }
.pesan.kunci small { font-size: .8rem; opacity: .85; }

/* Kepala panel asisten: avatar + identitas + lencana kesiapan. */
.ai-kepala { display: flex; align-items: center; gap: .75rem;
  padding-bottom: .9rem; margin-bottom: 1rem; border-bottom: 1px solid var(--garis-2); }
.ai-avatar { flex: none; width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hijau-100); color: var(--hijau-700); border: 1px solid var(--hijau-g);
  font-size: .78rem; font-weight: 700; letter-spacing: .04em; }
.ai-kepala > div { min-width: 0; flex: 1 1 auto; }
.ai-kepala > div b { display: block; font-size: .95rem; }
.ai-kepala > div small { font-size: .78rem; }
.ai-kepala .lencana { flex: none; }

/* ================================================================ rincian */
.rincian { display: grid; grid-template-columns: minmax(120px, 34%) minmax(0, 1fr);
  gap: .45rem .9rem; margin: 0 0 1rem; font-size: .875rem; }
/* Baris tombol yang menempel di atas daftar rincian (mis. "Ubah Data"/"Hapus")
   butuh jarak, kalau tidak label pertama terbaca sebagai bagian tombolnya. */
.tombol-baris + .rincian { margin-top: .9rem; }
.rincian dt { color: var(--pudar); font-weight: 600; }
.rincian dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.kotak { background: var(--zebra); border: 1px solid var(--garis-2); border-radius: var(--r-kecil);
  padding: .8rem .9rem; font-size: .875rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.kotak.catatan { background: var(--kuning-l); border-color: var(--kuning-g); margin-top: .8rem; }
.kotak.catatan b { display: block; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--kuning); margin-bottom: .3rem; }

/* ======================================================= berkas & linimasa */
.berkas { display: flex; justify-content: space-between; gap: 1rem; align-items: center;
  border-bottom: 1px solid var(--garis-2); padding: .75rem 0; }
.berkas:last-child { border-bottom: 0; padding-bottom: 0; }
.berkas:first-child { padding-top: 0; }
.berkas a { font-weight: 600; text-decoration: none; overflow-wrap: anywhere; }
.berkas a:hover { text-decoration: underline; }
.obrolan { list-style: none; margin: 0 0 1rem; padding: 0; display: flex; flex-direction: column;
  gap: .6rem; max-height: 420px; overflow-y: auto; }
.obrolan li { background: var(--zebra); border: 1px solid var(--garis-2);
  border-radius: var(--r-kecil); padding: .6rem .8rem; max-width: 92%; }
.obrolan li.dia { background: var(--hijau-l); border-color: var(--hijau-g);
  align-self: flex-end; }
.obrolan b { font-size: .82rem; }
.obrolan small { display: inline; margin-left: .45rem; font-size: .72rem; }
.obrolan p { margin: .25rem 0 0; font-size: .875rem; white-space: pre-wrap;
  overflow-wrap: anywhere; }
.kosong-obrolan { background: none; border: 0; padding: 0; max-width: none; }
.linimasa { list-style: none; margin: 0; padding: 0; }
.linimasa li { position: relative; border-left: 2px solid var(--garis); padding: 0 0 .9rem 1rem;
  margin-left: .35rem; }
.linimasa li::before { content: ""; position: absolute; left: -6px; top: .35rem; width: 10px;
  height: 10px; border-radius: 50%; background: var(--putih); border: 2px solid var(--hijau-300); }
.linimasa li:last-child { padding-bottom: 0; }
.linimasa b { font-size: .86rem; }
.linimasa small { margin-top: .1rem; }
.linimasa p { margin: .3rem 0 0; font-size: .84rem; color: var(--tinta-2); }

/* Cegah meluap: kolom grid tidak boleh melebihi lebar induk (min-width:0). */
.pub-dua, .pub-binaan, .pub-kaki-grid, .pub-media, .pub-kartu-grid,
.pub-langkah, .pub-halaman, .panel-masuk { min-width: 0; }
.pub-dua > *, .pub-binaan > *, .pub-kepala-bagian, .pub-kartu, .pub-artikel,
.pub-orang, .pub-langkah > li { min-width: 0; }
.pub-media h3, .pub-artikel h3, .pub-kaki-grid p, .pub-kaki-grid li { overflow-wrap: anywhere; }

/* ========================================================= halaman masuk */
.latar-publik { background: radial-gradient(120% 100% at 12% 8%, #33a253, #175f38 55%, #12472c);
  min-height: 100vh; }
/* `place-items: center` membuat item grid menyusut ke lebar MIN-CONTENT-nya.
   Di desktop tidak terasa (panel 1040px), tetapi di ponsel panel 480px menyusut
   ke 323px sementara anak-anaknya tetap 351px — meluber & terpotong
   `overflow:hidden` sehingga padding kanan hilang (terukur 5 Nov 2026).
   `justify-items: stretch` + kolom `minmax(0,1fr)` membuat panel mengisi lebar
   yang tersedia; pemusatan cukup secara vertikal. */
/* PEMUSATAN: `place-items: center` menyusutkan item ke min-content (panel
   ponsel jadi 323px), sedangkan `justify-items: stretch` menempelkan panel ke
   KIRI (terukur x=38 pada viewport 1440). Yang benar: satu track grid berukuran
   maksimum panel, lalu `place-content: center` memusatkan TRACK-nya —
   horizontal & vertikal sekaligus, tanpa menyusutkan isi. */
.masuk { min-height: 100vh; display: grid; place-content: center;
  grid-template-columns: minmax(0, 1040px);
  padding: clamp(1rem, .6rem + 2vw, 2.6rem); }
/* Panel masuk: di layar lebar dulu hanya 940 px sehingga terlihat "dipaksa ke
   tengah" dengan sisi kiri-kanan kosong menganga (keluhan Bos 5 Nov 2026).
   1040 px + kolom 1.05fr/1fr membuat dua sisi seimbang dan formulir lega. */
.panel-masuk { width: 100%; max-width: 1040px; display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); background: var(--putih); border-radius: 18px;
  overflow: hidden; box-shadow: 0 30px 60px -20px rgba(0, 0, 0, .5); }
.panel-kiri { background: linear-gradient(165deg, var(--hijau-800), #14532d 75%); color: #d8e5de;
  padding: 2.4rem 2.2rem; display: flex; flex-direction: column; gap: 1.2rem; }
.panel-kiri h1 { color: #fff; font-size: 1.7rem; margin: 0; }
.panel-kiri p { color: #a7c2b5; font-size: .92rem; margin: 0; }
.panel-kiri .ciri { list-style: none; margin: auto 0 0; padding: 0; display: grid; gap: .6rem; }
.panel-kiri .ciri li { display: flex; gap: .6rem; align-items: flex-start;
  font-size: .85rem; color: #c7d8d0; }
.panel-kiri .ciri li::before { content: "✓"; color: var(--hijau-300); font-weight: 700; }
.panel-kanan { padding: 2.4rem 2.2rem; display: flex; flex-direction: column;
  justify-content: center; }
.panel-kanan h2 { font-size: 1.15rem; text-transform: none; letter-spacing: -.01em;
  color: var(--tinta); margin-bottom: .3rem; }
/* Aktivasi akun pendamping: satu panel saja, tanpa panel promosi kiri. */
.panel-masuk.panel-aktivasi { grid-template-columns: 1fr; max-width: 520px; }
/* Jalur SIMKOPDES: kotak terpisah supaya tidak tertukar dengan form utama, dan
   tetap TERBUKA di ponsel — informasinya tidak boleh disembunyikan. */
.jalur-simkopdes { margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--garis); }
.jalur-simkopdes h3 { font-size: .95rem; margin: 0 0 .35rem; color: var(--tinta); }
.jalur-simkopdes ol { margin: .5rem 0 .7rem; padding-left: 1.1rem; }
.jalur-simkopdes li { margin-bottom: .3rem; }
.jalur-simkopdes .tautan-markah { font-weight: 600; }
.jalur-simkopdes form { margin-top: .6rem; }
.merek.besar { flex-direction: column; align-items: center; text-align: center; gap: .5rem;
  margin-bottom: 1.5rem; }

/* ========================================================= kartu koperasi */
.publik { min-height: 100vh; display: grid; place-items: center; padding: var(--sp); }
.kartu-publik { background: var(--putih); border-radius: 16px; max-width: 520px; width: 100%;
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, .5); overflow: hidden; }
.kartu-publik .kepala-kartu { background: linear-gradient(160deg, var(--hijau-800), #14532d);
  color: #d8e5de; padding: 1.4rem 1.6rem; }
.kartu-publik .badan { padding: 1.6rem; }
.kartu-publik h1 { font-size: 1.35rem; margin: .2rem 0 .1rem; }
.kode-koperasi { font-family: ui-monospace, monospace; color: var(--hijau-600); font-weight: 700;
  margin: 0 0 1.1rem; letter-spacing: .05em; }
.sidik { background: var(--zebra); border: 1px dashed var(--garis); border-radius: var(--r-kecil);
  padding: .6rem .75rem; font-size: .82rem; margin: .8rem 0 0; overflow-wrap: anywhere; }

/* ======================================================== layar sempit ≤900 */
@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  /* AKAR: di mobile kepala harus SATU baris. Sebelumnya .sisi tetap column,
     jadi merek dan identitas jatuh ke dua baris & tinggi kepala jadi ~104px. */
  /* align-self:start WAJIB: tanpa ini .shell (grid, min-height:100vh) meregangkan
     bar ini mengisi sisa layar -> tingginya = viewport - tinggi isi halaman
     (terukur 146px @845px, 346px @1200px; di layar pendek kebetulan 59px).
     Gejala: bar atas "sangat tinggi" hanya di HP berlayar tinggi / isi pendek. */
  .sisi { position: sticky; top: 0; height: auto; align-self: start; flex-direction: row;
    align-items: center; gap: .8rem; padding: .55rem var(--sp);
    border-bottom: 1px solid rgba(255, 255, 255, .1); }
  .sisi .merek small { display: none; }
  /* nav pindah ke bilah bawah; kepala hanya merek + identitas */
  .nav-sisi { display: none; }
  .sisi .merek { gap: .55rem; min-width: 0; }
  .sisi .merek svg { width: 26px; height: 26px; flex: 0 0 auto; }
  .sisi .merek b { font-size: .95rem; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; }
  .kaki { margin-top: 0; margin-left: auto; flex-direction: row; flex-wrap: nowrap;
    align-items: center; gap: .5rem; min-width: 0; }
  .kotak-pengguna { background: none; padding: 0; text-align: right; min-width: 0;
    max-width: 34vw; }
  .kotak-pengguna b { font-size: .8rem; }
  .kotak-pengguna small, .kotak-pengguna .tanda { display: none; }
  /* tombol keluar jadi ikon saja supaya tidak mencuri ruang kepala */
  .kaki .tombol { flex: 0 0 auto; width: auto; min-height: 40px; padding: .3rem .65rem; }
  .kaki .tombol .label-keluar { display: none; }
  .kaki .tombol .ik.kecil { width: 18px; height: 18px; }
  /* AKAR: aturan `nav` di atas menetapkan flex-direction: column — bilah bawah
     harus eksplisit row, kalau tidak ketiga item menumpuk vertikal. */
  .nav-bawah { display: flex; flex-direction: row; flex-wrap: nowrap;
    position: fixed; inset: auto 0 0 0; z-index: 40;
    background: var(--putih); border-top: 1px solid var(--garis);
    box-shadow: 0 -2px 12px rgba(16, 29, 24, .07);
    padding: .35rem .3rem calc(.35rem + env(safe-area-inset-bottom));
    justify-content: center; gap: .15rem; align-items: stretch;
    /* Menu admin kini 8 item — di layar sempit bilah ini bergulir mendatar
       daripada memaksa setiap item jadi terlalu kecil untuk disentuh. */
    overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; }
  .nav-bawah::-webkit-scrollbar { display: none; }
  .nav-bawah a { flex: 1 1 auto; min-width: 76px; max-width: 118px;
    /* position:relative WAJIB: `.lencana-notif` memakai position:absolute dan
       tanpa ini ia mencari leluhur terdekat yang berposisi — yaitu bilahnya
       sendiri (position:fixed) — sehingga SEMUA lencana menumpuk di tepi kanan
       bilah, bukan menempel di ikonnya masing-masing. */
    position: relative;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: .15rem; padding: .35rem .2rem;
    border-radius: var(--r-kecil); color: var(--tinta-2); text-decoration: none;
    font-size: .68rem; font-weight: 600; letter-spacing: .01em; }
  .nav-bawah a span { max-width: 100%; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
  /* Lencana "belum dibaca" di bilah bawah: ditempelkan ke IKON, bukan ke pojok
     butir. `.lencana-notif` bawaannya `right:-3px` (menempel di pojok kanan
     elemen ber-posisi = butir menu) — untuk butir selebar 83px ikonnya di tengah,
     jadi lencana tampak mengambang di tepi butir dan 2px-nya melewati batas butir
     sampai menimpa butir sebelah. Di sini acuannya diganti ke tengah butir
     (ikon 21px terpusat → tepi kanannya di 50% + 10.5px), dengan rumus yang sama
     seperti menempelkan lencana ke ikon lonceng. */
  .nav-bawah .lencana-notif { top: .15rem; left: calc(50% + 4px); right: auto; }
  .ik-bawah { width: 21px; height: 21px; fill: currentColor; }
  .nav-bawah a:hover { background: var(--hijau-100); }
  .nav-bawah a.ini { color: var(--hijau-700); background: var(--hijau-l); }
  /* Tinggi bilah bawah, satu angka untuk seluruh halaman. Dulu dipaku 5.2rem
     di `.isi`; sekarang diturunkan dari tinggi bilahnya sendiri supaya tidak
     bisa berselisih saat bilah berubah. Di desktop tak terpakai (bilahnya
     display:none). */
  :root { --tb: calc(2.75rem + env(safe-area-inset-bottom));
    /* Tinggi NYATA bilah menu bawah (terukur 66px pada 360x780). Dipakai
       dialog untuk tahu berapa ruang yang harus disisakan di bawah, supaya
       pusatnya berada di ruang di ATAS bilah — bukan di tengah seluruh layar,
       yang membuat dialog tinggi menutupi menu. Angka tunggal: kalau bilahnya
       berubah tinggi, ubah di sini saja. */
    --tb-nav: calc(4.125rem + env(safe-area-inset-bottom)); }
  .dua-kolom { grid-template-columns: 1fr; }
  .isi { padding-bottom: calc(var(--tb) + .6rem); }
  /* `.masuk` = grid; tanpa ini kolomnya selebar isi (min-content) sehingga
     panel 480px menyusut 28px lebih sempit dari anaknya dan padding kanan
     terpotong `overflow:hidden`. Terukur 5 Nov 2026: panel 323px, anak 351px. */
  .masuk { grid-template-columns: minmax(0, 480px); }
  .panel-masuk { grid-template-columns: 1fr; width: 100%; }
  .panel-kiri { padding: 1.6rem 1.6rem 1.4rem; gap: .8rem; }
  .panel-kiri .ciri { display: none; }
  .panel-kiri h1 { font-size: 1.4rem; }
  .panel-kanan { padding: 1.6rem; }
  .linimasa { max-height: 320px; overflow-y: auto; padding-right: .3rem; }
}

/* ======================================== mobile: tabel jadi daftar ≤720px */
@media (max-width: 720px) {
  .tabel-bungkus { overflow-x: visible; margin: 0; padding: 0; }
  .tabel-bungkus table, .tabel-bungkus tbody, .tabel-bungkus tr, .tabel-bungkus td { display: block; }
  .tabel-bungkus thead { display: none; }
  .tabel-bungkus tr { border: 1px solid var(--garis); border-radius: var(--r-kecil);
    background: var(--putih) !important; padding: .7rem .85rem; margin-bottom: .6rem;
    box-shadow: var(--bayang); }
  .tabel-bungkus tr:last-child { margin-bottom: 0; }
  .tabel-bungkus td { border: 0; padding: .3rem 0; display: grid;
    grid-template-columns: minmax(84px, 34%) minmax(0, 1fr); gap: .2rem .8rem;
    align-items: baseline; }
  .tabel-bungkus td::before { content: attr(data-l); font-size: .7rem; text-transform: uppercase;
    letter-spacing: .07em; color: var(--pudar); font-weight: 700; padding-top: .18rem; }
  /* AKAR "nilai menempel di kolom label" (terukur di /kerja /rapat /distribusi
     @320/360/390: seluruh sel bernilai >1 anak menaruh anak ke-2 di kolom 1).
     ::before memakai kolom 1 BARIS 1, jadi AUTO-PLACEMENT anak pertama sudah
     memakai kolom 2 baris 1 dan anak KEDUA tidak punya sisa sel di baris itu ->
     ia dibuang ke kolom 1 baris 2, yaitu tepat DI BAWAH LABEL, bukan di bawah
     nilai. Terlihat di /kerja: "Jumlah 5 SAK" + "diterima 0" (keterangan jatuh
     di bawah kata JUMLAH) dan "Tugas" + deskripsi di bawah kata TUGAS.
     Pisahkan lajur secara EKSPLISIT: label tetap kolom 1, dan SEMUA anak isi
     dikunci ke kolom 2 -> tiap anak dapat barisnya sendiri, rata dengan
     nilainya. Anak yang memang perlu selebar baris (panel/form terbuka,
     mis. `.lebar-penuh`) dikecualikan dan tetap 1 / -1. */
  .tabel-bungkus td > *:not(.lebar-penuh):not([class*="lebar-penuh"]) { grid-column: 2; }
  .tabel-bungkus td:not([data-l]) { display: block; padding-top: .5rem; }
  .tabel-bungkus td[data-l=""]:not(:has(*)) { display: none; }
  /* <th> sebagai label baris (tabel "pasangan label → nilai" seperti NPWP/NIK
     di /agri/hris/bpjs, yang <th>-nya ada di tbody, bukan thead). Tanpa aturan
     ini `th` tetap table-cell sementara `tr`/`td` sudah block, sehingga ia
     membentuk kotak anonim selebar isi judulnya dan tabelnya keluar layar —
     terukur: dokumen 438px di viewport 390px. Ketebalan: deskripsi di bawah
     label disembunyikan (labelnya sudah menyebut isinya); teks penuh tetap ada
     di berkas view. */
  .tabel-bungkus th { display: block; width: auto; padding: 0 0 .2rem;
    border: 0; font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; }
  .tabel-bungkus th .pudar { display: none; }

  /* sel aksi tanpa label jadi blok penuh; yang ber-label tetap grid supaya
     label dan nilainya tidak menempel (mis. "TUGAS" + "5" -> "TUGAS5") */
  .tabel-bungkus td.kolom-aksi { text-align: left; padding-top: .7rem; width: auto; }
  /* Kolom pilih kena masalah yang sama dengan kolom aksi: `width: 1%` (trik
     "selebar isinya") di ponsel membuat sel jadi ~3px sehingga kotak centang
     tercekik tak bisa ditekan. Reset ke `auto` + ukuran sentuh yang layak. */
  .tabel-bungkus td.kolom-pilih { width: auto; text-align: left; padding-top: .7rem; }
  .tabel-bungkus td.kolom-pilih input[type="checkbox"] { width: 20px; height: 20px; }
  /* Di ponsel sel berubah jadi grid label+nilai. `text-align: right` untuk kolom
     angka adalah aturan desktop (menyejajarkan digit); di sini ia justru
     menempelkan angka ke tepi kanan sementara labelnya di kiri, jadi angka
     Rp terlihat menjauh dari labelnya. Kembalikan ke kiri — kerapian digit
     tetap dijaga `tabular-nums`. */
  .tabel-bungkus td.angka-kanan { text-align: left; }
  /* Tombol aksi disusun sebaris; margin bawaan .sebaris dinolkan karena di sini
     lebarnya sudah dibagi flex, sisa margin bikin sel meluber dari kartu. */
  /* Di PONSEL `display:flex` pada sel aksi aman dan memang dibutuhkan: tabelnya
     sudah `display:block` (lihat awal media query ini), jadi tidak ada algoritma
     tata letak tabel yang bisa dirusak, dan tombol-tombolnya tetap sebaris.
     🔴 Yang merusak di sini adalah `width:1%` — pada wadah flex di dalam elemen
     blok, 1% × 324px = ~3px sehingga sel kolaps. Karena itu aturan `width:1%`
     untuk kolom aksi dibatasi ke desktop (lihat #buku di bagian bawah). */
  .tabel-bungkus td.kolom-aksi:not([data-l]) { display: flex; flex-wrap: wrap; gap: .5rem;
    padding-top: .7rem; }
  /* Panel ubah saat terbuka harus mengambil satu baris penuh. Tanpa ini .ubah
     tetap selebar tombolnya (terukur 58px), dan formulir di dalamnya ikut
     tercekik jadi 56px sehingga semua isian tak terbaca. */
  .tabel-bungkus .ubah[open] { flex: 1 1 100%; width: 100%; }
  .tabel-bungkus .kolom-aksi .sebaris { margin: 0; display: flex; flex: 1 1 auto; }
  .tabel-bungkus .kolom-aksi .tombol { width: auto; flex: 1 1 auto; }
  /* Formulir di dalam sel aksi ikut membagi lebar, bukan jatuh ke baris kedua:
     "Ubah" dan "Hapus" harus sebaris seperti di desktop. */
  .tabel-bungkus .kolom-aksi > form { flex: 1 1 0; display: flex; margin: 0; }
  .tabel-bungkus .kolom-aksi > form .tombol { width: 100%; }
  /* Kedua tombol aksi berbagi lebar SAMA, bukan menurut panjang teksnya. */
  .tabel-bungkus td.kolom-aksi:not([data-l]) > .tombol { flex: 1 1 0; }
  .tabel-bungkus .kolom-aksi .sebaris .tombol { width: 100%; }
  /* AKAR kepala ponsel tidak seragam (dulu /distribusi 155 vs dasbor 133):
     1) `flex-direction:column` menaruh baris tombol DI BAWAH judul -> semua
        halaman ber-tombol (+52px) selalu lebih tinggi dari yang tanpa tombol;
     2) deskripsi panjang membungkus 1-3 baris, jadi tingginya ikut teks.
     Solusi: kepala tetap SATU BARIS (judul kiri, tombol kanan) dan deskripsi
     dipotong ellipsis 1 baris -> tinggi kepala seragam di semua halaman
     (81px), tidak lagi bergantung panjang teks atau ada/tidaknya tombol.
     Teks deskripsi utuh tetap di DOM (pembaca layar & salin-tempel utuh). */
  /* AKAR "tombol kepala terpotong": dulu baris tombol dipaksa nowrap +
     overflow-x:auto supaya tinggi kepala seragam. Hasilnya tombol yang tak muat
     BUKAN turun baris, melainkan tergeser ke luar layar dan tak bisa ditekan
     (mis. "Ajukan Barang" di /kerja manajer 360px). Sekarang baris boleh
     membungkus: tombolnya selalu utuh & terjangkau. Tinggi kepala memang tidak
     lagi identik antar halaman, jadi gate menguji hal yang benar-benar penting —
     setiap tombol ada utuh di dalam layar (lihat _ukur_isi.py). */
  .kepala { flex-direction: row; align-items: flex-start; flex-wrap: wrap; gap: .45rem .6rem; }
  /* Judul didahulukan: TIDAK ikut menyusut saat baris tombol panjang, dan
     dipotong 1 baris (dulu ia terhimpit jadi 3 baris -> kepala 113px di
     /kerja & /distribusi manajer yang punya 2 tombol). */
  .kepala > div:first-child { flex: 1 1 auto; min-width: 0; }
  .kepala h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Deskripsi TIDAK dipotong di ponsel: butuh 1-3 baris (mis. /distribusi "0 surat
     jalan — alur: ..." = 508px teks di 358px layar, /admin/vendor 3 baris). Dulu
     dipaksa nowrap+ellipsis 1 baris demi tinggi seragam -> teksnya terpotong.
     Tinggi kepala kini mengikuti jumlah baris (tetap terbatas, lihat gate). */
  .kepala .tenang { white-space: normal; overflow: visible; text-overflow: clip; }
  /* Tombol tidak turun baris: yang menyusut adalah barisnya, bila tak muat
     barisnya bergulir mendatar (tinggi kepala tetap, tombol tetap terjangkau). */
  .kepala .tombol-baris { width: auto; flex: 1 1 auto; min-width: 0; flex-wrap: wrap;
    justify-content: flex-end; overflow: visible; }
  .kepala .tombol { width: auto; flex: 0 1 auto; white-space: nowrap;
    padding: .42rem .6rem; font-size: .86rem; }
  /* Tombol aksi kepala milik Agrinas disembunyikan di ponsel: baris tombol +
     judul tidak muat semeja, tombolnya terpotong tepi layar. Aksinya tetap
     terjangkau lewat bilah bawah & halaman Semua Fitur. */
  .kepala .hanya-desktop { display: none; }
  /* Kebalikannya: aksi kepala yang memang datang dari bilah bawah (mis. Ajukan
     Barang, sudah ada di Dasbor) disembunyikan di ponsel supaya baris tombol
     tidak menumpuk dua baris dan kepala tetap ringkas. */
  .kepala .hanya-ponsel { display: none; }
  .kartu.angka b { font-size: 1.7rem; }
  .blok { padding: 1rem; }
  .kaki .kotak-pengguna .tanda { display: none; }
}

/* Ponsel sempit: tombol kepala diperkecil supaya baris tombol (bisa 2 buah)
   muat semeja dengan judul -> kepala tetap 81px dan tombol tak terpotong. */
@media (max-width: 480px) {
  .kepala { gap: .45rem; }
  .kepala .tombol { padding: .34rem .42rem; font-size: .78rem; }
}

/* ======================================================= halaman beranda */
.beranda { max-width: 1000px; margin: 0 auto; padding: clamp(1.1rem, .6rem + 1.6vw, 2.2rem);
  display: flex; flex-direction: column; gap: clamp(1.4rem, 1rem + 1.6vw, 2.6rem); }
.beranda-kepala { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.beranda-kepala .merek { color: #fff; }
.beranda-kepala .merek .nama { text-align: left; }
.beranda-kepala .merek small { color: #a7c2b5; }
.beranda-hero { display: flex; flex-direction: column; gap: .9rem; padding-top: .4rem; }
.beranda-hero h1 { font-size: clamp(1.5rem, 1.1rem + 2.2vw, 2.5rem); color: #fff;
  max-width: 22ch; margin: 0; line-height: 1.15; }
.beranda-hero p { color: #bcd2c7; font-size: clamp(.9rem, .86rem + .3vw, 1.02rem);
  max-width: 62ch; margin: 0; }
.beranda-hero .tombol-baris { margin-top: .5rem; }
.beranda-hero .tombol.samar { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .28);
  color: #e6f6ee; }
.beranda-hero .tombol.samar:hover { background: rgba(255, 255, 255, .18); color: #fff; }
.beranda-ciri { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: 1rem; }
.beranda-ciri article { background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  padding: 1.15rem 1.25rem; box-shadow: var(--bayang); border-top: 3px solid var(--hijau-300); }
.beranda-ciri h2 { text-transform: none; letter-spacing: -.01em; font-size: .98rem;
  color: var(--tinta); margin: 0 0 .45rem; }
.beranda-ciri p { font-size: .875rem; color: var(--tinta-2); margin: 0; }
.beranda-judul { color: #fff; font-size: 1.05rem; text-transform: none; letter-spacing: -.01em;
  margin: 0 0 1rem; }
.beranda-alur ol { list-style: none; counter-reset: langkah; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 1rem; }
.beranda-alur li { counter-increment: langkah; background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .13); border-radius: var(--r); padding: 1.05rem 1.15rem;
  color: #c7d8d0; font-size: .85rem; }
.beranda-alur li::before { content: counter(langkah); display: flex; align-items: center;
  justify-content: center; width: 26px; height: 26px; border-radius: 50%; margin-bottom: .6rem;
  background: var(--hijau-300); color: var(--hijau-900); font-weight: 700; font-size: .8rem; }
.beranda-alur li b { display: block; color: #fff; font-size: .92rem; margin-bottom: .3rem; }
.beranda-kaki { display: flex; flex-wrap: wrap; gap: .3rem 1.4rem; justify-content: space-between;
  border-top: 1px solid rgba(255, 255, 255, .12); padding-top: 1.1rem;
  color: #8fa89c; font-size: .78rem; }
@media (max-width: 560px) {
  .beranda-kepala { gap: .7rem; }
  .beranda-kepala .merek small { display: none; }
  .beranda-kepala .tombol { min-height: 38px; padding: .4rem .8rem; }
  .beranda-hero h1 { max-width: none; }
  .beranda-hero .tombol { width: 100%; }
  .beranda-alur, .beranda-ciri { gap: .75rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* =========================================== paging dasbor (Prev 1 2 3 … N Next) */
.paging { display: flex; align-items: center; gap: .5rem; flex-wrap: nowrap;
  margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--garis-2);
  justify-content: center; }
.paging-angka { list-style: none; display: flex; align-items: center; gap: .25rem;
  margin: 0; padding: 0; min-width: 0; }
.paging-angka a, .paging-angka span { display: grid; place-items: center;
  min-width: 36px; height: 36px; padding: 0 .55rem; border-radius: var(--r-kecil);
  font-size: .85rem; font-weight: 600; text-decoration: none; color: var(--tinta-2);
  font-variant-numeric: tabular-nums; }
.paging-angka a { border: 1px solid var(--garis); background: var(--putih); }
.paging-angka a:hover { border-color: var(--hijau-500); color: var(--hijau-700); background: var(--hijau-100); }
.paging-angka span[aria-current] { background: var(--hijau-600); color: #fff;
  border: 1px solid var(--hijau-600); }
.paging-angka .celah { min-width: 22px; padding: 0; color: var(--pudar); letter-spacing: .05em; }
.paging .tombol { min-height: 36px; padding: .34rem .8rem; }
/* Tombol tepi tetap dirender walau tidak berlaku supaya deret nomor tidak
   bergeser saat berpindah halaman. */
.paging .tanpa-isi { visibility: hidden; }
.paging .kata { display: inline; }
/* Mobile: kalimat diganti panah saja; 5 nomor + 2 tombol muat di 360px. */
@media (max-width: 620px) {
  .paging { gap: .3rem; }
  .paging .kata { display: none; }
  .paging .tombol { padding: .3rem .55rem; }
  .paging-angka a, .paging-angka span { min-width: 30px; height: 32px; padding: 0 .4rem;
    font-size: .8rem; }
  .paging-angka { gap: .18rem; }
}

/* ============================================== halaman "Semua Fitur" (/fitur)
   Kisi ikon: 3 kolom di ponsel, melebar otomatis di layar besar. */
/* auto-FIT, bukan auto-fill: auto-fill menyisakan track kosong selebar 80px,
   jadi enam kartu Ruang Kerja tampak sempit dan menyisakan ruang mati di
   kanan (terukur: kartu 80px di wadah 902px). auto-fit meruntuhkan track yang
   tak terpakai sehingga kartu mengisi lebar penuh; di ponsel hasilnya tetap
   4 kolom (~80px) seperti sebelumnya. */
.kisi-fitur { display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
  gap: .7rem; margin-top: .4rem; }
.kartu-fitur { display: flex; flex-direction: column; align-items: center; gap: .5rem;
  padding: 1rem .5rem; text-align: center; text-decoration: none; color: var(--tinta-2);
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  font-size: .8rem; font-weight: 600; min-height: 104px; justify-content: center;
  font-family: inherit; cursor: pointer;
  transition: border-color .12s, background .12s, color .12s; }
.kartu-fitur:hover { border-color: var(--hijau-500); background: var(--hijau-100); color: var(--hijau-700); }
.kartu-fitur.ini { border-color: var(--hijau-600); background: var(--hijau-l); color: var(--hijau-700); }
.kartu-fitur-ikon { display: grid; place-items: center; width: 44px; height: 44px;
  border-radius: 50%; background: var(--zebra); }
.kartu-fitur.ini .kartu-fitur-ikon { background: var(--hijau-100); }
.ik-fitur { width: 24px; height: 24px; fill: currentColor; }
.kartu-fitur-label { overflow-wrap: anywhere; }

/* Butir terkunci: fitur AgriConnect sebelum akunnya dihubungkan (lihat
   agri/_nav.blade.php). Label & ikon tetap terbaca — yang hilang hanya
   kemampuan membuka halaman, dan kliknya menjawab lewat notifikasi. */
.kartu-fitur.terkunci { background: var(--zebra); border-style: dashed; color: var(--pudar); }
.kartu-fitur.terkunci .kartu-fitur-ikon { background: transparent; }
.kartu-fitur.terkunci:hover { border-color: var(--garis); background: var(--zebra); color: var(--pudar); }

/* ========== RUANG KERJA — kisi kartu modul ==========
   Revisi Bos: di DESKTOP 4 kolom TETAP → 2 baris rapi. `auto-fit` bawaan TIDAK
   bisa dibiarkan: di wadah lebar ia mengisi sebanyak track yang muat sehingga
   semua kartu berbaris jadi SATU baris tipis.
   Penandanya kelas `kisi-rk` (dipasang di workspace.blade.php), BUKAN jumlah
   kartu: dulu `:has(> .kartu-fitur:nth-child(8)):not(…nth-child(9))` yang
   berarti "kisi berisi TEPAT 8 kartu", dan aturannya langsung mati begitu
   Messenger disembunyikan + Koperasi pindah ke Pintasan (kartu jadi 7).
   Kelas stabil: kisi lain yang memakai `.kisi-fitur` — Pintasan (3),
   Semua Fitur (22) — tidak ikut berubah.                                     */
/* ponytail: breakpoint 900px selaras dengan blok media lain di berkas ini */
@media (min-width: 900px) {
  .kisi-rk { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Menu modul AgriConnect — kisi berkelompok (lihat agri/_nav.blade.php).
   Empat kartu sebaris TETAP: 4 kolom @358px = kartu 81px, dan 81px masih
   memuat label 3 baris tanpa meluber (inilah sebabnya `auto-fit` tidak dipakai
   — di ponsel ia menghasilkan kolom 86px sehingga "Perjalanan Dinas" pecah
   tiga baris). */
/* label terbaca) alih-alih menyembunyikan tautan. `display: block` pada kisi
   ini WAJIB: `:where(nav)` (baris 76) membuat SETIAP <nav> flex demi menu
   sisi, jadi `nav.kisi-modul` di dalam <main> pun flex — tiap .kisi-baris
   jadi flex-item yang menyusut sampai grid 4 kolomnya tinggal 24px dan label
   terpecah satu huruf per baris (terukur 390px: kartu 12x300px, dokumen
   melebar 620px). */
.kisi-modul { display: block; margin-bottom: var(--ruang); }
.kisi-baris { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .6rem; }
/* Kartu shortcut ini harus RINGKAS: `.kartu-fitur` aslinya untuk 6 tujuan
   (padding 1rem + min-height 104px). Dengan label 1-2 kata, padding itu
   menyisakan rongga kosong dan empat barisnya jadi 556px di layar 360px —
   separuh layar pertama habis sebelum isi halaman terlihat. */
/* Kartu di sini MEMBENTANG (ikon kiri, label kanan), bukan tumpuk tengah:
   `.kartu-fitur` aslinya 6 kartu pendek @80px, dan pada kartu selebar 272px
   (desktop) susunan tumpuk meninggalkan rongga kanan setengah kartu. */
.kisi-modul .kartu-fitur { padding: .6rem .7rem; gap: .6rem; min-height: 0;
  font-size: .78rem; flex-direction: row; align-items: center; text-align: left;
  justify-content: flex-start; height: 100%; }
.kisi-modul .kartu-fitur-ikon { width: 34px; height: 34px; flex: 0 0 auto; }
.kisi-modul .ik-fitur { width: 19px; height: 19px; }

/* Kelompok menu — judul kecil, bukan pelipat. Tiap kelompok SELALU terbuka
   (lihat agri/_nav.blade.php soal kenapa bukan <details>). `.kartu-fitur-label`
   dipaksa 2 baris rata: dengan 3 kata seperti "Akun AgriConnect" ia melipat
   tiga baris dan membuat SATU kartu lebih tinggi dari sebarisnya (terukur:
   baris 80-99px), jadi tinggi kartu dipatok seragam dan label dipotong elipsis
   — teks penuh tetap ada di title/teks tombolnya. */
.kisi-seksi { margin-top: .9rem; }
.kisi-seksi-judul {
  display: flex; align-items: center; gap: .45rem; margin: 0;
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--tinta-3);
}
.kisi-seksi-judul { flex: 1 1 auto; }
.kisi-seksi-jumlah {
  flex: 0 0 auto; font-size: .68rem; font-weight: 600; text-transform: none;
  letter-spacing: 0; color: var(--tinta-3); background: var(--zebra);
  border-radius: 999px; padding: .1rem .5rem;
}
.kisi-seksi .kisi-baris { margin-top: .5rem; align-items: stretch; }
.kisi-modul .kartu-fitur-label { display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; }

@media (max-width: 720px) {
  /* Ponsel: 2 kolom, bukan 4 — 84px terlalu sempit untuk label HR seperti
     "Perjalanan Dinas" (terukur: 2 kolom = 171px, label utuh 1 baris). */
  .kisi-modul .kisi-baris { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
  .kisi-modul .kartu-fitur { font-size: .82rem; padding: .55rem .6rem; gap: .5rem; }
  .kisi-modul .kartu-fitur-ikon { width: 30px; height: 30px; }
}

/* ======================================================================
   PRESENSI — foto & titik lokasi (gaya SIMKOPDES)
   ====================================================================== */
/* Foto bukti di riwayat: kotak POTRET 3:4. Perbandingan ini dipegang di sini
   (object-fit: cover) supaya baris dari mana pun — foto SIMKOPDES yang lanskap
   maupun potret hasil kamera Hub — tampil seragam tinggi tanpa perlu memotong
   berkasnya di server. */
.presensi-bukti { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .5rem; }
.foto-presensi { display: block; width: 60px; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--r-kecil); border: 1px solid var(--garis); background: var(--zebra); }
a:hover > .foto-presensi { border-color: var(--hijau-500); }
.peta-tautan { font-size: .8rem; font-weight: 600; text-decoration: none;
  color: var(--hijau-700, #15402f); white-space: nowrap; }
.peta-tautan:hover { text-decoration: underline; }
/* Isian berkas bawaan peramban tampak seperti teks polos tanpa batas, jadi
   tingginya tidak sejajar dengan isian teks di sebelahnya. `.form-cepat` sudah
   mengunci tinggi isian teks 42px — yang ini disamakan. */
.form-cepat input[type="file"] { width: 100%; margin: .35rem 0 0; padding: .4rem .5rem;
  height: 42px; font-size: .8rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); background: var(--putih); }
.form-cepat button[disabled] { opacity: .5; cursor: not-allowed; }

/* Bingkai kamera presensi: pratinjau dan potret menempati kotak yang SAMA, jadi
   tata letaknya tidak melompat saat beralih dari pratinjau ke hasil jepretan.
   aspect-ratio 3/4 POTRET: potretnya memang potret — bingkai lanskap membuat
   wajah tampil kecil, dan hasilnya harus dipotong lagi di kanvas. */
.kamera-bingkai { position: relative; aspect-ratio: 3 / 4; margin: .35rem 0 0;
  background: #000; border: 1px solid var(--garis); border-radius: var(--r-kecil);
  overflow: hidden; }
.kamera-bingkai video, .kamera-bingkai .potret { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; }
.kamera-bingkai video.cermin { transform: scaleX(-1); }   /* pratinjau selfie dicerminkan */
.kamera-bingkai .potret { background: #000; }
.kamera-pesan { position: absolute; left: 0; right: 0; bottom: 0; margin: 0;
  padding: .45rem .6rem; color: #f2f2f2; background: rgba(0, 0, 0, .62);
  font-size: .76rem; }
.label-kamera { display: block; font-size: .82rem; font-weight: 600; }
.label-kamera + .kamera-bingkai { margin-top: .5rem; }
.form-cepat .kamera-bingkai + .sebaris { margin-top: .5rem; }
/* Bingkai pratinjau di DALAM modal: 4/3 = tinggi 310px pada lebar 414 → badan
   modal (88vh) harus menggulir di ponsel lanskap/low-end, dan itu memang
   disengaja — memampatkan gambar hanya membuat wajah tak terbaca. */
.modal .kamera-bingkai + .tombol-baris { margin-top: .55rem; }

/* ================================================== teks monospace & bantuan */
.teks-polos { margin: 0; padding: .9rem 1rem; background: var(--zebra);
  border: 1px solid var(--garis-2); border-radius: var(--r-kecil);
  font-family: "JetBrains Mono", ui-monospace, monospace; font-size: .8rem;
  line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.teks-pesan { display: block; font-size: .82rem; color: var(--tinta-2);
  white-space: pre-wrap; max-width: 60ch; }
.samar-kecil { color: var(--pudar); font-size: .74rem; }
.bantuan { font-size: .8rem; color: var(--pudar); margin: .7rem 0 0; max-width: 78ch; }
textarea { width: 100%; font: inherit; padding: .6rem .7rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); background: var(--putih); color: var(--tinta); resize: vertical; }
input[type="file"] { padding: .45rem .5rem; background: var(--putih); }

/* ================================================ konferensi video (iframe) */
.bingkai-video { position: relative; width: 100%; aspect-ratio: 16 / 9;
  background: #0d1f17; border-radius: var(--r); overflow: hidden; }
.bingkai-video iframe { position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; }
@media (max-width: 620px) {
  /* Layar sempit: ruang vertikal lebih berharga daripada lebar; video di atas,
     kontrol Jitsi tetap terjangkau tanpa menggulir. */
  .bingkai-video { aspect-ratio: 4 / 3; }
}

/* ==================================== rapat Cloudflare Realtime (dua arah) */
.sfu-panggung { display: grid; gap: .6rem; background: #0d1f17;
  border-radius: var(--r); padding: .6rem;
  /* min(210px, 100%) — BUKAN minmax(210px, 1fr): pada kolom yang lebih sempit
     dari 210px (ponsel + grid masih dua kolom), minmax MEMAKSA 210px sehingga
     video meluber keluar kotaknya. Ini penyebab utama tata letak "berantakan". */
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr)); }
.sfu-kotak { position: relative; aspect-ratio: 16 / 9; background: #0a1710;
  border-radius: var(--r-kecil); overflow: hidden; }
.sfu-video { width: 100%; height: 100%; object-fit: cover; display: block; }
.sfu-nama { position: absolute; left: .4rem; bottom: .4rem; font-size: .72rem;
  padding: .1rem .45rem; border-radius: 999px; background: rgba(0, 0, 0, .55);
  color: #fff; }
/* Video orang lain yang sedang mematikan kamera: biar tidak terlihat "macet". */
.sfu-kotak.mati .sfu-video { visibility: hidden; }
.sfu-kotak.mati::after { content: "kamera mati"; position: absolute; inset: 0;
  display: grid; place-items: center; font-size: .78rem; color: var(--pudar); }

/* Tata letak rapat: panggung + sisi obrolan/peserta. */
.rapat-tata { display: grid; gap: .9rem; grid-template-columns: minmax(0, 1fr) clamp(260px, 24vw, 340px);
  align-items: start; }
.rapat-utama { min-width: 0; }
/* Panggung rapat: batas bawah dinaikkan dari 210px supaya di desktop tidak
   muncul 4 kotak kecil sebaris — 2 kotak per baris jauh lebih enak dilihat.
   min() menjaga kolom sempit tetap aman (lihat .sfu-panggung di atas). */
.sfu-panggung { grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
#sfu-saya-kotak { max-width: 100%; }
.rapat-kendali { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .6rem; }
.rapat-kendali .tombol { padding: .4rem .7rem; font-size: .84rem; }
.sfu-kotak.besar { grid-column: 1 / -1; }
.sfu-lencana { position: absolute; right: .4rem; bottom: .4rem; font-size: .8rem; }
/* Pager panggung (30+ peserta). Tombolnya memakai .tombol samar yang sudah ada,
   jadi yang perlu diatur hanya barisnya — dan `hidden` WAJIB menang atas
   `display:flex` di sini, kalau tidak bar navigasi tetap tampil di rapat 2 orang. */
.sfu-hal[hidden] { display: none; }
.sfu-hal { display: flex; align-items: center; justify-content: center; gap: .6rem;
  margin-top: .55rem; color: #cfe6d8; font-size: .82rem; flex-wrap: wrap; }
.sfu-hal .tombol[disabled] { opacity: .45; cursor: default; }
/* Kotak di luar halaman panggung: `hidden` saja cukup, tetapi `.sfu-kotak`
   memakai position/aspect-ratio — pastikan tidak ada display yang mengalahkannya. */
.sfu-kotak[hidden] { display: none; }
/* Dialog undang pembicara: daftar akun yang bisa digulir + saringan nama. */
.undang-daftar { max-height: min(46vh, 360px); overflow-y: auto; margin: .5rem 0 .2rem;
  border: 1px solid var(--garis); border-radius: var(--r-kecil); padding: .3rem; }
.undang-orang { display: grid; grid-template-columns: auto 1fr; gap: 0 .5rem;
  align-items: center; padding: .35rem .4rem; border-radius: var(--r-kecil); cursor: pointer; }
.undang-orang:hover { background: var(--hijau-muda, #eef7f1); }
.undang-orang input { grid-row: span 2; }
.undang-orang small { grid-column: 2; word-break: break-all; }

/* Sisi obrolan + daftar peserta. */
.rapat-sisi { display: flex; flex-direction: column; background: var(--putih);
  border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; }
.rapat-tab { display: flex; border-bottom: 1px solid var(--garis); }
.rapat-tab .tab { flex: 1; padding: .5rem; font: inherit; font-size: .85rem; cursor: pointer;
  background: none; border: 0; color: var(--pudar); border-bottom: 2px solid transparent; }
.rapat-tab .tab.aktif { color: var(--tinta); font-weight: 600; border-bottom-color: var(--hijau); }
.rapat-panel { display: flex; flex-direction: column; min-height: 320px; max-height: 60vh; }
.rapat-log { flex: 1; overflow-y: auto; padding: .6rem; font-size: .86rem; }
.rapat-pesan { margin-bottom: .5rem; line-height: 1.35; word-break: break-word; }
.rapat-pesan.rapat-sistem { color: var(--pudar); font-size: .8rem; }
.rapat-kirim { display: flex; gap: .35rem; padding: .5rem; border-top: 1px solid var(--garis); }
.rapat-kirim input { flex: 1; padding: .4rem .5rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); font: inherit; font-size: .86rem; }
.rapat-reaksi { display: flex; gap: .25rem; padding: 0 .5rem .5rem; }
.rapat-reaksi button { font-size: 1rem; padding: .1rem .25rem; background: none;
  border: 1px solid var(--garis); border-radius: var(--r-kecil); cursor: pointer; }
.rapat-orang { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem;
  padding: .35rem 0; border-bottom: 1px solid var(--garis); }
.rapat-nama { font-weight: 600; font-size: .86rem; }
.rapat-orang .pudar { font-size: .76rem; }
.rapat-kendali-peserta { display: flex; flex-wrap: wrap; gap: .25rem; margin-left: auto; }
.rapat-kendali-peserta button { font-size: .72rem; padding: .1rem .35rem; }
/* Reaksi terbang (gaya Zoom). */
.rapat-terbang { position: fixed; bottom: 18vh; left: 50%; font-size: 2rem;
  pointer-events: none; animation: terbang 2.6s ease-out forwards; z-index: 40; }
@keyframes terbang { from { opacity: 1; transform: translate(-50%, 0) scale(.8); }
  to { opacity: 0; transform: translate(-50%, -40vh) scale(1.6); } }
.pesan.galat { background: #fdecec; border-color: #f3b7b7; color: #7a1f1f; }
/* Lobi ruang rapat (gaya Zoom): pratinjau diri + pilih perangkat SEBELUM masuk.
   Dua kolom di layar lebar, satu kolom di ponsel — sama seperti .rapat-tata. */
/* Lobi tidak punya kotak pratinjau: gambar Anda tampil di panggung. Satu kolom
   supaya panel pengaturan tidak melebar aneh di desktop. */
.rapat-lobi { background: var(--putih); border: 1px solid var(--garis);
  border-radius: var(--r); padding: .9rem; margin-bottom: .7rem; max-width: 520px; }
.rapat-lobi-isi { display: flex; flex-direction: column; gap: .55rem; min-width: 0; }
.rapat-lobi-isi label { font-size: .82rem; }
.rapat-lobi-isi select { width: 100%; padding: .35rem .45rem; border: 1px solid var(--garis);
  border-radius: var(--r-kecil); font: inherit; font-size: .84rem; background: var(--putih); }
.rapat-lobi-nama { font-weight: 600; margin: 0; }
.rapat-lobi-isi .pesan { margin: 0; }


/* ---- Ruang rapat di layar sempit (ponsel & tablet) ----
   WAJIB satu kolom: `.rapat-tata` bawaannya `1fr 300px`, dan di 390px kolom
   utama menyusut jadi ~45px sehingga video, tombol, dan kotak obrolan saling
   menindih — persis keluhan "sangat berantakan". Aturan ini pernah ada lalu
   ikut terhapus saat menyunting blok lobi; ia dikembalikan di sini. */
@media (max-width: 900px) {
  .rapat-tata { grid-template-columns: 1fr; }
  /* Bilah kendali menempel di bawah: di ponsel tombolnya jauh dari jempol kalau
     harus digulir dulu, padahal ini panggilan video — kendalinya harus selalu
     terjangkau. Latar ditulis supaya video yang lewat di belakangnya tidak
     membuat tombol tak terbaca. */
  .rapat-kendali { position: sticky; bottom: 0; z-index: 5; margin-top: .5rem;
    padding: .45rem 0; background: var(--kertas); border-top: 1px solid var(--garis); }
  .rapat-kendali .tombol { flex: 1 1 auto; justify-content: center; min-height: 42px;
    padding: .5rem .6rem; font-size: .86rem; }
  /* Obrolan tidak perlu setinggi 60vh di ponsel — panggungnya yang utama. */
  .rapat-panel { min-height: 240px; max-height: 52vh; }
  .rapat-sisi { border-radius: var(--r); }
  /* Kartu peserta: satu baris per orang, kendali pengelola pindah ke bawah
     (di 390px tombolnya berdesakan dengan namanya kalau tetap sebaris). */
  .rapat-orang { flex-wrap: wrap; }
  .rapat-kendali-peserta { width: 100%; margin-left: 0; }
  /* Tombol kendali pengelola tidak memakai `.tombol.mini` (hanya `mini`), jadi
     aturan 40px di atas tidak menjangkaunya: terukur cuma 19px — terlalu kecil
     untuk jempol. Samakan tinggi sentuhnya dengan tombol mini lain di ponsel. */
  .rapat-kendali-peserta button { min-height: 40px; padding: .4rem .55rem; font-size: .8rem; }
}


/* ============================ beranda publik (gaya situs perusahaan) */
/* Struktur mengikuti pola situs agrinaspalma.co.id: latar terang, hero foto
   penuh lebar, seksi bergantian terang/gelap, kartu putih, aksen hijau. */
.beranda-tubuh { background: #f4f5f0; color: #202725; }
.situs { display: flex; flex-direction: column; align-items: stretch; }
.situs h1, .situs h2, .situs h3 { text-transform: none; letter-spacing: -.015em; margin: 0; }
/* :where() membuat selektor ini tetap (0,1,0) tapi tidak menimpa kelas
   modifier seperti .pub-media-aksi / .pub-media-catatan (yang juga 0,1,0 dan
   ditulis belakangan). Tanpa :where(), seluruh margin kelas itu hilang. */
.situs :where(p) { margin: 0; }

/* --- bilah atas --- */
/* Arah flex ditulis eksplisit: CSS lama punya aturan global `nav` yang
   membocorkan flex-direction column ke .pub-nav (menu jadi menumpuk tegak). */
.pub-bar { position: sticky; top: 0; z-index: 20; display: flex; flex-direction: row;
  align-items: center; gap: 1rem; padding: .55rem clamp(.9rem, .4rem + 2vw, 2.4rem);
  background: rgba(255, 255, 255, .94); backdrop-filter: blur(8px);
  border-bottom: 1px solid #e2e7e2; }
/* Dua logo terpisah + garis pemisah, mengikuti pola agrinaspalma.co.id */
.pub-merek { display: flex; align-items: center; gap: .6rem; margin-right: auto;
  text-decoration: none; }
.pub-merek img { height: auto; width: auto; display: block; }
.pub-merek .merek-danantara { height: 27px; }
.pub-merek .merek-pemisah { display: block; width: 1px; height: 26px; background: #d9e2dc; }
.pub-merek .merek-agrinas { height: 31px; }
.pub-nav { display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center;
  gap: 1.5rem; font-size: .875rem; }
.pub-nav a { color: #3f4b45; text-decoration: none; font-weight: 500;
  white-space: nowrap; }
.pub-nav a:hover { color: var(--hijau-700); text-decoration: underline; }
.pub-bar .tombol { white-space: nowrap; }
/* Jarak antar-tautan nav 1.5rem; beri tombol setengah gap bilah lagi supaya
   iramanya sama, bukan menempel lebih rapat dari tautan di sebelahnya. */
.pub-bar .masuk-bar { margin-left: .5rem; }

/* --- hero --- */
/* Latar dalam hijau lebih terang: foto disaring hijau muda, bukan hampir hitam. */
.pub-hero { position: relative; min-height: clamp(420px, 62vh, 620px);
  background: #dff2e4; display: flex; align-items: center; overflow: hidden; }
.pub-hero-gambar { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; }
.pub-hero::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, rgba(13, 76, 45, .89) 0%, rgba(17, 94, 55, .78) 42%,
    rgba(21, 110, 63, .42) 72%, rgba(24, 122, 70, .16) 100%); }
.pub-hero-isi { position: relative; z-index: 2; padding: clamp(1.6rem, .9rem + 3vw, 3.4rem)
  clamp(.9rem, .4rem + 2vw, 2.4rem); max-width: 1180px; margin: 0 auto; width: 100%;
  display: flex; flex-direction: column; gap: .8rem; }
.pub-hero-merek { color: var(--hijau-300); font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; }
.pub-hero h1 { color: #fff; font-size: clamp(1.7rem, 1.1rem + 3.1vw, 3.2rem);
  line-height: 1.08; max-width: 19ch; }
.pub-hero-isi > p { color: #cfe0d7; max-width: 58ch;
  font-size: clamp(.9rem, .87rem + .28vw, 1.05rem); }
.pub-hero .tombol-baris { margin-top: .6rem; }
.pub-hero .tombol.samar { background: rgba(255, 255, 255, .12);
  border-color: rgba(255, 255, 255, .34); color: #eaf5ee; }
.pub-hero .tombol.samar:hover { background: rgba(255, 255, 255, .22); color: #fff; }

/* --- bagian umum --- */
.pub-latar-lembut { background: #eef4f0; }
/* Kolom seksi 1180px dibuat oleh PADDING, bukan margin-auto tiap anak.
   Sebelumnya tiap anak punya margin auto sendiri, jadi judul seksi (74ch)
   ter-center di x≈403 sementara grid mulai di x≈130 — tampak melayang dan
   itulah yang membuat tata letak desktop terlihat berantakan. */
.pub-bagian { padding: clamp(2.2rem, 1.2rem + 3.6vw, 4.4rem)
  max(clamp(.9rem, .4rem + 2vw, 2.4rem), calc((100% - 1180px) / 2)); }
.pub-bagian > * { max-width: 1180px; margin-left: auto; margin-right: auto; }
.pub-kepala-bagian { max-width: 74ch; margin-left: 0; margin-right: 0; }
.pub-media-catatan, .pub-media-aksi, .pub-halaman, .pub-kutipan { margin-left: 0; }
.pub-kepala-bagian { display: flex; flex-direction: column; gap: .65rem; margin-bottom: 1.8rem;
  max-width: 74ch; }
.pub-kepala-bagian h2 { font-size: clamp(1.35rem, 1.05rem + 1.5vw, 2.15rem); line-height: 1.16; }
.pub-kepala-bagian > p { color: #4d5a53; font-size: clamp(.9rem, .87rem + .25vw, 1.02rem); }
.pub-eyebrow { color: var(--hijau-600); font-size: .76rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .13em; }
.pub-dua { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(1.4rem, .9rem + 2.2vw, 3rem); align-items: start; }
.pub-dua h2 { font-size: clamp(1.3rem, 1.02rem + 1.4vw, 2rem); line-height: 1.16; margin-bottom: .7rem; }
.pub-dua p + p { margin-top: .7rem; }
/* Judul kolom kiri disejajarkan dengan kartu di kanan: kartu punya padding
   atas ~1.35rem + garis 1px, kolom teks tidak — tanpa ini judul kiri
   menggantung 23px lebih tinggi dan seksi terlihat tidak rapi. */
.pub-cerita { padding-top: calc(1.35rem + 1px); }
.pub-dua > div > p { color: #4d5a53; }

/* bagian gelap */
/* Dua hal yang membuat seksi ini tampak kotor di layar sempit:
   (1) h2 judul seksi memakai warna global --pudar (#5f6f68) dan paragraf
       kolom memakai #4d5a53 — keduanya nyaris hilang di atas hijau
       (1,7:1 dan 1,3:1). Semua teks di seksi gelap di-override di bawah.
   (2) Latar #155238 bertabrakan dengan hijau tombol/aksen di dekatnya;
       hijau-900 (#12402a) sudah ada di palet dan memberi kontras lebih rata. */
.pub-gelap { background: var(--hijau-900); color: #e6eee9; }
.pub-gelap .pub-kepala-bagian h2 { color: #fff; }
.pub-gelap .pub-kepala-bagian > p { color: #cfe0d7; }
.pub-gelap .pub-dua > div > p { color: #cfe0d7; }
.pub-gelap .pub-daftar li { color: #cfe0d7; }
.pub-gelap .pub-kutipan figcaption { color: #a3bcae; }
.pub-gelap h3 { color: #fff; }
.pub-gelap .pub-eyebrow { color: var(--hijau-300); }
.pub-gelap > div > h3, .pub-gelap .pub-dua h3 { margin-bottom: .8rem; font-size: 1.02rem; }

/* --- daftar --- */
.pub-daftar, .pub-tanpa-tanda { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: .6rem; }
.pub-daftar li { position: relative; padding-left: 1.5rem; font-size: .9rem; color: #bfd2c7; }
.pub-daftar li::before { content: ""; position: absolute; left: .25rem; top: .52em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--hijau-300); }
.pub-tanpa-tanda li { font-size: .85rem; color: inherit; }

/* --- linimasa --- */
.pub-lini { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
  gap: .9rem; border-left: 2px solid #d9e2da; padding-left: 1.15rem; }
.pub-lini li { position: relative; display: flex; flex-direction: column; gap: .15rem; }
.pub-lini li::before { content: ""; position: absolute; left: -1.62rem; top: .38em;
  width: 11px; height: 11px; border-radius: 50%; background: var(--hijau-600);
  border: 2px solid #f4f5f0; }
.pub-lini b { font-size: .82rem; color: var(--hijau-700); letter-spacing: .04em; }
.pub-lini span { font-size: .88rem; color: #4d5a53; }

/* --- kartu --- */
.pub-kartu { background: #fff; border: 1px solid #e3e8e3; border-radius: 12px;
  padding: 1.35rem 1.45rem; box-shadow: 0 1px 2px rgba(16, 29, 24, .05); }
.pub-identitas h3 { font-size: .95rem; margin-bottom: .9rem; }
.pub-identitas dl { margin: 0; display: grid; grid-template-columns: minmax(6rem, 8.6rem) minmax(0, 1fr);
  gap: .55rem .9rem; }
.pub-identitas dt { font-size: .78rem; color: #6a776f; text-transform: uppercase;
  letter-spacing: .05em; }
.pub-identitas dd { margin: 0; font-size: .87rem; }
/* auto-fill (bukan auto-fit): baris terakhir tetap selebar kartu lain,
   tidak diregangkan memenuhi sisa lebar halaman. */
/* Lebar kolom dipatok 3 kolom di desktop: kartu 4 kolom menyisakan 2 kartu
   di baris kedua (banyak ruang kosong). */
.pub-kartu-grid { display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(min(238px, 100%), 1fr)); }
@media (min-width: 900px) {
  .pub-kartu-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.pub-kartu-grid .pub-kartu { border-top: 3px solid var(--hijau-300); }
.pub-kartu h3 { font-size: .98rem; margin-bottom: .45rem; }
.pub-kartu p { font-size: .875rem; color: #4d5a53; }
.pub-kartu-grid { margin-bottom: 1.6rem; }

/* --- langkah --- */
/* 2x2 di desktop supaya kolomnya sejajar dengan 3 kolom kartu di atasnya
   (sebelumnya 4 kolom sempit yang tidak sejajar apa pun). */
.pub-langkah { list-style: none; counter-reset: l; margin: 0; padding: 0; display: grid;
  gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr)); }
@media (min-width: 900px) {
  .pub-langkah { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.pub-langkah li { counter-increment: l; background: #fff; border: 1px solid #e3e8e3;
  border-radius: 12px; padding: 1.1rem 1.2rem; font-size: .85rem; color: #4d5a53; }
.pub-langkah li::before { content: counter(l); display: flex; align-items: center;
  justify-content: center; width: 26px; height: 26px; border-radius: 50%;
  margin-bottom: .6rem; background: var(--hijau-600); color: #fff; font-weight: 700;
  font-size: .8rem; }
.pub-langkah li b { display: block; color: #202725; font-size: .92rem; margin-bottom: .3rem; }

/* --- kutipan --- */
.pub-kutipan { margin: clamp(1.8rem, 1.2rem + 2vw, 2.8rem) 0 0;
  border-left: 3px solid var(--hijau-300); padding-left: 1.5rem; max-width: 74ch; }
.pub-kutipan blockquote { margin: 0; color: #dfeae3;
  font-size: clamp(1rem, .94rem + .5vw, 1.3rem); line-height: 1.45; }
.pub-kutipan figcaption { margin-top: .7rem; color: #93ac9f; font-size: .8rem; }

/* --- gambar + keterangan --- */
.pub-gambar { margin: 0; }
.pub-gambar img { width: 100%; height: auto; border-radius: 12px; display: block; }
.pub-gambar figcaption { margin-top: .6rem; font-size: .8rem; color: #6a776f; }
.pub-binaan { align-items: center; }

/* --- kaki --- */
.pub-kaki { background: #134430; color: #c3d6c9; margin-top: auto; }
.pub-kaki-grid { max-width: 1180px; margin: 0 auto; padding: clamp(1.8rem, 1.2rem + 2vw, 2.8rem)
  clamp(.9rem, .4rem + 2vw, 2.4rem); display: grid; gap: 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); }
.pub-kaki h3 { color: #fff; font-size: .82rem; text-transform: uppercase;
  letter-spacing: .08em; margin-bottom: .6rem; }
.pub-kaki p, .pub-kaki li { font-size: .83rem; line-height: 1.55; }
.pub-kaki ul { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: .4rem; }
.pub-kaki a { color: #b9c9c0; text-decoration: none; }
.pub-kaki a:hover { color: #fff; text-decoration: underline; }
.pub-kaki-logo { height: 42px; width: auto; display: block; margin-bottom: .7rem;
  background: #fff; padding: .35rem .5rem; border-radius: 6px; }
/* Kaki gelap: logo berwarna, jadi tiap logo berdiri di alas putih tipis
   supaya warna aslinya tidak hilang di latar hijau tua. */
.pub-kaki .lockup { height: 42px; width: auto; display: block; margin-bottom: .8rem; }
.pub-kaki .kaki-logo { display: inline-flex; align-items: center; gap: .55rem;
  background: #fff; border-radius: 8px; padding: .38rem .6rem; margin-bottom: .8rem; }
.pub-kaki .kaki-logo img { display: block; height: 30px; width: auto; }
.pub-kaki .kaki-logo .kaki-pemisah { width: 1px; height: 26px; background: #dbe4df; }
.pub-slogan { color: #8fa89c; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .06em; }
.pub-kaki-bawah { border-top: 1px solid rgba(255, 255, 255, .1);
  max-width: 1180px; margin: 0 auto; padding: .9rem clamp(.9rem, .4rem + 2vw, 2.4rem);
  display: flex; flex-wrap: wrap; gap: .35rem 1.6rem; justify-content: space-between;
  font-size: .76rem; color: #7d9488; }

/* ===================== revisi: header, direksi, ruang media, login ===================== */

/* --- header: lockup Danantara | Agrinas Pangan --- */
/* Lockup sudah memuat kedua logo, jadi cukup satu gambar.
   Nama perusahaan tetap ada di teks aria-label + footer. */
.pub-nav { gap: 1.15rem; }

/* Menu layar sempit: <details> supaya navbar tetap ada tanpa JavaScript. */
.pub-menu { display: none; position: relative; }
.pub-menu summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center;
  gap: .4rem; padding: .5rem .7rem; border: 1px solid #dde4e0; border-radius: 8px;
  font-size: .85rem; font-weight: 600; color: #3f4b45; background: #fff; }
.pub-menu summary::-webkit-details-marker { display: none; }
.pub-menu[open] summary { border-color: var(--hijau-500); color: var(--hijau-700); }
.pub-menu nav { position: absolute; right: 0; top: calc(100% + .45rem); z-index: 30;
  flex-direction: column; gap: .1rem; min-width: 232px; background: #fff; padding: .5rem;
  border: 1px solid #e2e7e2; border-radius: 12px; box-shadow: var(--bayang-2); }
.pub-menu nav a { color: #3f4b45; text-decoration: none; font-weight: 500; font-size: .9rem;
  padding: .55rem .7rem; border-radius: 8px; white-space: nowrap; }
.pub-menu nav a:hover { background: var(--hijau-100); color: var(--hijau-700); }
.pub-menu nav a.masuk-menu { margin-top: .3rem; border-top: 1px solid var(--garis-2);
  border-radius: 0 0 8px 8px; color: var(--hijau-700); font-weight: 700; }

/* --- jajaran direksi --- */
/* Kartu profil mendatar: potret 4/5 di kiri, biodata di kanan. Kartu potret
   tegak menyisakan separuh lebar halaman kosong saat direksinya sedikit. */
.pub-direksi { display: grid; gap: 1.2rem;
  grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr)); }
.pub-orang { display: flex; align-items: stretch; background: #fff;
  border: 1px solid #e3e8e3; border-radius: 12px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(16, 29, 24, .05); }
.pub-orang .foto { flex: 0 0 148px; background: #eef3f1; }
.pub-orang .foto img { width: 100%; height: 100%; object-fit: cover; object-position: top center;
  display: block; }
.pub-orang .foto.kosong { display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, var(--hijau-800), #14532d); }
.pub-orang .foto.kosong span { color: #fff; font-size: 2.6rem; font-weight: 700;
  letter-spacing: .04em; opacity: .92; }
.pub-orang .orang-isi { padding: 1.25rem 1.35rem; display: flex; flex-direction: column;
  justify-content: center; gap: .1rem; min-width: 0; }
.pub-orang .orang-jabatan { color: var(--hijau-600); font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; }
.pub-orang h3 { font-size: 1rem; margin: .3rem 0 .35rem; line-height: 1.3; }
.pub-orang p { font-size: .82rem; color: #4d5a53; }
.pub-orang .orang-sumber { font-size: .7rem; color: #7d8a83; margin-top: .55rem; }

/* --- pusat informasi / ruang media --- */
.pub-media { display: grid; gap: 1.2rem;
  grid-template-columns: repeat(auto-fill, minmax(min(310px, 100%), 1fr)); }
.pub-artikel { background: #fff; border: 1px solid #e3e8e3; border-radius: 12px; overflow: hidden;
  display: flex; flex-direction: column; text-decoration: none; color: inherit;
  box-shadow: 0 1px 2px rgba(16, 29, 24, .05); }
.pub-artikel:hover { border-color: var(--hijau-500); box-shadow: var(--bayang-2); }
.pub-artikel .gambar { position: relative; aspect-ratio: 16 / 9; background: #e9efeb; }
.pub-artikel .gambar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* logo Agrinas + Danantara ditempel di sudut tiap gambar berita */
.pub-artikel .badge { position: absolute; left: .55rem; bottom: .55rem;
  background: rgba(255, 255, 255, .95); border-radius: 6px; padding: .22rem .42rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18); }
.pub-artikel .badge img { height: 17px; width: auto; display: block; }
.pub-artikel .isi-artikel { padding: .95rem 1.05rem 1.15rem; display: flex;
  flex-direction: column; gap: .4rem; flex: 1; }
.pub-artikel .meta { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem;
  font-size: .72rem; color: #6a776f; }
.pub-artikel .meta .media { color: var(--hijau-700); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; }
.pub-artikel h3 { font-size: .97rem; line-height: 1.35; }
.pub-artikel p { font-size: .835rem; color: #4d5a53; }
.pub-artikel .baca { margin-top: auto; padding-top: .45rem; font-size: .8rem; font-weight: 600;
  color: var(--hijau-600); }
.pub-artikel:hover .baca { text-decoration: underline; }
.pub-artikel.tanpa-gambar .gambar { display: none; }
.pub-media-catatan { font-size: .76rem; color: #7d8a83; margin-top: 1.2rem; max-width: 74ch; }
.pub-media-aksi { margin: 2.4rem 0 0; text-align: center;
  display: flex; justify-content: center; }
.pub-media-aksi .tombol { min-height: 46px; padding: .7rem 1.6rem; }
/* Paging: dua tombol di ujung, nomor halaman di tengah. */
.pub-halaman { display: flex; align-items: center; gap: .6rem;
  margin: 2.4rem auto 0; padding-top: 1.6rem; border-top: 1px solid #dfe6e1;
  justify-content: center; }
.pub-halaman-angka { list-style: none; display: flex; align-items: center; gap: .3rem;
  margin: 0; padding: 0; }
.pub-halaman-angka a, .pub-halaman-angka span { display: grid; place-items: center;
  min-width: 40px; height: 40px; padding: 0 .5rem; border-radius: 8px; font-size: .85rem;
  font-weight: 600; text-decoration: none; color: #4d5a53; }
.pub-halaman-angka a { border: 1px solid #dfe6e1; background: #fff; }
.pub-halaman-angka a:hover { border-color: var(--hijau-500); color: var(--hijau-700);
  background: var(--hijau-100); }
.pub-halaman-angka span[aria-current] { background: var(--hijau-600); color: #fff;
  border: 1px solid var(--hijau-600); }
.pub-halaman .tombol { min-height: 40px; }
.pub-halaman .tanpa-isi { visibility: hidden; }
/* Mobile: tetap satu baris — 3 item (prev + nomor + next) muat di 390px;
   tombol selebar baris membuat paging jadi tiga tingkat. */
@media (max-width: 560px) {
  .pub-halaman { gap: .4rem; }
  .pub-halaman .tombol { padding: .5rem .7rem; font-size: .82rem; }
  .pub-halaman .tombol.tanpa-isi { display: none; }
}

/* --- halaman masuk: dua logo berwarna (Danantara | Agrinas), sama seperti kaki
   halaman. panel-kiri = flex column, jadi tanpa align-self: flex-start gambar
   diregangkan selebar panel dan rasionya jadi gepeng. */
.panel-kiri .merek-lockup { display: inline-flex; align-items: center; gap: .55rem;
  align-self: flex-start; background: #fff; border-radius: 8px; padding: .38rem .6rem; }
.panel-kiri .merek-lockup img { display: block; height: 30px; width: auto; }
.panel-kiri .merek-lockup .merek-pemisah { width: 1px; height: 26px; background: #d9e2dc; }

/* --- halaman masuk: rapatkan di layar PENDEK supaya form tetap utuh satu layar.
   Diletakkan di akhir berkas: blok .panel-kiri/.panel-kanan dasar dan aturan
   mobile (max-width:900px) ada di atas, spesifisitasnya sama, jadi urutan
   di sini yang menentukan. Jangan pindahkan ke atas. */
@media (max-height: 700px) {
  .masuk { padding: .75rem; }
  .panel-kiri, .panel-kanan { padding: 1.5rem 1.7rem; }
  .panel-kiri { gap: .85rem; }
  .panel-kiri h1 { font-size: 1.45rem; }
}
/* Kolom tunggal + pendek = paling boros tinggi (dua panel bertumpuk), padahal
   ruangnya paling sempit. Buang teks penjelas, sisakan logo, judul, dan form. */
@media (max-width: 900px) and (max-height: 700px) {
  .panel-kiri > p, .panel-kanan .bantuan { display: none; }
  .panel-kiri h1 { font-size: 1.3rem; }
}
/* Tingkat terakhir — HP kecil lawas (320x480, 4"). Semua dirapatkan; tidak ada
   yang disembunyikan lagi supaya form tetap lengkap. */
@media (max-width: 900px) and (max-height: 560px) {
  .masuk { padding: .5rem; }
  .panel-kiri, .panel-kanan { padding: .85rem 1rem; }
  .panel-kiri { gap: .5rem; }
  .panel-kiri h1 { font-size: 1.05rem; }
  .panel-kiri .merek-lockup img { height: 22px; }
  .panel-kanan h2 { font-size: 1rem; }
}

@media (max-width: 1060px) {
  .pub-nav { display: none; }
  .pub-menu { display: block; }
  /* Tombol Masuk di bilah hanya untuk desktop; di lebar ini tautannya sudah ada
     di dalam menu ☰ dan bilahnya harus tetap sesempit mungkin. */
  .pub-bar .masuk-bar { display: none; }
}
@media (max-width: 860px) {
  .pub-dua { grid-template-columns: 1fr; }
  .pub-binaan { grid-template-columns: 1fr; }
  .pub-identitas dl { grid-template-columns: 1fr; gap: .1rem; }
  .pub-identitas dd { margin-bottom: .5rem; }
}
@media (max-width: 560px) {
  .pub-merek { gap: .45rem; }
  .pub-merek .merek-danantara { height: 20px; }
  .pub-merek .merek-pemisah { height: 20px; }
  .pub-merek .merek-agrinas { height: 23px; }
  .pub-bar { gap: .4rem; padding: .5rem .9rem; }
  .pub-menu summary { padding: .45rem .55rem; font-size: .8rem; }
  /* Di mobile item ber-nomor (alur DesaPreneur) diletakkan di tengah:
     nomor, judul, dan teksnya ikut center supaya tidak menggantung kiri. */
  .pub-langkah li { text-align: center; }
  .pub-langkah li::before { margin-left: auto; margin-right: auto; }
  .pub-kaki .lockup { height: 34px; }
  /* 400px terasa pendek di 390px-lebar: judul + paragraf + dua tombol
     selebar baris hampir memenuhi, sisa ruang atas-bawah tinggal tipis.
     448px (+12%) memberi napas tanpa mendorong seksi berikutnya terlalu jauh. */
  .pub-hero { min-height: 448px; }
  .pub-hero-isi { gap: .65rem; }
  .pub-hero h1 { max-width: none; }
  .pub-hero .tombol { width: 100%; }
  .pub-hero::after { background: linear-gradient(180deg, rgba(11, 68, 40, .89) 0%,
    rgba(15, 82, 48, .82) 55%, rgba(18, 96, 56, .72) 100%); }
  .pub-kaki-logo { height: 36px; }
}



/* ------------------------------------------------------------ Ruang Kerja
   Bilah modul, kalender bulanan, pohon wiki, dan pesan berterjemahan.
   Semua memakai warna & bentuk yang sudah ada di berkas ini. */
.modul-nav { display:flex; gap:.4rem; flex-wrap:wrap; margin:0 0 1.1rem; }
.modul-nav a { display:inline-flex; align-items:center; gap:.4rem; padding:.42rem .7rem;
  border:1px solid var(--garis, #d8ded9); border-radius:999px; font-size:.86rem;
  text-decoration:none; color:inherit; white-space:nowrap; }
.modul-nav a.ini { background:#15402f; border-color:#15402f; color:#fff; }
.modul-nav a:hover { background:#eef3ef; }
.modul-nav a.ini:hover { background:#1b5139; color:#fff; }
/* Tiga tab modul Koperasi: lebarnya DISAMAKAN (dulu mengikuti panjang label —
   terukur 138/164/142px) dan di ponsel jadi tiga kolom berikon di atas label,
   supaya tidak pecah 2+1 baris. */
.modul-nav-3 a { justify-content: center; flex: 0 0 10.5rem; min-width: 0; }

.obrolan { border:1px solid var(--garis, #e2e7e3); border-radius:.8rem;
  padding:.75rem .9rem; margin-bottom:.7rem; background:#fff; }
.obrolan-kepala { display:flex; justify-content:space-between; gap:.6rem; align-items:baseline; }
.obrolan-kepala > small { font-size:.74rem; }
.pesan-terjemah { margin-top:.55rem; padding:.5rem .7rem; border-left:3px solid #15402f;
  background:#f3f7f4; border-radius:.35rem; }
.pesan-terjemah > small { display:block; margin-bottom:.2rem; color:#15402f; }

/* Wadah editor. ONLYOFFICE MENGGANTI #editor-dokumen dengan iframe-nya sendiri,
   jadi iframe itu jadi SAUDARA wadah, bukan anak — karena itu tinggi dipasang di
   wadah pembungkus ini dan memakai `> *` (anak apa pun), bukan `> iframe`. */
.editor-bingkai { height:70vh; min-height:520px; border:1px solid var(--garis, #d8ded9);
  border-radius:.5rem; background:#fff; overflow:hidden; }
.editor-bingkai > * { display:block; width:100%; height:100%; border:0; }
/* Editor VIDEO (OpenCut) butuh tinggi penuh: panel Media + pratinjau + garis
   waktu bertumpuk dalam 70vh -> tampak berantakan/terpotong. Tinggi dihitung
   dari layar supaya garis waktu tetap terlihat tanpa menggulir halaman. */
.editor-bingkai.tinggi { height:calc(100dvh - 150px); min-height:640px; }
@media (max-width:720px) {
  .editor-bingkai.tinggi { height:calc(100dvh - 110px); min-height:75dvh; }
}
/* ===== Halaman editor (gambar/video) = satu layar, tanpa gulir halaman =====
   Dulu bingkai dipaku `calc(100dvh - 150px)` DI DALAM halaman yang masih
   bergulir: di ponsel sisanya tertutup bilah menu bawah dan panel judul,
   sehingga editor terasa seperti bingkai sempit di tengah halaman — bukan
   aplikasi. Sekarang tinggi diturunkan dari rantai flex: tubuh = 100dvh,
   shell mengambil sisa, .isi jadi kolom, dan bingkai mengambil sisa .isi.
   Satu angka saja yang dipatok: ruang bilah bawah (--tb-nav) di ponsel. */
body.editor-penuh { display:flex; flex-direction:column;
  height:100vh; height:100dvh; overflow:hidden; }
body.editor-penuh .shell { flex:1 1 auto; height:auto; min-height:0; }
body.editor-penuh .sisi { overflow:auto; }
body.editor-penuh .isi { display:flex; flex-direction:column; min-height:0;
  overflow:hidden; padding-bottom:var(--sp); }
body.editor-penuh .kepala { flex:none; margin-bottom:.5rem; }
body.editor-penuh .kepala .tenang,
body.editor-penuh .modul-nav,
body.editor-penuh .bantuan { display:none; }
body.editor-penuh .blok { flex:1 1 auto; min-height:0; display:flex;
  padding:0; border:0; background:transparent; }
body.editor-penuh .editor-bingkai,
body.editor-penuh .editor-bingkai.tinggi { flex:1 1 auto; height:auto;
  min-height:0; width:100%; border:0; border-radius:0; }
@media (max-width:900px) {
  body.editor-penuh .isi { padding-bottom:calc(var(--tb-nav) + .4rem); }
  /* Kepala halaman dipadatkan jadi SATU baris setinggi ±40px. Tiap 50px yang
     dihemat di sini langsung jadi tinggi kanvas — di 658px layar, kepala dua
     baris memakan 99px dan menyisakan bingkai 380px saja. */
  body.editor-penuh .kepala { flex-direction:row; align-items:center; gap:.4rem;
    flex-wrap:nowrap; margin-bottom:.4rem; }
  body.editor-penuh .kepala h1 { font-size:.92rem; margin:0; white-space:nowrap; }
  body.editor-penuh .kepala .tombol-baris { flex:1 1 auto; min-width:0; flex-wrap:nowrap;
    overflow-x:auto; scrollbar-width:none; justify-content:flex-end; }
  body.editor-penuh .kepala .tombol-baris::-webkit-scrollbar { display:none; }
  body.editor-penuh .kepala .tombol { padding:.3rem .5rem; font-size:.74rem;
    white-space:nowrap; flex:0 0 auto; }
  /* Ponsel: sisakan HANYA "Layar penuh". Tautan lain sudah ada di menu bawah,
     dan tiga tombol berjejer membuat yang pertama terdorong keluar layar. */
  body.editor-penuh .kepala .tombol-baris .tombol ~ .tombol { display:none; }
}

.kal-grid { display:grid; grid-template-columns:repeat(7, 1fr); gap:3px; }
.kal-judul > div { text-align:center; font-size:.76rem; font-weight:600; padding:.3rem 0; color:#5b6b62; }
/* AKAR kalender meluber (terukur 407px dari layar 360px): kisi 7 kolom 1fr
   tidak boleh sempit dari MIN-CONTENT, dan min-content barisnya ditentukan
   isi. Tanpa `min-width:0` + `overflow:hidden`, satu judul acara yang panjang
   melebarkan kolomnya sendiri lalu mendorong SELURUH kisi keluar kartu. */
.kal-sel { min-height:88px; border:1px solid var(--garis, #e2e7e3); border-radius:.4rem;
  padding:.3rem; background:#fff; display:flex; flex-direction:column; gap:2px; min-width:0; overflow:hidden; }
.kal-luar { background:#f7f9f8; border-style:dashed; }
.kal-kini { outline:2px solid #15402f; }
.kal-tgl { font-size:.76rem; font-weight:600; color:#5b6b62; }
/* Wadah acara dalam satu sel. Desktop: bertumpuk, satu baris per acara
   (judul panjang dipotong) supaya kisi tetap rapi. */
.kal-acara-baris { display:flex; flex-direction:column; gap:2px; min-width:0; }
/* Di layar lebar judul panjang dipotong satu baris (kotak tetap rapi). Di
   ponsel `white-space:nowrap` DILEPAS: judul boleh membungkus 2 baris dan
   `overflow-wrap:anywhere` yang menjamin kata panjang pun tidak melebarkan
   kolom. Huruf dinaikkan ke .68rem agar tetap terbaca. */
.kal-acara { display:block; min-width:0; font-size:.7rem; line-height:1.25;
  padding:1px 3px; border-radius:.25rem; text-decoration:none; color:inherit;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; overflow-wrap:anywhere; }
.kal-rapat { background:#e3efe8; color:#15402f; }
.kal-rapat:hover { background:#cfe4d8; }
.kal-tenggat { background:#fdf1e3; color:#8a5a12; }

.wiki-pohon { list-style:none; margin:0; padding-left:1rem; }
.wiki-pohon > li { margin:.25rem 0; }
.wiki-pohon a { text-decoration:none; }
.wiki-pohon a:hover { text-decoration:underline; }
/* Ringkasan status persetujuan: tiga lencana sebaris, boleh melipat di ponsel. */
.setuju-ringkas { display:flex; flex-wrap:wrap; gap:.4rem; margin:0 0 .9rem; }
.daftar-langkah { list-style:none; margin:.4rem 0; padding-left:.8rem; font-size:.86rem; }
.baris-langkah { background:#fafcfb; }

@media (max-width: 720px) {
  /* 🔴 GRID KALENDER DI PONSEL: 7 kolom kisi TIDAK muat untuk menampilkan judul
     acara (tiap kolom ~40px). Pendekatan lama mengecilkannya jadi TITIK 7px
     `font-size:0` — informasinya hilang, hanya sisa "ada sesuatu hari itu".
     Sekarang: kisi tetap ada sebagai PETA BULAN (tanggal + jumlah acara), lalu
     daftar acara bulan itu ditampilkan sebagai AGENDA PER TANGGAL yang terbaca.
     Tidak ada yang disembunyikan, dan tidak perlu JS. */
  .kal-grid { gap:2px; }
  .kal-judul > div { font-size:.66rem; padding:.2rem 0; letter-spacing:.02em; }
  .kal-sel { min-height:0; padding:.3rem .2rem; border-radius:.35rem; }
  /* Sel di luar bulan ini TETAP ada sebagai kotak kosong: menyembunyikannya
     membuat sisa tanggal bergeser (terukur kolom 1-3 jadi 0px) dan nama hari
     tidak lagi sejajar dengan tanggalnya. */
  .kal-tgl { font-size:.8rem; justify-content:center; }
  .kal-titik { display:inline-flex; }
  /* Acara TIDAK lagi ditampilkan di dalam sel (tidak muat) — pindah ke daftar. */
  .kal-acara-baris { display:none; }
  .kal-sel.kal-pekan .kal-angka { color:#9aa5a0; }

  /* Daftar acara per tanggal (dirender oleh Blade setelah kisi). */
  .kal-daftar { display:grid; gap:.7rem; grid-template-columns:minmax(0, 1fr); }
  .kal-hari { border:1px solid var(--garis); border-radius:var(--r-kecil);
    background:var(--putih); padding:.55rem .7rem; }
  .kal-hari > h3 { margin:0 0 .35rem; font-size:.82rem; display:flex; gap:.45rem;
    align-items:center; flex-wrap:wrap; }
  .kal-hari > h3 .kal-angka { font-size:1rem; font-weight:700; }
  .kal-hari > h3 .kal-bulan { color:var(--pudar); font-weight:500; font-size:.76rem; }
  .kal-hari.kal-kini { border-color:var(--hijau-600); box-shadow:0 0 0 1px var(--hijau-600) inset; }
  .kal-hari .kal-acara { display:flex; gap:.5rem; align-items:flex-start; width:auto; height:auto;
    border-radius:var(--r-kecil); padding:.4rem .55rem; font-size:.85rem; margin-bottom:.3rem;
    position:static; /* 🔴 `white-space` bawaan .kal-acara = nowrap; tanpa normal di sini
       teks 539px tak bisa membungkus, kolom grid melebar jadi 621px, dan halaman
       meluber 264px di ponsel. */ white-space:normal; }
  .kal-hari .kal-acara:last-child { margin-bottom:0; }
  .kal-hari .kal-jam { flex:0 0 auto; font-weight:600; font-size:.78rem; opacity:.85; }
  .kal-hari .kal-nama { flex:1 1 auto; min-width:0; overflow-wrap:anywhere; }
  .kal-dua { grid-template-columns:1fr; }
  .kal-navigasi { width:100%; }
  .kal-navigasi .tombol { flex:1 1 auto; justify-content:center; }
}
/* Daftar acara per tanggal hanya untuk ponsel; di layar lebar acara ada DI DALAM
   sel kisi, jadi daftar ini disembunyikan agar tidak tampil dua kali. */
@media (min-width: 721px) { .kal-daftar { display:none; } }


/* ================================== surat jalan, jejak pantauan, baris turun */
.ttd-kisi { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; margin-top: 1.6rem; }
.ttd-kisi > div { border-top: 1px solid var(--garis); padding-top: .5rem; }
.ttd-kisi small { color: var(--pudar); }
.ttd-ruang { display: block; height: 58px; }
.ttd-kisi b { display: block; font-size: .86rem; border-top: 1px dotted var(--garis); padding-top: .25rem; }
@media (max-width: 620px) { .ttd-kisi { grid-template-columns: 1fr; gap: .8rem; } }

.jejak { margin: .5rem 0 0; padding: 0 0 0 .9rem; font-size: .78rem; color: var(--tinta-2); }
.jejak li { margin-bottom: .3rem; }
.baris-turun td { opacity: .55; }
.baris-turun .lencana.merah { opacity: 1; }
.ubah .jejak { list-style: disc; }

/* ======================================================================
   PERCAKAPAN (Messenger) — disusun seperti aplikasi pesan
   ----------------------------------------------------------------------
   Daftar ruang di kiri, percakapan di kanan. Nama kelas berawalan `wa-`
   supaya jelas ini satu sistem, bukan tumpukan kartu biasa.
   ====================================================================== */
/* ============================================= PERCAKAPAN — ukuran layar penuh

   Halaman percakapan mengisi SELURUH tinggi layar, bukan setinggi isinya.
   Sebelumnya .wa setinggi isi dan .wa-pesan dipaku height:min(62vh,560px),
   jadi di monitor besar percakapan menggantung di atas dan menyisakan ratusan
   piksel kosong di bawah — itu yang membuatnya terasa "nanggung".
   Rumus: 100dvh - kepala halaman - bilah nav bawah - tepi .isi. */

/* `100vh` dulu: peramban tanpa dukungan `dvh` (jadi `height` batal) membuat
   tinggi tubuh = setinggi isi, dan bilah bawah yang ikut aliran flex berhenti
   di tengah layar. */
body.wa-penuh { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }
/* Shell mengisi SISA ruang setelah bilah bawah, bukan setinggi layar penuh.
   Sisa ini dihitung peramban sendiri — itulah sebabnya bilah bawah di halaman
   ini dipindah ke dalam aliran flex (lihat `body.wa-penuh .nav-bawah`), bukan
   lagi `position: fixed` yang menutupi dasar layar tanpa diketahui isi. */
body.wa-penuh .shell { flex: 1 1 auto; height: auto; min-height: 0; }
body.wa-penuh .isi { display: flex; flex-direction: column; min-height: 0;
  /* Bilah bawah sudah DI LUAR area ini (baris flex sendiri), jadi tidak ada
     yang perlu disisakan — cukup jarak tepi halaman seperti desktop. */
  padding-bottom: var(--sp); }
body.wa-penuh .wa { flex: 1 1 auto; min-height: 0;
  grid-template-rows: minmax(0, 1fr); align-items: stretch; }
/* Di ponsel bilah bawah halaman obrolan TETAP `position: fixed` seperti halaman
   lain. Dulu ia dipindah ke aliran flex, dan itu membuat posisinya bergantung
   pada `100dvh`: di peramban yang menghitung dvh lebih pendek daripada layar
   nyata (Samsung Internet / WebView dalam-an), bilah berhenti 50-an px di atas
   dasar layar — keluhan "navbar naik ke atas" yang HANYA muncul di menu
   Message. Ruang untuk bilah kini disisakan di `.isi` memakai tinggi NYATA
   bilah (--tb-nav = 66px terukur), sebab itu dulu kolom tulis tertutup 49px
   saat masih dipaku --tb (44px). */
@media (max-width: 900px) {
  body.wa-penuh .isi { padding-bottom: calc(var(--tb-nav) + var(--sp)); }
}
.wa-sisi { display: flex; flex-direction: column; min-height: 0; }
.wa-atas { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .5rem .6rem; border-bottom: 1px solid var(--garis); }
.wa-atas b { font-size: .8rem; letter-spacing: .04em; text-transform: uppercase; color: var(--pudar); }
.wa-baru { display: flex; flex-direction: column; gap: .45rem; padding: .6rem;
  border-bottom: 1px solid var(--garis); background: var(--zebra);
  /* Dibatasi + bisa digulir: tanpa ini panel melar setinggi isinya (~700px,
     daftar peserta 29 nama) dan menyisakan hampir nol ruang untuk daftar
     percakapan di bawahnya. */
  max-height: min(62vh, 430px); overflow-y: auto; }
.wa-baru label { font-size: .78rem; color: var(--tinta-2); display: flex; flex-direction: column; gap: .2rem; }
.pilih { border: 1px solid var(--garis); border-radius: var(--r-kecil); background: var(--putih); }
.pilih-kepala { display: flex; gap: .4rem; align-items: center; padding: .4rem; border-bottom: 1px solid var(--garis); }
.pilih-kepala input[type="search"] { margin: 0; min-height: 34px; padding: .3rem .5rem; }
/* ---------- Select2 (pencarian di <select> panjang) ----------
   Lingkup peserta & rekan kini SATU kolom ber-Select2: kotak cari dibawa oleh
   perkakasnya sendiri, bukan kotak terpisah di atas <select>. Sebelumnya ada
   DUA kolom yang tampak sama (terukur 17 Okt 2026: cari 337x46 & select 337x45,
   bg/border/radius/font identik, tanpa ikon) sehingga pengguna mengira tak ada
   pencarian. Gaya di bawah menyetel Select2 agar setinggi & sebentuk isian
   Hub lain (min-height 42px, radius --r-kecil, border --garis). */
.pilih2 + .select2-container { width: 100% !important; margin-top: .35rem; }
.select2-container--default .select2-selection--single {
  min-height: 42px; height: auto; padding: .35rem .5rem; display: flex; align-items: center;
  border: 1px solid #ccd7d1; border-radius: var(--r-kecil); background: var(--putih); }
.select2-container--default .select2-selection--single:hover { border-color: #b6c4bd; }
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--hijau-600); outline: 2px solid var(--hijau-300); outline-offset: -1px; }
.select2-container--default .select2-selection--single .select2-selection__rendered {
  padding: 0; line-height: 1.35; color: var(--tinta); font-size: .875rem; }
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: #67766f; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 40px; right: .35rem; }
/* Kotak cari di dalam daftar turun: ikon kaca pembesar supaya jelas ia CARI,
   bukan isian biasa (perilaku ini yang dulu hilang). */
.select2-container--default .select2-search--dropdown .select2-search__field {
  min-height: 38px; padding: .4rem .6rem .4rem 2rem; border: 1px solid #ccd7d1;
  border-radius: var(--r-kecil); background: var(--zebra) no-repeat .55rem center;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235f6f68' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
  background-size: 15px 15px; font-size: .875rem; }
.select2-dropdown { border: 1px solid var(--garis); border-radius: var(--r-kecil);
  box-shadow: 0 10px 26px rgba(0, 0, 0, .12); font-size: .875rem; overflow: hidden; }
.select2-container--default .select2-results__option[aria-selected="true"] {
  background: var(--hijau-600); color: #fff; }
.select2-container--default .select2-results__option--highlighted[aria-selected] {
  background: var(--zebra); color: var(--tinta); }
.select2-container--default .select2-results__group { color: var(--tinta-2); font-weight: 600; }
/* Keterangan "tak ada yang cocok" ikut berbahasa Indonesia? Select2 menaruh
   teks bawaannya di sini; bahasanya diatur lewat opsi JS halaman ini. */
.pilih-aksi { display: flex; gap: .3rem; flex: none; }
/* Daftar bergulir: cukup tinggi untuk beberapa baris, tapi tidak memanjangkan
   panel "+ Baru" yang dipakai bersama formulir lain. */
.pilih-daftar { list-style: none; margin: 0; padding: .2rem; max-height: 178px; overflow-y: auto; }
.pilih-daftar li { margin: 0; }
.pilih-daftar li[hidden] { display: none; }
/* CATATAN: harus `.wa-baru .pilih-baris`, bukan `.pilih-baris` saja. Aturan
   `.wa-baru label { flex-direction: column }` (satu kelas + satu elemen) lebih
   spesifik daripada `.pilih-baris` (satu kelas), jadi tanpa ini setiap baris
   tersusun VERTIKAL: kotak centang tidak sebaris dengan nama dan tinggi baris
   melonjak 15px -> 92px (terukur). */
.wa-baru .pilih-baris { display: flex; flex-direction: row; align-items: center; gap: .5rem;
  margin: 0; padding: .35rem .45rem; border-radius: var(--r-kecil); cursor: pointer;
  font-weight: 400; font-size: .82rem; color: var(--tinta); }
.pilih-baris:hover { background: var(--hijau-100); }
/* Baris terpilih ditandai centang + latar, jadi pilihan tetap terlihat walau
   namanya sedang tersaring keluar dari daftar. */
.pilih-baris.centang { background: var(--hijau-100); }
.pilih-baris.centang .pilih-nama { font-weight: 700; }
.pilih-baris.centang::after { content: "✓"; margin-left: auto; color: var(--hijau-600); font-weight: 800; }
.wa-baru .pilih-nama { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-baru .pilih-baris small { flex: none; max-width: 45%; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--pudar); font-size: .72rem; font-weight: 400; }
.pilih-ringkas { margin: .35rem .5rem 0; font-size: .76rem; color: var(--hijau-700, var(--hijau-600)); font-weight: 600; }
.pilih-kosong { margin: .4rem .5rem; font-size: .8rem; color: var(--pudar); }
.wa-daftar { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.wa-ruang { min-height: 0; }
.wa-pesan { flex: 1 1 auto; height: auto; min-height: 0; overflow-y: auto; }
.wa-kepala-teks { min-width: 0; flex: 1 1 auto; }
.wa-kepala-teks b, .wa-kepala-teks small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-info { position: relative; flex: none; }
.wa-info > summary { list-style: none; cursor: pointer; }
.wa-peserta { position: absolute; right: 0; top: calc(100% + .3rem); z-index: 5; margin: 0;
  padding: .5rem .8rem; list-style: none; min-width: 180px; max-height: 260px; overflow-y: auto;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r-kecil);
  box-shadow: var(--bayang-2); font-size: .82rem; }
.wa-peserta li { padding: .18rem 0; }
/* Panel "Peserta" saat dibuka = satu kotak melayang berisi daftar peserta +
   form tambah peserta. Tanpa ini, form jatuh ke dalam baris kepala dan
   mendorong tombol semat/panel lain keluar layar. */
.wa-info[open] { position: absolute; right: 0; top: 100%; z-index: 6; display: flex;
  flex-direction: column; gap: .4rem; min-width: 250px; padding: .45rem .6rem;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r-kecil);
  box-shadow: var(--bayang-2); }
.wa-info[open] > summary { text-align: right; }
.wa-info[open] .wa-peserta { position: static; min-width: 0; max-height: 190px;
  padding: 0; border: 0; box-shadow: none; }
.wa-tambah-peserta { display: flex; gap: .35rem; align-items: center; border-top: 1px solid var(--garis-2); padding-top: .4rem; }
.wa-tambah-peserta .select2-container { flex: 1 1 auto; min-width: 140px; }
.wa-info .bantuan { margin: 0; font-size: .72rem; line-height: 1.35; }
/* Tombol kembali hanya berguna di ponsel (daftar jadi laci). */
.wa-kembali { display: none; flex: none; width: 36px; height: 36px; border: 0; background: none;
  font-size: 1.5rem; line-height: 1; color: var(--tinta-2); cursor: pointer; border-radius: 50%; }
.wa-kembali:hover { background: var(--hijau-100); }
.wa-ajak { display: grid; place-items: center; background: var(--zebra); }
.wa-ajak-dalam { max-width: 460px; padding: 1.5rem; }
.wa-cara { margin: .6rem 0; padding-left: 1.1rem; font-size: .88rem; color: var(--tinta-2); }
.wa-cara li { margin-bottom: .35rem; }

.wa { display: grid; grid-template-columns: minmax(0, 264px) minmax(0, 1fr); gap: .9rem; align-items: start; }
.wa-sisi { background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; }
.wa-cari { padding: .55rem; border-bottom: 1px solid var(--garis); }
.wa-cari input { min-height: 36px; }
.wa-daftar { display: flex; flex-direction: column; max-height: 68vh; overflow-y: auto; }
/* Daftar versi halaman /workspace/pesan: selebar kartu, bukan kolom sempit. */
.wa-daftar.lebar { max-height: none; background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; }
.wa-baris { display: flex; align-items: center; gap: .6rem; padding: .6rem .7rem; text-decoration: none; color: inherit; border-bottom: 1px solid var(--garis-2, #eef1ee); min-width: 0; }
.wa-baris:last-child { border-bottom: 0; }
.wa-baris:hover { background: var(--hijau-100); }
.wa-baris.ini { background: var(--hijau-l); }
.wa-avatar { flex: none; width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; background: var(--hijau-600, #15402f); color: #fff; font-weight: 700; font-size: .95rem; }
.wa-avatar.besar { width: 42px; height: 42px; }
.wa-baris-teks { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.wa-baris-teks b, .wa-baris-teks small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-baris-teks b { font-size: .9rem; }
.wa-baris-teks small { color: var(--pudar); font-size: .78rem; }
.wa-baris-meta { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: .2rem; font-size: .72rem; color: var(--pudar); }

.wa-ruang { display: flex; flex-direction: column; min-width: 0; background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; }
.wa-kepala { display: flex; align-items: center; gap: .65rem; padding: .6rem .8rem; border-bottom: 1px solid var(--garis); background: var(--zebra); }
.wa-kepala b { display: block; font-size: .95rem; }
.wa-kepala small { color: var(--pudar); font-size: .78rem; }
/* Papan pesan menggulir sendiri: kepala dan kotak tulis tetap di tempat. */
.wa-pesan { display: flex; flex-direction: column; gap: .35rem; padding: .85rem; background: #f3f5f2; overflow-y: auto; height: min(62vh, 560px); }
.wa-b { position: relative; max-width: 78%; align-self: flex-start; background: var(--putih); border: 1px solid var(--garis); border-radius: 14px 14px 14px 4px; padding: .45rem .8rem .3rem .65rem; box-shadow: 0 1px 1px rgba(16, 29, 24, .05); }
.wa-b.dia { align-self: flex-end; background: #dcf3dd; border-color: #c3e5c5; border-radius: 14px 14px 4px 14px; }
.wa-b.lanjut { margin-top: -.2rem; }
.wa-nama { display: block; font-size: .74rem; font-weight: 700; color: var(--hijau-700, #1b5139); margin-bottom: .1rem; }
.wa-teks { font-size: .9rem; overflow-wrap: anywhere; }
.wa-terjemah { margin-top: .3rem; padding-top: .25rem; border-top: 1px dashed var(--garis); font-size: .82rem; color: var(--tinta-2); }
.wa-jam { display: block; text-align: right; font-size: .66rem; color: var(--pudar); margin-top: .1rem; }
.wa-kirim-menunggu { opacity: .55; }
.wa-kosong { color: var(--pudar); font-size: .86rem; text-align: center; padding: 1rem; }
/* Alat per pesan (terjemahkan) disembunyikan di balik tombol titik-tiga. */
.wa-alat { position: absolute; top: .2rem; right: .3rem; }
.wa-alat > summary { list-style: none; cursor: pointer; color: var(--pudar); font-weight: 700; line-height: 1; padding: .1rem .3rem; border-radius: 4px; }
.wa-alat > summary::-webkit-details-marker { display: none; }
.wa-alat[open] { position: static; margin-top: .3rem; }
.wa-alat form { display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; }
.wa-kirim { display: flex; gap: .5rem; align-items: flex-end; padding: .55rem .65rem; border-top: 1px solid var(--garis); }
.wa-kirim textarea { flex: 1 1 auto; min-height: 40px; max-height: 132px; resize: none; }
.wa-kirim .tombol { flex: none; width: auto; min-height: 40px; padding: .5rem 1rem; }

/* --------------------------------------------------------------- Messenger baru
   Tambahan dari cara kerja Lark (kategori, balas, reaksi, semat, sebut, sunting,
   tarik, terjadwal, lampiran) yang dirasakan seperti WhatsApp (lencana, centang
   dibaca, foto/berkas/suara).

   Catatan penyusunan: `.wa-baris` sekarang <div> berisi <a> + <form>, karena
   <form> di dalam <a> tidak sah dan tombol sematnya jadi tak bisa diklik. Karena
   itu susunan flex-nya pindah ke `.wa-baris-isi`. */
.wa-baris-isi { display: flex; align-items: center; gap: .6rem; flex: 1 1 auto; min-width: 0;
  text-decoration: none; color: inherit; }
.wa-baris { position: relative; }
/* Tombol semat percakapan: tampil saat disentuh/di-hover saja supaya daftar
   tidak penuh ikon, tapi tetap ada di layar sentuh (opacity, bukan display none). */
.wa-semat-form { flex: none; }
.wa-semat-form .tombol { padding: .15rem .3rem; min-height: 0; opacity: .35; }
.wa-baris:hover .wa-semat-form .tombol, .wa-semat-form .tombol:focus { opacity: 1; }

/* Penyaring kategori (Lark: belum dibaca/pribadi/grup/sebutan/tersemat).
   6 pil butuh ~476px sedangkan panelnya hanya 262px di desktop (356px di ponsel),
   jadi dengan `overflow-x:auto` dua pil terakhir TERPOTONG tanpa tanda apa pun —
   kategori "tersemat" praktis tak bisa ditemukan. Karena bilah ini hanya 1-2 baris
   dan pemilihnya sedikit, membungkus (`flex-wrap`) lebih baik daripada menggeser:
   semua pilihan terlihat sekaligus, tidak ada yang disembunyikan, dan tak perlu
   petunjuk "geser ke kanan" yang di layar sentuh sering tak terbaca. */
.wa-saring { display: flex; flex-wrap: wrap; gap: .3rem;
  padding: .45rem .55rem; border-bottom: 1px solid var(--garis); }
.wa-pil { flex: none; padding: .22rem .6rem; border-radius: 999px; font-size: .76rem;
  text-decoration: none; color: var(--tinta-2); background: var(--zebra);
  border: 1px solid var(--garis-2, #eef1ee); white-space: nowrap; }
/* (mekanisme label ringkas sudah dihapus: label sama di semua lebar) */
.wa-pil:hover { background: var(--hijau-100); }
.wa-pil.ini { background: var(--hijau-600, #15402f); border-color: transparent; color: #fff; font-weight: 600; }

/* Lencana belum dibaca + sebutan (WhatsApp: angka hijau, Lark: @ penting). */
.wa-lencana { display: inline-grid; place-items: center; min-width: 20px; height: 20px;
  padding: 0 .35rem; border-radius: 999px; background: var(--hijau-600, #15402f); color: #fff;
  font-size: .7rem; font-weight: 700; }
.wa-lencana.sebut { background: #b91c1c; }
.wa-semat { font-size: .72rem; }
.wa-baris.belum .wa-baris-teks b { font-weight: 800; }

/* Balasan berkutip. */
.wa-kutip { display: block; margin-bottom: .28rem; padding: .2rem .45rem; border-left: 3px solid var(--hijau-600, #15402f);
  background: rgba(21, 64, 47, .07); border-radius: 4px; text-decoration: none; color: inherit; font-size: .78rem; }
.wa-kutip b { display: block; font-size: .72rem; color: var(--hijau-700, #1b5139); }
.wa-kutip span { color: var(--tinta-2); overflow-wrap: anywhere; }

/* Lampiran: foto, berkas, suara. */
.wa-foto { display: block; margin: -.1rem 0 .25rem; }
.wa-foto img { display: block; max-width: 100%; max-height: 260px; border-radius: 8px; cursor: zoom-in; }
.wa-berkas { display: flex; align-items: center; gap: .45rem; padding: .35rem .45rem; margin-bottom: .2rem;
  border: 1px solid var(--garis); border-radius: 8px; background: var(--putih); text-decoration: none; color: inherit; }
.wa-berkas-teks { display: flex; flex-direction: column; min-width: 0; }
.wa-berkas-teks b { font-size: .82rem; overflow-wrap: anywhere; }
.wa-berkas-teks small { color: var(--pudar); font-size: .7rem; }
.wa-suara audio { height: 34px; max-width: 230px; }

/* Reaksi emoji di bawah gelembung. */
.wa-reaksi { display: flex; flex-wrap: wrap; gap: .2rem; margin-top: .25rem; }
.wa-rx { display: inline-flex; align-items: center; gap: .15rem; padding: .05rem .35rem; font-size: .78rem;
  border: 1px solid var(--garis); border-radius: 999px; background: #fff; cursor: pointer; }
.wa-rx b { font-size: .68rem; color: var(--tinta-2); }
.wa-rx.saya { border-color: var(--hijau-600, #15402f); background: #e6f4e8; }
.wa-rx-baris { display: flex; flex-wrap: wrap; gap: .15rem; align-items: center; }

/* Baris bawah gelembung: sematan, "disunting", jam, centang dibaca. */
.wa-bawah { display: flex; align-items: center; justify-content: flex-end; gap: .3rem; margin-top: .1rem; }
.wa-bawah .wa-jam { margin: 0; }
.wa-suntingan { font-size: .66rem; color: var(--pudar); font-style: italic; }
.wa-tanda { font-size: .68rem; color: var(--pudar); letter-spacing: -.05em; }
.wa-tanda.dibaca { color: #1d7fd6; }
.wa-sebut { background: #fff2a8; color: inherit; border-radius: 3px; padding: 0 .12rem; }
.wa-b.sebut { box-shadow: 0 0 0 2px rgba(185, 28, 28, .35); }

/* Pita pesan yang disematkan + bilah balasan di atas kotak tulis. */
.wa-semat-pita { display: flex; align-items: center; gap: .4rem; padding: .35rem .7rem;
  background: #fff8e1; border-bottom: 1px solid var(--garis); font-size: .8rem; }
.wa-semat-isi { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--tinta-2); }
.wa-balas-bilah { display: flex; align-items: center; gap: .5rem; padding: .4rem .65rem;
  border-top: 1px solid var(--garis); background: var(--zebra); }
.wa-balas-teks { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.wa-balas-teks b { font-size: .74rem; color: var(--hijau-700, #1b5139); }
.wa-balas-teks small { color: var(--tinta-2); font-size: .76rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Alat per pesan versi baru: beberapa <form> bertumpuk dalam satu panel. */
.wa-alat-isi { display: flex; flex-direction: column; gap: .3rem; }
.wa-alat-isi .tombol { width: auto; }
.wa-jenis { display: flex; gap: .7rem; font-size: .78rem; }
.wa-jenis label { flex-direction: row; align-items: center; gap: .25rem; display: flex; }

/* Panel lampiran + rekam suara. */
.wa-lampir { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  padding: .5rem .65rem; border-top: 1px solid var(--garis); background: var(--zebra); }
.wa-lampir .bantuan { flex: 1 1 100%; margin: 0; }
.wa-lampir-form { display: flex; gap: .4rem; align-items: center; }
.wa-suara-rekam { display: flex; gap: .4rem; align-items: center; }
.wa-kirim .wa-ikon { min-height: 40px; width: auto; padding: .4rem .7rem; font-size: 1.05rem; }
.wa-lebih { align-self: center; margin: 0 auto .35rem; }

/* Lihat foto besar (ala WhatsApp). */
.wa-lihat-foto { border: 0; padding: 0; background: transparent; max-width: 96vw; max-height: 96vh; }
.wa-lihat-foto img { display: block; max-width: 96vw; max-height: 86vh; border-radius: 8px; }

/* ======================================================================
   PROFIL — kartu identitas + daftar nilai, bukan tabel polos
   ====================================================================== */
.profil-hero { display: flex; align-items: center; gap: 1rem; padding: 1.05rem 1.15rem; background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); box-shadow: var(--bayang); margin-bottom: var(--ruang); }
.profil-avatar { flex: none; width: 62px; height: 62px; border-radius: 50%; display: grid; place-items: center; background: linear-gradient(160deg, var(--hijau-800, #15402f), #1b5139); color: #fff; font-size: 1.35rem; font-weight: 700; }
.profil-hero > .identitas { min-width: 0; }
.profil-hero h2 { margin: 0 0 .15rem; font-size: 1.15rem; overflow-wrap: anywhere; }
.profil-hero p { color: var(--pudar); font-size: .86rem; overflow-wrap: anywhere; }
.profil-lencana { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .45rem; }
.identitas-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; }
.identitas-grid > div { padding: .7rem .9rem; border-bottom: 1px solid var(--garis-2, #eef1ee); min-width: 0; }
.identitas-grid small { display: block; font-size: .68rem; text-transform: uppercase; letter-spacing: .07em; color: var(--pudar); font-weight: 700; margin-bottom: .12rem; }
.identitas-grid b { font-weight: 600; font-size: .9rem; overflow-wrap: anywhere; }
.rekening-kartu { display: flex; flex-direction: column; gap: .2rem; }
.rekening-kartu b { font-variant-numeric: tabular-nums; }
/* /profil — satu baris riwayat = satu entri; garis pemisah supaya entri
   tidak menyatu jadi hamparan input yang tak terbaca. */
.form-kelompok-riwayat { margin: 1.15rem 0 .1rem; font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--pudar); }
.form-kelompok-riwayat:first-of-type { margin-top: .3rem; }
.baris-riwayat { border-top: 1px solid var(--garis-2, #eef1ee); padding-top: .75rem; margin-top: .75rem;
  grid-template-columns: repeat(4, minmax(0, 1fr)); }
.baris-riwayat:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
/* Baris baru (hasil "Tambah baris"): isian putus-putus supaya jelas belum
   tersimpan, dan tombolnya "Batal" bukan "Hapus". */
.baris-baru > label > input { border-style: dashed; }
.baris-riwayat > .baris-aksi { grid-column: 1 / -1; display: flex; justify-content: flex-end;
  gap: .5rem; margin-top: -.15rem; }
.kosong-riwayat { margin: .55rem 0 .2rem; font-size: .82rem; }
.tambah-baris { margin-top: .7rem; }
.simpan-riwayat { margin-top: 1.1rem; padding-top: .9rem;
  border-top: 1px solid var(--garis-2, #eef1ee); }

/* Kartu "Hapus data profil": keterangan di kiri, tombol di kanan. Dulu tombol
   dan kalimat penjelasnya berdiri sebaris tanpa aturan tata letak sehingga
   keterangannya menempel ke tombol. */
.hapus-data { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .6rem 1rem; margin-top: 1rem; }
.hapus-data > div { flex: 1 1 18rem; min-width: 0; }
.hapus-data b { display: block; font-size: .9rem; }
.hapus-data .pudar { margin: .2rem 0 0; font-size: .82rem; line-height: 1.5; }
.hapus-data > form { flex: 0 0 auto; margin: 0; }
@media (max-width: 560px) {
  /* Tombol tidak dilebarkan penuh: di ponsel selebar 320px tombol penuh
     terbaca sebagai kolom panjang, bukan tindakan. */
  .hapus-data { flex-direction: column; align-items: stretch; }
  /* flex-basis 18rem berlaku sebagai TINGGI saat arahnya kolom → keterangan
     mendapat 288px ruang kosong dan kartu jadi menjulang. */
  .hapus-data > div { flex: 0 0 auto; }
  .hapus-data > form { align-self: flex-start; }
  .hapus-data > form > .tombol { min-height: 44px; }
}
/* Satu entri = 4 isian: sebaris di layar lebar, 2x2 di tablet, satu kolom di
   ponsel — tanpa baris yang menggantung 1 isian sendirian. */
@media (max-width: 900px) { .baris-riwayat { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) {
  .baris-riwayat { grid-template-columns: 1fr; padding-top: .9rem; margin-top: .9rem; }
}

/* ======================================================================
   KATALOG BARANG — disusun seperti toko daring, plus saldo Agrinas
   ====================================================================== */
.saldo-kartu { display: flex; flex-wrap: wrap; gap: .55rem 1.2rem; align-items: center; justify-content: space-between; background: linear-gradient(160deg, var(--hijau-800, #15402f), #1b5139); color: #eef6f0; border-radius: var(--r); padding: .8rem 1rem; margin-bottom: var(--ruang); }
.saldo-kartu small { display: block; text-transform: uppercase; letter-spacing: .08em; font-size: .64rem; opacity: .88; font-weight: 700; }
.saldo-kartu b { display: block; font-size: clamp(1.3rem, 1rem + 1.2vw, 1.7rem); font-variant-numeric: tabular-nums; line-height: 1.2; }
.saldo-kartu p { color: #cfe0d7; font-size: .74rem; line-height: 1.4; margin: .15rem 0 0; }
.saldo-kartu .tombol { background: #eef6f0; color: #15402f; border-color: transparent; }
/* Tombol ikon keranjang di kepala: lencana jumlah menempel di sudutnya (pola
   toko daring). `.lencana-notif` memang sudah ada untuk lencana di atas lencana
   — di sini bingkainya putih, bukan hijau tua seperti di bilah sisi. */
.tombol-baris .posisi-lencana { position: relative; }
.tombol-baris .posisi-lencana .lencana-notif { border-color: var(--putih); background: var(--merah, #b91c1c); }
.katalog-baris { display: flex; flex-wrap: wrap; gap: .6rem; align-items: flex-end; margin-bottom: .9rem; }
.katalog-baris label { flex: 1 1 180px; }
/* Kisi produk. Lebar minimum kartu diturunkan dari 170px -> 150px: di layar 390px
   dan 1440px keduanya jadi satu kolom lebih banyak tanpa kartu terasa sempit
   (terukur 390px: 156px -> 2 kolom tetap; 1440px: 5 -> 6 kolom). */
.katalog-kisi { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); gap: .7rem; }
/* Keterangan kosong adalah anak kisi: tanpa grid-column ia hanya selebar satu
   kartu, jadi teks "tengah" tampak rata kiri. */
.katalog-kisi > p.kosong { grid-column: 1 / -1; }
/* Kartu produk. Seluruh ukuran di bawah ini diukur, bukan ditebak: kartu lama
   setinggi 472px — 3/5 di antaranya hanya hiasan (kotak jenjang grosir 71px +
   isyarat berulang 16px + jarak dalam). Kartu toko daring memuat: gambar, nama,
   harga, jenjang, stok, aksi — tanpa bingkai berlebih. */
.kat-kartu { display: flex; flex-direction: column; background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); overflow: hidden; box-shadow: var(--bayang); transition: box-shadow .12s; }
.kat-kartu:hover { box-shadow: 0 6px 18px -8px rgba(16, 29, 24, .28); }
.kat-gambar { position: relative; height: clamp(7rem, 32vw, 9.5rem); background: var(--zebra); display: grid; place-items: center; overflow: hidden; }
.kat-gambar img { width: 100%; height: 100%; object-fit: cover; }
.kat-inisial { font-size: 2.2rem; font-weight: 800; color: var(--hijau-600, #15402f); opacity: .45; }
.kat-lencana { position: absolute; top: .4rem; left: .4rem; background: rgba(21, 64, 47, .86); color: #fff; font-size: .66rem; font-weight: 700; padding: .15rem .4rem; border-radius: 6px; }
.kat-lencana.habis { background: rgba(150, 30, 30, .88); }
.kat-badan { padding: .55rem .65rem .65rem; display: flex; flex-direction: column; gap: .2rem; flex: 1 1 auto; }
/* Nama barang: dipangkas 2 baris. Sebelumnya `min-height: 2.3em` membuat SETIAP
   kartu menanggung tinggi nama terpanjang di kisi, dan nama panjang tumbuh
   bebas (kartu ponsel 439-493px, tidak seragam) sehingga baris kisi terlihat
   bergerigi. `min-height` dihapus supaya kartu pendek tetap pendek. */
.kat-badan h3 { font-size: .84rem; line-height: 1.28; margin: 0; font-weight: 600;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kat-harga { font-size: 1rem; font-weight: 800; color: var(--hijau-700, #15402f); font-variant-numeric: tabular-nums; line-height: 1.25; }
.kat-harga small { font-weight: 600; color: var(--pudar); font-size: .7rem; }
.kat-sisa { font-size: .72rem; color: var(--pudar); }
/* Lencana "Hemat" di pojok kanan atas gambar — hanya muncul bila ada jenjang
   grosir yang benar-benar lebih murah dari harga satuan. */
.kat-hemat { position: absolute; top: .4rem; right: .4rem; background: #c2410c; color: #fff;
  font-size: .66rem; font-weight: 800; padding: .15rem .4rem; border-radius: 6px; }
/* Kartu produk yang stoknya habis: gambar diredupkan, bukan disembunyikan —
   pembeli tetap bisa melihat barangnya. */
.kat-kartu.habis .kat-gambar img { filter: grayscale(.55) opacity(.75); }
/* Daftar jenjang harga grosir di kartu: PIL-nya ringkas, disusun mendatar dan
   MEMBUNGKUS (bukan kotak oranye bertumpuk). Isi tiap pil = "5+" + harga, sama
   seperti penanda grosir di toko daring. Tinggi kartu turun ~50px dan lebarnya
   tidak lagi terpotong di kartu 156px. */
.kat-grosir { list-style: none; margin: .1rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .2rem; }
.kat-grosir li { display: inline-flex; align-items: baseline; gap: .22rem;
  background: #fff7ed; border: 1px solid #fed7aa; border-radius: 999px;
  padding: .04rem .35rem; font-size: .68rem; color: #9a3412; font-variant-numeric: tabular-nums; }
.kat-grosir b { font-weight: 800; }
/* Baris aksi kartu katalog: kolom jumlah MELAR mengikuti lebar kartu, tombol
   keranjang tinggal ikon persegi. Sebelumnya input dipaku `width: 4.6rem`
   (terukur 74px di form 180px — sisa 100px kosong) dan tombolnya bertulisan
   "Keranjang" sehingga memakan hampir separuh lebar kartu.
   Tinggi disamakan (40px) supaya dasar keduanya rata. */
.kat-aksi { margin-top: auto; padding-top: .45rem; }
/* Satu variabel tinggi untuk kolom jumlah & tombol: tanpa ini keduanya berbeda
   (`stretch` ikut baris terbesar -> isian 51px, tombol 40px, dasar tidak rata).
   40px (bukan 42px): di kartu 150px, 42px membuat tombol keranjang tampak
   berat; 40px masih di atas ambang sasaran sentuh 36px dan menyisakan ruang. */
.kat-aksi form { --t: 40px; display: flex; gap: .45rem; align-items: center; }
.kat-aksi input[type="number"] { flex: 1 1 auto; width: auto; min-width: 0;
  height: var(--t); min-height: 0; margin: 0; }
.kat-aksi .tombol-ikon { flex: 0 0 auto; width: var(--t); height: var(--t);
  min-height: 0; padding: 0;
  /* Aturan global `input + .tombol { margin-top: .7rem }` menambah 11.2px di
     atas tombol ini (ia mengikuti isian jumlah di dalam formulirnya) sehingga
     dasar tombol meleset 5.6px dari dasar isian. Di baris flex, jarak diatur
     `gap` — margin itu murni merusak. */
  margin: 0; }

@media (max-width: 860px) {
  /* Ponsel: daftar ruang jadi pita mendatar supaya percakapan tetap lapang. */
  .wa { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
  /* Halaman DAFTAR: percakapan lama tak ditampilkan, daftarnya yang penuh. */
  .wa-sendiri .wa-ajak { display: none; }
  /* Halaman PERCAKAPAN: sisi kiri jadi LACI penuh yang dibuka tombol ‹,
     bukan pita mendatar (pita mendatar memakan ruang vertikal untuk daftar
     yang sedang tidak dipakai). */
  .wa-percakapan .wa-sisi { position: fixed; inset: 0; z-index: 60; border-radius: 0;
    width: 100%; transform: translateX(-102%); transition: transform .18s ease-out; }
  .wa-percakapan .wa-sisi.buka { transform: none; }
  .wa-laci.buka { position: fixed; inset: 0; background: rgba(16, 29, 24, .45); z-index: 55; }
  .wa-kembali { display: block; }
  .wa-b { max-width: 88%; }
  /* ---- Penyaring kategori: SATU BARIS di layar sempit ----
     Lima pil dengan label penuh butuh ±364px; layar 390px hanya menyisakan
     ±372px setelah padding, dan 360px GAGAL — "Semat"/"Disematkan" jatuh ke
     baris kedua dan menyisakan ruang kosong di kanannya (itu yang terlihat
     berantakan). Dua langkah:
     1. label dipendekkan (Belum / Semat) -> ±310px: muat satu baris di 360px;
     2. `nowrap` + `overflow-x: auto` sebagai jaring pengaman bila kelak ada
        kategori baru — pil berikutnya bisa DIGESER, bukan disembunyikan ke
        baris kedua. Scrollbar disembunyikan supaya tidak menambah tinggi. */
  .wa-saring { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    -ms-overflow-style: none; gap: .28rem; padding: .45rem .5rem; }
  .wa-saring::-webkit-scrollbar { display: none; }
  /* Kelima label dipakai UTUH ("Belum dibaca", "Disematkan") — tidak ada versi
     ringkas. Supaya tetap muat SATU baris di 320px, pilnya dirapatkan:
     padding .6rem -> .32rem, huruf .76rem -> .68rem, sela .28rem -> .24rem.
     Padding VERTIKAL tidak diubah, jadi tinggi sentuh tetap nyaman.
     `nowrap` + `overflow-x:auto` di atas tetap jadi jaring pengaman. */
  .wa-saring { gap: .24rem; padding: .45rem .4rem; }
  .wa-pil { flex: 0 0 auto; padding: .22rem .32rem; font-size: .68rem; }
  .katalog-kisi { grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); }
}

/* Gulir-tak-berujung katalog: penanda "muat lagi" + penutup akhir daftar. */
.katalog-lagi { display: flex; flex-direction: column; align-items: center; gap: .4rem;
  margin-top: 1rem; }
.katalog-lagi .tombol { min-width: 11rem; }
/* Saat gulir sedang mengambil halaman berikutnya: tombolnya berdenyut, supaya
   pengguna tahu gulirannya sedang bekerja dan tidak menggulir sia-sia. */
.katalog-lagi.memuat .tombol { opacity: .6; pointer-events: none; animation: katalog-denyut 1s ease-in-out infinite; }
@keyframes katalog-denyut { 0%, 100% { opacity: .45; } 50% { opacity: .9; } }
.katalog-habis { display: block; text-align: center; margin-top: 1rem; font-size: .82rem; }

/* Pilihan kanal pembayaran di checkout: kotak radio bawaan peramban tampak
   seperti daftar polos; ini menjadikannya kartu pilihan yang bisa ditekan. */
.pilihan-bayar { border: 0; padding: 0; margin: 0 0 .8rem; }
.pilihan-bayar legend { font-size: .74rem; text-transform: uppercase; letter-spacing: .07em; color: var(--pudar); font-weight: 700; margin-bottom: .35rem; }
.pilihan-bayar label.centang { align-items: flex-start; padding: .55rem .65rem; border: 1px solid var(--garis); border-radius: var(--r-kecil); margin-bottom: .4rem; cursor: pointer; }
.pilihan-bayar label.centang:hover { border-color: var(--hijau-500); background: var(--hijau-100); }
.pilihan-bayar label.centang input { margin-top: .25rem; }
.pilihan-bayar label.centang span { font-size: .86rem; line-height: 1.4; }
.pilihan-bayar label.centang small { display: block; font-size: .76rem; }

/* ======================================================================
   INVOICE — lembar yang bisa dicetak/disimpan PDF dari peramban
   ====================================================================== */
.invoice-lembar { background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r); padding: 1.4rem 1.5rem; max-width: 820px; }
.invoice-kepala { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; border-bottom: 2px solid var(--hijau-600, #15402f); padding-bottom: .8rem; margin-bottom: .9rem; }
.invoice-kepala h2 { margin: 0; font-size: 1.2rem; }
.invoice-nomor { text-align: right; font-variant-numeric: tabular-nums; }
.invoice-nomor b { display: block; font-size: 1.05rem; }
.invoice-pihak { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: .4rem 1.2rem; margin-bottom: .9rem; }
.invoice-pihak small { display: block; text-transform: uppercase; letter-spacing: .06em; font-size: .68rem; color: var(--pudar); font-weight: 700; }
.invoice-total { text-align: right; font-size: 1.05rem; font-weight: 800; padding-top: .5rem; }
.invoice-catatan { margin-top: .9rem; font-size: .8rem; color: var(--tinta-2); }
.invoice-lencana { display: inline-block; padding: .18rem .5rem; border-radius: 6px; font-size: .74rem; font-weight: 700; background: var(--zebra); border: 1px solid var(--garis); }

@media print {
  /* Cetak: hanya lembarnya, tanpa menu/hiasan halaman. */
  .sisi, .nav-bawah, .modul-nav, .kepala, .tombol, .tombol-baris, .pesan, #hub-proses, #hub-muat-tengah { display: none !important; }
  .shell { display: block; }
  .isi { margin: 0; padding: 0; }
  .invoice-lembar { border: 0; max-width: none; padding: 0; }
  body { background: #fff; }
  /* Bawaan semua halaman cetak: A4. Halaman nota menimpanya sendiri dengan
     kertas struk 80mm (`<style id="gaya-kertas">`), karena aturan `@page` yang
     dibaca belakangan yang dipakai peramban. */
  @page { size: A4; margin: 12mm; }

  /* NOTA — dicetak ke PRINTER KASIR (kertas gulung 80mm), bukan A4.
     Ukuran kertas sendiri diatur dari halaman nota (`<style id="gaya-kertas">`),
     sebab halaman lain tetap memakai A4 dan `@page` di sini berlaku global.
     Tiga cacat yang diperbaiki di blok ini:
     1. Kop koperasi TIDAK tercetak, karena `.kepala` di atas disembunyikan
        untuk semua halaman dan kop nota memakai kelas yang sama.
     2. Kolom nota berantakan: lima kolom di kertas 74mm memotong nama barang
        dan memaksa angka turun baris. Tabelnya kini DUA kolom (barang |
        subtotal) dengan jumlah × harga di bawah nama.
     3. Total/Dibayar/Kembalian dulu `<tfoot>` ber-colspan; sekarang blok
        `.nota-total` — lurus di struk maupun di layar ponsel. */
  .nota-cetak { border: 0; box-shadow: none; padding: 0; }
  /* Kop struk: RATA TENGAH dan satu blok (bukan flex dua kolom seperti layar).
     Di kertas 74mm, kop dua kolom memaksa nama koperasi terbelah dua baris
     sementara tombol cetak sudah disembunyikan — sisa ruangnya kosong. */
  .nota-cetak .kepala { display: block !important; text-align: center;
    border-bottom: 1px solid #000; padding: 0 0 .2mm; margin: 0 0 1.2mm; }
  .nota-cetak .nota-kop h1 { font-size: 7.5pt; line-height: 1.2; margin: 0 0 .3mm;
    text-transform: uppercase; letter-spacing: 0; }
  .nota-cetak .nota-kop p { font-size: 6.8pt; margin: 0; color: #000; }
  .nota-cetak .nota-kop .logo-nota { width: 20mm; margin: 0 auto .9mm; }
  .nota-cetak .bantuan { display: none; }
  .nota-cetak .rincian { margin: .6mm 0 1.4mm; gap: 0 .8mm; }
  .nota-cetak .rincian dt, .nota-cetak .rincian dd { font-size: 7pt; line-height: 1.35; }
  .nota-cetak .rincian dt { color: #000; }
  /* Padding/margin negatifnya trik "tabel selebar layar" di ponsel; di kertas
     ia membuat blok 6px lebih lebar dari halaman (terukur 805/794) sehingga
     tepi kanan angka terpotong. Nolkan saat cetak. */
  .nota-cetak .tabel-bungkus { overflow: visible; border: 0; border-radius: 0;
    padding: 0; margin: 0; }
  .nota-cetak table { width: 100%; table-layout: fixed; font-size: 7.5pt; }
  /* Selektor diperkuat: `.tabel-bungkus td` (didefinisikan SETELAH blok ini)
     memakai specificity sama dan menang, sehingga baris cetak setinggi 47px. */
  .nota-cetak table th, .nota-cetak table td { padding: .3mm .6mm;
    white-space: normal; line-height: 1.3; vertical-align: top; }
  .nota-cetak table thead th { border-bottom: .2mm solid #000; font-size: 6.8pt;
    text-transform: uppercase; letter-spacing: .03em; }
  .nota-cetak table thead th:nth-child(1) { width: 70%; }
  .nota-cetak table thead th:nth-child(2) { width: 30%; }
  .nota-cetak .nota-rinci { display: block; font-size: 6.5pt; }
  .nota-cetak .lencana { padding: 0 .6mm; font-size: 6pt; border: 0; }
  .nota-cetak tr { break-inside: avoid; }
  .nota-cetak .nota-total { margin: 1.2mm 0 0; font-size: 8pt; }
  .nota-cetak .nota-total div { padding: .3mm 0; }
  .nota-cetak .nota-total div:first-child { border-top: .2mm solid #000;
    padding-top: .8mm; }
  .nota-cetak .nota-total dt, .nota-cetak .nota-total dd { font-size: 8pt; }
  .nota-cetak .nota-total div:first-child dd { font-size: 9.5pt; font-weight: 700; }
  .nota-cetak .nota-terima { font-size: 6.8pt; text-align: center;
    margin: 1.6mm 0 0; }

  /* A4 (arsip): ruangnya lega, jadi huruf dan kop dibesarkan kembali. */
  body.kertas-a4 .nota-cetak { max-width: none; }
  body.kertas-a4 .nota-cetak .kepala { display: flex !important; text-align: left;
    align-items: flex-start; justify-content: space-between; gap: 1rem; }
  body.kertas-a4 .nota-cetak .nota-kop h1 { font-size: 15pt; }
  body.kertas-a4 .nota-cetak .nota-kop .logo-nota { width: 26mm; margin-left: 0; }
  body.kertas-a4 .nota-cetak .nota-kop p,
  body.kertas-a4 .nota-cetak .rincian dt,
  body.kertas-a4 .nota-cetak .rincian dd,
  body.kertas-a4 .nota-cetak .nota-terima { font-size: 9.5pt; }
  body.kertas-a4 .nota-cetak table { font-size: 9.5pt; }
  body.kertas-a4 .nota-cetak table th,
  body.kertas-a4 .nota-cetak table td { padding: .2rem .35rem; }
  body.kertas-a4 .nota-cetak table thead th { font-size: 9pt; }
  body.kertas-a4 .nota-cetak .nota-rinci { font-size: 8.5pt; }
  body.kertas-a4 .nota-cetak .nota-total { font-size: 10pt; margin-top: .6rem; }
  body.kertas-a4 .nota-cetak .nota-total dt,
  body.kertas-a4 .nota-cetak .nota-total dd { font-size: 10pt; }
  body.kertas-a4 .nota-cetak .nota-total div:first-child dd { font-size: 12pt; }
}

/* ---------------- nota di LAYAR (dan di ponsel sebelum dicetak)
   Blok total sengaja flex, bukan tabel: label dan angka satu baris pada lebar
   apa pun, dan angkanya rata kanan satu kolom (tabular-nums). */
/* Judul kolom mengikuti ISI-nya: nama barang rata kiri, uang rata kanan.
   `<th>` bawaannya rata tengah, jadi judul "Subtotal" melayang di atas
   angka yang rata kanan. */
/* Kop nota RATA TENGAH dengan logo di atas nama. Nota dibaca sebagai lembar
   resmi, bukan kepala halaman aplikasi yang dua kolom. `.tenang` bawaannya
   nowrap + elipsis (untuk kepala halaman lain) — di kop nota dibiarkan
   membungkus supaya alamat tidak terpotong. */
/* Kop nota jadi satu kolom di TENGAH (logo, nama, wilayah, lalu tombol di
   bawahnya). Dua kolom bawaan `.kepala` menaruh kop di kiri dan tombol di
   kanan, sehingga "tengah" hanya berlaku untuk separuh halaman. */
.nota-kop { flex-direction: column; align-items: center; gap: .6rem; text-align: center; }
.nota-kop .logo-nota { display: block; width: 84px; height: auto; margin: 0 auto .45rem; }
.nota-kop .tenang { white-space: normal; overflow: visible; text-overflow: clip; }
.nota-item th:first-child { text-align: left; }
.nota-item th:last-child { text-align: right; }
.nota-item td .nota-nama { display: block; }
.nota-item .nota-rinci { display: block; }
.nota-item tr.baris-gratis td { color: var(--hijau-700, #186d3f); }
.nota-item tr.baris-diskon td { color: var(--hijau-700, #186d3f); }
.nota-total { margin: .9rem 0 0; padding: .7rem .8rem; border-radius: var(--r-kecil);
  background: var(--zebra); display: grid; gap: .3rem; max-width: 22rem;
  margin-left: auto; }
.nota-total > div { display: flex; align-items: baseline; gap: 1rem;
  justify-content: space-between; }
.nota-total dt { color: var(--tinta-2); font-size: .9rem; }
.nota-total dd { margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
.nota-total > div:first-child dt { font-weight: 600; color: var(--tinta); }
.nota-total > div:first-child dd { font-size: 1.25rem; font-weight: 700; }
.nota-terima { font-size: .85rem; color: var(--tinta-2); text-align: center;
  margin: 1rem 0 0; }
@media (max-width: 720px) {
  .nota-total { max-width: none; margin-left: 0; }
  /* Nota tetap TABEL di ponsel. Pola kartu `.tabel-bungkus td[data-l]`
     mengubah tiap sel jadi label + nilai bertumpuk — untuk nota itu membuat
     satu baris barang setinggi 120px berisi kata "BARANG" dan "SUBTOTAL".
     Nota dibaca sebagai lembar/struk, jadi bentuk tabelnya dipertahankan. */
  .nota-cetak .tabel-bungkus table { display: table; }
  /* `tbody` = table-row-group, BUKAN `display:table`: sebagai tabel sendiri ia
     melepas kolomnya dari `<thead>`, sehingga lebar kolom barang/subtotal di
     judul dan di baris isi berbeda (terukur: judul 211/91px, sel 88/47px —
     angka rupiah berhenti di tengah kertas). */
  .nota-cetak .tabel-bungkus tbody { display: table-row-group; }
  .nota-cetak .tabel-bungkus thead { display: table-header-group; }
  .nota-cetak .tabel-bungkus tr { display: table-row; border: 0; margin: 0;
    padding: 0; box-shadow: none; background: none !important; }
  .nota-cetak .tabel-bungkus td { display: table-cell; padding: .5rem .2rem; }
  /* `<th>` WAJIB tetap table-cell di sini. Aturan kartu ponsel mengubahnya
     jadi `display:block`, dan lebar kertas 80mm (±302px) juga memicu media
     query itu saat mencetak: baris judul keluar dari kisi tabel, kolom
     Subtotal menyempit, angkanya tidak lagi lurus di bawah judulnya. */
  .nota-cetak .tabel-bungkus th { display: table-cell; }
  /* Nama barang rata kiri, uang rata kanan — jangan diwarisi aturan kartu
     ponsel `td.angka-kanan { text-align:left }`. */
  .nota-cetak .nota-item th:first-child,
  .nota-cetak .nota-item td:first-child { text-align: left; }
  .nota-cetak .nota-item th:last-child,
  .nota-cetak .nota-item td:last-child { text-align: right; }
  .nota-cetak .tabel-bungkus td::before { content: none; }
  .nota-cetak .tabel-bungkus td > * { grid-column: auto; }
}

/* =================================================== keuangan: angka & arus kas
   Halaman keuangan adalah halaman UANG: angka harus lurus satu kolom supaya
   digitnya bisa dibandingkan dengan mata. Angka proporsional (default) membuat
   "1" lebih sempit dari "8", jadi baris Rp 111.111 dan Rp 888.888 tidak pernah
   sejajar — di tabel keuangan itu terbaca seperti salah ketik.
   `tabular-nums` menyamakan lebar digit; sumbangan ruangnya diambil dari
   padding sel, bukan dari ukuran huruf, supaya tidak ada nomor yang terpotong. */
.angka-kanan { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table td.angka-kanan { font-feature-settings: "tnum"; }
/* Nilai rupiah pada kolom angka sedikit lebih rapat daripada teks biasa. */
td.angka-kanan b { font-variant-numeric: tabular-nums; }
/* Uraian berisi beberapa baris pendek (masuk / keluar / rujukan); beri sedikit
   jarak antar baris supaya tidak terbaca sebagai satu kalimat panjang. */
.kwitansi { display: block; font-size: .82rem; color: var(--tinta-2); }
.kwitansi + .kwitansi { margin-top: .1rem; }

/* ---- batang arus kas: murni CSS, tanpa JavaScript ---- */
.arus { display: flex; align-items: flex-end; gap: 2px; height: 92px; margin: .2rem 0 .3rem;
  padding: .5rem .55rem 0; background: var(--zebra); border: 1px solid var(--garis);
  border-radius: var(--r-kecil); box-shadow: var(--bayang); }
/* Tiap batang adalah satu hari, dengan garis nol di TENGAH wadah. Batang `naik`
   tumbuh dari garis nol ke atas, `turun` ke bawah.
   PENTING: batang harus di-ABSOLUT-kan terhadap garis 50% (`bottom:50%` /
   `top:50%`), bukan disusun flex dengan `align-items`. Dengan flex, `height`
   diukur dari tepi wadah, jadi batang tumbuh dari ATAS wadah — tingginya benar
   tapi alasnya melayang dan grafiknya berbohong (terukur: alas bersebar 34,5px
   sebelum diperbaiki). */
.arus-batang { flex: 1 1 0; min-width: 2px; height: 100%; position: relative; }
.arus-batang::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  background: var(--garis); }
.arus-batang i { position: absolute; left: 0; right: 0; display: block;
  border-radius: 2px; min-height: 2px; }
.arus-batang.naik i { bottom: 50%; }
.arus-batang.turun i { top: 50%; }
.arus-batang.naik i { background: var(--hijau-500); }
.arus-batang.turun i { background: var(--merah-g); }
.arus-batang:hover i { filter: brightness(.88); }
.arus-kaki { display: flex; justify-content: space-between; font-size: .72rem; color: var(--pudar); }

/* ============================================== sel tabel di layar sedang
   Tabel 5–6 kolom masih utuh di layar ≥721px, tapi wadahnya menyempit di
   721–1280px (sidebar 264px tetap + padding tepi) sehingga kolom tercekik:
   terukur @1024px sisa ruang di dalam sel Tugas tinggal 1,7px dan Surat Jalan
   20,1px — mata membacanya sebagai "kolom menempel". Padding sel dinaikkan
   HANYA di rentang itu: kolom yang benar-benar tercekik lalu membungkus isinya
   sendiri (baris jadi 2 baris seperti @1024px sekarang), dan jarak teks-ke-teks
   antar kolom ikut lega. Di ≥1281px tabel sudah lega (sisa 37–146px) jadi tidak
   diubah, dan di ≤720px tata letaknya milik media query ponsel. */
@media (min-width: 721px) and (max-width: 1280px) {
  th, td { padding-left: .85rem; padding-right: .85rem; }
}

/* ============================================== admin/akun: baris tabel & sel rapat
   Sel Aksi berisi <a> + <form class="sebaris"> + keterangan. Ketiganya anak
   INLINE, jadi selama ada di dalam satu baris teks (white-space berbeda pun
   tidak menolong di desktop, karena `.kolom-aksi` memakai `nowrap`), tingginya
   menumpuk: terukur 120px per baris di desktop dan 300–400px di ponsel untuk
   isi yang sebenarnya satu baris. Flex + wrap membuat keduanya sebaris dan
   tingginya wajar; ponsel sudah punya aturan flex-nya sendiri. */
.sebaris > .tombol { width: auto; }
.tabel-bungkus td.kolom-aksi { white-space: nowrap; }
.tabel-bungkus td.kolom-aksi > a.tombol,
.tabel-bungkus td.kolom-aksi > span.samar-kecil { vertical-align: middle; }
/* Tombol di dalam sel Aksi mewarisi margin-atas dari aturan formulir bertumpuk
   (.7rem). Margin itu benar untuk formulir yang BENAR-BENAR menumpuk, tetapi di
   sini tombolnya sebaris: margin 11,2px membuat sel setinggi 67px padahal
   tombolnya hanya 32px (terukur). Nolkan di dalam sel aksi. */
/* `:not(.ubah *)` WAJIB: panel `<details class="ubah">` juga berada di dalam sel
   aksi, dan isinya MENUMPUK vertikal. Tanpa pengecualian ini aturan di atas ikut
   menolkan margin tombol "Simpan" di /keuangan sehingga ia menempel kalimat
   bantuan di atasnya (terukur 0px). Yang dimaksud aturan ini hanya tombol
   SEBARIS sebagai anak langsung sel aksi. */
.tabel-bungkus td.kolom-aksi .tombol:not(.ubah *) { margin-top: 0; }
@media (min-width: 721px) {
  /* Isi sel aksi dibuat sebaris dengan `inline-flex` pada PEMBUNGKUSNYA, bukan
     dengan `display:flex` pada `<td>`-nya.
     🔴 `display:flex` pada `<td>` mengeluarkan sel dari algoritma tata letak
     tabel (elemen dengan display non-table-cell tidak lagi mengisi kolomnya),
     sehingga lebar kolom Aksi KOLAPS: terukur 22px di desktop dan 2,9px di
     ponsel — tombol 55px melimpah keluar sel dan tabel tampak "terpotong"
     walau tidak ada luber. Cukup satu aturan yang salah display. */
  .tabel-bungkus td.kolom-aksi > form.sebaris { display: inline-flex; margin: 0;
    vertical-align: middle; }
  .tabel-bungkus td.kolom-aksi > .tombol,
  .tabel-bungkus td.kolom-aksi > details.ubah { vertical-align: middle; }
  .tabel-bungkus td.kolom-aksi > * + * { margin-left: .5rem; }
  /* `line-height: 0` pada SEL, lalu dipulihkan pada anaknya. Tanpa ini kotak
     `inline-flex` (tombol) berada di dalam kotak baris dan menyisakan ruang
     descender ~11px, sehingga sel 66px untuk tombol 32px. Ruang itu milik garis
     dasar teks, bukan milik tombolnya. */
  .tabel-bungkus td.kolom-aksi { line-height: 0; }
  .tabel-bungkus td.kolom-aksi > * { line-height: 1.35; }
}

/* Lebar kolom tabel akun dipatok supaya tiap sel cukup untuk isinya dalam 1–2
   baris. Tanpa ini dua kolom identitas (nama & email) saling berebut lebar dan
   nama 32 karakter terpaksa jadi 4 baris — baris tabel 106px. Persentase di
   bawah berasal dari lebar TERUKUR isinya (tombol aksi 168px, lencana peran
   139px, cap waktu 112px), bukan angka karangan. */
.tabel-akun { table-layout: fixed; }
.tabel-akun th:nth-child(1) { width: 28%; }   /* Akun (nama + email) */
.tabel-akun th:nth-child(2) { width: 13%; }   /* Peran */
.tabel-akun th:nth-child(3) { width: 24%; }   /* Koperasi / Wilayah */
.tabel-akun th:nth-child(4) { width: 8%; }    /* Status */
.tabel-akun th:nth-child(5) { width: 11%; }   /* Masuk terakhir */
.tabel-akun th:nth-child(6) { width: 16%; }   /* Aksi */
/* Alamat surel panjang tanpa spasi melebarkan kolomnya sampai memaksa tabel
   menggulir mendatar. Biarkan membungkus di titik mana pun. */
.pecah { overflow-wrap: anywhere; word-break: break-word; }

/* Lebar kolom dasbor admin dipatok dari lebar TERUKUR isinya (bukan angka
   karangan). Tanpa patokan, kolom "Tugas" pada daftar tugas menelan 538px (48%
   tabel) untuk satu judul, sementara kode koperasi berdiri sendiri menghabiskan
   71px. Persentase di bawah = lebar isi terpanjang + padding. */
.tabel-tugas th:nth-child(1) { width: 44%; }   /* Tugas */
.tabel-tugas th:nth-child(2) { width: 22%; }   /* Koperasi */
.tabel-tugas th:nth-child(3) { width: 15%; }   /* Status */
.tabel-tugas th:nth-child(4) { width: 14%; }   /* Tenggat */
.tabel-tugas th:nth-child(5) { width: 5%; }    /* Aksi */
.tabel-koperasi th:nth-child(1) { width: 34%; } /* Koperasi (nama + kode) */
.tabel-koperasi th:nth-child(2) { width: 24%; } /* Wilayah */
.tabel-koperasi th:nth-child(3) { width: 24%; } /* Manajer */
.tabel-koperasi th:nth-child(4) { width: 9%; }  /* Status */
.tabel-koperasi th:nth-child(5) { width: 9%; }  /* Tugas */
@media (min-width: 721px) {
  .tabel-tugas, .tabel-koperasi { table-layout: fixed; }
}
/* Angka jumlah tugas disamakan lebarnya agar bisa dibandingkan antar baris. */
.tabel-koperasi td .angka { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---- Alat scan barcode (/distribusi/stok-koperasi) ----
   Kamera butuh area yang jelas: bingkai gelap + garis pemandu supaya pengguna tahu
   ke mana harus mengarahkan. Barcodenya sendiri tidak perlu presisi — pengenalan
   dilakukan peramban tiap 400 ms. */
.scan-bingkai { position: relative; border-radius: var(--r-kecil); overflow: hidden;
  background: #101914; aspect-ratio: 4 / 3; margin-bottom: .5rem; }
.scan-bingkai video { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-garis { position: absolute; left: 8%; right: 8%; top: 50%; height: 2px;
  background: var(--merah); box-shadow: 0 0 8px rgba(163, 34, 24, .8); }
#scan-modal .pilih-daftar { position: static; max-height: 220px; margin-top: .5rem; }
#scan-modal .kartu { margin-top: .5rem; }

/* ---- Pemilih KDMP yang bisa dicari (/keuangan) ----
   Kotak hasil MENGAMBANG di atas isi halaman (position:absolute) supaya
   membuka daftar tidak menggeser tabel, kartu, dan tombol di bawahnya —
   pada puluhan ribu koperasi daftar pernah dirender utuh dan mendorong
   seluruh halaman turun setiap kali dibuka. */
.cari-koperasi { align-items: flex-start; }
.cari-koperasi .cari-kop { position: relative; flex: 1 1 260px; min-width: 0; }
.cari-koperasi .cari-kop input[type="search"] { width: 100%; margin: 0; }
.cari-koperasi .pilih-daftar { position: absolute; inset-inline: 0; top: calc(100% + .25rem);
  z-index: 6; margin: 0; padding: .2rem; max-height: 260px; overflow-y: auto;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r-kecil);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .13); }
.cari-koperasi .pilih-daftar li[hidden] { display: none; }
/* Baris hasil = <a>, jadi ia perlu dilepas dari gaya tautan (garis bawah, warna
   biru) — kalau tidak, hasil pencarian terbaca seperti tautan keluar halaman. */
.cari-koperasi .pilih-baris { display: flex; flex-direction: row; align-items: center; gap: .5rem;
  padding: .4rem .45rem; border-radius: var(--r-kecil); text-decoration: none;
  color: var(--tinta); font-size: .85rem; }
.cari-koperasi .pilih-baris:hover { background: var(--hijau-100); }
.cari-koperasi .pilih-baris.centang { background: var(--hijau-100); }
.cari-koperasi .pilih-baris.centang .pilih-nama { font-weight: 700; }
.cari-koperasi .pilih-baris.centang::after { content: "✓"; margin-left: auto;
  color: var(--hijau-600); font-weight: 800; }
.cari-koperasi .pilih-nama { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.cari-koperasi .pilih-baris small { flex: 0 1 46%; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--pudar); font-size: .72rem; }
.cari-koperasi .pilih-kosong { margin: 0; padding: .5rem; font-size: .8rem; color: var(--pudar); }
#kop-terpilih { margin-top: .45rem; }

/* ---- Modal rincian Surat Jalan (/distribusi) ----
   <dialog> bawaan peramban: fokus terkunci, Esc menutup, latar inert. Yang
   ditambahkan hanya tampilannya. */
#rincian-modal { width: min(720px, calc(100vw - 1.6rem)); max-height: min(88vh, 860px);
  padding: 0; border: 0; border-radius: var(--r); box-shadow: var(--bayang-2);
  color: var(--tinta); overflow: hidden; }
#rincian-modal::backdrop { background: rgba(16, 29, 24, .48); }
#rincian-modal-isi { max-height: inherit; }
.rincian-modal-tutup { position: absolute; top: .55rem; right: .6rem; margin: 0; }
.rincian-modal-tutup .ikon-tutup { font-size: 1.15rem; line-height: 1; padding: .2rem .55rem; }
.sedang-muat { padding: 1.4rem 1.3rem; margin: 0; }

/* Panel: badan yang menggulir + kaki aksi yang selalu terlihat. Tanpa ini,
   tombol "Kirim Barang" tenggelam di dasar isi yang panjang dan pengguna
   menggulir dua kali untuk satu surat jalan. */
.rincian-panel { display: flex; flex-direction: column; max-height: min(88vh, 860px); }
.rincian-badan { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 1.2rem 1.3rem .4rem; }
.rincian-judul { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .6rem; margin-bottom: .9rem; padding-right: 2.2rem; }
.rincian-judul b { display: block; font-size: 1rem; }
.rincian-judul small { display: block; color: var(--pudar); font-size: .8rem; }
.rincian-sub { font-size: .82rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--pudar); margin: 1.1rem 0 .4rem; }
.rincian-kaki { flex: none; display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end;
  align-items: center; padding: .8rem 1.3rem; border-top: 1px solid var(--garis);
  background: var(--zebra); }
/* Halaman penuh: panel tidak perlu memahat tinggi layar. */
.blok .rincian-panel { max-height: none; }
.blok .rincian-badan { overflow: visible; padding: 0 0 .4rem; }
.blok .rincian-kaki { background: none; padding: .8rem 0 0; }
@media (max-width: 560px) {
  /* Sama seperti .modal: `margin-bottom: 0` + `100vw` melemparkan dialog ke
     dasar layar dan menutupi bilah menu bawah. Dibiarkan terpusat. */
  #rincian-modal { width: min(720px, calc(100vw - 1.6rem)); inset: .8rem .8rem var(--tb-nav);
    max-height: calc(100dvh - .8rem - var(--tb-nav)); }
  .rincian-kaki { justify-content: stretch; }
  .rincian-kaki .tombol { flex: 1 1 auto; }
}

/* ---- Kepala blok: judul kiri, tombol aksi kanan atas ---- */
.kepala-blok { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; margin-bottom: .7rem; }
.kepala-blok h2 { margin: 0; }

/* ---- Modal bersama: .modal ----
   <dialog> bawaan peramban: fokus terkunci, Esc menutup, latar inert, dan
   `margin: auto` bawaannya yang menempatkannya di TENGAH layar (dialog
   non-modal menempel di atas). Yang ditambahkan hanya tampilannya. Dipakai
   /admin/barang (Tambah/Ubah) dan /pasokan (Update status). */
.modal { width: min(640px, calc(100vw - 1.6rem)); max-height: min(88vh, 780px);
  padding: 0; border: 0; border-radius: var(--r); box-shadow: var(--bayang-2);
  color: var(--tinta); overflow: hidden;
  /* Kolom flex di dialog itu sendiri, bukan hanya di `<form>`-nya.
     `.modal-badan` memakai `flex: 1 1 auto; min-height: 0` supaya isi panjang
     MENYUSUT dan bergulir. Itu hanya bekerja bila induknya flex container.
     Modal yang isinya dibungkus `<form>` sudah memenuhi syarat; modal TANPA form
     (mis. Rincian lahan di /admin/koperasi) tidak — `.modal-badan` tumbuh
     mengikuti isi (terukur 866px di dialog 646px), meluber ke luar, lalu
     dipotong `overflow: hidden` dialog tanpa bisa digulir: `scrollHeight`
     sama persis dengan `clientHeight`, jadi tidak ada yang bisa digulir. */
  /* `white-space: normal` WAJIB di sini, bukan hiasan.
     `<dialog>` kerap ditulis DI DALAM sel tabel, dan `.kolom-aksi` memakai
     `white-space: nowrap` (supaya tombol tidak terpecah dua baris). `white-space`
     diwariskan, jadi seluruh isi modal ikut nowrap: judul dialog melebar 731px
     dan paragraf bantuan 1108px di layar 390px — teksnya tidak membungkus sama
     sekali (terukur pada /admin/koperasi, dialog rincian lahan).
     Ditaruh di `.modal`, bukan di sel tiap halaman: satu aturan ini menutup
     SEMUA modal yang duduk di dalam sel tabel, di halaman mana pun. */
  white-space: normal; }
/* Hanya saat TERBUKA: `display:flex` polos mengalahkan `dialog:not([open])
   { display:none }` bawaan peramban, dan semua dialog di halaman ikut tampil. */
.modal[open] { display: flex; flex-direction: column; }
.modal::backdrop { background: rgba(16, 29, 24, .48); }
.modal form { display: flex; flex-direction: column; max-height: inherit; }
.modal-kepala { flex: none; display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; padding: .9rem 1.2rem; border-bottom: 1px solid var(--garis); background: var(--zebra); }
.modal-kepala h2 { margin: 0; font-size: 1.02rem; }
.modal-badan { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 1.1rem 1.2rem .3rem; }
.modal-kaki { flex: none; display: flex; gap: .5rem; justify-content: flex-end;
  padding: .8rem 1.2rem; border-top: 1px solid var(--garis); background: var(--zebra); }
.modal-kaki .tombol { min-width: 7.5rem; }
/* Pengumuman pribadi (kredensial): teksnya harus bisa disalin rapi — sandi
   dipisah baris sendiri, bukan tenggelam dalam paragraf. */
.pribadi-isi + .pribadi-isi { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--garis); }
.pribadi-isi h3 { margin: 0 0 .4rem; font-size: .95rem; }
.pribadi-teks { white-space: normal; line-height: 1.55; font-size: .92rem;
  background: var(--hijau-muda, #eef7f1); border-radius: var(--r-kecil); padding: .6rem .7rem; }
/* Status kesiapan di kaki modal: rata KIRI, mendorong tombolnya ke kanan.
   Tanpa ini ia ikut terdorong ke tepi kanan oleh `justify-content: flex-end`
   dan terbaca seperti label tombolnya. */
.modal-kaki [data-siap-status] { flex: 1 1 auto; margin: 0; text-align: left; }
.modal-badan .pesan { margin: 0 0 .9rem; }
@media (max-width: 560px) {
  /* Aturan ini benar-benar mengubah tata letak <dialog>; sisanya hanya boleh
     menyentuh TAMPILANNYA, kalau tidak dialog kembali menempel ke dasar layar.
     Dua kesalahan nyata yang diperbaiki (terukur pada 360x780):
       1. `margin-bottom: 0` — <dialog> bawaan peramban dipusatkan oleh
          `margin: auto`, jadi begitu margin-bawah jadi 0 sisa `margin-top:auto`
          melempar dialog ke DASAR layar. Seluruh dialog terukur bottom=780 dan
          menutupi bilah menu 66px.
       2. `width: 100vw` + sudut hanya-atas — dialog menempel tepi tanpa sela.
     Yang dipakai sekarang: kotak acuan dialog dipersempit lewat `inset` supaya
     tinggi menu bawah tak ikut dihitung, lalu peramban memusatkannya sendiri
     (`margin: auto` bawaan, TIDAK ditulis ulang). */
  .modal { width: min(640px, calc(100vw - 1.6rem)); inset: .8rem .8rem var(--tb-nav);
    /* `max-height: 100%` SALAH di sini: persentase diselesaikan terhadap tinggi
       viewport (terukur 780), bukan terhadap kotak `inset` di atas, sehingga
       dialog yang isinya panjang tumbuh melewati kotaknya dan menimpa menu
       (terukur top -27/bottom 753). Dihitung eksplisit dari sisa ruang. */
    max-height: calc(100dvh - .8rem - var(--tb-nav)); }
  .modal-kaki { justify-content: stretch; }
  .modal-kaki .tombol { flex: 1 1 auto; min-width: 0; }
}

/* ---- Bilah saring: satu baris yang benar-benar rata ----
   Diberlakukan untuk SEMUA `.saring` (bukan per halaman): dulu aturan ini
   ter-scope `#stok`, sehingga bilah di /pasokan kembali bergerigi — input 43px
   di sebelah select 42px. Satu aturan, semua halaman ikut sehat.
   Tiga sebab "kurang rapi" sebelumnya, semuanya terukur:
     1. label 63px (caption di atas isian) di sebelah isian 43px -> bergerigi;
     2. <input> 43px vs <select> 42px -> beda 1px karena border-nya beda;
     3. lebar acak (input 226px, select 148px) karena flex-basis 220px pada
        keduanya, sementara select mengambil lebar sesuai opsinya.
   Diperbaiki dengan mengunci TINGGI baris (--tb-saring) dan memberi setiap
   jenis kontrol BASIS yang berbeda: pencarian melar, pemilih kategori tetap.

   AKAR "pencarian nempel": baris ini dulu `padding: .6rem 0`, yang MENGHAPUS
   padding samping dari aturan `.saring` pertama di atas (`.7rem .8rem`) —
   properti yang sama, aturan yang lebih bawah menang. Bingkai bilah tetap
   tampak (background/border tak tersentuh) sementara ISINYA menempel 1px dari
   bingkainya sendiri (terukur /distribusi & /pasokan @390/1024/1440px;
   `padding: 9.6px 0px`, isian kiri = 1px). Dulu ditambal per-halaman untuk
   /pasokan (`#ps form.saring`) — itu gejala; akarnya di sini, jadi dibetulkan
   di sini supaya 34 halaman lain ikut sehat. `.lingkup-kop form.saring` yang
   memang bilah-tertanam (padding 0 disengaja) tetap menang karena lebih khusus. */
.saring { --tb-saring: 42px; display: flex; flex-wrap: wrap; align-items: center;
  gap: .55rem; padding: .6rem .8rem; }
/* `border: 0; padding: 0` WAJIB: label pembungkus ternyata mewarisi border 1px
   dari aturan lain, sehingga label 44px berdiri di sebelah isian 42px dan bilah
   tampak bergerigi. Tinggi baris HARUS ditentukan oleh ISIANNYA, bukan wadahnya. */
.saring label { display: flex; align-items: center; margin: 0; padding: 0;
  border: 0; flex: 0 1 auto; min-width: 0; }
/* Pencarian: satu-satunya yang melar — kolom yang paling sering dipakai. */
.saring label.cari { position: relative; flex: 1 1 300px; max-width: 460px; }
.saring label.pilih { flex: 0 1 220px; }
/* Tinggi & jarak dalam dikunci: `height` (bukan min-height) supaya <input> dan
   <select> mustahil berbeda walau border/bawaannya beda. */
.saring input, .saring select { width: 100%; height: var(--tb-saring);
  min-height: 0; margin: 0; padding: 0 .8rem; font-size: .875rem; line-height: var(--tb-saring); }
/* Ikon cari di dalam kotak: dekorasi, sehingga isian diberi ruang kiri. */
.saring .ikon-cari { position: absolute; left: .7rem; top: 50%; transform: translateY(-50%);
  width: 1.05rem; height: 1.05rem; pointer-events: none; fill: none; stroke: var(--pudar);
  stroke-width: 1.7; stroke-linecap: round; }
.saring label.cari input { padding-left: 2.3rem; }
/* Ikon bawaan kotak `search` disembunyikan: ada ikon sendiri, dan bawaan WebKit
   letaknya bertabrakan dengan padding kiri di atas. */
.saring input[type="search"]::-webkit-search-decoration,
.saring input[type="search"]::-webkit-search-cancel-button { display: none; }
/* `margin: 0` WAJIB: aturan global `label + .tombol { margin-top: .7rem }`
   (baris ~402) menambah 11,2px di atas tombol yang mengikuti label pencarian,
   sehingga dasar tombol meleset 5,6px dari dasar isiannya (terukur di
   /distribusi/stok-koperasi: isian y=412,9 vs tombol y=418,5). Di bilah yang
   flex, jarak sudah diatur `gap` — margin itu murni merusak. Tambalan yang sama
   sudah ada di `.kat-aksi .tombol-ikon`; di sini ditutup untuk SEMUA bilah. */
.saring .tombol { height: var(--tb-saring); min-height: 0; flex: 0 0 auto; margin: 0; }
/* Tombol IKON di bilah saring (mis. scan barcode di /distribusi/stok-koperasi):
   persegi seperti tingginya, bukan selebar teksnya. `.tombol-ikon` hanya
   menghapus padding, jadi tanpa aturan ini tombolnya jadi sliver selebar 20px
   dengan ikon meluber keluar bingkainya. */
.saring .tombol-ikon { width: var(--tb-saring); padding: 0; }
@media (max-width: 640px) {
  /* Ponsel: pencarian memakai lebar penuh, kategori & tombol berbagi barisnya. */
  .saring label.cari { flex: 1 1 100%; max-width: none; }
  .saring label.pilih { flex: 1 1 60%; }
  /* KECUALI bila persis di sebelahnya ada tombol IKON (mis. scan barcode di
     /distribusi/stok-koperasi): keduanya WAJIB tetap sebaris — "di sebelah kolom
     pencarian" adalah permintaan harfiah, bukan hanya di desktop. Karena
     pencarian tak lagi boleh 100%, ia mengambil sisa lebarnya (`flex-basis: 0`
     supaya tidak menuntut lebar isinya lalu membungkus tombolnya ke baris dua).
     Selektornya sempit (`:has` + anak langsung) supaya bilah lain di ponsel
     tidak ikut berubah. */
  .saring label.cari:has(+ .tombol-ikon) { flex: 1 1 0; min-width: 0; }
}

/* ---- Pemetaan lahan: dua sel pendek sebaris di ponsel ----
   Di ponsel `.tabel-bungkus` mengubah tiap sel jadi label+nilai bertumpuk, jadi
   tinggi baris = jumlah sel × tinggi sel. Empat sel → 348–367px per titik
   (terukur; sebelumnya enam sel 404–423px). Dua sel isinya pendek (luas+potensi,
   dan lencana status), jadi keduanya dibuat SEBARIS: label dan nilai berdampingan,
   bukan bertumpuk. Tidak ada informasi yang disembunyikan — hanya tata letaknya
   yang dipadatkan, sesuai aturan Bos (jangan hilangkan teks di ponsel). */
@media (max-width: 720px) {
  .tabel-pemetaan td[data-l="Lahan & Potensi"],
  .tabel-pemetaan td[data-l="Pembangunan"] { display: flex; align-items: baseline;
    gap: .55rem; padding-top: .15rem; padding-bottom: .15rem; }
  .tabel-pemetaan td[data-l="Lahan & Potensi"]::before,
  .tabel-pemetaan td[data-l="Pembangunan"]::before { flex: 0 0 auto; padding-top: 0; }
  /* Halaman Koperasi: sel Manajer & Status isinya pendek, jadi disejajarkan.
     Empat sel (dari tujuh) sudah memangkas baris 440–480px → ± 340px; dua sel
     ini yang tersisa dipadatkan lagi tanpa menyembunyikan teksnya. */
  .tabel-koperasi td[data-l="Manajer"],
  .tabel-koperasi td[data-l="Status"] { display: flex; align-items: baseline;
    gap: .55rem; padding-top: .15rem; padding-bottom: .15rem; flex-wrap: wrap; }
  .tabel-koperasi td[data-l="Manajer"]::before,
  .tabel-koperasi td[data-l="Status"]::before { flex: 0 0 auto; padding-top: 0; }
}

/* Tombol rincian yang menyerupai tautan: dipakai di dalam sel tabel agar tidak
   menambah satu sel tersendiri (tiap sel = +80px di ponsel). Tetap fokusabel
   dan menyasar-sentuh 44px, jadi bukan sekadar memperkecil tombol. */
.tautan-mini { background: none; border: 0; padding: .35rem 0; margin: 0;
  font: inherit; font-size: .85rem; font-weight: 600; color: var(--hijau-700);
  cursor: pointer; text-decoration: underline; min-height: 44px; }
.tautan-mini:hover { color: var(--hijau-600); }

/* ---- Lonceng notifikasi (DESKTOP) ----
   Tetap ada seperti sebelumnya: sebaris dengan logo & tulisan "DesaPreneur",
   tepat di sebelahnya. Di PONSEL disembunyikan — tugasnya pindah ke butir
   "Notifikasi" di panel menu pojok kanan atas. */
.lonceng { position: relative; display: inline-flex; align-items: center;
  justify-content: center; flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 50%; color: #fff;
  background: rgba(255, 255, 255, .14); text-decoration: none; }
.lonceng:hover { background: rgba(255, 255, 255, .24); }
.lonceng .ik { width: 22px; height: 22px; fill: currentColor; }
/* Lencana angka: hiasan (angkanya sudah disebut di aria-label), jadi
   `aria-hidden` di markup supaya pembaca layar tidak membaca "3" sendirian. */
.lencana-notif { position: absolute; top: -3px; right: -3px; min-width: 19px;
  height: 19px; padding: 0 5px; border-radius: 10px; background: var(--merah);
  color: #fff; font-size: .68rem; font-weight: 700; line-height: 17px;
  text-align: center; border: 2px solid var(--hijau-900);
  box-sizing: content-box; pointer-events: none; }
@media (max-width: 900px) { .lonceng { display: none; } }

/* ---- Tombol menu di pojok kanan atas (PONSEL saja) ----
   Isinya: nama pengguna, Notifikasi, Keluar. Ikonnya tiga garis karena fungsinya
   menu — bukan lonceng. Tidak ada butir MENU di dalamnya (semua menu sudah di
   bilah bawah); "Notifikasi" bukan menu, ia pintu ke pengumuman. */
.menu-kanan { display: none; }
.menu-kanan-panel { display: none; }

/* Baris pertama kepala: merek kiri, tombol kanan. `.merek` flex:1 menyerap sisa
   lebar, jadi tombolnya terdorong ke ujung kanan tanpa menyentuh tata letak .sisi.
   `width: 100%` (bukan flex-grow): di ponsel `.sisi` itu baris flex, jadi tanpa
   ini kepalanya hanya selebar isinya (terukur 215px dari 390px) dan tombolnya
   berhenti di tengah, bukan di pojok. */
.sisi-kepala { display: flex; align-items: center; gap: .6rem;
  width: 100%; min-width: 0; }
.sisi-kepala .merek { flex: 1 1 auto; min-width: 0; }
/* "Koordinasi Manajer Koperasi" dibuang: memakan ruang kepala tanpa menambah
   informasi (teks itu juga muncul sebagai judul halaman). */
.sisi-kepala .nama small { display: none; }

@media (max-width: 900px) {
  /* Identitas pengguna + Keluar sudah pindah ke menu pojok, jadi `.kaki` tidak
     perlu tampil di kepala ponsel. Kalau dibiarkan ia memakan lebar di kanan —
     tombolnya berhenti di 320px dari 390px, tidak sampai pojok. */
  .sisi .kaki { display: none; }

  .menu-kanan { display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 auto; width: 44px; height: 44px; padding: 0; cursor: pointer;
    border: 0; border-radius: var(--r-kecil); color: #fff;
    background: rgba(255, 255, 255, .18); position: relative; }
  .menu-kanan:hover { background: rgba(255, 255, 255, .26); }
  .menu-kanan .ik { width: 24px; height: 24px; fill: currentColor; }
  /* Lencana di tombol: pakai `.lencana-notif` yang SAMA dengan lonceng desktop,
     jadi warnanya pasti merah dan angkanya tampil. Sebelumnya di sini hanya titik
     9px tanpa angka, dan latar tombolnya yang tembus pandang membuat lencananya
     tampak pucat. */
  .menu-kanan .lencana-notif { top: -4px; right: -4px; min-width: 20px;
    height: 20px; font-size: .7rem; line-height: 17px;
    border-color: var(--hijau-900); z-index: 2; }

  /* Panel: menempel dari kanan atas, di bawah kepala. */
  /* `bottom: auto; height: auto` WAJIB: gaya bawaan <dialog> memakai `inset: 0`,
     jadi tanpa ini kotaknya membentang sampai dasar layar dan menutupi seluruh
     halaman — tombolnya sendiri jadi tidak bisa diklik (terbukti di uji, bukan
     dugaan). `margin: 0` mematikan `margin: auto` bawaan yang memusatkan. */
  .menu-kanan-panel[open] { display: flex; flex-direction: column;
    position: fixed; top: calc(var(--sp) + 3.4rem); right: var(--sp);
    bottom: auto; left: auto; height: auto;
    width: min(16rem, calc(100vw - 2 * var(--sp))); margin: 0; padding: .3rem;
    border: 1px solid var(--garis-2); border-radius: var(--r-kecil);
    background: var(--putih); box-shadow: 0 12px 30px rgba(16, 29, 24, .22);
    gap: .1rem; z-index: 60; max-height: none; }
  .menu-pengguna { display: flex; flex-direction: column; gap: .1rem;
    padding: .5rem .6rem; border-bottom: 1px solid var(--garis-2); margin-bottom: .25rem; }
  .menu-pengguna b { font-size: .9rem; color: var(--tinta); }
  .menu-pengguna small { font-size: .74rem; color: var(--pudar);
    overflow: hidden; text-overflow: ellipsis; }
  .menu-pengguna .tanda { font-size: .72rem; color: var(--hijau-700); font-weight: 600; }
  /* Lencana angka di butir Notifikasi: penanda jumlah yang belum dibaca. */
  .menu-lencana { margin-left: auto; min-width: 20px; padding: 0 6px;
    border-radius: 10px; background: var(--merah); color: #fff;
    font-size: .7rem; font-weight: 700; line-height: 19px; text-align: center; }
  .menu-butir { display: flex; align-items: center; gap: .5rem;
    padding: .6rem .6rem; min-height: 44px; border-radius: var(--r-kecil);
    color: var(--tinta-2); text-decoration: none; font-size: .875rem; font-weight: 600; }
  .menu-butir:hover { background: var(--hijau-100); }
  .menu-butir.keluar { color: var(--merah); }
  .menu-butir.keluar:hover { background: var(--merah-l); }
}

/* ---- Pengumuman resmi: kop surat (dipakai halaman /pengumuman) ----
   Kop ini yang membuat pengumuman terbaca sebagai surat resmi perusahaan, bukan
   sekadar catatan. Latarnya putih supaya logo berwarna gelap tetap terbaca. */
.kop { display: flex; align-items: center; gap: .9rem;
  padding: .9rem 1rem; margin-bottom: .9rem;
  border: 1px solid var(--garis-2); border-bottom: 3px solid var(--hijau-700);
  border-radius: var(--r-kecil); background: #fff; }
.kop img { height: 46px; width: auto; flex: 0 0 auto; }
.kop div { min-width: 0; }
.kop b { display: block; font-size: 1rem; letter-spacing: .01em; }
.kop small { display: block; font-size: .78rem; color: var(--pudar); }
@media (max-width: 900px) {
  .kop img { height: 38px; }
  .kop b { font-size: .92rem; }
}

/* ---- Pengumuman & Aspirasi: daftar "kabar" ----
   Bukan tabel: isi pengumuman perlu lebar penuh untuk dibaca, dan di ponsel
   tabel akan memecahnya jadi label+nilai (tiap sel = tinggi baris). Satu kartu
   per kabar, judul + meta + isi. */
.kabar-daftar { display: flex; flex-direction: column; gap: .7rem; }
.kabar { border: 1px solid var(--garis-2); border-radius: var(--r-kecil);
  padding: .8rem .9rem; background: #fff; }
/* Belum dibaca: garis kiri hijau + latar tipis — penanda yang tetap terlihat
   tanpa bergantung warna lencana saja. */
.kabar-baru { border-left: 4px solid var(--hijau-600); background: var(--hijau-100); }
.kabar header { display: flex; flex-direction: column; gap: .15rem; margin-bottom: .35rem; }
.kabar h3 { margin: 0; font-size: .95rem; display: flex; flex-wrap: wrap;
  align-items: center; gap: .35rem; }
/* Daftar: judul jadi tautan ke halaman detail, ringkasan singkat di bawahnya.
   Seluruh kartu bisa diklik (tautan judul & "Baca lengkap" menuju halaman yang
   sama), jadi tidak ada lagi yang terasa "tidak bisa dibuka". */
.kabar-judul { color: inherit; text-decoration: none; }
.kabar-judul:hover, .kabar-judul:focus-visible { color: var(--hijau-700);
  text-decoration: underline; }
.kabar-ringkas { margin: .35rem 0 0; font-size: .875rem; line-height: 1.5;
  color: var(--tinta-2); overflow-wrap: anywhere; }
.kabar-buka { display: inline-block; margin-top: .45rem; font-size: .8rem;
  font-weight: 700; color: var(--hijau-700); text-decoration: none; }
.kabar-buka:hover { text-decoration: underline; }

/* Halaman detail pengumuman. Kelasnya SENDIRI-sendiri — sebelumnya bagian ini
   memakai `.jejak` (yang ternyata bilah progres, height 8px) sehingga tautan
   kembalinya tergencet jadi batang bergaris. */
.balik { margin: 0 0 .35rem; font-size: .82rem; font-weight: 600; }
.balik a { color: var(--hijau-700); text-decoration: none; }
.balik a:hover, .balik a:focus-visible { text-decoration: underline; }
.surat-meta { margin: 0 0 .7rem; padding-bottom: .55rem; font-size: .8rem;
  color: var(--pudar); border-bottom: 1px solid var(--garis-2); }
/* `pre-wrap` menjaga baris & paragraf yang ditulis pengirim; `overflow-wrap`
   menahan tautan panjang agar tidak meluber di ponsel. */
.surat-isi p { margin: 0; font-size: .95rem; line-height: 1.7;
  white-space: pre-wrap; overflow-wrap: anywhere; }
@media (max-width: 900px) {
  .surat-isi p { font-size: .9rem; line-height: 1.65; }
}
.kabar header small { font-size: .78rem; }
/* `overflow-wrap` wajib: manajer sering menempel tautan panjang di aspirasi. */
.kabar > p { margin: 0; font-size: .875rem; line-height: 1.5;
  white-space: pre-wrap; overflow-wrap: anywhere; }
.kabar .tanggapan { margin-top: .55rem; padding: .55rem .7rem; border-radius: var(--r-kecil);
  background: var(--hijau-l); border-left: 3px solid var(--hijau-600); }
.kabar .tanggapan p { margin: .2rem 0 0; font-size: .875rem; white-space: pre-wrap;
  overflow-wrap: anywhere; }
.kabar .tombol-baris { margin-top: .6rem; }

/* Formulir sederhana (pengumuman & aspirasi). Kolomnya menumpuk; `.lebar`
   menandai isian yang perlu baris penuh (perihal di desktop pun boleh lebar). */
.petak-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: .7rem; align-items: start; }
.petak-form label { display: flex; flex-direction: column; gap: .3rem; margin: 0; }
.petak-form label > span { font-size: .8rem; font-weight: 600; color: var(--pudar); }
.petak-form .lebar, .petak-form .tombol-baris { grid-column: 1 / -1; }
.petak-form textarea { min-height: 0; }

/* ---- Kartu status ringkas (/pasokan) ----
   Tingginya dipaku supaya deretan kartu rata walau labelnya satu/dua kata, dan
   angka dipisah sebagai baris tersendiri (labelnya kecil di atas). */
.kartu-status .kartu { display: flex; flex-direction: column; justify-content: center;
  gap: .15rem; min-height: 4.6rem; text-align: left; }
.kartu-status .kartu small { font-size: .74rem; letter-spacing: .02em; text-transform: uppercase;
  color: var(--pudar); font-weight: 600; }
.kartu-status .kartu b { font-size: 1.25rem; line-height: 1.1; }

/* ---- /pasokan: bilah saring & proporsi kolom ----
   Dua cacat terukur di halaman ini:

   1. "Pencarian terlalu nempel". Bingkai bilah `.saring` sudah x=33 pada
      viewport 390px (sudah sejajar tepi kartu tabel di bawahnya), tetapi
      ISIAN di dalamnya juga x=34 — hanya 1px dari garis bingkainya sendiri,
      karena `padding: .6rem 0` memang sengaja menghapus padding samping.
      Kini jaraknya 13px. Padding dinyatakan di sini, BUKAN di aturan `.saring`
      global: bilah saring dipakai 8 halaman lain yang sudah punya jarak sendiri
      (mis. #buku `.7rem 0`), dan mengubah spasi semua halaman itu bukan yang
      diminta — `.saring` global juga menahan bilah tanpa padding sama sekali.
   2. Kolom tabel: terukur 1073px terbagi Kode 440 (41%), UMKM & Komoditas 227,
      Jumlah & Nilai 125, Status & Pembayaran 192, Aksi 89. Kolom terlebar
      justru memuat informasi paling sedikit, sementara "Rp 7.000 / UNIT"
      terbelah dua baris di kolom 125px. Sebabnya nama koperasi yang panjang
      ("KOPERASI DESA MERAH PUTIH CIBEBER KECAMATAN SUKAGUMIWANG") ada di sel
      Kode, dan algoritma tabel otomatis melebarkan mengikuti isi terpanjang.
      Lebar di bawah dinyatakan per-kolom supaya kolom terlebar dipegang kolom
      yang paling banyak menjelaskan. Sengaja TETAP `table-layout: auto`:
      sel Aksi memakai `white-space: nowrap`, dan pada `fixed` isi yang tak
      muat LUBER keluar sel alih-alih melebarkan kolomnya — persentase di sini
      jadi arahan, bukan paku. */
#ps form.saring { padding: .7rem .8rem; }
@media (min-width: 721px) {
  /* Angka-angka ini hasil UKURAN, bukan selera. Percobaan pertama (18/31/16/23)
     membuat kolom Kode hanya 181px, sehingga nama koperasi panjang
     ("KOPERASI DESA MERAH PUTIH KENITEN KECAMATAN GEMUH…" — 56 karakter, data
     nyata) membungkus jadi TIGA baris dan barisnya jadi 143px sementara baris
     lain 91px. Dinaikkan ke 21% (228px) supaya nama sepanjang itu cukup DUA
     baris; ruangnya diambil dari kolom UMKM, yang tadinya paling lebar.
     Sesudahnya: 143px -> 91px, dan semua kolom sepadan dengan <th>-nya. */
  #ps th:nth-child(1) { width: 23%; }   /* Kode + tanggal + koperasi pembeli */
  #ps th:nth-child(2) { width: 23%; }   /* UMKM & Komoditas */
  #ps th:nth-child(3) { width: 16%; }   /* Jumlah & Nilai */
  #ps th:nth-child(4) { width: 20%; }   /* Status & Pembayaran */
  /* Aksi tidak diberi lebar: selebar isi tombolnya. */
}

/* ---- /pasokan (PONSEL): dua sel pendek disejajarkan ----
   Di ponsel tiap sel jadi label+nilai bertumpuk, jadi tinggi satu pasokan =
   jumlah sel x tinggi sel (terukur 477px untuk baris ber-nama-koperasi panjang,
   391px untuk sisanya). Kode dan Jumlah & Nilai isinya pendek, jadi label dan
   nilainya dibuat SEBARIS — tata letaknya dipadatkan, TIDAK ada teks yang
   disembunyikan. Pola sama dengan .tabel-koperasi td[data-l="Manajer"]. */
@media (max-width: 720px) {
  #ps .tabel-bungkus td[data-l="Kode"],
  #ps .tabel-bungkus td[data-l="Jumlah & Nilai"] { display: flex; align-items: baseline;
    gap: .55rem; padding-top: .15rem; padding-bottom: .15rem; flex-wrap: wrap; }
  #ps .tabel-bungkus td[data-l="Kode"]::before,
  #ps .tabel-bungkus td[data-l="Jumlah & Nilai"]::before { flex: 0 0 auto; padding-top: 0; }
}

/* ---- /pasokan: catatan penolakan memakai lebar penuh ----
   `.grid-form` merentangkan `<input>`/`<select>` jadi 100% kolomnya, termasuk
   yang berada DI DALAM modal. `<textarea>` tidak ikut: bawaannya ~20 kolom,
   jadi kotak "Keterangan / catatan penolakan" hanya ~60% lebar modal dan
   tampak menggantung. Dibuat penuh, karena itu isian paling panjang di modal. */
#bayar-ajukan textarea, #bayar-putus textarea, #pasokan-modal textarea, #lapor-alasan { width: 100%; }

/* ---- Notifikasi melayang (toast) ----
   Melayang di atas, di tengah, di atas segalanya. `position: fixed` supaya tidak
   ikut tergulir; `max-width` supaya pesan panjang tetap terbaca di ponsel. */
#hub-toast { position: fixed; top: .9rem; left: 50%; transform: translateX(-50%);
  z-index: 90; display: flex; flex-direction: column; gap: .5rem; width: min(30rem, calc(100vw - 1.6rem));
  pointer-events: none; }
#hub-toast .toast { pointer-events: auto; padding: .7rem 1rem; border-radius: var(--r-kecil);
  border: 1px solid; box-shadow: var(--bayang-2); font-size: .875rem; font-weight: 600;
  animation: toast-masuk .22s ease-out; }
#hub-toast .toast.ok { background: var(--hijau-l); color: #14512f; border-color: var(--hijau-g); }
#hub-toast .toast.rusak { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }
#hub-toast .toast.keluar { opacity: 0; transform: translateY(-.4rem); transition: all .35s ease-in; }
@keyframes toast-masuk { from { opacity: 0; transform: translateY(-.5rem); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  #hub-toast .toast { animation: none; }
  #hub-toast .toast.keluar { transition: none; }
}

/* ---- Form Tugas Cepat (/workspace) ----
   Bentuknya sengaja TIDAK memakai `.grid-form` generik. Terukur dengan
   `auto-fit minmax(230px,1fr)` pada form 1073px: grid menghasilkan EMPAT kolom
   sementara isiannya hanya dua (judul & tenggat, 255px masing-masing) — separuh
   kanan form menganggur dan isian tampak menggantung di kiri. Row-gap-nya juga 0
   (`.grid-form` hanya `gap: 0 1.1rem`), jadi barisnya rapat dan tidak terbaca
   sebagai kelompok.

   Di sini grid-nya eksplisit: dua kolom untuk judul & tenggat supaya keduanya
   memakai LEBAR PENUH form, dan satu baris untuk tombol yang rata kanan. */
.form-cepat { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 1.05rem 1.1rem; align-items: start; }
.form-cepat > .penuh { grid-column: 1 / -1; }
.form-cepat label { display: block; margin: 0; }
/* Tinggi kontrol dikunci dari SATU variabel. Tanpa ini <input> 43px berdiri di
   sebelah <input type=date> 45px — beda 2px dari bawaannya, dan itu yang paling
   kentara saat dikatakan "kurang rapih". */
.form-cepat input:not([type="hidden"]), .form-cepat select {
  width: 100%; height: 42px; min-height: 0; margin: .35rem 0 0; padding: 0 .8rem;
  font-size: .875rem; }
.form-cepat .cari-kop { margin-top: .35rem; }
.form-cepat .cari-kop input { margin-top: 0; }
/* Keterangan "Terpilih: …" menempel pada kotaknya, bukan melayang di bawah
   dengan jarak label — kalau tidak, blok Koperasi 20px lebih tinggi dari
   siblingnya dan barisnya tidak rata. */
.form-cepat .bantuan { margin-top: .4rem; }
.form-cepat .aksi { display: flex; justify-content: flex-end; align-items: center;
  gap: .6rem; padding-top: .3rem; }
.form-cepat .aksi .tombol { min-width: 9.5rem; }
@media (max-width: 720px) {
  .form-cepat { grid-template-columns: minmax(0, 1fr); }
  .form-cepat .aksi { justify-content: stretch; }
  .form-cepat .aksi .tombol { flex: 1 1 auto; }
}

/* ---- /keuangan: kotak lingkup (mode agregat) ----
   Sebelumnya baris "Sedang dilihat: …" hanya <p class="bantuan"> tanpa jarak
   bawah (terukur margin-bottom 0px, jarak ke kartu 0px) sehingga menempel ke
   kartu di bawahnya. Di mode agregat ia juga butuh wadah sendiri karena berisi
   pemilih koperasi — bukan sekadar keterangan. */
.lingkup-kop { display: flex; flex-wrap: wrap; gap: .8rem 1rem; align-items: center;
  justify-content: space-between; border: 1px solid var(--garis); border-radius: var(--r-kecil);
  background: var(--putih); padding: .8rem 1rem; margin: 0 0 1.1rem; }
.lingkup-kop b { font-size: .95rem; }
.lingkup-kop small { display: block; }
.lingkup-kop .cari-kop { margin-top: .3rem; min-width: 15rem; }
.lingkup-kop form.saring { margin: 0; padding: 0; }
/* Keterangan "Sedang dilihat" pada mode satu koperasi — jarak bawahnya dulu 0.
   Diberi cakupan #daftar (bukan #keuangan yang tidak ada) supaya SELECTOR-nya
   benar-benar cocok; selektor yang tidak cocok tidak memunculkan galat apa pun,
   hanya diam — persis jenis kesalahan yang paling lama dicari. */
#daftar .kop-terpilih { margin: .55rem 0 1.1rem; }

/* ---- /keuangan: tata letak Buku Kas ----
   Dua cacat terukur yang diperbaiki di sini:

   1. Tabel tidak memakai lebar yang tersedia — sel Aksi 22px dengan ~115px
      menganggur di kanan, dan kolom Uraian tercekik 95px walau isinya teks
      panjang. Sebabnya `th/td.kolom-aksi { width: 1% }` saja, sementara kolom
      teks tidak diberi arahan sama sekali sehingga semua kolom melebar rata.
      Di sini: kolom teks dibuat MELAR (Uraian), kolom angka & aksi tetap
      selebar isinya.
   2. `.dua-kolom` menaruh Rekap di kolom kanan yang sempit (407px dari 1117px),
      sehingga tabel kas berhenti di 648px dan sisa lebar kosong. Rekap dipindah
      ke bawah tabel; kelas `.dua-kolom` tidak dipakai lagi di halaman ini. */
#buku table { table-layout: auto; }
#buku th, #buku td { vertical-align: top; }
/* Uraian = satu-satunya kolom yang melar; sisanya selebar isinya. */
#buku th:nth-child(2), #buku td:nth-child(2) { width: auto; }
/* HANYA desktop. Aturan ini berada SETELAH media query ponsel dan memakai id
   (`#buku`), jadi spesifisitasnya mengalahkan `.tabel-bungkus td.kolom-aksi`
   milik ponsel — `width:1%` ikut terpakai di ponsel dan selnya kolaps jadi 3px
   lagi. Dibatasi ke min-width:721px supaya tata letak ponsel tetap milik
   media query-nya sendiri. */
@media (min-width: 721px) {
  #buku th.kolom-aksi, #buku td.kolom-aksi { width: 1%; white-space: nowrap; }
}
/* Isian panjang (nama koperasi pada mode agregat) jangan memaksa tabel melebar. */
#buku td.judul-sel, #buku .kwitansi { overflow-wrap: anywhere; }
@media (min-width: 721px) {
  /* Bilah saring Buku Kas: pencarian melar, dua pemilih tetap seukuran isinya. */
  #buku form.saring { display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 13rem) minmax(0, 11rem) auto auto;
    gap: .55rem; align-items: center; }
  #buku form.saring > * { min-width: 0; }
  #buku form.saring input, #buku form.saring select { width: 100%; }
}
/* Kotak pencarian koperasi pada kotak lingkup: satu bingkai (bukan .saring
   bersarang), dan kotak hasilnya mengambang dari tepi kiri kotak itu. */
.lingkup-kop form.cari-koperasi { position: relative; flex: 0 1 24rem; min-width: 0; }
.lingkup-kop form.cari-koperasi .cari-kop { margin: 0; }
.lingkup-kop form.cari-koperasi input[type="search"] { width: 100%; height: 42px;
  min-height: 0; margin: 0; padding: 0 .8rem; font-size: .875rem; }
/* Isian terkunci (baris otomatis) dibedakan tanpa menyembunyikan nilainya. */
.modal input.terkunci { background: var(--zebra); color: var(--pudar); cursor: not-allowed; }

/* ---- /workspace/dokumen: gaya halaman pengolah dokumen ----
   Kartu jenis berkas + ikon. Warnanya sengaja meniru konvensi yang sudah dikenal
   pengguna (Word biru, Excel hijau, PowerPoint oranye, PDF merah) supaya jenis
   berkas dikenali dari warna sebelum tulisannya dibaca. */
.kartu-jenis { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: .8rem; }
.kartu-jenis .dok-pilih { display: flex; flex-direction: column; align-items: center;
  gap: .35rem; padding: 1.1rem .8rem; text-align: center; cursor: pointer;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r);
  font-family: inherit; font-size: .9rem; color: var(--tinta);
  transition: border-color .12s, box-shadow .12s, transform .12s; }
.kartu-jenis .dok-pilih:hover { border-color: var(--hijau-500); box-shadow: var(--bayang-2);
  transform: translateY(-1px); }
.kartu-jenis .dok-pilih:focus-visible { outline: 2px solid var(--hijau-600); outline-offset: 2px; }
.kartu-jenis .dok-pilih b { font-size: .95rem; }
.kartu-jenis .dok-pilih small { display: block; font-size: .74rem; line-height: 1.3; }

.dok-ikon { width: 34px; height: 34px; flex: 0 0 auto; display: inline-flex;
  align-items: center; justify-content: center; border-radius: .5rem; color: #fff; }
.dok-ikon svg { width: 20px; height: 20px; }
.dok-ikon.kecil { width: 24px; height: 24px; border-radius: .35rem; vertical-align: -6px; }
.dok-ikon.kecil svg { width: 15px; height: 15px; }
.dok-ikon.doc { background: #2b579a; }
.dok-ikon.xls { background: #217346; }
.dok-ikon.ppt { background: #c43e1c; }
.dok-ikon.pdf { background: #b3202c; }

/* Tab kelompok dokumen — sebaris, aktif ditandai garis bawah. */
.dok-tab { display: flex; flex-wrap: wrap; gap: .2rem; margin: 0 0 .9rem;
  border-bottom: 1px solid var(--garis); }
.dok-tab a { display: inline-flex; align-items: center; gap: .4rem; padding: .5rem .85rem;
  font-size: .85rem; font-weight: 600; color: var(--tinta-2); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px; }
.dok-tab a:hover { color: var(--tinta); }
.dok-tab a.ini { color: var(--hijau-700); border-bottom-color: var(--hijau-600); }
.dok-tab .jml { background: var(--zebra); border-radius: 999px; padding: .05rem .45rem;
  font-size: .72rem; color: var(--pudar); }
.dok-tab a.ini .jml { background: var(--hijau-100); color: var(--hijau-700); }

/* Pilihan akses di dialog: radio + keterangan, satu baris per pilihan. */
.dok-pilih-akses { border: 0; padding: 0; margin: 0 0 .9rem; }
.dok-pilih-akses legend { font-size: .82rem; font-weight: 600; color: var(--tinta-2);
  padding: 0; margin-bottom: .4rem; }
.dok-pilih-akses .pilihan { display: flex; align-items: flex-start; gap: .55rem;
  border: 1px solid var(--garis); border-radius: var(--r-kecil); padding: .55rem .7rem;
  margin-bottom: .4rem; cursor: pointer; font-weight: 400; }
.dok-pilih-akses .pilihan:hover { border-color: var(--hijau-500); }
/* `:has()` memilih kartu yang radionya tercentang — tanpa JS sama sekali. */
.dok-pilih-akses .pilihan:has(input:checked) { border-color: var(--hijau-600);
  background: var(--hijau-l); }
.dok-pilih-akses .pilihan input { width: auto; height: auto; margin: .2rem 0 0; flex: 0 0 auto; }
.dok-pilih-akses .pilihan b { display: block; font-size: .87rem; }
.dok-pilih-akses .pilihan small { display: block; font-size: .76rem; color: var(--pudar); }

/* PDF: panel ringkas, bukan editor kosong. */
.dok-pdf { display: flex; gap: .9rem; align-items: flex-start; padding: .9rem;
  background: var(--zebra); border: 1px solid var(--garis); border-radius: var(--r-kecil); }
.dok-pdf .dok-ikon { width: 44px; height: 44px; }
.dok-pdf .dok-ikon svg { width: 26px; height: 26px; }
.dok-pdf b { font-size: .95rem; }
.dok-pdf p { margin: .2rem 0 0; font-size: .82rem; }

/* ---- /workspace/catatan-harian: catatan pribadi ----
   Kartu, bukan tabel: catatan itu tulisan bebas (bisa panjang, berbaris-baris),
   dan tabel memaksa isinya jadi satu baris terpotong. */
.cat-kepala { display: flex; flex-wrap: wrap; gap: .6rem 1rem; align-items: center;
  justify-content: space-between; margin-bottom: .9rem; }
.cat-kepala h2 { margin: 0; }
.cat-tanggal { display: flex; gap: .5rem; align-items: center; }
.cat-tanggal input[type="date"] { width: auto; margin: 0; height: 42px; }

.cat-kartu { display: flex; gap: .9rem; align-items: flex-start;
  background: var(--putih); border: 1px solid var(--garis); border-radius: var(--r-kecil);
  border-left: 3px solid var(--pudar); padding: .8rem .9rem; margin-bottom: .6rem; }
.cat-kartu.kecil { padding: .7rem .8rem; margin-bottom: 0; }
.cat-kartu .cat-isi { flex: 1 1 auto; min-width: 0; }
.cat-kartu h3 { margin: 0 0 .2rem; font-size: .98rem; line-height: 1.35; }
.cat-kartu.kecil h3 { font-size: .92rem; }
.cat-meta { margin: 0 0 .35rem; font-size: .74rem; color: var(--pudar);
  display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.cat-teks { font-size: .87rem; line-height: 1.5; color: var(--tinta-2);
  overflow-wrap: anywhere; }
/* Batasi tinggi pratinjau di arsip: satu catatan panjang tidak boleh mengubur
   puluhan catatan lain di bawahnya. */
.cat-kartu.kecil .cat-teks { display: -webkit-box; -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; overflow: hidden; }
.cat-kendala { margin-top: .45rem; padding: .45rem .6rem; font-size: .82rem;
  background: var(--zebra); border-radius: var(--r-kecil); color: var(--tinta-2);
  overflow-wrap: anywhere; }
.cat-kendala b { display: block; font-size: .72rem; text-transform: uppercase;
  letter-spacing: .05em; color: var(--pudar); margin-bottom: .15rem; }
.cat-aksi { flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: .35rem; align-items: flex-start; }
.cat-aksi form { margin: 0; }

/* Warna tepi kiri per jenis — dibaca sekilas sebelum teksnya dibaca. */
.cat-kegiatan { border-left-color: #2b579a; }
.cat-kendala  { border-left-color: #b3261e; }
.cat-rencana  { border-left-color: #0e5a66; }
.cat-ide      { border-left-color: #8a6d00; }
.cat-penting  { border-left-color: #7a3ea8; }

.cat-arsip-baris { display: grid; gap: .55rem; }
.cat-kosong { text-align: center; padding: 1.6rem 1rem; border: 1px dashed var(--garis);
  border-radius: var(--r-kecil); background: var(--zebra); }
.cat-kosong p { margin: 0 0 .35rem; }
.cat-kosong .tombol { margin-top: .5rem; }

/* Dua kolom di dalam dialog (jenis + tanggal) — berdampingan saat lapang. */
.cat-dua { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
.cat-saran { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.cat-saran .pil { font: inherit; font-size: .76rem; padding: .18rem .55rem; cursor: pointer;
  border: 1px solid var(--garis); border-radius: 999px; background: var(--putih);
  color: var(--tinta-2); }
.cat-saran .pil:hover { border-color: var(--hijau-500); color: var(--hijau-700); }

/* 🔴 Tinggi tombol disamakan lewat SEL-nya. Sebelum ini tombol 32px dan form
   jadi 43px: `align-items: flex-start` menjadikan tiap anak flex-item, sehingga
   FORM ikut jadi flex container dengan tinggi barisnya sendiri — dan Hapus
   tampak lebih tinggi daripada Ubah. `line-height: 0` pada wadah + dipulihkan
   pada form menghapus ruang descender tanpa mengubah ukuran tombol. */
.cat-aksi { align-items: center; }
.cat-aksi form { line-height: 0; display: flex; }
/* `margin: 0` WAJIB: ada aturan global yang memberi tombol di dalam form
   `margin-top: .7rem` (11,2px), sehingga wadah tombol jadi 43px sementara
   tombolnya sendiri tetap 32px — itulah "tombol berantakan" yang terlihat. */
.cat-aksi .tombol { line-height: 1.35; margin: 0; }

/* Dialog Detail (baca-saja). */
.cat-detail { font-size: .9rem; line-height: 1.55; color: var(--tinta-2);
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 46vh; overflow-y: auto;
  padding: .1rem 0; }
 #cat-lihat .cat-kendala { white-space: pre-wrap; }

/* Ponsel: aksi turun ke bawah isi (kartu satu kolom), tombol memenuhi lebar
   supaya mudah ditekan — bukan dua tombol kecil berdempetan. */
@media (max-width: 640px) {
  .cat-kartu { flex-direction: column; gap: .6rem; }
  .cat-aksi { width: 100%; }
  .cat-aksi .tombol, .cat-aksi form { flex: 1 1 auto; }
  .cat-aksi .tombol { width: 100%; justify-content: center; }
  .cat-dua { grid-template-columns: 1fr; }
  .cat-tanggal { width: 100%; }
  .cat-tanggal input[type="date"] { flex: 1 1 auto; min-width: 0; }
}

/* ---- /workspace/kalender: bagian desktop ----
   Peta bulan tetap kisi 7 kolom; acara tampil DI DALAM sel (lihat aturan .kal-*
   di atas). Daftar per tanggal hanya untuk ponsel. */
.kal-kepala { display: flex; flex-wrap: wrap; gap: .6rem 1rem; align-items: center;
  justify-content: space-between; margin-bottom: .9rem; }
.kal-kepala h2 { margin: 0; }
.kal-navigasi { display: flex; flex-wrap: wrap; gap: .35rem; }
.kal-tgl { display: flex; align-items: center; gap: .3rem; }
.kal-angka { font-variant-numeric: tabular-nums; }
.kal-titik { display: none; background: var(--hijau-100, #e3efe8); color: #15402f;
  border-radius: 999px; font-size: .66rem; font-weight: 700; padding: .02rem .34rem; }
.kal-jam { flex: 0 0 auto; }
.kal-nama { min-width: 0; }
.kal-dua { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
.kal-pekan .kal-angka { color: #9aa5a0; }

/* ---- /workspace/tugas: kartu ringkasan, status berwarna, progres ---- */
.tg-kartu { display: grid; grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); gap: .5rem;
  /* `grid-auto-rows: 1fr` menyamakan tinggi SELURUH baris kartu. Tanpa ini,
     label yang membungkus ("Perlu Revisi") membuat barisnya lebih tinggi daripada
     baris lain, dan deretan kartu tampak bergerigi. */
  grid-auto-rows: 1fr; }
.tg-kartu .kartu { text-align: center; padding: .6rem .5rem; text-decoration: none; }
.tg-kartu .kartu b { display: block; font-size: 1.25rem; line-height: 1.2; }
.tg-kartu .kartu small { font-size: .72rem; }
.tg-kartu .kartu.ini { outline: 2px solid var(--hijau-600); outline-offset: -2px; }
.pil-status { font-weight: 600; }
.pil-status.biru { color: #1d4ed8; } .pil-status.kuning { color: #92600a; }
.pil-status.ungu { color: #6b21a8; } .pil-status.oranye { color: #b45309; }
.pil-status.merah { color: #b3261e; } .pil-status.hijau { color: #1a7f4b; }
.prio-rendah { background: #eef2f0; color: #4b5b54; } .prio-normal { background: #e3efe8; color: #15402f; }
.prio-tinggi { background: #fdeceb; color: #b3261e; }
.tg-telat { color: #b3261e; font-weight: 600; }
.tg-desk, .tg-catatan { display: block; }
.tg-catatan { margin-top: .2rem; padding: .3rem .45rem; background: var(--zebra);
  border-radius: var(--r-kecil); font-size: .78rem; }
.tg-riwayat { margin: .4rem 0 0; padding-left: 1.1rem; font-size: .82rem; }
.tg-riwayat li { margin-bottom: .45rem; }
.tg-riwayat li div { overflow-wrap: anywhere; }
.tg-dua { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }

/* ---- /workspace/jobdesc: daftar uraian tugas dari Lampiran PKWT ---- */
.jd-daftar { display: grid; gap: .55rem; grid-template-columns: minmax(0, 1fr); }
.jd-kartu { border: 1px solid var(--garis); border-left: 3px solid var(--pudar);
  border-radius: var(--r-kecil); background: var(--putih); padding: .6rem .75rem; }
.jd-kartu.jd-wajib { border-left-color: #2b579a; }
.jd-kepala { display: flex; gap: .5rem; align-items: flex-start; flex-wrap: wrap; }
.jd-kepala h3 { margin: 0; font-size: .92rem; flex: 1 1 auto; min-width: 0; }
.jd-no { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 999px; background: var(--zebra);
  color: var(--tinta-2); font-size: .72rem; font-weight: 700; display: inline-flex;
  align-items: center; justify-content: center; }
.jd-wajib .jd-no { background: #2b579a; color: #fff; }
.jd-menit { flex: 0 0 auto; }
.jd-desk { margin: .35rem 0 0 30px; font-size: .82rem; line-height: 1.5; color: var(--tinta-2);
  overflow-wrap: anywhere; }
.jd-poin { margin: 1rem 0 .4rem; font-size: .86rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--hijau-700); }

@media (max-width: 640px) {
  .tg-kartu { grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); }
  .tg-dua { grid-template-columns: 1fr; }
  .jd-desk { margin-left: 0; }
}

/* Kepala satu bagian: judul di kiri, tombol di kanan (dipakai dasbor & halaman
   modul). Flex-wrap supaya di ponsel tombol turun sendiri, bukan menekan judul. */
.kepala-bagian { display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: center;
  justify-content: space-between; margin-bottom: .8rem; }
.kepala-bagian h2 { margin: 0; }
.kepala-bagian .tombol-baris { display: flex; flex-wrap: wrap; gap: .35rem; }

/* ============================================== AgriConnect (modul mandiri)
   Hanya tiga hal yang benar-benar baru: daftar alasan, daftar ringkas di kartu,
   dan isi pelajaran. Selebihnya memakai kelas bersama (.kartu, .blok, .lencana,
   .tabel-bungkus, .modal) — tidak ada gaya baru untuk hal yang sudah ada. */
.daftar-alasan { margin: .6rem 0 0; padding-left: 1.1rem; font-size: .86rem; line-height: 1.65; }
.daftar-alasan li { margin-bottom: .3rem; }
.daftar-ringkas { margin: .5rem 0 .7rem; padding-left: 1.1rem; font-size: .84rem; line-height: 1.5; }
.daftar-ringkas li { margin-bottom: .25rem; }
/* Isi pelajaran: teks apa adanya, tetapi baris barunya dipertahankan dan
   dibatasi lebarnya supaya enak dibaca di layar lebar. */
.materi-isi { white-space: pre-wrap; max-width: 68ch; line-height: 1.7; font-size: .93rem; }
.pilihan-sebaris { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }

/* Daftar langkah E-Learning: tombol centang di kiri, teks langkah di kanan.
   Baris yang sudah tuntas ditandai centang, bukan disembunyikan. */
.daftar-langkah { list-style: none; margin: .5rem 0 .7rem; padding: 0; font-size: .88rem; }
.daftar-langkah li { display: flex; align-items: center; gap: .5rem; padding: .3rem 0;
  border-bottom: 1px solid var(--garis, #e6e8ee); }
.daftar-langkah li form { margin: 0; }
.daftar-langkah li.sudah { color: var(--pudar, #6b7280); }

/* ---- /admin/materi: unggah berprogres + daftar materi ----
   Kotak seret-lepas di kiri, isian di kanan; satu kolom di layar sempit.

   Kotak IKUT TINGGI baris (`stretch`) dan isinya dipusatkan tegak. Dengan
   `align-items: start` kotak setinggi 186px menggantung di atas sementara isian
   kanan setinggi 330px, sehingga kotak terbaca "melayang terlalu ke atas".
   Meregangkannya membuat tepi atas & bawahnya sejajar dengan kolom isian. */
.grid-form-mm { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: 1.05rem 1.2rem; align-items: stretch; }
.lebar-penuh-mm { grid-column: 1 / -1; }
.mm-aksi { grid-column: 1 / -1; display: flex; align-items: center; justify-content: flex-end;
  gap: .8rem; flex-wrap: wrap; border-top: 1px solid var(--garis-2); padding-top: .9rem; }
/* Status kesiapan rata KIRI, mendorong tombolnya ke kanan — tanpa ini ia ikut
   terdorong dan terbaca seperti label tombolnya. */
.mm-aksi .bantuan { flex: 1 1 auto; margin: 0; text-align: left; }

/* Kotak seret-lepas. <input type=file> aslinya disembunyikan lewat clip-path,
   BUKAN display:none — supaya ia tetap fokusable dan label `for`-nya tetap
   terbuka oleh klik maupun Enter saat JavaScript mati.
   `flex-direction: column` menumpuk kartu berkas/bilah kemajuan tegak (bawaan
   flex adalah BARIS, yang membuat keduanya berdampingan). `min-height` menjaga
   kotak tidak mengempis di ponsel saat ajakan diganti kartu berkas — di sana
   grid satu kolom, jadi kotak tidak lagi mewarisi tinggi kolom isian. */
.mm-jatuh { position: relative; display: flex; flex-direction: column; justify-content: center;
  min-height: 172px;
  border: 1.5px dashed #c8d6cf;
  border-radius: var(--r); background: var(--zebra); transition: border-color .12s, background .12s; }
.mm-berkas { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); border: 0; }
/* `flex: 1 1 auto` membuat ajakan ini memenuhi tinggi kotak; `min-height`
   adalah LANTAI saat kolom kanan kebetulan lebih pendek (mis. sesudah berkas
   terpilih, tinggi kotak tidak lagi ikut baris). Isi dipusatkan tegak. */
.mm-jatuh-isi { display: flex; flex-direction: column; align-items: center; justify-content: center;
  flex: 1 1 auto; gap: .3rem; text-align: center; padding: 1.4rem 1rem; margin: 0; cursor: pointer;
  color: var(--tinta-2); font-weight: 500; min-height: 172px; }
.mm-jatuh-isi:hover { color: var(--hijau-700); }
.mm-jatuh-isi b { font-size: .95rem; }
.mm-jatuh-isi span { font-size: .85rem; color: var(--pudar); }
.mm-jatuh-isi u { text-decoration-color: var(--hijau-500); }
.mm-jatuh-isi small.bantuan { margin-top: .35rem; max-width: 32ch; }
.mm-jatuh-ikon { width: 34px; height: 34px; fill: none; stroke: var(--hijau-600);
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; margin-bottom: .2rem; }
.mm-jatuh.mm-seret { border-color: var(--hijau-500); background: var(--hijau-100); }
.mm-jatuh.mm-seret .mm-jatuh-isi { color: var(--hijau-700); }
/* Berkas terpilih: kotak isi diganti kartu berkas, jadi tidak ada dua ajakan
   yang saling menimpa dan bingkai putus-putusnya tidak lagi relevan. */
.mm-jatuh.ada-berkas { border-style: solid; border-color: var(--hijau-g); background: var(--putih); }
.mm-terpilih { display: flex; align-items: center; gap: .65rem; padding: 1rem; }
.mm-terpilih-ikon { width: 26px; height: 26px; flex: 0 0 auto; fill: none; stroke: var(--hijau-600);
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.mm-terpilih-teks { min-width: 0; flex: 1 1 auto; }
.mm-terpilih-teks b { display: block; font-size: .9rem; overflow-wrap: anywhere; }
.mm-terpilih-teks small { color: var(--pudar); }

/* Bilah kemajuan unggah — memakai .jejak yang sudah ada, bukan komponen baru. */
.mm-jalur { padding: .1rem 1rem 1rem; }
.mm-jalur .jejak { height: 10px; }
.mm-jalur .jejak > span { background: var(--hijau-600); transition: width .15s linear; }
.mm-jalur small { margin-top: .4rem; color: var(--pudar); }

.mm-isian label { display: block; }

/* Nama berkas bisa sangat panjang: boleh putus, dan dibatasi lebarnya supaya
   kolom lain tidak tercekik. */
.berkas-nama { display: block; max-width: 32ch; overflow-wrap: anywhere; }

/* Ponsel: isian minimal 16px.
   Safari iOS MEMPERBESAR halaman saat isian difokuskan bila ukuran hurufnya di
   bawah 16px — halaman melompat dan tata letaknya rusak di tengah pengisian.
   Basis huruf halaman 15px, jadi selisih 1px itu cukup untuk memicu zoom.
   Dipasang di SATU tempat untuk semua isian, bukan per halaman: satu aturan
   menutup seluruh formulir (profil, toko, stok, …) sekaligus. */
@media (max-width: 720px) {
  input, select, textarea { font-size: 16px; }
}

@media (max-width: 720px) {
  .grid-form-mm { grid-template-columns: minmax(0, 1fr); }
  .mm-aksi { justify-content: stretch; }
  .mm-aksi .bantuan { flex: 1 1 100%; }
  .mm-aksi .tombol { flex: 1 1 auto; }
}

/* ============================================ tab meja SDM (/admin/hr)
   Empat tab meja kepegawaian. Sama seperti .rapat-tab: satu baris, boleh
   digulir mendatar di ponsel supaya label tidak terpotong (bukan mengecilkan
   huruf), dan tab aktif ditandai garis bawah — bukan hanya warna. */
.pil-baris { display: flex; gap: .35rem; overflow-x: auto; overscroll-behavior-x: contain;
  border-bottom: 1px solid var(--garis); margin: 0 0 1rem; padding-bottom: 0; }
.pil-baris .pil { flex: none; padding: .45rem .8rem; font: inherit; font-size: .88rem;
  text-decoration: none; color: var(--pudar); border-bottom: 2px solid transparent;
  white-space: nowrap; }
.pil-baris .pil:hover { color: var(--tinta-2); }
.pil-baris .pil.ini { color: var(--tinta); font-weight: 600; border-bottom-color: var(--hijau); }

@media (max-width: 720px) {
  /* Ponsel: empat label panjang ("Rekrutmen & Onboarding") tidak muat sebaris.
     MEMBUNGKUS, bukan menggulir: gulir mendatar menyembunyikan tab terakhir —
     dan Bos melarang menyembunyikan informasi di ponsel (terukur 2 pil keluar
     layar di 320px saat mode gulir). */
  .pil-baris { flex-wrap: wrap; overflow-x: visible; margin-bottom: .8rem; row-gap: .1rem; }
  .pil-baris .pil { font-size: .84rem; padding: .4rem .6rem; }
}

/* ================================================== payroll (/admin/hr?tab=pembayaran)
   Satu baris aksi periode menampung saringan, isian UMK, dan tombol kunci.
   Sebelumnya formulir-formulir itu berdiri sendiri tanpa bingkai sehingga label,
   isian, dan tombol tidak sejajar (terukur: label 71 px melawan isian 43 px, dan
   tombol naik-turun antar breakpoint). */
.aksi-periode { display: flex; flex-wrap: wrap; gap: .6rem; align-items: flex-end;
  padding: .8rem; margin: .9rem 0 1rem; background: var(--zebra);
  border: 1px solid var(--garis); border-radius: var(--r); }
.aksi-periode > form { margin: 0; }
.aksi-periode .saring { flex: 1 1 30rem; min-width: 0; }
.aksi-periode .medan-aksi { display: flex; flex-wrap: wrap; gap: .5rem; align-items: flex-end; }
/* Tombol di ujung baris medan: `label + .tombol` (11,2 px) menambah jarak yang
   membuat dasarnya meleset dari dasar isian di sebelahnya — di baris ber-
   `align-items:flex-end` jarak itu justru merusak kesejajaran. */
.medan-aksi > .tombol { margin-top: 0; }
/* Kolom Sasaran (Select2) butuh lebih dari 9rem: nama wilayah + nominal. */
.medan-aksi .medan-sasaran { flex: 0 0 12rem; max-width: 12rem; }
.medan-sasaran .select2-container, .medan-sasaran .select2-selection { width: 100% !important; }
/* `margin: 0` WAJIB: `label` membawa margin-bawah 13,6 px (aturan global), dan
   pada baris ber-`align-items:flex-end` margin itu dihitung sebagai bagian
   kotak label — dasarnya jadi 13,6 px di atas tombol sebelahnya. */
.medan { display: flex; flex-direction: column; gap: .28rem; margin: 0; }
.medan > span { font-size: .72rem; letter-spacing: .03em; text-transform: uppercase; color: var(--tinta-2); }
.medan input, .medan select { height: 2.6rem; min-width: 9rem; margin: 0; }
.aksi-periode > .tombol { align-self: flex-end; }
/* Isi pengumuman berbagi formulir dengan massal: ia turun ke barisnya sendiri
   selebar baris (bukan kolom sempit di ujung), dan tombolnya tetap sejajar. */
.medan-aksi > .pengumuman-isi { flex: 1 0 100%; margin: 0; }
/* Tombol berdampingan ("Terapkan massal" + "Kirim Pengumuman") tetap satu gugus:
   tanpa wadah, tombol kedua terdorong ke baris sendiri dan kehilangan pasangannya. */
.pasangan-tombol { display: flex; gap: .5rem; flex: 0 0 auto; align-items: flex-end; }
/* Isi pengumuman: perihal di ATAS, pesan di bawahnya, keduanya selebar panel.
   `.grid-form` bawaan (auto-fit 230px, jarak baris 0) menaruh perihal dan pesan
   berdampingan lalu saling menempel — terbaca "asal ada". Dibuka, panelnya
   diberi latar & garis supaya jelas ini kotak isian, bukan baris tombol. */
.pengumuman-isi > summary { cursor: pointer; font-size: .8rem; font-weight: 600; color: var(--tinta-2); }
.pengumuman-isi > summary::marker { color: var(--hijau-700); }
.pengumuman-isi[open] { background: var(--putih); border: 1px solid var(--garis);
  border-radius: var(--r); padding: .7rem .85rem .85rem; }
.pengumuman-isi[open] > summary { margin-bottom: .65rem; }
.pengumuman-isi .grid-form { grid-template-columns: minmax(0, 1fr); gap: .75rem; }
.pengumuman-isi .medan input, .pengumuman-isi .medan textarea { width: 100%; box-sizing: border-box; }
.pengumuman-isi textarea { height: auto; min-height: 5.2rem; line-height: 1.55; resize: vertical; }
.pengumuman-isi .bantuan { margin: 0; }
/* Kepala panel asisten: tombol Hapus Percakapan jadi butir flex tersendiri. */
.ai-kepala > form { flex: none; margin: 0; }

/* Nominal uang: rata kanan + digit selebar sama, supaya angka bisa dibandingkan
   sekilas. Dulu kolom ini berisi <input type=number> selebar 71 px sehingga
   2.520.000 terpotong di tengah. */
.angka-sel { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.angka-sel b { display: block; font-size: 1rem; }
.angka-sel small { display: block; font-variant-numeric: tabular-nums; }
th.ka { text-align: right; }
/* Nama & rekening butuh ruang; tanpa ini kolomnya mengalah pada tombol dan
   setiap baris jadi tiga baris teks (terukur 261-298 px per baris). */
.tabel-bungkus td[data-l="Pegawai"] { min-width: 13rem; }
.tabel-bungkus td[data-l="Rekening"] { min-width: 11rem; }
/* Tombol tindakan selebar sama supaya kolomnya rata, bukan 89/80/44 px. */
.tabel-bungkus td.kolom-aksi .tombol.mini { min-width: 4.5rem; }
/* Tablet 768: kolom minimum selebar desktop membuat tabel 927 px di wadah 684 px.
   Dikecilkan di sini (bukan dihapus) supaya nama tetap dua baris, bukan lima. */
@media (max-width: 900px) {
  .tabel-bungkus td[data-l="Pegawai"] { min-width: 9rem; }
  .tabel-bungkus td[data-l="Rekening"] { min-width: 8rem; }
  .tabel-bungkus td.kolom-aksi .tombol.mini { min-width: 3.75rem; padding-inline: .45rem; }
}
.tabel-ringkas td, .tabel-ringkas th { font-size: .86rem; }

@media (max-width: 720px) {
  /* Ponsel: saringan & isian tidak mungkin sebaris — beri tiap form satu baris
     penuh, tombolnya melebar supaya mudah ditekan. */
  .aksi-periode { padding: .7rem; }
  .aksi-periode .saring, .aksi-periode .medan-aksi { flex: 1 1 100%; }
  .aksi-periode .medan-aksi .medan { flex: 1 1 100%; }
  .aksi-periode .medan-aksi .tombol { width: 100%; }
  /* Dua tombol berdampingan di ponsel: tetap SATU baris, lebar dibagi rata.
     Tanpa ini wadahnya memaksa lebar isi dan halaman meluber (terukur 53px
     pada 320px). */
  .aksi-periode .medan-aksi .pasangan-tombol { flex: 1 1 100%; }
  .aksi-periode .medan-aksi .pasangan-tombol .tombol { flex: 1 1 0; min-width: 0; width: auto; }
  .aksi-periode > .tombol { width: 100%; }
}

/* ================================================== panel analisa lintas modul
   Dipakai partials/analisa.blade.php (Jurnal Audit & Struktur & Tim). Semua
   grafiknya CSS murni — tanpa pustaka grafik, tanpa JavaScript — mengikuti pola
   grafik arus kas modul Keuangan.

   SATU batang per hari, tumbuh dari garis dasar (`align-items: flex-end`),
   BUKAN batang dua arah seperti arus kas: arus kas punya nol di tengah karena
   nilainya bisa negatif, sedangkan jumlah aktivitas tidak pernah negatif dan
   nol-di-tengah hanya membuat batangnya tampak menggantung. `height: 100%`
   pada kolom WAJIB ada di atas `align-items: flex-end` — tanpa itu persentase
   tinggi batang diukur dari tinggi intrinsik kolom dan grafiknya tidak tumbuh. */
.tren { display: flex; align-items: flex-end; gap: 2px; height: 96px; margin: .2rem 0 .3rem;
  padding: .5rem .55rem 0; background: var(--zebra); border: 1px solid var(--garis);
  border-radius: var(--r-kecil); box-shadow: var(--bayang); }
.tren-kolom { flex: 1 1 0; min-width: 2px; height: 100%; display: flex;
  align-items: flex-end; border-radius: 2px 2px 0 0; }
.tren-kolom i { display: block; width: 100%; min-height: 2px; border-radius: 2px;
  background: var(--hijau-500); }
/* Hari tanpa aktivitas tetap tampil (batang pendek) supaya hari sepi tidak
   menghilang dan trennya tidak terbaca lebih ramai daripada kenyataannya. */
.tren-kolom.kosong i { background: var(--garis); opacity: .55; }
.tren-kolom:hover i { filter: brightness(.88); }

/* Baris pita: label — batang — angka. Dipakai cakupan kerja, sebaran, aksi,
   dan kesiapan supaya semuanya terbaca dengan satu bahasa visual. */
.petak-kotak { display: grid; gap: .55rem; margin-top: .7rem; }
.petak-kotak .jejak-baris { display: grid; grid-template-columns: minmax(88px, 1.5fr) minmax(70px, 3fr) auto;
  align-items: center; gap: .7rem; }
.petak-kotak .jejak-baris .nama { min-width: 0; overflow-wrap: anywhere; font-size: .84rem; }
.petak-kotak .jejak-baris b { font-variant-numeric: tabular-nums; font-size: .84rem; color: var(--tinta); text-align: right; }
.petak-kotak .jejak-baris small { grid-column: 2 / -1; margin-top: -.2rem; }
/* Ember sebaran: hijau makin tua seiring aktivitas. Yang "belum ada" memakai
   abu-abu, BUKAN merah — ia keadaan awal, bukan kesalahan. */
.petak-kotak .jejak > span.e-nol { background: var(--garis); }
.petak-kotak .jejak > span.e-rendah { background: var(--merah-g); }
.petak-kotak .jejak > span.e-sedang { background: var(--kuning-g); }
.petak-kotak .jejak > span.e-tinggi { background: var(--hijau-500); }
.petak-kotak .jejak > span.peringatan { background: var(--merah-g); }
/* Deretan lencana nama koperasi dorman: wadah terpisah supaya tidak menempel
   satu baris teks panjang yang menyulitkan pemindaian.
   `white-space: normal` WAJIB di sini: `.lencana` memakai `nowrap`, dan nama
   koperasi bisa 56 karakter ("KOPERASI DESA MERAH PUTIH CIBEBER KECAMATAN
   SUKAGUMIWANG" terukur 441px) sehingga halaman meluber mendatar di ponsel
   (478px di layar 390px). Ia lencana nama, bukan penanda status — membungkus
   dua baris tidak apa-apa. */
.lencana.samar { background: var(--zebra); color: var(--tinta-2); font-size: .74rem;
  padding: .18rem .5rem; margin: 0 .25rem .3rem 0; white-space: normal;
  max-width: 100%; overflow-wrap: anywhere; }
.lencana.samar::before { display: none; }

/* Varian warna lencana untuk pengumuman & aspirasi (jenis + status).
   Rumah ini sudah punya polanya lewat `.s-<STATUS>`; varian nama-panjang ini
   dipakai di tempat yang statusnya bukan salah satu konstanta alur tugas. */
.lencana.hijau { background: var(--hijau-l); color: var(--hijau-600); border-color: var(--hijau-g); }
.lencana.kuning { background: var(--kuning-l); color: var(--kuning); border-color: var(--kuning-g); }
.lencana.biru { background: var(--biru-l); color: var(--biru); border-color: var(--biru-g); }
.lencana.merah { background: var(--merah-l); color: var(--merah); border-color: var(--merah-g); }

/* Forum di halaman indeks Messenger: daftar topik diskusi.
   Gaya `pilih-baris` di blok lain hanya berlaku DI DALAM `.wa-baru`, jadi
   baris forum (yang tinggal di panel ajakan) perlu bentuknya sendiri —
   kalau tidak, tautannya tampil sebagai teks polos tanpa sasaran ketuk. */
.wa-forum { margin: 1rem 0 0; text-align: left; }
.wa-forum > b { display: block; font-size: .82rem; color: var(--tinta-2); margin-bottom: .35rem; }
.wa-forum .pilih-daftar { max-height: none; padding: 0; }
.wa-forum .pilih-baris { display: block; padding: .5rem .55rem; border-radius: var(--r-kecil);
  text-decoration: none; color: inherit; }
.wa-forum .pilih-baris:hover { background: var(--hijau-100); }
.wa-forum .pilih-nama { display: block; font-weight: 600; }
.wa-forum .pilih-baris small { display: block; color: var(--pudar); font-size: .8rem; }

/* Pesan yang ditarik tampil sebagai keterangan (riwayat tidak berlubang). */
.wa-b .wa-ditarik { color: var(--pudar); }

/* Topik forum di dalam ruangnya: pembuka diskusi, bukan pesan. */
.wa-topik-bilah { display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap;
  padding: .55rem .8rem; border-bottom: 1px solid var(--garis); background: var(--zebra); }
.wa-topik-bilah b { flex: none; font-size: .74rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--pudar); }
.wa-topik-bilah span { font-size: .9rem; color: var(--tinta); }

/* ============================================ KOPERASI — halaman /kop (/kop/*)
   Semua kelas di blok ini berawalan `kop-` dan HANYA dipakai modul Koperasi.
   Sengaja tidak menumpang kelas bersama (`.kartu`, `.blok`): modul ini butuh
   tampilan yang lebih padat & berwibawa daripada daftar biasa, dan menaikkan
   gaya kelas bersama akan mengubah 40+ halaman lain yang memakainya.

   CATATAN: kepala halaman TIDAK punya gaya sendiri lagi. Versi gelap
   (`.kop-hero`) dibuang 2026-10-18 atas permintaan Bos — modul Koperasi harus
   memakai pola kepala Hub yang sama (`.kepala`), jadi tidak ada dua bahasa
   visual di satu aplikasi.
   ------------------------------------------------------------------------ */

/* Petak angka: ikon dalam kotak bersudut + angka besar. Kartu ringkasan biasa
   hanya punya label & angka, sehingga enam kotak berturut-turut tampak rata. */
.kop-stat { display: flex; gap: .7rem; align-items: flex-start; background: var(--putih);
  border: 1px solid var(--garis); border-radius: var(--r);
  padding: .85rem .95rem; box-shadow: var(--bayang); min-width: 0; }
/* Lebar kolom petak koperasi DIATUR DI SINI, bukan di `.petak` (dipakai juga
   oleh halaman lain): 7 kartu dengan auto-fit jatuh jadi 6+1. Ponsel 2 kolom,
   tablet 3, desktop 4 — 4+3 selalu terisi, tidak ada kartu yatim. */
.petak.kop-petak { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .7rem; }
@media (min-width: 700px) { .petak.kop-petak { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .petak.kop-petak { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.kop-stat-ikon { flex: 0 0 auto; width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center; background: var(--hijau-100); color: var(--hijau-700); }
.kop-stat-ikon .ik { width: 19px; height: 19px; }
.kop-stat-teks { min-width: 0; flex: 1 1 auto; }
.kop-stat-teks small { display: block; font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--pudar); }
.kop-stat-teks b { display: block; margin-top: .12rem; line-height: 1.15;
  font-size: clamp(1.15rem, 1rem + .8vw, 1.5rem);
  font-variant-numeric: tabular-nums; color: var(--tinta); overflow-wrap: anywhere; }
/* Nilai berupa TEKS (status, proses pembangunan) tidak boleh sebesar angka:
   "Belum diisi" pada 1,5rem memenuhi kartu dan terbaca seperti judul. */
.kop-stat-teks b.teks { font-size: .95rem; font-weight: 700; line-height: 1.3; }
/* Nilai uang: lebih panjang daripada angka biasa ("Rp 1.234.567"), jadi satu
   tingkat lebih kecil supaya tidak pecah 3 baris di ponsel. */
.kop-stat-teks b.uang { font-size: 1.05rem; font-weight: 700; }
.kop-stat-teks i { display: block; margin-top: .1rem; font-style: normal;
  font-size: .72rem; line-height: 1.35; color: var(--pudar); }

/* Judul blok ber-ikon — dipakai <h2> di dalam `.blok`. */
.kop-judul { display: inline-flex; align-items: center; gap: .45rem; }
.kop-judul .ik { width: 18px; height: 18px; flex: 0 0 auto; color: var(--hijau-600); }

/* Bilah progres tipis: satu angka persen lebih baik terbaca sebagai panjang. */
.kop-progres { height: 8px; border-radius: var(--r-kapsul); background: var(--garis-2);
  overflow: hidden; margin-top: .5rem; }
.kop-progres > span { display: block; height: 100%; border-radius: var(--r-kapsul);
  background: linear-gradient(90deg, var(--hijau-500), var(--hijau-700)); }

/* Panel "Padanan Pemetaan Lahan": baris kunci–nilai yang rapat. */
.kop-peta { display: grid; gap: .1rem; margin: 0 0 .6rem; }
.kop-peta-baris { display: flex; flex-wrap: wrap; gap: .3rem .6rem; align-items: baseline;
  padding: .5rem 0; border-bottom: 1px solid var(--garis-2); font-size: .85rem; }
.kop-peta-baris:last-child { border-bottom: 0; }
.kop-peta-baris > span:first-child { flex: 0 0 auto; min-width: 9rem;
  font-size: .74rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--pudar); }
.kop-peta-baris > b { font-variant-numeric: tabular-nums; }

/* Katalog sarana prasarana (halaman /kop/sarana).
   Satu tabel untuk semua butir; kelompok (jenis pengembangan + sub-kelompok)
   jadi baris pemisah, bukan tabel terpisah — dulu 3 tabel sehingga lebar
   kolomnya tidak sejajar (terukur 251/417/348px) dan kepala tabel diulang. */
tbody tr.baris-kelompok > td { background: var(--zebra); font-weight: 700; font-size: .78rem;
  text-transform: uppercase; letter-spacing: .05em; color: var(--tinta-2); padding: .45rem .8rem;
  border-bottom: 1px solid var(--garis-2); }
tbody tr.baris-kelompok:hover > td { background: var(--zebra); }
tbody tr.baris-kelompok small { text-transform: none; letter-spacing: 0; font-weight: 600; }
.tabel-katalog td input:not([type="checkbox"]) { width: 100%; }
/* Bilah simpan menempel di dasar layar selama daftar digulir; tanpa ini tombol
   "Simpan Centang" hanya terjangkau dari dasar halaman (terukur 4.934px di
   desktop, 13.429px di ponsel). */
.bilah-simpan { position: sticky; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap;
  align-items: center; gap: .5rem .8rem; background: var(--putih);
  border-top: 1px solid var(--garis-2); padding: .7rem 0; margin-top: .6rem;
  box-shadow: 0 -8px 14px -10px rgba(16, 29, 24, .35); }
.bilah-simpan > small { margin: 0; }

@media (max-width: 720px) {
  /* Tiga tab modul: tiga kolom sama lebar, ikon di atas label — tidak lagi
     pecah 2+1 baris dengan lebar berbeda. */
  .modul-nav-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .35rem; }
  .modul-nav-3 a { flex-direction: column; min-width: 0; gap: .2rem; padding: .5rem .3rem;
    font-size: .74rem; line-height: 1.25; text-align: center; }
  /* Empat tab modul (Koperasi: Data, Sarana, POS, Karyawan): 2×2 supaya tidak
     ada satu tab yatim di baris kedua. */
  .modul-nav-4 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .35rem; }
  .modul-nav-4 a { flex-direction: column; min-width: 0; gap: .2rem; padding: .5rem .3rem;
    font-size: .74rem; line-height: 1.25; text-align: center; }
  /* Kartu ponsel: jenis konstruksi jadi baris kecil di atas indikatornya
     (label + nilai tetap terpisah agar tidak menempel seperti "ARSITEKTURruang"). */
  /* Baris kelompok di mode kartu: garis judul, bukan kartu penuh berbayang. */
  .tabel-bungkus tr.baris-kelompok { box-shadow: none; border: 0; border-radius: 0;
    background: transparent !important; border-bottom: 1px solid var(--garis-2);
    padding: .9rem 0 .3rem; margin: 0 0 .3rem; }
  .tabel-bungkus tr.baris-kelompok > td { display: block; background: transparent; padding: 0; }
  .tabel-bungkus tr.baris-kelompok > td::before { content: none; }
  .bilah-simpan { padding: .6rem 0; }
  .bilah-simpan .tombol { flex: 1 1 100%; }
  /* Baris aksi Data Koperasi (Ubah / Hapus / Lepas Tautan): tiga tombol
     selebar 107+77+124px tidak pernah muat sebaris di 390px, jadi dulu
     pecah 2+1 dengan lebar berbeda. Di ponsel ditumpuk penuh — seragam. */
  .aksi-kop { display: grid; grid-template-columns: minmax(0, 1fr); gap: .45rem; }
  /* `display: contents` menjadikan tombol di dalam <form> sebagai butir grid
     langsung; tanpa itu kotak form 51px sementara tombolnya 40px (bergerigi). */
  .aksi-kop > form { display: contents; }
  .aksi-kop > *, .aksi-kop > form > .tombol { width: 100%; }
}


@media (max-width: 720px) {
  .kop-hero { padding: 1rem 1.05rem; }
  .kop-hero-isi { gap: .85rem; }
  .kop-hero h1 { max-width: none; }
  .kop-hero-status { display: inline-flex; width: auto; }
  /* Tombol melebar penuh: di ponsel tiga tombol berdampingan menyisakan ~90px
     per tombol dan labelnya ("Keuangan Koperasi") terpotong. */
  .kop-hero .tombol-baris { width: 100%; }
  .kop-hero .tombol-baris > .tombol,
  .kop-hero .tombol-baris > form { flex: 1 1 100%; }
  .kop-hero .tombol-baris > form > .tombol { width: 100%; }
  .kop-peta-baris > span:first-child { min-width: 100%; }
}

/* ---------------------------------------------- Koperasi: POS di PONSEL
   Terukur di 390px: tabel barang berubah jadi kartu per baris (aturan global
   `.tabel-bungkus` di atas) — lima sel bertumpuk = 205px per barang. Katalog
   300 barang berarti gulir 61.500px, dan tombol "+ Keranjang" baru terlihat
   SETELAH menggulir satu kartu penuh: kasir praktis tidak bisa memakainya.
   Yang dipadatkan: sel pendek (Harga, Stok) dibuat SEBARIS dengan labelnya,
   dan blok identitas → tombol disusun bertingkat. Tidak ada teks yang
   disembunyikan — hanya tata letaknya yang dirapatkan, sesuai aturan Bos.
   ---------------------------------------------------------------------- */
@media (max-width: 720px) {
  /* `tr` jadi GRID dua kolom: sel pendek berpasangan sebaris, sisanya melebar
     penuh. Terukur: 5 sel bertumpuk = kartu 205px; setelah dipadatkan begini
     turun ke ±130px, dan tombol "+ Keranjang" langsung terlihat tanpa menggulir
     satu kartu penuh. Tidak ada teks yang disembunyikan. */
  .tabel-pos tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: .7rem; padding: .55rem .7rem; margin-bottom: .45rem; }
  /* Barang = identitas: satu blok penuh, label atasannya dilepas karena nama
     barang sudah jelas, dan baris "BARANG" cuma menghabiskan tinggi kartu. */
  .tabel-pos td[data-l="Barang"] { grid-column: 1 / -1; display: block; padding: 0 0 .15rem; }
  .tabel-pos td[data-l="Barang"]::before { display: none; }
  /* Harga & Stok berdampingan: isinya pendek (satu baris), jadi dua sel satu
     baris lebih baik daripada dua baris terpisah. */
  .tabel-pos td[data-l="Harga"],
  .tabel-pos td[data-l="Stok"] { display: flex; align-items: baseline;
    gap: .4rem; padding: .1rem 0; flex-wrap: wrap; }
  .tabel-pos td[data-l="Harga"] { grid-column: 1; }
  .tabel-pos td[data-l="Stok"] { grid-column: 2; }
  .tabel-pos td[data-l="Harga"]::before,
  .tabel-pos td[data-l="Stok"]::before { flex: 0 0 auto; padding-top: 0; }
  /* Tombol keranjang jadi lebar penuh: sasaran sentuh besar, tidak meleset. */
  .tabel-pos td.kolom-aksi { grid-column: 1 / -1; padding-top: .5rem; }
  .tabel-pos td.kolom-aksi .tombol { width: 100%; min-height: 42px; }

  /* Riwayat nota: 7 sel = kartu 297px per nota. Nomor+Tanggal dan Total+Bayar
     dipasangkan sebaris; teks panjang (pembeli, status, aksi) melebar penuh. */
  .tabel-nota tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: .7rem; padding: .6rem .75rem; }
  .tabel-nota td[data-l="Nomor"],
  .tabel-nota td[data-l="Tanggal"],
  .tabel-nota td[data-l="Total"],
  .tabel-nota td[data-l="Bayar"] { display: flex; align-items: baseline;
    gap: .45rem; padding: .12rem 0; flex-wrap: wrap; }
  .tabel-nota td[data-l="Nomor"] { grid-column: 1; }
  .tabel-nota td[data-l="Tanggal"] { grid-column: 2; }
  .tabel-nota td[data-l="Total"] { grid-column: 1; }
  .tabel-nota td[data-l="Bayar"] { grid-column: 2; }
  .tabel-nota td[data-l="Pembeli"],
  .tabel-nota td[data-l="Status"],
  .tabel-nota td.kolom-aksi { grid-column: 1 / -1; }
  .tabel-nota td[data-l="Nomor"]::before,
  .tabel-nota td[data-l="Tanggal"]::before,
  .tabel-nota td[data-l="Total"]::before,
  .tabel-nota td[data-l="Bayar"]::before { flex: 0 0 auto; padding-top: 0; }
  .tabel-nota td.kolom-aksi { padding-top: .45rem; }

  /* Form kasir: pasangan isian pendek dijadikan DUA KOLOM supaya tidak menuntut
     gulir panjang sebelum tombol Simpan. `grid-form` global sudah satu kolom;
     hanya di POS isiannya pendek-pendek. */
  .kop-form-2 { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem .7rem; }
  .kop-form-2 > label { min-width: 0; }
  .kop-form-2 > label.lebar-penuh { grid-column: 1 / -1; }
  /* Tombol Simpan melebar penuh: di ponsel ia target utama, dan berdampingan
     dengan "Kosongkan Keranjang" membuat keduanya sempit. */
  .pos-aksi > .tombol { flex: 1 1 100%; min-height: 46px; }

  /* Kepala Koperasi: TIGA tombol berlabel panjang ("Tarik dari SIMKOPDES" 18
     karakter). Dibiarkan mengalir sebaris mereka mengecil sampai labelnya
     terpotong — dan di sini tombolnya bukan hiasan, itu aksi utama pengelola.
     Dipakai GRID, bukan flex: dengan `flex: 1 1 calc(50%-...)` pembulatan
     subpiksel kadang membuat dua tombol tidak muat semeja lalu masing-masing
     membungkus ke barisnya sendiri dan melebar penuh (terukur: 358px per
     tombol alih-alih ±175px). Grid menentukan kolomnya, bukan menebak. */
  .kepala-kop .tombol-baris { display: grid; grid-template-columns: 1fr 1fr;
    width: 100%; gap: .45rem; }
  /* "Tarik dari SIMKOPDES" selalu melebar penuh: labelnya paling panjang, dan
     ia satu-satunya yang berupa formulir (POST). */
  .kepala-kop .tombol-baris > form { grid-column: 1 / -1; }
  .kepala-kop .tombol { width: 100%; min-height: 42px; justify-content: center;
    font-size: .84rem; padding: .42rem .55rem; }
  .kepala-kop .tombol .ik { width: 15px; height: 15px; }
  /* Bila hanya ada SATU tombol langsung (mis. tak ada form Tarik), biarkan
     melebar penuh — dua kolom dengan satu isi menyisakan rongga aneh. */
  .kepala-kop .tombol-baris > .tombol:only-child { grid-column: 1 / -1; }
}

/* ---- Gerbang WhatsApp di formulir Siaran ----
   Duduk sebagai sel grid .grid-form, jadi tombolnya sebaris dengan kolom
   Sasaran di desktop. `align-self: end` + margin bawah yang sama dengan
   `label` menyejajarkannya dengan <select>, bukan dengan teks labelnya. */
.wa-gabung { display: flex; align-items: center; gap: .45rem; flex-wrap: nowrap;
  align-self: end; margin-bottom: .85rem; }
.wa-gabung .bantuan { margin: 0; flex: 1 1 auto; }
@media (max-width: 720px) { .wa-gabung { grid-column: 1 / -1; flex-wrap: wrap; } }
/* QR di dalam dialog: latar putih wajib — kode QR transparan tidak terbaca
   pemindai saat modal berlatar gelap, dan padding menjaga zona sunyi. */
.wa-qr-bingkai { margin: .3rem 0; text-align: center; }
.wa-qr-bingkai img { background: #fff; padding: 10px; border-radius: 12px;
  width: min(280px, 100%); height: auto; }

/* ================================================== /keuangan: rekap kategori
   "Ke mana uangnya pergi" — dua kolom berdampingan (pemasukan | pengeluaran),
   satu baris per kategori dengan batang persentase. Batangnya <i> di dalam
   <span>, bukan <progress>: <progress> tidak bisa diwarnai beda per sisi
   (masuk hijau, keluar merah) tanpa trik vendor, sedangkan elemen biasa cukup
   `width`.
   Di ponsel kolomnya menumpuk: dua kolom berisi nama kategori + rupiah +
   persen + batang menyisakan ~130px per kolom dan semuanya membungkus. */
.kategori-kas { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: .8rem 1.4rem; margin: .1rem 0 .9rem; }
.kategori-sisi { border: 1px solid var(--garis); border-radius: var(--r-kecil);
  padding: .7rem .85rem; background: var(--putih); }
.kategori-sisi > b { display: block; font-size: .82rem; margin-bottom: .55rem;
  padding-bottom: .45rem; border-bottom: 1px solid var(--garis-2); }
.kategori-baris { display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  gap: .1rem .55rem; align-items: baseline; margin-bottom: .5rem; }
.kategori-baris:last-child { margin-bottom: 0; }
.kategori-nama { font-size: .82rem; overflow-wrap: anywhere; }
.kategori-angka { font-size: .82rem; font-weight: 600; font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.kategori-persen { font-size: .75rem; font-variant-numeric: tabular-nums;
  white-space: nowrap; min-width: 3.2em; text-align: right; }
/* Batang menempati baris KEDUA, selebar seluruh kolom: ia membandingkan
   kategori satu sama lain, jadi skalanya harus sama panjang. */
.kategori-batang { grid-column: 1 / -1; display: block; height: 5px;
  background: var(--garis-2); border-radius: 3px; overflow: hidden; }
.kategori-batang > i { display: block; height: 100%; border-radius: 3px;
  background: var(--hijau-500); }
.kategori-sisi:last-child .kategori-batang > i { background: var(--merah-g); }
@media (max-width: 720px) {
  .kategori-kas { grid-template-columns: 1fr; }
}


/* ---- Navigasi halaman FITUR AgriConnect (/agri/hris/*) -------------------
   Pengganti kisi 21 kartu di atas isi halaman: satu jalur pulang + butir
   antarfitura. Di ponsel butirnya MENGALIR MENYAMPING (bukan disembunyikan dan
   bukan membungkus jadi tiga baris) supaya isi halaman tetap dekat. */
.agri-subnav { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap;
  margin: .1rem 0 1rem; padding: .5rem .6rem; background: var(--putih);
  border: 1px solid var(--garis); border-radius: var(--r); }
.agri-subnav-pulang { color: var(--hijau-700); font-weight: 600; text-decoration: none;
  white-space: nowrap; }
.agri-subnav-butir { display: flex; gap: .35rem; flex: 1 1 240px; min-width: 0;
  overflow-x: auto; padding-bottom: 2px; scrollbar-width: thin; }
.agri-subnav-butir a { padding: .3rem .6rem; border: 1px solid var(--garis);
  border-radius: 999px; color: var(--tinta-2); font-size: .82rem; text-decoration: none;
  white-space: nowrap; }
.agri-subnav-butir a:hover { border-color: var(--hijau-500); color: var(--hijau-700); }
.agri-subnav-butir a.ini { background: var(--hijau-l); border-color: var(--hijau-600);
  color: var(--hijau-700); font-weight: 600; }
.agri-subnav-status { padding: .25rem .55rem; border: 1px solid var(--hijau-g);
  border-radius: 999px; background: var(--hijau-l); color: #14512f;
  font-size: .78rem; font-weight: 600; white-space: nowrap; }
.agri-subnav-sambung { padding: .3rem .7rem; border: 1px solid var(--hijau-600);
  border-radius: 999px; background: var(--hijau-600); color: #fff;
  font-family: inherit; font-size: .82rem; font-weight: 600; cursor: pointer;
  white-space: nowrap; }
.agri-subnav-sambung:hover { background: var(--hijau-700); border-color: var(--hijau-700); }
/* Di ponsel butir antarfitura turun ke barisnya sendiri: satu baris tombol
   (pulang + Hubungkan/Tersambung), satu baris pil yang mengalir menyamping.
   Tanpa ini tombol Hubungkan terlempar ke baris ketiga. */
@media (max-width: 720px) {
  .agri-subnav { gap: .45rem .55rem; }
  .agri-subnav-pulang { order: 0; }
  .agri-subnav-status, .agri-subnav-sambung { order: 1; margin-left: auto; }
  .agri-subnav-butir { order: 2; flex: 1 1 100%; }
}

/* ==========================================================================
   AgriConnect — penyeragaman & polesan (2026-10-21)
   Satu blok untuk seluruh halaman /agri*: judul blok dengan penghitung baris,
   bar saring tabel, dan kartu Absen AgriConnect. Ditaruh di sini (bukan di
   dalam <style> per halaman) karena keluhan aslinya justru "tiap halaman beda".
   ========================================================================== */

/* ---- Judul blok + penghitung --------------------------------------------- */
.blok-kepala { display: flex; align-items: baseline; justify-content: space-between;
  gap: .6rem; flex-wrap: wrap; }
.blok-kepala h2 { margin-bottom: .35rem; }
.blok-kepala > :last-child { font-size: .8rem; font-variant-numeric: tabular-nums; }

/* ---- Bar saring yang dibuat hub-saring-tabel.js --------------------------- */
.saring-tabel { margin: 0 0 .6rem; }
.saring-tabel .saring-hitung { flex: 0 0 auto; font-size: .8rem;
  font-variant-numeric: tabular-nums; margin-left: auto; }
.saring-pager { display: flex; align-items: center; justify-content: flex-end;
  gap: .6rem; margin: .7rem 0 .1rem; font-size: .82rem; }
.saring-pager .tombol { min-height: 36px; padding: .25rem .7rem; }
.saring-pager .tombol[disabled] { opacity: .45; cursor: default; }
.saring-pager[hidden] { display: none; }
@media (max-width: 720px) {
  /* Di ponsel penghitung turun ke barisnya sendiri: kolom cari + select sudah
     memakai seluruh lebar, dan angka yang menempel di kanan akan terpotong. */
  .saring-tabel .saring-hitung { flex: 1 1 100%; margin-left: 0; }
  .saring-pager { justify-content: space-between; }
  .saring-pager .tombol { flex: 0 0 auto; }
}

/* ---- Kartu Absen AgriConnect -------------------------------------------- */
.agri-absen { border-left: 3px solid var(--hijau-600); }
.agri-absen-kepala { display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; flex-wrap: wrap; margin-bottom: .5rem; }
.agri-absen-kepala h2 { margin: 0; }
.agri-absen-form { display: grid; grid-template-columns: minmax(220px, 280px) 1fr;
  gap: .9rem 1.1rem; align-items: start; margin-top: .6rem; }
.agri-berkas, .agri-ket { display: flex; flex-direction: column; gap: .3rem;
  font-size: .85rem; font-weight: 600; color: var(--tinta-2); }
.agri-berkas input[type="file"] { font-weight: 400; font-size: .82rem;
  padding: .7rem .8rem; background: var(--hijau-100);
  border: 1px dashed var(--hijau-300); border-radius: var(--r); cursor: pointer;
  width: 100%; }
.agri-berkas input[type="file"]:hover { border-color: var(--hijau-600); }
.agri-berkas input[type="file"]::file-selector-button { margin-right: .7rem;
  padding: .4rem .8rem; border: 0; border-radius: 8px; background: var(--hijau-600);
  color: #fff; font: inherit; font-weight: 600; cursor: pointer; }
.agri-ket input[type="text"] { font-weight: 400; }
/* Minimap titik absen (embed OSM). Tinggi tetap supaya formulir tidak melompat
   saat iframe selesai memuat; di ponsel lebih pendek agar tombol absen tetap
   terlihat tanpa menggulir jauh. */
.agri-peta { grid-column: 1 / -1; display: flex; flex-direction: column; gap: .3rem; }
.agri-peta iframe { display: block; width: 100%; height: 240px; border: 1px solid var(--garis);
  border-radius: var(--r); background: var(--garis-2); }
.agri-peta .bantuan { font-weight: 400; }
@media (max-width: 720px) {
  .agri-peta iframe { height: 200px; }
}
.agri-absen-kaki { grid-column: 1 / -1; display: flex; align-items: center;
  gap: .8rem; flex-wrap: wrap; padding-top: .2rem; }
.agri-absen-kaki .tombol { min-height: 44px; padding-inline: 1.4rem; }
.agri-absen-kaki .bantuan { flex: 1 1 320px; margin: 0; font-weight: 400; }
.agri-absen-form .pesan { margin: .1rem 0 0; font-weight: 400; }
@media (max-width: 720px) {
  /* Satu kolom: berkas di atas, keterangan di bawah, tombol selebar kartu —
     ibu jari tidak perlu membidik tombol kecil di pojok. */
  .agri-absen-form { grid-template-columns: 1fr; gap: .7rem; }
  .agri-absen-kaki { flex-direction: column; align-items: stretch; gap: .45rem; }
  /* `flex: 1 1 320px` di atas jadi flex-BASIS sumbu tegak saat kolom →
     tinggi paksa 320px. Di ponsel kembalikan ke tinggi isinya. */
  .agri-absen-kaki .bantuan { flex: 0 0 auto; }
  .agri-absen-kaki .tombol { width: 100%; }
}

/* ---- Polesan kecil yang berlaku di semua halaman AgriConnect ------------- */
.petak .kartu.angka { transition: border-color .15s ease, box-shadow .15s ease; }
.petak .kartu.angka:hover { border-color: var(--hijau-300);
  box-shadow: 0 2px 10px rgba(16, 29, 24, .05); }
.blok .tabel-bungkus table tbody tr:hover { background: var(--zebra); }

/* Dua lencana keadaan Absen Masuk/Pulang berdampingan; di ponsel turun baris
   sendiri supaya judul kartu tidak terhimpit. */
.lencana-baris { display: flex; gap: .4rem; flex-wrap: wrap; }
@media (max-width: 720px) { .lencana-baris { width: 100%; } }


/* ===== Absen DesaPreneur (dipindah dari blade 2026-10-21) =====
   Sebelumnya CSS ini ditulis inline di setiap render halaman absen:
   +9,6 KB di SETIAP muat halaman dan tidak pernah bisa di-cache.
   Di sini ia ikut hub.css yang di-cache lama, jadi byte-nya dibayar
   sekali saja. Semua selektornya ber-scope kelas halaman absen. */
.kepala-blok { display: flex; align-items: center; justify-content: space-between; gap: .8rem;
    flex-wrap: wrap; margin-bottom: .9rem; }
  .kepala-blok h2 { margin: 0; }
  .notis { padding: .6rem .8rem; border-radius: var(--r-kecil); font-size: .88rem; margin-bottom: .8rem; }
  .notis-ok { background: var(--hijau-l); border: 1px solid var(--hijau-g); color: var(--hijau-800); }
  .notis-galat { background: var(--merah-l); border: 1px solid var(--merah-g); color: var(--merah); }

  .pilih-aksi { display: grid; gap: .6rem; margin-bottom: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
  .pilih-aksi-butir { display: flex; gap: .6rem; align-items: flex-start; padding: .75rem .85rem;
    border: 1px solid var(--garis); border-radius: var(--r-kecil); background: var(--putih);
    cursor: pointer; transition: border-color .15s, background .15s; }
  .pilih-aksi-butir:hover { border-color: var(--hijau-500); background: var(--hijau-100); }
  .pilih-aksi-butir input { margin-top: .2rem; accent-color: var(--hijau-600); }
  .pilih-aksi-butir input:checked + span strong { color: var(--hijau-700); }
  .pilih-aksi-butir span { display: block; }
  .pilih-aksi-butir strong { display: block; font-size: .9rem; }
  .pilih-aksi-butir small { color: var(--pudar); font-size: .78rem; }

  .bukti-baris { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    margin: 1rem 0; }
  .bukti-kotak { display: flex; flex-direction: column; gap: .55rem; }
  /* Tombol kamera & lokasi di tengah: keduanya aksi tunggal di kolom sempit,
     dan rata kiri membuatnya terlihat seperti potongan formulir yang terlepas. */
  .tombol-tengah { justify-content: center; }
  /* Tombol tetap BISA ditekan walau belum lengkap; hanya terlihat lebih redup
     supaya jelas ada yang kurang. Bukan `disabled`: tombol mati tidak bisa
     memberi alasan saat ditekan. */
  .tombol.utama.belum { opacity: .62; }
  .tombol-tengah > .tombol { min-width: 9.5rem; }
  .lokasi-kotak { border: 1px dashed var(--garis); border-radius: var(--r-kecil);
    padding: .8rem; background: var(--zebra); min-height: 96px; }
  .lokasi-rinci { margin: .5rem 0 0; display: grid; gap: .3rem; }
  .lokasi-rinci div { display: flex; justify-content: space-between; gap: .6rem; font-size: .8rem; }
  .lokasi-rinci dt { color: var(--pudar); margin: 0; }
  .lokasi-rinci dd { margin: 0; font-variant-numeric: tabular-nums; font-weight: 600; }
  /* Minimap: rasio tetap supaya kotak lokasi tidak melompat tinggi saat peta
     selesai dimuat. border-radius + overflow menutup sudut iframe, yang tidak
     bisa diberi radius sendiri. */
  .lokasi-peta { margin: .6rem 0 0; aspect-ratio: 16 / 10; border-radius: var(--r-mini);
    overflow: hidden; border: 1px solid var(--garis); background: var(--garis-2); }
  .lokasi-peta iframe { display: block; width: 100%; height: 100%; border: 0; }

  .linimasa { list-style: none; margin: 0; padding: 0; }
  .linimasa-butir { display: flex; gap: .75rem; padding: .55rem 0;
    border-bottom: 1px solid var(--garis-2); }
  .linimasa-butir:last-child { border-bottom: 0; }
  .linimasa-jam { font-variant-numeric: tabular-nums; font-weight: 700; font-size: .88rem;
    color: var(--hijau-700); flex: 0 0 3rem; }
  .linimasa-isi { min-width: 0; }
  .linimasa-isi strong { display: block; font-size: .88rem; }
  .linimasa-isi small { color: var(--pudar); font-size: .76rem; }
  .linimasa-keluar .linimasa-jam { color: var(--merah); }
  .linimasa-istirahat_mulai .linimasa-jam,
  .linimasa-istirahat_selesai .linimasa-jam { color: var(--kuning); }

  .daftar-ringkas { margin: 0; padding-left: 1.1rem; font-size: .85rem; line-height: 1.6; }
  .daftar-ringkas li { margin-bottom: .5rem; }
  .daftar-ringkas li:last-child { margin-bottom: 0; }

  /* ---------- Riwayat: filter & tabel yang jadi kartu di ponsel ---------- */
  /* Bentuk yang diminta Bos: label DI ATAS kotak pilih, tombol "Lihat" DI BAWAH.
     Dipakai GRID dua kolom, bukan flex: dengan flex, tombol bisa dipaksa turun
     lewat `flex-basis: 100%` tetapi lalu IKUT MELAR selebar layar. Di grid, tombol
     cukup ditugaskan ke baris kedua (`grid-column: 1 / -1`) dan lebarnya
     dikembalikan ke selebar teksnya lewat `justify-self: start`.
     Ponsel: tombol memang selebar layar (jempol lebih mudah). */
  .saring-riwayat { display: grid; grid-template-columns: auto auto;
    justify-content: start; align-items: end;
    gap: .55rem .7rem; margin-bottom: 1rem; }
  .saring-riwayat label { display: flex; flex-direction: column; align-items: stretch;
    gap: .3rem; min-width: 0; margin: 0; padding: 0; }
  .saring-label { font-size: .7rem; text-transform: uppercase;
    letter-spacing: .07em; color: var(--pudar); font-weight: 700; line-height: 1.2;
    white-space: nowrap; }
  /* Tinggi DIKUNCI 42px dan `flex: 0 0 auto`: aturan global
     `.saring select { flex: 1 1 220px }` dulu membuat select setinggi 220px di
     sini (flex-basis berlaku vertikal). Selektor (0,2,1) menang atas
     `.saring select` (0,1,1) tanpa bergantung urutan berkas. */
  .saring-riwayat select { flex: 0 0 auto; width: 9.5rem; max-width: 100%;
    height: 42px; min-height: 42px; margin-top: 0; padding: 0 .6rem; line-height: normal;
    border: 1px solid var(--garis); border-radius: var(--r-kecil);
    background: var(--putih); font: inherit; font-size: .875rem; color: var(--tinta); }
  .saring-riwayat select:focus-visible { outline: 2px solid var(--hijau-500); outline-offset: 1px; }
  .saring-riwayat .tombol { grid-column: 1 / -1; justify-self: start;
    height: 42px; min-height: 42px; margin: 0; }
  @media (max-width: 560px) {
    .saring-riwayat { grid-template-columns: 1fr 1fr; }
    .saring-riwayat select { width: 100%; }
    .saring-riwayat .tombol { justify-self: stretch; width: 100%; }
  }

  .riwayat-isi[aria-busy="true"] { opacity: .55; transition: opacity .12s; }
  .riwayat-kosong { padding: .6rem 0; }

  .riwayat-tabel table { width: 100%; border-collapse: collapse; }
  .riwayat-tabel th { text-align: left; font-size: .7rem; text-transform: uppercase;
    letter-spacing: .07em; color: var(--pudar); font-weight: 700;
    padding: .5rem .55rem; border-bottom: 1px solid var(--garis); white-space: nowrap; }
  .riwayat-tabel td { padding: .6rem .55rem; border-bottom: 1px solid var(--garis-2);
    font-size: .875rem; vertical-align: middle; }
  .riwayat-tabel tbody tr:hover { background: var(--zebra); }
  .riwayat-tanggal { font-weight: 400; text-align: left; text-transform: none;
    letter-spacing: 0; font-size: .875rem; color: var(--tinta); }
  .riwayat-tanggal b { display: block; font-weight: 700; }
  .riwayat-tanggal small { color: var(--pudar); font-size: .76rem; }
  .riwayat-angka { font-variant-numeric: tabular-nums; }
  .riwayat-angka small { display: inline; color: var(--pudar); font-size: .74rem; }

  .riwayat-kaki { display: flex; align-items: center; justify-content: space-between;
    gap: .8rem; flex-wrap: wrap; margin-top: .9rem; }
  .riwayat-kaki .bantuan { margin: 0; }

  @media (max-width: 720px) {
    .dua-kolom { grid-template-columns: 1fr; }

    /* Kepala tabel disembunyikan secara visual (bukan display:none) supaya
       pembaca layar tetap mendapat hubungan kolom -> nilai. */
    .riwayat-tabel thead { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
    .riwayat-tabel table, .riwayat-tabel tbody { display: block; }
    .riwayat-tabel tr { display: block; border: 1px solid var(--garis);
      border-radius: var(--r-kecil); background: var(--putih);
      box-shadow: var(--bayang); margin-bottom: .6rem; padding: .55rem .75rem; }
    .riwayat-tabel tr:hover { background: var(--putih); }
    .riwayat-tabel td { display: flex; align-items: baseline; justify-content: space-between;
      gap: .75rem; padding: .3rem 0; border-bottom: 0; font-size: .85rem; }
    .riwayat-tabel td::before { content: attr(data-label); flex: 0 0 44%;
      font-size: .7rem; text-transform: uppercase; letter-spacing: .05em;
      color: var(--pudar); font-weight: 700; }
    .riwayat-tabel th[scope="row"] { display: block; padding: 0 0 .45rem;
      margin-bottom: .35rem; border-bottom: 1px solid var(--garis-2); }
    .riwayat-tabel th[scope="row"]::before { content: none; }
    .riwayat-tanggal b { font-size: .95rem; }
    .riwayat-kaki { flex-direction: column; align-items: flex-start; }
    .riwayat-kaki .paging { width: 100%; justify-content: space-between; }
  }

  @media (max-width: 720px) {
    .dua-kolom { grid-template-columns: 1fr; }
  }


/* ===== Modal bukti foto absen: dua foto berdampingan =====
   Dua kolom di layar lebar supaya masuk & pulang bisa DIBANDINGKAN sejajar
   (itu gunanya); satu kolom di ponsel karena dua potret 3:4 berdampingan di
   layar 360px hanya menyisakan ~150px per wajah — terlalu kecil untuk dilihat. */
.foto-pasangan { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
.foto-kotak { margin: 0; display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
.foto-kotak figcaption { display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap; }
.foto-kotak figcaption strong { font-size: .8rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--pudar); }
.foto-kotak figcaption span { font-size: .8rem; color: var(--tinta-2);
  font-variant-numeric: tabular-nums; }
.foto-bingkai { position: relative; aspect-ratio: 3 / 4; border-radius: var(--r-kecil);
  overflow: hidden; background: var(--zebra); border: 1px solid var(--garis); }
.foto-bingkai img { width: 100%; height: 100%; object-fit: cover; display: block; }
.foto-kosong { margin: 0; position: absolute; inset: 0; display: grid; place-items: center;
  font-size: .8rem; color: var(--pudar); text-align: center; padding: .8rem; }
.tombol-x { font-size: 1.1rem; line-height: 1; padding: .2rem .55rem; min-width: 34px; }
@media (max-width: 560px) {
  .foto-pasangan { grid-template-columns: 1fr; gap: .8rem; }
  .foto-bingkai { aspect-ratio: 4 / 3; }
}


/* ===== Perpindahan halaman tanpa muat ulang (AJAX nav di hub.js) =====
   Isi <main id="isi"> diganti di tempat, jadi tanpa animasi layar berubah
   seketika dan terasa seperti kedip. Naik 6px + pudar 0.22s cukup memberi
   kesan "halaman datang", tanpa menunda apa pun: pengguna yang membaca cepat
   tetap melihat konten segera.

   Bilah #hub-proses yang sudah ada tetap dipakai sebagai penanda permintaan
   berjalan; animasi ini hanya untuk isi yang SUDAH tiba. */
.isi.masuk-nav { animation: hub-masuk-nav .22s ease-out; }
@keyframes hub-masuk-nav {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .isi.masuk-nav { animation: none; }
}


/* ===== Penanda jumlah barang di butir "Keranjang" (modul-nav Toko) =====
   Memakai gaya `.lencana-notif` yang sudah dipakai lonceng & bilah bawah, tapi
   duduk INLINE di dalam tautan (bukan menempel di pojok ikon), jadi posisinya
   dikembalikan ke static dan warnanya disamakan dengan butir yang aktif.
   `margin-left:auto` mendorongnya ke ujung kanan butir — sejajar di semua
   bahasa/lebar label, tanpa perlu mengukur teks. */
.modul-nav .lencana-nav {
  position: static; margin-left: auto; min-width: 19px; height: 19px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 .28rem; border-radius: 999px; font-size: .7rem; font-weight: 700;
  line-height: 1; color: #fff; background: var(--merah, #b91c1c);
  border: 1px solid var(--putih);
}
.modul-nav a.ini .lencana-nav { border-color: transparent; }

/* Teks untuk pembaca layar saja — tidak memakan ruang, tidak terlihat. */
.hanya-pembaca {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}


/* ===== Lencana JENIS produk di kartu katalog =====
   Tiga warna, tiga arti: subsidi (hijau = bantuan pemerintah), lokal (oranye
   = dari koperasi lain), non-subsidi (abu = komersial biasa). Tanpa beda warna,
   lencana hanya teks panjang yang sulit dipindai sementara berbelanja. */
.kat-lencana.j-subsidi { background: rgba(21, 100, 60, .92); }
.kat-lencana.j-lokal { background: rgba(154, 52, 18, .92); }
.kat-lencana.j-nonsubsidi { background: rgba(60, 72, 66, .82); }

/* Checkbox subsidi di formulir Kelola Katalog: kotak centang + dua baris teks.
   `.centang` global memakai flex-row sehingga keterangan panjang meluber;
   di sini teksnya dibungkus dan checkbox-nya tidak menyusut. */
.centang-subsidi { display: flex; align-items: flex-start; gap: .5rem; }
.centang-subsidi input[type="checkbox"] { flex: 0 0 auto; width: 1.05rem;
  height: 1.05rem; margin-top: .15rem; }
.centang-subsidi span { font-size: .85rem; line-height: 1.35; }
.centang-subsidi .bantuan { display: block; font-size: .76rem; }

/* ===== Katalog di PONSEL =====
   Tiga hal yang membuat halaman terasa berantakan di layar sempit:
   1) bilah saring membungkus jadi 3 baris (cari 1 baris, jenis 1 baris,
      tombol 1 baris) — total ~150px hanya untuk penyaring;
   2) kartu 140px memaksa nama produk terpotong jadi 2 kata;
   3) sisa ruang di kanan kisi karena `auto-fill` menyisakan kolom kosong.

   Perbaikannya: penyaring dipadatkan jadi DUA baris (cari, lalu jenis+tombol
   sebaris), dan kisi memakai `auto-fit` dengan minimum 46% supaya SELALU
   dua kolom rapi — tidak pernah menyisakan kolom setengah kosong. */
@media (max-width: 640px) {
  .saring-katalog { padding: .5rem .6rem; gap: .4rem; }
  .saring-katalog label.cari { flex: 1 1 100%; max-width: none; }
  /* Jenis + tombol berbagi satu baris; `min-width: 0` wajib supaya <select>
     yang opsinya panjang ("Produk Lokal & UMKM") tidak mendorong tombol keluar. */
  .saring-katalog label.pilih { flex: 1 1 auto; min-width: 0; }
  .saring-katalog .bersih-saring { flex: 0 0 auto; }
  .saring-katalog .bersih-saring[hidden] { display: none; }
}

@media (max-width: 560px) {
  /* Dua kolom pasti: 46% + gap, bukan `auto-fill` yang bergantung lebar sisa. */
  .katalog-kisi { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .55rem; }
  .kat-badan { padding: .45rem .5rem .55rem; }
  .kat-badan h3 { font-size: .8rem; }
  .kat-harga { font-size: .92rem; }
  /* Baris aksi: kolom jumlah menyusut, tombol tetap 38px agar bisa disentuh. */
  .kat-aksi form { --t: 38px; gap: .3rem; }
  .kat-aksi input[type="number"] { padding-left: .4rem; padding-right: .2rem; }
}



/* ====================================================================
   KERANJANG — gaya toko daring sebelum pesanan dibuat
   ====================================================================
   Prinsipnya: SATU kartu, garis pemisah antar barang. Versi pertama saya
   menaruh kartu berbingkai di dalam kartu berbingkai (.blok > .krj-baris),
   sehingga halaman terlihat seperti tumpukan kotak — itu yang membuatnya
   berantakan. Sekarang: satu wadah putih, tiap barang dipisah garis tipis
   seperti daftar pesanan toko daring mana pun.

   Semua selektor diberi awalan `.krj` (0,2,0 ke atas) supaya tidak ada aturan
   global `label`/`input`/`p` di berkas ini yang menimpanya. */

.krj { display: grid; grid-template-columns: minmax(0, 1fr) 336px;
  gap: 1.1rem; align-items: start; margin-bottom: var(--ruang);
  /* Lajur baris barang — SATU definisi, dipakai judul kolom DAN tiap baris.
     Dulu angkanya ditulis dua kali; begitu salah satu diubah, subtotal bergeser
     dari judulnya. Lajur terakhir cukup lebar untuk tombol "Hapus" berlabel. */
  --krj-kolom: minmax(0, 1fr) 8.4rem 14.2rem 7.2rem;
  /* Tinggi SATU baris aksi (input jumlah, Ubah, Hapus).
     Dulu input & Ubah 36px sedangkan Hapus 34px (min-height tanpa height) —
     selisih 2px membuat tepi bawah tombol tidak pernah rata. Sekarang ketiganya
     membaca variabel ini, jadi mustahil berbeda tinggi lagi. */
  --krj-h-aksi: 36px; }

/* ---- langkah belanja ---- */
.krj-langkah { list-style: none; display: flex; flex-wrap: wrap; align-items: center;
  gap: .35rem .55rem; margin: 0 0 1rem; padding: 0;
  font-size: .78rem; color: var(--pudar); }
.krj-langkah > li { display: inline-flex; align-items: center; gap: .4rem; margin: 0; }
.krj-langkah > li > span { display: inline-grid; place-items: center;
  width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: var(--garis-2); color: var(--pudar);
  font-size: .72rem; font-weight: 700; }
.krj-langkah > li.ini { color: var(--hijau-700); font-weight: 600; }
.krj-langkah > li.ini > span { background: var(--hijau-600); color: #fff; }
.krj-langkah > li + li::before { content: "›"; margin-right: .25rem;
  color: var(--garis); font-weight: 400; }

/* ---- kartu daftar barang ---- */
.krj-kartu { background: var(--putih); border: 1px solid var(--garis);
  border-radius: var(--r); overflow: hidden; box-shadow: var(--bayang); }
.krj-kartu-kepala { display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; padding: 1rem 1.15rem .85rem;
  border-bottom: 1px solid var(--garis-2); }
.krj-kartu-kepala h2 { margin: 0; font-size: 1.02rem; padding: 0; border: 0; }

/* Baris judul kolom — HANYA desktop. Ini yang membuat angka tidak "menempel":
   tiap lajur punya lebar pasti, dan judulnya memberi tahu lajur itu apa. */
.krj-kepala-kolom { display: grid; align-items: center; gap: 1rem;
  grid-template-columns: var(--krj-kolom);
  padding: .5rem 1.15rem; background: var(--zebra);
  border-bottom: 1px solid var(--garis-2);
  font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--pudar); font-weight: 700; }

.krj-daftar { list-style: none; margin: 0; padding: 0; }

/* Satu barang. Lajur & jarak SAMA dengan baris judul di atas. */
.krj-baris { display: grid; align-items: center; gap: 1rem;
  grid-template-columns: var(--krj-kolom);
  padding: .9rem 1.15rem; margin: 0; border-top: 1px solid var(--garis-2); }
.krj-daftar > .krj-baris:first-child { border-top: 0; }

/* Produk: inisial + nama + keterangan, sebaris. */
.krj-produk { display: flex; align-items: flex-start; gap: .75rem; min-width: 0; }
.krj-gambar { flex: 0 0 auto; width: 48px; height: 48px; border-radius: var(--r-mini);
  display: grid; place-items: center; background: var(--zebra);
  border: 1px solid var(--garis-2);
  color: var(--hijau-700); font-weight: 800; font-size: .95rem; letter-spacing: .02em; }
.krj-info { min-width: 0; }
.krj-info h3 { margin: 0 0 .15rem; font-size: .9rem; line-height: 1.3; font-weight: 600;
  overflow-wrap: anywhere; }
.krj-meta { margin: 0; font-size: .74rem; color: var(--pudar); line-height: 1.35; }

/* Harga satuan */
.krj-harga { font-size: .84rem; font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: .3rem; flex-wrap: wrap; }
.krj-harga b { font-weight: 700; color: var(--hijau-700); }
.krj-harga s { color: var(--pudar); font-size: .78rem; }
.krj-tanda { font-size: .68rem; background: var(--kuning-l); color: var(--kuning);
  border: 1px solid var(--kuning-g); border-radius: var(--r-kapsul); padding: 0 .4rem;
  white-space: nowrap; }

/* Jumlah: isian + tombol, tinggi seragam, tanpa margin bawaan global. */
/* Satu baris aksi: [jumlah][Ubah] lalu [Hapus] — bersebelahan, rata kiri.
   `flex-wrap` TIDAK dipakai: kalau dibungkus, tombol hapus jatuh ke baris
   kedua dan kembali terlihat "nyasar". Lajurnya (14.2rem) cukup untuk
   keempatnya; di layar lebih sempit baris ini turun jadi blok sendiri
   lewat media query. */
/* Wadah aksi: TINGGI DIPAKU, isi di tengah.
   `align-items: stretch` (versi sebelumnya) membiarkan tinggi form ditentukan
   isinya; karena satu form memuat <svg> dan yang lain tidak, keduanya berakhir
   beda tinggi dan tombol Hapus terdorong ke bawah ~11px — persis keluhan
   "tidak sejajar". Sekarang wadah DAN kedua form memakai tinggi yang sama,
   jadi tidak ada lagi ruang untuk bergeser. */
.krj-aksi { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.krj-aksi > form { display: flex; align-items: center; margin: 0; min-width: 0;
  height: var(--krj-h-aksi); }
/* Form pertama pun bisa kena margin global `label + .tombol` / `form + form`
   bila susunan markup berubah kelak. Patok eksplisit. */
.krj-aksi > form + form { margin-top: 0; }
.krj-jumlah { display: flex; align-items: center; gap: .3rem; margin: 0; min-width: 0;
  height: var(--krj-h-aksi); }
.krj-jumlah input[type="number"] { width: 4.2rem; min-width: 0; height: var(--krj-h-aksi);
  min-height: 0; margin: 0; padding: 0 .35rem; text-align: center;
  font-size: .86rem; font-variant-numeric: tabular-nums; }
/* Ubah dan Hapus: tinggi, ukuran huruf, dan padding vertikal SAMA.
   `box-sizing: border-box` wajib — tanpa itu tombol berbingkai (Hapus punya
   border 1px, Ubah juga) bisa melebar 2px dari tingginya. */
.krj-jumlah .tombol, .krj-hapus-tombol { box-sizing: border-box;
  height: var(--krj-h-aksi); min-height: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  padding-top: 0; padding-bottom: 0; font-size: .8rem; line-height: 1; }
.krj-jumlah .tombol { padding: 0 .65rem; flex: 0 0 auto; }

/* Subtotal */
.krj-sub { text-align: right; font-size: .95rem; font-weight: 700;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.krj-sub small { display: none; }        /* label ini hanya untuk ponsel */

/* Hapus */
/* `margin-top: 0` WAJIB dengan selektor 0,2,0.
   Aturan global di baris ~436 — `form + form:not(.kartu-baris > *) { margin-top: .7rem }`
   — punya spesifisitas (0,1,2). `.krj-hapus { margin: 0 }` hanya (0,1,0), jadi
   KALAH, dan setiap form hapus yang mengikuti form jumlah mendapat dorongan
   11,2px ke bawah. Itu sebabnya tombol Hapus selalu tampak tidak sejajar
   dengan Ubah, walau tingginya sudah identik. `.krj-aksi > .krj-hapus` = (0,2,0)
   menang, dan tidak mengubah halaman lain. */
.krj-aksi > .krj-hapus { margin: 0; }
.krj-hapus { margin: 0; display: flex; flex: 0 0 auto; }
/* Tombol hapus: IKON TEMPAT SAMPAH + label "Hapus".
   Versi sebelumnya hanya tanda &times; 29px tanpa label — di daftar barang,
   "×" samar itu ambigu: bisa dibaca "tutup", "batal", atau hiasan. Sekarang
   bentuknya tombol berbingkai dengan ikon yang dikenali dan kata "Hapus".
   Ukuran minimum 34px (di atas ambang sasaran sentuh 32px untuk kontrol
   sekunder); di ponsel jadi 40px ikon-saja. */
/* Tombol hapus: MERAH sejak awal (bukan hanya saat disorot) — aksi yang
   membuang barang harus terbaca sebagai tindakan berbeda, bukan tombol biasa.
   `--merah` #a32218 di atas `--merah-l` lolos kontras WCAG AA (5.4:1). */
.krj-hapus-tombol { gap: .32rem;
  padding-left: .6rem; padding-right: .6rem;
  border-radius: var(--r-kecil); border: 1px solid var(--merah-g);
  background: var(--merah-l); color: var(--merah);
  font-family: inherit; font-weight: 700;
  white-space: nowrap; cursor: pointer; width: auto; flex: 0 0 auto; }
.krj-hapus-ikon { width: 1rem; height: 1rem; flex: 0 0 auto; display: block;
  align-self: center; }
.krj-hapus-teks { display: inline; }
.krj-hapus-tombol:hover, .krj-hapus-tombol:focus-visible {
  background: var(--merah); border-color: var(--merah); color: #fff; }

.krj-kaki { display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; padding: .85rem 1.15rem;
  border-top: 1px solid var(--garis); background: var(--zebra); }
.krj-kaki .tombol { margin: 0; }

/* ---- panel ringkasan ---- */
.krj-ringkas { position: sticky; top: 1rem; }
.krj-ringkas-kotak { background: var(--putih); border: 1px solid var(--garis);
  border-radius: var(--r); padding: 1rem 1.1rem 1.15rem; box-shadow: var(--bayang); }
.krj-ringkas-kotak h2 { margin: 0 0 .75rem; font-size: 1.02rem; padding: 0; border: 0; }

.krj-total { margin: 0 0 .85rem; display: flex; flex-direction: column; gap: .4rem; }
.krj-total > div { display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; font-size: .84rem; }
.krj-total dt { margin: 0; color: var(--tinta-2); }
.krj-total dd { margin: 0; font-variant-numeric: tabular-nums; }
.krj-total .krj-total-baris { border-top: 1px solid var(--garis); margin-top: .3rem;
  padding-top: .6rem; font-size: .95rem; font-weight: 700; color: var(--tinta); }
.krj-total .krj-total-baris dd { font-size: 1.2rem; color: var(--hijau-700); }

/* Pilihan bayar & penyerahan */
.krj-pilih { border: 0; padding: 0; margin: 0 0 .75rem; min-width: 0; }
.krj-pilih legend { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--pudar); font-weight: 700; margin-bottom: .35rem; padding: 0; }
.krj-opsi { display: flex; align-items: flex-start; gap: .45rem;
  padding: .45rem .55rem; border: 1px solid var(--garis); border-radius: var(--r-kecil);
  margin: 0 0 .35rem; cursor: pointer; font-size: .82rem; line-height: 1.3;
  font-weight: 400; }
.krj-opsi:hover { border-color: var(--hijau-500); background: var(--hijau-100); }
.krj-opsi input { margin: .18rem 0 0; flex: 0 0 auto; width: 1rem; height: 1rem; }
.krj-opsi span { display: block; min-width: 0; }
.krj-opsi b { font-weight: 600; }
.krj-opsi small { display: block; font-size: .72rem; color: var(--pudar); font-weight: 400; }

.krj-catatan { display: block; font-size: .8rem; font-weight: 600; margin: 0 0 .7rem; }
.krj-catatan input { margin-top: .3rem; }
.krj-checkout .tombol.lebar { margin-top: .15rem; }

.krj-kosong { padding: 2.2rem 1rem; text-align: center; }
.krj-kosong p { margin: 0 0 .3rem; }
.krj-kosong .tombol { margin-top: .8rem; }

/* ---- ponsel & tablet ---- */
@media (max-width: 900px) {
  .krj { grid-template-columns: minmax(0, 1fr); }
  .krj-ringkas { position: static; }
}

@media (max-width: 700px) {
  /* Judul kolom disembunyikan; tiap barang jadi blok bertingkat dengan
     label kecil di kiri nilai yang butuh keterangan. */
  .krj-kepala-kolom { display: none; }

  /* Ponsel: produk di atas, lalu satu baris aksi (jumlah + Ubah + Hapus)
     dan subtotal di kanan. Tombol hapus TETAP di sebelah Ubah — itu yang
     diminta, dan memisahkannya ke pojok justru mengulang masalah lama. */
  .krj-baris { grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "produk produk" "aksi sub";
    gap: .65rem .7rem; padding: .85rem 1rem; align-items: center; }
  .krj-produk { grid-area: produk; }
  .krj-aksi { grid-area: aksi; }
  .krj-sub { grid-area: sub; align-self: center; }
  .krj-sub small { display: inline; font-size: .7rem; font-weight: 400;
    color: var(--pudar); margin-right: .3rem; text-transform: uppercase;
    letter-spacing: .05em; }
  /* Ponsel: SATU variabel menaikkan tinggi input, Ubah, dan Hapus sekaligus
     ke 40px — sasaran sentuh yang nyaman, dan tetap rata sempurna. */
  .krj { --krj-h-aksi: 40px; }
  .krj-jumlah input[type="number"] { width: 4.6rem; }
  .krj-kartu-kepala { padding: .85rem 1rem .7rem; }
  .krj-kaki { padding: .75rem 1rem; }
  /* Label "Hapus" disembunyikan (tempat sempit); tombol jadi kotak 40x40.
     Tingginya TETAP dari --krj-h-aksi, hanya lebarnya yang dipatok. */
  .krj-hapus-tombol { width: 40px; padding: 0; aspect-ratio: 1 / 1; }
  .krj-hapus-teks { display: none; }
  .krj-hapus-ikon { width: 1.15rem; height: 1.15rem; }

  /* Harga & status pindah ke bawah nama supaya kolom kanan tetap lapang. */
  .krj-produk { align-items: flex-start; }
  .krj-gambar { width: 44px; height: 44px; font-size: .88rem; }
}

@media (max-width: 420px) {
  /* ≤420px: produk, lalu aksi penuh selebar baris, lalu subtotal di bawahnya.
     Tidak ada lagi tombol yang diposisikan absolut — dulu itu yang membuatnya
     tampak melayang di luar susunan. */
  .krj-baris { grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "produk" "aksi" "sub"; gap: .55rem; }
  .krj-sub { text-align: left; }
  /* Jangan `flex-wrap`: kalau dibungkus, Hapus turun baris dan kembali
     terlihat tidak sejajar dengan Ubah. Lebar totalnya masih muat. */
  .krj-aksi { gap: .35rem; }
  .krj-jumlah input[type="number"] { width: 4.4rem; }
}

/* Lajur harga di desktop. Di ponsel lajur ini disembunyikan karena harganya
   sudah tampil di bawah nama produk (tidak perlu dua kali). */
.krj-harga-kolom { font-size: .86rem; font-variant-numeric: tabular-nums;
  display: flex; flex-direction: column; gap: .1rem; }
.krj-harga-kolom b { font-weight: 700; color: var(--hijau-700); }
.krj-harga-kolom s { font-size: .78rem; }

@media (max-width: 700px) {
  .krj-harga-kolom { display: none; }
  /* Di ponsel harga di dalam .krj-info tetap tampil. */
}

/* ============================== /agri/hris — jarak baca tabel & pasangan nilai
   Keluhan 2026-10-22: "kolom masih banyak yang terlalu nempel, tidak user
   friendly". Ditambal di KOMPONEN BERSAMA (bukan per halaman) supaya semua
   tabel Hub ikut lega dan tidak lahir tambalan kedua yang saling menimpa. */
.tabel-bungkus td { padding: .85rem 1rem; line-height: 1.55; }
.tabel-bungkus th { padding: .65rem 1rem; }
.tabel-bungkus td > small { display: block; margin-top: .2rem; }

/* Pasangan label -> nilai (dl.rincian) dipakai halaman HRIS untuk data tunggal:
   lebih terbaca daripada <table> ber-<th> di dalam tbody. */
.rincian { gap: .6rem 1.4rem; }
.rincian dt { font-size: .76rem; text-transform: uppercase; letter-spacing: .05em; }
.rincian dd { line-height: 1.55; }

@media (max-width: 720px) {
  /* Kartu sel di ponsel: label dan nilai butuh jarak vertikal, bukan .3rem. */
  .tabel-bungkus td { padding: .42rem 0; }
  .rincian { grid-template-columns: minmax(96px, 38%) minmax(0, 1fr); gap: .55rem 1rem; }
}

/* ---- Materi pelatihan: kartu per modul. Satu modul = satu blok berisi modul
   PDF, bahan tayang, dan kertas kerja; dibaca dari ponsel maupun desktop, jadi
   sampul 4:3 + judul 2 baris, tombol Baca/Unduh selalu terlihat. */
.materi-keping { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .7rem; }
.materi-keping a { display: inline-flex; align-items: center; gap: .4rem; min-height: 40px;
  padding: .4rem .8rem; border: 1px solid var(--garis); border-radius: var(--r-kapsul);
  background: var(--putih); color: var(--tinta-2); font-size: .82rem; text-decoration: none; }
.materi-keping a b { color: var(--hijau-700); font-weight: 600; }
.materi-keping a.aktif { background: var(--hijau-100); border-color: var(--hijau-500); color: var(--hijau-800); }

.materi-kisi { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.materi-kartu { display: flex; flex-direction: column; overflow: hidden; background: var(--putih);
  border: 1px solid var(--garis); border-radius: var(--r); box-shadow: var(--bayang); }
.materi-sampul { position: relative; display: block; aspect-ratio: 4 / 3; background: var(--hijau-100); }
.materi-sampul img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.materi-ikon { position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--hijau-700); font-weight: 700; letter-spacing: .08em; font-size: .9rem; }
.materi-isi { display: flex; flex: 1 1 auto; flex-direction: column; gap: .3rem; padding: .7rem .8rem .8rem; }
.materi-isi h3 { margin: 0; font-size: .92rem; line-height: 1.35; }
.materi-isi p { margin: 0; font-size: .76rem; line-height: 1.4; }
.materi-isi .lencana { align-self: flex-start; font-size: .7rem; }
.materi-isi .tombol-baris { margin-top: auto; padding-top: .4rem; }
@media (max-width: 720px) {
  .materi-kisi { grid-template-columns: 1fr 1fr; gap: .6rem; }
  .materi-isi h3 { font-size: .84rem; }
  .materi-isi p { font-size: .72rem; }
}
@media (max-width: 430px) { .materi-kisi { grid-template-columns: 1fr; } }
.materi-rentang { margin: .7rem 0 0; font-size: .78rem; }

/* ================================================== sandi berpenglihatan */
/* Ditaruh paling BAWAH dengan sengaja: aturan `input { width:100%; padding:.6rem .7rem }`
   di atas akan menimpa padding kanan di sini kalau urutannya dibalik, dan ikon
   mata akan menutupi huruf terakhir sandi. */
.kolom-sandi { position: relative; display: block; }
.kolom-sandi input { padding-right: 2.7rem; }
.lihat-sandi { position: absolute; right: .3rem; top: .35rem; bottom: 0; width: 2.1rem;
  height: auto; min-height: 0; margin: 0; padding: 0; display: inline-flex;
  align-items: center; justify-content: center; border: 0; border-radius: var(--r-kecil);
  background: transparent; color: #67766f; cursor: pointer; }
.lihat-sandi svg { width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.lihat-sandi:hover { color: var(--hijau-600); background: rgba(0, 0, 0, .05); }
.lihat-sandi:focus-visible { outline: 2px solid var(--hijau-300); outline-offset: 1px; }
/* Bawaan: mata terbuka (sandi tersembunyi). Saat .tampak: mata dicoret. */
.lihat-sandi .mata-tutup, .lihat-sandi.tampak .mata-buka { display: none; }
.lihat-sandi.tampak .mata-tutup { display: inline; }
.lihat-sandi.tampak { color: var(--hijau-700, #1d5c43); }

/* ---- Peta sebaran KDKMP (/peta) ---------------------------------------
   Peta butuh TINGGI, bukan lebar. Di ponsel: peta 56vh lalu daftar di
   bawahnya; di layar lebar: peta & daftar berdampingan. Tinggi wadah wajib
   ditentukan CSS — Leaflet mengukur wadahnya sendiri dan hasilnya 0 px kalau
   tingginya bergantung isi. */
.kdkmp { padding: .85rem; }
/* Urutan ponsel: PETA dulu, kartu ringkasan menyusul. Lima kartu di atas peta
   mendorong peta ke bawah lipatan (terukur: peta mulai di y=958 pada layar
   360x640). Di desktop kartu tetap di atas — urutannya dibalik lewat `order`. */
.kdkmp-halaman { display: flex; flex-direction: column; }
.kdkmp .saring { margin-bottom: .7rem; }
.kdkmp-cacah { display: flex; gap: .3rem; flex-wrap: wrap; flex: 0 1 auto; min-width: 0; max-width: 100%; }
.kdkmp-cacah button { font: inherit; font-size: .8rem; line-height: 1; padding: .55rem .7rem;
  border: 1px solid var(--garis); border-radius: var(--r-kapsul); background: var(--putih);
  color: var(--mute, #4b5a54); cursor: pointer; }
.kdkmp-cacah button:hover { border-color: var(--hijau-300); color: var(--hijau-700); }
.kdkmp-cacah button.ini { background: var(--hijau-600); border-color: var(--hijau-600); color: #fff; font-weight: 600; }
.kdkmp-isi { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(240px, 1fr);
  gap: .8rem; align-items: stretch; }
.kdkmp-kanvas { min-width: 0; display: flex; flex-direction: column; gap: .35rem; }
.kdkmp-bingkai { height: clamp(340px, 56vh, 600px); border: 1px solid var(--garis);
  border-radius: var(--r-kecil); background: var(--latar); z-index: 0; }
/* Catatan keabsahan data: sengaja terlihat, bukan disembunyikan di tooltip. */
.kdkmp-catatan { margin: 0 0 .7rem; padding: .55rem .7rem; font-size: .78rem; line-height: 1.45;
  color: #6b4a00; background: #fff8e6; border: 1px solid #f0dca8; border-radius: var(--r-kecil); }
.kdkmp-legenda { display: flex; flex-wrap: wrap; gap: .2rem .9rem; margin: 0; font-size: .75rem; color: var(--mute, #4b5a54); }
.kdkmp-legenda span { display: inline-flex; align-items: center; gap: .3rem; }
.kdkmp-legenda i { width: .6rem; height: .6rem; border-radius: 50%; background: currentColor; }
.kdkmp-legenda i.t-jalur { width: 1.1rem; height: 0; border-radius: 0; background: none;
  border-top: 2px dashed #2b7fd4; }
.kdkmp-panel { display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--garis); border-radius: var(--r-kecil); background: var(--putih); }
.kdkmp-ringkas { padding: .55rem .7rem; border-bottom: 1px solid var(--garis-2);
  display: flex; flex-wrap: wrap; gap: .1rem .45rem; align-items: baseline; font-size: .8rem; }
.kdkmp-ringkas b { font-size: 1.02rem; color: var(--hijau-800); }
.kdkmp-catat { flex-basis: 100%; color: var(--pudar, #6b7a73); font-size: .78rem; }
.kdkmp-daftar { list-style: none; margin: 0; padding: .25rem; overflow-y: auto;
  max-height: clamp(240px, 44vh, 450px); }
.kdkmp-daftar em { font-style: normal; color: #a86a00; }
.kdkmp-daftar li { margin: 0; }
.kdkmp-butir { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .1rem .5rem;
  width: 100%; padding: .45rem .5rem; text-align: left; font: inherit; color: inherit;
  background: none; border: 0; border-radius: var(--r-mini); cursor: pointer; }
.kdkmp-butir:hover { background: var(--hijau-100); }
.kdkmp-butir.ini { background: var(--hijau-100); box-shadow: inset 2px 0 0 var(--hijau-600); }
.kdkmp-nama { font-weight: 600; font-size: .86rem; overflow: hidden; text-overflow: ellipsis; }
.kdkmp-angka { font-weight: 700; font-size: .84rem; color: var(--hijau-700);
  font-variant-numeric: tabular-nums; }
.kdkmp-prov { grid-column: 1; font-size: .74rem; color: var(--pudar, #6b7a73);
  overflow: hidden; text-overflow: ellipsis; }
.kdkmp-bilah { grid-column: 1 / -1; height: 4px; border-radius: 999px; background: var(--garis-2); overflow: hidden; }
.kdkmp-bilah i { display: block; height: 100%; background: var(--hijau-500); }
.kdkmp-taut { font-size: .78rem; }
.kdkmp-balik { flex-basis: 100%; font-size: .78rem; }
/* Ponsel: peta tetap di atas (tempat orang melihat), daftar menggulir di bawah. */
@media (max-width: 900px) {
  /* Kartu ringkasan 2 kolom: 5 kartu bertumpuk selebar layar mendorong peta
     ke bawah lipatan (terukur: peta mulai di y=958 pada layar 360x640). */
  .petak-kdkmp { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .petak-kdkmp .kartu:first-child { grid-column: 1 / -1; }
  .kdkmp-halaman > .kdkmp { order: -1; }
  .kdkmp { padding: .7rem; }
  .kdkmp-isi { grid-template-columns: 1fr; }
  .kdkmp-bingkai { height: 52vh; min-height: 300px; }
  .kdkmp-daftar { max-height: 44vh; }
  /* Lima tombol saringan tidak muat satu baris di 360 px: bungkus, jangan
     biarkan barisnya mendorong halaman melebar (terukur geser 48 px). */
  .kdkmp-cacah { flex: 1 1 100%; }
  .kdkmp-cacah button { padding: .5rem .6rem; }
}

/* Tanda air identitas pengakses (chat, pengumuman, keuangan, data pribadi).
   Ini PENANGKAL kebocoran, bukan pemblokir tangkap layar — OS yang mengambil
   gambarnya, halaman web tidak bisa menolak. Karena menutupi isi di lapisan
   paling atas, tanda air tidak bisa dipotong dengan menyembunyikan elemen;
   pointer-events:none supaya klik tetap tembus; hilang saat cetak agar nota
   dan slip gaji tetap bersih (dokumen itu memang untuk dicetak). */
.tanda-air { position: fixed; inset: 0; z-index: 9998; display: flex;
  align-items: center; justify-content: center; overflow: hidden;
  pointer-events: none; }
.tanda-air span { transform: rotate(-28deg); white-space: pre; text-align: center;
  font: 500 clamp(12px, 1.4vw, 16px)/5.6 system-ui, -apple-system, "Segoe UI", sans-serif;
  color: #0b1f16; opacity: .07; user-select: none; }
@media print { .tanda-air { display: none; } }

/* ============================================================ Operasional gerai
   Padanan EBITDAMAX (Manager KDKMP). Satu rangkaian kelas `ger-*`, dipakai
   keenam halaman /workspace/tugas/gerai*. Semua bertumpuk jadi satu kolom di
   ponsel — tidak ada informasi yang disembunyikan. */
/* Bilah tab: SATU baris yang bergulir mendatar di semua lebar. Dulu pil-pilnya
   membungkus jadi 2-3 baris bergerigi (8 menu), tinggi tiap halaman beda. */
.ger-tab { display: flex; gap: .35rem; margin: 0 0 1rem; overflow-x: auto;
  padding-bottom: .3rem; scroll-snap-type: x proximity; scrollbar-width: thin; }
.ger-tab a { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap;
  padding: .45rem .8rem; border: 1px solid var(--garis, #d7ded9); border-radius: 999px;
  font-size: .86rem; color: inherit; text-decoration: none; background: #fff; }
.ger-tab a:hover { border-color: #0b6b46; color: #0b6b46; }
.ger-tab a.ini { background: #0b6b46; border-color: #0b6b46; color: #fff; }
.ger-tab a:focus-visible { outline: 2px solid #0b6b46; outline-offset: 2px; }

.ger-kpi { display: grid; gap: .7rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.ger-kartu { border: 1px solid var(--garis, #d7ded9); border-radius: .8rem; padding: .75rem .9rem;
  background: #fff; display: flex; flex-direction: column; gap: .15rem; }
.ger-label { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: #5a6b62; }
.ger-angka { font-size: 1.35rem; line-height: 1.2; }

.ger-stat { display: grid; gap: .5rem; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  margin: .9rem 0; }
.ger-stat > div { border: 1px solid var(--garis, #d7ded9); border-radius: .6rem; padding: .55rem .7rem;
  background: #fafcfb; }
.ger-stat span { display: block; font-size: .76rem; color: #5a6b62; }
.ger-stat b { font-size: 1.05rem; }

.ger-matriks table, .ger-tabel { width: 100%; border-collapse: collapse; font-size: .9rem; }
.ger-matriks th, .ger-matriks td, .ger-tabel th, .ger-tabel td {
  padding: .45rem .5rem; border-bottom: 1px solid #e6ece8; text-align: left; vertical-align: top; }
.ger-matriks thead th, .ger-tabel thead th { font-size: .78rem; text-transform: uppercase;
  letter-spacing: .03em; color: #5a6b62; }
.ger-tabel { display: block; overflow-x: auto; }              /* tabel lebar: geser, jangan dipotong */

.ger-sub { margin: 1.2rem 0 .5rem; font-size: .95rem; }
.ger-batang { display: grid; gap: .3rem; }
.ger-batang-baris { display: grid; grid-template-columns: 4.2rem 1fr 6.5rem; align-items: center; gap: .5rem; }
.ger-batang-tgl { font-size: .78rem; color: #5a6b62; }
.ger-batang-dua { display: grid; gap: 2px; }
.ger-batang-plan { height: 4px; border-radius: 2px; background: #b9d6c9; }
.ger-batang-nyata { height: 8px; border-radius: 2px; background: #0b6b46; }
.ger-batang-nilai { font-size: .78rem; text-align: right; }

.ger-opsi { display: grid; gap: .5rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.ger-opsi-satu { display: flex; gap: .55rem; align-items: flex-start; border: 1px solid var(--garis, #d7ded9);
  border-radius: .6rem; padding: .6rem .7rem; background: #fff; }
.ger-opsi-satu span { display: flex; flex-direction: column; gap: .1rem; }
.ger-opsi-satu b { font-size: .9rem; }
.ger-opsi-satu input[type=checkbox] { margin-top: .2rem; }

.ger-task { display: flex; gap: .8rem; justify-content: space-between; align-items: flex-start;
  border: 1px solid var(--garis, #d7ded9); border-radius: .7rem; padding: .8rem .9rem; margin-bottom: .55rem;
  background: #fff; }
.ger-task-isi h3 { font-size: .98rem; margin: 0 0 .3rem; display: flex; flex-wrap: wrap; gap: .35rem;
  align-items: center; }
.ger-task-no { color: #5a6b62; }
.ger-task-meta { font-size: .8rem; color: #5a6b62; margin: 0; }
.ger-task-aksi { flex: 0 0 auto; }
.ger-alokasi { border: 1px dashed #cfd9d3; border-radius: .6rem; padding: .6rem .8rem; margin: .6rem 0; }
.ger-alokasi legend { font-size: .82rem; color: #5a6b62; padding: 0 .3rem; }
.ger-centang { display: flex; gap: .45rem; align-items: center; font-size: .86rem; }
.ger-ingat { border-left: 3px solid #d9a441; background: #fdf7ea; padding: .6rem .8rem;
  border-radius: .4rem; font-size: .88rem; }

.ger-hari { margin-bottom: 1.4rem; }
.ger-rapat { border: 1px solid var(--garis, #d7ded9); border-radius: .7rem; padding: .8rem .9rem;
  margin-bottom: .7rem; background: #fff; }
.ger-rapat-kepala h3 { margin: 0 0 .15rem; font-size: 1rem; }
.ger-rapat-peserta { font-size: .85rem; margin: .4rem 0; }
.ger-aksi { list-style: none; margin: .5rem 0 0; padding: 0; display: grid; gap: .45rem; }
.ger-aksi li { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  border-top: 1px solid #eef2ef; padding-top: .45rem; font-size: .88rem; }
.ger-aksi-judul { font-weight: 600; }
.ger-aksi-form { display: flex; gap: .35rem; align-items: center; margin-left: auto; }
.ger-aksi-baris { display: grid; gap: .35rem; grid-template-columns: 2fr 1fr 1fr; margin-bottom: .35rem; }

.ger-nara { border: 1px solid var(--garis, #d7ded9); border-radius: .7rem; padding: .8rem .9rem;
  margin-bottom: .6rem; background: #fff; }
.ger-nara-kepala { display: flex; gap: .5rem; align-items: center; }
.ger-nara-ringkas { white-space: pre-line; font-size: .88rem; }

@media (max-width: 640px) {
  .ger-task { flex-direction: column; }
  .ger-task-aksi { align-self: stretch; }
  .ger-task-aksi .tombol { width: 100%; }
  .ger-aksi-baris { grid-template-columns: 1fr; }
  .ger-aksi-form { margin-left: 0; }
  .ger-batang-baris { grid-template-columns: 3.6rem 1fr; }
  .ger-batang-nilai { grid-column: 2; text-align: left; }
}

/* Kepala /workspace/tugas: tiga aksi (Jobdesc, Operasional Gerai, Tugas Baru)
   dulu berdesakan & terpotong di ponsel. Jadi kisi dua kolom dengan aksi utama
   selebar baris — tiap tombol utuh, tinggi seragam 42px, ikon tetap terlihat. */
@media (max-width: 720px) {
  .kepala .tombol-baris.tugas-aksi { flex: 1 0 100%; width: 100%; display: grid;
    grid-template-columns: 1fr 1fr; gap: .45rem; justify-content: stretch; }
  .kepala .tombol-baris.tugas-aksi > .tombol,
  .kepala .tombol-baris.tugas-aksi > form > .tombol {
    width: 100%; min-height: 42px; justify-content: center;
    font-size: .82rem; padding: .4rem .5rem; text-align: center; }
  .kepala .tombol-baris.tugas-aksi > .tombol .ik { width: 16px; height: 16px; flex: 0 0 auto; }
  .kepala .tombol-baris.tugas-aksi > .tombol.lebar { grid-column: 1 / -1; }
}

/* Dua aksi sekunder di kepala /workspace/tugas: latar putih, garis & ikon hijau
   (ikon mewarisi currentColor). Aksi utama (.lebar) tetap hijau penuh. */
.kepala .tombol-baris.tugas-aksi > .tombol:not(.lebar) {
  background: #fff; border-color: #0b6b46; color: #0b6b46; }
.kepala .tombol-baris.tugas-aksi > .tombol:not(.lebar):hover {
  background: #eaf5ef; border-color: #0b6b46; color: #085c3c; }

/* ===== Ringkasan stok koperasi + baris aksi kepala, di ponsel =====
   Terukur @390px SEBELUM: tiga kartu ringkas 2 kolom lalu kartu ketiga
   menggantung (123,5 vs 154,8 px), lima tombol jadi 3 baris bergerigi, dan
   blok ringkasan setinggi 252 px sehingga tabel baru mulai di y=522.
   Sekarang: tiga angka jadi SATU kartu bersekat (label kiri, nilai kanan
   sebaris, keterangan di bawah label), baris aksi kisi 2 kolom selebar baris.
   Tinggi blok ringkasan 252 -> 139 px. Informasi tidak ada yang disembunyikan. */
@media (max-width: 560px) {
  /* Blok pembungkus dilepas: kartu bersekat sudah jadi bingkainya sendiri,
     kalau tidak bingkainya dobel (border+padding 1rem di dalam border+padding). */
  .blok.blok-ringkas { padding: 0; background: none; border: 0; box-shadow: none; }
  .kartu-baris { grid-template-columns: 1fr; gap: .55rem; }
  .kartu-ringkas { display: block; gap: 0; background: var(--putih);
    border: 1px solid var(--garis); border-radius: var(--r); box-shadow: var(--bayang);
    overflow: hidden; }
  .kartu-ringkas > .kartu.angka { display: grid; grid-template-columns: minmax(0, 1fr) auto;
    /* `.kartu-status .kartu` memaku min-height 4,6rem (73,6 px) supaya deret
       kartu rata; di dalam satu kartu bersekat paku itu cuma rongga. */
    min-height: 0;
    align-items: center; column-gap: .9rem; padding: .55rem .85rem .6rem;
    border: 0; border-left: 3px solid var(--hijau-300);
    border-bottom: 1px solid var(--garis-2); border-radius: 0; box-shadow: none; }
  .kartu-ringkas > .kartu.angka:last-child { border-bottom: 0; }
  .kartu-ringkas > .kartu.angka > small:first-child { grid-area: 1 / 1; }
  /* `span 2` + 1.35rem membuat tiap kartu 73,6 px meski isinya cuma satu baris
     (terukur /pasokan @390: 4 kartu jenis = 296 px). Satu baris saja, angka
     lebih kecil: 39 px per kartu. Keterangan (anak ke-3) tetap di baris 2. */
  .kartu-ringkas > .kartu.angka > b { grid-area: 1 / 2; align-self: center; justify-self: end;
    margin: 0; font-size: 1.15rem; }
  .kartu-ringkas > .kartu.angka > small.pudar { grid-area: 2 / 1; letter-spacing: 0;
    text-transform: none; font-weight: 600; font-size: .72rem; line-height: 1.35; }
}
/* /pasokan: dua <select> saringan berbagi satu baris di ponsel. Aturan umum
   `.saring label.pilih { flex: 1 1 60% }` membuat 60%+60% selalu membungkus,
   jadi cari + 2 select = 3 baris (168 px). Dua kolom: 118 px. */
@media (max-width: 560px) {
  #ps .saring label.pilih { flex: 1 1 calc(50% - .45rem); }
}
@media (max-width: 720px) {
  .cat-kepala { display: grid; grid-template-columns: minmax(0, 1fr); gap: .5rem; }
  .cat-kepala > .tombol-baris { display: grid; grid-template-columns: 1fr 1fr;
    gap: .4rem; width: 100%; justify-content: stretch; }
  .cat-kepala > .tombol-baris > .tombol,
  .cat-kepala > .tombol-baris > form > .tombol { width: 100%; min-height: 38px;
    justify-content: center; text-align: center; font-size: .78rem; padding: .3rem .4rem; }
}
/* 360px: "Permintaan Produk" + ikon 16px tidak muat satu baris pada .78rem,
   tombolnya jadi dua baris dan barisnya bergerigi 3,5 px. Turunkan satu takik. */
@media (max-width: 380px) {
  .cat-kepala > .tombol-baris > .tombol,
  .cat-kepala > .tombol-baris > form > .tombol { font-size: .72rem; white-space: nowrap; }
}

/* ------------------------------------------------- lingkaran muat (navigasi)
   Dibuat hub.js saat halaman dimuat; tampil hanya bila perpindahan melewati
   150 ms, supaya klik yang cepat tidak berkedip.
   TANPA tirai putih: dulu latar .55 + blur menutupi isi halaman, sehingga di
   /asisten kolom tulis dan gelembung "sedang menulis" ikut memudar dan
   pengguna merasa tidak bisa mengetik. Sekarang hanya cincinnya. */
#hub-muat-tengah {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: center; justify-content: center;
  background: transparent;
  pointer-events: none;
}
#hub-muat-tengah[hidden] { display: none; }
/* Delapan titik hijau berputar membentuk lingkaran. Tiap titik digeser 45° dan
   pudarnya berurutan, jadi tampak seperti satu titik berjalan. */
#hub-muat-tengah .titik-titik {
  position: relative; width: 2.6rem; height: 2.6rem; display: block;
}
#hub-muat-tengah .titik-titik i {
  position: absolute; inset: 0; margin: auto;
  width: .4rem; height: .4rem; border-radius: 50%;
  background: var(--hijau-500, #1f8739); opacity: .15;
  transform: rotate(calc(var(--i) * 45deg)) translateY(-1.02rem);
  animation: hub-titik 1.1s linear infinite;
  animation-delay: calc(var(--i) * -.1375s);
}
@keyframes hub-titik {
  0%, 100% { opacity: .15; }
  40% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #hub-muat-tengah .titik-titik i { animation-duration: 3s; }
}

/* Daftar permintaan izin dokumen (>1 pemohon) di kolom aksi.
   Dilipat supaya kolom tidak penuh tombol; rincian muncul saat dibuka. */
.dok-minta { display: inline-block; }
.dok-minta > summary { cursor: pointer; list-style: none; }
.dok-minta > summary::-webkit-details-marker { display: none; }
.dok-minta-daftar { list-style: none; margin: .35rem 0 0; padding: 0; display: grid; gap: .3rem; }
.dok-minta-daftar > li {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem;
  font-size: .8rem; padding: .25rem .35rem; border: 1px solid var(--garis);
  border-radius: 8px; background: var(--zebra);
}
.dok-minta-daftar > li > span { flex: 1 1 8rem; font-weight: 600; }

/* ------------------------------------------------------------- halaman profil
   Baris aksi (Simpan profil, Pakai lokasi) dulu menempel di kiri dengan sisa
   ruang kosong panjang di layar lebar — terlihat "tidak rapih". Di layar lebar
   tombolnya rata kanan; di ponsel melebar penuh supaya mudah ditekan. */
.form-profil .form-aksi { justify-content: flex-end; align-items: center; row-gap: .5rem; }
.form-profil .form-aksi > small { flex: 1 1 100%; text-align: right; }
.form-profil #p-rumah-status.sedang-ambil { color: var(--hijau-600, #15402f); }
.form-profil .tombol-baris.simpan-riwayat { justify-content: flex-end; margin-top: .9rem; }
@media (max-width: 640px) {
  .form-profil .form-aksi,
  .form-profil .tombol-baris.simpan-riwayat { justify-content: stretch; }
  .form-profil .form-aksi > .tombol,
  .form-profil .tombol-baris.simpan-riwayat > .tombol { width: 100%; justify-content: center; min-height: 44px; }
  .form-profil .form-aksi > small { text-align: left; }
}

/* ---------- titik absen AgriConnect (5 Nov 2026) ----------
   Pemilihan lokasi harus terbaca sebagai pilihan, bukan catatan kaki: titik
   koperasi adalah alternatif sah saat GPS ditolak, bukan kegagalan. */
.agri-titik { border: 1px solid var(--garis); border-radius: 10px; padding: .8rem .9rem 1rem; margin: 1rem 0; }
.agri-titik legend { font-weight: 800; font-size: .92rem; padding: 0 .4rem; color: var(--hijau-800); }
.agri-titik-opsi { display: flex; gap: .6rem; align-items: flex-start; min-height: 44px;
  padding: .55rem .5rem; border-radius: 8px; cursor: pointer; }
.agri-titik-opsi:hover { background: #f4f8f7; }
.agri-titik-opsi input { margin-top: .25rem; width: 18px; height: 18px; }
.agri-titik-opsi b { display: block; font-size: .93rem; color: var(--tinta); }
.agri-titik-opsi i { display: block; font-style: normal; font-size: .82rem; color: var(--tinta-2); line-height: 1.45; }
/* Warna tegas ditulis langsung: `--teal` hanya ada di tani.css, BUKAN di
   hub.css — memakai variabel yang tidak dikenal membatalkan seluruh deklarasi
   box-shadow tanpa galat, dan pilihan yang aktif jadi tak terlihat. */
.agri-titik-opsi:has(input:checked) { background: #eef7f5; box-shadow: inset 0 0 0 2px #0a6b62; }

/* ---------- ODES: formulir warga di ponsel ----------
   Isian di bawah 16 px memicu zoom otomatis iOS dan tidak bisa diperkecil —
   pada formulir panjang (KTP, selfie, kendaraan) itu membuat warga kehilangan
   tempat setelah setiap ketukan. Semua isian di halaman ini dinaikkan. */
.odes-isi input, .odes-isi select, .odes-isi textarea,
form.grid-form input, form.grid-form select, form.grid-form textarea { font-size: 16px; }
@media (max-width: 560px) {
  form.grid-form input, form.grid-form select, form.grid-form textarea { font-size: 16px; }
}

/* ---------- ODES: hero & formulir warga (5 Nov 2026) ----------
   Hero = SATU bidang hijau berisi lencana → judul → keterangan, dibungkus
   kolom. Teks putih ditulis eksplisit: `.kepala` mewarisi `--tinta` (gelap),
   jadi tulisan hitam di atas hijau tua nyaris tak terbaca. */
.odes-hero { background: linear-gradient(160deg, var(--hijau-800), #14532d);
  color: #fff; border-radius: var(--r); padding: 1.5rem 1.35rem 1.6rem;
  margin-bottom: 1.2rem; }
.odes-hero-isi { max-width: 62ch; margin-inline: auto; }
.odes-hero-lencana { display: inline-block; font-size: .72rem; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase; color: #d8f0e2;
  background: rgba(255, 255, 255, .16); padding: .28rem .6rem; border-radius: 999px;
  margin-bottom: .7rem; }
.odes-hero h1 { color: #fff; font-size: 1.6rem; line-height: 1.22;
  margin: 0 0 .6rem; }
.odes-hero p { color: #e6f4ec; font-size: .95rem; line-height: 1.6;
  margin: 0; max-width: 60ch; }
.odes-hero b { color: #fff; }

/* Tiga syarat sebagai kartu bernomor; dalam satu kolom di ponsel supaya teks
   tidak terpotong jadi baris-baris pendek. */
.odes-syarat { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.odes-syarat .kartu-peran { padding: .95rem 1rem; }
.odes-syarat .kartu-peran small { font-size: .84rem; line-height: 1.55; }
.odes-nomor { display: inline-grid; place-items: center; width: 1.5rem; height: 1.5rem;
  margin-right: .45rem; border-radius: 50%; background: var(--hijau-100);
  color: var(--hijau-800); font-size: .82rem; font-weight: 800; vertical-align: -2px; }

/* Kotak "anda mendaftar ke koperasi": label → nama → alamat, tidak menyambung. */
.odes-kop { margin-bottom: .2rem; background: var(--hijau-100);
  border-color: var(--hijau-300); }
.odes-kop small { display: block; font-size: .74rem; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--hijau-800);
  margin-bottom: .3rem; }
.odes-kop b { display: block; font-size: .96rem; line-height: 1.4;
  color: var(--hijau-900); margin-bottom: .2rem; }
.odes-kop span { display: block; font-size: .84rem; color: var(--tinta-2); }

.odes-form { margin-top: 0; gap: .9rem 1rem; }
.odes-form label { font-size: .9rem; }
.odes-form input, .odes-form select { min-height: 2.75rem; }

@media (max-width: 640px) {
  .odes-hero { padding: 1.25rem 1.1rem 1.35rem; }
  .odes-hero h1 { font-size: 1.35rem; }
  .odes-hero p { font-size: .92rem; }
  .odes-syarat { grid-template-columns: 1fr; gap: .55rem; }
}

/* ---------- ODES: formulir warga di ponsel ----------
   Isian di bawah 16 px memicu zoom otomatis iOS dan tidak bisa diperkecil —
   pada formulir panjang (KTP, selfie, kendaraan) itu membuat warga kehilangan
   tempat setelah setiap ketukan. Semua isian di halaman ini dinaikkan. */
.odes-isi input, .odes-isi select, .odes-isi textarea,
form.grid-form input, form.grid-form select, form.grid-form textarea { font-size: 16px; }
@media (max-width: 560px) {
  form.grid-form input, form.grid-form select, form.grid-form textarea { font-size: 16px; }
}

/* ---------- ODES: hero & formulir warga (5 Nov 2026) ----------
   Keluhan Bos: header & hero formulir publik "berantakan". Sebabnya bukan
   halaman ini saja — `main.isi.polos` dulu padding:0 (lihat .isi.polos).
   Aturan di bawah merapikan sisanya: jarak kepala yang lega, paragraf yang
   boleh membungkus, dan formulir yang turun satu kolom di ponsel. */
.kepala.odes-kepala { display: block; border-bottom: 0; padding-bottom: 0;
  margin-bottom: 1.1rem; }
.kepala.odes-kepala .kepala-lencana { margin-bottom: .5rem; }
.kepala.odes-kepala h1 { font-size: 1.65rem; line-height: 1.25; margin: 0 0 .55rem; }
.kepala .odes-ringkas { font-size: .95rem; line-height: 1.55; color: var(--tinta-2);
  margin: 0; max-width: 62ch; white-space: normal; overflow: visible; text-overflow: clip; }

.odes-form { margin-top: 0; gap: .9rem 1rem; }
.odes-form label > span:first-child, .odes-form label { font-size: .9rem; }
.odes-form input, .odes-form select { min-height: 2.75rem; }
.odes-form fieldset legend { font-size: .92rem; padding: 0 .35rem; }

@media (max-width: 640px) {
  .kepala.odes-kepala h1 { font-size: 1.4rem; }
  .kepala .odes-ringkas { font-size: .92rem; }
}

/* ---------- BERANDA RUANG KERJA KDKMP (5 Nov 2026) ----------
   Beranda bukan profil perusahaan: hero tanpa foto sawah, angka nyata dari
   basis data, dan satu merek saja. Latar hijau penuh supaya teks putih terbaca
   (kontras terukur >10:1); foto petani dipakai di situs informasi (.com). */
.pub-hero-kerja { background: linear-gradient(150deg, #175433 0%, #12402a 55%, #0d3121 100%);
  min-height: clamp(380px, 56vh, 560px); }
.pub-hero-kerja::after { display: none; }        /* tanpa foto = tanpa lapisan gelap */
.pub-hero-kerja h1 { max-width: 22ch; }
.pub-hero-kerja .pub-hero-isi > p { color: #d7e8de; }
.pub-hero-angka { display: flex; flex-wrap: wrap; gap: 1.4rem 2.2rem; margin-top: 1.6rem;
  padding-top: 1.2rem; border-top: 1px solid rgba(255, 255, 255, .18); }
.pub-hero-angka > div { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.pub-hero-angka b { color: #fff; font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  line-height: 1.1; letter-spacing: -.01em; }
.pub-hero-angka span { color: #b9d3c4; font-size: .8rem; line-height: 1.35; }

/* Bilah atas: satu merek, jadi tidak butuh pemisah/logo kedua. */
.pub-merek .merek-agrinas b { color: var(--hijau-900); font-size: 1.05rem; letter-spacing: -.01em; }

/* ---------- BERANDA PUBLIK: skala & ritme ala Linear/Vercel (5 Nov 2026) ----------
   Diukur dari referensi nyata (1440px):
     Linear  h1 64px / line-height 1.0 / tracking -1.4px, font Inter Variable
     Vercel  h1 64px / line-height 1.0 / tracking -3.8px, font Geist
   Milik kita sebelumnya: h1 51px / lh 1.08 / tracking -0.77px, dan judul seksi
   hanya 74ch sehingga kolom isi 1180px tampak kosong di kanan — itulah kesan
   "tidak profesional". Sekarang: skala tipografi tegas, kolom judul mengikuti
   kolom isi, kartu sama tinggi, dan ritme spasinya satu nilai. */
.pub-hero h1 { font-size: clamp(2rem, 1.1rem + 3.9vw, 4rem); line-height: 1.02;
  letter-spacing: -.028em; max-width: 24ch; font-weight: 700; }
.pub-hero-kerja h1 { max-width: 26ch; }
.pub-hero-merek { letter-spacing: .16em; font-size: .74rem; }

/* Judul seksi selebar kolom isi (bukan 74ch yang membuat separuh kanan kosong). */
.pub-kepala-bagian { max-width: 100%; }
.pub-kepala-bagian h2, .pub-kepala-bagian > p { max-width: 68ch; }
.pub-kepala-bagian h2 { font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2.4rem);
  line-height: 1.12; letter-spacing: -.022em; font-weight: 700; }
.pub-kepala-bagian > p { font-size: clamp(.95rem, .9rem + .3vw, 1.09rem); line-height: 1.62; }

/* Ritme: satu nilai untuk semua seksi supaya jarak antar-bagian konsisten. */
.pub-bagian { padding-top: clamp(2.6rem, 1.4rem + 4vw, 5.2rem);
  padding-bottom: clamp(2.6rem, 1.4rem + 4vw, 5.2rem); }

/* Kartu: tinggi SERAGAM per baris. Tanpa ini kartu dengan teks 3 baris berdiri
   lebih tinggi dari tetangganya (terukur 165 vs 144px) dan kisi tampak miring. */
.pub-kartu-grid { align-items: stretch; gap: clamp(.9rem, .6rem + .8vw, 1.4rem); }
.pub-kartu-grid > .pub-kartu { display: flex; flex-direction: column; height: 100%;
  padding: clamp(1.15rem, 1rem + .5vw, 1.5rem);
  border-radius: 14px; transition: border-color .15s, box-shadow .15s, transform .15s; }
.pub-kartu-grid > .pub-kartu:hover { border-color: var(--hijau-300);
  box-shadow: 0 6px 18px -8px rgba(16, 29, 24, .25); transform: translateY(-1px); }
.pub-kartu h3 { font-size: 1.02rem; line-height: 1.3; margin-bottom: .45rem;
  letter-spacing: -.01em; }
.pub-kartu p { font-size: .93rem; line-height: 1.6; color: #4d5a53; }

/* Angka hero: garis pemisah tipis, angka lebih besar, label tenang. */
.pub-hero-angka { gap: 1.6rem 2.6rem; }
.pub-hero-angka b { font-size: clamp(1.5rem, 1.2rem + 1.1vw, 2.1rem); }
.pub-hero-angka span { font-size: .82rem; letter-spacing: .01em; }

/* Daftar langkah & lini: nomor tegas, teks sejajar. */
.pub-langkah { gap: 1rem; }
.pub-langkah > li { padding: 1.1rem 1.2rem; border-radius: 12px; background: #fff;
  border: 1px solid var(--garis); }
.pub-lini > li > b { font-size: .8rem; letter-spacing: .04em; color: var(--hijau-700); }

@media (max-width: 720px) {
  /* h1 ponsel: clamp dasar memberi 32.8px di 390px — terlalu kecil untuk judul
     utama. 37px (≈9.5vw) terbaca tegas tanpa memakan layar. */
  .pub-hero h1 { font-size: clamp(2.3rem, 8.6vw, 2.6rem); letter-spacing: -.022em;
    line-height: 1.06; }
  .pub-kepala-bagian > p { font-size: .95rem; }
  .pub-kartu-grid { gap: .8rem; }
  .pub-kartu h3 { font-size: .98rem; }
  .pub-kartu p { font-size: .9rem; }
  .pub-langkah { grid-template-columns: 1fr; }

  /* Di ponsel padding seksi + margin-auto anak menumpuk jadi 30px tiap sisi
     (isi hanya 329px dari 390px). Satu sisi 16px sudah cukup: teks 358px. */
  .pub-bagian { padding-left: 1rem; padding-right: 1rem; }
  .pub-bagian > * { margin-left: 0; margin-right: 0; }
  .pub-hero-isi { padding-left: 1rem; padding-right: 1rem; }
  .pub-bar { padding-left: 1rem; padding-right: 1rem; }
  .pub-hero-angka { gap: 1rem 1.6rem; }
  .pub-hero-angka > div { flex: 1 1 40%; }
}

/* ============ ODES PASAR (kanal belanja anggota) — 5 Nov 2026 ============
   Gaya aplikasi belanja harian (rujukan: astronauts.id): kepala lengket dengan
   pencarian, kisi ikon kategori, kartu produk rapat 2 kolom di ponsel / 4-5 di
   desktop, dan ringkasan total yang selalu terlihat. Warna mengikuti merek Hub
   (hijau), bukan kuning-oranye, supaya tidak terbaca sebagai situs lain. */
.odes-pasar { --pasar-garis: #e4eae5; --pasar-lembut: #f4f8f4; }
/* `clamp(.75rem,.4rem+2vw,2rem)` TIDAK SAH: perlu spasi di sekitar `+`, kalau
   tidak seluruh deklarasi dibuang peramban (terukur padding = 0px, kartu
   menempel tepi layar). Tulis tiga nilai spasi eksplisit. */
/* TEPI: JANGAN menambah padding kiri/kanan di sini. Kerangka (layouts.odes)
   sudah memberi --odes-tepi 15px, dan .odes-pasar menambah 16px lagi sehingga
   terukur 31px di ponsel — inilah "jarak kiri kanan terlalu lebar". Padding
   di sini hanya untuk RUANG BAWAH (navbar tetap + bilah keranjang). */
.odes-pasar { max-width: 1320px; margin-inline: auto;
  padding: 0 0 1.5rem; }

/* `top: 0` membuat kepala pasar MENUTUPI header Hub (terukur: elementFromPoint
   (20,20) = HEADER.pasar-kepala). Di layar sempit header Hub ikut sticky, jadi
   kepala pasar berhenti DI BAWAHNYA. */
.pasar-kepala { position: sticky; top: var(--tb-kepala, 0px); z-index: 12;
  display: flex; align-items: center; gap: .8rem; padding: .7rem 0;
  background: rgba(255, 255, 255, .97); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--pasar-garis); }
@media (max-width: 900px) { .pasar-kepala { top: 3.35rem; } }
.pasar-merek { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.pasar-merek b { display: block; line-height: 1.15; }
.pasar-merek small { display: block; color: var(--pudar); font-size: .74rem;
  max-width: 26ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pasar-cari { flex: 1 1 auto; display: flex; align-items: center; gap: .45rem;
  background: var(--pasar-lembut); border: 1px solid var(--pasar-garis);
  border-radius: 999px; padding: .45rem .85rem; min-width: 0; }
.pasar-cari svg { width: 18px; height: 18px; flex: 0 0 auto; stroke: var(--tinta-2);
  fill: none; stroke-width: 2; stroke-linecap: round; }
.pasar-cari input { border: 0; background: transparent; width: 100%; font-size: 16px;
  padding: .1rem 0; min-width: 0; }
.pasar-cari input:focus { outline: none; }
.pasar-keranjang { position: relative; flex: 0 0 auto; display: inline-flex;
  align-items: center; gap: .3rem; text-decoration: none; color: var(--tinta);
  background: var(--pasar-lembut); border: 1px solid var(--pasar-garis);
  border-radius: 999px; padding: .45rem .75rem; font-size: .9rem; }
.pasar-keranjang b { background: var(--hijau-700); color: #fff; border-radius: 999px;
  min-width: 1.35rem; text-align: center; font-size: .78rem; padding: .05rem .3rem; }

.pasar-status { display: flex; flex-wrap: wrap; gap: 1rem 2rem; margin: 1rem 0 0;
  padding: .9rem 1.1rem; background: var(--hijau-l); border: 1px solid var(--hijau-200);
  border-radius: 14px; }
.pasar-status > div { display: flex; flex-direction: column; gap: .1rem; }
.pasar-status small { color: var(--pudar); font-size: .74rem; }

.pasar-kategori { display: flex; gap: .5rem; overflow-x: auto; padding: .9rem 0 .3rem;
  scrollbar-width: thin; }
.pasar-kategori a { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center;
  gap: .25rem; padding: .55rem .7rem; border-radius: 12px; text-decoration: none;
  color: var(--tinta-2); border: 1px solid transparent; min-width: 74px; }
.pasar-kategori a span { font-size: 1.35rem; line-height: 1; }
.pasar-kategori a small { font-size: .72rem; text-align: center; line-height: 1.2; }
.pasar-kategori a:hover { background: var(--pasar-lembut); }
.pasar-kategori a.ini { background: #fff; border-color: var(--hijau-300);
  color: var(--hijau-800); font-weight: 600; }

.pasar-kisi { display: grid; gap: .75rem; margin-top: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
@media (min-width: 900px) { .pasar-kisi { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); } }
.pasar-kartu { display: flex; flex-direction: column; background: #fff;
  border: 1px solid var(--pasar-garis); border-radius: 14px; overflow: hidden;
  transition: box-shadow .15s, transform .15s; }
.pasar-kartu:hover { box-shadow: 0 8px 22px -12px rgba(16,29,24,.35); transform: translateY(-1px); }
.pasar-gambar { display: grid; place-items: center; aspect-ratio: 4/3;
  background: var(--pasar-lembut); font-size: 2.4rem; }
.pasar-isi { display: flex; flex-direction: column; gap: .2rem; padding: .7rem .8rem .8rem;
  flex: 1 1 auto; }
.pasar-nama { font-size: .88rem; line-height: 1.3; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.3em; }
.pasar-coret { color: var(--pudar); text-decoration: line-through; font-size: .74rem; }
.pasar-harga { display: flex; flex-direction: column; margin-top: auto; padding-top: .35rem; }
.pasar-harga b { font-size: 1rem; color: var(--hijau-800); letter-spacing: -.01em; }
.pasar-harga small { font-size: .7rem; }
.pasar-tambah { margin-top: .5rem; width: 100%; }
.pasar-kosong { grid-column: 1 / -1; padding: 2rem 1rem; text-align: center; color: var(--pudar); }

.pasar-pesan { margin-top: 2rem; padding: clamp(1rem, .8rem + 1vw, 1.6rem);
  background: #fff; border: 1px solid var(--pasar-garis); border-radius: 16px; scroll-margin-top: 5rem; }
.pasar-pesan h2 { font-size: 1.15rem; margin-bottom: .3rem; }
.pasar-keranjang-isi { display: flex; flex-direction: column; gap: .4rem; margin-top: .4rem;
  border: 1px dashed var(--pasar-garis); border-radius: 12px; padding: .7rem; min-height: 3rem; }
.pasar-baris { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding-bottom: .4rem; border-bottom: 1px solid var(--pasar-garis); }
.pasar-baris:last-child { border-bottom: 0; padding-bottom: 0; }
.pasar-baris-nama { flex: 1 1 40%; font-size: .9rem; min-width: 0; }
.pasar-baris-qty { display: inline-flex; align-items: center; gap: .25rem; }
.pasar-baris-qty button { width: 30px; height: 30px; border-radius: 8px;
  border: 1px solid var(--pasar-garis); background: var(--pasar-lembut); font-size: 1rem;
  line-height: 1; cursor: pointer; }
.pasar-baris-qty input { width: 46px; text-align: center; border: 1px solid var(--pasar-garis);
  border-radius: 8px; padding: .25rem; font-size: 16px; }
.pasar-hapus { border: 0; background: transparent; color: #a32218; font-size: 1.15rem;
  cursor: pointer; padding: 0 .2rem; }

.pasar-total { display: grid; gap: .3rem; padding: .9rem 1rem; background: var(--pasar-lembut);
  border-radius: 12px; }
.pasar-total > div { display: flex; justify-content: space-between; font-size: .9rem; color: var(--tinta-2); }
.pasar-total-besar { border-top: 1px solid var(--pasar-garis); padding-top: .45rem; margin-top: .2rem;
  font-size: 1rem !important; color: var(--tinta) !important; }
.pasar-total-besar b { font-size: 1.25rem; color: var(--hijau-800); }

@media (max-width: 640px) {
  .pasar-merek small { display: none; }
  .pasar-kepala { gap: .5rem; }
  /* Dua kolom dengan celah 8px: kartu jadi 171px di layar 390px (sebelumnya
     159px karena celah 10px + padding ganda). */
  .pasar-kisi { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .pasar-gambar { font-size: 2rem; }
  .pasar-nama { font-size: .82rem; }
  .pasar-harga b { font-size: .95rem; }
}

/* ============ Produk desa (panel manajer) — 5 Nov 2026 ============
   Kisi memakai .pasar-kartu (SAMA dengan katalog publik) supaya manajer
   melihat tampilan yang dilihat pembeli. Yang ditambah hanya dua tombol ikon. */
.produk-kepala { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: .8rem; }
.produk-saring { flex-wrap: wrap; }
.produk-kisi { margin-top: .8rem; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
@media (min-width: 900px) { .produk-kisi { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); } }
@media (max-width: 640px) { .produk-kisi { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.pasar-gambar { position: relative; overflow: hidden; }
.pasar-gambar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.produk-asal { position: absolute; top: .3rem; left: .3rem; background: rgba(255,255,255,.94); }
.produk-aksi { display: flex; gap: .35rem; margin-top: .5rem; }
.produk-aksi form { margin: 0; }
.produk-pusat { margin-top: .5rem; display: block; }
/* Tombol IKON saja: kotak sama sisi, tanpa teks. Target sentuh tetap >= 32px. */
.tombol.ikon-saja { padding: 0; width: 34px; height: 34px; display: inline-grid;
  place-items: center; }
.tombol.ikon-saja .ik { width: 17px; height: 17px; stroke: currentColor; fill: none; }
.produk-kartu.milik-desa { border-color: var(--hijau-300); }

/* ============ Ubah Jam Kerja (AgriConnect) — 6 Nov 2026 ============
   Halaman ini dulu memakai .grid-form polos sehingga terlihat seperti formulir
   mentah. Sekarang: kepala ringkas, empat angka, formulir + panel shift
   berdampingan (jadi satu kolom di ponsel), dan rentang tanggal berbentuk baris
   yang bisa ditambah/dihapus. */
.jamkerja { display: flex; flex-direction: column; gap: 1rem; max-width: 1180px; }
.jamkerja-kepala { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; }
.jamkerja-kepala h1 { font-size: clamp(1.4rem, 1.1rem + 1vw, 1.9rem); margin: .25rem 0 .3rem; }
.jamkerja-kepala p { color: var(--pudar); max-width: 62ch; margin: 0; }
.jamkerja-balik { font-size: .82rem; color: var(--hijau-800); text-decoration: none; }
.jamkerja-balik:hover { text-decoration: underline; }

.jamkerja-angka { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: .6rem; }
.jamkerja-angka > div { background: #fff; border: 1px solid var(--garis);
  border-radius: 12px; padding: .7rem .9rem; display: flex; flex-direction: column; gap: .1rem; }
.jamkerja-angka small { color: var(--pudar); font-size: .74rem; }
.jamkerja-angka b { font-size: 1.35rem; line-height: 1.1; letter-spacing: -.02em; }
.jamkerja-angka .kuning { color: #8a5a00; }
.jamkerja-angka .hijau { color: #1a7f37; }
.jamkerja-angka .merah { color: #a32218; }

.jamkerja-grid { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
@media (max-width: 900px) { .jamkerja-grid { grid-template-columns: minmax(0, 1fr); } }

.jamkerja-kartu { background: #fff; border: 1px solid var(--garis); border-radius: 14px;
  padding: 1rem 1.1rem 1.2rem; }
.jamkerja-kartu > header { margin-bottom: .8rem; }
.jamkerja-kartu h2 { font-size: 1rem; margin: 0 0 .15rem; }
.jamkerja-kartu .bantuan { font-size: .8rem; color: var(--pudar); margin: 0; }
.jamkerja-kosong { padding: 1.2rem; text-align: center; color: var(--pudar);
  background: var(--lembut, #f7f9f7); border-radius: 10px; font-size: .88rem; }

.jamkerja-isian { display: block; font-size: .82rem; font-weight: 600; color: var(--tinta-2); }
.jamkerja-isian textarea { width: 100%; margin-top: .3rem; padding: .55rem .7rem;
  border: 1px solid var(--garis); border-radius: 10px; font: inherit; font-size: 16px;
  resize: vertical; }
.jamkerja-isian small { display: block; margin-top: .25rem; font-weight: 400;
  color: var(--pudar); font-size: .74rem; }

.jamkerja-rentang-kepala { display: flex; align-items: center; justify-content: space-between;
  margin: 1rem 0 .5rem; font-size: .82rem; font-weight: 600; color: var(--tinta-2); }
#daftar-rentang { display: flex; flex-direction: column; gap: .5rem; }
.jamkerja-rentang { display: grid; align-items: end; gap: .5rem;
  grid-template-columns: 1fr auto 1fr 1.2fr auto;
  background: #f7f9f7; border: 1px solid var(--garis); border-radius: 12px; padding: .6rem .7rem; }
.jamkerja-rentang label { display: block; font-size: .74rem; font-weight: 600; color: var(--pudar); }
.jamkerja-rentang input, .jamkerja-rentang select { width: 100%; margin-top: .2rem;
  padding: .45rem .5rem; border: 1px solid var(--garis); border-radius: 8px;
  font: inherit; font-size: 16px; background: #fff; }
.jamkerja-panah { color: var(--pudar); padding-bottom: .6rem; }
.jamkerja-buang { width: 32px; height: 32px; border: 1px solid var(--garis); background: #fff;
  border-radius: 8px; color: #a32218; font-size: 1.1rem; line-height: 1; cursor: pointer;
  margin-bottom: .15rem; }
.jamkerja-buang:hover { background: #fdeeec; border-color: #f0c4bf; }

@media (max-width: 720px) {
  .jamkerja-angka { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .jamkerja-rentang { grid-template-columns: 1fr 1fr; }
  .jamkerja-panah { display: none; }
  .jamkerja-rentang label:nth-of-type(3) { grid-column: 1 / -1; }
  .jamkerja-buang { position: absolute; top: .4rem; right: .4rem; }
  .jamkerja-rentang { position: relative; padding-right: 2.6rem; }
}

.jamkerja-aksi { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
  margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--garis); }
.jamkerja-aksi small { font-size: .76rem; }

.jamkerja-sisi { align-self: start; }
.jamkerja-shift { list-style: none; margin: 0 0 .6rem; padding: 0;
  display: flex; flex-direction: column; gap: .4rem; }
.jamkerja-shift li { display: flex; align-items: baseline; justify-content: space-between;
  gap: .5rem; padding: .5rem .6rem; background: #f7f9f7; border-radius: 9px; font-size: .84rem; }
.jamkerja-shift li span { color: var(--pudar); font-variant-numeric: tabular-nums; font-size: .78rem; }

.jamkerja-tabel td[data-l="No."] code { font-size: .78rem; }

/* Cadangan <dialog> untuk peramban tanpa showModal(): atribut [open] saja tidak
   memunculkan backdrop dan tidak memusatkan kotak, jadi posisinya diatur di
   sini. Tanpa ini tombol "Tambah/Ubah/Scan" tampak tidak bereaksi di WebView
   lama karena kotaknya muncul di luar pandangan. */
dialog.modal.modal-tanpa-showmodal[open] {
  display: flex; flex-direction: column;
  position: fixed; inset: 0; margin: auto;
  z-index: 60; max-height: min(90vh, 46rem); overflow: auto;
  background: var(--putih, #fff); border-radius: var(--r, 14px);
  box-shadow: 0 24px 60px rgba(15, 40, 28, .28);
}
dialog.modal.modal-tanpa-showmodal[open]::before {
  content: ''; position: fixed; inset: 0; z-index: -1;
  background: rgba(12, 30, 20, .45);
}

/* ===== Indikator memuat halaman editor (CanvasCraft / OpenCut) =====
   Halaman Hub lain memakai `#isi.memuat` saat berpindah halaman; halaman editor
   hanya memasang <iframe>, jadi tanpa ini layar diam beberapa detik dan terasa
   macet ("tidak ada loading animation seperti pindah page lain").
   Dipasang DI DALAM .editor-bingkai, menutupi seluruh bingkai, dan dilepas oleh
   JS pada peristiwa `load` iframe. `hidden` tetap dihormati: tanpa itu kotak
   kosong menutupi editor yang sudah siap. */
.editor-pemuat {
  position: absolute; inset: 0; z-index: 5;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .8rem; background: #f4f8f5;
  font-size: .88rem; font-weight: 600; color: var(--hijau-800, #175433);
}
.editor-pemuat[hidden] { display: none; }
.editor-pemuat-bundar {
  width: 2.1rem; height: 2.1rem; border-radius: 50%;
  border: 3px solid #cfe3d6; border-top-color: var(--hijau-700, #1a7f37);
  animation: editor-pemuat-putar .8s linear infinite;
}
.editor-pemuat-teks { margin: 0; }
@keyframes editor-pemuat-putar { to { transform: rotate(360deg); } }
/* Bingkai harus jadi titik acuan posisi indikator. */
.editor-bingkai { position: relative; }
/* Hormati permintaan sistem: tanpa animasi berputar, tetap ada teksnya. */
@media (prefers-reduced-motion: reduce) {
  .editor-pemuat-bundar { animation: none; border-top-color: #cfe3d6; }
}

/* ---------- ODES: pilih desa (7 Nov 2026) ----------
   Satu KARTU di tengah, isi berurutan dengan jarak seragam. Sebelumnya label,
   select, dan tombol punya jarak berbeda dan select tidak mengikuti lebar kartu
   — terlihat berantakan (keluhan Bos). */
/* BUKAN grid: `place-items` membuat kolom mengikuti max-content isi (terukur
   432px pada layar 390px → halaman melebar 448px, dan Select2 ikut melebar).
   Blok biasa + margin auto memusatkan kartu tanpa memaksa lebar. */
.pilih-desa-hal { display: block; padding: 1.1rem 0 2rem; }
.pilih-desa-kartu { width: 100%; max-width: 520px; margin-inline: auto;
  background: #fff;
  border: 1px solid var(--garis); border-radius: 18px; padding: 1.15rem 1.1rem 1.25rem;
  box-shadow: 0 10px 30px -24px rgba(16, 29, 24, .5); }
.pilih-desa-judul { display: flex; align-items: flex-start; gap: .65rem; margin-bottom: 1rem; }
.pilih-desa-ikon { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--teal-tint, #eef6f1); color: var(--hijau-800); }
.pilih-desa-ikon svg { width: 19px; height: 19px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pilih-desa-judul b { display: block; font-size: 1.02rem; color: var(--hijau-800); line-height: 1.25; }
.pilih-desa-judul small { display: block; font-size: .82rem; color: var(--tinta-2); line-height: 1.45; }
/* SATU KOLOM, dipatok 1fr. Tanpa `minmax(0, 1fr)` kolom grid mengikuti
   max-content isi (terukur 400px di kartu 328px) → meluber dan memaksa seluruh
   halaman melebar 431px. Ini yang membuat tampilan "berantakan". */
.pilih-desa-form { position: relative; display: grid; gap: .45rem;
  grid-template-columns: minmax(0, 1fr); }
.pilih-desa-form > * { min-width: 0; max-width: 100%; }
.pilih-desa-label { font-size: .78rem; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: var(--tinta-2); }
.pilih-desa-ket { margin: .35rem 0 .15rem; font-size: .8rem; color: var(--tinta-2); line-height: 1.5; }
.pilih-desa-ket b { color: var(--hijau-800); }
.pilih-desa-form .tombol { min-height: 46px; margin-top: .2rem; }
/* Tombol mati sampai desa dipilih — beri tampilan yang jelas, bukan abu pucat. */
.pilih-desa-form .tombol[disabled] { opacity: .55; cursor: not-allowed; }
/* Ongkir tidak lagi diisi: tampil sebagai angka hasil hitung server. */
.pasar-ongkir { display: inline-block; font-variant-numeric: tabular-nums;
  font-weight: 700; color: var(--hijau-800); background: var(--teal-tint, #eef6f1);
  border-radius: 8px; padding: .45rem .6rem; font-size: .9rem; }
@media (max-width: 700px) {
  .odes-pilih-desa { padding: 1rem .85rem 2.5rem; }
  .pilih-desa-kartu { padding: 1rem .95rem 1.1rem; }
}

/* Select2 di layar pilih desa: samakan tinggi & ukuran huruf dengan kendali
   lain (44px, 16px). Bawaan Select2 32px/13px — di ponsel jadi terlalu kecil
   dan iOS memperbesar halaman saat kolom fokus. */
/* Select2 di layar pilih desa.
   SPESIFISITAS: aturan Select2 global di berkas ini memakai
   `.select2-container--default .select2-selection--single` (0,2,0) dan
   `.select2-container--default .select2-search--dropdown .select2-search__field`
   (0,3,0) dengan `min-height: 42px` / `font-size: .875rem`. Aturan (0,2,0) di
   sini KALAH — terukur 7 Nov 2026: kendali tetap 42px dan kolom cari tetap 14px.
   Jadi turunkan lewat induk yang lebih panjang (0,4,0), bukan !important. */
.pilih-desa-form .select2-container { width: 100% !important; }
.pilih-desa-form .select2-container .select2-selection--single {
  min-height: 46px; height: 46px; padding: 0;
  border: 1px solid var(--garis); border-radius: 10px; background: #fff;
  display: flex; align-items: center; }
.pilih-desa-form .select2-container .select2-selection--single .select2-selection__rendered {
  font-size: 1rem; line-height: 1.3; padding-left: .7rem; padding-right: 2rem; color: var(--tinta);
  /* Teks panjang (placeholder & nama desa) harus DIPOTONG, bukan meluber:
     terukur placeholder 355px di kotak 328px sehingga keluar dari kartu. */
  min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pilih-desa-form .select2-container .select2-selection--single { overflow: hidden; }
.pilih-desa-form .select2-container .select2-selection--single .select2-selection__arrow {
  height: 44px; right: .4rem; top: 0; }
.pilih-desa-form .select2-container .select2-selection--single .select2-selection__placeholder { color: var(--tinta-2); }
.pilih-desa-form .select2-container--focus .select2-selection--single,
.pilih-desa-form .select2-container--open .select2-selection--single {
  border-color: var(--teal); box-shadow: 0 0 0 2px rgba(23,84,51,.12); }
/* Daftar turun: kolom cari 16px (di bawah 16px iOS memperbesar halaman) dan
   baris opsi cukup tinggi untuk jari. */
.select2-container--open .select2-dropdown { border-radius: 10px; border-color: var(--garis);
  /* Select2 menghitung lebar dropdown dari lebar dokumen saat dipasang di wadah
     flex sempit: terukur 966px keluar dari form 492px (7 Nov 2026). Batasi. */
  max-width: 100%; box-sizing: border-box; }
/* Dropdown dipasang di DALAM .pilih-desa-form (dropdownParent). Dengan posisi
   absolute dan `left:0; right:0`, containing block-nya jadi VIEWPORT (form tidak
   positioned) — terukur 1440px penuh. Form dijadikan acuan posisi, dan lebar
   dropdown dibatasi container Select2 (inline width-nya sudah benar). */
.pilih-desa-form { position: relative; }
.pilih-desa-form .select2-dropdown { width: 100% !important; max-width: 100% !important;
  box-sizing: border-box; }
.pilih-desa-form .select2-search--dropdown .select2-search__field { width: 100% !important;
  box-sizing: border-box; }
.select2-container--open .select2-search--dropdown .select2-search__field {
  font-size: 1rem; min-height: 44px; padding: .5rem .6rem .5rem 2rem; }
.select2-container--open .select2-results__option { padding: .6rem .7rem; font-size: .95rem; }
.select2-container--open .select2-results__group { font-size: .74rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--tinta-2); font-weight: 800; padding: .5rem .7rem .3rem; }
.select2-container--open .select2-results__option--highlighted { background: var(--teal-tint, #eef6f1) !important; color: var(--hijau-800) !important; }

/* ============ ODES: kepala katalog, pencarian, keranjang (7 Nov 2026) ============
   Keluhan Bos: kepala menempel ke logo & keranjang, kolom cari tidak profesional,
   tombol keranjang tidak berfungsi. Tiga hal itu diperbaiki di sini, bukan
   dengan tambalan per-elemen:
     - kepala jadi KARTU ber-radius dengan jarak dalam (bukan pita putih penuh);
     - pencarian jadi satu baris utuh + tombol "Cari" yang terlihat;
     - keranjang menuju halaman /odes/keranjang (bukan jangkar #form-pesan). */
.pasar-kepala { position: sticky; top: var(--tb-kepala, 0px); z-index: 12;
  display: flex; flex-direction: column; gap: .7rem;
  margin: .7rem 0 .5rem; padding: .8rem .9rem;
  background: rgba(255, 255, 255, .96); backdrop-filter: blur(10px);
  border: 1px solid var(--pasar-garis); border-radius: 18px;
  box-shadow: 0 6px 20px -14px rgba(16, 29, 24, .35); }
/* `top: 0` — halaman ODES memakai layouts.odes yang TIDAK punya header aplikasi.
   Sebelumnya 3.35rem (sisa layout dasbor), sehingga kepala mengambang 54px dari
   atas dan menutupi baris kategori + kartu produk (terukur 7 Nov 2026:
   kategori.top 160 < kepala.bottom 194). */
@media (max-width: 900px) {
  .pasar-kepala { top: 0; margin: 0 0 .35rem; padding: .6rem .7rem; gap: .5rem;
    border-radius: 0 0 16px 16px; border-top: 0; }
  .pasar-baris-atas { gap: .5rem; }
}
.pasar-baris-atas { display: flex; align-items: center; gap: .75rem; min-width: 0; }
.pasar-merek { display: flex; align-items: center; gap: .55rem; min-width: 0;
  text-decoration: none; color: inherit; flex: 1 1 auto; }
.pasar-merek-teks { display: block; min-width: 0; }
.pasar-merek-teks b { display: block; line-height: 1.2; font-size: 1rem; color: var(--hijau-800); }
.pasar-merek-teks small { display: block; color: var(--pudar); font-size: .76rem;
  max-width: 30ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Tombol keranjang: pil berisi ikon + label + angka. Tinggi 44px (batas sentuh),
   dan angka selalu terlihat supaya jelas keranjang punya isi. */
.pasar-keranjang { flex: 0 0 auto; display: inline-flex; align-items: center; gap: .4rem;
  min-height: 44px; padding: .4rem .7rem .4rem .6rem; text-decoration: none;
  color: var(--hijau-800); background: var(--teal-tint, #eef6f1);
  border: 1px solid var(--hijau-300, #b9d8c6); border-radius: 999px;
  font-size: .9rem; font-weight: 700; transition: background .15s, border-color .15s; }
.pasar-keranjang:hover { background: #e2f0e7; border-color: var(--hijau-600, #2f7a52); }
.pasar-keranjang-ikon { width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pasar-keranjang b { background: var(--hijau-700, #175433); color: #fff; border-radius: 999px;
  min-width: 1.4rem; height: 1.4rem; display: inline-flex; align-items: center;
  justify-content: center; font-size: .76rem; padding: 0 .3rem; }

/* Pencarian: isian + tombol dalam satu kendali ber-radius. Tombolnya nyata
   (bukan hanya Enter), karena di lapangan banyak yang tidak menekan Enter. */
.pasar-cari { display: flex; align-items: center; gap: .5rem; width: 100%;
  background: #fff; border: 1px solid var(--pasar-garis); border-radius: 12px;
  padding: .25rem .3rem .25rem .8rem; min-height: 48px; }
.pasar-cari:focus-within { border-color: var(--hijau-600, #2f7a52);
  box-shadow: 0 0 0 3px rgba(23, 84, 51, .1); }
.pasar-cari svg { width: 19px; height: 19px; flex: 0 0 auto; stroke: var(--tinta-2);
  fill: none; stroke-width: 2; stroke-linecap: round; }
.pasar-cari input { flex: 1 1 auto; border: 0; background: transparent; min-width: 0;
  font-size: 16px; padding: .5rem 0; color: var(--tinta); }
.pasar-cari input:focus { outline: none; }
.pasar-cari-tombol { flex: 0 0 auto; min-height: 40px; padding: .45rem 1.1rem;
  border: 0; border-radius: 9px; background: var(--hijau-700, #175433); color: #fff;
  font: inherit; font-size: .9rem; font-weight: 700; cursor: pointer; }
.pasar-cari-tombol:hover { background: var(--hijau-800, #103d26); }
@media (max-width: 520px) {
  .pasar-cari-tombol { padding: .45rem .85rem; }
  .pasar-keranjang-teks { display: none; }      /* di HP: ikon + angka saja */
  .pasar-keranjang { padding: .4rem .5rem; gap: .3rem; }
}

/* Bilah bawah: ringkasan keranjang. Menempel di bawah, hanya muncul bila ada
   barang. `env(safe-area-inset-bottom)` menjaga tidak tertutup home-indicator. */
.pasar-bilah { position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(.7rem + env(safe-area-inset-bottom, 0px));
  width: min(680px, calc(100% - 1.6rem)); z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: .8rem;
  padding: .6rem .7rem .6rem 1rem; border-radius: 16px;
  background: #10331f; color: #fff; box-shadow: 0 14px 30px -12px rgba(6, 25, 14, .6); }
/* Bilah mengambang menutupi tombol "Tambah" pada kartu paling bawah.
   Beri ruang di bawah kisi supaya kartu terakhir bisa digulir MELEWATI bilah
   (tinggi bilah + navbar + safe-area). Tanpa ini tombol terakhir tak bisa
   ditekan saat sudah di dasar halaman. */
.pasar-kisi { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
.pasar-bilah small { display: block; font-size: .74rem; opacity: .75; }
.pasar-bilah b { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.pasar-bilah .tombol { min-height: 44px; background: #fff; color: #10331f;
  border-color: #fff; font-weight: 800; }
@media (max-width: 520px) { .pasar-bilah { width: calc(100% - 1.2rem); } }

/* ============ ODES: halaman keranjang ============ */
.odes-keranjang-hal { padding-bottom: 1.5rem; }
/* Baris pertama keranjang = tombol "Lanjut belanja"; beri jarak dari kepala
   tetap supaya tidak menempel. */
.odes-keranjang-hal > .pasar-kembali:first-child { display: inline-flex; margin-top: .1rem; }
/* "Lanjut belanja": tombol ringkas ber-ikon, diberi jarak dari kepala. Dulu ia
   hanya tautan kecil yang menempel kepala sehingga terlihat seperti sisa teks,
   bukan tombol (keluhan Bos 7 Nov 2026). */
.pasar-kembali { display: inline-flex; align-items: center; gap: .3rem;
  min-height: 40px; padding: .3rem .8rem .3rem .5rem; text-decoration: none;
  color: var(--hijau-800); font-weight: 700; font-size: .85rem;
  background: var(--teal-tint, #eef6f1); border: 1px solid var(--hijau-300, #b9d8c6);
  border-radius: 999px; margin: 0 0 .2rem; transition: background .15s; }
.pasar-kembali:hover { background: #e2f0e7; }
.pasar-kembali svg { width: 17px; height: 17px; }
.pasar-kembali svg { width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.keranjang-kartu, .keranjang-kosong-kartu { background: #fff; border: 1px solid var(--pasar-garis);
  border-radius: 18px; padding: 1.1rem 1.15rem 1.3rem; margin-top: .9rem;
  box-shadow: 0 6px 20px -16px rgba(16, 29, 24, .4); }
.keranjang-kartu h2 { font-size: 1.02rem; color: var(--hijau-800); margin: 0 0 .7rem; }
.keranjang-kartu h2.lebar-penuh { margin-top: .6rem; }
.keranjang-kosong-kartu { text-align: center; display: grid; justify-items: center; gap: .5rem;
  padding: 2.2rem 1.2rem; }
.keranjang-kosong-kartu span { font-size: 2.2rem; }
.keranjang-kosong-kartu b { font-size: 1.05rem; color: var(--hijau-800); }
.keranjang-kosong-kartu p { color: var(--tinta-2); font-size: .92rem; max-width: 40ch; }
.keranjang-daftar { display: flex; flex-direction: column; gap: .5rem; margin-bottom: 1rem; }
.keranjang-baris { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto;
  align-items: center; gap: .6rem; padding: .6rem .7rem;
  border: 1px solid var(--pasar-garis); border-radius: 12px; background: var(--pasar-lembut, #f7faf8); }
.keranjang-baris-utama b { display: block; font-size: .95rem; line-height: 1.25; }
.keranjang-baris-utama small { color: var(--tinta-2); font-size: .8rem; }
.keranjang-qty { display: inline-flex; align-items: center; gap: .15rem; }
.keranjang-qty button { width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--pasar-garis); background: #fff; font-size: 1.05rem; line-height: 1; }
.keranjang-qty output { min-width: 1.9rem; text-align: center; font-weight: 800;
  font-variant-numeric: tabular-nums; }
.keranjang-sub { font-variant-numeric: tabular-nums; font-size: .92rem; }
.keranjang-hapus { width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  border: 1px solid #e3cfcb; background: #fff; color: #a32218; font-size: 1.1rem; line-height: 1; }
.keranjang-hapus:hover { background: #fdf0ee; }
.keranjang-form { margin-top: .3rem; }
@media (max-width: 520px) {
  .keranjang-baris { grid-template-columns: minmax(0, 1fr) auto; row-gap: .45rem; }
  .keranjang-baris-utama { grid-column: 1 / -1; }
  .keranjang-sub { justify-self: start; }
}

/* ---------- ODES: akun pelanggan + titik antar (7 Nov 2026) ----------
   Akun pelanggan tampil di kepala katalog sebagai pil kecil (bukan menu):
   "Masuk" bila belum, huruf awal + nama depan bila sudah. NIK tidak pernah
   dicetak penuh di halaman — HP bisa dipakai bergantian. */
.pasar-akun { flex: 0 0 auto; display: inline-flex; align-items: center; gap: .4rem;
  min-height: 44px; padding: .4rem .7rem; text-decoration: none;
  color: var(--tinta-2); background: #fff; border: 1px solid var(--pasar-garis);
  border-radius: 999px; font-size: .88rem; font-weight: 700; }
.pasar-akun:hover { border-color: var(--hijau-600, #2f7a52); color: var(--hijau-800); }
.pasar-akun-awal { width: 24px; height: 24px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; background: var(--hijau-700, #175433);
  color: #fff; font-size: .78rem; font-weight: 800; }
@media (max-width: 520px) { .pasar-akun-teks { display: none; } .pasar-akun { padding: .4rem .5rem; } }

/* Halaman masuk/daftar akun: satu kartu sempit, seperti layar masuk aplikasi. */
.akun-kartu { max-width: 520px; margin: 1.4rem auto 3rem; background: #fff;
  border: 1px solid var(--garis); border-radius: 18px; padding: 1.2rem 1.15rem 1.4rem;
  box-shadow: 0 8px 24px -18px rgba(16, 29, 24, .5); }
.akun-kepala { display: flex; align-items: center; gap: .6rem; margin-bottom: .9rem; }
.akun-kepala b { display: block; font-size: 1.02rem; color: var(--hijau-800); }
.akun-kepala small { display: block; font-size: .8rem; color: var(--pudar); }
.akun-kaki { margin: .8rem 0 0; font-size: .86rem; color: var(--tinta-2); }

/* Pemesan yang sudah masuk: kartu ringkas, bukan isian NIK lagi. */
.akun-ringkas { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; background: var(--teal-tint, #eef6f1);
  border: 1px solid var(--hijau-300, #b9d8c6); border-radius: 12px; padding: .7rem .85rem; }
.akun-ringkas small { display: block; font-size: .74rem; color: var(--tinta-2); }
.akun-ringkas b { display: block; font-size: .96rem; }
.akun-ringkas span.pudar { font-size: .8rem; }

/* Titik antar pada formulir keranjang — OTOMATIS, tanpa tombol. */
.titik-antar { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; padding: .7rem .85rem; border-radius: 12px;
  background: var(--pasar-lembut, #f7faf8); border: 1px solid var(--pasar-garis); }

/* Peta mini titik antar. Tinggi dipatok (bukan aspect-ratio) supaya Leaflet
   punya kotak pasti saat pertama digambar — dengan tinggi otomatis, peta
   muncul 0px dan hanya terlihat abu-abu. */
.titik-peta { margin-top: .2rem; }
#peta-antar { height: 190px; width: 100%; border-radius: 12px;
  border: 1px solid var(--pasar-garis); background: #eef3ef; z-index: 0; }
@media (min-width: 700px) { #peta-antar { height: 230px; } }
.titik-peta small { display: block; margin-top: .3rem; font-size: .76rem; }
/* Atribusi OSM wajib terlihat, tetapi jangan menutupi tombol zoom. */
#peta-antar .leaflet-control-attribution { font-size: .62rem; }
.titik-antar small { display: block; font-size: .74rem; color: var(--tinta-2); }
.titik-antar b { display: block; font-size: .92rem; color: var(--hijau-800); }

/* Panel manajer: tautan rute peta untuk mitra ojek. */
.peta-antar { display: inline-flex; align-items: center; gap: .3rem; margin-top: .25rem;
  font-size: .8rem; font-weight: 700; color: var(--hijau-800); }
/* Tautan "Ganti akun" — WAJIB di luar #form-belanja (form bersarang merusak
   induknya, tombol Pesan jadi tidak mengirim apa pun). */
.ganti-akun { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; margin-top: .9rem; padding-top: .9rem;
  border-top: 1px solid var(--pasar-garis); font-size: .84rem; }

/* ============ ODES: kerangka aplikasi (7 Nov 2026) ============
   Bos: "pada mobile jarak kiri kanan layar all section termasuk header 15px",
   "header hanya menampilkan logo dan desa yang dipilih", "navbar fixed footer
   berisi Home, Keranjang, Transaksi, Akun dengan icon dan tulisan".

   Semua jarak tepi memakai --odes-tepi supaya SATU angka mengatur seluruh
   halaman. Jangan menambal per-section: dulu tiap blok punya padding sendiri,
   jadi tepinya tidak pernah lurus. */
.odes-tubuh {
  --odes-tepi: 15px;
  --odes-nav-h: 62px;
  --odes-kepala-h: 56px;
  background: var(--latar);
  /* Ruang bawah supaya konten terakhir tidak tertutup navbar tetap. */
  padding-bottom: calc(var(--odes-nav-h) + env(safe-area-inset-bottom, 0px) + 1rem);
}

/* Kepala: hanya logo + desa terpilih. Bukan sticky — isinya sedikit, dan
   sticky membuat kategori/produk tertutup saat menggulir (keluhan Bos). */
/* KEPALA TETAP (fixed) di semua halaman ODES — permintaan Bos 7 Nov 2026.
   Karena fixed, isi halaman WAJIB diberi padding-atas setinggi kepala, kalau
   tidak baris pertama tertutup. Tingginya dipatok --odes-kepala-h supaya satu
   angka mengatur keduanya. */
.odes-kepala { position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; min-height: var(--odes-kepala-h);
  padding: .5rem var(--odes-tepi);
  background: rgba(255, 255, 255, .95);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(16, 29, 24, .07);
  box-shadow: 0 4px 14px -12px rgba(6, 25, 14, .5); }
.odes-merek { display: flex; align-items: center; gap: .5rem; min-width: 0;
  text-decoration: none; color: inherit; }
.odes-merek b { display: block; line-height: 1.15; font-size: .95rem; color: var(--hijau-800); }
.odes-merek .odes-desa { display: block; font-size: .8rem; color: var(--tinta-2);
  max-width: 46vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.odes-ganti-desa { display: inline-flex; align-items: center; gap: .3rem;
  min-height: 40px; padding: .3rem .6rem; text-decoration: none; font-size: .8rem;
  font-weight: 700; color: var(--hijau-800); background: var(--teal-tint, #eef6f1);
  border: 1px solid var(--hijau-300, #b9d8c6); border-radius: 999px; }
.odes-ganti-desa svg { width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Isi: jarak tepi 15px seragam, lebar maksimum supaya tidak melebar di desktop. */
.odes-bungkus { max-width: 1100px; margin-inline: auto;
  padding: calc(var(--odes-kepala-h) + .6rem) var(--odes-tepi) 0; }

/* Judul halaman (Transaksi, Akun). */
.odes-halaman { padding-top: .9rem; }
.odes-judul { font-size: 1.15rem; margin: 0 0 .6rem; color: var(--hijau-800); }
.odes-ket { font-size: .84rem; color: var(--tinta-2); margin: 0 0 .7rem; }

/* Keadaan kosong & KARTU: satu pola untuk Transaksi, Akun, Keranjang. */
.odes-kosong { display: grid; justify-items: center; gap: .5rem; text-align: center;
  background: #fff; border: 1px solid var(--garis); border-radius: 16px;
  padding: 2rem 1.2rem; margin-top: .8rem; }
.odes-kosong span { font-size: 2rem; }
.odes-kosong b { font-size: 1rem; color: var(--hijau-800); }
.odes-kosong p { font-size: .88rem; color: var(--tinta-2); max-width: 42ch; margin: 0; }

/* NAVBAR BAWAH — dirancang sebagai bilah aplikasi, bukan baris teks.
   Sebelumnya: butir grid 1fr tanpa padding, ikon 22px menempel tulisan 11px,
   dan latar putih yang menyatu dengan footer teks di bawahnya sehingga terbaca
   sebagai "dua footer". Sekarang: bilah mengambang ber-radius, butir punya
   padding, butir aktif memakai pil lembut, dan footer teks DIHAPUS. */
.odes-nav { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: .15rem;
  padding: .35rem max(.35rem, calc((100vw - 520px) / 2));
  padding-bottom: calc(.35rem + env(safe-area-inset-bottom, 0px));
  background: rgba(255, 255, 255, .93);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  border-top: 1px solid rgba(16, 29, 24, .07);
  box-shadow: 0 -8px 24px -18px rgba(6, 25, 14, .55); }
.odes-nav-butir { position: relative; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .15rem;
  min-height: 52px; padding: .3rem .15rem .35rem;
  text-decoration: none; color: #7b8a83; font-weight: 600;
  border-radius: 12px; transition: color .15s, background .15s, transform .12s;
  -webkit-tap-highlight-color: transparent; }
.odes-nav-butir small { font-size: .66rem; line-height: 1; letter-spacing: .01em; }
.odes-nav-ikon { position: relative; display: inline-flex; align-items: center;
  justify-content: center; height: 24px; }
.odes-nav-ikon svg { width: 23px; height: 23px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  transition: stroke-width .15s; }
/* Butir AKTIF: warna merek + pil lembut di belakangnya. Tanpa pil, "aktif"
   hanya beda warna dan mudah terlewat di layar terang. */
.odes-nav-butir.ini { color: var(--hijau-800); background: rgba(23, 84, 51, .08); }
.odes-nav-butir.ini small { font-weight: 800; }
.odes-nav-butir.ini .odes-nav-ikon svg { stroke-width: 2.2; }
.odes-nav-butir:active { transform: scale(.96); }
/* Lencana jumlah barang: menempel di sudut ikon, bukan di luar butir. */
.odes-nav-lencana { position: absolute; top: -4px; right: -10px; min-width: 17px;
  height: 17px; display: inline-flex; align-items: center; justify-content: center;
  padding: 0 4px; border-radius: 999px; background: #c2410c; color: #fff;
  font-size: .62rem; font-weight: 800; line-height: 1;
  box-shadow: 0 0 0 2px #fff; }
@media (max-width: 380px) {
  .odes-nav-butir small { font-size: .6rem; }
  .odes-nav-ikon svg { width: 21px; height: 21px; }
}

/* Footer teks dihapus dari kerangka (dulu jadi footer kedua di samping navbar). */

/* Animasi muat halaman: tirai tipis + lingkaran di tengah. */
.odes-muat { position: fixed; inset: 0; z-index: 90; display: grid; place-content: center;
  justify-items: center; gap: .55rem; background: rgba(247, 250, 248, .78);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity .1s ease-out; }
.odes-muat[hidden] { display: none; }
.odes-muat.tampil { opacity: 1; }
.odes-muat-lingkar { width: 38px; height: 38px; border-radius: 50%;
  border: 3px solid rgba(23, 84, 51, .18); border-top-color: var(--hijau-700, #175433);
  animation: odes-putar .7s linear infinite; }
.odes-muat small { font-size: .78rem; color: var(--hijau-800); font-weight: 600; }
@keyframes odes-putar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .odes-muat-lingkar { animation-duration: 2s; }
  .odes-muat { transition: none; }
}

/* Kartu pencarian katalog: jarak tepi mengikuti variabel kerangka. */
.pasar-cari { margin: .2rem 0 .1rem; }
.pasar-kategori { padding-inline: 0; }
.pasar-bilah { bottom: calc(var(--odes-nav-h, 62px) + env(safe-area-inset-bottom, 0px) + .5rem);
  width: min(680px, calc(100% - 2 * var(--odes-tepi, 15px))); }

/* ---------- Transaksi ---------- */
.trx-daftar { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }
.trx-kartu { background: #fff; border: 1px solid var(--garis); border-radius: 14px;
  padding: .8rem .9rem; display: grid; gap: .45rem; }
.trx-atas { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.trx-atas code { font-size: .82rem; color: var(--tinta-2); }
.trx-barang { list-style: none; margin: 0; padding: .35rem 0 0; display: grid; gap: .2rem;
  border-top: 1px dashed var(--garis); }
.trx-barang li { display: flex; justify-content: space-between; gap: .6rem; font-size: .86rem; }
.trx-barang b { font-variant-numeric: tabular-nums; }
.trx-bawah { display: flex; align-items: center; justify-content: space-between;
  border-top: 1px solid var(--garis); padding-top: .45rem; font-size: .95rem; }
.trx-bawah b { color: var(--hijau-800); font-variant-numeric: tabular-nums; }
.trx-kaki { display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  font-size: .78rem; flex-wrap: wrap; }

/* ---------- Akun ---------- */
.akun-profil { background: #fff; border: 1px solid var(--garis); border-radius: 16px;
  padding: .9rem 1rem; display: grid; gap: .7rem; }
.akun-identitas { display: flex; align-items: center; gap: .7rem; min-width: 0; }
.akun-identitas b { display: block; font-size: 1rem; }
.akun-identitas small { display: block; font-size: .78rem; }
.akun-awal { width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hijau-700, #175433); color: #fff; font-weight: 800; font-size: 1.1rem; }
.akun-statistik { display: flex; gap: 1.6rem; border-top: 1px solid var(--garis); padding-top: .6rem; }
.akun-statistik small { display: block; font-size: .74rem; color: var(--tinta-2); }
.akun-statistik b { font-size: 1.15rem; color: var(--hijau-800); }
.akun-blok { background: #fff; border: 1px solid var(--garis); border-radius: 16px;
  padding: 1rem; margin-top: .8rem; }
.akun-blok h2 { font-size: .98rem; margin: 0 0 .5rem; color: var(--hijau-800); }
.akun-bahaya { border-color: #e8d5d1; }
.akun-aksi { display: flex; gap: .5rem; flex-wrap: wrap; }
.tombol.rusak { background: #a32218; border-color: #a32218; color: #fff; }
.tombol.rusak:hover { background: #8c1c13; }

/* ---------- Masuk / daftar: kartu di tengah ---------- */
.akun-kartu { max-width: 460px; margin: 1.6rem auto 3rem; background: #fff;
  border: 1px solid var(--garis); border-radius: 18px; padding: 1.3rem 1.2rem 1.5rem;
  box-shadow: 0 10px 30px -22px rgba(16, 29, 24, .55); }
@media (max-width: 700px) {
  .akun-kartu { margin: 1rem auto 2rem; padding: 1.1rem 1rem 1.3rem; border-radius: 16px; }
}

/* GAMBAR PRODUK dari katalog pusat + keterangan singkat.
   Gambar asli 1:1 dipotong rapi (object-fit) supaya tinggi kartu seragam;
   emoji kategori tetap ada DI BELAKANG gambar sebagai cadangan saat gambar
   gagal dimuat (sinyal desa buruk / CDN lambat). */
.pasar-gambar { position: relative; }
.pasar-gambar img { position: relative; z-index: 1; width: 100%; height: 100%;
  object-fit: contain; background: #fff; display: block; }
.pasar-gambar-cadangan { position: absolute; inset: 0; display: grid; place-items: center;
  z-index: 0; font-size: 2rem; }
/* Keterangan: dua baris saja, dipotong dengan elipsis. Tanpa batas, teks
   deskripsi Indomaret yang panjang membuat tinggi kartu tidak rata. */
.pasar-ket { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: .72rem; line-height: 1.35; color: var(--pudar); }

/* PENANDA PETA ODES — SVG sebaris (divIcon), bukan marker-icon.png yang tidak
   ikut tersalin ke /vendor sehingga tampil sebagai gambar rusak.
   Titik hijau dengan cincin putih + bayangan, supaya jelas di atas ubin peta
   yang ramai. Titik tengahnya tepat pada koordinat (iconAnchor 11,11). */
.odes-penanda { background: none; border: 0; }
.odes-penanda-titik { display: block; width: 22px; height: 22px; border-radius: 50%;
  background: var(--hijau-700, #175433); border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(6, 25, 14, .45); position: relative; }
.odes-penanda-titik::after { content: ''; position: absolute; inset: 5px;
  border-radius: 50%; background: #fff; opacity: .9; }

/* Pemberitahuan katalog terpotong + tautan muat semua. */
.pasar-sisa { margin: .9rem 0 .2rem; text-align: center; font-size: .82rem;
  color: var(--tinta-2); }
.pasar-sisa a { font-weight: 700; color: var(--hijau-800); }

/* PENANDA GULIR (infinite scroll). Berbentuk tautan supaya tetap bekerja
   tanpa JavaScript — kalau skrip mati, ia jadi tombol "muat lagi" biasa. */
.pasar-muat { display: flex; align-items: center; justify-content: center; gap: .5rem;
  margin: 1rem 0 .3rem; min-height: 46px; border-radius: 12px;
  background: var(--pasar-lembut, #f7faf8); border: 1px dashed var(--pasar-garis);
  text-decoration: none; font-size: .86rem; font-weight: 700; color: var(--hijau-800); }
.pasar-muat-putar { width: 16px; height: 16px; border-radius: 50%; flex: 0 0 auto;
  border: 2px solid rgba(23, 84, 51, .2); border-top-color: var(--hijau-700, #175433);
  animation: odes-putar .7s linear infinite; opacity: 0; }
.pasar-muat.sedang .pasar-muat-putar { opacity: 1; }
.pasar-muat.sedang .pasar-muat-teks { opacity: .8; }
@media (prefers-reduced-motion: reduce) { .pasar-muat-putar { animation-duration: 2s; } }

/* ---------- TARIK TUNAI (keranjang ODES) ----------
   Kotak centang besar + pilihan nominal. Uang cash DIBAYAR KE OJEK, jadi
   nominalnya sengaja tidak masuk "Dibayar di tempat" — hanya biaya layanan. */
.tarik-kartu { border: 1px solid var(--pasar-garis); border-radius: 12px;
  background: var(--pasar-lembut, #f7faf8); padding: .7rem .85rem; }
.tarik-kepala { display: flex; align-items: flex-start; gap: .6rem; cursor: pointer;
  min-height: 44px; margin: 0; }
.tarik-kepala input[type="checkbox"] { width: 20px; height: 20px; margin: .15rem 0 0;
  flex: 0 0 auto; accent-color: var(--hijau-700, #175433); }
.tarik-kepala b { display: block; font-size: .95rem; color: var(--hijau-800); }
.tarik-kepala small { display: block; font-size: .78rem; color: var(--tinta-2); line-height: 1.4; }
.tarik-isi { margin-top: .6rem; padding-top: .6rem;
  border-top: 1px dashed var(--pasar-garis); display: grid; gap: .4rem; }
.tarik-isi[hidden] { display: none; }
.tarik-isi label { font-size: .78rem; font-weight: 700; color: var(--tinta-2); }
.tarik-isi select { width: 100%; min-height: 46px; font-size: 1rem; padding: .5rem .6rem;
  border-radius: 10px; border: 1px solid var(--garis); background: #fff; margin-top: .25rem; }
.tarik-isi .bantuan { margin: 0; font-size: .78rem; }
.tarik-catatan { margin: .2rem 0 .4rem; padding: .6rem .75rem; border-radius: 10px;
  background: #fff8e6; border: 1px solid #f0dfae; font-size: .82rem; color: #6b4f11; }
.tarik-catatan b { color: #4a3608; }

/* Baris tarik tunai di panel mitra: harus MENONJOL — ojek wajib menyiapkan
   uang cash sebelum berangkat. */
.tarik-mitra { margin-top: .3rem; padding: .35rem .55rem; border-radius: 8px;
  background: #fff8e6; border: 1px solid #f0dfae; }
.tarik-mitra b { display: block; font-size: .82rem; color: #6b4f11; }
.tarik-mitra small { display: block; font-size: .74rem; color: #8a6a1e; }

/* ---------- LAYANAN UANG (tarik tunai & top up) di keranjang ----------
   Tampil sebagai bagian "Barang belanjaan": satu baris per layanan, nominal
   muncul setelah dicentang. Nominal + fee masuk total pesanan. */
.layanan-uang { display: grid; gap: .5rem; margin: .7rem 0 .3rem;
  padding: .7rem .85rem; border-radius: 12px;
  background: var(--pasar-lembut, #f7faf8); border: 1px solid var(--pasar-garis); }
.layanan-baris { display: flex; align-items: center; justify-content: space-between;
  gap: .7rem; flex-wrap: wrap; }
.layanan-pilih { display: flex; align-items: flex-start; gap: .55rem; min-height: 44px;
  flex: 1 1 190px; margin: 0; cursor: pointer; font-weight: 600; }
.layanan-pilih input[type="checkbox"] { width: 20px; height: 20px; margin: .15rem 0 0;
  flex: 0 0 auto; accent-color: var(--hijau-700, #175433); }
.layanan-pilih b { display: block; font-size: .93rem; color: var(--hijau-800); }
.layanan-pilih small { display: block; font-weight: 400; font-size: .76rem; color: var(--tinta-2); }
.layanan-nominal { display: flex; align-items: center; gap: .4rem; flex: 1 1 150px; }
.layanan-nominal[hidden] { display: none; }
.layanan-nominal select { flex: 1 1 auto; min-height: 44px; font-size: 1rem;
  padding: .45rem .6rem; border-radius: 10px; border: 1px solid var(--garis);
  background: #fff; }
.layanan-nominal .pudar { font-size: .72rem; white-space: nowrap; }
.layanan-uang .bantuan { margin: .2rem 0 0; font-size: .76rem; }
.layanan-luar { margin: .7rem 0 .2rem; padding: .6rem .75rem; border-radius: 10px;
  background: #f3f6f4; border: 1px solid var(--pasar-garis); font-size: .8rem; }

/* Peringatan minimal belanja untuk layanan uang. */
.tarik-min { margin: .3rem 0 0; padding: .5rem .65rem; border-radius: 8px;
  background: #fff4e5; border: 1px solid #f0d9b5; color: #6b4a11; font-size: .78rem; }
.tarik-min[hidden] { display: none; }

/* ---------- Select2 DI DALAM <dialog> ----------
   Select2 membungkus daftar hasil dengan wadah `position:absolute` yang
   lebarnya 0px. Aturan bawaan memberi dropdown `max-width:100%`, sehingga
   lebar 601px yang dihitung Select2 dipotong jadi ~2px dan daftar hasil
   TIDAK PERNAH terlihat walau datanya ada (terukur 7 Nov 2026 di /kop:
   dropdown 2px, hasil 0px, klik menembus ke modal).

   `max-width:none` mengembalikan lebar yang sudah dihitung Select2. Dibatasi
   pada dialog supaya pemilih di halaman biasa tidak berubah. */
dialog .select2-container--open .select2-dropdown { max-width: none; min-width: 220px; }
/* Wadah pembungkus juga perlu lebar: tanpa ini posisi horizontal meleset. */
dialog .select2-container--open { width: auto; }
