/* ══ huruf (self-hosted, satu origin — app tidak menembak layanan luar) ══
   Semuanya sudah di-subset: latin + aksen umum + tanda tipografi & mata uang,
   hinting dibuang, variable font dipangkas ke sumbu wght yang benar-benar
   dipakai. Nama family sengaja dikarang ("TP …") supaya tidak bergantung pada
   nama internal di dalam berkas. */
@font-face { font-family: "TP Nunito";  src: url(/fonts/nunito-var.woff2) format("woff2");
             font-weight: 400 700; font-style: normal; font-display: swap; }
@font-face { font-family: "TP Baloo";   src: url(/fonts/baloo2-700.woff2) format("woff2");
             font-weight: 700; font-style: normal; font-display: swap; }

/* ─────────────────────────────────────────────────────────────────────────
   TokoPintar — lapisan tampilan admin.

   Sistem desain: TokoPintar Clay (claymorphism di atas palette-v2).
   Palet: color-palette-v2.md ("Hijau Cuan"), tanpa satu hex baru pun
   kecuali tiga warna kaki ekstrusi.

   Amandemen palette-v2 §4 — larangan drop shadow DIBUKA, dengan pagar:
   · Bayangan selalu netral hijau-tinta rgba(6,32,24,α). Merah & kuning
     boleh memakai kanal keluarganya sendiri. Tidak ada warna lain.
   · Gradien dan glow tetap dilarang — permukaan clay selalu satu warna rata.

   Aturan lain yang dipegang di seluruh berkas ini:
   · Hex hanya ada di :root. Komponen selalu lewat token.
   · Hijau tua satu-satunya warna bidang lebar (topbar, tombol utama).
   · Kuning & merah tidak pernah jadi bidang lebar — badge, angka, banner
     tipis, tombol kecil saja.
   · Warna tidak pernah jadi satu-satunya pembawa arti; selalu ada teksnya.

   Empat resep clay, dan cuma empat. Kalau sebuah elemen tidak cocok dengan
   salah satunya, elemen itu yang salah — bukan resepnya yang ditambah.
   · timbul    → bisa ditekan / mengambang: kartu, panel, popover
   · kaki      → tombol dan chip; kaki solid = tinggi tombol
   · tenggelam → bisa diisi / sedang terpilih: input, select, nav aktif
   · kancing   → badge & lencana; kaki pendek dalam warna keluarganya
   Timbul = bisa ditekan, tenggelam = bisa diisi. Jangan dibalik.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  /* brand */
  --color-brand: #0B3D2E;
  --color-brand-hover: #0E4A38;
  --color-brand-soft: #E1F0E8;
  --color-brand-text: #085041;
  --color-brand-sub: #9FE1CB;      /* subjudul di atas bidang brand */

  /* aksen */
  --color-accent: #C6F432;
  --color-accent-hover: #B8E82A;
  --color-accent-text: #2A3D05;

  /* netral */
  --color-ink: #062018;
  --color-ink-secondary: #4A6B45;
  --color-ink-muted: #7E967A;
  --color-bg: #F4FBEA;
  --color-surface: #FFFFFF;
  --color-border: #DCE8D2;

  /* semantik */
  --color-warning: #FFC933;
  --color-warning-bg: #FFF6DC;
  --color-warning-text: #8A5F00;
  --color-warning-strong: #A87400;
  --color-danger: #DE3B3B;
  --color-danger-hover: #C93030;
  --color-danger-bg: #FDECEC;
  --color-danger-text: #9C1F1F;
  --color-success: #2E9E5B;
  --color-success-bg: #DFF5E6;
  --color-success-text: #116B33;

  /* tipografi
     Nunito untuk badan, Baloo 2 untuk judul & angka besar. Dipilih setelah
     dibandingkan berdampingan dengan Fredoka + DM Sans di layar sungguhan:
     Nunito membawa kesan clay ikut ke badan teks (di mana 90% piksel berada),
     sementara DM Sans netral sehingga clay-nya berhenti di judul saja; dan
     angka Baloo lebih lebar & terbuka daripada Fredoka, yang penting karena
     hampir setiap layar di sini penuh deret rupiah panjang.
     ui-rounded tetap disimpan sebagai cadangan: kalau woff2 gagal termuat,
     iOS/macOS masih dapat huruf membulat, sisanya jatuh ke sans sistem. */
  --font: "TP Nunito", ui-rounded, "SF Pro Rounded", -apple-system,
          BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-judul: "TP Baloo", var(--font);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* warna kaki ekstrusi — HANYA untuk box-shadow, tidak pernah jadi latar.
     Turunan gelap dari brand/lime/merah, bukan keluarga warna baru. */
  --kaki-brand: #04150F;
  --kaki-accent: #8FB81E;
  --kaki-danger: #7D1919;
  --kaki-netral: rgba(6, 32, 24, 0.12);

  /* bentuk & ukuran */
  --r-shell: 32px;   /* panel besar & rel nav */
  --r: 24px;         /* kartu & ubin */
  --r-kecil: 18px;   /* tombol, input, select */
  --r-nav: 16px;     /* item nav */
  --r-ikon: 12px;    /* ikon clay 26–34px */
  --r-pil: 999px;    /* badge, chip, stepper, tombol halaman publik */
  --sisi: 244px;
  --atas: 62px;
  --bar: 70px;

  /* --color-border (1.27:1 di atas putih) cuma boleh jadi garis pemisah.
     Kontrol yang harus dikenali sebagai kontrol — input, tombol sekunder —
     pakai border yang lolos 3:1 (WCAG 1.4.11). */
  --garis-kontrol: var(--color-ink-muted);

  /* ── empat resep clay ──
     Kaki tombol dibatasi 7px (maks. 10 menurut sistem desain): di HP kelas
     bawah kaki tebal terbaca sebagai dua elemen bertumpuk, bukan satu tombol
     yang timbul. Karena kaki dibuat dari box-shadow ia tidak makan ruang
     layout, jadi setiap elemen berkaki menambah margin-bawah setinggi kakinya
     sendiri — tanpa itu kaki menimpa apa pun yang ada di bawahnya. */
  --kaki-tinggi: 7px;

  /* Lapisan yang BUKAN kaki dipisah jadi tokennya sendiri. Alasannya bukan
     gaya: var() di dalam custom property diselesaikan di elemen tempat
     property itu dideklarasikan, jadi resep utuh yang menyebut var(--kaki)
     di :root akan selamanya memakai nilai --kaki milik :root — knob per
     komponen tidak akan pernah terbaca (diuji di browser, bukan dikira).
     Karena itu baris kakinya ditulis di komponen, sisanya diwarisi. */
  --clay-timbul:
    0 20px 34px -18px rgba(6, 32, 24, 0.30),
    inset 0 6px 0 rgba(255, 255, 255, 0.95),
    inset 0 -9px 0 rgba(6, 32, 24, 0.06);
  /* Versi pendek untuk kartu yang berjajar rapat: jatuh bayangan 20px
     membuat tiga kartu bersebelahan saling menggelapkan tetangganya. */
  --clay-timbul-kecil:
    0 14px 26px -14px rgba(6, 32, 24, 0.26),
    inset 0 4px 0 rgba(255, 255, 255, 0.90),
    inset 0 -6px 0 rgba(6, 32, 24, 0.05);
  /* dipakai sebagai: box-shadow: 0 var(--kaki-tinggi) 0 «kaki», var(--clay-kaki); */
  --clay-kaki:
    0 16px 24px -12px rgba(6, 32, 24, 0.55),
    inset 0 3px 0 rgba(255, 255, 255, 0.16);
  /* Ditekan: kaki menyusut 4px dan tombolnya turun 4px, jadi tinggi
     totalnya tetap — yang berubah cuma jarak tombol ke lantainya. */
  --clay-kaki-tekan:
    0 8px 14px -10px rgba(6, 32, 24, 0.55),
    inset 0 3px 0 rgba(255, 255, 255, 0.16);
  /* dipakai sebagai: box-shadow: var(--clay-tenggelam), inset 0 0 0 1px «cincin»;
     Kontrol interaktif memakai --garis-kontrol (3,04:1 di atas --color-bg,
     diukur) karena WCAG 1.4.11 tetap berlaku di bawah bayangan; permukaan
     tenggelam yang bukan kontrol boleh memakai --color-border yang lembut. */
  --clay-tenggelam:
    inset 0 6px 12px -3px rgba(6, 32, 24, 0.20),
    inset 0 -3px 0 rgba(255, 255, 255, 0.95);
  --clay-tenggelam-kecil:
    inset 0 4px 8px -2px rgba(6, 32, 24, 0.18),
    inset 0 -3px 0 rgba(255, 255, 255, 0.85);
  /* dipakai sebagai: box-shadow: 0 5px 0 «kaki», var(--clay-kancing); */
  --clay-kancing: inset 0 3px 0 rgba(255, 255, 255, 0.90);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Desain ini hanya punya satu tema. Menyatakannya bikin kontrol bawaan
     (scrollbar, pemilih tanggal, caret) ikut dirender terang — tanpa ini,
     browser bertema gelap menggambar date picker gelap di dalam kartu putih. */
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font: 15.5px/1.6 var(--font);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  /* Menahan gulir supaya tidak merembet ke chrome browser saat daftar panjang
     sudah mentok — di HP itu yang memicu pull-to-refresh tak sengaja waktu
     pengguna menggulir cepat di layar Barang atau Order. */
  overscroll-behavior-y: contain;
}

/* Semua yang bisa disentuh: hilangkan jeda 300ms double-tap-zoom, dan matikan
   kotak abu-abu bawaan Android saat ditekan. Keadaan tertekan tidak hilang —
   resep clay sudah punya :active sendiri (batang turun 4px, kaki memendek),
   yang lebih terbaca daripada kilatan abu-abu. */
a, button, input, select, textarea, label, [role="button"], [role="option"], summary {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* Topbar itu sticky setinggi --atas. Tanpa ini, apa pun yang digulir ke sebuah
   anchor (atau difokus keyboard dari bawah layar) mendarat persis di bawahnya
   dan tertutup. 14px tambahan menyamai jarak kartu ke topbar. */
:target, [id] { scroll-margin-top: calc(var(--atas) + 14px); }

/* Judul clay: lebih tebal, lebih rapat, dan line-height-nya sendiri.
   Bobot 700 di seluruh judul adalah pengganti "bentuk membulat" untuk platform
   yang fontnya tidak membulat — massa hurufnya yang membawa kesan tebal-lembut,
   bukan terminalnya. */
h1, h2, h3 {
  margin: 0;
  font-family: var(--font-judul);
  font-weight: 700;
  line-height: 1.25;
  /* Judul dua baris tidak boleh menyisakan satu kata sendirian di baris kedua.
     Nama toko di sapaan Ringkasan ("Siang, Toko Berkah Jaya") paling sering
     kena, dan di 360px ia memang membungkus. */
  text-wrap: balance;
}
h1 { font-size: 30px; letter-spacing: -0.03em; }
h2 { font-size: 19px; letter-spacing: -0.02em; }
h3 { font-size: 16px; letter-spacing: -0.015em; }
p { margin: 0 0 10px; }
p:last-child { margin-bottom: 0; }
a { color: var(--color-brand-text); }
hr { border: 0; border-top: 1px solid var(--color-border); margin: 14px 0; }
code { font-family: var(--font-mono); font-size: 0.9em; }

:where(a, button, input, select, textarea, [tabindex], summary):focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
  border-radius: var(--r-kecil);
}
/* Permukaan tenggelam memakai offset negatif: cincin fokus di luar kotak akan
   melayang di atas bayangan-dalam dan terbaca seperti elemen ketiga. */
:where(input, select, textarea):focus-visible { outline-offset: -1px; }

/* Tautan lewati: tersembunyi sampai difokus keyboard, lalu muncul sebagai pil
   clay di pojok kiri atas. Tidak memakai .sr karena ia harus BISA kelihatan —
   .sr memakai clip-path yang menyembunyikannya bahkan saat fokus. */
.lewati {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 100;
  transform: translateY(-160%);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 10px 18px;
  border-radius: var(--r-kecil);
  background: var(--color-brand);
  color: var(--color-accent);
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 6px 0 var(--kaki-brand), var(--clay-kaki);
}
/* :focus, bukan :focus-visible. Tautan ini cuma bisa dicapai lewat keyboard,
   dan :focus-visible bergantung pada heuristik browser yang tidak selalu cocok
   — diukur: fokus terpasang tapi tautannya tetap di luar layar. */
.lewati:focus { transform: translateY(0); }

.sr {
  position: absolute;
  width: 1px; height: 1px;
  /* min-height aturan input global menang atas height:1px, jadi radio tersembunyi
     terukur 1x52 dan ikut terhitung sebagai target sentuh palsu. Nolkan. */
  min-height: 0;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ───────────────────────────────────────────────────────────── kerangka */

.app {
  display: grid;
  grid-template-columns: var(--sisi) 1fr;
  grid-template-rows: var(--atas) 1fr;
  grid-template-areas: "atas atas" "sisi utama";
  min-height: 100dvh;
}

/* Satu-satunya bidang lebar berwarna di seluruh aplikasi. */
.topbar {
  grid-area: atas;
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  background: var(--color-brand);
  color: #fff;
  /* Bibir bawah gelap + sorotan atas: topbar jadi balok clay yang menekan
     halaman, bukan pita datar yang ditempel di atasnya. */
  box-shadow:
    inset 0 -7px 0 rgba(4, 21, 15, 0.5),
    inset 0 4px 0 rgba(255, 255, 255, 0.09);
}

.merek {
  display: flex;
  align-items: center;
  /* 44px, bukan setinggi isinya: WCAG 2.5.8 cuma minta 24px dan mark 34px
     sudah lolos, tapi palet proyek ini menetapkan 44x44 untuk semua yang
     bisa ditekan — dan tautan ini pulang ke Ringkasan. */
  min-height: 44px;
  gap: 10px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: #fff;
  text-decoration: none;
}
/* 28px, bukan 22 seperti kotak "TP" yang digantikannya: mark-nya warung
   lengkap dengan tenda dan etalase, dan di bawah 28px detail itu jadi bubur —
   diuji berjajar di 22/24/28/32/36/44. Latarnya sewarna topbar, jadi yang
   terlihat cuma siluet limenya; radius tidak perlu di sini. */
.merek img {
  width: 34px; height: 34px;
  flex: none;
  border-radius: 11px;
  /* Mark-nya duduk di atas hijau yang sama, jadi tanpa bayangan ia menyatu
     dengan topbar. Kanal 0,0,0 di sini, bukan 6,32,24: latarnya sudah hijau
     tua — bayangan hijau di atas hijau tidak kelihatan sama sekali. */
  box-shadow: 0 5px 10px -4px rgba(0, 0, 0, 0.6), inset 0 2px 0 rgba(255, 255, 255, 0.2);
}
/* Cadangan kalau aset merek gagal dimuat: kotak lime bertuliskan TP. */
.merek i {
  width: 26px; height: 26px;
  flex: none;
  border-radius: 9px;
  background: var(--color-accent);
  color: var(--color-accent-text);
  display: grid;
  place-items: center;
  font: 800 11px/1 var(--font);
  font-style: normal;
  letter-spacing: 0.01em;
}
.topbar .kanan {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13.5px;
  color: var(--color-brand-sub);
  min-width: 0;
}
.topbar .kanan span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar .kanan a {
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  padding: 0 14px;
  border-radius: 12px;
  white-space: nowrap;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  background: var(--color-brand-hover);
  /* Kaki 4px, bukan 7: tombol ini duduk di dalam topbar setinggi 62px, dan
     kaki penuh membuatnya menyentuh bibir bawah topbar. */
  box-shadow: 0 4px 0 rgba(4, 21, 15, 0.55), inset 0 2px 0 rgba(255, 255, 255, 0.12);
  margin-bottom: 4px;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.topbar .kanan a:hover { background: #12563F; }
.topbar .kanan a:active {
  transform: translateY(2px);
  box-shadow: 0 2px 0 rgba(4, 21, 15, 0.55), inset 0 2px 0 rgba(255, 255, 255, 0.12);
}
.topbar :focus-visible { outline-color: var(--color-accent); }

/* ─────────────────────────────────────────────────────────────── navigasi */

.sisi {
  grid-area: sisi;
  background: var(--color-surface);
  /* Bayangan-dalam di tepi kanan menggantikan border: sidebar jadi permukaan
     yang lebih tinggi dari isi, bukan dua bidang yang dipisah garis. */
  box-shadow: inset -6px 0 12px -8px rgba(6, 32, 24, 0.16);
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: sticky;
  top: var(--atas);
  align-self: stretch;
  height: calc(100dvh - var(--atas));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sisi a {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 50px;
  padding: 0 12px;
  border-radius: var(--r-nav);
  color: var(--color-ink-secondary);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
}
.sisi a .tl {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Ikon clay dipasang sebagai <img>; ukurannya dikunci di sini juga supaya
   satu berkas yang rasionya meleset tidak menggeser barisnya. */
.sisi a svg, .sisi .lain svg { flex: none; }
/* Ikon clay diberi radius + bayangan sendiri supaya ikut terbaca sebagai
   objek 3D kecil, bukan stiker datar yang ditempel di baris. */
.sisi .ikon {
  flex: none;
  width: 30px; height: 30px;
  object-fit: contain;
  border-radius: 10px;
  box-shadow: 0 4px 8px -3px rgba(6, 32, 24, 0.35);
}
.sisi a:hover { background: var(--color-bg); color: var(--color-ink); }
/* Nav aktif di sidebar putih TENGGELAM, bukan timbul — ia sedang terpilih,
   bukan sedang menunggu ditekan. Aturan yang sama dipakai di bar bawah HP,
   yang latarnya juga putih. */
.sisi a[aria-current="page"] {
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  font-weight: 700;
  box-shadow: var(--clay-tenggelam-kecil);
}
.sisi a[aria-current="page"] .ikon { box-shadow: 0 4px 8px -3px rgba(6, 32, 24, 0.5); }

/* Lencana tenggelam, bukan berkaki: ia menempel di dalam baris nav, dan
   kancing berkaki di dalam permukaan yang juga tenggelam terbaca kacau. */
.lencana {
  flex: none;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: var(--r-pil);
  background: var(--color-danger-bg);
  color: var(--color-danger-text);
  font-size: 12px;
  font-weight: 700;
  display: inline-grid;
  place-items: center;
  box-shadow:
    inset 0 3px 5px -2px rgba(156, 31, 31, 0.35),
    inset 0 -2px 0 rgba(255, 255, 255, 0.8);
}

/* Tombol + sheet "Lainnya". Hanya hidup di bar bawah HP; di layar lebar
   kesembilan tautan muat semua, jadi tombolnya tidak dirender secara visual.
   Sheet-nya popover bawaan browser — tutup-saat-klik-di-luar dan Esc datang
   gratis, tanpa satu baris JS pun. */
.sisi .lain {
  display: none;
  align-items: center;
  border: 0;
  background: transparent;
  border-radius: var(--r-nav);
  color: var(--color-ink-secondary);
  font-family: inherit;
  cursor: pointer;
}
.sisi .lain:hover { background: var(--color-bg); }
.sisi .lain[aria-current="page"] {
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  font-weight: 700;
  box-shadow: var(--clay-tenggelam-kecil);
}

#menu-lain {
  position: fixed;
  inset: auto 10px calc(var(--bar) + 10px + env(safe-area-inset-bottom)) auto;
  margin: 0;
  width: min(272px, calc(100vw - 20px));
  padding: 10px;
  border: 0;
  border-radius: var(--r-shell);
  background: var(--color-surface);
  box-shadow: var(--clay-timbul), 0 26px 50px -26px rgba(6, 32, 24, 0.45);
}
#menu-lain::backdrop { background: rgba(6, 32, 24, 0.28); }
#menu-lain a {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 50px;
  padding: 0 12px;
  border-radius: var(--r-nav);
  color: var(--color-ink);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
}
#menu-lain a .tl { flex: 1; min-width: 0; }
#menu-lain a:hover { background: var(--color-bg); }
#menu-lain a[aria-current="page"] {
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  font-weight: 700;
  box-shadow: var(--clay-tenggelam-kecil);
}

/* Hanya tampil di layar lebar. */
.hanya-lebar { display: inline; }

/* ──────────────────────────────────────────────────────────────── isi */

.utama {
  grid-area: utama;
  min-width: 0;
  padding: 22px 24px 40px;
  max-width: 1180px;
  width: 100%;
}
.utama:focus { outline: none; }

.judul {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.judul .ket {
  color: var(--color-ink-secondary);
  font-size: 14px;
  margin-top: 4px;
}
/* Blok tombol di kanan judul. :not(:first-child) penting — layar yang judulnya
   tanpa tombol hanya punya satu div, dan tanpa penjaga ini judul + keterangannya
   ikut ditata berdampingan. */
.judul > div:last-child:not(:first-child) { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-start; }

/* Resep 1 — timbul. Tiga lapis: jatuh bayangan, sorotan tepi atas, bibir
   bawah. Cincin 1px terakhir bukan hiasan: di layar HP murah dengan
   brightness rendah, jatuh bayangan -14px nyaris tidak terlihat dan kartu
   putih di atas latar #F4FBEA kehilangan tepinya sama sekali. */
.kartu {
  background: var(--color-surface);
  border: 0;
  border-radius: var(--r);
  padding: 20px 22px;
  margin-bottom: 16px;
  box-shadow: var(--clay-timbul-kecil), inset 0 0 0 1px rgba(6, 32, 24, 0.05);
}
.kartu:last-child { margin-bottom: 0; }
.kartu > h2:first-child, .kartu > h3:first-child { margin-bottom: 14px; }

.kepala {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}

.jajar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
}
.jajar > .kartu { margin-bottom: 0; }

/* ──────────────────────────────────────────────────────────────── teks */

.label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-ink-secondary);
}
/* Angka adalah "objek" terbesar di layar ini, jadi ia yang paling terasa clay:
   36px bobot 700, tracking rapat, line-height pendek — satu blok padat. */
.angka-besar {
  font-family: var(--font-judul);
  display: block;
  font-size: 36px;
  font-weight: 700;
  letter-spacing: -0.035em;
  margin: 9px 0 4px;
  line-height: 1.1;
}
.kecil { font-size: 13.5px; }
.mini { font-size: 12px; }
.redup { color: var(--color-ink-secondary); }
.tebal { font-weight: 700; }
.num { font-variant-numeric: tabular-nums; }
.r { text-align: right; }

/* Angka arah. Lime dipakai sebagai identitas "cuan" di badge, tapi tidak
   pernah sebagai teks — di atas putih kontrasnya jauh di bawah AA. Teks
   positif memakai hijau brand. */
.naik { color: var(--color-brand-text); }
/* Semua teks merah memakai danger-text (7,99:1), termasuk angka besar.
   --color-danger (#DE3B3B) hanya 4,38:1 di atas putih — lolos untuk teks
   besar 24px+, tapi .angka-besar turun jadi 21px di HP dan langsung jatuh
   di bawah AA. Satu warna untuk semua ukuran lebih aman daripada aturan yang
   benar hanya di satu breakpoint. */
.turun { color: var(--color-danger-text); }

/* ───────────────────────────────────────────────────────────── tombol */

/* Resep 2 — berkaki. Kaki solid ikut jadi tinggi tombol, jadi min-height 52px
   di sini terbaca 59px; itu yang membuat sistem desain menaikkan tombol utama
   ke 52–62px. Kakinya box-shadow (tidak makan ruang layout), jadi
   margin-bottom setinggi kaki wajib — tanpa itu kaki menimpa elemen di
   bawahnya. */
.tbl {
  --kaki: var(--kaki-brand);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 52px;
  padding: 10px 22px;
  border: 0;
  border-radius: var(--r-kecil);
  background: var(--color-brand);
  color: var(--color-accent);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.005em;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 var(--kaki-tinggi) 0 var(--kaki), var(--clay-kaki);
  margin-bottom: var(--kaki-tinggi);
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.tbl:hover { background: var(--color-brand-hover); }
.tbl:active { transform: translateY(4px); box-shadow: 0 3px 0 var(--kaki), var(--clay-kaki-tekan); }
/* Nonaktif tenggelam: tidak ada yang bisa ditekan, jadi tidak ada kaki.
   Kontras teks di sini boleh di bawah AA — WCAG 1.4.3 mengecualikan komponen
   nonaktif, dan menaikkannya justru membuat tombol mati terlihat hidup. */
.tbl:disabled, .tbl[disabled] {
  background: var(--color-bg);
  color: var(--color-ink-muted);
  cursor: not-allowed;
  box-shadow: var(--clay-tenggelam), inset 0 0 0 1px var(--color-border);
  transform: none;
  margin-bottom: var(--kaki-tinggi);
}

.tbl.kedua {
  --kaki: var(--kaki-netral);
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow:
    0 var(--kaki-tinggi) 0 var(--kaki),
    0 14px 20px -12px rgba(6, 32, 24, 0.35),
    inset 0 3px 0 #fff,
    /* Cincin kontrol 3:1 tetap ada di bawah bayangan (WCAG 1.4.11): tombol
       putih di atas kartu putih tidak boleh cuma dibedakan oleh bayangan. */
    inset 0 0 0 1px var(--garis-kontrol);
}
.tbl.kedua:hover { background: var(--color-brand-soft); }
.tbl.kedua:active {
  transform: translateY(4px);
  box-shadow:
    0 3px 0 var(--kaki),
    0 8px 12px -10px rgba(6, 32, 24, 0.35),
    inset 0 3px 0 #fff,
    inset 0 0 0 1px var(--garis-kontrol);
}

/* Hantu = kancing lebar: kaki pendek, tanpa jatuh bayangan. Dipakai untuk
   aksi tersier yang tidak boleh bersaing dengan tombol brand. */
.tbl.hantu {
  --kaki: rgba(6, 32, 24, 0.1);
  min-height: 44px;
  padding: 0 16px;
  border-radius: 14px;
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  font-size: 13.5px;
  box-shadow: 0 5px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.9);
  margin-bottom: 5px;
}
.tbl.hantu:hover { background: #D3E8DD; }
.tbl.hantu:active { transform: translateY(3px); box-shadow: 0 2px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.9); }

/* Merah hanya untuk tombol kecil. Tidak pernah selebar layar.
   Latarnya --color-danger-hover, bukan --color-danger: putih di atas #DE3B3B
   diukur 4,38:1 — di bawah AA untuk teks 14px. #C93030 memberi 5,32:1 dan
   masih terbaca merah. Ini penyimpangan sadar dari tabel di color-palette-v2.md
   yang mengklaim pasangan itu lolos AA; angkanya bilang lain. */
.tbl.bahaya {
  --kaki: var(--kaki-danger);
  min-height: 44px;
  padding: 0 18px;
  border-radius: 16px;
  background: var(--color-danger-hover);
  color: #fff;
  font-size: 14px;
  /* Kanal merah, bukan hijau-tinta: sistem desain mengizinkan bayangan memakai
     warna keluarganya sendiri untuk merah & kuning. */
  box-shadow:
    0 6px 0 var(--kaki),
    0 12px 18px -10px rgba(156, 31, 31, 0.6),
    inset 0 3px 0 rgba(255, 255, 255, 0.22);
  margin-bottom: 6px;
}
.tbl.bahaya:hover { background: var(--color-danger-text); }
.tbl.bahaya:active {
  transform: translateY(3px);
  box-shadow: 0 3px 0 var(--kaki), 0 7px 11px -9px rgba(156, 31, 31, 0.6), inset 0 3px 0 rgba(255, 255, 255, 0.22);
}
.tbl.hantu.bahaya {
  --kaki: rgba(156, 31, 31, 0.22);
  background: var(--color-danger-bg);
  color: var(--color-danger-text);
  box-shadow: 0 5px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.9);
  margin-bottom: 5px;
}
.tbl.hantu.bahaya:hover { background: #FADFDF; }

.tbl.penuh { display: flex; width: 100%; }
.tbl.kcl {
  min-height: 44px;
  padding: 0 16px;
  border-radius: 16px;
  font-size: 13.5px;
}

/* Resep 2 juga — chip saring. Yang aktif memakai brand penuh, bukan tint:
   di sistem clay chip adalah keluarga tersendiri, bukan tombol, jadi aturan
   "maks. 1 tombol brand per layar" tidak terlanggar. */
.chip {
  --kaki: var(--kaki-netral);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 18px;
  border-radius: var(--r-pil);
  border: 0;
  background: var(--color-surface);
  color: var(--color-ink);
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 6px 0 var(--kaki), inset 0 3px 0 #fff, inset 0 0 0 1px var(--garis-kontrol);
  margin-bottom: 6px;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.chip:hover { background: var(--color-bg); }
.chip:active { transform: translateY(3px); box-shadow: 0 3px 0 var(--kaki), inset 0 3px 0 #fff, inset 0 0 0 1px var(--garis-kontrol); }
.chip[aria-current="true"] {
  --kaki: var(--kaki-brand);
  background: var(--color-brand);
  color: var(--color-accent);
  box-shadow: 0 6px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.16);
}
.chip[aria-current="true"]:hover { background: var(--color-brand-hover); }
.chip[aria-current="true"]:active { box-shadow: 0 3px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.16); }
.deret { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }

/* ─────────────────────────────────────────────────────────────── grafik */

/* Batang pil, tanpa sumbu dan tanpa garis bantu.
   Membulat di kedua ujung supaya batang terbaca sebagai objek utuh, bukan
   kolom yang dipotong garis dasar — begitu ujung bawahnya ikut membulat,
   garis sumbu jadi mubazir dan bisa dihapus. Nilainya tidak dicetak di
   grafik: yang dibaca dari sini adalah bentuk (hari mana ramai), bukan
   angka. Angka pastinya ada di tooltip, di tabel Laba rugi, dan di CSV. */
.grafik { margin-top: 14px; }
.grafik .plot,
.grafik .sumbu {
  display: flex;
  gap: 4px;
  justify-content: space-between;
  align-items: flex-end;
}
.grafik .plot { height: 148px; }
.grafik .kol {
  flex: 1 1 0;
  min-width: 4px;
  max-width: 22px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
}
.grafik .btg {
  border-radius: var(--r-pil);
  background: var(--color-ink-muted);
  /* Hari yang omzetnya nyaris nol tetap harus terlihat sebagai titik.
     Tanpa ini batangnya menghilang dan hari itu terbaca seperti tidak ada
     datanya sama sekali — padahal ada, cuma kecil. */
  min-height: 5px;
  /* Batangnya jadi wadah dua deret bertumpuk: modal di bawah, laba di atas,
     dan jumlahnya persis omzet. overflow disembunyikan supaya kedua segmen
     ikut terpotong radius pil — kalau tidak, sudut segmen menyembul keluar
     dari ujung batang. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.grafik .btg i { display: block; width: 100%; flex: none; }
.grafik .btg .laba { background: var(--color-brand); }
.grafik .btg .modal { background: var(--color-ink-muted); }
/* Sorotan tipis di puncak batang — sama seperti tepi atas kartu, jadi
   batangnya terbaca sebagai pil clay, bukan bidang warna rata. Dipasang di
   segmen teratas, bukan di .btg: inset shadow milik induk tergambar di bawah
   anak-anaknya, jadi kalau ditaruh di .btg ia tertutup segmen dan hilang. */
.grafik .btg i:first-child { box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.16); }
.grafik .sumbu {
  margin-top: 10px;
  align-items: start;
}
/* Label melimpah keluar kotaknya dengan sengaja: slot label selebar batang
   (maks 22px) sedangkan "21/8" butuh ~26px. Karena label hanya dicetak tiap
   n hari (lihat laporan.js), limpahannya tidak pernah bertabrakan. */
/* Slot label selebar batangnya (4–22px), teksnya dipusatkan di atas slot itu
   lewat posisi absolut. Cara yang lebih pendek — text-align:center di slot —
   tidak jalan: Chrome hanya membagi sisa ruang, dan begitu teks lebih lebar
   dari kotaknya (28px vs 8px di 320px) seluruh limpahan lari ke kanan. Setiap
   label jadi meleset ~10px dari batangnya dan yang terakhir menembus tepi
   kartu. Dengan translateX(-50%) limpahannya simetris: paling jauh ~14px,
   masih di dalam padding kartu (13px di HP, 18px di desktop). */
.grafik .sumbu > span {
  position: relative;
  flex: 1 1 0;
  min-width: 4px;
  max-width: 22px;
  height: 1.35em;
}
.grafik .sumbu i {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-style: normal;
  white-space: nowrap;
}
/* Bilah kemajuan: relnya tenggelam, isiannya pil timbul — pasangan yang sama
   dengan input (tenggelam) dan tombol (timbul), supaya bilah tidak jadi resep
   kelima. */
.bilah {
  height: 10px;
  margin-top: 8px;
  border-radius: var(--r-pil);
  background: var(--color-brand-soft);
  box-shadow: inset 0 3px 6px -2px rgba(6, 32, 24, 0.28), inset 0 -2px 0 rgba(255, 255, 255, 0.8);
  padding: 2px;
}
.bilah > div {
  height: 100%;
  min-width: 6px;
  border-radius: var(--r-pil);
  background: var(--color-brand);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.18);
}
.bilah.pekat > div { background: var(--color-ink-secondary); }

.legenda { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.legenda span { display: inline-flex; align-items: center; gap: 6px; }
/* Titik legenda mewarisi warna deretnya lewat --warna, bukan currentColor:
   teksnya harus tetap ink-secondary (kontras AA), titiknya tidak. */
.legenda i {
  width: 9px;
  height: 9px;
  flex: none;
  border-radius: 50%;
  background: var(--warna, var(--color-brand));
}

/* ─────────────────────────────────────────────────────────────── badge */

/* Resep 4 — kancing. Kaki pendek 5px dalam warna keluarganya sendiri, dan
   selalu ada teksnya (status tidak pernah dibawa warna saja).
   margin-bottom 5px menyediakan ruang kakinya: tanpa itu kaki badge di dalam
   sel tabel menembus garis baris di bawahnya. */
.tag {
  display: inline-block;
  padding: 7px 14px;
  border-radius: var(--r-pil);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.005em;
  white-space: nowrap;
  background: var(--color-bg);
  color: var(--color-ink-secondary);
  /* Varian netral TENGGELAM, bukan berkaki: latarnya sama persis dengan latar
     halaman, jadi tanpa cincin ia lenyap begitu keluar dari kartu putih —
     dan kancing berkaki dalam warna netral terbaca seperti tombol mati. */
  box-shadow:
    inset 0 0 0 1px var(--color-border),
    inset 0 4px 7px -2px rgba(6, 32, 24, 0.14);
  margin-bottom: 5px;
}
.tag.baik  { --kaki: var(--kaki-accent);              background: var(--color-accent);     color: var(--color-accent-text); }
.tag.aktif { --kaki: rgba(6, 32, 24, 0.1);            background: var(--color-brand-soft); color: var(--color-brand-text); }
.tag.awas  { --kaki: rgba(138, 95, 0, 0.25);          background: var(--color-warning-bg); color: var(--color-warning-text); }
.tag.buruk { --kaki: rgba(156, 31, 31, 0.28);         background: var(--color-danger-bg);  color: var(--color-danger-text); }
.tag.baik, .tag.aktif, .tag.awas, .tag.buruk {
  box-shadow: 0 5px 0 var(--kaki), var(--clay-kancing);
}
/* Lime punya sorotan sendiri: rgba putih .9 di atas #C6F432 membuat tepi
   atasnya nyaris putih dan badge "Lunas" kehilangan warnanya. */
.tag.baik { box-shadow: 0 5px 0 var(--kaki), inset 0 3px 0 rgba(255, 255, 255, 0.5); }

/* ────────────────────────────────────────────────────────────── banner */

/* Batang kiri sekarang inset, bukan border. Alasannya bentuk: border satu sisi
   memaksa radius 0 (sudut membulat di tiga sisi saja terbaca patah), sedangkan
   di sistem clay tidak ada satu pun permukaan bersudut siku. Sebagai inset,
   batangnya ikut membulat mengikuti radius dan banner tetap punya penanda
   non-warna di kiri. */
.banner {
  --batang: var(--color-ink-secondary);
  border-radius: 20px;
  border: 0;
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  padding: 15px 18px 15px 24px;
  margin-bottom: 16px;
  box-shadow:
    inset 6px 0 0 var(--batang),
    inset 0 4px 0 rgba(255, 255, 255, 0.7),
    inset 0 -6px 0 rgba(6, 32, 24, 0.05),
    0 10px 18px -12px rgba(6, 32, 24, 0.35);
}
.banner.awas {
  --batang: var(--color-warning);
  background: var(--color-warning-bg);
  color: var(--color-warning-text);
  box-shadow:
    inset 6px 0 0 var(--batang),
    inset 0 4px 0 rgba(255, 255, 255, 0.7),
    inset 0 -6px 0 rgba(138, 95, 0, 0.07),
    0 10px 18px -12px rgba(138, 95, 0, 0.4);
}
.banner.bahaya {
  --batang: var(--color-danger);
  background: var(--color-danger-bg);
  color: var(--color-danger-text);
  box-shadow:
    inset 6px 0 0 var(--batang),
    inset 0 4px 0 rgba(255, 255, 255, 0.7),
    inset 0 -6px 0 rgba(156, 31, 31, 0.07),
    0 10px 18px -12px rgba(156, 31, 31, 0.45);
}
.banner b { display: block; font-weight: 700; }
.banner p { margin: 4px 0 0; font-size: 13.5px; }

/* ──────────────────────────────────────────────────────────────── tabel */

.tabel-gulung { overflow-x: auto; margin: 0 -16px; padding: 0 16px; }
/* width:auto + min-width:100% — tanpa ini tabel selalu memaksakan diri muat
   selebar layar, dan di HP kolom pertama tergencet sampai satu nama barang
   pecah jadi lima baris. Sekarang kolom mengambil lebar isinya dan tabelnya
   yang digeser. */
.tabel-gulung table { width: auto; min-width: 100%; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th {
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--color-ink-secondary);
  padding: 0 10px 8px 0;
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}
th:last-child, td:last-child { padding-right: 0; }
td {
  padding: 11px 10px 11px 0;
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
tr:last-child td { border-bottom: 0; }
td.r, th.r { text-align: right; }
td.r { white-space: nowrap; }
tr.klik { cursor: pointer; }
tr.klik:hover td { background: var(--color-bg); }
tr.klik:first-child:hover td:first-child { border-top-left-radius: var(--r-ikon); border-bottom-left-radius: var(--r-ikon); }
tr.klik:hover td:first-child { border-top-left-radius: var(--r-ikon); border-bottom-left-radius: var(--r-ikon); }
tr.klik:hover td:last-child { border-top-right-radius: var(--r-ikon); border-bottom-right-radius: var(--r-ikon); }
/* min-height 24px: nomor order ini tautan sungguhan, jadi ia harus memenuhi
   ukuran target minimum (WCAG 2.5.8) sendiri — bukan menumpang pada barisnya
   yang juga bisa diklik. */
a.baris {
  display: inline-block;
  min-height: 24px;
  padding: 3px 0;
  color: inherit;
  text-decoration: none;
  font-weight: 700;
}
a.baris:hover { text-decoration: underline; }

/* ────────────────────────────────────────────────────────── keadaan kosong */

.kosong { text-align: center; padding: 34px 16px; }
.kosong .rupa {
  width: 72px; height: 72px;
  margin: 0 auto 16px;
  border-radius: var(--r-pil);
  background: var(--color-brand-soft);
  color: var(--color-brand-text);
  display: grid;
  place-items: center;
  box-shadow: var(--clay-tenggelam-kecil);
}
/* Ilustrasi keadaan kosong. Rasio tiap aset berbeda (E03 melebar 480x226,
   E08 meninggi 236x480), jadi yang dikunci sisi terpanjangnya — bukan
   lebarnya — supaya kesepuluhnya duduk di kotak yang sama.

   Piksel tintanya tetap tidak sama rata: 4.313–17.489 px, selisih 4,05x.
   Itu geometri objeknya (paku bon memang sebagian besar ruang kosong, ceklis
   memang padat), bukan framing. Diukur juga cap 140x120 dan 132x112 —
   keduanya justru memperburuk selisihnya jadi 4,33x karena yang mengecil
   malah yang tintanya paling sedikit. Jadi 140x140 dipertahankan; jangan
   diutak-atik lagi tanpa mengukur ulang. */
.kosong .ilus {
  max-width: 140px;
  /* Sepuluh ilustrasi keadaan kosong rasionya beda-beda (480x226 sampai
     236x480), jadi dengan height:auto tinggi kotaknya baru diketahui setelah
     gambarnya termuat — dan seluruh teks di bawahnya melompat. Kotaknya
     dipesan 140 sejak awal, isinya di-contain, jadi ukuran tampak gambarnya
     tetap sama persis seperti sebelumnya, cuma tidak lagi menggeser apa pun. */
  height: 140px;
  width: auto;
  object-fit: contain;
  margin: 0 auto 14px;
  display: block;
}
.kosong h3 { margin-bottom: 6px; }
.kosong p {
  max-width: 42ch;
  margin: 0 auto 16px;
  color: var(--color-ink-secondary);
  font-size: 14px;
}

/* Rangka muat. Denyut opasitas, bukan gradien bergerak. */
.rangka {
  height: 16px;
  border-radius: var(--r-pil);
  background: var(--color-brand-soft);
  box-shadow: var(--clay-tenggelam-kecil);
  animation: denyut 1.3s ease-in-out infinite;
}
@keyframes denyut { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* Transisi tekan dimatikan, BAYANGAN TETAP. Yang memicu keluhan gerak adalah
   perpindahan 4px-nya, bukan reliefnya — mematikan bayangan juga akan
   menghapus satu-satunya pembeda antara "bisa ditekan" dan "bisa diisi". */
@media (prefers-reduced-motion: reduce) {
  .rangka { animation: none; }
  .tbl, .chip, .topbar .kanan a { transition: none; }
  .tbl:active, .chip:active, .topbar .kanan a:active { transform: none; }
}

/* ─────────────────────────────────────────────────────────────── isian */

.f { display: block; margin-bottom: 14px; }
.f > span {
  display: block;
  font-size: 13.5px;
  font-weight: 700;
  margin-bottom: 6px;
  color: var(--color-ink);
}
/* Resep 3 — tenggelam. Kalau bisa diisi atau sedang terpilih, ia tenggelam.
   --cincin dinaikkan ke --garis-kontrol (3,04:1 di atas --color-bg, diukur):
   sistem desain menulis #DCE8D2 di resepnya, tapi checklist-nya sendiri
   mensyaratkan "border kontrol 3:1 tetap ada di bawah bayangan" — dan #DCE8D2
   cuma 1,1:1. Yang dipakai checklist-nya. */
input, select, textarea {
  --cincin: var(--garis-kontrol);
  width: 100%;
  font: inherit;
  font-size: 15px;
  min-height: 52px;
  padding: 12px 18px;
  border: 0;
  border-radius: var(--r-kecil);
  background: var(--color-bg);
  color: var(--color-ink);
  box-shadow: var(--clay-tenggelam), inset 0 0 0 1px var(--cincin);
}
/* Panah select bawaan hilang begitu background diganti di sebagian browser,
   dan appearance:none mematikannya di semua. Panahnya digambar ulang sebagai
   SVG inline — satu warna rata, bukan gradien. */
select {
  appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%234A6B45' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 12px 8px;
}
textarea { min-height: 96px; resize: vertical; padding-top: 14px; }
/* --color-ink-muted (#7E967A) yang ditunjuk palet untuk placeholder cuma
   3,22:1 di atas --color-surface — gagal WCAG 1.4.3 (4,5:1). Placeholder
   bukan komponen nonaktif, jadi tidak kena pengecualian. Setiap input di
   sini sudah punya <label> terlihat, jadi hierarki tidak hilang saat
   placeholder-nya dinaikkan ke ink-secondary (6,03:1). */
input::placeholder, textarea::placeholder { color: var(--color-ink-secondary); }
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--color-brand);
  outline-offset: -1px;
  --cincin: var(--color-brand);
}
input.uang, input[type="number"] { font-variant-numeric: tabular-nums; }
.bantu {
  margin: 5px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-ink-secondary);
}
.bantu.turun { color: var(--color-danger-text); }
.baris-f { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
fieldset { border: 0; padding: 0; margin: 16px 0 0; min-width: 0; }
legend { padding: 0; }

/* ──────────────────────────────────────────────────────────────── kasir */

.kasir { display: grid; grid-template-columns: 1fr 340px; gap: 14px; align-items: start; }
.ringkas { position: sticky; top: calc(var(--atas) + 14px); }
/* Total kasir jadi balok clay hijau, bukan baris teks di antara dua garis.
   Ini satu-satunya angka di layar yang diperiksa berulang kali sebelum tombol
   simpan ditekan, jadi ia yang paling pantas jadi objek — dan lime di atas
   brand terukur 9,52:1, jauh di atas AA. */
.ringkas .total {
  display: block;
  margin: 4px 0 16px;
  padding: 16px 18px;
  border-radius: var(--r-kecil);
  background: var(--color-brand);
  box-shadow:
    0 10px 20px -12px rgba(6, 32, 24, 0.6),
    inset 0 3px 0 rgba(255, 255, 255, 0.14),
    inset 0 -5px 0 rgba(4, 21, 15, 0.5);
}
.ringkas .total .label { color: var(--color-brand-sub); }   /* 8,20:1 */
.ringkas .total b {
  display: block;
  font-family: var(--font-judul);
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.05;
  color: var(--color-accent);
  margin-top: 7px;
}
.ringkas .total .ket { display: block; margin-top: 3px; font-size: 13px; color: var(--color-brand-sub); }

.saran {
  position: absolute;
  z-index: 20;
  left: 0; right: 0;
  top: 100%;
  margin-top: 6px;
  max-height: 300px;
  overflow: hidden auto;
  overscroll-behavior: contain;
  background: var(--color-surface);
  border: 0;
  border-radius: var(--r);
  box-shadow: var(--clay-timbul), inset 0 0 0 1px var(--garis-kontrol);
}
.saran button {
  display: block;
  width: 100%;
  min-height: 48px;
  text-align: left;
  padding: 11px 18px;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  background: transparent;
  font: inherit;
  font-size: 14.5px;
  color: var(--color-ink);
  cursor: pointer;
}
.saran button:last-child { border-bottom: 0; }
.saran button:hover, .saran button.pilih { background: var(--color-brand-soft); }
.saran .h { float: right; font-weight: 600; margin-left: 10px; }

.keranjang-baris {
  display: grid;
  grid-template-columns: 1fr 84px 104px 116px 44px;
  gap: 8px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--color-border);
}
.keranjang-baris:last-child { border-bottom: 0; }
.keranjang-baris .nm { min-width: 0; font-size: 14.5px; font-weight: 600; line-height: 1.35; }
.keranjang-baris .nm small {
  display: block;
  font-size: 12px;
  color: var(--color-ink-secondary);
}
.keranjang-baris input, .keranjang-baris select {
  font-size: 14px;
  min-height: 44px;
  padding: 8px 12px;
  border-radius: 13px;
  box-shadow: var(--clay-tenggelam-kecil), inset 0 0 0 1px var(--cincin);
}
.keranjang-baris select { padding-right: 32px; background-position: right 11px center; }
.keranjang-baris .buang {
  min-height: 44px;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 13px;
  background: var(--color-danger-bg);
  color: var(--color-danger-text);
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  box-shadow: inset 0 3px 6px -2px rgba(156, 31, 31, 0.28), inset 0 0 0 1px rgba(156, 31, 31, 0.18);
}
.keranjang-baris .buang:hover { background: #FADFDF; }

/* ────────────────────────────────────────────────────── galeri foto barang */

.galeri {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: 8px;
}
.galeri .foto {
  display: block;
  border: 0;
  border-radius: var(--r-kecil);
  padding: 5px;
  cursor: pointer;
  background: var(--color-surface);
  box-shadow: 0 8px 14px -10px rgba(6, 32, 24, 0.4), inset 0 0 0 1px var(--garis-kontrol);
}
.galeri .foto img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--r-ikon);
  background: var(--color-bg);
}
/* Terpilih = tenggelam, bukan sekadar berganti border. */
.galeri .foto.pilih {
  background: var(--color-brand-soft);
  box-shadow: var(--clay-tenggelam-kecil), inset 0 0 0 2px var(--color-brand);
}
.galeri .foto:focus-within { outline: 2px solid var(--color-brand); outline-offset: 2px; }

/* ─────────────────────────────────────────────────────────────── dialog */

dialog {
  width: min(560px, calc(100vw - 24px));
  max-height: calc(100dvh - 40px);
  padding: 0;
  border: 0;
  border-radius: var(--r-shell);
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: var(--clay-timbul), 0 34px 70px -30px rgba(6, 32, 24, 0.55);
  overflow: hidden;   /* isi ikut membulat mengikuti radius shell */
}
dialog::backdrop { background: rgba(6, 32, 24, 0.42); }
dialog form { display: flex; flex-direction: column; max-height: calc(100dvh - 40px); }
/* contain: gulir yang sudah mentok di dalam dialog tidak boleh diteruskan ke
   halaman di belakangnya — kalau diteruskan, latar ikut bergeser dan posisi
   baca pengguna hilang begitu dialognya ditutup. */
dialog .isi { padding: 24px 24px 6px; overflow-y: auto; overscroll-behavior: contain; }
dialog .isi h2 { margin-bottom: 16px; }
dialog .kaki {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  /* padding-bawah dikurangi tinggi kaki tombol: tombol di dalamnya sudah
     membawa margin-bottom sendiri, jadi tanpa ini kakinya menumpuk. */
  padding: 16px 24px calc(16px - var(--kaki-tinggi));
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
  position: sticky;
  bottom: 0;
}

/* ──────────────────────────────────────────────────────────────── toast */

#toast {
  position: fixed;
  z-index: 60;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  width: max-content;
  max-width: calc(100vw - 32px);
  pointer-events: none;
}
#toast div {
  background: var(--color-brand);
  color: #fff;
  padding: 13px 20px;
  border-radius: var(--r-kecil);
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.45;
  box-shadow:
    0 6px 0 var(--kaki-brand),
    0 20px 34px -18px rgba(6, 32, 24, 0.6),
    inset 0 3px 0 rgba(255, 255, 255, 0.14);
}
#toast div.gagal {
  box-shadow:
    0 6px 0 var(--kaki-danger),
    0 20px 34px -18px rgba(156, 31, 31, 0.55),
    inset 0 3px 0 rgba(255, 255, 255, 0.2);
}
#toast div.gagal { background: var(--color-danger-hover); }

/* ──────────────────────────────────────────────────────────── responsif */

@media (max-width: 1000px) {
  .kasir { grid-template-columns: 1fr; }
  .ringkas { position: static; }
}

@media (max-width: 900px) {
  :root { --sisi: 0px; }

  .app {
    grid-template-columns: 1fr;
    grid-template-rows: var(--atas) 1fr auto;
    grid-template-areas: "atas" "utama" "sisi";
  }

  .utama {
    padding: 16px 14px 24px;
    /* Bar bawah menempel; isi diberi ruang supaya baris terakhir tidak tertutup. */
    padding-bottom: calc(var(--bar) + 24px + env(safe-area-inset-bottom));
  }

  /* Menu jadi bar bawah. Sembilan tautan tidak muat di 390px tanpa terpotong,
     jadi lima yang paling sering dipakai duduk di bar dan sisanya masuk sheet
     "Lainnya" — semua rute tetap ada, cuma tempatnya yang pindah. */
  /* Rel nav clay: sudut atas membulat 32px (radius shell) dan bayangan naik ke
     atas, jadi bar terbaca sebagai panel yang menempel di depan halaman —
     bukan pita yang dipotong tepi layar. */
  .sisi {
    position: fixed;
    z-index: 40;
    inset: auto 0 0 0;
    top: auto;
    height: auto;
    max-height: none;
    overflow: visible;
    flex-direction: row;
    /* gap 2px, bukan 4: enam slot di 390px berbagi (390 − padding − gap), dan
       tiap 2px gap memotong 1,7px dari tiap slot. Di 4px label "Ringkasan"
       (butuh ~60px di 12px) tinggal 57px dan berubah jadi "Ringkas…". */
    gap: 2px;
    padding: 8px 6px calc(8px + env(safe-area-inset-bottom));
    border-right: 0;
    border-top: 0;
    border-radius: var(--r-shell) var(--r-shell) 0 0;
    box-shadow: 0 -14px 26px -16px rgba(6, 32, 24, 0.45), inset 0 5px 0 rgba(255, 255, 255, 0.95);
  }
  /* Anak langsung saja: tautan di dalam sheet "Lainnya" tetap baris biasa. */
  .sisi > a, .sisi > .lain {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    padding: 5px 2px;
    min-height: 56px;
    font-size: 12px;
    font-weight: 600;
    position: relative;
    border-radius: var(--r-nav);
  }
  /* 26px, turun dari 30: lima slot di 320px cuma selebar 60px, dan ikon 30px
     plus label 12px membuat baris setinggi 63px — bar-nya jadi setinggi
     seperlima layar. */
  .sisi > a .ikon, .sisi > .lain .ikon { width: 26px; height: 26px; border-radius: 9px; }
  .sisi > a .tl, .sisi > .lain .tl {
    flex: none;
    width: 100%;
    text-align: center;
    font-size: 12px;
    line-height: 1.2;
  }
  .sisi > a[aria-current="page"] {
    background: var(--color-brand-soft);
    box-shadow: var(--clay-tenggelam-kecil);
  }
  .sisi > a.hp-sembunyi { display: none; }
  .sisi > .lain { display: flex; }
  .hanya-lebar { display: none; }
  /* Lencana pindah ke pojok ikon — di bar bawah tidak ada ruang di kanan teks. */
  .sisi > a .lencana {
    position: absolute;
    top: 2px;
    left: 50%;
    margin-left: 4px;
    min-width: 18px;
    height: 18px;
    font-size: 11px;
  }

  /* Di HP tabel digeser, bukan digencet. Tanpa nowrap browser memilih
     memuatkan tabel ke lebar layar dengan cara membelah "Beras Ramos 5kg"
     jadi tiga baris — kolomnya jadi selebar satu kata. */
  .tabel-gulung td, .tabel-gulung th, .tabel-gulung td .mini { white-space: nowrap; }

  .judul { margin-bottom: 14px; }
  .judul h1 { font-size: 24px; }
  h2 { font-size: 17.5px; }
  .tabel-gulung { margin: 0 -16px; padding: 0 16px; }
  /* Sistem desain meminta angka utama 36–48px; di HP itu tidak muat. Kartu
     .jajar di 390px lebarnya 175px dengan ruang dalam 143px, sedangkan
     "Rp 26.368.000" di Baloo 700 butuh ~8,05x ukuran font — 36px berarti
     290px. Angka diukur ulang di 320/360/390/414 dan 24px yang paling besar
     tanpa memecah "Rp" ke barisnya sendiri. 24px/700 tetap terhitung teks
     besar (>=18,66px bold), jadi ambang kontrasnya 3:1 dan tidak ada
     pasangan yang jatuh. */
  .angka-besar { font-size: 24px; margin: 7px 0 3px; }
  .ringkas .total b { font-size: 27px; }
  .baris-f { grid-template-columns: 1fr; }
  /* Kartu angka berpasangan di HP. Satu kolom membuat tiga angka ringkas
     memakan satu layar penuh sebelum sampai ke yang perlu ditindak. */
  /* 165px, naik dari 150. Di 360px kartu 150px menyisakan lebar dalam 156px,
     dan "Rp 26.368.000" di 22px butuh ~163px — angkanya pecah dua baris dengan
     "Rp" tertinggal sendirian. 165px membuat 360px turun ke satu kolom (angka
     utuh, lebih banyak gulir) sementara 390px tetap dua kolom selebar 175px.
     Diukur di 320/360/390/414. */
  .jajar { grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); gap: 12px; }
  /* Padding turun, radius TIDAK. Radius 24px yang dikecilkan bersama padding
     membuat kartu HP terlihat seperti sistem desain yang lain; yang boleh
     menyusut cuma ruang kosongnya. */
  .kartu { padding: 16px; margin-bottom: 14px; }
  /* Jatuh bayangan dipendekkan di HP: 26px blur di kartu selebar 175px yang
     berjajar rapat membuat tetangganya kelihatan kotor. */
  .kartu {
    box-shadow:
      0 10px 18px -12px rgba(6, 32, 24, 0.28),
      inset 0 4px 0 rgba(255, 255, 255, 0.9),
      inset 0 -6px 0 rgba(6, 32, 24, 0.05),
      inset 0 0 0 1px rgba(6, 32, 24, 0.05);
  }
  /* Tombol utama di HP jadi selebar kartu dan kakinya dipendekkan ke 5px:
     di layar 390px kaki 7px pada tombol selebar 358px terbaca sebagai dua
     balok bertumpuk, bukan satu tombol. */
  :root { --kaki-tinggi: 5px; }
  .tbl { min-height: 50px; }
  /* Batang menyempit, bukan menggulir. 30 hari x (22+4)px = 780px — grafik
     yang harus digeser ke samping kehilangan gunanya, yaitu membandingkan
     seluruh rentang dalam satu pandangan. */
  .grafik .plot { height: 120px; }
  .grafik .kol, .grafik .sumbu > span { max-width: 14px; }
  .grafik .plot, .grafik .sumbu { gap: 3px; }
  .label { letter-spacing: .03em; }   /* 12px tetap — batas minimum palet */
  #toast { bottom: calc(var(--bar) + 16px + env(safe-area-inset-bottom)); }

  /* Nama barang di baris atas, tiga kontrol berbagi baris di bawahnya. */
  .keranjang-baris {
    grid-template-columns: 76px 1fr 1fr 44px;
    grid-template-areas:
      "nm  nm     nm    buang"
      "qty satuan harga harga";
    gap: 8px;
  }
  .keranjang-baris .nm { grid-area: nm; }
  .keranjang-baris .buang { grid-area: buang; }
  .keranjang-baris .qty { grid-area: qty; }
  .keranjang-baris .satuan { grid-area: satuan; }
  .keranjang-baris .harga { grid-area: harga; }
}

@media (max-width: 420px) {
  .sisi > a .tl, .sisi > .lain .tl { font-size: 12px; letter-spacing: -0.02em; }
  .utama { padding-left: 12px; padding-right: 12px; }
  .tabel-gulung { margin: 0 -12px; padding: 0 12px; }
}

/* ───────────────────────────────────────────────────────────────── cetak */

@media print {
  .topbar, .sisi, .no-print, #toast, #menu-lain { display: none !important; }
  .app { display: block; }
  .utama { padding: 0; max-width: none; }
  /* Warna latar ikut tercetak. Tanpa ini batang grafik, bar kategori kas, dan
     badge status keluar putih polos — laporan yang dibawa ke bank kehilangan
     justru bagian yang paling cepat dibaca. Properti ini diwariskan, jadi satu
     deklarasi di body cukup. */
  body { background: #fff; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .kartu { border: 0; padding: 0 0 12px; margin-bottom: 8px; break-inside: avoid; }
  .tabel-gulung { overflow: visible; margin: 0; padding: 0; }
  /* Padding kartu hilang saat cetak, padahal label sumbu paling kiri dan kanan
     memang melimpah ~14px keluar slotnya. Tanpa ganti ruang ini tanggalnya
     kepotong tepi kertas. */
  .grafik { padding: 0 16px; }
}

