/* ============================================================
   theme.css — METEOR
   Dua tema terpisah:
     [data-theme="admin"]  → panel internal (biru meteor + bara)
     [data-theme="publik"] → halaman bayar & halaman lokasi
   Pakai: <body data-theme="admin"> atau <body data-theme="publik">

   Mode malam: <html data-mode="gelap"> — hanya untuk tema internal.
   Halaman pembeli sengaja TIDAK ikut; tampilan yang dilihat pelanggan
   dijaga tetap satu rupa.

   data-mode dipasang skrip kecil di <head> sebelum halaman digambar,
   dan sudah berupa hasil akhir — pilihan "ikut sistem" diterjemahkan
   di JS. Jadi CSS cukup punya satu jalur malam, tanpa blok kembar
   untuk prefers-color-scheme.

   WARNA DITURUNKAN DARI LOGO: biru meteor untuk warna utama, bara
   oranye dari inti api untuk aksen, netral sejuk supaya senada dengan
   birunya. Setiap pasangan teks/latar di file ini sudah diukur dan
   lulus 4,5:1 — termasuk di permukaan kartu, bukan cuma di background.
   ============================================================ */

/* ---------- 1. PALET MENTAH ---------- */
:root {
  /* Biru meteor — dari ekor dan wordmark logo */
  --azur-50:  #EEF5FF;
  --azur-100: #D9E8FF;
  --azur-200: #B6D2FF;
  --azur-300: #85B4FB;
  --azur-400: #4F91F5;
  --azur-500: #2472E0;  /* warna utama brand */
  --azur-600: #1A5CC0;
  --azur-700: #16499A;
  --azur-800: #143A78;
  --azur-900: #102A54;

  /* Bara — inti api di logo. Dipakai sebagai aksen kedua, bukan
     warna utama: porsinya kecil supaya tetap terasa "panas". */
  --bara-50:  #FFF6EC;
  --bara-100: #FFE8CE;
  --bara-200: #FFD09E;
  --bara-300: #FFB05F;
  --bara-400: #FB8F2A;
  --bara-500: #E8730D;
  --bara-600: #C25A06;
  --bara-700: #96450A;
  --bara-800: #6E340C;
  --bara-900: #47220A;

  /* Netral sejuk — sengaja kebiruan, bukan abu hangat, supaya
     nyambung sama azur dan tidak terlihat kotor di sebelahnya. */
  --sabak-25:  #FBFCFD;
  --sabak-50:  #F5F7FA;
  --sabak-100: #EDF1F6;  /* background aplikasi */
  --sabak-200: #DDE3EC;
  --sabak-300: #C4CDDA;
  --sabak-400: #9AA6B8;
  --sabak-500: #616B7E;  /* teks redup — 4,7:1 bahkan di latar paling muda */
  --sabak-600: #52606F;
  --sabak-700: #3A4655;
  --sabak-800: #232C38;
  --sabak-900: #131A23;

  /* Palet malam — netral sejuk yang sama, diturunkan terangnya.
     Sengaja bukan hitam pekat: di layar HP murah teks putih di atas
     #000 terlihat "bergetar", dan bayangan kartu hilang sama sekali. */
  --malam-900: #0D1219;  /* background aplikasi */
  --malam-800: #151C26;  /* permukaan kartu */
  --malam-700: #1D2733;  /* permukaan alternatif */
  --malam-600: #2A3646;  /* garis tepi */
  --malam-500: #3B4A5E;  /* garis tepi yang perlu lebih terlihat */
  --malam-100: #E8EDF4;  /* teks utama */
  --malam-200: #A9B6C7;  /* teks sekunder — 7,3:1 di permukaan paling muda */
  --malam-300: #8593A6;  /* teks redup — 4,8:1 di permukaan paling muda */

  /* Azur & bara di atas latar malam. Nada aslinya terlalu pekat di
     sana. Kedua nada ini terbaca DUA ARAH: sebagai warna teks di atas
     latar malam, dan sebagai latar tombol dengan tulisan pekat di
     atasnya — jadi satu token cukup untuk kedua peran. */
  --azur-malam:        #7FB2FF;
  --azur-malam-hover:  #9AC2FF;
  --azur-malam-press:  #6BA1F0;
  --azur-malam-soft:   #14243A;
  --azur-malam-border: #24405F;

  --bara-malam:        #FFA654;
  --bara-malam-soft:   #33200C;
  --bara-malam-border: #5A3818;

  /* Tulisan pekat di atas isian terang mode malam. */
  --tinta-malam: #0B1220;

  /* Warna status titik — dipakai di dua tema, harus konsisten.
     Nilai ini dipakai sebagai TEKS, jadi semuanya sudah diukur di
     atas permukaan kartu maupun permukaan alternatif. */
  --st-draft:       #5F6E85;
  --st-tersedia:    #BE185D;
  /* DIPESAN oranye dan TERJUAL merah (2026-09-15), ikut penanda peta.
     Nadanya tetap tingkat -700 supaya teks lencana terbaca di kartu putih. */
  --st-dipesan:     #C2410C;
  --st-terjual:     #B91C1C;
  /* DIAMBIL kini abu (2026-09-03). Nadanya tidak seterang penanda petanya:
     ini dipakai sebagai teks lencana, jadi berhenti di abu netral 4,8:1 —
     abu muda seperti di peta tidak akan terbaca di atas kartu putih. */
  --st-diambil:     #6B7280;
  --st-hilang:      #6D28D9;
  --st-kedaluwarsa: #71685F;
  /* Warna status bisa diganti dari Setelan. Token di atas cuma berlaku selama
     warnanya bawaan; warna pilihan sendiri diturunkan jadi warna teks lewat
     color-mix(pilihan 70%, --campur-teks) di app.js — digelapkan di sini,
     diterangkan di blok malam. */
  --campur-teks:    #000;

  /* Radius. Jauh lebih bulat dari sebelumnya — ini yang paling
     terasa "baru" tanpa mengubah tata letak apa pun. */
  --r-xs:   6px;
  --r-sm:   10px;
  --r-md:   16px;
  --r-lg:   22px;
  --r-xl:   28px;
  --r-full: 999px;

  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;
  --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-8: 48px;

  /* ---- MOTION ----
     Satu set kurva dipakai seluruh aplikasi supaya gerakannya terasa
     berasal dari satu benda. --ease-tegas melambat tajam di ujung:
     itu yang bikin panel terasa "mendarat", bukan sekadar bergeser. */
  --ease-tegas:   cubic-bezier(.16, .84, .28, 1);
  --ease-standar: cubic-bezier(.4, 0, .2, 1);
  --ease-masuk:   cubic-bezier(.55, 0, 1, .45);
  --ease-keluar:  cubic-bezier(0, .55, .45, 1);
  /* Pantulan kecil untuk benda yang muncul: tombol, lencana, sheet.
     Nilai kembarnya di --ease-tegas dipakai kalau browser lawas tidak
     mengenal linear() — cascade otomatis memilih yang dia paham. */
  --ease-pegas: cubic-bezier(.34, 1.56, .64, 1);

  --dur-1: 120ms;   /* umpan balik sentuh */
  --dur-2: 200ms;   /* ganti warna, fade kecil */
  --dur-3: 320ms;   /* pindah halaman, sheet */
  --dur-4: 480ms;   /* benda besar, orkestrasi bertingkat */
}

/* ---------- 2. TEMA INTERNAL ---------- */
[data-theme="admin"] {
  --bg:          var(--sabak-100);
  --surface:     #FFFFFF;
  --surface-alt: var(--sabak-50);
  --surface-2:   var(--sabak-25);
  --border:      var(--sabak-200);
  --border-kuat: var(--sabak-300);
  --divider:     var(--sabak-200);

  --text:    var(--sabak-900);
  --text-2:  var(--sabak-600);
  --text-3:  var(--sabak-500);

  --brand:        var(--azur-500);
  --brand-hover:  var(--azur-600);
  --brand-press:  var(--azur-700);
  --brand-soft:   var(--azur-50);
  --brand-border: var(--azur-200);
  --brand-teks:   var(--azur-600);  /* azur sebagai TEKS di latar muda */
  --on-brand:     #FFFFFF;

  /* Aksen bara. Isiannya terang, jadi tulisan di atasnya pekat —
     putih di atas bara cuma 2,6:1. */
  --aksen:        var(--bara-500);
  --aksen-hover:  var(--bara-400);
  --aksen-press:  var(--bara-600);
  --aksen-soft:   #FFF1E0;
  --aksen-border: var(--bara-200);
  --aksen-teks:   var(--bara-700);  /* bara sebagai TEKS di latar muda */
  --on-aksen:     #2A1503;

  --ok:    #15803D;
  --warn:  #B45309;
  --error: #B91C1C;
  --info:  var(--azur-600);

  /* Latar lembut untuk pil status (naik/turun, peringatan, hitung
     mundur). Pasangan teks/latarnya sudah diukur satu per satu. */
  --ok-soft:    #E8F7EE;
  --warn-soft:  #FEF4E2;
  --error-soft: #FDECEC;
  --info-soft:  #E8F1FE;

  /* Tulisan di atas isian --ok / --error (tombol sukses, angka
     notifikasi). Di mode malam warna status jadi terang, jadi
     tulisannya berbalik menjadi pekat. */
  --on-status: #FFFFFF;

  /* Gelembung pratinjau balasan WhatsApp — meniru warna asli
     aplikasinya, jadi admin tahu persis bentuk yang diterima pembeli. */
  --wa-bubble: #DCF8C6;
  --wa-teks:   #111111;

  /* ── Layar Chat (meniru WhatsApp) ──────────────────────────────
     Angkanya TETAP, bukan turunan --surface/--brand: yang dicari di
     layar ini adalah kontras gelembung DITERIMA vs DIKIRIM, dan itu
     harus sama di tema 1/2/3 supaya admin tidak pernah salah baca
     siapa yang bicara. Nadanya diambil dari WhatsApp 2026.
     Pasangan teks/latarnya: #111B21 di atas #FFFFFF = 16,1:1,
     #111B21 di atas #D9FDD3 = 14,6:1 — dua-duanya lulus jauh. */
  --chat-latar:       #EFE7DE;   /* dinding percakapan */
  --chat-pola:        rgba(17, 27, 33, .045);
  --chat-bar:         #F0F2F5;   /* kepala & kotak tulis */
  --chat-bar-garis:   #D1D7DB;
  --chat-masuk-bg:    #FFFFFF;
  --chat-masuk-teks:  #111B21;
  --chat-keluar-bg:   #D9FDD3;
  --chat-keluar-teks: #111B21;
  --chat-bot-bg:      #FFF4D4;   /* balasan robot — bukan ketikan orang */
  --chat-bot-teks:    #3B2F13;
  --chat-meta:        #5E6E78;   /* jam & nama pengirim di kaki — 4,8:1 di atas
                                    gelembung putih maupun hijau kirim */
  --chat-centang:     #4A8F85;
  --chat-pemisah-bg:  rgba(255, 255, 255, .92);
  --chat-pemisah-tek: #54656F;
  --chat-ekor-bayang: rgba(11, 20, 26, .13);
  --chat-tulis-bg:    #FFFFFF;
  --chat-kirim:       #008069;   /* putih di atasnya 4,6:1 */
  --chat-kirim-teks:  #FFFFFF;
  --chat-lencana:     #25D366;
  --chat-lencana-tek: #0B141A;

  --font-display: 'Archivo', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, sans-serif;
  --font-angka:   'Inter', system-ui, sans-serif;

  /* Bayangan berjenjang, semuanya dinaungi biru tua supaya tidak
     terlihat seperti noda abu di atas latar kebiruan. */
  --shadow-xs: 0 1px 2px rgba(16, 42, 84, .06);
  --shadow-sm: 0 1px 3px rgba(16, 42, 84, .08), 0 1px 2px rgba(16, 42, 84, .04);
  --shadow-md: 0 4px 12px rgba(16, 42, 84, .10), 0 2px 4px rgba(16, 42, 84, .05);
  --shadow-lg: 0 12px 28px rgba(16, 42, 84, .14), 0 4px 8px rgba(16, 42, 84, .06);
  --shadow-xl: 0 24px 56px rgba(16, 42, 84, .20), 0 8px 16px rgba(16, 42, 84, .08);
  --shadow-brand: 0 8px 24px rgba(36, 114, 224, .30);

  /* Lapisan kaca untuk bilah atas & nav mengambang. */
  --kaca:        rgba(255, 255, 255, .78);
  --kaca-border: rgba(255, 255, 255, .65);
}

/* ---------- 2b. TEMA INTERNAL — MODE MALAM ---------- */
/* Kekhususan selektor ini (0,2,0) mengalahkan [data-theme="admin"]
   (0,1,0), jadi cukup menimpa token; tidak ada satu pun komponen yang
   perlu ditulis ulang di sini. */
[data-mode="gelap"] [data-theme="admin"] {
  --bg:          var(--malam-900);
  --surface:     var(--malam-800);
  --surface-alt: var(--malam-700);
  --surface-2:   var(--malam-700);
  --border:      var(--malam-600);
  --border-kuat: var(--malam-500);
  --divider:     var(--malam-600);

  --text:   var(--malam-100);
  --text-2: var(--malam-200);
  --text-3: var(--malam-300);

  --brand:        var(--azur-malam);
  --brand-hover:  var(--azur-malam-hover);
  --brand-press:  var(--azur-malam-press);
  --brand-soft:   var(--azur-malam-soft);
  --brand-border: var(--azur-malam-border);
  --brand-teks:   var(--azur-malam);
  --on-brand:     var(--tinta-malam);

  --aksen:        var(--bara-malam);
  --aksen-hover:  #FFBC7C;
  --aksen-press:  #F09242;
  --aksen-soft:   var(--bara-malam-soft);
  --aksen-border: var(--bara-malam-border);
  --aksen-teks:   var(--bara-malam);
  --on-aksen:     var(--tinta-malam);

  --ok:    #4ADE80;
  --warn:  #FBBF24;
  --error: #FF8A80;
  --info:  var(--azur-malam);

  --ok-soft:    #0E2A1A;
  --warn-soft:  #2E2410;
  --error-soft: #31191A;
  --info-soft:  #111F33;
  --on-status:  var(--tinta-malam);

  --wa-bubble: #04594A;
  --wa-teks:   #E7F0EA;

  /* Layar Chat — mode malam WhatsApp. #E9EDEF di atas #202C33 = 11,6:1,
     di atas #005C4B = 7,4:1. */
  --chat-latar:       #0B141A;
  --chat-pola:        rgba(255, 255, 255, .035);
  --chat-bar:         #202C33;
  --chat-bar-garis:   #2A3942;
  --chat-masuk-bg:    #202C33;
  --chat-masuk-teks:  #E9EDEF;
  --chat-keluar-bg:   #005C4B;
  --chat-keluar-teks: #E9EDEF;
  --chat-bot-bg:      #2B2518;
  --chat-bot-teks:    #F3E6CB;
  --chat-meta:        #C2D0D6;   /* 5,1:1 di atas #005C4B */
  --chat-centang:     #8FD2C8;
  --chat-pemisah-bg:  #182229;
  --chat-pemisah-tek: #9EB0BA;
  --chat-ekor-bayang: rgba(0, 0, 0, .35);
  --chat-tulis-bg:    #2A3942;
  --chat-kirim:       #00A884;
  --chat-kirim-teks:  #0B141A;   /* ikon pekat — putih di atas #00A884 cuma 2,9:1 */
  --chat-lencana:     #00A884;
  --chat-lencana-tek: #0B141A;

  /* Yang memisahkan lapisan di mode malam adalah beda terang
     permukaan, bukan bayangan. Bayangan tetap ada, hanya untuk
     elemen yang benar-benar melayang. */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .40);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, .45);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, .55);
  --shadow-lg: 0 14px 34px rgba(0, 0, 0, .62);
  --shadow-xl: 0 26px 60px rgba(0, 0, 0, .70);
  --shadow-brand: 0 8px 24px rgba(0, 0, 0, .55);

  --kaca:        rgba(21, 28, 38, .80);
  --kaca-border: rgba(255, 255, 255, .07);

  /* Status dinaikkan terangnya — nada aslinya praktis tak terbaca di
     atas latar malam. Warna penanda di peta tidak diatur di sini:
     itu milik STATUS_COLORS di app.js dan duduk di atas ubin peta. */
  --st-draft:       #9FB0C4;
  --st-tersedia:    #F472B6;
  --st-dipesan:     #FB923C;
  --st-terjual:     #F87171;
  --st-diambil:     #CBD5E1;
  --st-hilang:      #C4A0FF;
  --st-kedaluwarsa: #B0A697;
  --campur-teks:    #FFF;
}

/* ---------- 3. TEMA PUBLIK ---------- */
/* Halaman pembeli. Biru yang sama dengan logo supaya satu merek, tapi
   lebih terang dan tanpa lapis kaca — dibuka sekali lewat tautan
   WhatsApp, jadi yang dikejar keterbacaan langsung, bukan kedalaman. */
[data-theme="publik"] {
  --bg:          var(--sabak-100);
  --surface:     #FFFFFF;
  --surface-alt: var(--sabak-50);
  --surface-2:   var(--sabak-25);
  --border:      var(--sabak-200);
  --border-kuat: var(--sabak-300);
  --divider:     var(--sabak-200);

  --text:   var(--sabak-900);
  --text-2: var(--sabak-600);
  --text-3: var(--sabak-500);

  --brand:        var(--azur-500);
  --brand-hover:  var(--azur-600);
  --brand-press:  var(--azur-700);
  --brand-soft:   var(--azur-50);
  --brand-border: var(--azur-200);
  --brand-teks:   var(--azur-600);
  --on-brand:     #FFFFFF;

  --aksen:        var(--bara-500);
  --aksen-hover:  var(--bara-400);
  --aksen-press:  var(--bara-600);
  --aksen-soft:   #FFF1E0;
  --aksen-border: var(--bara-200);
  --aksen-teks:   var(--bara-700);
  --on-aksen:     #2A1503;

  --ok:    #15803D;
  --warn:  #B45309;
  --error: #B91C1C;
  --info:  var(--azur-600);

  --ok-soft:    #E8F7EE;
  --warn-soft:  #FEF4E2;
  --error-soft: #FDECEC;
  --info-soft:  #E8F1FE;
  --on-status:  #FFFFFF;

  --wa-bubble: #DCF8C6;
  --wa-teks:   #111111;

  /* Font sistem: nol unduhan, penting buat sinyal tipis di lapangan */
  --font-display: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                  Helvetica, Arial, sans-serif;
  --font-body:    var(--font-display);
  --font-angka:   var(--font-display);

  --shadow-xs: 0 1px 2px rgba(16, 42, 84, .06);
  --shadow-sm: 0 1px 3px rgba(16, 42, 84, .09), 0 1px 2px rgba(16, 42, 84, .05);
  --shadow-md: 0 4px 14px rgba(16, 42, 84, .12);
  --shadow-lg: 0 12px 30px rgba(16, 42, 84, .15);
  --shadow-xl: 0 24px 56px rgba(16, 42, 84, .20);
  --shadow-brand: 0 8px 24px rgba(36, 114, 224, .28);

  --kaca:        rgba(255, 255, 255, .82);
  --kaca-border: rgba(255, 255, 255, .70);
}

/* ---------- 4. DASAR ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* Memberi tahu browser warna dasar halaman, supaya kolom isian bawaan,
   menu <select>, dan batang gulir ikut menyesuaikan — bagian yang tidak
   bisa disentuh CSS kita. */
[data-mode="gelap"]  { color-scheme: dark; }
[data-mode="terang"] { color-scheme: light; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 var(--sp-3);
}
h1 { font-size: 1.65rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }

a { color: var(--brand-teks); }

/* Angka di panel wajib rata — jangan sampai kolom rupiah goyang saat
   isinya berubah tiap beberapa detik. */
.angka, td, .stat-nilai {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ---------- 5. KOMPONEN ---------- */
.kartu {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  box-shadow: var(--shadow-sm);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 11px var(--sp-4);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font: inherit;
  font-weight: 650;
  letter-spacing: -0.01em;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--dur-2) var(--ease-standar),
              transform var(--dur-1) var(--ease-tegas),
              box-shadow var(--dur-2) var(--ease-standar);
}
/* Tekanan jari dibalas seketika. 0,97 cukup terasa tanpa bikin tata
   letak sekitarnya ikut bergoyang. */
.btn:active { transform: scale(.97); }

.btn-utama {
  background: var(--brand);
  color: var(--on-brand);
  box-shadow: var(--shadow-xs);
}
.btn-utama:hover  { background: var(--brand-hover); }
.btn-utama:active { background: var(--brand-press); }

.btn-kedua {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border-kuat);
}
.btn-kedua:hover  { background: var(--surface-alt); }
.btn-kedua:active { background: var(--border); }

.btn-aksen {
  background: var(--aksen);
  color: var(--on-aksen);
  box-shadow: var(--shadow-xs);
}
.btn-aksen:hover  { background: var(--aksen-hover); }
.btn-aksen:active { background: var(--aksen-press); }

.btn-blok { width: 100%; padding: 14px var(--sp-4); font-size: 1.02rem; }

/* Tombol sekunder yang menempel di dalam baris atau daftar — dipakai tombol
   "Izin" di tiap baris akun dan tombol preset di sheet izin. Tanpa ini
   keduanya setinggi tombol utama dan barisnya jadi berdesakan. */
.btn-kecil {
  padding: 6px var(--sp-3);
  font-size: .8rem;
  font-weight: 600;
  border-color: var(--border);
  background: var(--surface-2, transparent);
  color: var(--text-2, inherit);
}

.btn:disabled { opacity: .5; pointer-events: none; }

.btn:focus-visible,
.input:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.input {
  width: 100%;
  padding: 11px var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border-kuat);
  border-radius: var(--r-sm);
  font: inherit;
  color: var(--text);
  transition: border-color var(--dur-2) var(--ease-standar),
              box-shadow var(--dur-2) var(--ease-standar);
}
.input::placeholder { color: var(--text-3); }
.input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
  outline: none;
}

/* Badge status titik */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: var(--r-full);
  font-size: .76rem;
  font-weight: 650;
  letter-spacing: .01em;
  background: var(--surface-alt);
  color: var(--text-2);
  border: 1px solid var(--border);
}
.badge::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.badge[data-status="DRAFT"]       { color: var(--st-draft); }
/* TERSEDIA diwarnai per operator (2026-09-15), jadi satu warna teks tidak bisa
   mewakili semuanya — dan teks kuning di atas kartu putih tidak terbaca. Teksnya
   netral; cuma titik kecilnya yang memakai warna operator lewat --warna-titik,
   diisi app.js per baris. Tanpa variabel itu jatuh ke --st-tersedia. */
.badge[data-status="TERSEDIA"]    { color: var(--text); }
.badge[data-status="TERSEDIA"]::before { background: var(--warna-titik, var(--st-tersedia)); }
.badge[data-status="DIPESAN"]     { color: var(--st-dipesan); }
.badge[data-status="TERJUAL"]     { color: var(--st-terjual); }
.badge[data-status="DIAMBIL"]     { color: var(--st-diambil); }
.badge[data-status="HILANG"]      { color: var(--st-hilang); }
.badge[data-status="KEDALUWARSA"] { color: var(--st-kedaluwarsa); }

/* Titik TERSEDIA di PETA memancar seperti sonar: dua cincin sewarna status
   yang lahir di tepi titik, melebar, lalu habis. Kupon yang masih bisa dijual
   harus ketemu mata duluan di antara puluhan titik lain; status yang lain
   diam supaya yang bergerak tetap berarti sesuatu.

   Kenapa cincin, bukan halo yang meredup seperti sebelumnya: halo cuma
   membesarkan titiknya sekejap, sedangkan gelombang yang berjalan keluar
   punya ARAH — mata menangkapnya dari sudut layar tanpa harus sedang menatap
   ke situ. Itu bedanya "berkedip" dan "memanggil".

   Yang dianimasi cuma transform dan opacity, dua-duanya urusan compositor —
   tidak ada pengecatan ulang tiap frame walau titiknya jadi ratusan, dan itu
   penting karena animasi ini menumpang di atas Leaflet yang sudah sibuk
   sendiri waktu petanya digeser. Menganimasi width/inset akan memaksa layout
   ulang seluruh lapisan penanda tiap frame.

   Cincinnya dua, berangkat berselang setengah siklus, supaya ada denyut tiap
   1,3 detik tanpa perlu mempercepat animasinya sendiri.

   Rem prefers-reduced-motion ada di bagian AKSESIBILITAS di bawah dan berlaku
   ke semua keyframe, jadi tidak perlu ditulis ulang di sini. */
.dot-radar {
  position: relative;
  /* Bayangan dasar + cahaya sewarna status. Ditulis di sini, BUKAN di style
     inline penanda, karena currentColor cuma bisa dibaca dari CSS — dan
     warnanya sendiri memang sudah dititipkan lewat `color` inline. Karena
     inline tidak lagi menyebut box-shadow, aturan ini yang berlaku. */
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3), 0 0 9px -1px currentColor;
}

/* inset -2.5px = persis setebal cincin putih penanda, jadi gelombangnya
   lahir menempel di tepi luar titik, bukan melompat dari tengahnya. */
.dot-radar::before,
.dot-radar::after {
  content: "";
  position: absolute;
  inset: -2.5px;
  border-radius: 50%;
  border: 2px solid currentColor;
  opacity: 0;
  pointer-events: none;
  animation: radar-sebar 2.6s cubic-bezier(.15, .6, .3, 1) infinite;
  animation-delay: var(--fase, 0s);
}

/* Setengah siklus di belakang gelombang pertama. Delaynya dikurangi, bukan
   ditambah: --fase selalu negatif, jadi hasilnya tetap negatif dan gelombang
   kedua langsung tampil di tengah siklus — kalau ditambah, dia baru muncul
   1,3 detik setelah peta digambar. */
.dot-radar::after { animation-delay: calc(var(--fase, 0s) - 1.3s); }

/* TERSEDIA lewat 3x24 jam: gelombangnya dua kali lebih lambat (5,2 detik).
   Warnanya tetap warna produk -- sejak 6 Okt 2026 tanda basi ada di gerak,
   bukan di warna. app.js menghitung --fase dari periode 5,2 detik ini. */
.dot-radar.dot-lambat::before,
.dot-radar.dot-lambat::after { animation-duration: 5.2s; }
.dot-radar.dot-lambat::after { animation-delay: calc(var(--fase, 0s) - 2.6s); }

@keyframes radar-sebar {
  0%   { transform: scale(1);   opacity: .9; }
  70%  { opacity: .15; }
  100% { transform: scale(3.4); opacity: 0; }
}

/* Daftar titik dan lencana status: TERSEDIA berdenyut pelan pink -> putih.
   Kupon yang masih bisa dijual harus langsung ketemu mata di antara puluhan
   baris lain; status yang lain diam supaya yang berkedip tetap berarti
   sesuatu.

   Dipakai di daftar titik dan sheet detail, BUKAN lagi di peta — peta punya
   .dot-radar di atas. Di dua tempat itu titiknya duduk rapat dengan teks di
   sebelahnya, dan gelombang yang melebar 3,4 kali akan menabrak kode titik.

   Yang dianimasi HANYA opacity sebuah halo sewarna di belakang titiknya --
   lingkaran yang melebar 5px keluar, meniru .titik-dot::after di app.css yang
   sudah lebih dulu ada. Berganti warna pink-putih terlalu ramai. Opacity
   ditangani compositor, jadi tidak ada pengecatan ulang tiap frame.

   Rem prefers-reduced-motion ada di bagian AKSESIBILITAS di bawah dan berlaku
   ke semua keyframe, jadi tidak perlu ditulis ulang di sini. */
.dot-kedip { position: relative; }
.dot-kedip::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  background: inherit;
  opacity: 0;
  pointer-events: none;
  animation: kedip-tersedia 2.6s ease-in-out infinite;
  animation-delay: var(--fase, 0s);
}
@keyframes kedip-tersedia {
  0%, 100% { opacity: 0; }
  50%      { opacity: 1; }
}

/* TERSEDIA lewat 3x24 jam: halonya oranye, titiknya tetap warna operator —
   padanan gelombang oranye di peta. app.js menitipkan oranyenya lewat `color`
   inline. Dua kelas sekaligus supaya menang atas .titik-dot::after di app.css
   yang dimuat belakangan dan juga menulis `background: inherit`.

   Halonya CINCIN (box-shadow di luar), bukan lingkaran berisi: pseudo-element
   dilukis DI ATAS latar titiknya sendiri, jadi lingkaran oranye pekat akan
   menutup warna operator tiap puncak denyut. Tebal cincin 5px = inset -5px
   halo biasa, jadi ukuran luarnya sama persis. */
.dot-kedip.dot-basi::after {
  inset: 0;
  background: none;
  box-shadow: 0 0 0 5px currentColor;
  /* Sama dengan .dot-lambat di peta: basi = denyut dua kali lebih lambat. */
  animation-duration: 5.2s;
}

/* Badge tidak bisa pakai halo: titiknya sendiri sudah ::before, dan sebuah
   pseudo-element tidak bisa punya pseudo-element lagi. Jadi di sini titiknya
   yang meredup-menyala. Tetap opacity, tetap tidak ada ganti warna. */
.badge[data-status="TERSEDIA"]::before {
  animation: kedip-titik-badge 2.6s ease-in-out infinite;
  animation-delay: var(--fase, 0s);
}
@keyframes kedip-titik-badge {
  0%, 100% { opacity: 1; }
  50%      { opacity: .3; }
}

/* Nominal transfer — elemen paling penting di halaman bayar.
   Sengaja dibikin paling menonjol di seluruh halaman. */
.nominal-box {
  position: relative;
  overflow: hidden;
  background: var(--brand-soft);
  border: 1px solid var(--brand-border);
  border-radius: var(--r-md);
  padding: var(--sp-5);
  text-align: center;
}
/* Kilau tipis yang menyapu sekali saat halaman dibuka: menarik mata ke
   angka yang harus disalin persis, lalu berhenti. */
.nominal-box::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 35%,
              rgba(255, 255, 255, .55) 50%, transparent 65%);
  transform: translateX(-120%);
  animation: kilau 1.6s var(--ease-standar) .35s 1;
}
@keyframes kilau { to { transform: translateX(120%); } }

.nominal-angka {
  font-size: 2.5rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1.05;
}
.nominal-catatan {
  margin-top: var(--sp-2);
  font-size: .9rem;
  font-weight: 600;
  color: var(--error);
}

/* Peringatan */
.peringatan {
  background: var(--warn-soft);
  border-left: 4px solid var(--warn);
  border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  font-size: .92rem;
}

/* Countdown */
.countdown {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 7px var(--sp-3);
  border-radius: var(--r-full);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: background var(--dur-2) var(--ease-standar),
              color var(--dur-2) var(--ease-standar);
}
/* Denyut hanya menyala saat waktunya benar-benar menipis. Animasi yang
   jalan terus dari awal cuma jadi latar dan berhenti dibaca. */
.countdown[data-mendesak="1"] {
  background: var(--error-soft);
  color: var(--error);
  border-color: var(--error);
  animation: denyut-mendesak 1.4s var(--ease-standar) infinite;
}
@keyframes denyut-mendesak {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.045); }
}

/* Halaman publik dibuka di HP — batasi lebar, kasih ruang napas */
.wadah-publik {
  max-width: 480px;
  margin: 0 auto;
  padding: var(--sp-4);
}

/* ---------- 6. AKSESIBILITAS ---------- */
/* Satu-satunya rem darurat untuk seluruh motion aplikasi. Kalau
   pengguna minta gerakan dikurangi lewat setelan HP, semua transisi,
   keyframe, dan animasi View Transition ikut padam di sini — jadi
   komponen di file lain tidak perlu menuliskannya lagi satu per satu. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}
