/* ============================================================
   Webiko — assets/css/style.css
   Stylesheet utama. Ditulis vanilla CSS, mobile-first.
Arah visual: neo-brutalist "indigo pop" (rujukan visual canvas saja,
   teks/konten canvas tidak dipakai — copy UI milik Webiko).
   Tanpa framework, tanpa build step, tanpa dependency eksternal.

   Struktur file:
   1. Token (:root)
   2. Reset ringan & base
   3. Layout (container, section, grid)
   4. Komponen (btn, card, navbar, sidebar, footer, badge, alert, ...)
   5. Breakpoint (768px, 1024px)
   6. Aksesibilitas (prefers-reduced-motion, forced-colors)
   7. Halaman beranda (hero, panel kode, langkah, rapor contoh)
   ============================================================ */

/* ============================================================
   1. TOKEN
   Semua warna, ukuran, dan jarak berasal dari sini.
   Jangan hardcode warna di luar blok ini — pakai var().
   ============================================================ */
:root {
  /* Native control (scrollbar, isian) ikut tema halaman, bukan OS. */
  color-scheme: light;

  /* --- Warna: brand & aksen ---------------------------------
     Keluarga violet-nya condong ke biru (indigo), hue 231-242
     derajat, bukan ungu kemerahan. Kuning tetap jadi satu-satunya
     warna aksi supaya lawan warnanya makin kontras. */
  --color-primary: #433fd4;          /* violet aksen (fill), 7.24:1 di atas putih */
  --color-primary-hover: #332fc4;
  --color-primary-active: #2b27a8;
  --color-primary-soft: #8e8bf0;     /* fill dekoratif / badge */

  --color-secondary: #b8befb;        /* lilac indigo, 9.45:1 dengan --color-ink */
  --color-secondary-hover: #aab5f7;
  --color-secondary-active: #97a4f2;

  --color-accent: #ffe14d;           /* kuning pop, 12.86:1 dengan --color-on-accent */
  --color-accent-hover: #ffe97a;
  --color-accent-active: #f5d21f;

  /* Fill penanda (nomor bab, nomor langkah, logo). Sama dengan aksen di
     kedua tema, dan di tema gelap ikut aksen versi redup. */
  --color-marker-bg: var(--color-accent);

  /* Alias untuk layout.css. Bukan warna baru: cukup menamai ulang
     token yang sudah ada agar konsumen lama tidak putus. */
  --color-lilac: var(--color-secondary);
  --color-accent-2: var(--color-accent);

  --color-mint: #a8f0d0;
  --color-pink: #ffb7c5;

  /* --- Warna: permukaan & teks ------------------------------ */
  --color-background: #ecedfb;       /* latar halaman */
  --color-surface: #ffffff;          /* kartu */
  --color-surface-soft: #d6d9fc;     /* panel lilac indigo muda */
  --color-surface-raised: #aab5f7;   /* header, CTA */
  --color-ink: #1a1b33;              /* teks utama & border, 14.48:1 di latar */
  --color-ink-inverse: #ffffff;      /* teks di atas fill gelap */
  --color-on-accent: #1f1a33;        /* teks di atas fill terang (canvas) */
  --color-border: #1a1b33;
  --color-border-muted: #bdc1e3;     /* garis pembatas lembut */
  --color-disabled-bg: #e3e4f3;      /* isian/tombol nonaktif */

  /* Teks sekunder / aksen teks. Nilai canvas digelapkan
     secukupnya agar lolos WCAG AA (lihat laporan di ticket). */
  --color-muted: #3a3c7e;            /* 5.01:1 di --color-surface-raised */
  --color-accent-text: #3130b8;      /* 5.25:1 di --color-secondary */
  --color-accent-text-brand: #433fd4; /* canvas primary; teks besar/aksen di atas background */
  --color-placeholder: #595b73;      /* 4.79:1 di --color-surface-soft */

  /* --- Warna: status --------------------------------------- */
  --color-error: #b71c3a;
  --color-error-bg: #ffe3e8;
  --color-success: #046b3c;
  --color-success-bg: #d6f7e4;
  --color-warning: #7a4b00;
  --color-warning-bg: #fff3cf;
  --color-info: #2a2f8f;
  --color-info-bg: #e3e3ff;

  /* --- Warna: shadow (hard, tanpa blur) --------------------- */
  --color-shadow: #1a1b33;
  --color-shadow-accent: #3130b8;

  /* --- Tipografi ------------------------------------------- */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  /* Monospace hanya untuk potongan kode — bahannya memang kode. */
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --fs-h1: clamp(2rem, 6vw, 3.25rem);
  --fs-h2: clamp(1.625rem, 4.5vw, 2.5rem);
  --fs-h3: 1.375rem;
  --fs-h4: 1.125rem;
  --fs-h5: 1rem;
  --fs-h6: 0.875rem;
  --fs-body: 1rem;
  --fs-lg: 1.125rem;                 /* body besar / sub-judul kecil */
  --fs-lead: 1.0625rem;
  --fs-small: 0.875rem;
  --fs-sm: 0.9375rem;                /* teks UI sekunder */
  --fs-xs: 0.75rem;                  /* keterangan sangat kecil */
  --fs-label: 0.6875rem;             /* eyebrow / badge kecil */
  --fs-code: 0.8125rem;              /* potongan kode */

  --lh-display: 1.02;                /* heading besar */
  --lh-heading: 1.2;
  --lh-body: 1.65;
  --lh-small: 1.5;
  --lh-code: 1.75;

  --fw-regular: 500;
  --fw-bold: 700;
  --fw-black: 900;

  --tracking-display: -0.035em;
  --tracking-tight: -0.015em;
  --tracking-label: 0.18em;

  --measure: 62ch;                   /* panjang baris maksimum */

  /* --- Spacing (skala 4) ----------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;

  /* --- Border & radius ------------------------------------- */
  --border-w: 3px;
  --border-w-thin: 2px;              /* hanya untuk elemen hias kecil */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 1.25rem;
  --radius-pill: 999px;

  /* Hard shadow: offset-x offset-y 0 (tanpa blur) warna ink. */
  --shadow-hard-sm: 3px 3px 0 0 var(--color-shadow);
  --shadow-hard: 4px 4px 0 0 var(--color-shadow);
  --shadow-hard-hover: 6px 6px 0 0 var(--color-shadow);
  --shadow-hard-lg: 8px 8px 0 0 var(--color-shadow);
  --shadow-focus: 5px 5px 0 0 var(--color-shadow-accent);
  --shadow-none: 0 0 0 0 var(--color-shadow);
  --shadow-tile: 4px 4px 0 var(--color-ink);

  /* --- Layout ---------------------------------------------- */
  --container-max: 1152px;           /* setara max-w-6xl */
  --container-pad: var(--space-4);
  --tap-target: 44px;                /* ukuran sentuh minimum */
  --navbar-h: 64px;                  /* tinggi navbar */
  --sidebar-w: 17.5rem;              /* lebar sidebar materi */

  /* --- Kode (panel contoh) --------------------------------- */
  /* Panel kode sengaja gelap di kedua tema: potongan kode harus
     terbaca sama, dan warna di dalamnya memakai fill brand. */
  --color-code-bg: #1a1b33;
  --color-code-bar: #242750;
  --color-code-ink: #f3efff;         /* 16.78:1 di --color-code-bg */
  --color-code-muted: #a9aae4;       /* 7.65:1 di --color-code-bg */
  --color-code-tag: #8e8bf0;         /* 5.69:1 di --color-code-bg */
  --color-code-attr: #ffe14d;
  --color-code-string: #a8f0d0;

  /* --- Motion ---------------------------------------------- */
  --dur-fast: 120ms;
  --dur-base: 180ms;
  --dur-reveal: 520ms;
  --stagger: 70ms;                   /* jeda antar elemen saat muncul */
  --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1);
  --transition: var(--dur-base) var(--ease-out);
}

/* ============================================================
   TEMA GELAP
   Bukan lewat media query, tapi lewat atribut `data-tema` di <html>.
   Alasannya: pengguna harus bisa memaksa tema sendiri, tidak cuma
   ikut setelan sistem.

   Script kecil di <head> tiap halaman mengisi atribut itu SEBELUM
   halaman digambar — "terang" atau "gelap", hasil gabungan pilihan
   tersimpan (localStorage "tema") dan setelan sistem. Jadi blok ini
   satu-satunya sumber token gelap; tidak ada salinan kedua.

   Tanpa JavaScript atributnya tidak pernah ada, dan halaman memakai
   token terang di :root.

   Prinsip warna: garis dan shadow tidak memakai putih penuh
   (menyilaukan) melainkan lilac indigo; permukaan dibedakan lewat tiga
   tingkat terang; kuning hanya untuk aksi; dan setiap pasangan teks
   tetap >= 4.5:1 (angkanya ada di tiap baris).
   ============================================================ */

:root[data-tema="gelap"] {
  color-scheme: dark;

  --color-background: #11132b;
  --color-surface: #1a1d3a;
  --color-surface-soft: #242750;
  --color-surface-raised: #383a70;
  --color-ink: #f1efff;            /* 9.23:1 di --color-surface-raised */
  --color-ink-inverse: #12142d;    /* teks di atas fill terang, 5.14:1 di --color-primary */
  --color-on-accent: #1f1a33;
  --color-border: #8a8dda;         /* lilac indigo, bukan putih: 5.99:1 di background */
  --color-border-muted: #3a3f68;
  --color-disabled-bg: #2b2e57;

  --color-muted: #b4b5ea;          /* 5.35:1 di --color-surface-raised */
  --color-accent-text: #c8c6ff;    /* 6.47:1 di --color-surface-raised */
  --color-accent-text-brand: #c8c6ff;
  --color-placeholder: #a9aae4;    /* 6.45:1 di --color-surface-soft */

  /* Violet dinaikkan terangnya supaya teks --color-ink-inverse di
     atasnya lolos AA (5.14:1; tema sebelumnya cuma 2.62:1). */
  --color-primary: #7e7bf0;
  --color-primary-hover: #6765ec;
  --color-primary-active: #5352e6;
  --color-primary-soft: #9c9bf5;

  --color-secondary: #383e8f;      /* 8.22:1 dengan --color-ink */
  --color-secondary-hover: #3f44a0;
  --color-secondary-active: #49489f;

  --color-mint: #a8f0d0;
  --color-pink: #ffb7c5;

  /* Kuning diturunkan dari #ffe14d. Di latar sedalam ini kuning murni
     jadi satu-satunya titik paling terang, dan karena warnanya dipakai
     di banyak elemen, halaman terbaca seperti pola peringatan.
     11.25:1 dengan --color-on-accent. */
  --color-accent: #f0d264;
  --color-accent-hover: #f5dc81;
  --color-accent-active: #e0bf4a;

  /* Penanda tetap pakai kuning mentah #ffe14d seperti tema terang, bukan
     --color-accent yang sudah diredupkan: penanda bentuknya kecil, jadi
     warnanya yang terang justru membantu, dan penampangnya sama dengan
     tema terang. Kontras dengan --color-on-accent 12.86:1. */
  --color-marker-bg: #ffe14d;

  --color-error: #ff9aae;          /* 7.44:1 di --color-error-bg */
  --color-error-bg: #47152a;
  --color-success: #7de0af;        /* 9.02:1 di --color-success-bg */
  --color-success-bg: #0b3021;
  --color-warning: #f0d264;        /* 9.14:1 di --color-warning-bg */
  --color-warning-bg: #3a2c06;
  --color-info: #b9b3ff;           /* 7.70:1 di --color-info-bg */
  --color-info-bg: #232059;

  /* Shadow tetap offset keras, tapi jadi langkah violet-biru (2.41:1
     dari background) — bukan balok putih 8px yang bikin kartu
     menyilaukan. */
  --color-shadow: #4a4d94;
  --color-shadow-accent: #6f75f0;

  --color-code-bg: #0d0f22;
  --color-code-bar: #1a1d3a;
}

/* ============================================================
   2. RESET RINGAN & BASE
   ============================================================ */

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

* {
  margin: 0;
}

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

body {
  min-height: 100vh;
  background-color: var(--color-background);
  color: var(--color-ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img,
picture,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
}

img,
video {
  height: auto;
}

svg {
  flex-shrink: 0;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: 0;
}

a {
  color: var(--color-accent-text);
  text-decoration: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 3px;
}

a:hover {
  color: var(--color-accent-text);
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  padding: 0;
}

::selection {
  background-color: var(--color-accent);
  color: var(--color-on-accent);
}

/* --- Tipografi dasar -------------------------------------- */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
}

h2 {
  font-size: var(--fs-h2);
}

h3 {
  font-size: var(--fs-h3);
}

h4 {
  font-size: var(--fs-h4);
}

h5 {
  font-size: var(--fs-h5);
}

h6 {
  font-size: var(--fs-h6);
}

p,
li {
  max-width: var(--measure);
}

small,
.text-small {
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}

strong,
b {
  font-weight: var(--fw-black);
}

/* Label kecil berhuruf kapital — dipakai satu bahasa visual
   untuk eyebrow, meta, dan badge di seluruh situs. */
.label {
  display: inline-block;
  font-size: var(--fs-label);
  font-weight: var(--fw-black);
  line-height: var(--lh-small);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* Teks pendukung (tanggal, keterangan kartu). */
.text-muted {
  color: var(--color-muted);
}

/* Hanya untuk pembaca layar. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Fokus keyboard --------------------------------------- */
:focus-visible {
  outline: var(--border-w) solid var(--color-accent-text);
  outline-offset: 3px;
}

/* Fallback untuk browser lama tanpa :focus-visible. */
:focus:not(:focus-visible) {
  outline: none;
}

/* ============================================================
   3. LAYOUT
   ============================================================ */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.section {
  padding-block: var(--space-12);
}

.section__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-6);
}

.section__header p {
  margin-top: var(--space-1);
  color: var(--color-muted);
}

/* Grid sederhana untuk kartu materi: mobile 1 kolom. */
.grid-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

/* ============================================================
   4. KOMPONEN
   ============================================================ */

/* --- Tombol ----------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-6);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  color: var(--color-ink);
  font-size: var(--fs-small);
  font-weight: var(--fw-black);
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  box-shadow: var(--shadow-hard);
  transition:
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}

.btn:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow-hard-hover);
  color: var(--color-ink);
}

.btn:active {
  transform: translate(3px, 3px);
  box-shadow: var(--shadow-none);
}

.btn:focus-visible {
  outline: var(--border-w) solid var(--color-accent-text);
  outline-offset: 4px;
}

/* Ubin dengan sudut kiri-atas terpotong — satu ciri khas
   dari kartu judul di canvas, dipakai konsisten untuk aksi. */
.btn::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: var(--space-4);
  height: var(--space-4);
  border-right: var(--border-w) solid currentColor;
  border-bottom: var(--border-w) solid currentColor;
  border-bottom-right-radius: var(--radius-md);
  pointer-events: none;
}

.btn--primary,
.btn--secondary {
  padding-left: var(--space-8);
}

.btn--secondary {
  background-color: var(--color-secondary);
}

.btn--secondary:hover {
  background-color: var(--color-secondary-hover);
}

.btn--secondary:active {
  background-color: var(--color-secondary-active);
}

.btn--primary {
  background-color: var(--color-accent);
  color: var(--color-on-accent);
}

.btn--primary:hover {
  background-color: var(--color-accent-hover);
  color: var(--color-on-accent);
}

.btn--primary:active {
  background-color: var(--color-accent-active);
}

/* Varian untuk latar berwarna pekat (mis. CTA lilac). */
.btn--ghost {
  background-color: transparent;
  box-shadow: none;
}

.btn--ghost:hover {
  transform: none;
  background-color: var(--color-surface);
  box-shadow: var(--shadow-hard);
}

/* Nonaktif dibaca sebagai slot kosong, bukan tombol kelabu: bingkainya
   putus-putus, tanpa bayangan keras, dan tanpa lipatan sudut. */
.btn[disabled],
.btn[aria-disabled="true"] {
  border-style: dashed;
  border-color: var(--color-placeholder);
  background-color: transparent;
  color: var(--color-muted);
  box-shadow: var(--shadow-none);
  cursor: not-allowed;
  transform: none;
  opacity: 1;
}

.btn[disabled]::before,
.btn[aria-disabled="true"]::before {
  display: none;
}

.btn[disabled]:hover,
.btn[aria-disabled="true"]:hover {
  transform: none;
  box-shadow: var(--shadow-none);
}

.btn--block {
  display: flex;
  width: 100%;
}

/* --- Kartu ------------------------------------------------ */
.card {
  position: relative;
  padding: var(--space-4);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-hard-lg);
}

.card__label {
  margin-bottom: var(--space-3);
}

.card__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-black);
  text-transform: uppercase;
}

.card__text {
  margin-top: var(--space-2);
  color: var(--color-muted);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}

.card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: var(--border-w-thin) dashed var(--color-border-muted);
  font-size: var(--fs-small);
  color: var(--color-muted);
}

.card--tint {
  background-color: var(--color-surface-soft);
}

/* Kartu materi: angka progres ditulis sebagai label, bukan
   dekorasi nomor urut. Tingginya disamakan supaya baris meta
   antarkartu tetap sebaris walau panjang teksnya beda. */
.card--lesson {
  display: flex;
  flex-direction: column;
  /* Kartu dibungkus <li> (lihat main.js), jadi tinggi sel grid ada di
     <li>. Tanpa ini margin-top: auto di .card__meta tidak berefek dan
     baris meta antarkartu tidak sebaris. */
  height: 100%;
}

/* Garis putus-putus di kepala baris meta diberi jarak sama besar ke
   ringkasan di atas dan ke lencana di bawahnya, jadi terbaca duduk di
   tengah. Baris meta tetap dipaku ke bawah kartu supaya lencananya
   sebaris antarkartu. */
.card--lesson .card__text {
  margin-bottom: var(--space-6);
}

.card--lesson .card__meta {
  margin-top: auto;
  padding-top: var(--space-6);
}

.card--lesson .card__index {
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin-bottom: var(--space-3);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-marker-bg);
  color: var(--color-on-accent);
  font-size: var(--fs-small);
  font-weight: var(--fw-black);
  box-shadow: var(--shadow-hard-sm);
}

/* --- Navbar ----------------------------------------------- */
.navbar {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: var(--border-w) solid var(--color-border);
  background-color: var(--color-surface-raised);
}

.navbar__inner {
  display: flex;
  flex-wrap: wrap; /* izinkan panel menu mobile turun ke baris sendiri */
  align-items: center;
  gap: var(--space-3);
  min-height: 64px;
  padding-block: var(--space-2);
}

.navbar__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-ink);
  font-size: var(--fs-h6);
  font-weight: var(--fw-black);
  letter-spacing: var(--tracking-display);
  text-decoration: none;
  text-transform: uppercase;
}

.navbar__brand:hover {
  color: var(--color-ink);
}

.navbar__mark {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-marker-bg);
  color: var(--color-on-accent);
  box-shadow: var(--shadow-hard-sm);
  /* Logo bergoyang pelan terus-menerus, lihat @keyframes wg-rock. */
  animation: wg-rock 5.5s ease-in-out infinite alternate;
}

/* Panel menu. Di layar kecil melayang turun di bawah navbar, keluar
   dari aliran flex, supaya tinggi navbar tidak ikut berubah dan isi
   halaman tidak bergeser. Di desktop direset jadi baris biasa (lihat
   breakpoint "Tablet"). Tanpa JavaScript panel tetap display:none,
   jadi tidak ada isi yang tersembunyi karena script. */
.navbar__links {
  display: none;
  position: absolute;
  inset: 100% 0 auto 0;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2);
  margin-left: 0;
  padding: var(--space-3) var(--container-pad) var(--space-4);
  background-color: var(--color-surface-raised);
  border-bottom: var(--border-w) solid var(--color-border);
  box-shadow: var(--shadow-hard);
  opacity: 0;
  transform: translateY(-14px);
  /* Baris pertama = cadangan untuk browser tanpa `allow-discrete`:
     kalau tidak didukung, deklarasinya dibuang dan animasi buka tetap
     jalan, hanya tutup yang langsung hilang. */
  transition:
    opacity var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);
  transition:
    opacity var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out),
    display var(--dur-base) allow-discrete;
}

.navbar__link {
  padding: var(--space-2) var(--space-3);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: transparent;
  color: var(--color-ink);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  text-decoration: none;
  box-shadow: none;
  transition:
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

/* Semua tautan cuma kotak outline. Yang sedang di-hover dan halaman yang
   sedang dibuka jadi kotak padat + bayangan keras, senada dengan tombol
   kecil di footer. */
.navbar__link:hover,
.navbar__link[aria-current="page"] {
  border-color: var(--color-border);
  background-color: var(--color-surface);
  /* Tautan global berubah indigo saat hover (lihat aturan `a:hover`);
     di navbar teksnya tetap tinta supaya cuma kotaknya yang berubah. */
  color: var(--color-ink);
  box-shadow: var(--shadow-hard-sm);
}

/* Putih "pindah": begitu satu tautan di-hover, tautan aktif yang tidak
   di-hover kehilangan isinya, jadi cuma satu kotak putih yang tampak.
   Tanpa dukungan :has() browser lama cuma kehilangan efek pindah ini;
   keduanya tetap terbaca sebagai tautan aktif/hover. */
.navbar__links:has(.navbar__link:hover) .navbar__link[aria-current="page"]:not(:hover) {
  background-color: transparent;
  box-shadow: none;
}

/* Mobile: menu dibuka via tombol .navbar__toggle (lihat main.js).
   Panel meluncur turun dari bawah navbar, lalu tautannya menyusul
   satu per satu. Gerak cuma transform dan opacity. */
.navbar[data-open] .navbar__links {
  display: flex;
  opacity: 1;
  transform: none;
}

/* Panel baru muncul setelah display berubah dari none ke flex, jadi
   browser belum punya "keadaan sebelum" untuk dianimasikan. Blok ini
   memberi titik awalnya. Browser tanpa @starting-style hanya kehilangan
   animasi buka; panel tetap tampil penuh. */
@starting-style {
  .navbar[data-open] .navbar__links {
    opacity: 0;
    transform: translateY(-14px);
  }
}

.navbar[data-open] .navbar__link {
  animation: wg-menu-tautan 260ms var(--ease-out) backwards;
}

/* Ukuran sentuh tautan di panel dipatok di satu tempat, bukan cuma saat
   dibuka, supaya tinggi panel tidak menyusut sekejap ketika ditutup. */
.navbar__links .navbar__link {
  padding: var(--space-3);
}

.navbar[data-open] .navbar__link:nth-child(2) {
  animation-delay: 40ms;
}

.navbar[data-open] .navbar__link:nth-child(3) {
  animation-delay: 80ms;
}

.navbar[data-open] .navbar__link:nth-child(4) {
  animation-delay: 120ms;
}

.navbar[data-open] .navbar__link:nth-child(5) {
  animation-delay: 160ms;
}

/* Deretan tombol di ujung kanan navbar: tema, lalu menu (menu hanya
   muncul di layar kecil). */
.navbar__tools {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

/* Dasar visual untuk tombol ikon navbar. */
.navbar__btn {
  display: grid;
  place-items: center;
  min-width: var(--tap-target);
  height: var(--tap-target);
  padding-inline: var(--space-2);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-secondary);
  color: var(--color-ink);
  box-shadow: var(--shadow-hard-sm);
  transition:
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-base) var(--ease-out);
}

/* Tombol ini duduk di atas .navbar yang berlatar --color-surface-raised,
   jadi hover tidak boleh memakai --color-secondary-hover: warnanya sama
   persis dengan latar dan tombolnya hilang. Dipakai --color-surface,
   sama seperti tautan navigasi yang sedang aktif. */
.navbar__btn:hover {
  background-color: var(--color-surface);
  color: var(--color-ink);
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow-hard);
}

.navbar__btn:active {
  transform: translate(2px, 2px);
  box-shadow: var(--shadow-none);
}

/* Tombol tema: ikon mengikuti pilihan aktif, teksnya muncul di layar
   lebar. Logikanya di assets/js/main.js. */
.theme-toggle {
  grid-auto-flow: column;
  gap: var(--space-2);
}

.theme-toggle__label {
  display: none;
  /* Lebar dipatok: teks "Terang"/"Gelap"/"Sistem" panjangnya beda, dan
     tanpa ini tombolnya (serta seluruh navbar) bergeser tiap ganti
     pilihan. */
  min-width: 2.5rem;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
}

.theme-toggle__ikon {
  display: none;
}

.theme-toggle[data-pilihan="sistem"] .theme-toggle__ikon--sistem,
.theme-toggle[data-pilihan="terang"] .theme-toggle__ikon--terang,
.theme-toggle[data-pilihan="gelap"] .theme-toggle__ikon--gelap {
  display: block;
}

.navbar__toggle {
  display: grid;
}

/* --- Sidebar (navigasi materi) ---------------------------- */
.sidebar {
  padding: var(--space-4);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-hard);
}

.sidebar__title {
  margin-bottom: var(--space-3);
  font-size: var(--fs-label);
  font-weight: var(--fw-black);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.sidebar__list {
  display: grid;
  gap: var(--space-2);
  padding: 0;
  list-style: none;
}

.sidebar__link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: var(--border-w-thin) solid var(--color-border-muted);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-soft);
  color: var(--color-ink);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  text-decoration: none;
  transition:
    transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

.sidebar__link:hover {
  border-color: var(--color-border);
  transform: translateX(2px);
}

/* Lencana di dalam baris yang di-hover ikut membesar sedikit. */
.sidebar__link:hover .badge {
  transform: scale(1.08);
}

/* Bab yang sedang dibuka: kotaknya lebih pekat dari baris lain, plus
   bayangan keras sebagai penanda. */
.sidebar__link[aria-current="page"] {
  border-color: var(--color-border);
  background-color: var(--color-secondary);
  box-shadow: var(--shadow-hard-sm);
}

.sidebar__link[aria-disabled="true"] {
  color: var(--color-muted);
  cursor: not-allowed;
}

/* --- Footer ----------------------------------------------- */
.footer {
  margin-top: var(--space-12);
  padding-block: var(--space-12) var(--space-6);
  border-top: var(--border-w) solid var(--color-border);
  background-color: var(--color-surface-soft);
}

/* Brand di kiri, tautan di kanan; di layar sempit keduanya membungkus
   sendiri jadi dua baris rata kiri. */
.footer__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-8);
}

.footer__wordmark {
  font-size: var(--fs-h2);
  font-weight: var(--fw-black);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: -0.02em;
}

.footer__tagline {
  margin-top: var(--space-3);
  max-width: 34ch;
  color: var(--color-muted);
  font-size: var(--fs-small);
}

.footer__nav {
  padding-top: var(--space-2);
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: 0;
  list-style: none;
}

/* Tautan footer dibungkus seperti tombol kecil, senada dengan tombol
   dan elemen ber-border lain di halaman: border tebal + bayangan keras. */
.footer__links a {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  color: var(--color-ink);
  font-size: var(--fs-small);
  font-weight: var(--fw-black);
  letter-spacing: var(--tracking-tight);
  text-decoration: none;
  text-transform: uppercase;
  box-shadow: var(--shadow-hard-sm);
  transition:
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}

.footer__links a:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow-hard);
}

/* Baris dasar: hak cipta dan catatan, dipisah garis tipis. */
.footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: var(--border-w-thin) solid var(--color-border-muted);
  color: var(--color-muted);
  font-size: var(--fs-small);
}

/* --- Badge ------------------------------------------------ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border: var(--border-w-thin) solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-soft);
  color: var(--color-ink);
  font-size: var(--fs-label);
  font-weight: var(--fw-black);
  line-height: 1.6;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out);
}

.badge--accent {
  background-color: var(--color-accent);
  color: var(--color-on-accent);
}

.badge--primary {
  background-color: var(--color-primary);
  color: var(--color-ink-inverse);
}

.badge--mint {
  background-color: var(--color-mint);
  color: var(--color-on-accent);
}

.badge--pink {
  background-color: var(--color-pink);
  color: var(--color-on-accent);
}

.badge--outline {
  background-color: transparent;
}

/* --- Alert ------------------------------------------------ */
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-info-bg);
  color: var(--color-info);
  box-shadow: var(--shadow-hard-sm);
  font-size: var(--fs-small);
}

.alert__title {
  display: block;
  font-size: var(--fs-small);
  font-weight: var(--fw-black);
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
}

.alert__text {
  margin-top: var(--space-1);
  color: inherit;
}

.alert__text a {
  color: inherit;
}

.alert--error {
  background-color: var(--color-error-bg);
  color: var(--color-error);
}

.alert--success {
  background-color: var(--color-success-bg);
  color: var(--color-success);
}

.alert--warning {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
}

/* --- Form dasar (dipakai styleguide & halaman berikutnya) -- */
.field {
  display: grid;
  gap: var(--space-2);
  max-width: 32rem;
}

.field__label {
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
}

.input {
  width: 100%;
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  color: var(--color-ink);
  box-shadow: var(--shadow-hard-sm);
  transition:
    box-shadow var(--dur-base) var(--ease-out),
    background-color var(--dur-base) var(--ease-out);
}

.input::placeholder {
  color: var(--color-placeholder);
  opacity: 1;
}

.input:hover {
  background-color: var(--color-background);
}

.input:focus-visible {
  outline: var(--border-w) solid var(--color-accent-text);
  outline-offset: 2px;
  box-shadow: var(--shadow-focus);
}

.input:disabled {
  background-color: var(--color-disabled-bg);
  color: var(--color-muted);
  box-shadow: none;
  cursor: not-allowed;
}

.field__hint {
  font-size: var(--fs-small);
  color: var(--color-muted);
}

/* ============================================================
   5. BREAKPOINT (mobile-first)
   ============================================================ */

/* Tablet — breakpoint 768px dipakai juga di main.js (matchMedia) untuk reset menu. */
@media (min-width: 768px) {
  :root {
    --container-pad: var(--space-6);
  }

  .section {
    padding-block: var(--space-16);
  }

  .card {
    padding: var(--space-6);
  }

  .grid-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }

  /* Desktop: menu jadi baris biasa di navbar, bukan panel melayang. */
  .navbar__links {
    display: flex;
    position: static;
    inset: auto;
    flex-basis: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
    padding: 0;
    background-color: transparent;
    border-bottom: 0;
    box-shadow: none;
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* State menu mobile tidak berlaku di desktop. */
  .navbar[data-open] .navbar__links {
    flex-basis: auto;
    flex-direction: row;
    gap: var(--space-2);
    padding: 0;
    opacity: 1;
    transform: none;
  }

  .navbar__links .navbar__link {
    padding: var(--space-2) var(--space-3);
  }

  .navbar__toggle {
    display: none;
  }

  .theme-toggle__label {
    display: inline;
  }
}

/* Desktop */
@media (min-width: 1024px) {
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .navbar__inner {
    flex-wrap: nowrap;
    column-gap: var(--space-4);
    row-gap: var(--space-3);
  }

  /* Sidebar dan konten berdampingan. */
  .layout--with-sidebar {
    display: grid;
    grid-template-columns: 16rem minmax(0, 1fr);
    align-items: start;
    gap: var(--space-8);
  }

  .sidebar {
    position: sticky;
    top: calc(64px + var(--space-6));
  }
}

/* ============================================================
   6. AKSESIBILITAS
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

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

  /* Matikan pergeseran posisi, tapi pertahankan perubahan
     shadow supaya hover masih terbaca sebagai state. */
  .btn:hover,
  .btn:active,
  .navbar__btn:hover,
  .navbar__btn:active,
  .navbar__link:hover,
  .sidebar__link:hover,
  .footer__links a:hover {
    transform: none;
  }

  /* Gerakan berulang dimatikan total, dan isi tidak pernah
     disembunyikan menunggu animasi. */
  .navbar__mark {
    animation: none;
    transform: rotate(-3deg);
  }

  .reveal-siap [data-reveal]:not(.is-in) {
    opacity: 1;
    transform: none;
  }
}

/* Mode kontras tinggi: paksa border ikut warna teks. */
@media (forced-colors: active) {
  .btn,
  .card,
  .badge,
  .alert,
  .input,
  .sidebar,
  .navbar {
    border: var(--border-w) solid CanvasText;
    box-shadow: none;
  }

  :focus-visible {
    outline: var(--border-w) solid Highlight;
  }
}

/* ============================================================
   7. HALAMAN BERANDA
   Tata letak khusus index.html. Semua warna dan ukuran memakai
   token di bagian 1, jadi tema gelap ikut berubah sendiri.
   ============================================================ */

/* --- Aksi yang berjajar (hero & ajakan) ------------------- */
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.actions--spaced {
  margin-top: var(--space-6);
}

/* --- Hero ------------------------------------------------- */
.hero {
  padding-block: var(--space-12) var(--space-8);
}

.hero__grid {
  display: grid;
  gap: var(--space-8);
}

.hero__title {
  margin-top: var(--space-3);
}

.hero__lead {
  margin-top: var(--space-4);
  color: var(--color-muted);
  font-size: var(--fs-lead);
}

.hero__note {
  margin-top: var(--space-4);
  color: var(--color-muted);
}

/* --- Hiasan hero ------------------------------------------ */
/* Mengisi ruang kosong di kolom kiri pada tata letak dua kolom:
   --lebar untuk desktop (kolom pendek & lebar, dari 1024px), --tinggi
   untuk tablet (kolom sempit tapi tinggi, 768-1023px). Di luar itu
   hero satu kolom dan tidak ada ruang sisa, jadi keduanya dimatikan. */
.hero__deco {
  display: none;
}

.hero__deco svg {
  display: block;
  width: 100%;
  height: auto;
}

.hero__deco-jalur {
  fill: none;
  stroke: var(--color-border-muted);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 7 10;
}

/* Bayangan keras digambar sebagai kotak terpisah, bukan filter. */
.hero__deco-bayang {
  fill: var(--color-shadow);
}

.hero__deco-badan {
  fill: var(--color-surface-soft);
  stroke: var(--color-ink);
  stroke-width: 3;
}

.hero__deco-chip--2 .hero__deco-badan {
  fill: var(--color-marker-bg);
}

.hero__deco-chip--3 .hero__deco-badan {
  fill: var(--color-secondary);
}

.hero__deco-teks {
  fill: var(--color-ink);
  font-family: var(--font-mono);
  font-size: 21px;
  font-weight: var(--fw-bold);
  text-anchor: middle;
}

.hero__deco-titik {
  fill: var(--color-primary);
}

.hero__deco-titik--2 {
  fill: var(--color-marker-bg);
}

/* --- Panel (wadah kode dan hasilnya) ---------------------- */
.pane {
  overflow: hidden;
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-hard-lg);
}

.pane__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-w) solid var(--color-border);
  background-color: var(--color-surface-soft);
}

.pane__name {
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pane__badge {
  margin-left: auto;
  color: var(--color-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

.pane__dots {
  display: flex;
  gap: 6px;
}

.pane__dot {
  width: 10px;
  height: 10px;
  border: var(--border-w-thin) solid var(--color-border);
  border-radius: var(--radius-pill);
}

.pane__dot:nth-child(1) {
  background-color: var(--color-pink);
}

.pane__dot:nth-child(2) {
  background-color: var(--color-accent);
}

.pane__dot:nth-child(3) {
  background-color: var(--color-mint);
}

/* Panel kode sengaja selalu gelap — lihat token --color-code-*. */
.code-pane {
  background-color: var(--color-code-bg);
  /* Bayangan panel kode pakai indigo navbar, bukan tinta, supaya tidak
     tampak dobel bertumpuk dengan panelnya yang gelap. Panel hasil
     tetap pakai bayangan tinta bawaan .pane. */
  box-shadow: 8px 8px 0 0 var(--color-surface-raised);
}

.code-pane .pane__bar {
  border-bottom-color: var(--color-code-bar);
  background-color: var(--color-code-bar);
}

.code-pane .pane__name {
  color: var(--color-code-ink);
}

.code-pane .pane__badge {
  color: var(--color-code-muted);
}

.code {
  margin: 0;
  padding: var(--space-4);
  overflow-x: auto;
  color: var(--color-code-ink);
  font-family: var(--font-mono);
  font-size: var(--fs-code);
  line-height: var(--lh-code);
}

.code__line {
  display: block;
  /* Spasi di awal baris ikut ditulis di HTML; newline antar-baris
     source dibuang, jadi markup tetap menjorok rapi. */
  white-space: pre;
}

/* Nama token, bukan hiasan: tiap warna menandai satu jenis isi. */
.tok-tag {
  color: var(--color-code-tag);
}

.tok-attr {
  color: var(--color-code-attr);
}

.tok-string {
  color: var(--color-code-string);
}

.tok-punct {
  color: var(--color-code-muted);
}

/* Hasil: halaman kecil yang benar-benar dirender browser. */
.demo-page {
  padding: var(--space-6) var(--space-4);
  background-color: var(--color-surface);
}

.demo-page h1 {
  font-size: var(--fs-h4);
  letter-spacing: var(--tracking-tight);
  line-height: var(--lh-heading);
  text-transform: none;
}

.demo-page p {
  margin-top: var(--space-3);
}

/* Konektor dari kode ke hasilnya: panah turun penuh (batang + kepala).
   Digambar lewat clip-path supaya tetap satu elemen, tanpa gambar. */
.workbench__flow {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.workbench__flow::before,
.workbench__flow::after {
  content: "";
  width: 15px;
  height: var(--space-4);
  background-color: var(--color-ink);
  clip-path: polygon(50% 100%, 0 46%, 31% 46%, 31% 0, 69% 0, 69% 46%, 100% 46%);
}

/* Gerak halaman. Semuanya cuma opacity dan transform supaya murah
   digambar; tidak ada yang menggeser tata letak.

   1. Baris kode di hero muncul berurutan, lalu panel hasilnya.
   2. Logo navbar bergoyang pelan terus-menerus; ini dan hiasan hero
      (nomor 5) gerakan yang berulang.
   3. Elemen [data-reveal] naik halus saat masuk viewport, diatur
      assets/js/main.js.
   4. Panel menu mobile meluncur turun dan tautannya menyusul
      (wg-menu-tautan); menutup pun beranimasi.
   5. Hiasan hero terapung naik-turun dan titiknya berkedip
      (wg-deco-terapung, wg-deco-kedip), tampil di tata letak dua kolom
      (768px ke atas): varian --lebar di desktop, --tinggi di tablet. */
@keyframes wg-line {
  from {
    opacity: 0;
    transform: translateX(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes wg-appear {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes wg-reveal {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes wg-menu-tautan {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes wg-deco-terapung {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-9px);
  }
}

@keyframes wg-deco-kedip {
  from {
    opacity: 0.35;
  }
  to {
    opacity: 1;
  }
}

@keyframes wg-rock {
  from {
    transform: rotate(-4.5deg);
  }
  to {
    transform: rotate(-1.5deg);
  }
}

.code__line {
  animation: wg-line 220ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 90ms);
}

.result-pane {
  animation: wg-appear 320ms var(--ease-out) both;
  animation-delay: 900ms;
}

/* Keadaan tersembunyi hanya berlaku kalau script di <head> berhasil
   memasang .reveal-siap. Tanpa JavaScript (atau kalau
   IntersectionObserver tidak ada) tidak ada elemen yang disembunyikan,
   jadi isi halaman selalu terbaca. */
.reveal-siap [data-reveal]:not(.is-in) {
  opacity: 0;
  transform: translateY(14px);
}

/* `backwards` saja, tanpa `forwards`: setelah animasi selesai elemen
   kembali ke gaya dasarnya sehingga transform hover tidak terkunci.
   Jeda bertahap memakai --stagger; giliran tiap elemen diisi main.js
   lewat --reveal-step. */
.reveal-siap [data-reveal].is-in {
  animation: wg-reveal var(--dur-reveal) var(--ease-out) backwards;
  animation-delay: calc(var(--stagger) * var(--reveal-step, 0));
}

/* --- Langkah (urutan asli: 1 lalu 2 lalu 3) --------------- */
.steps {
  display: grid;
  gap: var(--space-6);
  padding: 0;
  list-style: none;
  counter-reset: langkah;
}

.steps__item {
  position: relative;
  padding-left: calc(36px + var(--space-4));
}

.steps__item::before {
  counter-increment: langkah;
  content: counter(langkah);
  position: absolute;
  top: 0;
  left: 0;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-marker-bg);
  box-shadow: var(--shadow-hard-sm);
  color: var(--color-on-accent);
  font-size: var(--fs-small);
  font-weight: var(--fw-black);
}

.steps__title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-black);
  text-transform: uppercase;
}

.steps__text {
  margin-top: var(--space-2);
  color: var(--color-muted);
  font-size: var(--fs-small);
}

/* --- Rapor contoh (kemajuan yang tersimpan) --------------- */
.report {
  display: grid;
  gap: var(--space-6);
}

.report__stack {
  display: grid;
  align-content: start;
  gap: var(--space-4);
}

.report__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

/* Di dalam daftar bab, lencana status menempel ke kanan. */
.sidebar__link .badge {
  margin-left: auto;
}

/* --- Breakpoint halaman beranda --------------------------- */
@media (min-width: 768px) {
  .report {
    grid-template-columns: 20rem minmax(0, 1fr);
    align-items: start;
  }

  /* Hero tablet: band judul penuh di atas, lalu dua kolom di bawahnya —
     kiri sisa elemen hero (tombol, catatan, hiasan), kanan panel kode
     dan hasilnya yang tinggi. Judul dibiarkan selebar band supaya
     barisnya tidak pecah jadi terlalu banyak potongan. */
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "intro intro"
      "ekstra kerja";
    align-items: start;
  }

  /* display: contents membuat --intro dan --extras naik jadi anak grid
     langsung, jadi keduanya bisa menempati area sendiri. Di luar
     rentang ini --copy tetap kotak biasa, jadi mobile & desktop sama. */
  .hero__copy {
    display: contents;
  }

  .hero__intro {
    grid-area: intro;
  }

  .hero__extras {
    grid-area: ekstra;
  }

  .hero__workbench {
    grid-area: kerja;
  }

  /* Jarak tombol dari teks judul diatur row-gap grid, bukan margin. */
  .hero__extras .actions--spaced {
    margin-top: 0;
  }

  /* Hiasan varian tinggi mengisi kolom kiri yang sempit tapi tinggi.
     Lebarnya dipatok: kalau ikut lebar kolom, tingginya (yang mengikuti
     rasio) melampaui tinggi panel kode di lebar besar. */
  .hero__deco--tinggi {
    display: block;
    margin-top: var(--space-6);
  }

  .hero__deco--tinggi svg {
    max-width: 25rem;
    margin-inline: auto;
  }

  /* Tiga chip terapung dengan durasi dan jeda berbeda supaya tidak
     bergerak serempak; dua titiknya berkedip. */
  .hero__deco-chip--1 {
    animation: wg-deco-terapung 3.2s var(--ease-out) infinite alternate;
  }

  .hero__deco-chip--2 {
    animation: wg-deco-terapung 4.2s var(--ease-out) -1.4s infinite alternate;
  }

  .hero__deco-chip--3 {
    animation: wg-deco-terapung 3.6s var(--ease-out) -2.1s infinite alternate;
  }

  .hero__deco-titik {
    animation: wg-deco-kedip 2.6s var(--ease-out) infinite alternate;
  }

  .hero__deco-titik--2 {
    animation: wg-deco-kedip 3.1s var(--ease-out) -1.2s infinite alternate;
  }
}

@media (min-width: 1024px) {
  .hero {
    padding-block: var(--space-16) var(--space-12);
  }

  /* Kembali ke dua kolom: teks di kiri, panel kode di kanan. Kolom
     teks sedikit lebih lebar dari kolom kode: judul display butuh
     ~470px per baris supaya "baris demi baris." tidak pecah jadi baris
     yatim; isi panel kode cuma butuh ~270px. Kolom teks lebih pendek
     dari panel kode; sisa ruang di bawahnya diisi hiasan --lebar, jadi
     tidak menganga kosong. */
  .hero__grid {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    grid-template-areas: none;
    align-items: start;
    gap: var(--space-12);
  }

  /* Batalkan pengaturan khusus tablet: --copy kembali jadi kotak biasa
     dan tak ada lagi area grid bernama. */
  .hero__copy {
    display: block;
  }

  .hero__intro,
  .hero__extras,
  .hero__workbench {
    grid-area: auto;
  }

  .hero__extras .actions--spaced {
    margin-top: var(--space-6);
  }

  .hero__deco--tinggi {
    display: none;
  }

  .hero__deco--lebar {
    display: block;
    margin-top: var(--space-6);
  }
}

/* Pengguna yang minta gerakan minim langsung dapat keadaan akhir. */
@media (prefers-reduced-motion: reduce) {
  .code__line,
  .result-pane {
    animation-delay: 0ms;
  }

  /* Hiasan hero dimatikan total (bukan cuma dipercepat), jadi chip dan
     titiknya diam di tempat. Ditaruh paling akhir, setelah aturan
     animasinya di breakpoint Tablet, supaya benar-benar menang. */
  .hero__deco-chip,
  .hero__deco-titik {
    animation: none;
  }
}
