/* ==========================================================================
   BERSUARA — sistem desain
   --------------------------------------------------------------------------
   Tampilan diadopsi dari aplikasi acuan REKAP: aksen biru & mint, netral
   biru-abu, Plus Jakarta Sans, kartu sudut besar, sidebar terang. CSS ini
   ditulis statis (bukan Tailwind runtime) supaya server produksi tidak perlu
   Node dan halaman tidak menanggung 451 KB kompilasi di peramban.

   Mode gelap memakai kelas `.dark` pada <html>, disetel sebelum render agar
   tidak ada kedipan putih.
   ========================================================================== */

/* ------------------------------------------------------------------ font */
/* Di-host lokal, BUKAN dari CDN Google: aplikasi harus tetap tampil benar di
   jaringan lapangan yang buruk atau terputus sama sekali. */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/PlusJakartaSans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/PlusJakartaSans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ----------------------------------------------------------------- token */
:root {
  /* Dua warna memikul seluruh aplikasi, dan masing-masing punya tugas tetap:
     BIRU untuk kerangka dan tindakan (nav, tombol, tautan, fokus), MINT untuk
     apa pun yang berarti "sudah masuk" — TPS terisi, bilah kemajuan, calon
     terpilih. Pembagian tugas inilah yang membuat pasangan ini terbaca sebagai
     sistem, bukan dua warna yang kebetulan bersanding: mata mencari mint untuk
     menilai progres dan biru untuk tahu apa yang bisa diklik, tanpa membaca
     satu label pun. Saturasi ditahan di tengah — warna menyala membuat angka
     pemilu terlihat seperti mainan, tapi kelabu penuh membuat halaman mati. */
  --brand-50:  #eff5fb;
  --brand-100: #dbe8f4;
  --brand-200: #bad3e9;
  --brand-300: #8ab2d7;
  --brand-400: #558cbe;
  --brand-500: #336ea6;
  --brand-600: #26588a;
  --brand-700: #1f4770;
  --brand-950: #0e1d2d;
  /* Kanal terpisah supaya bayangan & cincin fokus ikut berubah bila merek
     diganti — nilainya pernah tersebar sebagai angka mentah di seluruh berkas. */
  --brand-rgb: 38 88 138;
  --brand-soft:   var(--brand-50);
  --brand-soft-2: var(--brand-100);

  /* Mint baru terbaca sebagai hijau mulai nada 300; nada 600-700 sengaja
     ditarik ke arah biru supaya tetap satu keluarga dengan merek dan cukup
     pekat menopang teks putih (5,5:1) — mint pucat dengan tulisan putih di
     atasnya adalah cara termudah membuat lencana "terpilih" tak terbaca.
     Sebaliknya nada 400 hanya boleh dipakai di latar gelap: di atas putih
     kontrasnya 2,9:1, cukup untuk bidang warna tapi tidak untuk teks. */
  --mint-50:   #e6f6ef;
  --mint-200:  #a2ddc6;
  --mint-300:  #66c4a4;
  --mint-400:  #35ab86;
  --mint-600:  #12775b;
  --mint-700:  #0f5e48;
  --mint-rgb:  53 171 134;

  /* Netral ikut condong ke biru — abu-abu netral di samping biru dan mint
     tampak sedikit kekuningan, seperti kertas yang menua. */
  --bg:        #eef2f7;
  --surface:   #ffffff;
  --surface-2: #f6f9fc;
  --line:      #dee7f0;
  --line-2:    #eaf0f7;
  --hover:     #f0f4fa;

  --text:      #26313f;
  --text-str:  #0f1b28;
  --text-mut:  #5a6779;
  --text-fnt:  #626d80;

  /* "Berhasil" adalah mint itu sendiri: satu-satunya kabar baik yang dikejar
     aplikasi ini adalah data yang masuk, jadi warnanya tidak perlu dipisah. */
  --ok:          var(--mint-600);
  --ok-bg:       var(--mint-50);
  --ok-line:     var(--mint-200);
  --ok-text:     var(--mint-700);
  /* Peringatan & bahaya sengaja TIDAK ikut didinginkan. Tugasnya menyela, dan
     warna yang sekeluarga dengan biru-mint tidak menyela apa pun. */
  --warn:        #8a6c38;
  --warn-bg:     #f6ebd5;
  --warn-line:   #dfc79b;
  --warn-text:   #654920;
  --danger:      #a34346;
  --danger-bg:   #f9e7e7;
  --danger-line: #e0b0b1;
  --danger-text: #762e30;

  --veil:      rgb(10 16 23 / .55);
  --gulir:     rgb(90 103 121 / .38);

  --radius:    1rem;
  --radius-sm: .75rem;
  --radius-xs: .5rem;
  --shadow:    0 1px 2px 0 rgb(15 27 40 / .05);
  --shadow-md: 0 4px 14px -4px rgb(15 27 40 / .10);
  --shadow-lg: 0 24px 48px -16px rgb(15 27 40 / .28);

  --sidebar-w: 15rem;
}

.dark {
  /* Bukan hitam pekat: latar yang benar-benar gelap membuat tepi kartu
     berkilau berlebihan. Semua permukaan diangkat sedikit ke biru malam. */
  --bg:        #0a1017;
  --surface:   #121b26;
  --surface-2: #0e161f;
  --line:      #223141;
  --line-2:    #18222e;
  --hover:     #18222e;

  --text:      #c3ccd8;
  --text-str:  #eff4f9;
  --text-mut:  #94a2b4;
  --text-fnt:  #82909f;

  --brand-soft:   #14243a;
  --brand-soft-2: #1c3251;

  /* Mint di latar gelap dinaikkan dua langkah: nada 600 yang menopang teks
     putih di mode terang justru tenggelam jadi lumut di sini. */
  --ok-bg:       #0f2a22;
  --ok-line:     #255545;
  --ok-text:     #6fcda9;
  --warn-bg:     #2e2415;
  --warn-line:   #574023;
  --warn-text:   #d8b783;
  --danger-bg:   #331a1c;
  --danger-line: #5e2f32;
  --danger-text: #dc9b9e;

  --veil:      rgb(4 8 12 / .68);
  --gulir:     rgb(130 144 159 / .28);
}

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

html {
  font-family: 'Plus Jakarta Sans', 'Segoe UI', system-ui, -apple-system, sans-serif;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4 { margin: 0; color: var(--text-str); font-weight: 800; line-height: 1.25; }
h1 { font-size: 1.25rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }
p  { margin: 0; }

a { color: var(--brand-600); text-decoration: none; }
a:hover { text-decoration: underline; }
.dark a { color: var(--brand-400); }

:focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Panah spinner input angka disembunyikan agar entri cepat tidak salah klik. */
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type=number] { -moz-appearance: textfield; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--gulir); border-radius: 8px; }
.dark ::-webkit-scrollbar-thumb { background: var(--gulir); }

[hidden] { display: none !important; }

/* Ukuran ikon. Helper ikon() memancarkan <svg class="..."> tanpa dimensi,
   jadi ukurannya sepenuhnya ditentukan kelas di sini. */
.ic    { width: 1rem;    height: 1rem;    flex: none; }
.ic-xs { width: .75rem;  height: .75rem;  flex: none; }
.ic-sm { width: .875rem; height: .875rem; flex: none; }
.ic-lg { width: 1.25rem; height: 1.25rem; flex: none; }
.ic-xl { width: 1.5rem;  height: 1.5rem;  flex: none; }
.ic-2x { width: 1.75rem; height: 1.75rem; flex: none; }

.tabular { font-variant-numeric: tabular-nums; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* =================================================================== SHELL */

.app { display: flex; min-height: 100vh; }

/* ---------------------------------------------------------------- sidebar */
.sidebar {
  width: var(--sidebar-w);
  flex: none;
  background: var(--surface);
  border-right: 1px solid var(--line);
  height: 100vh;
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
}

.sidebar-head {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: 1rem;
  border-bottom: 1px solid var(--line);
}

.sidebar-logo {
  width: 2.25rem; height: 2.25rem; flex: none;
  border-radius: var(--radius-sm);
  background: var(--brand-600);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
}

.sidebar-title { font-weight: 800; color: var(--text-str); font-size: .875rem; line-height: 1.2; }
.sidebar-sub   { font-size: .6875rem; color: var(--text-mut); }

.sidebar-nav { flex: 1 1 auto; overflow-y: auto; padding: .75rem; }

.nav-group + .nav-group { margin-top: 1rem; }

.nav-label {
  padding: 0 .5rem;
  margin-bottom: .375rem;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-fnt);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  padding: .5rem .625rem;
  border-radius: var(--radius-sm);
  font-size: .875rem;
  font-weight: 600;
  color: var(--text-mut);
  transition: background .15s, color .15s;
}
.nav-item + .nav-item { margin-top: .125rem; }
.nav-item:hover { background: var(--line-2); text-decoration: none; color: var(--text-str); }
.dark .nav-item:hover { background: var(--line); }

.nav-item.is-active {
  background: var(--brand-600);
  color: #fff;
  box-shadow: 0 1px 2px 0 rgb(var(--brand-rgb) / .22);
}
.nav-item.is-active:hover { background: var(--brand-600); color: #fff; }

.nav-item svg { flex: none; }

.sidebar-foot { padding: .75rem; border-top: 1px solid var(--line); }

.user-chip { display: flex; align-items: center; gap: .625rem; padding: .5rem; }
.user-avatar {
  width: 2rem; height: 2rem; flex: none;
  border-radius: var(--radius-xs);
  background: var(--brand-100);
  color: var(--brand-700);
  display: flex; align-items: center; justify-content: center;
  font-size: .75rem; font-weight: 800;
}
.user-name { font-size: .875rem; font-weight: 700; color: var(--text-str); }

/* Laci sidebar untuk layar kecil. */
.sidebar-backdrop {
  position: fixed; inset: 0; z-index: 40;
  background: var(--veil);
  backdrop-filter: blur(2px);
  display: none;
}
.sidebar-backdrop.is-open { display: block; }

/* ----------------------------------------------------------------- topbar */
.app-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

/* Pita hanya-baca saat yang dibuka bukan pemilu penerima input.
   Sengaja selebar layar dan di atas bilah atas: setiap tombol simpan di halaman
   mana pun akan menolak, dan menolak tanpa memberitahu sebabnya lebih buruk
   daripada tidak menolak sama sekali. */
.bar-arsip {
  display: flex; align-items: center; gap: .5rem;
  padding: .5rem 1.25rem;
  background: var(--warn-bg);
  color: var(--warn-text);
  border-bottom: 1px solid var(--warn-line);
  font-size: .75rem; line-height: 1.5;
}
.bar-arsip > svg { flex: none; }

.topbar-row {
  display: flex; align-items: center; gap: .5rem;
  padding: .625rem .75rem;
}

.topbar-title { font-weight: 700; font-size: .875rem; color: var(--text-str); flex: 1 1 auto; }

.topbar-dapil {
  display: flex; align-items: center; gap: .5rem;
  font-size: .875rem; font-weight: 700; color: var(--text);
  flex: 1 1 auto; min-width: 0;
}

.topbar-actions { display: flex; align-items: center; gap: .5rem; flex: none; }

main { flex: 1 1 auto; padding: .75rem; width: 100%; max-width: 1600px; margin: 0 auto; }

@media (min-width: 640px) {
  .topbar-row { padding: .625rem 1.25rem; }
  main { padding: 1.25rem; }
}

/* ============================================================== KOMPONEN */

/* ------------------------------------------------------------------ kartu */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card-pad { padding: 1.25rem; }
.card-pad-sm { padding: 1rem; }

.card-head {
  display: flex; align-items: center; gap: .75rem;
  padding: .875rem 1rem;
  border-bottom: 1px solid var(--line-2);
}

.card-body { padding: 1rem; }

/* --------------------------------------------------------------- masthead */
.masthead {
  border-radius: var(--radius);
  border: 1px solid #1d3348;
  background: linear-gradient(140deg, #0e1d2d 0%, #14293d 55%, #1b3d5c 100%);
  overflow: hidden;
  color: #f2f4f8;
}
.masthead-inner { padding: 1.25rem 1.5rem; }
.masthead h1 { color: #f2f4f8; font-size: 1.5rem; }
.masthead-eyebrow {
  font-size: .625rem; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: var(--brand-200);
}
/* Keduanya duduk di atas gradien biru gelap yang tidak ikut tema, jadi warnanya
   pun tidak boleh ikut tema. Baris meta (waktu & hitungan TPS) dulu ditulis
   sebagai hex mentah di dalam View, dan tertinggal saat palet diganti. */
.masthead-sub, .masthead-meta { color: #a9bdd0; }
.masthead-sub  { font-size: .75rem; }
.masthead-meta { font-size: .6875rem; }

.masthead-btn {
  width: 2rem; height: 2rem; flex: none;
  border-radius: var(--radius-xs);
  background: rgb(255 255 255 / .07);
  color: #e6eef7; border: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s;
}
.masthead-btn:hover { background: rgb(255 255 255 / .14); }

.live-dot {
  display: inline-flex; align-items: center; gap: .375rem;
  padding: .25rem .625rem; border-radius: var(--radius-xs);
  background: rgb(var(--mint-rgb) / .14);
  border: 1px solid rgb(var(--mint-rgb) / .30);
  font-size: .6875rem; font-weight: 700; color: var(--mint-300);
}
.live-dot::before {
  content: ''; width: .375rem; height: .375rem; border-radius: 50%;
  background: var(--mint-400); animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

/* ------------------------------------------------------------------ stat */
.stat-label {
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-mut);
}
.stat-value {
  font-size: 1.5rem; font-weight: 800; color: var(--text-str);
  font-variant-numeric: tabular-nums; margin-top: .25rem; line-height: 1.15;
}
.stat-sub { font-size: .75rem; color: var(--text-mut); }

.stat-icon {
  width: 2.25rem; height: 2.25rem; flex: none;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-50); color: var(--brand-600);
}
.dark .stat-icon { background: var(--brand-soft); color: var(--brand-400); }

.stat-icon.tone-ok    { background: var(--ok-bg); color: var(--ok); }
.stat-icon.tone-warn  { background: var(--warn-bg); color: var(--warn); }
.stat-icon.tone-danger{ background: var(--danger-bg); color: var(--danger); }
/* Nada pekat ini disetel untuk latar terang; di mode gelap ikonnya jatuh ke
   2,6-3,1:1 di atas latarnya sendiri dan praktis hilang. Dipakai nada teks
   yang memang sadar tema. */
.dark .stat-icon.tone-ok    { color: var(--ok-text); }
.dark .stat-icon.tone-warn  { color: var(--warn-text); }
.dark .stat-icon.tone-danger{ color: var(--danger-text); }

/* --------------------------------------------------------------- tombol */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .5rem .875rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-family: inherit; font-size: .875rem; font-weight: 600;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, opacity .15s;
  white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn:disabled, .btn[aria-busy="true"] { opacity: .55; cursor: not-allowed; }

.btn-primary { background: var(--brand-600); color: #fff; box-shadow: 0 1px 2px 0 rgb(var(--brand-rgb) / .18); }
.btn-primary:hover:not(:disabled) { background: var(--brand-500); }
/* Di latar gelap nada 600 kehilangan tenaga dan terbaca sebagai pelat abu.
   Dinaikkan satu langkah supaya tombol utama tetap terasa sebagai ajakan. */
/* `color` diulang di sini, bukan cuma di `.btn-primary`: tombol yang ditulis
   sebagai <a> kalah dari `.dark a` (0,1,1) dan labelnya berubah biru di atas
   latar biru. Selektor bertingkat dua ini yang mengembalikannya. */
.dark .btn-primary { background: var(--brand-500); color: #fff; }
.dark .btn-primary:hover:not(:disabled) { background: var(--brand-400); color: var(--brand-950); }

.btn-outline { background: var(--surface); color: var(--text); border-color: var(--line); }
.dark .btn-outline { color: var(--text); }
.btn-outline:hover:not(:disabled) { background: var(--surface-2); }
.dark .btn-outline:hover:not(:disabled) { background: var(--line); }

.btn-soft { background: var(--brand-50); color: var(--brand-700); }
/* Nada 400 hanya 4,4:1 di atas brand-soft — cukup untuk ikon, kurang untuk
   label tombol; teksnya dinaikkan ke 300 seperti keping dan label partai. */
.dark .btn-soft { background: var(--brand-soft); color: var(--brand-300); }
.btn-soft:hover:not(:disabled) { background: var(--brand-100); }
.dark .btn-soft:hover:not(:disabled) { background: var(--brand-soft-2); }

.btn-danger { background: var(--danger); color: #fff; }
.dark .btn-danger { color: #fff; }
.btn-danger:hover:not(:disabled) { background: #8b383b; }

.btn-ghost { background: transparent; color: var(--text-mut); }
.dark .btn-ghost { color: var(--text-mut); }
.btn-ghost:hover:not(:disabled) { background: var(--line-2); color: var(--text-str); }
.dark .btn-ghost:hover:not(:disabled) { background: var(--line); }

.btn-sm { padding: .375rem .625rem; font-size: .75rem; gap: .375rem; }
.btn-lg { padding: .625rem 1.25rem; }
.btn-block { width: 100%; }

.btn-icon {
  width: 2rem; height: 2rem; padding: 0; flex: none;
  border-radius: var(--radius-xs);
}

/* Spinner tombol sibuk — dipakai bs.js lewat data-busy. */
.btn .spin { animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg) } }

@media (prefers-reduced-motion: reduce) {
  .btn .spin, .live-dot::before { animation: none; }
  * { transition-duration: .01ms !important; }
}

/* ------------------------------------------------------------------ pil */
.pil {
  display: inline-flex; align-items: center;
  padding: .125rem .5rem;
  border-radius: var(--radius-xs);
  font-size: .6875rem; font-weight: 700;
  background: var(--line-2); color: var(--text-mut);
}
.pil-brand  { background: var(--brand-100); color: var(--brand-700); }
.dark .pil-brand { background: var(--brand-950); color: var(--brand-200); }
.pil-ok     { background: var(--ok-bg); color: var(--ok-text); }
.pil-warn   { background: var(--warn-bg); color: var(--warn-text); }
.pil-danger { background: var(--danger-bg); color: var(--danger-text); }

/* -------------------------------------------------------------- progres */
.progress {
  height: .375rem; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
/* Bilah kemajuan memakai mint, bukan biru: isinya selalu "berapa yang sudah
   masuk" — makna yang sama dengan sel TPS terisi dan centangnya. Biru di sini
   akan membuatnya terbaca sebagai hiasan merek, bukan angka yang bergerak. */
.progress > span {
  display: block; height: 100%; border-radius: 999px;
  background: var(--ok);
  transition: width .5s ease;
}
/* Di latar gelap — mode gelap maupun masthead — nada 600 kehilangan tenaga. */
.dark .progress > span, .progress.on-dark > span { background: var(--mint-400); }
.progress.on-dark { background: rgb(255 255 255 / .07); }

/* ----------------------------------------------------------------- form */
.field + .field, .field + .field-row, .field-row + .field { margin-top: 1rem; }

.label {
  display: block;
  font-size: .75rem; font-weight: 700;
  color: var(--text-mut);
  margin-bottom: .375rem;
}
.label .req { color: var(--danger); }

.input, .select, .textarea {
  width: 100%;
  padding: .625rem .75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-str);
  font-family: inherit; font-size: .875rem;
  transition: border-color .15s, box-shadow .15s;
}
.dark .input, .dark .select, .dark .textarea { background: var(--surface-2); border-color: var(--line); }

.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / .25);
}
.input::placeholder { color: var(--text-fnt); }

.select { padding-right: 2rem; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a6779' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .625rem center; background-size: 1rem;
}

.hint { font-size: .6875rem; color: var(--text-mut); margin-top: .25rem; }

.check { display: flex; align-items: center; gap: .625rem; cursor: pointer; user-select: none; }
.check input { width: 1rem; height: 1rem; accent-color: var(--brand-600); }

.input-num {
  width: 6rem; text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums; padding: .375rem .625rem;
  font-size: .875rem; border-radius: var(--radius-xs);
}
.input-num.is-ai {
  border-color: var(--warn);
  background: var(--warn-bg);
  color: var(--warn-text);
}

/* ---------------------------------------------------------------- tabel */
.table-wrap { overflow-x: auto; }

table.tbl { width: 100%; border-collapse: collapse; font-size: .875rem; }
table.tbl th, table.tbl td { padding: .625rem .875rem; text-align: left; }
table.tbl thead th {
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-mut);
  white-space: nowrap;
}
.dark table.tbl thead th { background: var(--line-2); }
table.tbl tbody tr { border-bottom: 1px solid var(--line-2); }
table.tbl tbody tr:last-child { border-bottom: 0; }
table.tbl td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.tbl td.act { text-align: right; white-space: nowrap; }
table.tbl tr.is-win { background: color-mix(in srgb, var(--ok-bg) 45%, transparent); }

/* --------------------------------------------------- tabel rapat & kelompok */
/* Modifier, bukan perubahan pada .tbl: sebelas halaman lain memakai tabel yang
   sama dan tidak semuanya berisi ratusan baris. Yang butuh kerapatan meminta
   sendiri lewat kelas tambahan.

   Baris 53px yang lama membuat 152 TPS memakan dua belas layar. Dengan padding
   ini baris turun ke sekitar 38px — dan dua kolom yang dulu mengulang nama
   wilayah di tiap baris digantikan satu baris judul kelompok yang LENGKET,
   sehingga wilayahnya justru selalu terlihat saat menggulir. */
table.tbl-rapat th, table.tbl-rapat td { padding: .375rem .875rem; }

/* Tombol aksi ikut mengecil, dan ini bukan pemanis: .btn-icon setinggi 2rem
   menjadi LANTAI tinggi baris — merapatkan padding saja hanya menurunkan baris
   dari 53px ke 45px, karena tombolnya menahan sisanya. Ukurannya mengikuti
   preseden yang sudah ada di daftar caleg. */
table.tbl-rapat .btn-icon { width: 1.625rem; height: 1.625rem; }

table.tbl-rapat tr.grup th {
  position: sticky; top: 0; z-index: 1;
  padding: .4375rem .875rem;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: .75rem; font-weight: 700; letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}
.dark table.tbl-rapat tr.grup th { background: var(--line-2); }
table.tbl-rapat tr.grup th span {
  margin-left: .5rem;
  font-weight: 500;
  color: var(--text-mut);
  font-variant-numeric: tabular-nums;
}

/* Judul kelompok pada tampilan petak — sejajar dengan yang di tabel. */
.grup-judul {
  margin: 0 0 .625rem;
  font-size: .75rem; font-weight: 700;
  color: var(--text);
}
.grup-judul span { margin-left: .5rem; font-weight: 500; color: var(--text-mut); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ sakelar bentuk */
.seg {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.seg-btn {
  display: inline-flex; align-items: center; gap: .375rem;
  padding: .25rem .625rem;
  border-radius: calc(var(--radius-sm) - 2px);
  font-size: .8125rem; font-weight: 600;
  color: var(--text-mut);
  text-decoration: none;
  white-space: nowrap;
}
.seg-btn:hover { color: var(--text); text-decoration: none; }
.seg-btn.is-on {
  background: var(--surface);
  color: var(--brand-700);
  box-shadow: 0 1px 2px rgb(var(--brand-rgb) / .18);
}
.dark .seg-btn.is-on { background: var(--line-2); color: var(--brand-300); }

/* Petak pada halaman TPS memakai <button>, bukan <a> seperti di Input Suara —
   ia membuka modal, bukan berpindah halaman. Penyetelan tombol bawaan peramban
   dibatalkan supaya keduanya tampil persis sama. */
button.tps-cell {
  font: inherit;
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
}

/* --------------------------------------------------------------- remah */
.crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: .25rem; margin-bottom: 1rem; font-size: .875rem; }
.crumbs a { padding: .25rem .5rem; border-radius: var(--radius-xs); font-weight: 600; }
.crumbs a:hover { background: var(--brand-50); text-decoration: none; }
.dark .crumbs a:hover { background: var(--brand-soft); }
.crumbs .now { padding: .25rem .5rem; font-weight: 700; color: var(--text-str); }
.crumbs svg { color: var(--text-fnt); }

/* ==================================================== KARTU TPS (rekap) */
/* Padat dan bisa dibandingkan sekilas.
   Label satuan & nama kelurahan sengaja TIDAK diulang di tiap kartu — keduanya
   sudah dinyatakan di kartu statistik dan remah roti, dan mengulangnya 39 kali
   hanya memakan ruang yang lebih berguna untuk bilah pembanding. */

.tps-kartu-grid {
  display: grid;
  gap: .5rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px)  { .tps-kartu-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 960px)  { .tps-kartu-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .tps-kartu-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (min-width: 1600px) { .tps-kartu-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

.tps-kartu {
  position: relative;
  display: block;
  padding: .5rem .625rem .5625rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s, transform .1s;
}
.tps-kartu:hover {
  border-color: var(--brand-400);
  box-shadow: var(--shadow-md);
  text-decoration: none;
}

.tps-kartu-atas {
  display: flex;
  align-items: baseline;
  gap: .375rem;
  margin-bottom: .125rem;
  /* Ruang untuk penanda status/piala di pojok kanan; tanpa ini teks RT
     tertimpa dan nomornya tidak terbaca. */
  padding-right: .875rem;
}
.tps-kartu .no-tps {
  font-size: .8125rem;
  font-weight: 800;
  color: var(--text-str);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.tps-kartu .rt {
  font-size: .6875rem;
  color: var(--text-fnt);
  font-variant-numeric: tabular-nums;
  margin-left: auto;
  white-space: nowrap;
}

.tps-kartu .nilai {
  font-size: 1.375rem;
  font-weight: 800;
  line-height: 1.1;
  color: var(--text-str);
  font-variant-numeric: tabular-nums;
}

/* Bilah pembanding relatif TPS tertinggi pada tampilan ini — inilah yang
   membuat 39 angka bisa dinilai sekilas, bukan dibaca satu per satu. */
.tps-kartu .bilah {
  height: .25rem;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
  margin-top: .375rem;
}
.tps-kartu .bilah > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--brand-500);
  transition: width .4s ease;
}

/* TPS tertinggi pada tampilan ini ditandai — sering jadi yang dicari lebih dulu. */
.tps-kartu.is-puncak { border-color: var(--brand-400); }
.tps-kartu.is-puncak .bilah > span { background: var(--brand-600); }
.tps-kartu .mahkota {
  position: absolute;
  top: .375rem; right: .5rem;
  color: var(--warn);
}

/* Belum ada suara masuk: dipudarkan supaya tidak bersaing perhatian dengan
   yang sudah terisi, tapi tetap terbaca agar ketahuan mana yang tertinggal. */
.tps-kartu.is-kosong {
  border-style: dashed;
  background: var(--surface-2);
}
.tps-kartu.is-kosong .nilai { color: var(--text-fnt); font-weight: 700; }
.tps-kartu.is-kosong .bilah { opacity: .5; }

.tps-kartu .tanda {
  position: absolute;
  top: .5rem; right: .5rem;
  width: .5rem; height: .5rem;
  border-radius: 999px;
  background: var(--ok);
}

/* ------------------------------------------------------ ringkasan sebaran */
.sebaran {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .5rem;
  margin-bottom: .875rem;
}
@media (min-width: 720px) { .sebaran { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.sebaran-item {
  padding: .5rem .75rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-2);
}
.sebaran-item .k {
  font-size: .625rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-fnt);
}
.sebaran-item .v {
  font-size: 1rem; font-weight: 800; color: var(--text-str);
  font-variant-numeric: tabular-nums; line-height: 1.25;
}
.sebaran-item .s { font-size: .6875rem; color: var(--text-mut); }

/* --------------------------------------------------------- pengurut kecil */
.pengurut {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  padding: .1875rem;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
}
.pengurut a {
  padding: .25rem .5rem;
  border-radius: .375rem;
  font-size: .75rem;
  font-weight: 700;
  color: var(--text-mut);
  white-space: nowrap;
}
.pengurut a:hover { color: var(--text-str); text-decoration: none; }
.pengurut a.aktif {
  background: var(--surface);
  color: var(--text-str);
  box-shadow: var(--shadow);
}
.dark .pengurut a.aktif { background: var(--line); }

/* ------------------------------------------------------------ drill card */
.drill {
  display: block; width: 100%; text-align: left;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem;
  transition: border-color .15s, box-shadow .15s;
  cursor: pointer;
}
.drill:hover { border-color: var(--brand-400); box-shadow: var(--shadow-md); text-decoration: none; }
.drill-title { font-weight: 700; color: var(--text-str); }
.drill:hover .drill-title { color: var(--brand-700); }
.dark .drill:hover .drill-title { color: var(--brand-400); }
.drill-value { font-size: 1.25rem; font-weight: 800; color: var(--text-str); font-variant-numeric: tabular-nums; }
.drill-meta { font-size: .6875rem; color: var(--text-mut); }

/* ------------------------------------------------------------- grid TPS */
.tps-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .5rem;
}
@media (min-width: 640px)  { .tps-grid { grid-template-columns: repeat(5, minmax(0,1fr)); } }
@media (min-width: 1024px) { .tps-grid { grid-template-columns: repeat(8, minmax(0,1fr)); } }
@media (min-width: 1536px) { .tps-grid { grid-template-columns: repeat(10, minmax(0,1fr)); } }

.tps-cell {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: .625rem;
  text-align: center;
  transition: border-color .15s;
  cursor: pointer;
}
.tps-cell:hover { border-color: var(--brand-400); text-decoration: none; }
.tps-cell .no { font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.tps-cell .rt { font-size: .625rem; color: var(--text-mut); }

.tps-cell.is-filled { background: var(--ok-bg); border-color: var(--ok-line); }
.dark .tps-cell.is-filled { background: var(--ok-bg); border-color: var(--ok-line); }
.tps-cell.is-filled .no { color: var(--ok-text); }
.tps-cell .tick {
  position: absolute; top: -.375rem; right: -.375rem;
  width: 1.25rem; height: 1.25rem; border-radius: 50%;
  background: var(--ok); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow);
}

/* ----------------------------------------------------------- hemicycle */
.hemi { width: 100%; max-width: 32rem; margin: 0 auto; display: block; }
.hemi-kosong { color: var(--line); }
.dark .hemi-kosong { color: var(--line); }
.hemi-angka { font-size: .2px; font-weight: 800; fill: var(--text-str); }
.hemi-label { font-size: .085px; font-weight: 700; letter-spacing: .02px; fill: var(--text-mut); }

/* =========================================== PENGATURAN TAMPILAN DASHBOARD */

/* Kotak pilih bergulir untuk daftar panjang (108 caleg / 18 partai). */
.pilih-kotak {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}
.pilih-isi { max-height: 22rem; overflow-y: auto; }

.pilih-grup {
  display: flex; align-items: center; gap: .5rem;
  padding: .375rem .625rem;
  background: var(--surface-2);
  border-top: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-2);
  position: sticky; top: 0; z-index: 1;
}
.dark .pilih-grup { background: var(--line-2); }
.pilih-grup .nm { font-size: .75rem; font-weight: 700; color: var(--text-str); min-width: 0; }
.pilih-grup .mt { margin-left: auto; font-size: .6875rem; color: var(--text-fnt); white-space: nowrap; }

.pilih-baris {
  display: flex; align-items: center; gap: .5rem;
  padding: .3125rem .625rem;
  cursor: pointer;
  font-size: .8125rem;
}
.pilih-baris:hover { background: var(--surface-2); }
.dark .pilih-baris:hover { background: var(--hover); }
.pilih-baris input { width: 1rem; height: 1rem; accent-color: var(--brand-600); flex: none; }
.pilih-baris .nourut {
  flex: none; width: 1.25rem; height: 1.25rem;
  border-radius: .3125rem; background: var(--line-2); color: var(--text-mut);
  display: flex; align-items: center; justify-content: center;
  font-size: .625rem; font-weight: 800; font-variant-numeric: tabular-nums;
}
.pilih-baris .nm { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pilih-baris .sr {
  flex: none; font-size: .75rem; font-weight: 700; color: var(--text-mut);
  font-variant-numeric: tabular-nums;
}
.pilih-baris.terpilih-caleg { background: color-mix(in srgb, var(--ok-bg) 45%, transparent); }

/* Ringkasan pilihan aktif, tampil sebagai keping yang bisa dilepas. */
.keping-terpilih { display: flex; flex-wrap: wrap; gap: .375rem; min-height: 1.75rem; }
.keping {
  display: inline-flex; align-items: center; gap: .375rem;
  padding: .1875rem .5rem .1875rem .375rem;
  border-radius: 999px;
  background: var(--brand-50);
  border: 1px solid var(--brand-200);
  font-size: .75rem; font-weight: 600; color: var(--brand-700);
  max-width: 100%;
}
.dark .keping { background: var(--brand-soft); border-color: var(--brand-700); color: var(--brand-300); }
.keping .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.keping button {
  border: 0; background: none; padding: 0; cursor: pointer;
  color: inherit; opacity: .65; display: flex; line-height: 1;
}
.keping button:hover { opacity: 1; }
.keping-kosong { font-size: .75rem; color: var(--text-fnt); font-style: italic; }

/* ------------------------------------------- panel distribusi kursi */
/* Hemicycle di kiri, calon terpilih di kanan. Sebelumnya sisi kanan menganggur
   padahal calon terpilih adalah hasil paling penting dari seluruh aplikasi —
   dan tadinya hanya bisa ditemukan dengan menelusuri kartu partai di bawah. */
.kursi-panel {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 1024px) {
  .kursi-panel { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 1.75rem; }
}

.terpilih-kepala {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding-bottom: .5rem;
  margin-bottom: .25rem;
  border-bottom: 1px solid var(--line);
}
.terpilih-kepala .j {
  font-size: .6875rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-mut);
}
.terpilih-kepala .n { margin-left: auto; font-size: .6875rem; color: var(--text-fnt); }

.terpilih-baris {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .375rem .25rem;
}
.terpilih-baris + .terpilih-baris { border-top: 1px solid var(--line-2); }

.terpilih-baris .kursi-no {
  flex: none;
  width: 1.5rem; height: 1.5rem;
  border-radius: .4375rem;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: .6875rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.terpilih-baris .isi { flex: 1 1 auto; min-width: 0; }
.terpilih-baris .nm {
  font-size: .875rem; font-weight: 700; color: var(--text-str);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.terpilih-baris .pt {
  font-size: .6875rem; color: var(--text-mut);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.terpilih-baris .sr {
  flex: none; text-align: right;
}
.terpilih-baris .sr .a {
  font-size: .875rem; font-weight: 800; color: var(--text-str);
  font-variant-numeric: tabular-nums; display: block; line-height: 1.2;
}
.terpilih-baris .sr .b { font-size: .625rem; color: var(--text-fnt); }

/* Kursi yang partainya belum punya calon bersuara — tetap ditampilkan agar
   jumlah baris sama dengan jumlah kursi. */
.terpilih-baris.is-kosong .nm { color: var(--text-fnt); font-weight: 600; font-style: italic; }
.terpilih-baris.is-kosong .kursi-no { opacity: .45; }

/* Bilah proporsi kursi di bawah hemicycle. */
.kursi-bar { display: flex; height: .625rem; border-radius: 999px; overflow: hidden; background: var(--line); }
.kursi-bar > span:first-child { border-radius: 999px 0 0 999px; }
.kursi-bar > span:last-child  { border-radius: 0 999px 999px 0; }
.kursi-legenda { display: flex; flex-wrap: wrap; gap: .375rem 1rem; }
.kursi-legenda .item { display: flex; align-items: center; gap: .375rem; font-size: .75rem; }
.dot { width: .625rem; height: .625rem; border-radius: 50%; flex: none; }

/* Lencana nomor partai. */
.no-partai {
  width: 2.25rem; height: 2.25rem; flex: none;
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 800; font-size: .75rem;
}
.no-partai.sm { width: 1.75rem; height: 1.75rem; border-radius: var(--radius-xs); font-size: .6875rem; }

/* Lencana berlogo — dipakai bila paket `public/assets/partai/` punya berkasnya.
   Tiga aturan yang membuatnya terlihat disengaja, bukan tempelan:

   1. Logo SELALU berdiri di atas plat terang, di kedua tema. Logo partai dibuat
      untuk kertas suara putih; ditaruh langsung di kartu mode gelap warnanya
      jadi kotor dan yang berbingkai gelap malah lenyap.
   2. Cincin tipis mengambil warna partai, jadi kaitan ke hemicycle, legenda,
      dan bilah proporsi — yang semuanya cuma punya warna — tidak putus.
   3. Nomor urut tetap menempel. Seluruh alur kerja operator berbasis nomor:
      formulir C1 tersusun menurut nomor urut, bukan menurut logo. */
.lencana-partai {
  position: relative;
  width: 2.25rem; height: 2.25rem; flex: none;
  border-radius: var(--radius-sm);
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--warna-partai, var(--line));
  display: flex; align-items: center; justify-content: center;
}
/* `contain` + jarak tepi: logo partai berbeda-beda rasionya — ada yang 200x80,
   ada yang 2316x3343 — dan tanpa ini yang jangkung akan menempel ke tepi plat. */
.lencana-partai img {
  width: 100%; height: 100%;
  padding: .1875rem;
  object-fit: contain;
  border-radius: inherit;
}
.lencana-partai .nomor {
  position: absolute; right: -.1875rem; bottom: -.1875rem;
  min-width: 1.0625rem; height: 1.0625rem; padding: 0 .1875rem;
  border-radius: 999px;
  background: var(--warna-partai, var(--text-mut));
  color: #fff;
  font-size: .5625rem; font-weight: 800; line-height: 1.0625rem;
  text-align: center; font-variant-numeric: tabular-nums;
}
.lencana-partai.sm { width: 1.75rem; height: 1.75rem; border-radius: var(--radius-xs); }
.lencana-partai.sm img { padding: .125rem; }
.lencana-partai.sm .nomor {
  right: -.25rem; bottom: -.25rem;
  min-width: .9375rem; height: .9375rem;
  font-size: .5rem; line-height: .9375rem;
}

.no-caleg {
  width: 1.5rem; height: 1.5rem; flex: none;
  border-radius: .375rem;
  background: var(--line-2); color: var(--text-mut);
  display: flex; align-items: center; justify-content: center;
  font-size: .6875rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.dark .no-caleg { background: var(--line); }
.no-caleg.is-win { background: var(--ok); color: #fff; }
.no-caleg.is-top { background: var(--warn); color: #fff; }

.baris-caleg { display: flex; align-items: center; gap: .625rem; padding: .5rem .875rem; }
.baris-caleg + .baris-caleg { border-top: 1px solid var(--line-2); }
.baris-caleg.is-win { background: color-mix(in srgb, var(--ok-bg) 40%, transparent); }

.kursi-chip {
  flex: none; text-align: center;
  padding: .25rem .5rem; border-radius: var(--radius-xs);
  background: var(--brand-600); color: #fff;
}
.kursi-chip .n { font-size: .875rem; font-weight: 800; line-height: 1; }
.kursi-chip .l { font-size: .5rem; font-weight: 700; text-transform: uppercase; }

/* ================================================== KARTU INPUT SUARA */
/* Satu kartu per partai, disusun beberapa kolom.
   Nama calon SELALU terbaca di sebelah kotaknya — itu yang membuat operator
   yakin sedang mengisi orang yang benar saat mencocokkan dengan C1 kertas.
   Barisnya dipadatkan supaya tetap jauh lebih pendek daripada satu kolom. */

.kartu-suara-grid {
  display: grid;
  gap: .875rem;
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 700px)  { .kartu-suara-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1180px) { .kartu-suara-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1720px) { .kartu-suara-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.kartu-suara {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s;
}
/* Kartu yang sedang diisi menonjol — pada 18 kartu, posisi mudah hilang. */
.kartu-suara:focus-within { border-color: var(--brand-400); box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / .14); }

.kartu-suara-kepala {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .625rem .75rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.dark .kartu-suara-kepala { background: var(--line-2); }

.kartu-suara-kepala .nama {
  font-weight: 700;
  font-size: .8125rem;
  color: var(--text-str);
  line-height: 1.25;
  min-width: 0;
}

/* Baris suara partai: artinya berbeda dari suara calon, jadi dibedakan tegas. */
.baris-suara.baris-partai {
  background: var(--brand-50);
  border-bottom: 1px solid var(--line);
}
.dark .baris-suara.baris-partai { background: var(--brand-soft); }
.baris-suara.baris-partai .label { font-weight: 700; color: var(--brand-700); }
.dark .baris-suara.baris-partai .label { color: var(--brand-300); }

.baris-suara {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3125rem .75rem;
  min-height: 2.375rem;
}
.baris-suara + .baris-suara:not(.baris-partai) { border-top: 1px solid var(--line-2); }
.baris-suara:focus-within { background: var(--brand-50); }
.dark .baris-suara:focus-within { background: var(--brand-soft); }
.baris-suara.baris-partai:focus-within { background: var(--brand-100); }
.dark .baris-suara.baris-partai:focus-within { background: var(--brand-soft-2); }

.baris-suara .no {
  flex: none;
  width: 1.125rem;
  text-align: center;
  font-size: .6875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-fnt);
}

.baris-suara .lencana-p {
  flex: none;
  width: 1.25rem; height: 1.25rem;
  border-radius: .3125rem;
  background: var(--brand-600);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: .625rem; font-weight: 800;
}

/* Nama dibiarkan membungkus ke baris kedua, tidak dipotong: nama terpotong
   pada surat suara adalah cara paling mudah salah orang. */
.baris-suara .label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .8125rem;
  line-height: 1.3;
  color: var(--text);
  word-break: break-word;
}

.kartu-suara-kaki {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .5rem .75rem;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.dark .kartu-suara-kaki { background: var(--line-2); }
.kartu-suara-kaki .teks { font-size: .75rem; font-weight: 700; color: var(--text-mut); }
.kartu-suara-kaki .nilai {
  font-size: 1rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-str);
}

/* Kotak isian — 2,25rem tetap nyaman disentuh di ponsel. */
.sel-suara {
  flex: none;
  width: 4.25rem;
  height: 2.25rem;
  padding: .125rem .375rem;
  text-align: center;
  font-family: inherit;
  font-size: .875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-str);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: .5rem;
  transition: border-color .12s, box-shadow .12s;
}
.dark .sel-suara { background: var(--surface-2); border-color: var(--line); }

.sel-suara::placeholder { color: var(--text-fnt); font-weight: 400; }
.sel-suara:hover { border-color: var(--brand-400); }
.sel-suara:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / .30);
  background: var(--surface);
}
.dark .sel-suara:focus { background: var(--surface); }

/* Diisi hasil pindai AI dan belum diperiksa manusia. */
.sel-suara.is-ai { border-color: var(--warn); background: var(--warn-bg); color: var(--warn-text); }

/* Penunjuk isian yang sedang disorot, tampil di bilah bawah. */
.petunjuk-sel {
  font-size: .75rem;
  color: var(--text-mut);
  min-height: 1.1rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.petunjuk-sel strong { color: var(--text-str); }

/* --------------------------------------------------- panel periksa semua */
.periksa-grid { display: grid; gap: .5rem; }
@media (min-width: 640px)  { .periksa-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1024px) { .periksa-grid { grid-template-columns: repeat(3, minmax(0,1fr)); } }

.periksa-partai {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: .5rem .625rem;
  background: var(--surface-2);
}
.periksa-partai.kosong { opacity: .55; border-style: dashed; }
.periksa-baris { display: flex; justify-content: space-between; gap: .5rem; font-size: .75rem; }
.periksa-baris + .periksa-baris { margin-top: .125rem; }
.periksa-baris .n { font-variant-numeric: tabular-nums; font-weight: 700; }

/* ---------------------------------------------------- bilah simpan TPS */
/* Menempel di bawah layar supaya total & tombol Simpan selalu terlihat, sejauh
   apa pun operator menggulir daftar partai. */
.bar-simpan {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 30;
  background: color-mix(in srgb, var(--surface) 95%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--line);
  padding: .75rem;
}
@media (min-width: 1024px) { .bar-simpan { left: var(--sidebar-w); padding: .75rem 1.25rem; } }

.bar-simpan-isi {
  display: flex; align-items: center; gap: .75rem;
  max-width: 1600px; margin: 0 auto;
}

/* ================================================ DAFTAR CALEG (kelola) */
/* Satu kartu per partai, berkolom — sepola dengan kartu Input Suara supaya
   operator tidak perlu belajar dua tata letak untuk data yang sama. */

.caleg-grid {
  display: grid;
  gap: .75rem;
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 720px)  { .caleg-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .caleg-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1760px) { .caleg-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.caleg-kartu {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.caleg-kartu-kepala {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .625rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.dark .caleg-kartu-kepala { background: var(--line-2); }
.caleg-kartu-kepala .nm { font-size: .8125rem; font-weight: 700; color: var(--text-str); min-width: 0; }
.caleg-kartu-kepala .mt { font-size: .6875rem; color: var(--text-fnt); white-space: nowrap; margin-left: auto; }

.caleg-baris {
  display: flex;
  align-items: center;
  gap: .4375rem;
  padding: .1875rem .5rem .1875rem .625rem;
  min-height: 2.25rem;
}
.caleg-baris + .caleg-baris { border-top: 1px solid var(--line-2); }
.caleg-baris:hover { background: var(--surface-2); }
.dark .caleg-baris:hover { background: var(--hover); }

.caleg-baris .nourut {
  flex: none;
  width: 1.25rem; height: 1.25rem;
  border-radius: .3125rem;
  background: var(--line-2);
  color: var(--text-mut);
  display: flex; align-items: center; justify-content: center;
  font-size: .625rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.dark .caleg-baris .nourut { background: var(--line); }

.caleg-baris .nama {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .8125rem;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.caleg-baris .jk {
  flex: none;
  font-size: .625rem;
  font-weight: 800;
  color: var(--text-fnt);
  width: .75rem;
  text-align: center;
}

.caleg-baris .suara {
  flex: none;
  font-size: .75rem;
  font-weight: 700;
  color: var(--text-mut);
  font-variant-numeric: tabular-nums;
  min-width: 2.75rem;
  text-align: right;
}

/* Tombol aksi dikecilkan; pada 108 baris, tiap piksel lebar terasa. */
.caleg-baris .aksi { display: flex; gap: .0625rem; flex: none; }
.caleg-baris .aksi .btn-icon { width: 1.625rem; height: 1.625rem; }

/* ============================ DAFTAR CALEG TERDAFTAR (di dalam form) */
/* Muncul begitu partai dipilih, supaya operator tahu siapa yang sudah masuk
   dan nomor mana yang masih bebas — tanpa menutup form dan menengok daftar. */

.terdaftar {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
}

.terdaftar-kepala {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .4375rem .625rem;
  border-bottom: 1px solid var(--line);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-mut);
}

.terdaftar-isi { max-height: 11rem; overflow-y: auto; }

.terdaftar-baris {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3125rem .625rem;
  font-size: .8125rem;
}
.terdaftar-baris + .terdaftar-baris { border-top: 1px solid var(--line-2); }

.terdaftar-baris .no {
  flex: none;
  width: 1.375rem; height: 1.375rem;
  border-radius: .3125rem;
  background: var(--line);
  color: var(--text-mut);
  display: flex; align-items: center; justify-content: center;
  font-size: .6875rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.terdaftar-baris .nm { flex: 1 1 auto; min-width: 0; color: var(--text); word-break: break-word; }

/* Baris yang sedang disunting — supaya jelas mana dirinya sendiri. */
.terdaftar-baris.is-ini { background: var(--brand-50); }
.dark .terdaftar-baris.is-ini { background: var(--brand-soft); }
.terdaftar-baris.is-ini .no { background: var(--brand-600); color: #fff; }
.terdaftar-baris.is-ini .nm { font-weight: 700; color: var(--text-str); }

/* Baris yang nomornya sedang diketik di form — peringatan bentrok. */
.terdaftar-baris.is-bentrok { background: var(--danger-bg); }
.terdaftar-baris.is-bentrok .no { background: var(--danger); color: #fff; }
.terdaftar-baris.is-bentrok .nm { color: var(--danger-text); font-weight: 700; }

.terdaftar-kosong { padding: .75rem .625rem; font-size: .75rem; color: var(--text-fnt); }

.peringatan-nomor {
  display: none;
  margin-top: .25rem;
  font-size: .6875rem;
  font-weight: 700;
  color: var(--danger);
}
.peringatan-nomor.tampil { display: block; }

/* ---------------------------------------------------------------- modal */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: flex-end; justify-content: center;
  padding: 0;
}
@media (min-width: 640px) { .modal-backdrop { align-items: center; padding: 1rem; } }

.modal-veil { position: absolute; inset: 0; background: var(--veil); backdrop-filter: blur(2px); }

.modal {
  position: relative;
  width: 100%; max-width: 32rem;
  max-height: 92vh;
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-lg);
  animation: pop .16s ease-out;
}
@media (min-width: 640px) { .modal { border-radius: var(--radius); } }
@keyframes pop { from { transform: scale(.96); opacity: 0 } to { transform: none; opacity: 1 } }

.modal-sm { max-width: 24rem; }
.modal-lg { max-width: 42rem; }

.modal-head {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: 1rem 1.25rem; border-bottom: 1px solid var(--line); flex: none;
}
.modal-body { padding: 1rem 1.25rem; overflow-y: auto; flex: 1 1 auto; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: .5rem;
  padding: 1rem 1.25rem; border-top: 1px solid var(--line); flex: none;
}

/* ---------------------------------------------------------------- toast */
#toast-area {
  position: fixed; z-index: 60;
  bottom: 1rem; right: 1rem; left: 1rem;
  display: flex; flex-direction: column; gap: .5rem;
  align-items: stretch; pointer-events: none;
}
@media (min-width: 640px) { #toast-area { left: auto; align-items: flex-end; } }

.toast {
  pointer-events: auto; cursor: pointer;
  display: flex; align-items: flex-start; gap: .625rem;
  max-width: 24rem; padding: .75rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid #21384f;
  background: var(--brand-950); color: #eaf1f8;
  font-size: .875rem; font-weight: 500;
  box-shadow: var(--shadow-lg);
  animation: fade-in .18s ease-out;
}
.toast.is-error { background: var(--danger); border-color: var(--danger-line); }
@keyframes fade-in { from { opacity: 0; transform: translateY(4px) } to { opacity: 1; transform: none } }

/* ---------------------------------------------------------------- flash */
.flash {
  display: flex; align-items: flex-start; gap: .625rem;
  padding: .75rem 1rem; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-size: .875rem; margin-bottom: 1rem;
}
.flash-ok    { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-text); }
.flash-error { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-text); }
.flash-warn  { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-text); }

/* --------------------------------------------------------------- kosong */
.empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 3.5rem 1rem; }
.empty-icon {
  width: 3.5rem; height: 3.5rem; border-radius: var(--radius);
  background: var(--line-2); color: var(--text-fnt);
  display: flex; align-items: center; justify-content: center; margin-bottom: .75rem;
}
.dark .empty-icon { background: var(--line); }
.empty-title { font-weight: 700; color: var(--text); }
.empty-msg { font-size: .875rem; color: var(--text-mut); margin-top: .25rem; max-width: 26rem; }

/* --------------------------------------------------------------- pager */
.pager { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .75rem 1rem; border-top: 1px solid var(--line); }
.pager-info { font-size: .75rem; color: var(--text-mut); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ page head */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: .75rem; margin-bottom: 1.25rem; }
.page-head-l { display: flex; align-items: flex-start; gap: .75rem; min-width: 0; }
.page-icon {
  width: 2.5rem; height: 2.5rem; flex: none;
  border-radius: var(--radius-sm);
  background: var(--brand-600); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 2px 0 rgb(var(--brand-rgb) / .22);
}
.page-sub { font-size: .8125rem; color: var(--text-mut); margin-top: .125rem; }
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }

/* ------------------------------------------------------- overlay pindai */
.scan-overlay { position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.scan-veil { position: absolute; inset: 0; background: var(--veil); backdrop-filter: blur(2px); }
.scan-box { position: relative; text-align: center; max-width: 20rem; }
.scan-frame {
  position: relative; margin: 0 auto 1.25rem;
  width: 7rem; height: 9rem;
  border: 2px solid rgb(var(--brand-rgb) / .70);
  border-radius: var(--radius-sm);
  background: rgb(10 16 23 / .72);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-fnt);
}
.scan-line {
  position: absolute; left: 0; right: 0; height: 2px;
  background: var(--brand-400);
  box-shadow: 0 0 12px 2px rgb(var(--brand-rgb) / .85);
  animation: sweep 1.6s ease-in-out infinite alternate;
}
@keyframes sweep { from { top: 0 } to { top: 100% } }

/* =================================================================== TATA */

.grid { display: grid; gap: .75rem; }
/* Item grid bawaannya min-width:auto, jadi kartu berisi tabel/daftar panjang
   melebar melewati layar di ponsel — di sana .grid hanya punya satu kolom
   implisit yang ikut melar. Nol-kan supaya isinya yang menyusut. */
.grid > * { min-width: 0; }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width: 640px)  { .sm-grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1024px) { .lg-grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
                              .lg-grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
                              .lg-grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); } }
@media (min-width: 1536px) { .xl-grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
                              .xl-grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); } }

.row { display: flex; align-items: center; gap: .75rem; }
.row-top { display: flex; align-items: flex-start; gap: .75rem; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1 1 auto; min-width: 0; }
.none { flex: none; }

.stack > * + * { margin-top: .75rem; }
.stack-sm > * + * { margin-top: .5rem; }
.stack-lg > * + * { margin-top: 1.25rem; }

.mt-1 { margin-top: .25rem; }  .mt-2 { margin-top: .5rem; }
.mt-3 { margin-top: .75rem; }  .mt-4 { margin-top: 1rem; }
.mb-2 { margin-bottom: .5rem; } .mb-3 { margin-bottom: .75rem; } .mb-4 { margin-bottom: 1rem; }

.t-xs { font-size: .6875rem; }
.t-sm { font-size: .75rem; }
.t-md { font-size: .875rem; }
.t-lg { font-size: 1.125rem; }
.t-xl { font-size: 1.25rem; }
.t-mut { color: var(--text-mut); }
.t-fnt { color: var(--text-fnt); }
.t-str { color: var(--text-str); }
.t-bold { font-weight: 700; }
.t-black { font-weight: 800; }
.t-right { text-align: right; }
.t-center { text-align: center; }

/* ================================================================= MASUK */
.login-wrap {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.login-box { width: 100%; max-width: 22rem; }
.login-logo {
  width: 3.5rem; height: 3.5rem; margin: 0 auto;
  border-radius: var(--radius);
  background: var(--brand-600); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 12px 24px -8px rgb(var(--brand-rgb) / .40);
}

/* ============================================================ RESPONSIF */
@media (max-width: 1023px) {
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; z-index: 50;
    height: 100dvh;
    transform: translateX(-100%);
    transition: transform .2s ease;
    box-shadow: var(--shadow-lg);
  }
  .sidebar.is-open { transform: none; }
  .lg-only { display: none !important; }
}
@media (min-width: 1024px) {
  .mobile-only { display: none !important; }
}
