/* ClipperHub, dashboard campaign clipping.
 *
 * Bahasa visualnya dari dokumen-desain Sistem Pasha: tanpa warna sama sekali,
 * dasar #f1f1f1, kartu putih bersudut 16px yang diangkat bayangan dua lapis,
 * label kalimat biasa berikon keping, tinta tiga tingkat yang kontrasnya sudah
 * diuji di KEDUA latar (4,51:1 untuk yang tersamar, di dasar abu).
 *
 * YANG DIUTAMAKAN DI SINI: orang awam bisa langsung pakai.
 *
 * Client yang membuka halaman ini bukan analis. Dia mau tahu empat hal:
 * berapa totalnya, naik atau turun, campaign mana yang jalan, dan siapa yang
 * menghasilkan. Semua yang tidak menjawab salah satunya dibuang, termasuk
 * grafik sebaran yang butuh ditafsirkan dulu sebelum berguna.
 *
 * Daftar campaign adalah tokoh utama halaman depan, bukan pelengkap di bawah
 * kartu angka. Baris-barisnya tautan sungguhan: bisa di-tab, bisa dibuka di
 * tab baru, punya keadaan fokus yang terlihat.
 */

:root {
  color-scheme: light;

  --paper:       #f1f1f1;
  --surface:     #ffffff;
  --rule:        rgba(0, 0, 0, 0.09);
  --rule-strong: rgba(0, 0, 0, 0.17);

  --ink:   #0d0d0d;
  --ink-2: #474747;
  --ink-3: #6e6e6e;

  --accent:     #0d0d0d;
  --accent-ink: #ffffff;

  --bayang: 0 1px 2px rgba(0, 0, 0, 0.05), 0 6px 20px -10px rgba(0, 0, 0, 0.14);
  --bayang-angkat: 0 1px 2px rgba(0, 0, 0, 0.06), 0 12px 30px -12px rgba(0, 0, 0, 0.22);

  --r-kartu: 16px;
  --r: 10px;
  /* DUA NILAI, DAN BEDANYA PENTING.
     --gerak itu shorthand lengkap: durasi DAN lengkungannya. Dia benar dipakai
     sebagai `transition: transform var(--gerak)`.
     Tapi begitu ditulis `animation: sesuatu 400ms var(--gerak)`, nilai waktu
     kedua terbaca sebagai JEDA, bukan durasi, jadi animasinya diam 160 ms dulu
     baru mulai. Lima aturan di berkas ini pernah kena persis itu.
     --laju cuma lengkungannya, untuk yang menulis durasinya sendiri. */
  --gerak: 160ms cubic-bezier(0.22, 1, 0.36, 1);
  --laju: cubic-bezier(0.22, 1, 0.36, 1);
  /* Huruf bawaan sistem, diurutkan dari yang paling baik di tiap platform.
     "Segoe UI Variable Text" itu yang dipakai Windows 11 dan setara Inter;
     -apple-system menghasilkan SF Pro di Mac dan iOS. Inter tetap disebut
     paling depan supaya terpakai kalau memang terpasang di mesinnya. */
  --font: "Inter", "Segoe UI Variable Text", -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, system-ui, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }

body {
  background: var(--paper);
  color: var(--ink);
  font: 400 14px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}

.num { font-variant-numeric: tabular-nums; letter-spacing: -0.015em; }
a { color: inherit; }
svg { display: block; }

.keping svg, .glif { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* `svg { display: block }` di atas benar untuk ikon yang berdiri sendiri, tapi
   glif platform hidup DI DALAM KALIMAT: "(ikon) Instagram". Sebagai block dia
   memaksa ganti baris, jadi ikonnya melompat ke atas namanya dan tiap label
   platform jadi setinggi dua baris. Itu yang membuat baris "Tarik yang mana"
   terlihat berantakan padahal jaraknya tidak ada yang salah. */
.glif { width: 13px; height: 13px; flex: none; display: inline-block; vertical-align: -2px; }
.glif [fill] { fill: currentColor; stroke: none; }

/* Tautan lewati: syarat dasar keterjangkauan papan ketik. Tersembunyi sampai
   di-tab, lalu muncul sebagai tombol pertama halaman. */
.lewati {
  position: absolute;
  left: 12px; top: -60px;
  z-index: 20;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 10px 16px;
  border-radius: var(--r);
  font-size: 13px;
  font-weight: 550;
  text-decoration: none;
  transition: top var(--gerak);
}

.lewati:focus { top: 12px; }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ── Rangka ───────────────────────────────────────────────────────────── */

.rangka { display: grid; grid-template-columns: 236px minmax(0, 1fr); height: 100%; }

.samping {
  background: var(--surface);
  border-right: 1px solid var(--rule);
  padding: 18px 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
}

.merek { display: flex; align-items: center; gap: 10px; padding: 4px 6px 22px; text-decoration: none; border-radius: var(--r); }
.merek:hover .merek-teks b { text-decoration: underline; text-underline-offset: 3px; }

.merek-tanda {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-ink);
  border-radius: 10px;
  font-size: 12px; font-weight: 650; letter-spacing: 0.02em;
  flex: none;
}

.merek-teks { display: flex; flex-direction: column; line-height: 1.25; }
.merek-teks b { font-size: 14.5px; font-weight: 600; letter-spacing: -0.012em; }
.merek-teks small { font-size: 11.5px; color: var(--ink-3); }

.nav { display: flex; flex-direction: column; gap: 3px; }

.nav a {
  display: flex; align-items: center; gap: 11px;
  padding: 8px;
  border-radius: 12px;
  text-decoration: none;
  color: var(--ink-2);
  transition: background var(--gerak), color var(--gerak);
}

.nav a:hover { background: rgba(0, 0, 0, 0.045); color: var(--ink); }

.keping {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--rule);
  border-radius: 9px;
  color: var(--ink-2);
  flex: none;
  transition: background var(--gerak), color var(--gerak), border-color var(--gerak);
}

.keping svg { width: 15px; height: 15px; }

.nav-teks { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.nav-teks b { font-size: 13.5px; font-weight: 550; }
.nav-teks small { font-size: 11.5px; color: var(--ink-3); }

.nav a[aria-current="page"] { color: var(--ink); }
.nav a[aria-current="page"] .nav-teks b { font-weight: 650; }
.nav a[aria-current="page"] .keping { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.siapa {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 8px 2px;
  border-top: 1px solid var(--rule);
  font-size: 12.5px; line-height: 1.35;
}

.siapa-bulat {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  font-size: 12px; font-weight: 600;
  flex: none;
}

.siapa b { display: block; font-weight: 600; }
.siapa span { color: var(--ink-3); }

/* ── Kepala isi ───────────────────────────────────────────────────────── */

.utama { overflow-y: auto; padding: 24px 32px 72px; min-width: 0; }

/* LEBAR ISI DIBATASI, DAN INI BUKAN SOAL SELERA.
 *
 * Tanpa batas ini, di layar 2000px kolom isinya jadi 1685px dan semuanya ikut
 * melar: tombol "Tarik ulang lengkap" jadi palang hitam selebar 783px, kotak
 * ketikan untuk satu hashtag jadi 1616px, dan tiga angka di kartu penghapusan
 * terlempar sejauh 525px satu sama lain sampai mata harus menyeberang untuk
 * membacanya sebagai satu kelompok.
 *
 * Angkanya bukan tebakan: 1320px kira-kira sepuluh kolom tabel klip pada ukuran
 * huruf sekarang, jadi tabelnya tetap muat tanpa menggulir. Di layar 1440px ke
 * bawah, aturan ini tidak mengubah apa pun sama sekali. */
.utama > .atas,
.utama > #layar { max-width: 1320px; margin-inline: auto; }

.atas { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 24px; }
.atas-kiri { min-width: 0; }
.atas h1 { margin: 0; font-size: 26px; font-weight: 650; letter-spacing: -0.025em; }
.atas p { margin: 5px 0 0; font-size: 13.5px; color: var(--ink-2); }
.atas-kanan { display: flex; align-items: center; gap: 20px; flex: none; }

.remah { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-3); margin-bottom: 7px; }
.remah:empty { display: none; }
.remah a { text-decoration: none; border-radius: 4px; }
.remah a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

.peran { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-3); }

/* SEMUA JENIS KOTAK ISIAN, bukan cuma text dan email.
   Daftar ini dulu melewatkan password dan search, jadi kotak sandi di halaman
   masuk, undangan, dan ganti sandi memakai tampilan bawaan peramban: sudut
   siku, garis tebal, tinggi berbeda. Bersebelahan dengan kotak nama yang
   bergaya, bedanya langsung terlihat dan tampak seperti salah pasang. */
select,
input[type="text"], input[type="email"], input[type="password"],
input[type="search"], input[type="number"], input[type="url"], input[type="tel"] {
  font: inherit; font-size: 13px; color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  padding: 7px 11px;
  transition: border-color var(--gerak);
}

select:hover, input:hover { border-color: rgba(0, 0, 0, 0.32); }

.stempel { margin: 0; text-align: right; line-height: 1.35; font-size: 11.5px; color: var(--ink-3); }
.stempel b { display: block; font-size: 12.5px; font-weight: 550; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* ── Kartu ────────────────────────────────────────────────────────────── */

.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-kartu);
  box-shadow: var(--bayang);
  padding: 20px 22px;
}

.label-baris { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.label-baris .keping { width: 28px; height: 28px; border-radius: 8px; }
.label-baris .keping svg { width: 14px; height: 14px; }
.eyebrow { font-size: 13.5px; font-weight: 500; color: var(--ink-2); }
.pojok { margin-left: auto; font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; text-align: right; }
a.pojok { text-decoration: none; font-weight: 500; color: var(--ink-2); }
a.pojok:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

.angka-besar { font-variant-numeric: tabular-nums; letter-spacing: -0.032em; font-weight: 650; line-height: 1; }
.sub { margin: 10px 0 0; font-size: 12.5px; color: var(--ink-3); line-height: 1.55; }

/* Tiga angka. Yang pertama dominan karena memang yang paling ditanya. */
.angka-baris { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: 14px; margin-bottom: 14px; }
.angka-baris .angka-besar { font-size: 30px; }
.angka-baris .panel.hero .angka-besar { font-size: 52px; }

.duo-angka { display: flex; gap: 30px; flex-wrap: wrap; }
.duo-angka > div { display: flex; flex-direction: column; gap: 6px; }
.duo-angka small { font-size: 12px; color: var(--ink-3); }

/* ── Grafik ───────────────────────────────────────────────────────────── */

.grafik { display: block; width: 100%; height: auto; overflow: visible; }
.grafik text { font: 400 11px var(--font); fill: var(--ink-3); font-variant-numeric: tabular-nums; }
.grafik .sumbu { stroke: var(--rule-strong); stroke-width: 1; }
.grafik .kisi { stroke: var(--rule); stroke-width: 1; }

/* ── Daftar campaign: tokoh utama halaman depan ───────────────────────── */

.daftar { display: flex; flex-direction: column; gap: 10px; }

.kartu-camp {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  grid-template-areas: "no nama angka" "no meta angka" "bar bar bar";
  align-items: center;
  column-gap: 14px;
  row-gap: 4px;
  padding: 16px 20px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-kartu);
  box-shadow: var(--bayang);
  text-decoration: none;
  transition: box-shadow var(--gerak), transform var(--gerak), border-color var(--gerak);
}

.kartu-camp:hover { box-shadow: var(--bayang-angkat); transform: translateY(-2px); border-color: var(--rule-strong); }
.kartu-camp:active { transform: none; }

.kartu-camp .no {
  grid-area: no;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 10px;
  border: 1px solid var(--rule);
  font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.kartu-camp:first-child .no { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.camp-nama { grid-area: nama; font-size: 16px; font-weight: 600; letter-spacing: -0.015em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.camp-meta { grid-area: meta; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; font-size: 12.5px; color: var(--ink-3); }
.camp-meta .glif { color: var(--ink-3); }
.camp-meta .plat { display: inline-flex; align-items: center; gap: 5px; }

.tag {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  font-size: 11.5px;
  color: var(--ink-2);
}

.camp-angka { grid-area: angka; text-align: right; }
.camp-angka b { display: block; font-size: 21px; font-weight: 650; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; }
.camp-angka span { font-size: 11.5px; color: var(--ink-3); }

.kartu-camp .jalur { grid-area: bar; margin-top: 10px; }

.jalur { height: 6px; border-radius: 3px; background: rgba(0, 0, 0, 0.07); overflow: hidden; }
.jalur i { display: block; height: 100%; background: var(--ink); border-radius: 3px; }

/* ── Peringkat creator ────────────────────────────────────────────────── */

.peringkat { display: flex; flex-direction: column; }

.peringkat-baris {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) auto;
  grid-template-areas: "no nama nilai" "no bar bar";
  align-items: center;
  column-gap: 11px; row-gap: 7px;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}

.peringkat-baris:last-child { border-bottom: 0; padding-bottom: 2px; }
.peringkat-baris:first-child { padding-top: 2px; }

.peringkat-baris .no {
  grid-area: no;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: 7px;
  font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--rule);
  color: var(--ink-2);
}

.peringkat-baris:first-child .no { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.peringkat-nama { grid-area: nama; display: flex; align-items: center; gap: 7px; font-size: 13.5px; min-width: 0; }
.peringkat-nama b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.peringkat-nama .glif { color: var(--ink-3); }
.peringkat-nilai { grid-area: nilai; text-align: right; font-size: 13.5px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.015em; }
.peringkat-baris .jalur { grid-area: bar; height: 5px; }

/* ── Platform ─────────────────────────────────────────────────────────── */

.plat-blok { padding: 13px 0; border-bottom: 1px solid var(--rule); }
.plat-blok:last-child { border-bottom: 0; padding-bottom: 2px; }
.plat-blok:first-child { padding-top: 0; }
.plat-kepala { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
.plat-kepala b { font-size: 13.5px; font-weight: 550; }
.plat-kepala .nilai { margin-left: auto; font-size: 16px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.plat-kepala .porsi { font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }
.plat-rinci { margin: 8px 0 0; font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* ── Tabel ────────────────────────────────────────────────────────────── */

.gulung-x { overflow-x: auto; margin: 0 -22px; padding: 0 22px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }

th {
  text-align: left; font-size: 12px; font-weight: 500; color: var(--ink-3);
  padding: 0 14px 10px 0;
  border-bottom: 1px solid var(--rule-strong);
  white-space: nowrap;
}

th.n, td.n { text-align: right; }
td.n { font-variant-numeric: tabular-nums; }

th button {
  all: unset; cursor: pointer;
  display: inline-flex; gap: 5px; align-items: center;
  padding: 2px 4px; margin: -2px -4px;
  border-radius: 4px;
}

th button:hover { color: var(--ink); background: rgba(0, 0, 0, 0.04); }
th button .arah { font-size: 9px; }
th[aria-sort] button { color: var(--ink); font-weight: 600; }

td { padding: 9px 14px 9px 0; border-bottom: 1px solid var(--rule); vertical-align: baseline; }
tbody tr:hover td { background: rgba(0, 0, 0, 0.025); }
tbody tr:last-child td { border-bottom: 0; }

td a { font-weight: 500; text-decoration: underline; text-decoration-color: var(--rule-strong); text-underline-offset: 3px; }
td a:hover { text-decoration-color: var(--ink); }

.kosong { color: var(--ink-3); }
.plat { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.plat .glif { color: var(--ink-2); }
.potong { display: block; max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }

/* ── Saringan ─────────────────────────────────────────────────────────── */

.saring { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 16px; }
.pilihan { display: inline-flex; gap: 6px; }

.pilihan button {
  font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer;
  padding: 7px 14px;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  transition: background var(--gerak), color var(--gerak), border-color var(--gerak);
}

.pilihan button:hover { border-color: rgba(0, 0, 0, 0.32); color: var(--ink); }
.pilihan button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* SARINGAN "BARU", DIPISAH DARI SARINGAN PLATFORM.
 *
 * Bentuknya sama-sama pil, tapi dia bukan bagian dari kelompok di sebelahnya:
 * platform itu pilih-salah-satu, ini nyala-mati. Menaruhnya di dalam kelompok
 * yang sama akan berbohong tentang cara kerjanya, jadi dia berdiri sendiri
 * dengan jarak dan titik penanda di depannya.
 *
 * Titiknya hijau, warna yang sama dengan centang selesai penarikan, karena
 * keduanya menjawab pertanyaan yang sama: apa yang baru saja terjadi. */
.chip-baru {
  font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; margin-left: 4px;
  color: var(--ink-2); background: var(--surface);
  border: 1px solid var(--rule-strong); border-radius: 999px;
  transition: background var(--gerak), color var(--gerak), border-color var(--gerak);
}
.chip-baru::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: #1c7a4a; flex: none;
}
.chip-baru:hover { border-color: rgba(0, 0, 0, 0.32); color: var(--ink); }
.chip-baru[aria-pressed="true"] {
  background: #1c7a4a; border-color: #1c7a4a; color: #fff;
}
.chip-baru[aria-pressed="true"]::before { background: #fff; }

.cari { flex: 1; min-width: 190px; max-width: 300px; border-radius: 999px; padding: 8px 15px; }
.hitung { font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; margin-left: auto; }

/* Keadaan kosong: menjelaskan sebabnya dan menawarkan jalan keluar, bukan
   cuma memberi tahu bahwa tidak ada apa-apa. */
.hampa { padding: 44px 20px; text-align: center; }
.hampa b { display: block; font-size: 15px; font-weight: 600; margin-bottom: 6px; }
.hampa p { margin: 0 auto 16px; font-size: 13px; color: var(--ink-3); max-width: 46ch; line-height: 1.6; }

/* Varian tenang: dipakai untuk keadaan yang NORMAL, bukan salah. Dua belas
   dari tiga belas campaign memang baru ditarik ringkas; menampilkan blok
   kosong sebesar layar untuk keadaan yang lumrah membuat sistem yang sehat
   terlihat rusak. */
.hampa.tenang { padding: 4px 0 2px; text-align: left; }
.hampa.tenang b { font-size: 13.5px; }
.hampa.tenang p { margin: 0; max-width: 62ch; }

/* ── Identitas dan penghitung di bilah sisi ───────────────────────────── */
/* Identitas duduk tepat di bawah menu, seperti baris menu berikutnya.
   Penghitung video didorong ke dasar. Satu-satunya yang boleh memakai
   margin-top:auto adalah yang paling bawah; dua-duanya memakainya membuat
   keduanya saling menindih, dan itu yang terjadi di versi sebelumnya. */

.siapa {
  display: flex; align-items: center; gap: 10px;
  margin-top: 10px;
  padding: 12px 8px 0;
  border-top: 1px solid var(--rule);
  font-size: 12.5px; line-height: 1.35;
}

.siapa-bulat {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  font-size: 12px; font-weight: 600;
  flex: none;
}

.siapa b { display: block; font-weight: 600; }
.siapa span { color: var(--ink-3); }

.kuota { margin-top: auto; padding: 14px 8px 2px; border-top: 1px solid var(--rule); }
.kuota:empty { display: none; }
.kuota-teks { margin: 0; font-size: 12.5px; color: var(--ink-2); }
.kuota-teks b { font-size: 15px; font-weight: 650; color: var(--ink); margin-right: 4px; }
.kuota-kecil { margin: 3px 0 0; font-size: 11.5px; color: var(--ink-3); }

/* ── Cari hashtag baru ────────────────────────────────────────────────── */

.aksi-atas { margin-bottom: 16px; }
.tombol-isi { display: inline-flex; align-items: center; gap: 8px; }
.tombol-isi svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pojok-tombol { margin-left: auto; }

/* Form bertumpuk dan dibatasi lebarnya. Versi sebelumnya satu baris flex, dan
   di layar lebar medannya terlempar sejauh dua ribu piksel: kotak hashtag di
   ujung kiri, tombolnya di ujung kanan, mata harus menyeberang untuk satu
   isian. Form tidak pernah butuh selebar layar. */
.form-baru { margin-bottom: 16px; }
.form-isi { display: flex; flex-direction: column; gap: 16px; max-width: 460px; }
.form-isi .medan { gap: 6px; }
.form-isi .tarik-aksi { margin-top: 2px; }

.pagar {
  display: flex; align-items: center; gap: 2px;
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  padding-left: 11px;
  transition: border-color var(--gerak);
}

.pagar:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.09); }
.pagar span { color: var(--ink-3); font-size: 14px; }
.pagar input { border: 0; background: none; padding-left: 2px; width: 100%; min-width: 0; }
.pagar input:focus-visible { outline: none; box-shadow: none; }

fieldset.medan { border: 0; margin: 0; padding: 0; }
fieldset.medan legend { padding: 0; margin-bottom: 6px; font-size: 12px; color: var(--ink-3); }
.centang { display: flex; gap: 20px; }
.centang label { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; cursor: pointer; }
.centang input { width: 17px; height: 17px; accent-color: var(--ink); cursor: pointer; flex: none; margin: 0; }
.centang-teks { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.centang .glif { color: var(--ink-2); }

.galat { margin: 0; font-size: 12.5px; color: var(--ink); font-weight: 500; }
.galat:empty { display: none; }

.cek-hasil { padding: 4px 0 18px; max-width: 60ch; }
.cek-hasil p { margin: 0 0 8px; font-size: 13.5px; }
.cek-hasil .sub { margin: 0; }

/* ── Panel penarikan ──────────────────────────────────────────────────── */

/* Dua pilihan berdampingan, masing-masing menyebut akibatnya sendiri.
   Kalimat yang ditebalkan adalah yang menentukan pilihan, bukan judulnya. */
/* Dua kartu ini isinya cuma satu tombol masing-masing, dan tombolnya melebar
   penuh mengikuti kartunya. Tanpa batas, sepasang tombol jadi selebar halaman.
   Yang dibatasi grid-nya, bukan tombolnya: kalau tombolnya yang dipersempit,
   dia mengambang di tengah kartu kosong dan justru terlihat lebih salah. */
.pilih-tarik { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; max-width: 720px; }

.pilih-kartu {
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 16px 18px;
}

.pilih-kartu b { display: block; font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.pilih-kartu p { margin: 0 0 14px; font-size: 12.5px; color: var(--ink-3); line-height: 1.6; }
.pilih-kartu .tekan { color: var(--ink-2); font-weight: 550; }
.pilih-kartu .galat { margin-top: 10px; font-size: 12px; }
.pilih-kartu .tarik-aksi { align-items: center; }
.pilih-kartu .tarik-jeda { line-height: 1.4; }
.tarik-total { margin: 22px 0 0; padding: 14px 16px; background: var(--surface);
  border: 1px solid var(--rule); border-radius: 12px; max-width: none; }
.tarik-total b { font-size: 15px; color: var(--ink); }

.hasil-tarik { padding: 2px 0 16px; }
.hasil-tarik p { margin: 0 0 6px; font-size: 13.5px; }
.hasil-tarik .sub { margin: 0; }

/* ── Penanda ──────────────────────────────────────────────────────────── */

/* Kuning satu-satunya warna di seluruh sistem, dan itu disengaja: dokumen
   desain melarang warna sebagai hiasan, bukan sebagai penanda yang diminta.
   Dipakai HANYA untuk klip yang hashtagnya tidak cocok, dan selalu didampingi
   teks supaya penandanya tidak hilang saat dicetak hitam putih. */
.cap {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--rule-strong);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}

.cap.kuning { background: #fff3b0; border-color: #e8d47a; color: #4a3d00; }
/* "baru" pakai tinta pekat karena itu kabar baik yang memang dicari orang
   sehabis menarik. "belum disegarkan" tetap abu: itu peringatan, bukan
   kesalahan, dan tidak boleh berteriak lebih keras daripada datanya. */
.cap.baru { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.cap.basi { border-style: dashed; color: var(--ink-3); }

.panel.peringatan { margin-bottom: 14px; }
.daftar-tanda { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
/* Baris teks dibatasi sekitar 88 huruf. Lebih panjang dari itu, mata kehilangan
   awal baris berikutnya saat berpindah, dan paragraf pendek pun jadi melelahkan
   dibaca. Panel ini yang paling sering memuat kalimat penuh, jadi dia yang
   paling terasa kalau dibiarkan selebar halaman. */
.daftar-tanda li { font-size: 13px; color: var(--ink-2); line-height: 1.65; max-width: 88ch; }
.daftar-tanda .cap { margin-right: 6px; }

.sel-creator { margin-right: 7px; }
tr.baris-tag td { background: #fffdf2; }
tr.baris-tag:hover td { background: #fff8dc; }
tr.baris-hilang td { color: var(--ink-3); }
tr.baris-hilang .sel-creator { text-decoration: line-through; text-decoration-thickness: 1px; }

.tag-sel { display: flex; flex-wrap: wrap; gap: 4px; max-width: 34ch; }
.tag.cocok { border-color: var(--ink); color: var(--ink); font-weight: 550; }

/* ── Sasaran sentuh ───────────────────────────────────────────────────── */

.panel.tarik { margin-bottom: 14px; }
.tarik-ket { margin: -6px 0 16px; font-size: 13px; color: var(--ink-2); max-width: 68ch; line-height: 1.6; }
.tarik-aksi { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.tarik-jeda { font-size: 12.5px; color: var(--ink-3); }
.tarik-jeda b { color: var(--ink-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.tarik-kecil { margin: 14px 0 0; font-size: 12px; color: var(--ink-3); max-width: 68ch; line-height: 1.6; }
.label-baris .pojok b { display: block; color: var(--ink-2); font-weight: 550; }

/* Daftar tahap, bukan spinner.
 *
 * DESIGN.md melarang spinner di tengah konten dan meminta keadaan yang
 * MENJELASKAN apa yang sedang terjadi. Spinner cuma bilang "tunggu"; daftar
 * ini bilang sedang di bagian mana, dan kalau macet, macetnya di mana.
 *
 * Statusnya dibedakan BENTUK, bukan warna, mengikuti aturan tanpa warna:
 * isian penuh = selesai, cincin = sedang jalan, titik samar = belum. */
.langkah { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.langkah li {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 0;
  font-size: 13px;
  border-bottom: 1px solid var(--rule);
}

.langkah li:last-child { border-bottom: 0; }

.langkah .tanda {
  width: 13px; height: 13px; border-radius: 50%;
  flex: none;
  border: 2px solid var(--rule-strong);
}

.langkah .usai { color: var(--ink-2); }
.langkah .usai .tanda { background: var(--ink); border-color: var(--ink); }
.langkah .kini { color: var(--ink); font-weight: 550; }
.langkah .kini .tanda { border-color: var(--ink); }
.langkah .nanti { color: var(--ink-3); }
.kini-teks { margin-left: auto; font-size: 11.5px; color: var(--ink-3); font-weight: 400; }

/* ── Sasaran sentuh ───────────────────────────────────────────────────── */
/* WCAG 2.5.5 minta minimal 44x44 px. Di tetikus, kepadatan justru fitur dan
   sasaran 33px sama sekali tidak menyulitkan; di jari, 33px meleset terus.
   Jadi yang dilebarkan hanya di peranti berpenunjuk kasar, bukan di semua. */
@media (pointer: coarse) {
  .pilihan button { min-height: 44px; padding-left: 18px; padding-right: 18px; }
  .aksi { min-height: 44px; }
  .nav a, .merek { min-height: 44px; }
  th button { min-height: 44px; }
  td a, .remah a { display: inline-flex; align-items: center; min-height: 44px; }
  select,
  input[type="text"], input[type="email"], input[type="password"],
  input[type="search"], input[type="number"], input[type="url"], input[type="tel"] { min-height: 44px; }
  .cari { min-height: 44px; }
}

/* ── Tombol ───────────────────────────────────────────────────────────── */

/* SELEKTORNYA `.aksi`, BUKAN `button.aksi`.
 *
 * Enam tombol di sistem ini ditulis sebagai <a>, karena mereka memang berpindah
 * halaman: "Kembali ke dashboard", "Export Excel", "Batal". Semuanya memakai
 * kelas .aksi dan semuanya membawa `text-decoration:none` di atribut style,
 * yang artinya penulisnya jelas bermaksud mereka terlihat seperti tombol.
 *
 * Tapi selektornya dipatok ke <button>, jadi tidak satu pun dari mereka pernah
 * mendapat gaya itu. Export Excel setinggi 22 piksel, tanpa garis tepi, tanpa
 * latar, berdiri di sebelah tombol lain setinggi 40 piksel. Kelas yang
 * dituliskan tapi tidak pernah berlaku itu lebih buruk daripada tidak ada:
 * dia terlihat sudah beres di kode dan salah di layar.
 *
 * inline-flex supaya <a> ikut menerima padding tegak dan tingginya sama. */
.aksi {
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: 13px; font-weight: 550; cursor: pointer;
  text-decoration: none;
  padding: 9px 17px;
  border-radius: var(--r);
  border: 1px solid var(--accent);
  background: var(--accent); color: var(--accent-ink);
  transition: transform var(--gerak), box-shadow var(--gerak), opacity var(--gerak);
}

.aksi:hover { box-shadow: var(--bayang-angkat); transform: translateY(-1px); }
.aksi:active { transform: none; box-shadow: none; }
/* TINGGI YANG SAMA DENGAN TOMBOL UTAMA.
   Dulu padding tegaknya 7px lawan 9px, jadi tombol sekunder 36px dan tombol
   utama 40px. Sepasang tombol yang bersebelahan dengan tinggi berbeda selalu
   terbaca sebagai kesalahan, bukan sebagai hierarki: yang membedakan keduanya
   sudah warna dan garis tepinya, tidak perlu ditambah selisih empat piksel.
   Mendatarnya tetap lebih rapat, itu tidak mengganggu kesejajaran. */
.aksi.sekunder { background: var(--surface); color: var(--ink); border-color: var(--rule-strong); padding: 9px 15px; }
.aksi.sekunder:hover { border-color: rgba(0, 0, 0, 0.35); box-shadow: none; transform: none; }
.aksi:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; transform: none; }

/* ── Pengaturan ───────────────────────────────────────────────────────── */

.lencana {
  display: inline-block; padding: 3px 11px; border-radius: 999px;
  font-size: 11.5px; font-weight: 550;
  border: 1px solid var(--rule-strong); color: var(--ink-2);
  white-space: nowrap;
}

.lencana.super { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.baris-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px; }
.medan { display: flex; flex-direction: column; gap: 6px; }
.medan label { font-size: 12px; color: var(--ink-3); }
/* Kotak centang DIKECUALIKAN, dan ini yang membuat baris platform berantakan.
   Lebar minimum 195px itu untuk kotak teks dan daftar pilih, supaya tidak
   menyempit sampai tidak terbaca. Tapi selektornya menyapu semua <input>,
   termasuk centang Instagram dan TikTok, dan min-width mengalahkan width:17px
   yang sudah disetel untuknya. Akibatnya tiap centang jadi selebar 195px dan
   labelnya melar sampai 277px, jadi kelihatan tersebar acak padahal tidak ada
   satu pun jarak yang salah. */
.medan input:not([type="checkbox"]):not([type="radio"]),
.medan select { min-width: 195px; }

.catatan { margin: 16px 0 0; font-size: 12.5px; color: var(--ink-3); line-height: 1.7; max-width: 70ch; }
.catatan b { color: var(--ink-2); font-weight: 600; }

.tumpuk { display: flex; flex-direction: column; gap: 14px; }
.duo { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr); gap: 14px; }

/* ── Sempit ───────────────────────────────────────────────────────────── */

@media (max-width: 1080px) {
  .angka-baris { grid-template-columns: 1fr 1fr; }
  .angka-baris .panel.hero { grid-column: 1 / -1; }
  .duo { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 860px) {
  .rangka { grid-template-columns: 1fr; height: auto; }
  .samping {
    border-right: 0; border-bottom: 1px solid var(--rule);
    flex-direction: row; flex-wrap: wrap; align-items: center;
    gap: 8px; padding: 12px 14px; overflow: visible;
  }
  .merek { padding: 0 8px 0 0; }
  .nav { flex-direction: row; }
  .nav-teks small { display: none; }
  .siapa { display: none; }
  .utama { padding: 18px 15px 56px; }
  .atas { flex-wrap: wrap; gap: 14px; }
  .atas h1 { font-size: 22px; }
  .angka-baris { grid-template-columns: 1fr; }
  .angka-baris .panel.hero .angka-besar { font-size: 40px; }
  .pilih-tarik { grid-template-columns: 1fr; }
  .kuota { display: none; }
  .kartu-camp { grid-template-columns: 32px minmax(0, 1fr); grid-template-areas: "no nama" "no meta" "angka angka" "bar bar"; padding: 15px 16px; }
  .camp-angka { text-align: left; margin-top: 8px; }
  .kartu-camp .no { width: 28px; height: 28px; }
  .gulung-x { margin: 0 -16px; padding: 0 16px; }
  .panel { padding: 16px; }
}

@media (prefers-reduced-motion: reduce) { * { transition-duration: 1ms !important; } }

/* ══ Perbaikan dan tambahan ═══════════════════════════════════════════════ */

/* PERATAAN KARTU ANGKA.
 *
 * Kartu Total views memakai angka 52px, dua kartu di sebelahnya 30px. Karena
 * tinggi blok angkanya berbeda, kalimat keterangan di bawahnya berhenti di
 * ketinggian yang berbeda pula: yang kiri melayang jauh di bawah, dua lainnya
 * menempel di angkanya. Sebaris tiga kartu yang tidak sebaris.
 *
 * Yang diratakan keterangannya, BUKAN angkanya. Menyamakan ukuran angka juga
 * akan merapikan, tapi sekalian menghapus hierarkinya: kartu pertama memang
 * yang paling penting dan pantas paling besar. Jadi angkanya dibiarkan
 * berbeda, dan keterangannya yang dijatuhkan ke dasar kartu. */
/* Angkanya duduk di GARIS DASAR YANG SAMA meski ukurannya berbeda.
   Kotak angkanya diberi tinggi minimum setinggi angka terbesar, lalu isinya
   didorong ke bawah. Hasilnya kalimat keterangan di ketiga kartu mulai di
   ketinggian yang sama, dan itu yang terbaca sebagai "rata" oleh mata.

   Mendorong keterangannya ke dasar kartu juga meratakan, tapi cuma bagian
   bawahnya; kalau salah satu keterangan jadi dua baris, puncaknya melompat
   dan ketidakrataannya justru pindah tempat. */
.angka-baris .panel { display: flex; flex-direction: column; }
/* margin: 0 itu yang sebenarnya memperbaiki, dan sebabnya halus sekali.
   .angka-besar itu elemen <p>, dan margin bawaan <p> SEBANDING dengan ukuran
   hurufnya. Kartu pertama berhuruf 52px, dua lainnya 30px, jadi margin atasnya
   berselisih 22px, dan itu persis selisih yang terlihat di layar. Bukan
   tata letaknya yang salah, tapi gaya bawaan peramban yang tidak pernah
   dimatikan. */
.angka-baris .angka-besar { margin: 0; min-height: 52px; display: flex; align-items: flex-end; }
.angka-baris .panel .sub { margin-top: 12px; }

/* Kartu tarik sekarang cuma berisi tombol. Tanpa aturan ini dia mewarisi
   jarak untuk judul dan paragraf yang sudah tidak ada, dan tombolnya terlihat
   mengambang di kotak yang terlalu lapang. */
.pilih-kartu:has(> .aksi:only-child),
.pilih-kartu:has(> .aksi:first-child) { padding: 14px; }
.pilih-kartu > .aksi { width: 100%; justify-content: center; }

/* ── Memilih campaign untuk seorang client ────────────────────────────── */

/* Kotak centang, BUKAN daftar pilih tunggal.
   Satu client memang boleh memegang beberapa campaign, dan bentuk kendalinya
   harus mengatakan itu sebelum ada yang mencoba. Daftar pilih tunggal
   membuatnya tampak seperti pilihan yang saling meniadakan. */
.pilih-camp {
  margin-top: 18px; padding: 14px 16px;
  border: 1px solid var(--rule); border-radius: 12px;
  display: flex; flex-direction: column; gap: 2px;
}
/* NAMANYA .pilih-satu, BUKAN .centang, dan itu perbaikan atas kesalahan.
   Aturan ini semula ditulis sebagai .centang, padahal nama itu sudah dipakai
   formulir hashtag untuk WADAH berisi label, bukan untuk labelnya sendiri.
   Akibatnya wadah itu ikut mendapat padding dan gap yang bukan miliknya, dan
   pilihan Instagram/TikTok melebar sampai 277px lalu terlihat berantakan.
   Kelas yang dipakai dua maksud berbeda selalu berakhir begini. */
.pilih-satu {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 4px; border-radius: 8px; cursor: pointer; font-size: 13.5px;
}
.pilih-satu:hover { background: var(--wash); }
.pilih-satu input { width: 17px; height: 17px; accent-color: var(--ink); flex: none; cursor: pointer; margin: 0; }
.pilih-satu .tag { margin-left: 6px; }

/* ── Hasil undangan ───────────────────────────────────────────────────── */

.undangan-hasil {
  margin-top: 16px; padding: 15px 16px;
  border: 1px solid var(--rule); border-radius: 12px; background: var(--wash);
}
.undangan-hasil .sub { margin: 6px 0 0; }
.sukses { margin: 0; font-size: 13px; font-weight: 550; color: var(--ink); }

.salin-baris { display: flex; gap: 8px; margin-top: 13px; }
.salin-baris input {
  flex: 1; min-width: 0; font: 400 12.5px var(--mono, ui-monospace, Consolas, monospace);
  padding: 9px 11px; border: 1px solid var(--rule); border-radius: 9px;
  background: var(--surface); color: var(--ink-2);
}
.salin-baris .aksi { flex: none; }

/* Kartu campaign versi ringkas untuk halaman pengaturan client: tanpa nomor
   urut dan tanpa bilah, karena di sana tidak ada yang diperingkat. */
.kartu-camp.ringkas {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "nama angka" "meta angka";
}

@media (max-width: 720px) {
  .pilih-tarik { grid-template-columns: 1fr; }
  .salin-baris { flex-direction: column; }
  .salin-baris .aksi { width: 100%; justify-content: center; }
}

/* Sasaran sentuh 44px di perangkat sentuh, WCAG 2.5.5. */
@media (pointer: coarse) {
  .pilih-satu { min-height: 44px; }
  .salin-baris input { min-height: 44px; }
}

/* Halaman undangan berdiri sendiri: tanpa bilah sisi, tanpa pemilih peran.
   Yang membukanya belum punya akun, jadi tidak ada satu pun menu yang bisa
   dia pakai, dan pemilih peran justru membocorkan susunan peran di sistem. */
body[data-tanpa-bingkai] .samping,
body[data-tanpa-bingkai] .peran,
body[data-tanpa-bingkai] .stempel { display: none; }
body[data-tanpa-bingkai] .rangka { grid-template-columns: 1fr; }

/* ══ Gerak ════════════════════════════════════════════════════════════════
 *
 * GERBANG FREKUENSI DILEWATI DULU, SEBELUM SATU BARIS PUN DITULIS.
 *
 * Ini alat kerja, bukan halaman promosi. Yang dipakai puluhan kali per sesi
 * TIDAK diberi gerak sama sekali, karena di sana gerak berubah jadi antrean:
 *
 *   menyaring platform, mengurutkan kolom ...... tidak ada
 *   menggambar ulang 611 baris tabel ............ tidak ada
 *   apa pun yang dipicu papan ketik ............. tidak ada
 *
 * Yang diberi gerak cuma tiga, dan ketiganya punya alasan yang bisa disebut:
 *
 *   menekan tombol ....... umpan balik. Tangan perlu tahu tekanannya masuk
 *   berpindah halaman .... orientasi. Isi yang baru datang dari mana
 *   grafik dan bilah ..... pemahaman. Bentuknya terbaca saat terbentuk
 *
 * Tidak ada yang berdenyut, berkedip, atau bernapas. Gerak berulang tanpa
 * henti menarik mata terus-menerus ke hal yang sudah selesai dibaca.
 *
 * Durasinya di bawah 300ms. 180ms terasa lebih responsif daripada 400ms, dan
 * di alat kerja responsif lebih berharga daripada anggun.
 */

:root {
  /* MENGIKUTI --gerak YANG SUDAH ADA, bukan membuat tandingan.
     Berkas ini sudah memakai cubic-bezier(0.22, 1, 0.36, 1) di sebelas tempat
     sejak sebelum gerak ditambahkan. Memperkenalkan kurva kedua yang mirip
     tapi tidak sama membuat dua bagian layar melambat dengan cara berbeda,
     dan bedanya terasa tanpa bisa ditunjuk penyebabnya. Yang ditambahkan di
     sini cuma yang memang belum ada. */
  --datang: cubic-bezier(0.22, 1, 0.36, 1);      /* sama dengan --gerak */
  --ubah: cubic-bezier(0.4, 0, 0.2, 1);          /* yang berubah di tempat */
  --kilas: 110ms;
  --singkat: 180ms;
  --masuk: 260ms;
}

/* ── Umpan balik tekan ─────────────────────────────────────────────────
 *
 * scale(0.97), bukan 0.9. Yang dicari bukan efek yang terlihat, tapi rasa
 * bahwa tombolnya menerima tekanan. Angka yang terlalu kecil membuatnya
 * terlihat melompat, dan itu justru mengalihkan perhatian dari hasilnya.
 *
 * Ditekan: seketika, tanpa durasi. Dilepas: 110ms. Jari lebih dulu daripada
 * mata, jadi tekanannya harus mendahului dan pemulihannya boleh menyusul. */
.cip, .kartu-camp {
  transition: background-color var(--kilas) var(--ubah),
              border-color var(--kilas) var(--ubah),
              color var(--kilas) var(--ubah),
              transform var(--kilas) var(--ubah);
}

/* KEKHUSUSANNYA HARUS MENYAMAI `button.aksi:active` YANG SUDAH ADA.
   Aturan lama menyetel `transform: none` saat ditekan, dan ditulis sebagai
   `button.aksi` (elemen + kelas). Menulis `.aksi:active` saja kalah dan
   tekanannya tidak pernah terasa; kalah karena satu poin kekhususan, bukan
   karena kodenya salah. */
button.aksi:active,
button.tombol:active,
.cip:active {
  transform: scale(0.97);
  box-shadow: none;
  transition-duration: 0s;      /* masuk seketika, pulihnya boleh menyusul */
}
button.aksi:disabled:active, button.tombol:disabled:active { transform: none; }

/* Kartu campaign naik satu piksel saat disentuh tetikus. Satu piksel memang
   nyaris tak terlihat, dan itu memang maksudnya: yang perlu disampaikan
   cuma "ini bisa ditekan", bukan "lihat saya". */
.kartu-camp:hover { transform: translateY(-1px); }
.kartu-camp:active { transform: translateY(0) scale(0.995); transition-duration: 0s; }

/* ── Isi halaman yang datang ───────────────────────────────────────────
 *
 * HANYA saat rute berganti, dan itu ditegakkan lewat data-masuk yang dipasang
 * dari kode. Kalau dipasang di setiap penggambaran ulang, menyaring platform
 * pun ikut membuat seluruh halaman berkedip, dan penyaring yang berkedip tiap
 * ditekan lebih melelahkan daripada penyaring yang diam.
 *
 * translateY 8px, bukan 24px. Jarak yang jauh membuat mata mengejar, dan
 * mengejar itu pekerjaan. 8px cukup memberi tahu arahnya datang dari bawah. */
@keyframes masuk {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* `backwards`, BUKAN `both`, DAN INI YANG PALING PENTING DI SELURUH BLOK GERAK.
 *
 * `both` menahan keadaan AKHIR sekaligus keadaan AWAL. Keadaan awal di sini
 * opacity 0, jadi begitu animasinya tidak pernah jalan, elemennya tinggal
 * di situ: tidak terlihat, selamanya.
 *
 * Dan "tidak pernah jalan" itu bukan kemungkinan teoretis. Peramban
 * menghentikan animasi CSS di tab yang tersembunyi. Terukur di sini: tab
 * disembunyikan, waktu animasi berhenti di 0, dan ketujuh blok dashboard
 * opacity 0. Halamannya kosong melompong, dan tidak ada satu pun galat yang
 * memberi tahu kenapa.
 *
 * `backwards` cuma menahan keadaan awal SELAMA jeda, lalu melepaskannya
 * kembali ke gaya elemen sendiri setelah selesai. Digabung dengan pembersihan
 * data-masuk dari kode setelah 700ms, keadaan terlihat selalu jadi tujuan
 * akhirnya, apa pun yang terjadi pada animasinya.
 *
 * Aturannya: yang terlihat harus jadi keadaan BAWAAN, dan gerak cuma lapisan
 * sementara di atasnya. Bukan sebaliknya. Halaman kosong jauh lebih buruk
 * daripada halaman tanpa animasi. */
#layar[data-masuk="1"] > * {
  animation: masuk var(--masuk) var(--datang) backwards;
}
/* Bertahap, tapi pendek. 40ms per blok cukup membuat urutannya terbaca; lebih
   panjang dan yang di bawah terasa tertinggal. Dibatasi lima blok pertama,
   karena setelah itu penantiannya lebih terasa daripada urutannya. */
#layar[data-masuk="1"] > *:nth-child(2) { animation-delay: 40ms; }
#layar[data-masuk="1"] > *:nth-child(3) { animation-delay: 80ms; }
#layar[data-masuk="1"] > *:nth-child(4) { animation-delay: 120ms; }
#layar[data-masuk="1"] > *:nth-child(n+5) { animation-delay: 160ms; }

/* ── Grafik menggambar dirinya ─────────────────────────────────────────
 *
 * Ini satu-satunya gerak yang agak panjang, 620ms, dan itu dibela karena dia
 * BEKERJA: garis yang tumbuh dari kiri ke kanan membaca sumbu waktunya untuk
 * kita. Yang tumbuh dari nol ke 858.591 terlihat sebagai perolehan yang
 * menumpuk, bukan sekadar garis yang muncul.
 *
 * pathLength="1" dipasang di app.js supaya dasharray bisa memakai satuan
 * ternormalkan, tanpa perlu mengukur panjang garisnya lewat JavaScript. */
@keyframes tarikGaris { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes munculPelan { from { opacity: 0; } to { opacity: 1; } }

#layar[data-masuk="1"] .grafik path[stroke] {
  stroke-dasharray: 1;
  animation: tarikGaris 620ms var(--datang) backwards;
}
#layar[data-masuk="1"] .grafik path[fill]:not([fill="none"]) {
  animation: munculPelan 620ms var(--datang) backwards;
}
#layar[data-masuk="1"] .grafik circle {
  animation: munculPelan 240ms var(--datang) backwards;
  animation-delay: 480ms;
}

/* ── Bilah proporsi ────────────────────────────────────────────────────
 *
 * scaleX, BUKAN width. Menganimasikan width memaksa peramban menghitung ulang
 * tata letak di tiap bingkai; scaleX dikerjakan kartu grafis dan tidak
 * menyentuh tata letak sama sekali. Lebar akhirnya tetap disetel lewat style
 * dari kode, jadi kalau geraknya dimatikan, angkanya tetap benar. */
@keyframes isiBilah { from { transform: scaleX(0); } to { transform: scaleX(1); } }

#layar[data-masuk="1"] .jalur > i {
  transform-origin: left center;
  animation: isiBilah 460ms var(--datang) backwards;
  animation-delay: 90ms;
}

/* ── Tahapan penarikan ─────────────────────────────────────────────────
 *
 * Penarikan berlangsung menit, bukan detik, dan orang menonton daftar ini
 * untuk memastikan sistemnya masih hidup. Perpindahan tahap yang mulus
 * menjawab pertanyaan itu tanpa satu kata pun. */
.langkah li { transition: color var(--singkat) var(--ubah), opacity var(--singkat) var(--ubah); }

/* ── Formulir ──────────────────────────────────────────────────────────
 *
 * Bingkai fokus TIDAK diberi transisi. Fokus sering datang dari papan ketik,
 * dan gerak pada apa pun yang dipicu papan ketik selalu terasa lambat: yang
 * mengetik sudah tahu tujuannya, dia cuma ingin sampai. */
input, select, textarea { transition: border-color var(--kilas) var(--ubah); }
input:focus-visible, select:focus-visible, textarea:focus-visible { transition: none; }

/* Hasil undangan datang setelah menunggu jaringan, jadi kemunculannya perlu
   ditandai. Tanpa itu, teksnya tiba-tiba sudah ada dan orang tidak yakin
   apakah tombolnya benar-benar bekerja. */
.undangan-hasil { animation: masuk var(--masuk) var(--datang) backwards; }

/* ── Yang SENGAJA tidak digerakkan ─────────────────────────────────────
 *
 * Ditulis sebagai aturan, bukan sekadar dibiarkan kosong, supaya tidak ada
 * yang menambahkannya "biar seragam" di kemudian hari.
 *
 * Baris tabel: 611 baris, dan daftarnya digambar ulang tiap kali disaring
 * atau diurutkan. Gerak di sini bukan kehalusan, tapi penundaan yang berulang
 * puluhan kali per sesi. */
#layar[data-masuk="1"] tbody tr,
#layar[data-masuk="1"] .saring,
#layar[data-masuk="1"] .cip { animation: none; }

/* ── Kalau sistemnya diminta tenang ────────────────────────────────────
 *
 * Bukan basa-basi kepatuhan. Gerak bisa memicu mual dan pusing pada sebagian
 * orang, dan mereka sudah menyatakannya lewat setelan sistem. Yang dimatikan
 * geraknya, BUKAN keadaan akhirnya: semua tetap terbaca dan tetap di tempatnya. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .kartu-camp:hover { transform: none; }
  button.aksi:hover, button.aksi:active, button.tombol:active, .cip:active { transform: none; }
}

/* Hasil pemeriksaan hashtag: tiga keadaan, tiga rupa.
   Warnanya membawa arti, bukan hiasan. "Belum tahu" sengaja TIDAK merah:
   merah berarti ada yang salah, padahal yang terjadi cuma kita belum berhasil
   bertanya, dan hashtagnya mungkin sehat-sehat saja. */
.cek-ya, .cek-nol, .cek-gagal {
  display: inline-block; font-size: 11px; font-weight: 620;
  padding: 2px 8px; border-radius: 999px; margin-right: 7px;
  border: 1px solid var(--rule-strong);
}
.cek-ya { color: var(--ink); border-color: var(--ink); }
.cek-nol { color: var(--ink-3); }
.cek-gagal { color: #8a5300; border-color: rgba(138, 83, 0, .38); background: rgba(138, 83, 0, .07); }
.cek-hasil p { margin: 0 0 8px; font-size: 13.5px; }
.cek-hasil p:last-child { margin-bottom: 0; }
.cek-hasil .sub { display: block; margin-top: 3px; }

/* ── Impor Excel ──────────────────────────────────────────────────────── */

/* Dua pintu masuk sejajar. Impor bukan setelan tersembunyi: bagi orang yang
   mengambil alih pekerjaan agensi lain, justru itu pintu pertamanya. */
.aksi-duo { display: flex; gap: 10px; flex-wrap: wrap; }

.impor-angka { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; }
.impor-angka > div {
  border: 1px solid var(--rule); border-radius: 12px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 2px;
}
.impor-angka b { font-size: 26px; font-weight: 650; letter-spacing: -0.028em; line-height: 1.15; }
.impor-angka span { font-size: 12.5px; color: var(--ink-2); }
.impor-angka small { font-size: 11.5px; color: var(--ink-3); margin-top: 4px; }

/* Dua kartu pilihan platform, dibatasi seperti sepasang tombol tarik. Isinya
   satu centang dan satu kalimat pendek; dibiarkan selebar halaman, kalimatnya
   berhenti di sepertiga kartu dan sisanya kosong. */
.impor-rencana { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 20px; max-width: 720px; }
.impor-rencana > div { border: 1px solid var(--rule); border-radius: 12px; padding: 15px 17px; }
.impor-rencana b { display: block; font-size: 14px; font-weight: 600; margin-bottom: 7px; }
.impor-rencana p { margin: 0 0 6px; font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }
.impor-rencana .sub { margin: 0; font-size: 12px; color: var(--ink-3); }

@media (max-width: 720px) {
  .impor-rencana { grid-template-columns: 1fr; }
  .aksi-duo .aksi { width: 100%; justify-content: center; }
}

/* ── Penanda penarikan yang sedang jalan ──────────────────────────────── */

.kerja-bilah { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }

.kerja-baris {
  display: flex; align-items: center; gap: 13px; position: relative;
  padding: 13px 16px; border: 1px solid var(--rule); border-radius: 12px;
  background: var(--surface); text-decoration: none; overflow: hidden;
}
.kerja-baris:hover { border-color: var(--rule-strong); }
.kerja-teks { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.kerja-teks b { font-size: 13.5px; font-weight: 600; }
.kerja-teks span { font-size: 12px; color: var(--ink-3); }

/* Cincin berputar, satu-satunya gerak berulang di seluruh sistem.
   Dibolehkan karena dia menjawab pertanyaan yang benar-benar sedang ditanya:
   "masih jalan atau sudah mati?". Berhenti sendiri begitu pekerjaannya
   selesai, jadi dia tidak pernah jadi hiasan yang berputar selamanya. */
.kerja-putar {
  width: 15px; height: 15px; flex: none; border-radius: 50%;
  border: 2px solid var(--rule-strong); border-top-color: var(--ink);
  animation: putar 700ms linear infinite;
}
.kerja-putar.kecil { width: 10px; height: 10px; border-width: 1.5px; margin-right: 5px; }
@keyframes putar { to { transform: rotate(360deg); } }

.kerja-maju {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--rule);
}
.kerja-maju > i { display: block; height: 100%; background: var(--ink); transition: width 400ms var(--laju); }

.kerja-tanda {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  display: grid; place-items: center; font-size: 12px; font-weight: 700; color: #fff;
}
.kerja-baris.beres .kerja-tanda { background: #1c7a4a; animation: centang 420ms var(--laju) backwards; }
.kerja-baris.gagal .kerja-tanda { background: #a63a24; }
.kerja-baris.beres { border-color: rgba(28, 122, 74, 0.34); background: rgba(28, 122, 74, 0.05); }
.kerja-baris.gagal { border-color: rgba(166, 58, 36, 0.34); background: rgba(166, 58, 36, 0.05); }

/* Centangnya muncul sekali, tidak berdenyut. Yang perlu disampaikan
   "sudah selesai", dan itu cuma perlu dikatakan satu kali. */
@keyframes centang {
  from { transform: scale(0.7); opacity: 0; }
  60%  { transform: scale(1.06); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

.cap.jalan { display: inline-flex; align-items: center; }

/* Pilihan platform sebelum menarik */
.tarik-plat {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 12px;
  border: 1px solid var(--rule); border-radius: 10px;
}
.tarik-plat .eyebrow { margin-right: 4px; }
.tarik-plat .glif { width: 15px; height: 15px; margin-right: 5px; vertical-align: -2px; }

.rencana-pilih {
  display: flex; align-items: flex-start; gap: 12px; cursor: pointer;
  border: 1px solid var(--rule); border-radius: 12px; padding: 15px 17px;
}
.rencana-pilih:hover { border-color: var(--rule-strong); }
.rencana-pilih input { width: 17px; height: 17px; accent-color: var(--ink); flex: none; margin: 2px 0 0; cursor: pointer; }
.rencana-pilih b { display: block; font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.rencana-pilih .glif { width: 15px; height: 15px; margin-right: 6px; vertical-align: -2px; }
.rencana-pilih p { margin: 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }

@media (prefers-reduced-motion: reduce) {
  .kerja-putar { animation: none; border-top-color: var(--rule-strong); }
}

/* Hashtag tebakan yang bisa ditekan. Tampil sebagai kata bergaris bawah di
   dalam kalimat, bukan tombol, karena dia memang bagian dari kalimatnya. */
.tag-tebak {
  font: inherit; color: var(--ink); background: none; border: 0; padding: 0;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-color: var(--rule-strong);
}
.tag-tebak:hover { text-decoration-color: var(--ink); }

/* ── Baris pengaturan akses yang terbuka di bawah pengguna ────────────── */

/* Dibuka DI TEMPATNYA, bukan di jendela terpisah. Baris penggunanya tetap
   terlihat di atas, jadi tidak ada keraguan sedang mengatur akses siapa. */
.baris-atur > td { padding: 0 !important; background: var(--surface-2, rgba(0,0,0,0.02)); }
.atur-isi { padding: 16px 18px 18px; }
.atur-isi .pilih-camp { margin-top: 10px; }
.atur-isi .tarik-aksi { margin-top: 14px; }
.atur-isi .galat:empty { display: none; }

/* Muncul dengan membuka, bukan dengan berkedip. Baris yang langsung ada di
   layar tanpa gerak apa pun membuat orang mencari-cari apa yang berubah. */
.baris-atur { animation: buka-baris 240ms var(--laju) backwards; }
@keyframes buka-baris {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .baris-atur { animation: none; } }

/* ── Menghapus campaign ───────────────────────────────────────────────── */

/* Warna bahaya dipakai HEMAT, dan itu bukan soal selera.
   Kalau merah dipakai di banyak tempat, dia berhenti berarti "berhenti dulu".
   Di seluruh sistem ini merah cuma muncul di dua tempat: penarikan yang gagal,
   dan panel ini. */
/* IKON SAMPAH DI BARIS JUDUL PANEL TARIK.
 *
 * Diam-diam abu-abu sampai disentuh, baru memerah. Tindakan yang jarang
 * dilakukan tidak perlu berteriak sepanjang waktu; yang dia butuhkan cuma
 * berada di tempat yang bisa ditemukan saat dicari. Merahnya disimpan untuk
 * saat jarinya sudah di atas ikonnya, dan untuk kotak pemastiannya.
 *
 * Sasaran sentuhnya 32 piksel, bukan seukuran ikonnya yang 15. Di layar sentuh,
 * sasaran sekecil ikon berarti meleset, dan meleset di sebelah tombol tarik
 * berarti memulai penarikan yang tidak diminta. */
.ikon-bahaya {
  margin-left: 10px; flex: none;
  width: 32px; height: 32px; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: 9px;
  background: none; color: var(--ink-3); cursor: pointer;
  transition: color var(--gerak), background var(--gerak), border-color var(--gerak);
}
.ikon-bahaya svg { width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.ikon-bahaya:hover { color: #a63a24; border-color: rgba(166, 58, 36, 0.3); background: rgba(166, 58, 36, 0.06); }
.ikon-bahaya:focus-visible { outline: 2px solid #a63a24; outline-offset: 2px; }

/* Tanpa ini, `kapan` yang memakai margin-left:auto mendorong ikonnya ke tepi
   dan jaraknya jadi berbeda-beda tiap campaign, tergantung panjang teksnya. */
.label-baris .pojok + .ikon-bahaya { margin-left: 12px; }
.label-baris > .ikon-bahaya:first-of-type:not(.pojok + .ikon-bahaya) { margin-left: auto; }

.panel.bahaya { border-color: rgba(166, 58, 36, 0.28); }
.panel.bahaya .keping { color: #a63a24; }
.panel.bahaya .sub { max-width: 62ch; margin-bottom: 16px; }

.aksi.bahaya { background: #a63a24; border-color: #a63a24; color: #fff; }
.aksi.bahaya:hover:not(:disabled) { background: #8f3120; border-color: #8f3120; }
.aksi.bahaya:disabled { background: var(--rule); border-color: var(--rule); color: var(--ink-3); }

/* Panel yang terbuka tumbuh dari tempatnya, tidak muncul begitu saja.
   Geraknya menjelaskan asal-usulnya: yang baru ini datang dari tombol yang
   barusan ditekan, bukan dari tempat lain. */
.panel.bahaya.buka { animation: hapusBuka 260ms var(--laju) backwards; }
@keyframes hapusBuka {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.hapus-rinci {
  /* Tiga angka yang harus dibaca sebagai SATU kelompok, jadi mereka harus
     berdekatan. Dibiarkan selebar panel, jaraknya jadi setengah meter di layar
     lebar dan ketiganya berhenti terbaca sebagai satu kesatuan. */
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; max-width: 620px;
  padding: 16px; border: 1px solid var(--rule); border-radius: 12px;
  background: rgba(166, 58, 36, 0.04);
}
.hapus-rinci > div { display: flex; flex-direction: column; gap: 3px; }

/* Kotak untuk satu hashtag tidak pernah butuh lebih dari ini. Kotak isian yang
   jauh lebih lebar daripada isinya membuat orang mengira ada yang kurang. */
.panel.bahaya .medan { max-width: 320px; }
.hapus-rinci .num { font-size: 21px; font-weight: 600; letter-spacing: -0.01em; }
.hapus-rinci span { font-size: 12px; color: var(--ink-3); }

/* Panel yang sudah dihapus MENYUSUT, tidak cuma memudar.
   Memudar saja meninggalkan lubang seukuran panelnya selama seperempat detik,
   dan lubang itu terbaca sebagai halaman yang rusak. Menyusut sekalian dengan
   tingginya membuat yang di bawahnya naik mengisi, dan itu yang menyampaikan
   "sudah tidak ada" tanpa satu kata pun. */
.panel.bahaya.lenyap {
  animation: hapusLenyap 400ms var(--laju) forwards;
  overflow: hidden; pointer-events: none;
}
@keyframes hapusLenyap {
  from { opacity: 1; transform: scale(1); max-height: 460px; }
  to   { opacity: 0; transform: scale(0.97); max-height: 0;
         padding-top: 0; padding-bottom: 0; margin-top: 0; margin-bottom: 0; border-width: 0; }
}

/* ── Tabel yang disambung sambil digulir ──────────────────────────────── */

.sambung {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 16px 4px 4px;
}
.sambung > span { font-size: 12px; color: var(--ink-3); }

@media (max-width: 720px) {
  .hapus-rinci { grid-template-columns: 1fr; gap: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .panel.bahaya.buka { animation: none; }
  .panel.bahaya.lenyap { animation-duration: 1ms; }
}

/* ── Link yang tidak bisa dipakai, dijelaskan sebabnya ────────────────── */

.tak-terbaca {
  margin-top: 18px; padding: 14px 16px;
  border: 1px solid var(--rule); border-radius: 12px; background: var(--wash);
  max-width: 760px;
}
.tak-terbaca .eyebrow { display: block; margin-bottom: 10px; }
.tak-terbaca ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.tak-terbaca li { display: grid; grid-template-columns: auto auto 1fr; gap: 8px; align-items: baseline;
  font-size: 12.5px; color: var(--ink-3); line-height: 1.6; }
.tak-terbaca b { font-size: 13.5px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.tak-terbaca .nama { font-weight: 550; color: var(--ink-2); white-space: nowrap; }

@media (max-width: 720px) {
  .tak-terbaca li { grid-template-columns: auto 1fr; }
  .tak-terbaca li > span:last-child { grid-column: 1 / -1; }
}

/* Klip dari platform yang tidak punya penarik: angkanya beku sejak diimpor. */
.cap.beku { border-color: var(--rule-strong); color: var(--ink-3); background: var(--wash); }

/* ── Baris ganda di halaman pemeriksaan impor ─────────────────────────── */

.ganda-panel {
  margin-top: 18px; padding: 16px;
  border: 1px solid var(--rule); border-radius: 12px; background: var(--wash);
  max-width: 900px;
}
.ganda-panel .eyebrow { display: block; margin-bottom: 8px; }

.ganda-tabel { font-size: 12.5px; }
.ganda-tabel th { font-size: 11.5px; }
.ganda-tabel td { padding: 6px 12px 6px 0; }

/* Dua baris satu video diikat jadi satu blok: yang atas tanpa garis bawah,
   yang bawah yang menutup. Tanpa itu, pasangan-pasangan berbaur jadi satu
   daftar panjang dan hubungan antar barisnya hilang. */
.ganda-tabel tr.ganda-atas td { border-bottom: 0; padding-bottom: 1px; }
.ganda-tabel tr.ganda-bawah td { padding-top: 1px; }
.ganda-tabel tr.ganda-atas:hover td,
.ganda-tabel tr.ganda-bawah:hover td { background: transparent; }

.ganda-tautan {
  font-family: ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; word-break: break-all;
}
.ganda-tabel .cap { font-size: 10.5px; }

/* Bilah kemajuan saat berkas impor sedang diperiksa. Satu garis, tanpa angka
   di dalamnya: angkanya sudah ada di kalimat di atasnya, dan mengulanginya di
   dalam bilah cuma menambah yang harus dibaca. */
.muat-bilah {
  width: min(340px, 100%); height: 4px; margin: 18px auto 0;
  background: var(--rule); border-radius: 999px; overflow: hidden;
}
.muat-bilah > i {
  display: block; height: 100%; background: var(--ink);
  transition: width 300ms var(--laju);
}

/* ══ PONSEL: TIDAK ADA YANG DIGESER KE KIRI ATAU KE KANAN ═════════════════
 *
 * Tabel klip punya sepuluh kolom dan lebarnya 733px. Di layar 375px dia dulu
 * dibungkus kotak yang bisa digeser mendatar, dan itu terlihat seperti solusi
 * padahal bukan: untuk membaca views satu klip, orang harus menggeser ke kanan,
 * lalu menggeser balik ke kiri untuk tahu klip siapa yang barusan dibaca. Nama
 * dan angkanya tidak pernah bisa dilihat bersamaan.
 *
 * Jadi di layar sempit tabelnya berhenti jadi tabel. Tiap baris jadi satu
 * kartu: nama creator dan platform di atas, angkanya di bawah dengan namanya
 * masing-masing, tautannya jadi tombol selebar kartu. Semua muat, tidak ada
 * yang perlu digeser.
 *
 * Batasnya 640px, bukan 720px seperti yang lain: antara 640 dan 720 tabelnya
 * masih cukup terbaca, dan kartu di layar selebar itu justru boros ruang.
 */

/* Pengurut layar sempit. Tersembunyi di layar lebar — di sana kepala tabel yang
   mengerjakan tugas ini, dan dua pengurut sekaligus cuma membingungkan. */
.urut-ponsel { display: none; align-items: center; gap: 9px; margin-bottom: 12px; }
.urut-ponsel label { font-size: 12px; color: var(--ink-3); flex: none; }
.urut-ponsel select {
  flex: 1; min-width: 0; min-height: 44px;
  padding: 0 12px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--surface); color: var(--ink);
}
.urut-ponsel button {
  flex: none; width: 44px; min-height: 44px;
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--surface); color: var(--ink-2);
  font-size: 11px; cursor: pointer;
}
.urut-ponsel button:hover { border-color: var(--rule-strong); color: var(--ink); }

@media (max-width: 640px) {
  .urut-ponsel { display: flex; }

  /* Kepala dan cap waktu tidak lagi berdesakan dalam satu baris.
     Sebelumnya .atas-kanan selebar 445px di layar 375px, dan "terakhir ditarik"
     berada 85px di luar layar — tidak terlihat, dan tidak ada tanda bahwa dia
     ada di sana. */
  .atas-kanan { flex-wrap: wrap; width: 100%; gap: 10px 14px; }
  .atas-kanan .peran { flex: 1 1 100%; }
  .stempel { text-align: left; }

  /* ── Tabel klip jadi kartu ──────────────────────────────────────────── */

  .gulung-x.kartu-hp { overflow-x: visible; margin: 0; padding: 0; }
  .gulung-x.kartu-hp table { display: block; width: 100%; font-size: 13.5px; }
  .gulung-x.kartu-hp thead { display: none; }
  .gulung-x.kartu-hp tbody { display: block; }

  .gulung-x.kartu-hp tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    padding: 14px 15px;
    margin-bottom: 10px;
    border: 1px solid var(--rule);
    border-radius: 12px;
    background: var(--surface);
  }
  .gulung-x.kartu-hp tbody tr:hover td,
  .gulung-x.kartu-hp tbody tr:last-child td { background: none; }
  .gulung-x.kartu-hp td {
    display: block; grid-column: 1 / -1;
    border: 0; padding: 0; text-align: left;
  }

  /* Baris pertama kartu: siapa, dan di platform mana. */
  .gulung-x.klip-tabel td.k-u {
    grid-column: 1; font-size: 14.5px; font-weight: 600;
    padding-bottom: 11px; margin-bottom: 10px;
    border-bottom: 1px solid var(--rule);
  }
  .gulung-x.klip-tabel td.k-p {
    grid-column: 2; text-align: right;
    padding-bottom: 11px; margin-bottom: 10px;
    border-bottom: 1px solid var(--rule);
  }
  .gulung-x.klip-tabel td.k-p .plat { font-size: 12px; color: var(--ink-3); }

  /* Tiap angka menyebut namanya sendiri, diambil dari data-l di HTML. */
  .gulung-x.kartu-hp td[data-l] {
    display: grid; grid-template-columns: 92px minmax(0, 1fr);
    gap: 12px; padding: 3px 0;
  }
  .gulung-x.kartu-hp td[data-l]::before {
    content: attr(data-l); color: var(--ink-3); font-size: 12px;
  }

  /* Sel tanpa isi tidak diberi baris sama sekali. Di satu campaign, 100% klip
     tidak punya angka suka; tanpa aturan ini tiap kartu memuat tiga baris
     kosong yang tidak memberi tahu apa pun. */
  .gulung-x.kartu-hp td.kosong { display: none; }

  .gulung-x.klip-tabel td.k-g { margin-top: 9px; }
  .gulung-x.klip-tabel td.k-g .tag-sel { display: flex; flex-wrap: wrap; gap: 5px; }

  /* Tautan jadi tombol selebar kartu. "buka" setinggi 44px tapi selebar 29px
     itu sasaran yang meleset terus di jempol. */
  .gulung-x.klip-tabel td.k-l { margin-top: 12px; }
  .gulung-x.klip-tabel td.k-l a {
    display: flex; align-items: center; justify-content: center;
    min-height: 44px; border: 1px solid var(--rule); border-radius: 10px;
    text-decoration: none; font-weight: 550; color: var(--ink);
  }
  .gulung-x.klip-tabel td.k-l a:hover { border-color: var(--rule-strong); background: var(--wash); }

  /* Judul kartu untuk tabel selain klip: nama pengguna, alamat email undangan.
     Selebar kartu, karena di sana tidak ada pasangan kanan seperti platform. */
  .gulung-x.kartu-hp td.kepala-kartu {
    font-size: 14.5px; font-weight: 600;
    padding-bottom: 11px; margin-bottom: 10px;
    border-bottom: 1px solid var(--rule);
  }

  /* Tombol tindakan di kaki kartu, berjejer dan cukup besar untuk jempol. */
  .gulung-x.kartu-hp td.aksi-kartu {
    margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px;
  }
  .gulung-x.kartu-hp td.aksi-kartu .aksi { flex: 1; min-width: 120px; justify-content: center; min-height: 44px; }

  /* Baris saringan platform. Campaign dengan lima platform membuat barisnya
     538px, dan kotaknya tidak bisa membungkus karena inline-flex. */
  .pilihan { display: flex; flex-wrap: wrap; }
  .saring { width: 100%; }

  /* Baris yang ditandai tetap terbaca sebagai kartu, bukan sebagai baris. */
  .gulung-x.klip-tabel tr.baris-tag { border-color: rgba(180, 140, 40, 0.45); }
  .gulung-x.klip-tabel tr.baris-hilang { background: var(--wash); }
}

/* Sasaran sentuh 44px, WCAG 2.5.5. Tombol saring dan pilihan platform dulu
   setinggi 32px — cukup untuk kursor, meleset untuk jempol. */
@media (pointer: coarse) {
  .saring .pilihan button { min-height: 44px; }
  .saring input[type="search"], .saring input[type="text"] { min-height: 44px; }
  .sambung button { min-height: 44px; }
  /* Tombol hapus campaign 32x32 terlalu kecil untuk jempol, dan tindakannya
     termasuk yang paling tidak boleh salah tekan. Area sentuhnya dinaikkan ke
     44 tanpa mengubah ukuran ikonnya. */
  .ikon-bahaya { min-width: 44px; min-height: 44px; }
  a.lewati { min-height: 44px; display: inline-flex; align-items: center; }
}

/* ══ ATRIBUT hidden HARUS BENAR-BENAR MENYEMBUNYIKAN ══════════════════════
 *
 * Peramban menerapkan `hidden` lewat stylesheet bawaannya, dan aturan bawaan
 * itu KALAH dari aturan apa pun di berkas ini. Jadi `.peran { display: flex }`
 * membuat elemen ber-atribut hidden tetap tergambar.
 *
 * Akibatnya terlihat di produksi: pemilih "Lihat sebagai" sudah disembunyikan
 * dengan benar oleh kodenya — server tidak mengirim daftar peran saat login
 * aktif, dan app.js menyetel hidden = true — tapi kotaknya tetap muncul,
 * kosong, tanpa satu pun pilihan di dalamnya.
 *
 * Satu baris ini memperbaikinya untuk semua pemakaian `hidden`, sekarang dan
 * nanti. Ini salah satu dari sedikit tempat yang memang pantas pakai
 * !important: dia menegakkan perilaku bawaan HTML, bukan menimpanya. */
[hidden] { display: none !important; }

/* ══ HALAMAN TANPA BINGKAI: MASUK, LUPA SANDI, UNDANGAN ═══════════════════
 *
 * Halaman-halaman ini cuma memuat satu kartu kecil. Ditaruh di pojok kiri atas
 * seperti halaman dashboard, kartunya terlihat seperti sisa dari tata letak
 * yang gagal dimuat, bukan seperti sesuatu yang memang cuma itu isinya. */

body[data-tanpa-bingkai] .utama {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 24px 16px;
}

/* Dua pengganjal lentur, bukan justify-content: center.
   justify-content memang menengahkan, tapi kalau isinya lebih tinggi dari
   layar — ponsel kecil, papan ketik terbuka — bagian ATASNYA yang terpotong
   dan tidak bisa digulir kembali. Pengganjal ini mengempis lebih dulu, jadi
   yang hilang cuma jarak kosongnya. */
body[data-tanpa-bingkai] .utama::before,
body[data-tanpa-bingkai] .utama::after {
  content: "";
  flex: 1 1 0;
  min-height: 8px;
}

body[data-tanpa-bingkai] .utama > .atas {
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
  margin-bottom: 22px;
  max-width: 420px;
}
body[data-tanpa-bingkai] .utama > .atas h1 { font-size: 22px; letter-spacing: -0.02em; }
body[data-tanpa-bingkai] .utama > .atas p { margin-top: 2px; }

body[data-tanpa-bingkai] .utama > #layar { width: 100%; }
/* Kartunya menjaga lebar maksimumnya sendiri — 420px untuk masuk, 520px untuk
   undangan — dan cuma perlu ditengahkan. */
body[data-tanpa-bingkai] #layar > .panel { margin-inline: auto; }

/* ── Tombol keluar di bilah sisi ──────────────────────────────────────── */

.siapa-nama { min-width: 0; flex: 1; }
.siapa-nama b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.siapa-nama > span { color: var(--ink-3); }

.siapa-keluar {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0;
  border: 1px solid transparent; border-radius: 9px;
  background: none; color: var(--ink-3); cursor: pointer;
}
.siapa-keluar svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round; }
.siapa-keluar:hover { border-color: var(--rule-strong); color: var(--ink); background: var(--surface); }
.siapa-keluar:disabled { opacity: 0.5; cursor: default; }

/* Di perangkat sentuh area 32px terlalu kecil, tapi memperbesar kotaknya
   membuat baris identitas ikut melar. Yang diperbesar cuma area sentuhnya,
   lewat kotak semu yang tidak ikut menggeser tata letak. */
@media (pointer: coarse) {
  .siapa-keluar { position: relative; }
  .siapa-keluar::after {
    content: ""; position: absolute; inset: -6px;
  }
}

/* Bilah sisi disembunyikan di layar sempit, jadi tombol keluar ikut hilang.
   Di sana dia dimunculkan kembali sebagai baris penuh di bawah menu. */
@media (max-width: 860px) {
  .siapa { display: flex; padding: 0; border-top: 0; margin-left: auto; }
  .siapa-bulat, .siapa-nama { display: none; }
  .siapa-keluar { width: 40px; height: 40px; }
}

/* ── Kotak isian dalam satu baris dibuat sama lebar ───────────────────── */

/* .medan tidak punya flex sama sekali, jadi tiap kotak selebar isinya sendiri
   dan dua kotak bersebelahan hampir tidak pernah sama. Di halaman undangan
   akibatnya paling kentara: "Nama kamu" sempit, "Buat sandi" lebar, dan
   barisnya terlihat seperti tersusun asal-asalan.
   Kotak centang DIKECUALIKAN lewat :has(). Tanpa pengecualian itu, centang
   Instagram dan TikTok ikut melar memenuhi barisnya. */
.baris-form > .medan:has(> input:not([type="checkbox"]):not([type="radio"])),
.baris-form > .medan:has(> select) { flex: 1 1 195px; min-width: 0; }

.baris-form > .medan > input:not([type="checkbox"]):not([type="radio"]),
.baris-form > .medan > select { width: 100%; min-width: 0; }

/* ══ HALAMAN UNDANGAN ═════════════════════════════════════════════════════
 *
 * Satu kartu, satu alur baca dari atas ke bawah: tanda, judul, apa yang
 * didapat, lalu apa yang harus diisi. Sebelumnya isinya tabel yang dipakai
 * ulang dari halaman lain, dan tabel di kartu sekecil ini terbaca seperti
 * potongan laporan, bukan seperti sambutan. */

.kartu-undangan { text-align: center; padding: 34px 30px 30px; }
.kartu-undangan .medan { text-align: left; }

.und-judul {
  margin: 18px 0 8px; font-size: 20px; font-weight: 650;
  letter-spacing: -0.02em; line-height: 1.3;
}
.und-sub { margin: 0 auto; max-width: 34ch; font-size: 13.5px; color: var(--ink-2); line-height: 1.6; }
.und-catatan { margin: 18px 0 0; font-size: 12.5px; color: var(--ink-3); }

/* Rincian dibaca sebagai daftar, bukan tabel. Label kecil di atas, isinya di
   bawah — susunan yang sama dipakai kotak isian di bawahnya, jadi seluruh
   kartu terbaca dengan satu irama. */
.und-rinci {
  margin: 24px 0 22px; padding: 16px 0;
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  display: flex; flex-direction: column; gap: 13px; text-align: left;
}
.und-rinci > div { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 12px; align-items: baseline; }
.und-rinci dt { font-size: 12px; color: var(--ink-3); }
.und-rinci dd { margin: 0; font-size: 13.5px; }
.und-camp { display: flex; flex-wrap: wrap; gap: 5px; }

.und-form { display: flex; flex-direction: column; gap: 14px; margin-bottom: 18px; }
/* Kedua kotak selebar kartu, jadi tidak ada lagi yang lebih pendek dari yang
   lain. Bertumpuk, bukan bersebelahan: di kartu 460px, dua kotak berdampingan
   menyisakan lebar yang terlalu sempit untuk mengetik nama perusahaan. */
.und-form .medan input { width: 100%; min-width: 0; }
.und-tombol { width: 100%; justify-content: center; }

/* ── Tanda besar yang menggambar dirinya sendiri ──────────────────────── */

.tanda-besar { display: inline-block; width: 52px; height: 52px; }
.tanda-besar svg { width: 100%; height: 100%; display: block; overflow: visible; }

.tanda-lingkar {
  fill: none; stroke-width: 2; stroke-linecap: round;
  stroke-dasharray: 152; stroke-dashoffset: 152;
  animation: gambarLingkar 520ms var(--laju) forwards;
}
.tanda-garis {
  fill: none; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 48; stroke-dashoffset: 48;
  animation: gambarGaris 260ms var(--laju) forwards;
}
.tanda-garis-1 { animation-delay: 380ms; }
.tanda-garis-2 { animation-delay: 500ms; }

.tanda-gagal .tanda-lingkar { stroke: rgba(166, 58, 36, 0.32); }
.tanda-gagal .tanda-garis { stroke: #a63a24; }
.tanda-undang .tanda-lingkar { stroke: var(--rule-strong); }
.tanda-undang .tanda-garis { stroke: var(--ink); }

@keyframes gambarLingkar { to { stroke-dashoffset: 0; } }
@keyframes gambarGaris { to { stroke-dashoffset: 0; } }

/* Kartunya sendiri masuk pelan, isinya menyusul sedikit demi sedikit. Jeda
   antar bagian sengaja pendek: yang diinginkan kesan halaman yang tersusun,
   bukan pertunjukan yang harus ditunggu. */
.kartu-undangan { animation: masuk 320ms var(--laju) backwards; }
.kartu-undangan > *:not(.tanda-besar) { animation: masuk 300ms var(--laju) backwards; }
.kartu-undangan > .und-judul { animation-delay: 120ms; }
.kartu-undangan > .und-sub { animation-delay: 170ms; }
.kartu-undangan > .und-rinci { animation-delay: 220ms; }
.kartu-undangan > .und-form { animation-delay: 270ms; }
.kartu-undangan > .und-tombol { animation-delay: 320ms; }
.kartu-undangan > .und-catatan { animation-delay: 220ms; }

/* Kartu gagal diberi warna sedikit, secukupnya untuk terbaca sebagai kabar
   buruk tanpa berteriak. */
.kartu-gagal { border-color: rgba(166, 58, 36, 0.22); }

@media (prefers-reduced-motion: reduce) {
  .kartu-undangan, .kartu-undangan > * { animation: none !important; }
  .tanda-lingkar, .tanda-garis { animation: none !important; stroke-dashoffset: 0 !important; }
}
