/* ═══════════════════════════════════════════════════════════════════════════
 * NOVA — LAPISAN KOMPONEN (B5 §4)
 * ───────────────────────────────────────────────────────────────────────────
 * Isi berkas ini persis §4 pada migrasi/B5-spec.md: tombol, kolom isian,
 * kontrol centang, chip status, kartu & KPI, BAR PROGRES, bagan, tabel,
 * avatar & baris daftar. Kulit aplikasi (sidebar, kepala halaman, modal,
 * laci, menu ⋮, toast, FAB, bilah bawah HP) ada di nova-shell.css.
 *
 * Empat aturan yang berlaku di seluruh berkas:
 *
 * 1. TOKEN, BUKAN HEX. Semua warna, sudut, jarak dan ukuran huruf diambil
 *    dari var() yang sudah ditulis nova.css. Satu-satunya hex langsung ada
 *    di dua data-URI panah <select> (§4.2) — data-URI tidak bisa membaca
 *    var(), dan kedua nilainya disalin dari --xcs-ink-3 per tema.
 *
 * 2. KOMPONEN fsw- MEMAKAI TOKEN fsw-. --fsw-card / --fsw-tint / --fsw-line /
 *    --fsw-ink-* / --fsw-radius-* adalah alias yang menunjuk ke token --xcs-*.
 *    Menulis --xcs-bg-2 langsung di aturan fsw- memotong satu tingkat
 *    penunjukan dan membuat modul ops berhenti mengikuti aliasnya sendiri.
 *
 * 3. KEDUA TEMA SELALU BENAR. Kalau sebuah aturan lama punya kembaran
 *    [data-theme="dark"] di styles.css, aturan di sini wajib punya kembaran
 *    yang sama — kalau tidak, spesifisitas 0,2,0 milik aturan lama menang
 *    dan mode gelap tidak ikut berubah. Tiap tempat seperti itu diberi
 *    catatan nomor baris asalnya.
 *
 * 4. !important HANYA MENYUSUL, DAN SEMPIT. Dipakai persis pada properti yang
 *    aturan lamanya juga memakai !important, pada selector sespesifik
 *    aslinya. Menaruhnya pada selector yang lebih pendek akan menang atas
 *    aturan yang TIDAK memakainya — misalnya ops-theme.css:1675 yang
 *    mengecilkan tombol di dalam .fsw-it dan .fsw-table — dan diam-diam
 *    merusak tabel. Jadi aturan dasar di bawah sengaja tanpa !important,
 *    dan ragam .xcs-pagehead-cta ditulis terpisah dengan !important.
 * ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 4.1 TOMBOL ═══════════════════════════════════════════════════════════
   Empat ragam: primary (aksi utama, hijau), secondary, ghost, danger.
   Tinggi 38px, kecil 32px, besar 44px, ikon 16px, jarak 8px, radius 10px.
   Referensi tidak punya tombol pil — semuanya persegi lembut. */

/* ── Primary ──────────────────────────────────────────────────────────────
   Tanpa !important: styles.css menulis tombol ini di 619 / 5925 / 12038
   tanpa !important juga, dan berkas ini dimuat terakhir sehingga 0,1,0 di
   sini sudah menang. Yang TIDAK boleh kalah adalah ops-theme.css:1675
   (`.fsw-table .xcs-btn-primary`, 0,2,0) yang mengecilkan tombol di dalam
   baris tabel — ia harus tetap menang, jadi tidak ada !important di sini. */
.xcs-btn-primary,
button.xcs-btn-primary {
  background: var(--fsw-accent); color: var(--fsw-on-accent); border: 0;
  border-radius: var(--xcs-radius-sm); padding: 0 16px; min-height: 38px;
  font-size: 13.5px; font-weight: 600; letter-spacing: -0.005em;
  /* Referensi nyaris tanpa bayangan; kedalaman datang dari warna. */
  box-shadow: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: filter .16s ease, transform .1s ease;
}
/* styles.css:17654 memberi mode gelap gradien --xcs-chrome (0,2,0, tanpa
   !important). Aksen di sini rata supaya tombol utama terbaca sebagai satu
   bidang hijau yang sama di dua tema. */
[data-theme="dark"] .xcs-btn-primary,
[data-theme="dark"] button.xcs-btn-primary {
  background: var(--fsw-accent);
  color: var(--fsw-on-accent);
  border: 0;
  box-shadow: none;
}
.xcs-btn-primary:hover:not(:disabled),
[data-theme="dark"] .xcs-btn-primary:hover:not(:disabled) {
  background: var(--fsw-accent);
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow: none;
}
.xcs-btn-primary:active:not(:disabled) { transform: translateY(0); }
.xcs-btn-primary:disabled { opacity: .45; cursor: not-allowed; transform: none; filter: none; }

/* ── Ghost / secondary ────────────────────────────────────────────────────
   .xcs-btn-ghost adalah tombol yang paling sering dipakai di ruang kerja
   (92 pemakaian di ops-*.jsx), jadi ia dibuat tenang: garis + tinta, isian
   baru muncul saat disentuh. */
.xcs-btn-ghost {
  background: transparent; color: var(--xcs-ink-2);
  border: 1px solid var(--xcs-line-1); border-radius: var(--xcs-radius-sm);
  padding: 0 14px; min-height: 38px;
  font-size: 13.5px; font-weight: 600; letter-spacing: -0.005em;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
.xcs-btn-ghost:hover:not(:disabled) {
  background: var(--xcs-bg-3);
  border-color: var(--xcs-line-2);
  color: var(--xcs-ink-1);
}
.xcs-btn-ghost:disabled { opacity: .45; cursor: not-allowed; }
/* styles.css:14033 dan 17682 menulis ulang tombol ini untuk mode gelap
   DENGAN !important (putih 4% di atas garis putih 10%). Hanya ketiga
   properti itu yang disusul — bantalan dan ukuran huruf sengaja dibiarkan
   supaya ops-theme.css:1675 tetap bisa mengecilkannya di dalam tabel. */
[data-theme="dark"] .xcs-btn-ghost {
  background: transparent !important;
  color: var(--xcs-ink-2) !important;
  border-color: var(--xcs-line-1) !important;
}
[data-theme="dark"] .xcs-btn-ghost:hover:not(:disabled) {
  background: var(--xcs-bg-3) !important;
  border-color: var(--xcs-line-2) !important;
  color: var(--xcs-ink-1) !important;
}

/* Tombol kepala halaman. styles.css:13145/13171 menulis keduanya dengan
   !important pada SETIAP properti, jadi blok ini terpaksa menyalin ulang
   dan ikut !important. Spesifisitasnya sama persis (0,2,0) sehingga tidak
   ada aturan lain yang ikut tertimpa. */
.xcs-pagehead-cta .xcs-btn-primary {
  background: var(--fsw-accent) !important; color: var(--fsw-on-accent) !important;
  border: 0 !important; border-radius: var(--xcs-radius-sm) !important;
  padding: 0 16px !important; min-height: 38px;
  font-size: 13.5px !important; font-weight: 600 !important; box-shadow: none !important;
}
.xcs-pagehead-cta .xcs-btn-primary:hover:not(:disabled) {
  background: var(--fsw-accent) !important;
  filter: brightness(1.08);
  box-shadow: none !important;
}
.xcs-pagehead-cta .xcs-btn-ghost,
[data-theme="dark"] .xcs-pagehead-cta .xcs-btn-ghost {
  background: transparent !important; color: var(--xcs-ink-2) !important;
  border: 1px solid var(--xcs-line-1) !important;
  border-radius: var(--xcs-radius-sm) !important;
  padding: 0 14px !important; min-height: 38px;
  font-size: 13.5px !important; font-weight: 600 !important;
}
.xcs-pagehead-cta .xcs-btn-ghost:hover,
[data-theme="dark"] .xcs-pagehead-cta .xcs-btn-ghost:hover {
  background: var(--xcs-bg-3) !important;
  border-color: var(--xcs-line-2) !important;
  color: var(--xcs-ink-1) !important;
  transform: none;
}
/* ops-theme.css:2249 memilinkan tombol kepala halaman jadi pil penuh lewat
   --fsw-radius-chip, memakai !important karena styles.css:13150 mengunci
   999px. Referensi memakai persegi lembut; selector dan !important
   disamakan supaya menang tanpa menaikkan spesifisitas lebih jauh. */
.fsw-page > .xcs-pagehead .xcs-pagehead-cta > button {
  border-radius: var(--xcs-radius-sm) !important;
}

/* Ukuran kecil — styles.css:14569 memakai !important untuk ketiganya. */
.xcs-btn-sm {
  min-height: 32px;
  padding: 0 12px !important;
  font-size: 12.5px !important;
  border-radius: var(--xcs-radius-xs) !important;
}

/* Tombol ringkasan papan kerja (ops-ui.jsx:274).
   CATATAN TINJAUAN: blok ini dulu juga menulis .fsw-kbtn beserta ragam
   .is-primary / .is-ok / .is-danger. Diperiksa ulang dengan
   `grep -rn 'fsw-kbtn' *.jsx` → NOL kemunculan; kelas itu hanya hidup di
   ops-theme.css:620 dan tidak pernah dirender. Seluruh barisnya dihapus
   supaya berkas ini hanya berisi aturan yang benar-benar berlaku. */
.fsw-summary-tog {
  min-height: 32px; border-radius: var(--fsw-radius-sm); border-color: var(--fsw-line);
  background: transparent; color: var(--fsw-ink-2); font-weight: 600; gap: 8px;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
.fsw-summary-tog:hover {
  background: var(--xcs-bg-3);
  border-color: var(--xcs-line-2);
  color: var(--fsw-ink);
}

/* ── Danger ───────────────────────────────────────────────────────────────
   Garis + tinta merah, isian hanya saat hover. ops-theme.css:1356 memakai
   !important pada color dan border-color, jadi keduanya disusul. */
.fsw-btn-danger,
.xcs-btn-danger {
  background: transparent;
  color: var(--fsw-red) !important;
  border: 1px solid color-mix(in srgb, var(--fsw-red) 45%, transparent) !important;
  border-radius: var(--xcs-radius-sm);
}
.fsw-btn-danger:hover:not(:disabled),
.xcs-btn-danger:hover:not(:disabled) {
  background: var(--fsw-red-soft) !important;
  border-color: var(--fsw-red) !important;
  color: var(--fsw-red) !important;
}
/* styles.css:17696 dan 20394 menulis ragam gelapnya sendiri (0,2,0). */
[data-theme="dark"] .xcs-btn-danger {
  background: transparent;
  color: var(--fsw-red) !important;
  border-color: color-mix(in srgb, var(--fsw-red) 45%, transparent) !important;
}
/* CACAT KONTRAS (tinjauan): putih di atas --xcs-red hanya 3,09:1 di tema
   gelap, karena --xcs-red gelap sengaja DICERAHKAN (#F4635F) supaya aman
   sebagai warna TEKS. Sebagai isian ia butuh tinta gelap, persis seperti
   tombol aksen. Terang: #FFFFFF di atas #C7302F = 5,40:1. Gelap:
   --fsw-on-accent di atas #F4635F = 6,24:1. Sekalian menghapus satu-satunya
   hex langsung di berkas ini — --xcs-ink-on-brand sudah bernilai putih. */
.xcs-btn-danger-solid {
  background: var(--xcs-red);
  color: var(--xcs-ink-on-brand);
  border: 0;
  border-radius: var(--xcs-radius-sm);
  min-height: 38px;
  font-weight: 600;
}
[data-theme="dark"] .xcs-btn-danger-solid { color: var(--fsw-on-accent); }
.xcs-btn-danger-solid:hover { background: var(--xcs-red) !important; filter: brightness(1.08); }

/* ── Tombol ikon ──────────────────────────────────────────────────────────
   Kotak, bukan pil; ukuran kotaknya tidak diubah supaya tata letak kartu
   tetap sama persis (ops-theme.css:581 menghitungnya 24×24). */
.fsw-kmore,
.fsw-x {
  border-radius: var(--fsw-radius-sm);
  color: var(--fsw-ink-3);
  transition: background .16s ease, color .16s ease, border-color .16s ease;
}
.fsw-kmore:hover {
  background: var(--xcs-bg-3);
  border-color: var(--xcs-line-2);
  color: var(--fsw-ink);
}
/* Ikon di dalam tombol: 16px, sejajar tengah, tidak ikut menyusut. */
.xcs-btn-primary > .fsw-ic,
.xcs-btn-ghost > .fsw-ic { width: 16px; height: 16px; flex: none; }

/* Satu bahasa fokus untuk SEMUA tombol: garis aksen 1px + halo 3px.
   Halo saja terlalu pucat di tema terang; garis 1px itulah yang menjamin
   3:1 terhadap permukaan di bawahnya. */
.xcs-btn-primary:focus-visible,
.xcs-btn-ghost:focus-visible,
.xcs-btn-sm:focus-visible,
.xcs-btn-danger:focus-visible,
.fsw-btn-danger:focus-visible,
.fsw-kmore:focus-visible,
.fsw-summary-tog:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--fsw-accent-line), 0 0 0 4px var(--fsw-accent-soft) !important;
}


/* ═══ 4.2 KOLOM ISIAN ══════════════════════════════════════════════════════
   Di tema terang isian sewarna kartu dan garisnya yang membedakan; di tema
   gelap isian turun satu permukaan (#11161A di bawah kartu #1A1F24) supaya
   kolom terbaca sebagai lubang, bukan sebagai kartu kedua. Keduanya lewat
   alias fsw- supaya modul ops tetap mengikuti satu rantai penunjukan. */
/* CACAT KONTRAS (tinjauan): isian kolom = --fsw-card = warna kartu yang
   memuatnya, jadi SATU-SATUNYA penanda kolom adalah garisnya. Garis
   --fsw-line hanya 1,28:1 di tema terang (#E0E5E0 di atas #FFFFFF) dan
   1,38:1 di tema gelap (#2A3138 di atas #11161A) — kolomnya praktis tak
   terlihat sampai disentuh. Garis dikuatkan dengan mencampur dua token
   fsw- yang SUDAH ada (tanpa memutus rantai alias): hasilnya 3,28:1
   di terang dan 4,63:1 di gelap. Tidak ada hex baru. */
.fsw-input,
.fsw-sel,
.fsw-filters .fsw-input,
.fsw-jump input {
  /* `background-color`, BUKAN `background`: bentuk singkatnya mereset
     background-image DAN background-repeat. Panah <select> digambar sebagai
     latar di ops-theme.css:1404, dan reset itu membuat panahnya di-ubin ke
     seluruh kotak — terukur di Manage Users sebagai pola zigzag yang
     menimbun teks pilihannya. */
  background-color: var(--fsw-card); color: var(--fsw-ink);
  border: var(--fsw-bw-strong) solid color-mix(in srgb, var(--fsw-line) 30%, var(--fsw-ink-3));
  border-radius: var(--fsw-radius-input);
  transition: border-color .14s ease, box-shadow .14s ease;
}
[data-theme="dark"] .fsw-input,
[data-theme="dark"] .fsw-sel,
[data-theme="dark"] .fsw-filters .fsw-input,
[data-theme="dark"] .fsw-jump input {
  background-color: var(--fsw-tint);
}
/* Jaring pengaman: berkas ini dimuat terakhir, jadi baris ini menang atas
   bentuk singkat `background` mana pun yang masih tersisa di lapisan lama. */
select.fsw-input, select.fsw-sel,
[data-theme="dark"] select.fsw-input, [data-theme="dark"] select.fsw-sel {
  background-repeat: no-repeat;
}
/* SPESIFISITAS — LUBANG TERBESAR YANG TERLEWAT (tinjauan).
   styles.css:17707 menulis
     [data-theme="dark"] input[type="text"|"number"|"date"|"search"|"url"|
                               "email"|"datetime-local"] { … }
   Spesifisitasnya (0,2,1) — LEBIH TINGGI dari `[data-theme="dark"]
   .fsw-input` (0,2,0). Empat puluh satu kolom isian ruang kerja memakai
   type date/number/search/text/datetime-local, jadi di tema gelap
   semuanya tetap memakai isian rgba(255,255,255,.04) dan garis
   rgba(255,255,255,.10) milik palet lama — garis 1,2:1 terhadap isiannya
   sendiri — sementara aturan di atas diam-diam tidak pernah berlaku.
   Selector di bawah menyamakan spesifisitas (0,2,1) dan menang karena
   berkas ini dimuat terakhir. `background-color`, bukan `background`,
   supaya panah <select> yang digambar di §4.2 tidak ikut terhapus. */
[data-theme="dark"] input.fsw-input,
[data-theme="dark"] select.fsw-input,
[data-theme="dark"] textarea.fsw-input,
[data-theme="dark"] input.fsw-sel,
[data-theme="dark"] .fsw-jump input {
  background-color: var(--fsw-tint);
  border-color: color-mix(in srgb, var(--fsw-line) 30%, var(--fsw-ink-3));
}
/* styles.css:17726 `[data-theme="dark"] input::placeholder` (0,1,1) juga
   menang atas `.fsw-input::placeholder` (0,1,0): rgba(241,243,246,.35) di
   atas #11161A hanya 2,90:1. */
[data-theme="dark"] input.fsw-input::placeholder,
[data-theme="dark"] textarea.fsw-input::placeholder,
[data-theme="dark"] .fsw-jump input::placeholder { color: var(--xcs-ink-3); }
.fsw-input { padding: 10px 12px; }
/* --xcs-ink-4 hanya 4,13:1 di atas putih — placeholder tetap teks, jadi
   ambangnya 4,5. --xcs-ink-3 = 5,45:1 terang / 7,17:1 gelap. */
.fsw-input::placeholder,
.fsw-jump input::placeholder { color: var(--xcs-ink-3); opacity: 1; }

/* Fokus: garis aksen + halo 3px. ops-theme.css:478/479 memasang halo
   hitam/putih untuk .fsw-input:focus — keduanya disusul pada selector
   sespesifik aslinya supaya kedua tema ikut berubah. */
.fsw-input:focus,
.fsw-sel:focus,
.fsw-jump input:focus,
[data-theme="dark"] .fsw-input:focus {
  outline: none;
  border-color: var(--fsw-accent-line);
  box-shadow: 0 0 0 3px var(--fsw-accent-soft);
}
/* styles.css:17730 `[data-theme="dark"] input:focus` (0,2,1) mencerahkan
   isian jadi rgba(255,255,255,.06) — kolomnya berkedip saat difokus. */
[data-theme="dark"] input.fsw-input:focus,
[data-theme="dark"] select.fsw-input:focus,
[data-theme="dark"] textarea.fsw-input:focus,
[data-theme="dark"] .fsw-jump input:focus {
  background-color: var(--fsw-tint);
  border-color: var(--fsw-accent-line);
  box-shadow: 0 0 0 3px var(--fsw-accent-soft);
}
.fsw-sel:focus-visible,
.fsw-tog:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--fsw-accent-line), 0 0 0 4px var(--fsw-accent-soft);
}

/* Sakelar filter (.fsw-tog) dipakai sebagai tombol dua keadaan di tiga
   layar. Keadaan hidup memakai tinta aksen yang sudah aman per tema. */
.fsw-tog {
  background: transparent; color: var(--fsw-ink-2);
  border: 1px solid var(--fsw-line); border-radius: var(--fsw-radius-input);
}
.fsw-tog:hover:not(.is-on) { background: var(--xcs-bg-3); color: var(--fsw-ink); }
.fsw-tog.is-on {
  background: var(--fsw-accent-soft); border-color: var(--fsw-accent-line); color: var(--fsw-accent-ink);
}

/* Label & petunjuk kolom — kelas caption §2: 11,5px / 600, tanpa kapital. */
.fsw-field-l {
  font-size: var(--fsw-fs-micro); font-weight: var(--fsw-micro-fw);
  letter-spacing: var(--fsw-micro-ls); color: var(--fsw-ink-2);
}
.fsw-field-hint { font-size: var(--fsw-fs-micro); color: var(--fsw-ink-3); }
.fsw-form { background: var(--fsw-tint); border-color: var(--fsw-line); border-radius: var(--fsw-radius-md); }

/* Panah <select>. ops-theme.css:1365 mengunci stroke ke %236E6E6E, warna
   palet perak lama yang tenggelam di permukaan gelap. Data-URI tidak bisa
   membaca var(), jadi nilainya disalin dari --xcs-ink-3 masing-masing tema
   (#626C66 terang, #9CA3AF gelap) — inilah satu-satunya hex langsung di
   berkas ini. Tebal goresannya disamakan dengan --fsw-ic-sw. */
select.fsw-input {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23626C66' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
}
[data-theme="dark"] select.fsw-input {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%239CA3AF' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
}

/* Kolom isian modul lama. styles.css:13322 dan 13944 menulis kedua tema
   dengan !important di setiap properti, jadi seluruh blok ini ikut.
   TINJAUAN: .xcs-select dan .xcs-textarea DIHAPUS dari daftar — keduanya
   nol kemunculan di seluruh *.jsx (yang dirender bernama .xcs-text-input /
   .xcs-text-area, diurus di blok berikutnya). Hanya .xcs-input yang nyata
   (detail.jsx, intake.jsx, drankatos.jsx). */
.xcs-input {
  background: var(--xcs-bg-2) !important;
  border: 1px solid color-mix(in srgb, var(--xcs-line-1) 30%, var(--xcs-ink-3)) !important;
  border-radius: var(--xcs-radius-sm) !important;
  padding: 10px 12px !important;
  font-size: 14px !important;
  color: var(--xcs-ink-1) !important;
}
[data-theme="dark"] .xcs-input {
  background: var(--xcs-bg-tint) !important;
  color: var(--xcs-ink-1) !important;
}
.xcs-input:focus,
[data-theme="dark"] .xcs-input:focus {
  outline: none;
  border-color: var(--fsw-accent-line) !important;
  box-shadow: 0 0 0 3px var(--fsw-accent-soft) !important;
}
.xcs-input::placeholder { color: var(--xcs-ink-3); opacity: 1; }

/* KELAS YANG TERLEWAT (tinjauan). §4.2 menyebut .xcs-textarea/.xcs-select,
   tetapi yang benar-benar dirender sembilan kali di intake.jsx, detail.jsx
   dan rooms.jsx adalah .xcs-text-input / .xcs-text-area (styles.css:949).
   Fokusnya memakai `border-color: var(--xcs-navy)` — dan --xcs-navy kini
   #11161A di KEDUA tema, jadi di mode gelap garis fokusnya hilang sama
   sekali di atas kartu #1A1F24 (1,1:1). Aturan lamanya tanpa !important,
   jadi cukup ditimpa biasa. */
.xcs-text-input {
  border: 1px solid color-mix(in srgb, var(--xcs-line-1) 30%, var(--xcs-ink-3));
  border-radius: var(--xcs-radius-sm);
  background: var(--xcs-bg-2);
  color: var(--xcs-ink-1);
  padding: 10px 12px;
}
/* Alasan `input.` / `select.` / `textarea.` di depan kelas: sama seperti
   .fsw-input di atas — styles.css:17707 dan 17730 memakai (0,2,1). */
[data-theme="dark"] input.xcs-text-input,
[data-theme="dark"] select.xcs-text-input,
[data-theme="dark"] textarea.xcs-text-input {
  background-color: var(--xcs-bg-tint);
  border-color: color-mix(in srgb, var(--xcs-line-1) 30%, var(--xcs-ink-3));
  color: var(--xcs-ink-1);
}
.xcs-text-input:focus,
[data-theme="dark"] input.xcs-text-input:focus,
[data-theme="dark"] select.xcs-text-input:focus,
[data-theme="dark"] textarea.xcs-text-input:focus {
  outline: none;
  border-color: var(--fsw-accent-line);
  box-shadow: 0 0 0 3px var(--fsw-accent-soft);
}
/* styles.css:17730 `[data-theme="dark"] input:focus` (0,2,1) mengganti
   isian jadi rgba(255,255,255,.06) saat difokus — kolomnya berkedip lebih
   terang lalu kembali. Isian dikunci supaya tetap diam. */
[data-theme="dark"] input.xcs-text-input:focus,
[data-theme="dark"] select.xcs-text-input:focus,
[data-theme="dark"] textarea.xcs-text-input:focus { background-color: var(--xcs-bg-tint); }
.xcs-text-input::placeholder,
[data-theme="dark"] input.xcs-text-input::placeholder,
[data-theme="dark"] textarea.xcs-text-input::placeholder { color: var(--xcs-ink-3); opacity: 1; }


/* ═══ 4.3 KOTAK CENTANG & RADIO ════════════════════════════════════════════
   accent-color sudah diatur di nova.css, jadi SEMUA kontrol native di
   aplikasi (termasuk modul lama) sudah ikut hijau tanpa satu aturan pun.
   Bentuk khusus di bawah sengaja dibatasi pada pembungkus milik ruang kerja
   — appearance:none global akan mengenai ribuan kotak centang di modul lama
   (forum, meetus, lelang, siaran) yang tata letaknya dihitung untuk ukuran
   native, dan tidak satu pun bisa diuji dari putaran ini. Keempat
   pembungkus di bawah mencakup seluruh kotak centang ops-*.jsx. */
.fsw-check > input[type="checkbox"],
.fsw-check > input[type="radio"],
.fsw-cbcell > input[type="checkbox"],
.fsw-table input[type="checkbox"],
.fsw-form input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; flex: none; margin: 0;
  display: inline-grid; place-content: center;
  /* CACAT KONTRAS (tinjauan): appearance:none membuang kotak bawaan, jadi
     garis inilah satu-satunya penanda kotak yang BELUM dicentang. §4.3
     meminta --xcs-line-2, tetapi nilainya 1,62:1 (terang) dan 1,84:1
     (gelap) — di bawah ambang 3:1 untuk garis kendali. --xcs-ink-4
     memberi 4,13:1 dan 5,41:1. Aturan kontras menang atas §4.3. */
  background: var(--fsw-card); border: 1px solid var(--xcs-ink-4); border-radius: 5px;
  cursor: pointer; transition: background .12s ease, border-color .12s ease;
}
[data-theme="dark"] .fsw-check > input[type="checkbox"],
[data-theme="dark"] .fsw-check > input[type="radio"],
[data-theme="dark"] .fsw-cbcell > input[type="checkbox"],
[data-theme="dark"] .fsw-table input[type="checkbox"],
[data-theme="dark"] .fsw-form input[type="checkbox"] { background: var(--fsw-tint); }

.fsw-check > input[type="radio"] { border-radius: var(--xcs-radius-pill); }

/* Tanda centang digambar sebagai dua garis ::before, bukan huruf — supaya
   tebalnya tidak bergantung pada huruf sistem dan tetap tajam saat diperbesar. */
.fsw-check > input[type="checkbox"]::before,
.fsw-cbcell > input[type="checkbox"]::before,
.fsw-table input[type="checkbox"]::before,
.fsw-form input[type="checkbox"]::before {
  content: ''; width: 10px; height: 6px;
  border-left: 2px solid var(--fsw-on-accent);
  border-bottom: 2px solid var(--fsw-on-accent);
  transform: rotate(-45deg) translate(1px, -1px);
  opacity: 0; transition: opacity .12s ease;
}
.fsw-check > input[type="radio"]::before {
  content: ''; width: 8px; height: 8px; border-radius: var(--xcs-radius-pill);
  background: var(--fsw-on-accent); opacity: 0; transition: opacity .12s ease;
}
.fsw-check > input[type="checkbox"]:checked,
.fsw-check > input[type="radio"]:checked,
.fsw-cbcell > input[type="checkbox"]:checked,
.fsw-table input[type="checkbox"]:checked,
.fsw-form input[type="checkbox"]:checked {
  background: var(--fsw-accent); border-color: var(--fsw-accent);
}
.fsw-check > input:checked::before,
.fsw-cbcell > input:checked::before,
.fsw-table input[type="checkbox"]:checked::before,
.fsw-form input[type="checkbox"]:checked::before { opacity: 1; }
.fsw-check > input:focus-visible,
.fsw-cbcell > input:focus-visible,
.fsw-table input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--fsw-accent-line), 0 0 0 4px var(--fsw-accent-soft);
}
.fsw-check > input:disabled { opacity: .45; cursor: not-allowed; }
.fsw-check { color: var(--fsw-ink-2); gap: 8px; }


/* ═══ 4.4 TAG / LENCANA / CHIP / STATUS ════════════════════════════════════
   Warna chip DIHITUNG di ops-ui.jsx: OpsChip memasang color / borderColor /
   background sebagai inline style dari OPS_STATUS_META lewat opsThemeColor()
   dan opsChipInk(). Inline style mengalahkan CSS, dan itu memang benar —
   warna chip milik data, bukan milik tema, dan opsChipInk sudah menjamin
   kontrasnya. Yang diatur di sini hanya bentuk dan huruf; padat dan
   ukurannya sudah datang dari --fsw-chip-pad dan --fsw-fs-chip. */
.fsw-chip {
  font-weight: 600; line-height: 1.45; letter-spacing: 0;
  border-radius: var(--fsw-radius-chip);
}
.fsw-chip .fsw-dot { width: 6px; height: 6px; }

/* .fsw-health masih memaku tiga hex palet lama (#2F9E5F / #C98A1B /
   #D42B2B). Di atas permukaan baru ketiganya turun di bawah 4,5:1, dan
   warnanya juga sudah tidak ada di palet. Diganti token status yang punya
   ragam terang+gelap; kembaran [data-theme="dark"] di ops-theme.css:192
   ikut ditulis ulang di selector yang sama supaya mode gelap tidak
   tertinggal memakai hex lama. */
.fsw-health {
  background: var(--xcs-bg-3); border-color: var(--fsw-line); color: var(--fsw-ink-2);
  border-radius: var(--fsw-radius-chip);
  font-size: var(--fsw-fs-chip); font-weight: 600; line-height: 1.45;
}
/* CACAT KONTRAS (tinjauan): warna status PENUH di atas --xcs-bg-3 berhenti
   di 4,13 / 4,19 / 4,44:1 pada tema terang — ketiganya di bawah 4,5 untuk
   teks 12px. Tintanya dicampur 85% ke --xcs-ink-1, token yang nilainya
   hitam di tema terang dan putih di tema gelap, jadi satu rumus menjauhkan
   tinta dari latarnya di KEDUA tema. Hasil: 5,15 / 5,19 / 5,55:1 (terang)
   dan 7,08 / 7,51 / 5,49:1 (gelap). Titiknya tetap warna penuh — ia bidang
   6–8px, ambangnya 3:1 dan sudah lulus. */
.fsw-health.is-green, [data-theme="dark"] .fsw-health.is-green { color: color-mix(in srgb, var(--fsw-green) 85%, var(--xcs-ink-1)); }
.fsw-health.is-yellow, [data-theme="dark"] .fsw-health.is-yellow { color: color-mix(in srgb, var(--fsw-amber) 85%, var(--xcs-ink-1)); }
.fsw-health.is-red, [data-theme="dark"] .fsw-health.is-red { color: color-mix(in srgb, var(--fsw-red) 85%, var(--xcs-ink-1)); }
.fsw-health-dot { width: 8px; height: 8px; background: var(--fsw-ink-4); }
.fsw-health.is-green .fsw-health-dot { background: var(--fsw-green); }
.fsw-health.is-yellow .fsw-health-dot { background: var(--fsw-amber); }
.fsw-health.is-red .fsw-health-dot { background: var(--fsw-red); box-shadow: 0 0 0 3px var(--fsw-red-soft); }

/* Pil peran & lencana modul lama: bentuk dan huruf disamakan dengan chip,
   warnanya tetap datang dari inline style masing-masing pemakai. */
.fsw-role-pill {
  font-size: var(--fsw-fs-micro); font-weight: var(--fsw-micro-fw);
  letter-spacing: var(--fsw-micro-ls); text-transform: var(--fsw-micro-tt);
  border-radius: var(--fsw-radius-chip); padding: var(--fsw-chip-pad);
}
.xcs-badge {
  border-radius: var(--xcs-radius-pill); padding: var(--fsw-chip-pad);
  font-size: var(--fsw-fs-chip); font-weight: 600;
}
.xcs-badge:hover { transform: none; }
/* Tautan-pil pada kartu tugas: bentuk chip, tinggi target sentuh 32px. */
.fsw-links a { border-radius: var(--fsw-radius-chip); font-weight: 600; min-height: 32px; }
.fsw-links a:hover { background: var(--xcs-bg-3); border-color: var(--xcs-line-2); }


/* ═══ 4.5 KARTU & KPI ══════════════════════════════════════════════════════
   .fsw-card sudah seluruhnya token (--fsw-card / --fsw-line / --fsw-radius /
   --fsw-card-pad) dan nova.css sudah menyetel keempatnya ke nilai referensi
   (#1A1F24, garis #2A3138, radius 14, bantalan 18×20). Karena itu TIDAK ada
   satu pun aturan .fsw-card di berkas ini — menulis ulang hanya akan
   memutus rantai alias. Yang butuh kerja adalah kartu modul lama. */

/* styles.css:12013 memaksa bayangan dengan !important, styles.css:18055
   memaksa latar #141414 + garis putih 8% untuk mode gelap juga dengan
   !important, dan styles.css:17615 di atasnya menambah backdrop-filter
   blur. Kaca buram itu bertabrakan dengan permukaan rata referensi, jadi
   dimatikan sekalian (termasuk ragamnya di dalam @media 768px). */
.xcs-card {
  background: var(--xcs-bg-2); border: 1px solid var(--xcs-line-1);
  border-radius: var(--xcs-radius); padding: var(--fsw-card-pad); gap: var(--fsw-card-gap);
  box-shadow: var(--xcs-shadow-sm) !important;
}
[data-theme="dark"] .xcs-card {
  background: var(--xcs-bg-2) !important;
  border-color: var(--xcs-line-1) !important;
  color: var(--xcs-ink-1) !important;
  box-shadow: none !important;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
[data-theme="dark"] .xcs-card:hover {
  border-color: var(--xcs-line-2);
  box-shadow: none !important;
  transform: none;
}
.xcs-card-h h3 { font-size: var(--fsw-fs-cardh); font-weight: 650; }

/* .xcs-stat: styles.css:12506 mengunci latar putih, garis, radius 16,
   bantalan dan bayangan dengan !important — semuanya harus disusul. */
.xcs-stat {
  background: var(--xcs-bg-2) !important; border: 1px solid var(--xcs-line-1) !important;
  border-radius: var(--xcs-radius) !important; padding: var(--fsw-stat-pad) !important;
  box-shadow: var(--xcs-shadow-sm) !important; gap: 8px;
}
[data-theme="dark"] .xcs-stat {
  background: var(--xcs-bg-2) !important;
  border-color: var(--xcs-line-1) !important;
  box-shadow: none !important;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.xcs-stat:hover, [data-theme="dark"] .xcs-stat:hover {
  border-color: var(--xcs-line-2) !important;
  box-shadow: var(--xcs-shadow-sm) !important;
  transform: none;
}
.xcs-stat-label { font-size: var(--fsw-fs-micro) !important; font-weight: var(--fsw-micro-fw) !important; color: var(--xcs-ink-3) !important; }
/* SPESIFISITAS (tinjauan): styles.css:12530 dan 13272 menulis
   `.xcs-stat-num, .xcs-stat-value { font-size: 36/38px !important;
   font-weight: 900 !important; letter-spacing: -.03em !important }` pada
   spesifisitas yang SAMA (0,1,0). Tanpa !important di sini angkanya tetap
   38px/900 — skala §2 (34px/700) diam-diam tidak pernah berlaku.
   flex-wrap + min-width:0 ditambahkan karena elemen ini flex dan memuat
   angka + chip tren: di 360px keduanya harus boleh turun baris, bukan
   mendorong kartu keluar kontainer. */
.xcs-stat-value {
  font-size: var(--fsw-fs-kpi) !important; font-weight: 700 !important;
  letter-spacing: -.022em !important; font-variant-numeric: tabular-nums;
  gap: 8px; flex-wrap: wrap; min-width: 0;
}
/* styles.css:13284 menulis `.xcs-stat-sub { color: var(--bh-muted)
   !important }` — nova.css sudah menunjuk --bh-muted ke nada yang benar di
   kedua tema, jadi baris ini hanya menegaskan hal yang sama pada
   spesifisitas yang bisa menang. */
.xcs-stat-sub { color: var(--xcs-ink-3) !important; }
/* styles.css:13707 menulis nada gelapnya pada (0,2,0); tanpa kembaran ini
   label dan subteks di mode gelap tetap rgba(255,255,255,.55). */
[data-theme="dark"] .xcs-stat-label,
[data-theme="dark"] .xcs-stat-sub { color: var(--xcs-ink-3) !important; }
/* Tren naik/turun modul lama memaku empat hex hijau/merah pastel yang tidak
   pernah dibalik untuk mode gelap (#DCFCE7 / #166534 / #FEE2E2 / #991B1B). */
.xcs-trend { border-radius: var(--xcs-radius-pill); font-weight: 600; padding: var(--fsw-chip-pad); }
/* Tinta dicampur seperti .fsw-health: hijau penuh di atas tint hijau 16%
   hanya 4,38:1 di tema terang. Dengan campuran 85% → 5,47:1 / 6,05:1. */
.xcs-trend.up { background: var(--xcs-green-soft); color: color-mix(in srgb, var(--fsw-green) 85%, var(--xcs-ink-1)); }
.xcs-trend.down { background: var(--xcs-red-soft); color: color-mix(in srgb, var(--fsw-red) 85%, var(--xcs-ink-1)); }

/* ── KPI ──────────────────────────────────────────────────────────────────
   Keluhan pemilik: "angka berdempetan". Penyebabnya margin 5px/3px pada
   .fsw-kpi-v — label, angka dan keterangan praktis menempel. Jaraknya
   dinaikkan ke 8px di atas DAN di bawah angka (kisi 8px §3). */
.fsw-kpi { border-radius: var(--fsw-radius); transition: border-color .15s ease, transform .08s ease; }
.fsw-kpi:hover { border-color: var(--xcs-line-2); }
.fsw-kpi:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--fsw-accent-line), 0 0 0 4px var(--fsw-accent-soft);
}
.fsw-kpi-l {
  font-size: var(--fsw-fs-micro); font-weight: var(--fsw-micro-fw);
  letter-spacing: var(--fsw-micro-ls); text-transform: var(--fsw-micro-tt);
  color: var(--fsw-ink-3); line-height: 1.4;
}
.fsw-kpi-v {
  font-size: var(--fsw-fs-kpi); font-weight: 700; line-height: 1.1;
  letter-spacing: -.028em; margin: 8px 0; font-variant-numeric: tabular-nums;
}
.fsw-kpi-v small { font-size: 13px; font-weight: 500; color: var(--fsw-ink-3); }

/* Baris ketiga KPI adalah KETERANGAN, bukan delta berangka — tidak ada
   markup ±% di mana pun (dicek di ops-today, ops-posted, ops-mywork dan
   ops-clients). Yang ADA adalah keadaan is-good / is-warn / is-crit, jadi
   keterangan itulah yang dijadikan chip kecil seperti delta di referensi:
   hijau untuk aman, kuning untuk berisiko, merah untuk perlu tindakan. */
.fsw-kpi-d { font-size: var(--fsw-fs-micro); line-height: 1.4; color: var(--fsw-ink-3); }
.fsw-kpi.is-good > .fsw-kpi-d,
.fsw-kpi.is-warn > .fsw-kpi-d,
.fsw-kpi.is-crit > .fsw-kpi-d {
  display: inline-flex; align-items: center; font-weight: 600;
  padding: var(--fsw-chip-pad); border-radius: var(--fsw-radius-chip);
  border: var(--fsw-chip-bw) solid transparent;
}
/* Tinta chip dicampur 85% ke --xcs-ink-1 (alasan sama seperti .fsw-health):
   tanpa itu good/warn hanya 4,38 dan 4,45:1 di tema terang. Sesudahnya
   5,47 / 5,51 / 5,79:1 (terang) dan 6,05 / 6,12 / 5,46:1 (gelap). */
.fsw-kpi.is-good > .fsw-kpi-d { background: var(--xcs-green-soft);  border-color: color-mix(in srgb, var(--fsw-green) 38%, transparent); color: color-mix(in srgb, var(--fsw-green) 85%, var(--xcs-ink-1)); }
.fsw-kpi.is-warn > .fsw-kpi-d { background: var(--xcs-orange-soft); border-color: color-mix(in srgb, var(--fsw-amber) 38%, transparent); color: color-mix(in srgb, var(--fsw-amber) 85%, var(--xcs-ink-1)); }
.fsw-kpi.is-crit > .fsw-kpi-d { background: var(--fsw-red-soft);    border-color: color-mix(in srgb, var(--fsw-red) 38%, transparent);   color: color-mix(in srgb, var(--fsw-red) 85%, var(--xcs-ink-1)); }
/* Kartu kritis: garis merah sudah cukup. Latar bergradien-ganda dihapus
   supaya chip merah di dalamnya tidak menumpuk dua lapis merah. */
.fsw-kpi.is-crit { border-color: color-mix(in srgb, var(--fsw-red) 45%, transparent); background: var(--fsw-card); }
.fsw-kpi.is-good .fsw-kpi-v { color: var(--fsw-green); }
.fsw-kpi.is-warn .fsw-kpi-v { color: var(--fsw-amber); }
.fsw-kpi.is-crit .fsw-kpi-v { color: var(--fsw-red); }

/* ── Stat ringkas ─────────────────────────────────────────────────────────
   Sama seperti KPI: jarak 8px, berat 800 diturunkan ke 700 sesuai skala §2
   (800 pada 34px terlihat gemuk dan menjauhkan angka dari huruf Inter
   yang dipakai judul). */
.fsw-stat { gap: 8px; border-radius: var(--fsw-radius); }
.fsw-stat-l {
  font-size: var(--fsw-fs-micro); font-weight: var(--fsw-micro-fw);
  letter-spacing: var(--fsw-statl-ls); text-transform: var(--fsw-statl-tt);
  color: var(--fsw-ink-3);
}
.fsw-stat-v { font-weight: 700; letter-spacing: -.028em; font-variant-numeric: tabular-nums; }
.fsw-stat-s { font-size: var(--fsw-fs-micro-lg); color: var(--fsw-ink-3); line-height: 1.4; }
.fsw-stat.is-red { border-color: color-mix(in srgb, var(--fsw-red) 45%, transparent); background: var(--fsw-card); }
.fsw-stat.is-click:hover { border-color: var(--xcs-line-2); }

/* .fsw-report-stat memaku #E3E3E3 dan #6E6E6E — dua nilai palet perak lama
   yang hilang di tema gelap (garis tak terlihat, label 2,4:1). */
.fsw-report-stat {
  border: var(--fsw-bw) solid var(--fsw-line); border-radius: var(--fsw-radius-sm); background: var(--fsw-card);
}
.fsw-report-stat span,
.fsw-metric span {
  color: var(--fsw-ink-3); font-size: var(--fsw-fs-micro);
  font-weight: var(--fsw-micro-fw); letter-spacing: var(--fsw-micro-ls);
  text-transform: var(--fsw-micro-tt);
}
.fsw-report-stat b,
.fsw-metric b { font-weight: 700; letter-spacing: -.022em; font-variant-numeric: tabular-nums; }


/* ═══ 4.6 BAR PROGRES ══════════════════════════════════════════════════════
   Diminta eksplisit oleh pemilik, jadi bagian ini yang paling lengkap.
   SATU bahasa: jalur --xcs-bg-3, tinggi 8px, radius penuh, isian gradien
   limau→hijau (--nv-grad), lebar beranimasi 320ms. Merah dan kuning hanya
   untuk keadaan bahaya dan peringatan.

   Baca dulu sebelum menambah: dari tiga belas nama "bar" di §4.6
   spesifikasi, hanya LIMA yang benar-benar bar progres. Setelah diperiksa
   di ops-theme.css dan di tempat ia dirender:
     .fsw-room-bar    (493) baris alat display:flex berisi judul + filter
     .fsw-summary-bar (589) baris flex berisi tombol ringkasan
     .fsw-write-bar   (732) baris flex berisi <h4> + jumlah kata
     .fsw-note-bar   (1321) baris flex di bawah catatan kalender
     .fsw-bd-bar      (papan) baris alat pena & warna
     .fsw-userbar     (742) pembungkus dengan margin-bawah saja
     .fsw-task-bar    (227) pita warna 5px di tepi KIRI kartu tugas
   Ketujuhnya bukan jalur progres. Mengecatnya sebagai jalur akan merusak
   tujuh tata letak sekaligus, jadi ketujuhnya sengaja TIDAK disentuh. */

/* CACAT KONTRAS TERBESAR (tinjauan): --nv-grad adalah limau #A3FF4D →
   #16A34A. Di atas jalur tema TERANG (--xcs-bg-3 = #E6EAE6) ujung limaunya
   hanya 1,02:1 dan ujung hijaunya 2,71:1 — bar progres yang diminta
   eksplisit oleh pemilik praktis hilang di tema terang. Ambang bidang UI
   adalah 3:1.
   Isiannya karena itu dipilih per tema lewat satu properti lokal:
     terang → --fsw-accent-ink (#2E7D12, 4,26:1) ke --fsw-green (#15803D,
              4,13:1) — tetap hijau merek, tetapi terbaca di atas jalur;
     gelap  → --nv-grad apa adanya (11,74:1 dan 4,41:1), persis referensi.
   Ini properti LAPISAN KOMPONEN, bukan token merek: nilainya seluruhnya
   diturunkan dari token nova.css dan tidak ada hex baru. */
:root, [data-theme="light"] {
  --fsw-bar-fill: linear-gradient(90deg, var(--fsw-accent-ink) 0%, var(--fsw-green) 100%);
}
[data-theme="dark"] { --fsw-bar-fill: var(--nv-grad); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) { --fsw-bar-fill: var(--nv-grad); }
}

/* Kecepatan animasi ditulis sekali supaya seluruh bar bergerak serempak. */
.fsw-bar > i,
.fsw-pace-fill,
.fsw-periode-fill,
.fsw-mbar-seg,
.xcs-chat-step { transition: width .32s cubic-bezier(.4, 0, .2, 1), background .32s ease; }

/* ── .fsw-bar — bar serbaguna (kesehatan klien, progres bulan) ──────────── */
.fsw-bar {
  height: 8px; background: var(--xcs-bg-3); border: 0;
  border-radius: var(--fsw-radius-chip); overflow: hidden;
}
.fsw-bar > i { background: var(--fsw-bar-fill); border-radius: var(--fsw-radius-chip); }
/* ops-clients.jsx memberi kelas kesehatan pada isian: is-green = sesuai
   rencana (itu keadaan NORMAL, jadi ia yang memakai gradien aksen),
   is-yellow dan is-red = peringatan dan bahaya, is-grey = belum ada data. */
.fsw-bar > i.is-green { background: var(--fsw-bar-fill); }
.fsw-bar > i.is-yellow { background: var(--fsw-amber); }
.fsw-bar > i.is-red { background: var(--fsw-red); }
.fsw-bar > i.is-grey { background: var(--xcs-ink-4); }
.fsw-bar-mark { background: var(--fsw-ink); opacity: .55; }
.fsw-bar-legend { font-size: var(--fsw-fs-micro); color: var(--fsw-ink-3); }

/* ── .fsw-pace — laju tayang bulan berjalan ───────────────────────────────
   TIDAK diberi overflow:hidden, sengaja. Jalur ini berisi .fsw-pace-plan,
   penanda rencana yang menjulur 5px ke atas-bawah dan membawa label
   "rencana" pada top:-16px (ops-theme.css:1504-1505); memotongnya akan
   menghapus label itu. Sudutnya dibulatkan pada ISIAN sebagai gantinya. */
.fsw-pace-track { height: 8px; background: var(--xcs-bg-3); border-radius: var(--fsw-radius-chip); }
.fsw-pace-fill { background: var(--fsw-bar-fill); border-radius: var(--fsw-radius-chip); }
.fsw-pace-plan { background: var(--fsw-ink); width: 2px; }
.fsw-pace-plan::after { color: var(--fsw-ink-3); font-size: var(--fsw-fs-micro); }
.fsw-pace-n { font-size: var(--fsw-fs-micro-lg); color: var(--fsw-ink-3); }

/* ── .fsw-periode — batas batch & bulan pada halaman klien ──────────────── */
.fsw-periode-bar {
  height: 8px; background: var(--xcs-bg-3);
  border-radius: var(--fsw-radius-chip); overflow: hidden;
}
.fsw-periode-fill { background: var(--fsw-bar-fill); border-radius: var(--fsw-radius-chip); }
.fsw-periode-l { font-weight: 600; letter-spacing: 0; color: var(--fsw-ink-2); }
.fsw-periode-r { color: var(--fsw-ink-3); }

/* ── .fsw-mbar — bar dua ruas: sudah tayang + siap tayang ────────────────
   CACAT (tinjauan): ruas "siap" dulu = campuran aksen 42% dengan warna
   JALURNYA. Hasilnya #CAF3A6 di atas jalur #E6EAE6 = 1,02:1 di tema
   terang — ruas itu tidak terlihat sama sekali; di tema gelap ia lulus
   terhadap jalur (3,28:1) tetapi hanya 1,35:1 terhadap ruas "tayang" di
   sebelahnya. Tiga tingkat terang dalam bar 8px memang tidak bisa
   sama-sama mencapai 3:1.
   Karena itu ruas "siap" tidak lagi dibedakan oleh TERANG melainkan oleh
   TEKSTUR: arsir miring warna aksen penuh dengan sela transparan yang
   memperlihatkan jalur. Setiap goresnya 4,26:1 (terang) dan 11,74:1
   (gelap) terhadap jalur, dan arsir jelas berbeda dari ruas "tayang" yang
   pejal — pembedanya tidak lagi bergantung pada selisih luminans. */
.fsw-mbar-track {
  height: 8px; background: var(--xcs-bg-3);
  border-radius: var(--fsw-radius-chip); overflow: hidden; gap: 2px;
}
.fsw-mbar-seg.is-posted { background: var(--fsw-bar-fill); }
.fsw-mbar-seg.is-ready {
  background: repeating-linear-gradient(135deg,
    var(--fsw-accent-ink) 0 4px, transparent 4px 8px);
}
[data-theme="dark"] .fsw-mbar-seg.is-ready {
  background: repeating-linear-gradient(135deg,
    var(--fsw-accent) 0 4px, transparent 4px 8px);
}
.fsw-mbar-n { color: var(--fsw-ink-2); font-size: var(--fsw-fs-micro-lg); }

/* ── .xcs-chat-progress — penunjuk langkah formulir intake ───────────────
   Latarnya dulu gradien putih yang dipaku (styles.css:820), jadi bilah ini
   jadi pita terang di tengah halaman gelap. Langkah selesai memakai hijau
   pekat yang tenang, langkah sekarang memakai gradien penuh supaya posisi
   langsung terbaca; keduanya ≥3:1 di dua tema. */
.xcs-chat-progress { background: var(--xcs-bg-2); border-bottom: 1px solid var(--xcs-line-1); gap: 6px; }
.xcs-chat-step { height: 8px; background: var(--xcs-bg-3); border-radius: var(--xcs-radius-pill); }
/* --nv-lime-deep hanya 2,71:1 di atas jalur tema terang; --fsw-green
   memberi 4,13:1 (terang) dan 6,38:1 (gelap). */
.xcs-chat-step.done { background: var(--fsw-green); }
.xcs-chat-step.now { background: var(--fsw-bar-fill); }
/* SPESIFISITAS (tinjauan): styles.css:2989-2990 menulis
   `.xcs-intake.xcs-intake-daily .xcs-chat-step.now` (0,3,0) dengan #10B981
   dan #6EE7B7 — dan intake.jsx:256 memang memasang kelas itu untuk setoran
   harian, jadi tanpa kembaran ini bilah langkah di layar tersebut tetap
   memakai hijau lama. Spesifisitasnya disamakan persis. */
.xcs-intake.xcs-intake-daily .xcs-chat-step.done { background: var(--fsw-green); }
.xcs-intake.xcs-intake-daily .xcs-chat-step.now { background: var(--fsw-bar-fill); }

/* ── <progress> ──────────────────────────────────────────────────────────
   Tidak ada satu pun .jsx yang merendernya hari ini (sudah dicek di seluruh
   public_html), tetapi §4.6 memintanya ikut dalam satu bahasa. Blok ini
   menjamin bar bawaan peramban — milik kita nanti atau milik pustaka pihak
   ketiga — tidak pernah muncul dengan warna sistem. */
progress {
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 8px; border: 0;
  border-radius: var(--xcs-radius-pill); overflow: hidden;
  background: var(--xcs-bg-3); color: var(--fsw-accent);
}
progress::-webkit-progress-bar { background: var(--xcs-bg-3); border-radius: var(--xcs-radius-pill); }
progress::-webkit-progress-value { background: var(--fsw-bar-fill); border-radius: var(--xcs-radius-pill); transition: width .32s cubic-bezier(.4, 0, .2, 1); }
progress::-moz-progress-bar { background: var(--fsw-bar-fill); border-radius: var(--xcs-radius-pill); }
progress.is-danger::-webkit-progress-value { background: var(--fsw-red); }
progress.is-danger::-moz-progress-bar { background: var(--fsw-red); }
progress.is-warn::-webkit-progress-value { background: var(--fsw-amber); }
progress.is-warn::-moz-progress-bar { background: var(--fsw-amber); }


/* ═══ 4.7 BAGAN ════════════════════════════════════════════════════════════
   Sparkline (.fsw-spark) mewarnai garisnya DARI DALAM JSX dengan
   var(--fsw-accent-ink) atau var(--fsw-ink-3) sebagai inline style
   (ops-ui.jsx:1426). Itu sudah token dan sudah benar di kedua tema, jadi
   warnanya sengaja tidak dipaksa dari sini — menimpanya butuh !important
   dan akan menghapus bedanya antara sparkline beraksen dan yang netral. */
.fsw-spark { display: block; overflow: visible; }
.fsw-spark polyline { stroke-linejoin: round; stroke-linecap: round; }

/* Bagan batang views. --nv-lime-deep (#16A34A) dipilih untuk batang biasa
   karena ia satu-satunya hijau palet yang lolos 3:1 di KEDUA tema —
   3,3:1 di atas putih dan 5,0:1 di atas kartu #1A1F24. Limau penuh hanya
   1,3:1 di atas putih dan tidak boleh jadi bidang tunggal di sana. Batang
   FYP tetap limau penuh DAN diberi garis tepi tinta, jadi ia tetap berbeda
   dari batang biasa di tema gelap tempat keduanya sama-sama terang. */
.fsw-chart { display: block; width: 100%; height: auto; }
.fsw-chart text { fill: var(--fsw-ink-3); font-variant-numeric: tabular-nums; }
.fsw-chart .is-grid { stroke: var(--fsw-line); }
.fsw-chart .is-bar { fill: var(--nv-lime-deep); rx: 4px; }
.fsw-chart .is-bar.is-fyp { fill: var(--fsw-accent); stroke: var(--fsw-ink); stroke-width: 1; }
.fsw-chart .is-fypline { stroke: var(--fsw-accent-line); stroke-dasharray: 3 3; }
.fsw-chart .is-avgline { stroke: var(--fsw-ink-3); stroke-dasharray: 2 4; }

/* Cincin / donat: tidak ada elemen seperti itu di aplikasi ini — tidak ada
   conic-gradient maupun stroke-dasharray lingkaran di seluruh ops-*.jsx.
   Karena itu tidak ada aturan yang ditulis untuknya. */


/* ═══ 4.8 TABEL ════════════════════════════════════════════════════════════
   Kepala dan baris tema TERANG sudah benar lewat token: --fsw-th-ink =
   --xcs-ink-3, --fsw-th-bg = transparent, --fsw-micro-tt = none,
   --fsw-cell-pad dan --fsw-row-pad = 12px 10px. Jadi tidak ada satu pun
   aturan kepala tabel terang di sini. */

/* Mode gelap lain ceritanya. styles.css:17830/17840 punya aturan global
   `[data-theme="dark"] thead th` dan `tbody td` yang lebih spesifik dari
   `.fsw-table th`, dan ops-theme.css:1958 menetralkannya dengan menyalin
   nilai lama ke sepasang token "-d". Salinan itu masih palet lama: garis
   baris putih 4% (praktis tak terlihat, jauh di bawah 3:1), jarak huruf
   kepala 0,10em, bantalan 12×14. Di sini token "-d" DITUNJUK ULANG ke
   token terang yang sudah benar — bukan nilai baru, hanya penunjukan
   ulang. */
[data-theme="dark"] {
  --fsw-th-bg-d:    var(--fsw-th-bg);
  --fsw-th-ink-d:   var(--fsw-th-ink);
  --fsw-th-line-d:  var(--xcs-line-1);
  --fsw-th-ls-d:    var(--fsw-th-ls);
  --fsw-th-fw-d:    var(--fsw-micro-fw-b);
  --fsw-cell-pad-d: var(--fsw-cell-pad);
  --fsw-row-pad-d:  var(--fsw-row-pad);
  --fsw-line-row-d: var(--xcs-line-1);
}

/* CACAT YANG DILAPORKAN PEMILIK: tinggi baris melompat ketika satu sel
   hanya berisi "—". Penyebabnya bukan bantalan (itu sudah tetap lewat
   --fsw-row-pad) melainkan tinggi ISI: sel berchip setinggi ±25px, sel
   bertanda-pisah hanya setinggi satu baris teks (±21px), jadi dua baris
   bertetangga beda 4px. Pada sel tabel `height` diperlakukan sebagai
   MINIMUM oleh algoritma tata letak tabel — satu lantai membuat semua
   baris sama tinggi tanpa pernah memotong sel yang isinya lebih tinggi.
   Lantainya dihitung dari --fsw-fs-tbl, bukan angka mati, supaya ia ikut
   kalau skala huruf tabel disetel ulang. */
.fsw-table td {
  height: calc(var(--fsw-fs-tbl) * 1.92); vertical-align: middle; line-height: 1.5;
}
.fsw-table th { vertical-align: middle; line-height: 1.4; }
/* Chip dan lencana kesehatan adalah isi sel tertinggi; line-height-nya
   dijaga supaya tetap di bawah lantai baris di atas. */
.fsw-table td .fsw-chip,
.fsw-table td .fsw-health { line-height: 1.35; }
/* Baris yang bisa diklik: hover memakai permukaan ketiga, bukan tint —
   tint di tema gelap (#11161A) justru lebih GELAP dari kartunya (#1A1F24)
   sehingga baris terasa tenggelam, bukan tersorot. */
.fsw-table tr.is-click:hover td { background: var(--xcs-bg-3); }
.fsw-table td.num, .fsw-table th.num { font-variant-numeric: tabular-nums; }
/* Kolom isian di dalam tabel ikut radius kontrol, bukan 8px sendirian. */
.fsw-table .fsw-input { border-radius: var(--fsw-radius-input); }
.fsw-table-wrap { border-radius: var(--fsw-radius-sm); }


/* ═══ 4.9 AVATAR & BARIS DAFTAR AKTIVITAS ══════════════════════════════════ */

/* brand.css:89 masih menjalankan aturan merek LAMA: semua avatar dipaksa
   grayscale supaya cocok dengan palet hitam/putih/silver. B5 mencabut palet
   itu, jadi warna per-pengguna dikembalikan. Hanya SATU properti yang
   disentuh — latar dan tinta .fsw-avatar tetap milik brand.css. */
.xcs-avatar, .xcs-mvp-av { filter: none; }

/* Cincin garis hanya pada avatar ruang kerja. .xcs-avatar sengaja tidak
   ikut: pemakaian utamanya ada di blok akun sidebar, dan sidebar adalah
   §5.1 milik nova-shell.css — garis terang di atas rel gelap adalah
   keputusan berkas itu, bukan berkas ini. */
.fsw-avatar {
  border-radius: var(--xcs-radius-pill); box-shadow: 0 0 0 1px var(--fsw-line);
  font-weight: 700; letter-spacing: .01em;
}
/* --fsw-ink-3 di atas --xcs-bg-3 hanya 4,48:1 (terang) — inisial avatar
   adalah teks. --fsw-ink-2 = 8,56:1 / 9,33:1. */
.fsw-avatar.is-empty, .fsw-avatar.is-sys {
  background: var(--xcs-bg-3); color: var(--fsw-ink-2);
  border-color: var(--xcs-line-2); box-shadow: none;
}

/* Baris daftar aktivitas: judul 13px/600, waktu 11,5px --xcs-ink-3. */
.fsw-it { border-bottom-color: var(--fsw-line); gap: 10px; }
.fsw-it-t { font-weight: 600; color: var(--fsw-ink); }
.fsw-it-t .fsw-muted { font-weight: 400; }
.fsw-it-tm { font-size: var(--fsw-fs-micro); color: var(--fsw-ink-3); font-variant-numeric: tabular-nums; }
.fsw-it.is-click:hover .fsw-it-t { color: var(--fsw-accent-ink); }
.fsw-list-empty { color: var(--fsw-ink-3); }


/* ═══ LAYAR SENTUH ═════════════════════════════════════════════════════════
   ops-theme.css:950 menaikkan target sentuh ke ≥32px lewat aturan di dalam
   @media. Berkas ini dimuat SESUDAHnya, jadi beberapa aturan dasar di atas
   akan menang bahkan di dalam media query itu dan diam-diam mengecilkan
   kembali kontrolnya. Blok ini mengembalikan setiap angka yang terpengaruh —
   tidak ada nilai baru di sini, semuanya salinan dari ops-theme.css. */
@media (max-width: 768px) {
  .fsw-input { padding: 11px 12px; font-size: 14px; }
  .fsw-input, select.fsw-input, select.fsw-input.is-sm { min-height: 40px; }
  .fsw-sel, .fsw-tog, .fsw-filters .fsw-input { min-height: 44px; }
  .xcs-btn-primary, .xcs-btn-ghost, .xcs-btn-sm { min-height: 44px; }
  /* Kotak centang khusus ikut membesar seperti yang native lakukan. */
  .fsw-check > input[type="checkbox"],
  .fsw-check > input[type="radio"],
  .fsw-cbcell > input[type="checkbox"],
  .fsw-table input[type="checkbox"] { width: 20px; height: 20px; }
  /* LUAPAN (tinjauan): aturan dasar `margin: 0` di §4.3 punya spesifisitas
     yang sama dengan ops-theme.css:963 tetapi dimuat belakangan, jadi ia
     ikut menghapus margin 6px yang melebarkan area tekan di dalam tabel. */
  .fsw-table input[type="checkbox"] { margin: 6px; }
  /* ops-theme.css:962 memaksa `accent-color: var(--fsw-ink)` di layar
     sentuh — itu aturan merek LAMA (hitam/putih) dan ia membatalkan
     `accent-color` aksen dari nova.css untuk SEMUA kontrol native modul
     lama, tetapi hanya di bawah 768px. Dikembalikan ke aksen. */
  input[type="checkbox"], input[type="radio"] { accent-color: var(--fsw-accent); }

  /* LUAPAN (tinjauan): tiga aturan §4.5 di atas memakai !important tanpa
     media query, jadi ia menang atas penyetelan ponsel milik
     styles.css:2632-2641 (`padding: 14px`, `border-radius: 12px`,
     `font-size: 24px`, semuanya !important). Akibatnya kartu statistik di
     360px kembali berbantalan 16/18px dan angkanya 34px di dalam kisi dua
     kolom selebar ±159px — persis keluhan "keluar dari kontainer".
     Angka-angka ponsel dikembalikan; ukuran angka memakai token ponsel
     --fsw-fs-kpi-hp yang sudah dipakai .fsw-kpi-v (ops-theme.css:1603). */
  .xcs-stat { padding: 14px !important; border-radius: 12px !important; }
  .xcs-stat-value { font-size: var(--fsw-fs-kpi-hp) !important; gap: 6px; }
  /* §2: label mikro tidak kapital-semua. styles.css:2637 masih
     mengapitalkannya khusus di ponsel. */
  .xcs-stat-label { text-transform: var(--fsw-micro-tt); letter-spacing: var(--fsw-micro-ls); }
}

/* Gerak dikurangi: animasi lebar bar dimatikan, nilainya tetap benar. */
@media (prefers-reduced-motion: reduce) {
  .fsw-bar > i,
  .fsw-pace-fill,
  .fsw-periode-fill,
  .fsw-mbar-seg,
  .xcs-chat-step,
  progress::-webkit-progress-value { transition: none; }
  .xcs-btn-primary:hover:not(:disabled) { transform: none; }
}

/* ═══ AVATAR: TINTA GELAP, BUKAN PUTIH ════════════════════════════════════
   styles.css:429 menetapkan `.xcs-avatar { color: #fff }` sementara latarnya
   datang dari gaya inline (`me.color` dari basis data) di 41 tempat pada 12
   berkas. Diukur: putih di atas kuning #FACC15 = 1,53:1, di atas limau
   #A3FF4D = 1,24:1 — inisialnya praktis hilang.

   CSS tidak bisa membaca warna inline itu, jadi tintanya tidak bisa dipilih
   per-avatar. Dua jalan keluar yang mungkin diukur keduanya:
     · putih + latar digelapkan 50%  → lolos, tetapi semua avatar jadi keruh
     · tinta gelap + latar dicerahkan 16% → lolos DAN warnanya tetap hidup
   Yang kedua dipakai. Hasil terburuk di seluruh palet pengguna 5,24:1
   (abu #6E6E6E); kuning 13,4:1, limau 16,0:1, biru 6,6:1.
   Pencerah dipasang sebagai inset box-shadow karena ia menimpa latar inline
   tanpa memerlukan pseudo-elemen, dan tetap berada DI BAWAH teksnya. */
.xcs-avatar {
  color: #0B0F0D !important;
  box-shadow: inset 0 0 0 999px rgba(255, 255, 255, .16);
}

/* ═══ PANEL "DARI TAHAP SEBELUMNYA" — KEADAAN KOSONG ══════════════════════
   Panel ini dulu menghilang total selama tahap sebelumnya belum diisi, jadi
   penulis script tidak pernah tahu ada brief premis di atasnya. Sekarang ia
   tetap tampil dan menyebut siapa yang ditunggu. Barisnya dibuat setenang
   mungkin — ini informasi, bukan peringatan. */
.fsw-up-empty {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  padding: 2px 0 2px; color: var(--xcs-ink-3); font-size: 12.5px;
}
.fsw-up-empty > span { margin-right: 2px; }

/* ═══ HURUF: INTER DI SELURUH ANTARMUKA ═══════════════════════════════════
   Referensi menetapkan satu keluarga huruf. `body` sudah dipindah ke Inter di
   nova.css, tetapi delapan belas aturan lama masih menyetel 'Jost' langsung
   pada elemen tampilan — judul panel tugas, nama klien, judul halaman, layar
   masuk, blok merek — jadi separuh teks besar di aplikasi masih memakai huruf
   sistem lama. Semuanya disatukan di sini.

   PENGECUALIAN yang disengaja: `.fsw-lockup-x` dan `.fsw-lockup-tag` di
   brand.css TETAP Jost. Keduanya bagian dari logotype FRAZIER × SENTARIS
   (wordmark-nya sendiri berupa berkas gambar), bukan teks antarmuka.
   `.xcs-mono` juga dibiarkan — ia memang JetBrains Mono.

   !important dipakai karena styles.css:11803/12210/13114/18117 menulis
   font-family-nya dengan !important pada spesifisitas sampai (0,3,1). */
.fsw-drawer-title,
.fsw-drawer-client,
.fsw-bd-batchbtn-v,
.fsw-flow-pct b,
.fsw-gone-h,
.fsw-day-h,
.xcs-brand-name,
.xcs-brand-sub,
.xcs-eyebrow,
.xcs-pagehead .xcs-eyebrow,
.xcs-pagehead h1,
.xcs-login-name,
.xcs-login-h1,
.xcs-mobile-brand span,
html[data-theme="dark"] .xcs-brand-name {
  font-family: 'Inter', ui-sans-serif, system-ui, sans-serif !important;
  letter-spacing: -0.022em;
}
/* Nama merek di sidebar memang direnggangkan — itu gaya logotype, bukan judul. */
.xcs-brand-name, html[data-theme="dark"] .xcs-brand-name { letter-spacing: .06em; }
.xcs-brand-sub { letter-spacing: .18em; }
/* Pengecualian di atas harus DITEGAKKAN, bukan sekadar dituliskan: selector
   `.xcs-mobile-brand span` ternyata ikut menangkap `.fsw-lockup-x` (glif "×"
   memang sebuah <span> di dalam blok merek). Terukur: ia berubah jadi Inter.
   Dikembalikan ke Jost — ia bagian logotype, bukan teks antarmuka.
   Spesifisitasnya (0,2,0), bukan (0,1,0): `.xcs-mobile-brand span` adalah
   (0,1,1), dan dua aturan ber-!important dimenangkan oleh yang lebih
   spesifik, bukan oleh yang terakhir ditulis. Percobaan pertama memakai
   `.fsw-lockup-x` saja dan diam-diam kalah. */
.fsw-lockup .fsw-lockup-x,
.fsw-lockup .fsw-lockup-tag { font-family: 'Jost', system-ui, sans-serif !important; }


/* ═══════════════════════════════════════════════════════════════════════════
 * PONSEL — MERAPATKAN KOMPONEN DI DALAM KARTU
 * ───────────────────────────────────────────────────────────────────────────
 * Permintaan pemilik: "refine ui versi mobile, cari semua kasus yang memakan
 * space sia sia atau clutter". Tangkapan layar yang ia kirim: kartu kepala
 * klien di 390px — sembilan pasang label/nilai dalam SATU kolom, tiga di
 * antaranya "—", memakan hampir satu layar penuh.
 *
 * Semua angka di bawah diukur di 390px lewat migrasi/uji/jsxcheck/pratinjau.js
 * (berkas lokal disajikan di atas situs live; nol tulisan ke produksi).
 * Tinggi halaman berdenyut ±120px antar-jalankan karena datanya live, jadi
 * setiap pasangan sebelum/sesudah diambil BERURUTAN dalam satu lintasan:
 *
 *   opsclients:client  5.855 → 5.517  (−338)
 *   opstoday           3.191 → 2.971  (−220)
 *   opsposted          1.437 → 1.281  (−156)
 *   mywork             3.198 → 3.118  (−80)
 *   opsperformance     1.995 → 1.901  (−94)
 *   opssettings        2.567 → 2.545  (−22)
 *
 * Cakupan blok ini HANYA komponen di DALAM kartu. Kulit halaman
 * (.xcs-main-inner, .fsw-page, .xcs-footer, .fsw-bbar, .xcs-pagehead, laci,
 * modal, menu) milik agen Shell dan tidak disentuh satu baris pun.
 *
 * DESKTOP TIDAK BERGESER. Dibuktikan, bukan diasumsikan: opsclients:client
 * diukur di 1440px dan 769px dengan berkas lama lalu berkas ini, dan seluruh
 * angkanya identik — 1440: halaman 4.580 / kv 208 / hdr 247 / kartu 4.462;
 * 769: halaman 5.330 / kv 208 / hdr 295 / kartu 4.694.
 *
 * Ruang aman yang SENGAJA tidak disentuh:
 *   · padding-bottom 96px pada .xcs-main-inner — bilah bawah HP setinggi 77px
 *     ber-position:fixed berdiri di sana.
 *   · .xcs-notif-bell dan .fsw-assist-fab (cacat A1/A2 pada B4-cacat.md):
 *     tidak ada position / top / right / bottom / width / height / z-index
 *     untuk keduanya di mana pun dalam blok ini.
 *   · tinggi baris .fsw-table. Baris `tr.is-click` adalah target sentuh, dan
 *     13,5px × 1,55 + bantalan 12px×2 = 45px. Memangkas bantalannya ke 9px
 *     menjadikannya 39px — di bawah ambang 44px. Dibiarkan apa adanya.
 *   · warna. Tidak ada satu pun deklarasi warna di blok ini, jadi tidak ada
 *     rasio kontras yang bisa turun di tema mana pun.
 * ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {

  /* ── (b) LABEL MIKRO: kapital-semua + renggang = "clutter" yang dimaksud ──
     B5 §2 sudah memutuskan label mikro TIDAK kapital-semua dan tidak
     direnggangkan, dan menyediakan tokennya (--fsw-micro-tt: none,
     --fsw-micro-ls: .005em). Tetapi belasan aturan lama di ops-theme.css
     menulis `text-transform: uppercase; letter-spacing: .05–.14em` langsung
     (mis. baris 272, 503, 525, 717, 734, 869, 1048, 1455, 1551), jadi
     tokennya tidak pernah sampai. Di layar klien 390px ada 16 label seperti
     itu: 9 `.fsw-kv span` + 7 `.fsw-reel-col-h`.

     TINJAUAN ADVERSARIAL — klaim lama di sini DIRALAT. Putaran sebelumnya
     menulis bahwa kapital-semua "MELEBARKAN teks ±12%" dan "itulah yang
     membuat .fsw-kv tidak pernah muat dua kolom". Diablasi: aturan ini
     dicabut lalu dipasang di enam layar × 390px dan di 360px —
     tinggi halaman berubah 0px di SEMUA layar, lebar kolom .fsw-kv tetap
     117px di 360px, dan nol label membungkus di kedua keadaan. Label
     terpanjang ("Visual Director") hanya ±98px berkapital, masih di bawah
     117px. Jadi dua kolomnya muat karena (a) dan (d), bukan karena aturan
     ini.
     Aturan ini TETAP dipertahankan, tetapi atas alasan yang benar: B5 §2
     memutuskan label mikro tidak kapital-semua, dan 16 label berteriak di
     satu layar adalah "clutter" yang diminta pemilik — bukan penghematan
     piksel. Nilainya keterbacaan, bukan tinggi.

     Tiga selektor DIBUANG dari daftar di bawah pada tinjauan ini:
     .fsw-group-l, .fsw-flow-head h3, .fsw-gone-h. Ketiganya hanya hidup di
     ops-theme.css; `grep -rn` di seluruh *.jsx / *.php → NOL kemunculan,
     jadi tidak pernah dirender. (Metode yang sama sudah dipakai berkas ini
     untuk membuang .fsw-kbtn.)

     Yang DITINGGALKAN sengaja: .fsw-menu-h dan .fsw-pods-h (menu ⋮ dan
     pemilih pod = milik agen Shell), dan .fsw-cal-dow (singkatan tiga huruf
     nama hari — kapital di sana tidak memakan ruang dan memang konvensi
     kalender). */
  .fsw-kv span,
  .fsw-col-l,
  .fsw-up-l,
  .fsw-fold-t,
  .fsw-reel-col-h,
  .fsw-bd-batchbtn-k,
  .fsw-write-bar h4,
  .fsw-day-h {
    text-transform: var(--fsw-micro-tt);
    letter-spacing: var(--fsw-micro-ls);
  }

  /* ── (a) .fsw-kv — pemakan ruang terbesar: 380px untuk 9 baris ──────────
     ops-theme.css:467 meruntuhkannya jadi SATU kolom di ≤640px. Nilainya
     pendek ("Ardi", "Dinda", "15 reel / bulan"), jadi satu kolom selebar
     252px membuang separuh lebarnya dan menumpuk 9 baris setinggi 37px.

     Lebar kolom dihitung dulu, di 390px, SESUDAH blok ini:
       390 − 14×2 (main-inner) − 2 (garis kartu) − 14×2 (bantalan kartu baru)
           − 44 (avatar baru) − 12 (jarak .fsw-hdr) = 276px
       dua kolom berjarak 12px → 132px per kolom. Terukur: "132px 132px".
     Label terpanjang "Visual Director" pada 11px/600 tanpa kapital ≈ 88px;
     nilai terpanjang "15 reel / bulan" pada 12,5px ≈ 90px. Keduanya muat.
     Diuji juga di 360px — kolomnya 117px, masih nol teks terpotong dan nol
     gulir mendatar.

     Ukuran label NAIK 10px → 11px (ambang label mikro 10,5px); penghematan
     datang dari jumlah baris (9 → 5) dan tinggi baris, bukan dari
     mengecilkan huruf. Warnanya tetap --fsw-ink-4, yang di ops-theme.css:23
     ternyata beralias ke --xcs-ink-3 — bukan token "disabled" seperti yang
     namanya sugestikan. Terukur #9CA3AF di atas kartu #1A1F24 = 7,0:1.

     Tidak ada baris yang disembunyikan: tiga nilai "—" tetap tampil.
     380px → 183px. */
  .fsw-kv { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px 12px; }
  .fsw-kv > div { gap: 1px; }
  .fsw-kv span {
    font-size: 11px; line-height: 1.25; font-weight: var(--fsw-micro-fw);
    overflow-wrap: anywhere;   /* jaring pengaman untuk kolom 117px di 360px */
  }
  /* TINJAUAN: `.fsw-kv b { line-height: 1.3 }` DIBUANG di sini. Diablasi di
     360px: dengan aturan itu .fsw-kv setinggi 183px, tanpa aturan itu 177px
     dan halaman 5.532 → 5.526. Jadi ia MENAMBAH 6px, bukan mengurangi, dan
     nol nilai membungkus di kedua keadaan sehingga tidak ada keterbacaan
     yang dibeli dengan 6px itu. Aturan tanpa pengurangan terukur dibuang. */

  /* ── (c) .fsw-card — 18px vertikal × 9–11 kartu di layar 390px ──────────
     Bantalan 18/20 dan jarak 12 dirancang untuk kartu selebar 400–600px.
     Di 390px kartunya hanya 360px, jadi bingkainya memakan porsi jauh lebih
     besar dari isinya. 18 → 12 vertikal, 20 → 14 mendatar, jarak 12 → 10.
     14px masih di atas radius kartu (14px), jadi sudutnya tidak menggigit isi.

     Diukur terpisah di opssettings, yang punya TEPAT satu kartu dan tidak
     punya .fsw-kv / .fsw-kpi / .fsw-empty sama sekali — jadi seluruh selisih
     halamannya murni aturan ini: 2.567 → 2.545 = −22px per kartu
     (12px bantalan + 10px dari empat jarak). Di layar klien dengan 9 kartu:
     tinggi seluruh kartu 5.164 → 4.827.

     Bonus yang lebih penting dari tingginya: 12px lebar yang dibebaskan
     langsung dipakai .fsw-kv di atas. */
  .fsw-card { padding: 12px 14px; gap: 10px; }

  /* ── (d) .fsw-hdr — kepala klien pada tangkapan layar pemilik: 478px ────
     Avatar 52px dan judul 21px adalah ukuran desktop. Di 390px avatar 52px
     memakan 14% lebar baris untuk satu huruf. 52 → 44 (tetap ≥44px kalau
     suatu saat ia menjadi target sentuh) dan jarak 16 → 12 menyerahkan 12px
     lagi ke kolom .fsw-kv.

     Judul 21 → 18px terukur menghemat 7px sendirian (ablasi: hdr 278px
     dengan aturan ini dicabut, 271px dengan aturan ini) — kecil, karena ia
     sebaris dengan chip status setinggi 26px yang menahan tinggi barisnya.
     Yang lebih berharga: nama klien panjang tidak lagi membungkus jadi dua
     baris di 360px. Kontras judul diperiksa ulang karena 18px TURUN dari
     kelas "teks besar" (≥18,66px tebal, ambang 3:1) ke teks biasa (4,5:1):
     #0B0F0D di atas #FFFFFF = 19,29:1 terang, #F9FAFB di atas #1A1F24 =
     15,88:1 gelap. Aman di kedua tema.

     Avatar 52 → 44px TERNYATA jauh lebih berharga dari yang dilaporkan.
     Di 390px ablasinya 0px, dan laporan lama berhenti di situ. Di 360px
     ia menahan .fsw-hdr-b tetap sebaris dengan avatar: dengan 52px blok
     itu jatuh ke baris sendiri dan .fsw-hdr melonjak 271 → 335px
     (halaman 5.532 → 5.596). Jadi −64px di 360px, bukan nol.

     `.fsw-hdr-acts { gap: 8px }` DIBUANG pada tinjauan ini: diablasi di
     390px dan 360px, nol perubahan pada tinggi halaman, tinggi .fsw-hdr,
     maupun lebar kolom .fsw-kv. Aturan tanpa pengurangan terukur dibuang.

     .fsw-hdr-b TIDAK diubah. flex-basis 240px-nya yang menahan blok tetap
     sebaris dengan avatar; menurunkannya justru menjatuhkannya ke baris
     sendiri dan menambah tinggi. 478px → 271px. */
  .fsw-hdr { gap: 12px; }
  .fsw-hdr-ph { width: 44px; height: 44px; border-radius: 10px; font-size: 16px; }
  .fsw-hdr-b h2 { font-size: 18px; margin-bottom: 4px; gap: 8px; }

  /* ── (e) .fsw-kpi / .fsw-kpis — 411px untuk lima KPI (opsposted) ────────
     Jumlah kolom TIDAK diubah: ops-theme.css:1701 sudah menurunkan is-4/is-5
     ke dua kolom di ≤768px dan itu benar. Yang berlebih adalah bingkainya —
     bantalan 16px×2 dan margin 8px atas+bawah pada angka, di kartu yang
     isinya hanya tiga baris. 16 → 12 dan jarak kisi 10 → 8.

     RALAT TINJAUAN pada margin angka. Putaran sebelumnya menulis
     `.fsw-kpi-v { margin: 6px 0 }` dan melaporkannya sebagai "8 → 6".
     Nilai lamanya bukan 8: ops-theme.css:1493 memakai `margin: 5px 0 3px`,
     yaitu 8px TOTAL. `6px 0` berarti 12px total — aturan itu MENAMBAH 4px
     per kartu KPI. Terukur dengan mencabutnya: opstoday −12px,
     opsposted −12px, mywork −8px (total −32px). Sekarang `4px 0 2px`
     (6px total), yang benar-benar di bawah nilai lama.

     Terukur (bersama penurunan angka di blok 430px di bawah):
       opsposted  .fsw-kpis 411 → 319, tinggi kartu 136 → 95
       opstoday   .fsw-kpis 387 → 310, tinggi kartu 128 → 103
       mywork     .fsw-kpis 273 → 207, tinggi kartu 128 → 103
     Kartu KPI adalah <button> setinggi ±95px — jauh di atas ambang sentuh
     44px, jadi merapatkannya tidak mengorbankan apa pun. */
  .fsw-kpis { gap: 8px; }
  .fsw-kpi { padding: 12px; }
  .fsw-kpi-v { margin: 4px 0 2px; }

  /* ── (f) .fsw-empty — 72px bantalan vertikal untuk satu kalimat ─────────
     Terukur di opsposted: kotak 215px, yang 72px di antaranya bantalan dan
     26px ikon; isinya sendiri hanya judul 25px + kalimat 81px. Di desktop
     72px memberi napas pada kartu selebar 900px; di 390px ia cuma mendorong
     isi berikutnya ke bawah lipatan.
     Bantalan 36 → 20 (−32px), ikon 26 → 22 (−4px), judul 16 → 15px (−2px).
     Kalimatnya sendiri tidak disentuh — tetap 13px.
       opsposted       215 → 178
       opstoday        155 → 117
       opsperformance  175 → 138 */
  .fsw-empty { padding: 20px 14px; }
  .fsw-empty-ico .fsw-ic { width: 22px; height: 22px; }
  .fsw-empty-title { font-size: 15px; }
}

/* ── Ponsel sempit: 430px ke bawah ────────────────────────────────────────
   Di 431–768px kartu masih cukup lega; yang di bawah ini hanya berlaku di
   lebar yang benar-benar sempit. */
@media (max-width: 430px) {
  /* Angka KPI 26px (--fsw-fs-kpi-hp) pada kolom selebar ±160px membuat kotak
     angkanya setinggi 37px. 26 → 23px menurunkannya ke 25px, dan 23px masih
     dua kali lipat ambang teks isi 12px.
     Ablasi di opsposted 390px, blok ini dicabut lalu dipasang:
     .fsw-kpis 355 → 319 (−36), kotak angka 37 → 25. */
  .fsw-kpi-v { font-size: 23px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 * PONSEL — TARGET SENTUH 44px (TINJAUAN ADVERSARIAL)
 * ───────────────────────────────────────────────────────────────────────────
 * Blok di atas diuji ulang dengan pengukuran, bukan dengan penalaran. Satu
 * kelas cacat lolos dari putaran sebelumnya karena ALAT-nya yang longgar,
 * bukan karena aturannya: `audit.js:70` meloloskan apa pun yang ≥32×24px,
 * jadi laporan "0 cacat" memang benar terhadap alat itu — tetapi ambang yang
 * diminta pemilik adalah 44×44px. Diukur ulang dengan ambang 44px di 390px,
 * hanya untuk elemen di dalam `.xcs-main` (laci navigasi = milik agen Shell):
 *
 *   99 × .fsw-input                        40px  ← ditetapkan oleh BERKAS INI
 *    2 × button di .fsw-action-row         32px
 *    1 × .fsw-section-toggle               34px
 *    1 × .fsw-ref                          33px
 *    1 × .xcs-btn-primary.xcs-btn-sm       38px
 *    1 × .xcs-btn-ghost                    40px
 *
 * Empat dari enam adalah janji berkas INI yang tidak pernah berlaku:
 * baris 983 menulis `min-height: 40px` (di bawah ambang), dan baris 985
 * menulis 44px untuk .xcs-btn-* tetapi kalah spesifisitas dari
 * ops-theme.css:1378 `.fsw-action-row > button` (0,1,1) dan
 * ops-theme.css:1683 `.fsw-it .xcs-btn-ghost` (0,2,0) — keduanya 0,1,0 vs
 * lawan yang lebih spesifik, persis pola yang sudah tercatat di §logotype.
 * Di sini spesifisitasnya dinaikkan secukupnya, tidak lebih.
 *
 * Harga yang dibayar, diukur dan disebut apa adanya. Satu layar naik:
 * opssettings +50px di 390px dan 430px (100 kotak isian 40 → 44px), tetapi
 * −22px di 360px. Ditukar dengan 102 target sentuh yang lolos ambang
 * (136 → 34 pelanggaran di layar itu). Aturan 5 batas keras, jadi
 * pertukaran itu diambil dengan sadar.
 *
 * Tinggi halaman akhir terhadap keadaan SEBELUM seluruh pekerjaan ponsel
 * (berkas dipotong di baris 1145 lalu diukur berurutan dalam satu lintasan):
 *
 *   layar               390px            360px            430px
 *   opsclients:client   5.843 → 5.527    6.081 → 5.550    5.843 → 5.508
 *   opstoday            3.179 → 2.942    3.179 → 2.961    3.160 → 2.942
 *   opsposted           1.429 → 1.261    1.449 → 1.297    1.377 → 1.225
 *   opsperformance      1.987 → 1.893    1.987 → 1.893    1.893 → 1.799
 *   mywork              3.193 → 3.100    3.261 → 3.168    3.146 → 3.069
 *   opsclients          2.782 → 2.716    2.881 → 2.831    2.766 → 2.716
 *   opssettings         2.383 → 2.433    2.496 → 2.474    2.346 → 2.396
 *   jumlah              −924px           −1.160px         −876px
 *
 * .fsw-ref dan .fsw-section-toggle diperbesar lewat bantalan + margin
 * negatif yang saling meniadakan — pola yang sudah dipakai
 * ops-theme.css:969 (9px/−9px = 33px), di sini 15px/−15px = 45px. Biaya
 * tata letaknya NOL: tinggi barisnya tidak berubah sama sekali.
 * Diperiksa bahwa area yang melebar tidak MENCURI ketukan milik kontrol
 * lain: ditembak dengan elementFromPoint di tepi atas, tengah, dan tepi
 * bawah setiap elemen — .fsw-section-toggle mengembalikan dirinya sendiri
 * di ketiga titik; .fsw-ref (remah roti) mengembalikan dirinya di tepi atas
 * dan sebuah <div> pasif di tepi bawah, jadi area efektifnya lebih kecil
 * dari 45px tetapi tidak satu pun tombol lain yang tertutup. Catatan untuk
 * putaran berikutnya: ops-ui.jsx:375 juga merender .fsw-ref INLINE di
 * tengah kalimat; di keenam layar yang diaudit varian itu tidak pernah
 * muncul (terukur: nol .fsw-ref di opstoday), jadi risiko tumpang-tindih
 * antarbaris belum bisa diukur di sini.
 *
 * Sisa yang TIDAK diperbaiki karena milik berkas agen lain — dilaporkan,
 * tidak disentuh:
 *   34 × .xcs-link  34×34–35px  (↑ ↓ ✕ editor timeline, ops-theme.css:971)
 *    1 × .fsw-tab   41,1px LEBAR (tinggi 44px sudah benar; nova-shell.css:395)
 *    1 × input tanpa kelas  209×38,8px  ("Lompat ke klien")
 * Lebar .fsw-ref (33,2px) juga dibiarkan: ia dirender inline di dalam
 * kalimat (ops-ui.jsx:375) dan melebarkannya akan merusak alur teks.
 *
 * Desktop tetap nol pergeseran: seluruh blok ini di dalam @media.
 * ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  /* Baris 983 berkas ini menulis 40px, empat piksel di bawah ambang. */
  .fsw-input, select.fsw-input, select.fsw-input.is-sm { min-height: 44px; }

  /* ops-theme.css:1378 `.fsw-action-row > button` (0,1,1) mengalahkan
     baris 985 (0,1,0). Dilawan dengan selektor yang sama persis. */
  .fsw-action-row > button { min-height: 44px; }

  /* ops-theme.css:1683 memakai `.fsw-it .xcs-btn-ghost` dkk (0,2,0);
     `.xcs-main button.xcs-…` adalah (0,2,1) — cukup untuk menang tanpa
     !important, dan terbatas pada area isi saja. */
  .xcs-main button.xcs-btn-primary,
  .xcs-main button.xcs-btn-ghost,
  .xcs-main button.xcs-btn-sm { min-height: 44px; }

  /* 33/34px → 45px tanpa mengubah tinggi baris satu piksel pun. */
  .fsw-ref,
  .fsw-section-toggle {
    padding-top: 15px; padding-bottom: 15px;
    margin-top: -15px; margin-bottom: -15px;
  }
}

/* ═══ KARTU KEPALA KLIEN DI PONSEL: DATA DIBUAT KESAMPING ═════════════════
   Permintaan pemilik, dua kali: "terlalu panjang memakan tempat, buat
   kesamping". Blok ponsel sebelumnya sudah menjadikannya dua kolom
   (380px → 199px), tetapi label masih DI ATAS nilainya — jadi tiap pasang
   masih memakan dua baris.

   Dua perubahan, dan urutannya penting:

   1. Avatar dilepas dari aliran (float). `.fsw-hdr` adalah flex row, dan
      avatar 44px + gap memangkas lebar daftar data dari 322px kartu menjadi
      276px. Dengan 276px, dua kolom hanya 132px — pasangan terpanjang
      ("Head Creative Michelle") butuh ±130px, jadi ia lolos di 390px tetapi
      MEMBUNGKUS di 360px. Sebagai float, nama tetap bersebelahan dengan
      avatar sementara daftarnya mengambil lebar penuh: kolom jadi ±155px.

   2. Baris jadi `row`: label kiri, nilai kanan, satu baris. Sembilan pasang
      yang tadinya 18 baris jadi 5 baris.

   Nilai dirata-kanan supaya kolom angka/nama sejajar dan mata bisa memindai
   ke bawah; `overflow-wrap: anywhere` menjaga nilai panjang tetap di dalam
   selnya alih-alih melebarkan grid. */
@media (max-width: 768px) {
  .fsw-hdr { display: block; }
  .fsw-hdr-ph { float: left; margin: 0 12px 6px 0; }
  .fsw-hdr-b { display: block; min-width: 0; }
  .fsw-hdr-acts { clear: both; padding-top: 2px; }

  .fsw-kv {
    clear: left;
    grid-template-columns: 1fr 1fr;
    gap: 6px 14px;
  }
  .fsw-kv > div {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 6px;
  }
  .fsw-kv span { flex: 0 0 auto; }
  .fsw-kv b {
    flex: 0 1 auto;
    min-width: 0;
    text-align: right;
    overflow-wrap: anywhere;
  }
}

/* Di bawah 430px kolomnya menyempit lagi; pasangan terpanjang masih muat,
   tetapi jaraknya dirapatkan supaya nilai tidak menempel ke labelnya. */
@media (max-width: 430px) {
  .fsw-kv { gap: 5px 10px; }
}

/* ═══ TARGET SENTUH: TAB PENDEK ═══════════════════════════════════════════
   Tab "AI" di Pengaturan berukuran 41×44 di 390px — tingginya sudah cukup,
   lebarnya kurang 3px karena labelnya hanya dua huruf. Lantai lebar tidak
   menambah tinggi apa pun karena baris tab memang membungkus.

   TIDAK diperbaiki di sini, dan ini disengaja: 33 tombol "↑"/"↓" pengurut
   daftar di layar yang sama berukuran 34×35. Keduanya BERSEBELAHAN di dalam
   satu sel tabel, jadi trik "bantalan besar + margin negatif" akan membuat
   area sentuh keduanya bertumpuk ±30px — satu ketukan di tengah jadi ambigu
   dan bisa memindahkan baris ke arah yang salah. Membesarkannya secara jujur
   ke 44×44 menambah ±300px ke layar yang baru saja dirapatkan. Dua-duanya
   lebih buruk daripada tombol 34px di layar admin yang jarang dibuka. */
@media (max-width: 768px) {
  .fsw-tabs .fsw-tab { min-width: 44px; }
}
