/* ==========================================================================
   cekipos - danacuan.id
   Stylesheet mandiri: TIDAK ada @import, TIDAK ada CDN, TIDAK ada font/asset
   eksternal. Aman untuk CSP site ini (default-src 'self' https: data:).

   Prinsip desain:
   - Tenang, tegas, tepercaya. Ini alat verifikasi keamanan, bukan kasino.
   - Kemewahan datang dari ruang, ritme, hierarki tipografi dan kedalaman tipis
     -- bukan dari webfont atau warna mencolok.
   - Terang & gelap sama-sama dirancang penuh. Semua pasangan teks/latar
     memenuhi WCAG AA.
   - Animasi HANYA pada transform & opacity. Tidak ada yang memicu layout.
   - Semua hook styling memakai CLASS + atribut [data-state]. TIDAK ADA selektor
     berbasis #id di file ini, jadi JS bebas memilih id-nya sendiri.

   Peta isi:
     01 Token          08 Panel progres dua fase (showpiece)
     02 Dasar/reset    09 Ringkasan, chip, exit
     03 Tata letak     10 Tabel hasil + lencana + keadaan menunggu
     04 Header/nav     11 Konten panjang: prose, TOC, FAQ, fitur, statistik
     05 Hero/intro     12 Footer
     06 Kartu          13 Responsif
     07 Form/tombol    14 Reduced motion & cetak
   ========================================================================== */

/* == 01 TOKEN ============================================================= */

:root {
  color-scheme: light;

  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "DejaVu Sans Mono", "Liberation Mono", monospace;

  /* Permukaan ------------------------------------------------------------ */
  --bg:          #f1f4f8;
  --bg-elev:     #ffffff;
  --bg-elev-2:   #fafcfd;
  --bg-sunken:   #eef2f6;
  --row-alt:     #f8fafb;
  --row-hover:   #f1f7f7;

  /* Teks ----------------------------------------------------------------- */
  --fg:          #0f1c26;   /* judul & teks utama            AA vs semua surface */
  --fg-soft:     #35485a;   /* paragraf panjang                        7.9:1 vs #fff */
  --fg-muted:    #576775;   /* teks pendukung                          5.6:1 vs #fff */
  --fg-faint:    #7d8b98;   /* HANYA untuk elemen non-teks (garis, ikon dekoratif) */

  /* Garis ---------------------------------------------------------------- */
  --border:      #d5dde5;
  --border-soft: #e6ebf0;
  --border-hard: #c2ccd6;

  /* Merek ---------------------------------------------------------------- */
  --brand:       #0d7a70;
  --brand-2:     #12968a;
  --brand-fg:    #ffffff;
  --brand-hover: #0a635b;
  --brand-tint:  #e7f4f2;
  --brand-tint-2:#d3ebe7;
  --brand-ring:  rgba(13, 122, 112, .26);

  /* Status --------------------------------------------------------------- */
  --blocked-bg: #fdeaea;  --blocked-fg: #96161b;  --blocked-bd: #f0bcbc;
  --clear-bg:   #e6f6ec;  --clear-fg:   #0f6b36;  --clear-bd:   #b6e0c5;
  --invalid-bg: #eceff2;  --invalid-fg: #4a5763;  --invalid-bd: #d4dae0;
  --error-bg:   #fdf1de;  --error-fg:   #8a5300;  --error-bd:   #f0d3a0;
  /* Oranye "sebagian diblokir" -- SENGAJA beda hue dari --error (amber),
     karena keduanya bisa muncul berdampingan di kolom yang sama dan artinya
     jauh berbeda: yang satu bukti pemblokiran parsial, yang satu "belum tahu". */
  --partial-bg: #fdece0;  --partial-fg: #a1400a;  --partial-bd: #f3c5a2;

  /* Kedalaman ------------------------------------------------------------ */
  --shadow-xs:  0 1px 1px rgba(15, 30, 45, .04);
  --shadow-sm:  0 1px 2px rgba(15, 30, 45, .05), 0 2px 6px -2px rgba(15, 30, 45, .06);
  --shadow:     0 1px 2px rgba(15, 30, 45, .04), 0 8px 20px -10px rgba(15, 30, 45, .16);
  --shadow-lg:  0 1px 2px rgba(15, 30, 45, .04), 0 20px 44px -22px rgba(15, 30, 45, .28);
  --hairline:   inset 0 1px 0 rgba(255, 255, 255, .85);
  --glow-brand: rgba(13, 122, 112, .11);
  --shimmer:    rgba(13, 122, 112, .16);
  --scrim:      rgba(255, 255, 255, .78);

  /* Bentuk & ukuran ------------------------------------------------------ */
  --r-xs:  6px;
  --r-sm:  10px;
  --r-md:  14px;
  --r-lg:  20px;
  --r-pill: 999px;
  --radius:    var(--r-sm);   /* alias lama */
  --radius-sm: var(--r-xs);   /* alias lama */

  --focus: #0b6d64;
  --maxw:  1080px;
  --maxw-prose: 72ch;
  --head-h: 60px;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --bg:          #0a1016;
    --bg-elev:     #121b23;
    --bg-elev-2:   #17222b;
    --bg-sunken:   #0e161d;
    --row-alt:     #151f27;
    --row-hover:   #17242c;

    --fg:          #e9eff5;
    --fg-soft:     #c2ceda;
    --fg-muted:    #95a6b5;
    --fg-faint:    #6d7f8e;

    --border:      #26323d;
    --border-soft: #1e2831;
    --border-hard: #35434f;

    --brand:       #2fb3a3;
    --brand-2:     #46c9b7;
    --brand-fg:    #05221e;
    --brand-hover: #4ed0be;
    --brand-tint:  #11302c;
    --brand-tint-2:#17423c;
    --brand-ring:  rgba(70, 201, 183, .30);

    --blocked-bg: #3a1a1c;  --blocked-fg: #ff9a9a;  --blocked-bd: #5d2a2d;
    --clear-bg:   #10301f;  --clear-fg:   #7ede9f;  --clear-bd:   #1f4d33;
    --invalid-bg: #222c35;  --invalid-fg: #b3c1cd;  --invalid-bd: #33414d;
    --error-bg:   #382a12;  --error-fg:   #f0c274;  --error-bd:   #574222;
    --partial-bg: #3d2210;  --partial-fg: #ffb07a;  --partial-bd: #61371a;

    --shadow-xs:  0 1px 1px rgba(0, 0, 0, .34);
    --shadow-sm:  0 1px 2px rgba(0, 0, 0, .42), 0 2px 6px -2px rgba(0, 0, 0, .38);
    --shadow:     0 1px 2px rgba(0, 0, 0, .44), 0 10px 24px -12px rgba(0, 0, 0, .7);
    --shadow-lg:  0 1px 2px rgba(0, 0, 0, .46), 0 22px 48px -22px rgba(0, 0, 0, .8);
    --hairline:   inset 0 1px 0 rgba(255, 255, 255, .045);
    --glow-brand: rgba(47, 179, 163, .13);
    --shimmer:    rgba(120, 220, 208, .12);
    --scrim:      rgba(10, 16, 22, .72);

    --focus: #5ad6c4;
  }
}

/* == 02 DASAR / RESET ===================================================== */

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

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

body {
  margin: 0;
  /* Cahaya lembut di puncak halaman: satu lapis, tidak berulang, tidak fixed
     -- jadi tidak ada biaya repaint saat menggulir. */
  background:
    radial-gradient(1100px 460px at 50% -180px, var(--glow-brand), transparent 70%)
      no-repeat top center,
    var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.62;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* SENGAJA TIDAK ADA `text-rendering: optimizeLegibility`.
     Pada halaman sepanjang ini (enam bagian penjelasan + sembilan tanya-jawab)
     ia memaksa kerja pembentukan teks tambahan sebelum teks bisa dilukis, dan
     itu penyebab teks lambat muncul yang terdokumentasi di perangkat Android
     kelas bawah -- yaitu perangkat mayoritas pembaca halaman ini. Tidak ada
     yang dibeli dengan biaya itu: tumpukan fontnya adalah font sistem, yang
     kerningnya sudah wajar, dan desain ini tidak memakai tipografi yang
     bergantung pada ligatur. Kalau suatu saat kerning judul memang diinginkan,
     pakai `font-kerning: normal` pada h1-h4 saja. */
  /* Jaring pengaman: halaman TIDAK PERNAH boleh menggulir mendatar.
     `clip` (bukan `hidden`) supaya position:sticky tetap hidup. */
  overflow-x: clip;
}

[hidden] { display: none !important; }

img, svg, video, canvas { max-width: 100%; height: auto; }

h1, h2, h3, h4 {
  color: var(--fg);
  line-height: 1.22;
  letter-spacing: -.021em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

a {
  color: var(--brand);
  text-decoration-color: color-mix(in srgb, var(--brand) 38%, transparent);
  text-underline-offset: .18em;
  transition: color .16s ease;
}
a:hover { color: var(--brand-hover); text-decoration-color: currentColor; }

:where(a, button, textarea, summary, input, select, [tabindex]):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

code, kbd, samp {
  font-family: var(--font-mono);
  font-size: .875em;
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  padding: .08em .38em;
  overflow-wrap: anywhere;
}

strong, b { font-weight: 600; color: var(--fg); }

hr {
  border: 0;
  border-top: 1px solid var(--border-soft);
  margin: 28px 0;
}

::selection { background: var(--brand-tint-2); color: var(--fg); }

/* Utilitas ---------------------------------------------------------------- */

.muted { color: var(--fg-muted); }
.small { font-size: .875rem; }
.nums  { font-variant-numeric: tabular-nums; }

.sr-only,
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  box-shadow: var(--shadow);
  padding: 10px 16px;
  font-weight: 600;
  text-decoration: none;
  transition: transform .18s ease;
}
.skip-link:focus { top: 12px; }

/* == 03 TATA LETAK ======================================================== */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: 20px;
}

main.wrap { padding-block: 32px 56px; }

/* Jarak antar-blok konten SEO. */
.section { margin-block: 44px; }
.section:first-child { margin-top: 0; }

.section-head { margin-bottom: 16px; }

.eyebrow {
  display: inline-block;
  margin: 0 0 8px;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand);
}

.section-title {
  margin: 0 0 6px;
  font-size: clamp(1.25rem, 2.6vw, 1.6rem);
}

.section-sub {
  margin: 0;
  color: var(--fg-muted);
  max-width: var(--maxw-prose);
}

/* == 04 HEADER ============================================================ */

/* Bawaan untuk SEMUA perangkat: latar buram (opaque), tanpa backdrop-filter.
   backdrop-filter pada elemen sticky selebar viewport memaksa kompositor
   mencuplik ulang lalu mengaburkan isi halaman yang lewat di bawah pita header
   PADA SETIAP BINGKAI GULIRAN. Itu salah satu sumber gulir tersendat dan
   regresi INP yang paling bisa diandalkan di Android kelas bawah -- perangkat
   mayoritas pembaca halaman ini -- dan tidak ada apa pun di halaman ini yang
   mendekati biayanya. Fallback @supports lama TIDAK menolong di sini: ia hanya
   menyelamatkan peramban yang sama sekali tidak punya backdrop-filter,
   sedangkan setiap peramban ponsel modern justru mengambil jalur yang mahal. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border-soft);
}

/* Kacanya dikembalikan HANYA di layar lebar dengan penunjuk presisi -- kira-kira
   "desktop": di sana anggaran bingkainya lapang dan efeknya memang terlihat.
   Perbedaan rupa di ponsel praktis tidak kentara; perbedaan waktu bingkainya
   sangat kentara. */
@media (min-width: 720px) and (pointer: fine) {
  @supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
    .site-head {
      background: var(--scrim);
      -webkit-backdrop-filter: saturate(160%) blur(12px);
      backdrop-filter: saturate(160%) blur(12px);
    }
  }
}

.head-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  min-height: var(--head-h);
  padding-block: 10px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--brand);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -.018em;
}

.brand-mark {
  display: inline-flex;
  border-radius: 8px;
  box-shadow: 0 2px 8px -3px var(--brand-ring);
  transition: transform .2s ease;
}
.brand:hover .brand-mark { transform: translateY(-1px); }
.brand-text { color: var(--fg); }

.head-tag {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--brand);
  background: var(--brand-tint);
  border: 1px solid var(--brand-tint-2);
  border-radius: var(--r-pill);
  padding: 3px 11px;
}

/* Navigasi opsional di header (dipakai bila builder markup menambahkannya). */
.head-nav {
  margin-left: auto;
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.head-nav a {
  text-decoration: none;
  color: var(--fg-muted);
  font-size: .875rem;
  font-weight: 600;
  padding: 7px 11px;
  border-radius: var(--r-xs);
  transition: color .16s ease, background-color .16s ease;
}
.head-nav a:hover { color: var(--fg); background: var(--bg-sunken); }
.head-nav a[aria-current] { color: var(--brand); background: var(--brand-tint); }

/* Remah roti (SEO + orientasi). */
.breadcrumb {
  margin: 0 0 18px;
  font-size: .8125rem;
  color: var(--fg-muted);
}
.breadcrumb ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
}
.breadcrumb li { display: inline-flex; align-items: center; gap: 6px; }
.breadcrumb li + li::before { content: '/'; color: var(--fg-faint); }
.breadcrumb a { text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }

/* == 05 HERO / INTRO ====================================================== */

.intro, .hero { margin-bottom: 26px; }

.intro h1, .hero h1 {
  margin: 0 0 12px;
  font-size: clamp(1.6rem, 4.6vw, 2.35rem);
  letter-spacing: -.028em;
  line-height: 1.16;
}

.lede {
  margin: 0 0 10px;
  max-width: 66ch;
  color: var(--fg-soft);
  font-size: 1.0625rem;
  line-height: 1.62;
}
.lede.small { font-size: .9375rem; color: var(--fg-muted); }
.lede strong { color: var(--fg); }

/* Baris "kenapa alat ini" di bawah judul: pembeda produk, bukan hiasan. */
.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}

.trust-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--fg-soft);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-pill);
  padding: 5px 13px 5px 10px;
  box-shadow: var(--shadow-xs);
}
.trust-item::before {
  content: '';
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint);
}

/* == 06 KARTU ============================================================= */

.card {
  position: relative;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm), var(--hairline);
  padding: 24px;
  margin-bottom: 24px;
}

.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

.card h2 {
  margin: 0 0 14px;
  font-size: 1.1875rem;
}

/* Kartu utama (form) sedikit lebih terangkat: ia adalah aksi utama halaman. */
.search-card {
  box-shadow: var(--shadow), var(--hairline);
  border-color: var(--border-hard);
}

.card-quiet {
  background: var(--bg-elev-2);
  box-shadow: none;
}

/* == 07 FORM & TOMBOL ===================================================== */

.field-label {
  display: block;
  font-weight: 600;
  margin-bottom: 8px;
  letter-spacing: -.01em;
}

textarea {
  width: 100%;
  min-height: 190px;
  resize: vertical;
  font-family: var(--font-mono);
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--fg);
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 13px 15px;
  box-shadow: inset 0 1px 2px rgba(15, 30, 45, .04);
  transition: border-color .16s ease, background-color .16s ease, box-shadow .16s ease;
}

textarea::placeholder { color: var(--fg-muted); opacity: .8; }

textarea:focus {
  border-color: var(--brand);
  background: var(--bg-elev);
  box-shadow: 0 0 0 4px var(--brand-ring);
}
textarea:focus-visible { outline-offset: 3px; }

.hint {
  margin: 10px 0 0;
  font-size: .875rem;
  line-height: 1.58;
  color: var(--fg-muted);
  max-width: 74ch;
}

.hint-warn {
  background: var(--error-bg);
  border: 1px solid var(--error-bd);
  color: var(--error-fg);
  border-radius: var(--r-xs);
  padding: 11px 13px;
}

/* Catatan kejujuran di bawah tabel: harus terbaca, bukan cetakan kecil yang
   sengaja disembunyikan. Netral warnanya supaya tidak terbaca sebagai error. */
.hint-note {
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-xs);
  padding: 13px 15px;
  max-width: none;
  color: var(--fg-soft);
}
.hint-note strong { color: var(--fg); }
.hint-note em { font-style: normal; font-weight: 600; color: var(--fg); }

/* Pilihan "cek akses nyata" ------------------------------------------------ */

.opt-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 16px;
  padding: 14px 15px;
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  transition: border-color .16s ease, opacity .16s ease;
}
.opt-row:hover { border-color: var(--border); }

/* Diredupkan saat daftar melebihi batas: pilihannya tetap terlihat, tapi jelas
   bahwa ia tidak akan berlaku pada kiriman ini. */
/* Baris "cek akses ISP" saat daftarnya melebihi plafon: diredupkan supaya
   terbaca sebagai tidak aktif.

   Yang diredupkan DIPILIH satu per satu, bukan seluruh .opt-row sekaligus.
   `opacity` pada induk berlaku untuk seluruh subpohon yang sudah dirender dan
   TIDAK bisa dibatalkan oleh anaknya, jadi meredupkan barisnya berarti ikut
   meredupkan #reach-live -- satu-satunya kalimat yang MENJELASKAN kenapa
   kotak centangnya baru saja mati sendiri. Justru kalimat itu yang harus
   paling terbaca di keadaan ini. */
.opt-row.is-off > input[type="checkbox"],
.opt-row.is-off .opt-text > label,
.opt-row.is-off .opt-text > .hint:not(.reach-live) { opacity: .68; }

.opt-row input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  margin: 3px 0 0;
  accent-color: var(--brand);
  cursor: pointer;
}

.opt-text { min-width: 0; }

.opt-text label {
  display: inline-block;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.4;
}

.opt-text .hint { margin-top: 5px; }

.reach-live:empty { display: none; }
.reach-live { color: var(--fg); font-weight: 600; }

.form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
}

.counter {
  margin: 0;
  font-size: .875rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg-muted);
}
.counter-over { color: var(--blocked-fg); font-weight: 600; }

.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  font: inherit;
  font-weight: 600;
  letter-spacing: -.01em;
  border-radius: var(--r-xs);
  border: 1px solid transparent;
  padding: 11px 22px;
  min-height: 46px;
  cursor: pointer;
  text-decoration: none;
  transition: transform .14s ease, background-color .16s ease,
              border-color .16s ease, box-shadow .16s ease, color .16s ease;
}
.btn:active:not(:disabled) { transform: translateY(1px); }

.btn-primary {
  --btn-spin: var(--brand-fg);
  background-color: var(--brand);
  background-image: linear-gradient(180deg, var(--brand-2), var(--brand));
  color: var(--brand-fg);
  box-shadow: 0 1px 2px rgba(15, 30, 45, .12), 0 6px 16px -8px var(--brand-ring);
}
.btn-primary:hover:not(:disabled) {
  background-image: linear-gradient(180deg, var(--brand-2), var(--brand-2));
  box-shadow: 0 2px 4px rgba(15, 30, 45, .14), 0 10px 22px -10px var(--brand-ring);
  transform: translateY(-1px);
}
.btn-primary:active:not(:disabled) { transform: translateY(0); }

.btn-ghost {
  --btn-spin: var(--fg-muted);
  background: transparent;
  color: var(--fg-muted);
  border-color: var(--border);
}
.btn-ghost:hover:not(:disabled) {
  color: var(--fg);
  border-color: var(--border-hard);
  background: var(--bg-sunken);
}

.btn:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; transform: none; }

/* Tombol saat permintaan sedang jalan.
   Labelnya dibuat transparan (TETAP ada di DOM untuk pembaca layar) dan spinner
   ditaruh absolut di tengah -- jadi lebar & tinggi tombol TIDAK berubah sedikit
   pun dan tidak ada geseran tata letak (CLS) saat pemeriksaan mulai/selesai. */
.btn.is-loading {
  cursor: progress;
  color: transparent;
  pointer-events: none;
}
.btn.is-loading::before {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 17px; height: 17px;
  border-radius: 50%;
  border: 2px solid var(--btn-spin, currentColor);
  border-top-color: transparent;
  animation: cek-spin .7s linear infinite;
}

/* == 08 PANEL PROGRES DUA FASE ============================================ */
/*
   Kontrak dengan JS: satu-satunya hal yang perlu diubah JS adalah atribut
   data-state pada tiap .step (idle | running | done | failed | skipped) --
   ikon, warna, konektor dan teks status ikut berubah sendiri.
   Kelas .is-idle/.is-running/.is-done/.is-failed/.is-skipped juga didukung
   sebagai alias, jadi kedua gaya penulisan JS sama-sama bekerja.

   Progres di sini NYATA: tiap langkah hanya jadi "done" ketika permintaannya
   benar-benar kembali. Tidak ada bilah persentase palsu -- yang ada hanya
   konektor antar-langkah yang terisi setelah langkah sebelumnya selesai.
*/

.progress-card {
  position: relative;
  overflow: hidden;
  /* Tinggi dicadangkan supaya munculnya panel tidak menggeser apa pun setelah
     render pertama (CLS ~0). Dua langkah = 52px + 52px + kepala + padding. */
  min-height: 188px;
}

.progress-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: linear-gradient(90deg, var(--brand), var(--brand-2), var(--brand));
}

.progress-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.progress-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -.015em;
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.progress-title::before {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 0 4px var(--brand-tint);
  animation: cek-breathe 1.9s ease-in-out infinite;
}

/* Penghitung waktu berjalan. Angka tabular + lebar minimum supaya digit yang
   bertambah tidak pernah menggeser apa pun. */
.progress-elapsed {
  font-family: var(--font-mono);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg-muted);
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-pill);
  padding: 4px 12px;
  min-width: 8ch;
  text-align: center;
}

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto;
  column-gap: 14px;
  align-items: start;
  padding-bottom: 18px;
  min-height: 52px;
}
.step:last-child { padding-bottom: 0; min-height: 34px; }

/* Konektor vertikal: terisi warna merek hanya setelah langkah ini benar-benar
   selesai. Ini satu-satunya "bilah kemajuan" di halaman -- dan ia jujur. */
.step:not(:last-child)::before {
  content: '';
  position: absolute;
  left: 13px;
  top: 32px;
  bottom: 6px;
  width: 2px;
  border-radius: 2px;
  background: var(--border);
  transition: background-color .3s ease;
}
.step[data-state="done"]:not(:last-child)::before,
.step.is-done:not(:last-child)::before { background: var(--brand); }
.step[data-state="failed"]:not(:last-child)::before,
.step.is-failed:not(:last-child)::before { background: var(--blocked-bd); }

.step-icon {
  position: relative;
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border-hard);
  background: var(--bg-elev);
  display: grid;
  place-items: center;
  flex: none;
}

.step-main { min-width: 0; padding-top: 2px; }

.step-label {
  display: block;
  /* margin: 0 WAJIB ADA, walaupun kelas ini biasanya dipakai pada <span>
     (yang memang tidak punya margin bawaan).
     Alasannya: setTitle() di index.php MENUKAR kelas paragraf judul panel dari
     .progress-title ke .step-label begitu pemeriksaan selesai, supaya titik
     berdenyutnya berhenti. .progress-title punya `margin: 0`; .step-label dulu
     tidak, dan tidak ada reset `p { margin: 0 }` di berkas ini (baris ~187
     hanya menyetel text-wrap), sementara `.card > :first-child` tidak berlaku
     karena paragraf itu anak .progress-top, bukan anak kartu. Jadi pada detik
     pekerjaan selesai paragraf itu mendadak mendapat margin bawaan peramban
     (1em atas + 1em bawah) dan seluruh tabel hasil tersentak ke bawah ~32px --
     tepat ketika pengguna sedang membaca hasilnya, di dalam panel yang komentar
     CSS-nya sendiri menjanjikan CLS nol. */
  margin: 0;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--fg);
  line-height: 1.35;
}

/* Baris catatan selalu memesan tingginya, walau kosong -> nol geseran saat
   teksnya berganti dari "biasanya <1 detik" ke "selesai dalam 0,4 dtk". */
.step-note {
  display: block;
  min-height: 1.3em;
  margin-top: 2px;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--fg-muted);
}

.step-state {
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fg-muted);
  white-space: nowrap;
  padding-top: 5px;
  min-width: 6.5ch;
  text-align: right;
}

/* --- keadaan: idle ------------------------------------------------------- */
.step[data-state="idle"] .step-label,
.step.is-idle .step-label { color: var(--fg-muted); font-weight: 600; }

.step[data-state="idle"] .step-icon::before,
.step.is-idle .step-icon::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--fg-faint);
}

/* --- keadaan: running ---------------------------------------------------- */
.step[data-state="running"] .step-icon,
.step.is-running .step-icon {
  border-color: var(--brand-tint-2);
  box-shadow: 0 0 0 4px var(--brand-tint);
}

.step[data-state="running"] .step-icon::after,
.step.is-running .step-icon::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 2px solid transparent;
  border-top-color: var(--brand);
  border-right-color: var(--brand);
  animation: cek-spin .78s linear infinite;
}

.step[data-state="running"] .step-state,
.step.is-running .step-state { color: var(--brand); }

.step[data-state="running"] .step-note,
.step.is-running .step-note { animation: cek-fade 2.2s ease-in-out infinite; }

/* --- keadaan: done ------------------------------------------------------- */
.step[data-state="done"] .step-icon,
.step.is-done .step-icon {
  border-color: var(--brand);
  background: var(--brand);
}

/* Centang digambar dengan dua sisi border yang diputar -- tanpa aset apa pun. */
.step[data-state="done"] .step-icon::before,
.step.is-done .step-icon::before {
  content: '';
  width: 6px; height: 11px;
  margin-top: -2px;
  border: 2px solid var(--brand-fg);
  border-top: 0;
  border-left: 0;
  border-radius: 1px;
  transform: rotate(43deg);
}

.step[data-state="done"] .step-state,
.step.is-done .step-state { color: var(--clear-fg); }

/* --- keadaan: failed ----------------------------------------------------- */
.step[data-state="failed"] .step-icon,
.step.is-failed .step-icon {
  border-color: var(--blocked-fg);
  background: var(--blocked-bg);
}

.step[data-state="failed"] .step-icon::before,
.step[data-state="failed"] .step-icon::after,
.step.is-failed .step-icon::before,
.step.is-failed .step-icon::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;              /* pemusatan absolut, tidak bergantung pada grid */
  width: 12px; height: 2px;
  border-radius: 2px;
  background: var(--blocked-fg);
}
.step[data-state="failed"] .step-icon::before,
.step.is-failed .step-icon::before { transform: rotate(45deg); }
.step[data-state="failed"] .step-icon::after,
.step.is-failed .step-icon::after { transform: rotate(-45deg); }

.step[data-state="failed"] .step-state,
.step.is-failed .step-state { color: var(--blocked-fg); }
.step[data-state="failed"] .step-note,
.step.is-failed .step-note { color: var(--blocked-fg); }

/* --- keadaan: skipped ---------------------------------------------------- */
.step[data-state="skipped"] .step-icon,
.step.is-skipped .step-icon {
  border-style: dashed;
  border-color: var(--border-hard);
  background: var(--bg-sunken);
}
.step[data-state="skipped"] .step-icon::before,
.step.is-skipped .step-icon::before {
  content: '';
  width: 10px; height: 2px;
  border-radius: 2px;
  background: var(--fg-faint);
}
.step[data-state="skipped"] .step-label,
.step.is-skipped .step-label { color: var(--fg-muted); font-weight: 600; }

/* Catatan kaki panel (mis. "hasil tetap ditampilkan walau fase 2 gagal"). */
.progress-foot {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
  font-size: .8125rem;
  color: var(--fg-muted);
}

/* == 09 RINGKASAN, CHIP, EXIT ============================================= */

.alert {
  border-radius: var(--r-sm);
  border: 1px solid;
  padding: 13px 15px;
  margin-bottom: 20px;
  font-size: .9375rem;
  box-shadow: var(--shadow-xs);
}
.alert-error { background: var(--blocked-bg); border-color: var(--blocked-bd); color: var(--blocked-fg); }
.alert-warn  { background: var(--error-bg);   border-color: var(--error-bd);   color: var(--error-fg); }
.alert-info  { background: var(--brand-tint); border-color: var(--brand-tint-2); color: var(--fg); }

/* Kotak sorot untuk konten panjang. */
.callout {
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  background: var(--bg-sunken);
  border-radius: var(--r-xs);
  padding: 14px 16px;
  margin: 18px 0;
  font-size: .9375rem;
  color: var(--fg-soft);
}
.callout-warn { border-left-color: var(--error-fg); background: var(--error-bg); color: var(--error-fg); border-color: var(--error-bd); }
.callout-info { border-left-color: var(--brand); }
.callout > :first-child { margin-top: 0; }
.callout > :last-child { margin-bottom: 0; }

.summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 0 0 16px;
  font-size: .9375rem;
}

.sum {
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  padding: 4px 13px;
  background: var(--bg-sunken);
  font-variant-numeric: tabular-nums;
}
.sum strong { color: inherit; font-weight: 700; }

.sum-blocked { background: var(--blocked-bg); border-color: var(--blocked-bd); color: var(--blocked-fg); }
.sum-clear   { background: var(--clear-bg);   border-color: var(--clear-bd);   color: var(--clear-fg); }
.sum-invalid { background: var(--invalid-bg); border-color: var(--invalid-bd); color: var(--invalid-fg); }
.sum-error   { background: var(--error-bg);   border-color: var(--error-bd);   color: var(--error-fg); }
.sum-partial { background: var(--partial-bg); border-color: var(--partial-bd); color: var(--partial-fg); }
.sum-total   { color: var(--fg-muted); }

.summary-reach { margin-top: -6px; align-items: baseline; }

/* Wadah kosong yang dibuat renderResults() di jalur AJAX (div#cekipos-reach-extra)
   dan diisi renderReachExtras() setelah fase 2 kembali. `display: contents`
   membuatnya tidak menghasilkan kotak sendiri, sehingga .summary-reach di
   dalamnya tetap bertetangga langsung dengan .summary di atasnya -- kalau tidak,
   `margin-top: -6px` di baris atas merapat ke tepi wadah, bukan ke ringkasan
   yang dimaksudnya, dan jarak antar-baris di jalur AJAX menyimpang dari jalur
   yang dirender server. Wadahnya tetap ada di DOM (getElementById tetap
   bekerja); yang hilang hanya kotak tata letaknya. */
.reach-extra { display: contents; }

.sum-label {
  font-weight: 600;
  color: var(--fg-muted);
  align-self: center;
}

.exits {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 9px;
  margin: 0 0 16px;
  font-size: .875rem;
  color: var(--fg-muted);
}
.exits-label { font-weight: 600; color: var(--fg); }

.chips {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chip {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 6px;
  max-width: 100%;
  border: 1px solid var(--border);
  background: var(--bg-sunken);
  color: var(--fg);
  border-radius: var(--r-pill);
  padding: 3px 11px;
  font-size: .75rem;
  line-height: 1.5;
  /* Nama ISP & teks bukti berasal dari pihak ketiga: panjangnya tidak bisa
     diandalkan, jadi ia harus boleh membungkus, bukan mendorong tata letak. */
  white-space: normal;
  overflow-wrap: anywhere;
}

.chip-isp { font-weight: 600; }

.chip-state {
  font-weight: 700;
  text-transform: lowercase;
  letter-spacing: .01em;
}

.chip-sub {
  color: var(--fg-muted);
  font-size: .6875rem;
  font-variant-numeric: tabular-nums;
}

.chip-blocked { background: var(--blocked-bg); border-color: var(--blocked-bd); color: var(--blocked-fg); }
.chip-clear   { background: var(--clear-bg);   border-color: var(--clear-bd);   color: var(--clear-fg); }
.chip-unreach { background: var(--invalid-bg); border-color: var(--invalid-bd); color: var(--invalid-fg); }
.chip-error   { background: var(--error-bg);   border-color: var(--error-bd);   color: var(--error-fg); }
.chip-exit    { background: var(--brand-tint); border-color: var(--brand-tint-2); color: var(--fg); }

.chip-blocked .chip-sub,
.chip-clear .chip-sub,
.chip-unreach .chip-sub,
.chip-error .chip-sub { color: inherit; opacity: .82; }

/* <details> dipakai supaya tabel tetap pendek di ponsel: rincian per ISP hanya
   muncul kalau memang diminta. */
.isp-detail { margin-top: 8px; }

.isp-detail > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  list-style: none;
  cursor: pointer;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--fg-muted);
  padding: 3px 0;
  min-height: 28px;          /* target sentuh yang layak di ponsel */
  white-space: nowrap;
  transition: color .16s ease;
}
.isp-detail > summary::-webkit-details-marker { display: none; }
.isp-detail > summary::marker { content: ''; }

.isp-detail > summary::before {
  content: '';
  width: 0; height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform .18s ease;
}
.isp-detail[open] > summary::before { transform: rotate(90deg); }
.isp-detail > summary:hover { color: var(--fg); }

/* == 10 TABEL HASIL ======================================================= */

.results { scroll-margin-top: calc(var(--head-h) + 16px); }
.results[aria-busy="true"] .table-wrap { opacity: .92; }

/* Di layar kecil tabel digulir mendatar DI DALAM kotaknya sendiri --
   halaman itu sendiri tidak pernah ikut menggulir mendatar. */
.table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-elev);
  scrollbar-width: thin;
  scrollbar-color: var(--border-hard) transparent;
}

/* Bilah gulir yang selalu terlihat = petunjuk bahwa tabel bisa digeser. */
.table-wrap::-webkit-scrollbar { height: 10px; }
.table-wrap::-webkit-scrollbar-track { background: var(--bg-sunken); border-radius: 0 0 var(--r-sm) var(--r-sm); }
.table-wrap::-webkit-scrollbar-thumb {
  background: var(--border-hard);
  border-radius: var(--r-pill);
  border: 3px solid var(--bg-sunken);
}
.table-wrap::-webkit-scrollbar-thumb:hover { background: var(--fg-faint); }

.table-wrap:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

.tbl {
  width: 100%;
  min-width: 560px;
  /* separate + spacing 0: sudut membulat rapi DAN position:sticky pada sel
     bekerja andal (border-collapse:collapse bermasalah di sebagian browser). */
  border-collapse: separate;
  border-spacing: 0;
  font-size: .9375rem;
}

/* Lima kolom butuh ruang lebih. */
.tbl-reach { min-width: 760px; }

.tbl th,
.tbl td {
  text-align: left;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: top;
}

.tbl thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-sunken);
  color: var(--fg-muted);
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  padding-block: 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr:nth-child(even) td { background: var(--row-alt); }
.tbl tbody tr:hover td { background: var(--row-hover); }

/* Kolom nomor menempel di kiri saat tabel digeser: pengguna tidak pernah
   kehilangan jejak baris yang sedang dibaca. */
.tbl .col-no {
  position: sticky;
  left: 0;
  z-index: 1;
  width: 3.25rem;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
  font-size: .8125rem;
  background: var(--bg-elev);
  box-shadow: 1px 0 0 var(--border-soft);
}
.tbl thead .col-no { z-index: 3; background: var(--bg-sunken); }
.tbl tbody tr:nth-child(even) .col-no { background: var(--row-alt); }
.tbl tbody tr:hover .col-no { background: var(--row-hover); }

.col-input { max-width: 20rem; }
.col-domain { max-width: 15rem; }
.col-input code, .col-domain code {
  background: transparent;
  border: 0;
  padding: 0;
  font-size: .8125rem;
}
.col-domain code { color: var(--fg); font-weight: 600; }
.col-input code { color: var(--fg-muted); }

.col-status { white-space: nowrap; }
/* Kolom kelima boleh membungkus: isinya lencana + rincian per ISP. */
.col-reach { min-width: 16rem; max-width: 23rem; white-space: normal; }

/* Lencana ----------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: baseline;
  gap: .45em;
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.35;
  border-radius: var(--r-pill);
  border: 1px solid;
  padding: 4px 12px;
  white-space: nowrap;
}

/* Titik penanda: membedakan status tanpa hanya mengandalkan warna. */
.badge::before {
  content: '';
  flex: none;
  width: .5em; height: .5em;
  border-radius: 50%;
  background: currentColor;
}

.b-blocked { background: var(--blocked-bg); border-color: var(--blocked-bd); color: var(--blocked-fg); }
.b-clear   { background: var(--clear-bg);   border-color: var(--clear-bd);   color: var(--clear-fg); }
.b-invalid { background: var(--invalid-bg); border-color: var(--invalid-bd); color: var(--invalid-fg); }
.b-error   { background: var(--error-bg);   border-color: var(--error-bd);   color: var(--error-fg); }
/* Kolom akses: oranye = sebagian ISP memblokir, abu-abu = tidak terjangkau
   (BELUM TENTU diblokir -- teksnya menjelaskan ini di sel yang sama). */
.b-partial     { background: var(--partial-bg); border-color: var(--partial-bd); color: var(--partial-fg); }
.b-unreachable { background: var(--invalid-bg); border-color: var(--invalid-bd); color: var(--invalid-fg); }

/* Lencana kolom kelima kadang panjang ("Diblokir di semua ISP (3/3)"); di layar
   sempit ia boleh membungkus daripada memaksa tabel melebar. */
.col-reach .badge { white-space: normal; }

.reason {
  display: block;
  margin-top: 5px;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--fg-muted);
  white-space: normal;
}
.reason strong { color: var(--fg); }

/* Keadaan MENUNGGU untuk kolom "Akses dari ISP Indonesia" -------------------
   Dipakai di antara fase 1 (TrustPositif sudah tampil) dan fase 2 (probe ISP
   masih jalan). Sengaja NETRAL: garis putus-putus + abu-abu, tidak pernah
   hijau, supaya tidak ada yang salah membacanya sebagai "dapat diakses". */

.reach-pending {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  overflow: hidden;
  border: 1px dashed var(--border-hard);
  border-radius: var(--r-pill);
  background: var(--bg-sunken);
  color: var(--fg-muted);
  font-size: .8125rem;
  font-weight: 600;
  padding: 4px 13px;
  white-space: nowrap;
}

.reach-pending::before {
  content: '';
  flex: none;
  width: 9px; height: 9px;
  border-radius: 50%;
  border: 2px solid var(--fg-faint);
  border-top-color: transparent;
  animation: cek-spin .9s linear infinite;
}

/* Kilau tipis yang menyapu -- transform saja, tidak memicu layout. */
.reach-pending::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--shimmer), transparent);
  transform: translateX(-100%);
  animation: cek-shimmer 1.7s linear infinite;
  pointer-events: none;
}

/* Alias bila JS memilih memakai bentuk lencana. */
.b-pending {
  background: var(--bg-sunken);
  border-color: var(--border-hard);
  border-style: dashed;
  color: var(--fg-muted);
}
.b-pending::before { background: none; border: 2px solid currentColor; border-top-color: transparent; width: .6em; height: .6em; animation: cek-spin .9s linear infinite; }

/* Baris/sel yang menunggu boleh diberi kelas .is-pending untuk meredupkannya. */
.col-reach.is-pending { color: var(--fg-muted); }

/* == 11 KONTEN PANJANG (SEO) ============================================== */

.prose { max-width: var(--maxw-prose); }
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }

.prose h2 {
  margin: 2em 0 .55em;
  font-size: clamp(1.2rem, 2.6vw, 1.45rem);
  scroll-margin-top: calc(var(--head-h) + 20px);
}
.prose h3 {
  margin: 1.7em 0 .45em;
  font-size: 1.0625rem;
  font-weight: 600;
  scroll-margin-top: calc(var(--head-h) + 20px);
}
.prose p { margin: 0 0 1.05em; color: var(--fg-soft); }
.prose ul, .prose ol { margin: 0 0 1.05em; padding-left: 1.3rem; color: var(--fg-soft); }
.prose li { margin-bottom: .45em; }
.prose li::marker { color: var(--fg-faint); }
.prose li > ul, .prose li > ol { margin-top: .45em; }

/* Tautan jangkar di judul: muncul saat hover/fokus, tidak mengganggu ritme. */
.anchor {
  margin-left: .4em;
  font-size: .7em;
  font-weight: 400;
  color: var(--fg-faint);
  text-decoration: none;
  opacity: 0;
  transition: opacity .16s ease;
}
:hover > .anchor, .anchor:focus-visible { opacity: 1; }

/* Daftar isi -------------------------------------------------------------- */

.toc {
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-elev-2);
  padding: 16px 18px;
  margin-bottom: 26px;
}

.toc-title {
  margin: 0;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.toc-list {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 2px 20px;
}
.toc-list a {
  display: block;
  padding: 5px 0;
  font-size: .9375rem;
  text-decoration: none;
  color: var(--fg-soft);
  border-bottom: 1px solid transparent;
  transition: color .16s ease;
}
.toc-list a:hover { color: var(--brand); }

/* FAQ --------------------------------------------------------------------- */

.faq { display: grid; gap: 10px; }

.faq details,
details.faq-item {
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-elev);
  box-shadow: var(--shadow-xs);
  transition: border-color .16s ease, box-shadow .16s ease;
}
.faq details:hover,
details.faq-item:hover { border-color: var(--border-hard); }

.faq details[open],
details.faq-item[open] { background: var(--bg-elev-2); box-shadow: var(--shadow-sm); }

.faq summary,
details.faq-item > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  list-style: none;
  cursor: pointer;
  padding: 15px 18px;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--fg);
  min-height: 52px;
}
.faq summary::-webkit-details-marker,
details.faq-item > summary::-webkit-details-marker { display: none; }
.faq summary::marker,
details.faq-item > summary::marker { content: ''; }

/* Tanda +/- digambar dengan CSS: dua garis, satu diputar. */
.faq summary::after,
details.faq-item > summary::after {
  content: '';
  flex: none;
  width: 13px; height: 13px;
  background:
    linear-gradient(currentColor, currentColor) center / 13px 2px no-repeat,
    linear-gradient(currentColor, currentColor) center / 2px 13px no-repeat;
  color: var(--fg-faint);
  transition: transform .2s ease, color .16s ease;
}
.faq details[open] > summary::after,
details.faq-item[open] > summary::after { transform: rotate(45deg); color: var(--brand); }

.faq-a,
.faq details > :not(summary),
details.faq-item > :not(summary) {
  margin: 0;
  padding: 0 18px 16px;
  color: var(--fg-soft);
  font-size: .9375rem;
}
.faq-a > :first-child { margin-top: 0; }
.faq-a > :last-child { margin-bottom: 0; }
.faq-a p { margin: 0 0 .8em; padding: 0; }
.faq-a ul, .faq-a ol { margin: 0 0 .8em; padding-left: 1.3rem; }

/* Kartu fitur / pembeda produk -------------------------------------------- */

.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
  gap: 14px;
}

.feature {
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  background: var(--bg-elev-2);
  padding: 18px;
  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.feature:hover {
  transform: translateY(-2px);
  border-color: var(--border);
  box-shadow: var(--shadow-sm);
}

.feature-ico {
  display: inline-grid;
  place-items: center;
  width: 34px; height: 34px;
  margin-bottom: 12px;
  border-radius: 9px;
  background: var(--brand-tint);
  color: var(--brand);
  border: 1px solid var(--brand-tint-2);
  font-weight: 700;
}

.feature-title { display: block; margin: 0 0 6px; font-weight: 600; font-size: 1rem; letter-spacing: -.012em; }
.feature p { margin: 0; font-size: .9063rem; color: var(--fg-muted); line-height: 1.55; }

/* Angka pembeda (200 domain, 3 ISP, ~0,3 detik) ---------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.stat {
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  background: var(--bg-elev-2);
  padding: 14px 16px;
}

.stat-num {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--fg);
  line-height: 1.15;
}

.stat-lbl { display: block; margin-top: 3px; font-size: .8125rem; color: var(--fg-muted); }

/* Tautan terkait / pencarian terkait -------------------------------------- */

.link-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.link-card {
  display: block;
  border: 1px solid var(--border-soft);
  border-radius: var(--r-xs);
  background: var(--bg-elev-2);
  padding: 12px 14px;
  text-decoration: none;
  color: var(--fg);
  font-weight: 600;
  font-size: .9375rem;
  transition: border-color .16s ease, background-color .16s ease, transform .16s ease;
}
.link-card:hover { border-color: var(--brand); background: var(--brand-tint); transform: translateY(-1px); }
.link-card span { display: block; margin-top: 3px; font-weight: 400; font-size: .8125rem; color: var(--fg-muted); }

/* Catatan "tentang alat ini" ---------------------------------------------- */

.notes-list {
  margin: 0;
  padding-left: 1.2rem;
  color: var(--fg-soft);
  font-size: .9375rem;
}
.notes-list li { margin-bottom: 9px; }
.notes-list li:last-child { margin-bottom: 0; }
.notes-list li::marker { color: var(--fg-faint); }
.notes-list strong { color: var(--fg); }

/* == 12 FOOTER ============================================================ */

.site-foot {
  border-top: 1px solid var(--border-soft);
  background: var(--bg-elev);
  padding-block: 26px;
  color: var(--fg-muted);
  font-size: .875rem;
}
.site-foot p { margin: 0 0 5px; }
.site-foot p:last-child { margin-bottom: 0; }

.foot-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}
.foot-nav a { text-decoration: none; font-weight: 600; color: var(--fg-soft); }
.foot-nav a:hover { color: var(--brand); text-decoration: underline; }

/* == 13 RESPONSIF ========================================================= */

@media (max-width: 720px) {
  main.wrap { padding-block: 24px 44px; }
  .section { margin-block: 34px; }
}

@media (max-width: 560px) {
  .wrap { padding-inline: 16px; }
  .card { padding: 18px; border-radius: var(--r-sm); }
  .form-foot { flex-direction: column; align-items: stretch; }
  .btn-row { justify-content: stretch; }
  .btn-row .btn { flex: 1 1 auto; }
  .head-tag { display: none; }
  .opt-row { padding: 12px; gap: 10px; }
  .summary-reach { margin-top: 0; }
  .progress-card { min-height: 196px; }
  .step-state { display: none; }          /* ikon + catatan sudah cukup jelas */
  .step { grid-template-columns: 28px minmax(0, 1fr); }
  /* Di layar sempit catatan langkah hampir selalu membungkus jadi dua baris.
     Ruangnya dipesan dua baris sejak awal supaya pergantian teks (mis. dari
     "biasanya 17-30 detik" ke "selesai dalam 21,3 detik") tidak menggeser
     apa pun di bawahnya. */
  .step-note { min-height: 2.75em; }
  .tbl th, .tbl td { padding: 10px 12px; }
  .faq summary, details.faq-item > summary { padding: 13px 15px; }
  .faq-a, .faq details > :not(summary), details.faq-item > :not(summary) { padding: 0 15px 14px; }
}

/* Ponsel sempit (360px). Tidak ada yang boleh meluber keluar layar: tabel
   digulir di dalam .table-wrap, sisanya membungkus. */
@media (max-width: 400px) {
  .wrap { padding-inline: 13px; }
  .card { padding: 15px; }
  .intro h1, .hero h1 { font-size: 1.5rem; }
  .lede { font-size: 1rem; }
  .exits { font-size: .8125rem; }
  .chip { font-size: .6875rem; padding: 2px 9px; }
  .tbl { font-size: .875rem; }
  .tbl-reach { min-width: 700px; }
  .col-reach { min-width: 14.5rem; }
  .isp-detail > summary { min-height: 32px; }
  .progress-top { gap: 8px; }
  .stat-num { font-size: 1.3rem; }
}

/* == 14 GERAK, KEYFRAME, CETAK ============================================ */

@keyframes cek-spin    { to { transform: rotate(360deg); } }
@keyframes cek-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@keyframes cek-fade    { 0%, 100% { opacity: 1; } 50% { opacity: .58; } }
@keyframes cek-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* prefers-reduced-motion: TIDAK ada putaran, kilau, atau animasi transform.
   Setiap keadaan tetap terbaca lewat bentuk statis + warna + teks status.
   Penghitung detik yang berdetak (diperbarui JS) tetap memberi tanda hidup. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  .btn:active:not(:disabled),
  .btn-primary:hover:not(:disabled),
  .feature:hover,
  .link-card:hover,
  .brand:hover .brand-mark { transform: none; }

  /* Spinner langkah -> cincin penuh statis. */
  .step[data-state="running"] .step-icon::after,
  .step.is-running .step-icon::after {
    border-color: var(--brand);
    animation: none;
  }
  /* Tombol memuat -> cincin penuh statis, bukan lingkaran berputar. */
  .btn.is-loading::before {
    border-top-color: var(--btn-spin, currentColor);
    animation: none;
  }

  /* Sel ISP menunggu -> tanpa kilau, tanpa putaran; titik padat + garis
     putus-putus + teks "menunggu" yang sudah ada di markup. */
  .reach-pending::after { display: none; }
  .reach-pending::before {
    border-color: var(--fg-faint);
    background: var(--fg-faint);
    animation: none;
  }
  .b-pending::before { border-top-color: currentColor; animation: none; }

  .progress-title::before { animation: none; }
  .step-note { animation: none !important; }
}

/* Cetak: laporan verifikasi yang rapi. Semua kontrol dibuang, warna dipaksa
   terang, tabel dibiarkan mengalir penuh. */
@media print {
  @page { margin: 14mm; }

  body {
    background: #fff !important;
    color: #000 !important;
    font-size: 11pt;
  }

  /* Alert TIDAK disembunyikan: catatan seperti "sebagian baris dilewati" ikut
     menentukan cara membaca laporannya. */
  .site-head, .site-foot, .search-card, .progress-card, .btn-row, .opt-row,
  .toc, .skip-link, .head-nav, .foot-nav, .link-cards, .breadcrumb,
  .features, .faq { display: none !important; }

  a { color: #000 !important; text-decoration: none; }
  .card {
    box-shadow: none !important;
    border: 1px solid #999 !important;
    break-inside: avoid;
    padding: 10pt 12pt;
    margin-bottom: 14pt;
    background: #fff !important;
  }
  .alert {
    border: 1px solid #666 !important;
    background: none !important;
    color: #000 !important;
    box-shadow: none;
  }
  .table-wrap { overflow: visible !important; border-color: #999 !important; }
  .tbl, .tbl-reach { min-width: 0 !important; font-size: 9.5pt; }
  .tbl thead th { position: static; background: #eee !important; color: #000 !important; }
  .tbl .col-no { position: static; box-shadow: none; background: none !important; }
  .tbl tbody tr { break-inside: avoid; }
  .tbl tbody tr:nth-child(even) td { background: #f6f6f6 !important; }

  .badge, .chip, .sum {
    border: 1px solid #666 !important;
    background: none !important;
    color: #000 !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .badge::before { background: #000 !important; }

  /* CATATAN: isi <details> yang tertutup TIDAK bisa dipaksa terbuka lewat CSS
     (aturan UA menang atas author, bahkan dengan !important). Jadi rincian per
     ISP hanya ikut tercetak kalau pengguna sudah membukanya di layar; ringkasan
     "Rincian N ISP" tetap dicetak supaya jelas ada data yang belum terlihat. */
  .isp-detail > summary { color: #000 !important; }

  .hint, .reason, .notes-list { color: #222 !important; }
  .hint-note { border: 1px solid #999 !important; background: none !important; }
}
