/* Lapisan aplikasi di atas design system Organic.
   Semuanya dibangun dari token organic.css — tidak ada warna, font, atau skala
   baru (DESAIN.md §2, §5). Kalau butuh nilai yang belum ada tokennya, turunkan
   dari token, jangan tulis angka baru. */

/* ── app shell ─────────────────────────────────────────────── */
.app-shell { display: grid; grid-template-columns: 244px 1fr; min-height: 100vh; }

.sidebar {
  display: flex; flex-direction: column; gap: var(--space-4);
  padding: var(--space-4) var(--space-3);
  background: var(--color-neutral-900); color: var(--color-neutral-200);
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.sidebar-brand {
  display: flex; flex-direction: column; align-items: flex-start;
  text-decoration: none; color: inherit; padding: 0 var(--space-2);
}
/* Logo dibuang dari sidebar atas kiri (permintaan pemilik) — namanya yang
   dibesarkan sebagai gantinya, jadi identitasnya tetap terbaca dari jauh. */
.sidebar-brand .nama {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 27px; line-height: 1.1; color: var(--color-neutral-100);
  letter-spacing: -0.01em;
}
.sidebar-brand .tagline {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  /* Satu-satunya aksen MEREK (bukan status): hijau segar untuk "Farm to
     Kitchen" — produk usahanya memang sayur. Di atas hitam ~11:1. */
  color: var(--brand-segar);
}

.sidebar-nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.sidebar-nav a {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: 999px; text-decoration: none; font-size: 14px;
  color: var(--color-neutral-300);
}
.sidebar-nav a:hover { background: color-mix(in srgb, var(--color-neutral-100) 12%, transparent); color: var(--color-neutral-100); }
/* Menu aktif DIBALIK, bukan diberi warna aksen: di sidebar hitam, aksen yang
   sekarang hampir hitam praktis tidak kelihatan. Isi terang + teks gelap
   adalah penanda terkuat yang tersedia tanpa rona. */
.sidebar-nav a[aria-current='page'] { background: var(--color-neutral-100); color: var(--color-neutral-900); }
.sidebar-nav a.mati { opacity: 0.45; cursor: default; }
.sidebar-nav a.mati:hover { background: transparent; color: var(--color-neutral-300); }
/* Cincin fokus bawaan memakai aksen (hampir hitam) — hilang di atas sidebar
   hitam. Di sini harus terang, kalau tidak navigasi lewat keyboard buta. */
.sidebar :focus-visible { outline-color: var(--color-neutral-100); }
.ikon {
  /* Lucide via <symbol>+<use>: presentation attributes pada sprite hanya
     berlaku di tree asalnya, tidak ikut tersalin ke shadow tree <use> —
     jadi warnanya harus ditegaskan lagi di sini lewat CSS, kalau tidak
     browser jatuh ke default SVG (fill hitam solid). */
  fill: none; stroke: currentColor; stroke-width: 2.75;
  stroke-linecap: round; stroke-linejoin: round;
}
.sidebar-nav .ikon { width: 18px; height: 18px; flex: none; }

.sidebar-kaki { font-size: 12px; color: var(--color-neutral-400); padding: 0 var(--space-3); }
.sidebar-kaki a { color: var(--color-accent-400); }
.sidebar-kaki .nama-user { color: var(--color-neutral-100); font-weight: 600; }

.konten {
  padding: var(--space-6) var(--space-8);
  /* SENGAJA tanpa max-width: di layar lebar, mematoknya 1180px menyisakan
     ratusan piksel kosong di kanan (terukur 476px pada layar 1900px) sementara
     tabel operasional di dalamnya justru berdesakan. Yang perlu dibatasi bukan
     halamannya, tapi PARAGRAF-nya — lihat aturan lebar-baca di bawah. Halaman
     Panduan tetap terpusat lewat .pd-bungkus miliknya sendiri. */
  /* min-width:0 lepas dari default grid item ("tidak menyusut di bawah
     ukuran konten") — tanpa ini, satu elemen ber-min-width tetap (mis.
     diagram lebar di Panduan) memaksa seluruh app-shell melebar. */
  min-width: 0;
}

/* Lebar-baca: kalimat penjelas dibatasi ~80 karakter supaya mata tidak
   kehilangan baris saat melompat ke awal baris berikutnya di layar lebar.
   Yang dibatasi hanya TEKS mengalir — tabel, kartu, dan grid tetap memakai
   seluruh lebar yang ada. */
.kepala .sub, .bantuan, .kosong, .insight .isi { max-width: 80ch; }

/* ── kepala halaman ────────────────────────────────────────── */
/* flex-wrap DI KEDUANYA: beberapa halaman (Keuangan, Produk, Pengaturan
   pengguna, dst.) punya sampai 5 tombol aksi. Tanpa wrap, baris ini tak pernah
   menyusut di layar sempit — flex item ber-teks punya min-width bawaan sebesar
   kontennya sendiri, jadi begini gap habis, SELURUH HALAMAN ikut melebar
   mengikutinya (bukan cuma baris ini yang kepotong). */
.kepala { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-4); margin-bottom: var(--space-6); }
.kepala h1, .kepala h2 { margin-bottom: var(--space-1); }
.kepala .sub { font-size: 14px; color: var(--color-neutral-600); }
.kepala .aksi { margin-left: auto; display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }

/* ── stat tile (DESAIN.md §5.3) ────────────────────────────── */
/* Jarak ke elemen sesudahnya ADA DI SINI, bukan ditambal per halaman. Dulu
   sepuluh template menambalnya sendiri lewat style="margin-top:..." inline,
   dan dua halaman yang lupa (Laba rugi & Arus kas) merender panelnya menempel
   tanpa jarak sama sekali. Margin sebelah-menyebelah saling luruh (collapse),
   jadi halaman yang masih punya tambalan inline tidak jadi dobel. */
.stat-baris {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--space-4); margin-bottom: var(--panel-gap);
}
.stat {
  background: var(--color-surface); border-radius: calc(var(--radius-lg) * 1.15);
  padding: var(--space-4);
  /* Jadi container supaya angkanya bisa menyesuaikan LEBAR TILE INI, bukan
     lebar viewport — lihat .stat .angka. Aman: .stat selalu grid item yang
     lebarnya ditentukan grid (1fr), bukan oleh isinya. */
  container-type: inline-size;
}
.stat .label { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-neutral-600); }
.stat .angka {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 34px; line-height: 1.1; margin: var(--space-1) 0;
  /* Digit selebar sama: angka antar tile sebaris jadi rata, bukan bergoyang. */
  font-variant-numeric: tabular-nums;
  /* Jaring pengaman untuk browser tanpa container query: lebih baik angkanya
     turun baris daripada menembus keluar tile. */
  overflow-wrap: anywhere;
}
/* Rupiah panjang TIDAK muat di tile sempit pada 34px. Terukur di Figtree 700:
   "Rp-10.000.000" = 242px, sedangkan ruang dalam tile 4-kolom cuma 189px.
   Akibatnya dulu: angka tanpa tanda minus MELUBER menembus tile sebelah, dan
   yang PUNYA tanda minus malah wrap jadi dua baris sehingga tile sebaris ikut
   meninggi (154px vs 117px) — dua gejala, satu sebab.
   1cqw = 1% lebar tile, jadi angkanya hanya mengecil kalau tilenya memang
   sempit; di tile lega tetap 34px penuh. 12,5cqw dipilih dari pengukuran:
   pada tile tersempit yang dipakai app ini (189px) hasilnya 23,6px — cukup
   untuk angka miliaran ("Rp1.234.567.890" = 183px) tanpa perlu wrap. */
@supports (container-type: inline-size) {
  .stat .angka { font-size: min(34px, 12.5cqw); }
}
.stat .rincian { font-size: 12px; color: var(--color-neutral-600); }

/* ── kartu insight ─────────────────────────────────────────── */
/* Dibedakan dari .panel lewat isi yang setingkat lebih pekat + garis penuh
   (panel tidak bergaris). Bukan garis tepi kiri tebal — itu trik hiasan yang
   tidak menandakan apa-apa. */
.insight {
  display: flex; gap: var(--space-3); align-items: center;
  /* Kartu ini selalu berisi PERINGATAN (rekonsiliasi tak cocok, password
     bawaan) — sejak aksen semantik masuk, ia memakai amber: butuh dibaca,
     bukan bahaya merah. Border penuh, bukan garis tepi kiri. */
  background: var(--peringatan-bg); border: 1px solid var(--peringatan-garis);
  border-radius: calc(var(--radius-lg) * 1.15); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}
.insight .isi { flex: 1; font-size: 14px; color: var(--peringatan-tx); }
.insight .isi a { color: var(--peringatan-tx); }
.insight .judul {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 16px; color: var(--peringatan-tx);
}

/* ── notifikasi ────────────────────────────────────────────── */
/* Sejak aksen semantik masuk (20 Agu 2026): galat = merah pekat (bahasa
   kesalahan paling universal — dulu hitam karena palet belum boleh berwarna),
   sukses = isian hijau tipis + garis; tenang tapi jelas kabar baik. Token
   didefinisikan di blok "Aksen semantik" (bawah), dipakai di sini — urutan
   deklarasi CSS variabel bebas selama sama-sama :root. */
.notif { border-radius: 999px; padding: var(--space-2) var(--space-4); font-size: 14px; margin-bottom: var(--space-4); }
.notif-galat { background: var(--aksi-merah); color: #fff; }
.notif-galat a { color: #fff; }
.notif-sukses {
  background: var(--masuk-bg); color: var(--masuk-tx);
  box-shadow: inset 0 0 0 1px var(--masuk-garis);
}

/* ── tabel: varian padat untuk layar operasional ───────────── */
.table-padat td, .table-padat th { padding: 6px var(--space-2); }
/* Kebalikannya: ringkasan pendek yang dibaca baris per baris (Laba rugi),
   bukan dipindai sekilas. Barisnya diberi ruang supaya angka dan labelnya
   tidak berdesakan. */
.table-ringkas td, .table-ringkas th { padding: var(--space-3) var(--space-2); }
.table-ringkas tbody tr:last-child td { border-bottom: 0; }
.table td.angka, .table th.angka { text-align: right; font-variant-numeric: tabular-nums; }
.table .nowrap { white-space: nowrap; }
.kosong { text-align: center; padding: var(--space-8); color: var(--color-neutral-600); }

/* ── panel ─────────────────────────────────────────────────── */
.panel { background: var(--color-surface); border-radius: calc(var(--radius-lg) * 1.15); padding: var(--panel-pad); }
.panel + .panel { margin-top: var(--panel-gap); }

/* ── RITME VERTIKAL DI DALAM PANEL ──────────────────────────────────────────
   Blok yang berurutan di dalam panel otomatis berjarak. Ini menutup penyebab
   keluhan "dempet" yang berulang: dulu jarak diatur satu per satu lewat
   `style="margin-top:..."` di template (154 kali di 60 berkas), jadi (a) satu
   halaman bisa punya tiga ritme berbeda sekaligus, dan (b) setiap blok baru
   yang penulisnya lupa memberi margin langsung menempel ke atasnya. Sekarang
   lupa pun aman — jaraknya sudah dijamin sistem.

   `> * + *`: hanya anak LANGSUNG, dan tidak pernah kena elemen pertama (yang
   memang harus menempel ke padding panel). `> form > * + *` ikut disebut
   karena banyak panel membungkus isinya dalam <form> — tanpa itu, isi form
   luput justru di layar yang paling banyak isian.

   Inline style di template tetap MENANG atas aturan ini (spesifisitas inline),
   jadi tempat yang sengaja diatur khusus tidak berubah — ini jaring pengaman,
   bukan penyeragaman paksa. Margin yang bersebelahan juga saling luruh
   (collapse), jadi bar judul yang sudah punya margin-bottom sendiri tidak
   jadi dobel. */
.panel > * + *,
.panel > form > * + * { margin-top: var(--panel-ritme); }
/* `.bantuan` punya `margin-top: 4px` sendiri — dan itu BENAR ketika ia
   keterangan yang menempel pada isian di dalam `.field`. Tapi ketika ia berdiri
   sebagai blok tersendiri (mis. catatan di bawah tabel), 4px membuatnya
   menempel ke tabel. Dua konteks, dua jarak — karena itu dipisahkan di sini,
   bukan dengan mengubah nilai dasarnya. Spesifisitasnya (0,2,0)/(0,3,0)
   sengaja di atas `.bantuan` (0,1,0) supaya menang tanpa bergantung urutan
   berkas — jebakan yang sudah beberapa kali menggigit repo ini. */
.panel > .bantuan,
.panel > form > .bantuan { margin-top: var(--panel-ritme); }
/* Tabel & isian mengisi lebarnya sendiri; yang butuh ritme adalah jarak
   ANTAR blok, bukan di dalam baris tabel. Elemen yang memang harus menempel
   (bar judul yang dibentang) sudah diatur aturannya sendiri di bawah. */
/* Panel ISIAN: putih bergaris hitam, bukan abu seperti panel baca.
   Bedanya bermakna — abu = tempat MEMBACA (daftar, ringkasan, laporan), putih
   bergaris = tempat MENGISI. Kotak isian di app ini sendiri berlatar putih,
   jadi di atas panel abu ia menyatu dan formulirnya jadi kurang tegas; di atas
   putih, garis hitamnyalah yang memagari area kerjanya. */
.panel-isian {
  background: var(--color-bg); border: 1px solid var(--color-text);
}
/* Isi panel yang berupa beberapa blok SEMPIT (tabel label-nilai, ringkasan)
   mengalir berdampingan selama muat, lalu menumpuk sendiri di layar sempit.
   Tanpa ini, blok selebar 560px di panel selebar 1100px menyisakan ~530px
   kosong — melebarkan tabelnya bukan jawaban, karena label dan nilainya justru
   jadi berjauhan; yang benar adalah mengisi ruang itu dengan blok berikutnya. */
.panel-kolom {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--space-4) var(--space-6); align-items: start;
}
/* Sub-judul bawaan memakai garis pemisah horizontal — di dalam kolom
   berdampingan, garis itu memotong di tempat yang salah. */
.panel-kolom > * > .panel-sub:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

/* Beda dengan .panel-kolom di atas (blok SEMPIT saling mengalir dalam SATU
   panel): ini untuk DUA PANEL TERPISAH — satu bisa panjang (daftar transaksi),
   satu ringkas (ringkasan/saldo). Tanpa ini panel ringkas ditumpuk di BAWAH
   panel panjang, jadi baru kelihatan setelah menggulir sampai habis. Panel
   kedua dijadikan sticky — sama pola dengan .pratinjau di Input Transaksi
   Langsung — supaya tetap kelihatan sambil menggulir panel pertama. */
.kolom-sisi {
  display: grid; grid-template-columns: minmax(0, 1fr) 380px;
  gap: var(--space-6); align-items: start;
}
.kolom-sisi > *:last-child { position: sticky; top: var(--space-4); }
@media (max-width: 900px) {
  /* minmax(0, 1fr), BUKAN 1fr polos: track grid punya minimum bawaan
     "auto" (selebar konten terlebarnya), sama seperti .konten yang
     didokumentasikan di atas — tanpa 0 di sini, tabel berkolom lebar tetap
     (mis. Pergerakan arus kas) menolak menyusut, jadi SELURUH kolom (dan
     akhirnya viewport mobile) ikut melebar mengikutinya. */
  .kolom-sisi { grid-template-columns: minmax(0, 1fr); }
  .kolom-sisi > *:last-child { position: static; }
}
/* Kepala section DIBALIK: isi hitam, teks putih. Bahasa visual yang sama dengan
   menu sidebar aktif & tile utama — di palet monokrom, isi pekat adalah penanda
   tingkat terkuat yang tersedia tanpa rona. Hasilnya tiga tingkat yang tidak
   bisa tertukar: judul HALAMAN (teks besar) > kepala SECTION (bar hitam) >
   sub-bagian di dalamnya (.panel-sub: tebal + garis rambut). Kalau .panel-sub
   ikut dihitamkan, tingkat 2 dan 3 jadi rata lagi dan hierarkinya hilang. */
.panel-judul {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; margin-bottom: var(--space-3);
  background: var(--color-text); color: var(--color-bg);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
}
/* Judul yang MEMBUKA panel dibentang sampai tepi panel (margin negatif sebesar
   padding panel) supaya terbaca sebagai kepala section, bukan tombol yang
   mengambang di dalamnya. Sudut atasnya mengikuti radius panel; sudut bawah
   dibiarkan siku supaya menyatu dengan isinya. */
.panel > .panel-judul:first-child {
  margin: calc(var(--panel-pad) * -1) calc(var(--panel-pad) * -1) var(--panel-pad);
  padding: var(--space-3) var(--panel-pad);
  border-radius: calc(var(--radius-lg) * 1.15) calc(var(--radius-lg) * 1.15) 0 0;
}
/* Panel isian punya garis 1px, jadi margin negatifnya harus 1px LEBIH supaya
   bar judulnya menutupi garis itu — kalau tidak, tersisa celah putih setipis
   rambut di kiri, kanan, dan atas bar.
   WAJIB ditulis SESUDAH aturan di atas: spesifisitasnya persis sama (0,3,0),
   jadi yang menang urutan berkas, bukan bobot — sama seperti jebakan tab
   "Data induk" yang sudah tercatat. */
.panel-isian > .panel-judul:first-child {
  margin: calc(var(--panel-pad) * -1 - 1px) calc(var(--panel-pad) * -1 - 1px) var(--panel-pad);
}
/* Saringan yang tinggal DI DALAM panel daftarnya. Mengambang di luar (pola
   lama) bikin ia terbaca sebagai milik panel di ATASNYA — di halaman Pesanan
   ia terjepit antara panel formulir dan panel daftar, seolah menyaring
   formulirnya. Di dalam panel, hubungannya tak bisa salah baca lagi; garis
   tipis memisahkannya dari tabel tanpa memutus keduanya. */
.panel > .filter:first-of-type {
  margin-bottom: var(--space-4); padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
/* Tautan di dalam bar gelap ikut dibalik — warna aksen app ini nyaris hitam,
   jadi di atas bar hitam ia praktis tak terlihat. */
.panel-judul a { color: var(--color-bg); }

/* ── baris filter ──────────────────────────────────────────── */
.filter { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-end; margin-bottom: var(--space-4); }
/* Pemisah antar dua sumbu saring (arah | status) di Daftar Tagihan. */
.filter-pisah { width: 1px; height: 22px; background: var(--color-divider); margin: 0 4px; }
.filter .field { min-width: 150px; }
.filter select.input { min-height: 36px; }

/* ── form ──────────────────────────────────────────────────── */
.form-sempit { max-width: 420px; }
.field + .field { margin-top: var(--space-3); }
.bantuan { font-size: 12px; color: var(--color-neutral-600); margin-top: 4px; }
.cek { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 14px; }
.cek input { width: 17px; height: 17px; accent-color: var(--color-accent); cursor: pointer; }

/* ── halaman login ─────────────────────────────────────────── */
.login-layar { min-height: 100vh; display: grid; place-items: center; padding: var(--space-4); }
.login-kartu { width: min(380px, 100%); background: var(--color-surface); border-radius: calc(var(--radius-lg) * 1.15); padding: var(--space-6); box-shadow: var(--shadow-md); }
.login-kartu .merek { text-align: center; margin-bottom: var(--space-6); }
.login-kartu .merek .nama {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 26px;
}
.login-kartu .merek .tagline { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--aksi-hijau); }

/* ── log audit ─────────────────────────────────────────────── */
.diff { font-size: 12px; line-height: 1.5; }
.diff .sebelum { color: var(--color-neutral-600); text-decoration: line-through; }
.diff .sesudah { color: var(--color-text); font-weight: 600; }

@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  .sidebar { position: static; height: auto; flex-direction: row; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
  .sidebar-nav { flex-direction: row; flex-wrap: wrap; flex: 1 1 100%; }
  .sidebar-kaki { flex: 1 1 100%; }
  .konten { padding: var(--space-4); }
}

/* ── pemilih periode (templates/periode.html, static/js/periode.js) ──
   Dua lapis: markup polos (preset sebagai tautan biasa + dua <input date>)
   selalu ada di DOM supaya tetap berfungsi kalau JS gagal dimuat — penting di
   aplikasi ini karena purchasing sering buka dari pasar dengan sinyal buruk.
   periode.js MENYEMBUNYIKANNYA dan menggantinya dengan pemicu+dropdown begitu
   berhasil terpasang; kalau tidak, markup polos itulah yang tetap tampil. */
.periode { margin-bottom: var(--space-4); position: relative; }

/* KRUSIAL: .periode-polos/.periode-pemicu/.periode-dropdown semua diberi
   display eksplisit di bawah (flex/inline-flex). Atribut `hidden` bawaan
   browser cuma disetel lewat UA stylesheet ([hidden]{display:none}) yang
   berspesifisitas SAMA dengan selector class biasa — dan pada spesifisitas
   sama, stylesheet penulis (berkas ini) menang atas UA stylesheet apa pun
   urutannya. Tanpa baris [hidden] di bawah, elemen yang "disembunyikan" lewat
   `el.hidden = true` di periode.js TETAP TAMPIL — persis bug yang sempat lolos
   ke pratinjau (dropdown terus terlihat/melebar walau atribut hidden-nya benar
   di DOM). Tiga baris ini harus tetap ada tiap kali display diubah di bawah. */
.periode-polos[hidden], .periode-pemicu[hidden], .periode-dropdown[hidden] {
  display: none;
}

.periode-polos { display: flex; flex-direction: column; gap: var(--space-2); }
.periode-preset { display: flex; flex-wrap: wrap; gap: 6px; }
.periode-preset a { text-decoration: none; cursor: pointer; }
.periode-preset a:hover { background: var(--color-neutral-300); }
/* Preset terpilih sudah berisi pekat (.tag-accent) — hover tidak boleh
   memucatkannya, jadi override-nya ditegaskan lagi di sini. */
.periode-preset a[aria-current]:hover { background: var(--color-text); }
.periode-bebas { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-end; }
.periode-bebas .field { min-width: 148px; }
.periode-aktif { font-size: 13px; color: var(--color-neutral-600); }

/* — pemicu: tombol ringkas yang membuka dropdown — */
.periode-pemicu {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: 14px; white-space: nowrap;
}
/* Kedua ikon (kalender & chevron) WAJIB diberi ukuran di sini. .ikon dasar
   sengaja tidak punya width/height (lihat komentarnya di atas) — tanpa baris
   ini, <svg> tanpa viewBox sendiri jatuh ke ukuran bawaan 300x150 dan tombolnya
   melebar jadi raksasa. Ini persis yang lolos sebelumnya: aturan lama cuma
   membidik :last-child (si chevron), ikon kalender di :first-child tidak
   pernah kebagian ukuran sama sekali. */
.periode-pemicu .ikon { width: 15px; height: 15px; flex: none; }
.periode-pemicu .ikon:last-child { width: 12px; height: 12px; opacity: 0.6; }
.periode-pemicu[aria-expanded='true'] {
  background: var(--color-neutral-200); border-color: var(--color-neutral-400);
}

/* — dropdown: sidebar preset (kiri) + kalender & isian (kanan) — */
.periode-dropdown {
  position: absolute; z-index: 20; top: calc(100% + 6px); left: 0;
  display: flex; align-items: stretch;
  background: var(--color-surface); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg); overflow: hidden;
  width: max-content; max-width: min(92vw, 760px);
}
.periode-sisi {
  flex: none; width: 180px; padding: var(--space-2);
  border-right: 1px solid var(--color-neutral-300);
  display: flex; flex-direction: column; gap: 1px;
  max-height: 420px; overflow-y: auto;
}
.periode-item {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  cursor: pointer; font: inherit; color: var(--color-text);
  padding: 7px var(--space-2); border-radius: var(--radius-sm); font-size: 13px;
}
.periode-item:hover { background: var(--color-neutral-200); }
.periode-item-aktif, .periode-item-aktif:hover {
  background: var(--color-text); color: var(--color-bg); font-weight: 600;
}
/* "Semua" adalah pilihan terbuka (tanpa batas tanggal), bukan tanggal
   spesifik seperti yang lain — garis pemisah menandakan itu secara nyata,
   bukan hiasan. */
.periode-item[data-preset='semua'] {
  margin-top: var(--space-2); padding-top: 8px;
  border-top: 1px solid var(--color-neutral-300);
}

/* max-height & overflow-y TIDAK dipatok di sini — periode.js mengisinya
   sebagai inline style tiap dropdown dibuka, mengikuti ruang layar yang
   nyata saat itu (lihat posisikanDropdown()). Kalau JS gagal jalan, elemen
   ini tidak pernah terlihat sama sekali (markup polos yang tampil), jadi
   tidak butuh nilai bawaan di sini. */
.periode-isi { flex: 1; min-width: 0; padding: var(--space-3); }
.periode-nav {
  /* flex-start, bukan center: panah harus sejajar dengan BARIS JUDUL bulan
     (elemen pertama di dalam .periode-bulan), bukan mengambang di tengah
     tinggi seluruh grid kalender yang jauh lebih tinggi dari tombolnya. */
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-2); margin-bottom: var(--space-3);
}
.periode-nav button {
  border: 0; background: none; cursor: pointer; color: var(--color-text);
  display: grid; place-items: center; width: 28px; height: 28px; border-radius: 999px;
}
.periode-nav button:hover { background: var(--color-neutral-200); }
.periode-nav button:disabled { opacity: 0.3; cursor: default; background: none; }
.periode-nav button .ikon { width: 16px; height: 16px; }

.periode-bulan-baris { display: flex; gap: var(--space-4); }
.periode-bulan { width: 236px; }
.periode-bulan-judul {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; text-align: center; margin-bottom: var(--space-2);
}
.periode-grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
}
.periode-grid .dow {
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-neutral-600); text-align: center; padding-bottom: 4px;
}
.periode-hari {
  border: 0; background: none; cursor: pointer; font: inherit; font-size: 13px;
  color: var(--color-text); width: 32px; height: 32px; border-radius: 50%;
  font-variant-numeric: tabular-nums;
}
.periode-hari:disabled { visibility: hidden; }
.periode-hari:hover:not(:disabled) { background: var(--color-neutral-200); }
/* Rentang: isian tipis menyambungkan titik awal & akhir — kotak, bukan
   lingkaran, supaya benar-benar terlihat "tersambung" hari ke hari. */
.periode-hari.di-rentang { background: var(--color-neutral-200); border-radius: 0; }
.periode-hari.rentang-mulai { border-radius: 50% 0 0 50%; }
.periode-hari.rentang-akhir { border-radius: 0 50% 50% 0; }
.periode-hari.rentang-mulai.rentang-akhir { border-radius: 50%; }
.periode-hari.rentang-mulai, .periode-hari.rentang-akhir {
  background: var(--color-text); color: var(--color-bg); font-weight: 600;
}
.periode-hari.hari-ini:not(.rentang-mulai):not(.rentang-akhir) {
  box-shadow: inset 0 0 0 1.5px var(--color-neutral-400);
}

.periode-isian {
  display: flex; align-items: center; gap: var(--space-2);
  margin-top: var(--space-4); padding-top: var(--space-3);
  border-top: 1px solid var(--color-neutral-300);
}
.periode-isian input { min-width: 0; }
/* neutral-600, bukan -500: itu satu-satunya nilai redup yang dipatok lolos
   4,5:1 di atas --color-surface (lihat DESAIN.md §2). -500 cuma 2,7:1 di sini. */
.periode-isian .panah { color: var(--color-neutral-600); flex: none; }
.periode-aksi {
  display: flex; justify-content: flex-end; gap: var(--space-2);
  margin-top: var(--space-3);
}

@media (max-width: 680px) {
  .periode-dropdown {
    position: fixed; inset: 64px var(--space-3) var(--space-3) var(--space-3);
    /* width:max-content di aturan dasar mengalahkan peregangan left+right
       bawaan position:fixed — harus ditegaskan ulang di sini, kalau tidak
       dropdown tetap selebar isinya (~1260px) dan meluber dari layar. */
    width: auto; max-width: none; max-height: none;
    flex-direction: column; overflow-y: auto;
  }
  .periode-sisi {
    width: auto; max-height: 120px; flex-direction: row; flex-wrap: wrap;
    border-right: 0; border-bottom: 1px solid var(--color-neutral-300);
  }
  .periode-item[data-preset='semua'] { margin-top: 0; padding-top: 7px; border-top: 0; }
  .periode-bulan-baris > .periode-bulan:last-child { display: none; }
  .periode-bulan-baris, .periode-bulan { width: 100%; }
  .periode-hari { width: auto; aspect-ratio: 1; }
  .periode-isian { flex-wrap: wrap; }
}

/* ── bagan akun: indentasi mengikuti kedalaman induk ────────── */
/* Indentasi WAJIB lebih spesifik daripada `.table-padat td { padding: … }`
   (0,1,1). Aturan lama `.akun-dalam-1` (0,1,0) kalah spesifisitas DAN ditimpa
   shorthand `padding` — akibatnya semua level tampil rata di 8,8px dan
   hierarki induk-anak di Neraca serta Bagan Akun tidak pernah benar-benar
   terlihat. Diukur di browser: dalam-0 dan dalam-1 sama-sama 8,8px. */
.table td.akun-dalam-0 { padding-left: var(--space-2); }
.table td.akun-dalam-1 { padding-left: calc(var(--space-2) + 20px); }
.table td.akun-dalam-2 { padding-left: calc(var(--space-2) + 40px); }
.table td.akun-dalam-3 { padding-left: calc(var(--space-2) + 60px); }
/* Jarak saja belum cukup jadi penanda hierarki kalau angkanya rapat: induk
   (kelompok yang nilainya rollup anak-anaknya) dibuat tebal dan diberi napas
   di atasnya sebagai pemisah kelompok; anaknya sedikit lebih redup supaya mata
   membaca kelompok dulu, baru rinciannya. */
.akun-induk { font-weight: 700; }
.table td.akun-induk { padding-top: var(--space-3); }
.table td.akun-dalam-1, .table td.akun-dalam-2, .table td.akun-dalam-3 {
  color: var(--color-neutral-700);
}
/* Judul KELOMPOK di dalam tabel (Kewajiban / Ekuitas): dibedakan sebagai label
   seksi, bukan sebagai baris data — huruf kecil berspasi, tanpa angka. */
.table tr.baris-kelompok td {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-600); font-weight: 600;
  padding-top: var(--space-4); border-bottom: 0;
}
.table tbody tr.baris-kelompok:first-child td { padding-top: 6px; }
/* Dua tingkat penjumlahan, dua tebal garis: subtotal kelompok bergaris tipis,
   total akhir bergaris penuh. Batas antara rincian dan totalnya adalah hal
   pertama yang dicari pembaca neraca. */
.table tr.baris-subtotal td {
  border-top: 1px solid var(--color-divider); border-bottom: 0;
  font-weight: 600;
}
.table tr.baris-total td {
  border-top: 2px solid var(--color-text); border-bottom: 0;
  padding-top: var(--space-2);
}

/* ── identitas layar gudang (PENGECUALIAN monokrom) ─────────── */
/* Proses dan BS tertukar saat dipakai cepat. Warnanya dipasang di SATU kelas
   pembungkus dan bekerja lewat OVERRIDE TOKEN, bukan dengan mewarnai .panel —
   .panel dipakai puluhan template lain dan tidak boleh ikut berubah.
   Layar Penerimaan sengaja tetap putih: tiga layar ini saling bertaut lewat
   tombol di .kepala, jadi putih/hijau/merah membentuk satu set yang konsisten. */
.layar-proses {
  background: var(--layar-proses-bg);
  --color-surface: var(--layar-proses-panel);
  --color-neutral-600: var(--layar-proses-redup);
}
.layar-bs {
  background: var(--layar-bs-bg);
  --color-surface: var(--layar-bs-panel);
  --color-neutral-600: var(--layar-bs-redup);
}
/* Warnanya harus mengisi seluruh kolom konten, bukan cuma setinggi isinya —
   kalau tidak, identitas layar hilang begitu halamannya pendek. */
.layar-proses, .layar-bs { min-height: 100vh; }

/* ── sidebar bertingkat (grup Keuangan) ─────────────────────── */
/* Anak hanya dirender saat grupnya aktif — sidebar tetap pendek dan tidak
   perlu JavaScript buka-tutup di PWA lapangan. */
.sidebar-nav .grup-aktif { color: var(--color-neutral-100); }
.sidebar-anak { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 var(--space-2); }
.sidebar-anak a {
  display: block; padding: 6px var(--space-3) 6px calc(var(--space-3) + 26px);
  border-radius: 999px; text-decoration: none; font-size: 13px;
  color: var(--color-neutral-400);
}
.sidebar-anak a:hover {
  background: color-mix(in srgb, var(--color-neutral-100) 12%, transparent);
  color: var(--color-neutral-100);
}
.sidebar-anak a[aria-current='page'] {
  background: var(--color-neutral-100); color: var(--color-neutral-900); font-weight: 600;
}
@media (max-width: 900px) {
  /* Sidebar jadi baris membungkus di layar sempit; anak harus ikut jadi baris
     sendiri, kalau tidak indentasinya tidak berarti apa-apa. */
  .sidebar-anak { flex-direction: row; flex-wrap: wrap; flex: 1 1 100%; }
  .sidebar-anak a { padding-left: var(--space-3); }
}

/* ── aksi utama sidebar ──────────────────────────────────────────────────────
   Dua tombol aksi di atas menu. Dibedakan dari menu biasa lewat ISI TERANG di
   atas sidebar gelap — penanda terkuat tanpa rona. Dikelompokkan supaya
   jaraknya rapat satu sama lain, terpisah jelas dari brand & nav. */
.sidebar-aksi-grup { display: flex; flex-direction: column; gap: var(--space-2); }
.sidebar-aksi {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-2); padding: var(--space-3) var(--space-3);
  border-radius: 999px; text-decoration: none;
  background: var(--color-neutral-100); color: var(--color-neutral-900);
  font-weight: 700; font-size: 14px; line-height: 1.2;
  box-shadow: var(--shadow-sm);
}
.sidebar-aksi:hover { background: #fff; }
.sidebar-aksi .ikon { width: 17px; height: 17px; flex: none; }
/* Proses Pesanan sedang dibuka: cincin terang menandai "kamu di sini". */
.sidebar-aksi-aktif { box-shadow: 0 0 0 2px var(--color-neutral-100), var(--shadow-sm); }
/* Sekunder (Input transaksi langsung): garis saja, bukan isi penuh — hierarki
   di bawah Proses Pesanan. */
.sidebar-aksi-2 {
  background: transparent; color: var(--color-neutral-100);
  box-shadow: inset 0 0 0 1px var(--color-neutral-600); font-weight: 600;
}
.sidebar-aksi-2:hover {
  background: color-mix(in srgb, var(--color-neutral-100) 10%, transparent);
}

/* ── Proses Pesanan: tab berpanah + kartu tujuan ────────────────────────────
   Pola sama dengan tab Input Transaksi Langsung: radio tersembunyi + selektor
   saudara CSS, jalan tanpa JavaScript. Kunci tahap tetap, jadi selektornya
   statis. */
/* Judul section di atas bilah — dibalas dari referensi (dokumen: judul besar,
   lalu label kecil "Workflow" tepat di atas rangkaian status). Satu makro,
   jadi muncul sama di hub & sisip; di hub ia melengkapi judul halaman "Proses
   Pesanan" yang sudah dirender terpisah di atasnya (proses/index.html). */
/* 20px sempat lebih kecil dari judul halaman ("Pesanan" h2, 32px) — jadi
   terbaca kalah, bukan menonjol. Dinaikkan ke 38px (LEBIH BESAR dari h2)
   + font judul (--font-heading, sama dengan h1-h4) supaya "WORKFLOW" benar-
   benar jadi label paling menonjol di area ini. */
.alur-judul {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 38px; line-height: 1.05; letter-spacing: 0.01em;
  text-transform: uppercase; margin-bottom: var(--space-3);
}

/* Chip kecil & ringkas (referensi: status-bar Odoo-style). Riwayat 3 babak:
   40px penuh (ikon+nomor+nama) -> 20px (semua diperkecil, ikon 11px jadi tak
   terbaca) -> ikon+nomor DIBUANG total (chip murni teks) -> DIMINTA KEMBALI,
   kini hadir versi MINI (nomor 14px, ikon 11px) supaya penanda visualnya
   tetap ada tanpa membengkakkan chip. Proporsi tekstualnya (11px, padding
   3px 10px, radius calc(--radius-md*0.75)) tetap disamakan dengan `.tag` yang
   sudah dipakai di banyak tempat lain di app ini. */
.alur-tab { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.alur-radio {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.alur-tombol {
  flex: 0 0 auto; cursor: pointer; border-radius: calc(var(--radius-md) * 0.75);
  border: 1px solid var(--color-divider); background: var(--color-surface);
  padding: 3px 10px; display: inline-flex; align-items: center; gap: 5px;
  /* Varian sisip memakai <a>, bukan <label> — dijaga tampil sama persis. */
  text-decoration: none; color: var(--color-text);
}
.alur-tombol .ikon { width: 11px; height: 11px; flex: none; }
.alur-nomor {
  flex: none; width: 14px; height: 14px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-neutral-200); color: var(--color-neutral-700);
  font-size: 8px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.alur-nama {
  font-weight: 700; font-size: 11px; letter-spacing: 0.02em;
  text-transform: uppercase;
}
/* "Data induk" BUKAN tahap yang dilewati: didorong ke kanan supaya terpisah
   jelas dari rantai bernomor, dan tak ikut melebar — lebar bilah ini milik
   lima tahap alurnya.

   Diberi rona BIRU, satu-satunya tab yang tidak hitam. Mengikuti kamus rona
   app (DESAIN.md §2): biru = acuan & tautan, bukan aksi operasional — jadi
   "ini bukan bagian prosesnya" terbaca dari warnanya, tidak cuma dari
   absennya panah. Hitam tetap milik rantai bernomor.
   Kontras terukur: #0b5aa6 di atas putih = 6,9:1 (dan putih di atasnya sama),
   dua-duanya lewat ambang 4,5:1. */
.alur-tombol-data {
  margin-left: auto;
  border-color: var(--aksi-biru); color: var(--aksi-biru);
}
.alur-tombol-data .alur-nama { color: var(--aksi-biru); }
.alur-tombol-data:hover { border-color: var(--aksi-biru-tua); }
/* Kartu sub-langkah di dalam panel Data induk ikut biru, bukan hitam —
   kalau tidak, tab-nya biru tapi kartunya hitam dan pesannya jadi campur. */
[data-panel='data'] .alur-tujuan-kini,
[data-panel='data'] .alur-tujuan-kini:hover {
  background: var(--aksi-biru); border-color: var(--aksi-biru);
}
.alur-tombol:hover { border-color: var(--color-neutral-500); }
.alur-radio:focus-visible + .alur-tombol { outline: 2px solid var(--color-text); outline-offset: 2px; }
.alur-radio:checked + .alur-tombol { background: var(--color-text); border-color: var(--color-text); color: var(--color-bg); }
.alur-radio:checked + .alur-tombol .alur-nama { color: var(--color-bg); }
.alur-radio:checked + .alur-tombol .alur-nomor { background: var(--color-bg); color: var(--color-text); }
/* Varian sisip memakai <a>, jadi tak ada `:checked` — tahap aktif ditandai
   server lewat .alur-tombol-kini. Isinya harus identik dengan versi radio. */
.alur-tombol-kini { background: var(--color-text); border-color: var(--color-text); color: var(--color-bg); }
.alur-tombol-kini .alur-nama { color: var(--color-bg); }
.alur-tombol-kini .alur-nomor { background: var(--color-bg); color: var(--color-text); }

/* Data induk aktif: BIRU, bukan hitam. Harus berada SESUDAH aturan hitam di
   atas — spesifisitasnya persis sama (0,3,0: dua kelas + satu pseudo-kelas),
   jadi yang menang urutan berkas, bukan bobot. Ditaruh di dekat `.alur-tombol-
   data` (tempat alaminya) sempat bikin tab-nya tetap hitam padahal kartunya
   sudah biru. */
.alur-radio:checked + .alur-tombol-data,
.alur-tombol-data.alur-tombol-kini {
  background: var(--aksi-biru); border-color: var(--aksi-biru); color: #fff;
}
.alur-radio:checked + .alur-tombol-data .alur-nama,
.alur-tombol-data.alur-tombol-kini .alur-nama { color: #fff; }
.alur-panah { flex: none; display: inline-flex; color: var(--color-neutral-500); }
.alur-panah .ikon { width: 13px; height: 13px; }

.alur-isi { flex-basis: 100%; margin-top: var(--space-4); }
/* Kunci tetap: pesanan/belanja/penerimaan/kirim/tagihan/data. Tahap yang
   disaring hak akses tidak merender radionya, jadi selektornya cuma tidak
   pernah cocok. */
.alur-panel { display: none; }
#alur-pesanan:checked    ~ .alur-isi [data-panel='pesanan'],
#alur-belanja:checked    ~ .alur-isi [data-panel='belanja'],
#alur-penerimaan:checked ~ .alur-isi [data-panel='penerimaan'],
#alur-kirim:checked      ~ .alur-isi [data-panel='kirim'],
#alur-tagihan:checked    ~ .alur-isi [data-panel='tagihan'],
#alur-data:checked       ~ .alur-isi [data-panel='data'] { display: block; }
/* Varian sisip & etalase tak punya radio — panel yang tampil ditentukan server. */
.alur-panel-kini { display: block; }
/* Etalase (hub): panel-panel tampil berurutan, masing-masing berjudul tahapnya
   supaya kartunya tak jadi satu tumpukan tanpa konteks. */
/* --space-5 TIDAK ADA di skala app ini (1-4, 6, 8) — memakainya bikin
   deklarasinya jatuh jadi 0 dan panelnya berdempet. */
.alur-panel-kini + .alur-panel-kini { margin-top: var(--space-6); }
.alur-panel-judul {
  font-size: 13px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--color-neutral-600);
  margin-bottom: var(--space-3);
}

.alur-tujuan-baris {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-3);
}
.alur-tujuan {
  display: flex; align-items: center; gap: var(--space-3);
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: var(--space-4); text-decoration: none;
  color: var(--color-text);
}
.alur-tujuan:hover { border-color: var(--color-neutral-500); box-shadow: var(--shadow-sm); }
.alur-tujuan-isi { flex: 1; min-width: 0; }
.alur-tujuan-judul { font-weight: 700; font-size: 15px; }
.alur-tujuan-ket { font-size: 12.5px; color: var(--color-neutral-600); margin-top: 2px; }
.alur-tujuan-panah { width: 18px; height: 18px; flex: none; color: var(--color-neutral-500); }

/* Sub-langkah tempat halaman sekarang berada: diisi hitam pekat, bahasa visual
   yang SAMA dengan tab fase di atasnya (bukan cuma cincin/outline) — supaya
   "kamu di sini" konsisten dengan seluruh penanda posisi-aktif lain di app. */
.alur-tujuan-kini,
.alur-tujuan-kini:hover {
  background: var(--color-text); border-color: var(--color-text); color: var(--color-bg);
}
.alur-tujuan-kini .alur-tujuan-ket { color: var(--color-neutral-300); }
.alur-tujuan-kini .alur-tujuan-panah { color: var(--color-bg); }

/* Bilah fase sisipan (base.html): versi ramping dari .alur di atas tiap halaman
   alur, dengan garis pemisah supaya tak menyatu dengan isi halaman. Komponennya
   sama — hanya dirapatkan.

   margin-top DISENGAJA ~50px, lepas dari skala token (terdekat cuma
   --space-8 di 35,2px) — menyediakan ruang di atas bilah supaya ia langsung
   terbaca sebagai bagiannya sendiri, bukan menempel ke tepi `.konten`, dan
   cukup lega untuk judul/tulisan yang akan ditambahkan (belum ada isinya
   sekarang — cuma jarak). */
.alur-sisip {
  margin-top: 50px; margin-bottom: var(--space-6);
  padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-divider);
}
.alur-sisip .alur-isi { margin-top: var(--space-3); }
.alur-sisip .alur-tujuan { padding: var(--space-3); }
.alur-sisip .alur-tujuan-baris { gap: var(--space-2); }

@media (max-width: 680px) {
  .alur-panah { display: none; }
  /* Chip tetap kompak & melipat sendiri (flex-wrap) di mobile — beda dari
     desain kotak lama yang perlu dipaksa selebar layar. Dorong-ke-kanan
     "Data induk" tak lagi bermakna begitu baris melipat, jadi direset. */
  .alur-tombol-data { margin-left: 0; }
}

/* ── bilah "Langkah berikutnya" ─────────────────────────────────────────────
   Satu bentuk yang sama di seluruh halaman alur, diletakkan tepat di bawah
   judul halaman. Dibalik jadi gelap supaya ia menang telak atas tombol lain
   di halaman yang sama (Cetak, Kembali, Batalkan) — itu inti masalahnya: dulu
   tombol lanjut sebentuk & sederajat dengan tombol mundur, jadi tak terbaca
   sebagai arah. */
.langkah {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); flex-wrap: nowrap;
  background: var(--color-text); color: var(--color-bg);
  border-radius: var(--radius-md); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--panel-gap);
}
.langkah-teks { min-width: 0; }
.langkah-cap {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-400); margin-bottom: 2px;
}
.langkah-teks b { font-size: 16px; }
/* .bantuan default abu gelap — tak terbaca di atas hitam. */
.langkah-teks .bantuan { color: var(--color-neutral-300); max-width: 100%; }
.langkah-aksi {
  flex: none; display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
}
/* Tombol utama di dalam bilah gelap harus DIBALIK jadi terang, kalau tidak
   hitam-di-atas-hitam. */
.langkah-aksi .btn-primary {
  background: var(--color-bg); color: var(--color-text); border-color: var(--color-bg);
}
.langkah-aksi .btn-primary:hover { background: var(--color-neutral-200); }
.langkah-aksi .btn-secondary, .langkah-aksi .btn-ghost {
  background: transparent; color: var(--color-bg); border-color: var(--color-neutral-600);
}
.langkah-aksi .btn-secondary:hover, .langkah-aksi .btn-ghost:hover {
  border-color: var(--color-bg);
}
.langkah-aksi .input { min-width: 120px; }
.langkah-label { font-size: 12px; color: var(--color-neutral-300); white-space: nowrap; }
.langkah-aksi form { display: flex; align-items: center; gap: var(--space-2); }
/* Tahap terakhir: tak ada yang perlu didorong, jadi tak usah berteriak. */
.langkah-selesai {
  background: var(--color-surface); color: var(--color-text);
  border: 1px solid var(--color-divider);
}
.langkah-selesai .langkah-cap { color: var(--color-neutral-600); }
.langkah-selesai .langkah-teks .bantuan { color: var(--color-neutral-600); }
.langkah-selesai .langkah-aksi .btn-primary {
  background: var(--color-text); color: var(--color-bg); border-color: var(--color-text);
}
.langkah-selesai .langkah-aksi .btn-secondary {
  background: transparent; color: var(--color-text); border-color: var(--color-divider);
}
@media (max-width: 680px) {
  .langkah { flex-wrap: wrap; }
  .langkah-aksi { flex: 1 1 100%; }
  .langkah-aksi .btn { flex: 1 1 auto; }
}

/* ── bilah aksi pilih-massal ────────────────────────────────────────────────
   Dipakai form bertabel centang (Daftar PO). MENEMPEL di atas saat digulir:
   tabelnya bisa panjang, dan tombol yang cuma ada di dasar halaman membuat
   langkah setelah mencentang tak terlihat sama sekali. */
.aksi-pilih {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  /* nowrap: tombolnya HARUS tetap di kanan teks. Dengan `wrap`, blok teks
     (lebar min-content ~601px karena .bantuan dibatasi 80ch) menendang tombol
     ke baris bawah begitu bilah menyempit di bawah ~805px — persis yang
     dikeluhkan pemilik. Yang mengalah cukup teksnya: ia boleh menyusut dan
     kalimat bantuannya melipat jadi dua baris. */
  flex-wrap: nowrap;
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3); box-shadow: var(--shadow-sm);
}
/* min-width:0 melepas minimum `auto` bawaan flex item — tanpa ini teksnya
   menolak menyusut dan nowrap malah bikin tombol terdorong keluar bilah. */
.aksi-pilih-teks { min-width: 0; }
.aksi-pilih-teks b { font-size: 15px; }
.aksi-pilih-teks .bantuan { max-width: 100%; }
.aksi-pilih .btn { flex: none; }
/* Tombol mati = "masih ada yang kurang", bukan "rusak" — dibuat jelas redup
   tapi tetap terbaca. */
.aksi-pilih .btn[disabled] {
  opacity: 0.45; cursor: not-allowed; pointer-events: none;
}
.pilih-kotak { width: 17px; height: 17px; accent-color: var(--color-text); }
@media (max-width: 680px) {
  /* Di ponsel barulah menumpuk: sebaris memaksa teks jadi kolom sangat sempit
     yang melipat 4-5 baris, bilah sticky-nya jadi memakan layar. */
  .aksi-pilih { flex-wrap: wrap; }
  .aksi-pilih .btn { flex: 1 1 100%; }
}

.langsung { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--space-6); align-items: start; }

/* Tab tanpa JavaScript: radio tersembunyi + selektor saudara. Radio-nya
   sengaja TIDAK display:none supaya tetap bisa dijangkau keyboard; ia
   disembunyikan lewat clip, dan labelnya yang menerima cincin fokus. */
.langsung-tab { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.langsung-radio {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.langsung-tombol {
  flex: 1 1 150px; cursor: pointer; border-radius: var(--radius-md);
  border: 1px solid var(--color-divider); background: var(--color-surface);
  padding: var(--space-3); display: flex; flex-direction: column; gap: 2px;
}
.langsung-tombol b { font-size: 15px; font-weight: 700; }
.langsung-tombol span { font-size: 12px; color: var(--color-neutral-600); }
.langsung-tombol:hover { border-color: var(--color-neutral-500); }
.langsung-radio:focus-visible + .langsung-tombol { outline: 2px solid var(--color-text); outline-offset: 2px; }
.langsung-radio:checked + .langsung-tombol {
  background: var(--color-text); border-color: var(--color-text);
}
.langsung-radio:checked + .langsung-tombol b { color: var(--color-bg); }
.langsung-radio:checked + .langsung-tombol span { color: var(--color-neutral-300); }

.langsung-isi { flex-basis: 100%; }
/* Semua panel disembunyikan; yang radionya tercentang dimunculkan lagi.
   Aturan [hidden] tidak dipakai di sini — panelnya dikendalikan CSS penuh. */
.langsung-panel { display: none; }
#tab-pendapatan:checked ~ .langsung-isi [data-panel='pendapatan'],
#tab-stok:checked       ~ .langsung-isi [data-panel='stok'],
#tab-aset:checked       ~ .langsung-isi [data-panel='aset'],
#tab-biaya:checked      ~ .langsung-isi [data-panel='biaya'] { display: block; }

.langsung-form {
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: var(--space-4);
  margin-top: var(--space-3);
}
.grid-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-3); margin-bottom: var(--space-3);
}
.grid-form .field.lebar { grid-column: 1 / -1; }
/* `.field + .field { margin-top: var(--space-3) }` (di atas, bagian ── form ──)
   dibuat untuk field yang DITUMPUK vertikal (mis. form login) — tapi selektor
   sibling itu tidak tahu-menahu soal grid/baris, jadi field ke-2 dst di SETIAP
   baris grid ini pun ikut kena, terdorong turun ~13px dari field pertama di
   baris yang sama (padahal `gap` grid sudah menjaga jaraknya sendiri). Field
   ke-2/ke-3 lalu tidak sejajar lagi dengan field pertama. Dibatalkan di sini,
   bukan mencabut aturan aslinya — form yang memang ditumpuk (login, master
   data, dst.) masih perlu jaraknya. */
.grid-form > .field + .field { margin-top: 0; }
/* Input + tombol pintas (mis. "Full cash") sebaris; inputnya melar, tombolnya
   secukupnya. */
.input-aksi { display: flex; gap: var(--space-2); align-items: stretch; }
.input-aksi .input { flex: 1; min-width: 0; }
.input-aksi .btn { flex: none; white-space: nowrap; }
.pilihan { display: flex; align-items: center; gap: var(--space-2); font-size: 14px; cursor: pointer; }
.pilihan input { width: 16px; height: 16px; }
.langsung-ringkas { margin-top: var(--space-4); }

/* Panel pratinjau — menempel saat digulir, karena gunanya justru dibaca
   sambil mengisi form di sebelahnya. */
.pratinjau {
  position: sticky; top: var(--space-4);
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: var(--panel-pad);
}
.pratinjau[hidden] { display: none; }
/* Kepala panel pratinjau ikut dibalik seperti .panel-judul — panel ini sejajar
   dengan panel lain, cuma kelasnya beda karena ia menempel saat digulir. */
.pratinjau-judul {
  font-weight: 700; font-size: 14px;
  background: var(--color-text); color: var(--color-bg);
  margin: calc(var(--panel-pad) * -1) calc(var(--panel-pad) * -1) var(--panel-pad);
  padding: var(--space-3) var(--panel-pad);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
/* "JURNAL YANG TERBENTUK" adalah sub-bagian DI DALAM panel itu (tingkat 3),
   jadi ia dikembalikan ke gaya teks biasa — bukan bar kedua. */
.pratinjau-judul.kecil {
  background: transparent; color: var(--color-neutral-600);
  margin-inline: 0; padding: 0; border-radius: 0;
  font-size: 12px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--color-neutral-600);
  /* --space-5 TIDAK ADA di skala token (organic.css cuma punya 1-4,6,8) — var()
     tak dikenal membuat seluruh deklarasi computed value-nya gugur ke initial
     (margin-top:0), jadi header ini dulu nempel PERSIS ke baris terakhir di
     atasnya tanpa jarak sama sekali. --space-6 adalah token nyata terdekat. */
  margin-top: var(--space-6); margin-bottom: var(--space-2); }
/* Tiap dampak jadi baris daftar dengan ritme vertikal + garis rambut, bukan
   lima baris berdempet. Ruangnya ada di padding baris, bukan gap wadah, supaya
   garis pemisahnya rapat ke tepi baris. */
.pratinjau-dampak { display: flex; flex-direction: column; }
.pd {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3); font-size: 13px;
  padding: var(--space-2) 0; border-bottom: 1px solid var(--color-divider);
}
.pd:first-child { border-top: 1px solid var(--color-divider); }
.pd span { color: var(--color-neutral-600); }
.pd b { font-variant-numeric: tabular-nums; text-align: right; }
/* Arah perubahan ditandai berat huruf & garis, bukan hijau/merah: paletnya
   monokrom, dan naik/turun di sini tidak selalu berarti baik/buruk —
   kas turun karena beli aset itu netral, bukan kabar buruk. */
.pd b.naik { font-weight: 700; }
.pd b.turun { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.pd b.datar { font-weight: 400; color: var(--color-neutral-600); }

.pratinjau-jurnal { display: flex; flex-direction: column; gap: var(--space-3); }
.jurnal-entri { border-left: 2px solid var(--color-neutral-300); padding-left: var(--space-3); }
.jurnal-ket { font-size: 12px; color: var(--color-neutral-600); margin-bottom: 4px; }
.jurnal-tabel { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.jurnal-tabel td { padding: 2px 0; vertical-align: top; }
.jurnal-tabel td.angka { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; padding-left: var(--space-2); }
/* Baris kredit menjorok, seperti jurnal tulis tangan. */
.jurnal-tabel tr.kredit td:first-child { padding-left: var(--space-4); color: var(--color-neutral-700); }
.pratinjau-catatan { margin-top: var(--space-3); font-size: 12.5px; color: var(--color-neutral-700); }
.pratinjau-catatan p { margin: 0 0 var(--space-2); }
.pratinjau-pesan { font-size: 13px; color: var(--color-neutral-600); }
.pratinjau-pesan[hidden] { display: none; }

@media (max-width: 980px) {
  .langsung { grid-template-columns: 1fr; }
  .pratinjau { position: static; }
}

/* ── Daftar Tagihan ─────────────────────────────────────────────────────────
   BADGE piutang (biru) & hutang (merah) adalah PENGECUALIAN warna yang diminta
   pemilik secara eksplisit, di atas palet monokrom. Sama seperti layar Proses
   (hijau) & BS (merah): warna dipakai sebagai KODE STATUS, bukan hiasan —
   arah uang harus terbaca sekejap dari jauh. Tokennya dipatok di sini, bukan
   di organic.css, supaya jelas ini lapisan aplikasi, bukan design system. */
:root {
  --piutang-bg: #e6f0fb; --piutang-tx: #0b5aa6;
  --hutang-bg:  #fbe7e6; --hutang-tx:  #b3261e;
}
.badge {
  display: inline-block; min-width: 1.5em; text-align: center;
  font-size: 11px; font-weight: 700; line-height: 1.5;
  padding: 0 6px; border-radius: 999px; vertical-align: middle;
}
.badge-piutang { background: var(--piutang-bg); color: var(--piutang-tx); }
.badge-hutang  { background: var(--hutang-bg);  color: var(--hutang-tx); }
/* Versi TULISAN saja (tanpa latar pil) — untuk angka rupiah rata-kanan di
   kolom tabel, dimana pil badge terasa berat & merusak kerapatan digit. */
.tx-piutang { color: var(--piutang-tx); }
.tx-hutang  { color: var(--hutang-tx); }

/* Daftar Transaksi — badge JENIS tetap MONOKROM (jenis transaksi bukan status
   uang seperti piutang/hutang, jadi tak diberi warna). Bedanya cuma tebal-tipis:
   pemasukan (pendapatan) terisi gelap, pengeluaran abu-abu — arah kas terbaca
   sekejap tanpa keluar dari palet. */
.badge-tx {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.badge-tx-masuk  { background: var(--color-text); color: var(--color-bg); }
.badge-tx-keluar { background: var(--color-neutral-200); color: var(--color-neutral-700); }

/* ── Inventory ──────────────────────────────────────────────────────────────
   PENGECUALIAN monokrom berikutnya yang diminta pemilik ("jangan satu warna"):
   ARAH PERGERAKAN STOK sebagai kode status — masuk hijau, keluar merah —
   sekeluarga dengan piutang (biru) & hutang (merah) di atas. Dipakai di badge
   jenis mutasi, angka qty bertanda, dan nilai margin (untung hijau, rugi
   merah). Tetap KODE STATUS, bukan hiasan: elemen tanpa makna arah tidak ikut
   diwarnai. Merah memakai token hutang — sama-sama "keluar dari kita". */
:root {
  --masuk-bg: #e6f4ea; --masuk-tx: #137333;
  --keluar-bg: var(--hutang-bg); --keluar-tx: var(--hutang-tx);
}
.badge-masuk  { background: var(--masuk-bg);  color: var(--masuk-tx); }
.badge-keluar { background: var(--keluar-bg); color: var(--keluar-tx); }

/* ── Aksen semantik seluruh app (20 Agu 2026, permintaan pemilik) ───────────
   "Hitam-putih saja terasa flat" — maka rona ditambahkan, tapi tetap sebagai
   KODE MAKNA, bukan hiasan (DESAIN.md §2, amandemen). Kamusnya satu dan
   berlaku di semua layar:
     hijau  = uang/barang MASUK, berhasil, lunas, cocok
     merah  = KELUAR, bahaya/destruktif, selisih, abnormal
     biru   = piutang, tautan, aksi bayar terencana
     amber  = peringatan yang butuh dibaca (bukan bahaya)
   Yang SENGAJA tetap monokrom: struktur (bar hitam kepala section), seleksi
   (pill filter aktif, tab, menu sidebar), dan tombol primer netral — kalau
   seleksi ikut berwarna, warna berhenti berarti status. Semua pasangan di
   bawah lolos kontras 4,5:1 (teks) / 3:1 (komponen); nilai gelap tombol
   dihitung untuk teks putih di atasnya. */
:root {
  --aksi-hijau: var(--masuk-tx);   --aksi-hijau-tua: #0d5527;
  --aksi-biru:  var(--piutang-tx); --aksi-biru-tua:  #084a8a;
  --aksi-merah: var(--hutang-tx);  --aksi-merah-tua: #8f1d17;
  --peringatan-bg: #fdf1d8; --peringatan-garis: #ecd9a8; --peringatan-tx: #7a4d00;
  --masuk-garis: #bfe0c8;
  --tautan: var(--aksi-biru); --tautan-tua: var(--aksi-biru-tua);
  --brand-segar: #93d8aa;          /* tagline di atas sidebar hitam, ~11:1 */
}

/* Tombol berwarna — untuk AKSI yang maknanya searah kamus di atas:
   hijau = menerima uang / mencatat penjualan; biru = membayar yang terencana;
   merah = destruktif permanen (hapus, pulihkan-timpa). Simpan biasa tetap
   hitam (.btn-primary): kalau semua tombol berwarna, tidak ada yang menonjol. */
.btn-hijau { background: var(--aksi-hijau); color: #fff; }
.btn-hijau:hover, .btn-hijau:active { background: var(--aksi-hijau-tua); color: #fff; }
.btn-biru { background: var(--aksi-biru); color: #fff; }
.btn-biru:hover, .btn-biru:active { background: var(--aksi-biru-tua); color: #fff; }
.btn-merah { background: var(--aksi-merah); color: #fff; }
.btn-merah:hover, .btn-merah:active { background: var(--aksi-merah-tua); color: #fff; }
/* Varian teks untuk tombol hapus kecil di dalam tabel — solid merah di tiap
   baris tabel akan berteriak; teks merah cukup menandakan bahaya. */
.btn-bahaya { color: var(--aksi-merah); }
.btn-bahaya:hover { background: var(--hutang-bg); color: var(--aksi-merah-tua); }

/* Tag status semantik — melengkapi badge-masuk/keluar di atas. */
.tag-sukses     { background: var(--masuk-bg); color: var(--masuk-tx); }
.tag-bahaya     { background: var(--hutang-bg); color: var(--hutang-tx); }
.tag-peringatan { background: var(--peringatan-bg); color: var(--peringatan-tx); }

/* Tautan isi halaman: biru, penanda "bisa diklik" paling universal. Hanya
   anchor POLOS (tanpa class/role) yang kena — semua komponen tautan (btn, tag,
   hal, tab, kartu alur) punya class dan tersaring oleh :not([class]).
   Bagian anchor dibungkus :where() supaya bobot :not()-nya nol — tanpa itu,
   a:not([class]):not([role]) = 0,2,1, lebih tinggi dari .panel-judul a (0,1,1),
   dan tautan di bar hitam sempat ikut biru 2,7:1. Tapi .konten di DEPAN :where
   (bukan di dalamnya): spesifisitas akhir 0,1,0 — cukup untuk menang atas rule
   dasar `a { color: var(--color-accent) }` di organic.css (0,0,1; kalau kalah,
   tautan tetap hitam), dan tetap kalah dari SEMUA rule komponen (>=0,1,1).
   Tabrakan dengan komponen 0,1,0 (mis. .btn) mustahil: anchor berkelas sudah
   tersaring :not([class]) sejak tahap pencocokan, sebelum spesifisitas dihitung. */
.konten :where(a:not([class]):not([role])) { color: var(--tautan); }
.konten :where(a:not([class]):not([role])):hover { color: var(--tautan-tua); }
/* Penegasan eksplisit untuk bar hitam — kini menang telak, disimpan sebagai
   dokumentasi niat sekaligus jaring kalau ada anchor polos di dalam bar. */
.konten .panel-judul a { color: var(--color-bg); }
.angka-masuk  { color: var(--masuk-tx); }
.angka-keluar { color: var(--keluar-tx); }

/* Hierarki halaman Inventory: SATU tile utama dibalik gelap (angka yang paling
   penting — nilai persediaan), sisanya tetap putih. Pola yang sama dengan
   menu aktif sidebar: isi pekat = penanda terkuat. */
.stat-utama { background: var(--color-text); }
.stat-utama .angka { color: var(--color-bg); }
.stat-utama .label, .stat-utama .rincian { color: var(--color-neutral-400); }

/* Sub-bagian di DALAM satu panel (mis. "Margin produk" di dalam panel Rincian
   produk): judul tingkat dua + garis rambut pemisah, supaya dua bagian bisa
   berbagi satu latar tanpa kehilangan strukturnya. */
.panel-sub {
  font-family: var(--font-heading); font-weight: 700; font-size: 14px;
  margin-top: var(--space-4); margin-bottom: var(--space-2);
  padding-top: var(--space-4); border-top: 1px solid var(--color-divider);
}

/* ── asal-usul baris (baris belanja ini menutup pesanan siapa) ──────────────
   Menempel pada baris di ATASNYA, jadi TAK boleh berjarak seperti baris biasa:
   padding atas dinolkan dan sebatang garis kiri menariknya masuk ke induknya.
   Tanpa itu ia terbaca sebagai baris sederajat, bukan rincian. */
.baris-berasal > td { border-bottom: 0; }
.baris-asal > td { padding-top: 0; }
.asal { border-left: 2px solid var(--color-divider); padding-left: var(--space-3); }
.asal-cap {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-600); margin-bottom: 2px;
}
/* `width: auto` DISENGAJA: tabel ini merapat ke isinya sendiri, tidak ikut
   melebar selebar tabel induk — kalau melebar, nama customer dan qty-nya
   terlempar saling berjauhan dan justru jadi lebih sulit dibandingkan. */
.asal-tabel { width: auto; border-collapse: collapse; font-size: 12px; }
.asal-tabel td { padding: 2px var(--space-3) 2px 0; vertical-align: top; }
.asal-tabel td:last-child { padding-right: 0; }

/* Tabel lebar boleh digulir mendatar sendiri, badan halaman tidak. */
.tabel-gulir { overflow-x: auto; }
/* `.table` sendiri sudah `display:block; overflow-x:auto` (organic.css) supaya
   ~90 tabel LAIN di app ini bisa gulir sendiri tanpa wadah pembungkus (lihat
   catatan keputusan "Fullwidth: ruang kanan yang terbuang"). Tapi DUA tabel
   (Daftar Tagihan, Daftar Transaksi) SUDAH dibungkus `.tabel-gulir` sejak
   sebelum aturan itu ada — dobel pembungkus gulir ini yang menyebabkan
   kolomnya berhenti mengikuti lebar kotak (kotak melebar penuh, tapi kolom di
   dalamnya cuma selebar isinya, nyisa ratusan piksel kosong DI DALAM tabel):
   `display:block` pada `<table>` melepas elemen itu dari perannya sebagai
   akar tabel, jadi browser membuat kotak tabel ANONIM baru di sekitar
   thead/tbody-nya — kotak anonim ini tidak ikut kebagian `width:100%`
   (properti itu berlaku untuk kotak block terluar, bukan kotak anonim di
   dalamnya), jadi ia menyusut mengikuti isi, bukan mengikuti kotak luarnya.
   Begitu `.table` ada di dalam `.tabel-gulir`, wadah itu SUDAH cukup untuk
   gulir mendatar — `.table`-nya sendiri dikembalikan ke tabel biasa supaya
   algoritma lebar-kolom bawaan browser jalan lagi & kolom mengisi 100%. */
.tabel-gulir .table { display: table; overflow-x: visible; }
.btn-kecil { padding: 4px var(--space-2); font-size: 12px; border-radius: 999px; }

/* Form pelunasan di atas daftar (muncul saat ?bayar=...). */
.bayar-panel { border: 1px solid var(--color-neutral-300); }
.bayar-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3); align-items: end;
}
.bayar-form .field { min-width: 0; }
.bayar-form .input:disabled { color: var(--color-neutral-600); background: var(--color-neutral-100); }
.bayar-aksi { grid-column: 1 / -1; display: flex; gap: var(--space-2); align-items: center; }

/* Penomoran halaman. */
.paginasi { display: flex; flex-wrap: wrap; gap: 4px; margin-top: var(--space-4); }
.paginasi .hal {
  min-width: 34px; height: 34px; display: inline-flex; align-items: center;
  justify-content: center; padding: 0 8px; border-radius: var(--radius-md);
  border: 1px solid var(--color-divider); text-decoration: none;
  color: var(--color-text); font-size: 14px; font-variant-numeric: tabular-nums;
}
.paginasi a.hal:hover { border-color: var(--color-neutral-500); }
.paginasi .hal-aktif { background: var(--color-text); color: var(--color-bg); border-color: var(--color-text); }
/* Elipsis penanda nomor yang dilewati — bukan tombol, jadi tanpa kotak. */
.paginasi .hal-lompat { border-color: transparent; color: var(--color-neutral-600); }

/* ── tab isi (tautan, bukan radio) ──────────────────────────────────────────
   Dipakai saat isi tiap tab punya keadaan sisi server — halaman keberapa,
   rentang tanggal mana — sehingga tab aktif WAJIB ikut tercatat di URL. Tab
   radio+CSS (.alur-*, .langsung-*) tetap dipakai untuk tab yang isinya sudah
   ada semua di halaman dan tidak punya keadaan seperti itu. */
.tab-nav {
  display: flex; flex-wrap: wrap; gap: var(--space-1);
  border-bottom: 1px solid var(--color-divider); padding-bottom: var(--space-2);
  margin-bottom: var(--space-4);
}
.tab-nav a {
  padding: var(--space-2) var(--space-3); text-decoration: none; font-size: 14px;
  font-weight: 600; color: var(--color-neutral-600); border-radius: 999px;
}
.tab-nav a:hover { color: var(--color-text); }
/* Tab aktif diisi hitam pekat — pola yang sama dipakai di seluruh app
   (sidebar-nav, alur-tombol, langsung-tombol, tag-accent) supaya posisi
   pengguna saat ini selalu konsisten terlihat, bukan cuma garis bawah tipis. */
.tab-nav a[aria-current='page'] { background: var(--color-text); color: var(--color-bg); }

/* ── Jual langsung multi-baris ──────────────────────────────────────────────
   Baris barang: barang | jumlah | satuan | harga | subtotal | hapus. Jumlah
   SEBELUM satuan (permintaan pemilik). */
.jual-baris { display: flex; flex-direction: column; gap: var(--space-2); margin: var(--space-3) 0; }
.jual-baris-kepala, .jual-baris-row {
  display: grid;
  grid-template-columns: minmax(150px, 2fr) 88px 78px 108px minmax(84px, 1fr) 30px;
  gap: var(--space-2); align-items: center;
}
.jual-baris-kepala {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--color-neutral-600);
}
.jual-baris-kepala .angka { text-align: right; }
.jbr-barang { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.jbr-subtotal { text-align: right; font-variant-numeric: tabular-nums; font-size: 14px; color: var(--color-neutral-700); }
.jbr-hapus {
  border: 0; background: none; cursor: pointer; font-size: 20px; line-height: 1;
  color: var(--color-neutral-500); padding: 0; justify-self: center;
}
.jbr-hapus:hover { color: var(--aksi-merah); }

.jual-charge { display: flex; flex-wrap: wrap; gap: var(--space-4); margin: var(--space-3) 0; align-items: center; }
.jual-charge-item { display: flex; align-items: center; gap: var(--space-2); }
.jual-charge-item .input { width: 130px; }

.jual-total {
  display: flex; gap: var(--space-6); justify-content: flex-end; align-items: baseline;
  margin: var(--space-3) 0; padding-top: var(--space-2);
  border-top: 1px solid var(--color-divider);
}
.jual-total > div { display: flex; gap: var(--space-2); align-items: baseline; }
.jual-total span { font-size: 13px; color: var(--color-neutral-600); }
.jual-total b { font-variant-numeric: tabular-nums; }
.jual-total .besar b { font-size: 20px; font-weight: 700; }

/* Layar sempit: tiap baris jadi kartu bertumpuk, bukan grid mendatar. */
@media (max-width: 680px) {
  .jual-baris-kepala { display: none; }
  .jual-baris-row {
    grid-template-columns: 1fr 1fr; gap: var(--space-2);
    border: 1px solid var(--color-divider); border-radius: var(--radius-md);
    padding: var(--space-3); position: relative;
  }
  .jbr-barang { grid-column: 1 / -1; }
  .jbr-subtotal { grid-column: 1 / -1; text-align: left; }
  .jbr-hapus { position: absolute; top: 4px; right: 8px; }
}

/* ── kartu rencana belanja (alur baru) ──────────────────────────────────────
   Satu rencana belanja = satu PENUGASAN (siapa berangkat, bawa uang berapa),
   bukan deretan sel angka. Bentuk kartu dipakai supaya penugasannya terbaca
   sebagai satu benda utuh yang bisa dipegang satu orang.

   SENGAJA BUKAN `.panel`: `.panel + .panel { margin-top: var(--panel-gap) }`
   akan menyuntik margin ke tiap kartu mulai yang kedua dan merusak grid-nya. */
.db-kartu-baris {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-3);
}
/* `auto-fill`, bukan `auto-fit`: kalau cuma ada satu rencana, `auto-fit`
   memelarkannya selebar layar dan ia berhenti terbaca sebagai kartu. */
.db-kartu {
  display: flex; flex-direction: column; gap: var(--space-3);
  background: var(--color-surface); border: 1px solid var(--color-divider);
  border-radius: calc(var(--radius-lg) * 1.15); padding: var(--space-4);
}
.db-kartu:hover { border-color: var(--color-neutral-500); box-shadow: var(--shadow-sm); }
.db-kartu-kepala {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--space-2);
}
.db-kartu-tugas { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); }
.db-kartu-cap {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-600);
}
/* `overflow-wrap` supaya rupiah panjang tak melebarkan kolom grid-nya sendiri
   dan bikin satu kartu lebih lebar dari saudaranya. */
.db-kartu-nilai { font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.db-kartu-angka { font-size: 13px; color: var(--color-neutral-600); }
/* `margin-top:auto` menempelkan tombol ke DASAR kartu, jadi deretan kartu yang
   isinya beda panjang tetap punya garis tombol yang sejajar. */
.db-kartu-aksi {
  margin-top: auto; display: flex; flex-wrap: wrap; gap: var(--space-2);
  padding-top: var(--space-2); border-top: 1px solid var(--color-divider);
}

/* ── dua kolom: pesanan menunggu | rencana yang sudah jalan ─────────────────
   Desain owner: keduanya terbaca sekali pandang, tak perlu menggulir dari satu
   ke satunya. `auto-fit` + minmax menumpuk sendiri di bawah ~800px tanpa media
   query — dan itu memang yang benar di HP, tempat purchasing berada. */
.kolom-dua {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: var(--panel-gap); align-items: start;
}
/* Anak grid tak boleh punya lebar bawaan sebesar isinya, kalau tidak tabel
   panjang di kolom kiri melebarkan kolomnya dan kolom kanan terdesak habis. */
.kolom-dua > * { min-width: 0; }

/* ── kartu pesanan siap dibelanjakan ────────────────────────────────────────
   Menggantikan tabel 7 kolom yang, diukur di kolom setengah lebar (538px),
   memaksa baris setinggi 84px karena isinya membungkus tiga baris. Kartu
   memakai ruang sempit dengan menumpuk ke bawah, bukan memerasnya ke samping. */
.po-kartu-baris { display: flex; flex-direction: column; gap: var(--space-2); }
.po-kartu {
  display: flex; align-items: flex-start; gap: var(--space-2);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
  padding: var(--space-3);
}
/* Dicentang = ditandai jelas, bukan cuma kotak kecil yang berubah. Waktu
   mencentang 5 dari 12 pesanan, yang perlu terbaca sekilas adalah MANA saja
   yang sudah masuk — bukan harus memeriksa 12 kotak satu per satu. */
.po-kartu:has(input:checked) {
  border-color: var(--color-text);
  background: color-mix(in srgb, var(--color-text) 4%, transparent);
}
/* Seluruh kartu jadi sasaran klik — tak perlu mengenai kotak 17px. */
.po-kartu-pilih {
  flex: 1; min-width: 0; display: flex; align-items: flex-start;
  gap: var(--space-2); cursor: pointer;
}
.po-kartu-pilih input { margin-top: 3px; flex: none; }
.po-kartu-isi { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.po-kartu-kepala { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.po-kartu-cust { font-size: 14px; }
.po-kartu-ket { font-size: 12px; color: var(--color-neutral-600); }
.pilih-semua {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: 12px; color: var(--color-neutral-600); margin-bottom: var(--space-2);
}

/* ── seret pesanan ke kartu rencana ─────────────────────────────────────────
   Kelas `bisa-seret` dipasang seret.js SESUDAH ia benar-benar aktif. Petunjuk
   "bisa diseret" karena itu tak pernah muncul kalau skripnya gagal dimuat,
   tak ada sasaran, atau penggunanya tak berhak ubah — mengiklankan gerakan
   yang ternyata tak melakukan apa-apa lebih buruk daripada tak mengiklankannya. */
.bisa-seret .po-kartu { cursor: grab; }
.bisa-seret .po-kartu:active { cursor: grabbing; }
.po-kartu-terseret { opacity: 0.45; }
/* Sasaran menyala hanya saat ada yang benar-benar melayang di atasnya —
   garis putus menandakan "lepas di sini", beda tegas dari garis solid kartu
   biasa supaya tak tertukar dengan keadaan terpilih. */
.db-kartu-siap {
  border-style: dashed; border-color: var(--color-text);
  background: color-mix(in srgb, var(--color-text) 5%, transparent);
}

/* ── popup rincian rencana ──────────────────────────────────────────────────
   Dipakai saat "Buat Daftar Belanja" ditekan: isian nama/purchasing/budget
   muncul di tempat, bukan di halaman berikutnya. Lompatan halaman itu yang
   bikin bingung — di halaman baru orang baru sadar masih ada yang harus diisi. */
.popup {
  border: 1px solid var(--color-text); border-radius: var(--radius-lg);
  padding: 0; max-width: min(560px, calc(100vw - 2 * var(--space-4)));
  background: var(--color-bg); color: var(--color-text);
}
.popup::backdrop { background: color-mix(in srgb, #000000 38%, transparent); }
.popup-isi { padding: var(--panel-pad); }
.rencana-isian-judul {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; margin-bottom: var(--space-3);
}
/* Tombol didorong ke kanan & diberi garis pemisah: baris keputusan, bukan
   bagian dari isian di atasnya. */
.popup-aksi {
  display: flex; justify-content: flex-end; gap: var(--space-2);
  margin-top: var(--space-4); padding-top: var(--space-3);
  border-top: 1px solid var(--color-divider);
}
/* Versi TANPA JS: isian tampil sebaris di halaman, jadi ia butuh bingkainya
   sendiri supaya tak melayang tanpa batas di antara bilah aksi dan daftar. */
.rencana-isian:not(.popup .rencana-isian) {
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
  padding: var(--space-4); margin-bottom: var(--space-4);
}
