/* Ansalia Grafika POS — gaya aplikasi (tanpa framework CSS). */

/* Font desain: Plus Jakarta Sans, dihosting sendiri di assets/fonts supaya
   tidak bergantung layanan luar dan tetap ringan (variable font, 200–800). */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/plus-jakarta-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --radius: 0.875rem;
  --background: #f4f6fb;
  --foreground: #0f172a;
  --card: #ffffff;
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --primary-foreground: #ffffff;
  --secondary: #eef2f8;
  --muted: #f2f5fa;
  --muted-foreground: #64748b;
  --border: #e6ebf3;
  --destructive: #dc2626;
  --destructive-strong: #dc2626;
  --soft: #f6f8fc;
  --line: #eef2f8;
  --rail: #0b1526;
  /* Sidebar navy gelap dengan gelombang biru lembut di kaki sidebar
     (pola pada referensi desain) + kilau tipis di tepi atas. */
  --rail-bg:
    radial-gradient(150% 52% at 8% 118%, rgba(56, 132, 255, 0.5), rgba(56, 132, 255, 0) 64%),
    radial-gradient(130% 46% at 96% 110%, rgba(37, 99, 235, 0.36), rgba(37, 99, 235, 0) 62%),
    radial-gradient(120% 40% at 24% 0%, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0) 60%),
    linear-gradient(180deg, #0a1120 0%, #0b1628 48%, #0c1c36 100%);
  --rail-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 26px 52px -34px rgba(8, 15, 30, 0.75);
  --rail-muted: #9fb0c9;
  --accent-blue: #2563eb;
  --accent-lime: #22c55e;
  --accent-purple: #8b5cf6;
  --status-paid: #16a34a;
  --status-due: #d97706;
  --lime-soft: #dcfce7;
  --lime-text: #15803d;
  --danger-soft: #fef2f2;
  --danger-text: #b91c1c;
  --warning-soft: #fffbeb;
  --warning-text: #b45309;
  --success-soft: #ecfdf3;
  --success-text: #15803d;
  --promo-text: #b45309;
  --shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
  /* Bayangan kontrol (tombol, kolom isian, pemilih): pengganti garis tepi. */
  --kontrol-shadow: 0 1px 2px rgba(15, 23, 42, 0.07), 0 6px 14px -12px rgba(15, 23, 42, 0.3);
  --kontrol-shadow-hover: 0 2px 4px rgba(15, 23, 42, 0.08), 0 9px 18px -12px rgba(15, 23, 42, 0.35);
  /* Bayangan kartu: lembut dan rapat — tidak sampai menimpa elemen di
     bawahnya (celah antar kartu tetap bersih). Permukaan kartu tanpa garis
     tepi, jadi bayangan inilah pemisahnya dengan latar. */
  --card-shadow: 0 1px 2px rgba(15, 23, 42, 0.05), 0 5px 14px -10px rgba(15, 23, 42, 0.32);
  /* Skala sudut squircle (superellipse) untuk seluruh komponen UI. */
  --squircle-xs: 0.625rem;
  --squircle-sm: 0.75rem;
  --squircle-md: 1rem;
  --squircle-lg: 1.5rem;
  --squircle-xl: 1.75rem;
  --font-sans: "Plus Jakarta Sans", Inter, "Segoe UI", Arial, Helvetica, sans-serif;
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  /* Warna grafik mengikuti tema (dibaca skrip halaman). */
  --chart-grid: #e9eef6;
  --chart-label: #7c8798;
  --chart-average: #cbd5e1;
  /* Warna tint kartu/tile: latar lembut, garis tepi, dan ikon senada. */
  --tint-green: #eefbf3;
  --tint-green-line: #d7f0e2;
  --tint-green-icon: #16a34a;
  --tint-green-bg: #dcfce7;
  --tint-blue: #eff5ff;
  --tint-blue-line: #d9e6fb;
  --tint-blue-icon: #2563eb;
  --tint-blue-bg: #dbeafe;
  --tint-red: #fef4f4;
  --tint-red-line: #f9dee1;
  --tint-red-icon: #dc2626;
  --tint-red-bg: #fee2e2;
  --tint-purple: #f6f3ff;
  --tint-purple-line: #e5ddfb;
  --tint-purple-icon: #7c3aed;
  --tint-purple-bg: #ede9fe;
  --tint-amber: #fffaf0;
  --tint-amber-line: #f6e6c4;
  --tint-amber-icon: #d97706;
  --tint-amber-bg: #fef3c7;
  /* Scrollbar serasi di kedua tema. */
  --scrollbar-thumb: #c9d3e0;
  --scrollbar-thumb-hover: #a6b4c6;
  --scrollbar-rail: rgba(255, 255, 255, 0.22);
  --scrollbar-rail-hover: rgba(255, 255, 255, 0.34);
}

* { box-sizing: border-box; }
html { scrollbar-gutter: stable; }
/* Kunci zoom: teks tidak membesar sendiri & gestur cubit (pinch) dimatikan. */
html, body { touch-action: pan-x pan-y; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
/* Tab baru: halaman disembunyikan sebentar sampai status tab dipastikan ke
   server (lihat skrip di layout), supaya tidak ada kedipan halaman yang masih
   masuk sebelum berpindah ke halaman login. */
html.auth-gate { background: var(--background); }
html.auth-gate body { visibility: hidden; }
button, a, input, textarea, select { -webkit-tap-highlight-color: transparent; }
/* Kontrol tidak ikut menyorot teksnya saat diklik berulang (klik cepat tidak
   boleh terlihat seperti seleksi browser). Teks isi halaman tetap bisa disorot. */
:is(button, .btn, .tab, .chip, .tag, .pill, .nav-item, .select-trigger, .radio-group, .qty, .masters-chip, .icon-badge-count) {
  -webkit-user-select: none;
  user-select: none;
}
button:not(:disabled), a { cursor: pointer; }
a { color: var(--primary); text-decoration: none; }
h1, h2, h3 { margin: 0; letter-spacing: -0.01em; }
p { margin: 0; }
[hidden] { display: none !important; }
.mono { font-family: var(--font-mono); }
.muted { color: var(--muted-foreground); }
.small { font-size: 0.75rem; }
.right { text-align: right; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.tabular { font-variant-numeric: tabular-nums; }
.icon { width: 1rem; height: 1rem; flex: none; }

.skip-link {
  position: absolute; left: -999px; top: 0; z-index: 100;
  background: var(--card); padding: 0.5rem 0.75rem; border-radius: 0.5rem;
}
.skip-link:focus { left: 0.75rem; top: 0.75rem; }

/* ------------------------------------------------------------------ layout */
.rail {
  position: fixed; inset: 0 auto 0 0; z-index: 20;
  width: 14rem; margin: 0.75rem 0 0.75rem 0.75rem; padding: 1rem 0.875rem;
  display: none; flex-direction: column; gap: 0.875rem; overflow-y: auto;
  background: var(--rail-bg, var(--rail)); color: #fff; border-radius: 1.375rem;
  box-shadow: var(--rail-shadow);
}
.rail-brand, .mobile-top { display: flex; align-items: center; gap: 0.625rem; min-width: 0; }
/* Header kecil: logo + nama toko bisa diklik menuju Dashboard. */
.mobile-brand { display: flex; align-items: center; gap: 0.625rem; min-width: 0; flex: 1; color: inherit; text-decoration: none; border-radius: 0.75rem; -webkit-tap-highlight-color: transparent; }
/* Tanpa garis bawah dalam keadaan apa pun (hover, fokus, atau saat diklik). */
.mobile-brand:hover, .mobile-brand:focus, .mobile-brand:active,
.mobile-brand:hover strong, .mobile-brand:focus strong, .mobile-brand:active strong {
  text-decoration: none;
}
.mobile-actions { display: flex; align-items: center; gap: 0.5rem; flex: none; }
/* Lonceng di header kecil: tingginya sama dengan tombol Keluar (2rem). */
.mobile-actions #stock-bell { width: 2rem; height: 2rem; border-radius: 0.5625rem; }
.mobile-actions #stock-bell .icon-badge-count { top: -0.3rem; right: -0.3rem; min-width: 1rem; line-height: 1rem; font-size: 0.6rem; }
.brand-mark {
  display: grid; place-items: center; width: 2.5rem; height: 2.5rem; flex: none;
  overflow: hidden; border-radius: 0.875rem; background: #fff; color: #0f172a;
  font-weight: 700; font-size: 0.85rem;
}
.brand-mark img { width: 100%; height: 100%; object-fit: contain; }
.brand-text { min-width: 0; display: grid; }
.brand-text strong { font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brand-text small { font-size: 0.7rem; color: var(--rail-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mobile-header .brand-text small { color: var(--muted-foreground); }
.nav { display: grid; gap: 0.2rem; align-content: start; }
.nav-group {
  margin: 0.75rem 0 0.25rem; padding: 0 0.75rem; font-size: 0.65rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.14em; color: rgba(159, 176, 201, 0.75);
}
.nav-item {
  display: flex; align-items: center; gap: 0.625rem; padding: 0.5rem 0.75rem;
  border-radius: 0.75rem; font-size: 0.8125rem; font-weight: 600;
  color: var(--rail-muted); text-decoration: none;
}
.nav-item:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
/* Menu aktif: pil biru gradasi (pola referensi) dan tidak bisa diklik lagi. */
.nav-item.is-current {
  background: linear-gradient(180deg, #3b82f6, #2563eb); color: #fff;
  box-shadow: 0 10px 20px -14px rgba(37, 99, 235, 0.95);
  pointer-events: none; cursor: default;
}
.nav-item span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-badge {
  margin-left: auto; background: var(--lime-soft); color: var(--lime-text);
  font-size: 0.65rem; font-weight: 700; border-radius: 999px; padding: 0 0.4rem;
}
.rail-user-wrap {
  margin-top: auto; position: relative;
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.75rem 0.25rem 0.125rem; border-top: 1px solid rgba(255, 255, 255, 0.09);
}
/* Avatar jadi tombol menu; baris teks di sampingnya hanya keterangan. */
.rail-avatar-btn { border: 0; padding: 0; cursor: pointer; font: inherit; transition: box-shadow var(--dur-fast) ease; }
.rail-avatar-btn:hover, .rail-avatar-btn[aria-expanded="true"] { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.45); }
.rail-avatar-btn:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.6); }
/* Menu akun: hanya opsi keluar, muncul dengan animasi singkat. */
.user-menu {
  position: absolute; left: 0; bottom: calc(100% + 0.4rem); z-index: 5; min-width: 9rem;
  background: var(--card); color: var(--foreground); border: 0;
  border-radius: var(--squircle-md); box-shadow: 0 20px 40px -16px rgba(15, 23, 42, 0.45);
  padding: 0.3rem; display: grid; gap: 0.1rem;
}
.user-menu:not([hidden]) { animation: menu-in var(--dur) var(--ease-out) both; }
.user-menu-item {
  display: flex; align-items: center; gap: 0.5rem; width: 100%; border: 0; background: transparent;
  color: var(--foreground); font: inherit; font-size: 0.8125rem; font-weight: 600;
  padding: 0.45rem 0.5rem; border-radius: 0.625rem; text-align: left;
}
.user-menu-item:hover { background: var(--soft); color: var(--destructive); }
.user-menu-item .icon { width: 1rem; height: 1rem; }
/* Avatar bulat dengan cincin biru, pola pada referensi desain. */
.rail-avatar {
  display: grid; place-items: center; width: 2.125rem; height: 2.125rem; flex: none;
  border-radius: 999px; background: linear-gradient(180deg, #3b82f6, #2563eb);
  color: #fff; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.02em;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.16); overflow: hidden;
}
.rail-avatar img { width: 100%; height: 100%; object-fit: cover; }
/* Avatar pengguna di tabel Pengaturan. */
.user-avatar {
  display: grid; place-items: center; width: 2rem; height: 2rem; flex: none;
  border-radius: 999px; overflow: hidden; background: var(--tint-blue-bg); color: var(--tint-blue-icon);
  font-size: 0.7rem; font-weight: 700;
}
.user-avatar img { width: 100%; height: 100%; object-fit: cover; }
.rail-user-text { min-width: 0; flex: 1; display: grid; }
.rail-user-text strong { font-size: 0.75rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-user-text small { font-size: 0.68rem; color: var(--rail-muted); }
.content { min-height: 100vh; }
/* Halaman masuk dengan fade singkat saat dimuat penuh (mis. sehabis login).
   Navigasi dalam aplikasi tetap memakai animasi page-enter milik app.js. */
@keyframes halaman-masuk { from { opacity: 0; } to { opacity: 1; } }
.content { animation: halaman-masuk 0.42s var(--ease-out) both; }
.mobile-header { display: block; border-bottom: 1px solid var(--border); background: var(--card); padding: 0.75rem 1rem; }
.mobile-top { margin-bottom: 0.75rem; }
.mobile-top .brand-text { flex: 1; }
.mobile-header .nav.bar { display: flex; gap: 0.25rem; overflow-x: auto; padding-bottom: 0.25rem; }
.mobile-header .nav.bar .nav-item { flex: none; color: var(--muted-foreground); }
.mobile-header .nav.bar .nav-item.is-current { background: var(--primary); color: var(--primary-foreground); }
.main { padding: 1.25rem 1rem; }
@media (min-width: 1024px) {
  .rail { display: flex; }
  .mobile-header { display: none; }
  .content { padding-left: 16rem; }
  .main { padding: 1.5rem 2rem; }
}

/* ------------------------------------------------------------- page header */
.page-header { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 0.75rem; margin-bottom: 1rem; }
.breadcrumb { display: flex; align-items: center; gap: 0.375rem; font-size: 0.8125rem; color: var(--muted-foreground); }
/* Ikon rumah kecil di awal breadcrumb (pola referensi desain). */
.breadcrumb::before {
  content: ""; width: 0.9rem; height: 0.9rem; flex: none;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3 3 10v11h6v-6h6v6h6V10z'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3 3 10v11h6v-6h6v6h6V10z'/%3E%3C/svg%3E") no-repeat center / contain;
}
.breadcrumb .icon { width: 0.9rem; height: 0.9rem; }
.breadcrumb strong { color: var(--foreground); font-weight: 600; }
.page-title { font-size: 1.75rem; font-weight: 800; letter-spacing: -0.025em; }
.page-subtitle { margin-top: 0.25rem; font-size: 0.875rem; color: var(--muted-foreground); }
.page-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* ------------------------------------------------------------------- cards */
.card { border: 0; background: var(--card); border-radius: var(--squircle-lg); box-shadow: var(--card-shadow); overflow: hidden; }
.card + .card, .card + .stack { margin-top: 0.75rem; }
/* Di dalam grid, jarak antar kartu diatur oleh gap grid — bukan margin. */
.grid > .card, .grid > .stack { margin-top: 0; }
.card-header { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 0.75rem; border-bottom: 1px solid var(--border); padding: 0.75rem 1rem; }
.card-body { padding: 1rem; }
.card-body.flush { padding: 0; }
.kicker { font-size: 0.7rem; color: var(--muted-foreground); }
.card-title { font-size: 0.875rem; font-weight: 600; }
.card-desc { margin-top: 0.25rem; font-size: 0.75rem; color: var(--muted-foreground); }
.card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.soft-card { border: 0; background: var(--soft); border-radius: var(--squircle-lg); padding: 0.875rem; }
/* Kartu dashboard (Laba, Penjualan, BRILink) tampil sebagai kartu putih solid
   dengan bayangan lembut, tanpa garis tepi. */
[data-card] {
  display: flex; flex-direction: column;
  background: var(--card); border: 0;
  border-radius: var(--squircle-lg); box-shadow: var(--card-shadow); padding: 1rem;
}
.chart-grow { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }
.chart-grow > div { width: 100%; }

/* -------------------------------------------------------------------- grid */
.grid { display: grid; gap: 0.75rem; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Rekening BRILink: kartu menyesuaikan lebar layar dengan maksimal 5 kartu
   per baris — kolom minimal 13rem atau 1/5 lebar wadah (mana yang lebih
   besar), sehingga layar lebar tidak pernah memuat lebih dari 5. */
#brilink-accounts {
  grid-template-columns: repeat(auto-fit, minmax(max(13rem, calc((100% - 4 * 0.75rem) / 5)), 1fr));
}
.grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
/* Kartu saldo BRILink di dashboard: kartu dibuat cukup lebar supaya nominal
   panjang tampil penuh — jumlah per baris menyesuaikan ruang yang ada. */
#brilink-saldo { grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); gap: 0.4rem; }
/* Ringkasan laporan: 5 kartu untuk bulanan/tahunan, 4 kartu saat tab Harian. */
.grid-5.is-harian { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-kpi { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .grid-kpi { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .grid-kpi { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.stack { display: grid; gap: 0.75rem; }
.stack-sm { display: grid; gap: 0.5rem; }
/* Kolom pencarian memakai ikon kaca pembesar supaya langsung dikenali. */
input[type="search"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 0.6rem center;
  background-size: 0.95rem;
  padding-left: 2.05rem;
}
.row { display: flex; align-items: center; gap: 0.5rem; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
/* Garis putus-putus tipis penghubung nama transaksi dan nominal (daftar
   BRILink Dashboard) — sengaja lembut agar tidak mencolok. */
.leader-dashed { flex: 1 1 auto; min-width: 0.5rem; border-top: 1px dashed var(--border); opacity: 0.75; }
.row-wrap { flex-wrap: wrap; }
.spacer { flex: 1; }
@media (max-width: 1279px) {
  .grid-4, .grid-5, .grid-5.is-harian { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .grid-2, .grid-3, .grid-4, .grid-5, .grid-5.is-harian { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------------------------------- kpi */
.kpi {
  background: var(--card); border: 0; border-radius: var(--squircle-lg);
  padding: 1rem; display: grid; gap: 0.25rem; box-shadow: var(--card-shadow);
}
/* Kartu KPI dashboard diberi tint lembut sesuai jenisnya + ikon berwarna
   (pola referensi desain). Halaman lain memakai kartu putih bersih — pemilih
   dibatasi ke artikel kartu karena atribut data-kpi juga dipakai nilai
   (mis. data-kpi="pengeluaran" di halaman Kas). */
article.kpi[data-kpi] { background: linear-gradient(155deg, var(--kpi-tint, var(--card)), var(--card) 62%); border-color: var(--kpi-line, var(--border)); }
article.kpi[data-kpi="penjualan"] { --kpi-tint: var(--tint-green); --kpi-line: var(--tint-green-line); }
article.kpi[data-kpi="transaksi"] { --kpi-tint: var(--tint-blue); --kpi-line: var(--tint-blue-line); }
article.kpi[data-kpi="pengeluaran"] { --kpi-tint: var(--tint-red); --kpi-line: var(--tint-red-line); }
article.kpi[data-kpi="laba"] { --kpi-tint: var(--tint-green); --kpi-line: var(--tint-green-line); }
article.kpi[data-kpi="penjualan"] .kpi-icon { background: var(--tint-green-bg); color: var(--tint-green-icon); }
article.kpi[data-kpi="transaksi"] .kpi-icon { background: var(--tint-blue-bg); color: var(--tint-blue-icon); }
article.kpi[data-kpi="pengeluaran"] .kpi-icon { background: var(--tint-red-bg); color: var(--tint-red-icon); }
article.kpi[data-kpi="laba"] .kpi-icon { background: var(--tint-green-bg); color: var(--tint-green-icon); }
/* Label periode pada kartu Pengeluaran ikut merah, seperti referensi. */
article.kpi[data-kpi="pengeluaran"] .kpi-top > .small { color: var(--destructive); font-weight: 600; }
.kpi-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.kpi-icon {
  display: grid; place-items: center; width: 2.375rem; height: 2.375rem;
  border-radius: 0.75rem; background: var(--tint-blue-bg); color: var(--tint-blue-icon);
}
.kpi-label { font-size: 0.8125rem; font-weight: 500; color: var(--muted-foreground); }
.kpi-value { font-size: 1.625rem; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.kpi-note { font-size: 0.72rem; color: var(--muted-foreground); }
/* Kartu rekening BRILink memakai konsep kartu KPI dashboard: gradient tint
   lembut + aksen berwarna; warnanya (--kpi-tint/--kpi-line) diisi dari JS
   mengikuti warna rekening. Tanpa ikon dan rapat setinggi kartu sebelumnya.
   Gradasi diletakkan di sudut KANAN BAWAH kartu. */
article.kpi.kpi-rekening {
  display: flex; flex-direction: column; gap: 0; height: 100%;
  background: linear-gradient(315deg, var(--kpi-tint, var(--card)), var(--card) 62%);
  border-color: var(--kpi-line, var(--border));
}
/* Judul kartu dashboard dengan ikon kecil berwarna di kiri (pola referensi). */
.card-head { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9375rem; font-weight: 700; letter-spacing: -0.01em; }
.card-icon {
  display: grid; place-items: center; width: 1.875rem; height: 1.875rem; flex: none;
  border-radius: 0.625rem; background: var(--tint-blue-bg); color: var(--tint-blue-icon);
}
.card-icon.is-green { background: var(--tint-green-bg); color: var(--tint-green-icon); }
.card-icon.is-blue { background: var(--tint-blue-bg); color: var(--tint-blue-icon); }
.card-icon.is-purple { background: var(--tint-purple-bg); color: var(--tint-purple-icon); }
.card-icon.is-red { background: var(--tint-red-bg); color: var(--tint-red-icon); }
.card-icon.is-amber { background: var(--tint-amber-bg); color: var(--tint-amber-icon); }
.card-icon .icon { width: 1rem; height: 1rem; }
/* Kotak info lembut di dalam kartu (mis. catatan BRILink di dashboard). */
.info-box {
  display: flex; align-items: flex-start; gap: 0.5rem;
  background: var(--tint-blue); border: 0; border-radius: var(--squircle-md);
  padding: 0.625rem 0.75rem; font-size: 0.75rem; color: var(--muted-foreground); line-height: 1.4;
}
.info-box .icon { width: 1rem; height: 1rem; color: var(--tint-blue-icon); margin-top: 0.05rem; }
/* Status kas di header: pil hijau lembut (pola referensi desain). */
.btn.kas-status { background: var(--tint-green); border-color: var(--tint-green-line); color: var(--success-text); box-shadow: none; }
.btn.kas-status .icon { color: var(--tint-green-icon); }
/* Kartu ringkasan di halaman Laporan: label diberi ruang dua baris supaya
   tinggi kartu sama di tab Harian, Bulanan, dan Tahunan. */
[aria-label="Ringkasan laporan"] .kpi-label { min-height: 2.9em; }
[aria-label="Ringkasan laporan"] .kpi-top .chip { flex: none; }
.chip { display: inline-flex; align-items: center; gap: 0.25rem; border: 1px solid var(--border); background: var(--card); border-radius: 999px; padding: 0.1rem 0.5rem; font-size: 0.65rem; font-weight: 600; color: var(--muted-foreground); }

/* ------------------------------------------------------------------- chips */
.tag { display: inline-flex; align-items: center; border-radius: 0.5rem; padding: 0.12rem 0.5rem; font-size: 0.7rem; font-weight: 600; background: var(--soft); color: var(--muted-foreground); }
.tag.lime { background: var(--lime-soft); color: var(--lime-text); }
.tag.jasa { background: #e7e9ff; color: #3b3f8f; }
.tag.danger { background: var(--danger-soft); color: var(--danger-text); }
.tag.warning { background: var(--warning-soft); color: var(--warning-text); }
/* Pill status memakai ukuran yang sama dengan chip periode (kpi-period):
   teks gelap netral, hanya bulatan dan garis tepi yang berwarna sesuai status,
   dengan latar tipis senada. */
.pill { display: inline-flex; align-items: center; gap: 0.25rem; border: 1px solid var(--border); background: var(--card); border-radius: 999px; padding: 0.1rem 0.5rem; font-size: 0.65rem; font-weight: 600; color: var(--foreground); white-space: nowrap; }
.pill .dot { width: 0.4rem; height: 0.4rem; border-radius: 999px; background: var(--muted-foreground); }
.pill.paid { background: var(--success-soft); border-color: var(--tint-green-line); } .pill.paid .dot { background: var(--status-paid); }
.pill.due { background: var(--warning-soft); border-color: var(--tint-amber-line); } .pill.due .dot { background: var(--status-due); }
.pill.blue { background: var(--tint-blue); border-color: var(--tint-blue-line); } .pill.blue .dot { background: var(--accent-blue); }
.pill.purple { background: var(--tint-purple); border-color: var(--tint-purple-line); } .pill.purple .dot { background: var(--accent-purple); }

/* ------------------------------------------------------------- format rincian
   Dipakai dialog rincian transaksi (halaman Pelanggan) dan rincian mutasi
   BRILink: kisi 2 kolom untuk keterangan utama, lalu kelompok baris berlabel
   dengan garis pemisah tipis. */
.detail-box { display: grid; gap: 0.875rem; }
.detail-grid { display: grid; gap: 0.5rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.detail-sel { display: grid; gap: 0.1rem; padding: 0.45rem 0.625rem; background: var(--soft); border-radius: var(--squircle-md); min-width: 0; }
.detail-sel .label { font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted-foreground); }
.detail-sel .nilai { font-size: 0.875rem; font-weight: 600; overflow-wrap: anywhere; }
.detail-seksi { display: grid; gap: 0.25rem; }
.detail-seksi > strong { font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted-foreground); }
.detail-isi { display: grid; }
.detail-baris { display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; padding: 0.375rem 0; border-top: 1px solid var(--border); font-size: 0.8125rem; }
.detail-baris:first-child { border-top: 0; }
.detail-baris dt { color: var(--muted-foreground); min-width: 0; }
.detail-baris dd { font-weight: 600; text-align: right; overflow-wrap: anywhere; margin: 0; }
.detail-baris.is-total dd { font-size: 1rem; font-weight: 700; }
.amount-chip { display: inline-block; background: var(--soft); border-radius: 0.5rem; padding: 0.15rem 0.5rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.text-danger { color: var(--destructive); }
.text-paid { color: var(--status-paid); }
.text-lime { color: var(--lime-text); }
.text-promo { color: var(--promo-text); }

/* ------------------------------------------------------------------ button */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  height: 2.375rem; padding: 0 0.875rem; border-radius: 0.6875rem;
  border: 1px solid transparent; font: inherit; font-size: 0.875rem; font-weight: 600;
  text-decoration: none; white-space: nowrap;
}
.btn.sm { height: 2rem; padding: 0 0.625rem; font-size: 0.75rem; border-radius: 0.5625rem; }
.btn.lg { height: 2.5rem; padding: 0 1.5rem; }
.btn.block { width: 100%; }
.btn.primary { background: linear-gradient(180deg, #3b82f6, #2563eb 48%, #1d4ed8); border-color: var(--primary-dark); color: #fff; box-shadow: 0 8px 18px -12px rgba(37, 99, 235, 0.9); }
.btn.primary:hover { filter: brightness(1.04); }
.btn.outline { background: var(--card); border-color: var(--border); color: var(--foreground); }
.btn.outline:hover { background: var(--soft); }
.btn.destructive { background: var(--destructive-strong); border-color: #ad1725; color: #fff; }
.btn.destructive.tint { background: var(--danger-soft); border-color: #f3ccd3; color: var(--danger-text); }
.btn.ghost { background: transparent; color: inherit; }
.btn.ghost:hover { background: rgba(127, 127, 127, 0.12); }
.btn[disabled], .btn:disabled { opacity: 0.55; pointer-events: none; }
.icon-btn[disabled], .icon-btn:disabled { opacity: 0.55; pointer-events: none; }
.btn.link { background: none; border: 0; color: var(--primary); height: auto; padding: 0; }
.icon-btn {
  display: inline-grid; place-items: center; width: 2.375rem; height: 2.375rem;
  border-radius: 0.6875rem; border: 1px solid transparent; background: transparent; color: inherit;
}
.icon-btn.sm { width: 2rem; height: 2rem; }
.icon-btn.bordered {
  border-color: transparent; background: var(--card);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 8px 18px -12px rgba(15, 23, 42, 0.35);
}
.icon-btn.bordered:hover { box-shadow: 0 2px 4px rgba(15, 23, 42, 0.08), 0 10px 22px -12px rgba(15, 23, 42, 0.42); }
[data-theme="dark"] .icon-btn.bordered { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 22px -14px rgba(0, 0, 0, 0.85); }
[data-theme="dark"] .icon-btn.bordered:hover { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.45), 0 12px 26px -14px rgba(0, 0, 0, 0.9); }
/* Tombol WhatsApp: warna khas WhatsApp (latar hijau muda, tepi hijau, ikon hijau tua). */
.icon-btn.wa { background: #e7f9ef; border-color: #25d366; color: #128c7e; }
.icon-btn.wa:hover { background: #d6f5e3; }
/* Wadah tombol kanan: tombol tema + lonceng peringatan stok. */
.header-tools { display: inline-flex; align-items: center; gap: 0.375rem; }
#theme-toggle .ikon-gelap { display: grid; }
#theme-toggle .ikon-terang { display: none; }
[data-theme="dark"] #theme-toggle .ikon-gelap { display: none; }
[data-theme="dark"] #theme-toggle .ikon-terang { display: grid; }
.icon-btn:hover { background: rgba(127, 127, 127, 0.12); }
.icon-btn.danger { color: var(--destructive); }
.icon-btn.success { color: var(--status-paid); }
/* Tombol ikon netral yang berwarna saat disentuh (haus: merah, diskon: hijau). */
.icon-btn.danger-soft { color: var(--muted-foreground); }
.icon-btn.danger-soft:hover { color: var(--destructive); background: rgba(185, 28, 28, 0.08); }
.icon-btn.success-soft { color: var(--muted-foreground); }
.icon-btn.success-soft:hover { color: var(--status-paid); background: rgba(15, 158, 80, 0.1); }
.icon-btn.ghost { color: var(--rail-muted); }

/* ------------------------------------------------------------------- forms */
.field { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.3rem; font-size: 0.8125rem; font-weight: 500; }
.field > span { color: var(--foreground); }
.field .hint { font-size: 0.7rem; color: var(--muted-foreground); font-weight: 400; }
input, select, textarea {
  width: 100%; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--card);
  padding: 0.45rem 0.625rem; font: inherit; font-size: 0.8125rem; color: inherit; height: 2.25rem;
}
/* Huruf (terutama placeholder) duduk beberapa piksel di bawah titik tengah
   kotak karena metrik font, sehingga teks tampak agak ke bawah. Padding atas
   dikurangi dan bawah ditambah dengan besar sama supaya teks tampak di tengah.
   Ukuran kotak tidak berubah karena tingginya tetap dan border-box. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]) {
  padding-top: calc(0.45rem - 0.1em);
  padding-bottom: calc(0.45rem + 0.1em);
}
textarea { height: auto; min-height: 6rem; resize: vertical; }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid transparent; outline-offset: 0;
  border-color: var(--primary);
  /* Cincin fokus digambar di dalam kotak supaya tidak terpotong container. */
  box-shadow: inset 0 0 0 1px var(--primary);
}
/* Isian otomatis browser tetap memakai warna aplikasi (bukan kuning/biru bawaan). */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--foreground);
  -webkit-box-shadow: 0 0 0 1000px var(--card) inset;
  caret-color: var(--foreground);
  transition: background-color 5000s ease-in-out 0s;
}
button:focus-visible, a:focus-visible {
  outline: 2px solid transparent; box-shadow: 0 0 0 3px rgba(40, 120, 247, 0.35);
}
input[aria-invalid="true"], .invalid { border-color: #e58794 !important; background: #fffafa; }
.input-inline { width: auto; }
.nominal { text-align: right; font-variant-numeric: tabular-nums; font-weight: 400; }
/* Kolom Jumlah arus kas di Kas Harian: placeholder & teks di kiri (sesuai
   permintaan), berbeda dari kolom nominal lain yang rata kanan. */
#cash-jumlah { text-align: left; }
.form-error { color: var(--destructive); font-size: 0.75rem; font-weight: 500; }
.form-status { color: var(--lime-text); font-size: 0.75rem; font-weight: 500; }
.alert { border: 1px solid rgba(185, 28, 28, 0.3); background: rgba(185, 28, 28, 0.05); border-radius: 1rem; padding: 0.75rem 1rem; font-size: 0.875rem; color: var(--destructive); }
.alert.warning { border-color: #fde68a; background: var(--warning-soft); color: var(--warning-text); }
.alert.success { border-color: #bbf7d0; background: var(--success-soft); color: var(--success-text); }
.radio-group { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.radio-group button {
  border: 1px solid var(--border); background: var(--card); border-radius: 0.625rem;
  padding: 0.35rem 0.75rem; font: inherit; font-size: 0.8125rem; font-weight: 500; color: var(--muted-foreground);
}
.radio-group button.is-active { background: var(--primary); border-color: var(--primary-dark); color: #fff; font-weight: 600; }

/* Baris centang dengan keterangan (mis. opsi di dialog kelola saldo BRILink). */
.check-row {
  display: flex; align-items: flex-start; gap: 0.625rem;
  border: 1px solid var(--border); border-radius: 0.75rem;
  background: var(--card); padding: 0.625rem 0.75rem; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.check-row:hover { border-color: var(--muted-foreground); }
.check-row:has(input:checked) { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 6%, var(--card)); }
.check-row input { width: 1rem; height: 1rem; margin: 0.15rem 0 0; accent-color: var(--primary); flex: none; }
.check-row-text { min-width: 0; }
.check-row-text strong { display: block; font-size: 0.8125rem; font-weight: 600; }
.check-row-text small { display: block; color: var(--muted-foreground); font-size: 0.7rem; line-height: 1.35; }

/* Kalender aplikasi (mis. kolom tanggal di dialog) — desain sama seperti
   pemilih periode Laporan: navigasi bulan + kisi tanggal. */
.date-popover {
  position: fixed; z-index: 90; width: 16.5rem; padding: 0.625rem;
  border: 0; border-radius: var(--squircle-md); background: var(--card);
  box-shadow: 0 20px 44px -14px rgba(12, 14, 19, 0.3);
}
.date-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.15rem; text-align: center; }
.date-grid button {
  border: 0; border-radius: var(--squircle-xs); padding: 0.3rem 0; font: inherit;
  font-size: 0.75rem; background: transparent; color: inherit; cursor: pointer;
}
.date-grid button:hover { background: var(--soft); }
.date-grid button.is-selected { background: var(--primary); color: #fff; font-weight: 600; }
.date-grid .date-weekday { font-size: 0.65rem; color: var(--muted-foreground); }

/* Dropdown kustom (menggantikan tampilan <select> bawaan browser). */
.select { position: relative; display: inline-block; width: 100%; vertical-align: middle; }
.select > select.select-native {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; opacity: 0; pointer-events: none;
}
.select-trigger {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  width: 100%; min-width: 0; height: 2.25rem; padding: 0 0.625rem; border: 1px solid var(--border);
  border-radius: 0.5rem; background: var(--card); color: inherit; font: inherit; font-size: 0.8125rem; text-align: left;
}
/* Teks dropdown sejajar dengan teks input (padding simetris). */
.select-trigger {
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}
.select-trigger:hover { background: var(--soft); }
.select-trigger[aria-expanded="true"] { border-color: var(--primary); }
.select-trigger .select-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.select-trigger .chevron { flex: none; width: 1rem; height: 1rem; color: var(--muted-foreground); transition: transform 0.15s ease; }
.select-trigger[aria-expanded="true"] .chevron { transform: rotate(180deg); }
.select-trigger[disabled] { opacity: 0.55; pointer-events: none; }
.select-panel {
  position: fixed; z-index: 80; min-width: 8rem; max-height: 15rem; overflow-y: auto;
  border: 0; border-radius: var(--squircle-md); background: var(--card);
  box-shadow: 0 20px 44px -14px rgba(12, 14, 19, 0.3); padding: 0.25rem;
}
.select-option {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; width: 100%;
  border: 0; background: transparent; border-radius: 0.5rem; padding: 0.4rem 0.5rem;
  font: inherit; font-size: 0.8125rem; text-align: left; color: inherit;
}
.select-option.is-active { background: var(--soft); }
.select-option[aria-selected="true"] { font-weight: 600; }
.select-option .check { display: grid; place-items: center; color: var(--primary); }
.select-option .check .icon { width: 0.9rem; height: 0.9rem; }
.select-search {
  position: sticky; top: 0; z-index: 1;
  width: 100%; height: 2rem; margin-bottom: 0.25rem; border: 1px solid var(--border);
  border-radius: 0.5rem; padding: 0 0.5rem; font: inherit; font-size: 0.8125rem; background: var(--card);
}
.select-empty { margin: 0.25rem 0.5rem 0.5rem; font-size: 0.75rem; color: var(--muted-foreground); }
.checkbox { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.8125rem; }
.checkbox input { width: auto; height: auto; margin-top: 0.2rem; }

/* Sakelar (switch) tanpa teks untuk mengaktifkan/menonaktifkan rekening. */
.switch {
  position: relative; width: 2.25rem; height: 1.25rem; padding: 0; flex: none;
  border: 1px solid var(--border); border-radius: 999px; background: var(--soft);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.switch .switch-knob {
  position: absolute; top: 2px; left: 2px; width: 0.85rem; height: 0.85rem; border-radius: 999px;
  background: #fff; box-shadow: 0 1px 2px rgba(12, 14, 19, 0.25); transition: transform 0.15s ease;
}
.switch[aria-checked="true"] { background: var(--status-paid); border-color: #0d8a45; }
.switch[aria-checked="true"] .switch-knob { transform: translateX(1rem); }
.switch[disabled] { opacity: 0.55; pointer-events: none; }
/* ------------------------------------- POS: kartu keranjang & lencana ikon */
/* Kartu keranjang meregang setinggi kolom katalog; blok total menempel dasar. */
.pos-cart-card { height: 100%; display: flex; flex-direction: column; position: relative; }
.pos-cart-card > .card-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* Semua bagian kartu keranjang tetap pada ukurannya; hanya daftar item yang
   menggulir, sehingga tombol Simpan/Kosongkan/Bayar tidak pernah terpotong. */
.pos-cart-card > .card-body > * { flex: none; }
.pos-cart-card > .card-body > .cart-lines { flex: 1 1 auto; }
/* Katalog tidak ikut meregang: bila keranjang lebih panjang, katalog tetap
   setinggi isinya (tidak tertarik ke bawah). */
.pos-catalog-column { align-self: start; }
.icon-badge { position: relative; }
.icon-badge-count {
  position: absolute; top: -0.3rem; right: -0.3rem; min-width: 1.1rem; padding: 0 0.25rem;
  border-radius: 999px; background: var(--primary); color: #fff; font-size: 0.65rem;
  font-weight: 700; line-height: 1.1rem; text-align: center;
}
.icon-badge-count[hidden] { display: none; }

/* ------------------------------------------------------------------- tabs */
.tabs { display: flex; gap: 0.25rem; overflow-x: auto; background: var(--soft); border-radius: var(--squircle-md); padding: 0.25rem; }
/* Baris tab kategori POS diisi setelah data katalog termuat: tinggi minimum
   dijaga supaya tata letak (dan tinggi kartu keranjang) tidak melompat. */
#pos-category-tabs { min-height: 2.5rem; }
.tab {
  border: 0; background: transparent; border-radius: var(--squircle-sm); padding: 0.4rem 0.8rem;
  font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--muted-foreground); white-space: nowrap;
}
.tab.is-active { background: var(--card); color: var(--foreground); box-shadow: var(--shadow); }
/* Metode pembayaran POS: tiap tombol mengisi lebar yang tersedia sehingga
   keempatnya rata memenuhi baris. */
#pos-method-tabs .tab { flex: 1 1 0; text-align: center; }

/* ----------------------------------------------------------------- tables */
.table-wrap { overflow-x: auto; }
table.table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
table.table th {
  background: transparent; text-align: left; font-size: 0.72rem; color: var(--muted-foreground);
  text-transform: none; font-weight: 600; padding: 0.55rem 0.75rem; white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
table.table td { border-top: 1px solid var(--border); padding: 0.6rem 0.75rem; vertical-align: middle; }
table.table tr.is-muted td { opacity: 0.6; }
table.table td.num, table.table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Kolom aksi yang rata kanan (mis. tombol mata di riwayat sesi kas): aturan
   tabel di atas membuat th selalu rata kiri, jadi perlu penegasan di sini. */
table.table th.right, table.table td.right { text-align: right; }
table.table tfoot td { font-weight: 700; background: #fafafa; border-top: 1px solid var(--border); }
table.table .empty-cell { text-align: center; color: var(--muted-foreground); font-size: 0.75rem; padding: 1.25rem; }
/* Tab hak akses (Pengaturan): baris lega, kolom modul tegas, centang di tengah. */
#access-rows td { padding: 0.7rem 0.75rem; }
#access-rows td:first-child { font-weight: 600; }
#access-rows td:not(:first-child) { text-align: center; }
#access-rows input[type="checkbox"] { margin: 0 auto; }
/* Baris rincian sesi kas: rapi, tidak memicu gulir horizontal. */
.session-row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem;
  border: 0; background: var(--soft); border-radius: var(--squircle-md); padding: 0.5rem 0.625rem; min-width: 0;
}
.session-row-text { display: grid; gap: 0.15rem; min-width: 0; }
.session-row-top { display: flex; align-items: center; flex-wrap: wrap; gap: 0.35rem; font-size: 0.8125rem; }
.session-row-note { overflow-wrap: anywhere; }
.session-row > strong { white-space: nowrap; }
/* Ringkasan dialog sesi kas: kolom boleh menyusut dan nilai panjang dilipat
   rapi supaya label dan nominal tidak saling menumpuk. Tata kolomnya diatur
   layoutTwoColumns() seperti dialog lain (kolom kiri diisi lebih dulu). */
#session-detail-summary > div { min-width: 0; }
#session-detail-summary dt, #session-detail-summary dd { min-width: 0; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------- modals */
dialog.modal {
  border: 0; border-radius: var(--squircle-xl); background: var(--card); color: var(--foreground);
  padding: 1.25rem; width: min(28rem, calc(100vw - 2rem)); box-shadow: 0 24px 64px -18px rgba(12, 14, 19, 0.4);
}
dialog.modal.sm { width: min(22rem, calc(100vw - 2rem)); }
dialog.modal.lg { width: min(36rem, calc(100vw - 2rem)); }
/* Dialog lebar untuk tabel banyak kolom (mis. daftar transaksi per periode). */
dialog.modal.xl { width: min(64rem, calc(100vw - 2rem)); }
dialog.modal::backdrop { background: rgba(12, 14, 19, 0.55); }
.modal-title { font-size: 1.125rem; font-weight: 600; }
.modal-desc { margin-top: 0.25rem; font-size: 0.875rem; color: var(--muted-foreground); }
.modal-body { margin-top: 1rem; display: grid; gap: 0.75rem; max-height: min(65vh, 34rem); overflow-y: auto; padding: 2px; }
/* Isi grid boleh menyusut supaya tabel di dalam dialog menggulir sendiri
   (tanpa aturan ini tabel melebar ke luar dialog dan kolom kanan tak terlihat). */
.modal-body > * { min-width: 0; }
@media (min-width: 1024px) { dialog.modal.xl .modal-body { max-height: min(75vh, 44rem); } }
/* Dialog transaksi layanan BRILink: beri ruang lebih supaya form pelanggan baru
   muat utuh tanpa gulir sendiri selama tinggi layar mencukupi. */
#service-modal .modal-body { max-height: min(78vh, 42rem); }
.modal-actions { margin-top: 1rem; display: flex; justify-content: flex-end; gap: 0.5rem; }
.modal-actions .spacer { flex: 1; }
dl.deflist { display: grid; gap: 0.35rem; margin: 0; }
/* Ringkasan transaksi dua kolom supaya daftar produk di bawahnya lebih lega.
   Kolom kiri diisi lebih dulu; kolom kanan rata bawah (saat jumlahnya ganjil
   kolom kanan tidak ikut mengisi baris pertama) — posisinya diatur lewat
   layoutTwoColumns(). */
dl.deflist.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: column; column-gap: 1.5rem; row-gap: 0.35rem; }
dl.deflist > div { display: flex; justify-content: space-between; gap: 0.75rem; font-size: 0.8125rem; }
dl.deflist dt { color: var(--muted-foreground); }
dl.deflist dd { margin: 0; font-weight: 500; text-align: right; }
.def-block { border: 0; background: var(--soft); border-radius: var(--squircle-md); padding: 0.625rem 0.75rem; }
.item-list { display: grid; gap: 0.5rem; }
.item-row { display: flex; justify-content: space-between; gap: 0.75rem; font-size: 0.8125rem; }
.item-row .item-name { font-weight: 600; }
.item-row .item-sub { font-size: 0.72rem; color: var(--muted-foreground); }
/* Nominal laba/fee di daftar transaksi Laporan: hijau tanpa keterangan. */
.laba-chip { color: var(--status-paid); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Penjualan yang masih piutang: labanya belum masuk hitungan (kuning). */
.laba-chip.is-pending { color: var(--status-due); }
.status-dot.is-paid { background: var(--status-paid); }
.status-dot.is-due { background: var(--status-due); }
/* Perubahan warna state (status, chip, nominal) dibuat halus. */
.amount-chip, .pill, .tag, .chip, .status-dot { transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease; }

/* ------------------------------------------------- lonceng peringatan stok */
.stock-popover {
  position: fixed; z-index: 50; padding: 0.75rem;
  width: min(21.25rem, calc(100vw - 1.5rem));
  max-height: calc(100vh - 1.5rem);
  max-height: calc(100dvh - 1.5rem);
  overflow-y: auto;
  box-shadow: 0 14px 32px rgba(12, 14, 19, 0.16);
}
/* Ponsel: panel itu sendiri yang menggulir — gutter scrollbar dipesan agar
   isi tidak bergeser saat scrollbar muncul. Di desktop daftarnya yang
   menggulir (lihat aturan di bawah), sehingga gutter panel hanya akan
   menyisakan ruang kosong di kanan. */
@media (max-width: 899px) {
  .stock-popover { scrollbar-gutter: stable; }
}
/* Daftar produk bermasalah. Layar kecil: maksimal 4 produk (tanpa gulir
   sendiri). Layar desktop: semua produk tampil dan daftarnya bisa digulir
   sendiri supaya judul panel tetap terlihat. */
.stock-popover-list { display: grid; gap: 0.375rem; max-height: none; overflow: visible; padding-right: 0.125rem; }
@media (min-width: 900px) {
  .stock-popover-list { max-height: min(58vh, 24rem); overflow-y: auto; }
}
.stock-item {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  border: 0; background: var(--card); border-radius: var(--squircle-md);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
  padding: 0.45rem 0.6rem; transition: background-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.stock-item:hover { background: var(--soft); }
.stock-item-text { display: grid; gap: 0.1rem; min-width: 0; }
.stock-item-text strong { font-size: 0.8125rem; }
.stock-item .chip, .stock-item .pill { flex: none; }
/* Tag status stok (dipakai di notifikasi lonceng & Master Data - Stok). */
.stock-tag {
  display: inline-flex; align-items: center; border-radius: 999px;
  padding: 0.1rem 0.5rem; font-size: 0.65rem; font-weight: 600;
  border: 1px solid transparent; white-space: nowrap;
}
.stock-tag.is-habis { background: var(--tint-red); color: var(--danger-text); border-color: var(--tint-red-line); }
.stock-tag.is-menipis { background: var(--tint-amber); color: var(--warning-text); border-color: var(--tint-amber-line); }
.stock-tag.is-aman { background: var(--tint-green); color: var(--success-text); border-color: var(--tint-green-line); }
.stock-all { width: 100%; justify-content: center; margin-top: 0.125rem; }
/* Popup lonceng: animasi buka (sedikit turun + memudar) dan tutup
   (kebalikannya) supaya tidak muncul/hilang mendadak. */
@keyframes stock-pop-in { from { opacity: 0; transform: translateY(-6px) scale(0.985); } to { opacity: 1; transform: none; } }
@keyframes stock-pop-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-6px) scale(0.985); } }
.stock-popover.stock-pop-enter { animation: stock-pop-in 0.2s var(--ease-out) both; }
.stock-popover.stock-pop-leave { animation: stock-pop-out 0.15s var(--ease-out) both; }
/* Baris produk yang disorot dari lonceng stok. */
@keyframes row-flash { 0%, 100% { background: transparent; } 25%, 65% { background: rgba(21, 88, 200, 0.12); } }
table.table tbody tr.row-flash { animation: row-flash 2.2s var(--ease-out) both; }

/* Layar tablet ke bawah: keranjang selebar layar dan boleh memanjang,
   sehingga item yang terlihat tidak hanya satu atau dua. */
@media (max-width: 1279px) {
  .pos-cart-card { max-height: none; }
  .cart-lines { max-height: none; overflow: visible; }
  .pos-catalog-column .catalog-scroll { max-height: 60vh; }
}

/* Daftar pesanan: dua kolom bila layar cukup lebar. */
.orders-grid { display: grid; gap: 0.75rem; grid-template-columns: minmax(0, 1fr); }
/* Halaman Pesanan: tiap kartu pesanan memakai garis tepi kembali agar
   batas tiap pesanan jelas (kartu lain tetap tanpa tepi). */
.orders-grid > article.card {
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}
@media (min-width: 1100px) { .orders-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Tombol kosongkan pada input nominal pembayaran dan kolom pencarian. */
.input-clear { position: relative; display: block; }
.search-clear { max-width: 100%; }
.input-clear input { padding-right: 2.2rem; }
.input-clear-btn {
  position: absolute; right: 0.3rem; top: 50%; transform: translateY(-50%);
  width: 1.5rem; height: 1.5rem; padding: 0; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 999px; background: var(--soft); color: var(--muted-foreground);
  line-height: 1; cursor: pointer;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}
.input-clear-btn .icon { width: 0.9rem; height: 0.9rem; }
.input-clear-btn:hover { background: #e4e5e8; border-color: #cfd3da; color: var(--foreground); }
/* Ikon "x" bawaan browser pada kolom pencarian dimatikan: tombol di atas
   dipakai supaya tampilannya sama dan lebih jelas di semua perangkat. */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { -webkit-appearance: none; appearance: none; }
/* Nominal cepat: "Uang Pas" lebar dua kolom + penambah pecahan rapi kiri-kanan. */
.quick-cash { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.375rem; width: 100%; }
/* Angka nominal harus muat di dalam tombolnya (tidak keluar dari kotak). */
.quick-cash .btn {
  justify-content: center; padding-left: 0.3rem; padding-right: 0.3rem;
  font-size: 0.72rem; min-width: 0;
}
.quick-cash [data-exact-amount] { grid-column: span 2; }
/* Dialog sempit (ponsel): 3 kolom supaya nominal tetap muat. */
@media (max-width: 430px) {
  .quick-cash { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .quick-cash [data-exact-amount] { grid-column: span 3; }
}

/* ------------------------------------------------------------------ toast */
.toast-stack { position: fixed; top: 1rem; right: 1rem; z-index: 60; display: grid; gap: 0.5rem; width: min(22rem, calc(100vw - 2rem)); }
.toast {
  display: flex; gap: 0.625rem; align-items: flex-start;
  border: 0; border-radius: var(--squircle-md); background: var(--card);
  padding: 0.75rem 0.875rem; box-shadow: 0 16px 34px -12px rgba(12, 14, 19, 0.24);
}
.toast .toast-icon { flex: none; display: grid; place-items: center; width: 1.5rem; height: 1.5rem; border-radius: 999px; }
.toast .toast-icon .icon { width: 0.9rem; height: 0.9rem; }
.toast.info .toast-icon { background: #e8f1fe; color: #1a63d8; }
.toast.success { border-color: #cdebd8; }
.toast.success .toast-icon { background: #e5f7ec; color: #14803f; }
.toast.destructive { border-color: #f3ccd3; }
.toast.destructive .toast-icon { background: #fdecef; color: #b91c1c; }
.toast strong { font-size: 0.8125rem; display: block; }
.toast p { font-size: 0.75rem; color: var(--muted-foreground); margin-top: 0.1rem; }
.toast button { border: 0; background: none; color: var(--muted-foreground); padding: 0; line-height: 1; display: grid; place-items: center; }
.toast button .icon { width: 0.95rem; height: 0.95rem; }
.toast button:hover { color: var(--foreground); }
@keyframes toast-shake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-6px); } 40% { transform: translateX(6px); } 60% { transform: translateX(-4px); } 80% { transform: translateX(4px); } }
.toast.shake { animation: toast-shake 0.45s ease-in-out; }
@media (prefers-reduced-motion: reduce) { .toast.shake { animation: none; } }

/* ---------------------------------------------------------------- tooltip */
.tooltip-layer {
  position: fixed; z-index: 70; background: var(--card); color: var(--foreground);
  border: 0; border-radius: var(--squircle-xs); padding: 0.3rem 0.5rem;
  font-size: 0.7rem; box-shadow: 0 10px 24px -8px rgba(12, 14, 19, 0.24); pointer-events: none;
}

/* ------------------------------------------------------------------ empty */
.empty { text-align: center; padding: 2.5rem 1.25rem; border: 1px dashed var(--border); background: transparent; border-radius: var(--squircle-lg); }
.empty strong { display: block; font-size: 0.9rem; }
.empty p { margin-top: 0.25rem; font-size: 0.75rem; color: var(--muted-foreground); }
/* Keranjang POS kosong: ikon troli besar, latar putih dengan garis tepi. */
.empty-cart {
  background: var(--card); border: 1px solid var(--border);
  border-radius: 0.875rem; padding: 1.75rem 1rem;
}
/* Kotak keranjang kosong mengisi sisa tinggi kartu (tanpa menempel ke blok
   total di bawahnya). Tingginya stabil karena tinggi kartu sudah tetap. */
.pos-cart-card > .card-body > .empty-cart {
  flex: 1 1 auto; display: grid; align-content: center;
  min-height: 11.5rem; margin-bottom: 0.75rem;
}
/* Katalog diberi tinggi tetap (setinggi batas gulirnya) di layar lebar supaya
   tinggi kartu keranjang tidak berubah ketika produk selesai dimuat — termasuk
   saat halaman Penjualan baru dibuka. */
@media (min-width: 1280px) { .pos-catalog-column .catalog-scroll { min-height: 65vh; } }
@media (min-width: 1024px) and (max-width: 1279px) { .pos-catalog-column .catalog-scroll { min-height: 60vh; } }
/* Selagi katalog dimuat (atau tidak ada hasil), blok pesan memakai tinggi yang
   sama supaya tinggi kartu keranjang tidak melompat saat katalog muncul. */
@media (min-width: 1280px) { #pos-catalog-empty:not([hidden]) { min-height: 65vh; display: grid; align-content: center; } }
@media (min-width: 1024px) and (max-width: 1279px) { #pos-catalog-empty:not([hidden]) { min-height: 60vh; display: grid; align-content: center; } }
.empty-cart-icon {
  display: grid; place-items: center; width: 3.25rem; height: 3.25rem; margin: 0 auto 0.625rem;
  border-radius: 1rem; background: var(--tint-blue-bg); color: var(--tint-blue-icon);
}
.empty-cart-icon svg { width: 1.6rem; height: 1.6rem; }
.empty-page { min-height: 80vh; display: grid; place-content: center; gap: 0.5rem; text-align: center; }
.empty-page .mono { font-family: var(--font-mono); color: var(--muted-foreground); }

/* ------------------------------------------------------------------- auth */
.auth-page { background: var(--background); }
.auth-page .content { padding-left: 0; }
.auth-page .main { padding: 2rem 1rem; min-height: 100vh; display: grid; align-content: center; justify-items: center; position: relative; }
.auth-wrap { max-width: 26rem; width: 100%; display: grid; gap: 1rem; }
/* Catatan kecil dipatok di bawah agar kartu login tepat di tengah layar. */
.auth-note { position: absolute; left: 0; right: 0; bottom: 1.5rem; text-align: center; margin: 0 auto; padding: 0 1rem; }
.auth-card { border: 0; background: var(--card); border-radius: var(--squircle-xl); padding: 1.5rem; box-shadow: var(--card-shadow); }
/* Kartu login memudar saat berpindah ke halaman berikutnya. */
.auth-card.is-leaving { opacity: 0; transform: translateY(-6px); transition: opacity 0.2s ease, transform 0.2s ease; }
.auth-brand { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 1.25rem; }
.auth-brand .brand-mark { background: var(--rail); color: #fff; }
/* Header login: rata tengah memakai logo struk + identitas toko. */
.auth-brand-center { flex-direction: column; text-align: center; gap: 0.5rem; margin-bottom: 0.875rem; }
.auth-brand-center .brand-mark { width: 4rem; height: 4rem; border-radius: 1rem; font-size: 1.5rem; }
.auth-logo { display: grid; place-items: center; width: 100%; max-width: 12rem; }
.auth-logo img { max-width: 100%; max-height: 4.5rem; object-fit: contain; display: block; }
.auth-brand-text { display: grid; gap: 0.1rem; }
.auth-brand-text strong { font-size: 1.125rem; }
.auth-brand-text small { display: block; font-size: 0.75rem; color: var(--muted-foreground); }
.auth-heading { text-align: center; }
.auth-heading h1 { margin-top: 0; }
.auth-card h1 { font-size: 1.35rem; }
.auth-card .kicker { margin-bottom: 0.35rem; }
.auth-card form { margin-top: 0.875rem; }
.auth-footer { margin-top: 1rem; font-size: 0.8125rem; color: var(--muted-foreground); }
/* Keterangan sesi berakhir: tanpa garis, tenang, dan diletakkan setelah tombol
   Masuk supaya tidak menggeser posisi formulir. */
.auth-notice {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0.875rem 0.125rem 0;
  border: 0;
  border-radius: 0.75rem;
  padding: 0.625rem 0.75rem;
  background: var(--line);
  color: var(--muted-foreground);
  font-size: 0.78rem;
  line-height: 1.45;
}
.auth-notice .icon { width: 0.95rem; height: 0.95rem; margin-top: 0.0625rem; color: var(--primary); opacity: 0.9; }
.auth-notice + .auth-footer { margin-top: 0.625rem; }
[data-theme="dark"] .auth-notice { background: rgba(148, 163, 184, 0.12); }
.auth-note { text-align: center; font-size: 0.72rem; color: var(--muted-foreground); }

/* ----------------------------------------------------------- layar sambutan */
/* Transisi setelah masuk: satu layar penuh sebelum Dashboard. Halaman ini
   berdiri sendiri (tanpa kerangka aplikasi), mengikuti tema terang/gelap, dan
   sengaja tidak menampilkan apa pun dari Dashboard di belakangnya. */
.welcome-page { background: var(--background); }
/* Selama penutup aktif: gulir dikunci TANPA melepas ruang scrollbar, supaya
   lebar tata letak Dashboard sama persis sebelum dan sesudah penutup dibuka
   (tidak ada lompatan lebar saat scrollbar muncul). Penutup sendiri dilebarkan
   ke 100vw agar menutupi termasuk kolom scrollbar itu. */
html.sambutan-aktif { overflow: hidden; }
html.sambutan-aktif .content { animation: none; }
/* Setelah penutup dibuka, animasi masuk halaman tetap dimatikan: halaman itu
   memang sudah selesai tergambar selama penutup aktif. */
html.sambutan-selesai .content { animation: none; }
.welcome-screen {
  position: fixed; inset: 0; z-index: 110; overflow: hidden;
  /* 100vw: ikut menutupi kolom scrollbar yang ruangnya tetap disisakan
     (scrollbar-gutter: stable) supaya lebar halaman tidak berubah. */
  width: 100vw;
  display: grid; place-items: center;
  padding: 1.25rem;
  background: var(--background);
}
/* Kilau biru tipis di bagian atas supaya layar tidak terasa kosong. */
.welcome-screen::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(58% 42% at 50% -8%, rgba(37, 99, 235, 0.1), rgba(37, 99, 235, 0) 72%);
}
/* PENTING: penutup sudah menutup penuh sejak frame pertama (tanpa opacity 0).
   Kalau penutup baru memudar masuk dari transparan, Dashboard di belakangnya
   sempat terlihat sekejap. Yang dianimasikan hanya isinya (logo & teks). */
.welcome-screen.is-out { opacity: 0; transition: opacity 0.34s ease; }
/* Logo aplikasi: di area atas, tidak menempel tepi dan tidak terlalu tinggi.
   Batas atas mengikuti tinggi layar, tetapi tidak melewati ruang teks tengah. */
.welcome-top {
  position: absolute; left: 50%; top: clamp(2.5rem, min(23vh, calc(50% - 9rem)), 11rem);
  transform: translateX(-50%);
  display: grid; place-items: center;
}
/* Teks: tepat di tengah layar (sejajar mata pengguna). */
.welcome-center {
  position: relative; width: min(56rem, 92vw);
  display: grid; justify-items: center; text-align: center; gap: 0.5rem;
}
/* Isi penutup terlihat sejak awal (aman bila skrip gagal); animasi masuknya
   dijalankan lewat kelas `is-in` dari assets/pages/welcome.js. */
@keyframes sambutan-masuk {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to { opacity: 1; transform: none; }
}
@keyframes sambutan-pudar { from { opacity: 0; } to { opacity: 1; } }
/* Logo ikut digeser mendatar, jadi animasinya mempertahankan transform itu. */
@keyframes sambutan-logo {
  from { opacity: 0; transform: translateX(-50%) translateY(8px) scale(0.97); }
  to { opacity: 1; transform: translateX(-50%); }
}
/* Isi penutup: animasi masuk dijalankan langsung dari CSS (bukan menunggu
   kelas dari skrip) supaya tidak ada kedip "tampil → hilang → muncul".
   `both` membuat elemen mulai dari keadaan transparan lalu mengendap terlihat,
   dan tetap terlihat walau skrip gagal. */
.welcome-top { animation: sambutan-logo 0.52s var(--ease-out) 0.06s both; }
.welcome-center { animation: sambutan-pudar 0.5s ease 0.1s both; }
.welcome-title { animation: sambutan-masuk 0.56s var(--ease-out) 0.18s both; }
.welcome-sub { animation: sambutan-masuk 0.56s var(--ease-out) 0.28s both; }
.welcome-loader { animation: sambutan-masuk 0.5s var(--ease-out) 0.38s both; }

/* Logo aplikasi di tengah atas. */
.welcome-logo { display: block; max-width: 13rem; max-height: 4.25rem; object-fit: contain; }
.welcome-mark { width: 3.75rem; height: 3.75rem; font-size: 1.5rem; background: var(--rail); color: #fff; }
/* Judul: "Selamat datang," dan nama pengguna selalu utuh dalam satu baris.
   Bila keduanya tidak muat, nama turun sendiri ke baris berikutnya. */
.welcome-title {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline;
  column-gap: 0.35em; row-gap: 0.02em; max-width: 100%;
  font-size: clamp(1.375rem, 3.4vw, 1.875rem); font-weight: 650; letter-spacing: -0.02em;
}
.welcome-hello, .welcome-name { white-space: nowrap; }
.welcome-name { color: var(--primary); }
.welcome-sub { font-size: clamp(0.875rem, 2.4vw, 1rem); color: var(--muted-foreground); }
/* Indikator pemuatan yang sangat halus. */
.welcome-loader { display: inline-flex; align-items: center; gap: 0.375rem; margin-top: 1.125rem; }
.welcome-loader i {
  width: 0.375rem; height: 0.375rem; border-radius: 999px; corner-shape: round;
  background: var(--primary); opacity: 0.24;
  animation: sambutan-titik 1.15s ease-in-out infinite;
}
.welcome-loader i:nth-child(2) { animation-delay: 0.16s; }
.welcome-loader i:nth-child(3) { animation-delay: 0.32s; }
@keyframes sambutan-titik {
  0%, 100% { opacity: 0.2; transform: none; }
  45% { opacity: 0.8; transform: translateY(-2px); }
}
/* Keterangan untuk pembaca layar (tidak terlihat). */
.welcome-status {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Gerak dikurangi: konten tampil tanpa animasi. */
@media (prefers-reduced-motion: reduce) {
  .welcome-screen, .welcome-center, .welcome-center > *,
  .welcome-top, .welcome-title, .welcome-sub, .welcome-loader {
    opacity: 1; animation: none;
  }
  .welcome-top { transform: translateX(-50%); }
}

/* ------------------------------------------------------------------- POS */
.pos-grid { display: grid; gap: 0.75rem; align-items: stretch; }
/* Kolom POS mengisi baris grid; kartu di dalamnya mengisi kolom lewat flex.
   Dengan begitu tinggi kartu keranjang mengikuti baris grid (stabil) — bukan
   tinggi kontennya sendiri yang membuatnya sempat "pendek" sesaat setelah
   halaman dibuka. */
.pos-grid > section.stack { display: flex; flex-direction: column; min-width: 0; }
.pos-grid > section.stack > .card { flex: 1 1 auto; height: auto; min-width: 0; }
@media (min-width: 1280px) { .pos-grid { grid-template-columns: minmax(0, 1fr) 24rem; } }
.product-grid { display: grid; gap: 0.75rem; grid-auto-rows: 1fr; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1536px) { .product-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.catalog-scroll { max-height: 65vh; overflow-y: auto; padding: 6px 0 0; scrollbar-width: none; }
/* Scrollbar bawaan katalog disembunyikan; dipakai batang kustom tipis di tepi
   kanan kolom supaya lebar katalog rata dengan kotak pencarian di atasnya. */
.pos-catalog-column { position: relative; }
.catalog-scroll::-webkit-scrollbar { width: 0; height: 0; }
.catalog-scrollbar {
  /* Tepat di tengah celah antara katalog dan keranjang. */
  position: absolute; right: calc(-1 * (0.75rem + 0.3125rem) / 2); width: 0.3125rem;
  border-radius: 999px; corner-shape: round;
  background: var(--scrollbar-thumb); opacity: 0; z-index: 2;
  transition: opacity 0.28s ease; pointer-events: none;
}
.catalog-scrollbar.is-tampil { opacity: 1; pointer-events: auto; cursor: grab; }
.catalog-scrollbar.is-seret { cursor: grabbing; opacity: 1; }
/* Kartu katalog muncul berurutan saat filter berubah. */
@keyframes catalog-card-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* Animasi masuk kartu katalog dipasang per kartu oleh skrip (hanya kartu yang
   terlihat) supaya filter tetap mulus di perangkat sentuh. Daftar secara
   keseluruhan memudar sebagai satu lapisan (murah) agar tidak terlihat
   "berkedip" saat isinya diganti. */
@keyframes catalog-fade-in { from { opacity: 0.35; } to { opacity: 1; } }
.catalog-fade { animation: catalog-fade-in 0.18s ease both; }
.catalog-card-enter { animation: catalog-card-in 0.2s var(--ease-out) both; }
@keyframes tab-pop { 0% { transform: scale(0.94); } 60% { transform: scale(1.03); } 100% { transform: none; } }
.tab-pop { animation: tab-pop 0.18s var(--ease-out); }

/* Isi tab/panel yang baru ditampilkan (opacity agar aman untuk elemen fixed). */
@keyframes content-in { from { opacity: 0; } to { opacity: 1; } }
.content-enter { animation: content-in 0.22s var(--ease-out) both; }
/* Panel dropdown yang sedang menutup. */
.select-panel.is-closing { animation: menu-out 0.11s ease both; }
@keyframes menu-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-3px) scale(0.98); } }
/* Baris tabel yang baru ditambahkan (mis. "Muat 5 transaksi lainnya"):
   muncul halus dari sorotan biru pudar, tanpa mengubah posisi baris lain. */
@keyframes row-in {
  from { opacity: 0; background-color: rgba(21, 88, 200, 0.09); }
  to { opacity: 1; background-color: transparent; }
}
table.table tbody tr.row-enter { animation: row-in 0.5s var(--ease-out) both; }
.orders-grid > article.row-enter { animation: row-in 0.5s var(--ease-out) both; }
/* Baris/kartu yang muncul setelah filter, pencarian, atau ganti tab.
   Kartu memakai animasi memudar tanpa mengubah latar: animasi yang mengubah
   background-color membuat latar kartu sempat transparan lalu kembali
   (terlihat berkedip, terutama saat kursor menghampiri kartu). */
.row-enter { animation: row-in 0.5s var(--ease-out) both; }
@keyframes card-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.card-enter { animation: card-in 0.28s var(--ease-out) both; }
/* Tombol yang sedang memuat data tambahan. */
@keyframes busy-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
.btn.is-busy { pointer-events: none; }
.btn.is-busy .icon { animation: busy-pulse 0.9s ease-in-out infinite; }
/* Kartu produk: tinggi seragam semua kartu. Baris grid dipaksa sama tinggi
   (grid-auto-rows). Blok NAMA memakai ruang 2 baris (maksimal 2 baris) supaya
   baris stok, harga, dan promo selalu sejajar antar kartu dan tidak ada ruang
   menggantung di bawah promo. */
/* Sel kartu ikut meregang agar semua kartu dalam satu baris sama tinggi. */
.product-grid > [data-product-card] { display: flex; min-width: 0; }
.product-card .name {
  font-size: 0.8125rem; font-weight: 600;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden; min-height: 2.9em;
}
/* Baris pendukung selalu satu baris supaya tinggi kartu tidak berubah. */
.product-card .cat,
.product-card .meta,
.product-card .promo { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Slot promo: baris kecil di bawah harga — kosong pun tetap memakai tinggi
   yang sama supaya tata letak dalam kartu identik. */
.product-card .promo { font-size: 0.7rem; color: var(--promo-text); font-weight: 600; min-height: 1.02rem; }
.product-card {
  position: relative; text-align: left; border: 0; background: var(--card);
  border-radius: var(--squircle-md); padding: 0.625rem 2.25rem 0.625rem 0.75rem; display: grid; gap: 0.15rem;
  align-content: start; height: 100%; width: 100%; min-width: 0; font: inherit;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05), 0 5px 12px -10px rgba(15, 23, 42, 0.3);
}
/* Hover kartu katalog: cincin DI DALAM kartu (tanpa bayangan yang menjulur ke
   luar) supaya efeknya tidak pernah terpotong tepi area gulir — termasuk kartu
   paling bawah yang rata dengan keranjang. */
.product-card:hover { background: var(--soft); box-shadow: inset 0 0 0 2px var(--primary); }
.product-card[aria-disabled="true"] { opacity: 0.6; }
.product-card .cat { font-size: 0.65rem; font-weight: 700; }
.product-card .meta { font-size: 0.72rem; color: var(--muted-foreground); }
.product-card .price { font-size: 0.875rem; font-weight: 700; }
.product-card .price small { font-weight: 500; color: var(--muted-foreground); }
/* (slot promo diatur di blok "kartu produk" di atas) */
.fav-btn { position: absolute; z-index: 1; top: 0.35rem; right: 0.35rem; width: 1.9rem; height: 1.9rem; border-radius: 0.5rem; border: 0; background: transparent; color: #c9cbd1; display: grid; place-items: center; }
.fav-btn.is-fav { color: #d97706; }
.fav-btn:hover { background: rgba(127,127,127,0.12); }
.cart-lines { display: grid; gap: 0.5rem; align-content: start; flex: 1 1 auto; min-height: 0; max-height: none; overflow-y: auto; list-style: none; margin: 0 0 0.5rem; padding: 0 0 0.35rem; scrollbar-width: none; }
/* Scrollbar bawaan daftar keranjang disembunyikan; dipakai batang kustom
   (`.cart-scrollbar`) yang mengapung di tepi kanan — lebar baris produk tetap
   penuh, tidak terpotong scrollbar — dengan ujung bulat penuh. */
.cart-lines::-webkit-scrollbar { width: 0; height: 0; }
.cart-scrollbar {
  position: absolute; right: 0.3125rem; width: 0.375rem; border-radius: 999px; corner-shape: round;
  background: var(--scrollbar-thumb); opacity: 0; z-index: 2;
  transition: opacity 0.28s ease; pointer-events: none;
}
.cart-scrollbar.is-tampil { opacity: 1; pointer-events: auto; cursor: grab; }
.cart-scrollbar.is-seret { cursor: grabbing; opacity: 1; }
/* Baris produk yang baru masuk: muncul halus (memudar + mengembang sedikit).
   Tanpa gerakan naik/turun supaya tidak terlihat seperti dua pergerakan saat
   kartu ikut memanjang dan daftar menggulir. */
@keyframes line-masuk {
  from { opacity: 0; transform: scale(0.982); }
  to { opacity: 1; transform: none; }
}
.line.line-masuk { animation: line-masuk 0.3s cubic-bezier(0.22, 1, 0.36, 1) both; }
/* Baris produk yang dihapus: memudar + bergeser keluar dulu. */
@keyframes line-keluar {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateX(0.75rem) scale(0.985); }
}
.line.line-keluar { animation: line-keluar 0.2s cubic-bezier(0.4, 0, 1, 1) both; pointer-events: none; }
/* Tabel BRILink: lebar kolom dikunci lewat JS (dari lebar alami data + sedikit
   kelonggaran) supaya tidak bergeser saat baris baru dimuat. */

/* Kotak "Keranjang masih kosong" muncul kembali dengan halus. */
@keyframes keranjang-kosong-masuk {
  from { opacity: 0; transform: translateY(0.4rem) scale(0.98); }
  to { opacity: 1; transform: none; }
}
.empty-cart.empty-masuk { animation: keranjang-kosong-masuk 0.34s cubic-bezier(0.22, 1, 0.36, 1) both; }
/* Tombol keranjang (Simpan/Kosongkan/Bayar): status aktif/nonaktif berubah
   dengan halus, dan berdenyut kecil saat kembali aktif. */
#pos-save-btn:disabled, #pos-clear-btn:disabled, #pos-pay-btn:disabled { filter: saturate(0.6); }
@keyframes tombol-denyut {
  0% { transform: scale(1); }
  45% { transform: scale(1.045); }
  100% { transform: scale(1); }
}
.btn.btn-denyut { animation: tombol-denyut 0.3s cubic-bezier(0.22, 1, 0.36, 1); }
/* Kartu katalog yang datanya berubah (mis. stok berkurang setelah penjualan)
   diberi kilau halus — daftar tidak digambar ulang. */
@keyframes katalog-berubah {
  0% { box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.45), var(--card-shadow); }
  100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0), var(--card-shadow); }
}
.product-card.card-update { animation: katalog-berubah 0.7s ease both; }
/* Layar kecil (ponsel): bayangan kartu dipertegas supaya tetap terlihat. */
@media (max-width: 767px) {
  html:not([data-theme="dark"]) {
    --card-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 12px 26px -16px rgba(15, 23, 42, 0.5);
  }
}
.line { border: 1px solid var(--border); background: transparent; border-radius: var(--squircle-md); padding: 0.5rem 0.625rem; display: grid; gap: 0.4rem; min-width: 0; }
.line-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.25rem 0.5rem; min-width: 0; }
.line-title { font-weight: 600; font-size: 0.8125rem; min-width: 0; overflow-wrap: anywhere; }
.line-sub { font-size: 0.7rem; color: var(--muted-foreground); }
.line-promo { font-size: 0.7rem; color: var(--promo-text); font-weight: 600; }
.line-discount { font-size: 0.7rem; color: var(--status-paid); font-weight: 600; }
.line-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.5rem; min-width: 0; }
/* Baris kontrol: [qty] … [total] [hapus] lalu [diskon/unit] penuh di baris kedua. */
.line-controls > .qty { order: 1; }
.line-controls > .line-total { order: 1; margin-left: auto; }
.line-controls > .btn { order: 1; }
.line-controls > label.row { order: 2; flex: 1 1 100%; justify-content: flex-start; }
.qty { display: flex; align-items: center; gap: 0.25rem; }
.qty button {
  width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; border: 1px solid var(--border); background: var(--card); font: inherit; font-weight: 700;
  /* Glyph "−" dan "+" tepat di tengah kotak (padding bawah mengimbangi
     metrik font yang menaruh tanda sedikit ke bawah). */
  display: grid; place-items: center; line-height: 1; padding: 0 0 0.375rem;
}
.qty input { width: 3rem; height: 1.75rem; text-align: center; padding: 0; }
.line-total { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.totals { background: var(--soft); border-radius: 0.75rem; padding: 0.625rem 0.75rem; display: grid; gap: 0.3rem; font-size: 0.8125rem; }
/* Blok total menempel di dasar kartu pada layar lebar. Di layar kecil kartu
   tidak dibatasi tinggi, jadi beri jarak tetap supaya tidak menempel
   (berhimpit) dengan blok "keranjang masih kosong" atau daftar item. */
/* Blok total mengikuti isi di atasnya: yang menyerap sisa ruang adalah daftar
   item (atau kotak keranjang kosong), sehingga tidak ada celah kosong di
   bawahnya. Jarak aman ke konten berikutnya tetap ada. */
.pos-cart-card > .card-body > .totals { padding-top: 1.25rem; }
@media (max-width: 1279px) {
  .pos-cart-card > .card-body > .totals { margin-top: 0.75rem; padding-top: 0.75rem; }
}
.totals .row-between strong { font-variant-numeric: tabular-nums; }
.totals .grand { border-top: 1px solid var(--border); padding-top: 0.35rem; font-weight: 700; }
.held-list { display: grid; gap: 0.4rem; list-style: none; margin: 0; padding: 0; }
/* Baris ringkas: teks identitas di kiri, tombol Ambil/Hapus di kanan. */
.held-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.5rem 0.6rem; border: 0; background: var(--card); box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05); border-radius: var(--squircle-md); padding: 0.45rem 0.6rem; }
.held-item .held-text { min-width: 0; }
.held-item strong { display: block; font-size: 0.8125rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.held-item small { color: var(--muted-foreground); font-size: 0.7rem; }

/* ------------------------------------------------------------------ chart */
.chart { width: 100%; height: auto; display: block; }
.chart-axis { display: flex; justify-content: space-between; font-size: 0.7rem; color: var(--muted-foreground); margin-top: 0.25rem; }
.legend { display: flex; flex-wrap: wrap; gap: 0.75rem; font-size: 0.72rem; color: var(--muted-foreground); }
.legend span { display: inline-flex; align-items: center; gap: 0.35rem; }
.legend i { width: 0.6rem; height: 0.6rem; border-radius: 999px; display: inline-block; }
/* Tile ringkasan: di layar kecil menumpuk satu kolom (seperti sebelumnya),
   di layar lebar menyesuaikan jumlah kolom agar teks tidak keluar. */
.metric-tiles { display: grid; gap: 0.5rem; }
@media (min-width: 640px) { .metric-tiles { grid-template-columns: repeat(auto-fit, minmax(6.75rem, 1fr)); } }
/* Empat kartu ringkasan grafik laporan: satu baris pada layar lebar. */
@media (min-width: 640px) and (max-width: 899px) { .metric-tiles-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .metric-tiles-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Kartu ringkasan (tile) dengan ikon kecil di kiri dan tint sesuai jenisnya —
   pola pada referensi desain. Tanpa ikon, label & nilai tetap rapi. */
.metric-tile {
  display: grid; align-items: center; column-gap: 0.5rem; row-gap: 0.1rem;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "ikon label" "ikon nilai";
  background: var(--soft); border: 0; border-radius: var(--squircle-md);
  padding: 0.35rem 0.45rem; min-width: 0;
  --tile-bg: var(--tint-blue-bg); --tile-ikon: var(--tint-blue-icon);
}
.metric-tile > .tile-icon { grid-area: ikon; align-self: center; }
.metric-tile > small { grid-area: label; }
.metric-tile > strong { grid-area: nilai; }
.metric-tile .tile-icon {
  display: grid; place-items: center; width: 1.2rem; height: 1.2rem; flex: none;
  border-radius: 0.4rem; background: var(--tile-bg); color: var(--tile-ikon);
}
.metric-tile .tile-icon .icon { width: 0.72rem; height: 0.72rem; }
.metric-tile.is-green { background: var(--tint-green); border-color: var(--tint-green-line); --tile-bg: var(--tint-green-bg); --tile-ikon: var(--tint-green-icon); }
.metric-tile.is-blue { background: var(--tint-blue); border-color: var(--tint-blue-line); --tile-bg: var(--tint-blue-bg); --tile-ikon: var(--tint-blue-icon); }
.metric-tile.is-red { background: var(--tint-red); border-color: var(--tint-red-line); --tile-bg: var(--tint-red-bg); --tile-ikon: var(--tint-red-icon); }
.metric-tile.is-purple { background: var(--tint-purple); border-color: var(--tint-purple-line); --tile-bg: var(--tint-purple-bg); --tile-ikon: var(--tint-purple-icon); }
.metric-tile.is-amber { background: var(--tint-amber); border-color: var(--tint-amber-line); --tile-bg: var(--tint-amber-bg); --tile-ikon: var(--tint-amber-icon); }
.metric-tile small { font-size: 0.62rem; line-height: 1.15; overflow-wrap: anywhere; }
.metric-tile strong { font-size: 0.8125rem; font-weight: 700; }
/* Kartu rekening BRILink di dashboard: nama & nominal boleh membungkus agar
   angka penuh selalu terlihat; ukuran nominal kembali seperti kartu lain. */
.metric-tile-rekening small { line-height: 1.2; }
.metric-tile-rekening strong { overflow-wrap: anywhere; }
/* Label & subjudul kartu ringkasan diberi ruang dua baris supaya tinggi kartu
   dashboard tetap sama di semua periode (teks panjang membungkus). */
[data-card="penjualan"] .metric-tile small,
[data-card="laba"] .metric-tile small { min-height: 2.05em; display: flex; align-items: center; }
[data-card="penjualan"] #sales-subtitle,
[data-card="laba"] #laba-subtitle { min-height: 2.9em; }
.metric-tile strong { font-variant-numeric: tabular-nums; }
.swatch { width: 0.6rem; height: 0.6rem; border-radius: 999px; display: inline-block; }

/* ------------------------------------------------------------------ animasi
   Gerak halus untuk klik, hover, dropdown, modal, toast, dan perpindahan
   halaman. Semua dinonaktifkan saat pengguna memilih reduced motion. */
:root { --ease-out: cubic-bezier(0.22, 0.8, 0.3, 1); --dur-fast: 0.13s; --dur: 0.18s; --dur-slow: 0.24s; }

@keyframes page-enter { from { opacity: 0.55; } to { opacity: 1; } }
/* Isi halaman baru naik halus dan berurutan agar perpindahan terasa mengalir.
   Dialog dikecualikan supaya panel dropdown di dalamnya tetap presisi. */
@keyframes rise-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
/* Banner "Kas belum dibuka" di POS baru tampil setelah data kas termuat dan
   mengatur animasinya sendiri — jangan ikut animasi perpindahan halaman yang
   bisa terpotong dan membuatnya tampak berkedip. */
.page-enter > #pos-cash-banner { animation: none; }
.page-enter > *:not(dialog) { animation: rise-in 0.3s var(--ease-out) both; }
.page-enter > *:nth-child(2) { animation-delay: 0.04s; }
.page-enter > *:nth-child(3) { animation-delay: 0.08s; }
.page-enter > *:nth-child(4) { animation-delay: 0.12s; }
.page-enter > *:nth-child(n+5) { animation-delay: 0.16s; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px) scale(0.98); } to { opacity: 1; transform: none; } }
/* Modal memakai animasi opacity saja: transform pada elemen induk membuat
   dropdown/tooltip (position: fixed) salah menghitung posisinya. */
@keyframes modal-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-child-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes toast-in { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateX(18px); } }
@keyframes badge-pop { 0% { transform: scale(0.6); } 60% { transform: scale(1.15); } 100% { transform: scale(1); } }

.page-enter { animation: page-enter 0.18s var(--ease-out) both; }

/* Indikator progres perpindahan halaman. */
.nav-progress {
  position: fixed; top: 0; left: 0; z-index: 100; height: 3px; width: 0;
  background: linear-gradient(90deg, var(--primary), var(--accent-lime));
  opacity: 0; transition: width 0.25s var(--ease-out), opacity 0.25s ease;
}
.nav-progress.is-active { opacity: 1; }

/* Tombol dan kontrol: respons tekan + transisi warna. */
.btn, .icon-btn, .tab, .nav-item, .chip, .switch, .radio-group button, .select-trigger, .masters-chip, .masters-swatch, .fav-btn {
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease,
    color var(--dur-fast) ease, box-shadow var(--dur) ease, transform var(--dur-fast) var(--ease-out),
    opacity var(--dur) ease, filter var(--dur) ease;
}
.btn:not(:disabled):active { transform: translateY(1px) scale(0.995); }
.icon-btn:not(:disabled):active, .fav-btn:active { transform: scale(0.92); }
.btn.primary:not(:disabled):hover { box-shadow: 0 6px 16px rgba(21, 88, 200, 0.28); transform: translateY(-1px); }
.btn.outline:not(:disabled):hover { border-color: #cfd3da; }
.tab:not(.is-active):hover { background: rgba(255, 255, 255, 0.7); color: var(--foreground); }
.nav-item { transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease, transform var(--dur-fast) var(--ease-out); }
.nav-item:hover { transform: translateX(2px); }

/* Animasi kartu Penjualan & Laba dashboard, hanya pada kartu yang periodenya
   baru diganti (supaya kartu lain tidak ikut beranimasi). */
@keyframes bar-grow { from { transform: scaleY(0.03); opacity: 0.35; } to { transform: none; opacity: 1; } }
@keyframes split-grow { from { transform: scaleX(0.04); opacity: 0.45; } to { transform: none; opacity: 1; } }
[data-card="penjualan"].is-updating .chart-bar {
  transform-box: fill-box; transform-origin: bottom; animation: bar-grow 0.42s var(--ease-out) both;
}
[data-card="penjualan"].is-updating .metric-tile { animation: rise-in 0.32s var(--ease-out) both; }
[data-card="penjualan"].is-updating .metric-tile:nth-child(2) { animation-delay: 0.05s; }
[data-card="penjualan"].is-updating .metric-tile:nth-child(3) { animation-delay: 0.1s; }
[data-card="laba"].is-updating #laba-sources > * { animation: rise-in 0.3s var(--ease-out) both; }
[data-card="laba"].is-updating #laba-sources > *:nth-child(2) { animation-delay: 0.05s; }
[data-card="laba"].is-updating #laba-sources > *:nth-child(3) { animation-delay: 0.1s; }
[data-card="laba"].is-updating #laba-split > span {
  transform-origin: left center; animation: split-grow 0.45s var(--ease-out) both;
}
/* Tinggi minimum kartu supaya tata letak tidak bergeser saat ganti periode. */
[data-card="penjualan"], [data-card="laba"] { min-height: 24rem; }
[data-card="penjualan"] .chart-grow { min-height: 12.5rem; }

/* Daftar produk di dalam dialog (rincian pembayaran, rincian transaksi,
   keranjang tersimpan, detail transaksi dashboard): SATU desain — nama produk +
   total baris, sub "jumlah × harga satuan", dan catatan promo/diskon.
   Tinggi daftar rincian pembayaran diatur skrip (maksimal 5 produk penuh). */
dialog.modal.pay-dialog .modal-body { max-height: min(82vh, 46rem); }
.item-lines { display: grid; gap: 0.375rem; }
.item-lines-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.item-lines-title { font-size: 0.8125rem; font-weight: 600; }
.item-lines-list {
  display: grid; gap: 0.375rem; margin: 0; padding: 0.5rem 0.625rem;
  list-style: none; border-radius: var(--squircle-md); background: var(--soft);
  max-height: min(40vh, 18rem); overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparent;
}
.item-lines-list::-webkit-scrollbar { width: 6px; }
.item-lines-list::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 999px; corner-shape: round; }
.item-lines-list li { display: grid; gap: 0.1rem; padding-bottom: 0.375rem; border-bottom: 1px solid var(--border); }
.item-lines-list li:last-child { padding-bottom: 0; border-bottom: 0; }
.item-line-top { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; }
.item-line-name { font-size: 0.8125rem; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item-line-sub { font-size: 0.72rem; color: var(--muted-foreground); }
.item-line-note { font-size: 0.7rem; font-weight: 600; color: var(--promo-text); }
/* Uang diterima satu baris: label di kiri, kotak isian meregang mengisi
   seluruh sisa baris di kanannya. */
.pay-paid-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pay-paid-row > label { flex: none; font-size: 0.8125rem; font-weight: 600; }
.pay-paid-row > input,
.pay-paid-row > .input-clear { flex: 1 1 auto; min-width: 5rem; }
.pay-paid-row > .input-clear > input { width: 100%; }

/* Mode ponsel: keranjang memakai sudut rounded biasa (tanpa squircle) dan tanpa
   animasi supaya setiap pembaruan terasa instan di perangkat sentuh. */
@media (max-width: 767px) {
  .pos-cart-card,
  .pos-cart-card .line,
  .pos-cart-card .empty-cart { corner-shape: round; }
  #pos-cart-lines li,
  #pos-cart-empty { animation: none !important; }
}

/* Rincian paket promo di panel lonceng (produk menipis yang sedang promo). */
.stock-item-promo { font-size: 0.7rem; font-weight: 600; color: var(--promo-text); }

/* Transisi umum kartu, baris tabel, dan kartu produk. */.card, .soft-card, .kpi, .metric-tile, .line, .held-item, .product-card { transition: box-shadow var(--dur) ease, border-color var(--dur) ease, background-color var(--dur) ease, transform var(--dur) var(--ease-out); }
.product-card:not([aria-disabled="true"]):hover { transform: translateY(-1px); border-color: var(--primary); box-shadow: inset 0 0 0 2px var(--primary); }
table.table tbody tr { transition: background-color var(--dur-fast) ease; }
table.table tbody tr:hover { background: var(--soft); }
.kpi:hover, .metric-tile:hover { transform: translateY(-1px); }
.line:hover { border-color: #cbd5e1; }

/* Dropdown kustom. */
.select-panel { animation: menu-in var(--dur-fast) var(--ease-out) both; }
/* Popup pemilih periode di halaman Laporan: muncul halus saat dibuka dan
   isinya (kalender/bulan) beranimasi ringan tiap kali berganti. */
#period-popover:not([hidden]) { animation: menu-in var(--dur) var(--ease-out) both; }
.select-option { transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease, padding-left var(--dur-fast) ease; }
.select-option:hover, .select-option.is-active { background: var(--soft); padding-left: 0.7rem; }
.select-trigger:hover .chevron { color: var(--foreground); }

/* Grafik laporan: garis "digambar" saat tab/periode berganti. */
@keyframes chart-draw { to { stroke-dashoffset: 0; } }
@keyframes tooltip-in { from { opacity: 0; transform: translateY(3px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes tooltip-out { from { opacity: 1; } to { opacity: 0; transform: translateY(2px) scale(0.99); } }

/* Dialog tumbuh/menyusut dengan halus saat isinya bertambah. */
dialog.modal { transition: height 0.24s var(--ease-out), width 0.24s var(--ease-out); }
dialog.modal.is-resizing { overflow: hidden; }

/* Modal dan toast. Elemen isi modal naik halus; dialognya sendiri hanya
   memudar supaya tidak menjadi acuan posisi bagi dropdown/tooltip. */
dialog.modal[open] { animation: modal-in var(--dur) ease both; }
dialog.modal[open] > :not(.select-panel) { animation: modal-child-in var(--dur) var(--ease-out) both; }
dialog.modal[open]::backdrop { animation: fade-in var(--dur) ease both; }
/* Animasi menutup: dialog memudar dulu sebelum benar-benar ditutup. */
@keyframes modal-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }
dialog.modal.is-closing { animation: modal-out 0.15s ease both; }
dialog.modal.is-closing::backdrop { animation: fade-out 0.15s ease both; }
dialog.modal.is-closing > :not(.select-panel) { animation: modal-out 0.15s ease both; }
.toast { animation: toast-in var(--dur) var(--ease-out) both; }
/* Toast yang sedang menghilang: animasi keluar dulu sebelum elemennya dilepas. */
.toast.is-closing { animation: toast-out 0.18s ease both; pointer-events: none; }
.icon-badge-count.is-pop { animation: badge-pop var(--dur) var(--ease-out) both; }
/* Tombol urutkan Laporan: ikon berputar 180° saat arah urutan dibalik
   (up-down ↔ down-up). */
#sort-toggle .icon { transition: transform 0.25s var(--ease-out); }
#sort-toggle.is-flipped .icon { transform: rotate(180deg); }
/* Tooltip: desain standar + animasi masuk/keluar (tombol, kolom, grafik). */
.tooltip-layer:not([hidden]):not(.is-hiding) { animation: tooltip-in var(--dur-fast) var(--ease-out) both; }
.tooltip-layer.is-hiding { animation: tooltip-out 0.15s ease both; }
#sales-chart-tip:not([hidden]):not(.is-hiding) { animation: fade-in var(--dur-fast) ease both; }
#sales-chart-tip.is-hiding { animation: fade-out 0.15s ease both; }

/* ----------------------------------------------------------------- squircle
   Gaya "Squircle UI" untuk SELURUH antarmuka: sudut memakai kurva
   superellipse (continuous corner) — transisi sisi ke sudut halus dan panjang,
   bukan seperempat lingkaran / rounded rectangle biasa. `corner-shape` berlaku
   untuk semua elemen; browser yang belum mendukungnya (Safari/Firefox)
   mendapat fallback mask SVG dari `polyfill-squircle.js` — bentuknya tetap
   squircle, bukan rounded rectangle.

   Skala radius:
   - elemen KOTAK (logo, tombol ikon, avatar, ikon KPI) -> radius 45%;
   - permukaan/kontrol persegi panjang -> skala token --squircle-*. */
*, *::before, *::after {
  corner-shape: squircle;
}

/* Elemen kotak: squircle penuh seperti ikon iOS. */
.brand-mark,
.icon-btn,
.rail-avatar,
.user-avatar,
.kpi-icon,
.card-icon,
.metric-tile .tile-icon,
.fav-btn,
.masters-swatch,
.qty button {
  border-radius: 45%;
}
/* Elemen yang memang BULAT (bubble notifikasi, titik status, pill status,
   chip, tag stok, titik legenda, bar laba-split, switch) tetap bulat
   sempurna — bukan squircle. */
.pill,
.pill .dot,
.dot,
.chip,
.stock-tag,
.icon-badge-count,
.toast .toast-icon,
.switch,
.switch-knob,
.legend i,
#laba-split {
  border-radius: 999px;
  corner-shape: round;
}
.pill .dot,
.dot,
.switch-knob {
  border-radius: 50%;
}

/* Teks label (pill status, tag, chip) tepat di tengah antara tepi atas-bawah.
   `text-box-trim` memotong ruang kosong di atas huruf kapital dan di bawah
   garis dasar, sehingga teks benar-benar di tengah kotak (aturan ini berlaku
   untuk teks apa pun, termasuk yang punya ekor seperti "g"/"p"/"y").
   Padding vertikal dibuat simetris dan sedikit disesuaikan agar tinggi label
   tetap sama seperti sebelumnya. */
.pill,
.chip,
.stock-tag,
.tag,
.amount-chip {
  display: inline-block;
  width: fit-content;
  text-align: center;
  white-space: nowrap;
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}
.pill,
.chip,
.stock-tag {
  padding-top: 0.34rem;
  padding-bottom: 0.34rem;
}
.tag {
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
}
.amount-chip {
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}
/* Titik status: sejajar tengah dengan teks (gap tidak berlaku pada inline). */
.pill .dot,
.chip .dot {
  display: inline-block;
  vertical-align: middle;
  margin-right: 0.25rem;
  position: relative;
  top: -0.095em;
}

/* Browser lama tanpa text-box-trim: geser teks ke atas dengan padding bawah
   lebih besar; tinggi kotak tetap karena line-height ikut dikurangi. */
@supports not (text-box-trim: trim-both) {
  .pill,
  .chip,
  .stock-tag {
    line-height: 1.03;
    padding-top: 0.1rem;
    padding-bottom: 0.375rem;
  }
  .tag {
    line-height: 1;
    padding-top: 0.12rem;
    padding-bottom: 0.43rem;
  }
  .amount-chip {
    line-height: 1.065;
    padding-top: 0.15rem;
    padding-bottom: 0.46rem;
  }
  .pill .dot,
  .chip .dot {
    margin-top: 0.42em;
  }
}
/* Elemen yang sama tapi punya aturan radius sendiri (spesifisitas lebih
   tinggi) tetap ikut bentuk squircle. */
.mobile-actions #stock-bell,
.auth-brand-center .brand-mark {
  border-radius: 45%;
}

/* Skala radius seragam untuk kontrol & permukaan (semua dengan sudut menerus). */
.btn { border-radius: var(--squircle-sm); }
.btn.sm { border-radius: var(--squircle-xs); }
input, select, textarea { border-radius: var(--squircle-sm); }
.select-trigger { border-radius: var(--squircle-sm); }
.select-panel { border-radius: var(--squircle-md); }
.select-option, .select-search { border-radius: var(--squircle-xs); }
.nav-item { border-radius: var(--squircle-md); }
.tabs { border-radius: var(--squircle-md); }
.tab { border-radius: var(--squircle-sm); }
.radio-group button, .masters-chip { border-radius: var(--squircle-sm); }
.tag, .amount-chip { border-radius: var(--squircle-xs); }
.stock-item, .held-item, .line, .user-menu, .user-menu-item { border-radius: var(--squircle-md); }
.toast, .metric-tile { border-radius: var(--squircle-md); }
.card, .soft-card, .kpi, .empty, .stock-popover { border-radius: var(--squircle-lg); }
dialog.modal, .auth-card { border-radius: var(--squircle-xl); }

/* Fallback (Safari/Firefox): `polyfill-squircle.js` memasang mask SVG.
   Karena mask memotong semua yang di luar bentuk, garis fokus digeser ke
   dalam agar tetap terlihat pada elemen yang di-mask. */
/* ------------------------------------------------- tombol & kontrol seragam
   Semua tombol/kontrol memakai bahasa bentuk yang sama: TANPA garis tepi,
   pemisahnya bayangan halus (selaras dengan kartu), dan teksnya tepat di
   tengah secara vertikal. */

/* Tombol teks: isi tombol digeser sedikit ke atas karena metrik font menaruh
   garis dasar lebih rendah. Ikon TIDAK ikut digeser: dengan penyelarasan flex
   titik tengahnya sudah sejajar dengan teks — dorongan 2px yang lama justru
   membuat ikon terlihat turun dari teksnya. */
.btn:not(.link) {
  border: 0;
  padding-bottom: 0.125rem;
}
.btn.sm:not(.link) { padding-bottom: 0.1rem; }

/* Tombol outline / status (yang bersinggungan langsung dengan latar):
   tanpa tepi + bayangan seperti tombol utama. */
.btn.outline { border: 0; box-shadow: var(--kontrol-shadow); }
.btn.outline:hover { box-shadow: var(--kontrol-shadow-hover); }
.btn.kas-status { border: 0; box-shadow: var(--kontrol-shadow); }
.btn.destructive, .btn.destructive.tint { border: 0; }

/* Kolom isian, pemilih periode, dan kontrol lain: tanpa tepi + bayangan;
   fokus memakai cincin di dalam kotak (tidak terpotong kontainer). */
input, select, textarea { border: 0; box-shadow: var(--kontrol-shadow); }
input:hover:not(:focus-visible), select:hover:not(:focus-visible), textarea:hover:not(:focus-visible) {
  box-shadow: var(--kontrol-shadow-hover);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--primary), var(--kontrol-shadow);
}
input[aria-invalid="true"], .invalid {
  box-shadow: inset 0 0 0 1.5px #e58794, var(--kontrol-shadow);
}
.select-trigger { border: 0; box-shadow: var(--kontrol-shadow); }
.select-trigger:hover { box-shadow: var(--kontrol-shadow-hover); }
.select-trigger[aria-expanded="true"] { border-color: transparent; box-shadow: inset 0 0 0 1.5px var(--primary), var(--kontrol-shadow); }
.select-search { border: 0; box-shadow: var(--kontrol-shadow); }
.qty button { border: 0; box-shadow: var(--kontrol-shadow); }
.check-row { border: 0; box-shadow: var(--kontrol-shadow); }
.check-row:hover { box-shadow: var(--kontrol-shadow-hover); }
.check-row:has(input:checked) { border-color: transparent; box-shadow: inset 0 0 0 1.5px var(--primary), var(--kontrol-shadow); }
.input-clear-btn { border: 0; box-shadow: var(--kontrol-shadow); }
.input-clear-btn:hover { border-color: transparent; box-shadow: var(--kontrol-shadow-hover); }
.radio-group button { border: 0; box-shadow: var(--kontrol-shadow); }
.radio-group button.is-active { border-color: transparent; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22), 0 8px 16px -12px rgba(37, 99, 235, 0.9); }

/* Label status (pill/chip/tag stok): tanpa tepi, tinggi tetap sama. */
.pill, .chip, .stock-tag { border: 0; }
.pill, .chip, .stock-tag {
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
}

/* Tombol WhatsApp: warna solid khas WhatsApp, ikon putih, dan bayangan yang
   sama persis dengan tombol lain (tanpa tepi). */
.btn.wa, .icon-btn.wa {
  background: #25d366;
  border: 0;
  color: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 8px 18px -12px rgba(15, 23, 42, 0.35);
}
.btn.wa:hover, .icon-btn.wa:hover { background: #1fbe5a; }
.btn.wa .icon, .icon-btn.wa .icon { color: #fff; }
[data-theme="dark"] .btn.wa, [data-theme="dark"] .icon-btn.wa {
  background: #25d366;
  border: 0;
  color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 22px -14px rgba(0, 0, 0, 0.85);
}
[data-theme="dark"] .btn.wa:hover, [data-theme="dark"] .icon-btn.wa:hover { background: #1fbe5a; }

/* Banner "Kas belum dibuka": tanpa garis tepi + bayangan seperti elemen lain. */
#pos-cash-banner { border: 0; box-shadow: var(--kontrol-shadow); }

/* Kontrol di dalam kartu / bagian berlatar PUTIH tetap memakai desain
   sebelumnya (bergari tepi) — jangan diubah. */
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu)
  :is(input, select, textarea, .select-trigger, .select-search, .qty button, .check-row, .input-clear-btn, .radio-group button) {
  border: 1px solid var(--border);
  box-shadow: none;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu)
  :is(input, select, textarea, .select-trigger, .select-search):focus-visible {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn {
  border: 1px solid transparent;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.outline {
  border-color: var(--border);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.primary {
  border-color: var(--primary-dark);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.destructive {
  border-color: #ad1725;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.destructive.tint {
  border-color: #f3ccd3;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.outline,
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.outline:hover {
  box-shadow: none;
}
/* Daftar keranjang tersimpan (dialog) memakai garis tepi seperti semula. */
.held-item {
  border: 1px solid var(--border);
  box-shadow: none;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .check-row:has(input:checked) {
  border-color: var(--primary);
  box-shadow: none;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .radio-group button.is-active {
  border-color: var(--primary-dark);
  box-shadow: none;
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .input-clear-btn:hover {
  border-color: #cfd3da;
  box-shadow: none;
}

/* Halaman masuk (login): kolom isian & tombol memakai desain sebelumnya
   (bergari tepi) sama seperti kontrol di dalam kartu. */
.auth-card :is(input, select, textarea) {
  border: 1px solid var(--border);
  box-shadow: none;
}
/* Tanpa efek bayangan saat kursor di atas kolom isian login. */
.auth-card :is(input, select, textarea):hover,
.auth-card :is(input, select, textarea):hover:not(:focus-visible) {
  box-shadow: none;
}
.auth-card :is(input, select, textarea):focus-visible {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.auth-card input[aria-invalid="true"],
.auth-card .invalid {
  box-shadow: none;
}
.auth-card .btn { border: 1px solid transparent; }
.auth-card .btn.primary { border-color: var(--primary-dark); }

/* Tombol berbayang di atas latar PUTIH (di dalam kartu/dialog): bayangan lebih
   tegas supaya tombol lebih terlihat menonjol dari latar putihnya. */
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.bordered,
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.wa {
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.1), 0 10px 20px -10px rgba(15, 23, 42, 0.45);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.bordered:hover,
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.wa:hover {
  box-shadow: 0 2px 4px rgba(15, 23, 42, 0.12), 0 12px 24px -10px rgba(15, 23, 42, 0.5);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.primary {
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12), 0 10px 20px -10px rgba(37, 99, 235, 0.7);
}
:is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.wa {
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12), 0 10px 20px -10px rgba(37, 211, 102, 0.65);
}
[data-theme="dark"] :is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.bordered,
[data-theme="dark"] :is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .icon-btn.wa {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 24px -14px rgba(0, 0, 0, 0.95);
}
[data-theme="dark"] :is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.primary {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 10px 22px -10px rgba(37, 99, 235, 0.75);
}
[data-theme="dark"] :is(.card, .soft-card, .kpi, [data-card], dialog.modal, .stock-popover, .select-panel, .date-popover, .user-menu) .btn.wa {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 10px 22px -12px rgba(37, 211, 102, 0.6);
}

/* Kartu KPI Pesanan bisa diklik sebagai filter status. */
.kpi.kpi-klik { cursor: pointer; transition: box-shadow var(--dur-fast) ease, transform var(--dur-fast) var(--ease-out); }.kpi.kpi-klik:hover { transform: translateY(-1px); }
.kpi.kpi-klik.is-active { box-shadow: inset 0 0 0 1.5px var(--primary), var(--card-shadow); }
@media (prefers-reduced-motion: reduce) {
  .kpi.kpi-klik:hover { transform: none; }
}

/* Fallback bentuk (Safari/Firefox): fokus digeser ke dalam karena mask
   memotong apa pun di luar bentuk squircle. */
@supports not (corner-shape: squircle) {
  :where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline-offset: -3px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------------ print */
.print-doc { background: #fff; color: #000; }
@media print {
  body { background: #fff; }
  .no-print { display: none !important; }
}
.struk-page {
  max-width: 58mm; margin: 0 auto; padding: 6mm 3mm; background: #fff; color: #000;
  font-family: var(--font-mono); font-size: 10px; line-height: 1.45;
}
.struk-page header { text-align: center; margin-bottom: 6px; }
.struk-page header h1 { font-size: 12px; margin: 4px 0 2px; }
.struk-page header img { max-height: 40px; }
.struk-page .doc-meta { border-top: 1px dashed #000; border-bottom: 1px dashed #000; padding: 4px 0; margin: 6px 0; }
.struk-page table { width: 100%; border-collapse: collapse; }
.struk-page table td { padding: 2px 0; vertical-align: top; }
.struk-page .right { text-align: right; white-space: nowrap; }
.struk-page .totals { border-top: 1px dashed #000; margin-top: 4px; padding-top: 4px; }
.struk-page .footer { text-align: center; margin-top: 8px; }
.invoice-page {
  max-width: 210mm; margin: 0 auto; padding: 12mm; background: #fff; color: #111318;
  font-family: var(--font-sans); font-size: 12px;
}
.invoice-page header h1 { margin: 8px 0 2px; font-size: 20px; }
.invoice-page header img { max-height: 64px; }
.invoice-page table.items { width: 100%; border-collapse: collapse; }
.invoice-page table.items td { border-top: 1px solid #e5e5e7; padding: 8px 4px; vertical-align: top; }
.invoice-page .totals { margin-top: 12px; margin-left: auto; width: 260px; }
.invoice-page .row-total { border-top: 1px solid #111318; font-weight: bold; margin-top: 4px; padding-top: 6px; }
.report-page { max-width: 210mm; margin: 0 auto; padding: 12mm; background: #fff; color: #111318; font-family: var(--font-sans); font-size: 12px; }
.report-page h2 { font-size: 14px; margin: 20px 0 8px; }
.report-page table { width: 100%; border-collapse: collapse; }
.report-page th, .report-page td { border-bottom: 1px solid #e5e5e7; padding: 7px 4px; text-align: left; }
.report-page th { background: #f4f4f5; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
.report-page tfoot td { font-weight: bold; background: #fafafa; }
.report-page .kpis { display: flex; gap: 12px; margin-top: 12px; }
.report-page .kpis div { flex: 1; border: 1px solid #e5e5e7; border-radius: 8px; padding: 8px; }
.report-page .kpis span { display: block; color: #6b6e76; font-size: 10px; }
.report-page .kpis strong { font-size: 14px; }
.report-page p.note { margin-top: 18px; color: #6b6e76; }

/* ------------------------------------------------------------- mode gelap */
/* Tema gelap: permukaan navy lembut dengan tint yang lebih pekat, sidebar navy
   bergelombang biru. Halaman cetak (struk/invoice/laporan) tetap putih karena
   tidak memakai atribut data-theme. */
[data-theme="dark"] {
  color-scheme: dark;
  --background: #0a0f1a;
  --foreground: #e8eef8;
  --card: #131b2b;
  --primary: #3b82f6;
  --primary-dark: #2563eb;
  --secondary: #1b2436;
  --muted: #151d2e;
  --muted-foreground: #93a2b8;
  --border: #24314a;
  --destructive: #f87171;
  --destructive-strong: #dc2626;
  --soft: #172033;
  --line: #1e2a41;
  --rail: #12264d;
  /* Sidebar tema gelap memakai gradasi biru tombol (desain sebelumnya). */
  --rail-bg:
    radial-gradient(130% 42% at 24% 0%, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0) 58%),
    linear-gradient(180deg, #3b82f6 0%, #2563eb 45%, #1d4ed8 100%);
  --rail-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.34),
    inset 0 0 0 1px rgba(255, 255, 255, 0.10),
    inset -30px 0 50px -36px rgba(0, 0, 0, 0.42),
    inset 0 -34px 52px -38px rgba(0, 0, 0, 0.38),
    0 24px 50px -30px rgba(6, 16, 44, 0.85);
  --rail-muted: #dbe6ff;
  --accent-blue: #60a5fa;
  --accent-lime: #4ade80;
  --accent-purple: #a78bfa;
  --status-paid: #34d399;
  --status-due: #fbbf24;
  --lime-soft: #12301f;
  --lime-text: #86efac;
  --danger-soft: #351d22;
  --danger-text: #fca5a5;
  --warning-soft: #332a12;
  --warning-text: #fcd34d;
  --success-soft: #12301f;
  --success-text: #86efac;
  --promo-text: #fbbf24;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  --kontrol-shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 8px 18px -14px rgba(0, 0, 0, 0.9);
  --kontrol-shadow-hover: 0 2px 4px rgba(0, 0, 0, 0.55), 0 10px 22px -14px rgba(0, 0, 0, 0.95);
  /* Pemisah kartu di mode gelap: cincin tipis + bayangan rapat (tanpa border). */
  --card-shadow: 0 0 0 1px rgba(255, 255, 255, 0.055), 0 6px 16px -12px rgba(0, 0, 0, 0.9);
  --chart-grid: #24314a;
  --chart-label: #93a2b8;
  --chart-average: #3c4a63;
  --tint-green: #10231a;
  --tint-green-line: #1d3a2b;
  --tint-green-icon: #4ade80;
  --tint-green-bg: #16321f;
  --tint-blue: #111d31;
  --tint-blue-line: #1f3253;
  --tint-blue-icon: #60a5fa;
  --tint-blue-bg: #16263f;
  --tint-red: #241419;
  --tint-red-line: #43222a;
  --tint-red-icon: #f87171;
  --tint-red-bg: #351d22;
  --tint-purple: #1b1730;
  --tint-purple-line: #332a52;
  --tint-purple-icon: #a78bfa;
  --tint-purple-bg: #292145;
  --tint-amber: #241d10;
  --tint-amber-line: #43361a;
  --tint-amber-icon: #fbbf24;
  --tint-amber-bg: #332a12;
  --scrollbar-thumb: #33415c;
  --scrollbar-thumb-hover: #47597a;
}
[data-theme="dark"] .btn.outline:not(:disabled):hover,
[data-theme="dark"] .product-card:hover,
[data-theme="dark"] .line:hover,
[data-theme="dark"] .stock-item:hover,
[data-theme="dark"] .select-trigger[aria-expanded="true"] { border-color: #33415c; }
[data-theme="dark"] .btn.primary { background: linear-gradient(180deg, #3b82f6, #2563eb 45%, #1d4ed8); border-color: #1e40af; box-shadow: 0 8px 18px -12px rgba(37, 99, 235, 0.95); }
[data-theme="dark"] .nav-group { color: rgba(159, 176, 201, 0.75); }
/* Mode gelap: menu aktif memakai gradasi latar sidebar mode terang. */
[data-theme="dark"] .nav-item.is-current {
  background:
    radial-gradient(150% 52% at 8% 118%, rgba(56, 132, 255, 0.5), rgba(56, 132, 255, 0) 64%),
    radial-gradient(130% 46% at 96% 110%, rgba(37, 99, 235, 0.36), rgba(37, 99, 235, 0) 62%),
    radial-gradient(120% 40% at 24% 0%, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0) 60%),
    linear-gradient(180deg, #0a1120 0%, #0b1628 48%, #0c1c36 100%);
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 12px 24px -16px rgba(0, 0, 0, 0.6);
}
[data-theme="dark"] .nav-item.is-current .icon { color: #fff; }
[data-theme="dark"] .rail .nav-item:hover { background: rgba(255, 255, 255, 0.14); }
[data-theme="dark"] .tag { color: #b6c2d4; }
[data-theme="dark"] .tag.jasa { background: #262b4d; color: #c7cbff; }
[data-theme="dark"] .btn.destructive.tint { border-color: #5a2630; }
[data-theme="dark"] .icon-btn.wa { background: #25d366; border: 0; color: #fff; }
[data-theme="dark"] .icon-btn.wa:hover { background: #1fbe5a; }
[data-theme="dark"] .alert.warning { border-color: #57491a; }
[data-theme="dark"] .alert.success { border-color: #1f5c3a; }
[data-theme="dark"] .stock-tag.is-habis { background: #351d22; color: #fca5a5; border-color: #5a2630; }
[data-theme="dark"] .stock-tag.is-menipis { background: #332a12; color: #fcd34d; border-color: #57491a; }
[data-theme="dark"] .stock-tag.is-aman { background: #12301f; color: #86efac; border-color: #1f5c3a; }
[data-theme="dark"] .switch[aria-checked="false"] { background: #24314a; }
[data-theme="dark"] table.table tfoot td { background: var(--soft); }
[data-theme="dark"] input[aria-invalid="true"], [data-theme="dark"] .invalid { background: #2a161a; border-color: #7f3b45 !important; }
[data-theme="dark"] .input-clear-btn:hover { background: #24314a; border-color: #33415c; }
[data-theme="dark"] .toast.info .toast-icon { background: #16273f; color: #93b8f7; }
[data-theme="dark"] .toast.success { border-color: #1f5c3a; }
[data-theme="dark"] .toast.success .toast-icon { background: #12301f; color: #86efac; }
[data-theme="dark"] .toast.destructive { border-color: #5a2630; }
[data-theme="dark"] .toast.destructive .toast-icon { background: #351d22; color: #fca5a5; }

/* Transisi ganti tema: snapshot tema baru dibuka sebagai lingkaran dari tombol
   tema (lihat gantiTemaDariTombol di app.js). Animasi bawaan (crossfade)
   dimatikan supaya hanya lingkaran + gerak halus yang terlihat.
   Tepi lingkaran dilembutkan lewat mask bergradasi (tepi blur). Mask hanya
   dipakai bila browser mendukung properti mask tanpa awalan; kalau tidak,
   skrip memakai clip-path bulat biasa. Semua animasi snapshot lain (mask/filter)
   pernah membuat crash saat tombol ditekan beruntun — sekarang tombol mati
   selama animasi sehingga transisi tidak pernah beruntun. */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}
/* Lapisan transisi tidak boleh menelan klik: tombol (dan halaman) tetap bisa
   dipakai selama animasi berjalan. */
::view-transition {
  pointer-events: none;
}
/* Tepi lingkaran: padat di tengah, memudar di tepi (efek blur).
   Ukurannya dianimasikan skrip lewat mask-size; posisinya di tengah tombol. */
::view-transition-new(root) {
  -webkit-mask-image: radial-gradient(circle closest-side, #000 74%, transparent 90%);
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: var(--tema-mask, center);
  mask-image: radial-gradient(circle closest-side, #000 74%, transparent 90%);
  mask-repeat: no-repeat;
  mask-position: var(--tema-mask, center);
}

/* --------------------------------------------------------- checkbox tema */
/* Checkbox bawaan diganti gaya aplikasi (kotak membulat + centang putih),
   dipakai di Master Data, Pengaturan hak akses, dan dialog-dialog. */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  box-sizing: border-box;
  width: 1.1rem; height: 1.1rem; min-width: 1.1rem; min-height: 1.1rem; flex: none; margin: 0; padding: 0;
  aspect-ratio: 1 / 1; align-self: center;
  display: inline-grid; place-content: center; cursor: pointer;
  border: 1.5px solid var(--border); border-radius: 0.375rem; background: var(--card);
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}
input[type="checkbox"]::before {
  content: ""; width: 0.7rem; height: 0.7rem; transform: scale(0);
  background: currentColor; color: var(--primary-foreground);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") no-repeat center / contain;
  transition: transform var(--dur-fast) var(--ease-out);
}
input[type="checkbox"]:checked { background: var(--primary); border-color: var(--primary); }
input[type="checkbox"]:checked::before { transform: scale(1); }
input[type="checkbox"]:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35); }
input[type="checkbox"]:disabled { opacity: 0.5; cursor: not-allowed; }

/* ------------------------------------------------------------- scrollbar */
/* Scrollbar ramping, batang membulat, jalur tembus pandang agar tidak
   mengganggu tampilan. Warna mengikuti tema (terang/gelap). */
::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border: 3px solid transparent;
  border-radius: 999px;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
  background-clip: padding-box;
}
::-webkit-scrollbar-corner {
  background: transparent;
}
/* Di dalam rail (hitam/biru tua) batangnya dibuat lebih terang. */
.rail::-webkit-scrollbar-thumb {
  background: var(--scrollbar-rail);
  background-clip: padding-box;
}
.rail::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-rail-hover);
  background-clip: padding-box;
}
/* Penjelajah tanpa dukungan pseudo-elemen scrollbar memakai properti standar. */
@supports not selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) transparent;
  }
  .rail {
    scrollbar-color: var(--scrollbar-rail) transparent;
  }
}
