:root {
  /* Warna disamakan PERSIS dgn appscript/Index.html (arahan user "warna nya belum sama dengan
     appscript" + "saya suka agak biru warna nya") -- biru --accent:#4a6fa5 dgn --accent-light
     #eef2f8 utk background sidebar/active-state, GANTI dari skema coklat/oranye sebelumnya. */
  --accent: #4a6fa5;
  --accent-dark: #3c5a87;
  --accent-light: #eef2f8;
  --muted: #5a5f66;
  --line: #e2e5ea;
  --bg: #f5f6f8;
  --ink: #1f2328;
  --card-bg: #ffffff;
  --danger: #b42318;
}
* { box-sizing: border-box; }
body {
  /* Task #423 (user: "gunakan font Open Sans, Helvetica, sans-serif dan font size perkecil") -- Open
     Sans dimuat dari Google Fonts (lihat <link> di index.html), fallback Helvetica/sans-serif kalau
     CDN gagal. font-size dasar diturunkan 16px (default browser) -> 13px, jadi elemen apa pun yang
     TIDAK punya font-size eksplisit sendiri (lihat aturan lain di file ini yang MEMANG sudah kecil,
     12-13px) otomatis ikut lebih kecil juga. */
  font-family: "Open Sans", Helvetica, Arial, sans-serif;
  font-size: 13px;
  margin: 0;
  background: var(--bg);
  color: #2b2622;
}
.hidden { display: none !important; }
.screen { min-height: 100vh; }

/* Task #423 (16 Sep 2026, "tambahkan animasi loading page") -- bar tipis fixed di paling atas
   viewport, indeterminate sweep animation (BUKAN progress beneran -- kita tidak tahu berapa % request
   API sudah selesai, cuma tahu "lagi jalan/tidak", sama pola dgn loading bar YouTube/GitHub). Class
   `.active` ditambah/dilepas dari pageLoadingStart()/pageLoadingEnd() (app.js) via counter (>0 =
   tampil), supaya beberapa request bersamaan tetap nampilin 1 bar (tidak kedip nyala-mati). */
.page-loading-bar {
  position: fixed; top: 0; left: 0; height: 3px; width: 100%; z-index: 9999;
  background: transparent; opacity: 0; pointer-events: none; transition: opacity .25s ease;
  overflow: hidden;
}
.page-loading-bar.active { opacity: 1; }
.page-loading-bar::before {
  content: ''; position: absolute; top: 0; left: 0; height: 100%; width: 40%;
  background: var(--accent); border-radius: 0 4px 4px 0;
  transform: translateX(-100%);
}
.page-loading-bar.active::before { animation: page-loading-sweep 1.1s ease-in-out infinite; }
@keyframes page-loading-sweep {
  0% { transform: translateX(-100%); }
  55% { transform: translateX(140%); }
  100% { transform: translateX(140%); }
}

/* FIX (19 Sep 2026, user: "ini bukannya kita mau kasih animasi icon untuk menggambarkan
   progressnya" -- Pull GL Transaction cuma pesan teks statis "Menarik data GL..."/label "Berjalan..."
   TANPA ikon apa pun selagi proses background jalan, user ekspektasi ada animasi visual) -- ikon
   SVG "refresh/sync" (BUKAN cuma ring CSS polos -- user: "ini plain lagi" begitu lihat versi ring
   polos pertama, terlalu plain/kurang kelihatan sbg ikon) berputar terus-menerus, indeterminate SAMA
   spt page-loading-bar di atas (kita TIDAK tahu % selesai beneran, cuma tahu "lagi jalan/tidak").
   Dipakai di 2 tempat: (1) #glPullSpinner (index.html, sebelah #glMsg, toggle lewat
   setGlPullingUiState_() app.js), (2) inline di label "Berjalan..." kolom Status Pull History
   (renderGlHistoryTable() app.js) tiap baris yang statusnya masih 'running'. */
/* .hidden (global rule di atas, display:none !important) dipakai utk sembunyikan -- TIDAK perlu
   aturan .spinner-icon.hidden terpisah. */
.spinner-icon {
  display: inline-block; width: 15px; height: 15px; vertical-align: -3px; margin-right: 6px;
  color: var(--accent); animation: spinner-rotate 0.9s linear infinite;
}
@keyframes spinner-rotate { to { transform: rotate(360deg); } }

/* Login */
/* FIX (17 Sep 2026, user: "improve login page nya pake logo FFI") -- background halaman login dikasih
   gradient tipis (bukan flat --bg polos) + card dinaikkan (radius/shadow lebih besar, lebar +20px)
   supaya logo besar di dalamnya (login-logo) tidak terasa sempit. */
#loginScreen {
  display: flex; align-items: center; justify-content: center; min-height: 100vh;
  background: linear-gradient(160deg, var(--accent-light) 0%, var(--bg) 55%);
}
.login-card {
  background: var(--card-bg); border: 1px solid var(--line); border-radius: 14px;
  padding: 36px 32px 28px; width: 380px; box-shadow: 0 8px 28px rgba(31,35,40,0.08);
}
.login-brand { display: flex; justify-content: center; margin-bottom: 20px; }
/* FIX (17 Sep 2026, user: "replace all logo" -> logo BARU adalah lockup horizontal (kilat merah FFI +
   wordmark "Finata" + tagline). REVISI (user: "finata nya lebih pendek lagi" -> "jadi ga terlalu
   sejajar dengan ffi logo") -- wordmark "Finata"+tagline di file PNG-nya sendiri SUDAH di-scale turun
   (~68% tinggi) relatif terhadap ikon FFI (lihat finata-logo-full-v2.png, v1 lama proporsinya SAMA
   tinggi/"sejajar" dgn ikon) supaya ikon FFI kelihatan lebih dominan -- rasio lebar:tinggi file baru
   ini SEKARANG ~4.7:1 (beda dari v1 yg ~5.5:1), lebar di bawah disesuaikan ulang. */
.login-logo { display: block; width: 260px; max-width: 100%; height: auto; }
/* Task (17 Sep 2026, "loginnya bisa dikasih welcome text ga ya dan copyright") -- welcome text di
   ATAS form (bawah logo), copyright di BAWAH form (SAMA teks dgn .about-copyright, About modal --
   ditampilkan lagi di sini krn login screen kelihatan TANPA perlu login dulu). */
.login-welcome { text-align: center; font-size: 15px; color: var(--accent-dark); font-weight: 600; margin: 0 0 22px; }
.login-copyright {
  text-align: center; font-size: 11px; line-height: 1.6; color: var(--muted);
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line);
}
.login-card .desc { color: var(--muted); font-size: 12px; margin: 0 0 20px; }
.login-card label { display: block; font-size: 12px; margin: 12px 0 4px; }
.login-card input { width: 100%; padding: 9px 11px; border: 1px solid var(--line); border-radius: 6px; }
.login-card input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.login-card button { width: 100%; margin-top: 22px; padding: 10px; font-weight: 600; border-radius: 8px; }

/* Task #144 "Login via SSO" -- block ini disembunyikan by default lewat inline style di index.html
   (JS toggle, lihat initSsoLoginButton() app.js), tampil kalau server sudah dikonfigurasi SSO_*.
   Divider "or" + tombol outline (BUKAN warna solid var(--accent) spt tombol Login utama) supaya jelas
   ini pilihan ALTERNATIF, bukan pengganti login email/password di atasnya. */
.sso-divider { display: flex; align-items: center; margin: 18px 0 12px; color: var(--muted); font-size: 12px; }
.sso-divider::before, .sso-divider::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.sso-divider span { padding: 0 10px; }
.sso-login-btn {
  width: 100%; padding: 10px; font-weight: 600; border-radius: 8px;
  background: var(--card-bg); color: var(--accent-dark); border: 1px solid var(--accent);
}
.sso-login-btn:hover { background: var(--accent-light); }

/* FFI SSO Login Button & Divider */
.btn-sso {
  display: flex !important; align-items: center; justify-content: center; gap: 10px;
  width: 100%; background: #c8102e !important; color: #ffffff !important;
  border: none; border-radius: 8px; padding: 11px 16px; font-size: 13.5px;
  font-weight: 700; cursor: pointer; transition: background .15s ease, transform .1s ease;
  margin-top: 0 !important; margin-bottom: 16px; box-shadow: 0 2px 6px rgba(200, 16, 46, 0.25);
}
.btn-sso:hover { background: #a50b23 !important; }
.btn-sso:active { transform: scale(0.99); }
.sso-icon { fill: currentColor; }

.login-divider {
  display: flex; align-items: center; text-align: center; margin: 16px 0 12px;
  color: var(--muted); font-size: 11.5px;
}
.login-divider::before, .login-divider::after {
  content: ''; flex: 1; border-bottom: 1px solid var(--line);
}
.login-divider span { padding: 0 10px; }

/* Role Switcher dropdown in topbar user menu */
.user-menu-role-switcher {
  padding: 6px 10px 8px; margin-bottom: 6px; border-bottom: 1px solid var(--line);
}
.user-menu-role-label {
  font-size: 11px; font-weight: 600; color: var(--muted); margin-bottom: 4px; text-transform: uppercase; letter-spacing: .3px;
}
.user-menu-role-select {
  width: 100%; padding: 5px 8px; border: 1px solid var(--line); border-radius: 6px;
  font-size: 12px; background: var(--bg); color: var(--ink); cursor: pointer;
}
.user-menu-role-select:focus { outline: none; border-color: var(--accent); }

/* App shell: sidebar (brand + module nav) + main (topbar + module content) -- lihat catatan di
   index.html/app.js soal MODULES, ini fondasi yang dipakai ulang tiap modul baru ditambahkan. */
.app-shell { display: flex; min-height: 100vh; align-items: stretch; }
/* Sidebar disamakan PERSIS dgn appscript/Index.html (arahan user "sidebar dan warnanya belum sama
   dengan appscript" + "gunakan expand dan collapse yang sama") -- background gradient tipis dari
   --accent-light ke putih (BUKAN dark brown solid seperti sebelumnya), nav 1-level dikelompokkan per
   `section` (Finance/Admin/Report, lihat app.js:MODULES) jadi accordion .nav-group yang bisa
   expand/collapse (caret + slide max-height/opacity transition, sama pola appscript), header grup
   yang sedang berisi item aktif ikut di-highlight biru via :has() (browser modern). */
.sidebar {
  width: 240px; flex: 0 0 240px; background: linear-gradient(180deg, var(--accent-light) 0%, #ffffff 220px);
  color: var(--ink); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.sidebar .brand { padding: 18px 18px 16px; border-bottom: 1px solid #eef1f4; display: flex; justify-content: center; }
/* FIX (17 Sep 2026, user: "side bar gunakan ini tapi warna nya harus menyatu" -> "besar banget
   logonya" -> "ini maksudku rata kiri icon nya dan perkecil saja") -- 180px lalu 108px masih
   kegedean, diperkecil lagi ke 76px. .brand-left = rata KIRI (koreksi dari permintaan "rata kanan"
   sebelumnya), dipakai lewat class tambahan di HTML. */
.sidebar .brand.brand-left { justify-content: flex-start; }
.sidebar .brand-logo { display: block; width: 150px; max-width: 100%; height: auto; }
.sidebar .brand-name { font-size: 16px; font-weight: 800; letter-spacing: 0.3px; color: var(--ink); }
.sidebar .brand-tagline { font-size: 10.5px; color: var(--muted); margin-top: 4px; line-height: 1.4; }
.sidebar-nav { flex: 1; padding: 12px 0; overflow-y: auto; }

.nav-group-header {
  padding: 11px 18px; font-size: 12.5px; font-weight: 700; color: var(--ink);
  cursor: pointer; display: flex; align-items: center; justify-content: space-between; user-select: none;
}
.nav-group-header:hover { background: #f7f8fa; }
.nav-group-header .caret { font-size: 10px; color: var(--muted); transition: transform .18s ease; margin-left: 6px; }
.nav-group.collapsed .nav-group-header .caret { transform: rotate(-90deg); }
.nav-group-body { max-height: 1200px; opacity: 1; overflow: hidden; transition: max-height .25s ease, opacity .2s ease; }
.nav-group.collapsed .nav-group-body { max-height: 0; opacity: 0; transition: max-height .2s ease, opacity .12s ease; }
.nav-group:has(> .nav-group-body .sidebar-item.active) > .nav-group-header { color: var(--accent); background: var(--accent-light); }

/* FIX (16 Sep 2026, screenshot report "sub menu belum sejajar dengan menu") -- teks header grup
   (.nav-group-header) mulai di 18px(padding) + 14px(ikon) + 8px(gap) = 40px dari tepi kiri. Sub-item
   TIDAK punya ikon, jadi teksnya harus mulai di titik yang SAMA (40px) biar sejajar vertikal dgn teks
   header di atasnya -- padding-left 30px lama (+ border-left 3px = 33px) terlalu ke kiri 7px. */
/* FIX (16 Sep 2026, "submenu di sidebar jangan bold") -- sub-item (TTF-List/Vendor Master/dst) SEKARANG
   font-weight normal (dulu 600, sama beratnya dgn header grup "Finance"/"Master Data"/dst, jadi tidak
   ada kontras). Header grup TETAP bold (lihat .nav-group-header, tidak diubah) -- state active TETAP
   dikasih weight lebih (600) SUPAYA item yang lagi dipilih tetap kelihatan beda dari yang lain. */
.sidebar-item {
  display: flex; align-items: center; width: 100%; text-align: left; background: transparent; border: none;
  color: var(--muted); font-size: 13px; font-weight: 400; padding: 9px 18px 9px 37px; cursor: pointer;
  border-left: 3px solid transparent; margin: 0 0 4px;
}
.sidebar-item:hover:not(.active) { background: #f7f8fa; }
.sidebar-item.active { color: var(--accent); font-weight: 600; border-left-color: var(--accent); background: var(--accent-light); }
.nav-icon { display: inline-flex; flex-shrink: 0; margin-right: 8px; opacity: .85; }
.nav-icon svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; display: block; }

/* Task #423 (redesign sidebar, "Dashboard" berdiri sendiri di atas accordion Finance/Master Data/
   dst -- lihat MODULES[0].flat di app.js) -- padding disamakan dgn .nav-group-header (top-level),
   BUKAN dgn .sidebar-item biasa yang punya indent 30px (itu utk item DI DALAM grup). */
.sidebar-item-flat { padding: 11px 18px; margin: 4px 0 8px; }

/* FIX (17 Sep 2026, user: "logout jadi satu dengan profile di header" -> "terdapat text copyright" ->
   "copyright nya kepotong bisa dibikin di about ga?") -- .sidebar-footer (email+Logout, lalu cuma teks
   copyright) SUDAH TIDAK ADA lagi di sidebar (elemen-nya dihapus dari index.html) -- copyright pindah
   ke modal "About" (.about-* di bawah), dropdown #userMenu (topbar) yang sekarang isinya Change
   Password/About/Logout. */
.about-modal-box { max-width: 320px; text-align: center; }
/* Task #134 -- modal Confirm generic (askConfirm(), lihat app.js) SENGAJA lebih sempit dari modal
   form biasa (max-width: 720px, .modal-box) -- ini cuma 1 kalimat pertanyaan + 2 tombol, bukan form. */
.confirm-modal-box { max-width: 420px; }
.confirm-modal-box .modal-actions { display: flex; justify-content: flex-end; gap: 8px; }
.about-logo { width: 190px; max-width: 100%; height: auto; margin: 4px auto 16px; display: block; }
/* FIX (19 Sep 2026, user: "tambahkan juga versi aplikasi di abount") -- font-mono spy supaya angka
   versi gampang dibaca/dibedakan dari teks lain, sama semangat dgn nomor referensi/kode di modul lain. */
.about-version { font-size: 11px; font-family: "SF Mono", Consolas, monospace; color: var(--muted); margin-bottom: 10px; }
.about-copyright { font-size: 12px; line-height: 1.6; color: var(--muted); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; padding: 16px 24px; background: var(--card-bg);
  border-bottom: 1px solid var(--line);
}
.topbar-title { font-weight: 700; font-size: 14.5px; }

/* Task #423 (redesign top bar, mockup: search icon + notification/avatar di kanan) -- search sini
   SUNGGUHAN jalan (filter menu, lihat onTopbarSearchInput() di app.js), TIDAK ada bell notifikasi
   dekorasi kosong (belum ada sistem notifikasi sungguhan di app ini -- lebih baik tidak ditambah drpd
   nambah tombol yang tidak ngapa-ngapain kalau diklik). */
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.topbar-search-wrap { position: relative; }
.topbar-search-icon {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--muted);
  display: flex; pointer-events: none;
}
.topbar-search-icon svg { stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
.topbar-search {
  width: 220px; padding: 8px 10px 8px 32px; border: 1px solid var(--line); border-radius: 20px;
  font-size: 12.5px; background: var(--bg);
}
.topbar-search:focus { background: #fff; }
.topbar-search-results {
  position: absolute; top: calc(100% + 6px); left: 0; width: 280px; background: #fff;
  border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.08);
  z-index: 40; max-height: 260px; overflow-y: auto; padding: 6px;
}
.topbar-search-item {
  display: block; width: 100%; text-align: left; background: transparent; border: none; color: var(--ink);
  font-size: 12.5px; font-weight: 500; padding: 7px 10px; border-radius: 6px; margin: 0; cursor: pointer;
}
.topbar-search-item:hover { background: var(--accent-light); }
.topbar-search-item-section { display: block; font-size: 10.5px; color: var(--muted); font-weight: 600; }
.topbar-search-empty { padding: 8px 10px; font-size: 12px; color: var(--muted); }
/* Task #423 (search global TTF/Vendor/Dept/master lain) -- label grup ("TTF"/"Vendor Master"/dst) di
   atas tiap kelompok hasil, lihat topbarSearchAddGroup_() di app.js. */
.topbar-search-group-label {
  font-size: 10px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .4px;
  padding: 8px 10px 4px; border-top: 1px solid var(--line); margin-top: 2px;
}
.topbar-search-group-label:first-child { border-top: none; margin-top: 0; }

/* FIX (17 Sep 2026, user: "logout jadi satu dengan profile di header dan hilangkan duplikasi
   tampilan email" + "tambahkan fitur ganti password") -- user-chip SEKARANG buka dropdown (bukan
   langsung logout on-click), lihat toggleUserMenu()/#userMenu di app.js/index.html. */
.user-chip-wrap { position: relative; }
.user-chip { display: flex; align-items: center; gap: 9px; cursor: pointer; padding: 4px 6px; border-radius: 20px; }
.user-chip:hover { background: var(--accent-light); }
.avatar-circle {
  width: 32px; height: 32px; border-radius: 50%; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700;
  flex-shrink: 0;
}
.user-chip-text { display: flex; flex-direction: column; line-height: 1.3; }
.user-chip-name { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.user-chip-role { font-size: 11px; color: var(--muted); text-transform: capitalize; }
.user-menu {
  position: absolute; top: calc(100% + 8px); right: 0; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,0.1); min-width: 230px; z-index: 60; padding: 8px;
}
.user-menu-email {
  padding: 6px 10px 10px; margin-bottom: 6px; border-bottom: 1px solid var(--line);
  font-size: 12px; color: var(--muted); word-break: break-all;
}
.user-menu-item {
  display: block; width: 100%; text-align: left; background: transparent; border: none; color: var(--ink);
  font-size: 13px; padding: 8px 10px; border-radius: 6px; margin: 0; cursor: pointer;
}
.user-menu-item:hover { background: var(--accent-light); }
.user-menu-logout { color: var(--danger); }

.tabs { display: flex; gap: 4px; padding: 10px 24px 0; background: var(--card-bg); border-bottom: 1px solid var(--line); }
.tab-btn {
  background: transparent; border: none; padding: 10px 16px; font-size: 13px; cursor: pointer;
  color: var(--muted); border-bottom: 2px solid transparent;
}
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
/* FIX (16 Sep 2026, screenshot report "bikin full page" -- TTF List punya banyak ruang kosong abu-abu
   di kanan): max-width:900px + margin:0 auto sebelumnya bikin TTF - List/New (SATU-SATUNYA module yg
   pakai .tabpanel, module lain seperti Master Data langsung .module-panel > .card TANPA cap lebar)
   kepotong sempit & center di tengah, padahal tabel TTF List butuh lebar penuh spt tabel module lain.
   Cap dihapus -- SEKARANG konsisten full-width dgn semua module lain, cuma padding-nya yg dipertahankan. */
.tabpanel { padding: 20px 24px 60px; }
.module-panel.hidden { display: none; }

/* Cards / forms */
.card { background: var(--card-bg); border: 1px solid var(--line); border-radius: 10px; padding: 22px; }
.card h2 { margin-top: 0; font-size: 14.5px; }
.desc { color: var(--muted); font-size: 12px; }

/* Task #423 (redesign: TTF New/Edit mockup punya section berlabel "Vendor Information"/"Invoice
   Details"/dst, masing2 dgn ikon kecil biru) -- 1 style dipakai ulang di TTF New (public/index.html)
   DAN modal Edit TTF, biar konsisten. Ikon SVG inline sama pola dgn .nav-icon (stroke:currentColor). */
.section-header {
  display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 13px; color: var(--ink);
  margin: 4px 0 12px;
}
.section-header:first-of-type { margin-top: 0; }
/* Task #423 (user: "buatkan section divider juga") -- garis pemisah SUNGGUHAN antar section (Vendor
   Information/Invoice Details/dst), dipasang di index.html SEBELUM tiap .section-header berikutnya
   (bukan di section pertama) -- dipisah dari .section-header sendiri (yang sekarang TANPA border-
   bottom, lihat di atas) supaya tidak dobel garis. */
.section-divider { border-top: 1px solid var(--line); margin: 22px 0 18px; }
.section-icon { display: flex; flex-shrink: 0; color: var(--accent); }
.section-icon svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; display: block; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Badge hijau "Synced" (field NetSuite Transaction Number sudah terisi) -- lihat catatan panjang di
   index.html/app.js kenapa ini MURNI cerminan isi field, bukan hasil cek API live. */
.synced-badge {
  display: inline-block; margin-left: 8px; font-size: 10.5px; font-weight: 700; padding: 2px 7px;
  border-radius: 20px; background: #dcfce7; color: #166534; vertical-align: middle;
}

/* Task #423 (redesign: Dashboard landing page, MODULES[0] di app.js) */
.dash-welcome { margin-bottom: 18px; }
.dash-welcome h2 { margin: 0 0 4px; font-size: 17px; }
.dash-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 18px; }
.dash-stat-card { display: flex; flex-direction: column; gap: 6px; }
.dash-stat-label { font-size: 12px; color: var(--muted); font-weight: 600; }
.dash-stat-value { font-size: 30px; font-weight: 800; color: var(--accent); }
.dash-quicklinks { display: flex; gap: 10px; flex-wrap: wrap; }
.row { display: flex; gap: 14px; margin-bottom: 12px; flex-wrap: wrap; }
.row > div { flex: 1 1 200px; }
.row .narrow { flex: 0 1 220px; max-width: 220px; }
.row .grow { flex: 1 1 100%; }
/* FIX (16 Sep 2026, screenshot report "belum dibuat warna lebih gelap" -- teks NPWP/NITKU/Address di
   bawah Vendor Name terlalu terang/kontras rendah pakai var(--muted) #5a5f66) -- label tetap muted
   (abu-abu, secondary), TAPI nilainya (span di dalam <div>, lihat index.html) dibuat gelap/jelas
   dibaca via .muted-row > div (color var(--ink)), bukan ikut warna induk lagi. */
/* FIX (16 Sep 2026, follow-up screenshot -- "npwp, nitku, address diberikan background colour yang
   lebih gelap") -- selain teks yang sudah digelapkan (.muted-row > div), blok ini SEKARANG dikasih
   background sendiri (var(--bg), lebih gelap dari putih .card di belakangnya) + padding/rounded jadi
   kelihatan sbg 1 kotak info yang jelas beda dari field input di atasnya, bukan cuma baris teks polos. */
.muted-row {
  font-size: 12px; color: var(--muted); gap: 16px;
  background: var(--bg); padding: 10px 14px; border-radius: 8px; margin-bottom: 16px;
}
.muted-row > div { color: var(--ink); font-weight: 600; }
label { display: block; font-size: 12px; margin-bottom: 4px; color: #4a4038; }
input, select {
  width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 6px; font-size: 13px;
  background: #fff;
}
/* FIX (17 Sep 2026, user: "untuk semua placeholder di halaman entry new/edit warna nya harus lebih
   muda") -- placeholder browser default (~#767676, mendekati warna teks asli) diganti abu-abu lebih
   pucat supaya jelas beda dari teks yang sudah diisi user, di SEMUA form (bukan cuma TTF). */
input::placeholder, textarea::placeholder { color: #b9bec7; opacity: 1; }
/* FIX (17 Sep 2026, user: "ditambahkan button ... cek status pada netsuite" -- Item Receipt No. di TTF
   New/Edit sekarang punya tombol "Cek NetSuite" di sebelah inputnya, bukan di bawah) -- input ambil
   sisa lebar, tombol menyesuaikan lebar teksnya sendiri, sejajar horizontal. */
.input-with-button { display: flex; gap: 8px; align-items: center; }
.input-with-button input { flex: 1 1 auto; }
.input-with-button button { margin: 0; white-space: nowrap; }
button {
  background: var(--accent); color: #fff; border: none; border-radius: 6px; padding: 9px 16px;
  font-size: 13px; cursor: pointer; margin-right: 8px; margin-top: 6px;
}
button.secondary { background: #fff; color: #4a4038; border: 1px solid var(--line); }
button.small { padding: 5px 10px; font-size: 12px; }
button:hover { opacity: 0.9; }
/* Task #134 (confirm modal generic, dipakai ganti window.confirm() bawaan) -- tombol OK di modal
   Confirm diwarnai merah lewat class INI kalau `danger:true` (dipakai Delete), supaya beda jelas dari
   konfirmasi Save/navigasi yang netral (warna --accent biru default). */
button.danger { background: var(--danger); }
/* Task #423 ("Cek NetSuite" sekarang selalu ada di TTF List, disabled kalau Vendor Bill Number belum
   diisi -- lihat renderListTable() di app.js) -- beda tampilan jelas dari tombol aktif. */
button:disabled { background: #f0f1f3; color: var(--muted); border: 1px solid var(--line); cursor: not-allowed; opacity: 1; }
button:disabled:hover { opacity: 1; }

/* Task #423 (user: "invoice item tolong samain sama mockup design" + "buatkan section divider juga")
   -- Invoice Items header row dikasih background abu2 muda, TIAP baris item dipisah garis (row
   divider) BUKAN cuma margin-top kosong spt sebelumnya.
   FIX (18 Sep 2026, "buat scroll ke samping aja dan invoice no & description nya difreeze columnya")
   -- .items-card (overflow:hidden, TIDAK bisa scroll) DIGANTI .items-scroll (overflow-x:auto) supaya
   tabel item bisa di-scroll ke samping kalau kolomnya lebih lebar dari container -- Invoice No &
   Description di-freeze (position:sticky, lihat .item-row-grid > :nth-child di bawah) supaya tetap
   kelihatan pas scroll.
   FIX #146 (18 Sep 2026) -- grid 9 kolom FIXED PX (BUKAN fr, supaya offset sticky konsisten terlepas
   dari lebar viewport -- offset kolom ke-N = jumlah lebar kolom SEBELUMNYA, gap:0 sengaja dipilih spy
   tidak perlu hitung gap juga).
   FIX (19 Sep 2026) -- 3 iterasi Receipt No/PR No/PO No/Vendor Bill No di hari yang sama (riwayat
   lengkap di komentar dekat makeItemRowEl(), app.js): panel bersama (Task #146, "Ini tidak enak kalau
   panel nya dibawah") -> panel per-baris expand/collapse ("bikin pusing, po no dan vendorbill nya
   kenapa jadi row ke dua") -> FINAL (dipakai sekarang): grid 15 kolom FIXED PX, SEMUA field (termasuk
   Receipt No/PR No/PO No/Vendor Bill No/tombol Cek NetSuite/Status) jadi kolom inline BIASA lagi, SATU
   baris polos per item (user: "1 baris aja scroll ke samping"), font-size kolom2 baru ini dikecilkan
   (user: "fontsizenya diperkecil", lihat `.item-row-grid input, .item-row-grid button` di bawah) --
   lebar kolom2 ini SENGAJA ringkas (~90-120px, user: "ga panjang kok kolom nya kira2 25 digit"), BUKAN
   dilebarkan penuh spt kolom Tax No. Horizontal-scroll (.items-scroll) + freeze Invoice No/Description
   (position:sticky di bawah) SENGAJA TIDAK diubah sama sekali, sesuai arahan eksplisit user.
   FIX (19 Sep 2026, user: "untuk action cek netsuite jadi action button yang freeze juga di tabel alias
   tidak ikut scroll" + follow-up "action button di table seperti ini harusnya tidak scrollable jadi
   freeze per baris implement di semuanya") -- kolom "Status" (pesan hasil Cek NetSuite) DIPINDAH ke
   posisi ke-13 (sebelum tombol Cek NetSuite, LIHAT urutan div header di index.html & urutan elemen di
   makeItemRowEl(), app.js -- keduanya ikut diubah SAMA), supaya tombol "Cek NetSuite" (kolom 14) dan
   tombol Remove/x (kolom 15) jadi 2 kolom PALING KANAN yang di-freeze (position:sticky right:, lihat
   nth-child(14)/(15) di bawah) -- SAMA teknik dgn freeze Invoice No/Description di kiri (nth-child(1)/
   (2) di atas), cuma arahnya kebalik (nempel kanan, bukan kiri). */
.items-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: 8px; margin-top: 10px; }
.items-head, .item-row-grid {
  display: grid;
  grid-template-columns: 150px 220px 70px 100px 100px 190px 130px 130px 100px 90px 90px 120px 130px 90px 36px;
  gap: 0; min-width: 1746px; align-items: center;
}
.items-head {
  font-size: 11px; color: var(--muted); font-weight: 700; text-transform: uppercase; letter-spacing: .3px;
  background: var(--bg); padding: 10px 12px;
}
.items-card .item-row,
.item-row {
  border-top: 1px solid var(--line); padding: 0; margin-top: 0;
}
.item-row:first-of-type { border-top: none; }
.item-row-grid { padding: 8px 12px; }
.item-row-grid input { padding: 6px 8px; width: 100%; box-sizing: border-box; }
.item-row-grid .amount { text-align: right; font-size: 13px; padding: 6px 8px 6px 2px; }
/* FIX (19 Sep 2026, user: "please set different colour for this action button and background not
   transparent") -- tombol Remove (x) SEBELUMNYA background:transparent (menyatu dgn background kolom
   frozen di belakangnya, jadi kurang kelihatan sbg tombol) -- SEKARANG dikasih background solid merah
   muda + border, SAMA skema warna dgn .msg.error (styles.css atas) supaya konsisten sbg "warna
   danger/hapus" di seluruh app. */
.item-row-grid .remove-btn {
  background: #fdecea; color: var(--danger); border: 1px solid #f3c2bb; border-radius: 4px;
  cursor: pointer; padding: 2px 8px; margin: 0; font-size: 15px; line-height: 1.3; justify-self: center;
}
.item-row-grid .remove-btn:hover { background: #fbdcd8; }
/* Freeze (position:sticky) kolom Invoice No (kolom 1, left:0) & Description (kolom 2, left:150px --
   SAMA dgn lebar kolom 1 di grid-template-columns di atas) -- background SOLID (var(--card-bg))
   wajib supaya konten kolom lain yang di-scroll di baliknya TIDAK "tembus" kelihatan. border-right di
   kolom Description sbg garis pembatas visual antara area frozen & area yang bisa di-scroll.
   TIDAK diubah (19 Sep 2026, user: "sebaiknya scroll ke samping terus tapi kolom invoice no dan
   descript freeze") -- explicit constraint dari user, JANGAN dihapus/diganti pendekatan lain. */
.items-head > :nth-child(1), .item-row-grid > :nth-child(1) {
  position: sticky; left: 0; z-index: 2; background: var(--card-bg);
}
.items-head > :nth-child(2), .item-row-grid > :nth-child(2) {
  position: sticky; left: 150px; z-index: 2; background: var(--card-bg); border-right: 1px solid var(--line);
}
.item-row-grid > :nth-child(1), .item-row-grid > :nth-child(2) { padding-left: 0; }

/* FIX (19 Sep 2026, user: "action cek netsuite jadi action button yang freeze juga ... tidak ikut
   scroll") -- freeze kolom 14 (tombol "Cek NetSuite") & 15 (tombol Remove/x) di KANAN (position:sticky
   right:), SAMA teknik freeze dgn Invoice No/Description di kiri di atas. Offset kolom 14 (right:36px)
   = lebar kolom 15 (Remove, 36px) supaya kedua kolom ini nempel BERSEBELAHAN di ujung kanan, bukan
   tumpang tindih. border-left sbg garis pembatas visual (SAMA fungsi dgn border-right di kolom
   Description utk sisi kiri). */
.items-head > :nth-child(14), .item-row-grid > :nth-child(14) {
  position: sticky; right: 36px; z-index: 2; background: var(--card-bg); border-left: 1px solid var(--line);
}
.items-head > :nth-child(15), .item-row-grid > :nth-child(15) {
  position: sticky; right: 0; z-index: 2; background: var(--card-bg);
}

/* FIX (19 Sep 2026, user: "di sini kursor fokus diwarnai kuning biar aware usernya") -- input yang
   lagi difokus/diketik dikasih warna kuning KHUSUS (BUKAN outline focus bawaan browser) supaya jelas
   kelihatan field MANA PERSIS yang sedang diketik. */
.item-row-grid input:focus {
  outline: none; border-color: #d9a400; box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.4);
}

/* FIX (19 Sep 2026, user: "fontsizenya diperkecil") -- kolom2 ERP Reference (Receipt No/PR No/PO
   No/Vendor Bill No/tombol Cek NetSuite/Status) dikecilkan font-nya drpd kolom lain (13px bawaan
   .item-row-grid input) supaya tetap ringkas walau kolomnya sempit (~90-120px). */
.item-row-grid .it-receipt-no, .item-row-grid .it-pr-no, .item-row-grid .it-po-no, .item-row-grid .it-vendorbill-no {
  font-size: 11.5px; padding: 5px 6px;
}
/* FIX (19 Sep 2026, user: "please set different colour for this action button and background not
   transparent") -- tombol Cek NetSuite (SEKARANG nempel/frozen di kolom 14, lihat nth-child(14) di
   atas) dikasih warna biru muda solid (var(--accent-light)/var(--accent)), BEDA dari default
   button.secondary putih polos, supaya jelas kelihatan sbg tombol aksi biarpun nempel di atas
   background frozen (var(--card-bg), putih juga -- tanpa warna beda, tombolnya "hilang"/menyatu). */
.item-row-grid .it-ns-cek-btn {
  margin: 0; white-space: nowrap; padding: 5px 6px; font-size: 10.5px; justify-self: center;
  background: var(--accent-light); color: var(--accent-dark); border: 1px solid var(--accent);
}
.item-row-grid .it-ns-cek-btn:hover { background: #dfe8f2; }
.item-row-grid .it-ns-msg {
  font-size: 10.5px; margin: 0; min-height: 0; padding: 0 4px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 100%;
}
.item-row-grid .it-ns-msg:empty { padding: 0; }

.total-row {
  display: flex; justify-content: flex-end; gap: 25px; padding-top: 12px; margin-top: 10px;
  border-top: 1px solid var(--line); font-size: 15px;
}

.msg { font-size: 12px; margin-top: 10px; min-height: 16px; }
/* Task #134 (user: "untuk error2 system dikemas yang lain jangan default") -- .msg.error/.msg.ok
   SEBELUMNYA cuma teks kecil warna merah/hijau polos (gampang kelewat, "default"-looking) -- SEKARANG
   dikemas jadi kotak dgn border+background tint+ikon supaya jelas terlihat "ini pesan penting", bukan
   teks biasa. Pesan progres netral (showMsg(id, '...') TANPA kind, mis. "Uploading...") TETAP teks
   polos seperti sebelumnya (TIDAK kena styling boks ini) -- cuma .error/.ok yang dikemas ulang. */
.msg.error, .msg.ok {
  padding: 8px 10px 8px 30px; border-radius: 6px; position: relative; line-height: 1.4; font-weight: 500;
}
.msg.error:empty, .msg.ok:empty { padding: 0; border: none; background: none; min-height: 16px; }
.msg.error { color: var(--danger); background: #fdecea; border: 1px solid #f3c2bb; }
.msg.ok { color: #1a7f37; background: #e9f6ec; border: 1px solid #bfe3c8; }
.msg.error:not(:empty)::before {
  content: "!"; position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; line-height: 14px; border-radius: 50%; background: var(--danger);
  color: #fff; font-size: 10px; font-weight: 800; text-align: center;
}
.msg.ok:not(:empty)::before {
  content: "\2713"; position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; line-height: 14px; border-radius: 50%; background: #1a7f37;
  color: #fff; font-size: 10px; font-weight: 800; text-align: center;
}

.table-wrap { overflow-x: auto; margin-top: 14px; }
/* FIX (16 Sep 2026, "tabel nya lebih pendek lagi... terlalu ada spasi antar row") -- padding vertikal
   baris tabel Master Data/List diperkecil (6px -> 3px) + line-height dirapatkan, supaya lebih banyak
   baris kelihatan tanpa scroll, TANPA ubah lebar kolom/border. */
/* FIX (17 Sep 2026, user: "font size tolong direduce untuk semua tabel") -- diturunkan dari 12px ->
   11.5px + padding baris dipepetin dikit (3px 8px -> 2px 7px), berlaku ke SEMUA tabel yang pakai class
   ini (yang mana hampir semua tabel di app -- 1 pengecualian yang KELEWAT, tabel Report Tax, baru saja
   ditambah class="report"-nya juga, lihat renderTaxReportTable() di app.js). */
table.report { border-collapse: collapse; width: 100%; font-size: 11.5px; line-height: 1.25; }
table.report th, table.report td { border: 1px solid var(--line); padding: 2px 7px; text-align: left; white-space: nowrap; }
table.report th { background: var(--accent-light); font-weight: 700; }
table.report td.wrap { white-space: normal; max-width: 320px; word-break: break-word; }
/* FIX (17 Sep 2026, user: "description butuh didepan dan dilebarin sedikit lalu diwrap") -- kolom
   Description TTF List, class TERPISAH dari .wrap generic di atas (COA Mapping) krn butuh min-width
   sendiri: TANPA min-width, table-layout:auto bisa mepetin kolom ini sampai kata jadi kepotong tengah
   (mis. "maintenanc"/"e") kalau kolom lain di tabel sudah rebutan lebar. overflow-wrap (BUKAN
   word-break) dipakai supaya cuma kata yang BENERAN lebih panjang dari kolom yang dipotong paksa --
   kata normal tetap wrap di spasi apa adanya. */
table.report th.ttf-desc-col, table.report td.ttf-desc-col {
  white-space: normal; min-width: 220px; max-width: 320px; overflow-wrap: break-word;
}
/* FIX (18 Sep 2026, user: "sort yang saya ekspektasi seperti ini" + screenshot menu "..." dgn opsi
   "Sort A to Z"/"Sort Z to A") -- kolom sortable (TTF List/TTF List by Invoice, lihat sortableTh_()
   di app.js) SEKARANG isinya: label+panah (kalau kolom ini SEDANG aktif disortir) + tombol "..." yang
   buka menu kecil. `position: relative` di th supaya menu-nya (position: absolute) bisa nempel PAS di
   bawah tombol "..."-nya, BUKAN di pojok kiri-atas seluruh tabel. */
table.report th.sortable-th { position: relative; white-space: nowrap; }
table.report th.sortable-th .th-label { margin-right: 2px; }
table.report th.sortable-th .th-sort-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 16px; padding: 0; margin-left: 2px; vertical-align: middle;
  background: transparent; border: 1px solid transparent; border-radius: 3px;
  color: inherit; font-weight: 400; font-size: 12px; line-height: 1; cursor: pointer;
}
table.report th.sortable-th .th-sort-btn:hover,
table.report th.sortable-th .th-sort-btn.active { background: #dfe8f2; border-color: var(--line); }
table.report th.sortable-th .th-sort-menu {
  position: absolute; top: 100%; left: 0; z-index: 30; margin-top: 2px;
  background: #fff; border: 1px solid var(--line); border-radius: 4px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.15); min-width: 130px;
  font-weight: 400; text-transform: none; white-space: nowrap;
}
table.report th.sortable-th .th-sort-menu.hidden { display: none; }
table.report th.sortable-th .th-sort-menu div { padding: 6px 12px; cursor: pointer; }
table.report th.sortable-th .th-sort-menu div:hover { background: var(--accent-light); }

/* FIX (19 Sep 2026, user: "action button di table seperti ini harusnya tidak scrollable jadi freeze
   per baris implement di semuanya" -- screenshot Store List, Edit/Delete hilang ke kanan pas scroll
   horizontal) -- kolom aksi (Edit/Delete/Send/Open TTF/dst, SELALU kolom PALING KANAN di semua tabel
   .report yang generate tombol aksi -- lihat class="sticky-action-col" yang ditambahkan di app.js:
   renderMasterTable/renderUsersTable/renderRolesTable/renderListTable/renderListByInvoiceTable/
   renderTaxReportTable/renderTaxSetupTable) SEKARANG position:sticky nempel di kanan (right:0),
   SAMA teknik dgn Invoice No/Description freeze di Invoice Items (.items-head, lihat di bawah), jadi
   tombol aksi selalu kelihatan biarpun tabel discroll ke samping. TIDAK diterapkan ke tabel yang kolom
   terakhirnya BUKAN kolom aksi (mis. GL History "Detail", Permission Matrix) -- makanya per-kolom pakai
   class eksplisit, BUKAN blanket "kolom terakhir tabel.report manapun". */
table.report th.sticky-action-col, table.report td.sticky-action-col {
  position: sticky; right: 0; z-index: 2; background: var(--card-bg);
  box-shadow: -2px 0 4px rgba(0,0,0,0.08);
}
table.report th.sticky-action-col { background: var(--accent-light); z-index: 3; }
/* FIX (19 Sep 2026, user: "please set different colour for this action button and background not
   transparent") -- tombol Edit/Delete/Send/Open TTF/Data Tambahan di kolom aksi frozen (SEMUA tabel
   .report, lihat class="sticky-action-col" di app.js) SEKARANG warna biru muda solid, BEDA dari default
   button.secondary putih polos -- SAMA skema warna dgn Cek NetSuite di Invoice Items (lihat
   .item-row-grid .it-ns-cek-btn di atas) supaya konsisten 1 warna "tombol aksi" di seluruh app. */
table.report td.sticky-action-col button.secondary {
  background: var(--accent-light); color: var(--accent-dark); border: 1px solid var(--accent);
}
table.report td.sticky-action-col button.secondary:hover { background: #dfe8f2; }
.status-pill { display: inline-block; padding: 2px 8px; border-radius: 20px; font-size: 11px; font-weight: 600; }
.status-New { background: #eef2ff; color: #3730a3; }
.status-Billed { background: #fef3c7; color: #92400e; }
.status-Sent { background: #dcfce7; color: #166534; }
.status-Canceled { background: #fee2e2; color: #991b1b; }

/* Report PL (lihat public/index.html data-module="report-pl" + app.js:REPORT_DEFS) -- daftar tipe
   report ditampilkan sbg baris tombol kecil ("chip"), mirip .tab-btn tapi bisa wrap ke baris
   berikutnya (9 tipe, tidak muat 1 baris di layar sempit) dan punya state "unavailable" (backend
   belum di-port dari Apps Script -- lihat reportService.js:AVAILABLE_REPORT_TYPES) yang dibedakan
   visual dari tipe yang aktif/bisa dipakai. */
.report-type-list { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.report-type-btn {
  background: #fff; color: #4a4038; border: 1px solid var(--line); border-radius: 20px;
  padding: 7px 14px; font-size: 12.5px; cursor: pointer; margin: 0;
}
.report-type-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 600; }
.report-type-btn.unavailable { color: var(--muted); background: #f0f1f3; }
.report-type-btn.unavailable::after { content: ' (belum tersedia)'; font-size: 10.5px; }

/* Modals */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.35); display: flex;
  align-items: flex-start; justify-content: center; padding: 40px 16px; overflow-y: auto; z-index: 50;
}
.modal-box {
  background: #fff; border-radius: 10px; padding: 24px; width: 100%; max-width: 720px;
  box-shadow: 0 8px 30px rgba(0,0,0,0.2);
}
.modal-box h2 { margin-top: 0; font-size: 14.5px; }
.modal-actions { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 14px; }

/* Task "keamanan login" (19 Sep 2026, 2FA) -- grid 10 backup code, monospace supaya gampang dibaca/
   disalin (mirip tampilan kunci lisensi/kode voucher), panel latar beda supaya kelihatan "penting". */
.backup-codes-list {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin: 12px 0;
  padding: 14px; background: #f6f7f9; border: 1px solid var(--line); border-radius: 8px;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 13px; letter-spacing: 0.5px;
}

/* Autocomplete generic (custom-positioned, ganti native <input list=datalist> -- lihat catatan bugfix
   di app.js:loadVendorOptions/loadDeptOptions/renderAutocomplete_. Dipakai bergantian oleh Vendor Name
   DAN Department (Task #423). position:fixed dihitung manual dari getBoundingClientRect() input yang
   aktif, z-index di atas .modal-overlay (50) supaya tetap muncul benar di atas modal Edit TTF juga. */
.ac-list {
  position: fixed; z-index: 200; background: #fff; border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.15); max-height: 260px; overflow-y: auto;
}
.ac-list.hidden { display: none; }
.ac-item { padding: 6px 12px; font-size: 13px; cursor: pointer; }
.ac-item:hover { background: var(--accent-light); }
/* Task #423: baris ke-2 opsional per item (dipakai Vendor Name -- Alamat+RSC, lihat
   app.js:formatVendorAcItem_()) -- Department tetap 1 baris polos (.ac-item-main/.ac-item-sub tidak
   dipakai sama sekali di situ, .ac-item polos jatuh ke `textContent` biasa). */
.ac-item-main { line-height: 1.3; }
.ac-item-sub { font-size: 11px; color: var(--muted); line-height: 1.3; margin-top: 1px; }

/* Role Access checklist (Role Management > Buat/Edit Role) -- Task #423 (16 Sep 2026): user TOLAK
   versi kartu-per-menu (Task #419, aturan lama ada di riwayat git) dan minta layout sesuai referensi
   screenshot yang dikirim: 1 kotak "Search permission" + 1 daftar FLAT bisa di-scroll ("List of
   permission" + tombol "Active All" di header-nya), tiap baris "<Menu>: <Action>" dgn checkbox di
   kanan. Lihat app.js:renderPermissionMatrix()/filterPermissionRows()/toggleAllPermissionRows(). */
.rm-perm-search {
  width: 100%; margin-top: 8px; margin-bottom: 10px; padding: 8px 12px; font-size: 13px;
  border: 1px solid var(--line); border-radius: 8px; box-sizing: border-box;
}
.rm-perm-list { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: #fff; }
.rm-perm-list-header {
  display: flex; align-items: center; justify-content: space-between; padding: 10px 14px;
  background: var(--bg); border-bottom: 1px solid var(--line); font-size: 12.5px; font-weight: 700;
  color: var(--ink);
}
.rm-perm-active-all {
  border: 1px solid var(--line); background: #fff; border-radius: 6px; padding: 4px 10px;
  font-size: 12px; font-weight: 600; color: var(--accent); cursor: pointer;
}
.rm-perm-active-all:hover { background: var(--accent-light); }
.rm-perm-list-body { max-height: 340px; overflow-y: auto; }
.rm-perm-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px; font-size: 13px; font-weight: normal; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.rm-perm-item:last-child { border-bottom: none; }
.rm-perm-item:hover { background: var(--accent-light); }
.rm-perm-item.hidden { display: none; }
/* PENTING: reset `width`/`padding` bawaan aturan generic "input, select { width:100% }" (baris ~110)
   -- tanpa ini, checkbox jadi flex item dgn flex-basis:100% (spec: flex-basis:auto jatuh balik ke
   `width` yang di-set), artinya checkbox "minta" lebar SELEBAR SELURUH BARIS, label kepepet jadi
   sliver sempit (bungkus per-kata) & baris meluber ke kanan (nongol scrollbar horizontal di
   .table-wrap) -- ini PERSIS bug yang dilaporkan user ("masih brantakan", screenshot 16 Sep 2026). */
.rm-perm-item input[type="checkbox"] { width: 16px; height: 16px; padding: 0; margin: 0; flex: none; }
.rm-perm-item-label { flex: 1 1 auto; min-width: 0; }
.rm-perm-item:has(input:disabled) { cursor: not-allowed; color: var(--muted); opacity: .65; }
/* Task #421 (16 Sep 2026, "lengkapi halaman edit UI juga") -- lihat role Edit utk role SISTEM
   (admin/fin/acct/tax/cashier): semua checkbox read-only (lihat catatan panjang di index.html soal
   kenapa), tapi tanpa penanda apa pun sebelum ini bikin ambigu -- kelihatan kayak "role ini BENERAN
   0 akses" padahal cuma tabel role_permissions belum di-seed manual utk role sistem (aksesnya diatur
   di kode, bukan dari sini). Daftar di-dim sebagai penanda visual "view-only", di atas #rmSystemNote
   yang sudah menjelaskan teksnya. Tombol "Active All" juga TIDAK dirender sama sekali utk readonly
   (lihat renderPermissionMatrix()), jadi tidak perlu di-disable manual di sini. */
.rm-perm-list--readonly { background: var(--bg); opacity: .85; }

/* Pagination Master Data (Task #423, "buatkan pagination untuk semua master ... kecuali coa
   mapping") -- lihat app.js:buildMasterPager_(). */
.master-pager {
  display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 10px;
}
.master-pager-info { font-size: 12.5px; color: var(--muted); }

/* Toolbar search + page-size Master Data (Task #423, "default 20 baris, bisa pilih 20/50/100/200" +
   "sediakan fitur searchna") -- lihat app.js:buildMasterToolbar_(). */
.master-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 12px; flex-wrap: wrap;
}
.master-toolbar-search { flex: 1 1 240px; max-width: 320px; margin: 0; }
.master-toolbar-pagesize-wrap { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.master-toolbar-pagesize-wrap label { margin: 0; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.master-toolbar-pagesize-wrap select { margin: 0; width: auto; }

/* Kolom audit (Dibuat/Diubah Oleh/Pada) di tabel Master Data (Task #423) -- dibedakan visual dari
   kolom data biasa (lebih kecil/pudar) supaya jelas ini metadata read-only, bukan field yg bisa
   diedit lewat form di atasnya (lihat app.js:MASTER_AUDIT_FIELDS). */
.master-audit-col { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
/* Task (17 Sep 2026, "tambahkan no baris di setiap master") -- kolom "No." nomor urut, sempit +
   center + muted supaya tidak menarik perhatian lebih dari kolom data sebenarnya. */
.master-no-col { width: 1%; white-space: nowrap; text-align: center; color: var(--muted); }

#historyList { font-size: 12px; max-height: 320px; overflow-y: auto; }
.history-item { border-bottom: 1px solid var(--line); padding: 8px 0; }
.history-item .h-action { font-weight: 700; }
.history-item .h-meta { color: var(--muted); }

/* Print */
.print-only { display: none; }
@media print {
  #loginScreen, #appScreen, .modal-overlay { display: none !important; }
  .print-only { display: block; }
}

/* Task "MT940 Converter" (19 Sep 2026) -- 3 elemen yang Finata belum punya primitive generic-nya
   (dropzone upload, kartu ringkasan statistik, kotak pratinjau teks) -- SEMUA class di-scope dgn
   prefix `.mt940-` (BUKAN nama elemen polos spt `.dropzone`/`.stats`) supaya TIDAK bentrok/nge-leak
   ke modul lain kalau nanti ada fitur lain yang kebetulan mau nama class sama. Warna pakai variabel
   :root yang SUDAH ada (--line/--muted/--bg/--card-bg/--danger/--accent) -- BUKAN palet baru --
   supaya otomatis konsisten dgn look SELURUH app, bukan sisipan gaya asing dari file HTML sumbernya. */
.mt940-dropzone {
  border: 1.5px dashed var(--line); border-radius: 8px; padding: 14px 16px; background: var(--bg);
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.mt940-dropzone:hover, .mt940-dropzone.drag { border-color: var(--accent); background: var(--accent-light); }
.mt940-dz-text strong { display: block; font-size: 13px; font-weight: 600; }
.mt940-dz-text span { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }

.mt940-stats { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 10px; margin-bottom: 12px; }
@media (max-width: 720px) { .mt940-stats { grid-template-columns: repeat(2, minmax(0,1fr)); } }
.mt940-stat { background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.mt940-stat .k { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.mt940-stat .v { font-size: 13px; margin-top: 3px; word-break: break-all; font-weight: 600; }
.mt940-stat.debit .v { color: var(--danger); }
.mt940-stat.credit .v { color: #1a7f37; }

.mt940-output-wrap { border: 1px solid var(--line); border-radius: 8px; background: var(--bg); overflow: hidden; }
.mt940-output-empty { padding: 32px 16px; text-align: center; }
.mt940-textarea {
  display: block; width: 100%; min-height: 340px; max-height: 500px; resize: vertical; border: none;
  background: transparent; color: var(--ink); font-family: "SF Mono", Consolas, monospace; font-size: 12px;
  line-height: 1.6; padding: 12px 14px; white-space: pre; overflow: auto; box-sizing: border-box;
}
.mt940-textarea:focus-visible { outline: none; }

