/* 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(--space-4);
}
.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(--space-4); }
.panel + .panel { margin-top: var(--space-4); }
/* 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(--space-4) * -1) calc(var(--space-4) * -1) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: calc(var(--radius-lg) * 1.15) calc(var(--radius-lg) * 1.15) 0 0;
}
/* 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. */
.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: 1 1 auto; cursor: pointer; border-radius: var(--radius-md);
  border: 1px solid var(--color-divider); background: var(--color-surface);
  padding: var(--space-3); display: flex; align-items: center; gap: var(--space-2);
  min-width: 120px;
}
.alur-tombol .ikon { width: 18px; height: 18px; flex: none; }
.alur-nomor {
  flex: none; width: 22px; height: 22px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-neutral-200); color: var(--color-neutral-700);
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.alur-nama { font-weight: 600; font-size: 14px; }
.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); }
.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); }
.alur-panah { flex: none; display: inline-flex; color: var(--color-neutral-500); }
.alur-panah .ikon { width: 18px; height: 18px; }

.alur-isi { flex-basis: 100%; margin-top: var(--space-4); }
/* Kunci tetap: pesanan/belanja/penerimaan/stok/mitra. 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-stok:checked       ~ .alur-isi [data-panel='stok'],
#alur-mitra:checked      ~ .alur-isi [data-panel='mitra'] { display: block; }

.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: cincin gelap monokrom (bahasa
   visual yang sama dengan tab aktif yang terisi penuh), supaya "kamu di sini"
   terbaca tanpa warna. */
.alur-tujuan-kini {
  border-color: var(--color-text);
  box-shadow: inset 0 0 0 1px var(--color-text);
}
.alur-tujuan-kini .alur-tujuan-panah { color: var(--color-text); }

/* 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. */
.alur-sisip {
  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; }
  .alur-tombol { flex-basis: 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(--space-4);
}
.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(--space-4) * -1) calc(var(--space-4) * -1) var(--space-4);
  padding: var(--space-3) var(--space-4);
  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);
}

/* 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); 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);
  /* Garis bawah setebal penandanya sudah disiapkan sejak awal (transparan),
     supaya teksnya tidak bergeser 2px saat tab jadi aktif. */
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tab-nav a:hover { color: var(--color-text); }
.tab-nav a[aria-current='page'] {
  color: var(--color-text); border-bottom-color: var(--color-text);
}

/* ── 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; }
}
